diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index f2c56d408..b63261b9f 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -49,7 +49,8 @@ static cvar_t cl_sendchatstate = CVARD("cl_sendchatstate", "1", "Announce your c cvar_t cl_prydoncursor = CVAR("cl_prydoncursor", ""); //for dp protocol cvar_t cl_instantrotate = CVARF("cl_instantrotate", "1", CVAR_SEMICHEAT); -cvar_t in_xflip = {"in_xflip", "0"}; +cvar_t in_xflip = CVAR("in_xflip", "0"); +cvar_t in_vraim = CVARD("in_vraim", "1", "When set to 1, the 'view' angle sent to the server is controlled by your vr headset instead of separately. This is for fallback behaviour and blocks mouse+joy+gamepad aiming."); cvar_t prox_inmenu = CVAR("prox_inmenu", "0"); @@ -915,7 +916,7 @@ void CL_BaseMove (usercmd_t *cmd, int pnum, float priortime, float extratime) float nscale = extratime?extratime / (extratime+priortime):0; float oscale = 1 - nscale; - cmd->fservertime = cl.time*1000; + cmd->fservertime = cl.time; cmd->servertime = cl.time*1000; // @@ -940,7 +941,7 @@ void CL_BaseMove (usercmd_t *cmd, int pnum, float priortime, float extratime) CL_GatherButtons(cmd, pnum); } -static void CL_ClampPitch (int pnum, float frametime) +void CL_ClampPitch (int pnum, float frametime) { float mat[16]; float roll; @@ -1097,6 +1098,30 @@ static void CL_ClampPitch (int pnum, float frametime) pv->viewangles[YAW] *= 360; VectorClear(pv->viewanglechange); + if (in_vraim.ival && (pv->vrdev[VRDEV_HEAD].status&VRSTATUS_ANG)) + { //overcomplicated code to replace the pitch+roll angles and add to the yaw angle. +#if 0 + matrix3x4 base, head, res; + vec3_t na = {0, pv->viewangles[YAW], 0}; + vec3_t f,l,u,o; + Matrix3x4_RM_FromAngles(na, vec3_origin, base[0]); + for (i=0 ; i<3 ; i++) + na[i] = SHORT2ANGLE(pv->vrdev[VRDEV_HEAD].angles[i]); + Matrix3x4_RM_FromAngles(na, pv->vrdev[VRDEV_HEAD].origin, head[0]); + Matrix3x4_Multiply(head[0], base[0], res[0]); + Matrix3x4_RM_ToVectors(res[0], f,l,u,o); + VectorAngles(f,u,pv->aimangles,false); + for (i=0 ; i<3 ; i++) + cmd->angles[i] = ANGLE2SHORT(na[i]); +#else + pv->aimangles[PITCH] = SHORT2ANGLE(pv->vrdev[VRDEV_HEAD].angles[PITCH]); + pv->aimangles[YAW] = SHORT2ANGLE(pv->vrdev[VRDEV_HEAD].angles[YAW]) + pv->viewangles[YAW]; + pv->aimangles[ROLL] = SHORT2ANGLE(pv->vrdev[VRDEV_HEAD].angles[ROLL]); +#endif + } + else + VectorCopy(pv->viewangles, pv->aimangles); + #ifdef Q2CLIENT if (cls.protocol == CP_QUAKE2) { @@ -1129,6 +1154,11 @@ static void CL_ClampPitch (int pnum, float frametime) pv->viewangles[PITCH] = cl.maxpitch; if (pv->viewangles[PITCH] < cl.minpitch) pv->viewangles[PITCH] = cl.minpitch; + + if (pv->aimangles[PITCH] > cl.maxpitch) + pv->aimangles[PITCH] = cl.maxpitch; + if (pv->aimangles[PITCH] < cl.minpitch) + pv->aimangles[PITCH] = cl.minpitch; } // if (cl.viewangles[pnum][ROLL] > 50) @@ -1169,7 +1199,10 @@ static void CL_FinishMove (usercmd_t *cmd, int pnum) CL_GatherButtons(cmd, pnum); for (i=0 ; i<3 ; i++) - cmd->angles[i] = ((int)(cl.playerview[pnum].viewangles[i]*65536.0/360)&65535); + cmd->angles[i] = (int)(ANGLE2SHORT(cl.playerview[pnum].aimangles[i]))&65535; + cmd->vr[VRDEV_LEFT] = cl.playerview[pnum].vrdev[VRDEV_LEFT]; + cmd->vr[VRDEV_RIGHT] = cl.playerview[pnum].vrdev[VRDEV_RIGHT]; + cmd->vr[VRDEV_HEAD] = cl.playerview[pnum].vrdev[VRDEV_HEAD]; if (in_impulsespending[pnum] && !cl.paused) { @@ -2559,6 +2592,7 @@ void CL_InitInput (void) Cvar_Register (&cl_fastaccel, inputnetworkcvargroup); Cvar_Register (&in_xflip, inputnetworkcvargroup); + Cvar_Register (&in_vraim, inputnetworkcvargroup); Cvar_Register (&cl_nodelta, inputnetworkcvargroup); Cvar_Register (&prox_inmenu, inputnetworkcvargroup); diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index bdbcd4dd1..f8f9aca1c 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -5978,55 +5978,6 @@ qboolean Host_RunFile(const char *fname, int nlen, vfsfile_t *file) return true; } -void CL_UpdateHeadAngles(void) -{ -/*FIXME: no idea what I'm doing with this. lets just not break anything for now - //identity, for now - vec3_t headchange[3] = - { - {1,0,0}, - {0,1,0}, - {0,0,1} - }; - vec3_t tmp[3], tmp2[3]; - playerview_t *pv = &cl.playerview[0]; - - tmp2[0][0] = 0; - tmp2[0][1] = host_frametime*90; - tmp2[0][2] = 0; - AngleVectorsFLU(tmp2[0], headchange[0], headchange[1], headchange[2]); - - switch(cl_headmode.ival) - { - case 3: //head angles change both - R_ConcatRotations(headchange, r_refdef.headaxis, tmp); - break; - case 2: //head changes are entirely relative to the 'view' angle - R_ConcatRotations(headchange, r_refdef.headaxis, tmp); - memcpy(r_refdef.headaxis, tmp, sizeof(r_refdef.headaxis)); - break; - case 1: //head changes change the view angle directly. - - AngleVectorsFLU(pv->viewangles, tmp[0], tmp[1], tmp[2]); - R_ConcatRotations(headchange, tmp, tmp2); - VectorAngles(tmp2[0], tmp2[2], pv->viewangles); - pv->viewangles[0] *= r_meshpitch.value; - pv->viewangles[2] *= r_meshroll.value; - - //fall through - default: - case 0: //off - VectorSet(r_refdef.headaxis[0], 1, 0, 0); - VectorSet(r_refdef.headaxis[1], 0, 1, 0); - VectorSet(r_refdef.headaxis[2], 0, 0, 1); - break; - } - */ - VectorSet(r_refdef.headaxis[0], 1, 0, 0); - VectorSet(r_refdef.headaxis[1], 0, 1, 0); - VectorSet(r_refdef.headaxis[2], 0, 0, 1); -} - /* ================== Host_Frame @@ -6363,8 +6314,6 @@ double Host_Frame (double time) if (emscriptenfte_getvrframedata()) r_refdef.stereomethod = STEREO_WEBVR; #endif - CL_UpdateHeadAngles(); - { RSpeedMark(); vid.ime_allow = false; diff --git a/engine/client/cl_pred.c b/engine/client/cl_pred.c index 84e8dfb91..7c03b513a 100644 --- a/engine/client/cl_pred.c +++ b/engine/client/cl_pred.c @@ -1036,7 +1036,7 @@ void CL_PredictMovePNum (int seat) else { lerpangles = (cls.demoplayback == DPB_QUAKEWORLD); - VectorCopy (pv->viewangles, pv->simangles); + VectorCopy (pv->aimangles, pv->simangles); } } diff --git a/engine/client/client.h b/engine/client/client.h index a37c23206..3861e1f37 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -661,6 +661,7 @@ struct playerview_s // the client maintains its own idea of view angles, which are // sent to the server each frame. And only reset at level change // and teleport times + vec3_t aimangles; //angles actually being sent to the server (different due to in_vraim) vec3_t viewangles; //current angles vec3_t viewanglechange; //angles set by input code this frame vec3_t intermissionangles; //absolute angles for intermission @@ -773,6 +774,8 @@ struct playerview_s size_t reverbtype; vec3_t velocity; } audio; + + struct vrdevinfo_s vrdev[VRDEV_COUNT]; }; // diff --git a/engine/client/in_generic.c b/engine/client/in_generic.c index 7ee632112..53791945b 100644 --- a/engine/client/in_generic.c +++ b/engine/client/in_generic.c @@ -1092,6 +1092,7 @@ qboolean IN_SetHandPosition(const char *devname, vec3_t org, vec3_t ang, vec3_t { int dtype; int seat; + struct vrdevinfo_s *dev; if (!strncmp(devname, "left", 4)) { seat = atoi(devname+4); @@ -1111,23 +1112,35 @@ qboolean IN_SetHandPosition(const char *devname, vec3_t org, vec3_t ang, vec3_t return false; //no idea what you're talking about. if (seat < 0 || seat >= MAX_SPLITS) return false; //duuuude! - cl_pendingcmd[seat].vr[dtype].status = + dev = &cl.playerview[seat].vrdev[dtype]; + + if (org) + VectorCopy(org, dev->origin); + else + VectorClear(dev->origin); + if (ang) + { + dev->angles[0] = ANGLE2SHORT(ang[0]), + dev->angles[1] = ANGLE2SHORT(ang[1]), + dev->angles[2] = ANGLE2SHORT(ang[2]); + } + else + VectorClear(dev->angles); + if (vel) + VectorCopy(vel, dev->velocity); + else + VectorClear(dev->velocity); + if (avel) + dev->avelocity[0] = ANGLE2SHORT(avel[0]), + dev->avelocity[1] = ANGLE2SHORT(avel[1]), + dev->avelocity[2] = ANGLE2SHORT(avel[2]); + else + VectorClear(dev->avelocity); + + dev->status = (org ?VRSTATUS_ORG:0)| (ang ?VRSTATUS_ANG:0)| (vel ?VRSTATUS_VEL:0)| (avel?VRSTATUS_AVEL:0); - - if (org) - VectorCopy(org, cl_pendingcmd[seat].vr[dtype].origin); - if (ang) - cl_pendingcmd[seat].vr[dtype].angles[0] = ANGLE2SHORT(ang[0]), - cl_pendingcmd[seat].vr[dtype].angles[1] = ANGLE2SHORT(ang[1]), - cl_pendingcmd[seat].vr[dtype].angles[2] = ANGLE2SHORT(ang[2]); - if (vel) - VectorCopy(vel, cl_pendingcmd[seat].vr[dtype].velocity); - if (avel) - cl_pendingcmd[seat].vr[dtype].avelocity[0] = ANGLE2SHORT(avel[0]), - cl_pendingcmd[seat].vr[dtype].avelocity[1] = ANGLE2SHORT(avel[1]), - cl_pendingcmd[seat].vr[dtype].avelocity[2] = ANGLE2SHORT(avel[2]); return true; } diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index b2d1da442..4401741df 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -90,6 +90,7 @@ cvar_t pr_csqc_formenus = CVAR("pr_csqc_formenus", "0"); #endif static cvar_t dpcompat_csqcinputeventtypes = CVARD("dpcompat_csqcinputeventtypes", "999999", "Specifies the first csqc input event that the mod does not recognise. This should never have been a thing, but some mods are simply too buggy."); extern cvar_t dpcompat_stats; +extern cvar_t in_vraim; // standard effect cvars/sounds extern cvar_t r_explosionlight; @@ -2244,6 +2245,12 @@ nogameaccess: *r = r_refdef.viewangles[parametertype-VF_ANGLES_X]; break; + case VF_VRBASEORIENTATION: + if (csqc_nogameaccess && prinst == csqc_world.progs) + goto nogameaccess; + VectorCopy(r_refdef.base_angles, r); + break; + case VF_CL_VIEWANGLES_V: if (csqc_nogameaccess && prinst == csqc_world.progs) goto nogameaccess; @@ -2510,6 +2517,13 @@ void QCBUILTIN PF_R_SetViewFlag(pubprogfuncs_t *prinst, struct globalvars_s *pr_ r_refdef.viewangles[parametertype-VF_ANGLES_X] = *p; break; + case VF_VRBASEORIENTATION: + in_vraim.ival = 0; //csqc mod with explicit vr stuff. + r_refdef.base_known = true; + VectorCopy(p, r_refdef.base_angles); + VectorCopy(G_VECTOR(OFS_PARM2), r_refdef.base_origin); + break; + case VF_CL_VIEWANGLES_V: if (csqc_playerview) VectorCopy(p, csqc_playerview->viewangles); @@ -3823,7 +3837,7 @@ static void cs_set_input_state (usercmd_t *cmd) if (csqcg.input_servertime) *csqcg.input_servertime = cmd->fservertime; if (csqcg.input_clienttime) - *csqcg.input_clienttime = cmd->fclienttime/1000.0f; + *csqcg.input_clienttime = cmd->fclienttime; if (csqcg.input_cursor_screen) { @@ -3922,7 +3936,10 @@ static void cs_get_input_state (usercmd_t *cmd) if (csqcg.input_weapon) cmd->weapon = *csqcg.input_weapon; if (csqcg.input_servertime) + { cmd->fservertime = *csqcg.input_servertime; + cmd->servertime = *csqcg.input_servertime*1000; + } if (csqcg.input_cursor_screen) Vector2Copy(csqcg.input_cursor_screen, cmd->cursor_screen); @@ -4064,6 +4081,11 @@ static void QCBUILTIN PF_cs_getinputstate (pubprogfuncs_t *prinst, struct global if (!cmd->msec) *cmd = cl.outframes[(f-1)&UPDATE_MASK].cmd[seat]; cmd->msec = (realtime - cl.outframes[(f-1)&UPDATE_MASK].senttime)*1000; + + //make sure we have the latest info... + cmd->vr[VRDEV_LEFT] = csqc_playerview->vrdev[VRDEV_LEFT]; + cmd->vr[VRDEV_RIGHT] = csqc_playerview->vrdev[VRDEV_RIGHT]; + cmd->vr[VRDEV_HEAD] = csqc_playerview->vrdev[VRDEV_HEAD]; } else { @@ -7752,6 +7774,8 @@ void CSQC_Shutdown(void) memset(&csqc_world, 0, sizeof(csqc_world)); memset(&csqcg, 0, sizeof(csqcg)); + in_vraim.ival = in_vraim.value; //csqc mod with explicit vr stuff. + if (csqc_deprecated_warned>1) { if (!cl_csqc_nodeprecate.ival) diff --git a/engine/client/render.h b/engine/client/render.h index e286e22e1..bfb189774 100644 --- a/engine/client/render.h +++ b/engine/client/render.h @@ -260,10 +260,12 @@ typedef struct vec3_t vieworg; /*logical view center*/ vec3_t viewangles; vec3_t viewaxis[3]; /*forward, left, up (NOT RIGHT)*/ - vec3_t headaxis[3]; /*this is for head mounted displays. this is relative to the view*/ vec3_t eyeoffset; /*world space, for vr screenies*/ vec2_t projectionoffset; /*for off-centre rendering*/ + qboolean base_known; /*otherwise we do some fallback behaviour (ie: viewangles.0y0 and forcing input_angles)*/ + vec3_t base_angles, base_origin; /*for vr output, overrides per-eye viewangles according to that eye's matrix.*/ + float fov_x, fov_y, afov; float fovv_x, fovv_y; //viewmodel fovs float mindist, maxdist; //maxdist may be 0, for 'infinite', in which case mindist probably isn't valid either. diff --git a/engine/client/view.c b/engine/client/view.c index dfc87ccc9..2c150c3c8 100644 --- a/engine/client/view.c +++ b/engine/client/view.c @@ -326,7 +326,11 @@ void V_DriftPitch (playerview_t *pv) return; } +#ifdef QUAKESTATS + delta = pv->statsf[STAT_IDEALPITCH] - pv->viewangles[PITCH]; +#else delta = 0 - pv->viewangles[PITCH]; +#endif if (!delta) { diff --git a/engine/client/vr.h b/engine/client/vr.h index 6084a9e37..a0b6a5fd9 100644 --- a/engine/client/vr.h +++ b/engine/client/vr.h @@ -74,7 +74,7 @@ typedef struct plugvrfuncs_s qboolean (*Prepare) (vrsetup_t *setupinfo); //called before graphics context init qboolean (*Init) (vrsetup_t *setupinfo, rendererstate_t *info); //called after graphics context init qboolean (*SyncFrame)(double *frametime); //called in the client's main loop, to block/tweak frame times. True means the game should render as fast as possible. - qboolean (*Render) (void(*rendereye)(texid_t tex, vec4_t fovoverride, matrix3x4 axisorg)); + qboolean (*Render) (void(*rendereye)(texid_t tex, vec4_t fovoverride, vec3_t angorg[2])); void (*Shutdown) (void); #define plugvrfuncs_name "VR" } plugvrfuncs_t; diff --git a/engine/client/wad.c b/engine/client/wad.c index d096ce189..54e97d814 100644 --- a/engine/client/wad.c +++ b/engine/client/wad.c @@ -245,10 +245,10 @@ typedef struct int position; int size; } texwadlump_t; -int numwadtextures; +static int numwadtextures; static texwadlump_t texwadlump[TEXWAD_MAXIMAGES]; -wadfile_t *openwadfiles; +static wadfile_t *openwadfiles; void Wads_Flush (void) { diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index 7c143d8c1..224e65739 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -772,6 +772,39 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define fte_alignof(type) sizeof(qintptr_t) #endif +//WARNING: FTE_CONSTRUCTOR things are unordered. +#ifdef __cplusplus + //use standard constructors in any c++ code... + #define FTE_CONSTRUCTOR(fn) \ + static void fn(void); \ + class atinit_##fn {atinit_##fn(void){fn();}}; \ + static void fn(void) +#elif _MSC_VER + #pragma section(".CRT$XCU",read) + #if _MSC_VER >= 1500 //use '/include' so it doesn't get stripped from linker optimisations + #define INITIALIZER2_(f,p) \ + static void f(void); \ + __declspec(allocate(".CRT$XCU")) void (*f##_)(void) = f; \ + __pragma(comment(linker,"/include:" p #f "_")) \ + static void f(void) + #else // '/include' doesn't exist, hope there's no linker optimisations. + #define INITIALIZER2_(f,p) \ + static void f(void); \ + __declspec(allocate(".CRT$XCU")) void (*f##_)(void) = f; \ + static void f(void) + #endif + #ifdef _WIN64 + #define INITIALIZER(f) INITIALIZER2_(f,"") + #else + #define INITIALIZER(f) INITIALIZER2_(f,"_") + #endif +#else + //assume gcc/clang... + #define FTE_CONSTRUCTOR(fn) \ + __attribute__((constructor)) static void fn(void) +#endif + + //safeswitch(foo){safedefault: break;} //switch, but errors for any omitted enum values despite the presence of a default case. //(gcc will generally give warnings without the default, but sometimes you don't have control over the source of your enumeration values) diff --git a/engine/common/bspfile.h b/engine/common/bspfile.h index 907722c6d..7d50268c7 100644 --- a/engine/common/bspfile.h +++ b/engine/common/bspfile.h @@ -500,7 +500,7 @@ typedef struct #define FTECONTENTS_EMPTY 0x00000000 #define FTECONTENTS_SOLID 0x00000001 -//q2window 0x00000002 +#define FTECONTENTS_WINDOW 0x00000002 //solid to bullets, but not sight/agro //q2aux 0x00000004 #define FTECONTENTS_LAVA 0x00000008 #define FTECONTENTS_SLIME 0x00000010 @@ -656,8 +656,8 @@ typedef struct // content masks. Allow q2contents_window in here //#define MASK_ALL (-1) -#define MASK_WORLDSOLID (FTECONTENTS_SOLID|Q2CONTENTS_WINDOW) /*default trace type for something simple that ignores non-bsp stuff*/ -#define MASK_POINTSOLID (FTECONTENTS_SOLID|Q2CONTENTS_WINDOW|FTECONTENTS_BODY) /*default trace type for an entity of no size*/ +#define MASK_WORLDSOLID (FTECONTENTS_SOLID|FTECONTENTS_WINDOW) /*default trace type for something simple that ignores non-bsp stuff*/ +#define MASK_POINTSOLID (FTECONTENTS_SOLID|FTECONTENTS_WINDOW|FTECONTENTS_BODY) /*default trace type for an entity of no size*/ #define MASK_BOXSOLID (FTECONTENTS_SOLID|FTECONTENTS_PLAYERCLIP|Q2CONTENTS_WINDOW|FTECONTENTS_BODY) /*default trace type for an entity that does have size*/ #define MASK_PLAYERSOLID MASK_BOXSOLID //#define MASK_DEADSOLID (Q2CONTENTS_SOLID|Q2CONTENTS_PLAYERCLIP|Q2CONTENTS_WINDOW) diff --git a/engine/common/pr_common.h b/engine/common/pr_common.h index d2998bbcb..e2966e199 100644 --- a/engine/common/pr_common.h +++ b/engine/common/pr_common.h @@ -787,12 +787,12 @@ typedef enum VF_SKYROOM_CAMERA = 222, VF_PIXELPSCALE = 223, //[dpi_x, dpi_y, dpi_y/dpi_x] VF_PROJECTIONOFFSET = 224, //allows for off-axis projections. + VF_VRBASEORIENTATION= 225, //specifies the worldspace coords+angles of the VR room space. //WARNING: update fteqcc when new entries are added. VF_DP_CLEARSCREEN = 201, //misnomer - NOTOVERLAY would be a better name. when set to false prevents any and all post-proc things that might write colour values in areas with no geometry there. -//fuck DP and their complete lack of respect for existing implemenetations - VF_DP_FOG_DENSITY = 202, //misassigned + VF_DP_FOG_DENSITY = 202, //misassigned - fuck DP and their complete lack of respect for existing implemenetations VF_DP_FOG_COLOR = 203, //misassigned VF_DP_FOG_COLOR_R = 204, //misassigned VF_DP_FOG_COLOR_G = 205, //misassigned @@ -802,7 +802,7 @@ typedef enum VF_DP_FOG_END = 209, //misassigned VF_DP_FOG_HEIGHT = 210, //misassigned VF_DP_FOG_FADEDEPTH = 211, //misassigned - VF_DP_MAINVIEW = 400, // defective. should be a viewid instead, allowing for per-view motionblur instead of disabling it outright + VF_DP_MAINVIEW = 400, // defective. should have been a 1-based viewid instead, allowing for per-view motionblur instead of disabling it outright VF_DP_MINFPS_QUALITY = 401, //multiplier for lod and culling to try to reduce costs. } viewflags; diff --git a/engine/common/protocol.h b/engine/common/protocol.h index 33e17a341..0bf5eb40b 100644 --- a/engine/common/protocol.h +++ b/engine/common/protocol.h @@ -1189,6 +1189,22 @@ typedef struct size_t bonedatamax; } packet_entities_t; +struct vrdevinfo_s +{ + unsigned int status; +#define VRSTATUS_ORG (1u<<0) +#define VRSTATUS_ANG (1u<<1) +#define VRSTATUS_VEL (1u<<2) +#define VRSTATUS_AVEL (1u<<3) + short angles[3]; + short avelocity[3]; + vec3_t origin; + vec3_t velocity; +#define VRDEV_LEFT 0 +#define VRDEV_RIGHT 1 +#define VRDEV_HEAD 2 +#define VRDEV_COUNT 3 +}; typedef struct usercmd_s { //the first members of this structure MUST match the q2 version @@ -1214,21 +1230,7 @@ typedef struct usercmd_s unsigned int cursor_entitynumber; //vr things - struct - { - unsigned int status; -#define VRSTATUS_ORG (1u<<0) -#define VRSTATUS_ANG (1u<<1) -#define VRSTATUS_VEL (1u<<2) -#define VRSTATUS_AVEL (1u<<3) - short angles[3]; - short avelocity[3]; - vec3_t origin; - vec3_t velocity; -#define VRDEV_LEFT 0 -#define VRDEV_RIGHT 1 -#define VRDEV_HEAD 2 - } vr[3]; //left, right, head. + struct vrdevinfo_s vr[VRDEV_COUNT]; //left, right, head. } usercmd_t; typedef struct q2usercmd_s diff --git a/engine/common/zone.h b/engine/common/zone.h index 528a19f78..c17b0e131 100644 --- a/engine/common/zone.h +++ b/engine/common/zone.h @@ -88,6 +88,7 @@ Zone block #else #define VALGRIND_MAKE_MEM_UNDEFINED(ptr,sz) //as an alternative to memzero.. #define VALGRIND_MAKE_MEM_NOACCESS(ptr,sz) + #define VALGRIND_MAKE_MEM_DEFINED_IF_ADDRESSABLE(ptr,sz) //undo VALGRIND_MAKE_MEM_UNDEFINED, to make sure we don't read past the end of buffers. #endif void Memory_Init (void); diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c index 26e8b7dfd..1a87cdd40 100644 --- a/engine/gl/gl_rmain.c +++ b/engine/gl/gl_rmain.c @@ -435,7 +435,7 @@ void R_RotateForEntity (float *m, float *modelview, const entity_t *e, const mod R_SetupGL ============= */ -static void R_SetupGL (matrix3x4 eyematrix, vec4_t fovoverrides, float projmatrix[16]/*for webvr*/, texid_t fbo) +static void R_SetupGL (vec3_t eyeangorg[2], vec4_t fovoverrides, float projmatrix[16]/*for webvr*/, texid_t fbo) { int x, x2, y2, y, w, h; vec3_t newa; @@ -450,14 +450,32 @@ static void R_SetupGL (matrix3x4 eyematrix, vec4_t fovoverrides, float projmatri newa[0] = r_refdef.viewangles[0]; newa[1] = r_refdef.viewangles[1]; newa[2] = r_refdef.viewangles[2] + gl_screenangle.value; - if (eyematrix) + if (eyeangorg) { - matrix3x4 headmatrix; + extern cvar_t in_vraim; + matrix3x4 basematrix; + matrix3x4 eyematrix; matrix3x4 viewmatrix; - Matrix3x4_RM_FromAngles(newa, r_refdef.vieworg, headmatrix[0]); - Matrix3x4_Multiply(headmatrix[0], eyematrix[0], viewmatrix[0]); - Matrix3x4_RM_ToVectors(viewmatrix[0], vpn, vright, vup, r_origin); - VectorNegate(vright, vright); + + Matrix3x4_RM_FromAngles(eyeangorg[0], eyeangorg[1], eyematrix[0]); + if (r_refdef.base_known) + { //mod is specifying its own base ang+org. + Matrix3x4_RM_FromAngles(r_refdef.base_angles, r_refdef.base_origin, basematrix[0]); + Matrix3x4_Multiply(eyematrix[0], basematrix[0], viewmatrix[0]); + Matrix3x4_RM_ToVectors(viewmatrix[0], vpn, vright, vup, r_origin); + VectorNegate(vright, vright); + } + else + { //mod provides no info. + //client will fiddle with input_angles + newa[0] = newa[2] = 0; //ignore player pitch+roll. sorry. apply the eye's transform on top. + if (in_vraim.ival) + newa[1] -= SHORT2ANGLE(r_refdef.playerview->vrdev[VRDEV_HEAD].angles[YAW]); + Matrix3x4_RM_FromAngles(newa, r_refdef.vieworg, basematrix[0]); + Matrix3x4_Multiply(eyematrix[0], basematrix[0], viewmatrix[0]); + Matrix3x4_RM_ToVectors(viewmatrix[0], vpn, vright, vup, r_origin); + VectorNegate(vright, vright); + } } else { @@ -717,7 +735,7 @@ static void R_RenderScene_Internal(void) depthcleared = false; //whatever is in the depth buffer is no longer useful. } -static void R_RenderEyeScene (texid_t rendertarget, vec4_t fovoverride, matrix3x4 eyematrix) +static void R_RenderEyeScene (texid_t rendertarget, vec4_t fovoverride, vec3_t eyeangorg[2]) { extern qboolean depthcleared; refdef_t refdef = r_refdef; @@ -725,6 +743,11 @@ static void R_RenderEyeScene (texid_t rendertarget, vec4_t fovoverride, matrix3x int ph = vid.fbpheight; int r = 0; + extern void CL_ClampPitch (int pnum, float frametime); +/*the vr code tends to be somewhat laggy with its head angles, leaving it to the last minute, so redo this to reduce latency*/ + if ((size_t)(refdef.playerview-cl.playerview) < MAX_SPLITS) + CL_ClampPitch (refdef.playerview-cl.playerview, 0); + if (rendertarget) { r = GLBE_FBO_Update(&fbo_vr, FBO_RB_DEPTH, &rendertarget, 1, r_nulltex, rendertarget->width, rendertarget->height, 0); @@ -735,10 +758,10 @@ static void R_RenderEyeScene (texid_t rendertarget, vec4_t fovoverride, matrix3x vid.fbpheight = rendertarget->height; } - R_SetupGL (eyematrix, fovoverride, NULL, rendertarget); + R_SetupGL (eyeangorg, fovoverride, NULL, rendertarget); R_RenderScene_Internal(); - //if (eyematrix) + /*//if (eyematrix) { vec3_t newa, newo; matrix3x4 headmatrix; //position of the head in local space @@ -774,7 +797,7 @@ static void R_RenderEyeScene (texid_t rendertarget, vec4_t fovoverride, matrix3x if (R2D_Flush) R2D_Flush(); GL_SetShaderState2D(false); - } + }*/ if (rendertarget) { @@ -795,8 +818,7 @@ static void R_RenderScene (void) int i; int cull = r_refdef.flipcull; unsigned int colourmask = r_refdef.colourmask; - vec3_t ang, org; - matrix3x4 eyematrix; + vec3_t eyeangorg[2]; extern qboolean depthcleared; r_refdef.colourmask = 0u; @@ -914,12 +936,11 @@ static void R_RenderScene (void) } r_framecount++; //view position changes, if only slightly. which means we need to rebuild vis info. :( - ang[0] = 0; - ang[1] = r_stereo_convergence.value * (i?0.5:-0.5); - ang[2] = 0; - VectorSet(org, 0, stereooffset[i], 0); - Matrix3x4_RM_FromAngles(ang, org, eyematrix[0]); - R_SetupGL (eyematrix, NULL, NULL, NULL); + eyeangorg[0][0] = 0; + eyeangorg[0][1] = r_stereo_convergence.value * (i?0.5:-0.5); + eyeangorg[0][2] = 0; + VectorSet(eyeangorg[1], 0, stereooffset[i], 0); + R_SetupGL (eyeangorg, NULL, NULL, NULL); R_RenderScene_Internal (); } diff --git a/engine/gl/gl_shadow.c b/engine/gl/gl_shadow.c index a8dcdfd65..e8c7afbbc 100644 --- a/engine/gl/gl_shadow.c +++ b/engine/gl/gl_shadow.c @@ -58,7 +58,7 @@ cvar_t r_shadow_realtime_world = CVARFD ("r_shadow_realtime_world", "0", CVAR cvar_t r_shadow_realtime_world_shadows = CVARF ("r_shadow_realtime_world_shadows", "1", CVAR_ARCHIVE); cvar_t r_shadow_realtime_world_lightmaps = CVARFD ("r_shadow_realtime_world_lightmaps", "0", 0, "Specifies how much of the map's normal lightmap to retain when using world realtime lights. 0 completely replaces lighting."); cvar_t r_shadow_realtime_world_importlightentitiesfrommap = CVARFD ("r_shadow_realtime_world_importlightentitiesfrommap", "0", CVAR_ARCHIVE, "Controls default loading of map-based realtime lights.\n0: Load explicit .rtlight files only.\n1: Load explicit lights then try fallback to parsing the entities lump.\n2: Load only the entities lump."); -cvar_t r_shadow_realtime_dlight = CVARFD ("r_shadow_realtime_dlight", "1", CVAR_ARCHIVE, "Enables the use of dynamic realtime lights, allowing explosions to use bumpmaps etc properly."); +cvar_t r_shadow_realtime_dlight = CVARAFD ("r_shadow_realtime_dlight", "1", "r_shadow_realtime_dynamic", CVAR_ARCHIVE, "Enables the use of dynamic realtime lights, allowing explosions to use bumpmaps etc properly."); cvar_t r_shadow_realtime_dlight_shadows = CVARFD ("r_shadow_realtime_dlight_shadows", "1", CVAR_ARCHIVE, "Allows dynamic realtime lights to cast shadows as they move."); cvar_t r_shadow_realtime_dlight_ambient = CVAR ("r_shadow_realtime_dlight_ambient", "0"); cvar_t r_shadow_realtime_dlight_diffuse = CVAR ("r_shadow_realtime_dlight_diffuse", "1"); diff --git a/engine/http/httpclient.c b/engine/http/httpclient.c index 74632804d..d8aed1497 100644 --- a/engine/http/httpclient.c +++ b/engine/http/httpclient.c @@ -1594,7 +1594,10 @@ void DL_DeThread(void) { dl->threadenable = false; if (dl->threadctx) + { Sys_WaitOnThread(dl->threadctx); + dl->threadctx = NULL; + } } #endif } diff --git a/engine/qclib/qcc_pr_comp.c b/engine/qclib/qcc_pr_comp.c index 38b940044..4cc660f30 100644 --- a/engine/qclib/qcc_pr_comp.c +++ b/engine/qclib/qcc_pr_comp.c @@ -6147,7 +6147,7 @@ static void QCC_VerifyArgs_setviewprop (const char *funcname, QCC_ref_t **arglis {"VF_CL_VIEWANGLES_X", 35, ev_float}, {"VF_CL_VIEWANGLES_X", 36, ev_float}, {"VF_PERSPECTIVE", 200, ev_float}, - //201 +// {"VF_DP_CLEARSCENE", 201, ev_float}, {"VF_ACTIVESEAT", 202, ev_float, ev_float}, {"VF_AFOV", 203, ev_float}, // {"VF_SCREENVSIZE", 204, ev_vector}, @@ -6171,6 +6171,10 @@ static void QCC_VerifyArgs_setviewprop (const char *funcname, QCC_ref_t **arglis {"VF_SKYROOM_CAMERA", 222, ev_vector}, // {"VF_PIXELPSCALE", 223, ev_vector}, {"VF_PROJECTIONOFFSET", 224, ev_vector}, + {"VF_VRBASEORIENTATION",225, ev_vector, ev_vector}, + + {"VF_DP_MAINVIEW", 400, ev_float}, +// {"VF_DP_MINFPS_QUALITY", 401, ev_float}, }; char temp[256]; diff --git a/engine/qclib/qcc_pr_lex.c b/engine/qclib/qcc_pr_lex.c index 8cdfcdfe2..6e7cc10e9 100644 --- a/engine/qclib/qcc_pr_lex.c +++ b/engine/qclib/qcc_pr_lex.c @@ -5069,8 +5069,6 @@ QCC_type_t *QCC_PR_ParseFunctionType (int newtype, QCC_type_t *returntype) if (QCC_PR_CheckToken("=")) { paramlist[numparms].defltvalue = QCC_PR_ParseDefaultInitialiser(paramlist[numparms].type); - if (!paramlist[numparms].defltvalue.sym->constant) - QCC_PR_ParseError(0, "Default initialiser is not constant\n"); QCC_FreeTemp(paramlist[numparms].defltvalue); } numparms++; diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index b7a53424e..bda96e2aa 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -10291,9 +10291,109 @@ void SV_SetEntityButtons(edict_t *ent, unsigned int buttonbits) } } +static void SV_SetSSQCInputs(usercmd_t *ucmd) +{ + pr_global_struct->input_timelength = ucmd->msec/1000.0f * sv.gamespeed; + pr_global_struct->input_impulse = ucmd->impulse; +//precision inaccuracies. :( +#define ANGLE2SHORT(x) (x) * (65536/360.0) + if (sv_player->v->fixangle) + { + (pr_global_struct->input_angles)[0] = sv_player->v->v_angle[0]; + (pr_global_struct->input_angles)[1] = sv_player->v->v_angle[1]; + (pr_global_struct->input_angles)[2] = sv_player->v->v_angle[2]; + } + else + { + (pr_global_struct->input_angles)[0] = SHORT2ANGLE(ucmd->angles[0]); + (pr_global_struct->input_angles)[1] = SHORT2ANGLE(ucmd->angles[1]); + (pr_global_struct->input_angles)[2] = SHORT2ANGLE(ucmd->angles[2]); + } + + (pr_global_struct->input_movevalues)[0] = ucmd->forwardmove; + (pr_global_struct->input_movevalues)[1] = ucmd->sidemove; + (pr_global_struct->input_movevalues)[2] = ucmd->upmove; + pr_global_struct->input_buttons = ucmd->buttons; + if (pr_global_ptrs->input_weapon) + pr_global_struct->input_weapon = ucmd->weapon; + if (pr_global_ptrs->input_lightlevel) + pr_global_struct->input_lightlevel = ucmd->lightlevel; + + if (pr_global_ptrs->input_cursor_screen) + VectorSet(pr_global_struct->input_cursor_screen, ucmd->cursor_screen[0], ucmd->cursor_screen[1], 0); + if (pr_global_ptrs->input_cursor_trace_start) + VectorCopy(ucmd->cursor_start, pr_global_struct->input_cursor_trace_start); + if (pr_global_ptrs->input_cursor_trace_endpos) + VectorCopy(ucmd->cursor_impact, pr_global_struct->input_cursor_trace_endpos); + if (pr_global_ptrs->input_cursor_entitynumber) + pr_global_struct->input_cursor_entitynumber = ucmd->cursor_entitynumber; + + if (pr_global_ptrs->input_head_status) + pr_global_struct->input_head_status = ucmd->vr[VRDEV_HEAD].status; + if (pr_global_ptrs->input_head_origin) + VectorCopy(ucmd->vr[VRDEV_HEAD].origin, pr_global_struct->input_head_origin); + if (pr_global_ptrs->input_head_velocity) + VectorCopy(ucmd->vr[VRDEV_HEAD].velocity, pr_global_struct->input_head_velocity); + if (pr_global_ptrs->input_head_angles) + { + (pr_global_struct->input_head_angles)[0] = SHORT2ANGLE(ucmd->vr[VRDEV_HEAD].angles[0]); + (pr_global_struct->input_head_angles)[1] = SHORT2ANGLE(ucmd->vr[VRDEV_HEAD].angles[1]); + (pr_global_struct->input_head_angles)[2] = SHORT2ANGLE(ucmd->vr[VRDEV_HEAD].angles[2]); + } + if (pr_global_ptrs->input_head_avelocity) + { + (pr_global_struct->input_head_avelocity)[0] = SHORT2ANGLE(ucmd->vr[VRDEV_HEAD].avelocity[0]); + (pr_global_struct->input_head_avelocity)[1] = SHORT2ANGLE(ucmd->vr[VRDEV_HEAD].avelocity[1]); + (pr_global_struct->input_head_avelocity)[2] = SHORT2ANGLE(ucmd->vr[VRDEV_HEAD].avelocity[2]); + } + + if (pr_global_ptrs->input_left_status) + pr_global_struct->input_left_status = ucmd->vr[VRDEV_LEFT].status; + if (pr_global_ptrs->input_left_origin) + VectorCopy(ucmd->vr[VRDEV_LEFT].origin, pr_global_struct->input_left_origin); + if (pr_global_ptrs->input_left_velocity) + VectorCopy(ucmd->vr[VRDEV_LEFT].velocity, pr_global_struct->input_left_velocity); + if (pr_global_ptrs->input_left_angles) + { + (pr_global_struct->input_left_angles)[0] = SHORT2ANGLE(ucmd->vr[VRDEV_LEFT].angles[0]); + (pr_global_struct->input_left_angles)[1] = SHORT2ANGLE(ucmd->vr[VRDEV_LEFT].angles[1]); + (pr_global_struct->input_left_angles)[2] = SHORT2ANGLE(ucmd->vr[VRDEV_LEFT].angles[2]); + } + if (pr_global_ptrs->input_left_avelocity) + { + (pr_global_struct->input_left_avelocity)[0] = SHORT2ANGLE(ucmd->vr[VRDEV_LEFT].avelocity[0]); + (pr_global_struct->input_left_avelocity)[1] = SHORT2ANGLE(ucmd->vr[VRDEV_LEFT].avelocity[1]); + (pr_global_struct->input_left_avelocity)[2] = SHORT2ANGLE(ucmd->vr[VRDEV_LEFT].avelocity[2]); + } + + if (pr_global_ptrs->input_right_status) + pr_global_struct->input_right_status = ucmd->vr[VRDEV_RIGHT].status; + if (pr_global_ptrs->input_right_origin) + VectorCopy(ucmd->vr[VRDEV_RIGHT].origin, pr_global_struct->input_right_origin); + if (pr_global_ptrs->input_right_velocity) + VectorCopy(ucmd->vr[VRDEV_RIGHT].velocity, pr_global_struct->input_right_velocity); + if (pr_global_ptrs->input_right_angles) + { + (pr_global_struct->input_right_angles)[0] = SHORT2ANGLE(ucmd->vr[VRDEV_RIGHT].angles[0]); + (pr_global_struct->input_right_angles)[1] = SHORT2ANGLE(ucmd->vr[VRDEV_RIGHT].angles[1]); + (pr_global_struct->input_right_angles)[2] = SHORT2ANGLE(ucmd->vr[VRDEV_RIGHT].angles[2]); + } + if (pr_global_ptrs->input_right_avelocity) + { + (pr_global_struct->input_right_avelocity)[0] = SHORT2ANGLE(ucmd->vr[VRDEV_RIGHT].avelocity[0]); + (pr_global_struct->input_right_avelocity)[1] = SHORT2ANGLE(ucmd->vr[VRDEV_RIGHT].avelocity[1]); + (pr_global_struct->input_right_avelocity)[2] = SHORT2ANGLE(ucmd->vr[VRDEV_RIGHT].avelocity[2]); + } +} + //EXT_CSQC_1 (called when a movement command is received. runs full acceleration + movement) qboolean SV_RunFullQCMovement(client_t *client, usercmd_t *ucmd) { + if (ucmd->vr[VRDEV_HEAD].status & VRSTATUS_ANG) + sv_player->xv->idealpitch = SHORT2ANGLE(ucmd->vr[VRDEV_HEAD].angles[0]); + else + sv_player->xv->idealpitch = 0; + SV_SetSSQCInputs(ucmd); //make sure its available for PlayerPreThink. if (gfuncs.RunClientCommand) { vec3_t startangle; @@ -10352,107 +10452,6 @@ qboolean SV_RunFullQCMovement(client_t *client, usercmd_t *ucmd) V_CalcRoll (sv_player->v->angles, sv_player->v->velocity)*4; } - - - - - - - - - - pr_global_struct->input_timelength = ucmd->msec/1000.0f * sv.gamespeed; - pr_global_struct->input_impulse = ucmd->impulse; - //precision inaccuracies. :( -#define ANGLE2SHORT(x) (x) * (65536/360.0) - if (sv_player->v->fixangle) - { - (pr_global_struct->input_angles)[0] = sv_player->v->v_angle[0]; - (pr_global_struct->input_angles)[1] = sv_player->v->v_angle[1]; - (pr_global_struct->input_angles)[2] = sv_player->v->v_angle[2]; - } - else - { - (pr_global_struct->input_angles)[0] = SHORT2ANGLE(ucmd->angles[0]); - (pr_global_struct->input_angles)[1] = SHORT2ANGLE(ucmd->angles[1]); - (pr_global_struct->input_angles)[2] = SHORT2ANGLE(ucmd->angles[2]); - } - - (pr_global_struct->input_movevalues)[0] = ucmd->forwardmove; - (pr_global_struct->input_movevalues)[1] = ucmd->sidemove; - (pr_global_struct->input_movevalues)[2] = ucmd->upmove; - pr_global_struct->input_buttons = ucmd->buttons; - if (pr_global_ptrs->input_weapon) - pr_global_struct->input_weapon = ucmd->weapon; - if (pr_global_ptrs->input_lightlevel) - pr_global_struct->input_lightlevel = ucmd->lightlevel; - - if (pr_global_ptrs->input_cursor_screen) - VectorSet(pr_global_struct->input_cursor_screen, ucmd->cursor_screen[0], ucmd->cursor_screen[1], 0); - if (pr_global_ptrs->input_cursor_trace_start) - VectorCopy(ucmd->cursor_start, pr_global_struct->input_cursor_trace_start); - if (pr_global_ptrs->input_cursor_trace_endpos) - VectorCopy(ucmd->cursor_impact, pr_global_struct->input_cursor_trace_endpos); - if (pr_global_ptrs->input_cursor_entitynumber) - pr_global_struct->input_cursor_entitynumber = ucmd->cursor_entitynumber; - - if (pr_global_ptrs->input_head_status) - pr_global_struct->input_head_status = ucmd->vr[VRDEV_HEAD].status; - if (pr_global_ptrs->input_head_origin) - VectorCopy(ucmd->vr[VRDEV_HEAD].origin, pr_global_struct->input_head_origin); - if (pr_global_ptrs->input_head_velocity) - VectorCopy(ucmd->vr[VRDEV_HEAD].velocity, pr_global_struct->input_head_velocity); - if (pr_global_ptrs->input_head_angles) - { - (pr_global_struct->input_head_angles)[0] = SHORT2ANGLE(ucmd->vr[VRDEV_HEAD].angles[0]); - (pr_global_struct->input_head_angles)[1] = SHORT2ANGLE(ucmd->vr[VRDEV_HEAD].angles[1]); - (pr_global_struct->input_head_angles)[2] = SHORT2ANGLE(ucmd->vr[VRDEV_HEAD].angles[2]); - } - if (pr_global_ptrs->input_head_avelocity) - { - (pr_global_struct->input_head_avelocity)[0] = SHORT2ANGLE(ucmd->vr[VRDEV_HEAD].avelocity[0]); - (pr_global_struct->input_head_avelocity)[1] = SHORT2ANGLE(ucmd->vr[VRDEV_HEAD].avelocity[1]); - (pr_global_struct->input_head_avelocity)[2] = SHORT2ANGLE(ucmd->vr[VRDEV_HEAD].avelocity[2]); - } - - if (pr_global_ptrs->input_left_status) - pr_global_struct->input_left_status = ucmd->vr[VRDEV_LEFT].status; - if (pr_global_ptrs->input_left_origin) - VectorCopy(ucmd->vr[VRDEV_LEFT].origin, pr_global_struct->input_left_origin); - if (pr_global_ptrs->input_left_velocity) - VectorCopy(ucmd->vr[VRDEV_LEFT].velocity, pr_global_struct->input_left_velocity); - if (pr_global_ptrs->input_left_angles) - { - (pr_global_struct->input_left_angles)[0] = SHORT2ANGLE(ucmd->vr[VRDEV_LEFT].angles[0]); - (pr_global_struct->input_left_angles)[1] = SHORT2ANGLE(ucmd->vr[VRDEV_LEFT].angles[1]); - (pr_global_struct->input_left_angles)[2] = SHORT2ANGLE(ucmd->vr[VRDEV_LEFT].angles[2]); - } - if (pr_global_ptrs->input_left_avelocity) - { - (pr_global_struct->input_left_avelocity)[0] = SHORT2ANGLE(ucmd->vr[VRDEV_LEFT].avelocity[0]); - (pr_global_struct->input_left_avelocity)[1] = SHORT2ANGLE(ucmd->vr[VRDEV_LEFT].avelocity[1]); - (pr_global_struct->input_left_avelocity)[2] = SHORT2ANGLE(ucmd->vr[VRDEV_LEFT].avelocity[2]); - } - - if (pr_global_ptrs->input_right_status) - pr_global_struct->input_right_status = ucmd->vr[VRDEV_RIGHT].status; - if (pr_global_ptrs->input_right_origin) - VectorCopy(ucmd->vr[VRDEV_RIGHT].origin, pr_global_struct->input_right_origin); - if (pr_global_ptrs->input_right_velocity) - VectorCopy(ucmd->vr[VRDEV_RIGHT].velocity, pr_global_struct->input_right_velocity); - if (pr_global_ptrs->input_right_angles) - { - (pr_global_struct->input_right_angles)[0] = SHORT2ANGLE(ucmd->vr[VRDEV_RIGHT].angles[0]); - (pr_global_struct->input_right_angles)[1] = SHORT2ANGLE(ucmd->vr[VRDEV_RIGHT].angles[1]); - (pr_global_struct->input_right_angles)[2] = SHORT2ANGLE(ucmd->vr[VRDEV_RIGHT].angles[2]); - } - if (pr_global_ptrs->input_right_avelocity) - { - (pr_global_struct->input_right_avelocity)[0] = SHORT2ANGLE(ucmd->vr[VRDEV_RIGHT].avelocity[0]); - (pr_global_struct->input_right_avelocity)[1] = SHORT2ANGLE(ucmd->vr[VRDEV_RIGHT].avelocity[1]); - (pr_global_struct->input_right_avelocity)[2] = SHORT2ANGLE(ucmd->vr[VRDEV_RIGHT].avelocity[2]); - } - //prethink should be consistant with what the engine normally does pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, client->edict); PR_ExecuteProgram (svprogfuncs, pr_global_struct->PlayerPreThink); diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index 83e973bd5..5eec046e8 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -2271,6 +2271,7 @@ void SV_CalcClientStats(client_t *client, int statsi[MAX_CL_STATS], float statsf } statsf[STAT_VIEWHEIGHT] = ent->v->view_ofs[2]; + statsf[STAT_IDEALPITCH] = ent->xv->idealpitch; statsf[STAT_PUNCHANGLE_X] = ent->xv->punchangle[0]; statsf[STAT_PUNCHANGLE_Y] = ent->xv->punchangle[1]; diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index 04cde8f5b..bdcac5d3a 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -8113,9 +8113,9 @@ void SV_ExecuteClientMessage (client_t *cl) else while (split->lastruncmd < newcmd.servertime) { //try to find the oldest (valid) command. - if (split->lastcmd.servertime < oldest.servertime) + if (split->lastruncmd < oldest.servertime) c = &oldest; - else if (split->lastcmd.servertime < oldcmd.servertime) + else if (split->lastruncmd < oldcmd.servertime) c = &oldcmd; else c = &newcmd; diff --git a/engine/vk/vk_init.c b/engine/vk/vk_init.c index f093633e1..4b6a1e5d7 100644 --- a/engine/vk/vk_init.c +++ b/engine/vk/vk_init.c @@ -2656,7 +2656,7 @@ static qboolean VK_R_RenderScene_Cubemap(struct vk_rendertarg *fb) return true; } -void VK_R_RenderEye(texid_t image, vec4_t fovoverride, matrix3x4 axisorg) +void VK_R_RenderEye(texid_t image, vec4_t fovoverride, vec3_t eyeangorg[2]) { struct vk_rendertarg *rt; diff --git a/plugins/openxr.c b/plugins/openxr.c index a02f6ee1c..93ddc5c82 100644 --- a/plugins/openxr.c +++ b/plugins/openxr.c @@ -126,36 +126,6 @@ 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 Matrix3x4_FromAngles (const vec3_t angles, const vec3_t org, float *fte_restrict transform) -{ - float angle; - float sr, sp, sy, cr, cp, cy; - - 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); - - transform[0+0] = cp*cy; - transform[0+1] = cp*sy; - transform[0+2] = -sp; - transform[0+3] = org[0]; - - 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]; - - 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; @@ -178,62 +148,6 @@ static void XR_PoseToAngOrg(const XrPosef *pose, vec3_t ang, vec3_t org) 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 static void VectorAngles(const float *forward, const float *up, float *result, qboolean meshpitch) //up may be NULL @@ -1037,32 +951,14 @@ static int QDECL XR_BindProfileFile(const char *fname, qofs_t fsize, time_t mtim return false; } -static void XR_SetupInputs(void) +static const struct { - unsigned int h; - XrResult res; - -//begin instance-level init - { - XrActionSetCreateInfo info = {XR_TYPE_ACTION_SET_CREATE_INFO}; - Q_strlcpy(info.actionSetName, "actions", sizeof(info.actionSetName)); - Q_strlcpy(info.localizedActionSetName, FULLENGINENAME" Actions", sizeof(info.localizedActionSetName)); - info.priority = 0; - - xr.actionset.subactionPath = XR_NULL_PATH; - res = xrCreateActionSet(xr.instance, &info, &xr.actionset.actionSet); - if (XR_FAILED(res)) - Con_Printf("openxr: Unable to create actionset - %s\n", XR_StringForResult(res)); - } - - h = 0; - if (fsfuncs) - fsfuncs->EnumerateFiles("oxr_*.binds", XR_BindProfileFile, &h); - if (!h) //no user bindings defined, use fallbacks. probably this needs to be per-mod. - { - //FIXME: set up some proper bindings! - XR_BindProfileStr("khr_simple", - "/interaction_profiles/khr/simple_controller /user/hand/left/ /user/hand/right/\n" + const char *name; + const char *script; +} xr_knownprofiles[] = +{ + //FIXME: set up some proper bindings! + {"khr_simple", "/interaction_profiles/khr/simple_controller /user/hand/left/ /user/hand/right/\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" @@ -1072,10 +968,9 @@ static void XR_SetupInputs(void) // "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", - "/interaction_profiles/valve/index_controller /user/hand/left/ /user/hand/right/\n" +/* {"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" //"unbound \"Unused Button\" button input/a/click\n" @@ -1096,10 +991,9 @@ static void XR_SetupInputs(void) //"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" +/* {"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" @@ -1113,8 +1007,7 @@ static void XR_SetupInputs(void) //"unbound \"Unused Button\" vibration output/haptic\n" ); */ -/* XR_BindProfileStr("htc_vive_pro", - "/interaction_profiles/htc/vive_pro /user/head/\n" +/* {"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" @@ -1123,7 +1016,7 @@ static void XR_SetupInputs(void) */ //FIXME: map to quake's keys. - XR_BindProfileStr("gamepad", "/interaction_profiles/microsoft/xbox_controller /user/gamepad/\n" + {"gamepad", "/interaction_profiles/microsoft/xbox_controller /user/gamepad/\n" "togglemenu Menu button input/menu/click\n" //"unbound \"Unused Button\" button input/view/click\n" //"unbound \"Unused Button\" button input/a/click\n" @@ -1148,7 +1041,34 @@ static void XR_SetupInputs(void) //"unbound \"Unused Vibrator\" vibration output/haptic_left_trigger\n" //"unbound \"Unused Vibrator\" vibration output/haptic_right\n" //"unbound \"Unused Vibrator\" vibration output/haptic_right_trigger\n" - ); + }, +}; + +static void XR_SetupInputs(void) +{ + unsigned int h; + XrResult res; + +//begin instance-level init + { + XrActionSetCreateInfo info = {XR_TYPE_ACTION_SET_CREATE_INFO}; + Q_strlcpy(info.actionSetName, "actions", sizeof(info.actionSetName)); + Q_strlcpy(info.localizedActionSetName, FULLENGINENAME" Actions", sizeof(info.localizedActionSetName)); + info.priority = 0; + + xr.actionset.subactionPath = XR_NULL_PATH; + res = xrCreateActionSet(xr.instance, &info, &xr.actionset.actionSet); + if (XR_FAILED(res)) + Con_Printf("openxr: Unable to create actionset - %s\n", XR_StringForResult(res)); + } + + h = 0; + if (fsfuncs) + fsfuncs->EnumerateFiles("oxr_*.binds", XR_BindProfileFile, &h); + if (!h) //no user bindings defined, use fallbacks. probably this needs to be per-mod. + { + for (h = 0; h < countof(xr_knownprofiles); h++) + XR_BindProfileStr(xr_knownprofiles[h].name, xr_knownprofiles[h].script); } //begin session specific. stuff @@ -1295,8 +1215,7 @@ static void XR_UpdateInputs(XrTime time) (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]) - { + { //custom poses that mods might want to handle themselves... vec3_t angles; char cmd[256]; VectorAngles(transform[0], transform[2], angles, false); @@ -1695,7 +1614,7 @@ static qboolean XR_SyncFrame(double *frametime) return true; } -static qboolean XR_Render(void(*rendereye)(texid_t tex, vec4_t fovoverride, matrix3x4 axisorg)) +static qboolean XR_Render(void(*rendereye)(texid_t tex, vec4_t fovoverride, vec3_t angorg[2])) { XrFrameEndInfo endframeinfo = {XR_TYPE_FRAME_END_INFO}; unsigned int u; @@ -1762,7 +1681,6 @@ static qboolean XR_Render(void(*rendereye)(texid_t tex, vec4_t fovoverride, matr XrViewState viewstate = {XR_TYPE_VIEW_STATE}; XrViewLocateInfo locateinfo = {XR_TYPE_VIEW_LOCATE_INFO}; XrView eyeview[MAX_VIEW_COUNT]={}; - matrix3x4 transform, eyetransform, inv; for (u = 0; u < MAX_VIEW_COUNT; u++) eyeview[u].type = XR_TYPE_VIEW; @@ -1802,8 +1720,6 @@ static qboolean XR_Render(void(*rendereye)(texid_t tex, vec4_t fovoverride, matr 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); } @@ -1812,6 +1728,7 @@ static qboolean XR_Render(void(*rendereye)(texid_t tex, vec4_t fovoverride, matr vec4_t fovoverride; XrSwapchainImageWaitInfo waitinfo = {XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO}; unsigned int imgidx = 0; + vec3_t orientation[2]; res = xrAcquireSwapchainImage(xr.eye[u].swapchain, NULL, &imgidx); if (XR_FAILED(res)) Con_Printf("xrAcquireSwapchainImage: %s\n", XR_StringForResult(res)); @@ -1822,8 +1739,7 @@ static qboolean XR_Render(void(*rendereye)(texid_t tex, vec4_t fovoverride, matr projviews[u].fov = eyeview[u].fov; projviews[u].subImage = xr.eye[u].subimage; - XR_PoseToTransform(&eyeview[u].pose, transform[0]); - Matrix3x4_Multiply_XR(transform[0], inv[0], eyetransform[0]); + XR_PoseToAngOrg(&eyeview[u].pose, orientation[0], orientation[1]); fovoverride[0] = eyeview[u].fov.angleLeft * (180/M_PI); fovoverride[1] = eyeview[u].fov.angleRight * (180/M_PI); @@ -1834,7 +1750,7 @@ static qboolean XR_Render(void(*rendereye)(texid_t tex, vec4_t fovoverride, matr 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, eyetransform); + rendereye(&xr.eye[u].swapimages[imgidx], fovoverride, orientation); //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.