OpenXR - Emulate mouse cursor

This commit is contained in:
Lubos 2022-09-01 18:08:08 +02:00
parent 462174f548
commit 044d9a416b
7 changed files with 124 additions and 29 deletions

View File

@ -1,6 +1,7 @@
#include "Common/VR/PPSSPPVR.h"
#include "Common/VR/VRBase.h"
#include "Common/VR/VRInput.h"
#include "Common/VR/VRMath.h"
#include "Common/VR/VRRenderer.h"
#include "Common/VR/VRTweaks.h"
@ -31,6 +32,16 @@ struct ButtonMapping {
}
};
struct MouseActivator {
bool activate;
ovrButton ovr;
MouseActivator(bool activate, ovrButton ovr) {
this->activate = activate;
this->ovr = ovr;
}
};
static std::vector<ButtonMapping> leftControllerMapping = {
ButtonMapping(NKCODE_BUTTON_X, ovrButton_X),
ButtonMapping(NKCODE_BUTTON_Y, ovrButton_Y),
@ -61,6 +72,16 @@ static std::vector<ButtonMapping> controllerMapping[2] = {
leftControllerMapping,
rightControllerMapping
};
static int mouseController = -1;
static bool mousePressed[] = {false, false};
static std::vector<MouseActivator> mouseActivators = {
MouseActivator(true, ovrButton_Trigger),
MouseActivator(false, ovrButton_Up),
MouseActivator(false, ovrButton_Down),
MouseActivator(false, ovrButton_Left),
MouseActivator(false, ovrButton_Right),
};
/*
================================================================================
@ -99,7 +120,8 @@ void GetVRResolutionPerEye(int* width, int* height) {
}
}
void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool haptics) {
void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(const TouchInput &touch), bool haptics, float dp_xscale, float dp_yscale) {
//buttons
KeyInput keyInput = {};
for (int j = 0; j < 2; j++) {
int status = IN_VRGetButtonState(j);
@ -125,6 +147,53 @@ void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool haptics) {
}
}
}
//enable or disable mouse
for (int j = 0; j < 2; j++) {
int status = IN_VRGetButtonState(j);
for (MouseActivator& m : mouseActivators) {
if (status & m.ovr) {
mouseController = m.activate ? j : -1;
}
}
}
//mouse cursor
if (mouseController >= 0) {
//get position on screen
XrPosef pose = IN_VRGetPose(mouseController);
XrVector3f angles = XrQuaternionf_ToEulerAngles(pose.orientation);
float width = (float)VR_GetConfig(VR_CONFIG_VIEWPORT_WIDTH);
float height = (float)VR_GetConfig(VR_CONFIG_VIEWPORT_HEIGHT);
float cx = width / 2;
float cy = height / 2;
float speed = (cx + cy) / 2;
float x = cx - tan(ToRadians(angles.y - (float)VR_GetConfig(VR_CONFIG_MENU_YAW))) * speed;
float y = cy - tan(ToRadians(angles.x)) * speed;
//set renderer
VR_SetConfig(VR_CONFIG_MOUSE_X, (int)x);
VR_SetConfig(VR_CONFIG_MOUSE_Y, (int)y);
VR_SetConfig(VR_CONFIG_MOUSE_SIZE, 6 * (int)pow(VR_GetConfig(VR_CONFIG_CANVAS_DISTANCE), 0.25f));
//inform engine about the status
TouchInput touch;
touch.id = mouseController;
touch.x = x * dp_xscale;
touch.y = (height - y - 1) * dp_yscale;
bool pressed = IN_VRGetButtonState(mouseController) & ovrButton_Trigger;
if (mousePressed[mouseController] != pressed) {
if (!pressed) {
touch.flags = TOUCH_DOWN;
NativeTouch(touch);
touch.flags = TOUCH_UP;
NativeTouch(touch);
}
mousePressed[mouseController] = pressed;
}
} else {
VR_SetConfig(VR_CONFIG_MOUSE_SIZE, 0);
}
}
void UpdateVRScreenKey(const KeyInput &key) {

View File

@ -10,7 +10,7 @@ bool IsVRBuild();
void InitVROnAndroid(void* vm, void* activity, int version, char* name);
void EnterVR(bool firstStart);
void GetVRResolutionPerEye(int* width, int* height);
void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool haptics);
void UpdateVRInput(bool(*NativeKey)(const KeyInput &key), bool(*NativeTouch)(const TouchInput &touch), bool haptics, float dp_xscale, float dp_yscale);
void UpdateVRScreenKey(const KeyInput &key);
// VR rendering integration

View File

@ -506,3 +506,12 @@ uint32_t IN_VRGetButtonState( int controllerIndex ) {
XrVector2f IN_VRGetJoystickState( int controllerIndex ) {
return moveJoystickState[controllerIndex].currentState;
}
XrPosef IN_VRGetPose( int controllerIndex ) {
engine_t* engine = VR_GetEngine();
XrSpaceLocation loc = {};
loc.type = XR_TYPE_SPACE_LOCATION;
XrSpace aimSpace[] = { leftControllerAimSpace, rightControllerAimSpace };
xrLocateSpace(aimSpace[controllerIndex], engine->appState.CurrentSpace, engine->predictedDisplayTime, &loc);
return loc.pose;
}

View File

@ -32,4 +32,5 @@ void IN_VRInit( engine_t *engine );
void IN_VRInputFrame( engine_t* engine );
uint32_t IN_VRGetButtonState( int controllerIndex );
XrVector2f IN_VRGetJoystickState( int controllerIndex );
XrPosef IN_VRGetPose( int controllerIndex );
void INVR_Vibrate( int duration, int chan, float intensity );

View File

@ -16,9 +16,6 @@ GLboolean initialized = GL_FALSE;
GLboolean stageSupported = GL_FALSE;
int vrConfig[VR_CONFIG_MAX] = {};
float menuPitch = 0;
float menuYaw = 0;
float recenterYaw = 0;
XrVector3f hmdorientation;
XrVector3f hmdposition;
@ -135,7 +132,8 @@ void VR_Recenter(engine_t* engine) {
OXR(xrLocateSpace(engine->appState.HeadSpace, engine->appState.CurrentSpace, engine->predictedDisplayTime, &loc));
hmdorientation = XrQuaternionf_ToEulerAngles(loc.pose.orientation);
recenterYaw += ToRadians(hmdorientation.y);
vrConfig[VR_CONFIG_RECENTER_YAW] += (int)hmdorientation.y;
float recenterYaw = ToRadians((float)vrConfig[VR_CONFIG_RECENTER_YAW]);
spaceCreateInfo.poseInReferenceSpace.orientation.x = 0;
spaceCreateInfo.poseInReferenceSpace.orientation.y = sin(recenterYaw / 2);
spaceCreateInfo.poseInReferenceSpace.orientation.z = 0;
@ -171,8 +169,8 @@ void VR_Recenter(engine_t* engine) {
}
// Update menu orientation
menuPitch = hmdorientation.x;
menuYaw = 0;
vrConfig[VR_CONFIG_MENU_PITCH] = (int)hmdorientation.x;
vrConfig[VR_CONFIG_MENU_YAW] = 0;
}
void VR_InitRenderer( engine_t* engine, bool multiview ) {
@ -182,6 +180,8 @@ void VR_InitRenderer( engine_t* engine, bool multiview ) {
int eyeW, eyeH;
VR_GetResolution(engine, &eyeW, &eyeH);
vrConfig[VR_CONFIG_VIEWPORT_WIDTH] = eyeW;
vrConfig[VR_CONFIG_VIEWPORT_HEIGHT] = eyeH;
// Get the viewport configuration info for the chosen viewport configuration type.
engine->appState.ViewportConfig.type = XR_TYPE_VIEW_CONFIGURATION_PROPERTIES;
@ -321,15 +321,26 @@ void VR_EndFrame( engine_t* engine ) {
glClear(GL_COLOR_BUFFER_BIT);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
// Show mouse cursor
int vrMode = vrConfig[VR_CONFIG_MODE];
int size = vrConfig[VR_CONFIG_MOUSE_SIZE];
if ((vrMode == VR_MODE_FLAT_SCREEN) && (size > 0)) {
glEnable(GL_SCISSOR_TEST);
glScissor(vrConfig[VR_CONFIG_MOUSE_X], vrConfig[VR_CONFIG_MOUSE_Y], size, size);
glViewport(vrConfig[VR_CONFIG_MOUSE_X], vrConfig[VR_CONFIG_MOUSE_Y], size, size);
glClearColor(1, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_SCISSOR_TEST);
}
ovrFramebuffer* frameBuffer = &engine->appState.Renderer.FrameBuffer;
//ovrFramebuffer_Resolve(frameBuffer);
ovrFramebuffer_Release(frameBuffer);
ovrFramebuffer_SetNone();
XrCompositionLayerProjectionView projection_layer_elements[2] = {};
int vrMode = vrConfig[VR_CONFIG_MODE];
if ((vrMode == VR_MODE_MONO_6DOF) || (vrMode == VR_MODE_STEREO_6DOF)) {
menuYaw = hmdorientation.y;
vrConfig[VR_CONFIG_MENU_YAW] = (int)hmdorientation.y;
for (int eye = 0; eye < ovrMaxNumEyes; eye++) {
int imageLayer = eye;
@ -379,14 +390,16 @@ void VR_EndFrame( engine_t* engine ) {
cylinder_layer.subImage.imageRect.extent.width = width;
cylinder_layer.subImage.imageRect.extent.height = height;
cylinder_layer.subImage.imageArrayIndex = 0;
float distance = vrConfig[VR_CONFIG_CANVAS_DISTANCE];
float distance = (float)vrConfig[VR_CONFIG_CANVAS_DISTANCE];
float menuPitch = ToRadians((float)vrConfig[VR_CONFIG_MENU_PITCH]);
float menuYaw = ToRadians((float)vrConfig[VR_CONFIG_MENU_YAW]);
XrVector3f pos = {
invViewTransform[0].position.x - sin(ToRadians(menuYaw)) * distance,
invViewTransform[0].position.x - sin(menuYaw) * distance,
invViewTransform[0].position.y,
invViewTransform[0].position.z - cos(ToRadians(menuYaw)) * distance
invViewTransform[0].position.z - cos(menuYaw) * distance
};
XrQuaternionf pitch = XrQuaternionf_CreateFromVectorAngle({1, 0, 0}, -ToRadians(menuPitch));
XrQuaternionf yaw = XrQuaternionf_CreateFromVectorAngle({0, 1, 0}, ToRadians(menuYaw));
XrQuaternionf pitch = XrQuaternionf_CreateFromVectorAngle({1, 0, 0}, -menuPitch);
XrQuaternionf yaw = XrQuaternionf_CreateFromVectorAngle({0, 1, 0}, menuYaw);
cylinder_layer.pose.orientation = XrQuaternionf_Multiply(pitch, yaw);
cylinder_layer.pose.position = pos;
cylinder_layer.radius = 12.0f;

View File

@ -4,19 +4,22 @@
#include "VRMath.h"
enum VRConfig {
VR_CONFIG_MODE,
VR_CONFIG_6DOF_ENABLED,
VR_CONFIG_6DOF_SCALE,
VR_CONFIG_MIRROR_AXIS_X,
VR_CONFIG_MIRROR_AXIS_Y,
VR_CONFIG_MIRROR_AXIS_Z,
VR_CONFIG_MIRROR_PITCH,
VR_CONFIG_MIRROR_YAW,
VR_CONFIG_MIRROR_ROLL,
VR_CONFIG_3D_GEOMETRY_COUNT,
VR_CONFIG_FOV_SCALE,
VR_CONFIG_FORCE_2D,
VR_CONFIG_CANVAS_DISTANCE,
//switching between 2D and 3D
VR_CONFIG_MODE, VR_CONFIG_3D_GEOMETRY_COUNT, VR_CONFIG_FORCE_2D,
//camera setup
VR_CONFIG_FOV_SCALE, VR_CONFIG_CANVAS_DISTANCE,
//6DoF
VR_CONFIG_6DOF_ENABLED, VR_CONFIG_6DOF_SCALE,
VR_CONFIG_MIRROR_AXIS_X, VR_CONFIG_MIRROR_AXIS_Y, VR_CONFIG_MIRROR_AXIS_Z,
VR_CONFIG_MIRROR_PITCH, VR_CONFIG_MIRROR_YAW, VR_CONFIG_MIRROR_ROLL,
//2D canvas positioning
VR_CONFIG_MENU_PITCH, VR_CONFIG_MENU_YAW, VR_CONFIG_RECENTER_YAW,
//mouse cursor
VR_CONFIG_MOUSE_SIZE, VR_CONFIG_MOUSE_X, VR_CONFIG_MOUSE_Y,
//viewport size
VR_CONFIG_VIEWPORT_WIDTH, VR_CONFIG_VIEWPORT_HEIGHT,
//end
VR_CONFIG_MAX
};

View File

@ -1066,7 +1066,7 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayRender(JNIEnv *env,
}
if (IsVRBuild()) {
UpdateVRInput(NativeKey, g_Config.bHapticFeedback);
UpdateVRInput(NativeKey, NativeTouch, g_Config.bHapticFeedback, dp_xscale, dp_yscale);
}
}