OpenXR stuff should be a little more usable now.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5850 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2021-05-09 13:02:49 +00:00
parent 13d524a30b
commit f35928f4fd
25 changed files with 360 additions and 353 deletions

View file

@ -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_prydoncursor = CVAR("cl_prydoncursor", ""); //for dp protocol
cvar_t cl_instantrotate = CVARF("cl_instantrotate", "1", CVAR_SEMICHEAT); 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"); 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 nscale = extratime?extratime / (extratime+priortime):0;
float oscale = 1 - nscale; float oscale = 1 - nscale;
cmd->fservertime = cl.time*1000; cmd->fservertime = cl.time;
cmd->servertime = cl.time*1000; 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); CL_GatherButtons(cmd, pnum);
} }
static void CL_ClampPitch (int pnum, float frametime) void CL_ClampPitch (int pnum, float frametime)
{ {
float mat[16]; float mat[16];
float roll; float roll;
@ -1097,6 +1098,30 @@ static void CL_ClampPitch (int pnum, float frametime)
pv->viewangles[YAW] *= 360; pv->viewangles[YAW] *= 360;
VectorClear(pv->viewanglechange); 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 #ifdef Q2CLIENT
if (cls.protocol == CP_QUAKE2) if (cls.protocol == CP_QUAKE2)
{ {
@ -1129,6 +1154,11 @@ static void CL_ClampPitch (int pnum, float frametime)
pv->viewangles[PITCH] = cl.maxpitch; pv->viewangles[PITCH] = cl.maxpitch;
if (pv->viewangles[PITCH] < cl.minpitch) if (pv->viewangles[PITCH] < cl.minpitch)
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) // if (cl.viewangles[pnum][ROLL] > 50)
@ -1169,7 +1199,10 @@ static void CL_FinishMove (usercmd_t *cmd, int pnum)
CL_GatherButtons(cmd, pnum); CL_GatherButtons(cmd, pnum);
for (i=0 ; i<3 ; i++) 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) if (in_impulsespending[pnum] && !cl.paused)
{ {
@ -2559,6 +2592,7 @@ void CL_InitInput (void)
Cvar_Register (&cl_fastaccel, inputnetworkcvargroup); Cvar_Register (&cl_fastaccel, inputnetworkcvargroup);
Cvar_Register (&in_xflip, inputnetworkcvargroup); Cvar_Register (&in_xflip, inputnetworkcvargroup);
Cvar_Register (&in_vraim, inputnetworkcvargroup);
Cvar_Register (&cl_nodelta, inputnetworkcvargroup); Cvar_Register (&cl_nodelta, inputnetworkcvargroup);
Cvar_Register (&prox_inmenu, inputnetworkcvargroup); Cvar_Register (&prox_inmenu, inputnetworkcvargroup);

View file

@ -5978,55 +5978,6 @@ qboolean Host_RunFile(const char *fname, int nlen, vfsfile_t *file)
return true; 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 Host_Frame
@ -6363,8 +6314,6 @@ double Host_Frame (double time)
if (emscriptenfte_getvrframedata()) if (emscriptenfte_getvrframedata())
r_refdef.stereomethod = STEREO_WEBVR; r_refdef.stereomethod = STEREO_WEBVR;
#endif #endif
CL_UpdateHeadAngles();
{ {
RSpeedMark(); RSpeedMark();
vid.ime_allow = false; vid.ime_allow = false;

View file

@ -1036,7 +1036,7 @@ void CL_PredictMovePNum (int seat)
else else
{ {
lerpangles = (cls.demoplayback == DPB_QUAKEWORLD); lerpangles = (cls.demoplayback == DPB_QUAKEWORLD);
VectorCopy (pv->viewangles, pv->simangles); VectorCopy (pv->aimangles, pv->simangles);
} }
} }

View file

@ -661,6 +661,7 @@ struct playerview_s
// the client maintains its own idea of view angles, which are // the client maintains its own idea of view angles, which are
// sent to the server each frame. And only reset at level change // sent to the server each frame. And only reset at level change
// and teleport times // 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 viewangles; //current angles
vec3_t viewanglechange; //angles set by input code this frame vec3_t viewanglechange; //angles set by input code this frame
vec3_t intermissionangles; //absolute angles for intermission vec3_t intermissionangles; //absolute angles for intermission
@ -773,6 +774,8 @@ struct playerview_s
size_t reverbtype; size_t reverbtype;
vec3_t velocity; vec3_t velocity;
} audio; } audio;
struct vrdevinfo_s vrdev[VRDEV_COUNT];
}; };
// //

View file

