Updated to OpenXR

Also means the Pico 4 works now
This commit is contained in:
Simon 2022-12-22 22:22:52 +00:00
parent 605d1edb6e
commit b4a24d1765
21 changed files with 4029 additions and 2841 deletions

View file

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id=":VrSamples:QuakeQuest:Projects:Android" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="QuakeQuest.VrSamples.QuakeQuest.Projects" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<module external.linked.project.id=":XrSamples:QuakeQuest:Projects:Android" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="QuakeQuest.XrSamples.QuakeQuest.Projects" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle">
<configuration>
<option name="GRADLE_PROJECT_PATH" value=":VrSamples:QuakeQuest:Projects:Android" />
<option name="GRADLE_PROJECT_PATH" value=":XrSamples:QuakeQuest:Projects:Android" />
<option name="LAST_SUCCESSFUL_SYNC_AGP_VERSION" value="4.0.2" />
<option name="LAST_KNOWN_AGP_VERSION" value="4.0.2" />
</configuration>

View file

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.drbeef.quakequest"
android:versionCode="18"
android:versionName="1.4.11"
android:versionCode="20"
android:versionName="1.5.1"
android:installLocation="auto" >
<!-- Tell the system this app requires OpenGL ES 3.1. -->
@ -11,25 +11,25 @@
<uses-feature android:name="android.hardware.vr.headtracking" android:version="1"
android:required="true" />
<!-- Network access needed for OVRMonitor -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- Volume Control -->
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:allowBackup="false"
android:icon="@drawable/ic_qquest"
android:label="@string/quakequest"
android:extractNativeLibs="true">
<!-- META QUEST -->
<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"/>
<!-- The activity is the built-in NativeActivity framework class. -->
<!-- launchMode is set to singleTask because there should never be multiple copies of the app running. -->
<!-- Theme.Black.NoTitleBar.Fullscreen gives solid black instead of a (bad stereoscopic) gradient on app transition. -->
<!-- If targeting API level 24+, configChanges should additionally include 'density'. -->
<!-- If targeting API level 24+, android:resizeableActivity="false" should be added. -->
<!-- PICO XR -->
<meta-data android:name="pvr.app.type" android:value="vr" />
<activity
android:name="com.drbeef.quakequest.GLES3JNIActivity"
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"

View file

