openxr plugin: tweaked - inputs should be working properly now, and are visible to csqc. subject to further breaking changes, however.

_pext_vrinputs: added cvar to enable vr inputs protocol extension allowing vr inputs to be networked to ssqc too. defaults to 0 for now, will be renamed when deemed final.
updates menu: the prompt to enable sources is now more explicit instead of expecting the user to have a clue.
updates menu: added a v3 sources format, which should be more maintainable. not final.
updates menu: try to give reasons why sources might be failing (to help blame ISPs if they try fucking over TTH dns again).
presets menu: no longer closes the instant a preset is chosen. some presets have a couple of modifiers listed. force the demo loop in the background to serve as a preview.
prompts menus: now does word wrapping.
ftemaster: support importing server lists from other master servers (requested by Eukara).
server: try to detect when non-reply inbound packets are blocked by firewalls/nats/etc (using ftemaster to do so).
qcvm: added pointcontentsmask builtin, allowing it to probe more than just world, with fte's full contentbit range instead of just q1 legacy.
qcvm: memfill8 builtin now works on createbuffer() pointers.
qcvm: add missing unsigned ops. Fixed double comparison ops. fixed bug with op_store_i64. added missing OP_LOADP_I64
qcc: added '#pragma framerate RATE' for overriding implicit nextthink durations.
qcc: fixed '#pragma DONT_COMPILE_THIS_FILE' to not screw up comments.
qcc: added __GITURL__ __GITHASH__ __GITDATE__ __GITDATETIME__ __GITDESC__ for any mods that might want to make use of that.
qcc: fix up -Fhashonly a little
setrenderer: support for vulkan gpu enumeration.
rulesets: reworked to support custom rulesets (using hashes to catch haxxors, though still nothing prevents just changing the client to ignore rulesets)
bspx: use our BIH code for the bspx BRUSHLIST lump instead of the older less efficient code.
(static)iqm+obj: these model formats can now be used for the worldmodel (with a suitable .ent file). Also using BIH for much better collision performance.
pmove: tried to optimise PM_NudgePosition, should boost fps in stress tests.
wayland: fix a crash on startup. mousegrabs now works better.
imagetool: uses sdl for previews.


git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5813 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2021-04-14 05:21:04 +00:00
parent cd50a54a5a
commit b9cd6ec91b
160 changed files with 13078 additions and 5542 deletions

View file

@ -71,7 +71,13 @@ ifeq ($(PLUG_NATIVE_EXT),)
endif
endif
ifneq ($(shell echo|$(CC) -E -dM -|grep __ppc__),)
PLUG_NATIVE_EXT=_ppc.so
PLUG_NATIVE_EXT=_ppc.so #32bit big-endian
endif
ifneq ($(shell echo|$(CC) -E -dM -|grep __ppc64__),)
PLUG_NATIVE_EXT=_ppc64.so #64bit big-endian
endif
ifneq ($(shell echo|$(CC) -E -dM -|grep __ppc64le__),)
PLUG_NATIVE_EXT=_ppc64le.so #64bit little-endian.
endif
endif
ifeq ($(FTE_TARGET),droid)
@ -87,7 +93,7 @@ ifeq ($(FTE_TARGET),droid)
endif
#fallback
PLUG_NATIVE_EXT?=_unk.so
PLUG_NATIVE_EXT?=.so
PLUG_DEFFILE?=
PLUG_CFLAGS?=-fPIC -Wl,--no-undefined -Bsymbolic -fvisibility=hidden -static-libgcc
@ -333,7 +339,7 @@ $(PLUG_PREFIX)mpq$(PLUG_NATIVE_EXT): mpq/fs_mpq.c mpq/blast.c plugin.c
$(CC) $(BASE_CFLAGS) $(CFLAGS) -DFTEPLUGIN -o $@ -shared $(PLUG_CFLAGS) -Impq $^ $(PLUG_DEFFILE) $(PLUG_LDFLAGS_ZLIB) $(PLUG_LDFLAGS)
NATIVE_PLUGINS+=mpq
$(PLUG_PREFIX)xmpp$(PLUG_NATIVE_EXT): jabber/jabberclient.c jabber/jingle.c jabber/sift.c jabber/xml.c plugin.c ../engine/common/sha1.c emailnot/md5.c
$(PLUG_PREFIX)xmpp$(PLUG_NATIVE_EXT): jabber/jabberclient.c jabber/jingle.c jabber/sift.c jabber/xml.c plugin.c ../engine/common/sha1.c ../engine/common/sha2.c emailnot/md5.c
$(CC) $(BASE_CFLAGS) $(CFLAGS) -DFTEPLUGIN -o $@ -shared $(PLUG_CFLAGS) -Ijabber $^ $(PLUG_DEFFILE) $(PLUG_LDFLAGS) $(LIBRESOLV)
NATIVE_PLUGINS+=xmpp
@ -350,9 +356,9 @@ NATIVE_PLUGINS+=irc
#OpenXR plugin...
$(PLUG_PREFIX)openxr$(PLUG_NATIVE_EXT): openxr.c plugin.c
$(CC) $(BASE_CFLAGS) $(CFLAGS) -DFTEPLUGIN -o $@ -shared $(PLUG_CFLAGS) $^ $(PLUG_DEFFILE) $(PLUG_LDFLAGS) -DXR_NO_PROTOTYPES `pkg-config --cflags openxr` -DGLQUAKE -DVKQUAKE -DD3D11QUAKE
#ifeq ($(shell pkg-config --exists openxr && echo 1),1)
#NATIVE_PLUGINS+=openxr
#endif
ifeq ($(shell pkg-config --exists openxr && echo 1),1)
NATIVE_PLUGINS+=openxr
endif
#for compat with ezquake
$(PLUG_PREFIX)ezhud$(PLUG_NATIVE_EXT): ezhud/ezquakeisms.c ezhud/hud.c ezhud/hud_common.c ezhud/hud_editor.c plugin.c

View file

@ -435,7 +435,7 @@ static void AVEnc_Audio (void *vctx, void *data, int bytes)
{
int32_t *f = (int32_t *)ctx->audio_outbuf + p*planesize + offset;
for (i = 0; i < count*chans; i+=chans)
*f++ = bound(0x80000000, (in[i] * 0x7fffffff), 0x7fffffff);
*f++ = bound(0x80000000, (int)(in[i] * (float)0x7fffffff), 0x7fffffff);
in++;
}
break;

View file

