From c4132347eb8525e5cc48c603469113feafe43db3 Mon Sep 17 00:00:00 2001 From: Spoike Date: Sun, 15 Apr 2018 02:48:23 +0000 Subject: [PATCH] added sys_priority cvar to the windows build. rewrote tab completion logic. should no longer consume so much cpu time. added tab-completion for the connect command. server lists must have been requested previously (like the connectbr command requires). fix q1bsp fencetexture+fog combo. fix wateralpha/lavaalpha/slimealpha/telealpha worldspawn fields. added a couple of extra cvars to some rulesets. fix d3d9 mipmap-size issue. fix vid_reload issue (was crashing, but its also possible that it could have been the cause of VBO corruption). made pausable default to empty, allowing for smarter defaults like pausing SP but not DM. attempt to compensate for NQ's framerate-dependant waterjumps by making QW waterjumps slightly more permissive. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5241 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/client/cl_demo.c | 2 +- engine/client/cl_main.c | 57 ++-- engine/client/cl_master.h | 3 + engine/client/cl_parse.c | 21 +- engine/client/cl_pred.c | 6 +- engine/client/console.c | 37 ++- engine/client/keys.c | 180 ++++++----- engine/client/net_master.c | 58 +++- engine/client/r_surf.c | 3 + engine/client/sys_win.c | 24 ++ engine/client/valid.c | 3 + engine/client/wad.c | 10 +- engine/common/cmd.c | 399 ++++++++++++++++--------- engine/common/cmd.h | 20 +- engine/common/common.c | 8 +- engine/common/common.h | 1 + engine/common/fs.c | 75 ++++- engine/common/net_wins.c | 45 +-- engine/common/pmove.c | 38 ++- engine/d3d/d3d_backend.c | 14 +- engine/d3d/d3d_image.c | 19 +- engine/d3d/d3d_shader.c | 21 +- engine/gl/gl_backend.c | 25 ++ engine/gl/gl_heightmap.c | 60 +++- engine/gl/gl_shader.c | 136 +++++---- engine/gl/r_bishaders.h | 340 +++++++++++++++++++-- engine/qclib/qcc.h | 1 + engine/qclib/qcc_pr_comp.c | 12 + engine/server/pr_cmds.c | 2 + engine/server/pr_lua.c | 26 +- engine/server/savegame.c | 4 +- engine/server/sv_ccmds.c | 4 +- engine/server/sv_main.c | 2 +- engine/server/sv_phys.c | 2 +- engine/server/sv_sys_unix.c | 4 +- engine/server/sv_user.c | 7 +- engine/shaders/glsl/defaultwall.glsl | 1 + engine/shaders/vulkan/defaultwall.glsl | 1 + 38 files changed, 1233 insertions(+), 438 deletions(-) diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index d8c62bded..ef7f6c7b9 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -1986,7 +1986,7 @@ void CL_Record_f (void) static int QDECL CompleteDemoList (const char *name, qofs_t flags, time_t mtime, void *parm, searchpathfuncs_t *spath) { struct xcommandargcompletioncb_s *ctx = parm; - ctx->cb(name, ctx); + ctx->cb(name, NULL, NULL, ctx); return true; } void CL_DemoList_c(int argn, const char *partial, struct xcommandargcompletioncb_s *ctx) diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index a51b90da6..e96e64997 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -1233,6 +1233,7 @@ CL_Connect_f ================ */ +void CL_Connect_c(int argn, const char *partial, struct xcommandargcompletioncb_s *ctx); void CL_Connect_f (void) { char *server; @@ -1492,9 +1493,9 @@ void CL_ResetFog(int ftype) memset(&cl.fog[ftype], 0, sizeof(cl.fog[ftype])); cl.fog[ftype].time = realtime; cl.fog[ftype].density = 0; - cl.fog[ftype].colour[0] = 0.3; - cl.fog[ftype].colour[1] = 0.3; - cl.fog[ftype].colour[2] = 0.3; + cl.fog[ftype].colour[0] = //SRGBf(0.3); + cl.fog[ftype].colour[1] = //SRGBf(0.3); + cl.fog[ftype].colour[2] = SRGBf(0.3); cl.fog[ftype].alpha = 1; cl.fog[ftype].depthbias = 0; /* @@ -3962,20 +3963,20 @@ void CL_Fog_f(void) break; case 3: cl.fog[ftype].density = atof(Cmd_Argv(1)); - cl.fog[ftype].colour[0] = cl.fog[ftype].colour[1] = cl.fog[ftype].colour[2] = atof(Cmd_Argv(2)); + cl.fog[ftype].colour[0] = cl.fog[ftype].colour[1] = cl.fog[ftype].colour[2] = SRGBf(atof(Cmd_Argv(2))); break; case 4: cl.fog[ftype].density = 0.05; //make something up for vauge compat with fitzquake, so it doesn't get the default of 0 - cl.fog[ftype].colour[0] = atof(Cmd_Argv(1)); - cl.fog[ftype].colour[1] = atof(Cmd_Argv(2)); - cl.fog[ftype].colour[2] = atof(Cmd_Argv(3)); + cl.fog[ftype].colour[0] = SRGBf(atof(Cmd_Argv(1))); + cl.fog[ftype].colour[1] = SRGBf(atof(Cmd_Argv(2))); + cl.fog[ftype].colour[2] = SRGBf(atof(Cmd_Argv(3))); break; case 5: default: cl.fog[ftype].density = atof(Cmd_Argv(1)); - cl.fog[ftype].colour[0] = atof(Cmd_Argv(2)); - cl.fog[ftype].colour[1] = atof(Cmd_Argv(3)); - cl.fog[ftype].colour[2] = atof(Cmd_Argv(4)); + cl.fog[ftype].colour[0] = SRGBf(atof(Cmd_Argv(2))); + cl.fog[ftype].colour[1] = SRGBf(atof(Cmd_Argv(3))); + cl.fog[ftype].colour[2] = SRGBf(atof(Cmd_Argv(4))); break; } @@ -4357,13 +4358,22 @@ void CL_Init (void) Cmd_AddCommandD ("quit", CL_Quit_f, "Use this command when you get angry. Does not save any cvars. Use cfg_save to save settings, or use the menu for a prompt."); #if defined(CL_MASTER) - Cmd_AddCommandD ("connectbr", CL_ConnectBestRoute_f, "connect address:port\nConnect to a qw server using the best route we can detect."); + Cmd_AddCommandAD ("connectbr", CL_ConnectBestRoute_f, CL_Connect_c, "connect address:port\nConnect to a qw server using the best route we can detect."); #endif - Cmd_AddCommandD ("connect", CL_Connect_f, "connect scheme://address:port\nConnect to a server. " + Cmd_AddCommandAD("connect", CL_Connect_f, CL_Connect_c, "connect scheme://address:port\nConnect to a server. " + #if defined(FTE_TARGET_WEB) - "Use a scheme of ws:// or wss:// to connect via using websockets." -#else + "Use a scheme of rtc[s]://broker/gamename to connect via a webrtc broker." + "Use a scheme of ws[s]://server to connect via websockets." +#elif defined(TCPCONNECT) "Use a scheme of tcp:// or tls:// to connect via non-udp protocols." +// "Use a scheme of ws[s]://server to connect via websockets." +#endif +#ifdef HAVE_DTLS + "Use a scheme of dtls://server to connect securely." +#endif +#if defined(IRCCONNECT) + "Use irc://network:6667/user[@channel] to connect via an irc server. Not recommended." #endif #if defined(NQPROT) || defined(Q2CLIENT) || defined(Q3CLIENT) "\nDefault port is port "STRINGIFY(PORT_DEFAULTSERVER)"." @@ -4383,17 +4393,17 @@ void CL_Init (void) ); Cmd_AddCommandD ("cl_transfer", CL_Transfer_f, "Connect to a different server, disconnecting from the current server only when the new server replies."); #ifdef TCPCONNECT - Cmd_AddCommandD ("tcpconnect", CL_TCPConnect_f, "Connect to a server using the tcp:// prefix"); + Cmd_AddCommandAD ("tcpconnect", CL_TCPConnect_f, CL_Connect_c, "Connect to a server using the tcp:// prefix"); #endif #ifdef IRCCONNECT Cmd_AddCommand ("ircconnect", CL_IRCConnect_f); #endif #ifdef NQPROT - Cmd_AddCommandD ("nqconnect", CLNQ_Connect_f, "Connects to the specified server, defaulting to port "STRINGIFY(PORT_NQSERVER)"."); + Cmd_AddCommandD ("nqconnect", CLNQ_Connect_f, "Connects to the specified server, defaulting to port "STRINGIFY(PORT_NQSERVER)". Otherwise identical to the connect command."); #endif Cmd_AddCommand ("reconnect", CL_Reconnect_f); - Cmd_AddCommand ("join", CL_Join_f); - Cmd_AddCommand ("observe", CL_Observe_f); + Cmd_AddCommandAD ("join", CL_Join_f, CL_Connect_c, "Switches away from spectator mode, optionally connecting to a different server."); + Cmd_AddCommandAD ("observe", CL_Observe_f, CL_Connect_c, "Switches to spectator mode, optionally connecting to a different server."); Cmd_AddCommand ("rcon", CL_Rcon_f); Cmd_AddCommand ("packet", CL_Packet_f); @@ -4405,10 +4415,9 @@ void CL_Init (void) Cmd_AddCommand ("color", CL_Color_f); Cmd_AddCommand ("download", CL_Download_f); - Cmd_AddCommand ("dlsize", CL_DownloadSize_f); - - Cmd_AddCommand ("nextul", CL_NextUpload); - Cmd_AddCommand ("stopul", CL_StopUpload); + Cmd_AddCommandD ("dlsize", CL_DownloadSize_f, "For internal use"); + Cmd_AddCommandD ("nextul", CL_NextUpload, "For internal use"); + Cmd_AddCommandD ("stopul", CL_StopUpload, "For internal use"); Cmd_AddCommand ("skipdl", CL_SkipDownload_f); Cmd_AddCommand ("finishdl", CL_FinishDownload_f); @@ -4427,8 +4436,6 @@ void CL_Init (void) Cmd_AddCommand ("topten", NULL); - Cmd_AddCommandD ("fog", CL_Fog_f, "fog "); - Cmd_AddCommandD ("waterfog", CL_Fog_f, "waterfog "); Cmd_AddCommand ("kill", NULL); Cmd_AddCommand ("pause", NULL); Cmd_AddCommand ("say", CL_Say_f); @@ -4441,6 +4448,8 @@ void CL_Init (void) Cmd_AddCommand ("serverinfo", CL_ServerInfo_f); #endif + Cmd_AddCommandD ("fog", CL_Fog_f, "fog "); + Cmd_AddCommandD ("waterfog", CL_Fog_f, "waterfog "); Cmd_AddCommand ("skygroup", CL_Skygroup_f); // // Windows commands diff --git a/engine/client/cl_master.h b/engine/client/cl_master.h index 8709dfa4e..593e3f4c9 100644 --- a/engine/client/cl_master.h +++ b/engine/client/cl_master.h @@ -31,6 +31,9 @@ enum masterprotocol_e #define SS_KEEPINFO (1<<6u) #define SS_PROXY (1<<7u) +#define PING_DEAD 0xffff //default ping value to denote servers that are not responding. +#define PING_MAX 0xfffe //default ping value to denote servers that are not responding. + //despite not supporting nq or q2, we still load them. We just filter them. This is to make sure we properly write the listing files. enum mastertype_e diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index e26d561ac..79bf8651d 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -1610,6 +1610,21 @@ void CL_RequestNextDownload (void) stage = CL_LoadSounds(stage, true); total_loading_size = stage; cl.contentstage = 0; + + //might be safer to do it later, but kinder to do it before wasting time. + if (!FS_PureOkay()) + { + #ifdef HAVE_MEDIA_ENCODER + if (cls.demoplayback && Media_Capturing()) + { + Con_Printf(CON_ERROR "Aborting capture\n"); + CL_StopPlayback(); + } + #endif + SCR_SetLoadingStage(LS_NONE); + CL_Disconnect(); + return; + } } stage = 0; @@ -8038,9 +8053,9 @@ void CLNQ_ParseServerMessage (void) case svcfitz_fog: CL_ResetFog(0); cl.fog[0].density = MSG_ReadByte()/255.0f; - cl.fog[0].colour[0] = MSG_ReadByte()/255.0f; - cl.fog[0].colour[1] = MSG_ReadByte()/255.0f; - cl.fog[0].colour[2] = MSG_ReadByte()/255.0f; + cl.fog[0].colour[0] = SRGBf(MSG_ReadByte()/255.0f); + cl.fog[0].colour[1] = SRGBf(MSG_ReadByte()/255.0f); + cl.fog[0].colour[2] = SRGBf(MSG_ReadByte()/255.0f); cl.fog[0].time += ((unsigned short)MSG_ReadShort()) / 100.0; cl.fog_locked = !!cl.fog[0].density; break; diff --git a/engine/client/cl_pred.c b/engine/client/cl_pred.c index 52960b2fd..bfee59a9a 100644 --- a/engine/client/cl_pred.c +++ b/engine/client/cl_pred.c @@ -483,12 +483,14 @@ void CL_CalcCrouch (playerview_t *pv) return; } - //check if we moved in the x/y axis. if we didn't then we're on a moving platform and shouldn't be crouching. -/* VectorMA(pv->oldorigin, pv->oldz-orgz, pv->gravitydir, pv->oldorigin); +/*fixme: this helps lifts with cl_nopred, but seems to harm ramps slightly, might just be my imagination. I guess we need to check last frame too. + //check if we moved in the x/y axis. if we didn't then we're on a vertically moving platform and shouldn't be crouching. + VectorMA(pv->oldorigin, pv->oldz-orgz, pv->gravitydir, pv->oldorigin); VectorSubtract(pv->simorg, pv->oldorigin, delta); if (Length(delta)<0.001) pv->oldz = orgz; */ + VectorCopy (pv->simorg, pv->oldorigin); diff --git a/engine/client/console.c b/engine/client/console.c index 6e1e985da..6a249d3d1 100644 --- a/engine/client/console.c +++ b/engine/client/console.c @@ -65,6 +65,7 @@ cvar_t con_notify_y = CVAR("con_notify_y","0"); cvar_t con_notify_w = CVAR("con_notify_w","1"); cvar_t con_centernotify = CVAR("con_centernotify", "0"); cvar_t con_displaypossibilities = CVAR("con_displaypossibilities", "1"); +cvar_t con_showcompletion = CVAR("con_showcompletion", "1"); cvar_t con_maxlines = CVAR("con_maxlines", "1024"); cvar_t cl_chatmode = CVARD("cl_chatmode", "2", "0(nq) - everything is assumed to be a console command. prefix with 'say', or just use a messagemode bind\n1(q3) - everything is assumed to be chat, unless its prefixed with a /\n2(qw) - anything explicitly recognised as a command will be used as a command, anything unrecognised will be a chat message.\n/ prefix is supported in all cases.\nctrl held when pressing enter always makes any implicit chat into team chat instead."); cvar_t con_numnotifylines_chat = CVAR("con_numnotifylines_chat", "8"); @@ -1293,7 +1294,7 @@ int Con_DrawInput (console_t *con, qboolean focused, int left, int right, int y, i = 0; x = left; - if (con->commandcompletion) + if (con->commandcompletion && con_) { if (cl_chatmode.ival && (text[0] == '/' || (cl_chatmode.ival == 2 && Cmd_IsCommand(text)))) { //color the first token yellow, it's a valid command @@ -1310,7 +1311,7 @@ int Con_DrawInput (console_t *con, qboolean focused, int left, int right, int y, fname = Cmd_CompleteCommand(text+cmdstart, true, true, con_commandmatch, NULL); if (fname && strlen(fname) < 256) //we can compleate it to: { - for (p = min(strlen(fname), key_linepos-cmdstart); fname[p]>' '; p++) + for (p = min(strlen(fname), key_linepos-cmdstart); fname[p]>0; p++) textstart[p+cmdstart] = (unsigned int)fname[p] | (COLOR_GREEN<completionline->length = 0; - for (i = 1; ; i++) + c = Cmd_Complete(text+cmdstart, true); + + for (i = 0; i < c->num; i++) { - cmd = Cmd_CompleteCommand (text+cmdstart, true, true, i, NULL);//&desc); - if (!cmd) - { - if (i <= 2) - con_commandmatch = 0; - break; - } - - if (i == 50) - { - s = (conchar_t*)(con->completionline+1); - end = COM_ParseFunString((COLOR_WHITE<completionline->length, (con->completionline->maxlength-con->completionline->length)*sizeof(maskedtext[0]), true); - con->completionline->length = end - s; - break; - } - s = (conchar_t*)(con->completionline+1); + + cmd = c->completions[i].text; +// desc = c->completions[i].desc; // if (desc) // end = COM_ParseFunString((COLOR_GREEN<completionline->length, (con->completionline->maxlength-con->completionline->length)*sizeof(maskedtext[0]), true); // else end = COM_ParseFunString((COLOR_GREEN<completionline->length, (con->completionline->maxlength-con->completionline->length)*sizeof(maskedtext[0]), true); con->completionline->length = end - s; } + if (c->extra) + { + s = (conchar_t*)(con->completionline+1); + end = COM_ParseFunString((COLOR_WHITE<extra), s+con->completionline->length, (con->completionline->maxlength-con->completionline->length)*sizeof(maskedtext[0]), true); + con->completionline->length = end - s; + } if (con->completionline->length) y = Con_DrawConsoleLines(con, con->completionline, left, right, y, 0, selactive, selsx, selex, selsy, seley, 0); diff --git a/engine/client/keys.c b/engine/client/keys.c index 0ee3f4648..f94113294 100644 --- a/engine/client/keys.c +++ b/engine/client/keys.c @@ -337,12 +337,11 @@ int PaddedPrint (char *s, int x) } int con_commandmatch; -void CompleteCommand (qboolean force) +void Key_UpdateCompletionDesc(void) { - char *cmd, *s; const char *desc; - - s = key_lines[edit_line]; + cmd_completion_t *c; + const char *s = key_lines[edit_line]; if (*s == ' ' || *s == '\t') s++; if (*s == '\\' || *s == '/') @@ -350,68 +349,20 @@ void CompleteCommand (qboolean force) if (*s == ' ' || *s == '\t') s++; - //check for singular matches and complete if found - cmd = force?NULL:Cmd_CompleteCommand (s, true, true, 2, NULL); - if (!cmd) - { - if (!force) - cmd = Cmd_CompleteCommand (s, false, true, 1, &desc); - else - cmd = Cmd_CompleteCommand (s, true, true, con_commandmatch, &desc); - if (cmd) - { - if (strlen(cmd) < strlen(s)) - return; - - //complete to that (maybe partial) cmd. - Key_ClearTyping(); - Key_ConsoleInsert("/"); - Key_ConsoleInsert(cmd); - s = key_lines[edit_line]+1; - - //if its the only match, add a space ready for arguments. - cmd = Cmd_CompleteCommand (s, true, true, 0, NULL); - if (cmd && !strcmp(s, cmd)) - { - Key_ConsoleInsert(" "); - } - - if (!con_commandmatch) - con_commandmatch = 1; - - if (desc) - Con_Footerf(NULL, false, "%s: %s", cmd, desc); - else - Con_Footerf(NULL, false, ""); - return; - } - } - //complete to a partial match. - cmd = Cmd_CompleteCommand (s, false, true, 0, &desc); - if (cmd) - { - int i = key_lines[edit_line][0] == '/'?1:0; - if (i != 1 || strcmp(key_lines[edit_line]+i, cmd)) - { //if successful, use that instead. - Key_ClearTyping(); - Key_ConsoleInsert("/"); - Key_ConsoleInsert(cmd); - - s = key_lines[edit_line]; //readjust to cope with the insertion of a / - if (*s == '\\' || *s == '/') - s++; - } - } - con_commandmatch++; - cmd = Cmd_CompleteCommand(s, true, true, con_commandmatch, &desc); - if (!cmd) - { + c = Cmd_Complete(s, true); + if (!con_commandmatch || con_commandmatch > c->num) con_commandmatch = 1; - cmd = Cmd_CompleteCommand(s, true, true, con_commandmatch, &desc); - } - if (cmd) + + if (con_commandmatch <= c->num) { - cvar_t *var = Cvar_FindVar(cmd); + const char *cmd; + cvar_t *var; + if (c->completions[con_commandmatch-1].repl) + cmd = c->completions[con_commandmatch-1].repl; + else + cmd = c->completions[con_commandmatch-1].text; + desc = c->completions[con_commandmatch-1].desc; + var = Cvar_FindVar(cmd); if (var) { if (desc) @@ -434,6 +385,88 @@ void CompleteCommand (qboolean force) } } +void CompleteCommand (qboolean force) +{ + const char *cmd, *s; + const char *desc; + cmd_completion_t *c; + + s = key_lines[edit_line]; + if (*s == ' ' || *s == '\t') + s++; + if (*s == '\\' || *s == '/') + s++; + if (*s == ' ' || *s == '\t') + s++; + + //check for singular matches and complete if found + c = Cmd_Complete(s, true); + if (c->num == 1 || force) + { + desc = NULL; + if (!force && c->num != 1) + cmd = c->guessed; + else if (c->num) + { + int idx = max(0, con_commandmatch-1); + if (c->completions[idx].repl) + cmd = c->completions[idx].repl; + else + cmd = c->completions[idx].text; + } + else + cmd = NULL; + if (cmd) + { + if (strlen(cmd) < strlen(s)) + return; + + //complete to that (maybe partial) cmd. + Key_ClearTyping(); + Key_ConsoleInsert("/"); + Key_ConsoleInsert(cmd); + s = key_lines[edit_line]; + if (*s == '/') + s++; + + //if its the only match, add a space ready for arguments. + c = Cmd_Complete(s, true); + cmd = ((c->num >= 1)?(c->completions[0].repl?c->completions[0].repl:c->completions[0].text):NULL); + desc = ((c->num >= 1)?c->completions[0].desc:NULL); + if (c->num == 1) + Key_ConsoleInsert(" "); + + if (!con_commandmatch) + con_commandmatch = 1; + + if (desc) + Con_Footerf(NULL, false, "%s: %s", cmd, desc); + else + Con_Footerf(NULL, false, ""); + return; + } + } + //complete to a partial match. + cmd = c->guessed; + if (cmd) + { + int i = key_lines[edit_line][0] == '/'?1:0; + if (i != 1 || strcmp(key_lines[edit_line]+i, cmd)) + { //if successful, use that instead. + Key_ClearTyping(); + Key_ConsoleInsert("/"); + Key_ConsoleInsert(cmd); + + s = key_lines[edit_line]; //readjust to cope with the insertion of a / + if (*s == '\\' || *s == '/') + s++; + } + } + + con_commandmatch++; + Key_UpdateCompletionDesc(); +} + int Con_Navigate(console_t *con, char *line) { if (con->backshader) @@ -1266,8 +1299,12 @@ qboolean Key_EntryLine(unsigned char **line, int lineoffset, int *linepos, int k memmove((*line)+*linepos-charlen, (*line)+*linepos, strlen((*line)+*linepos)+1); *linepos -= charlen; } - if (!(*line)[lineoffset]) //oops? - con_commandmatch = 0; + + if (con_commandmatch) + { + Con_Footerf(NULL, false, ""); + con_commandmatch = 1; + } return true; } @@ -1579,14 +1616,16 @@ qboolean Key_Console (console_t *con, unsigned int unicode, int key) if (con_commandmatch) { //if that isn't actually a command, and we can actually complete it to something, then lets try to complete it. - char *txt = key_lines[edit_line]+1; + char *txt = key_lines[edit_line]; if (*txt == '/') txt++; - if (!Cmd_IsCommand(txt) && !Cmd_CompleteCommand(txt, true, true, con_commandmatch, NULL)) + if (!Cmd_IsCommand(txt) && Cmd_CompleteCommand(txt, true, true, con_commandmatch, NULL)) { CompleteCommand (true); return true; } + Con_Footerf(con, false, ""); + con_commandmatch = 0; } @@ -1598,7 +1637,6 @@ qboolean Key_Console (console_t *con, unsigned int unicode, int key) history_line = edit_line; } } - con_commandmatch = 0; Z_Free(key_lines[edit_line]); key_lines[edit_line] = BZ_Malloc(1); @@ -1609,7 +1647,7 @@ qboolean Key_Console (console_t *con, unsigned int unicode, int key) if (key == K_SPACE && ctrl && con->commandcompletion) { - char *txt = key_lines[edit_line]+1; + char *txt = key_lines[edit_line]; if (*txt == '/') txt++; if (Cmd_CompleteCommand(txt, true, true, con->commandcompletion, NULL)) @@ -2003,7 +2041,7 @@ void Key_Bind_c(int argn, const char *partial, struct xcommandargcompletioncb_s for (kn=keynames ; kn->name ; kn++) { if (!Q_strncasecmp(partial,kn->name, len)) - ctx->cb(kn->name, ctx); + ctx->cb(kn->name, NULL, NULL, ctx); } } /* diff --git a/engine/client/net_master.c b/engine/client/net_master.c index 1f7ca2740..5b80f0ace 100644 --- a/engine/client/net_master.c +++ b/engine/client/net_master.c @@ -890,8 +890,8 @@ qboolean Master_PassesMasks(serverinfo_t *a) // qboolean enabled; //always filter out dead unresponsive servers. -// if (!(a->status & 1)) -// return false; + if (!(a->status & 1)) + return false; /* switch(a->special & SS_PROTOCOLMASK) { @@ -1309,7 +1309,7 @@ static void Master_FloodRoute(serverinfo_t *node) struct peers_s *peer = node->peers; for (i = 0; i < node->numpeers; i++, peer++) { - if (peer->ping) + if (peer->ping && peer->ping != PING_DEAD) if ((unsigned int)(peer->peer->cost) > (unsigned int)(node->cost + peer->ping)) { //we found a shorter route. flood into it. peer->peer->prevpeer = node; @@ -2305,7 +2305,7 @@ void MasterInfo_ProcessHTTP(struct dl_download *dl) #endif info->refreshtime = 0; - info->ping = 0xffff; + info->ping = PING_DEAD; snprintf(info->name, sizeof(info->name), "%s h", NET_AdrToString(adrbuf, sizeof(adrbuf), &info->adr)); @@ -2406,7 +2406,7 @@ char *jsonnode(int level, char *node) else { info = Z_Malloc(sizeof(serverinfo_t)); - info->ping = 0xffff; + info->ping = PING_DEAD; info->adr = adr; info->sends = 1; info->special = flags; @@ -2644,7 +2644,7 @@ void MasterInfo_Refresh(void) #endif #ifdef NQPROT Master_AddMasterHTTP("http://www.gameaholic.com/servers/qspy-quake", MT_MASTERHTTP, MP_NETQUAKE, "gameaholic's NQ master"); - Master_AddMasterHTTP("http://servers.quakeone.com/index.php?format=json", MT_MASTERHTTPJSON, MP_NETQUAKE, "quakeone's server listing"); +// Master_AddMasterHTTP("http://servers.quakeone.com/index.php?format=json", MT_MASTERHTTPJSON, MP_NETQUAKE, "quakeone's server listing"); Master_AddMaster("255.255.255.255:"STRINGIFY(PORT_NQSERVER), MT_BCAST, MP_NETQUAKE, "Nearby Quake1 servers"); Master_AddMaster("255.255.255.255:"STRINGIFY(PORT_NQSERVER), MT_BCAST, MP_DPMASTER, "Nearby DarkPlaces servers"); #endif @@ -2980,7 +2980,7 @@ int CL_ReadServerInfo(char *msg, enum masterprotocol_e prototype, qboolean favor //server replied from a broadcast message, make sure we ping it to retrieve its actual ping info->sends = 1; - info->ping = 0xffff; //not known + info->ping = PING_DEAD; //not known info->special |= SS_LOCAL; } else @@ -2989,8 +2989,8 @@ int CL_ReadServerInfo(char *msg, enum masterprotocol_e prototype, qboolean favor if (info->refreshtime) { ping = (Sys_DoubleTime() - info->refreshtime)*1000; - if (ping > 0xfffe) - info->ping = 0xfffe; //highest (that is known) + if (ping > PING_MAX) + info->ping = PING_MAX; //highest (that is known) else info->ping = ping; } @@ -3048,7 +3048,7 @@ int CL_ReadServerInfo(char *msg, enum masterprotocol_e prototype, qboolean favor peer->peer->sends = 1; peer->peer->special = SS_QUAKEWORLD; peer->peer->refreshtime = 0; - peer->peer->ping = 0xffff; + peer->peer->ping = PING_DEAD; peer->peer->next = firstserver; snprintf(peer->peer->name, sizeof(peer->peer->name), "%s p", NET_AdrToString(adr, sizeof(adr), &pa)); firstserver = peer->peer; @@ -3427,7 +3427,7 @@ void CL_MasterListParse(netadrtype_t adrtype, int type, qboolean slashpad) default: break; } - info->ping = 0xffff; + info->ping = PING_DEAD; p1 = MSG_ReadByte(); p2 = MSG_ReadByte(); @@ -3463,5 +3463,41 @@ void CL_MasterListParse(netadrtype_t adrtype, int type, qboolean slashpad) firstserver = last; } + + +void CL_Connect_c(int argn, const char *partial, struct xcommandargcompletioncb_s *ctx) +{ + serverinfo_t *info; + char buf[512]; + int len; + if (argn == 1) + { + len = strlen(partial); + if (len > 1 && partial[len-1] == '\"') + len--; + for (info = firstserver; info; info = info->next) + { + if (info->ping != PING_DEAD) + { + if (len && !Q_strncasecmp(partial, info->name, len)) + { + ctx->cb(info->name, va("^[%s^], %i players, %i ping", info->name, info->players, info->ping), NET_AdrToString(buf, sizeof(buf), &info->adr), ctx); + continue; + } + + NET_AdrToString(buf, sizeof(buf), &info->adr); + //there are too many meaningless servers out there, so only suggest IP addresses if those servers are actually significant (ie: active, or favourite) + if (!strncmp(partial, buf, len)) + { + if (info->players || (info->special & SS_FAVORITE) || NET_ClassifyAddress(&info->adr, NULL)<=ASCOPE_LAN || len == strlen(buf)) + { + ctx->cb(buf, va("^[%s^], %i players, %i ping", info->name, info->players, info->ping), NULL, ctx); + continue; + } + } + } + } + } +} #endif diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index 07f0c0c1b..ca6c2557f 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -3683,6 +3683,9 @@ void Surf_LightmapMode(void) } if (cl.worldmodel->deluxdata) rgb = true; + + if (cl.worldmodel->terrain) //the terrain code can't deal with extended lightmap formats. + hdr = false; } if (sh_config.texfmt[PTI_E5BGR9] && hdr) diff --git a/engine/client/sys_win.c b/engine/client/sys_win.c index d03b85ba0..ebda88ea2 100644 --- a/engine/client/sys_win.c +++ b/engine/client/sys_win.c @@ -1494,6 +1494,28 @@ void Sys_Register_File_Associations_f(void) { Sys_DoFileAssociations(0); } + +static void QDECL Sys_Priority_Changed(cvar_t *var, char *oldval) +{ + HANDLE h = GetCurrentProcess(); + DWORD pc; + + if (var->ival >= 3) + pc = REALTIME_PRIORITY_CLASS; + else if (var->ival >= 2) + pc = HIGH_PRIORITY_CLASS; + else if (var->ival >= 1) + pc = ABOVE_NORMAL_PRIORITY_CLASS; + else if (var->ival >= 0) + pc = NORMAL_PRIORITY_CLASS; + else if (var->ival >= -1) + pc = BELOW_NORMAL_PRIORITY_CLASS; + else + pc = IDLE_PRIORITY_CLASS; + + SetPriorityClass(h, pc); +} +static cvar_t sys_priority = CVARFCD("sys_highpriority", "0", CVAR_NOTFROMSERVER, Sys_Priority_Changed, "Controls the process priority"); /* ================ Sys_Init @@ -1507,6 +1529,8 @@ void Sys_Init (void) Sys_QueryDesktopParameters(); + Cvar_Register(&sys_priority, "System vars"); + #ifndef SERVERONLY Cvar_Register(&sys_disableWinKeys, "System vars"); Cvar_Register(&sys_disableTaskSwitch, "System vars"); diff --git a/engine/client/valid.c b/engine/client/valid.c index 80570dfe5..ae3cb5523 100644 --- a/engine/client/valid.c +++ b/engine/client/valid.c @@ -391,11 +391,13 @@ rulesetrule_t rulesetrules_strict[] = { {"ruleset_allow_in", "0"}, {"r_projection", "0"}, {"gl_shadeq1_name", "*"}, + {"cl_iDrive", "0"}, {NULL} }; rulesetrule_t rulesetrules_nqr[] = { {"ruleset_allow_larger_models", "0"}, + {"ruleset_allow_watervis", "0"}, /*block seeing through turbs, as well as all our cool graphics stuff. apparently we're not allowed.*/ {"ruleset_allow_overlong_sounds", "0"}, {"ruleset_allow_particle_lightning", "0"}, {"ruleset_allow_packet", "0"}, @@ -411,6 +413,7 @@ rulesetrule_t rulesetrules_nqr[] = { {"ruleset_allow_in", "0"}, {"r_projection", "0"}, {"gl_shadeq1_name", "*"}, + {"cl_iDrive", "0"}, {NULL} }; diff --git a/engine/client/wad.c b/engine/client/wad.c index 9b10b6635..155fe0375 100644 --- a/engine/client/wad.c +++ b/engine/client/wad.c @@ -851,26 +851,26 @@ void Mod_ParseInfoFromEntityLump(model_t *wmodel) //actually, this should be in { cvar_t *var = Cvar_FindVar(key+5); if (var && !(var->flags & CVAR_NOTFROMSERVER)) - Cvar_LockFromServer(var, com_token); + Cvar_LockFromServer(var, token); } else if (!strcmp("wateralpha", key)) //override cvars so mappers don't end up hacking cvars and fucking over configs (at least in other engines). { - Cvar_LockFromServer(&r_wateralpha, com_token); + Cvar_LockFromServer(&r_wateralpha, token); Cvar_LockFromServer(&r_waterstyle, "1"); //force vanilla-style water too. } else if (!strcmp("slimealpha", key)) { - Cvar_LockFromServer(&r_slimealpha, com_token); + Cvar_LockFromServer(&r_slimealpha, token); Cvar_LockFromServer(&r_slimestyle, "1"); } else if (!strcmp("lavaalpha", key)) { - Cvar_LockFromServer(&r_lavaalpha, com_token); + Cvar_LockFromServer(&r_lavaalpha, token); Cvar_LockFromServer(&r_lavastyle, "1"); } else if (!strcmp("telealpha", key)) { - Cvar_LockFromServer(&r_telealpha, com_token); + Cvar_LockFromServer(&r_telealpha, token); Cvar_LockFromServer(&r_telestyle, "1"); } else if (!strcmp("skyname", key)) // for HalfLife maps diff --git a/engine/common/cmd.c b/engine/common/cmd.c index 02809f48a..f6fb7deb0 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -811,7 +811,7 @@ void Cmd_Exec_f (void) static int QDECL CompleteExecList (const char *name, qofs_t flags, time_t mtime, void *parm, searchpathfuncs_t *spath) { struct xcommandargcompletioncb_s *ctx = parm; - ctx->cb(name, ctx); + ctx->cb(name, NULL, NULL, ctx); return true; } void Cmd_Exec_c(int argn, const char *partial, struct xcommandargcompletioncb_s *ctx) @@ -868,7 +868,7 @@ static void Key_Alias_c(int argn, const char *partial, struct xcommandargcomplet for (a = cmd_alias ; a ; a=a->next) { if (!Q_strncasecmp(partial,a->name, len)) - ctx->cb(a->name, ctx); + ctx->cb(a->name, a->value, NULL, ctx); } } static void Cmd_ShowAlias_f (void) @@ -2183,107 +2183,193 @@ const char *Cmd_Describe (const char *cmd_name) Cmd_CompleteCommand ============ */ -typedef struct { - int matchnum; - qboolean allowcutdown; - qboolean cutdown; - char result[256]; - const char *desc; -} match_t; -void Cmd_CompleteCheck(const char *check, match_t *match, const char *desc) //compare cumulative strings and join the result -{ - if (*match->result) - { - char *r; - if (match->allowcutdown) - { - for(r = match->result; *r == *check && *r; r++, check++) - ; - *r = '\0'; - match->cutdown = true; - if (match->matchnum > 0) - match->matchnum--; - } - else if (match->matchnum > 0) - { - strcpy(match->result, check); - match->desc = desc; - match->matchnum--; - } - } - else - { - if (match->matchnum > 0) - match->matchnum--; - strcpy(match->result, check); - match->desc = desc; - } -} -struct cmdargcompletionctx_s + + +struct cmdargcompletion_ctx_s { struct xcommandargcompletioncb_s cb; cmd_function_t *cmd; const char *prefix; size_t prefixlen; - match_t *match; + qboolean quoted; + cmd_completion_t *res; const char *desc; }; -void Cmd_CompleteCheckArg(const char *value, struct xcommandargcompletioncb_s *vctx) //compare cumulative strings and join the result +static fte_inline int Q_tolower(char c) { - struct cmdargcompletionctx_s *ctx = (struct cmdargcompletionctx_s*)vctx; - match_t *match = ctx->match; - const char *desc = ctx->desc; + if (c >= 'a' && c <= 'z') + c -= ('a' - 'A'); + return c; +} +void Cmd_Complete_CheckArg(const char *value, const char *desc, const char *repl, struct xcommandargcompletioncb_s *vctx) //compare cumulative strings and join the result +{ + struct cmdargcompletion_ctx_s *ctx = (struct cmdargcompletion_ctx_s*)vctx; + cmd_completion_t *res = ctx->res; + char *text; - if (ctx->prefixlen >= countof(match->result)-1) - return; //don't allow overflows. + const char *c; + char *p; + char quoted[8192]; - if (*match->result) + if (!desc) //if no arg desc, use the command's. + desc = ctx->desc; + + if (strchr(value, ' ') || strchr(value, '\t') || strchr(value, '\"') || strchr(value, '\r') || strchr(value, '\n')) { - char *r; - const char *check; - if (match->allowcutdown) - { - for(r = match->result, check=ctx->prefix; check < ctx->prefix+ctx->prefixlen && *r == *check && *r; r++, check++) - ; - if (check == ctx->prefix+ctx->prefixlen) - { - for(check=value; *r == *check && *r; r++, check++) - ; - } - *r = '\0'; - match->cutdown = true; - if (match->matchnum > 0) - match->matchnum--; - } - else if (match->matchnum > 0) - { - memcpy(match->result, ctx->prefix, ctx->prefixlen); - Q_strncpyz(match->result+ctx->prefixlen, value, sizeof(match->result)-ctx->prefixlen); - match->desc = desc; - match->matchnum--; - } + if (/*ctx->prefix[ctx->prefixlen] &&*/ !ctx->quoted) //FIXME... Figure out some way to insert quotes earlier in the completion without it bugging out + return; + } + + if (ctx->quoted) + { + value = COM_QuotedString(value, quoted, sizeof(quoted), false); + value++; + } + + if (!res->guessed) + { + text = BZ_Malloc(ctx->prefixlen + strlen(value) + 1); + memcpy(text, ctx->prefix, ctx->prefixlen); + strcpy(text+ctx->prefixlen, value); + res->guessed = text; } else { - if (match->matchnum > 0) - match->matchnum--; - memcpy(match->result, ctx->prefix, ctx->prefixlen); - Q_strncpyz(match->result+ctx->prefixlen, value, sizeof(match->result)-ctx->prefixlen); - match->desc = desc; + for (p = res->guessed, c = ctx->prefix; *p && c < ctx->prefix+ctx->prefixlen; p++, c++) + { + if (Q_tolower(*p) != Q_tolower(*c)) + { + *p = 0; + break; + } + } + if (c == ctx->prefix+ctx->prefixlen) + for (c = value; *p; p++, c++) + { + if (Q_tolower(*p) != Q_tolower(*c)) + { + *p = 0; + break; + } + if (!*c) + break; + } } + + + if (res->num == countof(res->completions)) + { + res->extra++; + return; //no more space for more options + } + + text = BZ_Malloc(ctx->prefixlen + strlen(value) + 1); + memcpy(text, ctx->prefix, ctx->prefixlen); + strcpy(text+ctx->prefixlen, value); + + if (repl) + { + p = BZ_Malloc(ctx->prefixlen + strlen(repl) + 2); + memcpy(p, ctx->prefix, ctx->prefixlen); + strcpy(p+ctx->prefixlen, repl); + if (value == quoted+1) + Q_strcat(p, "\""); + repl = p; + } + + res->completions[res->num].text_alloced = true; + res->completions[res->num].text = text; + res->completions[res->num].desc_alloced = true; + res->completions[res->num].desc = Z_StrDup(desc); + res->completions[res->num].repl = repl; + res->num++; } -char *Cmd_CompleteCommand (const char *partial, qboolean fullonly, qboolean caseinsens, int matchnum, const char **descptr) + +void Cmd_Complete_Check(const char *check, cmd_completion_t *res, const char *desc) //compare cumulative strings and join the result +{ + const char *c; + char *p; + if (!res->guessed) + res->guessed = Z_StrDup(check); + else for (p = res->guessed, c = check; *p; p++, c++) + { //we need to do this stuff here because we're not always tracking all of them. + if (Q_tolower(*p) != Q_tolower(*c)) + { + *p = 0; + break; + } + + if (!*c) + break; + } + + if (res->num == countof(res->completions)) + { + res->extra++; + return; //no more space for more options + } + + res->completions[res->num].text_alloced = false; + res->completions[res->num].text = check; + res->completions[res->num].desc_alloced = false; + res->completions[res->num].desc = desc; + res->completions[res->num].repl = NULL; + res->num++; +} +void Cmd_Complete_End(cmd_completion_t *c) +{ + size_t u; + for (u = 0; u < c->num; u++) + { + if (c->completions[u].text_alloced) + Z_Free((char*)c->completions[u].text); + c->completions[u].text_alloced = false; + c->completions[u].text = NULL; + + if (c->completions[u].desc_alloced) + Z_Free((char*)c->completions[u].desc); + c->completions[u].desc_alloced = false; + c->completions[u].desc = NULL; + + c->completions[u].repl = NULL; + } + c->num = 0; + c->extra = 0; + Z_Free(c->guessed); + c->guessed = NULL; + Z_Free(c->partial); + c->partial = NULL; +} +int QDECL Cmd_Complete_Sort(const void *a, const void *b) +{ //FIXME: its possible that they're equal (eg: filesystem searches). we should strip one in that case, but gah. + const struct cmd_completion_opt_s *c1 = a, *c2 = b; + return strcmp(c1->text, c2->text); +} +cmd_completion_t *Cmd_Complete(const char *partial, qboolean caseinsens) { extern cvar_group_t *cvar_groups; cmd_function_t *cmd; int len; cmdalias_t *a; - static match_t match; - cvar_group_t *grp; cvar_t *cvar; const char *sp; + qboolean quoted = false; + + static cmd_completion_t c; + + if (!partial) + { + Cmd_Complete_End(&c); + return NULL; + } + + if ((c.partial && !strcmp(partial, c.partial)) && c.caseinsens == caseinsens) + return &c; //still valid. + Cmd_Complete_End(&c); + c.partial = Z_StrDup(partial); + c.caseinsens = caseinsens; for (sp = partial; *sp; sp++) { @@ -2295,89 +2381,118 @@ char *Cmd_CompleteCommand (const char *partial, qboolean fullonly, qboolean case { while (*sp == ' ' || *sp == '\t') sp++; + //try to handle quotes + if (*sp == '\\' && sp[1] == '\"') + { + sp+=2; + quoted = true; + } + else if (*sp == '\"') + { + sp++; + quoted = true; + } } else sp = NULL; - if (descptr) - *descptr = NULL; - - if (!len) - return NULL; - - if (matchnum == -1) - len++; - - match.allowcutdown = !fullonly?true:false; - match.cutdown = false; - match.desc = NULL; - if (matchnum) - match.matchnum = matchnum; - else - match.matchnum = 0; - - strcpy(match.result, ""); - - // check for partial match - if (caseinsens) + if (len) { - for (cmd=cmd_functions ; cmd ; cmd=cmd->next) - if (!Q_strncasecmp (partial,cmd->name, len) && (matchnum == -1 || !partial[len] || strlen(cmd->name) == len)) - { - if (sp && cmd->argcompletion) + if (caseinsens) + { + for (cmd=cmd_functions ; cmd ; cmd=cmd->next) + if (!Q_strncasecmp (partial,cmd->name, len) && (!partial[len] || strlen(cmd->name) == len)) { - struct cmdargcompletionctx_s ctx; - ctx.cb.cb = Cmd_CompleteCheckArg; - ctx.cmd = cmd; - ctx.prefix = partial; - ctx.prefixlen = sp-partial; - ctx.match = &match; - ctx.desc = cmd->description; - cmd->argcompletion(1, sp, &ctx.cb); + if (sp && cmd->argcompletion) + { + struct cmdargcompletion_ctx_s ctx; + ctx.cb.cb = Cmd_Complete_CheckArg; + ctx.cmd = cmd; + ctx.prefix = partial; + ctx.prefixlen = sp-partial; + ctx.res = &c; + ctx.desc = cmd->description; + ctx.quoted = quoted; + cmd->argcompletion(1, sp, &ctx.cb); + } + else + Cmd_Complete_Check(cmd->name, &c, cmd->description); } - else - Cmd_CompleteCheck(cmd->name, &match, cmd->description); + for (a=cmd_alias ; a ; a=a->next) + if (!Q_strncasecmp (partial, a->name, len) && (!partial[len] || strlen(a->name) == len)) + Cmd_Complete_Check(a->name, &c, a->value); + for (grp=cvar_groups ; grp ; grp=grp->next) + for (cvar=grp->cvars ; cvar ; cvar=cvar->next) + { + if (!Q_strncasecmp (partial,cvar->name, len) && (!partial[len] || strlen(cvar->name) == len)) + Cmd_Complete_Check(cvar->name, &c, cvar->description); + if (cvar->name2 && !Q_strncasecmp (partial,cvar->name2, len) && (!partial[len] || strlen(cvar->name2) == len)) + Cmd_Complete_Check(cvar->name2, &c, cvar->description); } - for (a=cmd_alias ; a ; a=a->next) - if (!Q_strncasecmp (partial, a->name, len) && (matchnum == -1 || !partial[len] || strlen(a->name) == len)) - Cmd_CompleteCheck(a->name, &match, a->value); - for (grp=cvar_groups ; grp ; grp=grp->next) - for (cvar=grp->cvars ; cvar ; cvar=cvar->next) - { - if (!Q_strncasecmp (partial,cvar->name, len) && (matchnum == -1 || !partial[len] || strlen(cvar->name) == len)) - Cmd_CompleteCheck(cvar->name, &match, cvar->description); - if (cvar->name2 && !Q_strncasecmp (partial,cvar->name2, len) && (matchnum == -1 || !partial[len] || strlen(cvar->name2) == len)) - Cmd_CompleteCheck(cvar->name2, &match, cvar->description); - } + } + else + { + for (cmd=cmd_functions ; cmd ; cmd=cmd->next) + if (!Q_strncmp (partial,cmd->name, len) && (!partial[len] || strlen(cmd->name) == len)) + Cmd_Complete_Check(cmd->name, &c, cmd->description); + for (a=cmd_alias ; a ; a=a->next) + if (!Q_strncmp (partial, a->name, len) && (!partial[len] || strlen(a->name) == len)) + Cmd_Complete_Check(a->name, &c, ""); + for (grp=cvar_groups ; grp ; grp=grp->next) + for (cvar=grp->cvars ; cvar ; cvar=cvar->next) + { + if (!Q_strncmp (partial,cvar->name, len) && (!partial[len] || strlen(cvar->name) == len)) + Cmd_Complete_Check(cvar->name, &c, cvar->description); + if (cvar->name2 && !Q_strncmp (partial,cvar->name2, len) && (!partial[len] || strlen(cvar->name2) == len)) + Cmd_Complete_Check(cvar->name2, &c, cvar->description); + } + } + } + + //quickly sort the completions. this is primarily so that the first item is the shortest, but whatever. + qsort(c.completions, c.num, sizeof(c.completions[0]), Cmd_Complete_Sort); + return &c; +} + +char *Cmd_CompleteCommand (const char *partial, qboolean fullonly, qboolean caseinsens, int matchnum, const char **descptr) +{ + cmd_completion_t *c = Cmd_Complete(partial, caseinsens); + const char *text = NULL, *desc = NULL; + + if (matchnum < 0) + { //completes only if there's an EXACT match. + for (matchnum = 0; matchnum < c->num; matchnum++) + { + if (!strcmp(partial, c->completions[matchnum].text)) + { + text = c->completions[matchnum].text; + desc = c->completions[matchnum].desc; + break; + } + } + } + else if (!matchnum) + { //returns the longest-common-denominator of all the matches + text = c->guessed; + desc = ((c->num==1)?c->completions[matchnum].desc:NULL); } else { - for (cmd=cmd_functions ; cmd ; cmd=cmd->next) - if (!Q_strncmp (partial,cmd->name, len) && (matchnum == -1 || !partial[len] || strlen(cmd->name) == len)) - Cmd_CompleteCheck(cmd->name, &match, cmd->description); - for (a=cmd_alias ; a ; a=a->next) - if (!Q_strncmp (partial, a->name, len) && (matchnum == -1 || !partial[len] || strlen(a->name) == len)) - Cmd_CompleteCheck(a->name, &match, ""); - for (grp=cvar_groups ; grp ; grp=grp->next) - for (cvar=grp->cvars ; cvar ; cvar=cvar->next) + matchnum--; + if (matchnum < c->num) { - if (!Q_strncmp (partial,cvar->name, len) && (matchnum == -1 || !partial[len] || strlen(cvar->name) == len)) - Cmd_CompleteCheck(cvar->name, &match, cvar->description); - if (cvar->name2 && !Q_strncmp (partial,cvar->name2, len) && (matchnum == -1 || !partial[len] || strlen(cvar->name2) == len)) - Cmd_CompleteCheck(cvar->name2, &match, cvar->description); + text = c->completions[matchnum].text; + desc = c->completions[matchnum].desc; } } - if (match.matchnum>0) - return NULL; - if (!*match.result) - return NULL; if (descptr) - *descptr = match.desc; - return match.result; + *descptr = desc; + return (char*)text; } + //lists commands, also prints restriction level void Cmd_List_f (void) { diff --git a/engine/common/cmd.h b/engine/common/cmd.h index c4e37bef1..8fef7576b 100644 --- a/engine/common/cmd.h +++ b/engine/common/cmd.h @@ -73,7 +73,8 @@ then searches for a command or variable that matches the first token. typedef void (*xcommand_t) (void); struct xcommandargcompletioncb_s { - void(*cb)(const char *arg, struct xcommandargcompletioncb_s *ctx); + //if repl is specified, then that is the text that will be used if this is the sole autocomplete, to complete using strings that are not actually valid. + void(*cb)(const char *arg, const char *desc, const char *repl, struct xcommandargcompletioncb_s *ctx); //private stuff follows. }; typedef void (*xcommandargcompletion_t)(int argn, const char *partial, struct xcommandargcompletioncb_s *ctx); @@ -102,6 +103,23 @@ char *Cmd_AliasExist(const char *name, int restrictionlevel); const char *Cmd_Describe (const char *cmd_name); +typedef struct +{ + char *guessed; //this is the COMPLETED partial. + char *partial; //the requested string that we completed + qboolean caseinsens; + size_t num, extra; //valid count, and ommitted count (if we were too lazy to find more) + struct cmd_completion_opt_s { + qboolean text_alloced:1; + qboolean desc_alloced:1; + const char *text; + const char *repl; //used for sole matches + const char *desc; + } completions[50]; +} cmd_completion_t; +cmd_completion_t *Cmd_Complete(const char *partial, qboolean caseinsens); //calculates and caches info. + +//these should probably be removed some time char *Cmd_CompleteCommand (const char *partial, qboolean fullonly, qboolean caseinsens, int matchnum, const char **descptr); qboolean Cmd_IsCommand (const char *line); // attempts to match a partial command for automatic command line completion diff --git a/engine/common/common.c b/engine/common/common.c index 8cef62396..566a7ee76 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -480,6 +480,12 @@ char *Q_strlwr(char *s) return ret; } +static char fte_inline Q_tolower(char c) +{ + if (c >= 'A' && c <= 'Z') + return c-'A'+'a'; + return c; +} int wildcmp(const char *wild, const char *string) { /* @@ -507,7 +513,7 @@ int wildcmp(const char *wild, const char *string) return true; string++; } - else if ((*wild == *string) || (*wild == '?')) + else if ((Q_tolower(*wild) == Q_tolower(*string)) || (*wild == '?')) { //this char matches wild++; diff --git a/engine/common/common.h b/engine/common/common.h index bac2dcd15..20931eb52 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -611,6 +611,7 @@ void FS_UnloadPackFiles(void); void FS_ReloadPackFiles(void); char *FSQ3_GenerateClientPacksList(char *buffer, int maxlen, int basechecksum); void FS_PureMode(int mode, char *purenamelist, char *purecrclist, char *refnamelist, char *refcrclist, int seed); //implies an fs_restart. ref package names are optional, for q3 where pure names don't contain usable paths +qboolean FS_PureOkay(void); //recursively tries to open files until it can get a zip. vfsfile_t *CL_OpenFileInPackage(searchpathfuncs_t *search, char *name); diff --git a/engine/common/fs.c b/engine/common/fs.c index 067da7198..b65274ce5 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -3524,6 +3524,79 @@ void FS_PureMode(int puremode, char *purenamelist, char *purecrclist, char *refn } } +qboolean FS_PureOkay(void) +{ + //returns true if all pure packages that we're meant to need could load. + //if they couldn't then they won't override things, or the game will just be completely screwed due to having absolutely no game data + if (fs_puremode == 1 && fs_purenames && *fs_purenames && fs_purecrcs && *fs_purecrcs) + { + char crctok[64]; + char nametok[MAX_QPATH]; + char nametok2[MAX_QPATH]; + searchpath_t *sp = com_purepaths; + char *names = fs_purenames, *pname; + char *crcs = fs_purecrcs; + int crc; + qboolean required; + + while(names && crcs) + { + crcs = COM_ParseOut(crcs, crctok, sizeof(crctok)); + names = COM_ParseOut(names, nametok, sizeof(nametok)); + + crc = strtoul(crctok, NULL, 0); + if (!crc) + continue; + + pname = nametok; + + if (fs_refnames && fs_refcrcs) + { //q3 is annoying as hell + int crc2; + char *rc = fs_refcrcs; + char *rn = fs_refnames; + pname = ""; + for (; rc && rn; ) + { + rc = COM_ParseOut(rc, crctok, sizeof(crctok)); + rn = COM_ParseOut(rn, nametok2, sizeof(nametok2)); + crc2 = strtoul(crctok, NULL, 0); + if (crc2 == crc) + { + COM_DefaultExtension(nametok2, ".pk3", sizeof(nametok2)); + pname = nametok2; + break; + } + } + } + required = *pname == '*'; + if (*pname == '*') // * means that its 'referenced' (read: actually useful) thus should be downloaded, which is not relevent here. + { + required = true; + pname++; + } + else + required = false; + + if (sp && sp->crc_check == crc) + { + sp = sp->nextpure; + continue; + } + else if (!required) //if its not referenced, then its not needed, and we probably didn't bother to download it. this might be an issue with sv_pure 1, but that has its own issues. + continue; + else //if (!sp) + { + Con_Printf("Pure package %s:%i missing\n", pname, crc); + return false; + } + } + return true; + } + + return true; +} + char *FSQ3_GenerateClientPacksList(char *buffer, int maxlen, int basechecksum) { //this is for q3 compatibility. @@ -3854,7 +3927,7 @@ void FS_ReloadPackFilesFlags(unsigned int reloadflags) } if (!sp) - Con_DPrintf("Pure crc %i wasn't found\n", crc); + Con_DPrintf("Pure package %s:%i wasn't found\n", pname, crc); } } } diff --git a/engine/common/net_wins.c b/engine/common/net_wins.c index f6ecdc537..d95a57cd6 100644 --- a/engine/common/net_wins.c +++ b/engine/common/net_wins.c @@ -1168,7 +1168,6 @@ size_t NET_StringToAdr2 (const char *s, int defaultport, netadr_t *a, size_t num if (!strncmp (s, "tcp://", 6)) { //make sure that the rest of the address is a valid ip address (4 or 6) - if (!NET_StringToSockaddr (s+6, defaultport, &sadr[0], NULL, NULL)) { a->type = NA_INVALID; @@ -1182,7 +1181,6 @@ size_t NET_StringToAdr2 (const char *s, int defaultport, netadr_t *a, size_t num if (!strncmp (s, "ws://", 5)) { //make sure that the rest of the address is a valid ip address (4 or 6) - if (!NET_StringToSockaddr (s+5, defaultport, &sadr[0], NULL, NULL)) { a->type = NA_INVALID; @@ -1195,8 +1193,10 @@ size_t NET_StringToAdr2 (const char *s, int defaultport, netadr_t *a, size_t num } if (!strncmp (s, "wss://", 6)) { +#ifndef HAVE_SSL + return false; +#else //make sure that the rest of the address is a valid ip address (4 or 6) - if (!NET_StringToSockaddr (s+6, defaultport, &sadr[0], NULL, NULL)) { a->type = NA_INVALID; @@ -1206,29 +1206,14 @@ size_t NET_StringToAdr2 (const char *s, int defaultport, netadr_t *a, size_t num SockadrToNetadr (&sadr[0], a); a->prot = NP_WSS; return true; - } - if (!strncmp (s, "dtls://", 7)) - { -#ifdef HAVE_DTLS - //make sure that the rest of the address is a valid ip address (4 or 6) - - if (!NET_StringToSockaddr (s+7, defaultport, &sadr[0], NULL, NULL)) - { - a->type = NA_INVALID; - return false; - } - - SockadrToNetadr (&sadr[0], a); - a->prot = NP_DTLS; - return true; -#else - return false; #endif } if (!strncmp (s, "tls://", 6)) { +#ifndef HAVE_SSL + return false; +#else //make sure that the rest of the address is a valid ip address (4 or 6) - if (!NET_StringToSockaddr (s+6, defaultport, &sadr[0], NULL, NULL)) { a->type = NA_INVALID; @@ -1238,8 +1223,26 @@ size_t NET_StringToAdr2 (const char *s, int defaultport, netadr_t *a, size_t num SockadrToNetadr (&sadr[0], a); a->prot = NP_TLS; return true; +#endif } #endif + if (!strncmp (s, "dtls://", 7)) + { +#ifndef HAVE_DTLS + return false; +#else + //make sure that the rest of the address is a valid ip address (4 or 6) + if (!NET_StringToSockaddr (s+7, defaultport, &sadr[0], NULL, NULL)) + { + a->type = NA_INVALID; + return false; + } + + SockadrToNetadr (&sadr[0], a); + a->prot = NP_DTLS; + return true; +#endif + } #ifdef IRCCONNECT if (!strncmp (s, "irc://", 6)) { diff --git a/engine/common/pmove.c b/engine/common/pmove.c index f029eec3a..cacfbc78c 100644 --- a/engine/common/pmove.c +++ b/engine/common/pmove.c @@ -1132,9 +1132,11 @@ PM_CheckWaterJump */ void PM_CheckWaterJump (void) { - vec3_t spot; - int cont; + vec3_t spot, spot2; +// int cont; vec3_t flatforward; + trace_t tr; + vec3_t oldmin, oldmax; if (pmove.waterjumptime>0) return; @@ -1151,6 +1153,37 @@ void PM_CheckWaterJump (void) flatforward[2] = 0; VectorNormalize (flatforward); +#if 1 //NQ does a traceline, which gives more permissive results. This is required for various maps that have awkward water jumps. + VectorCopy(pmove.player_mins, oldmin); + VectorCopy(pmove.player_maxs, oldmax); + VectorCopy(pmove.origin, spot); + spot[2] += 8 + 24+pmove.player_mins[2]; //hexen2 fix. calculated from the normal bottom of bbox + VectorMA (spot, 24, flatforward, spot2); + tr = PM_TraceLine(spot, spot2); + VectorCopy(oldmin, pmove.player_mins); + VectorCopy(oldmax, pmove.player_maxs); + if (tr.fraction == 1) //(possibly) give up if open at waist + { //NQ bug workaround: NQ does waterjump checks inside prethink, and THEN sets waterlevel after. + //The player then moves to where waterlevel SHOULD be 3, except you're still allowed to waterjump because of last frame. + //Which is horrible buggy framerate-dependant behaviour... + //so lets just try again 2qu up. + //This'll cause slight prediction issues with other qw engines, and maybe some newly bugged maps, but those maps were probably already buggy with a low enough nq framerate. + spot[2] += 2; + spot2[2] += 2; + tr = PM_TraceLine(spot, spot2); + VectorCopy(oldmin, pmove.player_mins); + VectorCopy(oldmax, pmove.player_maxs); + if (tr.fraction == 1) //give up if open at waist + return; + } + spot[2] += 24; + spot2[2] += 24; + tr = PM_TraceLine(spot, spot2); + VectorCopy(oldmin, pmove.player_mins); + VectorCopy(oldmax, pmove.player_maxs); + if (tr.fraction < 1) //give up if blocked at eye + return; +#else VectorMA (pmove.origin, 24, flatforward, spot); spot[2] += 8 + 24+pmove.player_mins[2]; //hexen2 fix. calculated from the normal bottom of bbox cont = PM_PointContents (spot); @@ -1160,6 +1193,7 @@ void PM_CheckWaterJump (void) cont = PM_PointContents (spot); if (cont != FTECONTENTS_EMPTY) return; +#endif // jump out of water VectorScale (flatforward, 50, pmove.velocity); pmove.velocity[2] = 310; diff --git a/engine/d3d/d3d_backend.c b/engine/d3d/d3d_backend.c index 15076441d..a4ff89c70 100644 --- a/engine/d3d/d3d_backend.c +++ b/engine/d3d/d3d_backend.c @@ -818,7 +818,7 @@ static void SelectPassTexture(unsigned int tu, shaderpass_t *pass) { default: case T_GEN_DIFFUSE: - if (shaderstate.curtexnums->base) + if (TEXLOADED(shaderstate.curtexnums->base)) BindTexture(tu, shaderstate.curtexnums->base); else BindTexture(tu, missing_texture); @@ -2049,6 +2049,13 @@ static void BE_ApplyUniforms(program_t *prog, int permu) IDirect3DDevice9_SetVertexShaderConstantF(pD3DDev9, h, mvp, 4); } break; + case SP_M_MODELVIEW: + { + float mv[16]; + Matrix4_Multiply(r_refdef.m_view, shaderstate.m_model, mv); + IDirect3DDevice9_SetVertexShaderConstantF(pD3DDev9, h, mv, 4); + } + break; case SP_LIGHTPOSITION: { @@ -2130,7 +2137,6 @@ static void BE_ApplyUniforms(program_t *prog, int permu) break; case SP_M_ENTBONES: - case SP_M_MODELVIEW: case SP_E_VLSCALE: case SP_E_ORIGIN: case SP_E_GLOWMOD: @@ -2177,9 +2183,9 @@ static void BE_RenderMeshProgram(shader_t *s, unsigned int vertbase, unsigned in return; } #endif - if (TEXVALID(shaderstate.curtexnums->bump) && p->permu[perm|PERMUTATION_BUMPMAP].h.loaded) + if (TEXLOADED(shaderstate.curtexnums->bump) && p->permu[perm|PERMUTATION_BUMPMAP].h.loaded) perm |= PERMUTATION_BUMPMAP; - if (TEXVALID(shaderstate.curtexnums->fullbright) && p->permu[perm|PERMUTATION_FULLBRIGHT].h.loaded) + if (TEXLOADED(shaderstate.curtexnums->fullbright) && p->permu[perm|PERMUTATION_FULLBRIGHT].h.loaded) perm |= PERMUTATION_FULLBRIGHT; if (p->permu[perm|PERMUTATION_UPPERLOWER].h.loaded && (TEXLOADED(shaderstate.curtexnums->upperoverlay) || TEXLOADED(shaderstate.curtexnums->loweroverlay))) perm |= PERMUTATION_UPPERLOWER; diff --git a/engine/d3d/d3d_image.c b/engine/d3d/d3d_image.c index 3846dea16..671c8c849 100644 --- a/engine/d3d/d3d_image.c +++ b/engine/d3d/d3d_image.c @@ -146,16 +146,29 @@ qboolean D3D9_LoadTextureMips(image_t *tex, const struct pendingtextureinfo *mip else if (mips->type == PTI_2D) { IDirect3DTexture9 *dt; - if (FAILED(IDirect3DDevice9_CreateTexture(pD3DDev9, mips->mip[0].width, mips->mip[0].height, mips->mipcount, 0, fmt, D3DPOOL_MANAGED, &dt, NULL))) + int mipcount = mips->mipcount; + for (i = 1; i < mipcount; i++) + { //OpenGL and Direct3D have different interpretations of mipmap sizes. + //OpenGL rounds up, direct3D rounds down. (d3d:3->1, gl:3->2) + //so if the mips are incompatible, just drop the smaller ones. + if (mips->mip[i].width != max(1,(mips->mip[i-1].width)>>1) || + mips->mip[i].height != max(1,(mips->mip[i-1].height)>>1)) + { + mipcount = i; + break; + } + } + + if (FAILED(IDirect3DDevice9_CreateTexture(pD3DDev9, mips->mip[0].width, mips->mip[0].height, mipcount, 0, fmt, D3DPOOL_MANAGED, &dt, NULL))) return false; dbt = (IDirect3DBaseTexture9*)dt; - for (i = 0; i < mips->mipcount; i++) + for (i = 0; i < mipcount; i++) { IDirect3DTexture9_GetLevelDesc(dt, i, &desc); if (mips->mip[i].height != desc.Height || mips->mip[i].width != desc.Width) - { + { //we got the above mipcount clamping wrong! IDirect3DTexture9_Release(dt); return false; } diff --git a/engine/d3d/d3d_shader.c b/engine/d3d/d3d_shader.c index 046e1231f..f34439085 100644 --- a/engine/d3d/d3d_shader.c +++ b/engine/d3d/d3d_shader.c @@ -180,7 +180,7 @@ static HRESULT STDMETHODCALLTYPE myID3DXIncludeVtbl_Open(myID3DXInclude *cls, D3 "float3 fog3(float3 regularcolour, float distance)" "{" - "float z = w_fogdensity * -distance;\n" + "float z = w_fogdensity * distance;\n" "z = max(0.0,z-w_fogdepthbias);\n" "if (r_fog_exp2)\n" "z *= z;\n" @@ -190,7 +190,7 @@ static HRESULT STDMETHODCALLTYPE myID3DXIncludeVtbl_Open(myID3DXInclude *cls, D3 "}\n" "float3 fog3additive(float3 regularcolour, float distance)" "{" - "float z = w_fogdensity * -distance;\n" + "float z = w_fogdensity * distance;\n" "z = max(0.0,z-w_fogdepthbias);\n" "if (r_fog_exp2)\n" "z *= z;\n" @@ -204,7 +204,7 @@ static HRESULT STDMETHODCALLTYPE myID3DXIncludeVtbl_Open(myID3DXInclude *cls, D3 "}\n" "float4 fog4additive(float4 regularcolour, float distance)" "{" - "float z = w_fogdensity * -distance;\n" + "float z = w_fogdensity * distance;\n" "z = max(0.0,z-w_fogdepthbias);\n" "if (r_fog_exp2)\n" "z *= z;\n" @@ -214,7 +214,7 @@ static HRESULT STDMETHODCALLTYPE myID3DXIncludeVtbl_Open(myID3DXInclude *cls, D3 "}\n" "float4 fog4blend(float4 regularcolour, float distance)" "{" - "float z = w_fogdensity * -distance;\n" + "float z = w_fogdensity * distance;\n" "z = max(0.0,z-w_fogdepthbias);\n" "if (r_fog_exp2)\n" "z *= z;\n" @@ -223,12 +223,11 @@ static HRESULT STDMETHODCALLTYPE myID3DXIncludeVtbl_Open(myID3DXInclude *cls, D3 "return regularcolour * float4(1.0, 1.0, 1.0, fac);\n" "}\n" "#else\n" - /*don't use macros for this - mesa bugs out*/ - "float3 fog3(float3 regularcolour, float4 fragcoord) { return regularcolour; }\n" - "float3 fog3additive(float3 regularcolour, float4 fragcoord) { return regularcolour; }\n" - "float4 fog4(float4 regularcolour, float4 fragcoord) { return regularcolour; }\n" - "float4 fog4additive(float4 regularcolour, float4 fragcoord) { return regularcolour; }\n" - "float4 fog4blend(float4 regularcolour, float4 fragcoord) { return regularcolour; }\n" + "float3 fog3(float3 regularcolour, float distance) { return regularcolour; }\n" + "float3 fog3additive(float3 regularcolour, float distance) { return regularcolour; }\n" + "float4 fog4(float4 regularcolour, float distance) { return regularcolour; }\n" + "float4 fog4additive(float4 regularcolour, float distance) { return regularcolour; }\n" + "float4 fog4blend(float4 regularcolour, float distance) { return regularcolour; }\n" "#endif\n" "#endif\n" ; @@ -580,7 +579,7 @@ void D3D9Shader_Init(void) sh_config.progpath = shaderlib?"hlsl/%s.hlsl":NULL; sh_config.shadernamefmt = "%s_hlsl9"; - sh_config.progs_supported = !!shaderlib; + sh_config.progs_supported = !!shaderlib && d3d9_hlsl.ival; sh_config.progs_required = false; sh_config.pDeleteProg = D3D9Shader_DeleteProg; diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index 6d5c5c997..282a6e78e 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -1525,6 +1525,30 @@ void GLBE_Shutdown(void) BZ_Free(shaderstate.wbatches); shaderstate.wbatches = NULL; shaderstate.maxwbatches = 0; + + //on vid_reload, the gl drivers might have various things bound that have since been destroyed/etc + //so reset that state to avoid any issues with state + /*shaderstate.sourcevbo = &shaderstate.dummyvbo; + memset(shaderstate.sourcevbo, 0, sizeof(*shaderstate.sourcevbo)); + shaderstate.pendingcolourvbo = 0; + shaderstate.pendingcolourpointer = NULL; + shaderstate.pendingvertexvbo = 0; + shaderstate.pendingvertexpointer = NULL; + for (u = 0; u < SHADER_TMU_MAX; u++) + { + shaderstate.pendingtexcoordparts[u] = 0; + shaderstate.pendingtexcoordvbo[u] = 0; + shaderstate.pendingtexcoordpointer[u] = NULL; + }*/ + if (sh_config.progs_supported) + BE_ApplyAttributes(0, (1u<= 3.0 && gl_config_nofixedfunc) diff --git a/engine/gl/gl_heightmap.c b/engine/gl/gl_heightmap.c index 2669f2a0a..8a299dcc8 100644 --- a/engine/gl/gl_heightmap.c +++ b/engine/gl/gl_heightmap.c @@ -5643,7 +5643,8 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e) default: Sys_Error("Bad lightmap_fmt\n"); break; - case TF_BGRA32: + case PTI_BGRA8: + case PTI_BGRX8: for (t = 0; t < br->faces[j].lmextents[1]; t++) { for (s = 0; s < br->faces[j].lmextents[0]; s++) @@ -5657,7 +5658,8 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e) out += (lm->width - br->faces[j].lmextents[0]) * 4; } break; - /*case TF_RGBA32: + case PTI_RGBA8: + case PTI_RGBX8: for (t = 0; t < br->faces[j].lmextents[1]; t++) { for (s = 0; s < br->faces[j].lmextents[0]; s++) @@ -5670,8 +5672,8 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e) } out += (lm->width - br->faces[j].lmextents[0]) * 4; } - break;*/ - /*case TF_BGR24: + break; + case PTI_BGR8: for (t = 0; t < br->faces[j].lmextents[1]; t++) { for (s = 0; s < br->faces[j].lmextents[0]; s++) @@ -5683,8 +5685,8 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e) } out += (lm->width - br->faces[j].lmextents[0]) * 3; } - break;*/ - case TF_RGB24: + break; + case PTI_RGB8: for (t = 0; t < br->faces[j].lmextents[1]; t++) { for (s = 0; s < br->faces[j].lmextents[0]; s++) @@ -5697,6 +5699,51 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e) out += (lm->width - br->faces[j].lmextents[0]) * 3; } break; + + + case PTI_A2BGR10: + for (t = 0; t < br->faces[j].lmextents[1]; t++) + { + for (s = 0; s < br->faces[j].lmextents[0]; s++) + { + *(unsigned int*)out = (0x3<<30) | (in[2]<<22) | (in[1]<<12) | (in[0]<<2); + out+=4; + in+=3; + } + out += (lm->width - br->faces[j].lmextents[0]) * 4; + } + break; + /*case PTI_E5BGR9: + for (t = 0; t < br->faces[j].lmextents[1]; t++) + { + for (s = 0; s < br->faces[j].lmextents[0]; s++) + { + *(unsigned int*)out = Surf_PackE5BRG9(in[0], in[1], in[2], 8); + out+=4; + in+=3; + } + out += (lm->width - br->faces[j].lmextents[0]) * 4; + } + break;*/ + case PTI_L8: + for (t = 0; t < br->faces[j].lmextents[1]; t++) + { + for (s = 0; s < br->faces[j].lmextents[0]; s++) + { + *out++ = max(max(in[0], in[1]), in[2]); + in+=3; + } + out += (lm->width - br->faces[j].lmextents[0]); + } + break; + case PTI_RGBA16F: + case PTI_RGBA32F: + case PTI_RGB565: + case PTI_RGBA4444: + case PTI_RGBA5551: + case PTI_ARGB4444: + case PTI_ARGB1555: + break; } } } @@ -5966,6 +6013,7 @@ static brushes_t *Terr_Brush_Insert(model_t *model, heightmap_t *hm, brushes_t * out->selected = false; out->contents = brush->contents; out->axialplanes = 0; + out->patch = NULL; out->planes = BZ_Malloc((sizeof(*out->planes)+sizeof(*out->faces)) * brush->numplanes); out->faces = (void*)(out->planes+brush->numplanes); diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index acc35369d..7242d6458 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -1014,6 +1014,22 @@ static void Shader_SurfaceParm ( shader_t *shader, shaderpass_t *pass, char **pt shader->flags |= SHADER_NOMARKS; //wrong, but whatever. else if ( !Q_stricmp( token, "nomarks" ) ) shader->flags |= SHADER_NOMARKS; + + //forceshader type things inherit certain textures from the original material + //however, that original material might not need those textures and thus won't have them loaded, which breaks replacement. + //these provide a way to override that. + else if (!Q_stricmp( token, "hasdiffuse")) + shader->flags |= SHADER_HASDIFFUSE; + else if (!Q_stricmp( token, "hasnormalmap")) + shader->flags |= SHADER_HASNORMALMAP; + else if (!Q_stricmp( token, "hasgloss")) + shader->flags |= SHADER_HASGLOSS; + else if (!Q_stricmp( token, "hasfullbright")) + shader->flags |= SHADER_HASFULLBRIGHT; + else if (!Q_stricmp( token, "haspaletted")) + shader->flags |= SHADER_HASPALETTED; + else if (!Q_stricmp(token, "hastop") || !Q_stricmp(token, "hasbottom") || !Q_stricmp(token, "hastopbottom")) + shader->flags |= SHADER_HASTOPBOTTOM; } static void Shader_Sort ( shader_t *shader, shaderpass_t *pass, char **ptr ) @@ -5918,7 +5934,7 @@ void Shader_DefaultBSPLM(const char *shortname, shader_t *s, const void *args) "}\n" ); } - if (!builtin && ((sh_config.progs_supported && qrenderer == QR_OPENGL) || sh_config.progs_required)) + if (!builtin && ((sh_config.progs_supported && (qrenderer == QR_OPENGL||qrenderer == QR_DIRECT3D9)) || sh_config.progs_required)) { builtin = ( "{\n" @@ -6111,38 +6127,43 @@ char *Shader_DefaultBSPWater(shader_t *s, const char *shortname, char *buffer, s "surfaceparm nodraw\n" "surfaceparm nodlight\n" "surfaceparm nomarks\n" + "surfaceparm hasdiffuse\n" "}\n" ); case -2: //regular with r_wateralpha forced off. return ( "{\n" - "program defaultwarp\n" "{\n" + "program defaultwarp\n" "map $diffuse\n" "tcmod turb 0.02 0.1 0.5 0.1\n" "}\n" "surfaceparm nodlight\n" "surfaceparm nomarks\n" + "surfaceparm hasdiffuse\n" "}\n" ); case 0: //fastturb return ( "{\n" -// "program defaultfill\n" "{\n" +// "program defaultfill\n" "map $whiteimage\n" "rgbgen srgb $r_fastturbcolour\n" "}\n" "surfaceparm nodlight\n" "surfaceparm nomarks\n" + "surfaceparm hasdiffuse\n" "}\n" ); default: case 1: //vanilla style Q_snprintfz(buffer, buffersize, "{\n" - "program defaultwarp%s\n" + "surfaceparm nodlight\n" + "surfaceparm nomarks\n" "{\n" + "program defaultwarp%s\n" "map $diffuse\n" "tcmod turb 0.02 0.1 0.5 0.1\n" "if %g < 1\n" @@ -6150,8 +6171,7 @@ char *Shader_DefaultBSPWater(shader_t *s, const char *shortname, char *buffer, s "blendfunc gl_src_alpha gl_one_minus_src_alpha\n" "endif\n" "}\n" - "surfaceparm nodlight\n" - "surfaceparm nomarks\n" + "surfaceparm hasdiffuse\n" "}\n" , explicitalpha?"":va("#ALPHA=%g",alpha), alpha, alpha); return buffer; @@ -6161,18 +6181,13 @@ char *Shader_DefaultBSPWater(shader_t *s, const char *shortname, char *buffer, s "surfaceparm nodlight\n" "surfaceparm nomarks\n" "{\n" + "program altwater#FRESNEL=4\n" "map $refraction\n" - "}\n" - "{\n" "map $null\n"//$reflection - "}\n" - "{\n" "map $null\n"//$ripplemap - "}\n" - "{\n" "map $null\n"//$refractiondepth "}\n" - "program altwater#FRESNEL=4\n" + "surfaceparm hasdiffuse\n" "}\n" ); case 3: //reflections @@ -6181,18 +6196,13 @@ char *Shader_DefaultBSPWater(shader_t *s, const char *shortname, char *buffer, s "surfaceparm nodlight\n" "surfaceparm nomarks\n" "{\n" + "program altwater#REFLECT#FRESNEL=4\n" "map $refraction\n" - "}\n" - "{\n" "map $reflection\n" - "}\n" - "{\n" "map $null\n"//$ripplemap - "}\n" - "{\n" "map $null\n"//$refractiondepth "}\n" - "program altwater#REFLECT#FRESNEL=4\n" + "surfaceparm hasdiffuse\n" "}\n" ); case 4: //ripples @@ -6201,18 +6211,13 @@ char *Shader_DefaultBSPWater(shader_t *s, const char *shortname, char *buffer, s "surfaceparm nodlight\n" "surfaceparm nomarks\n" "{\n" + "program altwater#RIPPLEMAP#FRESNEL=4\n" "map $refraction\n" - "}\n" - "{\n" "map $null\n"//$reflection - "}\n" - "{\n" "map $ripplemap\n" - "}\n" - "{\n" "map $null\n"//$refractiondepth "}\n" - "program altwater#RIPPLEMAP#FRESNEL=4\n" + "surfaceparm hasdiffuse\n" "}\n" ); case 5: //ripples+reflections @@ -6221,18 +6226,13 @@ char *Shader_DefaultBSPWater(shader_t *s, const char *shortname, char *buffer, s "surfaceparm nodlight\n" "surfaceparm nomarks\n" "{\n" + "program altwater#REFLECT#RIPPLEMAP#FRESNEL=4\n" "map $refraction\n" - "}\n" - "{\n" "map $reflection\n" - "}\n" - "{\n" "map $ripplemap\n" - "}\n" - "{\n" "map $null\n"//$refractiondepth "}\n" - "program altwater#REFLECT#RIPPLEMAP#FRESNEL=4\n" + "surfaceparm hasdiffuse\n" "}\n" ); } @@ -6377,42 +6377,48 @@ void Shader_DefaultBSPQ1(const char *shortname, shader_t *s, const void *args) if (!builtin && *shortname == '{') { /*alpha test*/ - /*FIXME: use defaultwall#ALPHA=0.666 or so*/ - builtin = ( - "{\n" - /* "if $deluxmap\n" - "{\n" - "map $normalmap\n" - "tcgen base\n" - "}\n" - "{\n" - "map $deluxmap\n" - "tcgen lightmap\n" - "}\n" - "endif\n"*/ + if (sh_config.progs_supported) + builtin = ( "{\n" - "map $diffuse\n" - "tcgen base\n" - "alphafunc ge128\n" + "fte_program defaultwall#MASK=0.666#MASKLT\n" "}\n" -// "if $lightmap\n" + ); + else + builtin = ( + "{\n" + /* "if $deluxmap\n" + "{\n" + "map $normalmap\n" + "tcgen base\n" + "}\n" + "{\n" + "map $deluxmap\n" + "tcgen lightmap\n" + "}\n" + "endif\n"*/ "{\n" - "map $lightmap\n" - "if gl_overbright > 1\n" - "blendfunc gl_dst_color gl_src_color\n" //scale it up twice. will probably still get clamped, but what can you do - "else\n" - "blendfunc gl_dst_color gl_zero\n" - "endif\n" + "map $diffuse\n" + "tcgen base\n" + "alphafunc ge128\n" + "}\n" + // "if $lightmap\n" + "{\n" + "map $lightmap\n" + "if gl_overbright > 1\n" + "blendfunc gl_dst_color gl_src_color\n" //scale it up twice. will probably still get clamped, but what can you do + "else\n" + "blendfunc gl_dst_color gl_zero\n" + "endif\n" + "depthfunc equal\n" + "}\n" + // "endif\n" + "{\n" + "map $fullbright\n" + "blendfunc add\n" "depthfunc equal\n" "}\n" -// "endif\n" - "{\n" - "map $fullbright\n" - "blendfunc add\n" - "depthfunc equal\n" "}\n" - "}\n" - ); + ); } /*Hack: note that halflife would normally expect you to use rendermode/renderampt*/ @@ -6610,7 +6616,7 @@ void Shader_Default2D(const char *shortname, shader_t *s, const void *genargs) "nomipmaps\n" "program default2d#PREMUL\n" "{\n" - "map $diffuse\n" + "clampmap $diffuse\n" "blendfunc gl_one gl_one_minus_src_alpha\n" "}\n" "sort additive\n" diff --git a/engine/gl/r_bishaders.h b/engine/gl/r_bishaders.h index acac005db..e6f211460 100644 --- a/engine/gl/r_bishaders.h +++ b/engine/gl/r_bishaders.h @@ -6048,6 +6048,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "if (gl_FragColor.a >= MASK)\n" "discard;\n" "#endif\n" +"gl_FragColor.a = 1.0; //alpha blending AND alpha testing usually looks stupid, plus it screws up our fog.\n" "#endif\n" //and finally hide it all if we're fogged. @@ -6062,7 +6063,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND #ifdef VKQUAKE {QR_VULKAN, -1, "defaultwall", "\xFF\x53\x50\x56\x01\x00\x00\x00\x9C\x1F\x00\x00\x01\x00\x00\x00\x2B\x00\x00\x00\x2C\x00\x00\x00\xA6\x00\x00\x00\xD4\x00\x00\x00" -"\x10\x15\x00\x00\xE4\x15\x00\x00\x18\x48\x00\x00\x01\x00\x66\x31\x72\x5F\x67\x6C\x73\x6C\x5F\x6F\x66\x66\x73\x65\x74\x6D\x61\x70" +"\x10\x15\x00\x00\xE4\x15\x00\x00\x38\x48\x00\x00\x01\x00\x66\x31\x72\x5F\x67\x6C\x73\x6C\x5F\x6F\x66\x66\x73\x65\x74\x6D\x61\x70" "\x70\x69\x6E\x67\x00\x00\x00\x00\x00\x01\x01\x66\x31\x72\x5F\x67\x6C\x73\x6C\x5F\x6F\x66\x66\x73\x65\x74\x6D\x61\x70\x70\x69\x6E" "\x67\x5F\x73\x63\x61\x6C\x65\x00\x3D\x23\xD7\x0A\x01\x02\x66\x31\x67\x6C\x5F\x73\x70\x65\x63\x75\x6C\x61\x72\x00\x3E\x99\x99\x9A" "\x01\x03\x62\x31\x72\x5F\x66\x6F\x67\x5F\x65\x78\x70\x32\x00\x00\x00\x00\x00\x01\x04\x42\x31\x76\x65\x72\x74\x65\x78\x6C\x69\x74" @@ -6236,7 +6237,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "\x81\x00\x05\x00\x06\x00\x00\x00\x31\x00\x00\x00\x2D\x00\x00\x00\x30\x00\x00\x00\x88\x00\x05\x00\x06\x00\x00\x00\x33\x00\x00\x00" "\x31\x00\x00\x00\x32\x00\x00\x00\x41\x00\x05\x00\x26\x00\x00\x00\x34\x00\x00\x00\x0C\x00\x00\x00\x2B\x00\x00\x00\x3E\x00\x03\x00" "\x34\x00\x00\x00\x33\x00\x00\x00\x3D\x00\x04\x00\x07\x00\x00\x00\x35\x00\x00\x00\x0C\x00\x00\x00\xFE\x00\x02\x00\x35\x00\x00\x00" -"\x38\x00\x01\x00\x03\x02\x23\x07\x00\x00\x01\x00\x01\x00\x08\x00\xDD\x02\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00" +"\x38\x00\x01\x00\x03\x02\x23\x07\x00\x00\x01\x00\x01\x00\x08\x00\xDE\x02\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00" "\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00" "\x01\x00\x00\x00\x0F\x00\x0C\x00\x04\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x3F\x00\x00\x00\x97\x01\x00\x00" "\x9F\x01\x00\x00\xA8\x01\x00\x00\xCF\x01\x00\x00\xDD\x01\x00\x00\x4C\x02\x00\x00\x10\x00\x03\x00\x04\x00\x00\x00\x07\x00\x00\x00" @@ -6292,16 +6293,16 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "\x66\x6C\x65\x63\x74\x6D\x61\x73\x6B\x00\x00\x00\x05\x00\x06\x00\x71\x02\x00\x00\x73\x5F\x72\x65\x66\x6C\x65\x63\x74\x63\x75\x62" "\x65\x00\x00\x00\x05\x00\x03\x00\x81\x02\x00\x00\x70\x61\x6C\x00\x05\x00\x05\x00\x82\x02\x00\x00\x73\x5F\x70\x61\x6C\x65\x74\x74" "\x65\x64\x00\x00\x05\x00\x04\x00\x8B\x02\x00\x00\x73\x5F\x74\x30\x00\x00\x00\x00\x05\x00\x06\x00\xB3\x02\x00\x00\x73\x5F\x66\x75" -"\x6C\x6C\x62\x72\x69\x67\x68\x74\x00\x00\x00\x00\x05\x00\x04\x00\xD7\x02\x00\x00\x70\x61\x72\x61\x6D\x00\x00\x00\x05\x00\x05\x00" -"\xDA\x02\x00\x00\x6C\x69\x67\x68\x74\x62\x6C\x6F\x63\x6B\x00\x00\x06\x00\x07\x00\xDA\x02\x00\x00\x00\x00\x00\x00\x6C\x5F\x63\x75" -"\x62\x65\x6D\x61\x74\x72\x69\x78\x00\x00\x00\x00\x06\x00\x07\x00\xDA\x02\x00\x00\x01\x00\x00\x00\x6C\x5F\x6C\x69\x67\x68\x74\x70" -"\x6F\x73\x69\x74\x69\x6F\x6E\x00\x06\x00\x05\x00\xDA\x02\x00\x00\x02\x00\x00\x00\x6C\x70\x61\x64\x31\x00\x00\x00\x06\x00\x07\x00" -"\xDA\x02\x00\x00\x03\x00\x00\x00\x6C\x5F\x6C\x69\x67\x68\x74\x63\x6F\x6C\x6F\x75\x72\x00\x00\x00\x06\x00\x05\x00\xDA\x02\x00\x00" -"\x04\x00\x00\x00\x6C\x70\x61\x64\x32\x00\x00\x00\x06\x00\x08\x00\xDA\x02\x00\x00\x05\x00\x00\x00\x6C\x5F\x6C\x69\x67\x68\x74\x63" -"\x6F\x6C\x6F\x75\x72\x73\x63\x61\x6C\x65\x00\x00\x06\x00\x07\x00\xDA\x02\x00\x00\x06\x00\x00\x00\x6C\x5F\x6C\x69\x67\x68\x74\x72" -"\x61\x64\x69\x75\x73\x00\x00\x00\x06\x00\x07\x00\xDA\x02\x00\x00\x07\x00\x00\x00\x6C\x5F\x73\x68\x61\x64\x6F\x77\x6D\x61\x70\x70" -"\x72\x6F\x6A\x00\x06\x00\x08\x00\xDA\x02\x00\x00\x08\x00\x00\x00\x6C\x5F\x73\x68\x61\x64\x6F\x77\x6D\x61\x70\x73\x63\x61\x6C\x65" -"\x00\x00\x00\x00\x06\x00\x05\x00\xDA\x02\x00\x00\x09\x00\x00\x00\x6C\x70\x61\x64\x33\x00\x00\x00\x05\x00\x03\x00\xDC\x02\x00\x00" +"\x6C\x6C\x62\x72\x69\x67\x68\x74\x00\x00\x00\x00\x05\x00\x04\x00\xD8\x02\x00\x00\x70\x61\x72\x61\x6D\x00\x00\x00\x05\x00\x05\x00" +"\xDB\x02\x00\x00\x6C\x69\x67\x68\x74\x62\x6C\x6F\x63\x6B\x00\x00\x06\x00\x07\x00\xDB\x02\x00\x00\x00\x00\x00\x00\x6C\x5F\x63\x75" +"\x62\x65\x6D\x61\x74\x72\x69\x78\x00\x00\x00\x00\x06\x00\x07\x00\xDB\x02\x00\x00\x01\x00\x00\x00\x6C\x5F\x6C\x69\x67\x68\x74\x70" +"\x6F\x73\x69\x74\x69\x6F\x6E\x00\x06\x00\x05\x00\xDB\x02\x00\x00\x02\x00\x00\x00\x6C\x70\x61\x64\x31\x00\x00\x00\x06\x00\x07\x00" +"\xDB\x02\x00\x00\x03\x00\x00\x00\x6C\x5F\x6C\x69\x67\x68\x74\x63\x6F\x6C\x6F\x75\x72\x00\x00\x00\x06\x00\x05\x00\xDB\x02\x00\x00" +"\x04\x00\x00\x00\x6C\x70\x61\x64\x32\x00\x00\x00\x06\x00\x08\x00\xDB\x02\x00\x00\x05\x00\x00\x00\x6C\x5F\x6C\x69\x67\x68\x74\x63" +"\x6F\x6C\x6F\x75\x72\x73\x63\x61\x6C\x65\x00\x00\x06\x00\x07\x00\xDB\x02\x00\x00\x06\x00\x00\x00\x6C\x5F\x6C\x69\x67\x68\x74\x72" +"\x61\x64\x69\x75\x73\x00\x00\x00\x06\x00\x07\x00\xDB\x02\x00\x00\x07\x00\x00\x00\x6C\x5F\x73\x68\x61\x64\x6F\x77\x6D\x61\x70\x70" +"\x72\x6F\x6A\x00\x06\x00\x08\x00\xDB\x02\x00\x00\x08\x00\x00\x00\x6C\x5F\x73\x68\x61\x64\x6F\x77\x6D\x61\x70\x73\x63\x61\x6C\x65" +"\x00\x00\x00\x00\x06\x00\x05\x00\xDB\x02\x00\x00\x09\x00\x00\x00\x6C\x70\x61\x64\x33\x00\x00\x00\x05\x00\x03\x00\xDD\x02\x00\x00" "\x00\x00\x00\x00\x47\x00\x04\x00\x28\x00\x00\x00\x01\x00\x00\x00\x15\x00\x00\x00\x47\x00\x04\x00\x36\x00\x00\x00\x06\x00\x00\x00" "\x10\x00\x00\x00\x48\x00\x04\x00\x37\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x48\x00\x05\x00\x37\x00\x00\x00\x00\x00\x00\x00" "\x23\x00\x00\x00\x00\x00\x00\x00\x48\x00\x05\x00\x37\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x10\x00\x00\x00\x48\x00\x04\x00" @@ -6341,15 +6342,15 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "\x22\x00\x00\x00\x00\x00\x00\x00\x47\x00\x04\x00\x8B\x02\x00\x00\x21\x00\x00\x00\x0B\x00\x00\x00\x47\x00\x04\x00\xAF\x02\x00\x00" "\x01\x00\x00\x00\x11\x00\x00\x00\x47\x00\x04\x00\xB3\x02\x00\x00\x22\x00\x00\x00\x00\x00\x00\x00\x47\x00\x04\x00\xB3\x02\x00\x00" "\x21\x00\x00\x00\x05\x00\x00\x00\x47\x00\x04\x00\xC2\x02\x00\x00\x01\x00\x00\x00\x06\x01\x00\x00\x47\x00\x04\x00\xC6\x02\x00\x00" -"\x01\x00\x00\x00\x07\x01\x00\x00\x48\x00\x04\x00\xDA\x02\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x48\x00\x05\x00\xDA\x02\x00\x00" -"\x00\x00\x00\x00\x23\x00\x00\x00\x00\x00\x00\x00\x48\x00\x05\x00\xDA\x02\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x10\x00\x00\x00" -"\x48\x00\x05\x00\xDA\x02\x00\x00\x01\x00\x00\x00\x23\x00\x00\x00\x40\x00\x00\x00\x48\x00\x05\x00\xDA\x02\x00\x00\x02\x00\x00\x00" -"\x23\x00\x00\x00\x4C\x00\x00\x00\x48\x00\x05\x00\xDA\x02\x00\x00\x03\x00\x00\x00\x23\x00\x00\x00\x50\x00\x00\x00\x48\x00\x05\x00" -"\xDA\x02\x00\x00\x04\x00\x00\x00\x23\x00\x00\x00\x5C\x00\x00\x00\x48\x00\x05\x00\xDA\x02\x00\x00\x05\x00\x00\x00\x23\x00\x00\x00" -"\x60\x00\x00\x00\x48\x00\x05\x00\xDA\x02\x00\x00\x06\x00\x00\x00\x23\x00\x00\x00\x6C\x00\x00\x00\x48\x00\x05\x00\xDA\x02\x00\x00" -"\x07\x00\x00\x00\x23\x00\x00\x00\x70\x00\x00\x00\x48\x00\x05\x00\xDA\x02\x00\x00\x08\x00\x00\x00\x23\x00\x00\x00\x80\x00\x00\x00" -"\x48\x00\x05\x00\xDA\x02\x00\x00\x09\x00\x00\x00\x23\x00\x00\x00\x88\x00\x00\x00\x47\x00\x03\x00\xDA\x02\x00\x00\x02\x00\x00\x00" -"\x47\x00\x04\x00\xDC\x02\x00\x00\x22\x00\x00\x00\x00\x00\x00\x00\x47\x00\x04\x00\xDC\x02\x00\x00\x21\x00\x00\x00\x01\x00\x00\x00" +"\x01\x00\x00\x00\x07\x01\x00\x00\x48\x00\x04\x00\xDB\x02\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x48\x00\x05\x00\xDB\x02\x00\x00" +"\x00\x00\x00\x00\x23\x00\x00\x00\x00\x00\x00\x00\x48\x00\x05\x00\xDB\x02\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x10\x00\x00\x00" +"\x48\x00\x05\x00\xDB\x02\x00\x00\x01\x00\x00\x00\x23\x00\x00\x00\x40\x00\x00\x00\x48\x00\x05\x00\xDB\x02\x00\x00\x02\x00\x00\x00" +"\x23\x00\x00\x00\x4C\x00\x00\x00\x48\x00\x05\x00\xDB\x02\x00\x00\x03\x00\x00\x00\x23\x00\x00\x00\x50\x00\x00\x00\x48\x00\x05\x00" +"\xDB\x02\x00\x00\x04\x00\x00\x00\x23\x00\x00\x00\x5C\x00\x00\x00\x48\x00\x05\x00\xDB\x02\x00\x00\x05\x00\x00\x00\x23\x00\x00\x00" +"\x60\x00\x00\x00\x48\x00\x05\x00\xDB\x02\x00\x00\x06\x00\x00\x00\x23\x00\x00\x00\x6C\x00\x00\x00\x48\x00\x05\x00\xDB\x02\x00\x00" +"\x07\x00\x00\x00\x23\x00\x00\x00\x70\x00\x00\x00\x48\x00\x05\x00\xDB\x02\x00\x00\x08\x00\x00\x00\x23\x00\x00\x00\x80\x00\x00\x00" +"\x48\x00\x05\x00\xDB\x02\x00\x00\x09\x00\x00\x00\x23\x00\x00\x00\x88\x00\x00\x00\x47\x00\x03\x00\xDB\x02\x00\x00\x02\x00\x00\x00" +"\x47\x00\x04\x00\xDD\x02\x00\x00\x22\x00\x00\x00\x00\x00\x00\x00\x47\x00\x04\x00\xDD\x02\x00\x00\x21\x00\x00\x00\x01\x00\x00\x00" "\x13\x00\x02\x00\x02\x00\x00\x00\x21\x00\x03\x00\x03\x00\x00\x00\x02\x00\x00\x00\x16\x00\x03\x00\x06\x00\x00\x00\x20\x00\x00\x00" "\x17\x00\x04\x00\x07\x00\x00\x00\x06\x00\x00\x00\x03\x00\x00\x00\x20\x00\x04\x00\x08\x00\x00\x00\x07\x00\x00\x00\x07\x00\x00\x00" "\x21\x00\x04\x00\x09\x00\x00\x00\x07\x00\x00\x00\x08\x00\x00\x00\x17\x00\x04\x00\x10\x00\x00\x00\x06\x00\x00\x00\x04\x00\x00\x00" @@ -6403,9 +6404,9 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "\x94\x02\x00\x00\x03\x00\x00\x00\x06\x00\x00\x00\x32\x00\x04\x00\x27\x00\x00\x00\xAF\x02\x00\x00\x11\x00\x00\x00\x3B\x00\x04\x00" "\x9C\x01\x00\x00\xB3\x02\x00\x00\x00\x00\x00\x00\x2B\x00\x04\x00\x27\x00\x00\x00\xBE\x02\x00\x00\x12\x00\x00\x00\x32\x00\x04\x00" "\x06\x00\x00\x00\xC2\x02\x00\x00\x00\x00\x83\x43\x32\x00\x04\x00\x27\x00\x00\x00\xC6\x02\x00\x00\x07\x01\x00\x00\x1E\x00\x0C\x00" -"\xDA\x02\x00\x00\x33\x00\x00\x00\x07\x00\x00\x00\x06\x00\x00\x00\x07\x00\x00\x00\x06\x00\x00\x00\x07\x00\x00\x00\x06\x00\x00\x00" -"\x10\x00\x00\x00\x1F\x00\x00\x00\x1F\x00\x00\x00\x20\x00\x04\x00\xDB\x02\x00\x00\x02\x00\x00\x00\xDA\x02\x00\x00\x3B\x00\x04\x00" -"\xDB\x02\x00\x00\xDC\x02\x00\x00\x02\x00\x00\x00\x36\x00\x05\x00\x02\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00" +"\xDB\x02\x00\x00\x33\x00\x00\x00\x07\x00\x00\x00\x06\x00\x00\x00\x07\x00\x00\x00\x06\x00\x00\x00\x07\x00\x00\x00\x06\x00\x00\x00" +"\x10\x00\x00\x00\x1F\x00\x00\x00\x1F\x00\x00\x00\x20\x00\x04\x00\xDC\x02\x00\x00\x02\x00\x00\x00\xDB\x02\x00\x00\x3B\x00\x04\x00" +"\xDC\x02\x00\x00\xDD\x02\x00\x00\x02\x00\x00\x00\x36\x00\x05\x00\x02\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00" "\xF8\x00\x02\x00\x05\x00\x00\x00\x3B\x00\x04\x00\x20\x00\x00\x00\x95\x01\x00\x00\x07\x00\x00\x00\x3B\x00\x04\x00\x1E\x00\x00\x00" "\xA0\x01\x00\x00\x07\x00\x00\x00\x3B\x00\x04\x00\x20\x00\x00\x00\xA2\x01\x00\x00\x07\x00\x00\x00\x3B\x00\x04\x00\x08\x00\x00\x00" "\xA4\x01\x00\x00\x07\x00\x00\x00\x3B\x00\x04\x00\x08\x00\x00\x00\xBA\x01\x00\x00\x07\x00\x00\x00\x3B\x00\x04\x00\x08\x00\x00\x00" @@ -6413,7 +6414,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "\xF9\x01\x00\x00\x07\x00\x00\x00\x3B\x00\x04\x00\x11\x00\x00\x00\x12\x02\x00\x00\x07\x00\x00\x00\x3B\x00\x04\x00\x08\x00\x00\x00" "\x19\x02\x00\x00\x07\x00\x00\x00\x3B\x00\x04\x00\x31\x00\x00\x00\x2A\x02\x00\x00\x07\x00\x00\x00\x3B\x00\x04\x00\x08\x00\x00\x00" "\x42\x02\x00\x00\x07\x00\x00\x00\x3B\x00\x04\x00\x31\x00\x00\x00\x81\x02\x00\x00\x07\x00\x00\x00\x3B\x00\x04\x00\x11\x00\x00\x00" -"\xD7\x02\x00\x00\x07\x00\x00\x00\x3D\x00\x04\x00\x1F\x00\x00\x00\x98\x01\x00\x00\x97\x01\x00\x00\x3E\x00\x03\x00\x95\x01\x00\x00" +"\xD8\x02\x00\x00\x07\x00\x00\x00\x3D\x00\x04\x00\x1F\x00\x00\x00\x98\x01\x00\x00\x97\x01\x00\x00\x3E\x00\x03\x00\x95\x01\x00\x00" "\x98\x01\x00\x00\xBA\x00\x05\x00\x2A\x00\x00\x00\x99\x01\x00\x00\x65\x01\x00\x00\x49\x00\x00\x00\xF7\x00\x03\x00\x9B\x01\x00\x00" "\x00\x00\x00\x00\xFA\x00\x04\x00\x99\x01\x00\x00\x9A\x01\x00\x00\x9B\x01\x00\x00\xF8\x00\x02\x00\x9A\x01\x00\x00\x3D\x00\x04\x00" "\x1D\x00\x00\x00\xA1\x01\x00\x00\x9D\x01\x00\x00\x3E\x00\x03\x00\xA0\x01\x00\x00\xA1\x01\x00\x00\x3D\x00\x04\x00\x1F\x00\x00\x00" @@ -6593,9 +6594,10 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "\x45\x00\x00\x00\x3D\x00\x04\x00\x06\x00\x00\x00\xD2\x02\x00\x00\xD1\x02\x00\x00\xBE\x00\x05\x00\x2A\x00\x00\x00\xD3\x02\x00\x00" "\xD2\x02\x00\x00\xC2\x02\x00\x00\xF7\x00\x03\x00\xD5\x02\x00\x00\x00\x00\x00\x00\xFA\x00\x04\x00\xD3\x02\x00\x00\xD4\x02\x00\x00" "\xD5\x02\x00\x00\xF8\x00\x02\x00\xD4\x02\x00\x00\xFC\x00\x01\x00\xF8\x00\x02\x00\xD5\x02\x00\x00\xF9\x00\x02\x00\xC9\x02\x00\x00" -"\xF8\x00\x02\x00\xC9\x02\x00\x00\xF9\x00\x02\x00\xC5\x02\x00\x00\xF8\x00\x02\x00\xC5\x02\x00\x00\x3D\x00\x04\x00\x10\x00\x00\x00" -"\xD8\x02\x00\x00\xA8\x01\x00\x00\x3E\x00\x03\x00\xD7\x02\x00\x00\xD8\x02\x00\x00\x39\x00\x05\x00\x10\x00\x00\x00\xD9\x02\x00\x00" -"\x14\x00\x00\x00\xD7\x02\x00\x00\x3E\x00\x03\x00\xA8\x01\x00\x00\xD9\x02\x00\x00\xFD\x00\x01\x00\x38\x00\x01\x00\x36\x00\x05\x00" +"\xF8\x00\x02\x00\xC9\x02\x00\x00\x41\x00\x05\x00\x94\x02\x00\x00\xD7\x02\x00\x00\xA8\x01\x00\x00\x45\x00\x00\x00\x3E\x00\x03\x00" +"\xD7\x02\x00\x00\x5D\x00\x00\x00\xF9\x00\x02\x00\xC5\x02\x00\x00\xF8\x00\x02\x00\xC5\x02\x00\x00\x3D\x00\x04\x00\x10\x00\x00\x00" +"\xD9\x02\x00\x00\xA8\x01\x00\x00\x3E\x00\x03\x00\xD8\x02\x00\x00\xD9\x02\x00\x00\x39\x00\x05\x00\x10\x00\x00\x00\xDA\x02\x00\x00" +"\x14\x00\x00\x00\xD8\x02\x00\x00\x3E\x00\x03\x00\xA8\x01\x00\x00\xDA\x02\x00\x00\xFD\x00\x01\x00\x38\x00\x01\x00\x36\x00\x05\x00" "\x07\x00\x00\x00\x0B\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x37\x00\x03\x00\x08\x00\x00\x00\x0A\x00\x00\x00\xF8\x00\x02\x00" "\x0C\x00\x00\x00\x3B\x00\x04\x00\x31\x00\x00\x00\x32\x00\x00\x00\x07\x00\x00\x00\x3B\x00\x04\x00\x31\x00\x00\x00\x57\x00\x00\x00" "\x07\x00\x00\x00\xAB\x00\x05\x00\x2A\x00\x00\x00\x2B\x00\x00\x00\x28\x00\x00\x00\x29\x00\x00\x00\xA8\x00\x04\x00\x2A\x00\x00\x00" @@ -6814,6 +6816,288 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "\xFE\x00\x02\x00\x90\x01\x00\x00\xF8\x00\x02\x00\x68\x01\x00\x00\xF9\x00\x02\x00\x12\x01\x00\x00\xF8\x00\x02\x00\x12\x01\x00\x00" "\x3D\x00\x04\x00\x1F\x00\x00\x00\x92\x01\x00\x00\x23\x00\x00\x00\xFE\x00\x02\x00\x92\x01\x00\x00\x38\x00\x01\x00"}, #endif +#ifdef D3D9QUAKE +{QR_DIRECT3D9, 9, "defaultwall", +//!!ver 100 150 +//!!permu DELUXE +"!!permu FULLBRIGHT\n" +"!!permu FOG\n" +//!!permu LIGHTSTYLED +//!!permu BUMP +//!!permu SPECULAR +//!!permu REFLECTCUBEMASK +//!!cvarf r_glsl_offsetmapping_scale +//!!cvardf r_tessellation_level=5 +//!!samps diffuse lightmap specular normalmap fullbright reflectmask reflectcube paletted lightmap1 lightmap2 lightmap3 +"!!samps diffuse fullbright lightmap\n" + +//#include "sys/defs.h" +"#define vec4 float4\n" +"#define vec3 float3\n" +"#define vec2 float2\n" +"#define texture2D tex2D\n" +"#define mat3 float3x3\n" +"#define mat4 float4x4\n" +"struct a2v\n" +"{\n" +"vec4 v_position : POSITION;\n" +"vec2 v_texcoord : TEXCOORD0;\n" +"vec2 v_lmcoord : TEXCOORD1;\n" +"};\n" +"struct v2f\n" +"{\n" +"#ifndef FRAGMENT_SHADER\n" +"vec4 pos: POSITION;\n" +"#endif\n" + +"#if defined(OFFSETMAPPING) || defined(SPECULAR) || defined(REFLECTCUBEMASK) || defined(FOG)\n" +"vec3 eyevector : TEXCOORD4;\n" +"#endif\n" + +"#if defined(REFLECTCUBEMASK) || defined(BUMPMODELSPACE)\n" +"mat3 invsurface : TEXCOORD5;\n" +"#endif\n" + +"vec4 tclm : TEXCOORD0;\n" +"vec4 vc : COLOR0;\n" +"#ifndef VERTEXLIT\n" +"#ifdef LIGHTSTYLED\n" +//we could use an offset, but that would still need to be per-surface which would break batches +//fixme: merge attributes? +"vec2 lm1 : TEXCOORD1, lm2 : TEXCOORD2, lm3 : TEXCOORD3;\n" +"#endif\n" +"#endif\n" +"};\n" + +//this is what normally draws all of your walls, even with rtlights disabled +//note that the '286' preset uses drawflat_walls instead. + +"#include \"sys/fog.h\"\n" + +"#ifdef VERTEX_SHADER\n" +"float4x4 m_modelviewprojection;\n" +"float4x4 m_modelview;\n" +"vec3 e_eyepos;\n" +"vec4 e_lmscale;\n" +"v2f main (a2v inp)\n" +"{\n" +"v2f outp;\n" + +"#if defined(OFFSETMAPPING) || defined(SPECULAR) || defined(REFLECTCUBEMASK)\n" +"vec3 eyeminusvertex = e_eyepos - inp.v_position.xyz;\n" +"outp.eyevector.x = dot(eyeminusvertex, inp.v_svector.xyz);\n" +"outp.eyevector.y = dot(eyeminusvertex, inp.v_tvector.xyz);\n" +"outp.eyevector.z = dot(eyeminusvertex, inp.v_normal.xyz);\n" +"#elif defined(FOG)\n" +"outp.eyevector = mul(m_modelview, inp.v_position);\n" +"#endif\n" +"#if defined(REFLECTCUBEMASK) || defined(BUMPMODELSPACE)\n" +"outp.invsurface[0] = inp.v_svector;\n" +"outp.invsurface[1] = inp.v_tvector;\n" +"outp.invsurface[2] = inp.v_normal;\n" +"#endif\n" +"outp.tclm.xy = inp.v_texcoord;\n" +"#ifdef FLOW\n" +// outp.tclm.x += e_time * -0.5; +"#endif\n" +"#ifdef VERTEXLIT\n" +"#ifdef LIGHTSTYLED\n" +//FIXME, only one colour. +"outp.vc = inp.v_colour * e_lmscale[0];\n" +"#else\n" +"outp.vc = inp.v_colour * e_lmscale;\n" +"#endif\n" +"#else\n" +"outp.vc = e_lmscale;\n" +"outp.tclm.zw = inp.v_lmcoord;\n" +"#ifdef LIGHTSTYLED\n" +"outp.lm1 = inp.v_lmcoord2;\n" +"outp.lm2 = inp.v_lmcoord3;\n" +"outp.lm3 = inp.v_lmcoord4;\n" +"#endif\n" +"#endif\n" +"outp.pos = mul(m_modelviewprojection, inp.v_position);\n" + +"return outp;\n" +"}\n" +"#endif\n" + + + + + + + + + + +"#ifdef FRAGMENT_SHADER\n" +"sampler s_diffuse : register(s0);\n" +//sampler s_normalmap; +//sampler s_specular; +//sampler s_upper; +//sampler s_lower; +"sampler s_fullbright : register(s1);\n" +//sampler s_paletted; +//sampler s_reflectcube; +//sampler s_reflectmask; +"sampler s_lightmap : register(s2);\n" +//sampler s_deluxmap; + + +//samplers +"#define s_colourmap s_t0\n" +//sampler2D s_colourmap; + +//vec4 e_lmscale; +"vec4 e_colourident;\n" + +"#ifdef OFFSETMAPPING\n" +"#include \"sys/offsetmapping.h\"\n" +"#endif\n" +"vec4 main (v2f inp) : COLOR0\n" +"{\n" +"vec4 gl_FragColor;\n" +"#define tc (inp.tclm.xy)\n" +"#define lm0 (inp.tclm.zw)\n" + + +//adjust texture coords for offsetmapping +"#ifdef OFFSETMAPPING\n" +"vec2 tcoffsetmap = offsetmap(s_normalmap, tc, eyevector);\n" +"#define tc tcoffsetmap\n" +"#endif\n" + +"#if defined(EIGHTBIT) && !defined(LIGHTSTYLED)\n" +//optional: round the lightmap coords to ensure all pixels within a texel have different lighting values either. it just looks wrong otherwise. +//don't bother if its lightstyled, such cases will have unpredictable correlations anyway. +//FIXME: this rounding is likely not correct with respect to software rendering. oh well. +"#if __VERSION__ >= 130\n" +"vec2 lmsize = vec2(textureSize(s_lightmap0, 0));\n" +"#else\n" +"#define lmsize vec2(128.0,2048.0)\n" +"#endif\n" +"#define texelstolightmap (16.0)\n" +"vec2 lmcoord0 = floor(lm0 * lmsize*texelstolightmap)/(lmsize*texelstolightmap);\n" +"#define lm0 lmcoord0\n" +"#endif\n" + + +//yay, regular texture! +"gl_FragColor = texture2D(s_diffuse, tc);\n" + +"#if defined(BUMP) && (defined(DELUXE) || defined(SPECULAR) || defined(REFLECTCUBEMASK))\n" +"vec3 norm = normalize(texture2D(s_normalmap, tc).rgb - 0.5);\n" +"#elif defined(SPECULAR) || defined(DELUXE) || defined(REFLECTCUBEMASK)\n" +"vec3 norm = vec3(0, 0, 1); //specular lighting expects this to exist.\n" +"#endif\n" + +//modulate that by the lightmap(s) including deluxemap(s) +"#ifdef VERTEXLIT\n" +"#error foobar\n" +"#ifdef LIGHTSTYLED\n" +"vec3 lightmaps = vc.rgb;\n" +"#else\n" +"vec3 lightmaps = vc.rgb;\n" +"#endif\n" +"#define delux vec3(0.0,0.0,1.0)\n" +"#else\n" +"#ifdef LIGHTSTYLED\n" +"#error foobar\n" +"#define delux vec3(0.0,0.0,1.0)\n" +"vec3 lightmaps;\n" +"#ifdef DELUXE\n" +"lightmaps = texture2D(s_lightmap0, lm0).rgb * e_lmscale[0].rgb * dot(norm, 2.0*texture2D(s_deluxmap0, lm0).rgb-0.5);\n" +"lightmaps += texture2D(s_lightmap1, lm1).rgb * e_lmscale[1].rgb * dot(norm, 2.0*texture2D(s_deluxmap1, lm1).rgb-0.5);\n" +"lightmaps += texture2D(s_lightmap2, lm2).rgb * e_lmscale[2].rgb * dot(norm, 2.0*texture2D(s_deluxmap2, lm2).rgb-0.5);\n" +"lightmaps += texture2D(s_lightmap3, lm3).rgb * e_lmscale[3].rgb * dot(norm, 2.0*texture2D(s_deluxmap3, lm3).rgb-0.5);\n" +"#else\n" +"lightmaps = texture2D(s_lightmap0, lm0).rgb * e_lmscale[0].rgb;\n" +"lightmaps += texture2D(s_lightmap1, lm1).rgb * e_lmscale[1].rgb;\n" +"lightmaps += texture2D(s_lightmap2, lm2).rgb * e_lmscale[2].rgb;\n" +"lightmaps += texture2D(s_lightmap3, lm3).rgb * e_lmscale[3].rgb;\n" +"#endif\n" +"#else\n" +"vec3 lightmaps = texture2D(s_lightmap, lm0).rgb;\n" +//modulate by the bumpmap dot light +"#ifdef DELUXE\n" +"#error foobar\n" +"vec3 delux = (texture2D(s_deluxmap, lm0).rgb-0.5);\n" +"#ifdef BUMPMODELSPACE\n" +"delux = normalize(delux*invsurface);\n" +"#else\n" +"lightmaps *= 2.0 / max(0.25, delux.z); //counter the darkening from deluxmaps\n" +"#endif\n" +"lightmaps *= dot(norm, delux);\n" +"#else\n" +"#define delux vec3(0.0,0.0,1.0)\n" +"#endif\n" +"#endif\n" +"lightmaps *= inp.vc.rgb;\n" +"#endif\n" + +//add in specular, if applicable. +"#ifdef SPECULAR\n" +"vec4 specs = texture2D(s_specular, tc);\n" +"vec3 halfdir = normalize(normalize(eyevector) + delux); //this norm should be the deluxemap info instead\n" +"float spec = pow(max(dot(halfdir, norm), 0.0), FTE_SPECULAR_EXPONENT * specs.a);\n" +"spec *= FTE_SPECULAR_MULTIPLIER;\n" +//NOTE: rtlights tend to have a *4 scaler here to over-emphasise the effect because it looks cool. +//As not all maps will have deluxemapping, and the double-cos from the light util makes everything far too dark anyway, +//we default to something that is not garish when the light value is directly infront of every single pixel. +//we can justify this difference due to the rtlight editor etc showing the *4. +"gl_FragColor.rgb += spec * specs.rgb;\n" +"#endif\n" + +"#ifdef REFLECTCUBEMASK\n" +"vec3 rtc = reflect(normalize(-eyevector), norm);\n" +"rtc = rtc.x*invsurface[0] + rtc.y*invsurface[1] + rtc.z*invsurface[2];\n" +"rtc = (m_model * vec4(rtc.xyz,0.0)).xyz;\n" +"gl_FragColor.rgb += texture2D(s_reflectmask, tc).rgb * textureCube(s_reflectcube, rtc).rgb;\n" +"#endif\n" + +"#ifdef EIGHTBIT //FIXME: with this extra flag, half the permutations are redundant.\n" +"lightmaps *= 0.5; //counter the fact that the colourmap contains overbright values and logically ranges from 0 to 2 intead of to 1.\n" +"float pal = texture2D(s_paletted, tc).r; //the palette index. hopefully not interpolated.\n" +"lightmaps -= 1.0 / 128.0; //software rendering appears to round down, so make sure we favour the lower values instead of rounding to the nearest\n" +"gl_FragColor.r = texture2D(s_colourmap, vec2(pal, 1.0-lightmaps.r)).r; //do 3 lookups. this is to cope with lit files, would be a waste to not support those.\n" +"gl_FragColor.g = texture2D(s_colourmap, vec2(pal, 1.0-lightmaps.g)).g; //its not very softwarey, but re-palettizing is ugly.\n" +"gl_FragColor.b = texture2D(s_colourmap, vec2(pal, 1.0-lightmaps.b)).b; //without lits, it should be identical.\n" +"#else\n" +//now we have our diffuse+specular terms, modulate by lightmap values. +"gl_FragColor.rgb *= lightmaps.rgb;\n" + +//add on the fullbright +"#ifdef FULLBRIGHT\n" +"vec4 fb = texture2D(s_fullbright, tc);\n" +"gl_FragColor.rgb += fb.rgb*fb.a;\n" +"#endif\n" +"#endif\n" + +//entity modifiers +"gl_FragColor = gl_FragColor * e_colourident;\n" + +"#if defined(MASK)\n" +"#if defined(MASKLT)\n" +"if (gl_FragColor.a < MASK)\n" +"discard;\n" +"#else\n" +"if (gl_FragColor.a >= MASK)\n" +"discard;\n" +"#endif\n" +"gl_FragColor.a = 1.0; //alpha blending AND alpha testing usually looks stupid, plus it screws up our fog.\n" +"#endif\n" + +//and finally hide it all if we're fogged. +"#ifdef FOG\n" +"gl_FragColor = fog4(gl_FragColor, length(inp.eyevector));\n" +"#endif\n" +"return gl_FragColor;\n" +"}\n" +"#endif\n" + +}, +#endif #ifdef D3D11QUAKE {QR_DIRECT3D11, 11, "defaultwall", "!!samps diffuse fullbright lightmap\n" diff --git a/engine/qclib/qcc.h b/engine/qclib/qcc.h index d93a3afc1..8cdee095e 100644 --- a/engine/qclib/qcc.h +++ b/engine/qclib/qcc.h @@ -774,6 +774,7 @@ enum { WARN_IMPLICITCONVERSION, WARN_EXTRAPRECACHE, WARN_NOTPRECACHED, + WARN_NONPORTABLEFILENAME, WARN_DEADCODE, WARN_UNREACHABLECODE, WARN_NOTSTANDARDBEHAVIOUR, diff --git a/engine/qclib/qcc_pr_comp.c b/engine/qclib/qcc_pr_comp.c index a65837ac1..bcc75dd55 100644 --- a/engine/qclib/qcc_pr_comp.c +++ b/engine/qclib/qcc_pr_comp.c @@ -4384,6 +4384,8 @@ void QCC_PrecacheSound (const char *n, int ch) precache_sound[i].block = ch; return; } + if (strchr(n, '\\')) + QCC_PR_ParseWarning(WARN_NONPORTABLEFILENAME, "backslashes in path names are non-portable - %s", n); if (numsounds == QCC_MAX_SOUNDS) return; // QCC_Error ("PrecacheSound: numsounds == MAX_SOUNDS"); @@ -4412,6 +4414,8 @@ void QCC_PrecacheModel (const char *n, int ch) } return; } + if (strchr(n, '\\')) + QCC_PR_ParseWarning(WARN_NONPORTABLEFILENAME, "backslashes in path names are non-portable - %s", n); if (nummodels == QCC_MAX_MODELS) return; // QCC_Error ("PrecacheModels: nummodels == MAX_MODELS"); @@ -4437,6 +4441,8 @@ void QCC_SetModel (const char *n) precache_model[i].used++; return; } + if (strchr(n, '\\')) + QCC_PR_ParseWarning(WARN_NONPORTABLEFILENAME, "backslashes in path names are non-portable - %s", n); if (nummodels == QCC_MAX_MODELS) return; strcpy (precache_model[i].name, n); @@ -4459,6 +4465,8 @@ void QCC_SoundUsed (const char *n) precache_sound[i].used++; return; } + if (strchr(n, '\\')) + QCC_PR_ParseWarning(WARN_NONPORTABLEFILENAME, "backslashes in path names are non-portable - %s", n); if (numsounds == QCC_MAX_SOUNDS) return; strcpy (precache_sound[i].name, n); @@ -4479,6 +4487,8 @@ void QCC_PrecacheTexture (const char *n, int ch) for (i=0 ; iname = (float *)PR_FindGlobal(svprogfuncs, #name, 0, NULL); if (need && !(pr_globals)->name) {static float fallback##name; (pr_globals)->name = &fallback##name; if (!muted) Con_DPrintf("Could not find \""#name"\" export in progs\n");} #define globalint(need,name) (pr_globals)->name = (int *)PR_FindGlobal(svprogfuncs, #name, 0, NULL); if (need && !(pr_globals)->name) {static int fallback##name; (pr_globals)->name = &fallback##name; if (!muted) Con_DPrintf("Could not find \""#name"\" export in progs\n");} #define globalstring(need,name) (pr_globals)->name = (int *)PR_FindGlobal(svprogfuncs, #name, 0, NULL); if (need && !(pr_globals)->name) {static string_t fallback##name; (pr_globals)->name = &fallback##name; if (!muted) Con_DPrintf("Could not find \""#name"\" export in progs\n");} diff --git a/engine/server/pr_lua.c b/engine/server/pr_lua.c index 52259a17e..7d78deefb 100644 --- a/engine/server/pr_lua.c +++ b/engine/server/pr_lua.c @@ -5,6 +5,8 @@ #include "pr_common.h" #include "hash.h" +#define LUA_MALLOC_TAG 0x55780128 + #define luagloballist \ globalentity (true, self) \ globalentity (true, other) \ @@ -83,7 +85,7 @@ luaextragloballist typedef struct { int type; - quintptr_t offset; + qintptr_t offset; char *name; bucket_t buck; } luafld_t; @@ -2218,7 +2220,7 @@ static int bi_lua_pairs (lua_State *L) { static int bi_lua_objerror (lua_State *L) { - SV_Error("objerror: %s\n", lua_tostring(L, 1)); + Con_Printf("\n"); lua_pushedict(L, lua.edicttable[lua.globals.self]); lua_pushnil(L); @@ -2230,11 +2232,11 @@ static int bi_lua_objerror (lua_State *L) { int i; const void *ud = lua_topointer(L, -2); - for (i = 0; i < countof(lua.entflds); i++) - if (lua.entflds[i].offset == (quintptr_t)ud) + for (i = 0; i < lua.numflds; i++) + if (lua.entflds[i].offset == (qintptr_t)ud) break; - if (i == countof(lua.entflds)) + if (i == lua.numflds) Con_Printf("%21s:", lua_typename(L, lua_type(L, -2))); else Con_Printf("%21s:", lua.entflds[i].name); @@ -2260,6 +2262,8 @@ static int bi_lua_objerror (lua_State *L) } lua_pop(L, 1); + + Con_Printf("objerror: %s\n", lua_tostring(L, 1)); return 0; } static int bi_lua_error (lua_State *L) @@ -2788,7 +2792,6 @@ static const char *Lua_ParseEdict (pubprogfuncs_t *progfuncs, const char *data, } */ cont: - fld = Hash_GetInsensitive(&lua.entityfields, keyname); if (fld && fld->type == ev_float) lua_pushnumber(L, atof(token)); @@ -2809,6 +2812,13 @@ cont: e++; lua_pushvector(L, x, y, z); } + else if (fld && fld->type == ev_function) + lua_getglobal(L, token); //functions are nameless, except for how they're invoked. so this is only for evil mods... + else if (fld && fld->type == ev_entity) + { + int num = atoi(token); + lua_pushedict(L, EDICT_NUM_UB((&lua.progfuncs), num)); + } else lua_pushstring(L, token); lua_setfield(L, -2, keyname); @@ -2942,7 +2952,7 @@ char *QDECL Lua_AddString(pubprogfuncs_t *prinst, const char *val, int minlength int len = strlen(val)+1; if (len < minlength) len = minlength; - ptr = Z_TagMalloc(len, 0x55780128); + ptr = Z_TagMalloc(len, LUA_MALLOC_TAG); strcpy(ptr, val); return ptr; } @@ -3215,6 +3225,8 @@ void PDECL Lua_CloseProgs(pubprogfuncs_t *inst) lua.maxedicts = 0; memset(&lua, 0, sizeof(lua)); + + Z_FreeTags(LUA_MALLOC_TAG); } static void QDECL Lua_Get_FrameState(world_t *w, wedict_t *ent, framestate_t *fstate) diff --git a/engine/server/savegame.c b/engine/server/savegame.c index 4b8884a81..ccae6b290 100644 --- a/engine/server/savegame.c +++ b/engine/server/savegame.c @@ -1413,7 +1413,7 @@ static int QDECL CompleteSaveList (const char *name, qofs_t flags, time_t mtime, if (l >= 9 && !Q_strcasecmp(trimmed+l-9, "/info.fsv")) { trimmed[l-9] = 0; - ctx->cb(trimmed, ctx); + ctx->cb(trimmed, NULL, NULL, ctx); } return true; } @@ -1422,7 +1422,7 @@ static int QDECL CompleteSaveListLegacy (const char *name, qofs_t flags, time_t struct xcommandargcompletioncb_s *ctx = parm; char stripped[64]; COM_StripExtension(name, stripped, sizeof(stripped)); - ctx->cb(stripped, ctx); + ctx->cb(stripped, NULL, NULL, ctx); return true; } void SV_Savegame_c(int argn, const char *partial, struct xcommandargcompletioncb_s *ctx) diff --git a/engine/server/sv_ccmds.c b/engine/server/sv_ccmds.c index d55b0329c..9765394bf 100644 --- a/engine/server/sv_ccmds.c +++ b/engine/server/sv_ccmds.c @@ -411,7 +411,7 @@ static int QDECL CompleteMapList (const char *name, qofs_t flags, time_t mtime, return true; COM_StripExtension(name+5, stripped, sizeof(stripped)); - ctx->cb(stripped, ctx); + ctx->cb(stripped, NULL, NULL, ctx); return true; } static int QDECL CompleteMapListExt (const char *name, qofs_t flags, time_t mtime, void *parm, searchpathfuncs_t *spath) @@ -420,7 +420,7 @@ static int QDECL CompleteMapListExt (const char *name, qofs_t flags, time_t mtim if (name[5] == 'b' && name[6] == '_') //skip box models return true; - ctx->cb(name+5, ctx); + ctx->cb(name+5, NULL, NULL, ctx); return true; } static void SV_Map_c(int argn, const char *partial, struct xcommandargcompletioncb_s *ctx) diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index d5af188a3..fb39e7334 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -132,7 +132,7 @@ cvar_t pext_ezquake_nochunks = CVARD("pext_ezquake_nochunks", "0", "Prevents ezq cvar_t sv_gamespeed = CVARAF("sv_gamespeed", "1", "slowmo", 0); cvar_t sv_csqcdebug = CVAR("sv_csqcdebug", "0"); cvar_t sv_csqc_progname = CVAR("sv_csqc_progname", "csprogs.dat"); -cvar_t pausable = CVAR("pausable", "1"); +cvar_t pausable = CVAR("pausable", ""); cvar_t sv_banproxies = CVARD("sv_banproxies", "0", "If enabled, anyone connecting via known proxy software will be refused entry. This should aid with blocking aimbots, but is only reliable for certain public proxies."); cvar_t sv_specprint = CVARD("sv_specprint", "3", "Bitfield that controls which player events spectators see when tracking that player.\n&1: spectators will see centerprints.\n&2: spectators will see sprints (pickup messages etc).\n&4: spectators will receive console commands, this is potentially risky.\nIndividual spectators can use 'setinfo sp foo' to limit this setting."); diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index 601213469..7f70efa7f 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -2225,7 +2225,7 @@ void WPhys_RunEntity (world_t *w, wedict_t *ent) else gravitydir = w->g.defaultgravitydir; - if (!WPhys_CheckWater (w, ent) && ! ((int)ent->v->flags & FL_WATERJUMP) ) + if (!WPhys_CheckWater (w, ent) && ! ((int)ent->v->flags & FL_WATERJUMP) ) //Vanilla Bug: the QC checks waterlevel inside PlayerPreThink, with waterlevel from a different position from the origin. WPhys_AddGravity (w, ent, gravitydir); WPhys_CheckStuck (w, ent); diff --git a/engine/server/sv_sys_unix.c b/engine/server/sv_sys_unix.c index 4d9a99ddc..7e8bd3b2a 100644 --- a/engine/server/sv_sys_unix.c +++ b/engine/server/sv_sys_unix.c @@ -728,7 +728,7 @@ static int Sys_CheckChRoot(void) const char *newhome; getresuid(&ruid, &euid, &suid); - printf("ruid %u, euid %u, suid %u\n", ruid, euid, suid); +// printf("ruid %u, euid %u, suid %u\n", ruid, euid, suid); if (!euid && ruid != euid) { //if we're running SUID-root then assume the admin set it up that way in order to use chroot without making any libraries available inside the jail. //however, chroot needs a certain level of sandboxing to prevent somehow running suid programs with eg a custom /etc/passwd, etc. @@ -775,7 +775,7 @@ static int Sys_CheckChRoot(void) //SSL_InitGlobal(true); //make sure we load our public cert from outside the sandbox. an exploit might still be able to find it in memory though. FIXME: disabled in case this reads from somewhere bad - we're still root. #endif - printf("Changing to root: \"%s\"\n", newroot); + printf("Changing root dir to \"%s\"\n", newroot); if (chroot(newroot)) { printf("chroot call failed\n"); diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index c41969d19..78e20654d 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -4007,7 +4007,12 @@ SV_Pause_f */ void SV_Pause_f (void) { - if (!pausable.value) + int maypause; + if (!*pausable.string) + maypause = !deathmatch.ival; + else + maypause = pausable.ival; + if (!maypause) { SV_ClientTPrintf (host_client, PRINT_HIGH, "Can't pause. Not allowed\n"); return; diff --git a/engine/shaders/glsl/defaultwall.glsl b/engine/shaders/glsl/defaultwall.glsl index c0412e2a6..5f5353056 100644 --- a/engine/shaders/glsl/defaultwall.glsl +++ b/engine/shaders/glsl/defaultwall.glsl @@ -352,6 +352,7 @@ void main () if (gl_FragColor.a >= MASK) discard; #endif + gl_FragColor.a = 1.0; //alpha blending AND alpha testing usually looks stupid, plus it screws up our fog. #endif //and finally hide it all if we're fogged. diff --git a/engine/shaders/vulkan/defaultwall.glsl b/engine/shaders/vulkan/defaultwall.glsl index 1d62d296e..28e63b817 100644 --- a/engine/shaders/vulkan/defaultwall.glsl +++ b/engine/shaders/vulkan/defaultwall.glsl @@ -200,6 +200,7 @@ void main () if (gl_FragColor.a >= arg_mask) discard; } + gl_FragColor.a = 1.0; } //and finally hide it all if we're fogged.