diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index b642a6d18..340d9b489 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -2133,6 +2133,7 @@ void V_AddAxisEntity(entity_t *in) void V_ClearEntity(entity_t *e) { memset(e, 0, sizeof(*e)); + e->pvscache.num_leafs = -1; e->playerindex = -1; e->topcolour = TOP_DEFAULT; e->bottomcolour = BOTTOM_DEFAULT; @@ -3342,11 +3343,11 @@ void CL_LinkStaticEntities(void *pvs) VectorCopy(stat->state.origin, mins); VectorCopy(stat->state.origin, maxs); } - cl.worldmodel->funcs.FindTouchedLeafs(cl.worldmodel, &stat->pvscache, mins, maxs); + cl.worldmodel->funcs.FindTouchedLeafs(cl.worldmodel, &stat->ent.pvscache, mins, maxs); } /*pvs test*/ - if (pvs && !cl.worldmodel->funcs.EdictInFatPVS(cl.worldmodel, &stat->pvscache, pvs)) + if (pvs && !cl.worldmodel->funcs.EdictInFatPVS(cl.worldmodel, &stat->ent.pvscache, pvs)) continue; @@ -3918,6 +3919,13 @@ void CL_LinkPacketEntities (void) le = &cl.lerpents[state->number]; ent = &cl_visedicts[cl_numvisedicts]; + ent->pvscache.num_leafs = 0; +#if defined(Q2BSPS) || defined(Q3BSPS) || defined(TERRAIN) + ent->pvscache.areanum = 0; + ent->pvscache.areanum2 = 0; + ent->pvscache.headnode = 0; +#endif + ent->rtype = RT_MODEL; ent->playerindex = -1; ent->customskin = 0; diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index e4d9a1b7c..352f5c427 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -2282,6 +2282,10 @@ void CL_SendCmd (double frametime, qboolean mainloop) { CL_SendDownloadReq(&buf); + //only start spamming userinfo blobs once we receive the initial serverinfo. + while (cls.userinfosync.numkeys && cls.netchan.message.cursize < 512 && (cl.haveserverinfo || cls.protocol == CP_QUAKE2 || cls.protocol == CP_QUAKE3)) + CL_SendUserinfoUpdate(); + while (clientcmdlist) { next = clientcmdlist->next; @@ -2289,6 +2293,8 @@ void CL_SendCmd (double frametime, qboolean mainloop) { if (cls.netchan.message.cursize + 2+strlen(clientcmdlist->command)+100 > cls.netchan.message.maxsize) break; + if (!strncmp(clientcmdlist->command, "spawn", 5) && cls.userinfosync.numkeys) + break; //HACK: don't send the spawn until all pending userinfos have been flushed. MSG_WriteByte (&cls.netchan.message, clc_stringcmd); MSG_WriteString (&cls.netchan.message, clientcmdlist->command); } @@ -2304,10 +2310,6 @@ void CL_SendCmd (double frametime, qboolean mainloop) Z_Free(clientcmdlist); clientcmdlist = next; } - - //only start spamming userinfo blobs once we receive the initial serverinfo. - while (cls.userinfosync.numkeys && cls.netchan.message.cursize < 512 && (cl.haveserverinfo || cls.protocol == CP_QUAKE2 || cls.protocol == CP_QUAKE3)) - CL_SendUserinfoUpdate(); } // if we're not doing clc_moves and etc, don't continue unless we wrote something previous diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 8e1f3f49c..8dc9d4a0a 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -3880,10 +3880,7 @@ static void CLNQ_ParseServerData(void) //Doesn't change gamedir - use with caut } static void CLNQ_SendInitialUserInfo(void *ctx, const char *key, const char *value) { - char keybuf[2048]; - char valbuf[4096]; - #warning FIXME: use CL_SendUserinfoUpdate or something - CL_SendClientCommand(true, "setinfo %s %s\n", COM_QuotedString(key, keybuf, sizeof(keybuf), false), COM_QuotedString(value, valbuf, sizeof(valbuf), false)); + InfoSync_Add(&cls.userinfosync, ctx, key); } void CLNQ_SignonReply (void) { @@ -3907,7 +3904,7 @@ Con_DPrintf ("CL_SignonReply: %i\n", cls.signon); CL_SendClientCommand(true, "name \"%s\"\n", name.string); CL_SendClientCommand(true, "color %i %i\n", topcolor.ival, bottomcolor.ival); if (cl.haveserverinfo) - InfoBuf_Enumerate(&cls.userinfo[0], NULL, CLNQ_SendInitialUserInfo); + InfoBuf_Enumerate(&cls.userinfo[0], &cls.userinfo[0], CLNQ_SendInitialUserInfo); else if (CPNQ_IS_DP) { //dp needs a couple of extras to work properly in certain cases. don't send them on other servers because that generally results in error messages. CL_SendClientCommand(true, "rate %s", rate.string); @@ -4593,7 +4590,7 @@ static void CL_ParseStaticProt (int baselinetype) cl_static_entities[i].state = es; ent = &cl_static_entities[i].ent; V_ClearEntity(ent); - memset(&cl_static_entities[i].pvscache, 0, sizeof(cl_static_entities[i].pvscache)); + memset(&cl_static_entities[i].ent.pvscache, 0, sizeof(cl_static_entities[i].ent.pvscache)); ent->keynum = es.number; @@ -4662,7 +4659,7 @@ static void CL_ParseStaticProt (int baselinetype) VectorCopy(es.origin, mins); VectorCopy(es.origin, maxs); } - cl.worldmodel->funcs.FindTouchedLeafs(cl.worldmodel, &cl_static_entities[i].pvscache, mins, maxs); + cl.worldmodel->funcs.FindTouchedLeafs(cl.worldmodel, &cl_static_entities[i].ent.pvscache, mins, maxs); #ifdef RTLIGHTS //and now handle any rtlight fields on it diff --git a/engine/client/client.h b/engine/client/client.h index 09b0d77c5..81115d16c 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -841,10 +841,6 @@ typedef struct } intermissionmode; // don't change view angle, full screen, etc float completed_time; // latched ffrom time at intermission start -#define Q2MAX_VISIBLE_WEAPONS 32 //q2 has about 20. - int numq2visibleweapons; //q2 sends out visible-on-model weapons in a wierd gender-nutral way. - char *q2visibleweapons[Q2MAX_VISIBLE_WEAPONS];//model names beginning with a # are considered 'sexed', and are loaded on a per-client basis. yay. :( - // // information that is static for the entire time connected to a server // @@ -860,6 +856,10 @@ typedef struct int particle_ssprecache[MAX_SSPARTICLESPRE]; //these are actually 1-based, so 0 can be used to lazy-init them. I cheat. #ifdef Q2CLIENT +#define Q2MAX_VISIBLE_WEAPONS 32 //q2 has about 20. + int numq2visibleweapons; //q2 sends out visible-on-model weapons in a wierd gender-nutral way. + char *q2visibleweapons[Q2MAX_VISIBLE_WEAPONS];//model names beginning with a # are considered 'sexed', and are loaded on a per-client basis. yay. :( + char *configstring_general[Q2MAX_CLIENTS|Q2MAX_GENERAL]; char *image_name[Q2MAX_IMAGES]; char *item_name[Q2MAX_ITEMS]; @@ -1043,7 +1043,6 @@ typedef struct entity_state_t state; trailstate_t *emit; int mdlidx; /*negative are csqc indexes*/ - pvscache_t pvscache; } static_entity_t; // FIXME, allocate dynamically diff --git a/engine/client/m_options.c b/engine/client/m_options.c index 68650f7d5..6dbab1c4b 100644 --- a/engine/client/m_options.c +++ b/engine/client/m_options.c @@ -605,7 +605,6 @@ void M_Menu_Audio_f (void) }; #ifdef VOICECHAT static const char *voipcodecoptions[] = { - "Auto", "Speex (ez-compat)", // "Raw16 (11025)", "Opus", @@ -617,8 +616,7 @@ void M_Menu_Audio_f (void) NULL }; static const char *voipcodecvalue[] = { - "", - "0", //speex non-standard + "0", //speex non-standard (outdated) // "1", //pcm16 sucks "2", //opus "3", //speex narrow diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index af302032f..0b91de6f5 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -860,7 +860,7 @@ static float CSQC_PitchScaleForModelIndex(int index) wedict_t *skel_gettaginfo_args (pubprogfuncs_t *prinst, vec3_t axis[3], vec3_t origin, int tagent, int tagnum); #endif -static qboolean CopyCSQCEdictToEntity(csqcedict_t *in, entity_t *out) +static qboolean CopyCSQCEdictToEntity(csqcedict_t *fte_restrict in, entity_t *fte_restrict out) { int ival; model_t *model; @@ -874,6 +874,7 @@ static qboolean CopyCSQCEdictToEntity(csqcedict_t *in, entity_t *out) memset(out, 0, sizeof(*out)); out->model = model; + out->pvscache = in->pvsinfo; rflags = in->xv->renderflags; if (csqc_isdarkplaces) @@ -882,7 +883,10 @@ static qboolean CopyCSQCEdictToEntity(csqcedict_t *in, entity_t *out) { rflags = in->xv->renderflags; if (rflags & CSQCRF_VIEWMODEL) + { out->flags |= RF_DEPTHHACK|RF_WEAPONMODEL; + out->pvscache.num_leafs = -1; + } if (rflags & CSQCRF_EXTERNALMODEL) out->flags |= RF_EXTERNALMODEL; if (rflags & CSQCRF_DEPTHHACK) @@ -947,6 +951,7 @@ static qboolean CopyCSQCEdictToEntity(csqcedict_t *in, entity_t *out) csqcedict_t *p = (csqcedict_t*)skel_gettaginfo_args(csqcprogs, out->axis, out->origin, in->xv->tag_entity, in->xv->tag_index); if (p && (int)p->xv->renderflags & CSQCRF_VIEWMODEL) out->flags |= RF_DEPTHHACK|RF_WEAPONMODEL; + out->pvscache.num_leafs = -1; //make visible globally #endif } @@ -1030,9 +1035,9 @@ static void QCBUILTIN PF_cs_makestatic (pubprogfuncs_t *prinst, struct globalvar cl_static_entities[cl.num_statics].emit = NULL; cl_static_entities[cl.num_statics].mdlidx = in->v->modelindex; if (cl.worldmodel && cl.worldmodel->funcs.FindTouchedLeafs) - cl.worldmodel->funcs.FindTouchedLeafs(cl.worldmodel, &cl_static_entities[cl.num_statics].pvscache, in->v->absmin, in->v->absmax); + cl.worldmodel->funcs.FindTouchedLeafs(cl.worldmodel, &cl_static_entities[cl.num_statics].ent.pvscache, in->v->absmin, in->v->absmax); else - memset(&cl_static_entities[cl.num_statics].pvscache, 0, sizeof(cl_static_entities[cl.num_statics].pvscache)); + memset(&cl_static_entities[cl.num_statics].ent.pvscache, 0, sizeof(cl_static_entities[cl.num_statics].ent.pvscache)); cl.num_statics++; //rtlights kinda need all this junk @@ -2116,13 +2121,24 @@ uploadfmt_t PR_TranslateTextureFormat(int qcformat) { switch(qcformat) { - case 1: return TF_RGBA32; - case 2: return TF_RGBA16F; - case 3: return TF_RGBA32F; - case 4: return TF_DEPTH16; - case 5: return TF_DEPTH24; - case 6: return TF_DEPTH32; - default:return TF_INVALID; + case 1: return PTI_RGBA8; + case 2: return PTI_RGBA16F; + case 3: return PTI_RGBA32F; + + case 4: return PTI_DEPTH16; + case 5: return PTI_DEPTH24; + case 6: return PTI_DEPTH32; + + case 7: return PTI_R8; + case 8: return PTI_R16F; + case 9: return PTI_R32F; + + case 10: return PTI_A2BGR10; + case 11: return PTI_RGB565; + case 12: return PTI_RGBA4444; + case 13: return PTI_RG8; + + default:return PTI_INVALID; } } void QCBUILTIN PF_R_SetViewFlag(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) diff --git a/engine/client/r_2d.c b/engine/client/r_2d.c index 3f8f031d6..a29245718 100644 --- a/engine/client/r_2d.c +++ b/engine/client/r_2d.c @@ -1373,7 +1373,7 @@ void R2D_BrightenScreen (void) RSpeedMark(); - if (fabs(v_contrast.value - 1.0) < 0.05 && fabs(v_brightness.value - 0) < 0.05 && fabs(v_gamma.value - 1) < 0.05) + if (fabs(v_contrast.value - 1.0) < 0.05 && fabs(v_contrastboost.value - 1.0) < 0.05 && fabs(v_brightness.value - 0) < 0.05 && fabs(v_gamma.value - 1) < 0.05) return; //don't go crazy with brightness. that makes it unusable and is thus unsafe - and worse, lots of people assume its based around 1 (like gamma and contrast are). cap to 0.5 @@ -1386,10 +1386,10 @@ void R2D_BrightenScreen (void) return; TRACE(("R2D_BrightenScreen: brightening\n")); - if ((v_gamma.value != 1 || v_contrast.value > 3) && shader_gammacb->prog) + if ((v_gamma.value != 1 || v_contrast.value > 3 || v_contrastboost.value != 1) && shader_gammacb->prog) { //this should really be done properly, with render-to-texture - R2D_ImageColours (v_gamma.value, v_contrast.value, v_brightness.value, 1); + R2D_ImageColours (v_gammainverted.ival?v_gamma.value:(1/v_gamma.value), v_contrast.value, v_brightness.value, v_contrastboost.value); R2D_Image(0, 0, vid.width, vid.height, 0, 0, 1, 1, shader_gammacb); } else diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index 7eccb4fb2..81b9b7f2d 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -4204,7 +4204,7 @@ TRACE(("dbg: Surf_NewMap: tp\n")); VectorCopy(maxs, cl_static_entities[i].ent.origin); } if (cl.worldmodel->funcs.FindTouchedLeafs) - cl.worldmodel->funcs.FindTouchedLeafs(cl.worldmodel, &cl_static_entities[i].pvscache, mins, maxs); + cl.worldmodel->funcs.FindTouchedLeafs(cl.worldmodel, &cl_static_entities[i].ent.pvscache, mins, maxs); cl_static_entities[i].emit = NULL; } diff --git a/engine/client/render.h b/engine/client/render.h index 3636ea5d6..9177d79b5 100644 --- a/engine/client/render.h +++ b/engine/client/render.h @@ -146,6 +146,8 @@ typedef struct entity_s struct shader_s *forcedshader; + pvscache_t pvscache; //for culling of csqc ents. + #ifdef PEXT_SCALE float scale; #endif @@ -322,7 +324,7 @@ extern struct texture_s *r_notexture_mip; extern entity_t r_worldentity; -void BE_GenModelBatches(struct batch_s **batches, const struct dlight_s *dl, unsigned int bemode); //if dl, filters based upon the dlight. +void BE_GenModelBatches(struct batch_s **batches, const struct dlight_s *dl, unsigned int bemode, qbyte *worldpvs); //if dl, filters based upon the dlight. //gl_alias.c void R_GAliasFlushSkinCache(qboolean final); diff --git a/engine/client/renderer.c b/engine/client/renderer.c index c50a3114e..2841165e9 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -105,6 +105,12 @@ extern cvar_t dpcompat_nopremulpics; cvar_t dpcompat_psa_ungroup = CVAR ("dpcompat_psa_ungroup", "0"); #endif +#ifdef HAVE_LEGACY +cvar_t r_ignoreentpvs = CVARD ("r_ignoreentpvs", "1", "Disables pvs culling of entities that have been submitted to the renderer."); +#else +cvar_t r_ignoreentpvs = CVARD ("r_ignoreentpvs", "0", "Disables pvs culling of entities that have been submitted to the renderer."); +#endif + cvar_t mod_md3flags = CVARD ("mod_md3flags", "1", "The flags field of md3s was never officially defined. If this is set to 1, the flags will be treated identically to mdl files. Otherwise they will be ignored. Naturally, this is required to provide rotating pickups in quake."); cvar_t r_ambient = CVARF ("r_ambient", "0", @@ -958,6 +964,7 @@ void Renderer_Init(void) //renderer + Cvar_Register (&r_ignoreentpvs, "Hacky bug workarounds"); Cvar_Register (&r_fullbright, SCREENOPTIONS); Cvar_Register (&r_drawentities, GRAPHICALNICETIES); Cvar_Register (&r_drawviewmodel, GRAPHICALNICETIES); diff --git a/engine/client/screen.h b/engine/client/screen.h index e93db8eca..a50cbae65 100644 --- a/engine/client/screen.h +++ b/engine/client/screen.h @@ -220,11 +220,6 @@ typedef enum uploadfmt PTI_MAX, TF_INVALID = PTI_INVALID, - TF_DEPTH16 = PTI_DEPTH16, - TF_DEPTH24 = PTI_DEPTH24, - TF_DEPTH32 = PTI_DEPTH32, - TF_RGBA16F = PTI_RGBA16F, - TF_RGBA32F = PTI_RGBA32F, TF_RGBA32 = PTI_RGBA8, /*rgba byte order*/ TF_BGRA32 = PTI_BGRA8, /*bgra byte order*/ TF_RGBX32 = PTI_RGBX8, /*rgb byte order, with extra wasted byte after blue*/ diff --git a/engine/client/snd_dma.c b/engine/client/snd_dma.c index 618ecf8de..094b397e6 100644 --- a/engine/client/snd_dma.c +++ b/engine/client/snd_dma.c @@ -288,7 +288,7 @@ enum #ifdef NOLEGACY #define VOIP_DEFAULT_CODEC VOIP_OPUS #else -#define VOIP_DEFAULT_CODEC (cls.protocol==CP_QUAKEWORLD?VOIP_SPEEX_OLD:VOIP_OPUS) //opus is preferred, but ezquake is still common and only supports my first attempt at voice compression so favour that for quakeworld. +#define VOIP_DEFAULT_CODEC ((cls.protocol==CP_QUAKEWORLD && !(cls.fteprotocolextensions2&PEXT2_REPLACEMENTDELTAS))?VOIP_SPEEX_OLD:VOIP_OPUS) //opus is preferred, but ezquake is still common and only supports my first attempt at voice compression so favour that for mvdsv servers. #endif static struct { diff --git a/engine/client/view.c b/engine/client/view.c index cb830aba3..a3006415e 100644 --- a/engine/client/view.c +++ b/engine/client/view.c @@ -333,8 +333,10 @@ cshift_t cshift_lava = { {255,80,0}, 150 }; cshift_t cshift_server = { {130,80,50}, 0 }; cvar_t v_gamma = CVARFCD("gamma", "1.0", CVAR_ARCHIVE|CVAR_RENDERERCALLBACK, V_Gamma_Callback, "Controls how bright the screen is. Setting this to anything but 1 without hardware gamma requires glsl support and can noticably harm your framerate."); -cvar_t v_contrast = CVARFCD("contrast", "1.0", CVAR_ARCHIVE, V_Gamma_Callback, "Scales colour values linearly to make your screen easier to see. Setting this to anything but 1 without hardware gamma will reduce your framerates a little."); -cvar_t v_brightness = CVARFCD("brightness", "0.0", CVAR_ARCHIVE, V_Gamma_Callback, "Brightness is how much 'white' to add to each and every pixel on the screen."); +cvar_t v_gammainverted = CVARFCD("v_gammainverted", "0", CVAR_ARCHIVE, V_Gamma_Callback, "Boolean that controls whether the gamma should be inverted (like quake) or not."); +cvar_t v_contrast = CVARAFCD("contrast", "1.0", "v_contrast", CVAR_ARCHIVE, V_Gamma_Callback, "Scales colour values linearly to make your screen easier to see. Setting this to anything but 1 without hardware gamma will reduce your framerates a little."); +cvar_t v_contrastboost = CVARFCD("v_contrastboost", "1.0", CVAR_ARCHIVE, V_Gamma_Callback, "Amplifies contrast in dark areas"); +cvar_t v_brightness = CVARAFCD("brightness", "0.0", "v_contrast", CVAR_ARCHIVE, V_Gamma_Callback, "Brightness is how much 'white' to add to each and every pixel on the screen."); qbyte gammatable[256]; // palette is sent through this @@ -363,14 +365,15 @@ void BuildGammaTable (float g) gammatable[i] = inf; } }*/ -void BuildGammaTable (float g, float c, float b) +void BuildGammaTable (float gamma, float cscale, float cboost, float brightness) { int i, inf; + float t; -// g = bound (0.1, g, 3); -// c = bound (1, c, 3); +// gamma = bound (0.1, gamma, 3); +// cscale = bound (1, cscale, 3); - if (g == 1 && c == 1) + if (gamma == 1 && cscale == 1 && cboost == 1 && brightness == 0) { for (i = 0; i < 256; i++) gammatable[i] = i; @@ -380,13 +383,11 @@ void BuildGammaTable (float g, float c, float b) for (i = 0; i < 256; i++) { //the 0.5s are for rounding. - inf = 255 * (pow ((i + 0.5) / 255.5 * c, g) + b) + 0.5; - if (inf < 0) - inf = 0; - else if (inf > 255) - inf = 255; - gammatable[i] = inf; - } + t = (i + 0.5) / 255.5; //scale the lighting + t = cboost * t/((cboost-1)*t + 1); + inf = 255 * (pow (t, gamma)*cscale + brightness) + 0.5; + gammatable[i] = bound(0, inf, 255); + } } /* @@ -396,7 +397,7 @@ V_CheckGamma */ static void QDECL V_Gamma_Callback(struct cvar_s *var, char *oldvalue) { - BuildGammaTable (v_gamma.value, v_contrast.value, v_brightness.value); + BuildGammaTable (v_gammainverted.ival?v_gamma.value:(1/v_gamma.value), v_contrast.value, v_contrastboost.value, v_brightness.value); V_UpdatePalette (true); } @@ -2582,9 +2583,10 @@ void V_Init (void) Cvar_Register (&ffov, VIEWVARS); Cvar_Register (&r_projection, VIEWVARS); - BuildGammaTable (1.0, 1.0, 0.0); // no gamma yet + BuildGammaTable (1.0, 1.0, 1.0, 0.0); // no gamma yet Cvar_Register (&v_gamma, VIEWVARS); Cvar_Register (&v_contrast, VIEWVARS); + Cvar_Register (&v_contrastboost, VIEWVARS); Cvar_Register (&v_brightness, VIEWVARS); Cvar_Register (&chase_active, VIEWVARS); diff --git a/engine/client/view.h b/engine/client/view.h index 9b71221d2..cbb7c6752 100644 --- a/engine/client/view.h +++ b/engine/client/view.h @@ -20,7 +20,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // view.h extern cvar_t v_gamma; +extern cvar_t v_gammainverted; extern cvar_t v_contrast; +extern cvar_t v_contrastboost; extern cvar_t v_brightness; extern float sw_blend[4]; extern float hw_blend[4]; diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index 1c9b4693c..875504c41 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -142,6 +142,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #endif #endif #endif +#ifndef NOLEGACY +#define HAVE_LEGACY +#endif #ifndef HAVE_SERVER #undef MVD_RECORDING @@ -542,7 +545,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #undef Q3CLIENT //reconsider this (later) #undef Q3SERVER //reconsider this (later) #endif -#ifdef DEBUG +#if defined(DEBUG) || defined(_DEBUG) #undef NOQCDESCRIPTIONS //don't disable writing fteextensions.qc in debug builds, otherwise how would you ever build one? :o #endif @@ -691,6 +694,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define NORETURN __attribute__((noreturn)) #endif +//unreachable marks the path leading to it as unreachable too. +#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) + #define FTE_UNREACHABLE __builtin_unreachable() +#endif + //I'm making my own restrict, because msvc's headers can't cope if I #define restrict to __restrict, and quite possibly other platforms too #if __STDC_VERSION__ >= 199901L #define fte_restrict restrict @@ -739,6 +747,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifndef FTE_DEPRECATED #define FTE_DEPRECATED #endif +#ifndef FTE_UNREACHABLE +#define FTE_UNREACHABLE +#endif #ifndef LIKEPRINTF #define LIKEPRINTF(x) #endif @@ -754,6 +765,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define ZEXPORTVA VARGS #endif +#ifdef _DEBUG + #undef FTE_UNREACHABLE + #define FTE_UNREACHABLE Sys_Error("Unreachable reached: %s %i\n", __FILE__, __LINE__) +#endif + // !!! if this is changed, it must be changed in d_ifacea.h too !!! #define CACHE_SIZE 32 // used to align key data structures diff --git a/engine/common/common.c b/engine/common/common.c index 94ebb4709..91dd04e24 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -4970,70 +4970,97 @@ static void COM_Version_f (void) Con_Printf("zlib: %s\n", ZLIB_VERSION); #endif - -#ifndef SERVERONLY - //but print client ones only if we're not dedicated -#ifndef AVAIL_PNGLIB - Con_Printf("libpng disabled\n"); -#else - #ifdef DYNAMIC_LIBPNG - Con_Printf("libPNG(dynamic) %s -%s", PNG_LIBPNG_VER_STRING, PNG_HEADER_VERSION_STRING); - #else - Con_Printf("libPNG %s -%s", PNG_LIBPNG_VER_STRING, PNG_HEADER_VERSION_STRING); +#ifdef HAVE_CLIENT + Con_Printf("image formats:"); + #ifdef IMAGEFMT_DDS + Con_Printf(" dds"); #endif -#endif -#ifndef AVAIL_JPEGLIB - Con_Printf("libjpeg disabled\n"); -#else - #ifdef DYNAMIC_LIBJPEG - Con_Printf("libjpeg(dynamic): %i (%d series)\n", JPEG_LIB_VERSION, ( JPEG_LIB_VERSION / 10 ) ); - #else - Con_Printf("libjpeg: %i (%d series)\n", JPEG_LIB_VERSION, ( JPEG_LIB_VERSION / 10 ) ); + #ifdef IMAGEFMT_KTX + Con_Printf(" ktx"); #endif -#endif + Con_Printf(" tga"); + #if defined(AVAIL_PNGLIB) + Con_Printf(" png"); + #ifdef DYNAMIC_LIBPNG + Con_Printf("^h(dynamic, %s)", PNG_LIBPNG_VER_STRING); + #else + Con_Printf("^h(%s)", PNG_LIBPNG_VER_STRING); + #endif + #else + Con_DPrintf(" ^h(disabled: png)"); + #endif + #ifdef IMAGEFMT_BMP + Con_Printf(" bmp+ico"); + #endif + #if defined(AVAIL_JPEGLIB) + Con_Printf(" jpeg"); + #ifdef DYNAMIC_LIBJPEG + Con_Printf("^h(dynamic, %i, %d series)", JPEG_LIB_VERSION, ( JPEG_LIB_VERSION / 10 ) ); + #else + Con_Printf("^h(%i, %d series)", JPEG_LIB_VERSION, ( JPEG_LIB_VERSION / 10 ) ); + #endif + #else + Con_DPrintf(" ^h(disabled: jpeg)"); + #endif + #ifdef IMAGEFMT_PBM + Con_Printf(" pfm+pbm+pgm+ppm"/*"+pam"*/); + #endif + #ifdef IMAGEFMT_PSD + Con_Printf(" psd"); + #endif + #ifdef IMAGEFMT_HDR + Con_Printf(" hdr"); + #endif + #ifdef IMAGEFMT_PKM + Con_Printf(" pkm"); + #endif + #ifdef IMAGEFMT_PCX + Con_Printf(" pcx"); + #endif + Con_Printf("\n"); Con_Printf("VoiceChat:"); -#if !defined(VOICECHAT) - Con_Printf(" disabled"); -#else - #ifdef SPEEX_STATIC - Con_Printf(" speex"); - Con_DPrintf("(static)"); + #if !defined(VOICECHAT) + Con_Printf(" disabled"); #else - Con_Printf(" speex(dynamic)"); + #ifdef SPEEX_STATIC + Con_Printf(" speex"); + Con_DPrintf("^h(static)"); + #else + Con_Printf(" speex^h(dynamic)"); + #endif + #ifdef OPUS_STATIC + Con_Printf(" opus"); + Con_DPrintf("^h(static)"); + #else + Con_Printf(" opus^h(dynamic)"); + #endif #endif - #ifdef OPUS_STATIC - Con_Printf(" opus"); - Con_DPrintf("(static)"); - #else - Con_Printf(" opus(dynamic)"); - #endif -#endif Con_Printf("\n"); Con_Printf("Audio Decoders:"); -#ifndef AVAIL_OGGVORBIS - Con_DPrintf(" ^h(disabled: Ogg Vorbis)^7"); -#elif defined(LIBVORBISFILE_STATIC) - Con_Printf(" Ogg Vorbis"); -#else - Con_Printf(" Ogg Vorbis(dynamic)"); -#endif -#if defined(AVAIL_MP3_ACM) - Con_Printf(" mp3(system)"); -#endif + #ifndef AVAIL_OGGVORBIS + Con_DPrintf(" ^h(disabled: Ogg Vorbis)^7"); + #elif defined(LIBVORBISFILE_STATIC) + Con_Printf(" Ogg Vorbis"); + #else + Con_Printf(" Ogg Vorbis^h(dynamic)"); + #endif + #if defined(AVAIL_MP3_ACM) + Con_Printf(" mp3(system)"); + #endif Con_Printf("\n"); #endif #ifdef SQL Con_Printf("Databases:"); #ifdef USE_MYSQL - Con_Printf(" mySQL(dynamic)"); + Con_Printf(" mySQL^h(dynamic)"); #else Con_DPrintf(" ^h(disabled: mySQL)^7"); #endif #ifdef USE_SQLITE - Con_Printf(" sqlite(dynamic)"); + Con_Printf(" sqlite^h(dynamic)"); #else Con_DPrintf(" ^h(disabled: sqlite)^7"); #endif @@ -5046,19 +5073,19 @@ static void COM_Version_f (void) #else Con_DPrintf(" ^h(disabled: mapcluster)^7"); #endif -#ifndef SERVERONLY +#ifdef HAVE_SERVER #ifdef AVAIL_FREETYPE #ifdef FREETYPE_STATIC Con_Printf(" freetype2"); - Con_DPrintf("(static)"); + Con_DPrintf("^h(static)"); #else - Con_Printf(" freetype2(dynamic)"); + Con_Printf(" freetype2^h(dynamic)"); #endif #else Con_DPrintf(" ^h(disabled: freetype2)^7"); #endif #ifdef AVAIL_OPENAL - Con_Printf(" openal(dynamic)"); + Con_Printf(" openal^h(dynamic)"); #else Con_DPrintf(" ^h(disabled: openal)^7"); #endif @@ -5125,7 +5152,7 @@ static void COM_Version_f (void) Con_Printf(" ssq1qvm"); #endif #if defined(VM_LUA) - Con_Printf(" ssq1lua(dynamic)"); + Con_Printf(" ssq1lua^h(dynamic)"); #endif #if defined(MENU_DAT) Con_Printf(" menuqc"); @@ -5136,7 +5163,7 @@ static void COM_Version_f (void) #if defined(CSQC_DAT) Con_Printf(" csqc"); #endif -#ifndef CLIENTONLY +#ifdef HAVE_SERVER Con_Printf(" ssqc"); #endif Con_Printf("\n"); diff --git a/engine/common/fs.c b/engine/common/fs.c index 06adf33d4..69910ed72 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -3077,10 +3077,11 @@ void COM_Gamedir (const char *dir, const struct gamepacks *packagespaths) #define ZFIXHACK "set r_polygonoffset_submodel_offset 25\nset r_polygonoffset_submodel_factor 0.05\n" #endif -/*quake requires a few settings for compatibility*/ +/*ezquake cheats and compat*/ #define EZQUAKECOMPETITIVE "set ruleset_allow_fbmodels 1\nset sv_demoExtensions \"\"\n" +/*quake requires a few settings for compatibility*/ #define QRPCOMPAT "set cl_cursor_scale 0.2\nset cl_cursor_bias_x 7.5\nset cl_cursor_bias_y 0.8" -#define QCFG "set con_stayhidden 0\nset com_parseutf8 0\nset allow_download_refpackages 0\nset sv_bigcoords \"\"\nmap_autoopenportals 1\n" "sv_port "STRINGIFY(PORT_QWSERVER)" "STRINGIFY(PORT_NQSERVER)"\n" ZFIXHACK EZQUAKECOMPETITIVE QRPCOMPAT +#define QCFG "set v_gammainverted 1\nset con_stayhidden 0\nset com_parseutf8 0\nset allow_download_refpackages 0\nset sv_bigcoords \"\"\nmap_autoopenportals 1\n" "sv_port "STRINGIFY(PORT_QWSERVER)" "STRINGIFY(PORT_NQSERVER)"\n" ZFIXHACK EZQUAKECOMPETITIVE QRPCOMPAT /*NetQuake reconfiguration, to make certain people feel more at home...*/ #define NQCFG "//-nohome\ncfg_save_auto 1\n" QCFG "sv_nqplayerphysics 1\ncl_loopbackprotocol auto\ncl_sbar 1\nplug_sbar 0\nsv_port "STRINGIFY(PORT_NQSERVER)"\ncl_defaultport "STRINGIFY(PORT_NQSERVER)"\n" //nehahra has to be weird with its extra cvars, and buggy fullbrights. @@ -3095,9 +3096,9 @@ void COM_Gamedir (const char *dir, const struct gamepacks *packagespaths) /*set some stuff so our regular qw client appears more like hexen2. sv_mintic is required to 'fix' the ravenstaff so that its projectiles don't impact upon each other*/ #define HEX2CFG "set com_parseutf8 -1\nset gl_font gfx/hexen2\nset in_builtinkeymap 0\nset_calc cl_playerclass int (random * 5) + 1\nset cl_forwardspeed 200\nset cl_backspeed 200\ncl_sidespeed 225\nset sv_maxspeed 640\ncl_run 0\nset watervis 1\nset r_lavaalpha 1\nset r_lavastyle -2\nset r_wateralpha 0.5\nset sv_pupglow 1\ngl_shaftlight 0.5\nsv_mintic 0.015\nset mod_warnmodels 0\nset cl_model_bobbing 1\nsv_sound_watersplash \"misc/hith2o.wav\"\nsv_sound_land \"fx/thngland.wav\"\nset sv_walkpitch 0\n" /*yay q2!*/ -#define Q2CFG "set com_parseutf8 0\ncom_nogamedirnativecode 0\nset sv_bigcoords 0\n" +#define Q2CFG "set v_gammainverted 1\nset com_parseutf8 0\ncom_nogamedirnativecode 0\nset sv_bigcoords 0\n" /*Q3's ui doesn't like empty model/headmodel/handicap cvars, even if the gamecode copes*/ -#define Q3CFG "set com_parseutf8 0\ngl_overbright 2\nseta model sarge\nseta headmodel sarge\nseta handicap 100\ncom_nogamedirnativecode 0\n" +#define Q3CFG "set v_gammainverted 0\nset com_parseutf8 0\ngl_overbright 2\nseta model sarge\nseta headmodel sarge\nseta handicap 100\ncom_nogamedirnativecode 0\n" //#define RMQCFG "sv_bigcoords 1\n" typedef struct { diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index 425aef100..04886554a 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -6012,21 +6012,29 @@ struct bihnode_s BIH_X, BIH_Y, BIH_Z, + BIH_GROUP, BIH_BRUSH, BIH_PATCHBRUSH, + BIH_TRISOUP, } type; union { struct{ - vec3_t temp_mins; - vec3_t temp_maxs; + int firstchild; + int numchildren; + } group; + struct{ int firstchild; float cmin[2]; float cmax[2]; - }; - union bihdata_s{ - q2cbrush_t *brush; - q2cbrush_t *patchbrush; + } node; + struct bihdata_s{ + unsigned int contents; + union { + q2cbrush_t *brush; + q2cbrush_t *patchbrush; + q3cmesh_t *cmesh; + }; } data; }; }; @@ -6041,177 +6049,213 @@ struct bihtrace_s vec3_t expand; qboolean negativedir[3]; - vec_t *startpos; //bounds.[min|max] + vec3_t startpos; //bounds.[min|max] vec3_t totalmove; - vec_t *endpos; //bounds.[min|max] + vec3_t endpos; //bounds.[min|max] trace_t *trace; }; -static void CM_RecursiveBIHTrace (struct bihtrace_s *fte_restrict tr, const struct bihnode_s *fte_restrict node, struct bihbox_s *fte_restrict movesubbounds, struct bihbox_s *fte_restrict nodebox) +static void CM_RecursiveBIHTrace (struct bihtrace_s *fte_restrict tr, const struct bihnode_s *fte_restrict node, const struct bihbox_s *fte_restrict movesubbounds, const struct bihbox_s *fte_restrict nodebox) { //if the tree were 1d, we wouldn't need to be so careful with the bounds, but if the trace is long then we want to avoid hitting all surfaces within that entire-map-encompassing move aabb - if (node->type > BIH_Z) + switch(node->type) { //leaf - if (node->type == BIH_BRUSH) + case BIH_BRUSH: { q2cbrush_t *b = node->data.brush; - if (b->contents & trace_contents) - if (BoundsIntersect(tr->bounds.min, tr->bounds.max, b->absmins, b->absmaxs)) + if (node->data.contents & trace_contents) + if (BoundsIntersect(b->absmins, b->absmaxs, movesubbounds->min, movesubbounds->max)) CM_ClipBoxToBrush (tr->size.min, tr->size.max, tr->startpos, tr->endpos, tr->trace, b); } - else //if (node->type == BIH_PATCHBRUSH) + return; + case BIH_PATCHBRUSH: { q2cbrush_t *b = node->data.patchbrush; - if (b->contents & trace_contents) - if (BoundsIntersect(tr->bounds.min, tr->bounds.max, b->absmins, b->absmaxs)) + if (node->data.contents & trace_contents) + if (BoundsIntersect(b->absmins, b->absmaxs, movesubbounds->min, movesubbounds->max)) CM_ClipBoxToPatch (tr->size.min, tr->size.max, tr->startpos, tr->endpos, tr->trace, b); } - } - else - { //node (x y or z) - struct bihbox_s bounds; - struct bihbox_s newbounds; - float distnear, distfar, nearfrac, farfrac, min, max; - unsigned int axis = node->type, child; + return; + case BIH_TRISOUP: + { + q3cmesh_t *cmesh = node->data.cmesh; + if (node->data.contents & trace_contents) + if (BoundsIntersect(cmesh->absmins, cmesh->absmaxs, movesubbounds->min, movesubbounds->max)) + Mod_Trace_Trisoup_(cmesh->xyz_array, cmesh->indicies, cmesh->numincidies, trace_start, trace_end, trace_mins, trace_maxs, &trace_trace, &cmesh->surface->c); + } + return; + case BIH_GROUP: + { + int i; + for (i = 0; i < node->group.numchildren; i++) + CM_RecursiveBIHTrace(tr, node+node->group.firstchild+i, movesubbounds, nodebox); + } + return; + case BIH_X: + case BIH_Y: + case BIH_Z: + { + struct bihbox_s bounds; + struct bihbox_s newbounds; + float distnear, distfar, nearfrac, farfrac, min, max; + unsigned int axis = node->type, child; + vec3_t points[2]; - if (!tr->totalmove[axis]) - { //doesn't move with respect to this axis. don't allow infinities. - for (child = 0; child < 2; child++) - { //only recurse if we are actually within the child - min = node->cmin[child] - tr->expand[axis]; - max = node->cmax[child] + tr->expand[axis]; - if (min <= tr->startpos[axis] && tr->startpos[axis] <= max) + if (!tr->totalmove[axis]) + { //doesn't move with respect to this axis. don't allow infinities. + for (child = 0; child < 2; child++) + { //only recurse if we are actually within the child + min = node->node.cmin[child] - tr->expand[axis]; + max = node->node.cmax[child] + tr->expand[axis]; + if (min <= tr->startpos[axis] && tr->startpos[axis] <= max) + { + bounds = *nodebox; + bounds.min[axis] = min; + bounds.max[axis] = max; + CM_RecursiveBIHTrace(tr, node+node->node.firstchild+child, movesubbounds, &bounds); + } + } + } + else if (tr->negativedir[axis]) + { //trace goes from right to left so favour the right. + for (child = 2; child-- > 0;) { bounds = *nodebox; - bounds.min[axis] = min; - bounds.max[axis] = max; - CM_RecursiveBIHTrace(tr, node+node->firstchild+child, movesubbounds, &bounds); - } - } - } - else if (tr->negativedir[axis]) - { //trace goes from right to left so favour the right. - for (child = 2; child-- > 0;) - { - bounds = *nodebox; - bounds.min[axis] = node->cmin[child] - tr->expand[axis]; - bounds.max[axis] = node->cmax[child] + tr->expand[axis]; //expand the bounds according to the player's size + bounds.min[axis] = node->node.cmin[child] - tr->expand[axis]; + bounds.max[axis] = node->node.cmax[child] + tr->expand[axis]; //expand the bounds according to the player's size -// CM_RecursiveBIHTrace(tr, node+node->firstchild+child, nodebox, &bounds); -// continue; + if (!BoundsIntersect(movesubbounds->min, movesubbounds->max, bounds.min, bounds.max)) + continue; +// if (movesubbounds->max[axis] < bounds.min[axis]) +// continue; //(clipped) move bounds is outside this child +// if (bounds.max[axis] < movesubbounds->min[axis]) +// continue; //(clipped) move bounds is outside this child - if (bounds.min[axis] > movesubbounds->max[axis]) - continue; //(clipped) move bounds is outside this child - if (bounds.max[axis] < movesubbounds->min[axis]) - continue; //(clipped) move bounds is outside this child - - distnear = bounds.max[axis] - tr->startpos[axis]; - nearfrac = distnear/tr->totalmove[axis]; -// if (/*nearfrac <= trace_truefraction &&*/ tr->startpos[axis] >= bounds.min[axis] && tr->trace->endpos[axis] <= bounds.max[axis]) - { - //we need to be careful when tracing, so that we can ignore children that do not overlap the trace - if (movesubbounds->min[axis] < bounds.min[axis]) + distnear = bounds.max[axis] - tr->startpos[axis]; + nearfrac = distnear/tr->totalmove[axis]; + if (nearfrac <= trace_truefraction) { + VectorMA(tr->startpos, nearfrac, tr->totalmove, points[0]); //clip the new movebounds (this is more to clip the other axis too) distfar = bounds.min[axis] - tr->startpos[axis]; farfrac = distfar/tr->totalmove[axis]; - VectorMA(tr->startpos, farfrac, tr->totalmove, newbounds.min); //clip the new movebounds (this is more to clip the other axis too) + VectorMA(tr->startpos, farfrac, tr->totalmove, points[1]); //clip the new movebounds (this is more to clip the other axis too) + + newbounds.min[0] = max(points[tr->negativedir[0]][0]-tr->expand[axis], bounds.min[0]); newbounds.max[0] = min(points[!tr->negativedir[0]][0]+tr->expand[axis], bounds.max[0]); + newbounds.min[1] = max(points[tr->negativedir[1]][1]-tr->expand[axis], bounds.min[1]); newbounds.max[1] = min(points[!tr->negativedir[1]][1]+tr->expand[axis], bounds.max[1]); + newbounds.min[2] = max(points[tr->negativedir[2]][2]-tr->expand[axis], bounds.min[2]); newbounds.max[2] = min(points[!tr->negativedir[2]][2]+tr->expand[axis], bounds.max[2]); + CM_RecursiveBIHTrace(tr, node+node->node.firstchild+child, &newbounds, &bounds); } - else - VectorCopy(movesubbounds->min, newbounds.min); - if (bounds.max[axis] < movesubbounds->max[axis]) - VectorMA(tr->startpos, nearfrac, tr->totalmove, newbounds.max); - else - VectorCopy(movesubbounds->max, newbounds.max); - CM_RecursiveBIHTrace(tr, node+node->firstchild+child, &newbounds, &bounds); } } - } - else - { //trace goes from left to right - for (child = 0; child < 2; child++) - { - bounds = *nodebox; - bounds.min[axis] = node->cmin[child] - tr->expand[axis]; - bounds.max[axis] = node->cmax[child] + tr->expand[axis]; //expand the bounds according to the player's size - -// CM_RecursiveBIHTrace(tr, node+node->firstchild+child, nodebox, &bounds); -// continue; - - if (bounds.min[axis] > movesubbounds->max[axis]) - continue; //(clipped) move bounds is outside this child - if (bounds.max[axis] < movesubbounds->min[axis]) - continue; //(clipped) move bounds is outside this child - - distnear = bounds.min[axis] - tr->startpos[axis]; - nearfrac = distnear/tr->totalmove[axis]; -// if (/*nearfrac <= trace_truefraction &&*/ tr->startpos[axis] <= bounds.max[axis] && tr->trace->endpos[axis] >= bounds.min[axis]) + else + { //trace goes from left to right + for (child = 0; child < 2; child++) { - //we need to be careful when tracing, so that we can ignore children that do not overlap the trace - if (movesubbounds->min[axis] < bounds.min[axis]) - VectorMA(tr->startpos, nearfrac, tr->totalmove, newbounds.min); //clip the new movebounds (this is more to clip the other axis too) - else - VectorCopy(movesubbounds->min, newbounds.min); - if (bounds.max[axis] < movesubbounds->max[axis]) + bounds = *nodebox; + bounds.min[axis] = node->node.cmin[child] - tr->expand[axis]; + bounds.max[axis] = node->node.cmax[child] + tr->expand[axis]; //expand the bounds according to the player's size + + if (!BoundsIntersect(movesubbounds->min, movesubbounds->max, bounds.min, bounds.max)) + continue; +// if (movesubbounds->max[axis] < bounds.min[axis]) +// continue; //(clipped) move bounds is outside this child +// if (bounds.max[axis] < movesubbounds->min[axis]) +// continue; //(clipped) move bounds is outside this child + + distnear = bounds.min[axis] - tr->startpos[axis]; + nearfrac = distnear/tr->totalmove[axis]; + if (nearfrac <= trace_truefraction) { + VectorMA(tr->startpos, nearfrac, tr->totalmove, points[0]); //clip the new movebounds (this is more to clip the other axis too) distfar = bounds.max[axis] - tr->startpos[axis]; farfrac = distfar/tr->totalmove[axis]; - VectorMA(tr->startpos, farfrac, tr->totalmove, newbounds.max); + VectorMA(tr->startpos, farfrac, tr->totalmove, points[1]); //clip the new movebounds (this is more to clip the other axis too) + + newbounds.min[0] = max(points[tr->negativedir[0]][0]-tr->expand[axis], bounds.min[0]); newbounds.max[0] = min(points[!tr->negativedir[0]][0]+tr->expand[axis], bounds.max[0]); + newbounds.min[1] = max(points[tr->negativedir[1]][1]-tr->expand[axis], bounds.min[1]); newbounds.max[1] = min(points[!tr->negativedir[1]][1]+tr->expand[axis], bounds.max[1]); + newbounds.min[2] = max(points[tr->negativedir[2]][2]-tr->expand[axis], bounds.min[2]); newbounds.max[2] = min(points[!tr->negativedir[2]][2]+tr->expand[axis], bounds.max[2]); + CM_RecursiveBIHTrace(tr, node+node->node.firstchild+child, &newbounds, &bounds); } - else - VectorCopy(movesubbounds->max, newbounds.max); - CM_RecursiveBIHTrace(tr, node+node->firstchild+child, &newbounds, &bounds); } } } + return; } + FTE_UNREACHABLE; } static void CM_RecursiveBIHTest (struct bihtrace_s *fte_restrict tr, const struct bihnode_s *fte_restrict node) { //with BIH, its possible for a large child node to have a box larger than its sibling. - if (node->type > BIH_Z) - { //leaf - if (node->type == BIH_BRUSH) + switch(node->type) + { + case BIH_BRUSH: { q2cbrush_t *b = node->data.brush; - if (b->contents & trace_contents) + if (node->data.contents & trace_contents) // if (BoundsIntersect(tr->bounds.min, tr->bounds.max, b->absmins, b->absmaxs)) CM_TestBoxInBrush (tr->size.min, tr->size.max, tr->startpos, tr->trace, b); } - else //if (node->type == BIH_PATCHBRUSH) + return; + case BIH_PATCHBRUSH: { q2cbrush_t *b = node->data.patchbrush; - if (b->contents & trace_contents) + if (node->data.contents & trace_contents) // if (BoundsIntersect(tr->bounds.min, tr->bounds.max, b->absmins, b->absmaxs)) CM_TestBoxInPatch (tr->size.min, tr->size.max, tr->startpos, tr->trace, b); } - } - else - { //node (x y or z) - float min; float max; - int axis = node->type; - min = node->cmin[0] - tr->expand[axis]; - max = node->cmax[0] + tr->expand[axis]; //expand the bounds according to the player's size - - //the point can potentially be within both children, or neither. - //it doesn't really matter which order we walk the tree, just be sure to do it efficiently. - if (min <= tr->startpos[axis] && tr->startpos[axis] <= max) + return; + case BIH_TRISOUP: { - CM_RecursiveBIHTest(tr, node+node->firstchild+0); - if (trace_trace.allsolid) - return; + q3cmesh_t *cmesh = node->data.cmesh; + if (node->data.contents & trace_contents) +// if (BoundsIntersect(cmesh->absmins, cmesh->absmaxs, tr->bounds.min, tr->bounds.max)) + Mod_Trace_Trisoup_(cmesh->xyz_array, cmesh->indicies, cmesh->numincidies, trace_start, trace_end, trace_mins, trace_maxs, &trace_trace, &cmesh->surface->c); } + return; + case BIH_GROUP: + { + int i; + for (i = 0; i < node->group.numchildren; i++) + { + CM_RecursiveBIHTest(tr, node+node->group.firstchild+i); + if (trace_trace.allsolid) + break; + } + } + return; + case BIH_X: + case BIH_Y: + case BIH_Z: + { //node (x y or z) + float min; float max; + int axis = node->type; + min = node->node.cmin[0] - tr->expand[axis]; + max = node->node.cmax[0] + tr->expand[axis]; //expand the bounds according to the player's size - min = node->cmin[1] - tr->expand[axis]; - max = node->cmax[1] + tr->expand[axis]; - if (min <= tr->startpos[axis] && tr->startpos[axis] <= max) - return CM_RecursiveBIHTest(tr, node+node->firstchild+1); + //the point can potentially be within both children, or neither. + //it doesn't really matter which order we walk the tree, just be sure to do it efficiently. + if (min <= tr->startpos[axis] && tr->startpos[axis] <= max) + { + CM_RecursiveBIHTest(tr, node+node->node.firstchild+0); + if (trace_trace.allsolid) + return; + } + + min = node->node.cmin[1] - tr->expand[axis]; + max = node->node.cmax[1] + tr->expand[axis]; + if (min <= tr->startpos[axis] && tr->startpos[axis] <= max) + return CM_RecursiveBIHTest(tr, node+node->node.firstchild+1); + } + return; } + FTE_UNREACHABLE; } + static unsigned int CM_PointContentsBIH (const struct bihnode_s *fte_restrict node, const vec3_t p) { - if (node->type > BIH_Z) + switch(node->type) { //leaf - if (node->type == BIH_BRUSH) + case BIH_BRUSH: { q2cbrush_t *b = node->data.brush; q2cbrushside_t *brushside = b->brushside; @@ -6226,26 +6270,42 @@ static unsigned int CM_PointContentsBIH (const struct bihnode_s *fte_restrict no } return b->contents; //inside all planes } - else //if (node->type == BIH_PATCHBRUSH) + case BIH_PATCHBRUSH: { //patches have no contents... return 0; } - } - else - { //node (x y or z) - unsigned int contents; + case BIH_TRISOUP: + { + //trisoup has no contents... + return 0; + } + case BIH_GROUP: + { + int i; + unsigned int contents = 0; + for (i = 0; i < node->group.numchildren; i++) + contents |= CM_PointContentsBIH(node+node->group.firstchild+i, p); + return contents; + } + case BIH_X: + case BIH_Y: + case BIH_Z: + { //node (x y or z) + unsigned int contents; - //the point can potentially be within both children, or neither. - //it doesn't really matter which order we walk the tree, just be sure to do it efficiently. - if (node->cmin[0] <= p[node->type] && p[node->type] <= node->cmax[0]) - contents = CM_PointContentsBIH(node+node->firstchild+0, p); - else - contents = 0; + //the point can potentially be within both children, or neither. + //it doesn't really matter which order we walk the tree, just be sure to do it efficiently. + if (node->node.cmin[0] <= p[node->type] && p[node->type] <= node->node.cmax[0]) + contents = CM_PointContentsBIH(node+node->node.firstchild+0, p); + else + contents = 0; - if (node->cmin[1] <= p[node->type] && p[node->type] <= node->cmax[1]) - contents |= CM_PointContentsBIH(node+node->firstchild+1, p); - return contents; + if (node->node.cmin[1] <= p[node->type] && p[node->type] <= node->node.cmax[1]) + contents |= CM_PointContentsBIH(node+node->node.firstchild+1, p); + return contents; + } } + FTE_UNREACHABLE; } struct bihleaf_s @@ -6253,7 +6313,7 @@ struct bihleaf_s int type; vec3_t mins; vec3_t maxs; - union bihdata_s data; + struct bihdata_s data; }; static int QDECL CM_SortBIH_X (const void *va, const void *vb) @@ -6288,10 +6348,38 @@ static struct bihbox_s CM_BuildBIHNode (struct bihnode_s *node, struct bihnode_s struct bihbox_s bounds; if (numleafs == 1) //the leaf just gives the brush pointer. { + size_t i; VectorCopy(leafs[0].mins, bounds.min); VectorCopy(leafs[0].maxs, bounds.max); node->type = leafs[0].type; node->data = leafs[0].data; + + //expand by 1qu, to avoid precision issues. + for (i = 0; i < 3; i++) + { + bounds.min[i] -= 1; + bounds.max[i] += 1; + } + } + else if (numleafs < 8) //the leaf just gives the brush pointer. + { + struct bihnode_s *cnodes; + struct bihbox_s cb; + size_t i; + node->type = BIH_GROUP; + + cnodes = *freenodes; + *freenodes += numleafs; + node->group.firstchild = cnodes - node; + node->group.numchildren = numleafs; + + bounds = CM_BuildBIHNode(cnodes+0, freenodes, leafs+0, 1); + for (i = 1; i < numleafs; i++) + { + cb = CM_BuildBIHNode(cnodes+i, freenodes, leafs+i, 1); + AddPointToBounds(cb.min, bounds.min, bounds.max); + AddPointToBounds(cb.max, bounds.min, bounds.max); + } } else { @@ -6299,8 +6387,8 @@ static struct bihbox_s CM_BuildBIHNode (struct bihnode_s *node, struct bihnode_s size_t numleft = numleafs / 2; //this ends up splitting at the median point. size_t numright = numleafs - numleft; struct bihbox_s left, right; - vec3_t size; struct bihnode_s *cnodes; + static int (QDECL *sorts[3]) (const void *va, const void *vb) = {CM_SortBIH_X, CM_SortBIH_Y, CM_SortBIH_Z}; VectorCopy(leafs[0].mins, bounds.min); VectorCopy(leafs[0].maxs, bounds.max); for (i = 1; i < numleafs; i++) @@ -6313,36 +6401,61 @@ static struct bihbox_s CM_BuildBIHNode (struct bihnode_s *node, struct bihnode_s bounds.max[j] = leafs[i].maxs[j]; } } - VectorSubtract(bounds.max, bounds.min, size); - if (size[0] > size[1] && size[0] > size[2]) - { - qsort(leafs, numleafs, sizeof(*leafs), CM_SortBIH_X); - node->type = BIH_X; +#if 1 + { //balanced by counts + vec3_t mid; + int onleft[3], onright[3], weight[3]; + VectorAvg(bounds.max, bounds.min, mid); + VectorClear(onleft); + VectorClear(onright); + for (i = 0; i < numleafs; i++) + { + for (j = 0; j < 3; j++) + { //ignore leafs that split the node. + if (leafs[i].maxs[j] < mid[j]) + onleft[j]++; + if (mid[j] > leafs[i].mins[j]) + onright[j]++; + } + } + for (j = 0; j < 3; j++) + weight[j] = onleft[j]+onright[j] - abs(onleft[j]-onright[j]); + //pick the most balanced. + if (weight[0] > weight[1] && weight[0] > weight[2]) + node->type = BIH_X; + else if (weight[1] > weight[2]) + node->type = BIH_Y; + else + node->type = BIH_Z; } - else if (size[1] > size[2]) - { - qsort(leafs, numleafs, sizeof(*leafs), CM_SortBIH_Y); - node->type = BIH_Y; +#else + { //balanced by volume + vec3_t size; + VectorSubtract(bounds.max, bounds.min, size); + if (size[0] > size[1] && size[0] > size[2]) + node->type = BIH_X; + else if (size[1] > size[2]) + node->type = BIH_Y; + else + node->type = BIH_Z;*/ } - else - { - qsort(leafs, numleafs, sizeof(*leafs), CM_SortBIH_Z); - node->type = BIH_Z; - } - - VectorCopy(bounds.min, node->temp_mins); - VectorCopy(bounds.max, node->temp_maxs); +#endif + qsort(leafs, numleafs, sizeof(*leafs), sorts[node->type]); cnodes = *freenodes; *freenodes += 2; - node->firstchild = cnodes - node; + node->node.firstchild = cnodes - node; left = CM_BuildBIHNode (cnodes+0, freenodes, leafs, numleft); right = CM_BuildBIHNode (cnodes+1, freenodes, &leafs[numleft], numright); - node->cmin[0] = left.min[node->type]; - node->cmax[0] = left.max[node->type]; - node->cmin[1] = right.min[node->type]; - node->cmax[1] = right.max[node->type]; + node->node.cmin[0] = left.min[node->type]; + node->node.cmax[0] = left.max[node->type]; + node->node.cmin[1] = right.min[node->type]; + node->node.cmax[1] = right.max[node->type]; + + bounds = left; + AddPointToBounds(right.min, bounds.min, bounds.max); + AddPointToBounds(right.max, bounds.min, bounds.max); } return bounds; } @@ -6361,6 +6474,7 @@ static struct bihnode_s *CM_BuildBIH (model_t *mod, cminfo_t *prv) { q2cbrush_t *b = &prv->brushes[i]; leaf->type = BIH_BRUSH; + leaf->data.contents = b->contents; leaf->data.brush = b; VectorCopy(b->absmins, leaf->mins); VectorCopy(b->absmaxs, leaf->maxs); @@ -6371,6 +6485,7 @@ static struct bihnode_s *CM_BuildBIH (model_t *mod, cminfo_t *prv) for (j = 0; j < p->numfacets; j++, leaf++) { leaf->type = BIH_PATCHBRUSH; + leaf->data.contents = p->facets[j].contents; leaf->data.patchbrush = &p->facets[j]; VectorCopy(p->facets[j].absmins, leaf->mins); VectorCopy(p->facets[j].absmaxs, leaf->maxs); @@ -6378,7 +6493,7 @@ static struct bihnode_s *CM_BuildBIH (model_t *mod, cminfo_t *prv) } tmpnodes = nodes+1; CM_BuildBIHNode(nodes, &tmpnodes, leafs, numleafs); - if (tmpnodes != nodes+numnodes) + if (tmpnodes > nodes+numnodes) Sys_Error("CM_BuildBIH: generated wrong number of nodes"); BZ_Free(leafs); //just for temporary storage so that CM_BuildBIHNode doesn't need to care return nodes; @@ -6532,9 +6647,8 @@ static trace_t CM_BoxTrace (model_t *mod, vec3_t start, vec3_t end, tr.negativedir[j] = (end[j] - start[j]) < 0; VectorSubtract(end, start, tr.totalmove); VectorCopy(trace_extents, tr.expand); - - tr.startpos = trace_start; - tr.endpos = trace_end; + VectorCopy(trace_start, tr.startpos); + VectorCopy(trace_end, tr.endpos); tr.trace = &trace_trace; if (start[0] == end[0] && start[1] == end[1] && start[2] == end[2]) CM_RecursiveBIHTest(&tr, prv->bihnodes); diff --git a/engine/common/q1bsp.c b/engine/common/q1bsp.c index 512f27a03..8ccea7303 100644 --- a/engine/common/q1bsp.c +++ b/engine/common/q1bsp.c @@ -1833,7 +1833,7 @@ static qboolean Q1BSP_EdictInFatPVS(model_t *mod, struct pvscache_s *ent, qbyte { int i; - if (ent->num_leafs == MAX_ENT_LEAFS+1) + if (ent->num_leafs < 0) return true; //it's in too many leafs for us to cope with. Just trivially accept it. for (i=0 ; i < ent->num_leafs ; i++) @@ -1865,9 +1865,9 @@ static void Q1BSP_RFindTouchedLeafs (model_t *wm, struct pvscache_s *ent, mnode_ if (node->contents == Q1CONTENTS_SOLID) return; - if (ent->num_leafs >= MAX_ENT_LEAFS) + if ((unsigned)ent->num_leafs >= MAX_ENT_LEAFS) { - ent->num_leafs = MAX_ENT_LEAFS+1; //too many. mark it as such so we can trivially accept huge mega-big brush models. + ent->num_leafs = -1; //too many. mark it as such so we can trivially accept huge mega-big brush models. return; } @@ -2368,10 +2368,10 @@ void BSPX_RenderEnvmaps(model_t *mod) case TF_BGR24: pxsize = 3; break; - case TF_RGBA16F: + case PTI_RGBA16F: pxsize = 8; break; - case TF_RGBA32F: + case PTI_RGBA32F: pxsize = 16; break; default: //erk! diff --git a/engine/gl/gl_alias.c b/engine/gl/gl_alias.c index 75a36452e..7c64ff7c1 100644 --- a/engine/gl/gl_alias.c +++ b/engine/gl/gl_alias.c @@ -2745,7 +2745,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) +void BE_GenModelBatches(batch_t **batches, const dlight_t *dl, unsigned int bemode, qbyte *worldpvs) { int i; entity_t *ent; @@ -2755,6 +2755,10 @@ void BE_GenModelBatches(batch_t **batches, const dlight_t *dl, unsigned int bemo // unsigned int orig_numstrisidx = cl_numstrisidx; // unsigned int orig_numstrisvert = cl_numstrisvert; extern cvar_t chase_active; //I fucking hate this cvar. die die die. + extern cvar_t r_ignoreentpvs; //legacy value is 1... + + if (r_ignoreentpvs.ival) + worldpvs = NULL; /*clear the batch list*/ for (i = 0; i < SHADER_SORT_COUNT; i++) @@ -2806,6 +2810,9 @@ void BE_GenModelBatches(batch_t **batches, const dlight_t *dl, unsigned int bemo } #endif + if (worldpvs && !cl.worldmodel->funcs.EdictInFatPVS(cl.worldmodel, &ent->pvscache, worldpvs)) + continue; + switch(ent->rtype) { case RT_MODEL: diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index 0ba59a4f5..27227d9d1 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -5559,12 +5559,12 @@ batch_t *GLBE_GetTempBatch(void) /*called from shadowmapping code*/ #ifdef RTLIGHTS -void GLBE_BaseEntTextures(void) +void GLBE_BaseEntTextures(qbyte *worldpvs) { batch_t *batches[SHADER_SORT_COUNT]; batch_t **ob = shaderstate.mbatches; shaderstate.mbatches = batches; - BE_GenModelBatches(batches, shaderstate.curdlight, shaderstate.mode); + BE_GenModelBatches(batches, shaderstate.curdlight, shaderstate.mode, worldpvs); GLBE_SubmitMeshes(NULL, SHADER_SORT_PORTAL, SHADER_SORT_SEETHROUGH+1); GLBE_SelectEntity(&r_worldentity); shaderstate.mbatches = ob; @@ -6231,7 +6231,7 @@ void GLBE_DrawWorld (batch_t **worldbatches) } //memset(batches, 0, sizeof(batches)); - BE_GenModelBatches(batches, shaderstate.curdlight, BEM_STANDARD); + BE_GenModelBatches(batches, shaderstate.curdlight, BEM_STANDARD, r_refdef.scenevis); R_GenDlightBatches(batches); shaderstate.curentity = &r_worldentity; // if (cl.paused || cls.state < ca_active) diff --git a/engine/gl/gl_heightmap.c b/engine/gl/gl_heightmap.c index 4468f7545..0c7db1e86 100644 --- a/engine/gl/gl_heightmap.c +++ b/engine/gl/gl_heightmap.c @@ -13,6 +13,13 @@ See gl_terrain.h for terminology, networking notes, etc. #include "gl_terrain.h" static terrainfuncs_t terrainfuncs; +struct patchvert_s +{ + vec3_t v; + vec2_t tc; + vec4_t rgba; +}; + cvar_t mod_terrain_networked = CVARD("mod_terrain_networked", "0", "Terrain edits are networked. Clients will download sections on demand, and servers will notify clients of changes."); cvar_t mod_terrain_defaulttexture = CVARD("mod_terrain_defaulttexture", "", "Newly created terrain tiles will use this texture. This should generally be updated by the terrain editor."); @@ -5470,6 +5477,7 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e) vec3_t normal[65536]; vec3_t svector[65536]; vec3_t tvector[65536]; + vec4_t rgba[65536]; index_t index[65535]; } *arrays = NULL; size_t numverts = 0; @@ -5858,6 +5866,7 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e) VectorCopy(br->patch->verts[r2].norm, arrays->normal[r1]); VectorCopy(br->patch->verts[r2].sdir, arrays->svector[r1]); VectorCopy(br->patch->verts[r2].tdir, arrays->tvector[r1]); + Vector4Copy(br->patch->verts[r2].rgba, arrays->rgba[r1]); Vector2Copy(br->patch->verts[r2].tc, arrays->lmcoord[r1]); } @@ -5891,6 +5900,7 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e) VectorCopy(br->planes[j], arrays->normal[o]); VectorCopy(br->faces[j].stdir[0], arrays->svector[o]); VectorCopy(br->faces[j].stdir[1], arrays->tvector[o]); + Vector4Set(arrays->rgba[o], 1.0, 1.0, 1.0, 1.0); //compute the texcoord planes s = (DotProduct(arrays->svector[o], arrays->coord[o]) + br->faces[j].stdir[0][3]); @@ -5915,7 +5925,7 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e) if (numverts || numindicies) { - bb = Z_Malloc(sizeof(*bb) + (sizeof(bb->mesh.xyz_array[0])+sizeof(arrays->texcoord[0])+sizeof(arrays->lmcoord[0])+sizeof(arrays->normal[0])+sizeof(arrays->svector[0])+sizeof(arrays->tvector[0])) * numverts); + bb = Z_Malloc(sizeof(*bb) + (sizeof(bb->mesh.xyz_array[0])+sizeof(arrays->texcoord[0])+sizeof(arrays->lmcoord[0])+sizeof(arrays->normal[0])+sizeof(arrays->svector[0])+sizeof(arrays->tvector[0])+sizeof(arrays->rgba[0])) * numverts); bb->next = bt->batches; bt->batches = bb; bb->lightmap = lmnum; @@ -5926,6 +5936,7 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e) BE_VBO_Data(&ctx, arrays->normal, sizeof(arrays->normal [0])*numverts, &bb->vbo.normals); BE_VBO_Data(&ctx, arrays->svector, sizeof(arrays->svector [0])*numverts, &bb->vbo.svector); BE_VBO_Data(&ctx, arrays->tvector, sizeof(arrays->tvector [0])*numverts, &bb->vbo.tvector); + BE_VBO_Data(&ctx, arrays->rgba, sizeof(arrays->rgba [0])*numverts, &bb->vbo.colours[0]); BE_VBO_Finish(&ctx, arrays->index, sizeof(arrays->index [0])*numindicies, &bb->vbo.indicies, &bb->vbo.vbomem, &bb->vbo.ebomem); bb->mesh.xyz_array = (vecV_t*)(bb+1); @@ -5940,6 +5951,8 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e) memcpy(bb->mesh.snormals_array, arrays->svector, sizeof(*bb->mesh.snormals_array) * numverts); bb->mesh.tnormals_array = (vec3_t*)(bb->mesh.snormals_array+numverts); memcpy(bb->mesh.tnormals_array, arrays->tvector, sizeof(*bb->mesh.tnormals_array) * numverts); + bb->mesh.colors4f_array[0] = (vec4_t*)(bb->mesh.tnormals_array+numverts); + memcpy(bb->mesh.colors4f_array[0], arrays->rgba, sizeof(*bb->mesh.colors4f_array[0]) * numverts); bb->pmesh = &bb->mesh; bb->mesh.numindexes = numindicies; @@ -6212,7 +6225,7 @@ static brushes_t *Terr_Brush_Insert(model_t *model, heightmap_t *hm, brushes_t * } -static brushes_t *Terr_Patch_Insert(model_t *model, heightmap_t *hm, brushtex_t *patch_tex, int patch_w, int patch_h, vec5_t *patch_v, int stride) +static brushes_t *Terr_Patch_Insert(model_t *model, heightmap_t *hm, brushtex_t *patch_tex, int patch_w, int patch_h, struct patchvert_s *patch_v, int stride) { int x, y; brushes_t brush; @@ -6232,11 +6245,9 @@ static brushes_t *Terr_Patch_Insert(model_t *model, heightmap_t *hm, brushtex_t { for (x = 0; x < patch_w; x++) { - brush.patch->verts[x + y*patch_w].v[0] = patch_v[x][0]; - brush.patch->verts[x + y*patch_w].v[1] = patch_v[x][1]; - brush.patch->verts[x + y*patch_w].v[2] = patch_v[x][2]; - brush.patch->verts[x + y*patch_w].tc[0] = patch_v[x][3]; - brush.patch->verts[x + y*patch_w].tc[1] = patch_v[x][4]; + VectorCopy(patch_v[x].v, brush.patch->verts[x + y*patch_w].v); + Vector2Copy(patch_v[x].tc, brush.patch->verts[x + y*patch_w].tc); + Vector4Copy(patch_v[x].rgba, brush.patch->verts[x + y*patch_w].rgba); //brush.patch->verts[x + y*patch_w].norm //brush.patch->verts[x + y*patch_w].sdir //brush.patch->verts[x + y*patch_w].tdir @@ -7083,7 +7094,16 @@ void Terr_WriteBrushInfo(vfsfile_t *file, brushes_t *br) VFS_PRINTF(file, "\n{"); if (br->patch) { - VFS_PRINTF(file, "\n\tpatchDef2\n\t{\n\t\t\"%s\"\n\t\t( %.9g %.9g %.9g %.9g %.9g )\n\t\t(\n", + qboolean hasrgba = false; + for (y = 0; y < br->patch->ypoints*br->patch->xpoints; y++) + { + if (br->patch->verts[y].rgba[0] != 1.0 || br->patch->verts[y].rgba[1] != 1.0 || br->patch->verts[y].rgba[2] != 1.0 || br->patch->verts[y].rgba[3] != 1.0) + break; + } + hasrgba = (y < br->patch->ypoints*br->patch->xpoints); + + VFS_PRINTF(file, "\n\tpatchDef%s\n\t{\n\t\t\"%s\"\n\t\t( %.9g %.9g %.9g %.9g %.9g )\n\t\t(\n", + hasrgba?"WS":"2", br->patch->tex?br->patch->tex->shadername:"", 0.0/*xoffset*/, 0.0/*yoffset*/, @@ -7095,11 +7115,20 @@ void Terr_WriteBrushInfo(vfsfile_t *file, brushes_t *br) VFS_PRINTF(file, "\t\t\t(\n"); for (x = 0; x < br->patch->xpoints; x++) { - VFS_PRINTF(file, "\t\t\t\t( %.9g %.9g %.9g %.9g %.9g )\n", br->patch->verts[x + y*br->patch->xpoints].v[0], - br->patch->verts[x + y*br->patch->xpoints].v[1], - br->patch->verts[x + y*br->patch->xpoints].v[2], - br->patch->verts[x + y*br->patch->xpoints].tc[0], - br->patch->verts[x + y*br->patch->xpoints].tc[1]); + const char *fmt; + if (hasrgba) + fmt = "\t\t\t\t( %.9g %.9g %.9g %.9g %.9g %.9g %.9g %.9g %.9g )\n"; + else + fmt = "\t\t\t\t( %.9g %.9g %.9g %.9g %.9g )\n"; //q3 compat. + VFS_PRINTF(file, fmt, br->patch->verts[x + y*br->patch->xpoints].v[0], + br->patch->verts[x + y*br->patch->xpoints].v[1], + br->patch->verts[x + y*br->patch->xpoints].v[2], + br->patch->verts[x + y*br->patch->xpoints].tc[0], + br->patch->verts[x + y*br->patch->xpoints].tc[1], + br->patch->verts[x + y*br->patch->xpoints].rgba[0], + br->patch->verts[x + y*br->patch->xpoints].rgba[1], + br->patch->verts[x + y*br->patch->xpoints].rgba[2], + br->patch->verts[x + y*br->patch->xpoints].rgba[3]); } VFS_PRINTF(file, "\t\t\t)\n"); } @@ -7329,7 +7358,7 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities) //patch info brushtex_t *patch_tex=NULL; int patch_w=0, patch_h=0; - vec5_t patch_v[64][64]; + struct patchvert_s patch_v[64][64]; #ifdef RUNTIMELIGHTING hm->entsdirty = true; @@ -7451,9 +7480,10 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities) continue; } } - else if (inbrush && !strcmp(token, "patchDef2")) + else if (inbrush && (!strcmp(token, "patchDef2") || !strcmp(token, "patchDefWS"))) { int x, y; + qboolean parsergba = !strcmp(token, "patchDefWS"); //fancy alternative with rgba colours per control point if (numplanes || patch_tex) { Con_Printf(CON_ERROR "%s: mixed patch+planes\n", mod->name); @@ -7491,15 +7521,34 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities) while (!strcmp(token, "(")) { entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); - patch_v[y][x][0] = atof(token); + patch_v[y][x].v[0] = atof(token); entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); - patch_v[y][x][1] = atof(token); + patch_v[y][x].v[1] = atof(token); entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); - patch_v[y][x][2] = atof(token); + patch_v[y][x].v[2] = atof(token); entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); - patch_v[y][x][3] = atof(token); + patch_v[y][x].tc[0] = atof(token); entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); - patch_v[y][x][4] = atof(token); + patch_v[y][x].tc[1] = atof(token); + + if (parsergba) + { + entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); + patch_v[y][x].rgba[0] = atof(token); + entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); + patch_v[y][x].rgba[1] = atof(token); + entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); + patch_v[y][x].rgba[2] = atof(token); + entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); + patch_v[y][x].rgba[3] = atof(token); + } + else + { //no data provided, use default values. + patch_v[y][x].rgba[0] = + patch_v[y][x].rgba[1] = + patch_v[y][x].rgba[2] = + patch_v[y][x].rgba[3] = 1.0; + } entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); if (strcmp(token, ")")) {Con_Printf(CON_ERROR "%s: invalid patch\n", mod->name);return false;} diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c index 7195d778d..d1a0c5787 100644 --- a/engine/gl/gl_rmain.c +++ b/engine/gl/gl_rmain.c @@ -1938,7 +1938,7 @@ void GLR_RenderView (void) if (r_hdr_framebuffer.ival && !(vid.flags & VID_FP16)) //primary use of this cvar is to fix q3shader overbrights (so bright lightmaps can oversaturate then drop below 1 by modulation with the lightmap forcedfb = true; - if (vid_hardwaregamma.ival == 4 && (v_gamma.value != 1 || v_contrast.value != 1 || v_brightness.value != 0)) + if (vid_hardwaregamma.ival == 4 && (v_gamma.value != 1 || v_contrast.value != 1 || v_contrastboost.value != 1|| v_brightness.value != 0)) r_refdef.flags |= RDF_SCENEGAMMA; } @@ -2158,7 +2158,7 @@ void GLR_RenderView (void) { if (r_refdef.flags & RDF_SCENEGAMMA) { - R2D_ImageColours (v_gamma.value, v_contrast.value, v_brightness.value, 1); + R2D_ImageColours (v_gammainverted.ival?v_gamma.value:(1/v_gamma.value), v_contrast.value, v_brightness.value, v_contrastboost.value); sourcetex = R_RenderPostProcess (sourcetex, RDF_SCENEGAMMA, scenepp_gamma, "rt/$gammaed"); R2D_ImageColours (1, 1, 1, 1); } diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index 0c68ffd2e..51782be79 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -556,6 +556,15 @@ static void Shader_ParseVector(shader_t *shader, char **ptr, vec3_t v) else bracket = false; + if (!strncmp(token, "0x", 2)) + { //0xRRGGBB + unsigned int hex = strtoul(token, NULL, 0); + v[0] = ((hex>>16)&255)/255.; + v[1] = ((hex>> 8)&255)/255.; + v[2] = ((hex>> 0)&255)/255.; + return; + } + v[0] = atof ( token ); token = Shader_ParseString ( ptr ); @@ -1422,7 +1431,7 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip if (type) *type++ = 0; else - type = "sampler2D"; + type = "2D"; if (idx) { *idx++ = 0; @@ -1434,7 +1443,7 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip prog->numsamplers = i+1; //I really want to use layout(binding = %i) here, but its specific to the glsl version (which we don't really know yet) - Q_strlcatfz(prescript, &offset, sizeof(prescript), "#define s_%s s_t%u\nuniform %s s_%s;\n", token, i, type, token); + Q_strlcatfz(prescript, &offset, sizeof(prescript), "#define s_%s s_t%u\nuniform %s%s s_%s;\n", token, i, strncmp(type, "sampler", 7)?"sampler":"", type, token); } else { @@ -6738,10 +6747,11 @@ static qboolean Shader_ReadShaderTerms(parsestate_t *ps, struct scondinfo_s *con { if (!Q_stricmp (token, shadermacros[i].name)) { -#define SHADER_MACRO_ARGS 6 +#define SHADER_MACRO_ARGS 8 int argn = 0; char *oldptr; char arg[SHADER_MACRO_ARGS][256]; + char tmp[4096], *out, *in; //parse args until the end of the line while (ps->ptr) { @@ -6756,8 +6766,38 @@ static qboolean Shader_ReadShaderTerms(parsestate_t *ps, struct scondinfo_s *con argn++; } } + for(out = tmp, in = shadermacros[i].body; *in; ) + { + if (out == tmp+countof(tmp)-1) + break; + if (*in == '%' && in[1] == '%') + in++; //skip doubled up percents + else if (*in == '%') + { //expand an arg + char *e; + int i = strtol(in+1, &e, 0); + if (e != in+1) + { + i--; + if (i >= 0 && i < countof(arg)) + { + for (in = arg[i]; *in; ) + { + if (out == tmp+countof(tmp)-1) + break; + *out++ = *in++; + } + in = e; + continue; + } + } + } + *out++ = *in++; + } + *out = 0; + oldptr = ps->ptr; - ps->ptr = shadermacros[i].body; + ps->ptr = tmp; Shader_ReadShaderTerms(ps, cond); ps->ptr = oldptr; return true; diff --git a/engine/gl/gl_shadow.c b/engine/gl/gl_shadow.c index 57c3626d2..b965dc47d 100644 --- a/engine/gl/gl_shadow.c +++ b/engine/gl/gl_shadow.c @@ -70,7 +70,7 @@ extern cvar_t r_shadow_shadowmapping_bias; cvar_t r_sun_dir = CVARD ("r_sun_dir", "0.2 0.5 0.8", "Specifies the direction that crepusular rays appear along"); cvar_t r_sun_colour = CVARFD ("r_sun_colour", "0 0 0", CVAR_ARCHIVE, "Specifies the colour of sunlight that appears in the form of crepuscular rays."); -static void Sh_DrawEntLighting(dlight_t *light, vec3_t colour); +static void Sh_DrawEntLighting(dlight_t *light, vec3_t colour, qbyte *pvs); static pvsbuffer_t lvisb, lvisb2; @@ -2237,7 +2237,7 @@ static void Sh_LightFrustumPlanes(dlight_t *l, vec3_t axis[3], vec4_t *planes, i //culling for the face happens in the caller. //these faces should thus match Sh_LightFrustumPlanes -static void Sh_GenShadowFace(dlight_t *l, vec3_t axis[3], int lighttype, shadowmesh_t *smesh, int face, int smsize, float proj[16]) +static void Sh_GenShadowFace(dlight_t *l, vec3_t axis[3], int lighttype, shadowmesh_t *smesh, int face, int smsize, float proj[16], qbyte *lightpvs) { vec3_t t1,t2,t3; texture_t *tex; @@ -2379,7 +2379,7 @@ static void Sh_GenShadowFace(dlight_t *l, vec3_t axis[3], int lighttype, shadowm break; #ifdef GLQUAKE case QR_OPENGL: - GLBE_BaseEntTextures(); + GLBE_BaseEntTextures(lightpvs); if (lighttype & LSHADER_ORTHO) qglDisable(GL_DEPTH_CLAMP_ARB); @@ -2387,17 +2387,17 @@ static void Sh_GenShadowFace(dlight_t *l, vec3_t axis[3], int lighttype, shadowm #endif #ifdef D3D9QUAKE case QR_DIRECT3D9: - D3D9BE_BaseEntTextures(); + D3D9BE_BaseEntTextures(lightpvs); break; #endif #ifdef D3D11QUAKE case QR_DIRECT3D11: - D3D11BE_BaseEntTextures(); + D3D11BE_BaseEntTextures(lightpvs); break; #endif #ifdef VKQUAKE case QR_VULKAN: - VKBE_BaseEntTextures(); + VKBE_BaseEntTextures(lightpvs); break; #endif } @@ -2546,7 +2546,7 @@ qboolean Sh_GenShadowMap (dlight_t *l, int lighttype, vec3_t axis[3], qbyte *lvi if (sidevisible & (1u<fov?LSHADER_SPOT:LSHADER_STANDARD); BE_SelectMode(BEM_LIGHT); - Sh_DrawEntLighting(dl, colour); + Sh_DrawEntLighting(dl, colour, vvis); } void Sh_DrawCrepuscularLight(dlight_t *dl, float *colours) diff --git a/engine/gl/gl_terrain.h b/engine/gl/gl_terrain.h index 256120587..251a7a4b1 100644 --- a/engine/gl/gl_terrain.h +++ b/engine/gl/gl_terrain.h @@ -277,6 +277,8 @@ typedef struct { vec3_t v; vec2_t tc; + vec4_t rgba; + vec3_t norm; vec3_t sdir; vec3_t tdir; diff --git a/engine/gl/r_bishaders.h b/engine/gl/r_bishaders.h index 13dd31f2b..073c5b123 100644 --- a/engine/gl/r_bishaders.h +++ b/engine/gl/r_bishaders.h @@ -7489,7 +7489,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND //this shader is applies gamma/contrast/brightness to the source image, and dumps it out. "varying vec2 tc;\n" -"varying vec4 vc;\n" +"varying vec4 vc; //gamma, contrast, brightness, contrastboost\n" "#ifdef VERTEX_SHADER\n" "attribute vec2 v_texcoord;\n" @@ -7504,7 +7504,9 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "#ifdef FRAGMENT_SHADER\n" "void main ()\n" "{\n" -"gl_FragColor = pow(texture2D(s_t0, tc) * vc.g, vec4(vc.r)) + vc.b;\n" +"vec3 t = texture2D(s_t0, tc).rgb;\n" +"t = vc.a * t/((vc.a-1)*t + 1);\n" +"gl_FragColor = vec4(pow(t, vec3(vc.r))*vc.g + vc.b, 1.0);\n" "}\n" "#endif\n" }, diff --git a/engine/gl/shader.h b/engine/gl/shader.h index 279e8af8a..01f9b301a 100644 --- a/engine/gl/shader.h +++ b/engine/gl/shader.h @@ -990,9 +990,9 @@ void GLBE_PolyOffsetStencilShadow(qboolean foobar); void GLBE_PolyOffsetStencilShadow(void); #endif //Called from shadowmapping code into backend -void GLBE_BaseEntTextures(void); -void D3D9BE_BaseEntTextures(void); -void D3D11BE_BaseEntTextures(void); +void GLBE_BaseEntTextures(qbyte *worldpvs); +void D3D9BE_BaseEntTextures(qbyte *worldpvs); +void D3D11BE_BaseEntTextures(qbyte *worldpvs); //prebuilds shadow volumes void Sh_PreGenerateLights(void); //Draws lights, called from the backend diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 85b1a2bfe..20cc918e5 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -12513,21 +12513,35 @@ void PR_DumpPlatform_f(void) {"VF_SCREENPSIZE", "const float", CS|MENU, D("Provides a reliable way to retrieve the current physical screen size (cvars need vid_restart for them to take effect)."), VF_SCREENPSIZE}, {"VF_VIEWENTITY", "const float", CS, D("Changes the RF_EXTERNALMODEL flag on entities to match the new selection, and removes entities flaged with RF_VIEWENTITY. Requires cunning use of .entnum and typically requires calling addentities(MASK_VIEWMODEL) too."), VF_VIEWENTITY}, - {"VF_RT_DESTCOLOUR", "const float", CS|MENU, D("The texture name to write colour info into, this includes both 3d and 2d drawing.\nAdditional arguments are: format (rgba8=1,rgba16f=2,rgba32f=3), sizexy.\nWritten to by both 3d and 2d rendering.\nNote that any rendertarget textures may be destroyed on video mode changes or so. Shaders can name render targets by prefixing texture names with '$rt:', or $sourcecolour."), VF_RT_DESTCOLOUR0}, -// {"VF_RT_DESTCOLOUR1", "const float", CS|MENU, D("Like VF_RT_DESTCOLOUR, for multiple render targets."), VF_RT_DESTCOLOUR1}, -// {"VF_RT_DESTCOLOUR2", "const float", CS|MENU, D("Like VF_RT_DESTCOLOUR, for multiple render targets."), VF_RT_DESTCOLOUR2}, -// {"VF_RT_DESTCOLOUR3", "const float", CS|MENU, D("Like VF_RT_DESTCOLOUR, for multiple render targets."), VF_RT_DESTCOLOUR3}, + {"VF_RT_DESTCOLOUR", "const float", CS|MENU, D("The texture name to write colour info into, this includes both 3d and 2d drawing.\nAdditional arguments are: format (IMGFMT_*), sizexy.\nWritten to by both 3d and 2d rendering.\nNote that any rendertarget textures may be destroyed on video mode changes or so. Shaders can name render targets by prefixing texture names with '$rt:', or $sourcecolour."), VF_RT_DESTCOLOUR0}, + {"VF_RT_DESTCOLOUR1", "const float", CS|MENU, D("Like VF_RT_DESTCOLOUR, for multiple render targets."), VF_RT_DESTCOLOUR1}, + {"VF_RT_DESTCOLOUR2", "const float", CS|MENU, D("Like VF_RT_DESTCOLOUR, for multiple render targets."), VF_RT_DESTCOLOUR2}, + {"VF_RT_DESTCOLOUR3", "const float", CS|MENU, D("Like VF_RT_DESTCOLOUR, for multiple render targets."), VF_RT_DESTCOLOUR3}, // {"VF_RT_DESTCOLOUR4", "const float", CS|MENU, D("Like VF_RT_DESTCOLOUR, for multiple render targets."), VF_RT_DESTCOLOUR4}, // {"VF_RT_DESTCOLOUR5", "const float", CS|MENU, D("Like VF_RT_DESTCOLOUR, for multiple render targets."), VF_RT_DESTCOLOUR5}, // {"VF_RT_DESTCOLOUR6", "const float", CS|MENU, D("Like VF_RT_DESTCOLOUR, for multiple render targets."), VF_RT_DESTCOLOUR6}, // {"VF_RT_DESTCOLOUR7", "const float", CS|MENU, D("Like VF_RT_DESTCOLOUR, for multiple render targets."), VF_RT_DESTCOLOUR7}, {"VF_RT_SOURCECOLOUR", "const float", CS|MENU, D("The texture name to use with shaders that specify a $sourcecolour map."), VF_RT_SOURCECOLOUR}, - {"VF_RT_DEPTH", "const float", CS|MENU, D("The texture name to use as a depth buffer. Also used for shaders that specify $sourcedepth. 1-based. Additional arguments are: format (16bit=4,24bit=5,32bit=6), sizexy."), VF_RT_DEPTH}, + {"VF_RT_DEPTH", "const float", CS|MENU, D("The texture name to use as a depth buffer. Also used for shaders that specify $sourcedepth. 1-based. Additional arguments are: format (IMGFMT_D*), sizexy."), VF_RT_DEPTH}, {"VF_RT_RIPPLE", "const float", CS|MENU, D("The texture name to use as a ripplemap (target for shaders with 'sort ripple'). Also used for shaders that specify $ripplemap. 1-based. Additional arguments are: format, sizexy."), VF_RT_RIPPLE}, {"VF_ENVMAP", "const float", CS|MENU, D("The cubemap name to use as a fallback for $reflectcube, if a shader was unable to load one. Note that this doesn't automatically change shader permutations or anything."), VF_ENVMAP}, {"VF_USERDATA", "const float", CS|MENU, D("Pointer (and byte size) to an array of vec4s. This data is then globally visible to all glsl via the w_user uniform."), VF_USERDATA}, {"VF_SKYROOM_CAMERA", "const float", CS, D("Controls the camera position of the skyroom (which will be drawn underneath transparent sky surfaces). This should move slightly with the real camera, but not so much that the skycamera enters walls. Requires a skyshader with a blend mode on the first pass (or no passes)."), VF_SKYROOM_CAMERA}, + {"IMGFMT_R8G8B8A8", "const float", CS|MENU, D("Typical 32bit rgba pixel format."), 1}, + {"IMGFMT_R16G16B16A16F","const float", CS|MENU, D("Half-Float pixel format. Requires gl3 support."), 2}, + {"IMGFMT_R32G32B32A32F","const float", CS|MENU, D("Regular Float pixel format. Requires gl3 support."), 3}, + {"IMGFMT_D16", "const float", CS|MENU, D("16-bit depth pixel format. Must not be used with VF_RT_DESTCOLOUR*."), 4}, + {"IMGFMT_D24", "const float", CS|MENU, D("24-bit depth pixel format. Must not be used with VF_RT_DESTCOLOUR*."), 5}, + {"IMGFMT_D32", "const float", CS|MENU, D("32-bit depth pixel format. Must not be used with VF_RT_DESTCOLOUR*."), 6}, + {"IMGFMT_R8", "const float", CS|MENU, D("Single channel red-only 8bit pixel format."), 7}, + {"IMGFMT_R16F", "const float", CS|MENU, D("Single channel red-only Half-Float pixel format. Requires gl3 support."), 8}, + {"IMGFMT_R32F", "const float", CS|MENU, D("Single channel red-only Float pixel format. Requires gl3 support."), 9}, + {"IMGFMT_A2B10G10R10", "const float", CS|MENU, D("Packed 32-bit packed 10-bit colour pixel format. Requires gl3 support."), 10}, + {"IMGFMT_R5G6B5", "const float", CS|MENU, D("Packed 16-bit colour pixel format."), 11}, + {"IMGFMT_R4G4B4A4", "const float", CS|MENU, D("Packed 16-bit colour pixel format, with alpha"), 12}, + {"IMGFMT_R8G8", "const float", CS|MENU, D("16-bit two-channel pixel format."), 13}, + {"RF_VIEWMODEL", "const float", CS, D("Specifies that the entity is a view model, and that its origin is relative to the current view position. These entities are also subject to viewweapon bob."), CSQCRF_VIEWMODEL}, {"RF_EXTERNALMODEL", "const float", CS, D("Specifies that this entity should be displayed in mirrors (and may still cast shadows), but will not otherwise be visible."), CSQCRF_EXTERNALMODEL}, {"RF_DEPTHHACK", "const float", CS|MENU, D("Hacks the depth values such that the entity uses depth values as if it were closer to the screen. This is useful when combined with viewmodels to avoid weapons poking in to walls."), CSQCRF_DEPTHHACK}, @@ -12751,6 +12765,7 @@ void PR_DumpPlatform_f(void) VFS_PRINTF(f, "#pragma warning enable F302 /*uninitialised locals. They usually default to 0 in qc (except in recursive functions), but its still probably a bug*/\n"); // VFS_PRINTF(f, "#pragma warning %s F308 /*Optional arguments differ on redeclaration.*/\n", (targ & ID1)?"disable":"enable"); +#ifdef HEXEN2 if ((targ&ALL) == H2) { if (targ&FTE) @@ -12759,6 +12774,7 @@ void PR_DumpPlatform_f(void) VFS_PRINTF(f, "#pragma target H2\n"); } else +#endif { if (targ&FTE) VFS_PRINTF(f, "#pragma target FTE\n"); diff --git a/engine/shaders/glsl/defaultgammacb.glsl b/engine/shaders/glsl/defaultgammacb.glsl index c57ff14f5..f1d44674c 100644 --- a/engine/shaders/glsl/defaultgammacb.glsl +++ b/engine/shaders/glsl/defaultgammacb.glsl @@ -3,7 +3,7 @@ //this shader is applies gamma/contrast/brightness to the source image, and dumps it out. varying vec2 tc; -varying vec4 vc; +varying vec4 vc; //gamma, contrast, brightness, contrastboost #ifdef VERTEX_SHADER attribute vec2 v_texcoord; @@ -18,6 +18,8 @@ void main () #ifdef FRAGMENT_SHADER void main () { - gl_FragColor = pow(texture2D(s_t0, tc) * vc.g, vec4(vc.r)) + vc.b; + vec3 t = texture2D(s_t0, tc).rgb; + t = vc.a * t/((vc.a-1)*t + 1); + gl_FragColor = vec4(pow(t, vec3(vc.r))*vc.g + vc.b, 1.0); } #endif diff --git a/engine/vk/vk_backend.c b/engine/vk/vk_backend.c index b58450e75..fa563a9e4 100644 --- a/engine/vk/vk_backend.c +++ b/engine/vk/vk_backend.c @@ -5785,10 +5785,10 @@ void VKBE_SubmitMeshes (batch_t **worldbatches, batch_t **blist, int first, int #ifdef RTLIGHTS //FIXME: needs context for threading -void VKBE_BaseEntTextures(void) +void VKBE_BaseEntTextures(qbyte *scenepvs) { batch_t *batches[SHADER_SORT_COUNT]; - BE_GenModelBatches(batches, shaderstate.curdlight, shaderstate.mode); + BE_GenModelBatches(batches, shaderstate.curdlight, shaderstate.mode, scenepvs); VKBE_SubmitMeshes(NULL, batches, SHADER_SORT_PORTAL, SHADER_SORT_SEETHROUGH+1); VKBE_SelectEntity(&r_worldentity); } @@ -6240,7 +6240,7 @@ void VKBE_DrawWorld (batch_t **worldbatches) shaderstate.curdlight = NULL; //fixme: figure out some way to safely orphan this data so that we can throw the rest to a worker. - BE_GenModelBatches(batches, shaderstate.curdlight, BEM_STANDARD); + BE_GenModelBatches(batches, shaderstate.curdlight, BEM_STANDARD, r_refdef.scenevis); BE_UploadLightmaps(false); if (r_refdef.scenevis) diff --git a/engine/vk/vkrenderer.h b/engine/vk/vkrenderer.h index f04493401..888b071bf 100644 --- a/engine/vk/vkrenderer.h +++ b/engine/vk/vkrenderer.h @@ -465,7 +465,7 @@ void VKBE_VBO_Data(vbobctx_t *ctx, void *data, size_t size, vboarray_t *varray); void VKBE_VBO_Finish(vbobctx_t *ctx, void *edata, size_t esize, vboarray_t *earray, void **vbomem, void **ebomem); void VKBE_VBO_Destroy(vboarray_t *vearray, void *mem); void VKBE_Scissor(srect_t *rect); -void VKBE_BaseEntTextures(void); +void VKBE_BaseEntTextures(qbyte *scenepvs); struct vk_shadowbuffer; struct vk_shadowbuffer *VKBE_GenerateShadowBuffer(vecV_t *verts, int numverts, index_t *indicies, int numindicies, qboolean istemp);