@ -1173,14 +1173,14 @@ typedef struct
int len;
char buf[512];
} buf_t;
static int sasl_scram_initial(struct sasl_ctx_s *ctx, char *buf, int bufsize, hashfunc_t *hashfunc, size_t hashsize, qboolean plus)
static int sasl_scram_initial(struct sasl_ctx_s *ctx, char *buf, int bufsize, hashfunc_t *hashfunc, qboolean plus)
{
if (ctx->allowauth_scramsha1)
{
unsigned int t;
buf_t bindingdata;
int bs;
if (!*ctx->password_plain && ctx->password_hash_size != hashsize)
if (!*ctx->password_plain && ctx->password_hash_size != hashfunc->digestsize)
return -2;
#if 1//FIXME: test that we're compliant when we're verifying channel bindings.
@ -1227,7 +1227,6 @@ static int sasl_scram_initial(struct sasl_ctx_s *ctx, char *buf, int bufsize, ha
Base64_Add((void*)&jclient_curtime, sizeof(jclient_curtime));
strcpy(ctx->scram.authnonce, Base64_Finish());
ctx->scram.hashfunc = hashfunc;
ctx->scram.hashsize = hashsize;
Q_snprintf(buf, bufsize, "%s,,n=%s,r=%s", ctx->scram.authcbindtype, ctx->username, ctx->scram.authnonce);
return strlen(buf);
@ -1236,11 +1235,27 @@ static int sasl_scram_initial(struct sasl_ctx_s *ctx, char *buf, int bufsize, ha
}
static int sasl_scramsha1minus_initial(struct sasl_ctx_s *ctx, char *buf, int bufsize)
{
return sasl_scram_initial(ctx, buf, bufsize, &hash_sha1, 20, false);
return sasl_scram_initial(ctx, buf, bufsize, &hash_sha1, false);
}
static int sasl_scramsha256minus_initial(struct sasl_ctx_s *ctx, char *buf, int bufsize)
{
return sasl_scram_initial(ctx, buf, bufsize, &hash_sha256, false);
}
static int sasl_scramsha512minus_initial(struct sasl_ctx_s *ctx, char *buf, int bufsize)
{
return sasl_scram_initial(ctx, buf, bufsize, &hash_sha512, false);
}
static int sasl_scramsha1plus_initial(struct sasl_ctx_s *ctx, char *buf, int bufsize)
{
return sasl_scram_initial(ctx, buf, bufsize, &hash_sha1, 20, true);
return sasl_scram_initial(ctx, buf, bufsize, &hash_sha1, true);
}
static int sasl_scramsha256plus_initial(struct sasl_ctx_s *ctx, char *buf, int bufsize)
{
return sasl_scram_initial(ctx, buf, bufsize, &hash_sha256, true);
}
static int sasl_scramsha512plus_initial(struct sasl_ctx_s *ctx, char *buf, int bufsize)
{
return sasl_scram_initial(ctx, buf, bufsize, &hash_sha512, true);
}
static void buf_cat(buf_t *buf, char *data, int len)
@ -1261,13 +1276,13 @@ static size_t HMAC_Hi(hashfunc_t *hashfunc, char *out, char *password, int passw
//first iteration is special
buf_cat(salt, "\0\0\0\1", 4);
digestsize = HMAC(hashfunc, prev, sizeof(prev), salt->buf, salt->len, password, passwordlen);
digestsize = CalcHMAC(hashfunc, prev, sizeof(prev), salt->buf, salt->len, password, passwordlen);
memcpy(out, prev, digestsize);
//later iterations just use the previous iteration
for (i = 1; i < times; i++)
{
HMAC(hashfunc, prev, digestsize, prev, digestsize, password, passwordlen);
CalcHMAC(hashfunc, prev, digestsize, prev, digestsize, password, passwordlen);
for (j = 0; j < digestsize; j++)
out[j] ^= prev[j];
@ -1276,9 +1291,8 @@ static size_t HMAC_Hi(hashfunc_t *hashfunc, char *out, char *password, int passw
}
static int sasl_scram_challenge(struct sasl_ctx_s *ctx, char *in, int inlen, char *out, int outlen)
{
#define MAX_DIGEST_SIZE 20
size_t digestsize = ctx->scram.hashsize;
hashfunc_t *func = ctx->scram.hashfunc;
size_t digestsize = func->digestsize;
//sasl SCRAM-SHA-1 challenge
//send back the same 'r' attribute
buf_t saslchal;
@ -1288,16 +1302,19 @@ static int sasl_scram_challenge(struct sasl_ctx_s *ctx, char *in, int inlen, cha
buf_t itr;
buf_t final;
buf_t sigkey;
unsigned char salted_password[MAX_DIGEST_SIZE];
unsigned char proof[MAX_DIGEST_SIZE];
unsigned char clientkey[MAX_DIGEST_SIZE];
unsigned char serverkey[MAX_DIGEST_SIZE];
unsigned char storedkey[MAX_DIGEST_SIZE];
unsigned char clientsignature[MAX_DIGEST_SIZE];
unsigned char salted_password[DIGEST_MAXSIZE];
unsigned char proof[DIGEST_MAXSIZE];
unsigned char clientkey[DIGEST_MAXSIZE];
unsigned char serverkey[DIGEST_MAXSIZE];
unsigned char storedkey[DIGEST_MAXSIZE];
unsigned char clientsignature[DIGEST_MAXSIZE];
char *username = ctx->username;
char validationstr[256];
const unsigned char *tmp;
if (digestsize > DIGEST_MAXSIZE)
return -1;
saslchal.len = 0;
buf_cat(&saslchal, in, inlen);
@ -1352,11 +1369,11 @@ static int sasl_scram_challenge(struct sasl_ctx_s *ctx, char *in, int inlen, cha
else
return -2; //panic. password not known any more. the server should not be changing salt/itr.
HMAC(func, clientkey, sizeof(clientkey), "Client Key", strlen("Client Key"), salted_password, digestsize);
CalcHMAC(func, clientkey, digestsize, "Client Key", strlen("Client Key"), salted_password, digestsize);
//Note: if we wanted to be fancy, we could store both clientkey and serverkey instead of salted_password, but I'm not sure there's all that much point.
tmp = clientkey;
CalcHash(func, storedkey, sizeof(storedkey), tmp, digestsize);
HMAC(func, clientsignature, sizeof(clientsignature), sigkey.buf, sigkey.len, storedkey, digestsize);
CalcHash(func, storedkey, digestsize, tmp, digestsize);
CalcHMAC(func, clientsignature, digestsize, sigkey.buf, sigkey.len, storedkey, digestsize);
for (i = 0; i < digestsize; i++)
proof[i] = clientkey[i] ^ clientsignature[i];
@ -1365,8 +1382,8 @@ static int sasl_scram_challenge(struct sasl_ctx_s *ctx, char *in, int inlen, cha
Base64_Finish();
//to validate the server...
HMAC(func, serverkey, sizeof(serverkey), "Server Key", strlen("Server Key"), salted_password, sizeof(salted_password));
HMAC(func, ctx->scram.authvhash, sizeof(ctx->scram.authvhash), sigkey.buf, sigkey.len, serverkey, sizeof(serverkey)); //aka:serversignature
CalcHMAC(func, serverkey, digestsize, "Server Key", strlen("Server Key"), salted_password, digestsize);
CalcHMAC(func, ctx->scram.authvhash, digestsize, sigkey.buf, sigkey.len, serverkey, digestsize); //aka:serversignature
//"c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,p=v0X8v3Bz2T0CJGbJQyF0X+HI4Ts="
Q_snprintf(out, outlen, "%s,p=%s", final.buf, base64);
@ -1379,7 +1396,7 @@ static int sasl_scram_final(struct sasl_ctx_s *ctx, char *in, int inlen)
valid.len = saslattr(valid.buf, sizeof(valid.buf), in, inlen, "v");
valid.len = Base64_Decode(valid.buf, sizeof(valid.buf), valid.buf, valid.len);
if (valid.len != 20 || memcmp(ctx->scram.authvhash, valid.buf, valid.len))
if (valid.len != ctx->scram.hashfunc->digestsize || memcmp(ctx->scram.authvhash, valid.buf, valid.len))
return -1; //server didn't give us the right answer. this is NOT the server we're looking for. give up now.
return true;
}
@ -1717,15 +1734,15 @@ static int sasl_oauth2_initial(struct sasl_ctx_s *ctx, char *buf, int bufsize)
//in descending priority order
static saslmethod_t saslmethods[] =
{
// {"SCRAM-SHA-512-PLUS", sasl_scramsha512plus_initial, sasl_scram_challenge, sasl_scram_final}, //lots of unreadable hashing, with added channel bindings
// {"SCRAM-SHA-256-PLUS", sasl_scramsha256plus_initial, sasl_scram_challenge, sasl_scram_final}, //lots of unreadable hashing, with added channel bindings
{"SCRAM-SHA-512-PLUS", sasl_scramsha512plus_initial, sasl_scram_challenge, sasl_scram_final}, //lots of unreadable hashing, with added channel bindings
{"SCRAM-SHA-256-PLUS", sasl_scramsha256plus_initial, sasl_scram_challenge, sasl_scram_final}, //lots of unreadable hashing, with added channel bindings
{"SCRAM-SHA-1-PLUS", sasl_scramsha1plus_initial, sasl_scram_challenge, sasl_scram_final}, //lots of unreadable hashing, with added channel bindings
// {"SCRAM-SHA-512", sasl_scramsha512minus_initial, sasl_scram_challenge, sasl_scram_final}, //lots of unreadable hashing
// {"SCRAM-SHA-256", sasl_scramsha256minus_initial, sasl_scram_challenge, sasl_scram_final}, //lots of unreadable hashing
{"SCRAM-SHA-512", sasl_scramsha512minus_initial, sasl_scram_challenge, sasl_scram_final}, //lots of unreadable hashing
{"SCRAM-SHA-256", sasl_scramsha256minus_initial, sasl_scram_challenge, sasl_scram_final}, //lots of unreadable hashing
{"SCRAM-SHA-1", sasl_scramsha1minus_initial, sasl_scram_challenge, sasl_scram_final}, //lots of unreadable hashing
{"DIGEST-MD5", sasl_digestmd5_initial, sasl_digestmd5_challenge, NULL}, //kinda silly
{"DIGEST-MD5", sasl_digestmd5_initial, sasl_digestmd5_challenge, NULL}, //kinda silly but still better than plaintext.
{"PLAIN", sasl_plain_initial, NULL, NULL}, //realm\0username\0password
{NULL, sasl_oauth2_initial, NULL, NULL} //potentially avoids having to ask+store their password. a browser is required to obtain auth token for us.
{NULL, sasl_oauth2_initial, NULL, NULL} //potentially avoids having to ask+store their password. a browser is required to obtain auth token for us, so basically like pulling teeth.
};
/*

View file

@ -202,11 +202,10 @@ typedef struct jclient_s
{
qboolean plus;
char authnonce[256];
char authvhash[20];
char authvhash[DIGEST_MAXSIZE];
char authcbindtype[20];
char authcbinding[256];
hashfunc_t *hashfunc;
size_t hashsize;
} scram;
struct

View file

@ -1,5 +1,6 @@
#include "plugin.h"
static plugfsfuncs_t *fsfuncs;
static pluginputfuncs_t *inputfuncs;
#include "../engine/client/vr.h"
@ -116,6 +117,7 @@ XRFUNCS
#endif
static cvar_t *xr_enable;
static cvar_t *xr_debug;
static cvar_t *xr_formfactor;
static cvar_t *xr_viewconfig;
static cvar_t *xr_metresize;
@ -124,36 +126,117 @@ static cvar_t *xr_skipregularview;
#define METRES_TO_QUAKE(x) ((x)*xr_metresize->value)
#define QUAKE_TO_METRES(x) ((x)/xr_metresize->value)
static void XR_PoseToTransform(XrPosef *pose, vec3_t axisorg[4])
static void Matrix3x4_FromAngles (const vec3_t angles, const vec3_t org, float *fte_restrict transform)
{
float xx, xy, xz, xw, yy, yz, yw, zz, zw;
float x2, y2, z2;
x2 = pose->orientation.x + pose->orientation.x;
y2 = pose->orientation.y + pose->orientation.y;
z2 = pose->orientation.z + pose->orientation.z;
float angle;
float sr, sp, sy, cr, cp, cy;
xx = pose->orientation.x * x2; xy = pose->orientation.x * y2; xz = pose->orientation.x * z2;
yy = pose->orientation.y * y2; yz = pose->orientation.y * z2; zz = pose->orientation.z * z2;
xw = pose->orientation.w * x2; yw = pose->orientation.w * y2; zw = pose->orientation.w * z2;
angle = angles[YAW] * (M_PI*2 / 360);
sy = sin(angle);
cy = cos(angle);
angle = angles[PITCH] * (M_PI*2 / 360);
sp = sin(angle);
cp = cos(angle);
angle = angles[ROLL] * (M_PI*2 / 360);
sr = sin(angle);
cr = cos(angle);
axisorg[0][0] = (1.0f - (yy + zz));
axisorg[0][1] = (xy + zw);
axisorg[0][2] = (xz - yw);
transform[0+0] = cp*cy;
transform[0+1] = cp*sy;
transform[0+2] = -sp;
transform[0+3] = org[0];
axisorg[1][0] = (xy - zw);
axisorg[1][1] = (1.0f - (xx + zz));
axisorg[1][2] = (yz + xw);
transform[4+0] = (-1*sr*sp*cy+-1*cr*-sy);
transform[4+1] = (-1*sr*sp*sy+-1*cr*cy);
transform[4+2] = -1*sr*cp;
transform[4+3] = org[1];
axisorg[2][0] = (xz + yw);
axisorg[2][1] = (yz - xw);
axisorg[2][2] = (1.0f - (xx + yy));
axisorg[3][0] = METRES_TO_QUAKE(-pose->position.z); //-z forward
axisorg[3][1] = METRES_TO_QUAKE(pose->position.x); //+x right
axisorg[3][2] = METRES_TO_QUAKE(pose->position.y); //+y up
transform[8+0] = (cr*sp*cy+-sr*-sy);
transform[8+1] = (cr*sp*sy+-sr*cy);
transform[8+2] = cr*cp;
transform[8+3] = org[2];
}
static void XR_PoseToAngOrg(const XrPosef *pose, vec3_t ang, vec3_t org)
{
XrQuaternionf q = pose->orientation;
const float sqw = q.w * q.w;
const float sqx = q.x * q.x;
const float sqy = q.y * q.y;
const float sqz = q.z * q.z;
ang[PITCH] = -asin(-2 * (q.y * q.z - q.w * q.x)) * (180/M_PI);
ang[YAW] = atan2(2 * (q.x * q.z + q.w * q.y), sqw - sqx - sqy + sqz) * (180/M_PI);
ang[ROLL] = -atan2(2 * (q.x * q.y + q.w * q.z), sqw - sqx + sqy - sqz) * (180/M_PI);
#if 1
org[0] = METRES_TO_QUAKE(-pose->position.z);
org[1] = METRES_TO_QUAKE(-pose->position.x);
org[2] = METRES_TO_QUAKE(pose->position.y);
#else
org[0] = METRES_TO_QUAKE(pose->position.x);
org[1] = METRES_TO_QUAKE(pose->position.y);
org[2] = METRES_TO_QUAKE(pose->position.z);
#endif
}
static void XR_PoseToTransform(const XrPosef *pose, float *fte_restrict transform)
{
vec3_t ang, org;
XR_PoseToAngOrg(pose, ang, org);
Matrix3x4_FromAngles(ang, org, transform);
}
static void Matrix3x4_Invert_XR (const float *in1, float *fte_restrict out)
{
// we only support uniform scaling, so assume the first row is enough
// (note the lack of sqrt here, because we're trying to undo the scaling,
// this means multiplying by the inverse scale twice - squaring it, which
// makes the sqrt a waste of time)
#if 1
double scale = 1.0 / (in1[0] * in1[0] + in1[1] * in1[1] + in1[2] * in1[2]);
#else
double scale = 3.0 / sqrt
(in1->m[0][0] * in1->m[0][0] + in1->m[0][1] * in1->m[0][1] + in1->m[0][2] * in1->m[0][2]
+ in1->m[1][0] * in1->m[1][0] + in1->m[1][1] * in1->m[1][1] + in1->m[1][2] * in1->m[1][2]
+ in1->m[2][0] * in1->m[2][0] + in1->m[2][1] * in1->m[2][1] + in1->m[2][2] * in1->m[2][2]);
scale *= scale;
#endif
// invert the rotation by transposing and multiplying by the squared
// recipricol of the input matrix scale as described above
out[0] = in1[0] * scale;
out[1] = in1[4] * scale;
out[2] = in1[8] * scale;
out[4] = in1[1] * scale;
out[5] = in1[5] * scale;
out[6] = in1[9] * scale;
out[8] = in1[2] * scale;
out[9] = in1[6] * scale;
out[10] = in1[10] * scale;
// invert the translate
out[3] = -(in1[3] * out[0] + in1[7] * out[1] + in1[11] * out[2]);
out[7] = -(in1[3] * out[4] + in1[7] * out[5] + in1[11] * out[6]);
out[11] = -(in1[3] * out[8] + in1[7] * out[9] + in1[11] * out[10]);
}
static void Matrix3x4_Multiply_XR(const float *a, const float *b, float *fte_restrict out)
{
out[0] = a[0] * b[0] + a[4] * b[1] + a[8] * b[2];
out[1] = a[1] * b[0] + a[5] * b[1] + a[9] * b[2];
out[2] = a[2] * b[0] + a[6] * b[1] + a[10] * b[2];
out[3] = a[3] * b[0] + a[7] * b[1] + a[11] * b[2] + b[3];
out[4] = a[0] * b[4] + a[4] * b[5] + a[8] * b[6];
out[5] = a[1] * b[4] + a[5] * b[5] + a[9] * b[6];
out[6] = a[2] * b[4] + a[6] * b[5] + a[10] * b[6];
out[7] = a[3] * b[4] + a[7] * b[5] + a[11] * b[6] + b[7];
out[8] = a[0] * b[8] + a[4] * b[9] + a[8] * b[10];
out[9] = a[1] * b[8] + a[5] * b[9] + a[9] * b[10];
out[10] = a[2] * b[8] + a[6] * b[9] + a[10] * b[10];
out[11] = a[3] * b[8] + a[7] * b[9] + a[11] * b[10] + b[11];
}
#define VectorAngles VectorAnglesPluginsSuck
void QDECL VectorAngles(const float *forward, const float *up, float *result, qboolean meshpitch) //up may be NULL
static void VectorAngles(const float *forward, const float *up, float *result, qboolean meshpitch) //up may be NULL
{
float yaw, pitch, roll;
@ -241,6 +324,7 @@ static struct
qboolean timeknown;
XrTime time;
XrFrameState framestate;
qboolean needrender; //we MUST call xrBegin before the next xrWait
int srgb; //<0 = gamma-only. 0 = no srgb at all, >0 full srgb, including textures and stuff
unsigned int numactions;
@ -382,12 +466,15 @@ static qboolean XR_PreInit(vrsetup_t *qreqs)
if (qreqs->structsize != sizeof(*qreqs))
return false; //nope, get lost.
if (!strncasecmp(xr_formfactor->string, "none", 4))
qreqs->vrplatform = VR_HEADLESS;
switch(qreqs->vrplatform)
{
/*case VR_HEADLESS:
#ifdef XR_MND_HEADLESS_EXTENSION_NAME
case VR_HEADLESS:
ext = XR_MND_HEADLESS_EXTENSION_NAME;
break;*/
break;
#endif
#ifdef XR_USE_GRAPHICS_API_VULKAN
case VR_VULKAN:
ext = XR_KHR_VULKAN_ENABLE_EXTENSION_NAME;
@ -398,6 +485,10 @@ static qboolean XR_PreInit(vrsetup_t *qreqs)
case VR_EGL:
ext = XR_MND_EGL_ENABLE_EXTENSION_NAME;
break;
#elif defined(XR_MNDX_EGL_ENABLE_EXTENSION_NAME)
case VR_EGL:
ext = XR_MNDX_EGL_ENABLE_EXTENSION_NAME;
break;
#endif
#ifdef XR_USE_PLATFORM_XLIB
case VR_X11_GLX:
@ -414,29 +505,10 @@ static qboolean XR_PreInit(vrsetup_t *qreqs)
break;
#endif
default:
Con_Printf("OpenXR: windowing-api or rendering-api not supported\n");
Con_Printf(CON_ERROR"OpenXR: windowing-api or rendering-api not supported\n");
return false;
}
#ifdef XR_NO_PROTOTYPES
{
static dllhandle_t *lib;
static dllfunction_t funcs[] = {
#define XRFUNC(n) {(void*)&n, #n},
XRFUNCS
#undef XRFUNC
{NULL}};
#define XR_LOADER_LIBNAME "libopenxr_loader"
if (!lib)
lib = plugfuncs->LoadDLL(XR_LOADER_LIBNAME, funcs);
if (!lib)
{
Con_Printf(CON_ERROR"OpenXR: Unable to load "XR_LOADER_LIBNAME"\n");
return false;
}
}
#endif
xr.instance = XR_NULL_HANDLE;
{
unsigned int exts = 0, u=0;
@ -449,10 +521,12 @@ static qboolean XR_PreInit(vrsetup_t *qreqs)
extlist[u].type = XR_TYPE_EXTENSION_PROPERTIES;
xrEnumerateInstanceExtensionProperties(NULL, exts, &exts, extlist);
Con_Printf("OpenXR:");
for (u = 0; u < exts; u++)
Con_Printf(" %s", extlist[u].extensionName);
Con_Printf("\n");
if (xr_debug->ival)
{
Con_Printf("OpenXR:\n");
for (u = 0; u < exts; u++)
Con_Printf("\t%s\n", extlist[u].extensionName);
}
for (u = 0; u < exts; u++)
if (!strcmp(extlist[u].extensionName, ext))
@ -460,10 +534,13 @@ static qboolean XR_PreInit(vrsetup_t *qreqs)
free(extlist);
}
else
Con_DPrintf("OpenXR: xrEnumerateInstanceExtensionProperties failed (%s)\n", XR_StringForResult(res));
{
Con_Printf(CON_ERROR"OpenXR: xrEnumerateInstanceExtensionProperties failed (%s)\n", XR_StringForResult(res));
return false;
}
if (u == exts)
{
Con_Printf("OpenXR: instance driver does not support required %s\n", ext);
Con_Printf(CON_ERROR"OpenXR: instance driver does not support required %s\n", ext);
return false; //would just give an error on xrCreateInstance anyway.
}
}
@ -485,10 +562,11 @@ static qboolean XR_PreInit(vrsetup_t *qreqs)
}
if (XR_FAILED(res) || !xr.instance)
{
Con_Printf("OpenXR Runtime: xrCreateInstance failed (%s)\n", XR_StringForResult(res));
Con_Printf(CON_ERROR"OpenXR Runtime: xrCreateInstance failed (%s)\n", XR_StringForResult(res));
return false;
}
if (xr_debug->ival)
{
XrInstanceProperties props = {XR_TYPE_INSTANCE_PROPERTIES};
if (!XR_FAILED(xrGetInstanceProperties(xr.instance, &props)))
@ -499,7 +577,9 @@ static qboolean XR_PreInit(vrsetup_t *qreqs)
{
XrSystemGetInfo systemInfo = { XR_TYPE_SYSTEM_GET_INFO };
if (!strncasecmp(xr_formfactor->string, "hand", 4))
if (qreqs->vrplatform == VR_HEADLESS)
systemInfo.formFactor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY; //err... woteva
else if (!strncasecmp(xr_formfactor->string, "hand", 4))
systemInfo.formFactor = XR_FORM_FACTOR_HANDHELD_DISPLAY;
else if (!strncasecmp(xr_formfactor->string, "head",4))
systemInfo.formFactor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;
@ -516,6 +596,7 @@ static qboolean XR_PreInit(vrsetup_t *qreqs)
return false;
}
if (xr_debug->ival)
{
XrSystemProperties props = {XR_TYPE_SYSTEM_PROPERTIES};
if (XR_SUCCEEDED(xrGetSystemProperties(xr.instance, xr.systemid, &props)))
@ -705,6 +786,18 @@ static qboolean XR_Init(vrsetup_t *qreqs, rendererstate_t *info)
xr.renderer = QR_OPENGL;
}
break;
#elif defined(XR_MNDX_EGL_ENABLE_EXTENSION_NAME)
case VR_EGL: //x11-egl, wayland, and hopefully android...
{
XrGraphicsBindingEGLMNDX *egl = xr.bindinginfo = calloc(1, sizeof(*egl));
egl->type = XR_TYPE_GRAPHICS_BINDING_EGL_MNDX;
egl->getProcAddress = (PFNEGLGETPROCADDRESSPROC)qreqs->egl.getprocaddr;
egl->display = qreqs->egl.egldisplay;
egl->config = qreqs->egl.eglconfig;
egl->context = qreqs->egl.eglcontext;
xr.renderer = QR_OPENGL;
}
break;
#endif
#ifdef XR_USE_PLATFORM_XLIB
case VR_X11_GLX:
@ -757,7 +850,7 @@ static XrAction XR_DefineAction(XrActionType type, const char *name, const char
int dconflicts = 0;
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].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:""))
{ //looks like a dupe...
return xr.actions[u].action;
}
@ -970,14 +1063,18 @@ static void XR_SetupInputs(void)
//FIXME: set up some proper bindings!
XR_BindProfileStr("khr_simple",
"/interaction_profiles/khr/simple_controller /user/hand/left/ /user/hand/right/\n"
"+select \"Select\" button input/select/click\n"
"togglemenu \"Toggle Menu\" button input/menu/click\n"
"grip_pose \"Grip Pose\" pose input/grip/pose\n"
"aim_pose \"Aim Pose\" pose input/aim/pose\n"
"+attack_left \"Left Attack\" button input/select/click /user/hand/left\n"
"+attack_right \"Right Attack\" button input/select/click /user/hand/right\n"
"+menu_left \"Left Menu\" button input/menu/click /user/hand/left\n"
"+menu_right \"Right Menu\" button input/menu/click /user/hand/right\n"
"left_aim \"Left Aim Pose\" pose input/grip/pose /user/hand/left\n"
"right_aim \"Right Aim Pose\" pose input/grip/pose /user/hand/right\n"
// "grip_pose \"Grip Pose\" pose input/grip/pose\n"
// "aim_pose \"Aim Pose\" pose input/aim/pose\n"
"vibrate \"A Vibrator\" vibration output/haptic\n"
);
XR_BindProfileStr("valve_index",
/* XR_BindProfileStr("valve_index",
"/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/touch\n"
@ -990,18 +1087,40 @@ static void XR_SetupInputs(void)
//"unbound \"Unused Button\" button input/trigger/click\n"
//"unbound \"Unused Button\" float input/trigger/value\n"
//"unbound \"Unused Button\" button input/trigger/touch\n"
//"unbound \"Unused Button\" float input/thumbstick/x\n"
//"unbound \"Unused Button\" float input/thumbstick/y\n"
//"unbound \"Unused Button\" vector2f input/thumbstick\n"
//"unbound \"Unused Button\" button input/thumbstick/click\n"
//"unbound \"Unused Button\" button input/thumbstick/touch\n"
//"unbound \"Unused Button\" float input/trackpad/x\n"
//"unbound \"Unused Button\" float input/trackpad/y\n"
//"unbound \"Unused Button\" vector2f input/trackpad\n"
//"unbound \"Unused Button\" button input/trackpad/force\n"
//"unbound \"Unused Button\" button input/trackpad/touch\n"
//"unbound \"Unused Button\" pose input/grip/pose\n"
//"unbound \"Unused Button\" pose input/aim/pose\n"
//"unbound \"Unused Button\" vibration output/haptic\n"
);
*/
/* XR_BindProfileStr("htc_vive",
"/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/squeeze/click\n"
//"unbound \"Unused Button\" button input/menu/click\n"
//"unbound \"Unused Button\" button input/trigger/click\n"
//"unbound \"Unused Button\" float input/trigger/value\n"
//"unbound \"Unused Button\" vector2f input/trackpad\n"
//"unbound \"Unused Button\" button input/trackpad/click\n"
//"unbound \"Unused Button\" button input/trackpad/touch\n"
//"unbound \"Unused Button\" pose input/grip/pose\n"
//"unbound \"Unused Button\" pose input/aim/pose\n"
//"unbound \"Unused Button\" vibration output/haptic\n"
);
*/
/* XR_BindProfileStr("htc_vive_pro",
"/interaction_profiles/htc/vive_pro /user/head/\n"
//"unbound \"Unused Button\" button input/system/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/mute_mic/click\n"
);
*/
//FIXME: map to quake's keys.
XR_BindProfileStr("gamepad", "/interaction_profiles/microsoft/xbox_controller /user/gamepad/\n"
@ -1068,12 +1187,13 @@ static void XR_SetupInputs(void)
}
#if 1
if (cvarfuncs->GetFloat("developer"))
if (xr_debug->ival)
{
XrInteractionProfileState profile = {XR_TYPE_INTERACTION_PROFILE_STATE};
XrPath path;
unsigned int u;
static const char *paths[] = {"/user/hand/left", "/user/hand/right", "/user/head", "/user/gamepad", "/user/treadmill", "/user/"};
Con_Printf("OpenXR Interaction Profiles:\n");
for (u = 0; u < countof(paths); u++)
{
xrStringToPath(xr.instance, paths[u], &path);
@ -1083,11 +1203,11 @@ static void XR_SetupInputs(void)
char buf[256];
uint32_t len = sizeof(buf);
if (!profile.interactionProfile)
Con_Printf("openxr: %s == no profile/device\n", paths[u]);
Con_Printf("\t%s: "S_COLOR_GRAY"no profile/device\n", paths[u]);
else
{
res = xrPathToString(xr.instance, profile.interactionProfile, sizeof(buf), &len, buf);
Con_Printf("openxr: %s == %s\n", paths[u], buf);
Con_Printf("\t%s: "S_COLOR_GREEN"%s\n", paths[u], buf);
}
}
}
@ -1104,7 +1224,9 @@ static void XR_SetupInputs(void)
if (XR_SUCCEEDED(res))
{
Con_Printf("\t%s:\n", xr.actions[u].actname);
for (i = 0; i < inputs; i++)
if (!inputs)
Con_Printf(S_COLOR_GRAY"\t(unbound)\n");
else for (i = 0; i < inputs; i++)
{
char buffer[8192];
XrInputSourceLocalizedNameGetInfo info = {XR_TYPE_INPUT_SOURCE_LOCALIZED_NAME_GET_INFO};
@ -1115,7 +1237,7 @@ static void XR_SetupInputs(void)
res = xrGetInputSourceLocalizedName(xr.session, &info, sizeof(buffer), &bufsize, buffer);
if (XR_FAILED(res))
Q_snprintf(buffer, sizeof(buffer), "error %i", res);
Con_Printf("\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.
@ -1155,23 +1277,33 @@ static void XR_UpdateInputs(XrTime time)
info.action = xr.actions[h].action;
info.subactionPath = xr.actions[h].path;
xrGetActionStatePose(xr.session, &info, &pose);
res = xrGetActionStatePose(xr.session, &info, &pose);
if (pose.isActive)
{ //its mapped to something, woo.
XrSpaceLocation loc = {XR_TYPE_SPACE_LOCATION};
vec3_t transform[4];
xrLocateSpace(xr.actions[h].space, xr.space, time, &loc);
//if (loc.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT)
//if (loc.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT)
//if (loc.locationFlags & XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT)
//if (loc.locationFlags & XR_SPACE_LOCATION_POSITION_TRACKED_BIT)
XR_PoseToTransform(&loc.pose, transform);
XrSpaceVelocity vel = {XR_TYPE_SPACE_VELOCITY};
XrSpaceLocation loc = {XR_TYPE_SPACE_LOCATION, &vel};
vec3_t transform[4], angles, lvel, avel;
res = xrLocateSpace(xr.actions[h].space, xr.space, time, &loc);
// XR_PoseToTransform(&loc.pose, transform);
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(avel, vel.angularVelocity.x, vel.angularVelocity.y, vel.angularVelocity.z);
if (!inputfuncs->SetHandPosition(xr.actions[h].actname,
(loc.locationFlags&XR_SPACE_LOCATION_POSITION_VALID_BIT)?transform[3]: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_ANGULAR_VALID_BIT)?avel:NULL))
if (transform[3][0] || transform[3][1] || transform[3][2])
{
vec3_t angles;
char cmd[256];
VectorAngles(transform[0], transform[2], angles, false);
Q_snprintf(cmd, sizeof(cmd), "echo %s %g %g %g %g %g %g\n", xr.actions[h].actname, angles[0], angles[1], angles[2], transform[3][0], transform[3][1], transform[3][2]);
Q_snprintf(cmd, sizeof(cmd), "%s %g %g %g %g %g %g %g %g %g %g %g %g\n", xr.actions[h].actname,
angles[0], angles[1], angles[2], transform[3][0], transform[3][1], transform[3][2],
vel.angularVelocity.x, vel.angularVelocity.y, vel.angularVelocity.z, vel.linearVelocity.x, vel.linearVelocity.y, vel.linearVelocity.z);
cmdfuncs->AddText(cmd, false);
}
}
@ -1211,7 +1343,7 @@ static void XR_UpdateInputs(XrTime time)
if (!state.isActive) state.currentState = 0.0f;
{
char cmd[256];
Q_snprintf(cmd, sizeof(cmd), "echo %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);
}
}
@ -1227,7 +1359,7 @@ static void XR_UpdateInputs(XrTime time)
if (!state.isActive) state.currentState.x = state.currentState.y = 0.0f;
{
char cmd[256];
Q_snprintf(cmd, sizeof(cmd), "echo %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);
cmdfuncs->AddText(cmd, false);
}
}
@ -1260,7 +1392,7 @@ static qboolean XR_Begin(void)
{
XrReferenceSpaceCreateInfo info = {XR_TYPE_REFERENCE_SPACE_CREATE_INFO};
info.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_VIEW;
info.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL;
info.poseInReferenceSpace.orientation.w = 1;
res = xrCreateReferenceSpace(xr.session, &info, &xr.space);
if (XR_FAILED(res))
@ -1279,6 +1411,7 @@ static qboolean XR_Begin(void)
for (u = 0; u < swapfmts; u++) switch(fmts[u])
{
case GL_RGBA16F: Con_DPrintf("OpenXr fmt%u: %s\n", u, "GL_RGBA16F"); if (xr.srgb) fmttouse = fmts[u],u=swapfmts; break;
case GL_RGB10_A2: Con_DPrintf("OpenXr fmt%u: %s\n", u, "GL_RGB10_A2"); if (!xr.srgb) fmttouse = fmts[u],u=swapfmts; break;
case GL_RGBA8: Con_DPrintf("OpenXr fmt%u: %s\n", u, "GL_RGBA8"); if (!xr.srgb) fmttouse = fmts[u],u=swapfmts; break;
case GL_SRGB8_ALPHA8_EXT: Con_DPrintf("OpenXr fmt%u: %s\n", u, "GL_SRGB8_ALPHA8");if (xr.srgb) fmttouse = fmts[u],u=swapfmts; break;
default:
@ -1510,22 +1643,34 @@ static qboolean XR_SyncFrame(double *frametime)
if (!xr.instance)
return false;
if (xr.needrender)
{ //something screwed up.
// *frametime = 0;
return true;
}
XR_ProcessEvents();
memset(&xr.framestate, 0, sizeof(xr.framestate));
xr.framestate.type = XR_TYPE_FRAME_STATE;
switch(xr.state)
{
case XR_SESSION_STATE_READY:
case XR_SESSION_STATE_FOCUSED:
case XR_SESSION_STATE_SYNCHRONIZED:
case XR_SESSION_STATE_VISIBLE:
xr.framestate.shouldRender = !!xr.session;
break;
default:
xr.framestate.shouldRender = false;
break;
}
if (xr.framestate.shouldRender)
{
XrTime time;
memset(&xr.framestate, 0, sizeof(xr.framestate));
xr.framestate.type = XR_TYPE_FRAME_STATE;
res = xrWaitFrame(xr.session, NULL, &xr.framestate);
if (XR_FAILED(res))
{
@ -1541,15 +1686,16 @@ static qboolean XR_SyncFrame(double *frametime)
}
xr.time = time;
xr.timeknown = true;
xr.needrender = true;
}
XR_ProcessEvents();
if (xr.session)
XR_UpdateInputs(xr.framestate.predictedDisplayTime);
return true;
}
static qboolean XR_Render(void(*rendereye)(texid_t tex, vec4_t fovoverride, vec3_t axisorg[4]))
static qboolean XR_Render(void(*rendereye)(texid_t tex, vec4_t fovoverride, matrix3x4 axisorg))
{
XrFrameEndInfo endframeinfo = {XR_TYPE_FRAME_END_INFO};
unsigned int u;
@ -1590,21 +1736,33 @@ static qboolean XR_Render(void(*rendereye)(texid_t tex, vec4_t fovoverride, vec3
case XR_SESSION_STATE_FOCUSED:
case XR_SESSION_STATE_SYNCHRONIZED:
case XR_SESSION_STATE_VISIBLE:
case XR_SESSION_STATE_READY:
break;
default:
return false; //not ready.
}
if (!xr.needrender)
return false; //xrWaitFrame not called?
xr.needrender = false;
res = xrBeginFrame(xr.session, NULL);
if (XR_FAILED(res))
{
Con_Printf("xrBeginFrame: %s\n", XR_StringForResult(res));
if(res == XR_ERROR_SESSION_LOST)
XR_SessionEnded();
else
XR_Shutdown();
return false;
}
if (xr.framestate.shouldRender)
{
uint32_t eyecount;
XrViewState viewstate = {XR_TYPE_VIEW_STATE};
XrViewLocateInfo locateinfo = {XR_TYPE_VIEW_LOCATE_INFO};
XrView eyeview[MAX_VIEW_COUNT]={};
vec3_t transform[4];
matrix3x4 transform, eyetransform, inv;
for (u = 0; u < MAX_VIEW_COUNT; u++)
eyeview[u].type = XR_TYPE_VIEW;
@ -1619,6 +1777,36 @@ static qboolean XR_Render(void(*rendereye)(texid_t tex, vec4_t fovoverride, vec3
proj.views = projviews;
endframeinfo.layerCount = 1;
//set up the head position, as an average of all the eyes, the eyes, the awful knowing eyes...
{
float scale;
vec3_t ang, org;
XrPosef apose = {0};
for (u = 0; u < xr.viewcount && u < eyecount; u++)
{ //add em up
apose.orientation.x += eyeview[u].pose.orientation.x;
apose.orientation.y += eyeview[u].pose.orientation.y;
apose.orientation.z += eyeview[u].pose.orientation.z;
apose.orientation.w += eyeview[u].pose.orientation.w;
apose.position.x += eyeview[u].pose.position.x;
apose.position.y += eyeview[u].pose.position.y;
apose.position.z += eyeview[u].pose.position.z;
}
//normalize them
scale = 1 / sqrt(apose.orientation.x*apose.orientation.x+apose.orientation.y*apose.orientation.y+apose.orientation.z*apose.orientation.z+apose.orientation.w*apose.orientation.w);
apose.orientation.x *= scale;
apose.orientation.y *= scale;
apose.orientation.z *= scale;
apose.orientation.w *= scale;
apose.position.x /= xr.viewcount;
apose.position.y /= xr.viewcount;
apose.position.z /= xr.viewcount;
XR_PoseToAngOrg(&apose, ang, org);
Matrix3x4_FromAngles(ang, org, transform[0]);
Matrix3x4_Invert_XR(transform[0], inv[0]);
inputfuncs->SetHandPosition("head", org, ang, NULL, NULL);
}
for (u = 0; u < xr.viewcount && u < eyecount; u++)
{
vec4_t fovoverride;
@ -1634,7 +1822,9 @@ static qboolean XR_Render(void(*rendereye)(texid_t tex, vec4_t fovoverride, vec3
projviews[u].fov = eyeview[u].fov;
projviews[u].subImage = xr.eye[u].subimage;
XR_PoseToTransform(&eyeview[u].pose, transform);
XR_PoseToTransform(&eyeview[u].pose, transform[0]);
Matrix3x4_Multiply_XR(transform[0], inv[0], eyetransform[0]);
fovoverride[0] = eyeview[u].fov.angleLeft * (180/M_PI);
fovoverride[1] = eyeview[u].fov.angleRight * (180/M_PI);
fovoverride[2] = eyeview[u].fov.angleDown * (180/M_PI);
@ -1644,7 +1834,7 @@ static qboolean XR_Render(void(*rendereye)(texid_t tex, vec4_t fovoverride, vec3
res = xrWaitSwapchainImage(xr.eye[u].swapchain, &waitinfo);
if (XR_FAILED(res))
Con_Printf("xrWaitSwapchainImage: %s\n", XR_StringForResult(res));
rendereye(&xr.eye[u].swapimages[imgidx], fovoverride, transform);
rendereye(&xr.eye[u].swapimages[imgidx], fovoverride, eyetransform);
//GL note: the OpenXR specification says NOTHING about the application having to glFlush or glFinish.
// I take this to mean that the openxr runtime is responsible for setting up barriers or w/e inside ReleaseSwapchainImage.
//VK note: the OpenXR spec does say that it needs to be color_attachment_optimal+owned by queue. which it is.
@ -1684,11 +1874,36 @@ static plugvrfuncs_t openxr =
qboolean Plug_Init(void)
{
#ifdef XR_NO_PROTOTYPES
{
static dllhandle_t *lib;
static dllfunction_t funcs[] = {
#define XRFUNC(n) {(void*)&n, #n},
XRFUNCS
#undef XRFUNC
{NULL}};
#ifdef _WIN32
#define XR_LOADER_LIBNAME "openxr_loader"
#else
#define XR_LOADER_LIBNAME "libopenxr_loader"
#endif
if (!lib)
lib = plugfuncs->LoadDLL(XR_LOADER_LIBNAME, funcs);
if (!lib)
{
Con_Printf(CON_ERROR"OpenXR: Unable to load "XR_LOADER_LIBNAME ARCH_DL_POSTFIX"\n");
return false;
}
}
#endif
fsfuncs = plugfuncs->GetEngineInterface(plugfsfuncs_name, sizeof(*fsfuncs));
inputfuncs = plugfuncs->GetEngineInterface(pluginputfuncs_name, sizeof(*inputfuncs));
plugfuncs->ExportFunction("MayUnload", XR_PluginMayUnload);
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_debug = cvarfuncs->GetNVFDG("xr_debug", "0", 0, "Controls whether to spam debug info or not.", "OpenXR configuration");
xr_formfactor = cvarfuncs->GetNVFDG("xr_formfactor", "head", CVAR_ARCHIVE, "Controls which VR system to try to use. Valid options are head, or hand", "OpenXR configuration");
xr_viewconfig = cvarfuncs->GetNVFDG("xr_viewconfig", "", CVAR_ARCHIVE, "Controls the type of view we aim for. Valid options are mono, stereo, or quad", "OpenXR configuration");
xr_metresize = cvarfuncs->GetNVFDG("xr_metresize", "26.24671916", CVAR_ARCHIVE, "Size of a metre in game units", "OpenXR configuration");

View file

@ -284,6 +284,7 @@ typedef struct //for menu-like stuff
F(const char*,GetKeyBind, (int bindmap, int keynum, int modifier));
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.
#define pluginputfuncs_name "Input"
} pluginputfuncs_t;

View file

@ -434,6 +434,7 @@ static void QI_AddPackages(xmltree_t *qifile)
const char *id;
char extra[1024];
char clean[512];
const char *hash;
unsigned int i;
xmltree_t *tech;
@ -488,6 +489,10 @@ static void QI_AddPackages(xmltree_t *qifile)
}
}
hash = XML_GetChildBody(qifile, "md5hash", "");
if (strchr(hash, '\\') || strchr(hash, '\"')) //if it has a dodgy escape-breaking char then drop it.
hash = "";
id = XML_GetParameter(qifile, "id", "unknown");
if (strchr(clean, '\\') || strchr(clean, '\"') || strchr(clean, '\n') || strchr(clean, ';'))
return;
@ -495,7 +500,7 @@ static void QI_AddPackages(xmltree_t *qifile)
return;
Q_snprintf(extra, sizeof(extra), " package \""FILEDOWNLOADURL"\" prefix \"%s\"", id, clean);
Q_snprintf(extra, sizeof(extra), " package \""FILEDOWNLOADURL"\" prefix \"%s\" hash \"md5:%s\"", id, clean, hash);
cmdfuncs->AddText(extra, false);
}
static void QI_RunMap(xmltree_t *qifile, const char *map)