@ -15,22 +15,19 @@ android {
applicationId "com.drbeef." + project.archivesBaseName
// override app plugin abiFilters for both 32 and 64-bit support
externalNativeBuild {
ndk {
abiFilters 'arm64-v8a'
}
ndkBuild {
abiFilters 'arm64-v8a'
}
}
externalNativeBuild {
ndk {
abiFilters 'arm64-v8a'
}
ndkBuild {
abiFilters 'arm64-v8a'
}
}
minSdkVersion 26
targetSdkVersion 26
}
task prepareKotlinBuildScriptModel {
}
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
@ -45,12 +42,13 @@ android {
targetCompatibility = '1.8'
}
compileSdkVersion = 26
buildToolsVersion = '29.0.2'
buildToolsVersion = '29.0.1'
}
dependencies {
implementation "com.android.support:support-compat:26.1.0"
implementation "com.android.support:support-core-utils:26.1.0"
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
}
repositories {

View file

@ -6,15 +6,21 @@ LOCAL_PATH:= $(call my-dir)
#--------------------------------------------------------
include $(CLEAR_VARS)
LOCAL_CFLAGS := -std=c99
# Uncomment for the correct headset - slight changes required in OpenXR implementation
#OPENXR_HMD = -DMETA_QUEST
OPENXR_HMD = -DPICO_XR
LOCAL_CFLAGS := $(OPENXR_HMD)
LOCAL_MODULE := quakequest
LOCAL_LDLIBS := -llog -landroid -lGLESv3 -lEGL -lOpenSLES # include default libraries
LOCAL_C_INCLUDES := ../QuakeQuestSrc/ \
../darkplaces/ \
$(SUPPORT_LIBS)/liboggvorbis/include
../darkplaces/ \
$(SUPPORT_LIBS)/liboggvorbis/include \
$(TOP_DIR)/../../../../../3rdParty/khronos/openxr/OpenXR-SDK/include
LOCAL_SHARED_LIBRARIES := vrapi libvorbis libogg libvorbis-jni
LOCAL_SHARED_LIBRARIES := openxr_loader libvorbis libogg libvorbis-jni
SRC_SND_COMMON := \
darkplaces/snd_opensl.c \
@ -121,7 +127,9 @@ SRC_COMMON := \
SRC_QUEST := \
QuakeQuestSrc/argtable3.c \
QuakeQuestSrc/QuakeQuest_SurfaceView.c \
QuakeQuestSrc/VrCompositor.c \
QuakeQuestSrc/OpenXrInput_MetaQuest.c \
QuakeQuestSrc/OpenXrInput_PicoXR.c \
QuakeQuestSrc/TBXR_Common.c \
LOCAL_SRC_FILES := \
$(SRC_QUEST) \
@ -135,4 +143,4 @@ LOCAL_SRC_FILES := \
include $(BUILD_SHARED_LIBRARY)
include $(SUPPORT_LIBS)/liboggvorbis/Android.mk
$(call import-module,VrApi/Projects/AndroidPrebuilt/jni)
$(call import-module,OpenXR/Projects/AndroidPrebuilt/jni)

View file

@ -0,0 +1,502 @@
#include "VrCommon.h"
#ifdef META_QUEST
extern ovrApp gAppState;
XrSpace CreateActionSpace(XrAction poseAction, XrPath subactionPath) {
XrActionSpaceCreateInfo asci = {};
asci.type = XR_TYPE_ACTION_SPACE_CREATE_INFO;
asci.action = poseAction;
asci.poseInActionSpace.orientation.w = 1.0f;
asci.subactionPath = subactionPath;
XrSpace actionSpace = XR_NULL_HANDLE;
OXR(xrCreateActionSpace(gAppState.Session, &asci, &actionSpace));
return actionSpace;
}
XrActionSuggestedBinding ActionSuggestedBinding(XrAction action, const char* bindingString) {
XrActionSuggestedBinding asb;
asb.action = action;
XrPath bindingPath;
OXR(xrStringToPath(gAppState.Instance, bindingString, &bindingPath));
asb.binding = bindingPath;
return asb;
}
XrActionSet CreateActionSet(int priority, const char* name, const char* localizedName) {
XrActionSetCreateInfo asci = {};
asci.type = XR_TYPE_ACTION_SET_CREATE_INFO;
asci.next = NULL;
asci.priority = priority;
strcpy(asci.actionSetName, name);
strcpy(asci.localizedActionSetName, localizedName);
XrActionSet actionSet = XR_NULL_HANDLE;
OXR(xrCreateActionSet(gAppState.Instance, &asci, &actionSet));
return actionSet;
}
XrAction CreateAction(
XrActionSet actionSet,
XrActionType type,
const char* actionName,
const char* localizedName,
int countSubactionPaths,
XrPath* subactionPaths) {
ALOGV("CreateAction %s, %" PRIi32, actionName, countSubactionPaths);
XrActionCreateInfo aci = {};
aci.type = XR_TYPE_ACTION_CREATE_INFO;
aci.next = NULL;
aci.actionType = type;
if (countSubactionPaths > 0) {
aci.countSubactionPaths = countSubactionPaths;
aci.subactionPaths = subactionPaths;
}
strcpy(aci.actionName, actionName);
strcpy(aci.localizedActionName, localizedName ? localizedName : actionName);
XrAction action = XR_NULL_HANDLE;
OXR(xrCreateAction(actionSet, &aci, &action));
return action;
}
bool ActionPoseIsActive(XrAction action, XrPath subactionPath) {
XrActionStateGetInfo getInfo = {};
getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO;
getInfo.action = action;
getInfo.subactionPath = subactionPath;
XrActionStatePose state = {};
state.type = XR_TYPE_ACTION_STATE_POSE;
OXR(xrGetActionStatePose(gAppState.Session, &getInfo, &state));
return state.isActive != XR_FALSE;
}
XrActionStateFloat GetActionStateFloat(XrAction action) {
XrActionStateGetInfo getInfo = {};
getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO;
getInfo.action = action;
XrActionStateFloat state = {};
state.type = XR_TYPE_ACTION_STATE_FLOAT;
OXR(xrGetActionStateFloat(gAppState.Session, &getInfo, &state));
return state;
}
XrActionStateBoolean GetActionStateBoolean(XrAction action) {
XrActionStateGetInfo getInfo = {};
getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO;
getInfo.action = action;
XrActionStateBoolean state = {};
state.type = XR_TYPE_ACTION_STATE_BOOLEAN;
OXR(xrGetActionStateBoolean(gAppState.Session, &getInfo, &state));
return state;
}
XrActionStateVector2f GetActionStateVector2(XrAction action) {
XrActionStateGetInfo getInfo = {};
getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO;
getInfo.action = action;
XrActionStateVector2f state = {};
state.type = XR_TYPE_ACTION_STATE_VECTOR2F;
OXR(xrGetActionStateVector2f(gAppState.Session, &getInfo, &state));
return state;
}
//OpenXR
XrPath leftHandPath;
XrPath rightHandPath;
XrAction handPoseLeftAction;
XrAction handPoseRightAction;
XrAction indexLeftAction;
XrAction indexRightAction;
XrAction menuAction;
XrAction buttonAAction;
XrAction buttonBAction;
XrAction buttonXAction;
XrAction buttonYAction;
XrAction gripLeftAction;
XrAction gripRightAction;
XrAction moveOnLeftJoystickAction;
XrAction moveOnRightJoystickAction;
XrAction thumbstickLeftClickAction;
XrAction thumbstickRightClickAction;
XrAction vibrateLeftFeedback;
XrAction vibrateRightFeedback;
XrActionSet runningActionSet;
XrSpace leftControllerAimSpace = XR_NULL_HANDLE;
XrSpace rightControllerAimSpace = XR_NULL_HANDLE;
bool inputInitialized = false;
bool useSimpleProfile = false;
//0 = left, 1 = right
float vibration_channel_duration[2] = {0.0f, 0.0f};
float vibration_channel_intensity[2] = {0.0f, 0.0f};
void TBXR_InitActions( void )
{
// Actions
runningActionSet = CreateActionSet(1, "running_action_set", "Action Set used on main loop");
indexLeftAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "index_left", "Index left", 0, NULL);
indexRightAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "index_right", "Index right", 0, NULL);
menuAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "menu_action", "Menu", 0, NULL);
buttonAAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "button_a", "Button A", 0, NULL);
buttonBAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "button_b", "Button B", 0, NULL);
buttonXAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "button_x", "Button X", 0, NULL);
buttonYAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "button_y", "Button Y", 0, NULL);
gripLeftAction = CreateAction(runningActionSet, XR_ACTION_TYPE_FLOAT_INPUT, "grip_left", "Grip left", 0, NULL);
gripRightAction = CreateAction(runningActionSet, XR_ACTION_TYPE_FLOAT_INPUT, "grip_right", "Grip right", 0, NULL);
moveOnLeftJoystickAction = CreateAction(runningActionSet, XR_ACTION_TYPE_VECTOR2F_INPUT, "move_on_left_joy", "Move on left Joy", 0, NULL);
moveOnRightJoystickAction = CreateAction(runningActionSet, XR_ACTION_TYPE_VECTOR2F_INPUT, "move_on_right_joy", "Move on right Joy", 0, NULL);
thumbstickLeftClickAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "thumbstick_left", "Thumbstick left", 0, NULL);
thumbstickRightClickAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "thumbstick_right", "Thumbstick right", 0, NULL);
vibrateLeftFeedback = CreateAction(runningActionSet, XR_ACTION_TYPE_VIBRATION_OUTPUT, "vibrate_left_feedback", "Vibrate Left Controller Feedback", 0, NULL);
vibrateRightFeedback = CreateAction(runningActionSet, XR_ACTION_TYPE_VIBRATION_OUTPUT, "vibrate_right_feedback", "Vibrate Right Controller Feedback", 0, NULL);
OXR(xrStringToPath(gAppState.Instance, "/user/hand/left", &leftHandPath));
OXR(xrStringToPath(gAppState.Instance, "/user/hand/right", &rightHandPath));
handPoseLeftAction = CreateAction(runningActionSet, XR_ACTION_TYPE_POSE_INPUT, "hand_pose_left", NULL, 1, &leftHandPath);
handPoseRightAction = CreateAction(runningActionSet, XR_ACTION_TYPE_POSE_INPUT, "hand_pose_right", NULL, 1, &rightHandPath);
if (leftControllerAimSpace == XR_NULL_HANDLE) {
leftControllerAimSpace = CreateActionSpace(handPoseLeftAction, leftHandPath);
}
if (rightControllerAimSpace == XR_NULL_HANDLE) {
rightControllerAimSpace = CreateActionSpace(handPoseRightAction, rightHandPath);
}
XrPath interactionProfilePath = XR_NULL_PATH;
XrPath interactionProfilePathTouch = XR_NULL_PATH;
XrPath interactionProfilePathKHRSimple = XR_NULL_PATH;
OXR(xrStringToPath(gAppState.Instance, "/interaction_profiles/oculus/touch_controller", &interactionProfilePathTouch));
OXR(xrStringToPath(gAppState.Instance, "/interaction_profiles/khr/simple_controller", &interactionProfilePathKHRSimple));
// Toggle this to force simple as a first choice, otherwise use it as a last resort
if (useSimpleProfile) {
ALOGV("xrSuggestInteractionProfileBindings found bindings for Khronos SIMPLE controller");
interactionProfilePath = interactionProfilePathKHRSimple;
} else {
// Query Set
XrActionSet queryActionSet = CreateActionSet(1, "query_action_set", "Action Set used to query device caps");
XrAction dummyAction = CreateAction(queryActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "dummy_action", "Dummy Action", 0, NULL);
// Map bindings
XrActionSuggestedBinding bindings[1];
int currBinding = 0;
bindings[currBinding++] = ActionSuggestedBinding(dummyAction, "/user/hand/right/input/system/click");
XrInteractionProfileSuggestedBinding suggestedBindings = {};
suggestedBindings.type = XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING;
suggestedBindings.next = NULL;
suggestedBindings.suggestedBindings = bindings;
suggestedBindings.countSuggestedBindings = currBinding;
// Try all
suggestedBindings.interactionProfile = interactionProfilePathTouch;
XrResult suggestTouchResult = xrSuggestInteractionProfileBindings(gAppState.Instance, &suggestedBindings);
OXR(suggestTouchResult);
if (XR_SUCCESS == suggestTouchResult) {
ALOGV("xrSuggestInteractionProfileBindings found bindings for QUEST controller");
interactionProfilePath = interactionProfilePathTouch;
}
if (interactionProfilePath == XR_NULL_PATH) {
// Simple as a fallback
bindings[0] = ActionSuggestedBinding(dummyAction, "/user/hand/right/input/select/click");
suggestedBindings.interactionProfile = interactionProfilePathKHRSimple;
XrResult suggestKHRSimpleResult = xrSuggestInteractionProfileBindings(gAppState.Instance, &suggestedBindings);
OXR(suggestKHRSimpleResult);
if (XR_SUCCESS == suggestKHRSimpleResult) {
ALOGV("xrSuggestInteractionProfileBindings found bindings for Khronos SIMPLE controller");
interactionProfilePath = interactionProfilePathKHRSimple;
} else {
ALOGE("xrSuggestInteractionProfileBindings did NOT find any bindings.");
assert(false);
}
}
}
// Action creation
{
// Map bindings
XrActionSuggestedBinding bindings[32]; // large enough for all profiles
int currBinding = 0;
{
if (interactionProfilePath == interactionProfilePathTouch) {
bindings[currBinding++] = ActionSuggestedBinding(indexLeftAction, "/user/hand/left/input/trigger");
bindings[currBinding++] = ActionSuggestedBinding(indexRightAction, "/user/hand/right/input/trigger");
bindings[currBinding++] = ActionSuggestedBinding(menuAction, "/user/hand/left/input/menu/click");
bindings[currBinding++] = ActionSuggestedBinding(buttonXAction, "/user/hand/left/input/x/click");
bindings[currBinding++] = ActionSuggestedBinding(buttonYAction, "/user/hand/left/input/y/click");
bindings[currBinding++] = ActionSuggestedBinding(buttonAAction, "/user/hand/right/input/a/click");
bindings[currBinding++] = ActionSuggestedBinding(buttonBAction, "/user/hand/right/input/b/click");
bindings[currBinding++] = ActionSuggestedBinding(gripLeftAction, "/user/hand/left/input/squeeze/value");
bindings[currBinding++] = ActionSuggestedBinding(gripRightAction, "/user/hand/right/input/squeeze/value");
bindings[currBinding++] = ActionSuggestedBinding(moveOnLeftJoystickAction, "/user/hand/left/input/thumbstick");
bindings[currBinding++] = ActionSuggestedBinding(moveOnRightJoystickAction, "/user/hand/right/input/thumbstick");
bindings[currBinding++] = ActionSuggestedBinding(thumbstickLeftClickAction, "/user/hand/left/input/thumbstick/click");
bindings[currBinding++] = ActionSuggestedBinding(thumbstickRightClickAction, "/user/hand/right/input/thumbstick/click");
bindings[currBinding++] = ActionSuggestedBinding(vibrateLeftFeedback, "/user/hand/left/output/haptic");
bindings[currBinding++] = ActionSuggestedBinding(vibrateRightFeedback, "/user/hand/right/output/haptic");
bindings[currBinding++] = ActionSuggestedBinding(handPoseLeftAction, "/user/hand/left/input/aim/pose");
bindings[currBinding++] = ActionSuggestedBinding(handPoseRightAction, "/user/hand/right/input/aim/pose");
}
if (interactionProfilePath == interactionProfilePathKHRSimple) {
bindings[currBinding++] = ActionSuggestedBinding(indexLeftAction, "/user/hand/left/input/select/click");
bindings[currBinding++] = ActionSuggestedBinding(indexRightAction, "/user/hand/right/input/select/click");
bindings[currBinding++] = ActionSuggestedBinding(buttonAAction, "/user/hand/left/input/menu/click");
bindings[currBinding++] = ActionSuggestedBinding(buttonXAction, "/user/hand/right/input/menu/click");
bindings[currBinding++] = ActionSuggestedBinding(vibrateLeftFeedback, "/user/hand/left/output/haptic");
bindings[currBinding++] = ActionSuggestedBinding(vibrateRightFeedback, "/user/hand/right/output/haptic");
bindings[currBinding++] = ActionSuggestedBinding(handPoseLeftAction, "/user/hand/left/input/aim/pose");
bindings[currBinding++] = ActionSuggestedBinding(handPoseRightAction, "/user/hand/right/input/aim/pose");
}
}
XrInteractionProfileSuggestedBinding suggestedBindings = {};
suggestedBindings.type = XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING;
suggestedBindings.next = NULL;
suggestedBindings.interactionProfile = interactionProfilePath;
suggestedBindings.suggestedBindings = bindings;
suggestedBindings.countSuggestedBindings = currBinding;
OXR(xrSuggestInteractionProfileBindings(gAppState.Instance, &suggestedBindings));
// Enumerate actions
XrPath actionPathsBuffer[32];
char stringBuffer[256];
XrAction actionsToEnumerate[] = {
indexLeftAction,
indexRightAction,
menuAction,
buttonAAction,
buttonBAction,
buttonXAction,
buttonYAction,
gripLeftAction,
gripRightAction,
moveOnLeftJoystickAction,
moveOnRightJoystickAction,
thumbstickLeftClickAction,
thumbstickRightClickAction,
vibrateLeftFeedback,
vibrateRightFeedback,
handPoseLeftAction,
handPoseRightAction
};
for (size_t i = 0; i < sizeof(actionsToEnumerate) / sizeof(actionsToEnumerate[0]); ++i) {
XrBoundSourcesForActionEnumerateInfo enumerateInfo = {};
enumerateInfo.type = XR_TYPE_BOUND_SOURCES_FOR_ACTION_ENUMERATE_INFO;
enumerateInfo.next = NULL;
enumerateInfo.action = actionsToEnumerate[i];
// Get Count
uint32_t countOutput = 0;
OXR(xrEnumerateBoundSourcesForAction(
gAppState.Session, &enumerateInfo, 0 /* request size */, &countOutput, NULL));
ALOGV(
"xrEnumerateBoundSourcesForAction action=%lld count=%u",
(long long)enumerateInfo.action,
countOutput);
if (countOutput < 32) {
OXR(xrEnumerateBoundSourcesForAction(
gAppState.Session, &enumerateInfo, 32, &countOutput, actionPathsBuffer));
for (uint32_t a = 0; a < countOutput; ++a) {
XrInputSourceLocalizedNameGetInfo nameGetInfo = {};
nameGetInfo.type = XR_TYPE_INPUT_SOURCE_LOCALIZED_NAME_GET_INFO;
nameGetInfo.next = NULL;
nameGetInfo.sourcePath = actionPathsBuffer[a];
nameGetInfo.whichComponents = XR_INPUT_SOURCE_LOCALIZED_NAME_USER_PATH_BIT |
XR_INPUT_SOURCE_LOCALIZED_NAME_INTERACTION_PROFILE_BIT |
XR_INPUT_SOURCE_LOCALIZED_NAME_COMPONENT_BIT;
uint32_t stringCount = 0u;
OXR(xrGetInputSourceLocalizedName(
gAppState.Session, &nameGetInfo, 0, &stringCount, NULL));
if (stringCount < 256) {
OXR(xrGetInputSourceLocalizedName(
gAppState.Session, &nameGetInfo, 256, &stringCount, stringBuffer));
char pathStr[256];
uint32_t strLen = 0;
OXR(xrPathToString(
gAppState.Instance,
actionPathsBuffer[a],
(uint32_t)sizeof(pathStr),
&strLen,
pathStr));
ALOGV(
" -> path = %lld `%s` -> `%s`",
(long long)actionPathsBuffer[a],
pathStr,
stringBuffer);
}
}
}
}
}
// Attach to session
XrSessionActionSetsAttachInfo attachInfo = {};
attachInfo.type = XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO;
attachInfo.next = NULL;
attachInfo.countActionSets = 1;
attachInfo.actionSets = &runningActionSet;
OXR(xrAttachSessionActionSets(gAppState.Session, &attachInfo));
inputInitialized = true;
}
void TBXR_SyncActions( void )
{
// sync action data
XrActiveActionSet activeActionSet = {};
activeActionSet.actionSet = runningActionSet;
activeActionSet.subactionPath = XR_NULL_PATH;
XrActionsSyncInfo syncInfo = {};
syncInfo.type = XR_TYPE_ACTIONS_SYNC_INFO;
syncInfo.next = NULL;
syncInfo.countActiveActionSets = 1;
syncInfo.activeActionSets = &activeActionSet;
OXR(xrSyncActions(gAppState.Session, &syncInfo));
// query input action states
XrActionStateGetInfo getInfo = {};
getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO;
getInfo.next = NULL;
getInfo.subactionPath = XR_NULL_PATH;
}
void TBXR_UpdateControllers( )
{
TBXR_SyncActions();
//get controller poses
XrAction controller[] = {handPoseLeftAction, handPoseRightAction};
XrPath subactionPath[] = {leftHandPath, rightHandPath};
XrSpace controllerSpace[] = {leftControllerAimSpace, rightControllerAimSpace};
for (int i = 0; i < 2; i++) {
if (ActionPoseIsActive(controller[i], subactionPath[i])) {
XrSpaceVelocity vel = {};
vel.type = XR_TYPE_SPACE_VELOCITY;
XrSpaceLocation loc = {};
loc.type = XR_TYPE_SPACE_LOCATION;
loc.next = &vel;
OXR(xrLocateSpace(controllerSpace[i], gAppState.CurrentSpace, gAppState.PredictedDisplayTime, &loc));
gAppState.TrackedController[i].Active = (loc.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) != 0;
gAppState.TrackedController[i].Pose = loc.pose;
gAppState.TrackedController[i].Velocity = vel;
} else {
ovrTrackedController_Clear(&gAppState.TrackedController[i]);
}
}
leftRemoteTracking_new = gAppState.TrackedController[0];
rightRemoteTracking_new = gAppState.TrackedController[1];
memset(&leftTrackedRemoteState_new, 0, sizeof leftTrackedRemoteState_new);
memset(&rightTrackedRemoteState_new, 0, sizeof rightTrackedRemoteState_new);
//button mapping
if (GetActionStateBoolean(menuAction).currentState) leftTrackedRemoteState_new.Buttons |= xrButton_Enter;
if (GetActionStateBoolean(buttonXAction).currentState) leftTrackedRemoteState_new.Buttons |= xrButton_X;
if (GetActionStateBoolean(buttonYAction).currentState) leftTrackedRemoteState_new.Buttons |= xrButton_Y;
leftTrackedRemoteState_new.GripTrigger = GetActionStateFloat(gripLeftAction).currentState;
if (leftTrackedRemoteState_new.GripTrigger > 0.5f) leftTrackedRemoteState_new.Buttons |= xrButton_GripTrigger;
if (GetActionStateBoolean(thumbstickLeftClickAction).currentState) leftTrackedRemoteState_new.Buttons |= xrButton_LThumb;
if (GetActionStateBoolean(buttonAAction).currentState) rightTrackedRemoteState_new.Buttons |= xrButton_A;
if (GetActionStateBoolean(buttonBAction).currentState) rightTrackedRemoteState_new.Buttons |= xrButton_B;
rightTrackedRemoteState_new.GripTrigger = GetActionStateFloat(gripRightAction).currentState;
if (rightTrackedRemoteState_new.GripTrigger > 0.5f) rightTrackedRemoteState_new.Buttons |= xrButton_GripTrigger;
if (GetActionStateBoolean(thumbstickRightClickAction).currentState) rightTrackedRemoteState_new.Buttons |= xrButton_RThumb;
//index finger click
if (GetActionStateBoolean(indexLeftAction).currentState) leftTrackedRemoteState_new.Buttons |= xrButton_Trigger;
if (GetActionStateBoolean(indexRightAction).currentState) rightTrackedRemoteState_new.Buttons |= xrButton_Trigger;
//thumbstick
XrActionStateVector2f moveJoystickState;
moveJoystickState = GetActionStateVector2(moveOnLeftJoystickAction);
leftTrackedRemoteState_new.Joystick.x = moveJoystickState.currentState.x;
leftTrackedRemoteState_new.Joystick.y = moveJoystickState.currentState.y;
moveJoystickState = GetActionStateVector2(moveOnRightJoystickAction);
rightTrackedRemoteState_new.Joystick.x = moveJoystickState.currentState.x;
rightTrackedRemoteState_new.Joystick.y = moveJoystickState.currentState.y;
}
void TBXR_Vibrate( int duration, int chan, float intensity )
{
for (int i = 0; i < 2; ++i)
{
int channel = 1-i;
if ((i + 1) & chan)
{
if (vibration_channel_duration[channel] > 0.0f)
return;
if (vibration_channel_duration[channel] == -1.0f && duration != 0.0f)
return;
vibration_channel_duration[channel] = duration;
vibration_channel_intensity[channel] = intensity;
}
}
}
void TBXR_ProcessHaptics() {
static float lastFrameTime = 0.0f;
float timestamp = (float)(TBXR_GetTimeInMilliSeconds());
float frametime = timestamp - lastFrameTime;
lastFrameTime = timestamp;
for (int i = 0; i < 2; ++i) {
if (vibration_channel_duration[i] > 0.0f ||
vibration_channel_duration[i] == -1.0f) {
// fire haptics using output action
XrHapticVibration vibration = {};
vibration.type = XR_TYPE_HAPTIC_VIBRATION;
vibration.next = NULL;
vibration.amplitude = vibration_channel_intensity[i];
vibration.duration = ToXrTime(vibration_channel_duration[i]);
vibration.frequency = 3000;
XrHapticActionInfo hapticActionInfo = {};
hapticActionInfo.type = XR_TYPE_HAPTIC_ACTION_INFO;
hapticActionInfo.next = NULL;
hapticActionInfo.action = i == 0 ? vibrateLeftFeedback : vibrateRightFeedback;
OXR(xrApplyHapticFeedback(gAppState.Session, &hapticActionInfo, (const XrHapticBaseHeader*)&vibration));
if (vibration_channel_duration[i] != -1.0f) {
vibration_channel_duration[i] -= frametime;
if (vibration_channel_duration[i] < 0.0f) {
vibration_channel_duration[i] = 0.0f;
vibration_channel_intensity[i] = 0.0f;
}
}
} else {
// Stop haptics
XrHapticActionInfo hapticActionInfo = {};
hapticActionInfo.type = XR_TYPE_HAPTIC_ACTION_INFO;
hapticActionInfo.next = NULL;
hapticActionInfo.action = i == 0 ? vibrateLeftFeedback : vibrateRightFeedback;
OXR(xrStopHapticFeedback(gAppState.Session, &hapticActionInfo));
}
}
}
#endif

