mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-26 05:41:52 +00:00
Rework openxr's actionset stuff.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@6136 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
d3f0bfea71
commit
1f01465cf3
5 changed files with 455 additions and 272 deletions
|
@ -98,6 +98,11 @@ void QDECL Plug_Key_SetKeyBind(int bindmap, int keycode, int modifier, const cha
|
||||||
Key_SetBinding (keycode, modifier, newbinding, RESTRICT_LOCAL);
|
Key_SetBinding (keycode, modifier, newbinding, RESTRICT_LOCAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned int IN_GetKeyDest(void)
|
||||||
|
{
|
||||||
|
return key_dest_mask;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
static void QDECL Plug_SCR_CenterPrint(int seat, const char *text)
|
static void QDECL Plug_SCR_CenterPrint(int seat, const char *text)
|
||||||
|
|
|
@ -1094,17 +1094,17 @@ qboolean IN_SetHandPosition(const char *devname, vec3_t org, vec3_t ang, vec3_t
|
||||||
int dtype;
|
int dtype;
|
||||||
int seat;
|
int seat;
|
||||||
struct vrdevinfo_s *dev;
|
struct vrdevinfo_s *dev;
|
||||||
if (!strncmp(devname, "left", 4))
|
if (!strncasecmp(devname, "left", 4))
|
||||||
{
|
{
|
||||||
seat = atoi(devname+4);
|
seat = atoi(devname+4);
|
||||||
dtype = VRDEV_LEFT;
|
dtype = VRDEV_LEFT;
|
||||||
}
|
}
|
||||||
else if (!strncmp(devname, "right", 5))
|
else if (!strncasecmp(devname, "right", 5))
|
||||||
{
|
{
|
||||||
seat = atoi(devname+5);
|
seat = atoi(devname+5);
|
||||||
dtype = VRDEV_RIGHT;
|
dtype = VRDEV_RIGHT;
|
||||||
}
|
}
|
||||||
else if (!strncmp(devname, "head", 4))
|
else if (!strncasecmp(devname, "head", 4))
|
||||||
{
|
{
|
||||||
seat = atoi(devname+4);
|
seat = atoi(devname+4);
|
||||||
dtype = VRDEV_HEAD;
|
dtype = VRDEV_HEAD;
|
||||||
|
|
|
@ -1972,6 +1972,12 @@ static void *QDECL PlugBI_GetEngineInterface(const char *interfacename, size_t s
|
||||||
Plug_Key_GetKeyBind,
|
Plug_Key_GetKeyBind,
|
||||||
Plug_Key_SetKeyBind,
|
Plug_Key_SetKeyBind,
|
||||||
|
|
||||||
|
IN_GetKeyDest,
|
||||||
|
IN_KeyEvent,
|
||||||
|
IN_MouseMove,
|
||||||
|
IN_JoystickAxisEvent,
|
||||||
|
IN_Accelerometer,
|
||||||
|
IN_Gyroscope,
|
||||||
IN_SetHandPosition,
|
IN_SetHandPosition,
|
||||||
};
|
};
|
||||||
if (structsize == sizeof(funcs))
|
if (structsize == sizeof(funcs))
|
||||||
|
|
526
plugins/openxr.c
526
plugins/openxr.c
|
@ -81,6 +81,7 @@ static pluginputfuncs_t *inputfuncs;
|
||||||
XRFUNC(xrAttachSessionActionSets) \
|
XRFUNC(xrAttachSessionActionSets) \
|
||||||
XRFUNC(xrSyncActions) \
|
XRFUNC(xrSyncActions) \
|
||||||
XRFUNC(xrGetActionStatePose) \
|
XRFUNC(xrGetActionStatePose) \
|
||||||
|
XRFUNC(xrApplyHapticFeedback) \
|
||||||
XRFUNC(xrLocateSpace) \
|
XRFUNC(xrLocateSpace) \
|
||||||
XRFUNC(xrGetActionStateBoolean) \
|
XRFUNC(xrGetActionStateBoolean) \
|
||||||
XRFUNC(xrGetActionStateFloat) \
|
XRFUNC(xrGetActionStateFloat) \
|
||||||
|
@ -140,6 +141,9 @@ static void XR_SetupInputs_Instance(void);
|
||||||
#define METRES_TO_QUAKE(x) ((x)*xr_metresize->value)
|
#define METRES_TO_QUAKE(x) ((x)*xr_metresize->value)
|
||||||
#define QUAKE_TO_METRES(x) ((x)/xr_metresize->value)
|
#define QUAKE_TO_METRES(x) ((x)/xr_metresize->value)
|
||||||
|
|
||||||
|
#define SECONDS_TO_NANOSECONDS(x) ((x)*1000000000)
|
||||||
|
#define NANOSECONDS_TO_SECONDS(x) ((x)/1000000000.0)
|
||||||
|
|
||||||
static void XR_PoseToAngOrg(const XrPosef *pose, vec3_t ang, vec3_t org)
|
static void XR_PoseToAngOrg(const XrPosef *pose, vec3_t ang, vec3_t org)
|
||||||
{
|
{
|
||||||
XrQuaternionf q = pose->orientation;
|
XrQuaternionf q = pose->orientation;
|
||||||
|
@ -163,63 +167,13 @@ static void XR_PoseToAngOrg(const XrPosef *pose, vec3_t ang, vec3_t org)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#define VectorAngles VectorAnglesPluginsSuck
|
enum actset_e
|
||||||
static void VectorAngles(const float *forward, const float *up, float *result, qboolean meshpitch) //up may be NULL
|
|
||||||
{
|
{
|
||||||
float yaw, pitch, roll;
|
AS_COMMON,
|
||||||
|
AS_MENU,
|
||||||
if (forward[1] == 0 && forward[0] == 0)
|
AS_GAME,
|
||||||
{
|
MAX_ACTIONSETS
|
||||||
if (forward[2] > 0)
|
};
|
||||||
{
|
|
||||||
pitch = -M_PI * 0.5;
|
|
||||||
yaw = up ? atan2(-up[1], -up[0]) : 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pitch = M_PI * 0.5;
|
|
||||||
yaw = up ? atan2(up[1], up[0]) : 0;
|
|
||||||
}
|
|
||||||
roll = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
yaw = atan2(forward[1], forward[0]);
|
|
||||||
pitch = -atan2(forward[2], sqrt (forward[0]*forward[0] + forward[1]*forward[1]));
|
|
||||||
|
|
||||||
if (up)
|
|
||||||
{
|
|
||||||
vec_t cp = cos(pitch), sp = sin(pitch);
|
|
||||||
vec_t cy = cos(yaw), sy = sin(yaw);
|
|
||||||
vec3_t tleft, tup;
|
|
||||||
tleft[0] = -sy;
|
|
||||||
tleft[1] = cy;
|
|
||||||
tleft[2] = 0;
|
|
||||||
tup[0] = sp*cy;
|
|
||||||
tup[1] = sp*sy;
|
|
||||||
tup[2] = cp;
|
|
||||||
roll = -atan2(DotProduct(up, tleft), DotProduct(up, tup));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
roll = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
pitch *= 180 / M_PI;
|
|
||||||
yaw *= 180 / M_PI;
|
|
||||||
roll *= 180 / M_PI;
|
|
||||||
// if (meshpitch)
|
|
||||||
// pitch *= r_meshpitch.value;
|
|
||||||
if (pitch < 0)
|
|
||||||
pitch += 360;
|
|
||||||
if (yaw < 0)
|
|
||||||
yaw += 360;
|
|
||||||
if (roll < 0)
|
|
||||||
roll += 360;
|
|
||||||
|
|
||||||
result[0] = pitch;
|
|
||||||
result[1] = yaw;
|
|
||||||
result[2] = roll;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct
|
static struct
|
||||||
{
|
{
|
||||||
|
@ -249,7 +203,7 @@ static struct
|
||||||
image_t *swapimages;
|
image_t *swapimages;
|
||||||
} eye[MAX_VIEW_COUNT]; //note that eye is a vauge term.
|
} eye[MAX_VIEW_COUNT]; //note that eye is a vauge term.
|
||||||
|
|
||||||
XrActiveActionSet actionset;
|
XrActiveActionSet actionset[MAX_ACTIONSETS];
|
||||||
|
|
||||||
qboolean timeknown;
|
qboolean timeknown;
|
||||||
XrTime time;
|
XrTime time;
|
||||||
|
@ -259,8 +213,10 @@ static struct
|
||||||
int colourformat;
|
int colourformat;
|
||||||
|
|
||||||
unsigned int numactions;
|
unsigned int numactions;
|
||||||
|
unsigned int maxactions;
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
|
enum actset_e set;
|
||||||
XrActionType acttype;
|
XrActionType acttype;
|
||||||
const char *actname; //doubles up as command names for buttons
|
const char *actname; //doubles up as command names for buttons
|
||||||
const char *actdescription; //user-visible string (exposed via openxr runtime somehow)
|
const char *actdescription; //user-visible string (exposed via openxr runtime somehow)
|
||||||
|
@ -270,7 +226,7 @@ static struct
|
||||||
XrPath path; //for querying.
|
XrPath path; //for querying.
|
||||||
XrSpace space; //for poses.
|
XrSpace space; //for poses.
|
||||||
qboolean held; //for buttons.
|
qboolean held; //for buttons.
|
||||||
} actions[256];
|
} *actions;
|
||||||
qboolean inputsdirty; //mostly for printing them.
|
qboolean inputsdirty; //mostly for printing them.
|
||||||
|
|
||||||
#ifdef XR_EXT_hand_tracking
|
#ifdef XR_EXT_hand_tracking
|
||||||
|
@ -930,7 +886,37 @@ static qboolean XR_Init(vrsetup_t *qreqs, rendererstate_t *info)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static XrAction XR_DefineAction(XrActionType type, const char *name, const char *description, const char *root)
|
static qboolean XR_HapticCommand_f(qboolean isinsecure)
|
||||||
|
{
|
||||||
|
size_t u;
|
||||||
|
char actionname[XR_MAX_ACTION_NAME_SIZE];
|
||||||
|
cmdfuncs->Argv(0, actionname, sizeof(actionname));
|
||||||
|
for (u = 0; u < xr.numactions; u++)
|
||||||
|
{
|
||||||
|
if (!strcasecmp(xr.actions[u].actname, actionname) && xr.actions[u].acttype == XR_ACTION_TYPE_VIBRATION_OUTPUT)
|
||||||
|
{
|
||||||
|
if (xr.session)
|
||||||
|
{
|
||||||
|
XrHapticActionInfo info = {XR_TYPE_HAPTIC_ACTION_INFO};
|
||||||
|
XrHapticVibration haptic = {XR_TYPE_HAPTIC_VIBRATION};
|
||||||
|
info.action = xr.actions[u].action;
|
||||||
|
info.subactionPath = XR_NULL_PATH;
|
||||||
|
|
||||||
|
cmdfuncs->Argv(1, actionname, sizeof(actionname));
|
||||||
|
haptic.duration = *actionname?SECONDS_TO_NANOSECONDS(atof(actionname)):XR_MIN_HAPTIC_DURATION;
|
||||||
|
cmdfuncs->Argv(2, actionname, sizeof(actionname));
|
||||||
|
haptic.amplitude = *actionname?atof(actionname):0;
|
||||||
|
cmdfuncs->Argv(3, actionname, sizeof(actionname));
|
||||||
|
haptic.frequency = *actionname?atof(actionname):XR_FREQUENCY_UNSPECIFIED;
|
||||||
|
xrApplyHapticFeedback(xr.session, &info, (XrHapticBaseHeader*)&haptic);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static XrAction XR_DefineAction(enum actset_e set, XrActionType type, const char *name, const char *description, const char *root)
|
||||||
{
|
{
|
||||||
XrActionCreateInfo info = {XR_TYPE_ACTION_CREATE_INFO};
|
XrActionCreateInfo info = {XR_TYPE_ACTION_CREATE_INFO};
|
||||||
XrResult res;
|
XrResult res;
|
||||||
|
@ -941,18 +927,31 @@ static XrAction XR_DefineAction(XrActionType type, const char *name, const char
|
||||||
int dconflicts = 0;
|
int dconflicts = 0;
|
||||||
for (u = 0; u < xr.numactions; u++)
|
for (u = 0; u < xr.numactions; u++)
|
||||||
{
|
{
|
||||||
if (xr.actions[u].acttype == type && !strcmp(xr.actions[u].actname, name) /*&& !strcmp(xr.actions[u].actdescription, description)*/ && !strcmp(xr.actions[u].subactionpath?xr.actions[u].subactionpath:"", root?root:""))
|
if (xr.actions[u].set != set)
|
||||||
|
continue;
|
||||||
|
if ((xr.actions[u].acttype == type || !type) && !strcmp(xr.actions[u].actname, name) /*&& !strcmp(xr.actions[u].actdescription, description)*/ && !strcmp(xr.actions[u].subactionpath?xr.actions[u].subactionpath:"", root?root:""))
|
||||||
{ //looks like a dupe...
|
{ //looks like a dupe...
|
||||||
return xr.actions[u].action;
|
return xr.actions[u].action;
|
||||||
}
|
}
|
||||||
if (!strcasecmp(xr.actions[u].actname, name))
|
if (!strcasecmp(xr.actions[u].actname, name))
|
||||||
nconflicts++; //arse balls knob cock
|
nconflicts++; //arse balls knob cock
|
||||||
if (!strcasecmp(xr.actions[u].actdescription, description))
|
if (description && !strcasecmp(xr.actions[u].actdescription, description))
|
||||||
dconflicts++; //arse balls knob cock
|
dconflicts++; //arse balls knob cock
|
||||||
}
|
}
|
||||||
if (xr.numactions == countof(xr.actions))
|
if (!description)
|
||||||
return XR_NULL_HANDLE; //nope, list full. sorry.
|
return XR_NULL_HANDLE; //none found
|
||||||
|
if (u == xr.maxactions)
|
||||||
|
{
|
||||||
|
size_t nm = (xr.maxactions+1)*2;
|
||||||
|
void *n = plugfuncs->Realloc(xr.actions, sizeof(*xr.actions) * nm);
|
||||||
|
if (!n)
|
||||||
|
return XR_NULL_HANDLE; //erk!
|
||||||
|
xr.actions = n;
|
||||||
|
xr.maxactions = nm;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&xr.actions[u], 0, sizeof(xr.actions[u]));
|
||||||
|
xr.actions[u].set = set;
|
||||||
xr.actions[u].acttype = type;
|
xr.actions[u].acttype = type;
|
||||||
xr.actions[u].actname = strdup(name);
|
xr.actions[u].actname = strdup(name);
|
||||||
xr.actions[u].actdescription = strdup(description);
|
xr.actions[u].actdescription = strdup(description);
|
||||||
|
@ -974,16 +973,29 @@ static XrAction XR_DefineAction(XrActionType type, const char *name, const char
|
||||||
info.subactionPaths = &xr.actions[u].path;
|
info.subactionPaths = &xr.actions[u].path;
|
||||||
}
|
}
|
||||||
info.actionType = xr.actions[u].acttype;
|
info.actionType = xr.actions[u].acttype;
|
||||||
if (*xr.actions[u].actname == '+')
|
|
||||||
Q_strlcpy(info.actionName, xr.actions[u].actname+1, sizeof(info.actionName));
|
|
||||||
else
|
|
||||||
Q_strlcpy(info.actionName, xr.actions[u].actname, sizeof(info.actionName));
|
Q_strlcpy(info.actionName, xr.actions[u].actname, sizeof(info.actionName));
|
||||||
while ((ffs=strchr(info.actionName, ' '))) *ffs = '_'; //convert spaces to underscores.
|
for (ffs = info.actionName; *ffs; ffs++)
|
||||||
|
{
|
||||||
|
if (*ffs >= 'A' && *ffs < 'Z')
|
||||||
|
*ffs += 'a'-'A'; //must be lower-case
|
||||||
|
else if (*ffs >= 'a' && *ffs <= 'z')
|
||||||
|
; //allowed
|
||||||
|
else if (*ffs >= '0' && *ffs <= '9')
|
||||||
|
; //allowed
|
||||||
|
else if (*ffs == '.' || *ffs == '-' || *ffs == '_')
|
||||||
|
; //allowed
|
||||||
|
// '/' is not allowed as it must be a single segment.
|
||||||
|
else
|
||||||
|
*ffs = '_'; //everything else is blocked
|
||||||
|
}
|
||||||
Q_strlcpy(info.localizedActionName, xr.actions[u].actdescription, sizeof(info.localizedActionName));
|
Q_strlcpy(info.localizedActionName, xr.actions[u].actdescription, sizeof(info.localizedActionName));
|
||||||
res = xrCreateAction(xr.actionset.actionSet, &info, &xr.actions[u].action);
|
res = xrCreateAction(xr.actionset[set].actionSet, &info, &xr.actions[u].action);
|
||||||
if (XR_FAILED(res))
|
if (XR_FAILED(res))
|
||||||
Con_Printf("openxr: Unable to create action %s [%s] - %s\n", info.actionName, info.localizedActionName, XR_StringForResult(res));
|
Con_Printf("openxr: Unable to create action %s [%s] - %s\n", info.actionName, info.localizedActionName, XR_StringForResult(res));
|
||||||
|
|
||||||
|
if (info.actionType == XR_ACTION_TYPE_VIBRATION_OUTPUT)
|
||||||
|
cmdfuncs->AddCommand(xr.actions[u].actname);
|
||||||
|
|
||||||
return xr.actions[u].action;
|
return xr.actions[u].action;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1025,8 +1037,8 @@ static int XR_BindProfileStr(const char *fname, const char *file)
|
||||||
{
|
{
|
||||||
XrAction act;
|
XrAction act;
|
||||||
XrResult res;
|
XrResult res;
|
||||||
XrPath path;
|
XrPath profilepath = XR_NULL_PATH;
|
||||||
char line[1024];
|
char line[1024], *linestart;
|
||||||
char name[1024];
|
char name[1024];
|
||||||
char type[256];
|
char type[256];
|
||||||
char desc[1024];
|
char desc[1024];
|
||||||
|
@ -1034,33 +1046,94 @@ static int XR_BindProfileStr(const char *fname, const char *file)
|
||||||
char root[1024];
|
char root[1024];
|
||||||
unsigned int p;
|
unsigned int p;
|
||||||
char prefix[2][1024];
|
char prefix[2][1024];
|
||||||
|
enum actset_e set;
|
||||||
|
|
||||||
//first line is eg: /interaction_profiles/khr/simple_controller
|
|
||||||
while (XR_ReadLine(&file, line, sizeof(line)))
|
|
||||||
{
|
|
||||||
cmdfuncs->TokenizeString(line);
|
|
||||||
if (cmdfuncs->Argc())
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
cmdfuncs->Argv(0, name, sizeof(name));
|
|
||||||
for (p = 0; p < countof(prefix); p++)
|
|
||||||
cmdfuncs->Argv(p+1, prefix[p], sizeof(prefix[p]));
|
|
||||||
if (*name && XR_SUCCEEDED(xrStringToPath(xr.instance, name, &path)))
|
|
||||||
{ //okay, it accepted that path at least...
|
|
||||||
XrInteractionProfileSuggestedBinding suggestedbindings = {XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING};
|
XrInteractionProfileSuggestedBinding suggestedbindings = {XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING};
|
||||||
unsigned int acts = 0;
|
unsigned int acts = 0;
|
||||||
XrActionSuggestedBinding bindings[256];
|
XrActionSuggestedBinding bindings[256];
|
||||||
|
unsigned int totalacts = 0;
|
||||||
|
|
||||||
while (XR_ReadLine(&file, line, sizeof(line)))
|
while (XR_ReadLine(&file, line, sizeof(line)))
|
||||||
{
|
{
|
||||||
cmdfuncs->TokenizeString(line);
|
set = AS_COMMON;
|
||||||
|
linestart = line;
|
||||||
|
while (*linestart == ' ' || *linestart == '\t')
|
||||||
|
linestart++;
|
||||||
|
|
||||||
|
if (!strncasecmp(linestart, "menu:", 5))
|
||||||
|
{
|
||||||
|
set = AS_MENU;
|
||||||
|
linestart+=5;
|
||||||
|
}
|
||||||
|
else if (!strncasecmp(linestart, "game:", 5))
|
||||||
|
{
|
||||||
|
set = AS_GAME;
|
||||||
|
linestart+=5;
|
||||||
|
}
|
||||||
|
else if (!strncasecmp(linestart, "common:", 7))
|
||||||
|
{ //the default, but nice to be able to be explicit (especially if you want a colon in the action name).
|
||||||
|
set = AS_COMMON;
|
||||||
|
linestart+=7;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdfuncs->TokenizeString(linestart);
|
||||||
if (cmdfuncs->Argc())
|
if (cmdfuncs->Argc())
|
||||||
{
|
{
|
||||||
cmdfuncs->Argv(0, name, sizeof(name));
|
cmdfuncs->Argv(0, name, sizeof(name));
|
||||||
|
|
||||||
|
if (!strcasecmp(name, "dev"))
|
||||||
|
{
|
||||||
|
cmdfuncs->Argv(1, root, sizeof(root));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (!strcasecmp(name, "profile"))
|
||||||
|
{
|
||||||
|
if (acts)
|
||||||
|
{
|
||||||
|
suggestedbindings.interactionProfile = profilepath;
|
||||||
|
suggestedbindings.countSuggestedBindings = acts;
|
||||||
|
suggestedbindings.suggestedBindings = bindings;
|
||||||
|
res = xrSuggestInteractionProfileBindings(xr.instance, &suggestedbindings);
|
||||||
|
if (XR_FAILED(res))
|
||||||
|
Con_Printf(CON_ERROR"%s: xrSuggestInteractionProfileBindings failed - %s\n", fname, XR_StringForResult(res));
|
||||||
|
totalacts += acts;
|
||||||
|
acts = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdfuncs->Argv(1, name, sizeof(name));
|
||||||
|
for (p = 0; p < countof(prefix); p++)
|
||||||
|
cmdfuncs->Argv(2+p, prefix[p], sizeof(prefix[p]));
|
||||||
|
*root = 0;
|
||||||
|
if (XR_FAILED(xrStringToPath(xr.instance, name, &profilepath)))
|
||||||
|
profilepath = XR_NULL_PATH;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (!strcasecmp(name, "action"))
|
||||||
|
{
|
||||||
|
cmdfuncs->Argv(1, name, sizeof(name));
|
||||||
|
cmdfuncs->Argv(2, desc, sizeof(desc));
|
||||||
|
cmdfuncs->Argv(3, type, sizeof(type));
|
||||||
|
cmdfuncs->Argv(4, bind, sizeof(bind));
|
||||||
|
}
|
||||||
|
else if (cmdfuncs->Argc() == 2)
|
||||||
|
{
|
||||||
|
*desc = 0;
|
||||||
|
*type = 0;
|
||||||
|
cmdfuncs->Argv(1, bind, sizeof(desc));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (cmdfuncs->Argc() < 4)
|
||||||
|
{
|
||||||
|
Con_Printf("Unknown action command \"%s\"\n", name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
cmdfuncs->Argv(1, desc, sizeof(desc));
|
cmdfuncs->Argv(1, desc, sizeof(desc));
|
||||||
cmdfuncs->Argv(2, type, sizeof(type));
|
cmdfuncs->Argv(2, type, sizeof(type));
|
||||||
cmdfuncs->Argv(3, bind, sizeof(bind));
|
cmdfuncs->Argv(3, bind, sizeof(bind));
|
||||||
cmdfuncs->Argv(4, root, sizeof(root));
|
if (cmdfuncs->Argc() >= 5)
|
||||||
|
Con_Printf("%s: %s: Extra tokens found\n", fname, name);
|
||||||
|
}
|
||||||
|
|
||||||
if (*type)
|
if (*type)
|
||||||
{
|
{
|
||||||
|
@ -1073,43 +1146,57 @@ static int XR_BindProfileStr(const char *fname, const char *file)
|
||||||
xrtype = XR_ACTION_TYPE_VECTOR2F_INPUT;
|
xrtype = XR_ACTION_TYPE_VECTOR2F_INPUT;
|
||||||
else if (!strcasecmp(type, "pose"))
|
else if (!strcasecmp(type, "pose"))
|
||||||
xrtype = XR_ACTION_TYPE_POSE_INPUT;
|
xrtype = XR_ACTION_TYPE_POSE_INPUT;
|
||||||
else if (!strcasecmp(type, "vibration"))
|
else if (!strcasecmp(type, "vibration") || !strcasecmp(type, "haptic"))
|
||||||
xrtype = XR_ACTION_TYPE_VIBRATION_OUTPUT;
|
xrtype = XR_ACTION_TYPE_VIBRATION_OUTPUT;
|
||||||
else
|
else
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
act = XR_DefineAction(xrtype, name, desc, root);
|
//define our action...
|
||||||
if (act != XR_NULL_HANDLE && *bind)
|
act = XR_DefineAction(set, xrtype, name, desc, root);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
act = XR_DefineAction(set, (XrActionType)0, name, NULL, root);
|
||||||
|
if(act==XR_NULL_HANDLE)
|
||||||
|
Con_Printf("Action %s not defined yet\n", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
//and add it to the profile we're building.
|
||||||
|
if (act != XR_NULL_HANDLE && *bind && profilepath!=XR_NULL_PATH)
|
||||||
{
|
{
|
||||||
if (*bind == '/')
|
if (*bind == '/')
|
||||||
{
|
{
|
||||||
res = xrStringToPath(xr.instance, bind, &bindings[acts].binding);
|
res = xrStringToPath(xr.instance, bind, &bindings[acts].binding);
|
||||||
if (XR_SUCCEEDED(res))
|
if (XR_SUCCEEDED(res) && acts < countof(bindings))
|
||||||
|
bindings[acts++].action = act;
|
||||||
|
}
|
||||||
|
else if (*root == '/')
|
||||||
|
{
|
||||||
|
res = xrStringToPath(xr.instance, va("%s/%s", root, bind), &bindings[acts].binding);
|
||||||
|
if (XR_SUCCEEDED(res) && acts < countof(bindings))
|
||||||
bindings[acts++].action = act;
|
bindings[acts++].action = act;
|
||||||
}
|
}
|
||||||
else for (p = 0; p < countof(prefix) && *prefix[p]=='/'; p++)
|
else for (p = 0; p < countof(prefix) && *prefix[p]=='/'; p++)
|
||||||
{
|
{
|
||||||
res = xrStringToPath(xr.instance, va("%s%s", prefix[p], bind), &bindings[acts].binding);
|
res = xrStringToPath(xr.instance, va("%s%s", prefix[p], bind), &bindings[acts].binding);
|
||||||
if (XR_SUCCEEDED(res))
|
if (XR_SUCCEEDED(res) && acts < countof(bindings))
|
||||||
bindings[acts++].action = act;
|
bindings[acts++].action = act;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (acts)
|
if (acts)
|
||||||
{
|
{
|
||||||
suggestedbindings.interactionProfile = path;
|
suggestedbindings.interactionProfile = profilepath;
|
||||||
suggestedbindings.countSuggestedBindings = acts;
|
suggestedbindings.countSuggestedBindings = acts;
|
||||||
suggestedbindings.suggestedBindings = bindings;
|
suggestedbindings.suggestedBindings = bindings;
|
||||||
res = xrSuggestInteractionProfileBindings(xr.instance, &suggestedbindings);
|
res = xrSuggestInteractionProfileBindings(xr.instance, &suggestedbindings);
|
||||||
if (XR_FAILED(res))
|
if (XR_FAILED(res))
|
||||||
Con_Printf("%s: xrSuggestInteractionProfileBindings failed - %s\n", fname, XR_StringForResult(res));
|
Con_Printf(CON_ERROR"%s: xrSuggestInteractionProfileBindings failed - %s\n", fname, XR_StringForResult(res));
|
||||||
return acts;
|
totalacts += acts;
|
||||||
}
|
}
|
||||||
}
|
return totalacts;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int QDECL XR_BindProfileFile(const char *fname, qofs_t fsize, time_t mtime, void *ctx, struct searchpathfuncs_s *package)
|
static int QDECL XR_BindProfileFile(const char *fname, qofs_t fsize, time_t mtime, void *ctx, struct searchpathfuncs_s *package)
|
||||||
|
@ -1135,19 +1222,24 @@ static const struct
|
||||||
} xr_knownprofiles[] =
|
} xr_knownprofiles[] =
|
||||||
{
|
{
|
||||||
//FIXME: set up some proper bindings!
|
//FIXME: set up some proper bindings!
|
||||||
{"khr_simple", "/interaction_profiles/khr/simple_controller /user/hand/left/ /user/hand/right/\n"
|
{"khr_simple", "profile /interaction_profiles/khr/simple_controller /user/hand/left/ /user/hand/right/\n"
|
||||||
"+attack_left \"Left Attack\" button input/select/click /user/hand/left\n"
|
"dev /user/hand/left\n"
|
||||||
"+attack_right \"Right Attack\" button input/select/click /user/hand/right\n"
|
"+attack_left \"Left Attack\" button input/select/click\n"
|
||||||
"+menu_left \"Left Menu\" button input/menu/click /user/hand/left\n"
|
"+menu_left \"Left Menu\" button input/menu/click\n"
|
||||||
"+menu_right \"Right Menu\" button input/menu/click /user/hand/right\n"
|
"#POSE_LEFT \"Left Aim Pose\" pose input/aim/pose\n"
|
||||||
"left_aim \"Left Aim Pose\" pose input/grip/pose /user/hand/left\n"
|
//"left_grip \"Left Grip Pose\" pose input/grip/pose\n"
|
||||||
"right_aim \"Right Aim Pose\" pose input/grip/pose /user/hand/right\n"
|
"haptic_left \"Left Haptic\" haptic output/haptic\n"
|
||||||
// "grip_pose \"Grip Pose\" pose input/grip/pose\n"
|
"dev /user/hand/right\n"
|
||||||
// "aim_pose \"Aim Pose\" pose input/aim/pose\n"
|
"menu: #GP_START \"Menu Enter\" button input/select/click\n"
|
||||||
"vibrate \"A Vibrator\" vibration output/haptic\n"
|
"menu: #GP_BACK \"Menu Escape\" button input/menu/click\n"
|
||||||
|
"game: +attack_right \"Right Attack\" button input/select/click\n"
|
||||||
|
"game: +menu_right \"Right Menu\" button input/menu/click\n"
|
||||||
|
"#POSE_RIGHT \"Right Aim Pose\" pose input/aim/pose\n"
|
||||||
|
//"right_grip \"Right Grip Pose\" pose input/grip/pose\n"
|
||||||
|
"haptic_right \"Right Haptic\" haptic output/haptic\n"
|
||||||
},
|
},
|
||||||
|
|
||||||
/* {"valve_index", "/interaction_profiles/valve/index_controller /user/hand/left/ /user/hand/right/\n"
|
/* {"valve_index", "profile /interaction_profiles/valve/index_controller /user/hand/left/ /user/hand/right/\n"
|
||||||
//"unbound \"Unused Button\" button input/system/click\n"
|
//"unbound \"Unused Button\" button input/system/click\n"
|
||||||
//"unbound \"Unused Button\" button input/system/touch\n"
|
//"unbound \"Unused Button\" button input/system/touch\n"
|
||||||
//"unbound \"Unused Button\" button input/a/click\n"
|
//"unbound \"Unused Button\" button input/a/click\n"
|
||||||
|
@ -1167,10 +1259,10 @@ static const struct
|
||||||
//"unbound \"Unused Button\" button input/trackpad/touch\n"
|
//"unbound \"Unused Button\" button input/trackpad/touch\n"
|
||||||
//"unbound \"Unused Button\" pose input/grip/pose\n"
|
//"unbound \"Unused Button\" pose input/grip/pose\n"
|
||||||
//"unbound \"Unused Button\" pose input/aim/pose\n"
|
//"unbound \"Unused Button\" pose input/aim/pose\n"
|
||||||
//"unbound \"Unused Button\" vibration output/haptic\n"
|
//"unbound \"Unused Button\" haptic output/haptic\n"
|
||||||
},
|
},
|
||||||
*/
|
*/
|
||||||
/* {"htc_vive", "/interaction_profiles/htc/vive_controller /user/hand/left/ /user/hand/right/\n"
|
/* {"htc_vive", "profile /interaction_profiles/htc/vive_controller /user/hand/left/ /user/hand/right/\n"
|
||||||
//"unbound \"Unused Button\" button input/system/click\n"
|
//"unbound \"Unused Button\" button input/system/click\n"
|
||||||
//"unbound \"Unused Button\" button input/squeeze/click\n"
|
//"unbound \"Unused Button\" button input/squeeze/click\n"
|
||||||
//"unbound \"Unused Button\" button input/menu/click\n"
|
//"unbound \"Unused Button\" button input/menu/click\n"
|
||||||
|
@ -1181,10 +1273,10 @@ static const struct
|
||||||
//"unbound \"Unused Button\" button input/trackpad/touch\n"
|
//"unbound \"Unused Button\" button input/trackpad/touch\n"
|
||||||
//"unbound \"Unused Button\" pose input/grip/pose\n"
|
//"unbound \"Unused Button\" pose input/grip/pose\n"
|
||||||
//"unbound \"Unused Button\" pose input/aim/pose\n"
|
//"unbound \"Unused Button\" pose input/aim/pose\n"
|
||||||
//"unbound \"Unused Button\" vibration output/haptic\n"
|
//"unbound \"Unused Button\" haptic output/haptic\n"
|
||||||
);
|
);
|
||||||
*/
|
*/
|
||||||
/* {"htc_vive_pro", "/interaction_profiles/htc/vive_pro /user/head/\n"
|
/* {"htc_vive_pro", "profile /interaction_profiles/htc/vive_pro /user/head/\n"
|
||||||
//"unbound \"Unused Button\" button input/system/click\n"
|
//"unbound \"Unused Button\" button input/system/click\n"
|
||||||
//"unbound \"Unused Button\" button input/volume_up/click\n"
|
//"unbound \"Unused Button\" button input/volume_up/click\n"
|
||||||
//"unbound \"Unused Button\" button input/volume_down/click\n"
|
//"unbound \"Unused Button\" button input/volume_down/click\n"
|
||||||
|
@ -1192,32 +1284,32 @@ static const struct
|
||||||
);
|
);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//FIXME: map to quake's keys.
|
//just map everything to quake's various buttons so that mods with proper gamepad mapping will work here too.
|
||||||
{"gamepad", "/interaction_profiles/microsoft/xbox_controller /user/gamepad/\n"
|
{"gamepad", "profile /interaction_profiles/microsoft/xbox_controller /user/gamepad/\n"
|
||||||
"togglemenu Menu button input/menu/click\n"
|
"#GP_START \"Start\" button input/menu/click\n"
|
||||||
//"unbound \"Unused Button\" button input/view/click\n"
|
"#GP_BACK \"Back\" button input/view/click\n"
|
||||||
//"unbound \"Unused Button\" button input/a/click\n"
|
"#GP_A \"A Button\" button input/a/click\n"
|
||||||
//"unbound \"Unused Button\" button input/b/click\n"
|
"#GP_B \"B Button\" button input/b/click\n"
|
||||||
//"unbound \"Unused Button\" button input/x/click\n"
|
"#GP_X \"X Button\" button input/x/click\n"
|
||||||
//"unbound \"Unused Button\" button input/y/click\n"
|
"#GP_Y \"Y Button\" button input/y/click\n"
|
||||||
"+back \"Move Backwards\" button input/dpad_down/click\n"
|
"#GP_DPAD_DOWN \"Move Backwards\" button input/dpad_down/click\n"
|
||||||
"+moveright \"Move Right\" button input/dpad_right/click\n"
|
"#GP_DPAD_RIGHT \"Move Right\" button input/dpad_right/click\n"
|
||||||
"+forward \"Move Forward\" button input/dpad_up/click\n"
|
"#GP_DPAD_UP \"Move Forward\" button input/dpad_up/click\n"
|
||||||
"+moveleft \"Move Left\" button input/dpad_left/click\n"
|
"#GP_DPAD_LEFT \"Move Left\" button input/dpad_left/click\n"
|
||||||
"+jump \"Jump\" button input/shoulder_left/click\n"
|
"#GP_LSHOULDER \"Jump\" button input/shoulder_left/click\n"
|
||||||
"+attack \"Attack\" button input/shoulder_right/click\n"
|
"#GP_RSHOULDER \"Attack\" button input/shoulder_right/click\n"
|
||||||
//"unbound \"Unused Button\" button input/thumbstick_left/click\n"
|
"#GP_LTHUMB \"Left Thumb\" button input/thumbstick_left/click\n"
|
||||||
//"unbound \"Unused Button\" button input/thumbstick_right/click\n"
|
"#GP_RTHUMB \"Right Thumb\" button input/thumbstick_right/click\n"
|
||||||
//"unbound \"Unused Axis\" float input/trigger_left/click\n"
|
"#GP_AXIS_LTRIGGER \"Left Trigger\" float input/trigger_left/value\n"
|
||||||
//"unbound \"Unused Axis\" float input/trigger_right/click\n"
|
"#GP_AXIS_RTRIGGER \"Right Trigger\" float input/trigger_right/value\n"
|
||||||
//"unbound \"Unused Axis\" float input/thumbstick_left/x\n"
|
"#GP_AXIS_LEFT_X \"Left Thumbstick X\" float input/thumbstick_left/x\n"
|
||||||
//"unbound \"Unused Axis\" float input/thumbstick_left/y\n"
|
"#GP_AXIS_LEFT_Y \"Left Thumbstick y\" float input/thumbstick_left/y\n"
|
||||||
//"unbound \"Unused Axis\" float input/thumbstick_right/x\n"
|
"#GP_AXIS_RIGHT_X \"Right Thumbstick X\" float input/thumbstick_right/x\n"
|
||||||
//"unbound \"Unused Axis\" float input/thumbstick_right/y\n"
|
"#GP_AXIS_RIGHT_X \"Right Thumbstick Y\" float input/thumbstick_right/y\n"
|
||||||
//"unbound \"Unused Vibrator\" vibration output/haptic_left\n"
|
"haptic_gp_left \"Left Haptic (Main)\" haptic output/haptic_left\n"
|
||||||
//"unbound \"Unused Vibrator\" vibration output/haptic_left_trigger\n"
|
"haptic_gp_left_trigger \"Left-Trigger Haptic\" haptic output/haptic_left_trigger\n"
|
||||||
//"unbound \"Unused Vibrator\" vibration output/haptic_right\n"
|
"haptic_gp_right \"Right Haptic (Main)\" haptic output/haptic_right\n"
|
||||||
//"unbound \"Unused Vibrator\" vibration output/haptic_right_trigger\n"
|
"haptic_gp_right_trigger \"Right-Trigger Haptic\" haptic output/haptic_right_trigger\n"
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1225,16 +1317,19 @@ static void XR_SetupInputs_Instance(void)
|
||||||
{
|
{
|
||||||
unsigned int h;
|
unsigned int h;
|
||||||
XrResult res;
|
XrResult res;
|
||||||
|
int set;
|
||||||
|
char *actionsetNames[] = {"genericactions", "menuactions", "gameactions"};
|
||||||
|
char *actionsetNamesText[] = {"Generic Actions", "Menu Actions", "Game Actions"};
|
||||||
|
|
||||||
//begin instance-level init
|
for (set = 0; set < MAX_ACTIONSETS; set++)
|
||||||
{
|
{
|
||||||
XrActionSetCreateInfo info = {XR_TYPE_ACTION_SET_CREATE_INFO};
|
XrActionSetCreateInfo info = {XR_TYPE_ACTION_SET_CREATE_INFO};
|
||||||
Q_strlcpy(info.actionSetName, "actions", sizeof(info.actionSetName));
|
Q_strlcpy(info.actionSetName, actionsetNames[set], sizeof(info.actionSetName));
|
||||||
Q_strlcpy(info.localizedActionSetName, FULLENGINENAME" Actions", sizeof(info.localizedActionSetName));
|
Q_strlcpy(info.localizedActionSetName, actionsetNamesText[set], sizeof(info.localizedActionSetName));
|
||||||
info.priority = 0;
|
info.priority = 0;
|
||||||
|
|
||||||
xr.actionset.subactionPath = XR_NULL_PATH;
|
xr.actionset[set].subactionPath = XR_NULL_PATH;
|
||||||
res = xrCreateActionSet(xr.instance, &info, &xr.actionset.actionSet);
|
res = xrCreateActionSet(xr.instance, &info, &xr.actionset[set].actionSet);
|
||||||
if (XR_FAILED(res))
|
if (XR_FAILED(res))
|
||||||
Con_Printf("openxr: Unable to create actionset - %s\n", XR_StringForResult(res));
|
Con_Printf("openxr: Unable to create actionset - %s\n", XR_StringForResult(res));
|
||||||
}
|
}
|
||||||
|
@ -1279,8 +1374,12 @@ static void XR_SetupInputs_Session(void)
|
||||||
//and attach it.
|
//and attach it.
|
||||||
{
|
{
|
||||||
XrSessionActionSetsAttachInfo info = {XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO};
|
XrSessionActionSetsAttachInfo info = {XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO};
|
||||||
info.countActionSets = 1;
|
XrActionSet sets[MAX_ACTIONSETS];
|
||||||
info.actionSets = &xr.actionset.actionSet;
|
unsigned int set;
|
||||||
|
for (set = 0; set < MAX_ACTIONSETS; set++)
|
||||||
|
if (xr.actionset[set].actionSet)
|
||||||
|
sets[info.countActionSets++] = xr.actionset[set].actionSet;
|
||||||
|
info.actionSets = sets;
|
||||||
res = xrAttachSessionActionSets(xr.session, &info);
|
res = xrAttachSessionActionSets(xr.session, &info);
|
||||||
if (XR_FAILED(res))
|
if (XR_FAILED(res))
|
||||||
Con_Printf("openxr: xrAttachSessionActionSets failed - %s\n", XR_StringForResult(res));
|
Con_Printf("openxr: xrAttachSessionActionSets failed - %s\n", XR_StringForResult(res));
|
||||||
|
@ -1305,12 +1404,10 @@ static void XR_SetupInputs_Session(void)
|
||||||
static void XR_PrintInputs(void)
|
static void XR_PrintInputs(void)
|
||||||
{
|
{
|
||||||
XrResult res;
|
XrResult res;
|
||||||
if (xr_debug->ival)
|
|
||||||
{
|
|
||||||
XrInteractionProfileState profile = {XR_TYPE_INTERACTION_PROFILE_STATE};
|
XrInteractionProfileState profile = {XR_TYPE_INTERACTION_PROFILE_STATE};
|
||||||
XrPath path;
|
XrPath path;
|
||||||
unsigned int u;
|
unsigned int u;
|
||||||
static const char *paths[] = {"/user/hand/left", "/user/hand/right", "/user/head", "/user/gamepad", "/user/treadmill", "/user/"};
|
static const char *paths[] = {"/user/hand/left", "/user/hand/right", "/user/head", "/user/gamepad"};
|
||||||
Con_Printf("OpenXR Interaction Profiles:\n");
|
Con_Printf("OpenXR Interaction Profiles:\n");
|
||||||
for (u = 0; u < countof(paths); u++)
|
for (u = 0; u < countof(paths); u++)
|
||||||
{
|
{
|
||||||
|
@ -1341,9 +1438,9 @@ static void XR_PrintInputs(void)
|
||||||
res = xrEnumerateBoundSourcesForAction(xr.session, &info, countof(input), &inputs, input);
|
res = xrEnumerateBoundSourcesForAction(xr.session, &info, countof(input), &inputs, input);
|
||||||
if (XR_SUCCEEDED(res))
|
if (XR_SUCCEEDED(res))
|
||||||
{
|
{
|
||||||
Con_Printf("\t%s:\n", xr.actions[u].actname);
|
Con_Printf("\t%s "S_COLOR_GRAY"(%s)"S_COLOR_WHITE":\n", xr.actions[u].actname, xr.actions[u].actdescription);
|
||||||
if (!inputs)
|
if (!inputs)
|
||||||
Con_Printf(S_COLOR_GRAY"\t(unbound)\n");
|
Con_Printf(S_COLOR_GRAY"\t\t(unbound)\n");
|
||||||
else for (i = 0; i < inputs; i++)
|
else for (i = 0; i < inputs; i++)
|
||||||
{
|
{
|
||||||
char buffer[8192];
|
char buffer[8192];
|
||||||
|
@ -1354,27 +1451,36 @@ static void XR_PrintInputs(void)
|
||||||
XR_INPUT_SOURCE_LOCALIZED_NAME_COMPONENT_BIT; //'trigger'
|
XR_INPUT_SOURCE_LOCALIZED_NAME_COMPONENT_BIT; //'trigger'
|
||||||
res = xrGetInputSourceLocalizedName(xr.session, &info, sizeof(buffer), &bufsize, buffer);
|
res = xrGetInputSourceLocalizedName(xr.session, &info, sizeof(buffer), &bufsize, buffer);
|
||||||
if (XR_FAILED(res))
|
if (XR_FAILED(res))
|
||||||
Q_snprintf(buffer, sizeof(buffer), "error %i", res);
|
Q_snprintf(buffer, sizeof(buffer), S_COLOR_RED"error %i", res);
|
||||||
|
else
|
||||||
Con_Printf(S_COLOR_GREEN"\t\t%s\n", buffer);
|
Con_Printf(S_COLOR_GREEN"\t\t%s\n", buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (res == XR_ERROR_HANDLE_INVALID) //monado reports this for unimplemented things.
|
else if (res == XR_ERROR_HANDLE_INVALID) //monado reports this for unimplemented things.
|
||||||
Con_Printf("\t%s: error XR_ERROR_HANDLE_INVALID (not implemented?)\n", xr.actions[u].actname);
|
Con_Printf(S_COLOR_RED"\t%s: error XR_ERROR_HANDLE_INVALID (not implemented?)\n", xr.actions[u].actname);
|
||||||
else
|
else
|
||||||
Con_Printf("\t%s: error %s\n", xr.actions[u].actname, XR_StringForResult(res));
|
Con_Printf(S_COLOR_RED"\t%s: error %s\n", xr.actions[u].actname, XR_StringForResult(res));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void XR_UpdateInputs(XrTime time)
|
static void XR_UpdateInputs(XrTime time)
|
||||||
{
|
{
|
||||||
XrResult res;
|
XrResult res;
|
||||||
unsigned int h;
|
size_t h;
|
||||||
|
qboolean activesets[MAX_ACTIONSETS] = {true};
|
||||||
|
|
||||||
|
if (inputfuncs->GetKeyDest() & ~kdm_game)
|
||||||
|
activesets[AS_MENU] = true; //used while looking at the menuqc/emenus/console/etc.
|
||||||
|
else
|
||||||
|
activesets[AS_GAME] = true; //used while the game has focus.
|
||||||
|
|
||||||
{
|
{
|
||||||
XrActionsSyncInfo syncinfo = {XR_TYPE_ACTIONS_SYNC_INFO};
|
XrActionsSyncInfo syncinfo = {XR_TYPE_ACTIONS_SYNC_INFO};
|
||||||
syncinfo.countActiveActionSets = 1;
|
XrActiveActionSet sets[MAX_ACTIONSETS];
|
||||||
syncinfo.activeActionSets = &xr.actionset;
|
for (h = 0; h < MAX_ACTIONSETS; h++)
|
||||||
|
if (activesets[h])
|
||||||
|
sets[syncinfo.countActiveActionSets++] = xr.actionset[h];
|
||||||
|
syncinfo.activeActionSets = sets;
|
||||||
res = xrSyncActions(xr.session, &syncinfo);
|
res = xrSyncActions(xr.session, &syncinfo);
|
||||||
if (res == XR_SESSION_NOT_FOCUSED)
|
if (res == XR_SESSION_NOT_FOCUSED)
|
||||||
; //handle it anyway, giving us a chance to disable various inputs.
|
; //handle it anyway, giving us a chance to disable various inputs.
|
||||||
|
@ -1386,7 +1492,7 @@ static void XR_UpdateInputs(XrTime time)
|
||||||
{
|
{
|
||||||
if (xr.actions[h].action == XR_NULL_HANDLE) //failed to init
|
if (xr.actions[h].action == XR_NULL_HANDLE) //failed to init
|
||||||
continue;
|
continue;
|
||||||
switch(xr.actions[h].acttype)
|
safeswitch(xr.actions[h].acttype)
|
||||||
{
|
{
|
||||||
case XR_ACTION_TYPE_POSE_INPUT:
|
case XR_ACTION_TYPE_POSE_INPUT:
|
||||||
{
|
{
|
||||||
|
@ -1395,32 +1501,53 @@ static void XR_UpdateInputs(XrTime time)
|
||||||
info.action = xr.actions[h].action;
|
info.action = xr.actions[h].action;
|
||||||
info.subactionPath = xr.actions[h].path;
|
info.subactionPath = xr.actions[h].path;
|
||||||
|
|
||||||
res = xrGetActionStatePose(xr.session, &info, &pose);
|
if (XR_FAILED(xrGetActionStatePose(xr.session, &info, &pose)))
|
||||||
if (pose.isActive)
|
break;
|
||||||
|
if (pose.isActive && activesets[xr.actions[h].set])
|
||||||
{ //its mapped to something, woo.
|
{ //its mapped to something, woo.
|
||||||
XrSpaceVelocity vel = {XR_TYPE_SPACE_VELOCITY};
|
XrSpaceVelocity vel = {XR_TYPE_SPACE_VELOCITY};
|
||||||
XrSpaceLocation loc = {XR_TYPE_SPACE_LOCATION, &vel};
|
XrSpaceLocation loc = {XR_TYPE_SPACE_LOCATION, &vel};
|
||||||
vec3_t transform[4], angles, lvel, avel;
|
vec3_t angles, org, lvel, avel;
|
||||||
res = xrLocateSpace(xr.actions[h].space, xr.space, time, &loc);
|
res = xrLocateSpace(xr.actions[h].space, xr.space, time, &loc);
|
||||||
// XR_PoseToTransform(&loc.pose, transform);
|
XR_PoseToAngOrg(&loc.pose, angles, org);
|
||||||
XR_PoseToAngOrg(&loc.pose, angles, transform[3]);
|
|
||||||
|
|
||||||
// VectorAngles(transform[0], transform[2], angles, false);
|
|
||||||
VectorSet(lvel, vel.linearVelocity.x, vel.linearVelocity.y, vel.linearVelocity.z);
|
VectorSet(lvel, vel.linearVelocity.x, vel.linearVelocity.y, vel.linearVelocity.z);
|
||||||
VectorSet(avel, vel.angularVelocity.x, vel.angularVelocity.y, vel.angularVelocity.z);
|
VectorSet(avel, vel.angularVelocity.x, vel.angularVelocity.y, vel.angularVelocity.z);
|
||||||
if (!inputfuncs->SetHandPosition(xr.actions[h].actname,
|
if (!strncasecmp(xr.actions[h].actname, "#POSE_", 6))
|
||||||
(loc.locationFlags&XR_SPACE_LOCATION_POSITION_VALID_BIT)?transform[3]:NULL,
|
{
|
||||||
|
if (inputfuncs->SetHandPosition(xr.actions[h].actname+6,
|
||||||
|
(loc.locationFlags&XR_SPACE_LOCATION_POSITION_VALID_BIT)?org:NULL,
|
||||||
(loc.locationFlags&XR_SPACE_LOCATION_ORIENTATION_VALID_BIT)?angles:NULL,
|
(loc.locationFlags&XR_SPACE_LOCATION_ORIENTATION_VALID_BIT)?angles:NULL,
|
||||||
(vel.velocityFlags&XR_SPACE_VELOCITY_LINEAR_VALID_BIT)?lvel:NULL,
|
(vel.velocityFlags&XR_SPACE_VELOCITY_LINEAR_VALID_BIT)?lvel:NULL,
|
||||||
(vel.velocityFlags&XR_SPACE_VELOCITY_ANGULAR_VALID_BIT)?avel:NULL))
|
(vel.velocityFlags&XR_SPACE_VELOCITY_ANGULAR_VALID_BIT)?avel:NULL))
|
||||||
|
;
|
||||||
|
else
|
||||||
|
Con_Printf("Pose \"%s\" for action \"%s\" is not a known pose name\n", xr.actions[h].actname+1, xr.actions[h].actdescription);
|
||||||
|
}
|
||||||
|
else
|
||||||
{ //custom poses that mods might want to handle themselves...
|
{ //custom poses that mods might want to handle themselves...
|
||||||
vec3_t angles;
|
|
||||||
char cmd[256];
|
char cmd[256];
|
||||||
VectorAngles(transform[0], transform[2], angles, false);
|
unsigned int status = 0;
|
||||||
|
status |= (loc.locationFlags&XR_SPACE_LOCATION_POSITION_VALID_BIT)?VRSTATUS_ORG:0;
|
||||||
Q_snprintf(cmd, sizeof(cmd), "%s %g %g %g %g %g %g %g %g %g %g %g %g\n", xr.actions[h].actname,
|
status |= (loc.locationFlags&XR_SPACE_LOCATION_ORIENTATION_VALID_BIT)?VRSTATUS_ANG:0;
|
||||||
angles[0], angles[1], angles[2], transform[3][0], transform[3][1], transform[3][2],
|
status |= (vel.velocityFlags&XR_SPACE_VELOCITY_LINEAR_VALID_BIT)?VRSTATUS_VEL:0;
|
||||||
|
status |= (vel.velocityFlags&XR_SPACE_VELOCITY_ANGULAR_VALID_BIT)?VRSTATUS_AVEL:0;
|
||||||
|
if (status & (VRSTATUS_VEL|VRSTATUS_AVEL))
|
||||||
|
{
|
||||||
|
Q_snprintf(cmd, sizeof(cmd), "%s %u %g %g %g %g %g %g %g %g %g %g %g %g\n", xr.actions[h].actname, status,
|
||||||
|
angles[0], angles[1], angles[2], org[0], org[1], org[2],
|
||||||
vel.angularVelocity.x, vel.angularVelocity.y, vel.angularVelocity.z, vel.linearVelocity.x, vel.linearVelocity.y, vel.linearVelocity.z);
|
vel.angularVelocity.x, vel.angularVelocity.y, vel.angularVelocity.z, vel.linearVelocity.x, vel.linearVelocity.y, vel.linearVelocity.z);
|
||||||
|
}
|
||||||
|
else if (status & VRSTATUS_ORG)
|
||||||
|
{
|
||||||
|
Q_snprintf(cmd, sizeof(cmd), "%s %u %g %g %g %g %g %g\n", xr.actions[h].actname, status,
|
||||||
|
angles[0], angles[1], angles[2], org[0], org[1], org[2]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Q_snprintf(cmd, sizeof(cmd), "%s %u %g %g %g\n", xr.actions[h].actname, status,
|
||||||
|
angles[0], angles[1], angles[2]);
|
||||||
|
}
|
||||||
cmdfuncs->AddText(cmd, false);
|
cmdfuncs->AddText(cmd, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1432,12 +1559,23 @@ static void XR_UpdateInputs(XrTime time)
|
||||||
XrActionStateGetInfo info = {XR_TYPE_ACTION_STATE_GET_INFO};
|
XrActionStateGetInfo info = {XR_TYPE_ACTION_STATE_GET_INFO};
|
||||||
info.action = xr.actions[h].action;
|
info.action = xr.actions[h].action;
|
||||||
info.subactionPath = xr.actions[h].path;
|
info.subactionPath = xr.actions[h].path;
|
||||||
xrGetActionStateBoolean(xr.session, &info, &state);
|
if (XR_FAILED(xrGetActionStateBoolean(xr.session, &info, &state)))
|
||||||
|
break;
|
||||||
if (!state.isActive) state.currentState = XR_FALSE;
|
if (!state.isActive) state.currentState = XR_FALSE;
|
||||||
if ((!!state.currentState) != xr.actions[h].held)
|
if ((!!state.currentState) != xr.actions[h].held)
|
||||||
{
|
{
|
||||||
xr.actions[h].held = !!state.currentState;
|
xr.actions[h].held = !!state.currentState;
|
||||||
if (xr.actions[h].held || *xr.actions[h].actname == '+')
|
if (xr.actions[h].held && !activesets[xr.actions[h].set])
|
||||||
|
break; //don't fire the down event when this action's set isn't meant to be active...
|
||||||
|
if (*xr.actions[h].actname == '#')
|
||||||
|
{
|
||||||
|
int k = inputfuncs->GetKeyCode(xr.actions[h].actname+1, NULL);
|
||||||
|
if (k >= 0)
|
||||||
|
inputfuncs->KeyEvent(0, xr.actions[h].held, k, 0);
|
||||||
|
else
|
||||||
|
Con_Printf("Key \"%s\" for action \"%s\" is not a known key code\n", xr.actions[h].actname+1, xr.actions[h].actdescription);
|
||||||
|
}
|
||||||
|
else if (xr.actions[h].held || *xr.actions[h].actname == '+')
|
||||||
{
|
{
|
||||||
char cmd[256];
|
char cmd[256];
|
||||||
Q_strlcpy(cmd, xr.actions[h].actname, sizeof(cmd));
|
Q_strlcpy(cmd, xr.actions[h].actname, sizeof(cmd));
|
||||||
|
@ -1455,15 +1593,38 @@ static void XR_UpdateInputs(XrTime time)
|
||||||
XrActionStateGetInfo info = {XR_TYPE_ACTION_STATE_GET_INFO};
|
XrActionStateGetInfo info = {XR_TYPE_ACTION_STATE_GET_INFO};
|
||||||
info.action = xr.actions[h].action;
|
info.action = xr.actions[h].action;
|
||||||
info.subactionPath = xr.actions[h].path;
|
info.subactionPath = xr.actions[h].path;
|
||||||
xrGetActionStateFloat(xr.session, &info, &state);
|
if (XR_FAILED(xrGetActionStateFloat(xr.session, &info, &state)))
|
||||||
|
break;
|
||||||
|
|
||||||
if (!state.isActive) state.currentState = 0.0f;
|
if (state.isActive && activesets[xr.actions[h].set])
|
||||||
{
|
{
|
||||||
char cmd[256];
|
char cmd[256];
|
||||||
|
if (!strncasecmp(xr.actions[h].actname, "#GP_AXIS_", 9))
|
||||||
|
{
|
||||||
|
int axis = -1;
|
||||||
|
if (!strcasecmp(xr.actions[h].actname+9, "LTRIGGER"))
|
||||||
|
axis = GPAXIS_LT_TRIGGER;
|
||||||
|
else if (!strcasecmp(xr.actions[h].actname+9, "RTRIGGER"))
|
||||||
|
axis = GPAXIS_RT_TRIGGER;
|
||||||
|
else if (!strcasecmp(xr.actions[h].actname+9, "LEFT_X"))
|
||||||
|
axis = GPAXIS_LT_RIGHT;
|
||||||
|
else if (!strcasecmp(xr.actions[h].actname+9, "LEFT_Y"))
|
||||||
|
axis = GPAXIS_LT_DOWN;
|
||||||
|
else if (!strcasecmp(xr.actions[h].actname+9, "RIGHT_X"))
|
||||||
|
axis = GPAXIS_RT_RIGHT;
|
||||||
|
else if (!strcasecmp(xr.actions[h].actname+9, "RIGHT_Y"))
|
||||||
|
axis = GPAXIS_RT_DOWN;
|
||||||
|
else
|
||||||
|
Con_Printf("Unknown gamepad axis: \"%s\"\n", xr.actions[h].actname+1);
|
||||||
|
inputfuncs->JoystickAxisEvent(0, axis, state.currentState);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
Q_snprintf(cmd, sizeof(cmd), "%s %g\n", xr.actions[h].actname, state.currentState);
|
Q_snprintf(cmd, sizeof(cmd), "%s %g\n", xr.actions[h].actname, state.currentState);
|
||||||
cmdfuncs->AddText(cmd, false);
|
cmdfuncs->AddText(cmd, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case XR_ACTION_TYPE_VECTOR2F_INPUT:
|
case XR_ACTION_TYPE_VECTOR2F_INPUT:
|
||||||
{
|
{
|
||||||
|
@ -1471,9 +1632,10 @@ static void XR_UpdateInputs(XrTime time)
|
||||||
XrActionStateGetInfo info = {XR_TYPE_ACTION_STATE_GET_INFO};
|
XrActionStateGetInfo info = {XR_TYPE_ACTION_STATE_GET_INFO};
|
||||||
info.action = xr.actions[h].action;
|
info.action = xr.actions[h].action;
|
||||||
info.subactionPath = xr.actions[h].path;
|
info.subactionPath = xr.actions[h].path;
|
||||||
xrGetActionStateVector2f(xr.session, &info, &state);
|
if (XR_FAILED(xrGetActionStateVector2f(xr.session, &info, &state)))
|
||||||
|
break;
|
||||||
|
|
||||||
if (!state.isActive) state.currentState.x = state.currentState.y = 0.0f;
|
if (state.isActive && activesets[xr.actions[h].set])
|
||||||
{
|
{
|
||||||
char cmd[256];
|
char cmd[256];
|
||||||
Q_snprintf(cmd, sizeof(cmd), "%s %g %g\n", xr.actions[h].actname, state.currentState.x, state.currentState.y);
|
Q_snprintf(cmd, sizeof(cmd), "%s %g %g\n", xr.actions[h].actname, state.currentState.x, state.currentState.y);
|
||||||
|
@ -1481,8 +1643,9 @@ static void XR_UpdateInputs(XrTime time)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case XR_ACTION_TYPE_VIBRATION_OUTPUT:
|
case XR_ACTION_TYPE_VIBRATION_OUTPUT: //output only, nothing to read.
|
||||||
default:
|
case XR_ACTION_TYPE_MAX_ENUM: //not a real value
|
||||||
|
safedefault:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1497,6 +1660,7 @@ static qboolean XR_Begin(void)
|
||||||
|
|
||||||
xr.beginning = false;
|
xr.beginning = false;
|
||||||
xr.ending = false;
|
xr.ending = false;
|
||||||
|
xr.inputsdirty = true;
|
||||||
|
|
||||||
{
|
{
|
||||||
XrSessionCreateInfo sessioninfo = {XR_TYPE_SESSION_CREATE_INFO};
|
XrSessionCreateInfo sessioninfo = {XR_TYPE_SESSION_CREATE_INFO};
|
||||||
|
@ -1855,7 +2019,7 @@ static qboolean XR_SyncFrame(double *frametime)
|
||||||
{
|
{
|
||||||
if (time < xr.time) //make sure time doesn't go backward...
|
if (time < xr.time) //make sure time doesn't go backward...
|
||||||
time = xr.time;
|
time = xr.time;
|
||||||
*frametime = (time-xr.time)/1000000000.0;
|
*frametime = NANOSECONDS_TO_SECONDS(time-xr.time);
|
||||||
}
|
}
|
||||||
xr.time = time;
|
xr.time = time;
|
||||||
xr.timeknown = true;
|
xr.timeknown = true;
|
||||||
|
@ -1884,9 +2048,10 @@ static qboolean XR_Render(void(*rendereye)(texid_t tex, vec4_t fovoverride, vec3
|
||||||
if (!xr.session || !xr.beginning)
|
if (!xr.session || !xr.beginning)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (xr.inputsdirty)
|
if (xr.inputsdirty && xr.state==XR_SESSION_STATE_FOCUSED)
|
||||||
{
|
{
|
||||||
xr.inputsdirty = false;
|
xr.inputsdirty = false;
|
||||||
|
if (xr_debug->ival)
|
||||||
XR_PrintInputs();
|
XR_PrintInputs();
|
||||||
}
|
}
|
||||||
#ifdef XR_EXT_hand_tracking
|
#ifdef XR_EXT_hand_tracking
|
||||||
|
@ -2038,7 +2203,7 @@ static qboolean XR_Render(void(*rendereye)(texid_t tex, vec4_t fovoverride, vec3
|
||||||
fovoverride[2] = eyeview[u].fov.angleDown * (180/M_PI);
|
fovoverride[2] = eyeview[u].fov.angleDown * (180/M_PI);
|
||||||
fovoverride[3] = eyeview[u].fov.angleUp * (180/M_PI);
|
fovoverride[3] = eyeview[u].fov.angleUp * (180/M_PI);
|
||||||
|
|
||||||
waitinfo.timeout = 100000;
|
waitinfo.timeout = SECONDS_TO_NANOSECONDS(0.1);
|
||||||
res = xrWaitSwapchainImage(xr.eye[u].swapchain, &waitinfo);
|
res = xrWaitSwapchainImage(xr.eye[u].swapchain, &waitinfo);
|
||||||
if (XR_FAILED(res))
|
if (XR_FAILED(res))
|
||||||
Con_Printf("xrWaitSwapchainImage: %s\n", XR_StringForResult(res));
|
Con_Printf("xrWaitSwapchainImage: %s\n", XR_StringForResult(res));
|
||||||
|
@ -2108,6 +2273,7 @@ qboolean Plug_Init(void)
|
||||||
fsfuncs = plugfuncs->GetEngineInterface(plugfsfuncs_name, sizeof(*fsfuncs));
|
fsfuncs = plugfuncs->GetEngineInterface(plugfsfuncs_name, sizeof(*fsfuncs));
|
||||||
inputfuncs = plugfuncs->GetEngineInterface(pluginputfuncs_name, sizeof(*inputfuncs));
|
inputfuncs = plugfuncs->GetEngineInterface(pluginputfuncs_name, sizeof(*inputfuncs));
|
||||||
plugfuncs->ExportFunction("MayUnload", XR_PluginMayUnload);
|
plugfuncs->ExportFunction("MayUnload", XR_PluginMayUnload);
|
||||||
|
plugfuncs->ExportFunction("ExecuteCommand", XR_HapticCommand_f);
|
||||||
if (plugfuncs->ExportInterface(plugvrfuncs_name, &openxr, sizeof(openxr)))
|
if (plugfuncs->ExportInterface(plugvrfuncs_name, &openxr, sizeof(openxr)))
|
||||||
{
|
{
|
||||||
xr_enable = cvarfuncs->GetNVFDG("xr_enable", "1", 0, "Controls whether to use openxr rendering or not.", "OpenXR configuration");
|
xr_enable = cvarfuncs->GetNVFDG("xr_enable", "1", 0, "Controls whether to use openxr rendering or not.", "OpenXR configuration");
|
||||||
|
|
|
@ -306,7 +306,13 @@ typedef struct //for menu-like stuff
|
||||||
F(const char*,GetKeyBind, (int bindmap, int keynum, int modifier));
|
F(const char*,GetKeyBind, (int bindmap, int keynum, int modifier));
|
||||||
F(void, SetKeyBind, (int bindmap, int keycode, int modifier, const char *newbinding));
|
F(void, SetKeyBind, (int bindmap, int keycode, int modifier, const char *newbinding));
|
||||||
|
|
||||||
F(qboolean, SetHandPosition, (const char *devname, vec3_t org, vec3_t ang, vec3_t vel, vec3_t avel)); //for VR.
|
unsigned int (*GetKeyDest) (void);
|
||||||
|
void (*KeyEvent) (unsigned int devid, int down, int keycode, int unicode);
|
||||||
|
void (*MouseMove) (unsigned int devid, int abs, float x, float y, float z, float size);
|
||||||
|
void (*JoystickAxisEvent) (unsigned int devid, int axis, float value);
|
||||||
|
void (*Accelerometer) (unsigned int devid, float x, float y, float z);
|
||||||
|
void (*Gyroscope) (unsigned int devid, float pitch, float yaw, float roll);
|
||||||
|
qboolean (*SetHandPosition) (const char *devname, vec3_t org, vec3_t ang, vec3_t vel, vec3_t avel); //for VR.
|
||||||
#define pluginputfuncs_name "Input"
|
#define pluginputfuncs_name "Input"
|
||||||
} pluginputfuncs_t;
|
} pluginputfuncs_t;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue