Merge branch 'master' into dev

This commit is contained in:
bjorn 2023-02-21 21:12:33 -08:00
commit abbc6a6dc6
6 changed files with 142 additions and 42 deletions

View File

@ -210,24 +210,17 @@ endif()
# OpenXR
if(LOVR_ENABLE_HEADSET AND LOVR_USE_OPENXR)
include_directories(deps/openxr/include)
if(ANDROID)
add_library(openxr_loader SHARED IMPORTED)
set(LOVR_OPENXR openxr_loader)
set(LOVR_OPENXR_OCULUS_PATH "${CMAKE_CURRENT_SOURCE_DIR}/deps/oculus-openxr" CACHE STRING "The path to the Oculus OpenXR loader")
set_target_properties(openxr_loader PROPERTIES IMPORTED_LOCATION "${LOVR_OPENXR_OCULUS_PATH}/Libs/Android/${ANDROID_ABI}/Release/libopenxr_loader.so")
else()
if(LOVR_SYSTEM_OPENXR)
pkg_search_module(OPENXR openxr)
if(NOT OPENXR_FOUND)
message(FATAL_ERROR "OpenXR not found.")
endif()
include_directories(${OPENXR_INCLUDE_DIRS})
set(LOVR_OPENXR ${OPENXR_LIBRARIES})
else()
set(DYNAMIC_LOADER ON CACHE BOOL "")
add_subdirectory(deps/openxr openxr)
set(LOVR_OPENXR openxr_loader)
if(LOVR_SYSTEM_OPENXR AND NOT ANDROID)
pkg_search_module(OPENXR openxr)
if(NOT OPENXR_FOUND)
message(FATAL_ERROR "OpenXR not found.")
endif()
include_directories(${OPENXR_INCLUDE_DIRS})
set(LOVR_OPENXR ${OPENXR_LIBRARIES})
else()
set(DYNAMIC_LOADER ON CACHE BOOL "")
add_subdirectory(deps/openxr openxr)
set(LOVR_OPENXR openxr_loader)
endif()
endif()
@ -740,6 +733,16 @@ elseif(EMSCRIPTEN)
target_sources(lovr PRIVATE src/core/os_wasm.c)
configure_file(etc/lovr.ico favicon.ico COPYONLY)
elseif(ANDROID)
set(ANDROID_MANIFEST "${CMAKE_CURRENT_SOURCE_DIR}/etc/AndroidManifest.xml" CACHE STRING "The AndroidManifest.xml file to use")
file(READ ${ANDROID_MANIFEST} ANDROID_MANIFEST_CONTENT)
string(REGEX MATCH "package=\"([^\"]*)" _ ${ANDROID_MANIFEST_CONTENT})
set(ANDROID_PACKAGE ${CMAKE_MATCH_1})
string(REPLACE "." "_" ANDROID_PACKAGE_C ${ANDROID_PACKAGE})
string(REPLACE "." "/" ANDROID_PACKAGE_JAVA ${ANDROID_PACKAGE})
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/etc/Activity.java ${CMAKE_CURRENT_BINARY_DIR}/Activity.java)
target_compile_definitions(lovr PRIVATE "LOVR_JAVA_PACKAGE=${ANDROID_PACKAGE_C}")
target_sources(lovr PRIVATE src/core/os_android.c)
target_link_libraries(lovr log android dl)
target_include_directories(lovr PRIVATE "${ANDROID_NDK}/sources/android/native_app_glue")
@ -755,20 +758,30 @@ elseif(ANDROID)
if(LOVR_BUILD_EXE)
set(ANDROID_JAR "${ANDROID_SDK}/platforms/${ANDROID_PLATFORM}/android.jar")
set(ANDROID_TOOLS "${ANDROID_SDK}/build-tools/${ANDROID_BUILD_TOOLS_VERSION}")
set(ANDROID_MANIFEST "${CMAKE_CURRENT_SOURCE_DIR}/etc/AndroidManifest.xml" CACHE STRING "The AndroidManifest.xml file to use")
# If assets are included in the apk then add '-A assets' to aapt, otherwise don't add any flags
if(ANDROID_ASSETS)
set(ANDROID_ASSETS -A ${ANDROID_ASSETS})
endif()
if(ANDROID_PACKAGE)
set(PACKAGE_RENAME "--rename-manifest-package" "${ANDROID_PACKAGE}")
endif()
if(LOVR_USE_OPENXR)
get_target_property(OPENXR_LIB ${LOVR_OPENXR} IMPORTED_LOCATION)
file(COPY ${OPENXR_LIB} DESTINATION raw/lib/${ANDROID_ABI})
add_custom_command(TARGET move_files POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
$<TARGET_SONAME_FILE:${LOVR_OPENXR}>
raw/lib/${ANDROID_ABI}/libopenxr_loader_generic.so
)
set(PICO_LOADER "${CMAKE_CURRENT_SOURCE_DIR}/deps/pico-openxr/libs/android.${ANDROID_ABI}/libopenxr_loader.so")
if(EXISTS ${PICO_LOADER})
configure_file(${PICO_LOADER} "raw/lib/${ANDROID_ABI}/libopenxr_loader_pico.so" COPYONLY)
endif()
set(OCULUS_LOADER "${CMAKE_CURRENT_SOURCE_DIR}/deps/oculus-openxr/Libs/Android/${ANDROID_ABI}/Release/libopenxr_loader.so")
if(EXISTS ${OCULUS_LOADER})
configure_file(${OCULUS_LOADER} "raw/lib/${ANDROID_ABI}/libopenxr_loader_oculus.so" COPYONLY)
endif()
configure_file("${ANDROID_NDK}/toolchains/llvm/prebuilt/${ANDROID_HOST_TAG}/sysroot/usr/lib/aarch64-linux-android/libc++_shared.so" "raw/lib/${ANDROID_ABI}/libc++_shared.so" COPYONLY)
endif()
if(LOVR_USE_OCULUS_AUDIO)
@ -786,9 +799,8 @@ elseif(ANDROID)
buildAPK ALL
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMAND ${CMAKE_COMMAND} -E copy "${ANDROID_MANIFEST}" AndroidManifest.xml
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/etc/Activity.java Activity.java
COMMAND ${Java_JAVAC_EXECUTABLE} -classpath "${ANDROID_JAR}" -d . Activity.java
COMMAND ${ANDROID_TOOLS}/d8 --min-api ${ANDROID_NATIVE_API_LEVEL} --output raw org/lovr/app/Activity.class
COMMAND ${ANDROID_TOOLS}/d8 --min-api ${ANDROID_NATIVE_API_LEVEL} --output raw ${ANDROID_PACKAGE_JAVA}/Activity.class
COMMAND
${ANDROID_TOOLS}/aapt
package -f

