From aeea639fc2d7a2818c381be48c876c8561a4a60c Mon Sep 17 00:00:00 2001 From: Spoike Date: Sat, 11 Mar 2006 03:12:10 +0000 Subject: [PATCH] Filename security paranoia. Added a glsl extension to the shader system. using serverinfo, you can enable shaders without cheats now. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@2079 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/client/cl_demo.c | 10 +- engine/client/cl_main.c | 11 ++ engine/client/cl_parse.c | 4 +- engine/client/cl_screen.c | 4 +- engine/client/fragstats.c | 2 +- engine/client/image.c | 6 +- engine/client/m_items.c | 2 +- engine/client/m_mp3.c | 54 ++++--- engine/client/merged.h | 2 +- engine/client/r_part.c | 2 +- engine/client/renderer.c | 2 +- engine/client/skin.c | 9 +- engine/client/snd_dma.c | 4 +- engine/client/sys_linux.c | 15 +- engine/client/zqtp.c | 4 +- engine/common/cmd.c | 8 +- engine/common/common.c | 18 ++- engine/common/common.h | 6 +- engine/common/fs.c | 29 ++-- engine/common/gl_q2bsp.c | 2 +- engine/gl/gl_alias.c | 32 ++-- engine/gl/gl_backend.c | 249 ++++++++++++++++++++---------- engine/gl/gl_model.c | 44 +++--- engine/gl/gl_ppl.c | 9 ++ engine/gl/gl_rmisc.c | 4 +- engine/gl/gl_shader.c | 317 ++++++++++++++++++++++++++++++-------- engine/gl/gl_vidcommon.c | 2 + engine/gl/glquake.h | 1 + engine/gl/shader.h | 30 +++- engine/http/ftpclient.c | 9 +- engine/makeconfig.sh | 9 +- engine/server/pr_cmds.c | 2 +- engine/server/savegame.c | 4 +- engine/server/sv_ccmds.c | 2 +- engine/server/sv_init.c | 31 ++-- engine/server/sv_mvd.c | 6 +- 36 files changed, 647 insertions(+), 298 deletions(-) diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index 540e000bc..a67ea2d15 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -770,7 +770,7 @@ void CL_Record_f (void) f = FS_OpenVFS (name, "rb", FS_GAME); if (f) { - COM_StripExtension(name, name); + COM_StripExtension(name, name, sizeof(name)); p = name + strlen(name); strcat(p, "_XX.qwd"); p++; @@ -1106,7 +1106,7 @@ void CL_ReRecord_f (void) // // open the demo file // - COM_DefaultExtension (name, ".qwd"); + COM_DefaultExtension (name, ".qwd", sizeof(name)); cls.demofile = FS_OpenVFS (name, "wb", FS_GAME); if (!cls.demofile) @@ -1181,18 +1181,18 @@ void CL_PlayDemo(char *demoname) // open the demo file // Q_strncpyz (name, demoname, sizeof(name)); - COM_DefaultExtension (name, ".qwd"); + COM_DefaultExtension (name, ".qwd", sizeof(name)); cls.demofile = FS_OpenVFS(name, "rb", FS_GAME); if (!cls.demofile) { Q_strncpyz (name, demoname, sizeof(name)); - COM_DefaultExtension (name, ".dem"); + COM_DefaultExtension (name, ".dem", sizeof(name)); cls.demofile = FS_OpenVFS(name, "rb", FS_GAME); } if (!cls.demofile) { Q_strncpyz (name, demoname, sizeof(name)); - COM_DefaultExtension (name, ".mvd"); + COM_DefaultExtension (name, ".mvd", sizeof(name)); cls.demofile = FS_OpenVFS(name, "rb", FS_GAME); } if (!cls.demofile) diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index d85ab2068..59d315848 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -1293,6 +1293,9 @@ void CL_CheckServerInfo(void) char *s; unsigned int allowed; int oldstate; + qboolean oldallowshaders; + + oldallowshaders = cls.allow_shaders; cl.teamplay = atoi(Info_ValueForKey(cl.serverinfo, "teamplay")); cl.deathmatch = atoi(Info_ValueForKey(cl.serverinfo, "deathmatch")); @@ -1357,6 +1360,11 @@ void CL_CheckServerInfo(void) cls.allow_cheats = false; } + cls.allow_shaders = cls.allow_cheats; + + if (cls.demoplayback || atoi(Info_ValueForKey(cl.serverinfo, "allow_shaders"))) + cls.allow_shaders=true; + cls.maxfps = atof(Info_ValueForKey(cl.serverinfo, "maxfps")); if (cls.maxfps < 20) @@ -1425,6 +1433,9 @@ void CL_CheckServerInfo(void) Cvar_ForceCheatVars(cls.allow_semicheats, cls.allow_cheats); + + if (oldallowshaders != cls.allow_shaders) + Cache_Flush(); //this will cause all models to be reloaded. } /* ================== diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 0d55a613c..12f0ef74d 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -328,7 +328,7 @@ void CL_SendDownloadRequest(char *filename, char *localname) // download to a temp name, and only rename // to the real name when done, so if interrupted // a runt file wont be left - COM_StripExtension (localname, cls.downloadtempname); + COM_StripExtension (localname, cls.downloadtempname, sizeof(cls.downloadtempname)-5); strcat (cls.downloadtempname, ".tmp"); CL_SendClientCommand(true, "download %s", filename); @@ -2640,7 +2640,7 @@ void CL_NewTranslation (int slot) player = &cl.players[slot]; s = Skin_FindName (player); - COM_StripExtension(s, s); + COM_StripExtension(s, s, MAX_QPATH); if (player->skin && !stricmp(s, player->skin->name)) player->skin = NULL; diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index fcb6ce2d2..b3c2b87c8 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -1407,7 +1407,7 @@ void SCR_EndLoadingPlaque (void) void SCR_ImageName (char *mapname) { strcpy(levelshotname, "levelshots/"); - COM_FileBase(mapname, levelshotname + strlen(levelshotname)); + COM_FileBase(mapname, levelshotname + strlen(levelshotname), sizeof(levelshotname)-strlen(levelshotname)); #ifdef RGLQUAKE if (qrenderer == QR_OPENGL) @@ -1709,7 +1709,7 @@ void SCR_ScreenShot_f (void) Con_Printf("Screenshot name refused\n"); return; } - COM_DefaultExtension (pcxname, scr_sshot_type.string); + COM_DefaultExtension (pcxname, scr_sshot_type.string, sizeof(pcxname)); } else { diff --git a/engine/client/fragstats.c b/engine/client/fragstats.c index 1e41abe8f..6995ea4db 100644 --- a/engine/client/fragstats.c +++ b/engine/client/fragstats.c @@ -307,7 +307,7 @@ static void Stats_LoadFragFile(char *name) Stats_Clear(); strcpy(filename, name); - COM_DefaultExtension(filename, ".dat"); + COM_DefaultExtension(filename, ".dat", sizeof(filename)); file = COM_LoadTempFile(filename); if (!file || !*file) diff --git a/engine/client/image.c b/engine/client/image.c index 4692f20fe..d11b43e85 100644 --- a/engine/client/image.c +++ b/engine/client/image.c @@ -1912,7 +1912,7 @@ int Mod_LoadHiResTexture(char *name, char *subpath, qboolean mipmap, qboolean al int i, e; - COM_StripExtension(name, nicename); + COM_StripExtension(name, nicename, sizeof(nicename)); while((data = strchr(nicename, '*'))) { @@ -2036,7 +2036,7 @@ int Mod_LoadBumpmapTexture(char *name, char *subpath) TRACE(("dbg: Mod_LoadBumpmapTexture: texture %s\n", name)); - COM_StripExtension(name, nicename); + COM_StripExtension(name, nicename, sizeof(nicename)); if ((len = GL_FindTexture(name))!=-1) //don't bother if it already exists. return len; @@ -2062,7 +2062,7 @@ int Mod_LoadBumpmapTexture(char *name, char *subpath) Q_strncpyz(map, sv.name, sizeof(map)); else #endif - COM_FileBase(cl.model_name[1], map); + COM_FileBase(cl.model_name[1], map, sizeof(map)); snprintf(fname, sizeof(fname)-1, path[i], map, nicename, extensions[e]); } else diff --git a/engine/client/m_items.c b/engine/client/m_items.c index d6a1933cf..d836a4095 100644 --- a/engine/client/m_items.c +++ b/engine/client/m_items.c @@ -238,7 +238,7 @@ void MenuDrawItems(int xpos, int ypos, menuoption_t *option, menu_t *menu) { char selname[MAX_QPATH]; Q_strncpyz(selname, option->picture.picturename, sizeof(selname)); - COM_StripExtension(selname, selname); + COM_StripExtension(selname, selname, sizeof(selname)); p = Draw_SafeCachePic(va("%s_sel", selname)); } diff --git a/engine/client/m_mp3.c b/engine/client/m_mp3.c index 316ecd9f6..5eb8b3183 100644 --- a/engine/client/m_mp3.c +++ b/engine/client/m_mp3.c @@ -859,6 +859,7 @@ struct cin_s { float filmstarttime; float nextframetime; + float filmlasttime; int currentframe; //last frame in buffer qbyte *framedata; //Z_Malloced buffer @@ -1132,14 +1133,19 @@ cin_t *Media_StartCin(char *name) return NULL; } -qboolean Media_DecodeFrame(cin_t *cin) +qboolean Media_DecodeFrame(cin_t *cin, qboolean nosound) { float curtime = Sys_DoubleTime(); switch (cin->filmtype) { case MFT_ROQ: - if (curtimenextframetime || roq_read_frame(cin->roq.roqfilm)==1) //0 if end, -1 if error, 1 if success + if ((int)(cin->filmlasttime*30) == (int)((float)realtime*30)) + { + cin->outunchanged = !!cin->outtype; + return true; + } + else if (curtimenextframetime || roq_read_frame(cin->roq.roqfilm)==1) //0 if end, -1 if error, 1 if success { //#define LIMIT(x) ((x)<0xFFFF)?(x)>>16:0xFF; #define LIMIT(x) ((((x) > 0xffffff) ? 0xff0000 : (((x) <= 0xffff) ? 0 : (x) & 0xff0000)) >> 16) @@ -1153,6 +1159,9 @@ qboolean Media_DecodeFrame(cin_t *cin) int x; qbyte *framedata; + + cin->filmlasttime = (float)realtime; + if (!(curtimenextframetime)) //roq file was read properly { cin->nextframetime += 1/30.0; //add a little bit of extra speed so we cover up a little bit of glitchy sound... :o) @@ -1197,11 +1206,6 @@ qboolean Media_DecodeFrame(cin_t *cin) if(y & 0x01) { pb += num_columns; pc += num_columns; } } } - else if (vid.numpages == 1) //previous frame is still in page. - { - cin->outunchanged = true; - return true; - } cin->outunchanged = false; cin->outtype = 1; @@ -1209,6 +1213,7 @@ qboolean Media_DecodeFrame(cin_t *cin) cin->outheight = cin->roq.roqfilm->height; cin->outdata = cin->framedata; + if (!nosound) if (cin->roq.roqfilm->audio_channels && sndcardinfo && cin->roq.roqfilm->aud_pos < cin->roq.roqfilm->vid_pos) if (roq_read_audio(cin->roq.roqfilm)>0) { @@ -1349,7 +1354,7 @@ qboolean Media_ShowFilm(void) { if (!fullscreenvid) return false; - if (!Media_DecodeFrame(fullscreenvid)) + if (!Media_DecodeFrame(fullscreenvid, false)) { Media_ShutdownCin(fullscreenvid); fullscreenvid = NULL; @@ -1377,27 +1382,30 @@ int Media_UpdateForShader(int texnum, cin_t *cin) { if (!cin) return 0; - if (!Media_DecodeFrame(cin)) + if (!Media_DecodeFrame(cin, true)) { return 0; } - GL_Bind(100); - switch(cin->outtype) + if (!cin->outunchanged) { - case 1: - GL_Upload32("cin", (unsigned int*)cin->outdata, cin->outwidth, cin->outheight, false, false); - break; - case 2: - GL_Upload8("cin", cin->outdata, cin->outwidth, cin->outheight, false, false); - break; - case 3: - GL_Upload24BGR_Flip ("cin", cin->outdata, cin->outwidth, cin->outheight, false, false); - break; + GL_Bind(texnum); + switch(cin->outtype) + { + case 1: + GL_Upload32("cin", (unsigned int*)cin->outdata, cin->outwidth, cin->outheight, false, false); + break; + case 2: + GL_Upload8("cin", cin->outdata, cin->outwidth, cin->outheight, false, false); + break; + case 3: + GL_Upload24BGR_Flip ("cin", cin->outdata, cin->outwidth, cin->outheight, false, false); + break; + } } - return 100; + return texnum; } #endif @@ -1691,8 +1699,8 @@ void Media_RecordFilm_f (void) if (capturetype == CT_AVI) { snprintf(filename, 192, "%s%s", com_gamedir, Cmd_Argv(1)); - COM_StripExtension(filename, filename); - COM_DefaultExtension (filename, ".avi"); + COM_StripExtension(filename, filename, sizeof(filename)); + COM_DefaultExtension (filename, ".avi", sizeof(filename)); //wipe it. f = fopen(filename, "rb"); diff --git a/engine/client/merged.h b/engine/client/merged.h index c63337d56..c5e6da039 100644 --- a/engine/client/merged.h +++ b/engine/client/merged.h @@ -34,7 +34,7 @@ extern void (*Draw_ConsoleBackground) (int lines); extern void (*Draw_EditorBackground) (int lines); extern void (*Draw_TileClear) (int x, int y, int w, int h); extern void (*Draw_Fill) (int x, int y, int w, int h, int c); -extern void (*Draw_FillRGB) (int x, int y, int w, int h, float r, float g, float b); +extern void (*Draw_FillRGB) (int x, int y, int w, int h, float r, float g, float b); extern void (*Draw_FadeScreen) (void); extern void (*Draw_BeginDisc) (void); extern void (*Draw_EndDisc) (void); diff --git a/engine/client/r_part.c b/engine/client/r_part.c index 17d4406b1..20eca41c9 100644 --- a/engine/client/r_part.c +++ b/engine/client/r_part.c @@ -1596,7 +1596,7 @@ void P_ReadPointFile_f (void) char line[1024]; char *s; - COM_StripExtension(cl.worldmodel->name, name); + COM_StripExtension(cl.worldmodel->name, name, sizeof(name)); strcat(name, ".pts"); f = FS_OpenVFS(name, "rb", FS_GAME); diff --git a/engine/client/renderer.c b/engine/client/renderer.c index c2e555beb..8ee202d32 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -180,7 +180,7 @@ cvar_t scr_chatmodecvar = SCVAR("scr_chatmode", "0"); cvar_t gl_shadeq3 = SCVARF("gl_shadeq3", "1", CVAR_SEMICHEAT); //use if you want. cvar_t gl_shadeq2 = SCVARF("gl_shadeq2", "0", CVAR_SEMICHEAT); //use if you want. extern cvar_t r_vertexlight; -cvar_t gl_shadeq1 = SCVARF("gl_shadeq1", "0", CVAR_CHEAT); //FIXME: :( +cvar_t gl_shadeq1 = SCVARF("gl_shadeq1", "0", CVAR_SEMICHEAT); cvar_t gl_shadeq1_name = SCVAR("gl_shadeq1_name", "*"); #endif diff --git a/engine/client/skin.c b/engine/client/skin.c index ede48300d..9003bf3e4 100644 --- a/engine/client/skin.c +++ b/engine/client/skin.c @@ -138,12 +138,13 @@ void Skin_Find (player_info_t *sc) if (*mn) { mn = va("%s/%s", mn, s); - COM_StripExtension (mn, name); + COM_StripExtension (mn, name, sizeof(name)); } else - - s = Skin_FindName(sc); - COM_StripExtension (s, name); + { + s = Skin_FindName(sc); + COM_StripExtension (s, name, sizeof(name)); + } s = strchr(name, '/'); if (s) diff --git a/engine/client/snd_dma.c b/engine/client/snd_dma.c index 903c3ce66..8981cbcea 100644 --- a/engine/client/snd_dma.c +++ b/engine/client/snd_dma.c @@ -1599,7 +1599,7 @@ void S_RawAudio(int sourceid, qbyte *data, int speed, int samples, int channels, spare = s->sfxcache->length; if (spare > snd_speed) { - Con_Printf("Sacrificed raw sound stream\n"); + Con_DPrintf("Sacrificed raw sound stream\n"); spare = 0; //too far out. sacrifice it all } } @@ -1611,7 +1611,7 @@ void S_RawAudio(int sourceid, qbyte *data, int speed, int samples, int channels, if (s->sfxcache->length > snd_speed*2) // more than 2 seconds of sound { - Con_Printf("Sacrificed raw sound stream\n"); + Con_DPrintf("Sacrificed raw sound stream\n"); spare = 0; //too far out. sacrifice it all } } diff --git a/engine/client/sys_linux.c b/engine/client/sys_linux.c index a0cdf9813..a87c880b8 100644 --- a/engine/client/sys_linux.c +++ b/engine/client/sys_linux.c @@ -478,13 +478,18 @@ void Sys_ServerActivity(void) -char *Sys_GetClipboard(void) -{ - return NULL; + +#define SYS_CLIPBOARD_SIZE 256 +static char clipboard_buffer[SYS_CLIPBOARD_SIZE] = {0}; + +char *Sys_GetClipboard(void) { + return clipboard_buffer; } + void Sys_CloseClipboard(char *bf) { } -void Sys_SaveClipboard(char *text) -{ + +void Sys_SaveClipboard(char *text) { + Q_strncpyz(clipboard_buffer, text, SYS_CLIPBOARD_SIZE); } diff --git a/engine/client/zqtp.c b/engine/client/zqtp.c index c20afa0ad..090d18442 100644 --- a/engine/client/zqtp.c +++ b/engine/client/zqtp.c @@ -1438,7 +1438,7 @@ static void TP_LoadLocFile (char *filename, qbool quiet) return; Q_snprintfz (fullpath, sizeof(fullpath) - 4, "locs/%s", filename); - COM_DefaultExtension (fullpath, ".loc"); + COM_DefaultExtension (fullpath, ".loc", sizeof(fullpath)); buf = (char *) COM_LoadTempFile (fullpath); if (!buf) { @@ -3005,7 +3005,7 @@ qbool TP_CheckSoundTrigger (char *str) if (!snd_initialized) return false; - COM_DefaultExtension (soundname, ".wav"); + COM_DefaultExtension (soundname, ".wav", sizeof(soundname)); // make sure we have it on disk (FIXME) if (!FS_FLocateFile (va("sound/%s", soundname), FSLFRT_IFFOUND, NULL)) diff --git a/engine/common/cmd.c b/engine/common/cmd.c index aab7ae6d8..bca8e6ecc 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -499,7 +499,7 @@ void Cmd_Exec_f (void) if (!*f) f = "fte"; snprintf(name, sizeof(name)-5, "configs/%s", f); - COM_DefaultExtension(name, ".cfg"); + COM_DefaultExtension(name, ".cfg", sizeof(name)); } else Q_strncpyz(name, Cmd_Argv(1), sizeof(name)); @@ -2719,6 +2719,7 @@ void Cmd_WriteConfig_f(void) { vfsfile_t *f; char *filename; + char fname[MAX_OSPATH]; filename = Cmd_Argv(1); if (!*filename) @@ -2733,7 +2734,8 @@ void Cmd_WriteConfig_f(void) filename = va("configs/%s.cfg",filename); } - COM_DefaultExtension(filename, ".cfg"); + Q_strncpyz(fname, filename, sizeof(fname)); + COM_DefaultExtension(fname, ".cfg", sizeof(fname)); FS_CreatePath(filename, FS_CONFIGONLY); f = FS_OpenVFS(filename, "wb", FS_CONFIGONLY); if (!f) @@ -2786,7 +2788,7 @@ void Cmd_Condump_f(void) filename = "condump"; filename = va("%s", filename); - COM_DefaultExtension(filename, ".txt"); + COM_DefaultExtension(filename, ".txt", MAX_QPATH); f = FS_OpenVFS (filename, "wb", FS_GAME); if (!f) diff --git a/engine/common/common.c b/engine/common/common.c index 8273438a2..df78ccfc4 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -1371,11 +1371,12 @@ char *COM_SkipPath (char *pathname) COM_StripExtension ============ */ -void COM_StripExtension (char *in, char *out) +void COM_StripExtension (char *in, char *out, int outlen) { char *s; - strcpy(out, in); + if (out != in) + Q_strncpyz(out, in, outlen); s = out+strlen(out); @@ -1467,7 +1468,7 @@ void COM_CleanUpPath(char *str) COM_FileBase ============ */ -void COM_FileBase (char *in, char *out) +void COM_FileBase (char *in, char *out, int outlen) { char *s, *s2; @@ -1487,8 +1488,11 @@ void COM_FileBase (char *in, char *out) else { s--; - Q_strncpyS (out,s2+1, s-s2); - out[s-s2] = 0; + outlen--; + if (outlen > s-s2) + outlen = s-s2; + Q_strncpyS (out,s2+1, outlen); + out[outlen] = 0; } } @@ -1498,7 +1502,7 @@ void COM_FileBase (char *in, char *out) COM_DefaultExtension ================== */ -void COM_DefaultExtension (char *path, char *extension) +void COM_DefaultExtension (char *path, char *extension, int maxlen) { char *src; // @@ -1514,7 +1518,7 @@ void COM_DefaultExtension (char *path, char *extension) src--; } - strcat (path, extension); + Q_strncatz (path, extension, maxlen); } //============================================================================ diff --git a/engine/common/common.h b/engine/common/common.h index 9f9a9f50f..e1043681b 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -249,9 +249,9 @@ void COM_InitArgv (int argc, char **argv); void COM_ParsePlusSets (void); char *COM_SkipPath (char *pathname); -void COM_StripExtension (char *in, char *out); -void COM_FileBase (char *in, char *out); -void COM_DefaultExtension (char *path, char *extension); +void COM_StripExtension (char *in, char *out, int outlen); +void COM_FileBase (char *in, char *out, int outlen); +void COM_DefaultExtension (char *path, char *extension, int maxlen); char *COM_FileExtension (char *in); void COM_CleanUpPath(char *str); diff --git a/engine/common/fs.c b/engine/common/fs.c index 376f44b33..2e7c8596b 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -1252,29 +1252,18 @@ The filename will be prefixed by the current game directory */ void COM_WriteFile (char *filename, void *data, int len) { - FILE *f; - char name[MAX_OSPATH]; + vfsfile_t *vfs; - sprintf (name, "%s/%s", com_gamedir, filename); + Sys_Printf ("COM_WriteFile: %s\n", filename); - COM_CreatePath(name); - - f = fopen (name, "wb"); - if (!f) + FS_CreatePath(filename, FS_GAMEONLY); + vfs = FS_OpenVFS(filename, "wb", FS_GAMEONLY); + if (vfs) { - Sys_mkdir(com_gamedir); - f = fopen (name, "wb"); - if (!f) - { - Con_Printf("Error opening %s for writing\n", filename); - return; - } + VFS_WRITE(vfs, data, len); + VFS_CLOSE(vfs); } - Sys_Printf ("COM_WriteFile: %s\n", name); - fwrite (data, 1, len, f); - fclose (f); - com_fschanged=true; } @@ -1997,7 +1986,7 @@ void FS_CreatePath(char *pname, int relativeto) { case FS_GAMEONLY: case FS_GAME: - snprintf(fullname, sizeof(fullname), "%s%s", com_gamedir, pname); + snprintf(fullname, sizeof(fullname), "%s/%s", com_gamedir, pname); break; case FS_BASE: if (*com_homedir) @@ -2069,7 +2058,7 @@ qbyte *COM_LoadFile (char *path, int usehunk) com_filesize = len = VFS_GETLEN(f); // extract the filename base name for hunk tag - COM_FileBase (path, base); + COM_FileBase (path, base, sizeof(base)); if (usehunk == 0) buf = (qbyte*)Z_Malloc (len+1); diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index 3e620eca2..fc99f8ec0 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -992,7 +992,7 @@ void *Mod_LoadWall(char *name) int width, height; char ln[32]; - COM_FileBase(name, ln); + COM_FileBase(name, ln, sizeof(ln)); wal = (void *)COM_LoadMallocFile (name); if (!wal) diff --git a/engine/gl/gl_alias.c b/engine/gl/gl_alias.c index c2a5b8fb0..0934e71d3 100644 --- a/engine/gl/gl_alias.c +++ b/engine/gl/gl_alias.c @@ -2826,7 +2826,7 @@ int GL_BuildSkinFileList(char *modelname) } skinfilecount=0; - COM_StripExtension(modelname, skinfilename); + COM_StripExtension(modelname, skinfilename, sizeof(skinfilename)); //try and add numbered skins, and then try fixed names. for (i = 0; ; i++) @@ -3205,12 +3205,15 @@ static void *Q1_LoadSkins (daliasskintype_t *pskintype, qboolean alpha) outskin->texnums=1; outskin->ofstexnums = (char *)texnums - (char *)outskin; -/* + #ifdef Q3SHADERS - sprintf(skinname, "%s_%i", loadname, i); - texnums->shader = R_RegisterSkin(skinname); + if (cls.allow_shaders) + { + sprintf(skinname, "%s_%i", loadname, i); + texnums->shader = R_RegisterCustom (skinname, NULL); + } #endif -*/ + texnums->base = texture; texnums->fullbright = fbtexture; @@ -3290,12 +3293,15 @@ static void *Q1_LoadSkins (daliasskintype_t *pskintype, qboolean alpha) if (t != 0) //only keep the first. BZ_Free(saved); } -/* + #ifdef Q3SHADERS - sprintf(skinname, "%s_%i_%i", loadname, i, t); - texnums->shader = R_RegisterSkin(skinname); + if (cls.allow_shaders) + { + sprintf(skinname, "%s_%i_%i", loadname, i, t); + texnums->shader = R_RegisterCustom (skinname, NULL); + } #endif -*/ + texnums->base = texture; texnums->fullbright = fbtexture; } @@ -3471,13 +3477,13 @@ int Mod_ReadFlagsFromMD1(char *name, int md3version) { dmdl_t *pinmodel; char fname[MAX_QPATH]; - COM_StripExtension(name, fname); - COM_DefaultExtension(fname, ".mdl"); + COM_StripExtension(name, fname, sizeof(fname)); + COM_DefaultExtension(fname, ".mdl", sizeof(fname)); if (strcmp(name, fname)) //md3 renamed as mdl { - COM_StripExtension(name, fname); //seeing as the md3 is named over the mdl, - COM_DefaultExtension(fname, ".md1");//read from a file with md1 (one, not an ell) + COM_StripExtension(name, fname, sizeof(fname)); //seeing as the md3 is named over the mdl, + COM_DefaultExtension(fname, ".md1", sizeof(fname));//read from a file with md1 (one, not an ell) return 0; } diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index 89ac33516..b506cf3cb 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -276,6 +276,97 @@ int r_backendStart; int r_dlighttexture; + extern qbyte *host_basepal; + extern qboolean gammaworks; + extern qbyte gammatable[256]; + +void R_FetchTopColour(int *retred, int *retgreen, int *retblue) +{ + int i; + if (currententity->scoreboard) + { + i = currententity->scoreboard->topcolor; + //colour forcing + if (cl.splitclients<2 && !(cl.fpd & FPD_NO_FORCE_COLOR)) //no colour/skin forcing in splitscreen. + { + if (cl.teamplay && !strcmp(currententity->scoreboard->team, cl.players[cl.playernum[0]].team)) + { + if (cl_teamtopcolor>=0) + i = cl_teamtopcolor; + } + else + { + if (cl_enemytopcolor>=0) + i = cl_enemytopcolor; + } + } + } + else + i = TOP_RANGE>>4; + if (i > 8) + { + i<<=4; + } + else + { + i<<=4; + i+=15; + } + i*=3; + *retred = host_basepal[i+0]; + *retgreen = host_basepal[i+1]; + *retblue = host_basepal[i+2]; + if (!gammaworks) + { + *retred = gammatable[*retred]; + *retgreen = gammatable[*retgreen]; + *retblue = gammatable[*retblue]; + } +} +void R_FetchBottomColour(int *retred, int *retgreen, int *retblue) +{ + int i; + if (currententity->scoreboard) + { + i = currententity->scoreboard->bottomcolor; + //colour forcing + if (cl.splitclients<2 && !(cl.fpd & FPD_NO_FORCE_COLOR)) //no colour/skin forcing in splitscreen. + { + if (cl.teamplay && !strcmp(currententity->scoreboard->team, cl.players[cl.playernum[0]].team)) + { + if (cl_teambottomcolor>=0) + i = cl_teambottomcolor; + } + else + { + if (cl_enemybottomcolor>=0) + i = cl_enemybottomcolor; + } + } + } + else + i = BOTTOM_RANGE>>4; + if (i > 8) + { + i<<=4; + } + else + { + i<<=4; + i+=15; + } + i*=3; + *retred = host_basepal[i+0]; + *retgreen = host_basepal[i+1]; + *retblue = host_basepal[i+2]; + if (!gammaworks) + { + *retred = gammatable[*retred]; + *retgreen = gammatable[*retgreen]; + *retblue = gammatable[*retblue]; + } +} + void R_InitDynamicLightTexture (void) { int x, y; @@ -1335,10 +1426,7 @@ R_ModifyColor */ void R_ModifyColor ( meshbuffer_t *mb, shaderpass_t *pass ) { - extern qbyte *host_basepal; - extern qboolean gammaworks; - extern qbyte gammatable[256]; - + int i, b; float *table, c, a; vec3_t t, v; @@ -1420,45 +1508,7 @@ void R_ModifyColor ( meshbuffer_t *mb, shaderpass_t *pass ) case RGB_GEN_TOPCOLOR: //multiply vertex by topcolor (for player models) { int rc, gc, bc; - if (currententity->scoreboard) - { - i = currententity->scoreboard->topcolor; - //colour forcing - if (cl.splitclients<2 && !(cl.fpd & FPD_NO_FORCE_COLOR)) //no colour/skin forcing in splitscreen. - { - if (cl.teamplay && !strcmp(currententity->scoreboard->team, cl.players[cl.playernum[0]].team)) - { - if (cl_teamtopcolor>=0) - i = cl_teamtopcolor; - } - else - { - if (cl_enemytopcolor>=0) - i = cl_enemytopcolor; - } - } - } - else - i = TOP_RANGE>>4; - if (i > 8) - { - i<<=4; - } - else - { - i<<=4; - i+=15; - } - i*=3; - rc = host_basepal[i+0]; - gc = host_basepal[i+1]; - bc = host_basepal[i+2]; - if (!gammaworks) - { - rc = gammatable[rc]; - gc = gammatable[gc]; - bc = gammatable[bc]; - } + R_FetchTopColour(&rc, &gc, &bc); for ( i = 0; i < numColors; i++, bArray += 4, vArray += 4 ) { bArray[0] = (vArray[0]*rc)>>8; bArray[1] = (vArray[1]*gc)>>8; @@ -1470,45 +1520,7 @@ void R_ModifyColor ( meshbuffer_t *mb, shaderpass_t *pass ) case RGB_GEN_BOTTOMCOLOR: //multiply vertex by bottomcolor (for player models) { int rc, gc, bc; - if (currententity->scoreboard) - { - i = currententity->scoreboard->bottomcolor; - //colour forcing - if (cl.splitclients<2 && !(cl.fpd & FPD_NO_FORCE_COLOR)) //no colour/skin forcing in splitscreen. - { - if (cl.teamplay && !strcmp(currententity->scoreboard->team, cl.players[cl.playernum[0]].team)) - { - if (cl_teambottomcolor>=0) - i = cl_teambottomcolor; - } - else - { - if (cl_enemybottomcolor>=0) - i = cl_enemybottomcolor; - } - } - } - else - i = BOTTOM_RANGE>>4; - if (i > 8) - { - i<<=4; - } - else - { - i<<=4; - i+=15; - } - i*=3; - rc = host_basepal[i+0]; - gc = host_basepal[i+1]; - bc = host_basepal[i+2]; - if (!gammaworks) - { - rc = gammatable[rc]; - gc = gammatable[gc]; - bc = gammatable[bc]; - } + R_FetchBottomColour(&rc, &gc, &bc); for ( i = 0; i < numColors; i++, bArray += 4, vArray += 4 ) { bArray[0] = (vArray[0]*rc)>>8; bArray[1] = (vArray[1]*gc)>>8; @@ -2055,6 +2067,69 @@ void R_RenderMeshCombined ( meshbuffer_t *mb, shaderpass_t *pass ) R_FlushArraysMtex (); } +void R_RenderMeshProgram ( meshbuffer_t *mb, shaderpass_t *pass ) +{ + shader_t *s; + int i; + vec3_t param3; + int r, g, b; + + r_numUnits = pass->numMergedPasses; + + R_SetShaderpassState ( pass, true ); + R_ModifyColor ( mb, pass ); + + GL_SelectTexture( mtexid0 ); + if ( pass->blendmode == GL_REPLACE ) + GL_TexEnv( GL_REPLACE ); + else + GL_TexEnv( GL_MODULATE ); + R_ModifyTextureCoords ( pass, 0 ); + + for ( i = 1, pass++; i < r_numUnits; i++, pass++ ) + { + GL_SelectTexture( mtexid0 + i ); + + R_ModifyTextureCoords ( pass, i ); + } + + s = mb->shader; + GLSlang_UseProgram(s->programhandle); + for (i = 0; i < s->numprogparams; i++) + { + switch(s->progparm[i].type) + { + case SP_TIME: + qglUniform1fARB(s->progparm[i].handle, r_localShaderTime); + break; + + case SP_ENTCOLOURS: + qglUniform4fvARB(s->progparm[i].handle, 1, currententity->shaderRGBAf); + break; + case SP_TOPCOLOURS: + R_FetchTopColour(&r, &g, &b); + param3[0] = r/255; + param3[1] = g/255; + param3[2] = b/255; + qglUniform3fvARB(s->progparm[i].handle, 1, param3); + break; + case SP_BOTTOMCOLOURS: + R_FetchBottomColour(&r, &g, &b); + param3[0] = r/255; + param3[1] = g/255; + param3[2] = b/255; + qglUniform3fvARB(s->progparm[i].handle, 1, param3); + break; + + default: + Host_EndGame("Bad shader program parameter type (%i)", s->progparm[i].type); + break; + } + } + R_FlushArraysMtex (); + GLSlang_UseProgram(0); +} + /* ================ R_RenderMeshBuffer @@ -2398,7 +2473,11 @@ void R_FinishMeshBuffer ( meshbuffer_t *mb ) qboolean dlight; shader = mb->shader; - dlight = (mb->dlightbits != 0) && !(shader->flags & SHADER_FLARE); + if ((mb->dlightbits != 0) && !(shader->flags & SHADER_FLARE)) + dlight = (currententity->model->type == mod_brush && currententity->model->fromgame == fg_quake3); + else + dlight = false; + fogged = mb->fog && ((shader->sort < SHADER_SORT_UNDERWATER && (shader->flags & (SHADER_DEPTHWRITE|SHADER_SKY))) || shader->fog_dist); @@ -2410,7 +2489,7 @@ void R_FinishMeshBuffer ( meshbuffer_t *mb ) qglDisable ( GL_ALPHA_TEST ); qglDepthMask ( GL_FALSE ); - if (dlight && (currententity->model->type == mod_brush && currententity->model->fromgame == fg_quake3)) //HACK: the extra check is because we play with the lightmaps in q1/q2 + if (dlight) //HACK: the extra check is because we play with the lightmaps in q1/q2 { R_AddDynamicLights ( mb ); } @@ -2419,6 +2498,8 @@ void R_FinishMeshBuffer ( meshbuffer_t *mb ) { R_RenderFogOnMesh ( shader, mb->fog ); } + + qglDepthMask ( GL_TRUE ); } if ( r_showtris.value || r_shownormals.value ) { diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index 7a575c1e5..0d8b66ab8 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -336,15 +336,15 @@ void GLMod_Think (void) if (lightmodel->deluxdata) { - COM_StripExtension(lightmodel->name, filename); - COM_DefaultExtension(filename, ".lux"); + COM_StripExtension(lightmodel->name, filename, sizeof(filename)); + COM_DefaultExtension(filename, ".lux", sizeof(filename)); FS_WriteFile(filename, lightmodel->deluxdata-8, numlightdata*3+8, FS_GAME); } if (writelitfile) //the user might already have a lit file (don't overwrite it). { - COM_StripExtension(lightmodel->name, filename); - COM_DefaultExtension(filename, ".lit"); + COM_StripExtension(lightmodel->name, filename, sizeof(filename)); + COM_DefaultExtension(filename, ".lit", sizeof(filename)); FS_WriteFile(filename, lightmodel->lightdata-8, numlightdata*3+8, FS_GAME); } } @@ -459,7 +459,7 @@ model_t *GLMod_LoadModel (model_t *mod, qboolean crash) if (Q_strcasecmp(ext, "spr") && Q_strcasecmp(ext, "sp2")) { char mdlbase[MAX_QPATH]; - COM_StripExtension(mod->name, mdlbase); + COM_StripExtension(mod->name, mdlbase, sizeof(mdlbase)); #ifdef MD3MODELS if (!buf) buf = (unsigned *)COM_LoadStackFile (va("%s.md3", mdlbase), stackbuf, sizeof(stackbuf)); @@ -507,7 +507,7 @@ couldntload: // // allocate a new model // - COM_FileBase (mod->name, loadname); + COM_FileBase (mod->name, loadname, sizeof(loadname)); Validation_IncludeFile(mod->name, (char *)buf, com_filesize); // @@ -1009,21 +1009,21 @@ TRACE(("dbg: GLMod_LoadTextures: inittexturedescs\n")); } } #ifdef Q3SHADERS //load q3 syntax shader last, after the textures inside the bsp have been loaded and stuff. - if (gl_shadeq1.value && *gl_shadeq1_name.string) + if (cls.allow_shaders && gl_shadeq1.value && *gl_shadeq1_name.string) { char *star; //find the * if (!strcmp(gl_shadeq1_name.string, "*")) - tx->shader = R_RegisterShader(mt->name); //just load the regular name. + tx->shader = R_RegisterCustom(mt->name, NULL); //just load the regular name. else if (!(star = strchr(gl_shadeq1_name.string, '*')) || (strlen(gl_shadeq1_name.string)+strlen(mt->name)+1>=sizeof(altname))) //it's got to fit. - tx->shader = R_RegisterShader(gl_shadeq1_name.string); + tx->shader = R_RegisterCustom(gl_shadeq1_name.string, NULL); else { strncpy(altname, gl_shadeq1_name.string, star-gl_shadeq1_name.string); //copy the left altname[star-gl_shadeq1_name.string] = '\0'; strcat(altname, mt->name); //insert the * strcat(altname, star+1); //add any final text. - tx->shader = R_RegisterShader(altname); + tx->shader = R_RegisterCustom(altname, NULL); } } #endif @@ -1247,19 +1247,19 @@ void GLMod_LoadLighting (lump_t *l) if (!luxdata) { strcpy(luxname, loadmodel->name); - COM_StripExtension(loadmodel->name, luxname); - COM_DefaultExtension(luxname, ".lux"); + COM_StripExtension(loadmodel->name, luxname, sizeof(luxname)); + COM_DefaultExtension(luxname, ".lux", sizeof(luxname)); luxdata = COM_LoadHunkFile(luxname); } if (!luxdata) { strcpy(luxname, "luxs/"); - COM_StripExtension(COM_SkipPath(loadmodel->name), luxname+5); + COM_StripExtension(COM_SkipPath(loadmodel->name), luxname+5, sizeof(luxname)-5); strcat(luxname, ".lux"); luxdata = COM_LoadHunkFile(luxname); } - COM_StripExtension(COM_SkipPath(loadmodel->name), luxname+5); + COM_StripExtension(COM_SkipPath(loadmodel->name), luxname+5, sizeof(luxname)-5); strcat(luxname, ".lux"); if (luxdata) { @@ -1300,13 +1300,13 @@ void GLMod_LoadLighting (lump_t *l) { strcpy(litnamemaps, loadmodel->name); - COM_StripExtension(loadmodel->name, litnamemaps); - COM_DefaultExtension(litnamemaps, ".lit"); + COM_StripExtension(loadmodel->name, litnamemaps, sizeof(litnamemaps)); + COM_DefaultExtension(litnamemaps, ".lit", sizeof(litnamemaps)); depthmaps = COM_FDepthFile(litnamemaps, false); } { strcpy(litnamelits, "lits/"); - COM_StripExtension(COM_SkipPath(loadmodel->name), litnamelits+5); + COM_StripExtension(COM_SkipPath(loadmodel->name), litnamelits+5, sizeof(litnamelits) - 5); strcat(litnamelits, ".lit"); depthlits = COM_FDepthFile(litnamelits, false); } @@ -1319,7 +1319,7 @@ void GLMod_LoadLighting (lump_t *l) } litdata = COM_LoadHunkFile(litname); - COM_StripExtension(COM_SkipPath(loadmodel->name), litname+5); + COM_StripExtension(COM_SkipPath(loadmodel->name), litname+5, sizeof(litname)-5); strcat(litname, ".lit"); if (litdata && (litdata[0] == 'Q' && litdata[1] == 'L' && litdata[2] == 'I' && litdata[3] == 'T')) { @@ -1994,8 +1994,8 @@ void GLMod_LoadCrouchHull(void) //find a name for a ccn and try to load it. strcpy(crouchhullname, loadmodel->name); - COM_StripExtension(loadmodel->name, crouchhullname); - COM_DefaultExtension(crouchhullname, ".crh"); //crouch hull + COM_StripExtension(loadmodel->name, crouchhullname, sizeof(crouchhullname)); + COM_DefaultExtension(crouchhullname, ".crh",sizeof(crouchhullname)); //crouch hull crouchhullfile = COM_LoadMallocFile(crouchhullname); //or otherwise temporary storage. load on hunk if you want, but that would be a waste. if (!crouchhullfile) @@ -2781,13 +2781,13 @@ void * GLMod_LoadSpriteFrame (void * pin, mspriteframe_t **ppframe, int framenum } if (!pspriteframe->gl_texturenum) { //the older fte way. - COM_StripExtension(loadmodel->name, name); + COM_StripExtension(loadmodel->name, name, sizeof(name)); strcat(name, va("_%i", framenum)); pspriteframe->gl_texturenum = Mod_LoadReplacementTexture(name, "sprites", true, true, true); } if (!pspriteframe->gl_texturenum) { //the fuhquake way - COM_StripExtension(COM_SkipPath(loadmodel->name), name); + COM_StripExtension(COM_SkipPath(loadmodel->name), name, sizeof(name)); strcat(name, va("_%i", framenum)); pspriteframe->gl_texturenum = Mod_LoadReplacementTexture(name, "sprites", true, true, true); } diff --git a/engine/gl/gl_ppl.c b/engine/gl/gl_ppl.c index 006e4672d..d40c5b357 100644 --- a/engine/gl/gl_ppl.c +++ b/engine/gl/gl_ppl.c @@ -1528,11 +1528,18 @@ static void PPL_BaseTextureChain(msurface_t *first) if (mb.mesh) R_RenderMeshBuffer ( &mb, false ); + return; } #endif qglEnable(GL_TEXTURE_2D); + + + + + + t = GLR_TextureAnimation (first->texinfo->texture); if (first->flags & SURF_DRAWTURB) @@ -4753,6 +4760,8 @@ qboolean PPL_AddLight(dlight_t *dl) qglStencilFunc( GL_ALWAYS, 0, ~0 ); qglDisable(GL_SCISSOR_TEST); + qglDisable(GL_BLEND); + GL_TexEnv(GL_REPLACE); return true; } diff --git a/engine/gl/gl_rmisc.c b/engine/gl/gl_rmisc.c index 639d6cebb..08fb93ab5 100644 --- a/engine/gl/gl_rmisc.c +++ b/engine/gl/gl_rmisc.c @@ -905,7 +905,7 @@ void R_LoadRTLights(void) cl_dlights[i].radius = 0; } - COM_StripExtension(cl.worldmodel->name, fname); + COM_StripExtension(cl.worldmodel->name, fname, sizeof(fname)); strncat(fname, ".rtlights", MAX_QPATH-1); file = COM_LoadTempFile(fname); @@ -992,7 +992,7 @@ void GLR_NewMap (void) r_worldentity.model = cl.worldmodel; - COM_StripExtension(COM_SkipPath(cl.worldmodel->name), namebuf); + COM_StripExtension(COM_SkipPath(cl.worldmodel->name), namebuf, sizeof(namebuf)); Cvar_Set(&host_mapname, namebuf); // clear out efrags in case the level hasn't been reloaded diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index dcccf3f4a..f71da4fa8 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -539,6 +539,111 @@ static void Shader_EntityMergable ( shader_t *shader, shaderpass_t *pass, char * shader->flags |= SHADER_ENTITY_MERGABLE; } +static void Shader_ProgramName ( shader_t *shader, shaderpass_t *pass, char **ptr ) +{ + char *vert, *frag; + char *token; + if (shader->programhandle) + { //this allows fallbacks + token = Shader_ParseString ( ptr ); + token = Shader_ParseString ( ptr ); + return; + } + token = Shader_ParseString ( ptr ); + FS_LoadFile(token, &vert); + token = Shader_ParseString ( ptr ); + FS_LoadFile(token, &frag); + if (vert && frag) + shader->programhandle = GLSlang_CreateProgram("", vert, frag); + if (vert) + FS_FreeFile(vert); + if (frag) + FS_FreeFile(frag); +} + +static void Shader_ProgramParam ( shader_t *shader, shaderpass_t *pass, char **ptr ) +{ + cvar_t *cv; + int specialint = 0; + float specialfloat = 0; + enum shaderprogparmtype_e parmtype = SP_BAD; + char *token; + unsigned int uniformloc; + + token = Shader_ParseString ( ptr ); + if (!Q_stricmp(token, "texture")) + { + token = Shader_ParseString ( ptr ); + specialint = atoi(token); + parmtype = SP_TEXTURE; + } + else if (!Q_stricmp(token, "cvari")) + { + token = Shader_ParseString ( ptr ); + cv = Cvar_Get(token, "", 0, "GLSL Shader parameters"); + if (cv) + { //Cvar_Get returns null if the cvar is the name of a command + specialint = atoi(cv->string); + specialfloat = cv->value; + } + parmtype = SP_CVARI; + } + else if (!Q_stricmp(token, "cvarf")) + { + token = Shader_ParseString ( ptr ); + cv = Cvar_Get(token, "", 0, "GLSL Shader parameters"); + if (cv) + { //Cvar_Get returns null if the cvar is the name of a command + specialint = atoi(cv->string); + specialfloat = cv->value; + } + parmtype = SP_CVARF; + } + else if (!Q_stricmp(token, "time")) + { + parmtype = SP_TIME; + } + + + if (!shader->programhandle) + { + Con_Printf("shader %s: param without program set\n", shader->name); + token = Shader_ParseString ( ptr ); + } + else + { + GLSlang_UseProgram(shader->programhandle); + + token = Shader_ParseString ( ptr ); + uniformloc = GLSlang_GetUniformLocation(shader->programhandle, token); + + if (uniformloc == -1) + { + Con_Printf("shader %s: param without uniform \"%s\"\n", shader->name, token); + return; + } + else + { + switch(parmtype) + { + case SP_TEXTURE: + case SP_CVARI: + GLSlang_SetUniform1i(uniformloc, specialint); + break; + case SP_CVARF: + GLSlang_SetUniform1f(uniformloc, specialfloat); + break; + default: + shader->progparm[shader->numprogparams].type = parmtype; + shader->progparm[shader->numprogparams].handle = uniformloc; + shader->numprogparams++; + break; + } + } + GLSlang_UseProgram(0); + } +} + static shaderkey_t shaderkeys[] = { {"cull", Shader_Cull }, @@ -552,6 +657,10 @@ static shaderkey_t shaderkeys[] = {"deformvertexes", Shader_DeformVertexes }, {"portal", Shader_Portal }, {"entitymergable", Shader_EntityMergable }, + + {"program", Shader_ProgramName }, //glsl + {"param", Shader_ProgramParam }, + {NULL, NULL} }; @@ -1367,6 +1476,57 @@ static qboolean Shader_Parsetok (shader_t *shader, shaderpass_t *pass, shaderkey } } + if (!Q_stricmp(token, "if")) + { + int indent = 0; + cvar_t *cv; + qboolean conditiontrue = true; + token = COM_ParseExt ( ptr, false ); + if (*token == '!') + { + conditiontrue = false; + token++; + } + cv = Cvar_Get(token, "", 0, "Shader Conditions"); + if (cv) + conditiontrue = conditiontrue == !!cv->value; + + if (conditiontrue) + { + while ( ptr ) + { + token = COM_ParseExt (ptr, true); + if ( !token[0] ) + continue; + else if (token[0] == ']' || token[0] == '}') + indent--; + else if (token[0] == '[') + indent++; + else + Shader_Parsetok (shader, pass, keys, token, ptr); + if (!indent) + break; + } + } + else + { + while ( ptr ) + { + token = COM_ParseExt (ptr, true); + if (!token[0]) + continue; + else if (token[0] == ']' || token[0] == '}') + indent--; + else if (token[0] == '[') + indent++; + if (!indent) + break; + } + } + + return ( ptr && *ptr && **ptr == '}' ); + } + // Next Line while (ptr) { @@ -1553,7 +1713,7 @@ void Shader_Finish ( shader_t *s ) s->sort = SHADER_SORT_ADDITIVE - 1; } - if ( r_vertexlight.value ) + if ( r_vertexlight.value && !s->programhandle) { // do we have a lightmap pass? pass = s->passes; @@ -1718,6 +1878,14 @@ done:; s->flags &= ~SHADER_DEPTHWRITE; } + if (s->programhandle) + { + if (!s->numpasses) + s->numpasses = 1; + s->passes->numMergedPasses = s->numpasses; + s->passes->flush = R_RenderMeshProgram; + } + Shader_SetFeatures ( s ); } /* @@ -1849,7 +2017,7 @@ void Shader_DefaultBSP(char *shortname, shader_t *s) int bumptex; extern cvar_t gl_bump; - if (0)//this isn't working right yet gl_config.arb_texture_env_dot3) + if (gl_config.arb_texture_env_dot3) { if (gl_bump.value) bumptex = Mod_LoadHiResTexture(va("normalmaps/%s", shortname), NULL, true, false, false);//GL_FindImage (shortname, 0); @@ -2201,15 +2369,83 @@ void Shader_Default2D(char *shortname, shader_t *s) s->registration_sequence = 1;//fizme: registration_sequence; } +qboolean Shader_ParseShader(char *shortname, char *usename, shader_t *s) +{ + unsigned int offset = 0, length; + char path[MAX_QPATH]; + char *buf = NULL, *ts = NULL; + + Shader_GetPathAndOffset( shortname, &ts, &offset ); + + if ( ts ) + { + Com_sprintf ( path, sizeof(path), "%s", ts ); + length = FS_LoadFile ( path, (void **)&buf ); + } + else + length = 0; + + // the shader is in the shader scripts + if ( ts && buf && (offset < length) ) + { + char *file, *token; + + + file = buf + offset; + token = COM_ParseExt (&file, true); + if ( !file || token[0] != '{' ) + { + FS_FreeFile(buf); + return false; + } + + + memset ( s, 0, sizeof( shader_t ) ); + + Com_sprintf ( s->name, MAX_QPATH, usename ); + + // set defaults + s->flags = SHADER_CULL_FRONT; + s->registration_sequence = 1;//fizme: registration_sequence; + +// if (!strcmp(COM_FileExtension(ts), "rscript")) +// { +// Shader_DefaultBSP(shortname, s); +// } + + while ( file ) + { + token = COM_ParseExt (&file, true); + + if ( !token[0] ) + continue; + else if ( token[0] == '}' ) + break; + else if ( token[0] == '{' ) + Shader_Readpass ( s, &file ); + else if ( Shader_Parsetok (s, NULL, shaderkeys, token, &file ) ) + break; + } + + Shader_Finish ( s ); + + FS_FreeFile(buf); + return true; + } + + if (buf) + FS_FreeFile(buf); + + return false; +} + int R_LoadShader ( char *name, void(*defaultgen)(char *name, shader_t*)) { int i, f = -1; - unsigned int offset = 0, length = 0; - char shortname[MAX_QPATH], path[MAX_QPATH]; - char *buf = NULL, *ts = NULL; + char shortname[MAX_QPATH]; shader_t *s; - COM_StripExtension ( name, shortname ); + COM_StripExtension ( name, shortname, sizeof(shortname)); COM_CleanUpPath(shortname); @@ -2237,65 +2473,26 @@ int R_LoadShader ( char *name, void(*defaultgen)(char *name, shader_t*)) } s = &r_shaders[f]; - memset ( s, 0, sizeof( shader_t ) ); - Com_sprintf ( s->name, MAX_QPATH, shortname ); - - Shader_GetPathAndOffset( shortname, &ts, &offset ); - - if ( ts ) { - Com_sprintf ( path, sizeof(path), "%s", ts ); - length = FS_LoadFile ( path, (void **)&buf ); - } - - // the shader is in the shader scripts - if ( ts && buf && (offset < length) ) + if (gl_config.arb_shader_objects) { - char *ptr, *token; - - // set defaults - s->flags = SHADER_CULL_FRONT; - s->registration_sequence = 1;//fizme: registration_sequence; - -// if (!strcmp(COM_FileExtension(ts), "rscript")) -// { -// Shader_DefaultBSP(shortname, s); -// } - - ptr = buf + offset; - token = COM_ParseExt (&ptr, true); - - if ( !ptr || token[0] != '{' ) { - return -1; - } - - while ( ptr ) - { - token = COM_ParseExt (&ptr, true); - - if ( !token[0] ) { - continue; - } else if ( token[0] == '}' ) { - break; - } else if ( token[0] == '{' ) { - Shader_Readpass ( s, &ptr ); - } else if ( Shader_Parsetok (s, NULL, shaderkeys, token, &ptr ) ) { - break; - } - } - - Shader_Finish ( s ); - FS_FreeFile ( buf ); + if (Shader_ParseShader(va("%s_glsl", shortname), shortname, s)) + return f; } - else // make a default shader + if (Shader_ParseShader(shortname, shortname, s)) + return f; + + // make a default shader + + if (defaultgen) { - if (defaultgen) - defaultgen(shortname, s); - else - return -1; - } + memset ( s, 0, sizeof( shader_t ) ); + Com_sprintf ( s->name, MAX_QPATH, shortname ); + defaultgen(shortname, s); - return f; + return f; + } + return -1; } shader_t *R_RegisterPic (char *name) diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c index f96c6eed5..23a46732f 100644 --- a/engine/gl/gl_vidcommon.c +++ b/engine/gl/gl_vidcommon.c @@ -112,6 +112,7 @@ PFNGLGETINFOLOGARBPROC qglGetInfoLogARB; PFNGLLINKPROGRAMARBPROC qglLinkProgramARB; PFNGLGETUNIFORMLOCATIONARBPROC qglGetUniformLocationARB; PFNGLUNIFORM4FARBPROC qglUniform4fARB; +PFNGLUNIFORM4FVARBPROC qglUniform4fvARB; PFNGLUNIFORM3FARBPROC qglUniform3fARB; PFNGLUNIFORM3FVARBPROC qglUniform3fvARB; PFNGLUNIFORM1IARBPROC qglUniform1iARB; @@ -369,6 +370,7 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name)) qglLinkProgramARB = (void *)getglext("glLinkProgramARB"); qglGetUniformLocationARB = (void *)getglext("glGetUniformLocationARB"); qglUniform4fARB = (void *)getglext("glUniform4fARB"); + qglUniform4fvARB = (void *)getglext("glUniform4fvARB"); qglUniform3fARB = (void *)getglext("glUniform3fARB"); qglUniform3fvARB = (void *)getglext("glUniform3fvARB"); qglUniform1iARB = (void *)getglext("glUniform1iARB"); diff --git a/engine/gl/glquake.h b/engine/gl/glquake.h index f33cbc8ab..f3c93aa19 100644 --- a/engine/gl/glquake.h +++ b/engine/gl/glquake.h @@ -765,6 +765,7 @@ extern PFNGLGETINFOLOGARBPROC qglGetInfoLogARB; extern PFNGLLINKPROGRAMARBPROC qglLinkProgramARB; extern PFNGLGETUNIFORMLOCATIONARBPROC qglGetUniformLocationARB; extern PFNGLUNIFORM4FARBPROC qglUniform4fARB; +extern PFNGLUNIFORM4FVARBPROC qglUniform4fvARB; extern PFNGLUNIFORM3FARBPROC qglUniform3fARB; extern PFNGLUNIFORM3FVARBPROC qglUniform3fvARB; extern PFNGLUNIFORM1IARBPROC qglUniform1iARB; diff --git a/engine/gl/shader.h b/engine/gl/shader.h index fd61f4f68..d432dff82 100644 --- a/engine/gl/shader.h +++ b/engine/gl/shader.h @@ -5,6 +5,8 @@ #define SHADER_MAX_ANIMFRAMES 8 #define SHADER_ANIM_FRAMES_MAX 16 +#define SHADER_PROGPARMS_MAX 16 + typedef enum { SHADER_BSP, SHADER_BSP_VERTEX, @@ -175,8 +177,7 @@ typedef struct shaderpass_s { SHADER_PASS_LIGHTMAP = 1 << 5, SHADER_PASS_DELUXMAP = 1 << 6, SHADER_PASS_NOCOLORARRAY = 1<< 7, - SHADER_PASS_ANIMMAP = 1 << 8, - SHADER_PASS_GPUPROGRAM = 1 << 9 + SHADER_PASS_ANIMMAP = 1 << 8 } flags; } shaderpass_t; @@ -188,6 +189,23 @@ typedef struct int nearbox_textures[6]; } skydome_t; +typedef struct { + enum shaderprogparmtype_e { + SP_BAD, + SP_ENTCOLOURS, + SP_TOPCOLOURS, + SP_BOTTOMCOLOURS, + SP_TIME, + + //things that are set immediatly + SP_FIRSTIMMEDIATE, //never set + SP_CVARI, + SP_CVARF, + SP_TEXTURE + } type; + unsigned int handle; +} shaderprogparm_t; + typedef struct shader_s { int numpasses; //careful... 0 means it's not loaded... and not actually a proper shader. struct shader_s *next; @@ -215,10 +233,13 @@ typedef struct shader_s { SHADER_DEPTHWRITE = 1 << 11, SHADER_AGEN_PORTAL = 1 << 12, SHADER_BLEND = 1 << 13, //blend or alphatest (not 100% opaque). - SHADER_NODRAW = 1 << 14, //parsed only to pee off developers when they forget it on no-pass shaders. - SHADER_PROGRAM = 1 << 15 //run a script + SHADER_NODRAW = 1 << 14 //parsed only to pee off developers when they forget it on no-pass shaders. } flags; + unsigned int programhandle; + int numprogparams; + shaderprogparm_t progparm[SHADER_PROGPARMS_MAX]; + shaderpass_t passes[SHADER_PASS_MAX]; shadersort_t sort; @@ -238,6 +259,7 @@ extern shader_t r_shaders[]; void R_RenderMeshGeneric ( meshbuffer_t *mb, shaderpass_t *pass ); void R_RenderMeshCombined ( meshbuffer_t *mb, shaderpass_t *pass ); void R_RenderMeshMultitextured ( meshbuffer_t *mb, shaderpass_t *pass ); +void R_RenderMeshProgram ( meshbuffer_t *mb, shaderpass_t *pass ); shader_t *R_RegisterPic (char *name); shader_t *R_RegisterShader (char *name); diff --git a/engine/http/ftpclient.c b/engine/http/ftpclient.c index 01640fbd2..6b83b25c4 100644 --- a/engine/http/ftpclient.c +++ b/engine/http/ftpclient.c @@ -435,10 +435,11 @@ usepasv: else if (ret == 125) //begining transfer { if (con->type == ftp_getting) - { - COM_StripExtension(con->localfile, msg); - strcat(msg, ".tmp"); - con->f = FS_OpenVFS (msg, "wb", FS_GAME); + { + char tempname[MAX_OSPATH]; + COM_StripExtension(con->localfile, tempname, MAX_OSPATH); + strcat(tempname, ".tmp"); + con->f = FS_OpenVFS (tempname, "wb", FS_GAME); if (!con->f) { msg = va("ABOR\r\nQUIT\r\n"); //bummer. we couldn't open this file to output to. diff --git a/engine/makeconfig.sh b/engine/makeconfig.sh index 2bd4e4d45..c03ac8b3a 100644 --- a/engine/makeconfig.sh +++ b/engine/makeconfig.sh @@ -6,7 +6,7 @@ #the Makefile explicitally tests for config.h, and will pass the right precompiler to gcc so that this file is actually used. #And so we don't break in the absence of this file. -if [ $1 = y ]; then +if [ "$1" = "y" ]; then defaulttoyes=true echo "Checking installed libraries" else @@ -26,13 +26,13 @@ echo "" >> config.h query() { - if [ $defaulttoyes = true ]; then + if [ "$defaulttoyes" = "true" ]; then ans=y else read -n 1 -p "$1 " ans echo "" fi - if [ $ans = y -o $ans = Y ]; then + if [ "$ans" = "y" -o "$ans" = "Y" ]; then echo "#define $2" >> config.h else echo "//#define $2" >> config.h @@ -48,6 +48,7 @@ querylibrary() query "$1" "$2" return fi +#they don't have it, force no. echo "$1 n" echo "//#define $2" >> config.h } @@ -84,7 +85,7 @@ query "Do you want to enable fish-eye views (only in software) ?" FISH query "Do you want to enable the built in http/ftp server ?" WEBSERVER query "Do you want to enable the built in http/ftp clients ?" WEBCLIENT query "Do you want to enable the deluxemap generation routine ?" RUNTIMELIGHTING -query "Do you want to enable the 'qterm' (this is a major security risk) ?" QTERM +#query "Do you want to enable the 'qterm' (this is a major security risk) ?" QTERM query "Do you want to enable the server browser ?" CL_MASTER query "Do you want to enable the serial-mouse support (used in splitscreen) ?" SERIALMOUSE query "Do you want to enable the per-pixel lighting routines ?" PPL diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 0d1b49428..4282dcd63 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -1012,7 +1012,7 @@ void Q_InitProgs(void) if (*progs.string && strlen(progs.string)<64 && *progs.string != '*') //a * is a special case to not load a q2 dll. { Q_strncpyz(addons, progs.string, MAX_QPATH); - COM_DefaultExtension(addons, ".dat"); + COM_DefaultExtension(addons, ".dat", sizeof(addons)); } oldprnum= AddProgs(addons); diff --git a/engine/server/savegame.c b/engine/server/savegame.c index e97095e67..a34ae23c1 100644 --- a/engine/server/savegame.c +++ b/engine/server/savegame.c @@ -535,7 +535,7 @@ qboolean SV_LoadLevelCache(char *level, char *startspot, qboolean ignoreplayers) gametype = cache->gametype; sprintf (name, "saves/%s", level); - COM_DefaultExtension (name, ".lvc"); + COM_DefaultExtension (name, ".lvc", sizeof(name)); // Con_TPrintf (STL_LOADGAMEFROM, name); @@ -763,7 +763,7 @@ void SV_SaveLevelCache(qboolean dontharmgame) sprintf (name, "%s/saves/%s", com_gamedir, cache->mapname); - COM_DefaultExtension (name, ".lvc"); + COM_DefaultExtension (name, ".lvc", sizeof(name)); COM_CreatePath(name); diff --git a/engine/server/sv_ccmds.c b/engine/server/sv_ccmds.c index 9ff9b2004..02c38462e 100644 --- a/engine/server/sv_ccmds.c +++ b/engine/server/sv_ccmds.c @@ -482,7 +482,7 @@ void SV_Map_f (void) if (!strcmp(level, ".")) //restart current { - COM_StripExtension(COM_SkipPath(sv.modelname), level); + COM_StripExtension(COM_SkipPath(sv.modelname), level, sizeof(level)); issamelevel = true; Q_strncpyz(spot, Info_ValueForKey(svs.info, "*startspot"), sizeof(spot)); diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index b97af7098..18243bb57 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -732,6 +732,26 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us COM_FlushTempoaryPacks(); + + //This fixes a bug where the server advertises cheats, the internal client connects, and doesn't think cheats are allowed. + //this applies to a few other things too, but cheats is the only special one (because of the *) + if (sv_cheats.value) + { + sv_allow_cheats = true; + Info_SetValueForStarKey(svs.info, "*cheats", "ON", MAX_SERVERINFO_STRING); + } + else + { + sv_allow_cheats = false; + Info_SetValueForStarKey(svs.info, "*cheats", "", MAX_SERVERINFO_STRING); + } +#ifndef CLIENTONLY + Q_strncpyz(cl.serverinfo, svs.info, sizeof(cl.serverinfo)); + CL_CheckServerInfo(); +#endif + + + if (usecinematic) { strcpy (sv.name, server); @@ -781,17 +801,6 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us // SV_ClearWorld (); - if (sv_cheats.value) - { - sv_allow_cheats = true; - Info_SetValueForStarKey(svs.info, "*cheats", "ON", MAX_SERVERINFO_STRING); - } - else - { - sv_allow_cheats = false; - Info_SetValueForStarKey(svs.info, "*cheats", "", MAX_SERVERINFO_STRING); - } - //do we allow csprogs? #ifdef PEXT_CSQC file = COM_LoadTempFile("csprogs.dat"); diff --git a/engine/server/sv_mvd.c b/engine/server/sv_mvd.c index cc4830601..6b8a48420 100644 --- a/engine/server/sv_mvd.c +++ b/engine/server/sv_mvd.c @@ -1582,8 +1582,8 @@ void SV_MVD_Record_f (void) snprintf (name, MAX_OSPATH+MAX_MVD_NAME, "%s/%s/%s", com_gamedir, sv_demoDir.string, newname); - COM_StripExtension(name, name); - COM_DefaultExtension(name, ".mvd"); + COM_StripExtension(name, name, sizeof(name)); + COM_DefaultExtension(name, ".mvd", sizeof(name)); COM_CreatePath(name); // @@ -2093,7 +2093,7 @@ void SV_MVDRemove_f (void) } Q_strncpyz(name, Cmd_Argv(1), MAX_MVD_NAME); - COM_DefaultExtension(name, ".mvd"); + COM_DefaultExtension(name, ".mvd", sizeof(name)); snprintf(path, MAX_OSPATH, "%s/%s/%s", com_gamedir, sv_demoDir.string, name);