diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index a46d8296..2460ddf1 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -2169,8 +2169,8 @@ void CLQ1_AddOrientedHalfSphere(shader_t *shader, float radius, float gap, float { //use simple algo //a series of cylinders that gets progressively narrower - int latsteps = 16; - int lngsteps = 16; + const int latsteps = 16; + const int lngsteps = 8;//16; float cradius; int v, i, j; scenetris_t *t; @@ -2182,7 +2182,7 @@ void CLQ1_AddOrientedHalfSphere(shader_t *shader, float radius, float gap, float return; /*reuse the previous trigroup if its the same shader*/ - if (cl_numstris && cl_stris[cl_numstris-1].shader == shader && cl_stris[cl_numstris-1].flags == flags) + if (cl_numstris && cl_stris[cl_numstris-1].shader == shader && cl_stris[cl_numstris-1].flags == flags && cl_stris[cl_numstris-1].numvert < MAX_INDICIES-(latsteps-1)*(lngsteps-1)) t = &cl_stris[cl_numstris-1]; else { @@ -2244,19 +2244,19 @@ void CLQ1_AddOrientedHalfSphere(shader_t *shader, float radius, float gap, float v = latsteps-1; for (v = 0; v < latsteps-1; v++) { - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+lngsteps + v*lngsteps + i; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+0 + v*lngsteps + i; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+1 + v*lngsteps + i; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+lngsteps+1 + v*lngsteps + i; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+lngsteps + v*lngsteps + i; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+1 + v*lngsteps + i; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+lngsteps + v*lngsteps + i; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+0 + v*lngsteps + i; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+1 + v*lngsteps + i; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+lngsteps+1 + v*lngsteps + i; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+lngsteps + v*lngsteps + i; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+1 + v*lngsteps + i; } - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert + i; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+0 + v*lngsteps + i; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+1 + v*lngsteps + i; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+1 + i; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert + i; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+1 + v*lngsteps + i; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert + i; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+0 + v*lngsteps + i; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+1 + v*lngsteps + i; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+1 + i; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert + i; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+1 + v*lngsteps + i; } } else @@ -2266,19 +2266,19 @@ void CLQ1_AddOrientedHalfSphere(shader_t *shader, float radius, float gap, float v = latsteps-1; for (v = 0; v < latsteps-1; v++) { - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+0 + v*lngsteps + i; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+lngsteps + v*lngsteps + i; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+1 + v*lngsteps + i; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+lngsteps + v*lngsteps + i; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+lngsteps+1 + v*lngsteps + i; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+1 + v*lngsteps + i; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+0 + v*lngsteps + i; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+lngsteps + v*lngsteps + i; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+1 + v*lngsteps + i; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+lngsteps + v*lngsteps + i; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+lngsteps+1 + v*lngsteps + i; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+1 + v*lngsteps + i; } - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+0 + v*lngsteps + i; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert + i; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+1 + v*lngsteps + i; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert + i; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+1 + i; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+1 + v*lngsteps + i; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+0 + v*lngsteps + i; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert + i; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+1 + v*lngsteps + i; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert + i; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+1 + i; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+1 + v*lngsteps + i; } } @@ -2287,6 +2287,12 @@ void CLQ1_AddOrientedHalfSphere(shader_t *shader, float radius, float gap, float cl_numstrisvert += lngsteps*latsteps; } +void CLQ1_AddOrientedSphere(shader_t *shader, float radius, float *matrix, float r, float g, float b, float a) +{ + CLQ1_AddOrientedHalfSphere(shader, radius, 0, matrix, r, g, b, a); + CLQ1_AddOrientedHalfSphere(shader, -radius, 0, matrix, r, g, b, a); +} + void CLQ1_AddOrientedCylinder(shader_t *shader, float radius, float height, qboolean capsule, float *matrix, float r, float g, float b, float a) { int sides = 16; @@ -2357,31 +2363,31 @@ void CLQ1_AddOrientedCylinder(shader_t *shader, float radius, float height, qboo } for (v = 0; v < sides-1; v++) { - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+2 + v*2; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+1 + v*2; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+0 + v*2; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+3 + v*2; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+1 + v*2; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+2 + v*2; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+2 + v*2; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+1 + v*2; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+0 + v*2; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+3 + v*2; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+1 + v*2; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+2 + v*2; } - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+0; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+1 + v*2; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+0 + v*2; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+1; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+1 + v*2; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+0; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+0; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+1 + v*2; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+0 + v*2; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+1; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+1 + v*2; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+0; if (!capsule) { for (v = 4; v < sides*2; v+=2) { - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+v; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+(v-2); - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+0; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+v; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+(v-2); + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+0; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+1; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+(v-2)+1; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+v+1; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+1; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+(v-2)+1; + cl_strisidx[cl_numstrisidx++] = cl_numstrisvert-t->firstvert+v+1; } } diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index e96e6499..a334a4b3 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -2169,6 +2169,7 @@ void CL_CheckServerInfo(void) s = Info_ValueForKey(cl.serverinfo, "pm_flyfriction"); movevars.flyfriction = *s?Q_atof(s):4; } + movevars.coordsize = cls.netchan.netprim.coordsize; // Initialize cl.maxpitch & cl.minpitch if (cls.protocol == CP_QUAKEWORLD || cls.protocol == CP_NETQUAKE) diff --git a/engine/client/cl_plugin.inc b/engine/client/cl_plugin.inc index 6a23f52d..7ed2bd20 100644 --- a/engine/client/cl_plugin.inc +++ b/engine/client/cl_plugin.inc @@ -722,6 +722,7 @@ static qintptr_t VARGS Plug_GetNetworkInfo(void *offset, quintptr_t mask, const } #undef has +#ifdef QUAKEHUD static qintptr_t VARGS Plug_GetTrackerOwnFrags(void *offset, quintptr_t mask, const qintptr_t *arg) { int ret; @@ -734,6 +735,7 @@ static qintptr_t VARGS Plug_GetTrackerOwnFrags(void *offset, quintptr_t mask, co VM_FLOAT(ret) = Stats_GetLastOwnFrag(seat, outptr, outlen); return ret; } +#endif static qintptr_t VARGS Plug_GetLocationName(void *offset, quintptr_t mask, const qintptr_t *arg) { @@ -1297,6 +1299,7 @@ void Plug_Client_Init(void) #ifdef QUAKEHUD Plug_RegisterBuiltin("GetTeamInfo", Plug_GetTeamInfo, PLUG_BIF_NEEDSRENDERER); Plug_RegisterBuiltin("GetWeaponStats", Plug_GetWeaponStats, PLUG_BIF_NEEDSRENDERER); + Plug_RegisterBuiltin("GetTrackerOwnFrags", Plug_GetTrackerOwnFrags, PLUG_BIF_NEEDSRENDERER); #endif Plug_RegisterBuiltin("GetLocationName", Plug_GetLocationName, PLUG_BIF_NEEDSRENDERER); Plug_RegisterBuiltin("GetPlayerInfo", Plug_GetPlayerInfo, PLUG_BIF_NEEDSRENDERER); @@ -1305,7 +1308,6 @@ void Plug_Client_Init(void) Plug_RegisterBuiltin("GetServerInfo", Plug_GetServerInfo, PLUG_BIF_NEEDSRENDERER); Plug_RegisterBuiltin("SetUserInfo", Plug_SetUserInfo, PLUG_BIF_NEEDSRENDERER); Plug_RegisterBuiltin("GetNetworkInfo", Plug_GetNetworkInfo, PLUG_BIF_NEEDSRENDERER); - Plug_RegisterBuiltin("GetTrackerOwnFrags", Plug_GetTrackerOwnFrags, PLUG_BIF_NEEDSRENDERER); Plug_RegisterBuiltin("S_RawAudio", Plug_S_RawAudio, PLUG_BIF_NEEDSRENDERER); diff --git a/engine/client/in_win.c b/engine/client/in_win.c index fe68a9be..74c60c39 100644 --- a/engine/client/in_win.c +++ b/engine/client/in_win.c @@ -1879,9 +1879,18 @@ void INS_Commands (void) K_GP_X, K_GP_Y, - //not part of xinput specs, but appended by us from analog triggers + //not part of xinput specs, but used to treat the various axis as buttons. + K_GP_LEFT_THUMB_UP, + K_GP_LEFT_THUMB_DOWN, + K_GP_LEFT_THUMB_LEFT, + K_GP_LEFT_THUMB_RIGHT, + K_GP_RIGHT_THUMB_UP, + K_GP_RIGHT_THUMB_DOWN, + K_GP_RIGHT_THUMB_LEFT, + K_GP_RIGHT_THUMB_RIGHT, + K_GP_LEFT_TRIGGER, - K_GP_RIGHT_TRIGGER + K_GP_RIGHT_TRIGGER, }; static const int mmjbuttons[32] = { @@ -2061,10 +2070,28 @@ static qboolean INS_ReadJoystick (struct wjoy_s *joy) joy->devstate = DS_PRESENT; joy->buttonstate = xistate.Gamepad.wButtons & 0xffff; + if (xistate.Gamepad.sThumbLY < -16364) + joy->buttonstate |= 0x00010000; + if (xistate.Gamepad.sThumbLY > 16364) + joy->buttonstate |= 0x00020000; + if (xistate.Gamepad.sThumbLX < -16364) + joy->buttonstate |= 0x00040000; + if (xistate.Gamepad.sThumbLX > 16364) + joy->buttonstate |= 0x00080000; + + if (xistate.Gamepad.sThumbRY < -16364) + joy->buttonstate |= 0x00100000; + if (xistate.Gamepad.sThumbRY > 16364) + joy->buttonstate |= 0x00200000; + if (xistate.Gamepad.sThumbRX < -16364) + joy->buttonstate |= 0x00400000; + if (xistate.Gamepad.sThumbRX > 16364) + joy->buttonstate |= 0x00800000; + if (xistate.Gamepad.bLeftTrigger >= 128) - joy->buttonstate |= 0x10000; + joy->buttonstate |= 0x01000000; if (xistate.Gamepad.bRightTrigger >= 128) - joy->buttonstate |= 0x20000; + joy->buttonstate |= 0x02000000; if (joy->devid != DEVID_UNSET) { diff --git a/engine/client/keys.c b/engine/client/keys.c index eb04ab14..c8151118 100644 --- a/engine/client/keys.c +++ b/engine/client/keys.c @@ -129,7 +129,7 @@ keyname_t keynames[] = {"RCTRL", K_RCTRL}, {"LSHIFT", K_LSHIFT}, {"RSHIFT", K_RSHIFT}, - {"ALT", K_ALT}, //depricated name + {"ALT", K_ALT}, //depricated name {"CTRL", K_CTRL}, //depricated name {"SHIFT", K_SHIFT}, //depricated name @@ -184,22 +184,34 @@ keyname_t keynames[] = {"KP_7", K_KP_HOME}, {"KP_8", K_KP_UPARROW}, {"KP_9", K_KP_PGUP}, + //dp compat + {"KP_PERIOD", K_KP_DEL}, + {"KP_DIVIDE", K_KP_SLASH}, + {"NUMLOCK", K_KP_NUMLOCK}, - {"MOUSE1", K_MOUSE1}, - {"MOUSE2", K_MOUSE2}, - {"MOUSE3", K_MOUSE3}, - {"MOUSE4", K_MOUSE4}, - {"MOUSE5", K_MOUSE5}, - {"MOUSE6", K_MOUSE6}, - {"MOUSE7", K_MOUSE7}, - {"MOUSE8", K_MOUSE8}, - {"MOUSE9", K_MOUSE9}, - {"MOUSE10", K_MOUSE10}, + + + {"MOUSE1", K_MOUSE1}, + {"MOUSE2", K_MOUSE2}, + {"MOUSE3", K_MOUSE3}, + {"MOUSE4", K_MOUSE4}, + {"MOUSE5", K_MOUSE5}, + {"MOUSE6", K_MOUSE6}, + {"MOUSE7", K_MOUSE7}, + {"MOUSE8", K_MOUSE8}, + {"MOUSE9", K_MOUSE9}, + {"MOUSE10", K_MOUSE10}, {"MWHEELUP", K_MWHEELUP}, {"MWHEELDOWN", K_MWHEELDOWN}, - {"LWIN", K_LWIN}, - {"RWIN", K_RWIN}, + {"LWIN", K_LWIN}, //windows name + {"RWIN", K_RWIN}, //windows name + {"WIN", K_WIN}, //depricated + {"RCOMMAND",K_RWIN}, //mac name + {"LCOMMAND",K_LWIN}, //mac name + {"COMMAND", K_WIN}, //quakespasm(mac) compat + {"LMETA", K_LWIN}, //linux name + {"RMETA", K_RWIN}, //linux name {"APP", K_APP}, {"MENU", K_APP}, {"SEARCH", K_SEARCH}, @@ -253,6 +265,7 @@ keyname_t keynames[] = {"SEMICOLON", ';'}, // because a raw semicolon seperates commands {"PLUS", '+'}, // because "shift++" is inferior to shift+plus + {"MINUS", '-'}, // because "shift+-" is inferior to shift+minus {"TILDE", '~'}, {"BACKQUOTE", '`'}, @@ -277,6 +290,62 @@ keyname_t keynames[] = {"GP_GUIDE", K_GP_GUIDE}, {"GP_UNKNOWN", K_GP_UNKNOWN}, + //names for playstation controllers + {"GP_CROSS", K_GP_A}, + {"GP_CIRCLE", K_GP_B}, + {"GP_SQUARE", K_GP_X}, + {"GP_TRIANGLE", K_GP_Y}, + + //axis->button emulation + {"GP_LTHUMB_UP", K_GP_LEFT_THUMB_UP}, + {"GP_LTHUMB_DOWN", K_GP_LEFT_THUMB_DOWN}, + {"GP_LTHUMB_LEFT", K_GP_LEFT_THUMB_LEFT}, + {"GP_LTHUMB_RIGHT", K_GP_LEFT_THUMB_RIGHT}, + {"GP_RTHUMB_UP", K_GP_RIGHT_THUMB_UP}, + {"GP_RTHUMB_DOWN", K_GP_RIGHT_THUMB_DOWN}, + {"GP_RTHUMB_LEFT", K_GP_RIGHT_THUMB_LEFT}, + {"GP_RTHUMB_RIGHT", K_GP_RIGHT_THUMB_RIGHT}, + +#ifndef QUAKETC + //dp compat + {"X360_DPAD_UP", K_GP_DPAD_UP}, + {"X360_DPAD_DOWN", K_GP_DPAD_DOWN}, + {"X360_DPAD_LEFT", K_GP_DPAD_LEFT}, + {"X360_DPAD_RIGHT", K_GP_DPAD_RIGHT}, + {"X360_START", K_GP_START}, + {"X360_BACK", K_GP_BACK}, + {"X360_LEFT_THUMB", K_GP_LEFT_THUMB}, + {"X360_RIGHT_THUMB", K_GP_RIGHT_THUMB}, + {"X360_LEFT_SHOULDER", K_GP_LEFT_SHOULDER}, + {"X360_RIGHT_SHOULDER", K_GP_RIGHT_SHOULDER}, + {"X360_A", K_GP_A}, + {"X360_B", K_GP_B}, + {"X360_X", K_GP_X}, + {"X360_Y", K_GP_Y}, + {"X360_LEFT_TRIGGER", K_GP_LEFT_TRIGGER}, + {"X360_RIGHT_TRIGGER", K_GP_RIGHT_TRIGGER}, + {"X360_LEFT_THUMB_UP", K_GP_LEFT_THUMB_UP}, + {"X360_LEFT_THUMB_DOWN", K_GP_LEFT_THUMB_DOWN}, + {"X360_LEFT_THUMB_LEFT", K_GP_LEFT_THUMB_LEFT}, + {"X360_LEFT_THUMB_RIGHT", K_GP_LEFT_THUMB_RIGHT}, + {"X360_RIGHT_THUMB_UP", K_GP_RIGHT_THUMB_UP}, + {"X360_RIGHT_THUMB_DOWN", K_GP_RIGHT_THUMB_DOWN}, + {"X360_RIGHT_THUMB_LEFT", K_GP_RIGHT_THUMB_LEFT}, + {"X360_RIGHT_THUMB_RIGHT", K_GP_RIGHT_THUMB_RIGHT}, + + //quakespasm compat + {"LTHUMB", K_GP_LEFT_THUMB}, + {"RTHUMB", K_GP_RIGHT_THUMB}, + {"LSHOULDER", K_GP_LEFT_SHOULDER}, + {"RSHOULDER", K_GP_RIGHT_SHOULDER}, + {"ABUTTON", K_GP_A}, + {"BBUTTON", K_GP_B}, + {"XBUTTON", K_GP_X}, + {"YBUTTON", K_GP_Y}, + {"LTRIGGER", K_GP_LEFT_TRIGGER}, + {"RTRIGGER", K_GP_RIGHT_TRIGGER}, +#endif + {NULL, 0} }; @@ -1000,9 +1069,11 @@ void Key_DefaultLinkClicked(console_t *con, char *text, char *info) } } -void Key_ConsoleRelease(console_t *con, int key, int unicode) +void Key_ConsoleRelease(console_t *con, int key, unsigned int unicode) { char *buffer; + if (key < 0) + key = 0; if (key == K_MOUSE1 && con->buttonsdown == CB_SELECT) { @@ -1438,14 +1509,14 @@ Key_Console Interactive line editing and console scrollback ==================== */ -qboolean Key_Console (console_t *con, unsigned int unicode, int key) +qboolean Key_Console (console_t *con, int key, unsigned int unicode) { qboolean ctrl = keydown[K_LCTRL] || keydown[K_RCTRL]; qboolean shift = keydown[K_LSHIFT] || keydown[K_RSHIFT]; int rkey = key; //weirdness for the keypad. - if ((unicode >= '0' && unicode <= '9') || unicode == '.') + if ((unicode >= '0' && unicode <= '9') || unicode == '.' || key < 0) key = 0; if (con->redirect) @@ -1906,7 +1977,7 @@ static char *Key_KeynumToStringRaw (int keynum) keyname_t *kn; static char tinystr[2]; - if (keynum == -1) + if (keynum < 0) return ""; if (keynum > 32 && keynum < 127 && keynum != '\'' && keynum != '\"') { // printable ascii @@ -2694,7 +2765,7 @@ void Key_Event (unsigned int devid, int key, unsigned int unicode, qboolean down { con->mousecursor[0] = mousecursor_x - ((con->flags & CONF_ISWINDOW)?con->wnd_x+8:0); con->mousecursor[1] = mousecursor_y - ((con->flags & CONF_ISWINDOW)?con->wnd_y:0); - if (Key_Console (con, unicode, key)) + if (Key_Console (con, key, unicode)) return; } else @@ -2792,7 +2863,8 @@ void Key_Event (unsigned int devid, int key, unsigned int unicode, qboolean down //csqc key codes may even have no standard keycode so cannot easily be bound from qc. switch(key) { - //left+right alts got split + //left+right alts/etc got split + //the generic name maps to the left key, so the right key needs to try the left case K_RALT: bkey = K_LALT; break; @@ -2802,6 +2874,9 @@ void Key_Event (unsigned int devid, int key, unsigned int unicode, qboolean down case K_RSHIFT: bkey = K_LSHIFT; break; + case K_RWIN: + bkey = K_LWIN; + break; //gamepad buttons should get fallbacks out of the box, even if they're not initially listed on the binds menu. //these may be redefined later... diff --git a/engine/client/keys.h b/engine/client/keys.h index a7a8d073..c3866bf3 100644 --- a/engine/client/keys.h +++ b/engine/client/keys.h @@ -202,6 +202,20 @@ K_GP_DPAD_LEFT = 253, K_GP_DPAD_RIGHT = 254, K_GP_UNKNOWN = 255, +//axis->button emulation. for weird people. +K_GP_LEFT_THUMB_UP, +K_GP_LEFT_THUMB_DOWN, +K_GP_LEFT_THUMB_LEFT, +K_GP_LEFT_THUMB_RIGHT, +K_GP_RIGHT_THUMB_UP, +K_GP_RIGHT_THUMB_DOWN, +K_GP_RIGHT_THUMB_LEFT, +K_GP_RIGHT_THUMB_RIGHT, +K_JOY_UP, +K_JOY_DOWN, +K_JOY_LEFT, +K_JOY_RIGHT, + K_MM_BROWSER_BACK, K_MM_BROWSER_FAVORITES, K_MM_BROWSER_FORWARD, @@ -220,6 +234,7 @@ K_MAX #define KEY_MODIFIER_SHIFT (1<<0) #define KEY_MODIFIER_ALT (1<<1) #define KEY_MODIFIER_CTRL (1<<2) +//#define KEY_MODIFIER_META (1<= 2) || qwinvermaj>6)?1:0; +#else + const int bppbias = 0; +#endif static const char *refreshopts[] = { @@ -2821,7 +2841,7 @@ void M_Menu_Video_f (void) MB_COMBORETURN("Size", resaspects[2], reschoices[2], info->ressize[2], "Select resolution for display."), MB_SPACING(-8), MB_COMBORETURN("Size", resaspects[3], reschoices[3], info->ressize[3], "Select resolution for display."), - MB_COMBOCVARRETURN("Color Depth", vid_bpp, bppopts, bppvalues, info->bppfixed, vid_bpp.description), + MB_COMBOCVARRETURN("Color Depth", vid_bpp, bppopts+bppbias, bppvalues+bppbias, info->bppfixed, vid_bpp.description), MB_COMBOCVARRETURN("Refresh Rate", vid_refreshrate, refreshopts, refreshvalues, info->hzfixed, vid_refreshrate.description), MB_SPACING(-24), // really hacky... // custom entries @@ -2852,6 +2872,7 @@ void M_Menu_Video_f (void) MB_SLIDER("View Size", scr_viewsize, 30, 120, 10, NULL), MB_COMBOCVAR("Gamma Mode", v_gamma, gammamodeopts, gammamodevalues, "Controls how gamma is applied"), MB_SLIDER("Gamma", v_gamma, 1.5, 0.25, -0.05, NULL), + MB_COMBOCVAR("Gamma Mode", vid_srgb, srgbopts, srgbvalues, "Controls the colour space to try to use."), MB_SLIDER("Contrast", v_contrast, 0.8, 3, 0.05, NULL), MB_END() }; diff --git a/engine/client/pr_clcmd.c b/engine/client/pr_clcmd.c index 494f6d37..d6741c82 100644 --- a/engine/client/pr_clcmd.c +++ b/engine/client/pr_clcmd.c @@ -140,29 +140,53 @@ int MP_TranslateFTEtoQCCodes(int code) case K_AUX31: return 814; case K_AUX32: return 815; - case K_GP_DPAD_UP: return 816; - case K_GP_DPAD_DOWN: return 817; - case K_GP_DPAD_LEFT: return 818; - case K_GP_DPAD_RIGHT: return 819; - case K_GP_START: return 820; - case K_GP_BACK: return 821; - case K_GP_LEFT_THUMB: return 822; - case K_GP_RIGHT_THUMB: return 823; - case K_GP_LEFT_SHOULDER:return 824; - case K_GP_RIGHT_SHOULDER:return 825; - case K_GP_A: return 826; - case K_GP_B: return 827; - case K_GP_X: return 828; - case K_GP_Y: return 829; - case K_GP_LEFT_TRIGGER: return 830; - case K_GP_RIGHT_TRIGGER:return 831; + case K_GP_DPAD_UP: return 816; + case K_GP_DPAD_DOWN: return 817; + case K_GP_DPAD_LEFT: return 818; + case K_GP_DPAD_RIGHT: return 819; + case K_GP_START: return 820; + case K_GP_BACK: return 821; + case K_GP_LEFT_THUMB: return 822; + case K_GP_RIGHT_THUMB: return 823; + case K_GP_LEFT_SHOULDER: return 824; + case K_GP_RIGHT_SHOULDER: return 825; + case K_GP_A: return 826; + case K_GP_B: return 827; + case K_GP_X: return 828; + case K_GP_Y: return 829; + case K_GP_LEFT_TRIGGER: return 830; + case K_GP_RIGHT_TRIGGER: return 831; + case K_GP_LEFT_THUMB_UP: return 832; + case K_GP_LEFT_THUMB_DOWN: return 833; + case K_GP_LEFT_THUMB_LEFT: return 834; + case K_GP_LEFT_THUMB_RIGHT: return 835; + case K_GP_RIGHT_THUMB_UP: return 836; + case K_GP_RIGHT_THUMB_DOWN: return 837; + case K_GP_RIGHT_THUMB_LEFT: return 838; + case K_GP_RIGHT_THUMB_RIGHT:return 839; + case K_JOY_UP: return 840; + case K_JOY_DOWN: return 841; + case K_JOY_LEFT: return 842; + case K_JOY_RIGHT: return 843; - case K_VOLUP: return -code; - case K_VOLDOWN: return -code; - case K_APP: return -code; + + case K_F13: + case K_F14: + case K_F15: + case K_POWER: + case K_LWIN: + case K_RWIN: + case K_VOLUP: + case K_VOLDOWN: + case K_APP: case K_SEARCH: return -code; - default: return code; + default: + if (code < 0) //negative values are 'qc-native' keys, for stuff that the api lacks. + return -code; + if (code >= 0 && code < 128) //ascii codes identical + return code; + return -code; //unknown key. } } @@ -308,18 +332,24 @@ int MP_TranslateQCtoFTECodes(int code) case 829: return K_GP_Y; case 830: return K_GP_LEFT_TRIGGER; case 831: return K_GP_RIGHT_TRIGGER; -// case 832: return K_GP_LEFT_THUMB_UP; -// case 833: return K_GP_LEFT_THUMB_DOWN; -// case 834: return K_GP_LEFT_THUMB_LEFT; -// case 835: return K_GP_LEFT_THUMB_RIGHT; -// case 836: return K_GP_RIGHT_THUMB_UP; -// case 837: return K_GP_RIGHT_THUMB_DOWN; -// case 838: return K_GP_RIGHT_THUMB_LEFT; -// case 839: return K_GP_RIGHT_THUMB_RIGHT; + case 832: return K_GP_LEFT_THUMB_UP; + case 833: return K_GP_LEFT_THUMB_DOWN; + case 834: return K_GP_LEFT_THUMB_LEFT; + case 835: return K_GP_LEFT_THUMB_RIGHT; + case 836: return K_GP_RIGHT_THUMB_UP; + case 837: return K_GP_RIGHT_THUMB_DOWN; + case 838: return K_GP_RIGHT_THUMB_LEFT; + case 839: return K_GP_RIGHT_THUMB_RIGHT; + case 840: return K_JOY_UP; + case 841: return K_JOY_DOWN; + case 842: return K_JOY_LEFT; + case 843: return K_JOY_RIGHT; default: if (code < 0) //negative values are 'fte-native' keys, for stuff that the api lacks. return -code; - return code; + if (code >= 0 && code < 128) + return code; + return -code; //these keys are not supported in fte. use negatives so that they can be correctly mapped back to qc codes if the need arises. no part of the engine will recognise them. } } @@ -328,15 +358,21 @@ void QCBUILTIN PF_cl_findkeysforcommand (pubprogfuncs_t *prinst, struct globalva { const char *cmdname = PR_GetStringOfs(prinst, OFS_PARM0); int bindmap = (prinst->callargc > 1)?G_FLOAT(OFS_PARM1):0; - int keynums[2]; + int keynums[16]; char keyname[512]; + size_t u; M_FindKeysForCommand(bindmap, 0, cmdname, keynums, NULL, countof(keynums)); keyname[0] = '\0'; - - Q_strncatz (keyname, va(" \'%i\'", MP_TranslateFTEtoQCCodes(keynums[0])), sizeof(keyname)); - Q_strncatz (keyname, va(" \'%i\'", MP_TranslateFTEtoQCCodes(keynums[1])), sizeof(keyname)); + for (u = 0; u < countof(keynums); u++) + { + if (keynums[u] >= 0) + keynums[u] = MP_TranslateFTEtoQCCodes(keynums[u]); + else if (u >= 2) //would ideally be 0, but nexuiz would bug out then. + break; + Q_strncatz (keyname, va(" \'%i\'", keynums[u]), sizeof(keyname)); + } RETURN_TSTRING(keyname); } diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index adc05315..59b4ce16 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -6192,6 +6192,10 @@ static struct { {"brush_findinvolume", PF_brush_findinvolume, 0}, #endif +#ifdef ENGINE_ROUTING + {"route_calculate", PF_route_calculate, 0}, +#endif + {"touchtriggers", PF_touchtriggers, 279},//void() touchtriggers = #279; {"skel_ragupdate", PF_skel_ragedit, 281},// (FTE_QC_RAGDOLL) {"skel_mmap", PF_skel_mmap, 282},// (FTE_QC_RAGDOLL) @@ -7168,6 +7172,7 @@ qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checks movevars.watersinkspeed = 60;//*pm_watersinkspeed.string?pm_watersinkspeed.value:60; movevars.flyfriction = 4;//*pm_flyfriction.string?pm_flyfriction.value:4; movevars.stepheight = PM_DEFAULTSTEPHEIGHT; + movevars.coordsize = 4; } for (i = 0; i < sizeof(csqc_builtin)/sizeof(csqc_builtin[0]); i++) diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c index fac3a9ae..d9b5f199 100644 --- a/engine/client/pr_menu.c +++ b/engine/client/pr_menu.c @@ -1097,8 +1097,6 @@ void QCBUILTIN PF_SubConDraw (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl Con_DrawOneConsole(con, con->flags & CONF_KEYFOCUSED, PR_CL_ChooseFont(world->g.drawfont, fontsize, fontsize), pos[0], pos[1], size[0], size[1], 0); } -qboolean Key_Console (console_t *con, unsigned int unicode, int key); -void Key_ConsoleRelease (console_t *con, unsigned int unicode, int key); void QCBUILTIN PF_SubConInput (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { const char *conname = PR_GetStringOfs(prinst, OFS_PARM0); @@ -1117,7 +1115,7 @@ void QCBUILTIN PF_SubConInput (pubprogfuncs_t *prinst, struct globalvars_s *pr_g if ((pa && qcinput_scan != pa) || (pb && pb != qcinput_unicode)) G_FLOAT(OFS_RETURN) = 0; else - G_FLOAT(OFS_RETURN) = Key_Console(con, pb, MP_TranslateQCtoFTECodes(pa)); + G_FLOAT(OFS_RETURN) = Key_Console(con, MP_TranslateQCtoFTECodes(pa), pb); break; case CSIE_KEYUP: //scan, char diff --git a/engine/client/r_part.c b/engine/client/r_part.c index 55e89c0d..297de68c 100644 --- a/engine/client/r_part.c +++ b/engine/client/r_part.c @@ -210,7 +210,10 @@ static void R_Clutter_Insert_Mesh(clutter_build_ctx_t *ctx, model_t *mod, float while(inf) { galiasskin_t *skins = inf->ofsskins; - re.framestate.g[FS_REG].frame[0] = randanim%inf->numanimations; + if (inf->numanimations >= 1) + re.framestate.g[FS_REG].frame[0] = randanim%inf->numanimations; + else + re.framestate.g[FS_REG].frame[0] = 0; if (skins->numframes) { unsigned int frame = randskin%skins->numframes; diff --git a/engine/client/renderer.c b/engine/client/renderer.c index 89c51409..9f993570 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -132,8 +132,8 @@ cvar_t r_fastsky = CVARF ("r_fastsky", "0", CVAR_ARCHIVE); cvar_t r_fastskycolour = CVARF ("r_fastskycolour", "0", CVAR_RENDERERCALLBACK|CVAR_SHADERSYSTEM); -cvar_t r_fb_bmodels = CVARAF("r_fb_bmodels", "1", - "gl_fb_bmodels", CVAR_SEMICHEAT|CVAR_RENDERERLATCH); +cvar_t r_fb_bmodels = CVARAFD("r_fb_bmodels", "1", + "gl_fb_bmodels", CVAR_SEMICHEAT|CVAR_RENDERERLATCH, "Enables loading lumas on the map, as well as any external bsp models."); cvar_t r_fb_models = CVARAFD ("r_fb_models", "1", "gl_fb_models", CVAR_SEMICHEAT, "Enables the use of lumas on models. Note that if ruleset_allow_fbmodels is enabled, then all models are unconditionally fullbright in deathmatch, because cheaters would set up their models like that anyway, hurrah for beating them at their own game. QuakeWorld players suck."); cvar_t r_skin_overlays = CVARF ("r_skin_overlays", "1", @@ -278,10 +278,10 @@ cvar_t vid_multisample = CVARFD ("vid_multisample", "0", cvar_t vid_refreshrate = CVARF ("vid_displayfrequency", "0", CVAR_ARCHIVE | CVAR_VIDEOLATCH); cvar_t vid_srgb = CVARFD ("vid_srgb", "0", - CVAR_ARCHIVE, "0: Off. Colour blending will be wrong.\n1: Only the framebuffer should use sRGB colourspace, textures and colours will be assumed to be linear. This has the effect of brightening the screen.\n2: Use sRGB extensions/support to ensure that the sh"); + CVAR_ARCHIVE, "-1: Only the framebuffer should use sRGB colourspace, textures and colours will be assumed to be linear. This has the effect of just brightening the screen according to a gamma ramp of about 2.2 (or .45 in quake's backwards gamma terms).\n0: Off. Colour blending will be wrong, you're likely to see obvious banding.\n1: Use sRGB extensions/support to ensure that the lighting aproximately matches real-world lighting (required for PBR).\n2: Attempt to use a linear floating-point framebuffer, which should enable monitor support for HDR.\nNote that driver behaviour varies by a disturbing amount, and much of the documentation conflicts with itself (the term 'linear' is awkward when the eye's perception of linear is non-linear)."); cvar_t vid_wndalpha = CVARD ("vid_wndalpha", "1", "When running windowed, specifies the window's transparency level."); #if defined(_WIN32) && defined(MULTITHREAD) -cvar_t vid_winthread = CVARFD ("vid_winthread", "", CVAR_ARCHIVE|CVAR_VIDEOLATCH, "When enabled, window messages will be handled by a separate thread. This allows the game to continue rendering when Microsoft Windows blocks while resizing etc."); +cvar_t vid_winthread = CVARFD ("vid_winthread", "", CVAR_ARCHIVE|CVAR_VIDEOLATCH, "When enabled, window messages will be handled by a separate thread. This allows the game to continue rendering when Microsoft Windows blocks while resizing, etc."); #endif //more readable defaults to match conwidth/conheight. cvar_t vid_width = CVARFD ("vid_width", "0", @@ -333,6 +333,9 @@ cvar_t vid_gl_context_es = CVARD ("vid_gl_context_es", "0", "Requests an Op cvar_t vid_gl_context_robustness = CVARD ("vid_gl_context_robustness", "1", "Attempt to enforce extra buffer protection in the gl driver, but can be slower with pre-gl3 hardware."); cvar_t vid_gl_context_selfreset = CVARD ("vid_gl_context_selfreset", "1", "Upon hardware failure, have the engine create a new context instead of depending on the drivers to restore everything. This can help to avoid graphics drivers randomly killing your game, and can help reduce memory requirements."); cvar_t vid_gl_context_noerror = CVARD ("vid_gl_context_noerror", "", "Disables OpenGL's error checks for a small performance speedup. May cause segfaults if stuff wasn't properly implemented/tested."); + +cvar_t gl_immutable_textures = CVARD ("gl_immutable_textures", "1", "Controls whether to use immutable GPU memory allocations for OpenGL textures. This potentially means less work for the drivers and thus higher framerates."); +cvar_t gl_immutable_buffers = CVARD ("gl_immutable_buffers", "1", "Controls whether to use immutable GPU memory allocations for static OpenGL vertex buffers. This potentially means less work for the drivers and thus higher framerates."); #endif #if 1 @@ -498,6 +501,9 @@ void GLRenderer_Init(void) Cvar_Register (&vid_gl_context_selfreset, GLRENDEREROPTIONS); Cvar_Register (&vid_gl_context_noerror, GLRENDEREROPTIONS); + Cvar_Register (&gl_immutable_textures, GLRENDEREROPTIONS); + Cvar_Register (&gl_immutable_buffers, GLRENDEREROPTIONS); + //renderer Cvar_Register (&gl_affinemodels, GLRENDEREROPTIONS); @@ -974,6 +980,7 @@ void Renderer_Init(void) Cvar_Register (&r_fb_bmodels, GRAPHICALNICETIES); Cvar_Register (&r_fb_models, GRAPHICALNICETIES); +// Cvar_Register (&r_fullbrights, GRAPHICALNICETIES); //dpcompat: 1 if r_fb_bmodels&&r_fb_models Cvar_Register (&r_skin_overlays, GRAPHICALNICETIES); Cvar_Register (&r_globalskin_first, GRAPHICALNICETIES); Cvar_Register (&r_globalskin_count, GRAPHICALNICETIES); @@ -1298,16 +1305,16 @@ void R_ShutdownRenderer(qboolean devicetoo) Media_VideoRestarting(); + //these functions need to be able to cope with vid_reload, so don't clear them. + //they also need to be able to cope with being re-execed in the case of failed startup. if (R_DeInit) { TRACE(("dbg: R_ApplyRenderer: R_DeInit\n")); R_DeInit(); - R_DeInit = NULL; } if (Draw_Shutdown) Draw_Shutdown(); - Draw_Shutdown = NULL; TRACE(("dbg: R_ApplyRenderer: SCR_DeInit\n")); SCR_DeInit(); @@ -1316,7 +1323,6 @@ void R_ShutdownRenderer(qboolean devicetoo) { TRACE(("dbg: R_ApplyRenderer: VID_DeInit\n")); VID_DeInit(); - VID_DeInit = NULL; } COM_FlushTempoaryPacks(); diff --git a/engine/client/snd_mem.c b/engine/client/snd_mem.c index 015bd0aa..d4185fc1 100644 --- a/engine/client/snd_mem.c +++ b/engine/client/snd_mem.c @@ -26,6 +26,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. typedef struct { + int format; int rate; int width; int numchannels; @@ -717,6 +718,19 @@ static qboolean QDECL S_LoadDoomSound (sfx_t *s, qbyte *data, size_t datalen, in } #endif +void S_ShortedLittleFloats(void *p, size_t samples) +{ + short *out = p; + float *in = p; + int t; + while(samples --> 0) + { + t = LittleFloat(*in++) * 32767; + t = bound(-32768, t, 32767); + *out++ = t; + } +} + static qboolean QDECL S_LoadWavSound (sfx_t *s, qbyte *data, size_t datalen, int sndspeed) { wavinfo_t info; @@ -732,10 +746,28 @@ static qboolean QDECL S_LoadWavSound (sfx_t *s, qbyte *data, size_t datalen, int return false; } - if (info.width == 1) + if (info.format == 1 && info.width == 1) COM_CharBias(data + info.dataofs, info.samples*info.numchannels); - else if (info.width == 2) + else if (info.format == 1 && info.width == 2) COM_SwapLittleShortBlock((short *)(data + info.dataofs), info.samples*info.numchannels); + else if (info.format == 3 && info.width == 4) + { + S_ShortedLittleFloats(data + info.dataofs, info.samples*info.numchannels); + info.width = 2; + } + else + { + s->loadstate = SLS_FAILED; + switch(info.format) + { + case 1: + case 3: Con_Printf ("%s has an unsupported width (%i bits).\n", s->name, info.width*8); break; + case 6: Con_Printf ("%s uses unsupported a-law format.\n", s->name); break; + case 7: Con_Printf ("%s uses unsupported mu-law format.\n", s->name); break; + default: Con_Printf ("%s has an unsupported format.\n", s->name); break; + } + return false; + } return ResampleSfx (s, info.rate, info.numchannels, info.width, info.samples, info.loopstart, data + info.dataofs); } @@ -1050,7 +1082,6 @@ static wavinfo_t GetWavinfo (char *name, qbyte *wav, int wavlength) { wavinfo_t info; int i; - int format; int samples; int chunklen; wavctx_t ctx; @@ -1087,12 +1118,7 @@ static wavinfo_t GetWavinfo (char *name, qbyte *wav, int wavlength) return info; } ctx.data_p += 8; - format = GetLittleShort(&ctx); - if (format != 1) - { - Con_Printf("Microsoft PCM format only\n"); - return info; - } + info.format = GetLittleShort(&ctx); info.numchannels = GetLittleShort(&ctx); info.rate = GetLittleLong(&ctx); diff --git a/engine/client/vid.h b/engine/client/vid.h index f23dd270..230b5716 100644 --- a/engine/client/vid.h +++ b/engine/client/vid.h @@ -45,7 +45,7 @@ typedef struct { int height; int fullscreen; //0 = windowed. 1 = fullscreen (mode changes). 2 = borderless+maximized qboolean stereo; - qboolean srgb; + int srgb; //<0 = gamma-only. 0 = no srgb at all, >0 full srgb, including textures and stuff int bpp; //16, 24(aka 32), 30, and 48 are meaningful int rate; int wait; //-1 = default, 0 = off, 1 = on, 2 = every other @@ -125,9 +125,6 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette); // the palette data will go away after the call, so it must be copied off if // the video driver will need it again -void GLVID_Shutdown (void); -// Called at shutdown - void GLVID_Crashed(void); void GLVID_Update (vrect_t *rects); diff --git a/engine/client/view.c b/engine/client/view.c index 257eda26..503e29ae 100644 --- a/engine/client/view.c +++ b/engine/client/view.c @@ -95,6 +95,7 @@ cvar_t v_ringcshift = CVAR("v_ringcshift", "1"); cvar_t v_pentcshift = CVAR("v_pentcshift", "1"); cvar_t v_gunkick = CVAR("v_gunkick", "0"); cvar_t v_gunkick_q2 = CVAR("v_gunkick_q2", "1"); +cvar_t v_viewmodel_quake = CVARD("r_viewmodel_quake", "0", "Controls whether to use weird viewmodel movements from vanilla quake."); //name comes from MarkV. cvar_t v_viewheight = CVAR("v_viewheight", "0"); cvar_t v_projectionmode = CVAR("v_projectionmode", "0"); @@ -1002,7 +1003,7 @@ void V_CalcGunPositionAngle (playerview_t *pv, float bob) // fudge position around to keep amount of weapon visible // roughly equal with different FOV //FIXME: should use y fov, not viewsize. - if (r_refdef.drawsbar) //no sbar = no viewsize cvar. + if (r_refdef.drawsbar && v_viewmodel_quake.ival) //no sbar = no viewsize cvar. { if (scr_viewsize.value == 110) pv->vw_origin[2] += 1; diff --git a/engine/common/cmd.c b/engine/common/cmd.c index cc8e04a0..9bf70c42 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -773,7 +773,9 @@ void Cmd_Exec_f (void) } #ifndef QUAKETC //hack to try to work around nquake's b0rkedness - if (!strncmp(s, "// ", 3)) + if (!strncmp(s, "// This is nQuake's Frogbot config", 33)) + s = "echo Refusing to exec nQuake's Frogbot config"; //otherwise many people with nquake installed will be fucked over whenever they try playing singleplayer + else if (!strncmp(s, "// ", 3)) { char *eol = strstr(s, "\n"); if (eol) @@ -4052,6 +4054,8 @@ void Cmd_Shutdown(void) } } + Cmd_Complete(NULL, false); //NULL frees any cached results without generating new ones. + while(cmd_functions) { c = cmd_functions; diff --git a/engine/common/fs.c b/engine/common/fs.c index b65274ce..1186010e 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -3118,7 +3118,9 @@ const gamemode_info_t gamemode_info[] = { //for quake, we also allow extracting all files from paks. some people think it loads faster that way or something. #ifndef NOLEGACY //cmdline switch exename protocol name(dpmaster) identifying file exec dir1 dir2 dir3 dir(fte) full name - {"-quake", "q1", "FTE-Quake DarkPlaces-Quake", {"id1/pak0.pak", "id1/quake.rc"},QCFG, {"id1", "qw", "*fte"}, "Quake", "https://fte.triptohell.info/downloadables.php" /*,"id1/pak0.pak|http://quakeservers.nquake.com/qsw106.zip|http://nquake.localghost.net/qsw106.zip|http://qw.quakephil.com/nquake/qsw106.zip|http://fnu.nquake.com/qsw106.zip"*/}, + //two quakes - one without extra game dirs which should avoid fuckups from nquake's configs (which screw over cvars that every nq progs.dat depends upon but which the ezquake id1-only less-compatible gamecode ignores). + {"-quake", "qw", "FTE-Quake DarkPlaces-Quake", {"id1/pak0.pak", "id1/quake.rc"},QCFG, {"id1", "qw", "*fte"}, "Quake", "https://fte.triptohell.info/downloadables.php" /*,"id1/pak0.pak|http://quakeservers.nquake.com/qsw106.zip|http://nquake.localghost.net/qsw106.zip|http://qw.quakephil.com/nquake/qsw106.zip|http://fnu.nquake.com/qsw106.zip"*/}, + {"-netquake", "q1", "FTE-Quake DarkPlaces-Quake", {"id1/pak0.pak", "id1/quake.rc"},QCFG, {"id1"}, "Quake", "https://fte.triptohell.info/downloadables.php" /*,"id1/pak0.pak|http://quakeservers.nquake.com/qsw106.zip|http://nquake.localghost.net/qsw106.zip|http://qw.quakephil.com/nquake/qsw106.zip|http://fnu.nquake.com/qsw106.zip"*/}, //quake's mission packs should not be favoured over the base game nor autodetected //third part mods also tend to depend upon the mission packs for their huds, even if they don't use any other content. //and q2 also has a rogue/pak0.pak file that we don't want to find and cause quake2 to look like dissolution of eternity diff --git a/engine/common/pmove.h b/engine/common/pmove.h index f7286d26..f6e0a369 100644 --- a/engine/common/pmove.h +++ b/engine/common/pmove.h @@ -120,6 +120,8 @@ typedef struct { qboolean slidyslopes; int stepheight; + qbyte coordsize; + unsigned int flags; } movevars_t; diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index 13057bcf..fcf5ebdb 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -92,6 +92,10 @@ void PF_Common_RegisterCvars(void) #endif WPhys_Init(); + +#ifdef ENGINE_ROUTING + PR_Route_Init(); +#endif } qofs_t PR_ReadBytesString(char *str) @@ -6227,6 +6231,9 @@ void PR_Common_Shutdown(pubprogfuncs_t *progs, qboolean errored) #endif PR_fclose_progs(progs); search_close_progs(progs, !errored); +#ifdef ENGINE_ROUTING + PR_Route_Shutdown (progs->parms->user); +#endif #ifdef TEXTEDITOR Editor_ProgsKilled(progs); #endif diff --git a/engine/common/pr_common.h b/engine/common/pr_common.h index 18fe8e77..2026001e 100644 --- a/engine/common/pr_common.h +++ b/engine/common/pr_common.h @@ -80,6 +80,14 @@ int MP_TranslateFTEtoQCCodes(int code); int MP_TranslateQCtoFTECodes(int code); qboolean WPhys_Push (world_t *w, wedict_t *pusher, vec3_t move, vec3_t amove); +#ifdef ENGINE_ROUTING +//sv_move.c routing +void QCBUILTIN PF_route_calculate (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); +void PR_Route_Shutdown (world_t *world); +void PR_Route_Visualise (void); +void PR_Route_Init (void); +#endif + //pr_cmds.c builtins that need to be moved to a common. void VARGS PR_BIError(pubprogfuncs_t *progfuncs, char *format, ...) LIKEPRINTF(2); void QCBUILTIN PF_print (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); diff --git a/engine/common/world.h b/engine/common/world.h index 9b99723f..523b1697 100644 --- a/engine/common/world.h +++ b/engine/common/world.h @@ -264,6 +264,10 @@ struct world_s qboolean rbe_hasphysicsents; rigidbodyengine_t *rbe; #endif + +#ifdef ENGINE_ROUTING + void *waypoints; +#endif }; typedef struct world_s world_t; diff --git a/engine/d3d/d3d11_backend.c b/engine/d3d/d3d11_backend.c index 8b148e91..db88b95d 100644 --- a/engine/d3d/d3d11_backend.c +++ b/engine/d3d/d3d11_backend.c @@ -672,18 +672,9 @@ static void D3D11BE_ApplyShaderBits(unsigned int bits, void **blendstatecache) */ } - if (delta & (SBITS_MISC_DEPTHEQUALONLY|SBITS_MISC_DEPTHCLOSERONLY|SBITS_MISC_NODEPTHTEST|SBITS_MISC_DEPTHWRITE)) + if (delta & (SBITS_DEPTHFUNC_BITS|SBITS_MISC_NODEPTHTEST|SBITS_MISC_DEPTHWRITE)) { - unsigned int key = 0; - if (bits & SBITS_MISC_DEPTHEQUALONLY) - key |= 1u<<0; - if (bits & SBITS_MISC_DEPTHCLOSERONLY) - key |= 1u<<1; - if (bits & SBITS_MISC_NODEPTHTEST) - key |= 1u<<2; - if (bits & SBITS_MISC_DEPTHWRITE) - key |= 1u<<3; - + unsigned int key = (bits&(SBITS_DEPTHFUNC_BITS|SBITS_MISC_NODEPTHTEST|SBITS_MISC_DEPTHWRITE))>>16; if (shaderstate.depthstates[key]) ID3D11DeviceContext_OMSetDepthStencilState(d3ddevctx, shaderstate.depthstates[key], 0); else @@ -698,18 +689,21 @@ static void D3D11BE_ApplyShaderBits(unsigned int bits, void **blendstatecache) else depthdesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; - switch(bits & (SBITS_MISC_DEPTHEQUALONLY|SBITS_MISC_DEPTHCLOSERONLY)) + switch(bits & SBITS_DEPTHFUNC_BITS) { default: - case 0: + case SBITS_DEPTHFUNC_CLOSEREQUAL: depthdesc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL; break; - case SBITS_MISC_DEPTHEQUALONLY: + case SBITS_DEPTHFUNC_EQUAL: depthdesc.DepthFunc = D3D11_COMPARISON_EQUAL; break; - case SBITS_MISC_DEPTHCLOSERONLY: + case SBITS_DEPTHFUNC_CLOSER: depthdesc.DepthFunc = D3D11_COMPARISON_LESS; break; + case SBITS_DEPTHFUNC_FURTHER: + depthdesc.DepthFunc = D3D11_COMPARISON_GREATER; + break; } //make sure the stencil part is actually valid, even if we're not using it. diff --git a/engine/d3d/d3d8_backend.c b/engine/d3d/d3d8_backend.c index f7c57ba2..bfd053a0 100644 --- a/engine/d3d/d3d8_backend.c +++ b/engine/d3d/d3d8_backend.c @@ -394,20 +394,23 @@ static void BE_ApplyShaderBits(unsigned int bits) IDirect3DDevice8_SetRenderState(pD3DDev8, D3DRS_ZENABLE, TRUE); } - if (delta & (SBITS_MISC_DEPTHEQUALONLY|SBITS_MISC_DEPTHCLOSERONLY)) + if (delta & SBITS_DEPTHFUNC_BITS) { - switch(bits & (SBITS_MISC_DEPTHEQUALONLY|SBITS_MISC_DEPTHCLOSERONLY)) + switch(bits & SBITS_DEPTHFUNC_BITS) { default: - case 0: + case SBITS_DEPTHFUNC_CLOSEREQUAL: IDirect3DDevice8_SetRenderState(pD3DDev8, D3DRS_ZFUNC, D3DCMP_LESSEQUAL); break; - case SBITS_MISC_DEPTHEQUALONLY: + case SBITS_DEPTHFUNC_EQUAL: IDirect3DDevice8_SetRenderState(pD3DDev8, D3DRS_ZFUNC, D3DCMP_EQUAL); break; - case SBITS_MISC_DEPTHCLOSERONLY: + case SBITS_DEPTHFUNC_CLOSER: IDirect3DDevice8_SetRenderState(pD3DDev8, D3DRS_ZFUNC, D3DCMP_LESS); break; + case SBITS_DEPTHFUNC_FURTHER: + IDirect3DDevice8_SetRenderState(pD3DDev8, D3DRS_ZFUNC, D3DCMP_GREATER); + break; } } diff --git a/engine/d3d/d3d_backend.c b/engine/d3d/d3d_backend.c index a4ff89c7..ffbcbfd1 100644 --- a/engine/d3d/d3d_backend.c +++ b/engine/d3d/d3d_backend.c @@ -464,20 +464,23 @@ static void BE_ApplyShaderBits(unsigned int bits) IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ZENABLE, TRUE); } - if (delta & (SBITS_MISC_DEPTHEQUALONLY|SBITS_MISC_DEPTHCLOSERONLY)) + if (delta & SBITS_DEPTHFUNC_BITS) { - switch(bits & (SBITS_MISC_DEPTHEQUALONLY|SBITS_MISC_DEPTHCLOSERONLY)) + switch(bits & SBITS_DEPTHFUNC_BITS) { default: - case 0: + case SBITS_DEPTHFUNC_CLOSEREQUAL: IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ZFUNC, D3DCMP_LESSEQUAL); break; - case SBITS_MISC_DEPTHEQUALONLY: + case SBITS_DEPTHFUNC_EQUAL: IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ZFUNC, D3DCMP_EQUAL); break; - case SBITS_MISC_DEPTHCLOSERONLY: + case SBITS_DEPTHFUNC_CLOSER: IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ZFUNC, D3DCMP_LESS); break; + case SBITS_DEPTHFUNC_FURTHER: + IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ZFUNC, D3DCMP_GREATER); + break; } } @@ -2679,7 +2682,7 @@ static void BE_DrawMeshChain_Internal(void) IDirect3DDevice9_SetTextureStageState(pD3DDev9, passno, D3DTSS_ALPHAARG1, D3DTA_CONSTANT); IDirect3DDevice9_SetTextureStageState(pD3DDev9, passno, D3DTSS_ALPHAARG2, D3DTA_TEXTURE); IDirect3DDevice9_SetTextureStageState(pD3DDev9, passno, D3DTSS_ALPHAOP, D3DTOP_MODULATE); - BE_ApplyShaderBits(SBITS_SRCBLEND_SRC_ALPHA | SBITS_DSTBLEND_ONE_MINUS_SRC_ALPHA | (useshader->numpasses?SBITS_MISC_DEPTHEQUALONLY:0)); + BE_ApplyShaderBits(SBITS_SRCBLEND_SRC_ALPHA | SBITS_DSTBLEND_ONE_MINUS_SRC_ALPHA | (useshader->numpasses?SBITS_DEPTHFUNC_EQUAL:0)); allocvertexbuffer(shaderstate.dynst_buff[passno], shaderstate.dynst_size, &shaderstate.dynst_offs[passno], &map, vertcount*sizeof(vec2_t)); for (mno = 0, vertcount = 0; mno < shaderstate.nummeshes; mno++) @@ -2754,7 +2757,7 @@ static void BE_DrawMeshChain_Internal(void) IDirect3DDevice9_SetTextureStageState(pD3DDev9, passno, D3DTSS_ALPHAARG1, D3DTA_CONSTANT); IDirect3DDevice9_SetTextureStageState(pD3DDev9, passno, D3DTSS_ALPHAARG2, D3DTA_TEXTURE); IDirect3DDevice9_SetTextureStageState(pD3DDev9, passno, D3DTSS_ALPHAOP, D3DTOP_MODULATE); - BE_ApplyShaderBits(SBITS_SRCBLEND_SRC_ALPHA | SBITS_DSTBLEND_ONE_MINUS_SRC_ALPHA | (useshader->numpasses?SBITS_MISC_DEPTHEQUALONLY:0)); + BE_ApplyShaderBits(SBITS_SRCBLEND_SRC_ALPHA | SBITS_DSTBLEND_ONE_MINUS_SRC_ALPHA | (useshader->numpasses?SBITS_DEPTHFUNC_EQUAL:0)); allocvertexbuffer(shaderstate.dynst_buff[passno], shaderstate.dynst_size, &shaderstate.dynst_offs[passno], &map, vertcount*sizeof(vec2_t)); for (mno = 0, vertcount = 0; mno < shaderstate.nummeshes; mno++) @@ -3542,7 +3545,7 @@ static void BE_SubmitMeshesSortList(batch_t *sortlist) if (R_DrawSkyChain (batch)) continue; } - else if (shaderstate.mode != BEM_FOG && shaderstate.mode != BEM_CREPUSCULAR && shaderstate.mode != BEM_WIREFRAME) + else if (/*shaderstate.mode != BEM_FOG &&*/ shaderstate.mode != BEM_CREPUSCULAR && shaderstate.mode != BEM_WIREFRAME) continue; } diff --git a/engine/gl/gl_alias.c b/engine/gl/gl_alias.c index bed98955..7994b059 100644 --- a/engine/gl/gl_alias.c +++ b/engine/gl/gl_alias.c @@ -2737,6 +2737,7 @@ static void BE_GenPolyBatches(batch_t **batches) } } void R_HalfLife_GenerateBatches(entity_t *e, batch_t **batches); +void PR_Route_Visualise(void); void BE_GenModelBatches(batch_t **batches, const dlight_t *dl, unsigned int bemode) { int i; @@ -2766,6 +2767,9 @@ void BE_GenModelBatches(batch_t **batches, const dlight_t *dl, unsigned int bemo #ifndef CLIENTONLY SV_AddDebugPolygons(); #endif +#ifdef ENGINE_ROUTING + PR_Route_Visualise(); +#endif //the alias cache is a backend thing that provides support for multiple entities using the same skeleton. //thus it needs to be cleared so that it won't reuse the cache over multiple frames. diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index 282a6e78..7c5a96f4 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -1036,7 +1036,7 @@ static void RevertToKnownState(void) } #endif - shaderstate.shaderbits &= ~(SBITS_MISC_DEPTHEQUALONLY|SBITS_MISC_DEPTHCLOSERONLY|SBITS_MASK_BITS|SBITS_AFFINE); + shaderstate.shaderbits &= ~(SBITS_DEPTHFUNC_BITS|SBITS_MASK_BITS|SBITS_AFFINE); shaderstate.shaderbits |= SBITS_MISC_DEPTHWRITE; shaderstate.shaderbits &= ~(SBITS_BLEND_BITS); @@ -1528,27 +1528,13 @@ void GLBE_Shutdown(void) //on vid_reload, the gl drivers might have various things bound that have since been destroyed/etc //so reset that state to avoid any issues with state - /*shaderstate.sourcevbo = &shaderstate.dummyvbo; - memset(shaderstate.sourcevbo, 0, sizeof(*shaderstate.sourcevbo)); - shaderstate.pendingcolourvbo = 0; - shaderstate.pendingcolourpointer = NULL; - shaderstate.pendingvertexvbo = 0; - shaderstate.pendingvertexpointer = NULL; - for (u = 0; u < SHADER_TMU_MAX; u++) - { - shaderstate.pendingtexcoordparts[u] = 0; - shaderstate.pendingtexcoordvbo[u] = 0; - shaderstate.pendingtexcoordpointer[u] = NULL; - }*/ - if (sh_config.progs_supported) - BE_ApplyAttributes(0, (1u<numpasses?SBITS_MISC_DEPTHEQUALONLY:0)); + BE_SendPassBlendDepthMask(SBITS_SRCBLEND_SRC_ALPHA | SBITS_DSTBLEND_ONE_MINUS_SRC_ALPHA | (shaderstate.curshader->numpasses?SBITS_DEPTHFUNC_EQUAL:0)); GenerateTCFog(0, shaderstate.curbatch->fog); BE_EnableShaderAttributes((1u< 1) - { //full srgb wanted - qglEnable(GL_FRAMEBUFFER_SRGB); - vid.flags |= VID_SRGB_FB_LINEAR; - } else - { //srgb wanted only for the framebuffer, for gamma tricks. + { vid.flags |= VID_SRGB_FB_LINEAR; qglEnable(GL_FRAMEBUFFER_SRGB); } } - if ((vid.flags & VID_SRGB_FB) && vid_srgb.ival != 1) + if ((vid.flags & VID_SRGB_FB) && vid_srgb.ival >= 0) vid.flags |= VID_SRGBAWARE; else vid.flags &= ~VID_SRGBAWARE; diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index 24b8d1cb..12408d29 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -2301,13 +2301,24 @@ qboolean Mod_LoadVertexNormals (model_t *loadmodel, qbyte *mod_base, lump_t *l) float *out; int i, count; - in = (void *)(mod_base + l->fileofs); - if (l->filelen % sizeof(vec3_t)) + if (l) { - Con_Printf (CON_ERROR "MOD_LoadBmodel: funny lump size in %s\n", loadmodel->name); - return false; + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(vec3_t)) + { + Con_Printf (CON_ERROR "MOD_LoadBmodel: funny lump size in %s\n", loadmodel->name); + return false; + } + count = l->filelen / sizeof(vec3_t); + } + else + { + in = Q1BSPX_FindLump("VERTEXNORMALS", &count); + if (in) + count /= sizeof(vec3_t); + else + count = 0; } - count = l->filelen / sizeof(vec3_t); if (count != loadmodel->numvertexes) return false; //invalid number of verts there, can't use this. diff --git a/engine/gl/gl_screen.c b/engine/gl/gl_screen.c index c1b0f27f..e1117650 100644 --- a/engine/gl/gl_screen.c +++ b/engine/gl/gl_screen.c @@ -77,12 +77,12 @@ qboolean GLSCR_UpdateScreen (void) //vid_srgb can be changed between 0 and 1, but other values need texture reloads. do that without too much extra weirdness. if ((vid.flags & VID_SRGB_CAPABLE) && gl_config.arb_framebuffer_srgb) { //srgb-capable - if (vid_srgb.ival > 1 && (vid.flags & VID_SRGBAWARE)) + if (vid_srgb.ival > 0 && (vid.flags & VID_SRGBAWARE)) { //full srgb wanted (and textures are loaded) qglEnable(GL_FRAMEBUFFER_SRGB); vid.flags |= VID_SRGB_FB_LINEAR; } - else if (vid_srgb.ival==1 || (vid.flags & VID_SRGBAWARE)) + else if (vid_srgb.ival < 0 || (vid.flags & VID_SRGBAWARE)) { //srgb wanted only for the framebuffer, for gamma tricks. qglEnable(GL_FRAMEBUFFER_SRGB); vid.flags |= VID_SRGB_FB_LINEAR; diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index 7242d645..af02e749 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -216,18 +216,20 @@ static float Shader_FloatArgument(shader_t *shader, char *arg) #define HASH_SIZE 128 -enum shaderparsemode_e -{ - SPM_DEFAULT, /*quake3/fte internal*/ - SPM_DOOM3, -}; +#define SPF_DEFAULT 0u /*quake3/fte internal*/ +#define SPF_PROGRAMIFY (1u<<0) /*quake3/fte internal*/ +#define SPF_DOOM3 (1u<<1) /*any commands, args, etc, should be interpretted according to doom3's norms*/ -static struct +typedef struct { - enum shaderparsemode_e mode; + shader_t *s; //the shader we're parsing + shaderpass_t *pass; //the pass we're currently parsing + char *ptr; //the src file pointer we're at + + const char *forcedshader; + unsigned int parseflags; //SPF_* qboolean droppass; - qboolean forceprogramify; //for dpwater compat, used to generate a program int dpwatertype; float reflectmin; @@ -244,7 +246,8 @@ static struct float offsetmappingbias; float specularexpscale; //*32 ish float specularvalscale; //*1 ish -} parsestate; +} parsestate_t; +static parsestate_t parsestate; //FIXME typedef struct shaderkey_s { @@ -255,7 +258,8 @@ typedef struct shaderkey_s typedef struct shadercachefile_s { char *data; size_t length; - enum shaderparsemode_e parsemode; + unsigned int parseflags; + char forcedshadername[64]; struct shadercachefile_s *next; char name[1]; } shadercachefile_t; @@ -279,11 +283,11 @@ void *shader_active_hash_mem; //static float r_skyheight; char *Shader_Skip( char *ptr ); -static qboolean Shader_Parsetok(shader_t *shader, shaderpass_t *pass, shaderkey_t *keys, char *token, char **ptr); +static qboolean Shader_Parsetok(parsestate_t *ps, shaderkey_t *keys, char *token); static void Shader_ParseFunc(shader_t *shader, char **args, shaderfunc_t *func); -static void Shader_MakeCache(const char *path); -static qboolean Shader_LocateSource(char *name, char **buf, size_t *bufsize, size_t *offset, enum shaderparsemode_e *parsemode); -static void Shader_ReadShader(shader_t *s, char *shadersource, int parsemode); +static void Shader_MakeCache(const char *path, unsigned int parseflags); +static qboolean Shader_LocateSource(char *name, char **buf, size_t *bufsize, size_t *offset, shadercachefile_t **sourcefile); +static void Shader_ReadShader(shader_t *s, char *shadersource, shadercachefile_t *sourcefile); static qboolean Shader_ParseShader(char *parsename, shader_t *s); //=========================================================================== @@ -794,7 +798,7 @@ texid_t R_LoadColourmapImage(void) static texid_t Shader_FindImage ( char *name, int flags ) { extern texid_t missing_texture_normal; - if (parsestate.mode == SPM_DOOM3) + if (parsestate.parseflags & SPF_DOOM3) { if (!Q_stricmp (name, "_default")) return r_whiteimage; /*fixme*/ @@ -2437,7 +2441,7 @@ static void Shader_DP_Camera(shader_t *shader, shaderpass_t *pass, char **ptr) } static void Shader_DP_Water(shader_t *shader, shaderpass_t *pass, char **ptr) { - parsestate.forceprogramify = true; + parsestate.parseflags |= SPF_PROGRAMIFY; parsestate.dpwatertype |= 3; parsestate.reflectmin = Shader_ParseFloat(shader, ptr, 0); @@ -2450,7 +2454,7 @@ static void Shader_DP_Water(shader_t *shader, shaderpass_t *pass, char **ptr) } static void Shader_DP_Reflect(shader_t *shader, shaderpass_t *pass, char **ptr) { - parsestate.forceprogramify = true; + parsestate.parseflags |= SPF_PROGRAMIFY; parsestate.dpwatertype |= 1; parsestate.reflectmin = 1; @@ -2460,7 +2464,7 @@ static void Shader_DP_Reflect(shader_t *shader, shaderpass_t *pass, char **ptr) } static void Shader_DP_Refract(shader_t *shader, shaderpass_t *pass, char **ptr) { - parsestate.forceprogramify = true; + parsestate.parseflags |= SPF_PROGRAMIFY; parsestate.dpwatertype |= 2; parsestate.refractfactor = Shader_ParseFloat(shader, ptr, 0); @@ -3339,17 +3343,25 @@ static void Shaderpass_DepthFunc (shader_t *shader, shaderpass_t *pass, char **p { char *token; - pass->shaderbits &= ~(SBITS_MISC_DEPTHEQUALONLY|SBITS_MISC_DEPTHCLOSERONLY); + pass->shaderbits &= ~(SBITS_DEPTHFUNC_BITS); token = Shader_ParseString (ptr); if (!Q_stricmp (token, "equal")) - pass->shaderbits |= SBITS_MISC_DEPTHEQUALONLY; + pass->shaderbits |= SBITS_DEPTHFUNC_EQUAL; else if (!Q_stricmp (token, "lequal")) - ; //default + pass->shaderbits |= SBITS_DEPTHFUNC_CLOSEREQUAL; //default else if (!Q_stricmp (token, "less")) - pass->shaderbits |= SBITS_MISC_DEPTHCLOSERONLY; + pass->shaderbits |= SBITS_DEPTHFUNC_CLOSER; else if (!Q_stricmp (token, "greater")) - pass->shaderbits |= SBITS_MISC_DEPTHCLOSERONLY|SBITS_MISC_DEPTHEQUALONLY; + pass->shaderbits |= SBITS_DEPTHFUNC_FURTHER; +// else if (!Q_stricmp (token, "gequal")) +// pass->shaderbits |= SBITS_DEPTHFUNC_FURTHEREQUAL; +// else if (!Q_stricmp (token, "nequal")) +// pass->shaderbits |= SBITS_DEPTHFUNC_NOTEQUAL; +// else if (!Q_stricmp (token, "never")) +// pass->shaderbits |= SBITS_DEPTHFUNC_NEVER; +// else if (!Q_stricmp (token, "always")) +// pass->shaderbits |= SBITS_DEPTHFUNC_ALWAYS; else Con_DPrintf("Invalid depth func %s\n", token); } @@ -3799,7 +3811,12 @@ void Shader_Free (shader_t *shader) int QDECL Shader_InitCallback (const char *name, qofs_t size, time_t mtime, void *param, searchpathfuncs_t *spath) { - Shader_MakeCache(name); + Shader_MakeCache(name, SPF_DEFAULT); + return true; +} +int QDECL Shader_InitCallback_Doom3 (const char *name, qofs_t size, time_t mtime, void *param, searchpathfuncs_t *spath) +{ + Shader_MakeCache(name, SPF_DOOM3); return true; } @@ -3879,7 +3896,7 @@ void Shader_FlushCache(void) } } -static void Shader_MakeCache(const char *path) +static void Shader_MakeCache(const char *path, unsigned int parseflags) { unsigned int key; char *buf, *ptr, *token; @@ -3901,6 +3918,7 @@ static void Shader_MakeCache(const char *path) strcpy(cachefile->name, path); size = FS_LoadFile(path, (void **)&cachefile->data); cachefile->length = size; + cachefile->parseflags = parseflags; if (filelink) filelink->next = cachefile; else @@ -3923,6 +3941,59 @@ static void Shader_MakeCache(const char *path) ptr = buf = cachefile->data; size = cachefile->length; + + //look for meta comments. + while (1) + { + //parse metas + while (*ptr == ' ' || *ptr == '\t') + ptr++; + if (ptr[0] == '\r' && ptr[1] == '\n') + ptr+=2; //blank line with dos ending + else if (ptr[0] == '\r' || ptr[0] == '\n') + ptr+=1; //blank line with mac or unix ending + else if (ptr[0] == '/' && ptr[1] == '/') + { + char *e = strchr(ptr, '\n'); + if (e) + e++; + else + e = ptr + strlen(ptr); + + ptr += 2; + while (*ptr == ' ' || *ptr == '\t') + ptr++; + if (!strncmp(ptr, "meta:", 5)) + { + ptr+=5; + + token = COM_ParseExt (&ptr, false, true); + if (!strcmp(token, "forceprogramify")) + { + cachefile->parseflags |= SPF_PROGRAMIFY; + token = COM_ParseExt (&ptr, false, true); + if (*token) + Q_strncpyz(cachefile->forcedshadername, token, sizeof(cachefile->forcedshadername)); + } + else + Con_DPrintf("unknown shader meta term \"%s\" in %s\n", token, name); + + while (*ptr == ' ' || *ptr == '\t') + ptr++; + if (*ptr != '\r' && *ptr != '\n') + { + while (*ptr && (*ptr != '\r' && *ptr != '\n')) + ptr++; + Con_DPrintf("junk after shader meta in %s\n", name); + } + } + ptr = e; + } + else + break; //the actual shader started. + } + + //now scan the file looking for each individual shader. do { if ( ptr - buf >= size ) @@ -3954,7 +4025,7 @@ static void Shader_MakeCache(const char *path) } while ( ptr ); } -static qboolean Shader_LocateSource(char *name, char **buf, size_t *bufsize, size_t *offset, enum shaderparsemode_e *parsemode) +static qboolean Shader_LocateSource(char *name, char **buf, size_t *bufsize, size_t *offset, shadercachefile_t **sourcefile) { unsigned int key; shadercache_t *cache; @@ -3971,7 +4042,7 @@ static qboolean Shader_LocateSource(char *name, char **buf, size_t *bufsize, siz *buf = cache->source->data; *bufsize = cache->source->length; *offset = cache->offset; - *parsemode = cache->source->parsemode; + *sourcefile = cache->source; } return true; } @@ -4333,8 +4404,9 @@ static qboolean Shader_Conditional_Read(shader_t *shader, struct scondinfo_s *co return true; } -void Shader_Readpass (shader_t *shader, char **ptr) +void Shader_Readpass (parsestate_t *ps) { + shader_t *shader = ps->s; char *token; shaderpass_t *pass; static shader_t dummy; @@ -4368,21 +4440,23 @@ void Shader_Readpass (shader_t *shader, char **ptr) if (shader->flags & SHADER_NOMIPMAPS) pass->flags |= SHADER_PASS_NOMIPMAP; - while ( *ptr ) + ps->pass = pass; + + while ( ps->ptr ) { - token = COM_ParseExt (ptr, true, true); + token = COM_ParseExt (&ps->ptr, true, true); if ( !token[0] ) { continue; } - else if (!Shader_Conditional_Read(shader, &cond, token, ptr)) + else if (!Shader_Conditional_Read(shader, &cond, token, &ps->ptr)) { if ( token[0] == '}' ) break; else if (token[0] == '{') Con_Printf("unexpected indentation in %s\n", shader->name); - else if ( Shader_Parsetok (shader, pass, shaderpasskeys, token, ptr) ) + else if ( Shader_Parsetok (ps, shaderpasskeys, token) ) break; } } @@ -4479,11 +4553,12 @@ void Shader_Readpass (shader_t *shader, char **ptr) shader->numpasses--; } shader->flags = oldflags; - return; } + ps->pass = NULL; } -static qboolean Shader_Parsetok (shader_t *shader, shaderpass_t *pass, shaderkey_t *keys, char *token, char **ptr) +//we've read the first token, now make sense of it and any args +static qboolean Shader_Parsetok(parsestate_t *ps, shaderkey_t *keys, char *token) { shaderkey_t *key; char *prefix; @@ -4513,9 +4588,9 @@ static qboolean Shader_Parsetok (shader_t *shader, shaderpass_t *pass, shaderkey if (!prefix || (prefix && key->prefix && !Q_strncasecmp(prefix, key->prefix, strlen(key->prefix)))) { if (key->func) - key->func ( shader, pass, ptr ); + key->func ( ps->s, ps->pass, &ps->ptr ); - return ( ptr && *ptr && **ptr == '}' ); + return (ps->ptr && *ps->ptr == '}' ); } } } @@ -4523,15 +4598,15 @@ static qboolean Shader_Parsetok (shader_t *shader, shaderpass_t *pass, shaderkey if (!toolchainprefix) //we don't really give a damn about prefixes owned by various toolchains - they shouldn't affect us. { if (prefix) - Con_DPrintf("Unknown shader directive parsing %s: \"%s\"\n", shader->name, prefix); + Con_DPrintf("Unknown shader directive parsing %s: \"%s\"\n", ps->s->name, prefix); else - Con_DPrintf("Unknown shader directive parsing %s: \"%s\"\n", shader->name, token); + Con_DPrintf("Unknown shader directive parsing %s: \"%s\"\n", ps->s->name, token); } // Next Line - while (ptr) + while (ps->ptr) { - token = COM_ParseExt(ptr, false, true); + token = COM_ParseExt(&ps->ptr, false, true); if ( !token[0] ) { break; @@ -4563,7 +4638,7 @@ void Shader_SetPassFlush (shaderpass_t *pass, shaderpass_t *pass2) return; /*rgbgen must be identity too except if the later pass is identity_ligting, in which case all is well and we can switch the first pass to identity_lighting instead*/ - if (pass2->rgbgen == RGB_GEN_IDENTITY_LIGHTING && pass2->blendmode == PBM_MODULATE && pass->rgbgen == RGB_GEN_IDENTITY) + if (pass2->rgbgen == RGB_GEN_IDENTITY_LIGHTING && (pass2->blendmode == PBM_OVERBRIGHT || pass2->blendmode == PBM_MODULATE) && pass->rgbgen == RGB_GEN_IDENTITY) { if (pass->blendmode == PBM_REPLACE) pass->blendmode = PBM_REPLACELIGHT; @@ -4574,8 +4649,8 @@ void Shader_SetPassFlush (shaderpass_t *pass, shaderpass_t *pass2) else if (pass2->rgbgen != RGB_GEN_IDENTITY || (pass->rgbgen != RGB_GEN_IDENTITY && pass->rgbgen != RGB_GEN_IDENTITY_LIGHTING)) return; - /*if its alphatest, don't merge with anything other than lightmap*/ - if ((pass->shaderbits & SBITS_ATEST_BITS) && (!(pass2->shaderbits & SBITS_MISC_DEPTHEQUALONLY) || pass2->texgen != T_GEN_LIGHTMAP)) + /*if its alphatest, don't merge with anything other than lightmap (although equal stuff can be merged)*/ + if ((pass->shaderbits & SBITS_ATEST_BITS) && (((pass2->shaderbits & SBITS_DEPTHFUNC_BITS) != SBITS_DEPTHFUNC_EQUAL) || pass2->texgen != T_GEN_LIGHTMAP)) return; if ((pass->shaderbits & SBITS_MASK_BITS) != (pass2->shaderbits & SBITS_MASK_BITS)) @@ -4655,7 +4730,7 @@ const char *Shader_AlphaMaskProgArgs(shader_t *s) void Shader_Programify (shader_t *s) { unsigned int reflectrefract = 0; - char *prog = NULL; + const char *prog = NULL; const char *mask; char args[1024]; qboolean eightbit = false; @@ -4699,7 +4774,9 @@ void Shader_Programify (shader_t *s) return;*/ } - if (parsestate.dpwatertype) + if (parsestate.forcedshader) + prog = parsestate.forcedshader; + else if (parsestate.dpwatertype) { prog = va("altwater%s#USEMODS#FRESNEL_EXP=2.0" //variable parts @@ -4717,7 +4794,7 @@ void Shader_Programify (shader_t *s) parsestate.wateralpha ); //clear out blending and force regular depth. - s->passes[0].shaderbits &= ~(SBITS_BLEND_BITS|SBITS_MISC_NODEPTHTEST|SBITS_MISC_DEPTHEQUALONLY|SBITS_MISC_DEPTHCLOSERONLY); + s->passes[0].shaderbits &= ~(SBITS_BLEND_BITS|SBITS_MISC_NODEPTHTEST|SBITS_DEPTHFUNC_BITS); s->passes[0].shaderbits |= SBITS_MISC_DEPTHWRITE; if (parsestate.dpwatertype & 1) @@ -4733,7 +4810,6 @@ void Shader_Programify (shader_t *s) } else if (modellighting) { - pass = modellighting; eightbit = r_softwarebanding && (qrenderer == QR_OPENGL) && sh_config.progs_supported; if (eightbit) prog = "defaultskin#EIGHTBIT"; @@ -4742,7 +4818,6 @@ void Shader_Programify (shader_t *s) } else if (lightmap) { - pass = modellighting; eightbit = r_softwarebanding && (qrenderer == QR_OPENGL || qrenderer == QR_VULKAN) && sh_config.progs_supported; if (eightbit) prog = "defaultwall#EIGHTBIT"; @@ -4751,14 +4826,20 @@ void Shader_Programify (shader_t *s) } else if (vertexlighting) { - pass = vertexlighting; - prog = "default2d"; + if (r_forceprogramify.ival < 0) + prog = "defaultfill"; + else + { + pass = vertexlighting; + prog = "default2d"; + } } else { - pass = NULL; - prog = "default2d"; - return; + if (r_forceprogramify.ival < 0) + prog = "defaultfill"; + else + return; } args[0] = 0; @@ -5231,7 +5312,7 @@ done:; } } - if (!s->prog && sh_config.progs_supported && (r_forceprogramify.ival || parsestate.forceprogramify)) + if (!s->prog && sh_config.progs_supported && (r_forceprogramify.ival || (parsestate.parseflags & SPF_PROGRAMIFY))) { if (r_forceprogramify.ival >= 2) { @@ -5239,7 +5320,7 @@ done:; s->passes[0].numtcmods = 0; //DP sucks and doesn't use normalized texture coords *if* there's a shader specified. so lets ignore any extra scaling that this imposes. if (s->passes[0].shaderbits & SBITS_ATEST_BITS) //mimic DP's limited alphafunc support s->passes[0].shaderbits = (s->passes[0].shaderbits & ~SBITS_ATEST_BITS) | SBITS_ATEST_GE128; - s->passes[0].shaderbits &= ~SBITS_MISC_DEPTHEQUALONLY; //DP ignores this too. + s->passes[0].shaderbits &= ~SBITS_DEPTHFUNC_BITS; //DP ignores this too. } Shader_Programify(s); } @@ -5867,7 +5948,7 @@ void Shader_DefaultScript(const char *shortname, shader_t *s, const void *args) if (*f == '{') { f++; - Shader_ReadShader(s, (void*)f, SPM_DEFAULT); + Shader_ReadShader(s, (void*)f, 0); } }; @@ -5934,30 +6015,15 @@ void Shader_DefaultBSPLM(const char *shortname, shader_t *s, const void *args) "}\n" ); } - if (!builtin && ((sh_config.progs_supported && (qrenderer == QR_OPENGL||qrenderer == QR_DIRECT3D9)) || sh_config.progs_required)) + //d3d has no position-invariant. this results in all sorts of glitches, so try not to use it. + if (!builtin && ((sh_config.progs_supported && (qrenderer == QR_OPENGL/*||qrenderer == QR_DIRECT3D9*/)) || sh_config.progs_required)) { builtin = ( "{\n" "fte_program defaultwall\n" "{\n" - //FIXME: these maps are a legacy thing, and could be removed if third-party glsl properly contains s_diffuse "map $diffuse\n" "}\n" - "{\n" - "map $lightmap\n" - "}\n" - "{\n" - "map $normalmap\n" - "}\n" - "{\n" - "map $deluxmap\n" - "}\n" - "{\n" - "map $fullbright\n" - "}\n" - "{\n" - "map $specular\n" - "}\n" "}\n" ); } @@ -6643,18 +6709,18 @@ void Shader_Default2D(const char *shortname, shader_t *s, const void *genargs) } } -static qboolean Shader_ReadShaderTerms(shader_t *s, char **shadersource, int parsemode, struct scondinfo_s *cond) +static qboolean Shader_ReadShaderTerms(parsestate_t *ps, struct scondinfo_s *cond) { char *token; - if (!*shadersource) + if (!ps->ptr) return false; - token = COM_ParseExt (shadersource, true, true); + token = COM_ParseExt (&ps->ptr, true, true); if ( !token[0] ) return true; - else if (!Shader_Conditional_Read(s, cond, token, shadersource)) + else if (!Shader_Conditional_Read(ps->s, cond, token, &ps->ptr)) { int i; for (i = 0; shadermacros[i].name; i++) @@ -6666,9 +6732,9 @@ static qboolean Shader_ReadShaderTerms(shader_t *s, char **shadersource, int par char *body; char arg[SHADER_MACRO_ARGS][256]; //parse args until the end of the line - while (*shadersource) + while (ps->ptr) { - token = COM_ParseExt(shadersource, false, true); + token = COM_ParseExt(&ps->ptr, false, true); if ( !token[0] ) { break; @@ -6680,30 +6746,37 @@ static qboolean Shader_ReadShaderTerms(shader_t *s, char **shadersource, int par } } body = shadermacros[i].body; - Shader_ReadShaderTerms(s, &body, parsemode, cond); + Shader_ReadShaderTerms(ps, cond); return true; } } if (token[0] == '}') return false; else if (token[0] == '{') - Shader_Readpass(s, shadersource); - else if (Shader_Parsetok(s, NULL, shaderkeys, token, shadersource)) + Shader_Readpass(ps); + else if (Shader_Parsetok(ps, shaderkeys, token)) return false; } return true; } //loads a shader string into an existing shader object, and finalises it and stuff -static void Shader_ReadShader(shader_t *s, char *shadersource, int parsemode) +static void Shader_ReadShader(shader_t *s, char *shadersource, shadercachefile_t *sourcefile) { struct scondinfo_s cond = {0}; - char *shaderstart = shadersource; memset(&parsestate, 0, sizeof(parsestate)); - parsestate.mode = parsemode; + if (sourcefile) + { + parsestate.forcedshader = *sourcefile->forcedshadername?sourcefile->forcedshadername:NULL; + parsestate.parseflags = sourcefile->parseflags; + } + else + parsestate.parseflags = 0; parsestate.specularexpscale = 1; parsestate.specularvalscale = 1; + parsestate.ptr = shadersource; + parsestate.s = s; if (!s->defaulttextures) { @@ -6714,7 +6787,7 @@ static void Shader_ReadShader(shader_t *s, char *shadersource, int parsemode) // set defaults s->flags = SHADER_CULL_FRONT; - while (Shader_ReadShaderTerms(s, &shadersource, parsemode, &cond)) + while (Shader_ReadShaderTerms(&parsestate, &cond)) { } @@ -6728,11 +6801,11 @@ static void Shader_ReadShader(shader_t *s, char *shadersource, int parsemode) //querying the shader body often requires generating the shader, which then gets parsed. if (saveshaderbody) { - size_t l = shadersource - shaderstart; + size_t l = parsestate.ptr?parsestate.ptr - shadersource:0; Z_Free(*saveshaderbody); *saveshaderbody = BZ_Malloc(l+1); (*saveshaderbody)[l] = 0; - memcpy(*saveshaderbody, shaderstart, l); + memcpy(*saveshaderbody, shadersource, l); saveshaderbody = NULL; } } @@ -6741,9 +6814,9 @@ static qboolean Shader_ParseShader(char *parsename, shader_t *s) { size_t offset = 0, length; char *buf = NULL; - enum shaderparsemode_e parsemode = SPM_DEFAULT; + shadercachefile_t *sourcefile = NULL; - if (Shader_LocateSource(parsename, &buf, &length, &offset, &parsemode)) + if (Shader_LocateSource(parsename, &buf, &length, &offset, &sourcefile)) { // the shader is in the shader scripts if (buf && offset < length ) @@ -6761,7 +6834,7 @@ static qboolean Shader_ParseShader(char *parsename, shader_t *s) Shader_Reset(s); - Shader_ReadShader(s, file, parsemode); + Shader_ReadShader(s, file, sourcefile); return true; } @@ -6931,6 +7004,7 @@ static char *Shader_DecomposePass(char *o, shaderpass_t *p, qboolean simple) { switch(p->rgbgen) { + default: sprintf(o, "RGB_GEN_? "); break; case RGB_GEN_ENTITY: sprintf(o, "RGB_GEN_ENTITY "); break; case RGB_GEN_ONE_MINUS_ENTITY: sprintf(o, "RGB_GEN_ONE_MINUS_ENTITY "); break; case RGB_GEN_VERTEX_LIGHTING: sprintf(o, "RGB_GEN_VERTEX_LIGHTING "); break; @@ -6938,7 +7012,6 @@ static char *Shader_DecomposePass(char *o, shaderpass_t *p, qboolean simple) case RGB_GEN_ONE_MINUS_VERTEX: sprintf(o, "RGB_GEN_ONE_MINUS_VERTEX "); break; case RGB_GEN_IDENTITY_LIGHTING: sprintf(o, "RGB_GEN_IDENTITY_LIGHTING "); break; case RGB_GEN_IDENTITY_OVERBRIGHT: sprintf(o, "RGB_GEN_IDENTITY_OVERBRIGHT "); break; - default: case RGB_GEN_IDENTITY: sprintf(o, "RGB_GEN_IDENTITY "); break; case RGB_GEN_CONST: sprintf(o, "RGB_GEN_CONST "); break; case RGB_GEN_ENTITY_LIGHTING_DIFFUSE: sprintf(o, "RGB_GEN_ENTITY_LIGHTING_DIFFUSE "); break; @@ -6946,15 +7019,41 @@ static char *Shader_DecomposePass(char *o, shaderpass_t *p, qboolean simple) case RGB_GEN_WAVE: sprintf(o, "RGB_GEN_WAVE "); break; case RGB_GEN_TOPCOLOR: sprintf(o, "RGB_GEN_TOPCOLOR "); break; case RGB_GEN_BOTTOMCOLOR: sprintf(o, "RGB_GEN_BOTTOMCOLOR "); break; + case RGB_GEN_UNKNOWN: sprintf(o, "RGB_GEN_UNKNOWN "); break; + } + o+=strlen(o); + sprintf(o, "\n"); o+=strlen(o); + + switch(p->alphagen) + { + default: sprintf(o, "ALPHA_GEN_? "); break; + case ALPHA_GEN_ENTITY: sprintf(o, "ALPHA_GEN_ENTITY "); break; + case ALPHA_GEN_WAVE: sprintf(o, "ALPHA_GEN_WAVE "); break; + case ALPHA_GEN_PORTAL: sprintf(o, "ALPHA_GEN_PORTAL "); break; + case ALPHA_GEN_SPECULAR: sprintf(o, "ALPHA_GEN_SPECULAR "); break; + case ALPHA_GEN_IDENTITY: sprintf(o, "ALPHA_GEN_IDENTITY "); break; + case ALPHA_GEN_VERTEX: sprintf(o, "ALPHA_GEN_VERTEX "); break; + case ALPHA_GEN_CONST: sprintf(o, "ALPHA_GEN_CONST "); break; } o+=strlen(o); sprintf(o, "\n"); o+=strlen(o); } + if (p->prog) + { + sprintf(o, "program\n"); + o+=strlen(o); + } + if (p->shaderbits & SBITS_MISC_DEPTHWRITE) { sprintf(o, "SBITS_MISC_DEPTHWRITE\n"); o+=strlen(o); } if (p->shaderbits & SBITS_MISC_NODEPTHTEST) { sprintf(o, "SBITS_MISC_NODEPTHTEST\n"); o+=strlen(o); } - if (p->shaderbits & SBITS_MISC_DEPTHEQUALONLY) { sprintf(o, "SBITS_MISC_DEPTHEQUALONLY\n"); o+=strlen(o); } - if (p->shaderbits & SBITS_MISC_DEPTHCLOSERONLY) { sprintf(o, "SBITS_MISC_DEPTHCLOSERONLY\n"); o+=strlen(o); } + else switch (p->shaderbits & SBITS_DEPTHFUNC_BITS) + { + case SBITS_DEPTHFUNC_EQUAL: sprintf(o, "depthfunc equal\n"); break; + case SBITS_DEPTHFUNC_CLOSER: sprintf(o, "depthfunc less\n"); break; + case SBITS_DEPTHFUNC_CLOSEREQUAL: sprintf(o, "depthfunc lequal\n"); break; + case SBITS_DEPTHFUNC_FURTHER: sprintf(o, "depthfunc greater\n"); break; + } if (p->shaderbits & SBITS_TESSELLATION) { sprintf(o, "SBITS_TESSELLATION\n"); o+=strlen(o); } if (p->shaderbits & SBITS_AFFINE) { sprintf(o, "SBITS_AFFINE\n"); o+=strlen(o); } if (p->shaderbits & SBITS_MASK_BITS) { sprintf(o, "SBITS_MASK_BITS\n"); o+=strlen(o); } @@ -7005,35 +7104,76 @@ static char *Shader_DecomposePass(char *o, shaderpass_t *p, qboolean simple) switch(p->shaderbits & SBITS_ATEST_BITS) { + case SBITS_ATEST_NONE: break; case SBITS_ATEST_GE128: sprintf(o, "SBITS_ATEST_GE128\n"); break; case SBITS_ATEST_LT128: sprintf(o, "SBITS_ATEST_LT128\n"); break; case SBITS_ATEST_GT0: sprintf(o, "SBITS_ATEST_GT0\n"); break; } o+=strlen(o); + return o; } static char *Shader_DecomposeSubPass(char *o, shaderpass_t *p, qboolean simple) { + int i; if (!simple) { + switch(p->tcgen) + { + default: sprintf(o, "TC_GEN_? "); break; + case TC_GEN_BASE: sprintf(o, "TC_GEN_BASE "); break; + case TC_GEN_LIGHTMAP: sprintf(o, "TC_GEN_LIGHTMAP "); break; + case TC_GEN_ENVIRONMENT: sprintf(o, "TC_GEN_ENVIRONMENT "); break; + case TC_GEN_DOTPRODUCT: sprintf(o, "TC_GEN_DOTPRODUCT "); break; + case TC_GEN_VECTOR: sprintf(o, "TC_GEN_VECTOR "); break; + case TC_GEN_NORMAL: sprintf(o, "TC_GEN_NORMAL "); break; + case TC_GEN_SVECTOR: sprintf(o, "TC_GEN_SVECTOR "); break; + case TC_GEN_TVECTOR: sprintf(o, "TC_GEN_TVECTOR "); break; + case TC_GEN_SKYBOX: sprintf(o, "TC_GEN_SKYBOX "); break; + case TC_GEN_WOBBLESKY: sprintf(o, "TC_GEN_WOBBLESKY "); break; + case TC_GEN_REFLECT: sprintf(o, "TC_GEN_REFLECT "); break; + case TC_GEN_UNSPECIFIED: sprintf(o, "TC_GEN_UNSPECIFIED "); break; + } + o+=strlen(o); + sprintf(o, "\n"); o+=strlen(o); + + for (i = 0; i < p->numtcmods; i++) + { + switch(p->tcmods[i].type) + { + default: sprintf(o, "TCMOD_GEN_? "); break; + case SHADER_TCMOD_NONE: sprintf(o, "SHADER_TCMOD_NONE "); break; + case SHADER_TCMOD_SCALE: sprintf(o, "SHADER_TCMOD_SCALE "); break; + case SHADER_TCMOD_SCROLL: sprintf(o, "SHADER_TCMOD_SCROLL "); break; + case SHADER_TCMOD_STRETCH: sprintf(o, "SHADER_TCMOD_STRETCH "); break; + case SHADER_TCMOD_ROTATE: sprintf(o, "SHADER_TCMOD_ROTATE "); break; + case SHADER_TCMOD_TRANSFORM: sprintf(o, "SHADER_TCMOD_TRANSFORM "); break; + case SHADER_TCMOD_TURB: sprintf(o, "SHADER_TCMOD_TURB "); break; + case SHADER_TCMOD_PAGE: sprintf(o, "SHADER_TCMOD_PAGE "); break; + } + o+=strlen(o); + sprintf(o, "\n"); o+=strlen(o); + } + + switch(p->blendmode) { - default: - case PBM_MODULATE: sprintf(o, "modulate "); break; - case PBM_OVERBRIGHT: sprintf(o, "overbright "); break; - case PBM_DECAL: sprintf(o, "decal "); break; - case PBM_ADD:sprintf(o, "add "); break; - case PBM_DOTPRODUCT: sprintf(o, "dotproduct "); break; - case PBM_REPLACE: sprintf(o, "replace "); break; - case PBM_REPLACELIGHT: sprintf(o, "replacelight "); break; - case PBM_MODULATE_PREV_COLOUR: sprintf(o, "modulate_prev "); break; + default: sprintf(o, "PBM_? "); break; + case PBM_MODULATE: sprintf(o, "PBM_MODULATE "); break; + case PBM_OVERBRIGHT: sprintf(o, "PBM_OVERBRIGHT "); break; + case PBM_DECAL: sprintf(o, "PBM_DECAL "); break; + case PBM_ADD: sprintf(o, "PBM_ADD "); break; + case PBM_DOTPRODUCT: sprintf(o, "PBM_DOTPRODUCT "); break; + case PBM_REPLACE: sprintf(o, "PBM_REPLACE "); break; + case PBM_REPLACELIGHT: sprintf(o, "PBM_REPLACELIGHT "); break; + case PBM_MODULATE_PREV_COLOUR: sprintf(o, "PBM_MODULATE_PREV_COLOUR "); break; } o+=strlen(o); } switch(p->texgen) { - default: + default: sprintf(o, "T_GEN_? "); break; case T_GEN_SINGLEMAP: if (p->anim_frames[0]) { @@ -7096,6 +7236,7 @@ static char *Shader_DecomposeSubPass(char *o, shaderpass_t *p, qboolean simple) case T_GEN_VIDEOMAP: sprintf(o, "videomap "); break; case T_GEN_CUBEMAP: sprintf(o, "cubemap "); break; case T_GEN_3DMAP: sprintf(o, "3dmap "); break; + case T_GEN_GBUFFERCASE: sprintf(o, "gbuffer%i ",p->texgen-T_GEN_GBUFFER0); break; } o+=strlen(o); @@ -7113,6 +7254,7 @@ char *Shader_Decompose(shader_t *s) switch (s->sort) { + default: sprintf(o, "sort %i\n", s->sort); break; case SHADER_SORT_NONE: sprintf(o, "sort %i (SHADER_SORT_NONE)\n", s->sort); break; case SHADER_SORT_RIPPLE: sprintf(o, "sort %i (SHADER_SORT_RIPPLE)\n", s->sort); break; case SHADER_SORT_DEFERREDLIGHT: sprintf(o, "sort %i (SHADER_SORT_DEFERREDLIGHT)\n", s->sort); break; @@ -7126,7 +7268,6 @@ char *Shader_Decompose(shader_t *s) case SHADER_SORT_BLEND: sprintf(o, "sort %i (SHADER_SORT_BLEND)\n", s->sort); break; case SHADER_SORT_ADDITIVE: sprintf(o, "sort %i (SHADER_SORT_ADDITIVE)\n", s->sort); break; case SHADER_SORT_NEAREST: sprintf(o, "sort %i (SHADER_SORT_NEAREST)\n", s->sort); break; - default: sprintf(o, "sort %i\n", s->sort); break; } o+=strlen(o); @@ -7149,7 +7290,7 @@ char *Shader_Decompose(shader_t *s) o = Shader_DecomposePass(o, p, false); for (j = 0; j < p->numMergedPasses; j++) - o = Shader_DecomposeSubPass(o, p+j, false); + o = Shader_DecomposeSubPass(o, p+j, !!p->prog); sprintf(o, "}\n"); o+=strlen(o); } } @@ -7338,7 +7479,7 @@ void Shader_DoReload(void) if (ruleset_allow_shaders.ival) { - COM_EnumerateFiles("materials/*.mtr", Shader_InitCallback, NULL); + COM_EnumerateFiles("materials/*.mtr", Shader_InitCallback_Doom3, NULL); COM_EnumerateFiles("shaders/*.shader", Shader_InitCallback, NULL); COM_EnumerateFiles("scripts/*.shader", Shader_InitCallback, NULL); COM_EnumerateFiles("scripts/*.rscript", Shader_InitCallback, NULL); diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c index f65277a9..48f046e6 100644 --- a/engine/gl/gl_vidcommon.c +++ b/engine/gl/gl_vidcommon.c @@ -4,6 +4,10 @@ #include "gl_draw.h" #include "shader.h" + +extern cvar_t gl_immutable_textures; +extern cvar_t gl_immutable_buffers; + #ifndef GL_STATIC //standard gles2 opengl calls. void (APIENTRY *qglBlendFunc) (GLenum sfactor, GLenum dfactor); @@ -913,7 +917,8 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name)) #endif { if ((!gl_config.gles && gl_config.glversion >= 4.4) || GL_CheckExtension("GL_ARB_buffer_storage")) - qglBufferStorage = (void *)getglext("glBufferStorage"); //no arb postfix even with the extension form of it. + if (gl_immutable_buffers.ival) + qglBufferStorage = (void *)getglext("glBufferStorage"); //no arb postfix even with the extension form of it. } #ifdef GL_STATIC @@ -1129,16 +1134,16 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name)) else gl_config.geometryshaders = false; + qglTexStorage2D = NULL; + qglTexStorage3D = NULL; if ((!gl_config.gles && gl_config.glversion >= 4.2) || ( gl_config.gles && gl_config.glversion >= 3.0)) { //from gles3.0 or gl4.2 onwards - qglTexStorage2D = getglext("glTexStorage2D"); - qglTexStorage3D = getglext("glTexStorage3D"); - } - else - { - qglTexStorage2D = NULL; - qglTexStorage3D = NULL; + if (gl_immutable_textures.ival) + { + qglTexStorage2D = getglext("glTexStorage2D"); + qglTexStorage3D = getglext("glTexStorage3D"); + } } #ifdef GL_STATIC @@ -2743,6 +2748,293 @@ static void GLSlang_ProgAutoFields(program_t *prog, const char *progname, cvar_t } } +void GL_ForgetPointers(void) +{ //its at times like this that I wish I had put all of these into a struct. + //but GL_STATIC and webgl makes that sub-optimal. *sigh* +#ifndef GL_STATIC + qglBindTexture = NULL; + qglBlendFunc = NULL; + qglClear = NULL; + qglClearColor = NULL; + qglClearStencil = NULL; + qglColorMask = NULL; + qglCopyTexImage2D = NULL; + qglCopyTexSubImage2D= NULL; + qglCullFace = NULL; + qglDepthFunc = NULL; + qglDepthMask = NULL; +// qglDepthRangef = NULL; + qglDisable = NULL; + qglEnable = NULL; + qglFinish = NULL; + qglFlush = NULL; + qglGenTextures = NULL; + qglGetFloatv = NULL; + qglGetIntegerv = NULL; + qglGetString = NULL; + qglHint = NULL; + qglIsEnabled = NULL; + qglReadPixels = NULL; + qglTexImage2D = NULL; + qglTexSubImage2D = NULL; + qglTexParameteri = NULL; + qglTexParameterf = NULL; + qglTexParameteriv = NULL; + qglTexParameterfv = NULL; + qglViewport = NULL; + qglGetBooleanv = NULL; + qglGetError = NULL; + qglDeleteTextures = NULL; + qglDrawElements = NULL; + qglDrawArrays = NULL; + qglStencilOp = NULL; + qglStencilFunc = NULL; + qglScissor = NULL; + qglPolygonOffset = NULL; +#endif +#ifndef FTE_TARGET_WEB + qglAlphaFunc = NULL; + qglBegin = NULL; + qglClearDepth = NULL; + qglClipPlane = NULL; +// qglColor3f = NULL; +// qglColor3ub = NULL; + qglColor4f = NULL; + qglColor4fv = NULL; +// qglColor4ub = NULL; +// qglColor4ubv = NULL; +// qglDepthRange = NULL; + qglDrawBuffer = NULL; + qglDrawPixels = NULL; + qglEnd = NULL; + qglFrustum = NULL; + qglGetTexLevelParameteriv = NULL; + qglLoadIdentity = NULL; + qglLoadMatrixf = NULL; + qglNormal3f = NULL; + qglNormal3fv = NULL; + qglMatrixMode = NULL; + qglMultMatrixf = NULL; +// qglOrtho = NULL; + qglPolygonMode = NULL; + qglPopMatrix = NULL; + qglPushMatrix = NULL; + qglReadBuffer = NULL; + qglRotatef = NULL; + qglScalef = NULL; + qglShadeModel = NULL; + qglTexCoord1f = NULL; + qglTexCoord2f = NULL; + qglTexCoord2fv = NULL; + qglTexEnvf = NULL; + qglTexEnvfv = NULL; + qglTexEnvi = NULL; + qglTexGeni = NULL; + qglTexGenfv = NULL; + qglTexImage3D = NULL; + qglTexSubImage3D = NULL; + qglTranslatef = NULL; + qglVertex2f = NULL; + qglVertex3f = NULL; + qglVertex3fv = NULL; +#endif + + //various vertex array stuff. + qglArrayElement = NULL; + qglVertexPointer = NULL; + qglNormalPointer = NULL; + qglTexCoordPointer = NULL; + qglColorPointer = NULL; + qglEnableClientState = NULL; + qglDisableClientState = NULL; + + qglDrawRangeElements = NULL; + + //fixme: definatly make non-core + qglPushAttrib = NULL; + qglPopAttrib = NULL; + + //does this need to be non-core as well? + qglFogi = NULL; + qglFogf = NULL; + qglFogfv = NULL; + + + qglGetTexEnviv = NULL; + qglGetPointerv = NULL; + + qglGetStringi = NULL; + + //used by heightmaps + qglGenLists = NULL; + qglNewList = NULL; + qglEndList = NULL; + qglCallList = NULL; + +#ifndef GL_STATIC + qglBindBufferARB = NULL; +#endif + + gl_vendor = NULL; + gl_renderer = NULL; + gl_version = NULL; + gl_extensions = NULL; + gl_num_extensions = 0; + +#ifndef qglActiveTextureARB + qglActiveTextureARB = NULL; +#endif + qglClientActiveTextureARB = NULL; + qglSelectTextureSGIS = NULL; + qglMTexCoord2fSGIS = NULL; + qglMultiTexCoord2fARB = NULL; + qglMultiTexCoord3fARB = NULL; + qglMTexCoord2fSGIS = NULL; + qglSelectTextureSGIS = NULL; + mtexid0 = 0; + +#ifndef GL_STATIC + qglGenFramebuffersEXT = NULL; + qglDeleteFramebuffersEXT = NULL; + qglBindFramebufferEXT = NULL; + qglGenRenderbuffersEXT = NULL; + qglDeleteRenderbuffersEXT = NULL; + qglBindRenderbufferEXT = NULL; + qglRenderbufferStorageEXT = NULL; + qglFramebufferTexture2DEXT = NULL; +#endif + + //no GL_EXT_stencil_two_side + qglActiveStencilFaceEXT = NULL; + + //no truform. sorry. + qglPNTrianglesfATI = NULL; + qglPNTrianglesiATI = NULL; + + //fragment programs +// qglProgramStringARB = NULL; +// qglGetProgramivARB = NULL; +// qglBindProgramARB = NULL; +// qglGenProgramsARB = NULL; + + +#ifndef GL_STATIC + qglStencilOpSeparateATI = NULL; +#endif + qglActiveStencilFaceEXT = NULL; + +#ifndef GL_STATIC + qglCompressedTexImage2D = NULL; + qglCompressedTexImage3D = NULL; + qglCompressedTexSubImage2D = NULL; + qglCompressedTexSubImage3D = NULL; + qglGetCompressedTexImage = NULL; +#endif + qglDepthBoundsEXT = NULL; + qglPNTrianglesfATI = NULL; + qglPNTrianglesiATI = NULL; + qglPatchParameteriARB = NULL; +#ifndef GL_STATIC + qglBindTexture = NULL; +#endif + qglLockArraysEXT = NULL; + qglUnlockArraysEXT = NULL; + qglBufferStorage = NULL; +#if !defined(GL_STATIC) + qglGenBuffersARB = NULL; + qglDeleteBuffersARB = NULL; + qglBindBufferARB = NULL; + qglBufferDataARB = NULL; + qglBufferSubDataARB = NULL; + qglMapBufferARB = NULL; + qglUnmapBufferARB = NULL; + qglMapBufferRange = NULL; + + qglCreateProgramObjectARB = NULL; + qglDeleteProgramObject_ = NULL; + qglDeleteShaderObject_ = NULL; + qglUseProgramObjectARB = NULL; + qglCreateShaderObjectARB = NULL; + qglGetProgramParameteriv_ = NULL; + qglGetShaderParameteriv_ = NULL; + qglAttachObjectARB = NULL; + qglGetProgramInfoLog_ = NULL; + qglGetShaderInfoLog_ = NULL; + qglShaderSourceARB = NULL; + qglCompileShaderARB = NULL; + qglLinkProgramARB = NULL; + qglBindAttribLocationARB = NULL; + qglGetAttribLocationARB = NULL; + qglVertexAttribPointer = NULL; + qglGetVertexAttribiv = NULL; + qglGetVertexAttribPointerv = NULL; + qglEnableVertexAttribArray = NULL; + qglDisableVertexAttribArray = NULL; + qglGetUniformLocationARB = NULL; + qglUniformMatrix4fvARB = NULL; + qglUniformMatrix3x4fv = NULL; + qglUniformMatrix4x3fv = NULL; + qglUniform4fARB = NULL; + qglUniform4fvARB = NULL; + qglUniform3fARB = NULL; + qglUniform3fvARB = NULL; + qglUniform2fvARB = NULL; + qglUniform1iARB = NULL; + qglUniform1fARB = NULL; + qglGetShaderSource = NULL; +#endif + + qglGetProgramBinary = NULL; + qglProgramBinary = NULL; + + qglGetGraphicsResetStatus = NULL; //its not allowed to crash us. probably will. grr. oh well. + + + qglGenVertexArrays = NULL; + qglBindVertexArray = NULL; + qglTexStorage2D = NULL; + qglTexStorage3D = NULL; + +#ifndef GL_STATIC + qglGenFramebuffersEXT = NULL; + qglDeleteFramebuffersEXT = NULL; + qglBindFramebufferEXT = NULL; + qglGenRenderbuffersEXT = NULL; + qglDeleteRenderbuffersEXT = NULL; + qglBindRenderbufferEXT = NULL; + qglRenderbufferStorageEXT = NULL; + qglFramebufferTexture2DEXT = NULL; + qglFramebufferRenderbufferEXT = NULL; + qglCheckFramebufferStatusEXT = NULL; + qglGetFramebufferAttachmentParameteriv = NULL; +#endif +#ifdef DEBUG + qglDebugMessageControlARB = NULL; + qglDebugMessageInsertARB = NULL; + qglDebugMessageCallbackARB = NULL; + qglGetDebugMessageLogARB = NULL; +#endif + + qglGenQueriesARB = NULL; + qglDeleteQueriesARB = NULL; + qglBeginQueryARB = NULL; + qglEndQueryARB = NULL; + qglGetQueryObjectuivARB = NULL; + + qglGenVertexArrays = NULL; + qglBindVertexArray = NULL; + + qglDrawBuffers = NULL; + + qglLoadMatrixf = NULL; + qglPolygonMode = NULL; + qglShadeModel = NULL; + qglDrawBuffer = NULL; + + memset(&sh_config, 0, sizeof(sh_config)); + memset(&gl_config, 0, sizeof(gl_config)); +} + //the vid routines have initialised a window, and now they are giving us a reference to some of of GetProcAddress to get pointers to the funcs. qboolean GL_Init(rendererstate_t *info, void *(*getglfunction) (char *name)) { diff --git a/engine/gl/gl_viddroid.c b/engine/gl/gl_viddroid.c index 2ac5d0f8..2f07905f 100644 --- a/engine/gl/gl_viddroid.c +++ b/engine/gl/gl_viddroid.c @@ -90,6 +90,8 @@ void GLVID_DeInit(void) sys_context = EGL_NO_CONTEXT; sys_surface = EGL_NO_SURFACE; + GL_ForgetPointers(); + Sys_Printf("GLVID_DeInited\n"); } diff --git a/engine/gl/gl_vidlinuxglx.c b/engine/gl/gl_vidlinuxglx.c index 493152e5..5c36ee9c 100644 --- a/engine/gl/gl_vidlinuxglx.c +++ b/engine/gl/gl_vidlinuxglx.c @@ -2413,6 +2413,7 @@ void GLVID_Shutdown(void) #ifdef USE_EGL case PSL_EGL: EGL_Shutdown(); + GL_ForgetPointers(); break; #endif case PSL_GLX: @@ -2421,6 +2422,7 @@ void GLVID_Shutdown(void) glx.DestroyContext(vid_dpy, ctx); ctx = NULL; } + GL_ForgetPointers(); break; #endif #ifdef VKQUAKE diff --git a/engine/gl/gl_vidmacos.c b/engine/gl/gl_vidmacos.c index aa14bea8..fe94d90f 100644 --- a/engine/gl/gl_vidmacos.c +++ b/engine/gl/gl_vidmacos.c @@ -111,6 +111,7 @@ qboolean GLVID_Init(rendererstate_t *info, unsigned char *palette) void GLVID_DeInit(void) { killCocoa(); + GL_ForgetPointers(); } void GLVID_SetPalette (unsigned char *palette) diff --git a/engine/gl/gl_vidnt.c b/engine/gl/gl_vidnt.c index 74ec6c1b..e0c2b2d5 100644 --- a/engine/gl/gl_vidnt.c +++ b/engine/gl/gl_vidnt.c @@ -1703,6 +1703,10 @@ void VID_UnSetMode (void) } *opengldllname = 0; #endif + +#ifdef GLQUAKE + GL_ForgetPointers(); +#endif } diff --git a/engine/gl/gl_vidsdl.c b/engine/gl/gl_vidsdl.c index 4497fa41..03fee99b 100644 --- a/engine/gl/gl_vidsdl.c +++ b/engine/gl/gl_vidsdl.c @@ -379,6 +379,7 @@ void GLVID_DeInit (void) #endif SDL_QuitSubSystem(SDL_INIT_VIDEO); + GL_ForgetPointers(); } diff --git a/engine/gl/glquake.h b/engine/gl/glquake.h index fa9c6cb4..9d8fa0b6 100644 --- a/engine/gl/glquake.h +++ b/engine/gl/glquake.h @@ -1112,6 +1112,7 @@ void GL_SelectProgram(int program); qboolean GL_Init(rendererstate_t *info, void *(*getglfunction) (char *name)); +void GL_ForgetPointers(void); #endif diff --git a/engine/gl/r_bishaders.h b/engine/gl/r_bishaders.h index e6f21146..754755d9 100644 --- a/engine/gl/r_bishaders.h +++ b/engine/gl/r_bishaders.h @@ -6831,6 +6831,8 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND //!!samps diffuse lightmap specular normalmap fullbright reflectmask reflectcube paletted lightmap1 lightmap2 lightmap3 "!!samps diffuse fullbright lightmap\n" +"#undef SPECULAR\n" + //#include "sys/defs.h" "#define vec4 float4\n" "#define vec3 float3\n" @@ -6842,7 +6844,17 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "{\n" "vec4 v_position : POSITION;\n" "vec2 v_texcoord : TEXCOORD0;\n" + +"#if defined(OFFSETMAPPING) || defined(SPECULAR) || defined(REFLECTCUBEMASK)\n" +"vec3 v_normal : NORMAL;\n" +"vec3 v_svector : TANGENT;\n" +"vec3 v_tvector : BINORMAL;\n" +"#endif\n" +"#ifdef VERTEXLIT\n" +"vec4 v_colour : COLOR0;\n" +"#else\n" "vec2 v_lmcoord : TEXCOORD1;\n" +"#endif\n" "};\n" "struct v2f\n" "{\n" @@ -6858,7 +6870,11 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "mat3 invsurface : TEXCOORD5;\n" "#endif\n" +"#ifdef VERTEXLIT\n" +"vec2 tclm : TEXCOORD0;\n" +"#else\n" "vec4 tclm : TEXCOORD0;\n" +"#endif\n" "vec4 vc : COLOR0;\n" "#ifndef VERTEXLIT\n" "#ifdef LIGHTSTYLED\n" @@ -6994,11 +7010,10 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND //modulate that by the lightmap(s) including deluxemap(s) "#ifdef VERTEXLIT\n" -"#error foobar\n" "#ifdef LIGHTSTYLED\n" -"vec3 lightmaps = vc.rgb;\n" +"vec3 lightmaps = inp.vc.rgb;\n" "#else\n" -"vec3 lightmaps = vc.rgb;\n" +"vec3 lightmaps = inp.vc.rgb;\n" "#endif\n" "#define delux vec3(0.0,0.0,1.0)\n" "#else\n" diff --git a/engine/gl/shader.h b/engine/gl/shader.h index b3336a66..96f087e5 100644 --- a/engine/gl/shader.h +++ b/engine/gl/shader.h @@ -158,10 +158,13 @@ enum #define SBITS_ATEST_SHIFT 12 SBITS_MISC_DEPTHWRITE = 0x00010000, - SBITS_MISC_NODEPTHTEST = 0x00020000, - SBITS_MISC_DEPTHEQUALONLY = 0x00040000, - SBITS_MISC_DEPTHCLOSERONLY = 0x00080000, -//#define SBITS_MISC_BITS 0x000f0000 + SBITS_MISC_NODEPTHTEST = 0x00020000, //strictly speaking, this is NOT the same as 'depthfunc always', which is unfortunate. + + SBITS_DEPTHFUNC_CLOSEREQUAL = 0x00000000, + SBITS_DEPTHFUNC_EQUAL = 0x00040000, + SBITS_DEPTHFUNC_CLOSER = 0x00080000, + SBITS_DEPTHFUNC_FURTHER = 0x000c0000, +#define SBITS_DEPTHFUNC_BITS 0x000c0000 SBITS_TESSELLATION = 0x00100000, SBITS_AFFINE = 0x00200000, @@ -974,5 +977,6 @@ void CLQ1_DrawLine(shader_t *shader, vec3_t v1, vec3_t v2, float r, float g, flo void CLQ1_AddOrientedCube(shader_t *shader, vec3_t mins, vec3_t maxs, float *matrix, float r, float g, float b, float a); void CL_DrawDebugPlane(float *normal, float dist, float r, float g, float b, qboolean enqueue); void CLQ1_AddOrientedCylinder(shader_t *shader, float radius, float height, qboolean capsule, float *matrix, float r, float g, float b, float a); +void CLQ1_AddOrientedSphere(shader_t *shader, float radius, float *matrix, float r, float g, float b, float a); void CLQ1_AddOrientedHalfSphere(shader_t *shader, float radius, float gap, float *matrix, float r, float g, float b, float a); #endif diff --git a/engine/nacl/gl_vidppapi.c b/engine/nacl/gl_vidppapi.c index 5fad5063..ed34ae67 100644 --- a/engine/nacl/gl_vidppapi.c +++ b/engine/nacl/gl_vidppapi.c @@ -269,9 +269,7 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette) // vid.pixelwidth = info->width; // vid.pixelheight = info->height; - GL_Init(PPAPI_GetGLSymbol); - - return true; + return GL_Init(PPAPI_GetGLSymbol); } void GLVID_Shutdown (void) @@ -282,6 +280,8 @@ void GLVID_Shutdown (void) ppb_core->ReleaseResource(glcontext); // glTerminatePPAPI(); + + GL_ForgetPointers(); } void GLVID_DeInit (void) { diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index e7a0a713..17e0c8c9 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -9466,6 +9466,10 @@ static void QCBUILTIN PF_runclientphys(pubprogfuncs_t *prinst, struct globalvars if (ent->xv->hasted) movevars.maxspeed *= ent->xv->hasted; #endif + if (client) + movevars.coordsize = client->netchan.netprim.coordsize; + else + movevars.coordsize = svs.netprim.coordsize; pmove.numtouch = 0; pmove.world = &sv.world; @@ -10423,6 +10427,14 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs // {"brush_transformselected",PF_brush_transformselected,0,0,0, 0, D("int(float modelid, int brushid, float *matrix)", "Transforms selected brushes by the given transform")}, #endif +#ifdef ENGINE_ROUTING +#define qcnodeslist \ + "typedef struct\n{\n" \ + "\tvector dest;\n" \ + "\tint linkflags;\n"\ + "} nodeslist_t;\n" + {"route_calculate", PF_route_calculate,0, 0, 0, 0, D(qcnodeslist "void(entity ent, vector dest, int denylinkflags, void(entity ent, vector dest, int numnodes, nodeslist_t *nodelist) callback)", "Begin calculating a route. The callback function will be called once the route has finished being calculated. The route must be memfreed once it is no longer needed. The route must be followed in reverse order (ie: the first node that must be reached is at index numnodes-1). If no route is available then the callback will be called with no nodes.")}, +#endif {"touchtriggers", PF_touchtriggers, 0, 0, 0, 279, D("void(optional entity ent, optional vector neworigin)", "Triggers a touch events between self and every SOLID_TRIGGER entity that it is in contact with. This should typically just be the triggers touch functions. Also optionally updates the origin of the moved entity.")},// {"WriteFloat", PF_WriteFloat, 0, 0, 0, 280, "void(float buf, float fl)"},// @@ -10541,7 +10553,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"findfont", PF_Fixme, 0, 0, 0, 356, D("float(string s)", "Looks up a named font slot. Matches the actual font name as a last resort.")},//; {"loadfont", PF_Fixme, 0, 0, 0, 357, D("float(string fontname, string fontmaps, string sizes, float slot, optional float fix_scale, optional float fix_voffset)", "too convoluted for me to even try to explain correct usage. Try drawfont = loadfont(\"\", \"cour\", \"16\", -1, 0, 0); to switch to the courier font (optimised for 16 virtual pixels high), if you have the freetype2 library in windows..")}, //358 - {"sendevent", PF_Fixme, 0, 0, 0, 359, D("void(string evname, string evargs, ...)", "Invoke Cmd_evname_evargs in ssqc. evargs must be a string of initials refering to the types of the arguments to pass. v=vector, e=entity(.entnum field is sent), f=float, i=int. 6 arguments max - you can get more if you pack your floats into vectors.")},// (EXT_CSQC_1) + {"sendevent", PF_Fixme, 0, 0, 0, 359, D("void(string evname, string evargs, ...)", "Invoke CSEv_evname_evargs in ssqc. evargs must be a string of initials refering to the types of the arguments to pass. v=vector, e=entity(.entnum field is sent), f=float, i=int. 6 arguments max - you can get more if you pack your floats into vectors.")},// (EXT_CSQC_1) {"readbyte", PF_Fixme, 0, 0, 0, 360, "float()"},// (EXT_CSQC) {"readchar", PF_Fixme, 0, 0, 0, 361, "float()"},// (EXT_CSQC) diff --git a/engine/server/sv_move.c b/engine/server/sv_move.c index 41a2fb8d..00007e4d 100644 --- a/engine/server/sv_move.c +++ b/engine/server/sv_move.c @@ -626,4 +626,645 @@ qboolean World_MoveToGoal (world_t *world, wedict_t *ent, float dist) return true; } + + +#ifdef ENGINE_ROUTING +cvar_t route_shownodes = CVAR("route_shownodes", "0"); + +#define LF_EDGE 0x00000001 +#define LF_JUMP 0x00000002 +#define LF_CROUCH 0x00000004 +#define LF_TELEPORT 0x00000008 +#define LF_USER 0x7fffff00 +#define LF_DESTINATION 0x80000000 //You have reached your destination... +struct waypointnetwork_s +{ + size_t refs; + size_t numwaypoints; + model_t *worldmodel; + + struct resultnodes_s + { + vec3_t pos; + int linkflags; + } *displaynode; + int displaynodes; + + struct waypoint_s + { + vec3_t org; + float radius; //used for picking the closest waypoint. aka proximity weight. also relaxes routes inside the area. + struct wpneighbour_s + { + int node; + float linkcost;//might be much lower in the case of teleports, or expensive if someone wanted it to be a lower priority link. + int linkflags; //LF_* + } *neighbour; + int neighbours; + } waypoints[1]; +}; +void WayNet_Done(struct waypointnetwork_s *net) +{ + if (net) + if (0 == --net->refs) + { + Z_Free(net); + } +} +static qboolean WayNet_TokenizeLine(char **linestart) +{ + char *end = *linestart; + if (!*end) + { //clear it out... + Cmd_TokenizeString("", false, false); + return false; + } + for (; *end; end++) + { + if (*end == '\n') + { + *end++ = 0; + break; + } + } + Cmd_TokenizeString(*linestart, false, false); + *linestart = end; + return true; +} +static struct waypointnetwork_s *WayNet_Begin(void **ctxptr, model_t *worldmodel) +{ + struct waypointnetwork_s *net = *ctxptr; + if (!net) + { + char *wf = NULL, *l, *e; + int numwaypoints, maxlinks, numlinks; + struct wpneighbour_s *nextlink; + if (!worldmodel) + return NULL; + if (!wf && !strncmp(worldmodel->name, "maps/", 5)) + { + char n[MAX_QPATH]; + COM_StripExtension(worldmodel->name+5, n, sizeof(n)); + wf = FS_MallocFile(va("data/%s.way", n), FS_GAME, NULL); + } + if (!wf) + wf = FS_MallocFile(va("%s.way", worldmodel->name), FS_GAME, NULL); + + l = wf; + //read the number of waypoints + WayNet_TokenizeLine(&l); + numwaypoints = atoi(Cmd_Argv(0)); + //count lines and guess the link count. + for (e = l, maxlinks=0; *e; e++) + if (*e == '\n') + maxlinks++; + maxlinks -= numwaypoints; + + net = Z_Malloc(sizeof(*net)-sizeof(net->waypoints) + (numwaypoints*sizeof(struct waypoint_s)) + (maxlinks*sizeof(struct wpneighbour_s))); + net->refs = 1; + net->worldmodel = worldmodel; + *ctxptr = net; + + nextlink = (struct wpneighbour_s*)(net->waypoints+numwaypoints); + + while (WayNet_TokenizeLine(&l) && net->numwaypoints < numwaypoints) + { + if (!Cmd_Argc()) + continue; //a comment line? + net->waypoints[net->numwaypoints].org[0] = atof(Cmd_Argv(0)); + net->waypoints[net->numwaypoints].org[1] = atof(Cmd_Argv(1)); + net->waypoints[net->numwaypoints].org[2] = atof(Cmd_Argv(2)); + net->waypoints[net->numwaypoints].radius = 64;//atof(Cmd_Argv(3)); + numlinks = bound(0, atoi(Cmd_Argv(4)), maxlinks); + + //make sure the links are valid, and clamp to avoid problems (even if we're then going to mis-parse. + net->waypoints[net->numwaypoints].neighbour = nextlink; + while (numlinks-- > 0 && WayNet_TokenizeLine(&l)) + { + if (!Cmd_Argc()) + continue; //a comment line? + nextlink[net->waypoints[net->numwaypoints].neighbours].node = atoi(Cmd_Argv(0)); + nextlink[net->waypoints[net->numwaypoints].neighbours].linkcost = atof(Cmd_Argv(1)); + nextlink[net->waypoints[net->numwaypoints].neighbours++].linkflags = atoi(Cmd_Argv(2)); + } + maxlinks -= net->waypoints[net->numwaypoints].neighbours; + nextlink += net->waypoints[net->numwaypoints++].neighbours; + } + BZ_Free(wf); + } + + net->refs++; + return net; +} + +struct waydist_s +{ + int node; + float sdist; +}; +int QDECL WayNet_Prioritise(const void *a, const void *b) +{ + const struct waydist_s *w1 = a, *w2 = b; + if (w1->sdist < w2->sdist) + return -1; + if (w1->sdist == w2->sdist) + return 0; + return 1; +} +int WayNet_FindNearestNode(struct waypointnetwork_s *net, vec3_t pos) +{ + if (net && net->numwaypoints) + { + //we qsort the possible nodes, in an attempt to reduce traces. + struct waydist_s *sortedways = alloca(sizeof(*sortedways) * net->numwaypoints); + size_t u; + vec3_t disp; + float sradius; + trace_t tr; + for (u = 0; u < net->numwaypoints; u++) + { + sortedways[u].node = u; + VectorSubtract(net->waypoints[u].org, pos, disp); + sortedways[u].sdist = DotProduct(disp, disp); + sradius = net->waypoints[u].radius*net->waypoints[u].radius; + if (sortedways[u].sdist < sradius) + sortedways[u].sdist -= sradius; //if we're inside the waypoint's radius, push inwards resulting in negatives, so these are always highly prioritised + } + qsort(sortedways, net->numwaypoints, sizeof(struct waydist_s), WayNet_Prioritise); + + //can't trace yet... + if (net->worldmodel->loadstate != MLS_LOADED) + return sortedways[0].node; + for (u = 0; u < net->numwaypoints; u++) + { + if (sortedways[u].sdist > 0) + { //if we're outside the node, we need to do a trace to make sure we can actually reach it. + net->worldmodel->funcs.NativeTrace(net->worldmodel, 0, NULL, NULL, pos, net->waypoints[sortedways[u].node].org, vec3_origin, vec3_origin, false, MASK_WORLDSOLID, &tr); + if (tr.fraction < 1) + continue; //this node is blocked. just move on to the next. + } + return sortedways[u].node; + } + } + return -1; +} + +struct routecalc_s +{ + world_t *world; + int spawncount; //so we don't confuse stuff if the map gets restarted. + wedict_t *ed; +// float spawnid; //so the route fails if the ent is removed. + func_t callback; + + vec3_t start; + vec3_t end; + int denylinkflags; + + int startn; + int endn; + + int numresultnodes; + struct resultnodes_s *resultnodes; + + struct waypointnetwork_s *waynet; +}; +//main thread +void Route_Calculated(void *ctx, void *data, size_t a, size_t b) +{ + struct routecalc_s *route = data; + pubprogfuncs_t *prinst = route->world->progs; + //let the gamecode know the results + + if (!route->callback) + { + BZ_Free(route->waynet->displaynode); + route->waynet->displaynode = BZ_Malloc(sizeof(struct resultnodes_s) * route->numresultnodes); + route->waynet->displaynodes = route->numresultnodes; + memcpy(route->waynet->displaynode, route->resultnodes, sizeof(struct resultnodes_s) * route->numresultnodes); + } + else if (route->callback && route->world->spawncount == route->spawncount/* && route->spawnid == route->ed->xv->uniquespawnid*/) + { + struct globalvars_s * pr_globals = PR_globals(prinst, PR_CURRENT); + struct resultnodes_s *ptr = prinst->AddressableAlloc(prinst, sizeof(struct resultnodes_s) * route->numresultnodes); + memcpy(ptr, route->resultnodes, sizeof(struct resultnodes_s) * route->numresultnodes); + + G_INT(OFS_PARM0) = EDICT_TO_PROG(prinst, route->ed); + VectorCopy(route->end, G_VECTOR(OFS_PARM1)); + G_INT(OFS_PARM2) = route->numresultnodes; + G_INT(OFS_PARM3) = (char*)ptr-prinst->stringtable; + PR_ExecuteProgram(prinst, route->callback); + } + + //and we're done. destroy everything. + WayNet_Done(route->waynet); + Z_Free(route->resultnodes); + Z_Free(route); +} + +//#define FLOODALL +#define COST_INFINITE FLT_MAX + +static qboolean Route_Completed(struct routecalc_s *r, int *nodecamefrom) +{ + size_t u; + struct waypointnetwork_s *n = r->waynet; + r->resultnodes = Z_Malloc(sizeof(*r->resultnodes)*(n->numwaypoints+1)*3); + + r->numresultnodes = 0; + + //target point is first. yay. + VectorCopy(r->end, r->resultnodes[0].pos); + r->resultnodes[0].linkflags = LF_DESTINATION; + r->numresultnodes++; + + u = r->endn; + for (;;) + { + VectorCopy(n->waypoints[u].org, r->resultnodes[r->numresultnodes].pos); + r->resultnodes[r->numresultnodes].linkflags = 0; + r->numresultnodes++; + if (u == r->startn) + break; + u = nodecamefrom[u]; + } + + //and include the start point, because we can + VectorCopy(r->start, r->resultnodes[r->numresultnodes].pos); + r->resultnodes[r->numresultnodes].linkflags = 0; + r->numresultnodes++; + return true; +} + +#if 1 +static float Route_GuessCost(struct routecalc_s *r, float *fromorg) +{ //if we want to guarentee the shortest route, then we MUST always return a value <= to the actual cost here. + //unfortunately we don't know how many teleporters are between the two points. + //on the plus side, a little randomness here means we'll find alternative (longer) routes some times, which will reduce flash points and help flag carriers... + vec3_t disp; + VectorSubtract(r->end, fromorg, disp); + return sqrt(DotProduct(disp,disp)); +} +static qboolean Route_Process(struct routecalc_s *r) +{ + struct waypointnetwork_s *n = r->waynet; + int opennodes = 0; + int u, j; + float guesscost; + struct opennode_s { + int node; + float cost; + } *open = alloca(sizeof(*open)*n->numwaypoints); + float *nodecost = alloca(sizeof(*nodecost)*n->numwaypoints); + int *nodecamefrom = alloca(sizeof(*nodecamefrom)*n->numwaypoints); + + for(u = 0; u < n->numwaypoints; u++) + nodecost[u] = COST_INFINITE; + + if (r->startn >= 0) + { + nodecost[r->startn] = 0; + open[0].node = r->startn; + open[0].cost = 0; + opennodes++; + } + + while(opennodes) + { + int nodeidx = open[--opennodes].node; + struct waypoint_s *wp = &n->waypoints[nodeidx]; +#ifdef _DEBUG + if (nodeidx < 0 || nodeidx >= n->numwaypoints) + { + Con_Printf("Bad node index in open list\n"); + return false; + } +#endif + if (nodeidx == r->endn) + { //we found the end! + return Route_Completed(r, nodecamefrom); + } + for (u = 0; u < wp->neighbours; u++) + { + struct wpneighbour_s *l = &wp->neighbour[u]; + int linkidx = l->node; + + float realcost = nodecost[nodeidx] + l->linkcost; +#ifdef _DEBUG + if (linkidx < 0 || linkidx >= n->numwaypoints) + { + Con_Printf("Bad node link index in routing table\n"); + return false; + } +#endif + if (realcost >= nodecost[linkidx]) + continue; + + nodecamefrom[linkidx] = nodeidx; + nodecost[linkidx] = realcost; + + for (j = opennodes-1; j >= 0; j--) + { + if (open[j].node == linkidx) + break; + } + guesscost = realcost + Route_GuessCost(r, n->waypoints[linkidx].org); + + if (j < 0) + { //not already in the list + //tbh, we should probably just directly bubble in this loop instead of doing the memcpy (with its internal second loop). + for (j = opennodes-1; j >= 0; j--) + if (guesscost <= open[j].cost) + break; + j++; + //move them up + memmove(&open[j+1], &open[j], sizeof(*open)*(opennodes-j)); + open[j].node = linkidx; + open[j].cost = guesscost; + opennodes++; + } + else if (guesscost < open[j].cost) + { //if it got cheaper, be prepared to move the node towards the higher addresses (these will be checked first). + for (; j+1 < opennodes && open[j+1].cost > guesscost; j++) + open[j] = open[j+1]; + //okay, so we can't keep going... this is our new slot! + open[j].node = linkidx; + open[j].cost = guesscost; + } + //otherwise it got more expensive, and we don't care about that + } + } + + return false; +} +#else +static qboolean Route_Process(struct routecalc_s *r) +{ + struct waypointnetwork_s *n = r->waynet; + int opennodes = 0; + int u, j; + + //we use an open list in a desperate attempt to avoid recursing the entire network + int *open = alloca(sizeof(*open)*n->numwaypoints); + float *nodecost = alloca(sizeof(*nodecost)*n->numwaypoints); + int *nodecamefrom = alloca(sizeof(*nodecamefrom)*n->numwaypoints); + + for(u = 0; u < n->numwaypoints; u++) + nodecost[u] = COST_INFINITE; + + nodecost[r->startn] = 0; + open[opennodes++] = r->startn; + + while(opennodes) + { + int nodeidx = open[--opennodes]; + struct waypoint_s *wp = &n->waypoints[nodeidx]; +// if (nodeidx < 0 || nodeidx >= n->numwaypoints) +// return false; + + for (u = 0; u < wp->neighbours; u++) + { + struct wpneighbour_s *l = &wp->neighbour[u]; + int linkidx = l->node; + + float realcost = nodecost[nodeidx] + l->linkcost; +// if (linkidx < 0 || linkidx >= n->numwaypoints) +// return false; + if (realcost >= nodecost[linkidx]) + continue; + + nodecamefrom[linkidx] = nodeidx; + nodecost[linkidx] = realcost; + + for (j = 0; j < opennodes; j++) + { + if (open[j] == linkidx) + break; + } + + if (j == opennodes) //not already queued + open[opennodes++] = linkidx; + } + } + + if (r->endn >= 0 && nodecost[r->endn] < COST_INFINITE) + { //we found the end! we can build the route from end to start. + return Route_Completed(r, nodecamefrom); + } + return false; +} +#endif + +//worker thread +void Route_Calculate(void *ctx, void *data, size_t a, size_t b) +{ + struct routecalc_s *route = data; + + //first thing is to find the start+end nodes. + + if (route->waynet && route->startn >= 0 && route->endn >= 0 && Route_Process(route)) + ; + else + { + route->numresultnodes = 0; + route->resultnodes = Z_Malloc(sizeof(*route->resultnodes)*2); + VectorCopy(route->end, route->resultnodes[0].pos); + route->resultnodes[0].linkflags = LF_DESTINATION; + route->numresultnodes++; + + VectorCopy(route->start, route->resultnodes[route->numresultnodes].pos); + route->resultnodes[route->numresultnodes].linkflags = 0; + route->numresultnodes++; + } + + COM_AddWork(WG_MAIN, Route_Calculated, NULL, route, 0, 0); +} + +/* +============= +PF_route_calculate + +engine reads+caches the nodes from a file. +the route's nodes must be memfreed on completion. +the first node in the nodelist is the destination. + +typedef struct { + vector dest; + int linkflags; +} nodeslist_t; +void(entity ent, vector dest, int denylinkflags, void(entity ent, vector dest, int numnodes, nodeslist_t *nodelist) callback) route_calculate = #0; +============= +*/ +void QCBUILTIN PF_route_calculate (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + struct routecalc_s *route = Z_Malloc(sizeof(*route)); + float *end; + route->world = prinst->parms->user; + route->spawncount = route->world->spawncount; + route->ed = G_WEDICT(prinst, OFS_PARM0); +// route->spawnid = route->ed->xv->uniquespawnid; + end = G_VECTOR(OFS_PARM1); + route->denylinkflags = G_INT(OFS_PARM2); + route->callback = G_INT(OFS_PARM3); + + VectorCopy(route->ed->v->origin, route->start); + VectorCopy(end, route->end); + + route->waynet = WayNet_Begin(&route->world->waypoints, route->world->worldmodel); + + //tracelines use some sequence info to avoid retracing the same brush multiple times. + // this means that we can't reliably trace on worker threads (would break the main thread occasionally). + // so we have to do this here. + //FIXME: find a safe way to NOT do this here. + route->startn = WayNet_FindNearestNode(route->waynet, route->start); + route->endn = WayNet_FindNearestNode(route->waynet, route->end); + + COM_AddWork(WG_LOADER, Route_Calculate, NULL, route, 0, 0); +} +#ifndef SERVERONLY +static void Route_Visualise_f(void) +{ + extern world_t csqc_world; + vec3_t targ = {atof(Cmd_Argv(1)),atof(Cmd_Argv(2)),atof(Cmd_Argv(3))}; + struct routecalc_s *route = Z_Malloc(sizeof(*route)); + route->world = &csqc_world; + route->spawncount = route->world->spawncount; + route->ed = route->world->edicts; +// route->spawnid = route->ed->xv->uniquespawnid; + VectorCopy(r_refdef.vieworg, route->start); + VectorCopy(targ, route->end); + + route->waynet = WayNet_Begin(&route->world->waypoints, route->world->worldmodel); + + //tracelines use some sequence info to avoid retracing the same brush multiple times. + // this means that we can't reliably trace on worker threads (would break the main thread occasionally). + // so we have to do this here. + //FIXME: find a safe way to NOT do this here. + route->startn = WayNet_FindNearestNode(route->waynet, route->start); + route->endn = WayNet_FindNearestNode(route->waynet, route->end); + + COM_AddWork(WG_LOADER, Route_Calculate, NULL, route, 0, 0); +} + +#include "shader.h" +void PR_Route_Visualise (void) +{ + extern world_t csqc_world; + world_t *w = &csqc_world; + struct waypointnetwork_s *wn; + size_t u; + + wn = (w && (w->waypoints || route_shownodes.ival))?WayNet_Begin(&w->waypoints, w->worldmodel):NULL; + if (wn) + { + if (route_shownodes.ival) + { + float mat[12] = {1,0,0,0, 0,1,0,0, 0,0,1,0}; + shader_t *shader_out = R_RegisterShader("waypointvolume_out", SUF_NONE, + "{\n" + "polygonoffset\n" + "nodepth\n" + "{\n" + "map $whiteimage\n" + "blendfunc add\n" + "rgbgen vertex\n" + "alphagen vertex\n" + "}\n" + "}\n"); + shader_t *shader_in = R_RegisterShader("waypointvolume_in", SUF_NONE, + "{\n" + "polygonoffset\n" + "cull disable\n" + "nodepth\n" + "{\n" + "map $whiteimage\n" + "blendfunc add\n" + "rgbgen vertex\n" + "alphagen vertex\n" + "}\n" + "}\n"); + float radius; + vec3_t dir; + //should probably use a different colour for the node you're inside. + for (u = 0; u < wn->numwaypoints; u++) + { + mat[3] = wn->waypoints[u].org[0]; + mat[7] = wn->waypoints[u].org[1]; + mat[11] = wn->waypoints[u].org[2]; + radius = wn->waypoints[u].radius; + if (radius <= 0) + radius = 1; //waypoints shouldn't really have a radius of 0, but if they do we'll still want to draw something. + + VectorSubtract(wn->waypoints[u].org, r_refdef.vieworg, dir); + if (DotProduct(dir,dir) < radius*radius) + CLQ1_AddOrientedSphere(shader_in, radius, mat, 0.0, 0.1, 0, 1); + else + CLQ1_AddOrientedSphere(shader_out, radius, mat, 0.2, 0.0, 0, 1); + } + for (u = 0; u < wn->numwaypoints; u++) + { + size_t n; + for (n = 0; n < wn->waypoints[u].neighbours; n++) + { + struct waypoint_s *r = wn->waypoints + wn->waypoints[u].neighbour[n].node; + CLQ1_DrawLine(shader_out, wn->waypoints[u].org, r->org, 0, 0, 1, 1); + } + } + } + if (wn->displaynodes) + { //FIXME: we should probably use beams here + shader_t *shader_route = R_RegisterShader("waypointroute", SUF_NONE, + "{\n" + "polygonoffset\n" + "nodepth\n" + "{\n" + "map $whiteimage\n" + "blendfunc add\n" + "rgbgen vertex\n" + "alphagen vertex\n" + "}\n" + "}\n"); + + for (u = wn->displaynodes-1; u > 0; u--) + { + vec_t *start = wn->displaynode[u].pos; + vec_t *end = wn->displaynode[u-1].pos; + CLQ1_DrawLine(shader_route, start, end, 0.5, 0.5, 0.5, 1); + } + } + } + WayNet_Done(wn); +} +#endif + +//destroys the routing waypoint cache. +void PR_Route_Shutdown (world_t *world) +{ + WayNet_Done(world->waypoints); + world->waypoints = NULL; +} + +static void Route_Reload_f(void) +{ +#if !defined(SERVERONLY) && defined(CSQC_DAT) + extern world_t csqc_world; + PR_Route_Shutdown(&csqc_world); +#endif +#ifndef CLIENTONLY + PR_Route_Shutdown(&sv.world); +#endif +} +void PR_Route_Init (void) +{ +#if !defined(SERVERONLY) && defined(CSQC_DAT) + Cvar_Register(&route_shownodes, NULL); + Cmd_AddCommand("route_visualise", Route_Visualise_f); +#endif + Cmd_AddCommand("route_reload", Route_Reload_f); +} + +//route_force +//COM_WorkerPartialSync +#endif + #endif diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index 78e20654..ceb09d77 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -6898,6 +6898,7 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean recurse) movevars.slidyslopes = (pm_slidyslopes.value!=0); movevars.watersinkspeed = *pm_watersinkspeed.string?pm_watersinkspeed.value:60; movevars.flyfriction = *pm_flyfriction.string?pm_flyfriction.value:4; + movevars.coordsize = host_client->netchan.netprim.coordsize; for (i=0 ; i<3 ; i++) { @@ -7144,6 +7145,7 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean recurse) movevars.slidyslopes = (pm_slidyslopes.value!=0); movevars.watersinkspeed = *pm_watersinkspeed.string?pm_watersinkspeed.value:60; movevars.flyfriction = *pm_flyfriction.string?pm_flyfriction.value:4; + movevars.coordsize = host_client->netchan.netprim.coordsize; // should already be folded into host_client->maxspeed // if (sv_player->xv->hasted) diff --git a/engine/shaders/hlsl9/defaultwall.hlsl b/engine/shaders/hlsl9/defaultwall.hlsl new file mode 100644 index 00000000..d7adad0b --- /dev/null +++ b/engine/shaders/hlsl9/defaultwall.hlsl @@ -0,0 +1,293 @@ +//!!ver 100 150 +//!!permu DELUXE +!!permu FULLBRIGHT +!!permu FOG +//!!permu LIGHTSTYLED +//!!permu BUMP +//!!permu SPECULAR +//!!permu REFLECTCUBEMASK +//!!cvarf r_glsl_offsetmapping_scale +//!!cvardf r_tessellation_level=5 +//!!samps diffuse lightmap specular normalmap fullbright reflectmask reflectcube paletted lightmap1 lightmap2 lightmap3 +!!samps diffuse fullbright lightmap + +#undef SPECULAR + +//#include "sys/defs.h" +#define vec4 float4 +#define vec3 float3 +#define vec2 float2 +#define texture2D tex2D +#define mat3 float3x3 +#define mat4 float4x4 + struct a2v + { + vec4 v_position : POSITION; + vec2 v_texcoord : TEXCOORD0; + +#if defined(OFFSETMAPPING) || defined(SPECULAR) || defined(REFLECTCUBEMASK) + vec3 v_normal : NORMAL; + vec3 v_svector : TANGENT; + vec3 v_tvector : BINORMAL; +#endif +#ifdef VERTEXLIT + vec4 v_colour : COLOR0; +#else + vec2 v_lmcoord : TEXCOORD1; +#endif + }; + struct v2f + { + #ifndef FRAGMENT_SHADER + vec4 pos: POSITION; + #endif + + #if defined(OFFSETMAPPING) || defined(SPECULAR) || defined(REFLECTCUBEMASK) || defined(FOG) + vec3 eyevector : TEXCOORD4; + #endif + + #if defined(REFLECTCUBEMASK) || defined(BUMPMODELSPACE) + mat3 invsurface : TEXCOORD5; + #endif + +#ifdef VERTEXLIT + vec2 tclm : TEXCOORD0; +#else + vec4 tclm : TEXCOORD0; +#endif + vec4 vc : COLOR0; + #ifndef VERTEXLIT + #ifdef LIGHTSTYLED + //we could use an offset, but that would still need to be per-surface which would break batches + //fixme: merge attributes? + vec2 lm1 : TEXCOORD1, lm2 : TEXCOORD2, lm3 : TEXCOORD3; + #endif + #endif + }; + +//this is what normally draws all of your walls, even with rtlights disabled +//note that the '286' preset uses drawflat_walls instead. + +#include "sys/fog.h" + +#ifdef VERTEX_SHADER +float4x4 m_modelviewprojection; +float4x4 m_modelview; +vec3 e_eyepos; +vec4 e_lmscale; +v2f main (a2v inp) +{ + v2f outp; + +#if defined(OFFSETMAPPING) || defined(SPECULAR) || defined(REFLECTCUBEMASK) + vec3 eyeminusvertex = e_eyepos - inp.v_position.xyz; + outp.eyevector.x = dot(eyeminusvertex, inp.v_svector.xyz); + outp.eyevector.y = dot(eyeminusvertex, inp.v_tvector.xyz); + outp.eyevector.z = dot(eyeminusvertex, inp.v_normal.xyz); +#elif defined(FOG) + outp.eyevector = mul(m_modelview, inp.v_position); +#endif +#if defined(REFLECTCUBEMASK) || defined(BUMPMODELSPACE) + outp.invsurface[0] = inp.v_svector; + outp.invsurface[1] = inp.v_tvector; + outp.invsurface[2] = inp.v_normal; +#endif + outp.tclm.xy = inp.v_texcoord; +#ifdef FLOW +// outp.tclm.x += e_time * -0.5; +#endif +#ifdef VERTEXLIT + #ifdef LIGHTSTYLED + //FIXME, only one colour. + outp.vc = inp.v_colour * e_lmscale[0]; + #else + outp.vc = inp.v_colour * e_lmscale; + #endif +#else + outp.vc = e_lmscale; + outp.tclm.zw = inp.v_lmcoord; + #ifdef LIGHTSTYLED + outp.lm1 = inp.v_lmcoord2; + outp.lm2 = inp.v_lmcoord3; + outp.lm3 = inp.v_lmcoord4; + #endif +#endif + outp.pos = mul(m_modelviewprojection, inp.v_position); + + return outp; +} +#endif + + + + + + + + + + +#ifdef FRAGMENT_SHADER +sampler s_diffuse : register(s0); +//sampler s_normalmap; +//sampler s_specular; +//sampler s_upper; +//sampler s_lower; +sampler s_fullbright : register(s1); +//sampler s_paletted; +//sampler s_reflectcube; +//sampler s_reflectmask; +sampler s_lightmap : register(s2); +//sampler s_deluxmap; + + +//samplers +#define s_colourmap s_t0 +//sampler2D s_colourmap; + +//vec4 e_lmscale; +vec4 e_colourident; + +#ifdef OFFSETMAPPING +#include "sys/offsetmapping.h" +#endif +vec4 main (v2f inp) : COLOR0 +{ + vec4 gl_FragColor; +#define tc (inp.tclm.xy) +#define lm0 (inp.tclm.zw) + + +//adjust texture coords for offsetmapping +#ifdef OFFSETMAPPING + vec2 tcoffsetmap = offsetmap(s_normalmap, tc, eyevector); +#define tc tcoffsetmap +#endif + +#if defined(EIGHTBIT) && !defined(LIGHTSTYLED) + //optional: round the lightmap coords to ensure all pixels within a texel have different lighting values either. it just looks wrong otherwise. + //don't bother if its lightstyled, such cases will have unpredictable correlations anyway. + //FIXME: this rounding is likely not correct with respect to software rendering. oh well. +#if __VERSION__ >= 130 + vec2 lmsize = vec2(textureSize(s_lightmap0, 0)); +#else + #define lmsize vec2(128.0,2048.0) +#endif +#define texelstolightmap (16.0) + vec2 lmcoord0 = floor(lm0 * lmsize*texelstolightmap)/(lmsize*texelstolightmap); +#define lm0 lmcoord0 +#endif + + +//yay, regular texture! + gl_FragColor = texture2D(s_diffuse, tc); + +#if defined(BUMP) && (defined(DELUXE) || defined(SPECULAR) || defined(REFLECTCUBEMASK)) + vec3 norm = normalize(texture2D(s_normalmap, tc).rgb - 0.5); +#elif defined(SPECULAR) || defined(DELUXE) || defined(REFLECTCUBEMASK) + vec3 norm = vec3(0, 0, 1); //specular lighting expects this to exist. +#endif + +//modulate that by the lightmap(s) including deluxemap(s) +#ifdef VERTEXLIT + #ifdef LIGHTSTYLED + vec3 lightmaps = inp.vc.rgb; + #else + vec3 lightmaps = inp.vc.rgb; + #endif + #define delux vec3(0.0,0.0,1.0) +#else + #ifdef LIGHTSTYLED +#error foobar + #define delux vec3(0.0,0.0,1.0) + vec3 lightmaps; + #ifdef DELUXE + lightmaps = texture2D(s_lightmap0, lm0).rgb * e_lmscale[0].rgb * dot(norm, 2.0*texture2D(s_deluxmap0, lm0).rgb-0.5); + lightmaps += texture2D(s_lightmap1, lm1).rgb * e_lmscale[1].rgb * dot(norm, 2.0*texture2D(s_deluxmap1, lm1).rgb-0.5); + lightmaps += texture2D(s_lightmap2, lm2).rgb * e_lmscale[2].rgb * dot(norm, 2.0*texture2D(s_deluxmap2, lm2).rgb-0.5); + lightmaps += texture2D(s_lightmap3, lm3).rgb * e_lmscale[3].rgb * dot(norm, 2.0*texture2D(s_deluxmap3, lm3).rgb-0.5); + #else + lightmaps = texture2D(s_lightmap0, lm0).rgb * e_lmscale[0].rgb; + lightmaps += texture2D(s_lightmap1, lm1).rgb * e_lmscale[1].rgb; + lightmaps += texture2D(s_lightmap2, lm2).rgb * e_lmscale[2].rgb; + lightmaps += texture2D(s_lightmap3, lm3).rgb * e_lmscale[3].rgb; + #endif + #else + vec3 lightmaps = texture2D(s_lightmap, lm0).rgb; + //modulate by the bumpmap dot light + #ifdef DELUXE +#error foobar + vec3 delux = (texture2D(s_deluxmap, lm0).rgb-0.5); + #ifdef BUMPMODELSPACE + delux = normalize(delux*invsurface); +#else + lightmaps *= 2.0 / max(0.25, delux.z); //counter the darkening from deluxmaps + #endif + lightmaps *= dot(norm, delux); + #else + #define delux vec3(0.0,0.0,1.0) + #endif + #endif + lightmaps *= inp.vc.rgb; +#endif + +//add in specular, if applicable. +#ifdef SPECULAR + vec4 specs = texture2D(s_specular, tc); + vec3 halfdir = normalize(normalize(eyevector) + delux); //this norm should be the deluxemap info instead + float spec = pow(max(dot(halfdir, norm), 0.0), FTE_SPECULAR_EXPONENT * specs.a); + spec *= FTE_SPECULAR_MULTIPLIER; +//NOTE: rtlights tend to have a *4 scaler here to over-emphasise the effect because it looks cool. +//As not all maps will have deluxemapping, and the double-cos from the light util makes everything far too dark anyway, +//we default to something that is not garish when the light value is directly infront of every single pixel. +//we can justify this difference due to the rtlight editor etc showing the *4. + gl_FragColor.rgb += spec * specs.rgb; +#endif + +#ifdef REFLECTCUBEMASK + vec3 rtc = reflect(normalize(-eyevector), norm); + rtc = rtc.x*invsurface[0] + rtc.y*invsurface[1] + rtc.z*invsurface[2]; + rtc = (m_model * vec4(rtc.xyz,0.0)).xyz; + gl_FragColor.rgb += texture2D(s_reflectmask, tc).rgb * textureCube(s_reflectcube, rtc).rgb; +#endif + +#ifdef EIGHTBIT //FIXME: with this extra flag, half the permutations are redundant. + lightmaps *= 0.5; //counter the fact that the colourmap contains overbright values and logically ranges from 0 to 2 intead of to 1. + float pal = texture2D(s_paletted, tc).r; //the palette index. hopefully not interpolated. + lightmaps -= 1.0 / 128.0; //software rendering appears to round down, so make sure we favour the lower values instead of rounding to the nearest + gl_FragColor.r = texture2D(s_colourmap, vec2(pal, 1.0-lightmaps.r)).r; //do 3 lookups. this is to cope with lit files, would be a waste to not support those. + gl_FragColor.g = texture2D(s_colourmap, vec2(pal, 1.0-lightmaps.g)).g; //its not very softwarey, but re-palettizing is ugly. + gl_FragColor.b = texture2D(s_colourmap, vec2(pal, 1.0-lightmaps.b)).b; //without lits, it should be identical. +#else + //now we have our diffuse+specular terms, modulate by lightmap values. + gl_FragColor.rgb *= lightmaps.rgb; + +//add on the fullbright +#ifdef FULLBRIGHT + vec4 fb = texture2D(s_fullbright, tc); + gl_FragColor.rgb += fb.rgb*fb.a; +#endif +#endif + +//entity modifiers + gl_FragColor = gl_FragColor * e_colourident; + +#if defined(MASK) +#if defined(MASKLT) + if (gl_FragColor.a < MASK) + discard; +#else + if (gl_FragColor.a >= MASK) + discard; +#endif + gl_FragColor.a = 1.0; //alpha blending AND alpha testing usually looks stupid, plus it screws up our fog. +#endif + +//and finally hide it all if we're fogged. +#ifdef FOG + gl_FragColor = fog4(gl_FragColor, length(inp.eyevector)); +#endif + return gl_FragColor; +} +#endif + diff --git a/engine/vk/vk_backend.c b/engine/vk/vk_backend.c index 952d9217..0b13e8e9 100644 --- a/engine/vk/vk_backend.c +++ b/engine/vk/vk_backend.c @@ -2672,6 +2672,7 @@ static void BE_CreatePipeline(program_t *p, unsigned int shaderflags, unsigned i VkPipelineColorBlendAttachmentState att_state[1]; VkGraphicsPipelineCreateInfo pipeCreateInfo = {VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO}; VkPipelineShaderStageCreateInfo shaderStages[2] = {{0}}; + VkPipelineRasterizationStateRasterizationOrderAMD ro = {VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_RASTERIZATION_ORDER_AMD}; //long enough names for you? struct specdata_s { int alphamode; @@ -2802,18 +2803,39 @@ static void BE_CreatePipeline(program_t *p, unsigned int shaderflags, unsigned i else rs.depthBiasEnable = VK_FALSE; + if (vk.amd_rasterization_order) + { + unsigned int b = blendflags & SBITS_BLEND_BITS; + //we potentially allow a little z-fighting if they're equal. a single batch shouldn't really have such primitives. + //must be no blending, or additive blending. + switch(blendflags & SBITS_DEPTHFUNC_BITS) + { + case SBITS_DEPTHFUNC_EQUAL: + break; + default: + if ((blendflags&(SBITS_MISC_NODEPTHTEST|SBITS_MISC_DEPTHWRITE)) == SBITS_MISC_DEPTHWRITE && + (!b || b == (SBITS_SRCBLEND_ONE|SBITS_DSTBLEND_ZERO) || b == SBITS_DSTBLEND_ONE)) + { + rs.pNext = &ro; + ro.rasterizationOrder = VK_RASTERIZATION_ORDER_RELAXED_AMD; + } + } + } + ms.pSampleMask = NULL; ms.rasterizationSamples = vk.multisamplebits; // ms.sampleShadingEnable = VK_TRUE; //call the fragment shader multiple times, instead of just once per final pixel // ms.minSampleShading = 0.25; ds.depthTestEnable = (blendflags&SBITS_MISC_NODEPTHTEST)?VK_FALSE:VK_TRUE; ds.depthWriteEnable = (blendflags&SBITS_MISC_DEPTHWRITE)?VK_TRUE:VK_FALSE; - if (blendflags & SBITS_MISC_DEPTHEQUALONLY) - ds.depthCompareOp = VK_COMPARE_OP_EQUAL; - else if (blendflags & SBITS_MISC_DEPTHCLOSERONLY) - ds.depthCompareOp = VK_COMPARE_OP_LESS; - else - ds.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; + switch(blendflags & SBITS_DEPTHFUNC_BITS) + { + default: + case SBITS_DEPTHFUNC_CLOSEREQUAL: ds.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; break; + case SBITS_DEPTHFUNC_EQUAL: ds.depthCompareOp = VK_COMPARE_OP_EQUAL; break; + case SBITS_DEPTHFUNC_CLOSER: ds.depthCompareOp = VK_COMPARE_OP_LESS; break; + case SBITS_DEPTHFUNC_FURTHER: ds.depthCompareOp = VK_COMPARE_OP_GREATER; break; + } ds.depthBoundsTestEnable = VK_FALSE; ds.back.failOp = VK_STENCIL_OP_KEEP; ds.back.passOp = VK_STENCIL_OP_KEEP; @@ -3016,7 +3038,7 @@ static void BE_BindPipeline(program_t *p, unsigned int shaderflags, unsigned int struct pipeline_s *pipe; blendflags &= 0 | SBITS_SRCBLEND_BITS | SBITS_DSTBLEND_BITS | SBITS_MASK_BITS | SBITS_ATEST_BITS - | SBITS_MISC_DEPTHWRITE | SBITS_MISC_NODEPTHTEST | SBITS_MISC_DEPTHEQUALONLY | SBITS_MISC_DEPTHCLOSERONLY + | SBITS_MISC_DEPTHWRITE | SBITS_MISC_NODEPTHTEST | SBITS_DEPTHFUNC_BITS | SBITS_LINES ; shaderflags &= 0 diff --git a/engine/vk/vk_init.c b/engine/vk/vk_init.c index 1a38f5a8..e60ed707 100644 --- a/engine/vk/vk_init.c +++ b/engine/vk/vk_init.c @@ -15,6 +15,7 @@ extern cvar_t vk_nv_glsl_shader; extern cvar_t vk_nv_dedicated_allocation; extern cvar_t vk_khr_dedicated_allocation; extern cvar_t vk_khr_push_descriptor; +extern cvar_t vk_amd_rasterization_order; extern cvar_t vid_srgb, vid_vsync, vid_triplebuffer, r_stereo_method, vid_multisample, vid_bpp; void R2D_Console_Resize(void); @@ -414,8 +415,8 @@ static qboolean VK_CreateSwapChain(void) if (vk.khr_dedicated_allocation) { khr_mdai.pNext = memAllocInfo.pNext; - khr_mdai.image = images[i]; - memAllocInfo.pNext = &khr_mdai; + khr_mdai.image = images[i]; + memAllocInfo.pNext = &khr_mdai; } VkAssert(vkAllocateMemory(vk.device, &memAllocInfo, vkallocationcb, &memories[i])); @@ -426,7 +427,7 @@ static qboolean VK_CreateSwapChain(void) { //using vulkan's presentation engine. int BOOST_UNORM, BOOST_SNORM, BOOST_SRGB, BOOST_UFLOAT, BOOST_SFLOAT; - if (vid_srgb.ival > 2) + if (vid_srgb.ival > 1) { //favour float formats, then srgb, then unorms BOOST_UNORM = 0; BOOST_SNORM = 0; @@ -602,7 +603,7 @@ static qboolean VK_CreateSwapChain(void) if (swapinfo.imageFormat == VK_FORMAT_UNDEFINED) { //if we found this format then it means the drivers don't really give a damn. pick a real format. - if (vid_srgb.ival > 2 && swapinfo.imageColorSpace == VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT) + if (vid_srgb.ival > 1 && swapinfo.imageColorSpace == VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT) swapinfo.imageFormat = VK_FORMAT_R16G16B16A16_SFLOAT; else if (vid_srgb.ival) swapinfo.imageFormat = VK_FORMAT_R8G8B8A8_SRGB; @@ -3802,16 +3803,17 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre const char *name; cvar_t *var; qboolean def; - qboolean *superseeded; //if this is set then the extension will not be enabled after all - const char *neededfor; + qboolean *superseeded; //if this is set then the extension will not be enabled after all + const char *warningtext; //printed if the extension is requested but not supported by the device qboolean supported; } knowndevexts[] = { {&vk.khr_swapchain, VK_KHR_SWAPCHAIN_EXTENSION_NAME, NULL, true, NULL, " Nothing will be drawn!"}, {&vk.nv_glsl_shader, VK_NV_GLSL_SHADER_EXTENSION_NAME, &vk_nv_glsl_shader, false, NULL, " Direct use of glsl is not supported."}, - {&vk.nv_dedicated_allocation, VK_NV_DEDICATED_ALLOCATION_EXTENSION_NAME, &vk_nv_dedicated_allocation, true, &vk.khr_dedicated_allocation, ""}, - {&vk.khr_dedicated_allocation, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME, &vk_khr_dedicated_allocation, true, NULL, ""}, - {&vk.khr_push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME, &vk_khr_push_descriptor, true, NULL, ""}, + {&vk.nv_dedicated_allocation, VK_NV_DEDICATED_ALLOCATION_EXTENSION_NAME, &vk_nv_dedicated_allocation, true, &vk.khr_dedicated_allocation, NULL}, + {&vk.khr_dedicated_allocation, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME, &vk_khr_dedicated_allocation, true, NULL, NULL}, + {&vk.khr_push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME, &vk_khr_push_descriptor, true, NULL, NULL}, + {&vk.amd_rasterization_order, VK_AMD_RASTERIZATION_ORDER_EXTENSION_NAME, &vk_amd_rasterization_order, false, NULL, NULL}, }; size_t e; @@ -4200,7 +4202,7 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre devextensions[numdevextensions++] = knowndevexts[e].name; } else if (knowndevexts[e].var->ival) - Con_Printf("unable to enable %s extension.%s\n", knowndevexts[e].name, knowndevexts[e].neededfor); + Con_Printf("unable to enable %s extension.%s\n", knowndevexts[e].name, knowndevexts[e].warningtext?knowndevexts[e].warningtext:""); else if (knowndevexts[e].supported) Con_DPrintf("Ignoring %s.\n", knowndevexts[e].name); else diff --git a/engine/vk/vkrenderer.h b/engine/vk/vkrenderer.h index a3a0a3a3..2a45ea8e 100644 --- a/engine/vk/vkrenderer.h +++ b/engine/vk/vkrenderer.h @@ -257,6 +257,7 @@ extern struct vulkaninfo_s qboolean nv_dedicated_allocation; //nvidia-specific extension that provides hints that there's no memory aliasing going on. qboolean khr_dedicated_allocation; //standardised version of the above where the driver decides whether a resource is worth a dedicated allocation. qboolean khr_push_descriptor; //more efficient descriptor streaming + qboolean amd_rasterization_order; //allows primitives to draw in any order VkInstance instance; VkDevice device; diff --git a/engine/web/gl_vidweb.c b/engine/web/gl_vidweb.c index e33ea2ac..4c030ea7 100644 --- a/engine/web/gl_vidweb.c +++ b/engine/web/gl_vidweb.c @@ -304,6 +304,8 @@ void GLVID_DeInit (void) vid.activeapp = false; emscriptenfte_setupcanvas(-1, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + + GL_ForgetPointers(); } diff --git a/fteqtv/httpsv.c b/fteqtv/httpsv.c index 51030cbf..9c37f044 100644 --- a/fteqtv/httpsv.c +++ b/fteqtv/httpsv.c @@ -891,7 +891,7 @@ static void HTTPSV_GeneratePlugin(cluster_t *cluster, oproxy_t *dest) "function playdemo(d)\n" "{\n" - "getplug().mapsrc = \"http://bigfoot.morphos-team.net/misc/quakemaps/\";\n" +// "getplug().mapsrc = \"http://bigfoot.morphos-team.net/misc/quakemaps/\";\n" "getplug().stream = \"file:\"+d+\"@" ; Net_ProxySend(cluster, dest, html, strlen(html));