View File

@ -43,7 +43,7 @@ config = {
keystore = '/path/to/keystore',
keystorepass = 'pass:password',
manifest = nil,
package = nil,
package = 'org.lovr.app',
project = nil
}
}
@ -175,6 +175,7 @@ if target == 'android' then
flags += config.debug and '-funwind-tables' or ''
cflags += '-D_POSIX_C_SOURCE=200809L'
cflags += ('-I%s/sources/android/native_app_glue'):format(config.android.ndk)
cflags += '-DLOVR_JAVA_PACKAGE=' .. config.android.package:gsub('%.', '_')
lflags += '-shared -landroid'
end
@ -455,7 +456,7 @@ comp = 'etc/shaders/*.comp'
function compileShaders(stage)
pattern = 'etc/shaders/*.' .. stage
tup.foreach_rule(pattern, 'glslangValidator --quiet -Os --target-env vulkan1.1 --vn lovr_shader_%B_' .. stage .. ' -o %o %f', '%f.h')
tup.foreach_rule(pattern, 'glslangValidator --quiet --target-env vulkan1.1 --vn lovr_shader_%B_' .. stage .. ' -o %o %f', '%f.h')
end
compileShaders('vert')
@ -490,7 +491,7 @@ if target == 'android' then
end
java = 'bin/Activity.java'
class = 'org/lovr/app/Activity.class'
class = config.android.package:gsub('%.', '/') .. '/Activity.class'
binclass = 'bin/' .. class
jar = 'bin/lovr.jar'
dex = 'bin/apk/classes.dex'
@ -499,7 +500,7 @@ if target == 'android' then
apk = 'bin/lovr.apk'
manifest = config.android.manifest or 'etc/AndroidManifest.xml'
package = config.android.package and #config.android.package > 0 and ('--rename-manifest-package ' .. config.android.package) or ''
package = '--rename-manifest-package ' .. config.android.package
project = config.android.project and #config.android.project > 0 and ('-A ' .. config.android.project) or ''
version = config.android.version
@ -509,7 +510,7 @@ if target == 'android' then
tools = config.android.sdk .. '/build-tools/' .. config.android.buildtools
copy(manifest, 'bin/AndroidManifest.xml')
copy('etc/Activity.java', java)
tup.rule('etc/Activity.java', 'tup varsed %f %o', java)
tup.rule(java, '^ JAVAC %b^ javac -classpath $(androidjar) -d bin %f', binclass)
tup.rule(binclass, '^ JAR %b^ jar -cf %o -C bin $(class)', jar)
tup.rule(jar, '^ D8 %b^ $(tools)/d8 --min-api $(version) --output bin/apk %f', dex)

