diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index ef7f6c7b9..e71d4a052 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -378,6 +378,10 @@ void CL_ProgressDemoTime(void) return; } + if (cl.demopausedtilltime >= realtime) + return; + cl.demopausedtilltime = 0; + cl.demonudge = 0; if (cl_demospeed.value >= 0 && cls.state == ca_active) demtime += host_frametime*cl_demospeed.value; else @@ -448,6 +452,51 @@ void CL_DemoJump_f(void) cls.demoseeking = true; } +void CL_DemoNudge_f(void) +{ + extern cvar_t cl_demospeed; + int move = atoi(Cmd_Argv(1)); + int newnudge; + + if (!cls.demoplayback) + { + Con_Printf("not playing a demo, cannot nudge.\n"); + return; + } + + if (!move) + move = 1; + + newnudge = cl.demonudge + move; + if (newnudge <= -(int)countof(cl.inframes)) + newnudge = 1-(int)countof(cl.inframes); + + if (newnudge < 0) + { //if we're nudging to a past frame, make sure that its actually valid. + for(;-(int)countof(cl.inframes) < newnudge && newnudge < 0;) + { + int i = cls.netchan.incoming_sequence+newnudge; + if (i < 0) + break; + if (cl.inframes[i&UPDATE_MASK].frameid == i && !cl.inframes[i&UPDATE_MASK].invalid) + { + cl.demonudge = newnudge; + break; + } + if (move < 0) + newnudge--; + else + newnudge++; + } + if (!newnudge) + cl.demonudge = newnudge; + } + else + cl.demonudge = newnudge; + + cl.demopausedtilltime = realtime + 3; +} + /* ==================== CL_GetDemoMessage @@ -537,13 +586,13 @@ qboolean CL_GetDemoMessage (void) #endif if (cls.demoplayback == DPB_NETQUAKE && cls.signon == 4/*SIGNONS*/) { - if (!demtime) + /*if (!demtime) { cl.gametime = 0; cl.gametimemark = demtime; olddemotime = 0; return 0; - } + }*/ cls.netchan.last_received = realtime; if (cls.demoseeking) { @@ -553,6 +602,8 @@ qboolean CL_GetDemoMessage (void) return 0; } } + else if (cl.demonudge > 0) + cl.demonudge--; else if ((cls.timedemo && host_framecount == demoframe) || (!cls.timedemo && demtime < cl.gametime && cl.gametime))// > dem_lasttime+demtime) { if (demtime <= cl.gametime-1) @@ -688,6 +739,11 @@ readnext: cls.td_starttime = Sys_DoubleTime(); demtime = demotime; // warp } + else if (cl.demonudge > 0) + { + cl.demonudge--; + demtime = demotime; // warp + } else if (!(cl.paused&~4) && cls.state >= ca_onserver) { // always grab until fully connected if (demtime + 1.0 < demotime) diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index 2460ddf17..ffbfbb7ac 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -3680,7 +3680,12 @@ void CL_TransitionEntities (void) } //force our emulated time to as late as we can, if we're not using interpolation, which has the effect of disabling all interpolation - if (nolerp) + if (cl.demonudge < 0) + { + servertime = cl.inframes[(cls.netchan.incoming_sequence+cl.demonudge)&UPDATE_MASK].packet_entities.servertime; + nolerp = true; + } + else if (nolerp) servertime = cl.inframes[cls.netchan.incoming_sequence&UPDATE_MASK].packet_entities.servertime; else servertime = cl.servertime; @@ -4969,6 +4974,7 @@ void CL_LinkPlayers (void) float predictmsmult = 1000*cl_predict_players_frac.value; int modelindex2; extern cvar_t cl_demospeed; + int displayseq; if (!cl.worldmodel || cl.worldmodel->loadstate != MLS_LOADED) return; @@ -4982,7 +4988,11 @@ void CL_LinkPlayers (void) if (playertime > realtime) playertime = realtime; - frame = &cl.inframes[cl.validsequence&UPDATE_MASK]; + if (cl.demonudge < 0) + displayseq = cl.lerpentssequence; + else + displayseq = cl.validsequence; + frame = &cl.inframes[displayseq&UPDATE_MASK]; predictplayers = cl_predict_players.ival; if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV) @@ -4993,7 +5003,7 @@ void CL_LinkPlayers (void) { nametagseen[j] = false; - if (state->messagenum != cl.validsequence) + if (state->messagenum != displayseq) { #ifdef CSQC_DAT CSQC_DeltaPlayer(j, NULL); diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index a334a4b38..1e287d55a 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -4340,6 +4340,7 @@ void CL_Init (void) Cmd_AddCommand ("qtvlist", CL_QTVList_f); Cmd_AddCommand ("qtvdemos", CL_QTVDemos_f); Cmd_AddCommandD ("demo_jump", CL_DemoJump_f, "Jump to a specified time in a demo. Prefix with a + or - for a relative offset. Seeking backwards will restart the demo and the fast forward, which can take some time in long demos."); + Cmd_AddCommandD ("demo_nudge", CL_DemoNudge_f, "Nudge the demo by one frame. Argument should be +1 or -1. Nudging backwards is limited."); Cmd_AddCommandAD ("timedemo", CL_TimeDemo_f, CL_DemoList_c, NULL); Cmd_AddCommand ("crashme_endgame", CL_CrashMeEndgame_f); diff --git a/engine/client/cl_master.h b/engine/client/cl_master.h index 593e3f4c9..7b03cc03a 100644 --- a/engine/client/cl_master.h +++ b/engine/client/cl_master.h @@ -222,7 +222,7 @@ unsigned int Master_TotalCount(void); unsigned int Master_NumPolled(void); //progress indicator unsigned int Master_NumAlive(void); void Master_SetupSockets(void); -void MasterInfo_Refresh(void); +void MasterInfo_Refresh(qboolean doreset); void Master_QueryServer(serverinfo_t *server); void MasterInfo_WriteServers(void); diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 79bf8651d..8f151e1d3 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -1461,8 +1461,9 @@ static int CL_LoadSounds(int stage, qboolean dontactuallyload) void Sound_CheckDownload(const char *s) { +#ifndef QUAKETC char mangled[512]; - +#endif if (*s == '*') //q2 sexed sound return; @@ -1473,11 +1474,13 @@ void Sound_CheckDownload(const char *s) if (CL_CheckFile(s)) return; //we have it already +#if !defined(QUAKETC) && defined(AVAIL_OGGVORBIS) //the things I do for nexuiz... *sigh* COM_StripExtension(s, mangled, sizeof(mangled)); COM_DefaultExtension(mangled, ".ogg", sizeof(mangled)); if (CL_CheckFile(mangled)) return; +#endif //check with the sound/ prefix s = va("sound/%s",s); @@ -1485,12 +1488,13 @@ void Sound_CheckDownload(const char *s) if (CL_CheckFile(s)) return; //we have it already +#if !defined(QUAKETC) && defined(AVAIL_OGGVORBIS) //the things I do for nexuiz... *sigh* COM_StripExtension(s, mangled, sizeof(mangled)); COM_DefaultExtension(mangled, ".ogg", sizeof(mangled)); if (CL_CheckFile(mangled)) return; - +#endif //download the one the server said. CL_CheckOrEnqueDownloadFile(s, NULL, 0); } @@ -7932,9 +7936,26 @@ void CLNQ_ParseServerMessage (void) CL_SetStatNumeric (0, i, j, j); break; case svcdp_updatestatbyte: - i = MSG_ReadByte (); - j = MSG_ReadByte (); - CL_SetStatNumeric (0, i, j, j); + //case svcneh_fog: + if (CPNQ_IS_BJP || cls.protocol_nq == PROTOCOL_VERSION_NEHD) + { + CL_ResetFog(0); + if (MSG_ReadByte()) + { + cl.fog[0].density = MSG_ReadFloat(); + cl.fog[0].colour[0] = SRGBf(MSG_ReadByte()/255.0f); + cl.fog[0].colour[1] = SRGBf(MSG_ReadByte()/255.0f); + cl.fog[0].colour[2] = SRGBf(MSG_ReadByte()/255.0f); + cl.fog[0].time += 0.25; //change fairly fast, but not instantly + } + cl.fog_locked = !!cl.fog[0].density; + } + else + { + i = MSG_ReadByte (); + j = MSG_ReadByte (); + CL_SetStatNumeric (0, i, j, j); + } break; case svcfte_updatestatstring: i = MSG_ReadByte(); @@ -8086,7 +8107,7 @@ void CLNQ_ParseServerMessage (void) cls.signon = 4; CLNQ_SignonReply (); } - //well, it's really any protocol, but we're only going to support version 5. + //well, it's really any protocol, but we're only going to support version 5 (through 7). CLDP_ParseDarkPlaces5Entities(); break; case svcdp_spawnbaseline2: diff --git a/engine/client/cl_pred.c b/engine/client/cl_pred.c index bfee59a9a..fd5772969 100644 --- a/engine/client/cl_pred.c +++ b/engine/client/cl_pred.c @@ -651,7 +651,7 @@ void CL_CalcClientTime(void) if (max) { extern cvar_t cl_demospeed; - if (cls.demoplayback && cl_demospeed.value >= 0 && cls.state == ca_active) + if (cls.demoplayback && cl_demospeed.value > 0 && cls.state == ca_active) cl.servertime += host_frametime*cl_demospeed.value; else cl.servertime += host_frametime; diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index 5ff00e05c..fe41ed795 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -419,9 +419,12 @@ void SCR_CenterPrint (int pnum, const char *str, qboolean skipgamecode) cvar_t *var; var = Cvar_FindVar ("scr_centerprinttext"); if (!var) - Cvar_Get("scr_centerprinttext", "", 0, "Script Notifications"); - Cvar_Set(var, str); - Cbuf_AddText("f_centerprint\n", RESTRICT_LOCAL); + var = Cvar_Get("scr_centerprinttext", "", 0, "Script Notifications"); + if (var) + { + Cvar_Set(var, str); + Cbuf_AddText("f_centerprint\n", RESTRICT_LOCAL); + } } p = &scr_centerprint[pnum]; @@ -550,7 +553,10 @@ void SCR_CenterPrint (int pnum, const char *str, qboolean skipgamecode) for (i = 0; i < p->charcount; i++) { if (p->string[i] == CON_LINKSTART) + { p->flags |= CPRINT_CURSOR; + break; + } } } diff --git a/engine/client/cl_ui.c b/engine/client/cl_ui.c index 6f0077637..758282dd6 100644 --- a/engine/client/cl_ui.c +++ b/engine/client/cl_ui.c @@ -836,7 +836,7 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con { extern qboolean NET_SendPollPacket(int len, void *data, netadr_t to); netadr_t na; - MasterInfo_Refresh(); + MasterInfo_Refresh(false); if (NET_StringToAdr("255.255.255.255", PORT_Q3SERVER, &na)) NET_SendPollPacket (14, va("%c%c%c%cgetstatus\n", 255, 255, 255, 255), na); diff --git a/engine/client/client.h b/engine/client/client.h index da2b5e964..da05aab06 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -818,6 +818,8 @@ typedef struct float oldgametime; //used as the old time to lerp cl.time from. float oldgametimemark; //if it's 0, cl.time will casually increase. float demogametimebias; //mvd timings are weird. + int demonudge; // + float demopausedtilltime;//demo is paused until realtime>this float minpitch; float maxpitch; @@ -1229,6 +1231,7 @@ void CL_QTVPoll (void); void CL_QTVList_f (void); void CL_QTVDemos_f (void); void CL_DemoJump_f(void); +void CL_DemoNudge_f(void); void CL_ProgressDemoTime(void); void CL_TimeDemo_f (void); typedef struct diff --git a/engine/client/image.c b/engine/client/image.c index 16d388abc..e523b8002 100644 --- a/engine/client/image.c +++ b/engine/client/image.c @@ -4433,6 +4433,7 @@ typedef union byte_vec4_t v; unsigned int u; } pixel32_t; +#define etc_expandv(p,x,y,z) p.v[0]|=p.v[0]>>x,p.v[1]|=p.v[1]>>y,p.v[2]|=p.v[2]>>z #ifdef DECOMPRESS_ETC2 //FIXME: this is littleendian only... static void Image_Decode_ETC2_Block_TH_Internal(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w, pixel32_t base1, pixel32_t base2, int d, qboolean tmode) @@ -4507,8 +4508,6 @@ static void Image_Decode_ETC2_Block_Internal(qbyte *fte_restrict in, pixel32_t * unsigned char R1,G1,B1; pixel32_t *out1, *out2, *out3; -#define etc_expandv(p,x,y,z) p.v[0]|=p.v[0]>>x,p.v[1]|=p.v[1]>>y,p.v[2]|=p.v[2]>>z - qboolean opaque; if (alphamode) @@ -4757,15 +4756,15 @@ static void Image_Decode_S3TC_Block_Internal(qbyte *fte_restrict in, pixel32_t * } static void Image_Decode_BC1_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) { - Image_S3TC_Decode_Block_Internal(in, out, w, 0xff); + Image_Decode_S3TC_Block_Internal(in, out, w, 0xff); } static void Image_Decode_BC1A_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) { - Image_S3TC_Decode_Block_Internal(in, out, w, 0); + Image_Decode_S3TC_Block_Internal(in, out, w, 0); } static void Image_Decode_BC2_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) { - Image_S3TC_Decode_Block_Internal(in+8, out, w, 0xff); + Image_Decode_S3TC_Block_Internal(in+8, out, w, 0xff); //BC2 has straight 4-bit alpha. #define BC2_AlphaRow() \ @@ -4849,8 +4848,8 @@ static void Image_Decode_RGTC_Block_Internal(qbyte *fte_restrict in, qbyte *fte_ //s3tc rgb channel, with an rgtc alpha channel that depends upon both encodings (really the origin of rgtc, but mneh). static void Image_Decode_BC3_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) { - Image_S3TC_Decode_Block_Internal(in+8, out, w, 0xff); - Image_RGTC_Decode_Block_Internal(in, out->v+3, w*4, false); + Image_Decode_S3TC_Block_Internal(in+8, out, w, 0xff); + Image_Decode_RGTC_Block_Internal(in, out->v+3, w*4, false); } #endif static void Image_Decode_BC4U_Block(qbyte *fte_restrict in, pixel32_t *fte_restrict out, int w) @@ -5241,7 +5240,20 @@ static void Image_ChangeFormat(struct pendingtextureinfo *mips, unsigned int fla //if that format isn't supported/desired, try converting it. if (sh_config.texfmt[mips->encoding]) - return; + { + if (sh_config.texture_allow_block_padding && mips->mipcount) + { //direct3d is annoying, and will reject any block-compressed format with a base mip size that is not a multiple of the block size. + //its fine with weirdly sized mips though. I have no idea why there's this restriction, but whatever. + //we need to de + int blockbytes, blockwidth, blockheight; + Image_BlockSizeForEncoding(mips->encoding, &blockbytes, &blockwidth, &blockheight); + if (!(mips->mip[0].width % blockwidth) && !(mips->mip[0].height % blockheight)) + return; + //else encoding isn't supported for this size. fall through. + } + else + return; + } { //various compressed formats might not be supported. void *decodefunc = NULL; diff --git a/engine/client/keys.c b/engine/client/keys.c index c81511181..822445871 100644 --- a/engine/client/keys.c +++ b/engine/client/keys.c @@ -2745,7 +2745,8 @@ void Key_Event (unsigned int devid, int key, unsigned int unicode, qboolean down default: dc = keybindings[key][modifierstate]; //toggleconsole or +showFOO keys should do their regular bind action - if (!dc || (strcmp(dc, "toggleconsole") && strncmp(dc, "+show", 5))) + //demo_jump/demo_setspeed/demo_nudge should be allowed too. + if (!dc || (strcmp(dc, "toggleconsole") && strncmp(dc, "+show", 5) && strncmp(dc, "demo_", 5))) { M_ToggleMenu_f (); return; diff --git a/engine/client/m_master.c b/engine/client/m_master.c index b1cf05aad..eb407f134 100644 --- a/engine/client/m_master.c +++ b/engine/client/m_master.c @@ -1110,9 +1110,13 @@ static void SL_Remove (menu_t *menu) static qboolean SL_DoRefresh (menuoption_t *opt, menu_t *menu, int key) { - MasterInfo_Refresh(); - isrefreshing = true; - return true; + if (key == K_MOUSE1 || key == K_MOUSE1 || key == K_ENTER || key == K_KP_ENTER) + { + MasterInfo_Refresh(false); + isrefreshing = true; + return true; + } + return false; } void M_Menu_ServerList2_f(void) @@ -1249,7 +1253,7 @@ void M_Menu_ServerList2_f(void) if (!Master_TotalCount()) { - MasterInfo_Refresh(); + MasterInfo_Refresh(true); isrefreshing = true; } @@ -1309,7 +1313,7 @@ static void M_QuickConnect_PreDraw(menu_t *menu) } //retry - MasterInfo_Refresh(); + MasterInfo_Refresh(false); isrefreshing = true; } } @@ -1340,7 +1344,7 @@ void M_QuickConnect_f(void) Key_Dest_Add(kdm_emenu); - MasterInfo_Refresh(); + MasterInfo_Refresh(false); isrefreshing = true; quickconnecttimeout = Sys_DoubleTime() + 5; diff --git a/engine/client/m_mp3.c b/engine/client/m_mp3.c index 84ec55dcf..c21aa6284 100644 --- a/engine/client/m_mp3.c +++ b/engine/client/m_mp3.c @@ -351,7 +351,10 @@ qboolean Media_NamedTrack(const char *track, const char *looptrack) static char *ext[] = { "", -#ifdef AVAIL_OGGVORBIS +#if defined(AVAIL_OGGOPUS) || defined(FTE_TARGET_WEB) + ".opus", +#endif +#if defined(AVAIL_OGGVORBIS) || defined(FTE_TARGET_WEB) ".ogg", #endif #if defined(AVAIL_MP3_ACM) || defined(FTE_TARGET_WEB) diff --git a/engine/client/m_single.c b/engine/client/m_single.c index 05e88930f..d24d8eaba 100644 --- a/engine/client/m_single.c +++ b/engine/client/m_single.c @@ -1106,8 +1106,13 @@ void M_Menu_MediaFiles_f (void) info->ext[info->numext] = ".wav"; info->command[info->numext] = "media_add"; info->numext++; +#if defined(AVAIL_OGGOPUS) || defined(FTE_TARGET_WEB) + info->ext[info->numext] = ".opus"; + info->command[info->numext] = "media_add"; + info->numext++; +#endif #if defined(AVAIL_OGGVORBIS) || defined(FTE_TARGET_WEB) - info->ext[info->numext] = ".ogg"; //will this ever be added properly? + info->ext[info->numext] = ".ogg"; info->command[info->numext] = "media_add"; info->numext++; #endif diff --git a/engine/client/menu.c b/engine/client/menu.c index 523abe42c..ad20ec30b 100644 --- a/engine/client/menu.c +++ b/engine/client/menu.c @@ -1468,7 +1468,7 @@ void M_Keydown (int key, int unicode) if (key == K_MOUSE1) //mouse clicks are deferred until the release event. this is for touch screens and aiming. menu_mousedown = true; else if (key == K_LSHIFT || key == K_RSHIFT || key == K_LALT || key == K_RALT || key == K_LCTRL || key == K_RCTRL) - ; + ; //modifiers are sent on up events instead. else M_Complex_Key (key, unicode); return; diff --git a/engine/client/net_master.c b/engine/client/net_master.c index 71c0f6fbc..0b49a2785 100644 --- a/engine/client/net_master.c +++ b/engine/client/net_master.c @@ -2618,11 +2618,18 @@ void MasterInfo_WriteServers(void) } //poll master servers for server lists. -void MasterInfo_Refresh(void) +void MasterInfo_Refresh(qboolean doreset) { master_t *mast; + serverinfo_t *info; qboolean loadedone; + if (doreset) + { + for (info = firstserver; info; info = info->next) + info->status &= ~1; //hide until we get a new response from it. + } + loadedone = false; loadedone |= Master_LoadMasterList("masters.txt", false, MT_MASTERUDP, MP_QUAKEWORLD, 5); //fte listing diff --git a/engine/client/pr_clcmd.c b/engine/client/pr_clcmd.c index d6741c82f..456746661 100644 --- a/engine/client/pr_clcmd.c +++ b/engine/client/pr_clcmd.c @@ -376,7 +376,6 @@ void QCBUILTIN PF_cl_findkeysforcommand (pubprogfuncs_t *prinst, struct globalva RETURN_TSTRING(keyname); } - void QCBUILTIN PF_cl_findkeysforcommandex (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { const char *cmdname = PR_GetStringOfs(prinst, OFS_PARM0); @@ -384,9 +383,7 @@ void QCBUILTIN PF_cl_findkeysforcommandex (pubprogfuncs_t *prinst, struct global int keynums[256]; int keymods[countof(keynums)]; char keyname[512]; - int i, count; - - count = M_FindKeysForBind(bindmap, cmdname, keynums, keymods, countof(keynums)); + int i, count = M_FindKeysForBind(bindmap, cmdname, keynums, keymods, countof(keynums)); keyname[0] = '\0'; @@ -797,7 +794,8 @@ void QCBUILTIN PF_cl_sethostcachesort(pubprogfuncs_t *prinst, struct globalvars_ //void refreshhostcache(void) = #620; void QCBUILTIN PF_cl_refreshhostcache(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { - MasterInfo_Refresh(); + qboolean doreset = (prinst->callargc>=1)?G_FLOAT(OFS_PARM0):false; + MasterInfo_Refresh(doreset); } //float gethostcachenumber(float fld, float hostnr) = #621; void QCBUILTIN PF_cl_gethostcachenumber(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) diff --git a/engine/client/snd_mem.c b/engine/client/snd_mem.c index d4185fc1b..2e14a974d 100644 --- a/engine/client/snd_mem.c +++ b/engine/client/snd_mem.c @@ -873,7 +873,15 @@ static void S_LoadSoundWorker (void *ctx, void *ctxdata, size_t a, size_t b) //Con_Printf ("S_LoadSound: %x\n", (int)stackbuf); // load it in const char *prefixes[] = {"sound/", ""}; - const char *extensions[] = {".wav", ".ogg"}; + const char *extensions[] = { + ".wav", +#ifdef AVAIL_OGGOPUS + ".opus", +#endif +#ifdef AVAIL_OGGVORBIS + ".ogg", +#endif + }; char altname[sizeof(namebuffer)]; char orig[16]; size_t pre, ex; diff --git a/engine/client/view.c b/engine/client/view.c index 503e29ae8..167e65c1c 100644 --- a/engine/client/view.c +++ b/engine/client/view.c @@ -772,7 +772,7 @@ void V_CalcBlend (float *hw_blend) a2 = pv->cshifts[j].percent / 255.0; //don't allow modification of this one. } - if (!a2) + if (a2 <= 0) continue; if (j == CSHIFT_SERVER) diff --git a/engine/common/protocol.h b/engine/common/protocol.h index 43db506fd..282094445 100644 --- a/engine/common/protocol.h +++ b/engine/common/protocol.h @@ -318,6 +318,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define svcfitz_spawnstatic2 43 #define svcfitz_spawnstaticsound2 44 +//nehahra svcs +#define svcneh_skyboxsize 50 // [coord] size (default is 4096) +#define svcneh_fog 51 // [byte] enable [float] density [byte] red [byte] green [byte] blue + //DP extended svcs #define svcdp_downloaddata 50 #define svcdp_updatestatbyte 51 diff --git a/engine/d3d/d3d_image.c b/engine/d3d/d3d_image.c index 671c8c849..dd5c04fb2 100644 --- a/engine/d3d/d3d_image.c +++ b/engine/d3d/d3d_image.c @@ -35,12 +35,12 @@ qboolean D3D9_LoadTextureMips(image_t *tex, const struct pendingtextureinfo *mip fmt = D3DFMT_R5G6B5; break; case PTI_RGBA4444://not supported on d3d9 - return false; + break; case PTI_ARGB4444: fmt = D3DFMT_A4R4G4B4; break; case PTI_RGBA5551://not supported on d3d9 - return false; + break; case PTI_ARGB1555: fmt = D3DFMT_A1R5G5B5; break; @@ -159,6 +159,8 @@ qboolean D3D9_LoadTextureMips(image_t *tex, const struct pendingtextureinfo *mip } } + //Microsoft's code will reject any dxt texture with a mip[0] width/height that is not a multiple of 4. + if (FAILED(IDirect3DDevice9_CreateTexture(pD3DDev9, mips->mip[0].width, mips->mip[0].height, mipcount, 0, fmt, D3DPOOL_MANAGED, &dt, NULL))) return false; dbt = (IDirect3DBaseTexture9*)dt; diff --git a/engine/d3d/d3d_shader.c b/engine/d3d/d3d_shader.c index f581eb9c4..919cb8c77 100644 --- a/engine/d3d/d3d_shader.c +++ b/engine/d3d/d3d_shader.c @@ -597,6 +597,7 @@ void D3D9Shader_Init(void) IDirect3DDevice9_GetDeviceCaps(pD3DDev9, &caps); + sh_config.texture_allow_block_padding = false; //microsoft blocks this. if (caps.TextureCaps & D3DPTEXTURECAPS_POW2) { //this flag is a LIMITATION, not a capability. sh_config.texture_non_power_of_two = false; diff --git a/engine/d3d/vid_d3d11.c b/engine/d3d/vid_d3d11.c index 6d9561405..df23dd2ef 100644 --- a/engine/d3d/vid_d3d11.c +++ b/engine/d3d/vid_d3d11.c @@ -856,6 +856,7 @@ static qboolean initD3D11Device(HWND hWnd, rendererstate_t *info, PFN_D3D11_CREA memset(&sh_config, 0, sizeof(sh_config)); sh_config.texture_non_power_of_two = flevel>=D3D_FEATURE_LEVEL_10_0; //npot MUST be supported on all d3d10+ cards. sh_config.texture_non_power_of_two_pic = true; //always supported in d3d11, supposedly, even with d3d9 devices. + sh_config.texture_allow_block_padding = false; //microsoft blocks this. sh_config.npot_rounddown = false; if (flevel>=D3D_FEATURE_LEVEL_11_0) sh_config.texture2d_maxsize = 16384; diff --git a/engine/d3d/vid_d3d8.c b/engine/d3d/vid_d3d8.c index a6081cb42..65edcf04d 100644 --- a/engine/d3d/vid_d3d8.c +++ b/engine/d3d/vid_d3d8.c @@ -504,6 +504,7 @@ void D3D8Shader_Init(void) IDirect3DDevice8_GetDeviceCaps(pD3DDev8, &caps); + sh_config.texture_allow_block_padding = false; //microsoft blocks this. if (caps.TextureCaps & D3DPTEXTURECAPS_POW2) { //this flag is a LIMITATION, not a capability. sh_config.texture_non_power_of_two = false; diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c index 48f046e6e..5348412a9 100644 --- a/engine/gl/gl_vidcommon.c +++ b/engine/gl/gl_vidcommon.c @@ -668,6 +668,11 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name)) Con_DPrintf("Anisotropic filter extension found (%dx max).\n",gl_config.ext_texture_filter_anisotropic); } + if ((!gl_config.gles && gl_config.glversion >= 2) || GL_CheckExtension("GL_ARB_texture_non_power_of_two")) + sh_config.texture_allow_block_padding = true; //gl2/npot explicitly relaxes this restriction + else + sh_config.texture_allow_block_padding = false; //gles does not support padded sizes, even with gles3. This is especially true if we're running atop d3d-via-webgl. + if (!gl_config.gles && gl_config.glversion >= 3) { //GL_ARB_texture_non_power_of_two is supposed to be mandatory in gl2+ and thus checking for it is redundant and not forwards-compatible //geforcefx apparently software emulates it, so only activate it unconditionally on gl3+ hardware. diff --git a/engine/gl/shader.h b/engine/gl/shader.h index 96f087e5b..043af6720 100644 --- a/engine/gl/shader.h +++ b/engine/gl/shader.h @@ -767,6 +767,7 @@ typedef struct unsigned int texturecube_maxsize; qboolean texture_non_power_of_two; //full support for npot qboolean texture_non_power_of_two_pic; //npot only works with clamp-to-edge mipless images. + qboolean texture_allow_block_padding; //mip 0 of compressed formats can be any size, with implicit padding. qboolean npot_rounddown; //memory limited systems can say that they want to use less ram. qboolean tex_env_combine; qboolean nv_tex_env_combine4; diff --git a/engine/qclib/pr_edict.c b/engine/qclib/pr_edict.c index 2e96b73cc..3e527f824 100644 --- a/engine/qclib/pr_edict.c +++ b/engine/qclib/pr_edict.c @@ -1206,6 +1206,8 @@ pbool PDECL ED_ParseEval (pubprogfuncs_t *ppf, eval_t *eval, int type, const cha break; case ev_entity: + if (!strncmp(s, "entity ", 7)) //cope with etos weirdness. + s += 7; eval->edict = atoi (s); break; diff --git a/engine/qclib/qcc_pr_comp.c b/engine/qclib/qcc_pr_comp.c index 00a4cfe72..286a1924e 100644 --- a/engine/qclib/qcc_pr_comp.c +++ b/engine/qclib/qcc_pr_comp.c @@ -10156,12 +10156,12 @@ void QCC_PR_ParseStatement (void) if (QCC_PR_CheckKeyword(keyword_return, "return")) { - /*if (pr_classtype) - { - e = QCC_PR_GetDef(NULL, "__oself", pr_scope, false, 0); - e2 = QCC_PR_GetDef(NULL, "self", NULL, false, 0); - QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_STORE_ENT], e, QCC_PR_DummyDef(pr_classtype, "self", pr_scope, 0, e2->ofs, false), NULL)); - }*/ + /* + accumulate behaviour requires the ability to just run code without explicit returns. + return = foo; sets the value that will be returned when the function finally exits, without returning now. + return; returns that value now, without execing later accumulations. + return 5; also returns now. + */ if (QCC_PR_CheckToken (";")) { @@ -10186,6 +10186,9 @@ void QCC_PR_ParseStatement (void) // if (opt_return_only) // QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[OP_DONE], nullsref, nullsref, NULL)); // else + if (pr_scope->type->aux_type->type == ev_vector) //make sure bad returns don't return junk in the y+z members. + QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[OP_RETURN], QCC_MakeVectorConst(0,0,0), nullsref, NULL)); + else QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[OP_RETURN], nullsref, nullsref, NULL)); return; } @@ -12252,6 +12255,7 @@ void QCC_PR_FinaliseFunction(QCC_function_t *f) QCC_PR_ResumeFunction(f); pr_token_line_last = f->line_end; + s_filen = f->filen; if (f->returndef.cast) { diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 17e0c8c94..e2f9bdaa2 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -10849,7 +10849,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"sethostcachemasknumber",PF_Fixme, 0, 0, 0, 617, "void(float mask, float fld, float num, float op)"}, {"resorthostcache", PF_Fixme, 0, 0, 0, 618, "void()"}, {"sethostcachesort",PF_Fixme, 0, 0, 0, 619, "void(float fld, float descending)"}, - {"refreshhostcache",PF_Fixme, 0, 0, 0, 620, "void()"}, + {"refreshhostcache",PF_Fixme, 0, 0, 0, 620, "void(optional float dopurge)"}, {"gethostcachenumber",PF_Fixme, 0, 0, 0, 621, "float(float fld, float hostnr)"}, {"gethostcacheindexforkey",PF_Fixme, 0, 0, 0, 622, "float(string key)"}, {"addwantedhostcachekey",PF_Fixme, 0, 0, 0, 623, "void(string key)"}, diff --git a/engine/vk/vk_init.c b/engine/vk/vk_init.c index e60ed707a..058b81aea 100644 --- a/engine/vk/vk_init.c +++ b/engine/vk/vk_init.c @@ -4304,6 +4304,7 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre sh_config.minver = -1; sh_config.maxver = -1; + sh_config.texture_allow_block_padding = true; sh_config.texture_non_power_of_two = true; //is this always true? sh_config.texture_non_power_of_two_pic = true; //probably true... sh_config.npot_rounddown = false; diff --git a/specs/bspx.txt b/specs/bspx.txt new file mode 100644 index 000000000..b2040a7d4 --- /dev/null +++ b/specs/bspx.txt @@ -0,0 +1,109 @@ +BSPX is a format originally invented by Tonik, I believe, and is already implemented in both ezQuake and FTE. +It is not so much a format itself, but more of an extensible way to shove additional lumps within an existing BSP. +Typically these additional lumps will provide supplemental information or replace existing info. +BSPX itself can logically be applied to the BSP file format of Quake, Quake II, or Quake III. + +BSPX itself can be defined in just the following two structures: +typedef struct { + char lumpname[24]; // up to 23 chars, zero-padded + int fileofs; // from file start + int filelen; +} bspx_lump_t; +typedef struct { + char id[4]; // 'BSPX' + int numlumps; + bspx_lump_t lumps[1]; +} bspx_header_t; + +The bspx_header_t struct can be found immediately following the BSP's standard header. It is only valid if the standard header specifies no lump as starting at that location, and if the magic id matches. +The engine can then walk the lump list looking for lumps that it recognises. Unknown lumps MUST be ignored. + + + +These lumps are currently defined: + +RGBLIGHTING: +(applies to fte, ezquake, qss) +This is equivelent to the information stored in a .lit file (sans header), and must contain the same number of samples as the lightmap lump would normally contain, because it doesn't make much sense otherwise. +Presence of this lump permits omitting the regular mono lightmap to save space, but doing so will harm compatibility. + +LIGHTING_E5BGR9: +(applies to fte) +This is a more advanced alternative to RGBLIGHTING. +Each luxel is a E5BGR9 int32 packed value (ie: on little-endian machines, the exponent is the high 5 bits), resulting in what is effectively a memory-efficient floating point rgb value. +This lightmap format virtually removes all oversaturation limits, and promises greater precision in dark areas too. +This format is directly supported on ALL OpenGL[ES] 3.0+ gpus (aka: GL_EXT_texture_shared_exponent). +As a floating point format, a logical value of 1.0 is considered as identity (instead of 255 being an [overbright] multiplier of 2.0). +Lighting values are always assumed to be linear. + +LIGHTINGDIR: +(applies to fte) +This lump contains surface-space light directions (read: deluxemap), equivelent to fte's .lux file, or dp's .dlit files (sans header). +(as unorm values, these need to be biased before use). +If bumpmaps or specular maps are not available then the effects of this may not be significant/noticable. + +LMSHIFT: +(applies to fte, qss) +This is a series of per-surface bytes. Each byte provides the (1< [alpha] [scale] Specifies a ramp index in rgb terms, regardless of palette. stains + (Not supported in QSS) How much the effect discolours the wall upon impact. The stained colour is based upon the colour of the particle upon impact. @@ -359,6 +360,7 @@ spawnvel [vert] obsolete viewspace [frac] + (Not supported in QSS) Specifies that this particle type should move relative to the camera. Not compatible with splitscreen. Should not normally be used in combination with clipping/bouncing. @@ -412,6 +414,7 @@ lightshadows lightcorona model [options] + (Not supported in QSS) options are: frame= framestart= @@ -442,6 +445,8 @@ sound [options] Plays a sound when the effect is spawned. Only ONE sound will be used, picked randomly from the included sounds according to their weights. spawnstain + (Not supported in QSS) + Controls whether a stain will be created at the same time as any particles (instead of depending upon impacts). rainfrequency Specifies the interval between spawning new particle puffs on surfaces.