diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c
index f4df928b6..e41a192e2 100644
--- a/engine/client/cl_parse.c
+++ b/engine/client/cl_parse.c
@@ -1802,7 +1802,6 @@ downloadlist_t *CL_DownloadFailed(const char *name, qdownload_t *qdl)
}
#ifdef PEXT_CHUNKEDDOWNLOADS
-#define DLBLOCKSIZE 1024
int CL_DownloadRate(void)
{
diff --git a/engine/client/image.c b/engine/client/image.c
index 0c1c0c944..7de60b0d2 100644
--- a/engine/client/image.c
+++ b/engine/client/image.c
@@ -3092,7 +3092,12 @@ static qboolean Image_ReadBLPFile(texid_t tex, unsigned int flags, char *fname,
mips->mipcount = miplevel;
}
- COM_AddWork(WG_MAIN, Image_LoadTextureMips, tex, mips, 0, 0);
+ tex->width = w;
+ tex->height = h;
+ if (flags & IF_NOWORKER)
+ Image_LoadTextureMips(tex, mips, 0, 0);
+ else
+ COM_AddWork(WG_MAIN, Image_LoadTextureMips, tex, mips, 0, 0);
return true;
}
diff --git a/engine/client/keys.c b/engine/client/keys.c
index f6ae286ba..13a363103 100644
--- a/engine/client/keys.c
+++ b/engine/client/keys.c
@@ -2623,8 +2623,11 @@ void Key_Event (unsigned int devid, int key, unsigned int unicode, qboolean down
if (Key_Dest_Has(kdm_emenu))
{
- M_Keydown (key, unicode);
- return;
+ if (key < K_F1 || key > K_F15)
+ { //function keys don't get intercepted by the menu...
+ M_Keydown (key, unicode);
+ return;
+ }
}
#ifdef MENU_DAT
if (Key_Dest_Has(kdm_gmenu))
diff --git a/engine/client/m_mp3.c b/engine/client/m_mp3.c
index 8a254402b..af31e2ff1 100644
--- a/engine/client/m_mp3.c
+++ b/engine/client/m_mp3.c
@@ -2585,7 +2585,7 @@ qboolean Media_ShowFilm(void)
ch = 3;
}
- R2D_Letterbox(0, 0, vid.pixelwidth, vid.pixelheight, videoshader, cw, ch);
+ R2D_Letterbox(0, 0, vid.fbvwidth, vid.fbvheight, videoshader, cw, ch);
SCR_SetUpToDrawConsole();
if (scr_con_current)
@@ -3778,9 +3778,8 @@ void Media_InitFakeSoundDevice (int speed, int channels, int samplebits)
S_DefaultSpeakerConfiguration(sc);
}
-
-
-void Media_StopRecordFilm_f (void)
+//stops capturing and destroys everything.
+static void Media_FlushCapture(void)
{
#ifdef GLQUAKE_PBOS
if (offscreen_format && qrenderer == QR_OPENGL)
@@ -3835,6 +3834,20 @@ void Media_StopRecordFilm_f (void)
}
#endif
+#ifdef GLQUAKE
+ if (capturingfbo && qrenderer == QR_OPENGL)
+ {
+ GLBE_FBO_Pop(captureoldfbo);
+ GLBE_FBO_Destroy(&capturefbo);
+ vid.framebuffer = NULL;
+ }
+#endif
+}
+
+void Media_StopRecordFilm_f (void)
+{
+ Media_FlushCapture();
+ capturingfbo = false;
if (capture_fakesounddevice)
S_ShutdownCard(capture_fakesounddevice);
@@ -3850,18 +3863,32 @@ void Media_StopRecordFilm_f (void)
currentcapture_ctx = NULL;
currentcapture_funcs = NULL;
-#ifdef GLQUAKE
- if (capturingfbo && qrenderer == QR_OPENGL)
- {
- GLBE_FBO_Pop(captureoldfbo);
- GLBE_FBO_Destroy(&capturefbo);
- }
-#endif
- vid.framebuffer = NULL;
- capturingfbo = false;
-
Cvar_ForceCallback(&vid_conautoscale);
}
+void Media_VideoRestarting(void)
+{
+ Media_FlushCapture();
+}
+void Media_VideoRestarted(void)
+{
+#ifdef GLQUAKE
+ if (capturingfbo && qrenderer == QR_OPENGL && gl_config.ext_framebuffer_objects)
+ { //restore it how it was, if we can.
+ int w = capturefbo.rb_size[0], h = capturefbo.rb_size[1];
+ capturingfbo = true;
+ capturetexture = R2D_RT_Configure("$democapture", w, h, TF_BGRA32, RT_IMAGEFLAGS);
+ captureoldfbo = GLBE_FBO_Update(&capturefbo, FBO_RB_DEPTH|(Sh_StencilShadowsActive()?FBO_RB_STENCIL:0), &capturetexture, 1, r_nulltex, capturetexture->width, capturetexture->height, 0);
+ vid.fbpwidth = capturetexture->width;
+ vid.fbpheight = capturetexture->height;
+ vid.framebuffer = capturetexture;
+ }
+ else
+#endif
+ capturingfbo = false;
+
+ if (capturingfbo)
+ Cvar_ForceCallback(&vid_conautoscale);
+}
static void Media_RecordFilm (char *recordingname, qboolean demo)
{
int sndkhz, sndchannels, sndbits;
@@ -4067,6 +4094,8 @@ void Media_CaptureDemoEnd(void) {}
qboolean Media_PausedDemo(qboolean fortiming) {return false;}
double Media_TweekCaptureFrameTime(double oldtime, double time) { return oldtime+time ; }
void Media_RecordFrame (void) {}
+void Media_VideoRestarting(void) {}
+void Media_VideoRestarted(void) {}
#endif
diff --git a/engine/client/merged.h b/engine/client/merged.h
index 166cdcb54..574ce04e3 100644
--- a/engine/client/merged.h
+++ b/engine/client/merged.h
@@ -373,6 +373,11 @@ typedef union vboarray_s
unsigned int offs;
} vk;
#endif
+ struct
+ { //matches the biggest version. currently vulkan. this ensures that plugins can allocate model data without caring about renderers.
+ qint64_t buff;
+ unsigned int offs;
+ } pad;
} vboarray_t;
//scissor rects
diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c
index 9c4d2e0e4..f28fddf28 100644
--- a/engine/client/pr_menu.c
+++ b/engine/client/pr_menu.c
@@ -1070,7 +1070,11 @@ void QCBUILTIN PF_SubConPrintf (pubprogfuncs_t *prinst, struct globalvars_s *pr_
const char *fmt = PR_GetStringOfs(prinst, OFS_PARM1);
console_t *con = Con_FindConsole(conname);
if (!con)
- return;
+ {
+ con = Con_Create(conname, 0);
+ if (!con)
+ return;
+ }
PF_sprintf_internal(prinst, pr_globals, fmt, 2, outbuf, sizeof(outbuf));
Con_PrintCon(con, outbuf, con->parseflags);
}
diff --git a/engine/client/r_2d.c b/engine/client/r_2d.c
index 75f3122a2..f9df941f1 100644
--- a/engine/client/r_2d.c
+++ b/engine/client/r_2d.c
@@ -1664,7 +1664,7 @@ texid_t R2D_RT_GetTexture(const char *id, unsigned int *width, unsigned int *hei
if (!strcmp(id, "-"))
{
tid = internalrt;
- internalrt = r_nulltex;
+// internalrt = r_nulltex;
}
else
tid = Image_FindTexture(id, NULL, RT_IMAGEFLAGS);
diff --git a/engine/client/render.h b/engine/client/render.h
index 519212765..c3e2497e1 100644
--- a/engine/client/render.h
+++ b/engine/client/render.h
@@ -542,6 +542,8 @@ qboolean Media_PausedDemo (qboolean fortiming);
int Media_Capturing (void);
double Media_TweekCaptureFrameTime(double oldtime, double time);
void Media_WriteCurrentTrack(sizebuf_t *buf);
+void Media_VideoRestarting(void);
+void Media_VideoRestarted(void);
void MYgluPerspective(double fovx, double fovy, double zNear, double zFar);
diff --git a/engine/client/renderer.c b/engine/client/renderer.c
index fa88b5e39..61c0b1fee 100644
--- a/engine/client/renderer.c
+++ b/engine/client/renderer.c
@@ -455,6 +455,7 @@ cvar_t vk_submissionthread = CVARD ("vk_submissionthread", "", "Execute su
cvar_t vk_debug = CVARD ("vk_debug", "0", "Register a debug handler to display driver/layer messages. 2 enables the standard validation layers.");
cvar_t vk_dualqueue = CVARD ("vk_dualqueue", "", "Attempt to use a separate queue for presentation. Blank for default.");
cvar_t vk_busywait = CVARD ("vk_busywait", "", "Force busy waiting until the GPU finishes doing its thing.");
+cvar_t vk_waitfence = CVARD ("vk_waitfence", "", "Waits on fences, instead of semaphores. This is more likely to result in gpu stalls while the cpu waits.");
cvar_t vk_nv_glsl_shader = CVARD ("vk_loadglsl", "", "Enable direct loading of glsl, where supported by drivers. Do not use in combination with vk_debug 2 (vk_debug should be 1 if you want to see any glsl compile errors). Don't forget to do a vid_restart after.");
cvar_t vk_nv_dedicated_allocation = CVARD ("vk_nv_dedicated_allocation", "", "Flag vulkan memory allocations as dedicated, where applicable.");
//cvar_t vk_khr_dedicated_allocation = CVARD ("vk_khr_dedicated_allocation", "", "Flag vulkan memory allocations as dedicated, where applicable.");
@@ -981,6 +982,7 @@ void Renderer_Init(void)
Cvar_Register (&vk_debug, VKRENDEREROPTIONS);
Cvar_Register (&vk_dualqueue, VKRENDEREROPTIONS);
Cvar_Register (&vk_busywait, VKRENDEREROPTIONS);
+ Cvar_Register (&vk_waitfence, VKRENDEREROPTIONS);
Cvar_Register (&vk_nv_glsl_shader, VKRENDEREROPTIONS);
Cvar_Register (&vk_nv_dedicated_allocation, VKRENDEREROPTIONS);
@@ -1257,6 +1259,8 @@ void R_ShutdownRenderer(qboolean devicetoo)
IN_Shutdown();
+ Media_VideoRestarting();
+
if (R_DeInit)
{
TRACE(("dbg: R_ApplyRenderer: R_DeInit\n"));
@@ -1466,6 +1470,7 @@ TRACE(("dbg: R_ApplyRenderer: screen inited\n"));
Sbar_Flush();
IN_ReInit();
+ Media_VideoRestarted();
Cvar_ForceCallback(&v_gamma);
}
diff --git a/engine/client/snd_dma.c b/engine/client/snd_dma.c
index 40f912414..413818c96 100644
--- a/engine/client/snd_dma.c
+++ b/engine/client/snd_dma.c
@@ -158,7 +158,7 @@ cvar_t snd_voip_showmeter = CVARAFD("cl_voip_showmeter", "1", NULL, CVAR_ARCHIV
cvar_t snd_voip_play = CVARAFCD("cl_voip_play", "1", NULL, CVAR_ARCHIVE, S_Voip_Play_Callback, "Enables voip playback. Value is a volume scaler.");
cvar_t snd_voip_ducking = CVARAFD("cl_voip_ducking", "0.5", NULL, CVAR_ARCHIVE, "Scales game audio by this much when someone is talking to you. Does not affect your speaker volume when you speak (minimum of cl_voip_capturingvol and cl_voip_ducking is used).");
cvar_t snd_voip_micamp = CVARAFD("cl_voip_micamp", "2", NULL, CVAR_ARCHIVE, "Amplifies your microphone when using voip.");
-cvar_t snd_voip_codec = CVARAFD("cl_voip_codec", "", NULL, CVAR_ARCHIVE, "0: speex(@11khz). 1: raw. 2: opus. 3: speex(@8khz). 4: speex(@16). 5:speex(@32).");
+cvar_t snd_voip_codec = CVARAFD("cl_voip_codec", "", NULL, CVAR_ARCHIVE, "0: speex(@11khz). 1: raw. 2: opus. 3: speex(@8khz). 4: speex(@16). 5:speex(@32). 6: pcma. 7: pcmu.");
cvar_t snd_voip_noisefilter = CVARAFD("cl_voip_noisefilter", "1", NULL, CVAR_ARCHIVE, "Enable the use of the noise cancelation filter.");
cvar_t snd_voip_autogain = CVARAFD("cl_voip_autogain", "0", NULL, CVAR_ARCHIVE, "Attempts to normalize your voice levels to a standard level. Useful for lazy people, but interferes with voice activation levels.");
cvar_t snd_voip_opus_bitrate = CVARAFD("cl_voip_opus_bitrate", "3000", NULL, CVAR_ARCHIVE, "For codecs with non-specific bitrates, this specifies the target bitrate to use.");
@@ -1349,6 +1349,7 @@ void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf)
switch(s_voip.enccodec)
{
case VOIP_SPEEX_OLD:
+ //this is from before I understood speex properly.
level += S_Voip_Preprocess(start, s_voip.encframesize, micamp);
qspeex_bits_reset(&s_voip.speex.encbits);
qspeex_encode_int(s_voip.encoder, start, &s_voip.speex.encbits);
@@ -1364,6 +1365,7 @@ void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf)
case VOIP_SPEEX_NARROW:
case VOIP_SPEEX_WIDE:
case VOIP_SPEEX_ULTRAWIDE:
+ //write multiple speex frames into a single merged frame
qspeex_bits_reset(&s_voip.speex.encbits);
for (; encpos+s_voip.encframesize*2 <= s_voip.capturepos; )
{
@@ -1394,6 +1396,7 @@ void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf)
break;
case VOIP_PCMA:
case VOIP_PCMU:
+ //FIXME: what's with this /2? these are just 8-bit mono (logarithmic) pcm...
len = s_voip.capturepos-encpos; //amount of data to be eaten in this frame
len = min(len, sizeof(outbuf)-outpos);
len = min(len, s_voip.encframesize*2);
@@ -1463,6 +1466,8 @@ void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf)
break;
}
+ //opus has no way to detect the end properly.
+ //standard rtp favours many small packets.
if (rtpstream || s_voip.enccodec == VOIP_OPUS)
break;
}
@@ -1503,10 +1508,20 @@ void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf)
{
if (buf->maxsize - buf->cursize >= 5+outpos)
{
+ qbyte cgen = ((s_voip.enccodec&0x7)<<4) | (s_voip.generation & 0x0f);
+ if (s_voip.enccodec >= 8 || 0)
+ cgen |= 0x80;
+
MSG_WriteByte(buf, clc);
- MSG_WriteByte(buf, (s_voip.enccodec<<4) | (s_voip.generation & 0x0f)); /*gonna leave that nibble clear here... in this version, the client will ignore packets with those bits set. can use them for codec or something*/
+ MSG_WriteByte(buf, cgen);
MSG_WriteByte(buf, initseq&0xff);
- MSG_WriteShort(buf, outpos);
+ /*if (cgen & 0x80)
+ {
+ MSG_WriteShort(buf, 1+outpos);
+ MSG_WriteByte(buf, s_voip.enccodec>>3);
+ }
+ else*/
+ MSG_WriteShort(buf, outpos); //even with codecs where the size is easy to determine, this is still useful for servers (which are unaware of the actual codec)
SZ_Write(buf, outbuf, outpos);
}
else
diff --git a/engine/client/wad.c b/engine/client/wad.c
index 12ed0cf18..459bd0ba3 100644
--- a/engine/client/wad.c
+++ b/engine/client/wad.c
@@ -776,7 +776,7 @@ qboolean Wad_NextDownload (void)
{
k = wads[i];
wads[i] = 0;
- strcpy(wadname+9, &wads[j]);
+ Q_strncpyz(wadname+9, &wads[j], sizeof(wadname)-9);
if (wadname[9])
{
if (COM_FCheckExists(wadname+9))
diff --git a/engine/common/bspfile.h b/engine/common/bspfile.h
index baddf7a96..289f9bef6 100644
--- a/engine/common/bspfile.h
+++ b/engine/common/bspfile.h
@@ -488,40 +488,40 @@ typedef struct
// a given brush can contribute multiple content bits
// multiple brushes can be in a single leaf
-#define FTECONTENTS_EMPTY 0x00000000
-#define FTECONTENTS_SOLID 0x00000001
-//q2window 0x00000002
-//q2aux 0x00000004
-#define FTECONTENTS_LAVA 0x00000008
-#define FTECONTENTS_SLIME 0x00000010
-#define FTECONTENTS_WATER 0x00000020
-#define FTECONTENTS_FLUID (FTECONTENTS_WATER|FTECONTENTS_SLIME|FTECONTENTS_LAVA|FTECONTENTS_SKY) //sky is a fluid for q1 code.
-//q2mist 0x00000040
-//q3notteam1 0x00000080
-//q3notteam2 0x00000100
-//q3nobotclip 0x00000200
-// 0x00000400
-// 0x00000800
-// 0x00001000
-// 0x00002000
-#define FTECONTENTS_LADDER 0x00004000
-//q2areaportal,q3areaportal 0x00008000
-#define FTECONTENTS_PLAYERCLIP 0x00010000
-#define FTECONTENTS_MONSTERCLIP 0x00020000
-//q2current0,q3teleporter 0x00040000
-//q2current90,q3jumppad 0x00080000
-//q2current180,q3clusterportal 0x00100000
-//q2current270,q3donotenter 0x00200000
-//q2currentup,q3botclip 0x00400000
-//q2currentdown,q3mover 0x00800000
-//q2origin,q3origin 0x01000000
-#define FTECONTENTS_BODY 0x02000000
-#define FTECONTENTS_CORPSE 0x04000000
-//q2detail,q3detail 0x08000000
-//q2translucent,q3structual 0x10000000
-//q2ladder,q3translucent 0x20000000
-//q3trigger 0x40000000
-#define FTECONTENTS_SKY 0x80000000
+#define FTECONTENTS_EMPTY 0x00000000
+#define FTECONTENTS_SOLID 0x00000001
+//q2window 0x00000002
+//q2aux 0x00000004
+#define FTECONTENTS_LAVA 0x00000008
+#define FTECONTENTS_SLIME 0x00000010
+#define FTECONTENTS_WATER 0x00000020
+#define FTECONTENTS_FLUID (FTECONTENTS_WATER|FTECONTENTS_SLIME|FTECONTENTS_LAVA|FTECONTENTS_SKY) //sky is a fluid for q1 code.
+//q2mist 0x00000040
+//q3notteam1 0x00000080
+//q3notteam2 0x00000100
+//q3nobotclip 0x00000200
+// 0x00000400
+// 0x00000800
+// 0x00001000
+// 0x00002000
+#define FTECONTENTS_LADDER 0x00004000
+//q2areaportal,q3areaportal 0x00008000
+#define FTECONTENTS_PLAYERCLIP 0x00010000
+#define FTECONTENTS_MONSTERCLIP 0x00020000
+//q2current0,q3teleporter 0x00040000
+//q2current90,q3jumppad 0x00080000
+//q2current180,q3clusterportal 0x00100000
+//q2current270,q3donotenter 0x00200000
+//q2currentup,q3botclip 0x00400000
+//q2currentdown,q3mover 0x00800000
+//q2origin,q3origin 0x01000000 //could define, but normally removed by compiler, so why?
+#define FTECONTENTS_BODY 0x02000000
+#define FTECONTENTS_CORPSE 0x04000000
+//q2detail,q3detail 0x08000000 //not very useful to us
+//q2translucent,q3structual 0x10000000
+//q2ladder,q3translucent 0x20000000
+//q3trigger 0x40000000
+#define FTECONTENTS_SKY/*q3nodrop*/ 0x80000000
// lower bits are stronger, and will eat weaker brushes completely
#define Q2CONTENTS_SOLID FTECONTENTS_SOLID //0x00000001
diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c
index 88f3ff3f1..9a26e6879 100644
--- a/engine/common/com_mesh.c
+++ b/engine/common/com_mesh.c
@@ -2805,60 +2805,14 @@ int Mod_CountSkinFiles(model_t *mod)
return i;
}
-//support for foo.md3_0.skin
-shader_t *Mod_ShaderFromQ3SkinFile(galiasinfo_t *surf, model_t *mod, int skinnum)
-{
- shader_t *result = NULL;
- skinid_t skinid;
- skinfile_t *skinfile;
- int i;
- char *filedata;
- char skinfilename[MAX_QPATH];
- char *modelname = mod->name;
-
- if (qrenderer == QR_NONE)
- return NULL;
-
- Q_snprintfz(skinfilename, sizeof(skinfilename), "%s_%i.skin", modelname, skinnum);
- filedata = FS_LoadMallocFile(skinfilename, NULL);
- if (!filedata)
- {
- COM_StripExtension(modelname, skinfilename, sizeof(skinfilename));
- Q_snprintfz(skinfilename+strlen(skinfilename), sizeof(skinfilename)-strlen(skinfilename), "_%i.skin", skinnum);
- filedata = FS_LoadMallocFile(skinfilename, NULL);
- }
- if (filedata)
- {
- skinid = Mod_ReadSkinFile(skinfilename, filedata);
- Z_Free(filedata);
-
- skinfile = Mod_LookupSkin(skinid);
- if (skinfile)
- {
- //check if this skinfile has a mapping.
- for (i = 0; i < skinfile->nummappings; i++)
- {
- if (!strcmp(surf->surfacename, skinfile->mappings[i].surface))
- {
- skinfile->mappings[i].shader->uses++; //so it doesn't blow up when the skin gets freed.
- result = skinfile->mappings[i].shader;
- break;
- }
- }
- Mod_WipeSkin(skinid);
- }
- }
-
- return result;
-}
-
void Mod_LoadAliasShaders(model_t *mod)
{
qbyte *mipdata[4];
galiasinfo_t *ai = mod->meshinfo;
galiasskin_t *s;
skinframe_t *f;
- int i, j;
+ int i, j, k;
+ int numskins;
unsigned int loadflags;
unsigned int imageflags;
@@ -2906,15 +2860,64 @@ void Mod_LoadAliasShaders(model_t *mod)
- for (ai = mod->meshinfo; ai; ai = ai->nextsurf)
+ for (ai = mod->meshinfo, numskins = 0; ai; ai = ai->nextsurf)
{
+ if (numskins < ai->numskins)
+ numskins = ai->numskins;
Mod_GenerateMeshVBO(ai); //FIXME: shares verts
- for (i = 0, s = ai->ofsskins; i < ai->numskins; i++, s++)
+ }
+ for (i = 0; i < numskins; i++)
+ {
+ shader_t *result = NULL;
+ skinid_t skinid;
+ skinfile_t *skinfile;
+ char *filedata;
+ char skinfilename[MAX_QPATH];
+ char *modelname = mod->name;
+
+ skinid = 0;
+ skinfile = NULL;
+ if (qrenderer != QR_NONE)
{
+ Q_snprintfz(skinfilename, sizeof(skinfilename), "%s_%i.skin", modelname, i);
+ filedata = FS_LoadMallocFile(skinfilename, NULL);
+ if (!filedata)
+ {
+ COM_StripExtension(modelname, skinfilename, sizeof(skinfilename));
+ Q_snprintfz(skinfilename+strlen(skinfilename), sizeof(skinfilename)-strlen(skinfilename), "_%i.skin", i);
+ filedata = FS_LoadMallocFile(skinfilename, NULL);
+ }
+ if (filedata)
+ {
+ skinid = Mod_ReadSkinFile(skinfilename, filedata);
+ Z_Free(filedata);
+ skinfile = Mod_LookupSkin(skinid);
+ }
+ }
+
+ for (ai = mod->meshinfo; ai; ai = ai->nextsurf)
+ {
+ if (i >= ai->numskins)
+ continue;
+
+ s = ai->ofsskins+i;
for (j = 0, f = s->frame; j < s->numframes; j++, f++)
{
- if (j == 0)
- f->shader = Mod_ShaderFromQ3SkinFile(ai, mod, i);
+ if (j == 0 && skinfile)
+ {
+ //check if this skinfile has a mapping.
+ for (k = 0; k < skinfile->nummappings; k++)
+ {
+ if (!strcmp(ai->surfacename, skinfile->mappings[k].surface))
+ {
+ skinfile->mappings[k].shader->uses++; //so it doesn't blow up when the skin gets freed.
+ f->shader = skinfile->mappings[k].shader;
+ f->texnums = skinfile->mappings[k].texnums;
+ skinfile->mappings[k].needsfree = 0; //don't free any composed texture. it'll live on as part of the model.
+ break;
+ }
+ }
+ }
else
f->shader = NULL;
if (!f->shader)
@@ -2944,6 +2947,7 @@ void Mod_LoadAliasShaders(model_t *mod)
R_BuildDefaultTexnums(&f->texnums, f->shader);
}
}
+ Mod_WipeSkin(skinid);
}
}
#endif
diff --git a/engine/common/console.h b/engine/common/console.h
index a429dbb8c..12c55ff5e 100644
--- a/engine/common/console.h
+++ b/engine/common/console.h
@@ -168,6 +168,7 @@ typedef struct console_s
conchar_t defaultcharbits;
int commandcompletion; //allows tab completion of quake console commands
+ //WARNING: note that links do NOT represent any sort of security. text can be inserted from anywhere. Its fine to use such things for context, but don't treat them as sescure.
int (*linebuffered) (struct console_s *con, char *line); //if present, called on enter, causes the standard console input to appear. return 2 to not save the line in history.
qboolean (*redirect) (struct console_s *con, unsigned int unicode, int key); //if present, called every character.
qboolean (*mouseover)(struct console_s *con, char **out_tiptext, shader_t **out_shader);
diff --git a/engine/common/fs.c b/engine/common/fs.c
index 439dce444..669bd5339 100644
--- a/engine/common/fs.c
+++ b/engine/common/fs.c
@@ -6111,6 +6111,7 @@ void FS_RegisterDefaultFileSystems(void)
FS_RegisterFileSystemType(NULL, "pk4", FSZIP_LoadArchive, true);
FS_RegisterFileSystemType(NULL, "apk", FSZIP_LoadArchive, false);
FS_RegisterFileSystemType(NULL, "zip", FSZIP_LoadArchive, false);
+ FS_RegisterFileSystemType(NULL, "exe", FSZIP_LoadArchive, false); //for self-extracting zips.
#endif
#ifdef PACKAGE_DOOMWAD
FS_RegisterFileSystemType(NULL, "wad", FSDWD_LoadArchive, true);
diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c
index 9bd1fea24..53b9b9b09 100644
--- a/engine/common/gl_q2bsp.c
+++ b/engine/common/gl_q2bsp.c
@@ -3439,13 +3439,20 @@ static qboolean CModQ3_LoadVisibility (model_t *mod, qbyte *mod_base, lump_t *l)
if (l->filelen == 0)
{
int i;
+#if 0
+ //the 'correct' code
numclusters = 0;
for (i = 0; i < mod->numleafs; i++)
- if (numclusters <= mod->leafs[i].cluster)
+ if (numclusters < mod->leafs[i].cluster+1)
numclusters = mod->leafs[i].cluster+1;
numclusters++;
-
+#else
+ //but its much faster to merge all leafs into a single pvs cluster. no vis is no vis.
+ numclusters = 2;
+ for (i = 0; i < mod->numleafs; i++)
+ mod->leafs[i].cluster = !!mod->leafs[i].cluster;
+#endif
prv->q3pvs = ZG_Malloc(&mod->memgroup, sizeof(*prv->q3pvs) + (numclusters+7)/8 * numclusters);
memset (prv->q3pvs, 0xff, sizeof(*prv->q3pvs) + (numclusters+7)/8 * numclusters);
prv->q3pvs->numclusters = numclusters;
@@ -3564,7 +3571,7 @@ static void CModQ3_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l)
}
}
}
- for (; m%loadmodel->lightmaps.merge; m++)
+ /*for (; m%loadmodel->lightmaps.merge; m++)
{
out = loadmodel->lightdata;
//figure out which merged lightmap we're putting it into
@@ -3578,7 +3585,7 @@ static void CModQ3_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l)
out[s+1] = 255;
out[s+2] = 0;
}
- }
+ }*/
}
static qboolean CModQ3_LoadLightgrid (model_t *loadmodel, qbyte *mod_base, lump_t *l)
@@ -4199,7 +4206,8 @@ static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboole
CModQ3_LoadLighting (mod, mod_base, &header.lumps[Q3LUMP_LIGHTMAPS]); //fixme: duplicated loading.
}
#endif
- noerrors = noerrors && CModQ3_LoadMarksurfaces (mod, mod_base, &header.lumps[Q3LUMP_LEAFSURFACES]); noerrors = noerrors && CModQ3_LoadLeafs (mod, mod_base, &header.lumps[Q3LUMP_LEAFS]);
+ noerrors = noerrors && CModQ3_LoadMarksurfaces (mod, mod_base, &header.lumps[Q3LUMP_LEAFSURFACES]);
+ noerrors = noerrors && CModQ3_LoadLeafs (mod, mod_base, &header.lumps[Q3LUMP_LEAFS]);
noerrors = noerrors && CModQ3_LoadNodes (mod, mod_base, &header.lumps[Q3LUMP_NODES]);
noerrors = noerrors && CModQ3_LoadSubmodels (mod, mod_base, &header.lumps[Q3LUMP_MODELS]);
noerrors = noerrors && CModQ3_LoadVisibility (mod, mod_base, &header.lumps[Q3LUMP_VISIBILITY]);
diff --git a/engine/common/protocol.h b/engine/common/protocol.h
index 42bcf6c72..0f9a1ffe5 100644
--- a/engine/common/protocol.h
+++ b/engine/common/protocol.h
@@ -472,6 +472,8 @@ enum {
#define DLERR_REDIRECTPACK -5 //client should download the specified package instead.
#define DLERR_PACKAGE -6 //not networked. packages require special file access.
+#define DLBLOCKSIZE 1024 //chunked downloads use fixed-size chunks (which I somewhat regret, but too late now I guess, really ought to use ranges.).
+
//these flags are sent as part of the svc_precache index, for any-time precaches. using the upper two bits means we still have 16k available models/sounds/etc
#define PC_TYPE 0xc000
#define PC_MODEL 0x0000
diff --git a/engine/dotnet2005/ftequake.vcproj b/engine/dotnet2005/ftequake.vcproj
index 9b3d9aa84..92ba3aa3e 100644
--- a/engine/dotnet2005/ftequake.vcproj
+++ b/engine/dotnet2005/ftequake.vcproj
@@ -1080,6 +1080,7 @@
AdditionalIncludeDirectories="../libs/speex;..\client;../libs/freetype2/include;../common;../server;../gl;../sw;../qclib;../libs;../libs/dxsdk9/include;../libs/dxsdk7/include"
PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;GLQUAKE;D3D9QUAKE;D3D11QUAKE;SWQUAKE;VKQUAKE;USE_EGL"
StringPooling="true"
+ ExceptionHandling="0"
RuntimeLibrary="0"
EnableFunctionLevelLinking="true"
FloatingPointModel="2"
@@ -1102,6 +1103,7 @@
/>
nummappings; i++)
{
if (sk->mappings[i].needsfree)
+ {
Image_UnloadTexture(sk->mappings[i].texnums.base);
+ sk->mappings[i].texnums.base = r_nulltex;
+ }
R_UnloadShader(sk->mappings[i].shader);
}
Z_Free(registeredskins[id]);
@@ -115,16 +118,18 @@ skinfile_t *Mod_LookupSkin(skinid_t id)
return registeredskins[id];
return NULL;
}
-static void Mod_ComposeSkin(char *texture, struct cctx_s *cctx)
+struct composeline_s
+{
+ shader_t *sourceimg;
+
+ vec2_t pos, size;
+ vec4_t tc;
+ vec4_t rgba;
+};
+static void Mod_ParseComposeLine(char *texture, struct composeline_s *line)
{
- float x=0, y=0;
- float w, h;
- int iw=0, ih=0;
- float s1 = 0, t1 = 0, s2 = 1, t2 = 1;
- float r=1,g=1,b=1,a=1;
int l;
char *s, tname[MAX_QPATH];
- shader_t *sourceimg;
for (s = texture; *s; s++)
{
if (*s == '@' || *s == ':' || *s == '?' || *s == '*')
@@ -138,59 +143,55 @@ static void Mod_ComposeSkin(char *texture, struct cctx_s *cctx)
tname[l] = 0;
//load the image and set some default sizes, etc.
- sourceimg = R2D_SafeCachePic(tname);
-
- if (!sourceimg || R_GetShaderSizes(sourceimg, &iw, &ih, true) != 1) //no shader? no point in doing anything.
- {
- w = 0;
- h = 0;
- sourceimg = NULL;
- }
+ if (*tname)
+ line->sourceimg = R2D_SafeCachePic(tname);
else
- {
- w = iw;
- h = ih;
- }
+ line->sourceimg = NULL;
+
+ Vector2Set(line->pos, 0, 0);
+ Vector2Set(line->size, -1, -1);
+ Vector4Set(line->tc, 0, 0, 1, 1);
+ Vector4Set(line->rgba, 1, 1, 1, 1);
while(*s)
{
switch(*s)
{
case '@':
- x = strtod(s+1, &s);
+ line->pos[0] = strtod(s+1, &s);
if (*s == ',')
s++;
- y = strtod(s, &s);
+ line->pos[1] = strtod(s, &s);
break;
case ':':
- w = strtod(s+1, &s);
+ line->size[0] = strtod(s+1, &s);
if (*s == ',')
s++;
- h = strtod(s, &s);
+ line->size[1] = strtod(s, &s);
break;
case '$':
- s1 = strtod(s+1, &s);
+ line->tc[0] = strtod(s+1, &s);
if (*s == ',')
s++;
- t1 = strtod(s, &s);
+ line->tc[1] = strtod(s, &s);
if (*s == ',')
s++;
- s2 = strtod(s, &s);
+ line->tc[2] = strtod(s, &s);
if (*s == ',')
s++;
- t2 = strtod(s, &s);
+ line->tc[3] = strtod(s, &s);
break;
case '?':
- r = strtod(s+1, &s);
+ line->rgba[0] = strtod(s+1, &s);
if (*s == ',')
s++;
- g = strtod(s, &s);
+ line->rgba[1] = strtod(s, &s);
if (*s == ',')
s++;
- b = strtod(s, &s);
+ line->rgba[2] = strtod(s, &s);
if (*s == ',')
s++;
- a = strtod(s, &s);
+ line->rgba[3] = strtod(s, &s);
break;
// case '*':
// break;
@@ -199,26 +200,46 @@ static void Mod_ComposeSkin(char *texture, struct cctx_s *cctx)
break;
}
}
+}
+static void Mod_ComposeSkin(char *texture, struct cctx_s *cctx, struct composeline_s *line)
+{
+ int iw=0, ih=0;
- if (!w || !h)
- return;
-
- //create a render target if one is not already selected
- if (!TEXVALID(cctx->diffuse))
+ if (!line->sourceimg || R_GetShaderSizes(line->sourceimg, &iw, &ih, false) != 1) //no shader? no point in doing anything.
{
- strcpy(r_refdef.rt_destcolour[0].texname, "-");
- cctx->width = x+w;
- cctx->height = y+h;
- cctx->diffuse = R2D_RT_Configure(r_refdef.rt_destcolour[0].texname, cctx->width, cctx->height, TF_RGBA32, RT_IMAGEFLAGS);
- BE_RenderToTextureUpdate2d(true);
+ iw = ih = 0;
+ line->sourceimg = NULL;
+ }
+ if (line->size[0] < 0)
+ line->size[0] = iw;
+ if (line->size[1] < 0)
+ line->size[1] = ih;
+
+ if (line->size[0]>0 && line->size[1]>0)
+ {
+ //create a render target if one is not already selected
+ if (!TEXVALID(cctx->diffuse))
+ {
+ if (R2D_Flush)
+ R2D_Flush();
+
+ strcpy(r_refdef.rt_destcolour[0].texname, "-");
+ cctx->width = line->pos[0]+line->size[0];
+ cctx->height = line->pos[1]+line->size[1];
+ cctx->diffuse = R2D_RT_Configure(r_refdef.rt_destcolour[0].texname, cctx->width, cctx->height, TF_RGBA32, RT_IMAGEFLAGS);
+ BE_RenderToTextureUpdate2d(true);
+ }
+
+ if (line->sourceimg)
+ {
+ R2D_ImageColours(line->rgba[0],line->rgba[1],line->rgba[2],line->rgba[3]);
+ R2D_Image(line->pos[0], line->pos[1], line->size[0], line->size[1], line->tc[0], line->tc[1], line->tc[2], line->tc[3], line->sourceimg);
+ }
}
- if (!sourceimg)
- return;
-
- R2D_ImageColours(r,g,b,a);
- R2D_Image(x, cctx->height-(y+h), w, h, s1, t2, s2, t1, sourceimg);
- R_UnloadShader(sourceimg); //we're done with it now
+ if (R2D_Flush)
+ R2D_Flush();
+ R_UnloadShader(line->sourceimg); //we're done with it now
}
//create a new skin with explicit name and text. even if its already loaded. this means you can free it safely.
skinid_t Mod_ReadSkinFile(const char *skinname, const char *skintext)
@@ -279,6 +300,8 @@ skinid_t Mod_ReadSkinFile(const char *skinname, const char *skintext)
//body
if (com_tokentype != TTP_LINEENDING)
{
+ size_t l,lines;
+ struct composeline_s line[64];
//fixme: this blocks waiting for the textures to load.
struct cctx_s cctx;
memset(&cctx, 0, sizeof(cctx));
@@ -290,7 +313,8 @@ skinid_t Mod_ReadSkinFile(const char *skinname, const char *skintext)
R_BuildDefaultTexnums(NULL, skin->mappings[skin->nummappings].shader);
skin->mappings[skin->nummappings].texnums = *skin->mappings[skin->nummappings].shader->defaulttextures;
- for(;;)
+ //parse the lines, and start to load the various shaders.
+ for(lines = 0;linesmappings[skin->nummappings].needsfree = 1;
skin->mappings[skin->nummappings].texnums.base = cctx.diffuse;
skin->nummappings++;
-
- *r_refdef.rt_destcolour[0].texname = 0;
- BE_RenderToTextureUpdate2d(true);
}
}
else if (!strcmp(com_token, "geomset"))
diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c
index e64063b1e..706e08285 100644
--- a/engine/gl/gl_backend.c
+++ b/engine/gl/gl_backend.c
@@ -3705,7 +3705,7 @@ void GLBE_SelectMode(backendmode_t mode)
if (!shaderstate.allblackshader.glsl.handle)
{
const char *defs[] = {NULL};
- shaderstate.allblackshader = GLSlang_CreateProgram(NULL, "allblackprogram", gl_config_gles?100:110, defs, "#include \"sys/skeletal.h\"\nvoid main(){gl_Position = skeletaltransform();}", NULL, NULL, NULL, "void main(){gl_FragColor=vec4(0.0,0.0,0.0,1.0);}", false, NULL);
+ shaderstate.allblackshader = GLSlang_CreateProgram(NULL, "allblackprogram", sh_config.minver, defs, "#include \"sys/skeletal.h\"\nvoid main(){gl_Position = skeletaltransform();}", NULL, NULL, NULL, "void main(){gl_FragColor=vec4(0.0,0.0,0.0,1.0);}", false, NULL);
shaderstate.allblack_mvp = qglGetUniformLocationARB(shaderstate.allblackshader.glsl.handle, "m_modelviewprojection");
}
/*BEM_DEPTHONLY does support mesh writing, but its not the only way its used... FIXME!*/
@@ -3734,7 +3734,7 @@ void GLBE_SelectMode(backendmode_t mode)
if (gl_config_nofixedfunc && !shaderstate.allblackshader.glsl.handle)
{
const char *defs[] = {NULL};
- shaderstate.allblackshader = GLSlang_CreateProgram(NULL, "allblackprogram", gl_config_gles?100:110, defs, "#include \"sys/skeletal.h\"\nvoid main(){gl_Position = skeletaltransform();}", NULL, NULL, NULL, "void main(){gl_FragColor=vec4(0.0,0.0,0.0,1.0);}", false, NULL);
+ shaderstate.allblackshader = GLSlang_CreateProgram(NULL, "allblackprogram", sh_config.minver, defs, "#include \"sys/skeletal.h\"\nvoid main(){gl_Position = skeletaltransform();}", NULL, NULL, NULL, "void main(){gl_FragColor=vec4(0.0,0.0,0.0,1.0);}", false, NULL);
shaderstate.allblack_mvp = qglGetUniformLocationARB(shaderstate.allblackshader.glsl.handle, "m_modelviewprojection");
}
@@ -4303,7 +4303,7 @@ static void DrawMeshes(void)
if (!shaderstate.allblackshader.glsl.handle)
{
const char *defs[] = {NULL};
- shaderstate.allblackshader = GLSlang_CreateProgram(NULL, "allblackprogram", gl_config_gles?100:110, defs, "#include \"sys/skeletal.h\"\nvoid main(){gl_Position = skeletaltransform();}", NULL, NULL, NULL, "void main(){gl_FragColor=vec4(0.0,0.0,0.0,1.0);}", false, NULL);
+ shaderstate.allblackshader = GLSlang_CreateProgram(NULL, "allblackprogram", sh_config.minver, defs, "#include \"sys/skeletal.h\"\nvoid main(){gl_Position = skeletaltransform();}", NULL, NULL, NULL, "void main(){gl_FragColor=vec4(0.0,0.0,0.0,1.0);}", false, NULL);
shaderstate.allblack_mvp = qglGetUniformLocationARB(shaderstate.allblackshader.glsl.handle, "m_modelviewprojection");
}
diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c
index 3259f45c0..82f5c3670 100644
--- a/engine/gl/gl_shader.c
+++ b/engine/gl/gl_shader.c
@@ -1797,7 +1797,7 @@ static void Shader_LoadGeneric(sgeneric_t *g, int qrtype)
ver = sbuiltins[i].apiver;
if (ver < sh_config.minver || ver > sh_config.maxver)
- if (!(qrenderer==QR_OPENGL&&ver==110&&sh_config.maxver==100))
+ if (!(qrenderer==QR_OPENGL&&ver==110))
continue;
g->failed = !Shader_LoadPermutations(g->name, &g->prog, sbuiltins[i].body, qrtype, ver, blobname);
diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c
index e774a3d1b..cc8929978 100644
--- a/engine/gl/gl_vidcommon.c
+++ b/engine/gl/gl_vidcommon.c
@@ -2997,8 +2997,23 @@ qboolean GL_Init(rendererstate_t *info, void *(*getglfunction) (char *name))
if (GL_CheckExtension("GL_EXT_packed_depth_stencil"))
sh_config.texfmt[PTI_DEPTH24_8] = true;
- sh_config.minver = gl_config.arb_shader_objects?110:0;
- sh_config.maxver = gl_config.arb_shader_objects?gl_config.maxglslversion:0;
+ if (gl_config.nofixedfunc)
+ { //core contexts don't normally support glsl < 140 (such glsl versions have lots of compat syntax still, which will not function on core. drivers might accept it anyway, but yeah, lots of crap that shouldn't work)
+ //FIXME: GL_NUM_SHADING_LANGUAGE_VERSIONS and GL_SHADING_LANGUAGE_VERSION might allow for earlier versions.
+ sh_config.minver = 140;
+ sh_config.maxver = gl_config.maxglslversion;
+ }
+ else if (gl_config.arb_shader_objects)
+ {
+ //FIXME: we could accept 100 here, but that gets messy when gles is considered, and old drivers suck anyway.
+ sh_config.minver = 110;
+ sh_config.maxver = gl_config.maxglslversion;
+ }
+ else
+ {
+ sh_config.minver = 0;
+ sh_config.maxver = 0;
+ }
sh_config.blobpath = "glsl/%s.blob";
sh_config.progpath = "glsl/%s.glsl";
sh_config.shadernamefmt = "%s_glsl";
diff --git a/engine/gl/r_bishaders.h b/engine/gl/r_bishaders.h
index d0a390e79..3b31d3a16 100644
--- a/engine/gl/r_bishaders.h
+++ b/engine/gl/r_bishaders.h
@@ -5,6 +5,8 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
#ifdef GLQUAKE
{QR_OPENGL, 110, "fixedemu",
+"!!ver 100-450\n"
+
//this shader is present for support for gles/gl3core contexts
//it is single-texture-with-vertex-colours, and doesn't do anything special.
//beware that a few things use this, including apparently fonts and bloom rescaling.
@@ -2418,6 +2420,8 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "default2d",
+"!!ver 100-450\n"
+
//this shader is present for support for gles/gl3core contexts
//it is single-texture-with-vertex-colours, and doesn't do anything special.
//beware that a few things use this, including apparently fonts and bloom rescaling.
@@ -4964,6 +4968,8 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "defaultfill",
+"!!ver 100-450\n"
+
"#ifdef VERTEX_SHADER\n"
"attribute vec4 v_colour;\n"
"varying vec4 vc;\n"
@@ -7392,6 +7398,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "defaultgammacb",
+"!!ver 100-450\n"
//this shader is applies gamma/contrast/brightness to the source image, and dumps it out.
"varying vec2 tc;\n"
diff --git a/engine/qclib/qcc.h b/engine/qclib/qcc.h
index 130f37ee3..7fd30a42c 100644
--- a/engine/qclib/qcc.h
+++ b/engine/qclib/qcc.h
@@ -731,6 +731,7 @@ enum {
WARN_READNOTWRITTEN,
WARN_NOTREFERENCED,
WARN_NOTREFERENCEDCONST,
+ WARN_NOTREFERENCEDFIELD,
WARN_CONFLICTINGRETURNS,
WARN_TOOFEWPARAMS,
WARN_TOOMANYPARAMS,
diff --git a/engine/qclib/qcc_pr_comp.c b/engine/qclib/qcc_pr_comp.c
index f4ac7e82c..66a044e1d 100644
--- a/engine/qclib/qcc_pr_comp.c
+++ b/engine/qclib/qcc_pr_comp.c
@@ -10145,8 +10145,9 @@ void QCC_PR_ParseStatement (void)
{
PR_GenerateReturnOuts();
if (pr_scope->type->aux_type->type != ev_void)
- {
- QCC_PR_ParseWarning(WARN_MISSINGRETURNVALUE, "\'%s\' returned nothing, expected %s", pr_scope->name, pr_scope->type->aux_type->name);
+ { //accumulated functions are not required to return anything, on the assumption that a previous 'part' of the function did so
+ if (!pr_scope->def || !pr_scope->def->accumulate || !pr_scope->returndef.cast)
+ QCC_PR_ParseWarning(WARN_MISSINGRETURNVALUE, "\'%s\' returned nothing, expected %s", pr_scope->name, pr_scope->type->aux_type->name);
//this should not normally happen
if (!pr_scope->returndef.cast)
{ //but if it does, allocate a local that can be return=foo; before the return. depend upon qc's null initialisation rules for the default value.
@@ -11849,6 +11850,8 @@ pbool QCC_CheckUninitialised(int firststatement, int laststatement)
{
if (local->constant)
continue; //will get some other warning, so we don't care.
+ if (local->isstatic)
+ continue; //not a real local, so will be properly initialised.
if (local->symbolheader != local)
continue; //ignore slave symbols, cos they're not interesting and should have been checked as part of the parent.
if (local->ofs < paramend)
@@ -11878,13 +11881,13 @@ void QCC_Marshal_Locals(int firststatement, int laststatement)
if (qccwarningaction[WARN_UNINITIALIZED])
QCC_CheckUninitialised(firststatement, laststatement); //still need to call it for warnings, but if those warnings are off we can skip the cost
}
- else if (!pr_scope->def->accumulate && !opt_locals_overlapping)
+ else if (!opt_locals_overlapping)
{
if (qccwarningaction[WARN_UNINITIALIZED])
QCC_CheckUninitialised(firststatement, laststatement); //still need to call it for warnings, but if those warnings are off we can skip the cost
error = true; //always use the legacy behaviour
}
- else if (QCC_CheckUninitialised(firststatement, laststatement) && !pr_scope->def->accumulate)
+ else if (QCC_CheckUninitialised(firststatement, laststatement))
{
error = true;
// QCC_PR_Note(ERR_INTERNAL, strings+s_file, pr_source_line, "Not overlapping locals from %s due to uninitialised locals", pr_scope->name);
@@ -13884,7 +13887,7 @@ pbool QCC_PR_ParseInitializerType(int arraysize, QCC_def_t *basedef, QCC_sref_t
//generate a goto statement around the nested function, so that nothing is hurt.
patch = QCC_Generate_OP_GOTO();
- f = QCC_PR_ParseImmediateStatements (NULL, type, flags&PIF_WRAP);
+ f = QCC_PR_ParseImmediateStatements (def.sym->isstatic?def.sym:NULL, type, flags&PIF_WRAP);
patch->a.ofs = &statements[numstatements] - patch;
if (patch->a.ofs == 1)
numstatements--; //never mind then.
diff --git a/engine/qclib/qccmain.c b/engine/qclib/qccmain.c
index 95ef2e96e..c45911832 100644
--- a/engine/qclib/qccmain.c
+++ b/engine/qclib/qccmain.c
@@ -218,6 +218,7 @@ struct {
{" F322", WARN_IFSTRING_USED},
{" F323", WARN_UNREACHABLECODE},
+ {" F207", WARN_NOTREFERENCEDFIELD},
{" F208", WARN_NOTREFERENCEDCONST},
{" F209", WARN_EXTRAPRECACHE},
{" F210", WARN_NOTPRECACHED},
@@ -962,7 +963,7 @@ void QCC_DetermineNeededSymbols(QCC_def_t *endsyssym)
}
}
//non-system fields should maybe be present too.
- for (; sym; sym = sym->next)
+/* for (; sym; sym = sym->next)
{
if (sym->constant && sym->type->type == ev_field && !opt_stripunusedfields)
{
@@ -977,6 +978,7 @@ void QCC_DetermineNeededSymbols(QCC_def_t *endsyssym)
// sym->symbolheader->used = true;
// }
}
+*/
for (i=0 ; isymbolheader != def)
+ {
QCC_FinaliseDef(def->symbolheader);
+ def->referenced = true;
+ }
if (def->symbolheader == def && def->deftail)
{
//for head symbols, we go through and touch all of their children
QCC_def_t *prev, *sub;
- if (!def->referenced)
+ if (def->used && !def->referenced)
{
pbool ignoreone = true;
//touch all but one child
@@ -1022,18 +1027,16 @@ void QCC_FinaliseDef(QCC_def_t *def)
def->referenced=true; //if one child is referenced, the composite is referenced
else if (!sub->referenced && ignoreone)
ignoreone = false; //this is the one we're going to warn about
- else
- sub->referenced |= def->referenced;
}
- if (!def->referenced) //no child defs were referenced at all. if we're going to be warning about this then at least mute warnings for any other fields
- for (prev = def, sub = prev->next; prev != def->deftail; sub = (prev=sub)->next)
- sub->referenced = true;
+// if (def->referenced) //no child defs were referenced at all. if we're going to be warning about this then at least mute warnings for any other fields
+// for (prev = def, sub = prev->next; prev != def->deftail; sub = (prev=sub)->next)
+// sub->referenced = true;
}
else
{
- //touch children
+ //touch children to silence annoying warnings.
for (prev = def, sub = prev->next; prev != def->deftail; sub = (prev=sub)->next)
- sub->referenced |= def->referenced;
+ sub->referenced |= true;
}
#ifdef TODO_READWRITETRACK
@@ -1698,9 +1701,11 @@ pbool QCC_WriteData (int crc)
QCC_PR_Warning(WARN_WRITTENNOTREAD, def->filen, def->s_line, "%s %s = %s written, but not read.", TypeName(def->type, typestr, sizeof(typestr)), def->name, QCC_VarAtOffset(sr));
}
#endif
- if (!def->symbolheader->read && !def->symbolheader->written && !def->symbolheader->referenced)
+ if (!def->symbolheader->read && !def->symbolheader->written && !def->referenced)
{
int wt = def->constant?WARN_NOTREFERENCEDCONST:WARN_NOTREFERENCED;
+ if (def->type->type == ev_field && def->constant)
+ wt = WARN_NOTREFERENCEDFIELD;
pr_scope = def->scope;
if (!strncmp(def->name, "spawnfunc_", 10))
; //no warnings from unreferenced entry points.
diff --git a/engine/server/net_preparse.c b/engine/server/net_preparse.c
index ef6d7c151..2cd12b724 100644
--- a/engine/server/net_preparse.c
+++ b/engine/server/net_preparse.c
@@ -588,8 +588,10 @@ extern qboolean ssqc_deprecated_warned;
#define svc_setfrags 14
#define svc_updatecolors 17
+#ifdef HEXEN2
#define svch2_clearviewflags 41 //hexen2.
#define svch2_setangles_lerp 50
+#endif
//these are present in the darkplaces engine.
//I wanna knick their mods.
@@ -706,9 +708,9 @@ void NPP_NQFlush(void)
{
client_t *cl;
int i;
+#ifdef HEXEN2
char *h2finale = NULL;
char *h2title = NULL;
-#ifdef HEXEN2
if (progstype == PROG_H2)
{
/*FIXME: hexen2 intermission+finale includes the viewheight. NQ does not, and QW has explicit position with scores but no finale*/
@@ -728,6 +730,7 @@ void NPP_NQFlush(void)
{
if (cl->state == cs_spawned && ISQWCLIENT(cl))
{
+#ifdef HEXEN2
if (h2finale)
{
ClientReliableCheckBlock(cl, 6 + strlen(h2title) + 3 + strlen(h2finale) + 1);
@@ -747,7 +750,9 @@ void NPP_NQFlush(void)
ClientReliableWrite_String(cl, h2finale);
}
- else if (cl->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)
+ else
+#endif
+ if (cl->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)
{ //special intermission mode to leave the view attached to the viewentity (as required for nq - especially rogue's finale) instead of hacking it to some specific point
ClientReliableCheckBlock(cl, 5);
ClientReliableWrite_Byte(cl, svc_finale);
diff --git a/engine/server/sv_ccmds.c b/engine/server/sv_ccmds.c
index 8991ce0d1..90813f56c 100644
--- a/engine/server/sv_ccmds.c
+++ b/engine/server/sv_ccmds.c
@@ -2904,7 +2904,7 @@ void SV_MemInfo_f(void)
}
void SV_Download_f (void)
-{
+{ //command for dedicated servers. apparently.
#ifdef WEBCLIENT
char *url = Cmd_Argv(1);
char *localname = Cmd_Argv(2);
diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c
index 319e4bbd0..5236efaf6 100644
--- a/engine/server/sv_main.c
+++ b/engine/server/sv_main.c
@@ -5233,7 +5233,7 @@ void SV_FixupName(char *in, char *out, unsigned int outlen)
s = out;
while(iswhite(*in) || isinvalid(*in) || *in == '\1' || *in == '\2') //1 and 2 are to stop clients from printing the entire line as chat. only do that for the leading charater.
in++;
- while(*in && len > 0)
+ while(*in && len > 1)
{
if (isinvalid(*in))
{
diff --git a/engine/shaders/glsl/default2d.glsl b/engine/shaders/glsl/default2d.glsl
index 5f6e459ae..98532eabc 100644
--- a/engine/shaders/glsl/default2d.glsl
+++ b/engine/shaders/glsl/default2d.glsl
@@ -1,3 +1,5 @@
+!!ver 100-450
+
//this shader is present for support for gles/gl3core contexts
//it is single-texture-with-vertex-colours, and doesn't do anything special.
//beware that a few things use this, including apparently fonts and bloom rescaling.
diff --git a/engine/shaders/glsl/defaultfill.glsl b/engine/shaders/glsl/defaultfill.glsl
index 1c901b178..aeefe8cbc 100644
--- a/engine/shaders/glsl/defaultfill.glsl
+++ b/engine/shaders/glsl/defaultfill.glsl
@@ -1,3 +1,5 @@
+!!ver 100-450
+
#ifdef VERTEX_SHADER
attribute vec4 v_colour;
varying vec4 vc;
diff --git a/engine/shaders/glsl/defaultgammacb.glsl b/engine/shaders/glsl/defaultgammacb.glsl
index e0dc973d5..daa6da8cd 100644
--- a/engine/shaders/glsl/defaultgammacb.glsl
+++ b/engine/shaders/glsl/defaultgammacb.glsl
@@ -1,3 +1,4 @@
+!!ver 100-450
//this shader is applies gamma/contrast/brightness to the source image, and dumps it out.
varying vec2 tc;
diff --git a/engine/shaders/glsl/fixedemu.glsl b/engine/shaders/glsl/fixedemu.glsl
index e9b2b0563..a3984d4c6 100644
--- a/engine/shaders/glsl/fixedemu.glsl
+++ b/engine/shaders/glsl/fixedemu.glsl
@@ -1,3 +1,5 @@
+!!ver 100-450
+
//this shader is present for support for gles/gl3core contexts
//it is single-texture-with-vertex-colours, and doesn't do anything special.
//beware that a few things use this, including apparently fonts and bloom rescaling.
diff --git a/engine/vk/vk_init.c b/engine/vk/vk_init.c
index d645cf943..3ce67c815 100644
--- a/engine/vk/vk_init.c
+++ b/engine/vk/vk_init.c
@@ -10,6 +10,7 @@ extern cvar_t vk_submissionthread;
extern cvar_t vk_debug;
extern cvar_t vk_dualqueue;
extern cvar_t vk_busywait;
+extern cvar_t vk_waitfence;
extern cvar_t vk_nv_glsl_shader;
extern cvar_t vk_nv_dedicated_allocation;
extern cvar_t vk_khr_dedicated_allocation;
@@ -220,7 +221,8 @@ static void VK_DestroySwapChain(void)
vk.dopresent(NULL);
while (vk.aquirenext < vk.aquirelast)
{
- VkWarnAssert(vkWaitForFences(vk.device, 1, &vk.acquirefences[vk.aquirenext%ACQUIRELIMIT], VK_FALSE, UINT64_MAX));
+ if (vk.acquirefences[vk.aquirenext%ACQUIRELIMIT])
+ VkWarnAssert(vkWaitForFences(vk.device, 1, &vk.acquirefences[vk.aquirenext%ACQUIRELIMIT], VK_FALSE, UINT64_MAX));
vk.aquirenext++;
}
if (vk.device)
@@ -281,6 +283,7 @@ static qboolean VK_CreateSwapChain(void)
vid_triplebuffer.modified = false;
vid_srgb.modified = false;
vk_submissionthread.modified = false;
+ vk_waitfence.modified = false;
vid_multisample.modified = false;
vk.triplebuffer = vid_triplebuffer.ival;
@@ -305,9 +308,19 @@ static qboolean VK_CreateSwapChain(void)
vk.aquirelast = vk.aquirenext = 0;
for (i = 0; i < ACQUIRELIMIT; i++)
{
- VkFenceCreateInfo fci = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO};
- fci.flags = VK_FENCE_CREATE_SIGNALED_BIT;
- VkAssert(vkCreateFence(vk.device,&fci,vkallocationcb,&vk.acquirefences[i]));
+ if (1)
+ {
+ VkFenceCreateInfo fci = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO};
+ fci.flags = VK_FENCE_CREATE_SIGNALED_BIT;
+ VkAssert(vkCreateFence(vk.device,&fci,vkallocationcb,&vk.acquirefences[i]));
+ vk.acquiresemaphores[i] = VK_NULL_HANDLE;
+ }
+ else
+ {
+ VkSemaphoreCreateInfo sci = {VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO};
+ VkAssert(vkCreateSemaphore(vk.device, &sci, vkallocationcb, &vk.acquiresemaphores[i]));
+ vk.acquirefences[i] = VK_NULL_HANDLE;
+ }
vk.acquirebufferidx[vk.aquirelast%ACQUIRELIMIT] = vk.aquirelast%vk.backbuf_count;
vk.aquirelast++;
@@ -411,8 +424,12 @@ static qboolean VK_CreateSwapChain(void)
uint32_t priority = 0;
switch(presentmode[i])
{
- default://ignore it.
+ default://ignore it if we don't know it.
break;
+ //this is awkward. normally we use vsync<0 to allow tearing-with-vsync, but that leaves us with a problem as far as what 0 should signify - tearing or not.
+ //if we're using mailbox then we could instead discard the command buffers and skip rendering of the actual scenes.
+ //we could have our submission thread wait some time period after the last vswap (ie: before the next) before submitting the command.
+ //this could reduce gpu load at higher resolutions without lying too much about cpu usage...
case VK_PRESENT_MODE_IMMEDIATE_KHR:
priority = (vk.vsync?0:2) + 2; //for most quake players, latency trumps tearing.
break;
@@ -434,7 +451,7 @@ static qboolean VK_CreateSwapChain(void)
}
if (!vk.vsync && swapinfo.presentMode != VK_PRESENT_MODE_IMMEDIATE_KHR)
- Con_Printf("Warning: vulkan graphics driver does not fully support disabling vsync.\n");
+ Con_Printf("Warning: vulkan graphics driver does not support VK_PRESENT_MODE_IMMEDIATE_KHR.\n");
vk.srgbcapable = false;
swapinfo.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
@@ -499,13 +516,23 @@ static qboolean VK_CreateSwapChain(void)
vk.aquirelast = vk.aquirenext = 0;
for (i = 0; i < ACQUIRELIMIT; i++)
{
- VkFenceCreateInfo fci = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO};
- VkAssert(vkCreateFence(vk.device,&fci,vkallocationcb,&vk.acquirefences[i]));
+ if (vk_waitfence.ival)
+ {
+ VkFenceCreateInfo fci = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO};
+ VkAssert(vkCreateFence(vk.device,&fci,vkallocationcb,&vk.acquirefences[i]));
+ vk.acquiresemaphores[i] = VK_NULL_HANDLE;
+ }
+ else
+ {
+ VkSemaphoreCreateInfo sci = {VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO};
+ VkAssert(vkCreateSemaphore(vk.device, &sci, vkallocationcb, &vk.acquiresemaphores[i]));
+ vk.acquirefences[i] = VK_NULL_HANDLE;
+ }
}
/*-1 to hide any weird thread issues*/
while (vk.aquirelast < ACQUIRELIMIT-1 && vk.aquirelast < vk.backbuf_count && vk.aquirelast <= vk.backbuf_count-surfcaps.minImageCount)
{
- VkAssert(vkAcquireNextImageKHR(vk.device, vk.swapchain, UINT64_MAX, VK_NULL_HANDLE, vk.acquirefences[vk.aquirelast%ACQUIRELIMIT], &vk.acquirebufferidx[vk.aquirelast%ACQUIRELIMIT]));
+ VkAssert(vkAcquireNextImageKHR(vk.device, vk.swapchain, UINT64_MAX, vk.acquiresemaphores[vk.aquirelast%ACQUIRELIMIT], vk.acquirefences[vk.aquirelast%ACQUIRELIMIT], &vk.acquirebufferidx[vk.aquirelast%ACQUIRELIMIT]));
vk.aquirelast++;
}
}
@@ -1074,7 +1101,8 @@ void *VK_FencedBegin(void (*passed)(void *work), size_t worksize)
return w;
}
-//end+submit a commandbuffer, and set up a fence so we know when its complete
+//end+submit a commandbuffer, and set up a fence so we know when its complete. this is not within the context of any frame, so make sure any textures are safe to rewrite early...
+//completion can be signalled before the current frame finishes, so watch out for that too.
void VK_FencedSubmit(void *work)
{
struct vk_fencework *w = work;
@@ -2623,6 +2651,7 @@ VkCommandBuffer VK_AllocFrameCBuf(void)
qboolean VK_SCR_GrabBackBuffer(void)
{
+ VkSemaphore sem;
RSpeedLocals();
if (vk.frame) //erk, we already have one...
@@ -2643,31 +2672,37 @@ qboolean VK_SCR_GrabBackBuffer(void)
while (vk.aquirenext == vk.aquirelast)
{ //we're still waiting for the render thread to increment acquirelast.
+ //shouldn't really happen, but can if the gpu is slow.
Sys_Sleep(0); //o.O
#ifdef _WIN32
Sys_SendKeyEvents();
#endif
}
- //wait for the queued acquire to actually finish
- if (vk_busywait.ival)
- { //busy wait, to try to get the highest fps possible
- while (VK_TIMEOUT == vkGetFenceStatus(vk.device, vk.acquirefences[vk.aquirenext%ACQUIRELIMIT]))
- ;
- }
- else
+ if (vk.acquirefences[vk.aquirenext%ACQUIRELIMIT] != VK_NULL_HANDLE)
{
- //friendly wait
- VkResult err = vkWaitForFences(vk.device, 1, &vk.acquirefences[vk.aquirenext%ACQUIRELIMIT], VK_FALSE, UINT64_MAX);
- if (err)
- {
- if (err == VK_ERROR_DEVICE_LOST)
- Sys_Error("Vulkan device lost");
- return false;
+ //wait for the queued acquire to actually finish
+ if (vk_busywait.ival)
+ { //busy wait, to try to get the highest fps possible
+ while (VK_TIMEOUT == vkGetFenceStatus(vk.device, vk.acquirefences[vk.aquirenext%ACQUIRELIMIT]))
+ ;
}
+ else
+ {
+ //friendly wait
+ VkResult err = vkWaitForFences(vk.device, 1, &vk.acquirefences[vk.aquirenext%ACQUIRELIMIT], VK_FALSE, UINT64_MAX);
+ if (err)
+ {
+ if (err == VK_ERROR_DEVICE_LOST)
+ Sys_Error("Vulkan device lost");
+ return false;
+ }
+ }
+ VkAssert(vkResetFences(vk.device, 1, &vk.acquirefences[vk.aquirenext%ACQUIRELIMIT]));
}
vk.bufferidx = vk.acquirebufferidx[vk.aquirenext%ACQUIRELIMIT];
- VkAssert(vkResetFences(vk.device, 1, &vk.acquirefences[vk.aquirenext%ACQUIRELIMIT]));
+
+ sem = vk.acquiresemaphores[vk.aquirenext%ACQUIRELIMIT];
vk.aquirenext++;
//grab the first unused
@@ -2684,6 +2719,7 @@ qboolean VK_SCR_GrabBackBuffer(void)
vk.frame->numcbufs = 0;
vk.rendertarg->cbuf = VK_AllocFrameCBuf();
+ vk.frame->acquiresemaphore = sem;
RSpeedEnd(RSPEED_SETUP);
@@ -2859,7 +2895,7 @@ qboolean VK_SCR_UpdateScreen (void)
VK_FencedCheck();
//a few cvars need some extra work if they're changed
- if ((vk.allowsubmissionthread && vk_submissionthread.modified) || vid_vsync.modified || vid_triplebuffer.modified || vid_srgb.modified || vid_multisample.modified)
+ if ((vk.allowsubmissionthread && vk_submissionthread.modified) || vid_vsync.modified || vk_waitfence.modified || vid_triplebuffer.modified || vid_srgb.modified || vid_multisample.modified)
vk.neednewswapchain = true;
if (vk.devicelost)
@@ -2989,7 +3025,7 @@ qboolean VK_SCR_UpdateScreen (void)
vk.frame->frameendjobs = vk.frameendjobs;
vk.frameendjobs = NULL;
- VK_Submit_Work(vk.rendertarg->cbuf, VK_NULL_HANDLE, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, vk.frame->backbuf->presentsemaphore, vk.frame->finishedfence, vk.frame, &fw->fw);
+ VK_Submit_Work(vk.rendertarg->cbuf, vk.frame->acquiresemaphore, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, vk.frame->backbuf->presentsemaphore, vk.frame->finishedfence, vk.frame, &fw->fw);
}
//now would be a good time to do any compute work or lightmap updates...
@@ -3161,7 +3197,7 @@ void VK_DoPresent(struct vkframe *theframe)
}
else
{
- err = vkAcquireNextImageKHR(vk.device, vk.swapchain, 0, VK_NULL_HANDLE, vk.acquirefences[vk.aquirelast%ACQUIRELIMIT], &vk.acquirebufferidx[vk.aquirelast%ACQUIRELIMIT]);
+ err = vkAcquireNextImageKHR(vk.device, vk.swapchain, 0, vk.acquiresemaphores[vk.aquirelast%ACQUIRELIMIT], vk.acquirefences[vk.aquirelast%ACQUIRELIMIT], &vk.acquirebufferidx[vk.aquirelast%ACQUIRELIMIT]);
if (err)
{
Con_Printf("ERROR: vkAcquireNextImageKHR: %x\n", err);
diff --git a/engine/vk/vkrenderer.h b/engine/vk/vkrenderer.h
index a531c96e4..3fccf50b3 100644
--- a/engine/vk/vkrenderer.h
+++ b/engine/vk/vkrenderer.h
@@ -208,6 +208,7 @@ enum dynbuf_e
};
struct vk_rendertarg
{
+
VkCommandBuffer cbuf; //cbuf allocated for this render target.
VkFramebuffer framebuffer;
vk_image_t colour, depth, mscolour;
@@ -265,6 +266,7 @@ extern struct vulkaninfo_s
VkPhysicalDeviceLimits limits;
#define ACQUIRELIMIT 8
+ VkSemaphore acquiresemaphores[ACQUIRELIMIT];
VkFence acquirefences[ACQUIRELIMIT];
uint32_t acquirebufferidx[ACQUIRELIMIT];
unsigned int aquirenext;
@@ -315,6 +317,7 @@ extern struct vulkaninfo_s
struct vkframe *next;
struct dynbuffer *dynbufs[DB_MAX];
struct descpool *descpools;
+ VkSemaphore acquiresemaphore;
VkCommandBuffer *cbufs;
size_t numcbufs;
size_t maxcbufs;