View File

@ -1,12 +1,23 @@
package org.lovr.app;
package @ANDROID_PACKAGE@;
import android.Manifest;
import android.app.NativeActivity;
import android.content.pm.PackageManager;
import android.util.Log;
import android.os.Build;
public class Activity extends NativeActivity {
static {
System.loadLibrary("openxr_loader");
if (Build.MANUFACTURER.contains("Oculus")) {
Log.d("LOVR", "Using Oculus OpenXR Loader");
System.loadLibrary("openxr_loader_oculus");
} else if (Build.MANUFACTURER.contains("Pico")) {
Log.d("LOVR", "Using Pico OpenXR Loader");
System.loadLibrary("openxr_loader_pico");
} else {
Log.d("LOVR", "Using Generic OpenXR Loader");
System.loadLibrary("openxr_loader_generic");
}
System.loadLibrary("lovr");
}

View File

@ -1,29 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.lovr.app" android:installLocation="auto" android:versionCode="1">
<uses-sdk android:minSdkVersion="23" android:targetSdkVersion="26"/>
<uses-feature android:glEsVersion="0x00030001" android:required="true"/>
<uses-feature android:name="android.hardware.vr.headtracking" android:required="false"/>
<uses-feature android:name="oculus.software.handtracking" android:required="false"/>
<!-- Oculus -->
<uses-feature android:name="oculus.software.trackedkeyboard" android:required="false"/>
<uses-feature android:name="com.oculus.feature.RENDER_MODEL" android:required="false"/>
<uses-feature android:name="com.oculus.feature.PASSTHROUGH" android:required="false"/>
<uses-permission android:name="com.oculus.permission.HAND_TRACKING"/>
<uses-permission android:name="com.oculus.permission.TRACKED_KEYBOARD"/>
<uses-permission android:name="com.oculus.permission.RENDER_MODEL"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-permission android:name="android.permission.INTERNET"/>
<!-- Khronos/Generic -->
<uses-permission android:name="org.khronos.openxr.permission.OPENXR"/>
<uses-permission android:name="org.khronos.openxr.permission.OPENXR_SYSTEM"/>
<queries>
<provider android:name="org.khronos.openxr.runtime_broker" android:authorities="org.khronos.openxr.runtime_broker;org.khronos.openxr.system_runtime_broker"/>
</queries>
<application android:allowBackup="false" android:label="LÖVR" android:extractNativeLibs="false" android:debuggable="true">
<meta-data android:name="pvr.app.type" android:value="vr"/> <!-- Pico -->
<meta-data android:name="com.samsung.android.vr.application.mode" android:value="vr_only"/>
<meta-data android:name="com.oculus.supportedDevices" android:value="quest|quest2"/>
<meta-data android:name="com.oculus.handtracking.version" android:value="V2.0"/>
<activity android:name="Activity" android:launchMode="singleTask" android:screenOrientation="landscape" android:excludeFromRecents="true">
<activity android:name="Activity" android:launchMode="singleTask" android:screenOrientation="landscape" android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen" android:excludeFromRecents="true">
<meta-data android:name="android.app.lib_name" android:value="lovr"/>
<meta-data android:name="com.oculus.vr.focusaware" android:value="true"/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="com.oculus.intent.category.VR"/>
<category android:name="org.khronos.openxr.intent.category.IMMERSIVE_HMD"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>

View File

@ -241,7 +241,10 @@ void os_sleep(double seconds) {
while (nanosleep(&t, &t));
}
JNIEXPORT void JNICALL Java_org_lovr_app_Activity_lovrPermissionEvent(JNIEnv* jni, jobject activity, jint permission, jboolean granted) {
#define _JNI(PKG, X) Java_ ## PKG ## _ ## X
#define JNI(PKG, X) _JNI(PKG, X)
JNIEXPORT void JNICALL JNI(LOVR_JAVA_PACKAGE, Activity_lovrPermissionEvent)(JNIEnv* jni, jobject activity, jint permission, jboolean granted) {
if (state.onPermissionEvent) {
state.onPermissionEvent(permission, granted);
}

View File

@ -375,6 +375,10 @@ static bool openxr_init(HeadsetConfig* config) {
#ifdef LOVR_VK
{ "XR_KHR_vulkan_enable2", NULL, true },
#endif
#ifdef __ANDROID__
{ "XR_KHR_android_create_instance", NULL, true },
#endif
{ "XR_KHR_composition_layer_depth", &state.features.depth, config->submitDepth },
{ "XR_EXT_eye_gaze_interaction", &state.features.gaze, true },
{ "XR_EXT_hand_tracking", &state.features.handTracking, true },
@ -383,7 +387,9 @@ static bool openxr_init(HeadsetConfig* config) {
{ "XR_FB_hand_tracking_mesh", &state.features.handTrackingMesh, true },
{ "XR_FB_keyboard_tracking", &state.features.keyboardTracking, true },
{ "XR_FB_passthrough", &state.features.passthrough, true },
#ifndef __ANDROID__
{ "XR_MND_headless", &state.features.headless, true },
#endif
{ "XR_MSFT_controller_model", &state.features.controllerModel, true },
{ "XR_ULTRALEAP_hand_tracking_forearm", &state.features.handTrackingElbow, true },
{ "XR_EXTX_overlay", &state.features.overlay, config->overlay },
@ -402,8 +408,20 @@ static bool openxr_init(HeadsetConfig* config) {
free(extensionProperties);
#ifdef __ANDROID__
XrInstanceCreateInfoAndroidKHR androidInfo = {
.type = XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR,
.applicationVM = os_get_java_vm(),
.applicationActivity = os_get_jni_context(),
.next = NULL
};
#endif
XrInstanceCreateInfo info = {
.type = XR_TYPE_INSTANCE_CREATE_INFO,
#ifdef __ANDROID__
.next = &androidInfo,
#endif
.applicationInfo.engineName = "LÖVR",
.applicationInfo.engineVersion = (LOVR_VERSION_MAJOR << 24) + (LOVR_VERSION_MINOR << 16) + LOVR_VERSION_PATCH,
.applicationInfo.applicationName = "LÖVR",
@ -588,6 +606,7 @@ static bool openxr_init(HeadsetConfig* config) {
PROFILE_WMR,
PROFILE_TRACKER,
PROFILE_GAZE,
PROFILE_PICO,
MAX_PROFILES
};
@ -599,7 +618,8 @@ static bool openxr_init(HeadsetConfig* config) {
[PROFILE_INDEX] = "/interaction_profiles/valve/index_controller",
[PROFILE_WMR] = "/interaction_profiles/microsoft/motion_controller",
[PROFILE_TRACKER] = "/interaction_profiles/htc/vive_tracker_htcx",
[PROFILE_GAZE] = "/interaction_profiles/ext/eye_gaze_interaction"
[PROFILE_GAZE] = "/interaction_profiles/ext/eye_gaze_interaction",
[PROFILE_PICO] = "/interaction_profiles/pico/neo3_controller"
};
typedef struct {
@ -798,6 +818,45 @@ static bool openxr_init(HeadsetConfig* config) {
[PROFILE_GAZE] = (Binding[]) {
{ ACTION_GAZE_POSE, "/user/eyes_ext/input/gaze_ext/pose" },
{ 0, NULL }
},
[PROFILE_PICO] = (Binding[]) {
{ ACTION_HAND_POSE, "/user/hand/left/input/grip/pose" },
{ ACTION_HAND_POSE, "/user/hand/right/input/grip/pose" },
{ ACTION_POINTER_POSE, "/user/hand/left/input/aim/pose" },
{ ACTION_POINTER_POSE, "/user/hand/right/input/aim/pose" },
{ ACTION_TRIGGER_DOWN, "/user/hand/left/input/trigger/value" },
{ ACTION_TRIGGER_DOWN, "/user/hand/right/input/trigger/value" },
{ ACTION_TRIGGER_TOUCH, "/user/hand/left/input/trigger/touch" },
{ ACTION_TRIGGER_TOUCH, "/user/hand/right/input/trigger/touch" },
{ ACTION_TRIGGER_AXIS, "/user/hand/left/input/trigger/value" },
{ ACTION_TRIGGER_AXIS, "/user/hand/right/input/trigger/value" },
{ ACTION_THUMBSTICK_DOWN, "/user/hand/left/input/thumbstick/click" },
{ ACTION_THUMBSTICK_DOWN, "/user/hand/right/input/thumbstick/click" },
{ ACTION_THUMBSTICK_TOUCH, "/user/hand/left/input/thumbstick/touch" },
{ ACTION_THUMBSTICK_TOUCH, "/user/hand/right/input/thumbstick/touch" },
{ ACTION_THUMBSTICK_X, "/user/hand/left/input/thumbstick/x" },
{ ACTION_THUMBSTICK_X, "/user/hand/right/input/thumbstick/x" },
{ ACTION_THUMBSTICK_Y, "/user/hand/left/input/thumbstick/y" },
{ ACTION_THUMBSTICK_Y, "/user/hand/right/input/thumbstick/y" },
//{ ACTION_MENU_DOWN, "/user/hand/left/input/menu/click" }, //Imposter
{ ACTION_MENU_DOWN, "/user/hand/right/input/system/click" },
{ ACTION_GRIP_DOWN, "/user/hand/left/input/squeeze/click" },
{ ACTION_GRIP_DOWN, "/user/hand/right/input/squeeze/click" },
{ ACTION_GRIP_AXIS, "/user/hand/left/input/squeeze/value" },
{ ACTION_GRIP_AXIS, "/user/hand/right/input/squeeze/value" },
{ ACTION_A_DOWN, "/user/hand/right/input/a/click" },
{ ACTION_A_TOUCH, "/user/hand/right/input/a/touch" },
{ ACTION_B_DOWN, "/user/hand/right/input/b/click" },
{ ACTION_B_TOUCH, "/user/hand/right/input/b/touch" },
{ ACTION_X_DOWN, "/user/hand/left/input/x/click" },
{ ACTION_X_TOUCH, "/user/hand/left/input/x/touch" },
{ ACTION_Y_DOWN, "/user/hand/left/input/y/click" },
{ ACTION_Y_TOUCH, "/user/hand/left/input/y/touch" },
{ ACTION_THUMBREST_TOUCH, "/user/hand/left/input/thumbrest/touch" },
{ ACTION_THUMBREST_TOUCH, "/user/hand/right/input/thumbrest/touch" },
{ ACTION_VIBRATE, "/user/hand/left/output/haptic" },
{ ACTION_VIBRATE, "/user/hand/right/output/haptic" },
{ 0, NULL }
}
};
@ -821,12 +880,16 @@ static bool openxr_init(HeadsetConfig* config) {
if (count > 0) {
XR_INIT(xrStringToPath(state.instance, interactionProfilePaths[i], &path));
XR_INIT(xrSuggestInteractionProfileBindings(state.instance, &(XrInteractionProfileSuggestedBinding) {
XrResult result = (xrSuggestInteractionProfileBindings(state.instance, &(XrInteractionProfileSuggestedBinding) {
.type = XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING,
.interactionProfile = path,
.countSuggestedBindings = count,
.suggestedBindings = suggestedBindings
}));
if (XR_FAILED(result)) {
lovrLog(LOG_WARN, "XR", "Failed to suggest input bindings for %s", interactionProfilePaths[i]);
}
}
}
}