View file

@ -0,0 +1,640 @@
#include "VrCommon.h"
#ifdef PICO_XR
extern ovrApp gAppState;
XrResult CheckXrResult(XrResult res, const char* originator) {
if (XR_FAILED(res)) {
dpsnprintf("error: %s", originator);
}
return res;
}
#define CHECK_XRCMD(cmd) CheckXrResult(cmd, #cmd);
#define SIDE_LEFT 0
#define SIDE_RIGHT 1
#define SIDE_COUNT 2
XrActionSet actionSet;
XrAction grabAction;
XrAction poseAction;
XrAction vibrateAction;
XrAction quitAction;
/*************************pico******************/
XrAction touchpadAction;
XrAction AXAction;
XrAction homeAction;
XrAction BYAction;
XrAction backAction;
XrAction sideAction;
XrAction triggerAction;
XrAction joystickAction;
XrAction batteryAction;
//---add new----------
XrAction AXTouchAction;
XrAction BYTouchAction;
XrAction RockerTouchAction;
XrAction TriggerTouchAction;
XrAction ThumbrestTouchAction;
XrAction GripAction;
//---add new----------zgt
XrAction AAction;
XrAction BAction;
XrAction XAction;
XrAction YAction;
XrAction ATouchAction;
XrAction BTouchAction;
XrAction XTouchAction;
XrAction YTouchAction;
XrAction aimAction;
/*************************pico******************/
XrSpace aimSpace[SIDE_COUNT];
XrPath handSubactionPath[SIDE_COUNT];
XrSpace handSpace[SIDE_COUNT];
XrActionSuggestedBinding ActionSuggestedBinding(XrAction action, XrPath path) {
XrActionSuggestedBinding asb;
asb.action = action;
asb.binding = path;
return asb;
}
XrActionStateBoolean GetActionStateBoolean(XrAction action, int hand) {
XrActionStateGetInfo getInfo = {};
getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO;
getInfo.action = action;
if (hand >= 0)
getInfo.subactionPath = handSubactionPath[hand];
XrActionStateBoolean state = {};
state.type = XR_TYPE_ACTION_STATE_BOOLEAN;
CHECK_XRCMD(xrGetActionStateBoolean(gAppState.Session, &getInfo, &state));
return state;
}
XrActionStateFloat GetActionStateFloat(XrAction action, int hand) {
XrActionStateGetInfo getInfo = {};
getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO;
getInfo.action = action;
if (hand >= 0)
getInfo.subactionPath = handSubactionPath[hand];
XrActionStateFloat state = {};
state.type = XR_TYPE_ACTION_STATE_FLOAT;
CHECK_XRCMD(xrGetActionStateFloat(gAppState.Session, &getInfo, &state));
return state;
}
XrActionStateVector2f GetActionStateVector2(XrAction action, int hand) {
XrActionStateGetInfo getInfo = {};
getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO;
getInfo.action = action;
if (hand >= 0)
getInfo.subactionPath = handSubactionPath[hand];
XrActionStateVector2f state = {};
state.type = XR_TYPE_ACTION_STATE_VECTOR2F;
CHECK_XRCMD(xrGetActionStateVector2f(gAppState.Session, &getInfo, &state));
return state;
}
void TBXR_InitActions( void )
{
// Create an action set.
{
XrActionSetCreateInfo actionSetInfo = {};
actionSetInfo.type = XR_TYPE_ACTION_SET_CREATE_INFO;
strcpy(actionSetInfo.actionSetName, "gameplay");
strcpy(actionSetInfo.localizedActionSetName, "Gameplay");
actionSetInfo.priority = 0;
CHECK_XRCMD(xrCreateActionSet(gAppState.Instance, &actionSetInfo, &actionSet));
}
// Get the XrPath for the left and right hands - we will use them as subaction paths.
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left", &handSubactionPath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right", &handSubactionPath[SIDE_RIGHT]));
// Create actions.
{
// Create an input action for grabbing objects with the left and right hands.
XrActionCreateInfo actionInfo = {};
actionInfo.type = XR_TYPE_ACTION_CREATE_INFO;
actionInfo.actionType = XR_ACTION_TYPE_FLOAT_INPUT;
strcpy(actionInfo.actionName, "grab_object");
strcpy(actionInfo.localizedActionName, "Grab Object");
actionInfo.countSubactionPaths = SIDE_COUNT;
actionInfo.subactionPaths = handSubactionPath;
CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &grabAction));
// Create an input action getting the left and right hand poses.
actionInfo.actionType = XR_ACTION_TYPE_POSE_INPUT;
strcpy(actionInfo.actionName, "hand_pose");
strcpy(actionInfo.localizedActionName, "Hand Pose");
actionInfo.countSubactionPaths = SIDE_COUNT;
actionInfo.subactionPaths = handSubactionPath;
CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &poseAction));
actionInfo.actionType = XR_ACTION_TYPE_POSE_INPUT;
strcpy(actionInfo.actionName, "aim_pose");
strcpy(actionInfo.localizedActionName, "Aim Pose");
actionInfo.countSubactionPaths = SIDE_COUNT;
actionInfo.subactionPaths = handSubactionPath;
CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &aimAction));
// Create output actions for vibrating the left and right controller.
actionInfo.actionType = XR_ACTION_TYPE_VIBRATION_OUTPUT;
strcpy(actionInfo.actionName, "vibrate_hand");
strcpy(actionInfo.localizedActionName, "Vibrate Hand");
actionInfo.countSubactionPaths = SIDE_COUNT;
actionInfo.subactionPaths = handSubactionPath;
CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &vibrateAction));
// Create input actions for quitting the session using the left and right controller.
// Since it doesn't matter which hand did this, we do not specify subaction paths for it.
// We will just suggest bindings for both hands, where possible.
actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
strcpy(actionInfo.actionName, "quit_session");
strcpy(actionInfo.localizedActionName, "Quit Session");
actionInfo.countSubactionPaths = SIDE_COUNT;
actionInfo.subactionPaths = handSubactionPath;
CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &quitAction));
/**********************************pico***************************************/
// Create input actions for toucpad key using the left and right controller.
actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
strcpy(actionInfo.actionName, "touchpad");
strcpy(actionInfo.localizedActionName, "Touchpad");
actionInfo.countSubactionPaths = SIDE_COUNT;
actionInfo.subactionPaths = handSubactionPath;
CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &touchpadAction));
actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
strcpy(actionInfo.actionName, "axkey");
strcpy(actionInfo.localizedActionName, "AXkey");
actionInfo.countSubactionPaths = SIDE_COUNT;
actionInfo.subactionPaths = handSubactionPath;
CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &AXAction));
actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
strcpy(actionInfo.actionName, "homekey");
strcpy(actionInfo.localizedActionName, "Homekey");
actionInfo.countSubactionPaths = SIDE_COUNT;
actionInfo.subactionPaths = handSubactionPath;
CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &homeAction));
actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
strcpy(actionInfo.actionName, "bykey");
strcpy(actionInfo.localizedActionName, "BYkey");
actionInfo.countSubactionPaths = SIDE_COUNT;
actionInfo.subactionPaths = handSubactionPath;
CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &BYAction));
actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
strcpy(actionInfo.actionName, "backkey");
strcpy(actionInfo.localizedActionName, "Backkey");
actionInfo.countSubactionPaths = SIDE_COUNT;
actionInfo.subactionPaths = handSubactionPath;
CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &backAction));
actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
strcpy(actionInfo.actionName, "sidekey");
strcpy(actionInfo.localizedActionName, "Sidekey");
actionInfo.countSubactionPaths = SIDE_COUNT;
actionInfo.subactionPaths = handSubactionPath;
CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &sideAction));
actionInfo.actionType = XR_ACTION_TYPE_FLOAT_INPUT;
strcpy(actionInfo.actionName, "trigger");
strcpy(actionInfo.localizedActionName, "Trigger");
actionInfo.countSubactionPaths = SIDE_COUNT;
actionInfo.subactionPaths = handSubactionPath;
CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &triggerAction));
actionInfo.actionType = XR_ACTION_TYPE_VECTOR2F_INPUT;
strcpy(actionInfo.actionName, "joystick");
strcpy(actionInfo.localizedActionName, "Joystick");
actionInfo.countSubactionPaths = SIDE_COUNT;
actionInfo.subactionPaths = handSubactionPath;
CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &joystickAction));
actionInfo.actionType = XR_ACTION_TYPE_FLOAT_INPUT;
strcpy(actionInfo.actionName, "battery");
strcpy(actionInfo.localizedActionName, "battery");
actionInfo.countSubactionPaths = SIDE_COUNT;
actionInfo.subactionPaths = handSubactionPath;
CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &batteryAction));
//------------------------add new---------------------------------
actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
strcpy(actionInfo.actionName, "axtouch");
strcpy(actionInfo.localizedActionName, "AXtouch");
actionInfo.countSubactionPaths = SIDE_COUNT;
actionInfo.subactionPaths = handSubactionPath;
CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &AXTouchAction));
actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
strcpy(actionInfo.actionName, "bytouch");
strcpy(actionInfo.localizedActionName, "BYtouch");
actionInfo.countSubactionPaths = SIDE_COUNT;
actionInfo.subactionPaths = handSubactionPath;
CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &BYTouchAction));
actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
strcpy(actionInfo.actionName, "rockertouch");
strcpy(actionInfo.localizedActionName, "Rockertouch");
actionInfo.countSubactionPaths = SIDE_COUNT;
actionInfo.subactionPaths = handSubactionPath;
CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &RockerTouchAction));
actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
strcpy(actionInfo.actionName, "triggertouch");
strcpy(actionInfo.localizedActionName, "Triggertouch");
actionInfo.countSubactionPaths = SIDE_COUNT;
actionInfo.subactionPaths = handSubactionPath;
CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &TriggerTouchAction));
actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
strcpy(actionInfo.actionName, "thumbresttouch");
strcpy(actionInfo.localizedActionName, "Thumbresttouch");
actionInfo.countSubactionPaths = SIDE_COUNT;
actionInfo.subactionPaths = handSubactionPath;
CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &ThumbrestTouchAction));
actionInfo.actionType = XR_ACTION_TYPE_FLOAT_INPUT;
strcpy(actionInfo.actionName, "gripvalue");
strcpy(actionInfo.localizedActionName, "GripValue");
actionInfo.countSubactionPaths = SIDE_COUNT;
actionInfo.subactionPaths = handSubactionPath;
CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &GripAction));
//--------------add new----------zgt
actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
strcpy(actionInfo.actionName, "akey");
strcpy(actionInfo.localizedActionName, "Akey");
actionInfo.countSubactionPaths = SIDE_COUNT;
actionInfo.subactionPaths = handSubactionPath;
CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &AAction));
actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
strcpy(actionInfo.actionName, "bkey");
strcpy(actionInfo.localizedActionName, "Bkey");
actionInfo.countSubactionPaths = SIDE_COUNT;
actionInfo.subactionPaths = handSubactionPath;
CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &BAction));
actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
strcpy(actionInfo.actionName, "xkey");
strcpy(actionInfo.localizedActionName, "Xkey");
actionInfo.countSubactionPaths = SIDE_COUNT;
actionInfo.subactionPaths = handSubactionPath;
CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &XAction));
actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
strcpy(actionInfo.actionName, "ykey");
strcpy(actionInfo.localizedActionName, "Ykey");
actionInfo.countSubactionPaths = SIDE_COUNT;
actionInfo.subactionPaths = handSubactionPath;
CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &YAction));
actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
strcpy(actionInfo.actionName, "atouch");
strcpy(actionInfo.localizedActionName, "Atouch");
actionInfo.countSubactionPaths = SIDE_COUNT;
actionInfo.subactionPaths = handSubactionPath;
CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &ATouchAction));
actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
strcpy(actionInfo.actionName, "btouch");
strcpy(actionInfo.localizedActionName, "Btouch");
actionInfo.countSubactionPaths = SIDE_COUNT;
actionInfo.subactionPaths = handSubactionPath;
CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &BTouchAction));
actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
strcpy(actionInfo.actionName, "xtouch");
strcpy(actionInfo.localizedActionName, "Xtouch");
actionInfo.countSubactionPaths = SIDE_COUNT;
actionInfo.subactionPaths = handSubactionPath;
CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &XTouchAction));
actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
strcpy(actionInfo.actionName, "ytouch");
strcpy(actionInfo.localizedActionName, "Ytouch");
actionInfo.countSubactionPaths = SIDE_COUNT;
actionInfo.subactionPaths = handSubactionPath;
CHECK_XRCMD(xrCreateAction(actionSet, &actionInfo, &YTouchAction));
/**********************************pico***************************************/
}
XrPath selectPath[SIDE_COUNT];
XrPath squeezeValuePath[SIDE_COUNT];
XrPath squeezeClickPath[SIDE_COUNT];
XrPath posePath[SIDE_COUNT];
XrPath hapticPath[SIDE_COUNT];
XrPath menuClickPath[SIDE_COUNT];
XrPath systemPath[SIDE_COUNT];
XrPath thumbrestPath[SIDE_COUNT];
XrPath triggerTouchPath[SIDE_COUNT];
XrPath triggerValuePath[SIDE_COUNT];
XrPath thumbstickClickPath[SIDE_COUNT];
XrPath thumbstickTouchPath[SIDE_COUNT];
XrPath thumbstickPosPath[SIDE_COUNT];
XrPath aimPath[SIDE_COUNT];
/**************************pico************************************/
XrPath touchpadPath[SIDE_COUNT];
XrPath AXValuePath[SIDE_COUNT];
XrPath homeClickPath[SIDE_COUNT];
XrPath BYValuePath[SIDE_COUNT];
XrPath backPath[SIDE_COUNT];
XrPath sideClickPath[SIDE_COUNT];
XrPath triggerPath[SIDE_COUNT];
XrPath joystickPath[SIDE_COUNT];
XrPath batteryPath[SIDE_COUNT];
//--------------add new----------
XrPath GripPath[SIDE_COUNT];
XrPath AXTouchPath[SIDE_COUNT];
XrPath BYTouchPath[SIDE_COUNT];
XrPath RockerTouchPath[SIDE_COUNT];
XrPath TriggerTouchPath[SIDE_COUNT];
XrPath ThumbresetTouchPath[SIDE_COUNT];
//--------------add new----------zgt
XrPath AValuePath[SIDE_COUNT];
XrPath BValuePath[SIDE_COUNT];
XrPath XValuePath[SIDE_COUNT];
XrPath YValuePath[SIDE_COUNT];
XrPath ATouchPath[SIDE_COUNT];
XrPath BTouchPath[SIDE_COUNT];
XrPath XTouchPath[SIDE_COUNT];
XrPath YTouchPath[SIDE_COUNT];
/**************************pico************************************/
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/select/click", &selectPath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/select/click", &selectPath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/menu/click", &menuClickPath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/menu/click", &menuClickPath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/squeeze/value", &squeezeValuePath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/squeeze/value", &squeezeValuePath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/squeeze/click", &squeezeClickPath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/squeeze/click", &squeezeClickPath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/grip/pose", &posePath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/grip/pose", &posePath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/aim/pose", &aimPath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/aim/pose", &aimPath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/output/haptic", &hapticPath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/output/haptic", &hapticPath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/trigger/touch", &triggerTouchPath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/trigger/touch", &triggerTouchPath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/trigger/value", &triggerValuePath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/trigger/value", &triggerValuePath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/thumbstick/click", &thumbstickClickPath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/thumbstick/click", &thumbstickClickPath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/thumbstick/touch", &thumbstickTouchPath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/thumbstick/touch", &thumbstickTouchPath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/thumbstick", &thumbstickPosPath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/thumbstick", &thumbstickPosPath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/system/click", &systemPath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/system/click", &systemPath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/thumbrest/touch", &thumbrestPath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/thumbrest/touch", &thumbrestPath[SIDE_RIGHT]));
/**************************pico************************************/
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/back/click", &backPath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/back/click", &backPath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/battery/value", &batteryPath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/battery/value", &batteryPath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/x/click", &XValuePath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/y/click", &YValuePath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/a/click", &AValuePath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/b/click", &BValuePath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/x/touch", &XTouchPath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/y/touch", &YTouchPath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/a/touch", &ATouchPath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/b/touch", &BTouchPath[SIDE_RIGHT]));
/**************************pico************************************/
XrActionSuggestedBinding bindings[128];
int currBinding = 0;
// Suggest bindings for the Pico Neo 3 controller
{
XrPath picoMixedRealityInteractionProfilePath;
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/interaction_profiles/pico/neo3_controller",
&picoMixedRealityInteractionProfilePath));
bindings[currBinding++] = ActionSuggestedBinding(touchpadAction, thumbstickClickPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(touchpadAction, thumbstickClickPath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(joystickAction, thumbstickPosPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(joystickAction, thumbstickPosPath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(RockerTouchAction, thumbstickTouchPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(RockerTouchAction, thumbstickTouchPath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(triggerAction, triggerValuePath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(triggerAction, triggerValuePath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(TriggerTouchAction, triggerTouchPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(TriggerTouchAction, triggerTouchPath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(sideAction, squeezeClickPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(sideAction, squeezeClickPath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(GripAction, squeezeValuePath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(GripAction, squeezeValuePath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(poseAction, posePath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(poseAction, posePath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(homeAction, systemPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(homeAction, systemPath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(backAction, backPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(backAction, backPath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(batteryAction, batteryPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(batteryAction, batteryPath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(ThumbrestTouchAction, thumbrestPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(ThumbrestTouchAction, thumbrestPath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(vibrateAction, hapticPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(vibrateAction, hapticPath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(XTouchAction, XTouchPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(YTouchAction, YTouchPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(ATouchAction, ATouchPath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(BTouchAction, BTouchPath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(XAction, XValuePath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(YAction, YValuePath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(AAction, AValuePath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(BAction, BValuePath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(aimAction, aimPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(aimAction, aimPath[SIDE_RIGHT]);
XrInteractionProfileSuggestedBinding suggestedBindings = {};
suggestedBindings.type = XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING;
suggestedBindings.interactionProfile = picoMixedRealityInteractionProfilePath;
suggestedBindings.suggestedBindings = bindings;
suggestedBindings.countSuggestedBindings = currBinding;
CHECK_XRCMD(xrSuggestInteractionProfileBindings(gAppState.Instance, &suggestedBindings));
}
XrActionSpaceCreateInfo actionSpaceInfo = {};
actionSpaceInfo.type = XR_TYPE_ACTION_SPACE_CREATE_INFO;
actionSpaceInfo.action = poseAction;
actionSpaceInfo.poseInActionSpace.orientation.w = 1.f;
actionSpaceInfo.subactionPath = handSubactionPath[SIDE_LEFT];
CHECK_XRCMD(xrCreateActionSpace(gAppState.Session, &actionSpaceInfo, &handSpace[SIDE_LEFT]));
actionSpaceInfo.subactionPath = handSubactionPath[SIDE_RIGHT];
CHECK_XRCMD(xrCreateActionSpace(gAppState.Session, &actionSpaceInfo, &handSpace[SIDE_RIGHT]));
actionSpaceInfo.action = aimAction;
actionSpaceInfo.poseInActionSpace.orientation.w = 1.f;
actionSpaceInfo.subactionPath = handSubactionPath[SIDE_LEFT];
CHECK_XRCMD(xrCreateActionSpace(gAppState.Session, &actionSpaceInfo, &aimSpace[SIDE_LEFT]));
actionSpaceInfo.subactionPath = handSubactionPath[SIDE_RIGHT];
CHECK_XRCMD(xrCreateActionSpace(gAppState.Session, &actionSpaceInfo, &aimSpace[SIDE_RIGHT]));
XrSessionActionSetsAttachInfo attachInfo = {};
attachInfo.type = XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO;
attachInfo.countActionSets = 1;
attachInfo.actionSets = &actionSet;
CHECK_XRCMD(xrAttachSessionActionSets(gAppState.Session, &attachInfo));
}
void TBXR_SyncActions( void )
{
XrActiveActionSet activeActionSet = {};
activeActionSet.actionSet = actionSet;
activeActionSet.subactionPath = XR_NULL_PATH;
XrActionsSyncInfo syncInfo;
syncInfo.type = XR_TYPE_ACTIONS_SYNC_INFO;
syncInfo.countActiveActionSets = 1;
syncInfo.activeActionSets = &activeActionSet;
CHECK_XRCMD(xrSyncActions(gAppState.Session, &syncInfo));
}
void TBXR_UpdateControllers( )
{
TBXR_SyncActions();
//get controller poses
for (int i = 0; i < 2; i++) {
XrSpaceVelocity vel = {};
vel.type = XR_TYPE_SPACE_VELOCITY;
XrSpaceLocation loc = {};
loc.type = XR_TYPE_SPACE_LOCATION;
loc.next = &vel;
XrResult res = xrLocateSpace(aimSpace[i], gAppState.CurrentSpace, gAppState.PredictedDisplayTime, &loc);
if (res != XR_SUCCESS) {
dpsnprintf("xrLocateSpace error: %d", (int)res);
}
gAppState.TrackedController[i].Active = (loc.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) != 0;
gAppState.TrackedController[i].Pose = loc.pose;
gAppState.TrackedController[i].Velocity = vel;
}
leftRemoteTracking_new = gAppState.TrackedController[0];
rightRemoteTracking_new = gAppState.TrackedController[1];
//button mapping
leftTrackedRemoteState_new.Buttons = 0;
if (GetActionStateBoolean(backAction, SIDE_LEFT).currentState) leftTrackedRemoteState_new.Buttons |= xrButton_Enter;
if (GetActionStateBoolean(XAction, SIDE_LEFT).currentState) leftTrackedRemoteState_new.Buttons |= xrButton_X;
if (GetActionStateBoolean(YAction, SIDE_LEFT).currentState) leftTrackedRemoteState_new.Buttons |= xrButton_Y;
if (GetActionStateBoolean(sideAction, SIDE_LEFT).currentState) leftTrackedRemoteState_new.Buttons |= xrButton_GripTrigger;
if (GetActionStateBoolean(touchpadAction, SIDE_LEFT).currentState) leftTrackedRemoteState_new.Buttons |= xrButton_LThumb;
if (GetActionStateFloat(triggerAction, SIDE_LEFT).currentState > 0.5f) leftTrackedRemoteState_new.Buttons |= xrButton_Trigger;
rightTrackedRemoteState_new.Buttons = 0;
if (GetActionStateBoolean(backAction, SIDE_RIGHT).currentState) rightTrackedRemoteState_new.Buttons |= xrButton_Enter;
if (GetActionStateBoolean(AAction, SIDE_RIGHT).currentState) rightTrackedRemoteState_new.Buttons |= xrButton_A;
if (GetActionStateBoolean(BAction, SIDE_RIGHT).currentState) rightTrackedRemoteState_new.Buttons |= xrButton_B;
if (GetActionStateBoolean(sideAction, SIDE_RIGHT).currentState) rightTrackedRemoteState_new.Buttons |= xrButton_GripTrigger;
if (GetActionStateBoolean(touchpadAction, SIDE_RIGHT).currentState) rightTrackedRemoteState_new.Buttons |= xrButton_RThumb;
if (GetActionStateFloat(triggerAction, SIDE_RIGHT).currentState > 0.5f) rightTrackedRemoteState_new.Buttons |= xrButton_Trigger;
//thumbstick
XrActionStateVector2f moveJoystickState;
moveJoystickState = GetActionStateVector2(joystickAction, SIDE_LEFT);
leftTrackedRemoteState_new.Joystick.x = moveJoystickState.currentState.x;
leftTrackedRemoteState_new.Joystick.y = moveJoystickState.currentState.y;
moveJoystickState = GetActionStateVector2(joystickAction, SIDE_RIGHT);
rightTrackedRemoteState_new.Joystick.x = moveJoystickState.currentState.x;
rightTrackedRemoteState_new.Joystick.y = moveJoystickState.currentState.y;
}
//0 = left, 1 = right
float vibration_channel_duration[2] = {0.0f, 0.0f};
float vibration_channel_intensity[2] = {0.0f, 0.0f};
void TBXR_Vibrate( int duration, int chan, float intensity )
{
for (int i = 0; i < 2; ++i)
{
int channel = 1-i;
if ((i + 1) & chan)
{
if (vibration_channel_duration[channel] > 0.0f)
return;
if (vibration_channel_duration[channel] == -1.0f && duration != 0.0f)
return;
vibration_channel_duration[channel] = duration;
vibration_channel_intensity[channel] = intensity;
}
}
}
void TBXR_ProcessHaptics() {
static float lastFrameTime = 0.0f;
float timestamp = (float)(TBXR_GetTimeInMilliSeconds( ));
float frametime = timestamp - lastFrameTime;
lastFrameTime = timestamp;
for (int i = 0; i < 2; ++i) {
if (vibration_channel_duration[i] > 0.0f ||
vibration_channel_duration[i] == -1.0f) {
// fire haptics using output action
XrHapticVibration vibration = {};
vibration.type = XR_TYPE_HAPTIC_VIBRATION;
vibration.next = NULL;
vibration.amplitude = vibration_channel_intensity[i];
vibration.duration = ToXrTime(vibration_channel_duration[i]);
vibration.frequency = 3000;
XrHapticActionInfo hapticActionInfo = {};
hapticActionInfo.type = XR_TYPE_HAPTIC_ACTION_INFO;
hapticActionInfo.next = NULL;
hapticActionInfo.action = vibrateAction;
hapticActionInfo.subactionPath = handSubactionPath[i];
OXR(xrApplyHapticFeedback(gAppState.Session, &hapticActionInfo, (const XrHapticBaseHeader*)&vibration));
if (vibration_channel_duration[i] != -1.0f) {
vibration_channel_duration[i] -= frametime;
if (vibration_channel_duration[i] < 0.0f) {
vibration_channel_duration[i] = 0.0f;
vibration_channel_intensity[i] = 0.0f;
}
}
} else {
// Stop haptics
XrHapticActionInfo hapticActionInfo = {};
hapticActionInfo.type = XR_TYPE_HAPTIC_ACTION_INFO;
hapticActionInfo.next = NULL;
hapticActionInfo.action = vibrateAction;
hapticActionInfo.subactionPath = handSubactionPath[i];
OXR(xrStopHapticFeedback(gAppState.Session, &hapticActionInfo));
}
}
}
#endif //PICO_XR

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,334 @@
#if !defined(tbxr_common_h)
#define tbxr_common_h
//OpenXR
#define XR_USE_GRAPHICS_API_OPENGL_ES 1
#define XR_USE_PLATFORM_ANDROID 1
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES3/gl3.h>
#include <GLES3/gl3ext.h>
#include <jni.h>
#include <openxr/openxr.h>
#include <openxr/openxr_platform.h>
#include <openxr/openxr_oculus_helpers.h>
#include <android/native_window_jni.h>
#include <android/log.h>
#include <stdbool.h>
#include <pthread.h>
#ifndef NDEBUG
#define DEBUG 1
#endif
#define LOG_TAG "TBXR"
#define ALOGE(...) __android_log_print( ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__ )
#if DEBUG
#define ALOGV(...) __android_log_print( ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__ )
#else
#define ALOGV(...)
#endif
enum { ovrMaxLayerCount = 1 };
enum { ovrMaxNumEyes = 2 };
typedef enum xrButton_ {
xrButton_A = 0x00000001, // Set for trigger pulled on the Gear VR and Go Controllers
xrButton_B = 0x00000002,
xrButton_RThumb = 0x00000004,
xrButton_RShoulder = 0x00000008,
xrButton_X = 0x00000100,
xrButton_Y = 0x00000200,
xrButton_LThumb = 0x00000400,
xrButton_LShoulder = 0x00000800,
xrButton_Up = 0x00010000,
xrButton_Down = 0x00020000,
xrButton_Left = 0x00040000,
xrButton_Right = 0x00080000,
xrButton_Enter = 0x00100000,
xrButton_Back = 0x00200000,
xrButton_GripTrigger = 0x04000000,
xrButton_Trigger = 0x20000000,
xrButton_Joystick = 0x80000000,
xrButton_EnumSize = 0x7fffffff
} xrButton;
typedef struct {
uint32_t Buttons;
float IndexTrigger;
float GripTrigger;
XrVector2f Joystick;
} ovrInputStateTrackedRemote;
typedef struct {
GLboolean Active;
XrPosef Pose;
XrSpaceVelocity Velocity;
} ovrTrackedController;
typedef enum control_scheme {
RIGHT_HANDED_DEFAULT = 0,
LEFT_HANDED_DEFAULT = 10,
WEAPON_ALIGN = 99
} control_scheme_t;
typedef struct {
float M[4][4];
} ovrMatrix4f;
typedef struct {
XrSwapchain Handle;
uint32_t Width;
uint32_t Height;
} ovrSwapChain;
typedef struct {
int Width;
int Height;
int Multisamples;
uint32_t TextureSwapChainLength;
uint32_t TextureSwapChainIndex;
ovrSwapChain ColorSwapChain;
XrSwapchainImageOpenGLESKHR* ColorSwapChainImage;
GLuint* DepthBuffers;
GLuint* FrameBuffers;
} ovrFramebuffer;
/*
================================================================================
ovrRenderer
================================================================================
*/
typedef struct
{
ovrFramebuffer FrameBuffer[ovrMaxNumEyes];
} ovrRenderer;
/*
================================================================================
ovrApp
================================================================================
*/
typedef enum
{
MQ_WAIT_NONE, // don't wait
MQ_WAIT_RECEIVED, // wait until the consumer thread has received the message
MQ_WAIT_PROCESSED // wait until the consumer thread has processed the message
} ovrMQWait;
#define MAX_MESSAGE_PARMS 8
#define MAX_MESSAGES 1024
typedef struct
{
int Id;
ovrMQWait Wait;
long long Parms[MAX_MESSAGE_PARMS];
} srufaceMessage;
typedef struct
{
srufaceMessage Messages[MAX_MESSAGES];
volatile int Head; // dequeue at the head
volatile int Tail; // enqueue at the tail
ovrMQWait Wait;
volatile bool EnabledFlag;
volatile bool PostedFlag;
volatile bool ReceivedFlag;
volatile bool ProcessedFlag;
pthread_mutex_t Mutex;
pthread_cond_t PostedCondition;
pthread_cond_t ReceivedCondition;
pthread_cond_t ProcessedCondition;
} surfaceMessageQueue;
typedef struct
{
JavaVM * JavaVm;
jobject ActivityObject;
jclass ActivityClass;
pthread_t Thread;
surfaceMessageQueue MessageQueue;
ANativeWindow * NativeWindow;
} ovrAppThread;
typedef union {
XrCompositionLayerProjection Projection;
XrCompositionLayerQuad Quad;
} xrCompositorLayer_Union;
#define GL(func) func;
// Forward declarations
XrInstance TBXR_GetXrInstance();
#if defined(DEBUG)
static void
OXR_CheckErrors(XrInstance instance, XrResult result, const char* function, bool failOnError) {
if (XR_FAILED(result)) {
char errorBuffer[XR_MAX_RESULT_STRING_SIZE];
xrResultToString(instance, result, errorBuffer);
if (failOnError) {
ALOGE("OpenXR error: %s: %s\n", function, errorBuffer);
} else {
ALOGV("OpenXR error: %s: %s\n", function, errorBuffer);
}
}
}
#endif
#if defined(DEBUG)
#define OXR(func) OXR_CheckErrors(TBXR_GetXrInstance(), func, #func, true);
#else
#define OXR(func) func;
#endif
typedef struct {
EGLint MajorVersion;
EGLint MinorVersion;
EGLDisplay Display;
EGLConfig Config;
EGLSurface TinySurface;
EGLSurface MainSurface;
EGLContext Context;
} ovrEgl;
/// Java details about an activity
typedef struct ovrJava_ {
JavaVM* Vm; //< Java Virtual Machine
JNIEnv* Env; //< Thread specific environment
jobject ActivityObject; //< Java activity object
} ovrJava;
typedef struct
{
ovrJava Java;
ovrEgl Egl;
ANativeWindow* NativeWindow;
bool Resumed;
bool Focused;
bool FrameSetup;
float Width;
float Height;
XrInstance Instance;
XrSession Session;
XrViewConfigurationProperties ViewportConfig;
XrViewConfigurationView ViewConfigurationView[ovrMaxNumEyes];
XrSystemId SystemId;
XrSpace HeadSpace;
XrSpace StageSpace;
XrSpace FakeStageSpace;
XrSpace CurrentSpace;
GLboolean SessionActive;
XrPosef xfStageFromHead;
XrView* Projections;
XrMatrix4x4f ProjectionMatrices[2];
float currentDisplayRefreshRate;
float* SupportedDisplayRefreshRates;
uint32_t RequestedDisplayRefreshRateIndex;
uint32_t NumSupportedDisplayRefreshRates;
PFN_xrGetDisplayRefreshRateFB pfnGetDisplayRefreshRate;
PFN_xrRequestDisplayRefreshRateFB pfnRequestDisplayRefreshRate;
XrTime PredictedDisplayTime;
int SwapInterval;
int MainThreadTid;
int RenderThreadTid;
xrCompositorLayer_Union Layers[ovrMaxLayerCount];
int LayerCount;
ovrRenderer Renderer;
ovrTrackedController TrackedController[2];
} ovrApp;
enum
{
MESSAGE_ON_CREATE,
MESSAGE_ON_START,
MESSAGE_ON_RESUME,
MESSAGE_ON_PAUSE,
MESSAGE_ON_STOP,
MESSAGE_ON_DESTROY,
MESSAGE_ON_SURFACE_CREATED,
MESSAGE_ON_SURFACE_DESTROYED
};
extern ovrAppThread * gAppThread;
extern ovrApp gAppState;
extern ovrJava java;
void ovrTrackedController_Clear(ovrTrackedController* controller);
void * AppThreadFunction(void * parm );
void ovrAppThread_Create( ovrAppThread * appThread, JNIEnv * env, jobject activityObject, jclass activityClass );
void ovrAppThread_Destroy( ovrAppThread * appThread, JNIEnv * env );
/*
* Surface Lifecycle Message Queue
*/
void surfaceMessage_Init(srufaceMessage * message, const int id, const int wait );
void * surfaceMessage_GetPointerParm(srufaceMessage * message, int index );
void surfaceMessage_SetPointerParm(srufaceMessage * message, int index, void * ptr );
void surfaceMessageQueue_Create(surfaceMessageQueue * messageQueue );
void surfaceMessageQueue_Destroy(surfaceMessageQueue * messageQueue );
void surfaceMessageQueue_Enable(surfaceMessageQueue * messageQueue, const bool set );
void surfaceMessageQueue_PostMessage(surfaceMessageQueue * messageQueue, const srufaceMessage * message );
//Functions that need to be implemented by the game specific code
void VR_FrameSetup();
bool VR_UseScreenLayer();
float VR_GetScreenLayerDistance();
bool VR_GetVRProjection(int eye, float zNear, float zFar, float* projection);
void VR_HandleControllerInput();
void VR_SetHMDOrientation(float pitch, float yaw, float roll );
void VR_SetHMDPosition(float x, float y, float z );
void VR_HapticEvent(const char* event, int position, int flags, int intensity, float angle, float yHeight );
void VR_HapticUpdateEvent(const char* event, int intensity, float angle );
void VR_HapticEndFrame();
void VR_HapticStopEvent(const char* event);
void VR_HapticEnable();
void VR_HapticDisable();
void VR_Shutdown();
//Reusable Team Beef OpenXR stuff (in TBXR_Common.cpp)
double TBXR_GetTimeInMilliSeconds();
int TBXR_GetRefresh();
void TBXR_Recenter();
void TBXR_InitialiseOpenXR();
void TBXR_WaitForSessionActive();
void TBXR_InitRenderer();
void TBXR_EnterVR();
void TBXR_GetScreenRes(int *width, int *height);
void TBXR_InitActions( void );
void TBXR_Vibrate(int duration, int channel, float intensity );
void TBXR_ProcessHaptics();
void TBXR_FrameSetup();
void TBXR_updateProjections();
void TBXR_UpdateControllers( );
void TBXR_prepareEyeBuffer(int eye );
void TBXR_finishEyeBuffer(int eye );
void TBXR_submitFrame();
#endif //vrcommon_h

View file

@ -1,13 +1,12 @@
#if !defined(vrcommon_h)
#define vrcommon_h
//#include <VrApi_Ext.h>
#include <VrApi_Input.h>
#include <android/log.h>
#include "../darkplaces/mathlib.h"
#include "TBXR_Common.h"
#define LOG_TAG "QuakeQuest"
#ifndef NDEBUG
@ -22,17 +21,21 @@
#define ALOGV(...)
#endif
float playerHeight;
float playerYaw;
extern ovrInputStateTrackedRemote leftTrackedRemoteState_old;
extern ovrInputStateTrackedRemote leftTrackedRemoteState_new;
extern ovrTrackedController leftRemoteTracking_new;
extern ovrInputStateTrackedRemote rightTrackedRemoteState_old;
extern ovrInputStateTrackedRemote rightTrackedRemoteState_new;
extern ovrTrackedController rightRemoteTracking_new;
extern float playerHeight;
extern float playerYaw;
extern vec3_t hmdorientation;
float radians(float deg);
float degrees(float rad);
qboolean isMultiplayer();
double GetTimeInMilliSeconds();
float length(float x, float y);
float nonLinearFilter(float in);
bool between(float min, float val, float max);
void QuatToYawPitchRoll(ovrQuatf q, float pitchAdjust, vec3_t out);
qboolean useScreenLayer();
#endif //vrcommon_h

View file

@ -1,595 +0,0 @@
/************************************************************************************
Filename : VrCompositor.c
*************************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/prctl.h> // for prctl( PR_SET_NAME )
#include <android/log.h>
#include <android/window.h> // for AWINDOW_FLAG_KEEP_SCREEN_ON
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES3/gl3.h>
#include <GLES3/gl3ext.h>
#include <VrApi.h>
#include <VrApi_Helpers.h>
#include "VrCompositor.h"
/*
================================================================================
renderState
================================================================================
*/
void getCurrentRenderState( renderState * state)
{
state->VertexBuffer = 0;
state->IndexBuffer = 0;
state->VertexArrayObject = 0;
state->Program = 0;
glGetIntegerv(GL_ARRAY_BUFFER, &state->VertexBuffer );
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER, &state->IndexBuffer );
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &state->VertexArrayObject );
glGetIntegerv(GL_CURRENT_PROGRAM, &state->Program );
}
void restoreRenderState( renderState * state )
{
GL( glUseProgram( state->Program ) );
GL( glBindVertexArray( state->VertexArrayObject ) );
GL( glBindBuffer( GL_ARRAY_BUFFER, state->VertexBuffer ) );
GL( glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, state->IndexBuffer ) );
}
/*
================================================================================
ovrGeometry
================================================================================
*/
enum VertexAttributeLocation
{
VERTEX_ATTRIBUTE_LOCATION_POSITION,
VERTEX_ATTRIBUTE_LOCATION_COLOR,
VERTEX_ATTRIBUTE_LOCATION_UV,
};
typedef struct
{
enum VertexAttributeLocation location;
const char * name;
} ovrVertexAttribute;
static ovrVertexAttribute ProgramVertexAttributes[] =
{
{ VERTEX_ATTRIBUTE_LOCATION_POSITION, "vertexPosition" },
{ VERTEX_ATTRIBUTE_LOCATION_COLOR, "vertexColor" },
{ VERTEX_ATTRIBUTE_LOCATION_UV, "vertexUv" },
};
static void ovrGeometry_Clear( ovrGeometry * geometry )
{
geometry->VertexBuffer = 0;
geometry->IndexBuffer = 0;
geometry->VertexArrayObject = 0;
geometry->VertexCount = 0;
geometry->IndexCount = 0;
for ( int i = 0; i < MAX_VERTEX_ATTRIB_POINTERS; i++ )
{
memset( &geometry->VertexAttribs[i], 0, sizeof( geometry->VertexAttribs[i] ) );
geometry->VertexAttribs[i].Index = -1;
}
}
static void ovrGeometry_CreateGroundPlane( ovrGeometry * geometry )
{
typedef struct
{
float positions[4][4];
unsigned char colors[4][4];
} ovrCubeVertices;
static const ovrCubeVertices cubeVertices =
{
// positions
{
{ 4.5f, -1.2f, 4.5f, 1.0f },
{ 4.5f, -1.2f, -4.5f, 1.0f },
{ -4.5f, -1.2f, -4.5f, 1.0f },
{ -4.5f, -1.2f, 4.5f, 1.0f }
},
// colors
{
{ 255, 0, 0, 255 },
{ 0, 255, 0, 255 },
{ 0, 0, 255, 255 },
{ 255, 255, 0, 255 },
},
};
static const unsigned short cubeIndices[6] =
{
0, 1, 2,
0, 2, 3,
};
geometry->VertexCount = 4;
geometry->IndexCount = 6;
geometry->VertexAttribs[0].Index = VERTEX_ATTRIBUTE_LOCATION_POSITION;
geometry->VertexAttribs[0].Size = 4;
geometry->VertexAttribs[0].Type = GL_FLOAT;
geometry->VertexAttribs[0].Normalized = false;
geometry->VertexAttribs[0].Stride = sizeof( cubeVertices.positions[0] );
geometry->VertexAttribs[0].Pointer = (const GLvoid *)offsetof( ovrCubeVertices, positions );
geometry->VertexAttribs[1].Index = VERTEX_ATTRIBUTE_LOCATION_COLOR;
geometry->VertexAttribs[1].Size = 4;
geometry->VertexAttribs[1].Type = GL_UNSIGNED_BYTE;
geometry->VertexAttribs[1].Normalized = true;
geometry->VertexAttribs[1].Stride = sizeof( cubeVertices.colors[0] );
geometry->VertexAttribs[1].Pointer = (const GLvoid *)offsetof( ovrCubeVertices, colors );
renderState state;
getCurrentRenderState(&state);
GL( glGenBuffers( 1, &geometry->VertexBuffer ) );
GL( glBindBuffer( GL_ARRAY_BUFFER, geometry->VertexBuffer ) );
GL( glBufferData( GL_ARRAY_BUFFER, sizeof( cubeVertices ), &cubeVertices, GL_STATIC_DRAW ) );
GL( glGenBuffers( 1, &geometry->IndexBuffer ) );
GL( glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, geometry->IndexBuffer ) );
GL( glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof( cubeIndices ), cubeIndices, GL_STATIC_DRAW ) );
restoreRenderState(&state);
}
static void ovrGeometry_Destroy( ovrGeometry * geometry )
{
GL( glDeleteBuffers( 1, &geometry->IndexBuffer ) );
GL( glDeleteBuffers( 1, &geometry->VertexBuffer ) );
ovrGeometry_Clear( geometry );
}
static void ovrGeometry_CreateVAO( ovrGeometry * geometry )
{
renderState state;
getCurrentRenderState(&state);
GL( glGenVertexArrays( 1, &geometry->VertexArrayObject ) );
GL( glBindVertexArray( geometry->VertexArrayObject ) );
GL( glBindBuffer( GL_ARRAY_BUFFER, geometry->VertexBuffer ) );
for ( int i = 0; i < MAX_VERTEX_ATTRIB_POINTERS; i++ )
{
if ( geometry->VertexAttribs[i].Index != -1 )
{
GL( glEnableVertexAttribArray( geometry->VertexAttribs[i].Index ) );
GL( glVertexAttribPointer( geometry->VertexAttribs[i].Index, geometry->VertexAttribs[i].Size,
geometry->VertexAttribs[i].Type, geometry->VertexAttribs[i].Normalized,
geometry->VertexAttribs[i].Stride, geometry->VertexAttribs[i].Pointer ) );
}
}
GL( glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, geometry->IndexBuffer ) );
restoreRenderState(&state);
}
static void ovrGeometry_DestroyVAO( ovrGeometry * geometry )
{
GL( glDeleteVertexArrays( 1, &geometry->VertexArrayObject ) );
}
/*
================================================================================
ovrProgram
================================================================================
*/
typedef struct
{
enum
{
UNIFORM_VIEW_PROJ_MATRIX,
} index;
enum
{
UNIFORM_TYPE_VECTOR4,
UNIFORM_TYPE_MATRIX4X4,
UNIFORM_TYPE_INT,
UNIFORM_TYPE_BUFFER,
} type;
const char * name;
} ovrUniform;
static ovrUniform ProgramUniforms[] =
{
{ UNIFORM_VIEW_PROJ_MATRIX, UNIFORM_TYPE_MATRIX4X4, "viewProjectionMatrix" },
};
static void ovrProgram_Clear( ovrProgram * program )
{
program->Program = 0;
program->VertexShader = 0;
program->FragmentShader = 0;
memset( program->UniformLocation, 0, sizeof( program->UniformLocation ) );
memset( program->UniformBinding, 0, sizeof( program->UniformBinding ) );
memset( program->Textures, 0, sizeof( program->Textures ) );
}
static bool ovrProgram_Create( ovrProgram * program, const char * vertexSource, const char * fragmentSource )
{
GLint r;
GL( program->VertexShader = glCreateShader( GL_VERTEX_SHADER ) );
GL( glShaderSource( program->VertexShader, 1, &vertexSource, 0 ) );
GL( glCompileShader( program->VertexShader ) );
GL( glGetShaderiv( program->VertexShader, GL_COMPILE_STATUS, &r ) );
if ( r == GL_FALSE )
{
GLchar msg[4096];
GL( glGetShaderInfoLog( program->VertexShader, sizeof( msg ), 0, msg ) );
ALOGE( "%s\n%s\n", vertexSource, msg );
return false;
}
GL( program->FragmentShader = glCreateShader( GL_FRAGMENT_SHADER ) );
GL( glShaderSource( program->FragmentShader, 1, &fragmentSource, 0 ) );
GL( glCompileShader( program->FragmentShader ) );
GL( glGetShaderiv( program->FragmentShader, GL_COMPILE_STATUS, &r ) );
if ( r == GL_FALSE )
{
GLchar msg[4096];
GL( glGetShaderInfoLog( program->FragmentShader, sizeof( msg ), 0, msg ) );
ALOGE( "%s\n%s\n", fragmentSource, msg );
return false;
}
GL( program->Program = glCreateProgram() );
GL( glAttachShader( program->Program, program->VertexShader ) );
GL( glAttachShader( program->Program, program->FragmentShader ) );
// Bind the vertex attribute locations.
for ( int i = 0; i < sizeof( ProgramVertexAttributes ) / sizeof( ProgramVertexAttributes[0] ); i++ )
{
GL( glBindAttribLocation( program->Program, ProgramVertexAttributes[i].location, ProgramVertexAttributes[i].name ) );
}
GL( glLinkProgram( program->Program ) );
GL( glGetProgramiv( program->Program, GL_LINK_STATUS, &r ) );
if ( r == GL_FALSE )
{
GLchar msg[4096];
GL( glGetProgramInfoLog( program->Program, sizeof( msg ), 0, msg ) );
ALOGE( "Linking program failed: %s\n", msg );
return false;
}
int numBufferBindings = 0;
// Get the uniform locations.
memset( program->UniformLocation, -1, sizeof( program->UniformLocation ) );
for ( int i = 0; i < sizeof( ProgramUniforms ) / sizeof( ProgramUniforms[0] ); i++ )
{
const int uniformIndex = ProgramUniforms[i].index;
if ( ProgramUniforms[i].type == UNIFORM_TYPE_BUFFER )
{
GL( program->UniformLocation[uniformIndex] = glGetUniformBlockIndex( program->Program, ProgramUniforms[i].name ) );
program->UniformBinding[uniformIndex] = numBufferBindings++;
GL( glUniformBlockBinding( program->Program, program->UniformLocation[uniformIndex], program->UniformBinding[uniformIndex] ) );
}
else
{
GL( program->UniformLocation[uniformIndex] = glGetUniformLocation( program->Program, ProgramUniforms[i].name ) );
program->UniformBinding[uniformIndex] = program->UniformLocation[uniformIndex];
}
}
renderState state;
getCurrentRenderState(&state);
GL( glUseProgram( program->Program ) );
// Get the texture locations.
for ( int i = 0; i < MAX_PROGRAM_TEXTURES; i++ )
{
char name[32];
sprintf( name, "Texture%i", i );
program->Textures[i] = glGetUniformLocation( program->Program, name );
if ( program->Textures[i] != -1 )
{
GL( glUniform1i( program->Textures[i], i ) );
}
}
restoreRenderState(&state);
return true;
}
static void ovrProgram_Destroy( ovrProgram * program )
{
if ( program->Program != 0 )
{
GL( glDeleteProgram( program->Program ) );
program->Program = 0;
}
if ( program->VertexShader != 0 )
{
GL( glDeleteShader( program->VertexShader ) );
program->VertexShader = 0;
}
if ( program->FragmentShader != 0 )
{
GL( glDeleteShader( program->FragmentShader ) );
program->FragmentShader = 0;
}
}
static const char VERTEX_SHADER[] =
"#version 300 es\n"
"in vec3 vertexPosition;\n"
"in vec4 vertexColor;\n"
"uniform mat4 viewProjectionMatrix;\n"
"out vec4 fragmentColor;\n"
"void main()\n"
"{\n"
" gl_Position = viewProjectionMatrix * vec4( vertexPosition, 1.0 );\n"
" fragmentColor = vertexColor;\n"
"}\n";
static const char FRAGMENT_SHADER[] =
"#version 300 es\n"
"in lowp vec4 fragmentColor;\n"
"out lowp vec4 outColor;\n"
"void main()\n"
"{\n"
" outColor = fragmentColor;\n"
"}\n";
/*
================================================================================
ovrScene
================================================================================
*/
void ovrScene_Clear( ovrScene * scene )
{
scene->CreatedScene = false;
scene->CreatedVAOs = false;
ovrProgram_Clear( &scene->Program );
ovrGeometry_Clear( &scene->GroundPlane );
ovrRenderer_Clear( &scene->CylinderRenderer );
scene->CylinderWidth = 0;
scene->CylinderHeight = 0;
}
bool ovrScene_IsCreated( ovrScene * scene )
{
return scene->CreatedScene;
}
void ovrScene_CreateVAOs( ovrScene * scene )
{
if ( !scene->CreatedVAOs )
{
ovrGeometry_CreateVAO( &scene->GroundPlane );
scene->CreatedVAOs = true;
}
}
void ovrScene_DestroyVAOs( ovrScene * scene )
{
if ( scene->CreatedVAOs )
{
ovrGeometry_DestroyVAO( &scene->GroundPlane );
scene->CreatedVAOs = false;
}
}
void ovrScene_Create( int width, int height, ovrScene * scene, const ovrJava * java )
{
// Simple ground plane geometry.
{
ovrProgram_Create( &scene->Program, VERTEX_SHADER, FRAGMENT_SHADER );
ovrGeometry_CreateGroundPlane( &scene->GroundPlane );
ovrScene_CreateVAOs( scene );
}
// Create Cylinder renderer
{
scene->CylinderWidth = width;
scene->CylinderHeight = height;
//Create cylinder renderer
ovrRenderer_Create( width, height, &scene->CylinderRenderer, java );
}
scene->CreatedScene = true;
}
void ovrScene_Destroy( ovrScene * scene )
{
ovrScene_DestroyVAOs( scene );
ovrProgram_Destroy( &scene->Program );
ovrGeometry_Destroy( &scene->GroundPlane );
ovrRenderer_Destroy( &scene->CylinderRenderer );
scene->CreatedScene = false;
}
/*
================================================================================
ovrRenderer
================================================================================
*/
ovrLayerProjection2 ovrRenderer_RenderGroundPlaneToEyeBuffer( ovrRenderer * renderer, const ovrJava * java,
const ovrScene * scene, const ovrTracking2 * tracking )
{
ovrLayerProjection2 layer = vrapi_DefaultLayerProjection2();
layer.HeadPose = tracking->HeadPose;
for ( int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; eye++ )
{
ovrFramebuffer * frameBuffer = &renderer->FrameBuffer[eye];
layer.Textures[eye].ColorSwapChain = frameBuffer->ColorTextureSwapChain;
layer.Textures[eye].SwapChainIndex = frameBuffer->TextureSwapChainIndex;
layer.Textures[eye].TexCoordsFromTanAngles = ovrMatrix4f_TanAngleMatrixFromProjection( &tracking->Eye[eye].ProjectionMatrix );
}
layer.Header.Flags |= VRAPI_FRAME_LAYER_FLAG_CHROMATIC_ABERRATION_CORRECTION;
for ( int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; eye++ )
{
ovrFramebuffer * frameBuffer = &renderer->FrameBuffer[eye];
ovrFramebuffer_SetCurrent( frameBuffer );
renderState state;
getCurrentRenderState(&state);
GL( glUseProgram( scene->Program.Program ) );
ovrMatrix4f viewProjMatrix = ovrMatrix4f_Multiply( &tracking->Eye[eye].ProjectionMatrix, &tracking->Eye[eye].ViewMatrix );
glUniformMatrix4fv( scene->Program.UniformLocation[UNIFORM_VIEW_PROJ_MATRIX], 1, GL_TRUE, &viewProjMatrix.M[0][0] );
GL( glEnable( GL_SCISSOR_TEST ) );
GL( glDepthMask( GL_TRUE ) );
GL( glEnable( GL_DEPTH_TEST ) );
GL( glDepthFunc( GL_LEQUAL ) );
GL( glEnable( GL_CULL_FACE ) );
GL( glCullFace( GL_BACK ) );
GL( glViewport( 0, 0, frameBuffer->Width, frameBuffer->Height ) );
GL( glScissor( 0, 0, frameBuffer->Width, frameBuffer->Height ) );
GL( glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ) );
GL( glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) );
//bind buffers
GL( glBindBuffer( GL_ARRAY_BUFFER, scene->GroundPlane.VertexBuffer ) );
GL( glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, scene->GroundPlane.IndexBuffer ) );
GL( glBindVertexArray( scene->GroundPlane.VertexArrayObject ) );
GL( glDrawElements( GL_TRIANGLES, scene->GroundPlane.IndexCount, GL_UNSIGNED_SHORT, NULL ) );
restoreRenderState(&state);
// Explicitly clear the border texels to black when GL_CLAMP_TO_BORDER is not available.
ovrFramebuffer_ClearEdgeTexels( frameBuffer );
ovrFramebuffer_Resolve( frameBuffer );
ovrFramebuffer_Advance( frameBuffer );
}
ovrFramebuffer_SetNone();
return layer;
}
// Assumes landscape cylinder shape.
static ovrMatrix4f CylinderModelMatrix( const int texWidth, const int texHeight,
const ovrVector3f translation,
const float rotateYaw,
const float rotatePitch,
const float radius,
const float density )
{
const ovrMatrix4f scaleMatrix = ovrMatrix4f_CreateScale( radius, radius * (float)texHeight * VRAPI_PI / density, radius );
const ovrMatrix4f transMatrix = ovrMatrix4f_CreateTranslation( translation.x, translation.y, translation.z );
const ovrMatrix4f rotXMatrix = ovrMatrix4f_CreateRotation( rotateYaw, 0.0f, 0.0f );
const ovrMatrix4f rotYMatrix = ovrMatrix4f_CreateRotation( 0.0f, rotatePitch, 0.0f );
const ovrMatrix4f m0 = ovrMatrix4f_Multiply( &transMatrix, &scaleMatrix );
const ovrMatrix4f m1 = ovrMatrix4f_Multiply( &rotXMatrix, &m0 );
const ovrMatrix4f m2 = ovrMatrix4f_Multiply( &rotYMatrix, &m1 );
return m2;
}
ovrLayerCylinder2 BuildCylinderLayer( ovrRenderer * cylinderRenderer,
const int textureWidth, const int textureHeight,
const ovrTracking2 * tracking, float rotatePitch )
{
ovrLayerCylinder2 layer = vrapi_DefaultLayerCylinder2();
const float fadeLevel = 1.0f;
layer.Header.ColorScale.x =
layer.Header.ColorScale.y =
layer.Header.ColorScale.z =
layer.Header.ColorScale.w = fadeLevel;
layer.Header.SrcBlend = VRAPI_FRAME_LAYER_BLEND_SRC_ALPHA;
layer.Header.DstBlend = VRAPI_FRAME_LAYER_BLEND_ONE_MINUS_SRC_ALPHA;
//layer.Header.Flags = VRAPI_FRAME_LAYER_FLAG_CLIP_TO_TEXTURE_RECT;
layer.HeadPose = tracking->HeadPose;
const float density = 4500.0f;
const float rotateYaw = 0.0f;
const float radius = 2.0f;
const ovrVector3f translation = { 0.0f, 1.5f, -2.5f };
ovrMatrix4f cylinderTransform =
CylinderModelMatrix( textureWidth, textureHeight, translation,
rotateYaw, rotatePitch, radius, density );
const float circScale = density * 0.5f / textureWidth;
const float circBias = -circScale * ( 0.5f * ( 1.0f - 1.0f / circScale ) );
for ( int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; eye++ )
{
ovrFramebuffer * cylinderFrameBuffer = &cylinderRenderer->FrameBuffer[eye];
ovrMatrix4f modelViewMatrix = ovrMatrix4f_Multiply( &tracking->Eye[eye].ViewMatrix, &cylinderTransform );
layer.Textures[eye].TexCoordsFromTanAngles = ovrMatrix4f_Inverse( &modelViewMatrix );
layer.Textures[eye].ColorSwapChain = cylinderFrameBuffer->ColorTextureSwapChain;
layer.Textures[eye].SwapChainIndex = cylinderFrameBuffer->TextureSwapChainIndex;
// Texcoord scale and bias is just a representation of the aspect ratio. The positioning
// of the cylinder is handled entirely by the TexCoordsFromTanAngles matrix.
const float texScaleX = circScale;
const float texBiasX = circBias;
const float texScaleY = -0.5f;
const float texBiasY = texScaleY * ( 0.5f * ( 1.0f - ( 1.0f / texScaleY ) ) );
layer.Textures[eye].TextureMatrix.M[0][0] = texScaleX;
layer.Textures[eye].TextureMatrix.M[0][2] = texBiasX;
layer.Textures[eye].TextureMatrix.M[1][1] = texScaleY;
layer.Textures[eye].TextureMatrix.M[1][2] = -texBiasY;
layer.Textures[eye].TextureRect.width = 1.0f;
layer.Textures[eye].TextureRect.height = 1.0f;
}
return layer;
}

View file

@ -1,216 +0,0 @@
/************************************************************************************
Filename : VrCompositor.h
*************************************************************************************/
#define CHECK_GL_ERRORS
#ifdef CHECK_GL_ERRORS
#include "VrCommon.h"
static const char * GlErrorString( GLenum error )
{
switch ( error )
{
case GL_NO_ERROR: return "GL_NO_ERROR";
case GL_INVALID_ENUM: return "GL_INVALID_ENUM";
case GL_INVALID_VALUE: return "GL_INVALID_VALUE";
case GL_INVALID_OPERATION: return "GL_INVALID_OPERATION";
case GL_INVALID_FRAMEBUFFER_OPERATION: return "GL_INVALID_FRAMEBUFFER_OPERATION";
case GL_OUT_OF_MEMORY: return "GL_OUT_OF_MEMORY";
default: return "unknown";
}
}
static void GLCheckErrors( int line )
{
for ( int i = 0; i < 10; i++ )
{
const GLenum error = glGetError();
if ( error == GL_NO_ERROR )
{
break;
}
ALOGE( "GL error on line %d: %s", line, GlErrorString( error ) );
}
}
#define GL( func ) func; GLCheckErrors( __LINE__ );
#else // CHECK_GL_ERRORS
#define GL( func ) func;
#endif // CHECK_GL_ERRORS
/*
================================================================================
ovrFramebuffer
================================================================================
*/
typedef struct
{
int Width;
int Height;
int Multisamples;
int TextureSwapChainLength;
int TextureSwapChainIndex;
ovrTextureSwapChain * ColorTextureSwapChain;
GLuint * DepthBuffers;
GLuint * FrameBuffers;
} ovrFramebuffer;
void ovrFramebuffer_SetCurrent( ovrFramebuffer * frameBuffer );
void ovrFramebuffer_Destroy( ovrFramebuffer * frameBuffer );
void ovrFramebuffer_SetNone();
void ovrFramebuffer_Resolve( ovrFramebuffer * frameBuffer );
void ovrFramebuffer_Advance( ovrFramebuffer * frameBuffer );
void ovrFramebuffer_ClearEdgeTexels( ovrFramebuffer * frameBuffer );
/*
================================================================================
ovrRenderer
================================================================================
*/
typedef struct
{
ovrFramebuffer FrameBuffer[VRAPI_FRAME_LAYER_EYE_MAX];
int NumBuffers;
} ovrRenderer;
void ovrRenderer_Clear( ovrRenderer * renderer );
void ovrRenderer_Create( int width, int height, ovrRenderer * renderer, const ovrJava * java );
void ovrRenderer_Destroy( ovrRenderer * renderer );
/*
================================================================================
renderState
================================================================================
*/
typedef struct
{
GLuint VertexBuffer;
GLuint IndexBuffer;
GLuint VertexArrayObject;
GLuint Program;
GLuint VertexShader;
GLuint FragmentShader;
} renderState;
void getCurrentRenderState( renderState * state);
void restoreRenderState( renderState * state );
/*
================================================================================
ovrGeometry
================================================================================
*/
typedef struct
{
GLuint Index;
GLint Size;
GLenum Type;
GLboolean Normalized;
GLsizei Stride;
const GLvoid * Pointer;
} ovrVertexAttribPointer;
#define MAX_VERTEX_ATTRIB_POINTERS 3
typedef struct
{
GLuint VertexBuffer;
GLuint IndexBuffer;
GLuint VertexArrayObject;
int VertexCount;
int IndexCount;
ovrVertexAttribPointer VertexAttribs[MAX_VERTEX_ATTRIB_POINTERS];
} ovrGeometry;
/*
================================================================================
ovrProgram
================================================================================
*/
#define MAX_PROGRAM_UNIFORMS 8
#define MAX_PROGRAM_TEXTURES 8
typedef struct
{
GLuint Program;
GLuint VertexShader;
GLuint FragmentShader;
// These will be -1 if not used by the program.
GLint UniformLocation[MAX_PROGRAM_UNIFORMS]; // ProgramUniforms[].name
GLint UniformBinding[MAX_PROGRAM_UNIFORMS]; // ProgramUniforms[].name
GLint Textures[MAX_PROGRAM_TEXTURES]; // Texture%i
} ovrProgram;
/*
================================================================================
ovrScene
================================================================================
*/
typedef struct
{
bool CreatedScene;
bool CreatedVAOs;
ovrProgram Program;
ovrGeometry GroundPlane;
//Proper renderer for stereo rendering to the cylinder layer
ovrRenderer CylinderRenderer;
int CylinderWidth;
int CylinderHeight;
} ovrScene;
bool ovrScene_IsCreated( ovrScene * scene );
void ovrScene_Clear( ovrScene * scene );
void ovrScene_Create( int width, int height, ovrScene * scene, const ovrJava * java );
void ovrScene_CreateVAOs( ovrScene * scene );
void ovrScene_DestroyVAOs( ovrScene * scene );
void ovrScene_Destroy( ovrScene * scene );
/*
================================================================================
ovrRenderer
================================================================================
*/
ovrLayerProjection2 ovrRenderer_RenderGroundPlaneToEyeBuffer( ovrRenderer * renderer, const ovrJava * java,
const ovrScene * scene, const ovrTracking2 * tracking );
ovrLayerProjection2 ovrRenderer_RenderToEyeBuffer( ovrRenderer * renderer, const ovrJava * java,
const ovrTracking2 * tracking );
ovrLayerCylinder2 BuildCylinderLayer( ovrRenderer * cylinderRenderer,
const int textureWidth, const int textureHeight,
const ovrTracking2 * tracking, float rotateYaw );
;

View file

@ -2116,8 +2116,10 @@ float GetFOV();
r_refdef.view.ortho_x = atan(r_refdef.view.frustum_x) * (360.0 / M_PI); // abused as angle by VM_CL_R_SetView
r_refdef.view.ortho_y = atan(r_refdef.view.frustum_y) * (360.0 / M_PI); // abused as angle by VM_CL_R_SetView
if(!CL_VM_UpdateView(r_stereo_side ? 0.0 : max(0.0, cl.time - cl.oldtime)))
R_RenderView();
if(r_stereo_side == 0)
CL_VM_UpdateView(max(0.0, cl.time - cl.oldtime));
R_RenderView();
}
r_refdef.view.width = vid.width;
@ -2749,7 +2751,9 @@ void CL_BeginUpdateScreen()
GL_DepthMask(true);
R_ClearScreen(false);
r_refdef.view.clear = false;
//For some reason, with this line in it breaks the left eye rendering on OpenXR, I HAVE NO IDEA WHY!?!
//r_refdef.view.clear = false;
r_refdef.view.isoverlay = false;
// calculate r_refdef.view.quality

View file

@ -3,6 +3,7 @@
#include "cl_collision.h"
#include "dpsoftrast.h"
#include "glquake.h"
#include <stdbool.h>
// on GLES we have to use some proper #define's
#ifndef GL_FRAMEBUFFER
@ -916,6 +917,7 @@ void R_Viewport_InitOrtho(r_viewport_t *v, const matrix4x4_t *cameramatrix, int
#endif
}
bool VR_GetVRProjection(int eye, float zNear, float zFar, float* projection);
void R_Viewport_InitPerspective(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, float frustumx, float frustumy, float nearclip, float farclip, const float *nearplane)
{
matrix4x4_t tempmatrix, basematrix;
@ -955,10 +957,11 @@ void R_Viewport_InitPerspective(r_viewport_t *v, const matrix4x4_t *cameramatrix
m[12] = -m[12];
}
VR_GetVRProjection(r_stereo_side, nearclip, farclip, m);
Matrix4x4_FromArrayFloatGL(&v->projectmatrix, m);
}
void R_Viewport_InitPerspectiveInfinite(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, float frustumx, float frustumy, float nearclip, const float *nearplane)
void R_Viewport_InitPerspectiveInfinite(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, float frustumx, float frustumy, float nearclip, const float *nearplane, const int allowwaterclippingplane)
{
matrix4x4_t tempmatrix, basematrix;
const float nudge = 1.0 - 1.0 / (1<<23);
@ -998,6 +1001,11 @@ void R_Viewport_InitPerspectiveInfinite(r_viewport_t *v, const matrix4x4_t *came
m[12] = -m[12];
}
if (allowwaterclippingplane)
{
VR_GetVRProjection(r_stereo_side, nearclip, 8192, m);
}
Matrix4x4_FromArrayFloatGL(&v->projectmatrix, m);
}
@ -2629,6 +2637,9 @@ void GL_ReadPixelsBGRA(int x, int y, int width, int height, unsigned char *outpi
void R_Mesh_Start(void)
{
BACKENDACTIVECHECK
//Get the current fbo
qglGetIntegerv(GL_FRAMEBUFFER_BINDING, &gl_state.defaultframebufferobject);
R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
R_Mesh_SetUseVBO();
if (gl_printcheckerror.integer && !gl_paranoid.integer)

View file

@ -26,7 +26,7 @@ void R_Viewport_TransformToScreen(const r_viewport_t *v, const vec4_t in, vec4_t
qboolean R_ScissorForBBox(const float *mins, const float *maxs, int *scissor);
void R_Viewport_InitOrtho(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, float x1, float y1, float x2, float y2, float zNear, float zFar, const float *nearplane);
void R_Viewport_InitPerspective(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, float frustumx, float frustumy, float zNear, float zFar, const float *nearplane);
void R_Viewport_InitPerspectiveInfinite(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, float frustumx, float frustumy, float zNear, const float *nearplane);
void R_Viewport_InitPerspectiveInfinite(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, float frustumx, float frustumy, float zNear, const float *nearplane, const int allowwaterclippingplane);
void R_Viewport_InitCubeSideView(r_viewport_t *v, const matrix4x4_t *cameramatrix, int side, int size, float nearclip, float farclip, const float *nearplane);
void R_Viewport_InitRectSideView(r_viewport_t *v, const matrix4x4_t *cameramatrix, int side, int size, int border, float nearclip, float farclip, const float *nearplane);
void R_SetViewport(const r_viewport_t *v);

View file

@ -51,11 +51,11 @@ static qboolean r_gpuskeletal;
// 1.0 pixel unit / 1.5 inch == 0.666666 pixel units per inch
cvar_t vr_worldscale = {CVAR_SAVE, "vr_worldscale", "26.2467", "VR World scale multiplier"};
qboolean useScreenLayer();
qboolean VR_UseScreenLayer();
float GetStereoSeparation()
{
return useScreenLayer() ? 0.0f : vr_worldscale.value * 0.065f;
return VR_UseScreenLayer() ? 0.0f : vr_worldscale.value * 0.065f;
}
@ -5613,7 +5613,7 @@ void R_SetupView(qboolean allowwaterclippingplane, int fbo, rtexture_t *depthtex
if (!r_refdef.view.useperspective)
R_Viewport_InitOrtho(&r_refdef.view.viewport, &r_refdef.view.matrix, r_refdef.view.x, rtheight - scaledheight - r_refdef.view.y, scaledwidth, scaledheight, -r_refdef.view.ortho_x, -r_refdef.view.ortho_y, r_refdef.view.ortho_x, r_refdef.view.ortho_y, -r_refdef.farclip, r_refdef.farclip, customclipplane);
else if (vid.stencil && r_useinfinitefarclip.integer)
R_Viewport_InitPerspectiveInfinite(&r_refdef.view.viewport, &r_refdef.view.matrix, r_refdef.view.x, rtheight - scaledheight - r_refdef.view.y, scaledwidth, scaledheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, customclipplane);
R_Viewport_InitPerspectiveInfinite(&r_refdef.view.viewport, &r_refdef.view.matrix, r_refdef.view.x, rtheight - scaledheight - r_refdef.view.y, scaledwidth, scaledheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, customclipplane, allowwaterclippingplane);
else
R_Viewport_InitPerspective(&r_refdef.view.viewport, &r_refdef.view.matrix, r_refdef.view.x, rtheight - scaledheight - r_refdef.view.y, scaledwidth, scaledheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, r_refdef.farclip, customclipplane);
R_Mesh_SetRenderTargets(fbo, depthtexture, colortexture, NULL, NULL, NULL);

View file

@ -3597,7 +3597,7 @@ static void M_Credits_Draw (void)
" QQQQQQQQ QQQQQQQQ ",
" QQQ QQQ ",
" Q Q ",
" Q Q v1.4.11");
" Q Q v1.5.1");
int i, l, linelength, firstline, lastline, lines;
for (i = 0, linelength = 0, firstline = 9999, lastline = -1;m_credits_message[i];i++)

View file

@ -134,11 +134,11 @@ int Sbar_GetYOffset()
return offset;
}
qboolean useScreenLayer();
qboolean VR_UseScreenLayer();
int Sbar_GetXOffset()
{
if (useScreenLayer())
if (VR_UseScreenLayer())
return 0;
//This will give the status bar depth in the 3D space

View file

@ -1,4 +1,4 @@
rootProject.projectDir = new File(settingsDir, '../../../..')
rootProject.name = "QuakeQuest"
include ':', 'VrSamples:QuakeQuest:Projects:Android'
include ':', 'XrSamples:QuakeQuest:Projects:Android'

View file

@ -138,9 +138,6 @@ import android.support.v4.content.ContextCompat;
copy_asset("/sdcard/QuakeQuest/id1", "config.cfg");
copy_asset("/sdcard/QuakeQuest", "commandline.txt");
GLES3JNILib.setCallbackObjects(this);
//Read these from a file and pass through
commandLineParams = new String("quake");
@ -209,13 +206,16 @@ import android.support.v4.content.ContextCompat;
}
}
public void shutdown() {
System.exit(0);
}
@Override protected void onStart()
{
Log.v( TAG, "GLES3JNIActivity::onStart()" );
super.onStart();
GLES3JNILib.onStart( mNativeHandle );
GLES3JNILib.onStart( mNativeHandle, this );
}
@Override protected void onResume()

View file

@ -10,7 +10,7 @@ public class GLES3JNILib
{
// Activity lifecycle
public static native long onCreate( Activity obj, String commandLineParams );
public static native void onStart( long handle );
public static native void onStart( long handle, Object obj );
public static native void onResume( long handle );
public static native void onPause( long handle );
public static native void onStop( long handle );
@ -20,6 +20,4 @@ public class GLES3JNILib
public static native void onSurfaceCreated( long handle, Surface s );
public static native void onSurfaceChanged( long handle, Surface s );
public static native void onSurfaceDestroyed( long handle );
public static native void setCallbackObjects(Object obj);
}