@ -1092,6 +1092,7 @@ qboolean IN_SetHandPosition(const char *devname, vec3_t org, vec3_t ang, vec3_t
{ {
int dtype; int dtype;
int seat; int seat;
struct vrdevinfo_s *dev;
if (!strncmp(devname, "left", 4)) if (!strncmp(devname, "left", 4))
{ {
seat = atoi(devname+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. return false; //no idea what you're talking about.
if (seat < 0 || seat >= MAX_SPLITS) if (seat < 0 || seat >= MAX_SPLITS)
return false; //duuuude! 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)| (org ?VRSTATUS_ORG:0)|
(ang ?VRSTATUS_ANG:0)| (ang ?VRSTATUS_ANG:0)|
(vel ?VRSTATUS_VEL:0)| (vel ?VRSTATUS_VEL:0)|
(avel?VRSTATUS_AVEL: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; return true;
} }

View file

@ -90,6 +90,7 @@ cvar_t pr_csqc_formenus = CVAR("pr_csqc_formenus", "0");
#endif #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."); 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 dpcompat_stats;
extern cvar_t in_vraim;
// standard effect cvars/sounds // standard effect cvars/sounds
extern cvar_t r_explosionlight; extern cvar_t r_explosionlight;
@ -2244,6 +2245,12 @@ nogameaccess:
*r = r_refdef.viewangles[parametertype-VF_ANGLES_X]; *r = r_refdef.viewangles[parametertype-VF_ANGLES_X];
break; 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: case VF_CL_VIEWANGLES_V:
if (csqc_nogameaccess && prinst == csqc_world.progs) if (csqc_nogameaccess && prinst == csqc_world.progs)
goto nogameaccess; 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; r_refdef.viewangles[parametertype-VF_ANGLES_X] = *p;
break; 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: case VF_CL_VIEWANGLES_V:
if (csqc_playerview) if (csqc_playerview)
VectorCopy(p, csqc_playerview->viewangles); VectorCopy(p, csqc_playerview->viewangles);
@ -3823,7 +3837,7 @@ static void cs_set_input_state (usercmd_t *cmd)
if (csqcg.input_servertime) if (csqcg.input_servertime)
*csqcg.input_servertime = cmd->fservertime; *csqcg.input_servertime = cmd->fservertime;
if (csqcg.input_clienttime) if (csqcg.input_clienttime)
*csqcg.input_clienttime = cmd->fclienttime/1000.0f; *csqcg.input_clienttime = cmd->fclienttime;
if (csqcg.input_cursor_screen) if (csqcg.input_cursor_screen)
{ {
@ -3922,7 +3936,10 @@ static void cs_get_input_state (usercmd_t *cmd)
if (csqcg.input_weapon) if (csqcg.input_weapon)
cmd->weapon = *csqcg.input_weapon; cmd->weapon = *csqcg.input_weapon;
if (csqcg.input_servertime) if (csqcg.input_servertime)
{
cmd->fservertime = *csqcg.input_servertime; cmd->fservertime = *csqcg.input_servertime;
cmd->servertime = *csqcg.input_servertime*1000;
}
if (csqcg.input_cursor_screen) if (csqcg.input_cursor_screen)
Vector2Copy(csqcg.input_cursor_screen, cmd->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) if (!cmd->msec)
*cmd = cl.outframes[(f-1)&UPDATE_MASK].cmd[seat]; *cmd = cl.outframes[(f-1)&UPDATE_MASK].cmd[seat];
cmd->msec = (realtime - cl.outframes[(f-1)&UPDATE_MASK].senttime)*1000; 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 else
{ {
@ -7752,6 +7774,8 @@ void CSQC_Shutdown(void)
memset(&csqc_world, 0, sizeof(csqc_world)); memset(&csqc_world, 0, sizeof(csqc_world));
memset(&csqcg, 0, sizeof(csqcg)); memset(&csqcg, 0, sizeof(csqcg));
in_vraim.ival = in_vraim.value; //csqc mod with explicit vr stuff.
if (csqc_deprecated_warned>1) if (csqc_deprecated_warned>1)
{ {
if (!cl_csqc_nodeprecate.ival) if (!cl_csqc_nodeprecate.ival)

View file

@ -260,10 +260,12 @@ typedef struct
vec3_t vieworg; /*logical view center*/ vec3_t vieworg; /*logical view center*/
vec3_t viewangles; vec3_t viewangles;
vec3_t viewaxis[3]; /*forward, left, up (NOT RIGHT)*/ 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*/ vec3_t eyeoffset; /*world space, for vr screenies*/
vec2_t projectionoffset; /*for off-centre rendering*/ 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 fov_x, fov_y, afov;
float fovv_x, fovv_y; //viewmodel fovs 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. float mindist, maxdist; //maxdist may be 0, for 'infinite', in which case mindist probably isn't valid either.

View file

@ -326,7 +326,11 @@ void V_DriftPitch (playerview_t *pv)
return; return;
} }
#ifdef QUAKESTATS
delta = pv->statsf[STAT_IDEALPITCH] - pv->viewangles[PITCH];
#else
delta = 0 - pv->viewangles[PITCH]; delta = 0 - pv->viewangles[PITCH];
#endif
if (!delta) if (!delta)
{ {

View file

@ -74,7 +74,7 @@ typedef struct plugvrfuncs_s
qboolean (*Prepare) (vrsetup_t *setupinfo); //called before graphics context init qboolean (*Prepare) (vrsetup_t *setupinfo); //called before graphics context init
qboolean (*Init) (vrsetup_t *setupinfo, rendererstate_t *info); //called after 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 (*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); void (*Shutdown) (void);
#define plugvrfuncs_name "VR" #define plugvrfuncs_name "VR"
} plugvrfuncs_t; } plugvrfuncs_t;

View file

@ -245,10 +245,10 @@ typedef struct
int position; int position;
int size; int size;
} texwadlump_t; } texwadlump_t;
int numwadtextures; static int numwadtextures;
static texwadlump_t texwadlump[TEXWAD_MAXIMAGES]; static texwadlump_t texwadlump[TEXWAD_MAXIMAGES];
wadfile_t *openwadfiles; static wadfile_t *openwadfiles;
void Wads_Flush (void) void Wads_Flush (void)
{ {

View file

@ -772,6 +772,39 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define fte_alignof(type) sizeof(qintptr_t) #define fte_alignof(type) sizeof(qintptr_t)
#endif #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;} //safeswitch(foo){safedefault: break;}
//switch, but errors for any omitted enum values despite the presence of a default case. //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) //(gcc will generally give warnings without the default, but sometimes you don't have control over the source of your enumeration values)

View file

@ -500,7 +500,7 @@ typedef struct
#define FTECONTENTS_EMPTY 0x00000000 #define FTECONTENTS_EMPTY 0x00000000
#define FTECONTENTS_SOLID 0x00000001 #define FTECONTENTS_SOLID 0x00000001
//q2window 0x00000002 #define FTECONTENTS_WINDOW 0x00000002 //solid to bullets, but not sight/agro
//q2aux 0x00000004 //q2aux 0x00000004
#define FTECONTENTS_LAVA 0x00000008 #define FTECONTENTS_LAVA 0x00000008
#define FTECONTENTS_SLIME 0x00000010 #define FTECONTENTS_SLIME 0x00000010
@ -656,8 +656,8 @@ typedef struct
// content masks. Allow q2contents_window in here // content masks. Allow q2contents_window in here
//#define MASK_ALL (-1) //#define MASK_ALL (-1)
#define MASK_WORLDSOLID (FTECONTENTS_SOLID|Q2CONTENTS_WINDOW) /*default trace type for something simple that ignores non-bsp stuff*/ #define MASK_WORLDSOLID (FTECONTENTS_SOLID|FTECONTENTS_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_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_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_PLAYERSOLID MASK_BOXSOLID
//#define MASK_DEADSOLID (Q2CONTENTS_SOLID|Q2CONTENTS_PLAYERCLIP|Q2CONTENTS_WINDOW) //#define MASK_DEADSOLID (Q2CONTENTS_SOLID|Q2CONTENTS_PLAYERCLIP|Q2CONTENTS_WINDOW)

View file

@ -787,12 +787,12 @@ typedef enum
VF_SKYROOM_CAMERA = 222, VF_SKYROOM_CAMERA = 222,
VF_PIXELPSCALE = 223, //[dpi_x, dpi_y, dpi_y/dpi_x] VF_PIXELPSCALE = 223, //[dpi_x, dpi_y, dpi_y/dpi_x]
VF_PROJECTIONOFFSET = 224, //allows for off-axis projections. 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. //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. 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 - fuck DP and their complete lack of respect for existing implemenetations
VF_DP_FOG_DENSITY = 202, //misassigned
VF_DP_FOG_COLOR = 203, //misassigned VF_DP_FOG_COLOR = 203, //misassigned
VF_DP_FOG_COLOR_R = 204, //misassigned VF_DP_FOG_COLOR_R = 204, //misassigned
VF_DP_FOG_COLOR_G = 205, //misassigned VF_DP_FOG_COLOR_G = 205, //misassigned
@ -802,7 +802,7 @@ typedef enum
VF_DP_FOG_END = 209, //misassigned VF_DP_FOG_END = 209, //misassigned
VF_DP_FOG_HEIGHT = 210, //misassigned VF_DP_FOG_HEIGHT = 210, //misassigned
VF_DP_FOG_FADEDEPTH = 211, //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. VF_DP_MINFPS_QUALITY = 401, //multiplier for lod and culling to try to reduce costs.
} viewflags; } viewflags;

View file

@ -1189,6 +1189,22 @@ typedef struct
size_t bonedatamax; size_t bonedatamax;
} packet_entities_t; } 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 typedef struct usercmd_s
{ {
//the first members of this structure MUST match the q2 version //the first members of this structure MUST match the q2 version
@ -1214,21 +1230,7 @@ typedef struct usercmd_s
unsigned int cursor_entitynumber; unsigned int cursor_entitynumber;
//vr things //vr things
struct struct vrdevinfo_s vr[VRDEV_COUNT]; //left, right, head.
{
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.
} usercmd_t; } usercmd_t;
typedef struct q2usercmd_s typedef struct q2usercmd_s

View file

@ -88,6 +88,7 @@ Zone block
#else #else
#define VALGRIND_MAKE_MEM_UNDEFINED(ptr,sz) //as an alternative to memzero.. #define VALGRIND_MAKE_MEM_UNDEFINED(ptr,sz) //as an alternative to memzero..
#define VALGRIND_MAKE_MEM_NOACCESS(ptr,sz) #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 #endif
void Memory_Init (void); void Memory_Init (void);

View file

@ -435,7 +435,7 @@ void R_RotateForEntity (float *m, float *modelview, const entity_t *e, const mod
R_SetupGL 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; int x, x2, y2, y, w, h;
vec3_t newa; vec3_t newa;
@ -450,16 +450,34 @@ static void R_SetupGL (matrix3x4 eyematrix, vec4_t fovoverrides, float projmatri
newa[0] = r_refdef.viewangles[0]; newa[0] = r_refdef.viewangles[0];
newa[1] = r_refdef.viewangles[1]; newa[1] = r_refdef.viewangles[1];
newa[2] = r_refdef.viewangles[2] + gl_screenangle.value; 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 viewmatrix;
Matrix3x4_RM_FromAngles(newa, r_refdef.vieworg, headmatrix[0]);
Matrix3x4_Multiply(headmatrix[0], eyematrix[0], viewmatrix[0]); 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); Matrix3x4_RM_ToVectors(viewmatrix[0], vpn, vright, vup, r_origin);
VectorNegate(vright, vright); VectorNegate(vright, vright);
} }
else 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
{ {
AngleVectors (newa, vpn, vright, vup); AngleVectors (newa, vpn, vright, vup);
VectorCopy(r_refdef.vieworg, r_origin); VectorCopy(r_refdef.vieworg, r_origin);
@ -717,7 +735,7 @@ static void R_RenderScene_Internal(void)
depthcleared = false; //whatever is in the depth buffer is no longer useful. 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; extern qboolean depthcleared;
refdef_t refdef = r_refdef; 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 ph = vid.fbpheight;
int r = 0; 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) if (rendertarget)
{ {
r = GLBE_FBO_Update(&fbo_vr, FBO_RB_DEPTH, &rendertarget, 1, r_nulltex, rendertarget->width, rendertarget->height, 0); 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; vid.fbpheight = rendertarget->height;
} }
R_SetupGL (eyematrix, fovoverride, NULL, rendertarget); R_SetupGL (eyeangorg, fovoverride, NULL, rendertarget);
R_RenderScene_Internal(); R_RenderScene_Internal();
//if (eyematrix) /*//if (eyematrix)
{ {
vec3_t newa, newo; vec3_t newa, newo;
matrix3x4 headmatrix; //position of the head in local space 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) if (R2D_Flush)
R2D_Flush(); R2D_Flush();
GL_SetShaderState2D(false); GL_SetShaderState2D(false);
} }*/
if (rendertarget) if (rendertarget)
{ {
@ -795,8 +818,7 @@ static void R_RenderScene (void)
int i; int i;
int cull = r_refdef.flipcull; int cull = r_refdef.flipcull;
unsigned int colourmask = r_refdef.colourmask; unsigned int colourmask = r_refdef.colourmask;
vec3_t ang, org; vec3_t eyeangorg[2];
matrix3x4 eyematrix;
extern qboolean depthcleared; extern qboolean depthcleared;
r_refdef.colourmask = 0u; 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. :( r_framecount++; //view position changes, if only slightly. which means we need to rebuild vis info. :(
ang[0] = 0; eyeangorg[0][0] = 0;
ang[1] = r_stereo_convergence.value * (i?0.5:-0.5); eyeangorg[0][1] = r_stereo_convergence.value * (i?0.5:-0.5);
ang[2] = 0; eyeangorg[0][2] = 0;
VectorSet(org, 0, stereooffset[i], 0); VectorSet(eyeangorg[1], 0, stereooffset[i], 0);
Matrix3x4_RM_FromAngles(ang, org, eyematrix[0]); R_SetupGL (eyeangorg, NULL, NULL, NULL);
R_SetupGL (eyematrix, NULL, NULL, NULL);
R_RenderScene_Internal (); R_RenderScene_Internal ();
} }

View file

@ -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_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_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_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_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_ambient = CVAR ("r_shadow_realtime_dlight_ambient", "0");
cvar_t r_shadow_realtime_dlight_diffuse = CVAR ("r_shadow_realtime_dlight_diffuse", "1"); cvar_t r_shadow_realtime_dlight_diffuse = CVAR ("r_shadow_realtime_dlight_diffuse", "1");

View file

@ -1594,7 +1594,10 @@ void DL_DeThread(void)
{ {
dl->threadenable = false; dl->threadenable = false;
if (dl->threadctx) if (dl->threadctx)
{
Sys_WaitOnThread(dl->threadctx); Sys_WaitOnThread(dl->threadctx);
dl->threadctx = NULL;
}
} }
#endif #endif
} }

View file

@ -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", 35, ev_float},
{"VF_CL_VIEWANGLES_X", 36, ev_float}, {"VF_CL_VIEWANGLES_X", 36, ev_float},
{"VF_PERSPECTIVE", 200, ev_float}, {"VF_PERSPECTIVE", 200, ev_float},
//201 // {"VF_DP_CLEARSCENE", 201, ev_float},
{"VF_ACTIVESEAT", 202, ev_float, ev_float}, {"VF_ACTIVESEAT", 202, ev_float, ev_float},
{"VF_AFOV", 203, ev_float}, {"VF_AFOV", 203, ev_float},
// {"VF_SCREENVSIZE", 204, ev_vector}, // {"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_SKYROOM_CAMERA", 222, ev_vector},
// {"VF_PIXELPSCALE", 223, ev_vector}, // {"VF_PIXELPSCALE", 223, ev_vector},
{"VF_PROJECTIONOFFSET", 224, 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]; char temp[256];

View file

@ -5069,8 +5069,6 @@ QCC_type_t *QCC_PR_ParseFunctionType (int newtype, QCC_type_t *returntype)
if (QCC_PR_CheckToken("=")) if (QCC_PR_CheckToken("="))
{ {
paramlist[numparms].defltvalue = QCC_PR_ParseDefaultInitialiser(paramlist[numparms].type); 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); QCC_FreeTemp(paramlist[numparms].defltvalue);
} }
numparms++; numparms++;

View file

@ -10291,76 +10291,8 @@ void SV_SetEntityButtons(edict_t *ent, unsigned int buttonbits)
} }
} }
//EXT_CSQC_1 (called when a movement command is received. runs full acceleration + movement) static void SV_SetSSQCInputs(usercmd_t *ucmd)
qboolean SV_RunFullQCMovement(client_t *client, usercmd_t *ucmd)
{ {
if (gfuncs.RunClientCommand)
{
vec3_t startangle;
#ifdef SVCHAT
if (SV_ChatMove(ucmd->impulse))
{
ucmd->buttons = 0;
ucmd->impulse = 0;
ucmd->forwardmove = ucmd->sidemove = ucmd->upmove = 0;
}
#endif
if (!sv_player->v->fixangle)
{
sv_player->v->v_angle[0] = SHORT2ANGLE(ucmd->angles[0]);
sv_player->v->v_angle[1] = SHORT2ANGLE(ucmd->angles[1]);
sv_player->v->v_angle[2] = SHORT2ANGLE(ucmd->angles[2]);
}
VectorCopy(sv_player->v->v_angle, startangle);
#ifdef HEXEN2
if (progstype == PROG_H2)
sv_player->xv->light_level = 128; //hmm... HACK!!!
#endif
SV_SetEntityButtons(sv_player, ucmd->buttons);
if (ucmd->impulse && SV_FilterImpulse(ucmd->impulse, host_client->trustlevel))
sv_player->v->impulse = ucmd->impulse;
if (host_client->penalties & BAN_CUFF)
{
sv_player->v->impulse = 0;
sv_player->v->button0 = 0;
}
if (host_client->state && host_client->protocol != SCP_BAD)
{
sv_player->xv->movement[0] = ucmd->forwardmove;
sv_player->xv->movement[1] = ucmd->sidemove;
sv_player->xv->movement[2] = ucmd->upmove;
}
WPhys_CheckVelocity(&sv.world, (wedict_t*)sv_player);
//
// angles
// show 1/3 the pitch angle and all the roll angle
if (sv_player->v->health > 0)
{
if (!sv_player->v->fixangle)
{
sv_player->v->angles[PITCH] = r_meshpitch.value * sv_player->v->v_angle[PITCH]/3;
sv_player->v->angles[YAW] = sv_player->v->v_angle[YAW];
}
sv_player->v->angles[ROLL] =
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_timelength = ucmd->msec/1000.0f * sv.gamespeed;
pr_global_struct->input_impulse = ucmd->impulse; pr_global_struct->input_impulse = ucmd->impulse;
//precision inaccuracies. :( //precision inaccuracies. :(
@ -10452,6 +10384,73 @@ qboolean SV_RunFullQCMovement(client_t *client, usercmd_t *ucmd)
(pr_global_struct->input_right_avelocity)[1] = SHORT2ANGLE(ucmd->vr[VRDEV_RIGHT].avelocity[1]); (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]); (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;
#ifdef SVCHAT
if (SV_ChatMove(ucmd->impulse))
{
ucmd->buttons = 0;
ucmd->impulse = 0;
ucmd->forwardmove = ucmd->sidemove = ucmd->upmove = 0;
}
#endif
if (!sv_player->v->fixangle)
{
sv_player->v->v_angle[0] = SHORT2ANGLE(ucmd->angles[0]);
sv_player->v->v_angle[1] = SHORT2ANGLE(ucmd->angles[1]);
sv_player->v->v_angle[2] = SHORT2ANGLE(ucmd->angles[2]);
}
VectorCopy(sv_player->v->v_angle, startangle);
#ifdef HEXEN2
if (progstype == PROG_H2)
sv_player->xv->light_level = 128; //hmm... HACK!!!
#endif
SV_SetEntityButtons(sv_player, ucmd->buttons);
if (ucmd->impulse && SV_FilterImpulse(ucmd->impulse, host_client->trustlevel))
sv_player->v->impulse = ucmd->impulse;
if (host_client->penalties & BAN_CUFF)
{
sv_player->v->impulse = 0;
sv_player->v->button0 = 0;
}
if (host_client->state && host_client->protocol != SCP_BAD)
{
sv_player->xv->movement[0] = ucmd->forwardmove;
sv_player->xv->movement[1] = ucmd->sidemove;
sv_player->xv->movement[2] = ucmd->upmove;
}
WPhys_CheckVelocity(&sv.world, (wedict_t*)sv_player);
//
// angles
// show 1/3 the pitch angle and all the roll angle
if (sv_player->v->health > 0)
{
if (!sv_player->v->fixangle)
{
sv_player->v->angles[PITCH] = r_meshpitch.value * sv_player->v->v_angle[PITCH]/3;
sv_player->v->angles[YAW] = sv_player->v->v_angle[YAW];
}
sv_player->v->angles[ROLL] =
V_CalcRoll (sv_player->v->angles, sv_player->v->velocity)*4;
}
//prethink should be consistant with what the engine normally does //prethink should be consistant with what the engine normally does
pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, client->edict); pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, client->edict);

View file

@ -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_VIEWHEIGHT] = ent->v->view_ofs[2];
statsf[STAT_IDEALPITCH] = ent->xv->idealpitch;
statsf[STAT_PUNCHANGLE_X] = ent->xv->punchangle[0]; statsf[STAT_PUNCHANGLE_X] = ent->xv->punchangle[0];
statsf[STAT_PUNCHANGLE_Y] = ent->xv->punchangle[1]; statsf[STAT_PUNCHANGLE_Y] = ent->xv->punchangle[1];

View file

@ -8113,9 +8113,9 @@ void SV_ExecuteClientMessage (client_t *cl)
else while (split->lastruncmd < newcmd.servertime) else while (split->lastruncmd < newcmd.servertime)
{ {
//try to find the oldest (valid) command. //try to find the oldest (valid) command.
if (split->lastcmd.servertime < oldest.servertime) if (split->lastruncmd < oldest.servertime)
c = &oldest; c = &oldest;
else if (split->lastcmd.servertime < oldcmd.servertime) else if (split->lastruncmd < oldcmd.servertime)
c = &oldcmd; c = &oldcmd;
else else
c = &newcmd; c = &newcmd;

View file

@ -2656,7 +2656,7 @@ static qboolean VK_R_RenderScene_Cubemap(struct vk_rendertarg *fb)
return true; 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; struct vk_rendertarg *rt;

View file

@ -126,36 +126,6 @@ static cvar_t *xr_skipregularview;
#define METRES_TO_QUAKE(x) ((x)*xr_metresize->value) #define METRES_TO_QUAKE(x) ((x)*xr_metresize->value)
#define QUAKE_TO_METRES(x) ((x)/xr_metresize->value) #define QUAKE_TO_METRES(x) ((x)/xr_metresize->value)
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) static void XR_PoseToAngOrg(const XrPosef *pose, vec3_t ang, vec3_t org)
{ {
XrQuaternionf q = pose->orientation; 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); org[2] = METRES_TO_QUAKE(pose->position.z);
#endif #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 #define VectorAngles VectorAnglesPluginsSuck
static void 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
@ -1037,32 +951,14 @@ static int QDECL XR_BindProfileFile(const char *fname, qofs_t fsize, time_t mtim
return false; return false;
} }
static void XR_SetupInputs(void) static const struct
{ {
unsigned int h; const char *name;
XrResult res; const char *script;
} xr_knownprofiles[] =
//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! //FIXME: set up some proper bindings!
XR_BindProfileStr("khr_simple", {"khr_simple", "/interaction_profiles/khr/simple_controller /user/hand/left/ /user/hand/right/\n"
"/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_left \"Left Attack\" button input/select/click /user/hand/left\n"
"+attack_right \"Right Attack\" button input/select/click /user/hand/right\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_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" // "grip_pose \"Grip Pose\" pose input/grip/pose\n"
// "aim_pose \"Aim Pose\" pose input/aim/pose\n" // "aim_pose \"Aim Pose\" pose input/aim/pose\n"
"vibrate \"A Vibrator\" vibration output/haptic\n" "vibrate \"A Vibrator\" vibration output/haptic\n"
); },
/* XR_BindProfileStr("valve_index", /* {"valve_index", "/interaction_profiles/valve/index_controller /user/hand/left/ /user/hand/right/\n"
"/interaction_profiles/valve/index_controller /user/hand/left/ /user/hand/right/\n"
//"unbound \"Unused Button\" button input/system/click\n" //"unbound \"Unused Button\" button input/system/click\n"
//"unbound \"Unused Button\" button input/system/touch\n" //"unbound \"Unused Button\" button input/system/touch\n"
//"unbound \"Unused Button\" button input/a/click\n" //"unbound \"Unused Button\" button input/a/click\n"
@ -1096,10 +991,9 @@ static void XR_SetupInputs(void)
//"unbound \"Unused Button\" pose input/grip/pose\n" //"unbound \"Unused Button\" pose input/grip/pose\n"
//"unbound \"Unused Button\" pose input/aim/pose\n" //"unbound \"Unused Button\" pose input/aim/pose\n"
//"unbound \"Unused Button\" vibration output/haptic\n" //"unbound \"Unused Button\" vibration output/haptic\n"
); },
*/ */
/* XR_BindProfileStr("htc_vive", /* {"htc_vive", "/interaction_profiles/htc/vive_controller /user/hand/left/ /user/hand/right/\n"
"/interaction_profiles/htc/vive_controller /user/hand/left/ /user/hand/right/\n"
//"unbound \"Unused Button\" button input/system/click\n" //"unbound \"Unused Button\" button input/system/click\n"
//"unbound \"Unused Button\" button input/squeeze/click\n" //"unbound \"Unused Button\" button input/squeeze/click\n"
//"unbound \"Unused Button\" button input/menu/click\n" //"unbound \"Unused Button\" button input/menu/click\n"
@ -1113,8 +1007,7 @@ static void XR_SetupInputs(void)
//"unbound \"Unused Button\" vibration output/haptic\n" //"unbound \"Unused Button\" vibration output/haptic\n"
); );
*/ */
/* XR_BindProfileStr("htc_vive_pro", /* {"htc_vive_pro", "/interaction_profiles/htc/vive_pro /user/head/\n"
"/interaction_profiles/htc/vive_pro /user/head/\n"
//"unbound \"Unused Button\" button input/system/click\n" //"unbound \"Unused Button\" button input/system/click\n"
//"unbound \"Unused Button\" button input/volume_up/click\n" //"unbound \"Unused Button\" button input/volume_up/click\n"
//"unbound \"Unused Button\" button input/volume_down/click\n" //"unbound \"Unused Button\" button input/volume_down/click\n"
@ -1123,7 +1016,7 @@ static void XR_SetupInputs(void)
*/ */
//FIXME: map to quake's keys. //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" "togglemenu Menu button input/menu/click\n"
//"unbound \"Unused Button\" button input/view/click\n" //"unbound \"Unused Button\" button input/view/click\n"
//"unbound \"Unused Button\" button input/a/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_left_trigger\n"
//"unbound \"Unused Vibrator\" vibration output/haptic_right\n" //"unbound \"Unused Vibrator\" vibration output/haptic_right\n"
//"unbound \"Unused Vibrator\" vibration output/haptic_right_trigger\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 //begin session specific. stuff
@ -1295,8 +1215,7 @@ static void XR_UpdateInputs(XrTime time)
(loc.locationFlags&XR_SPACE_LOCATION_ORIENTATION_VALID_BIT)?angles:NULL, (loc.locationFlags&XR_SPACE_LOCATION_ORIENTATION_VALID_BIT)?angles:NULL,
(vel.velocityFlags&XR_SPACE_VELOCITY_LINEAR_VALID_BIT)?lvel:NULL, (vel.velocityFlags&XR_SPACE_VELOCITY_LINEAR_VALID_BIT)?lvel:NULL,
(vel.velocityFlags&XR_SPACE_VELOCITY_ANGULAR_VALID_BIT)?avel:NULL)) (vel.velocityFlags&XR_SPACE_VELOCITY_ANGULAR_VALID_BIT)?avel:NULL))
if (transform[3][0] || transform[3][1] || transform[3][2]) { //custom poses that mods might want to handle themselves...
{
vec3_t angles; vec3_t angles;
char cmd[256]; char cmd[256];
VectorAngles(transform[0], transform[2], angles, false); VectorAngles(transform[0], transform[2], angles, false);
@ -1695,7 +1614,7 @@ static qboolean XR_SyncFrame(double *frametime)
return true; 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}; XrFrameEndInfo endframeinfo = {XR_TYPE_FRAME_END_INFO};
unsigned int u; 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}; XrViewState viewstate = {XR_TYPE_VIEW_STATE};
XrViewLocateInfo locateinfo = {XR_TYPE_VIEW_LOCATE_INFO}; XrViewLocateInfo locateinfo = {XR_TYPE_VIEW_LOCATE_INFO};
XrView eyeview[MAX_VIEW_COUNT]={}; XrView eyeview[MAX_VIEW_COUNT]={};
matrix3x4 transform, eyetransform, inv;
for (u = 0; u < MAX_VIEW_COUNT; u++) for (u = 0; u < MAX_VIEW_COUNT; u++)
eyeview[u].type = XR_TYPE_VIEW; 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.y /= xr.viewcount;
apose.position.z /= xr.viewcount; apose.position.z /= xr.viewcount;
XR_PoseToAngOrg(&apose, ang, org); 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); 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; vec4_t fovoverride;
XrSwapchainImageWaitInfo waitinfo = {XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO}; XrSwapchainImageWaitInfo waitinfo = {XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO};
unsigned int imgidx = 0; unsigned int imgidx = 0;
vec3_t orientation[2];
res = xrAcquireSwapchainImage(xr.eye[u].swapchain, NULL, &imgidx); res = xrAcquireSwapchainImage(xr.eye[u].swapchain, NULL, &imgidx);
if (XR_FAILED(res)) if (XR_FAILED(res))
Con_Printf("xrAcquireSwapchainImage: %s\n", XR_StringForResult(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].fov = eyeview[u].fov;
projviews[u].subImage = xr.eye[u].subimage; projviews[u].subImage = xr.eye[u].subimage;
XR_PoseToTransform(&eyeview[u].pose, transform[0]); XR_PoseToAngOrg(&eyeview[u].pose, orientation[0], orientation[1]);
Matrix3x4_Multiply_XR(transform[0], inv[0], eyetransform[0]);
fovoverride[0] = eyeview[u].fov.angleLeft * (180/M_PI); fovoverride[0] = eyeview[u].fov.angleLeft * (180/M_PI);
fovoverride[1] = eyeview[u].fov.angleRight * (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); res = xrWaitSwapchainImage(xr.eye[u].swapchain, &waitinfo);
if (XR_FAILED(res)) if (XR_FAILED(res))
Con_Printf("xrWaitSwapchainImage: %s\n", XR_StringForResult(res)); Con_Printf("xrWaitSwapchainImage: %s\n", XR_StringForResult(res));
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. //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. // 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. //VK note: the OpenXR spec does say that it needs to be color_attachment_optimal+owned by queue. which it is.