From 4d25c073eccee3b90c8111056ec30475bc4cc7d6 Mon Sep 17 00:00:00 2001 From: Spoike Date: Mon, 26 Oct 2020 06:30:35 +0000 Subject: [PATCH] big commit. :( fix crash from qwplayers with invalid modelindexes rework allow_skybox a little. now applies immediately. try to fix the appears-outside-of-map bug, again. dir *.wav now shows a little extra info on mouse-over. try loading music file extensions that we expect to be able to play via ffmpeg, not just the ones that are directly supported. rework the hidden fps_presets, show them with tab completion. fix a possible crash with r_temporalscenecache fix lightmap updates on submodels not happening properly with the scenecache. fix the serious memory leak with scenecache. add r_glsl_pbr cvar to force use of pbr pathways in our glsl. fix bug in alsa output not supporting float output properly. preliminary work to have the mixer use floating point mixing. disabled for now. try to update sys_register_file_associations on linux, still needs work though. try to work around nquake's config quirks, so config files don't get overwritten. repackage quake's conchars in order to add padding. this should avoid extra junk on the outside of glyphs. give fteqcc(commandline version) some extra package extration/creation support. our paks should be more end-user-friendly, and our spanned pk3s are awesome. write rune state to legacy saved games, so we don't ever have the missing-runes bug ever again... git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5780 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/Makefile | 4 +- engine/client/cl_ents.c | 2 +- engine/client/cl_main.c | 104 +++++--- engine/client/cl_pred.c | 3 + engine/client/cl_screen.c | 2 +- engine/client/client.h | 2 +- engine/client/console.c | 39 ++- engine/client/image.c | 21 +- engine/client/m_mp3.c | 14 + engine/client/m_options.c | 276 +++++++++++--------- engine/client/m_single.c | 19 +- engine/client/menu.c | 3 +- engine/client/quakedef.h | 6 +- engine/client/r_2d.c | 13 +- engine/client/r_surf.c | 100 +++++-- engine/client/renderer.c | 6 +- engine/client/snd_alsa.c | 17 +- engine/client/snd_dma.c | 10 +- engine/client/snd_mem.c | 6 +- engine/client/snd_mix.c | 302 +++++++++++---------- engine/client/sound.h | 8 +- engine/client/sys_linux.c | 66 +++-- engine/client/valid.c | 39 ++- engine/client/view.c | 16 +- engine/common/bothdefs.h | 9 +- engine/common/cmd.c | 75 ++++-- engine/common/com_mesh.c | 3 + engine/common/cvar.c | 107 +++++++- engine/common/cvar.h | 1 - engine/common/fs_zip.c | 2 +- engine/common/q1bsp.c | 15 +- engine/gl/gl_font.c | 377 +++++++++++++++++---------- engine/gl/gl_shader.c | 13 +- engine/gl/gl_warp.c | 24 +- engine/gl/r_bishaders.h | 77 +++--- engine/qclib/cmdlib.h | 55 ++-- engine/qclib/hash.c | 2 +- engine/qclib/packager.c | 193 ++++++++++++-- engine/qclib/pr_exec.c | 4 +- engine/qclib/progslib.h | 9 +- engine/qclib/qcc.h | 8 +- engine/qclib/qcc_pr_comp.c | 26 +- engine/qclib/qcc_pr_lex.c | 1 + engine/qclib/qccguiqt.cpp | 54 ++-- engine/qclib/qccguistuff.c | 2 +- engine/qclib/qccmain.c | 4 +- engine/qclib/qcctui.c | 129 +++++++++ engine/qclib/qcd_main.c | 9 +- engine/server/pr_cmds.c | 4 +- engine/server/savegame.c | 107 +++++--- engine/server/server.h | 2 +- engine/server/sv_ccmds.c | 16 +- engine/server/sv_ents.c | 7 +- engine/server/sv_main.c | 2 +- engine/server/sv_phys.c | 24 +- engine/server/sv_send.c | 8 +- engine/server/world.c | 2 + engine/shaders/glsl/defaultskin.glsl | 19 +- engine/shaders/glsl/defaultwall.glsl | 88 ++++--- engine/shaders/glsl/rtlight.glsl | 16 +- 60 files changed, 1733 insertions(+), 839 deletions(-) diff --git a/engine/Makefile b/engine/Makefile index 443259f9d..63890075f 100644 --- a/engine/Makefile +++ b/engine/Makefile @@ -2018,11 +2018,11 @@ m-profile: _qcc-tmp: $(REQDIR) @$(MAKE) $(TYPE) EXE_NAME="$(EXE_NAME)$(EXEPOSTFIX)" PRECOMPHEADERS="" OUT_DIR="$(OUT_DIR)" WCFLAGS="$(CLIENT_ONLY_CFLAGS) $(WCFLAGS)" LDFLAGS="$(LDFLAGS) $(QCC_LDFLAGS)" OBJS="QCC_OBJS SOBJS" qcc-rel: - @$(MAKE) _qcc-tmp TYPE=_out-rel REQDIR=reldir EXE_NAME="../fteqcc$(BITS)" OUT_DIR="$(RELEASE_DIR)/$(NCDIRPREFIX)$(QCC_DIR)" SOBJS="qcctui.o $(if $(findstring win,$(FTE_TARGET)),fteqcc.o)" + @$(MAKE) _qcc-tmp TYPE=_out-rel REQDIR=reldir EXE_NAME="../fteqcc$(BITS)" OUT_DIR="$(RELEASE_DIR)/$(NCDIRPREFIX)$(QCC_DIR)" SOBJS="qcctui.o packager.o $(if $(findstring win,$(FTE_TARGET)),fteqcc.o)" qccgui-rel: @$(MAKE) _qcc-tmp TYPE=_out-rel REQDIR=reldir EXE_NAME="../fteqccgui$(BITS)" LTO= OUT_DIR="$(RELEASE_DIR)/$(NCDIRPREFIX)$(QCC_DIR)gui" SOBJS="qccgui.o qccguistuff.o packager.o decomp.o fteqcc.o" LDFLAGS="$(LDFLAGS) -lole32 -lcomdlg32 -lcomctl32 -lshlwapi -mwindows" qcc-dbg: - @$(MAKE) _qcc-tmp TYPE=_out-dbg REQDIR=debugdir EXE_NAME="../fteqcc$(BITS)" OUT_DIR="$(DEBUG_DIR)/$(NCDIRPREFIX)$(QCC_DIR)" SOBJS="qcctui.o $(if $(findstring win,$(FTE_TARGET)),fteqcc.o)" + @$(MAKE) _qcc-tmp TYPE=_out-dbg REQDIR=debugdir EXE_NAME="../fteqcc$(BITS)" OUT_DIR="$(DEBUG_DIR)/$(NCDIRPREFIX)$(QCC_DIR)" SOBJS="qcctui.o packager.o $(if $(findstring win,$(FTE_TARGET)),fteqcc.o)" qccgui-dbg: @$(MAKE) _qcc-tmp TYPE=_out-dbg REQDIR=debugdir EXE_NAME="../fteqccgui$(BITS)" LTO= OUT_DIR="$(DEBUG_DIR)/$(NCDIRPREFIX)$(QCC_DIR)gui" SOBJS="qccgui.o qccguistuff.o packager.o decomp.o fteqcc.o" LDFLAGS="$(LDFLAGS) -lole32 -lcomdlg32 -lcomctl32 -lshlwapi -mwindows" diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index 3a9d270b0..b6cd2fa7f 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -5199,7 +5199,7 @@ void CL_LinkPlayers (void) continue; #endif - if (info->spectator) + if (info->spectator || state->modelindex >= countof(cl.model_precache)) continue; //the extra modelindex check is to stop lame mods from using vweps with rings diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 74f0c7a00..f237ff822 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -2280,7 +2280,8 @@ void CL_CheckServerInfo(void) qboolean spectating = true; int i; qboolean oldwatervis = cls.allow_watervis; - + int oldskyboxes = cls.allow_unmaskedskyboxes; + //spectator 2 = spectator-with-scores, considered to be players. this means we don't want to allow spec cheats while they're inactive, because that would be weird. for (i = 0; i < cl.splitclients; i++) if (cl.playerview[i].spectator != 1) @@ -2291,7 +2292,7 @@ void CL_CheckServerInfo(void) cls.allow_cheats = false; cls.allow_semicheats=true; - cls.allow_skyboxes=false; + cls.allow_unmaskedskyboxes=false; cls.allow_fbskins = 1; // cls.allow_fbskins = 0; // cls.allow_overbrightlight; @@ -2306,8 +2307,12 @@ void CL_CheckServerInfo(void) else cls.allow_watervis=false; - if (spectating || cls.demoplayback || atoi(InfoBuf_ValueForKey(&cl.serverinfo, "allow_skybox")) || atoi(InfoBuf_ValueForKey(&cl.serverinfo, "allow_skyboxes"))) - cls.allow_skyboxes=true; //mostly obsolete. + s = InfoBuf_ValueForKey(&cl.serverinfo, "allow_skybox"); + if (!*s) + s = InfoBuf_ValueForKey(&cl.serverinfo, "allow_skyboxes"); + if (!*s) + cls.allow_unmaskedskyboxes = (cl.worldmodel && cl.worldmodel->fromgame != fg_quake); + else cls.allow_unmaskedskyboxes = !!atoi(s); s = InfoBuf_ValueForKey(&cl.serverinfo, "fbskins"); if (*s) @@ -2409,7 +2414,7 @@ void CL_CheckServerInfo(void) // if (allowed & 2) // cls.allow_rearview = true; if (allowed & 4) - cls.allow_skyboxes = true; + cls.allow_unmaskedskyboxes = true; // if (allowed & 8) // cls.allow_mirrors = true; //16 @@ -2480,7 +2485,7 @@ void CL_CheckServerInfo(void) if (oldteamplay != cl.teamplay) Skin_FlushPlayers(); - if (oldwatervis != cls.allow_watervis) + if (oldwatervis != cls.allow_watervis || oldskyboxes != cls.allow_unmaskedskyboxes) Shader_NeedReload(false); CSQC_ServerInfoChanged(); @@ -5885,45 +5890,66 @@ qboolean Host_RunFile(const char *fname, int nlen, vfsfile_t *file) } else #endif + { if (nlen >= 5 && !strncmp(fname, "qw://", 5)) - { //this is also implemented by ezquake, so be careful here... - //"qw://[stream@]host[:port]/COMMAND" join, spectate, qtvplay - char *t, *cmd; - const char *url; - char buffer[8192]; - t = Z_Malloc(nlen+1); - memcpy(t, fname, nlen); - t[nlen] = 0; - url = t+5; + { //this is also implemented by ezquake, so be careful here... + //"qw://[stream@]host[:port]/COMMAND" join, spectate, qtvplay + char *t, *cmd; + const char *url; + char buffer[8192]; + t = Z_Malloc(nlen+1); + memcpy(t, fname, nlen); + t[nlen] = 0; + url = t+5; - for (cmd = t+5; *cmd; cmd++) - { - if (*cmd == '/') + for (cmd = t+5; *cmd; cmd++) { - *cmd++ = 0; - break; + if (*cmd == '/') + { + *cmd++ = 0; + break; + } } + + //quote the url safely. + url = COM_QuotedString(url, buffer, sizeof(buffer), false); + + //now figure out what the command actually was + if (!Q_strcasecmp(cmd, "join")) + Cbuf_AddText(va("join %s\n", url), RESTRICT_LOCAL); + else if (!Q_strcasecmp(cmd, "spectate") || !strcmp(cmd, "observe")) + Cbuf_AddText(va("observe %s\n", url), RESTRICT_LOCAL); + else if (!Q_strcasecmp(cmd, "qtvplay")) + Cbuf_AddText(va("qtvplay %s\n", url), RESTRICT_LOCAL); + else if (!*cmd || !Q_strcasecmp(cmd, "connect")) + Cbuf_AddText(va("connect %s\n", url), RESTRICT_LOCAL); + else + Con_Printf("Unknown url command: %s\n", cmd); + + if(file) + VFS_CLOSE(file); + Z_Free(t); + return true; } - //quote the url safely. - url = COM_QuotedString(url, buffer, sizeof(buffer), false); - - //now figure out what the command actually was - if (!Q_strcasecmp(cmd, "join")) - Cbuf_AddText(va("join %s\n", url), RESTRICT_LOCAL); - else if (!Q_strcasecmp(cmd, "spectate") || !strcmp(cmd, "observe")) - Cbuf_AddText(va("observe %s\n", url), RESTRICT_LOCAL); - else if (!Q_strcasecmp(cmd, "qtvplay")) - Cbuf_AddText(va("qtvplay %s\n", url), RESTRICT_LOCAL); - else if (!*cmd || !Q_strcasecmp(cmd, "connect")) - Cbuf_AddText(va("connect %s\n", url), RESTRICT_LOCAL); - else - Con_Printf("Unknown url command: %s\n", cmd); - - if(file) - VFS_CLOSE(file); - Z_Free(t); - return true; + { + const char *netschemes[] = {"udp://", "udp4//", "udp6//", "ipx://", "tcp://", "tcp4//", "tcp6//", "spx://", "ws://", "wss://", "tls://", "dtls://", "ice://", "rtc://", "ices://", "rtcs://", "irc://", "udg://", "unix://"}; + int i; + size_t slen; + for (i = 0; i < countof(netschemes); i++) + { + slen = strlen(netschemes[i]); + if (nlen >= slen && !strncmp(fname, netschemes[i], slen)) + { + char quoted[8192]; + char *t = Z_Malloc(nlen+1); + memcpy(t, fname, nlen); + t[nlen] = 0; + Cbuf_AddText(va("connect %s\n", COM_QuotedString(t, quoted, sizeof(quoted), false)), RESTRICT_LOCAL); + Z_Free(t); + } + } + } } f = Z_Malloc(sizeof(*f) + nlen); diff --git a/engine/client/cl_pred.c b/engine/client/cl_pred.c index ab2d99fca..84e8dfb91 100644 --- a/engine/client/cl_pred.c +++ b/engine/client/cl_pred.c @@ -891,6 +891,7 @@ void CL_PredictEntityMovement(entity_state_t *estate, float age) VectorClear(startstate.velocity); startstate.onground = false; startstate.jump_held = false; + startstate.flags = 0; CL_EntStateToPlayerState(&startstate, estate); CL_EntStateToPlayerCommand(&cmd, estate, age); @@ -1174,6 +1175,8 @@ void CL_PredictMovePNum (int seat) { packet_entities_t *pe; pe = &cl.inframes[from.frame & UPDATE_MASK].packet_entities; + if (!pe->num_entities && !from.frame) + pe = &cl.inframes[to.frame & UPDATE_MASK].packet_entities; for (i = 0; i < pe->num_entities; i++) { if (pe->entities[i].number == trackent) diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index 90ce91454..13c0cb717 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -222,7 +222,7 @@ qboolean scr_drawloading; float scr_disabled_time; cvar_t con_stayhidden = CVARFD("con_stayhidden", "1", CVAR_NOTFROMSERVER, "0: allow console to pounce on the user\n1: console stays hidden unless explicitly invoked\n2:toggleconsole command no longer works\n3: shift+escape key no longer works"); -cvar_t show_fps = CVARFD("show_fps", "0", CVAR_ARCHIVE, "Displays the current framerate on-screen.\n0: Off.\n1: framerate average over a second.\n2: Show a frametimes graph (with additional timing info).\n-1: Normalized graph that focuses on the variation ignoring base times."); +cvar_t show_fps = CVARAFD("show_fps"/*qw*/, "0", "scr_showfps"/*qs*/, CVAR_ARCHIVE, "Displays the current framerate on-screen.\n0: Off.\n1: framerate average over a second.\n2: Show a frametimes graph (with additional timing info).\n-1: Normalized graph that focuses on the variation ignoring base times."); cvar_t show_fps_x = CVAR("show_fps_x", "-1"); cvar_t show_fps_y = CVAR("show_fps_y", "-1"); cvar_t show_clock = CVAR("cl_clock", "0"); diff --git a/engine/client/client.h b/engine/client/client.h index 20b99d658..36d9362aa 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -527,8 +527,8 @@ typedef struct float latency; // rolling average + char allow_unmaskedskyboxes; //skyboxes/domes do not need to be depth-masked when set. FIXME: we treat this as an optimisation hint, but some hl/q2/q3 maps require strict do-not-mask rules to look right. qboolean allow_anyparticles; - qboolean allow_skyboxes; //skyboxes/domes do not need to be depth-masked when set. FIXME: we treat this as an optimisation hint, but some hl/q2/q3 maps require strict do-not-mask rules to look right. qboolean allow_watervis; //fixme: not checked any more float allow_fbskins; //fraction of allowance qboolean allow_cheats; diff --git a/engine/client/console.c b/engine/client/console.c index 309e14632..9649c5c76 100644 --- a/engine/client/console.c +++ b/engine/client/console.c @@ -2770,6 +2770,8 @@ static void Con_DrawMouseOver(console_t *mouseconsole) char *tiptext = NULL; shader_t *shader = NULL; model_t *model = NULL; + sfx_t *audio = NULL; + char *mouseover; if (!mouseconsole->mouseover || !mouseconsole->mouseover(mouseconsole, &tiptext, &shader)) { @@ -2856,17 +2858,25 @@ static void Con_DrawMouseOver(console_t *mouseconsole) if (model->loadstate != MLS_LOADED) model = NULL; } + + key = Info_ValueForKey(info, "playaudio"); + if (*key) + { + audio = S_PrecacheSound(key); + if (audio && audio->loadstate != SLS_LOADED) + audio = NULL; + } } tiptext = Info_ValueForKey(info, "tip"); } Z_Free(mouseover); } } - if ((tiptext && *tiptext) || shader || model) + if ((tiptext && *tiptext) || shader || model || audio) { //FIXME: draw a proper background. //FIXME: support line breaks. - conchar_t buffer[2048], *starts[64], *ends[countof(starts)]; + conchar_t buffer[2048], *starts[64], *ends[countof(starts)], *eot; int lines, i, px, py; float tw, th; float ih = 0, iw = 0; @@ -2874,7 +2884,30 @@ static void Con_DrawMouseOver(console_t *mouseconsole) float y = mousecursor_y+8; Font_BeginString(font_console, x, y, &px, &py); - lines = Font_LineBreaks(buffer, COM_ParseFunString(CON_WHITEMASK, tiptext, buffer, sizeof(buffer), false), (256.0 * vid.pixelwidth) / vid.width, countof(starts), starts, ends); + eot = COM_ParseFunString(CON_WHITEMASK, tiptext, buffer, sizeof(buffer), false); + if (audio) + { + struct sfxcache_s cache; + char name[MAX_OSPATH]; + float len; + *name = 0; + len = audio->decoder.querydata?audio->decoder.querydata(audio, &cache, name, sizeof(name)):-1; + if (len >= 0) + { + eot = COM_ParseFunString(CON_WHITEMASK, va("\n\n%s\n%gkhz, %s, %ibit, %g seconds%s", + name, cache.speed/1000.0, cache.numchannels==1?"mono":"stereo", QAF_BYTES(cache.format)*8, len, audio->loopstart>=0?" looped":"" + ), eot, sizeof(buffer)-((char*)eot-(char*)buffer), false); + } + else + { + cache = *(struct sfxcache_s *)audio->decoder.buf; + len = (double)cache.length / cache.speed; + eot = COM_ParseFunString(CON_WHITEMASK, va("\n\n\n%gkhz, %s, %ibit, %g seconds%s", + cache.speed/1000.0, cache.numchannels==1?"mono":"stereo", QAF_BYTES(cache.format)*8, len, audio->loopstart>=0?" looped":"" + ), eot, sizeof(buffer)-((char*)eot-(char*)buffer), false); + } + } + lines = Font_LineBreaks(buffer, eot, (256.0 * vid.pixelwidth) / vid.width, countof(starts), starts, ends); th = (Font_CharHeight()*lines * vid.height) / vid.pixelheight; if (model) diff --git a/engine/client/image.c b/engine/client/image.c index 2c274d2d4..1c637375d 100644 --- a/engine/client/image.c +++ b/engine/client/image.c @@ -4812,7 +4812,7 @@ qboolean Image_WriteKTXFile(const char *filename, enum fs_relative fsroot, struc Image_BlockSizeForEncoding(mips->encoding, &bb, &bw, &bh, &bd); - switch(mips->encoding) + safeswitch(mips->encoding) { case PTI_ETC1_RGB8: header.glinternalformat = 0x8D64/*GL_ETC1_RGB8_OES*/; break; case PTI_ETC2_RGB8: header.glinternalformat = 0x9274/*GL_COMPRESSED_RGB8_ETC2*/; break; @@ -4933,6 +4933,7 @@ qboolean Image_WriteKTXFile(const char *filename, enum fs_relative fsroot, struc case PTI_R16F: header.glinternalformat = 0x822D/*GL_R16F*/; header.glbaseinternalformat = 0x1903/*GL_RED*/; header.glformat = 0x1903/*GL_RED*/; header.gltype = 0x140B/*GL_HALF_FLOAT*/; header.gltypesize = 2; break; case PTI_R32F: header.glinternalformat = 0x822E/*GL_R32F*/; header.glbaseinternalformat = 0x1903/*GL_RED*/; header.glformat = 0x1903/*GL_RED*/; header.gltype = 0x1406/*GL_FLOAT*/; header.gltypesize = 4; break; case PTI_RGBA16F: header.glinternalformat = 0x881A/*GL_RGBA16F*/; header.glbaseinternalformat = 0x1908/*GL_RGBA*/; header.glformat = 0x1908/*GL_RGBA*/; header.gltype = 0x140B/*GL_HALF_FLOAT*/; header.gltypesize = 2; break; + case PTI_RGB32F: header.glinternalformat = 0x8815/*GL_RGB32F*/; header.glbaseinternalformat = 0x1907/*GL_RGB*/; header.glformat = 0x1907/*GL_RGB*/; header.gltype = 0x1406/*GL_FLOAT*/; header.gltypesize = 4; break; case PTI_RGBA32F: header.glinternalformat = 0x8814/*GL_RGBA32F*/; header.glbaseinternalformat = 0x1908/*GL_RGBA*/; header.glformat = 0x1908/*GL_RGBA*/; header.gltype = 0x1406/*GL_FLOAT*/; header.gltypesize = 4; break; case PTI_A2BGR10: header.glinternalformat = 0x8059/*GL_RGB10_A2*/; header.glbaseinternalformat = 0x1908/*GL_RGBA*/; header.glformat = 0x1908/*GL_RGBA*/; header.gltype = 0x8368/*GL_UNSIGNED_INT_2_10_10_10_REV*/; header.gltypesize = 4; break; case PTI_E5BGR9: header.glinternalformat = 0x8C3D/*GL_RGB9_E5*/; header.glbaseinternalformat = 0x8C3D/*GL_RGB9_E5*/; header.glformat = 0x1907/*GL_RGB*/; header.gltype = 0x8C3E/*GL_UNSIGNED_INT_5_9_9_9_REV*/; header.gltypesize = 4; break; @@ -4956,7 +4957,6 @@ qboolean Image_WriteKTXFile(const char *filename, enum fs_relative fsroot, struc case PTI_DEPTH32: header.glinternalformat = 0x81A7/*GL_DEPTH_COMPONENT32*/; header.glbaseinternalformat = 0x1902/*GL_DEPTH_COMPONENT*/; header.glformat = 0x1902/*GL_DEPTH_COMPONENT*/; header.gltype = 0x1406/*GL_FLOAT*/; header.gltypesize = 4; break; case PTI_DEPTH24_8: header.glinternalformat = 0x88F0/*GL_DEPTH24_STENCIL8*/; header.glbaseinternalformat = 0x84F9/*GL_DEPTH_STENCIL*/; header.glformat = 0x84F9/*GL_DEPTH_STENCIL*/; header.gltype = 0x84FA/*GL_UNSIGNED_INT_24_8*/; header.gltypesize = 4; break; - case PTI_RGB32F: #ifdef FTE_TARGET_WEB case PTI_WHOLEFILE: #endif @@ -4964,8 +4964,8 @@ qboolean Image_WriteKTXFile(const char *filename, enum fs_relative fsroot, struc case PTI_MAX: return false; -// default: -// return; + safedefault: + return false; } if (strchr(filename, '*') || strchr(filename, ':')) @@ -5142,6 +5142,7 @@ static struct pendingtextureinfo *Image_ReadKTXFile(unsigned int flags, const ch case 0x8040/*GL_LUMINANCE8*/: encoding = PTI_L8; break; case 0x8045/*GL_LUMINANCE8_ALPHA8*/: encoding = PTI_L8A8; break; case 0x881A/*GL_RGBA16F_ARB*/: encoding = PTI_RGBA16F; break; + case 0x8815/*GL_RGB32F_ARB*/: encoding = PTI_RGB32F; break; case 0x8814/*GL_RGBA32F_ARB*/: encoding = PTI_RGBA32F; break; case 0x8059/*GL_RGB10_A2*/: encoding = PTI_A2BGR10; break; case 0x8229/*GL_R8*/: encoding = PTI_R8; break; @@ -5200,6 +5201,10 @@ static struct pendingtextureinfo *Image_ReadKTXFile(unsigned int flags, const ch else if (header.glformat == 0x80E1/*GL_BGRA*/ && header.gltype == 0x8365/*GL_UNSIGNED_SHORT_4_4_4_4_REV*/) encoding = PTI_ARGB4444; break; + + default: + encoding = TF_INVALID; + break; } if (encoding == TF_INVALID) { @@ -6065,7 +6070,7 @@ qboolean Image_WriteDDSFile(const char *filename, enum fs_relative fsroot, struc #define DX9RGBA (0x40|0x1) #define DX9LUM 0x20000 #define DX9LUMALPHA (0x20000|0x1) - switch(mips->encoding) + safeswitch(mips->encoding) { // case PTI_INVALID: h10.dxgiformat = 0x0/*DXGI_FORMAT_UNKNOWN*/; break; // case PTI_INVALID: h10.dxgiformat = 0x1/*DXGI_FORMAT_R32G32B32A32_TYPELESS*/; break; @@ -6298,10 +6303,8 @@ qboolean Image_WriteDDSFile(const char *filename, enum fs_relative fsroot, struc case PTI_MAX: return false; -#ifndef _DEBUG -// default: //don't enable in debug builds, so we get warnings for any cases being missed. - // return false; -#endif + safedefault: //don't enable in debug builds, so we get warnings for any cases being missed. + return false; } //truncate the mip chain if they're dodgy sizes. diff --git a/engine/client/m_mp3.c b/engine/client/m_mp3.c index b0b5dc223..5b561517a 100644 --- a/engine/client/m_mp3.c +++ b/engine/client/m_mp3.c @@ -352,6 +352,20 @@ qboolean Media_CleanupTrackName(const char *track, int *out_track, char *result, ".mp3", #endif ".wav", +#if defined(PLUGINS) //ffmpeg plugin? woo. + #if !(defined(AVAIL_OGGOPUS) || defined(FTE_TARGET_WEB)) + ".opus", //opus might be the future, but ogg is the present + #endif + #if !(defined(AVAIL_OGGVORBIS) || defined(FTE_TARGET_WEB)) + ".ogg", + #endif + #if !(defined(AVAIL_MP3_ACM) || defined(FTE_TARGET_WEB)) + ".mp3", + #endif + ".flac", //supported by QS at least. + //".s3m", //some variant of mod that noone cares about. listed because of qs. + //".umx", //wtf? qs is weird. +#endif NULL }; unsigned int tracknum; diff --git a/engine/client/m_options.c b/engine/client/m_options.c index ec1b4b438..65e81f42a 100644 --- a/engine/client/m_options.c +++ b/engine/client/m_options.c @@ -703,7 +703,7 @@ void M_Menu_Audio_f (void) MB_SLIDER("Volume", volume, 0, 1, 0.1, NULL), MB_COMBOCVAR("Speaker Setup", snd_speakers, speakeroptions, speakervalues, NULL), MB_COMBOCVAR("Frequency", snd_khz, soundqualityoptions, soundqualityvalues, NULL), - MB_CHECKBOXCVAR("Low Quality (8-bit)", loadas8bit, 0), + MB_CHECKBOXCVAR("Low Quality (8-bit)", snd_loadas8bit, 0), MB_CHECKBOXCVAR("Flip Speakers", snd_leftisright, 0), MB_SLIDER("Mixahead", _snd_mixahead, 0, 1, 0.05, NULL), MB_CHECKBOXCVAR("Disable All Sounds", nosound, 0), @@ -795,7 +795,7 @@ void M_Menu_Particles_f (void) "highfps", "spikeset", "spikeset tsshaft", - "spikeset high tsshaft", + "high tsshaft", "minimal", NULL }; @@ -1052,6 +1052,116 @@ const char *presetexec[] = //end 'realtime' }; +struct +{ + const char *name; + const char *desc; + const char *settings; +} builtinpresets[] = +{ + { "hdr", + "Don't let colour depth stop you!", + + "set vid_srgb 2\n" + "set r_hdr_irisadaptation 1\n" + }, + { "shib", + "Performance optimisations for large/detailed maps.", + + "if r_dynamic >= 1\n" + "{\n" //fake it anyway. + "set r_shadow_realtime_dlight 1\n" + "set r_shadow_realtime_dlight_shadows 0\n" + "set r_dynamic 0\n" + "}\n" + "set r_temporalscenecache 1\n" //the main speedup. + "set r_lightstylespeed 0\n" //FIXME: we shouldn't need this, but its too stuttery without. + "set sv_autooffload 1\n" //Needs polish still. + "set gl_pbolightmaps 1\n" //FIXME: this needs to be the default eventually. + }, + { "qw", + "Enable QuakeWorld-isms, for better gameplay.", + + "set sv_nqplayerphysics 0\n" + "set sv_gameplayfix_multiplethinks 1\n" + }, + { "nq" + "Disable QuakeWorld-isms, for nq mod compat.", + + "set sv_nqplayerphysics 1\n" + "set sv_gameplayfix_multiplethinks 0\n" + }, + + { "dp", + "Reconfigures FTE to mimic DP for compat reasons.", + + "if $server then echo Be sure to restart your server\n" + + "fps_preset nq\n" + //these are for smc+derived mods + "sv_listen_dp 1\n" //awkward, but forces the server to load the effectinfo.txt in advance. + "sv_bigcoords 1\n" //for viewmodel lep precision (would be better to use csqc) + "r_particledesc \"effectinfo high\"\n" //blurgh. + "dpcompat_noretouchground 1\n" //don't call touch functions on entities that already appear onground. this also changes the order that the onground flag is set relative to touch functions. + "cl_nopred 1\n" //DP doesn't predict by default, and DP mods have a nasty habit of clearing .solid values during prethinks, which screws up prediction. so play safe. + "r_dynamic 0\nr_shadow_realtime_dlight 1\n" //fte has separate cvars for everything. which kinda surprises people and makes stuff twice as bright as it should be. + "r_coronas_intensity 0.25\n" + "con_logcenterprint 0\n" //kinda annoying.... + "scr_fov_mode 4\n" //for fairer framerate comparisons + + //general compat stuff + "dpcompat_console 1\n" // + "dpcompat_findradiusarealinks 1\n" //faster findradiuses (but that require things are setorigined properly) + "dpcompat_makeshitup 2\n" //flatten shaders to a single pass, then add new specular etc passes. + //"dpcompat_nopremulpics 1\n" //don't use premultiplied alpha (solving issues with compressed image formats) + "dpcompat_psa_ungroup 1\n" //don't use framegroups with psk models at all. + "dpcompat_set 1\n" //handle 3-arg sets differently + "dpcompat_stats 1\n" //truncate float stats + "dpcompat_strcat_limit 16383\n" //xonotic compat. maximum length of strcat strings. + +// "sv_listen_dp 1\nsv_listen_nq 0\nsv_listen_qw 0\ncl_loopbackprotocol dpp7\ndpcompat_nopreparse 1\n" + }, + + { "tenebrae", + "Reconfigures FTE to mimic Tenebrae for compat/style reasons.", + //for the luls. combine with the tenebrae mod for maximum effect. + "fps_preset nq\n" + "set r_shadow_realtime_world 1\n" + "set r_shadow_realtime_dlight 1\n" + "set r_shadow_bumpscale_basetexture 4\n" + "set r_shadow_shadowmapping 0\n" + "set gl_specular 1\n" + "set gl_specular_power 16\n" + "set gl_specular_fallback 1\n" + "set mod_litsprites_force 1\n" + "set r_nolerp 1\n" //well, that matches tenebrae. for the luls, right? + }, + + { "timedemo", + "Reconfigure some stuff to get through timedemos really fast. Some people might consider this cheating.", + //some extra things to pwn timedemos. + "fps_preset fast\n" + "set r_renderscale 1\n" + "set contrast 1\n" + "set gamma 1\n" + "set brightness 0\n" + "set scr_autoid 0\n" + "set scr_autoid_team 0\n" + "set r_dynamic 0\n" + "set sbar_teamstatus 2\n" + "set gl_polyblend 0\n" +#if 1 + //these are cheaty settings. + "set gl_flashblend 0\n" + "set cl_predict_players 0\n" //very cheaty. you won't realise its off, but noone would disable it for actual play. +#else + //to make things fair + "set gl_flashblend 1\n" + "set r_part_density 1\n" +#endif + }, +}; + typedef struct fpsmenuinfo_s { menucombo_t *preset; @@ -1159,125 +1269,6 @@ void FPS_Preset_f (void) } } - if (!stricmp("hdr", arg)) - { - Cbuf_InsertText( - "set vid_srgb 2\n" - "set r_hdr_irisadaptation 1\n" - , RESTRICT_LOCAL, false); - return; - } - if (!stricmp("shib", arg)) - { - Cbuf_InsertText( - "if r_dynamic >= 1\n" - "{\n" //fake it anyway. - "set r_shadow_realtime_dlight 1\n" - "set r_shadow_realtime_dlight_shadows 0\n" - "set r_dynamic 0\n" - "}\n" - "set r_temporalscenecache 1\n" //the main speedup. - "set r_lightstylespeed 0\n" //FIXME: we shouldn't need this, but its too stuttery without. - "set sv_autooffload 1\n" //Needs polish still. - "set gl_pbolightmaps 1\n" //FIXME: this needs to be the default eventually. - , RESTRICT_LOCAL, false); - return; - } - if (!stricmp("qw", arg)) - { //enable qwisms - Cbuf_InsertText( - "set sv_nqplayerphysics 0\n" - "set sv_gameplayfix_multiplethinks 1\n" - , RESTRICT_LOCAL, false); - return; - } - if (!stricmp("nq", arg)) - { //disable qwisms, for better mod compat - Cbuf_InsertText( - "set sv_nqplayerphysics 1\n" - "set sv_gameplayfix_multiplethinks 0\n" - , RESTRICT_LOCAL, false); - return; - } - - if (!stricmp("dp", arg)) - { -#ifdef HAVE_SERVER - if (sv.state) - Cbuf_InsertText("echo Be sure to restart your server\n", RESTRICT_LOCAL, false); -#endif - Cbuf_InsertText( - "fps_preset nq\n" - //these are for smc+derived mods - "sv_listen_dp 1\n" //awkward, but forces the server to load the effectinfo.txt in advance. - "sv_bigcoords 1\n" //for viewmodel lep precision (would be better to use csqc) - "r_particledesc \"effectinfo high\"\n" //blurgh. - "dpcompat_noretouchground 1\n" //don't call touch functions on entities that already appear onground. this also changes the order that the onground flag is set relative to touch functions. - "cl_nopred 1\n" //DP doesn't predict by default, and DP mods have a nasty habit of clearing .solid values during prethinks, which screws up prediction. so play safe. - "r_dynamic 0\nr_shadow_realtime_dlight 1\n" //fte has separate cvars for everything. which kinda surprises people and makes stuff twice as bright as it should be. - "r_coronas_intensity 0.25\n" - "con_logcenterprint 0\n" //kinda annoying.... - "scr_fov_mode 4\n" //for fairer framerate comparisons - - //general compat stuff - "dpcompat_console 1\n" // - "dpcompat_findradiusarealinks 1\n" //faster findradiuses (but that require things are setorigined properly) - "dpcompat_makeshitup 2\n" //flatten shaders to a single pass, then add new specular etc passes. - //"dpcompat_nopremulpics 1\n" //don't use premultiplied alpha (solving issues with compressed image formats) - "dpcompat_psa_ungroup 1\n" //don't use framegroups with psk models at all. - "dpcompat_set 1\n" //handle 3-arg sets differently - "dpcompat_stats 1\n" //truncate float stats - "dpcompat_strcat_limit 16383\n" //xonotic compat. maximum length of strcat strings. - -// "sv_listen_dp 1\nsv_listen_nq 0\nsv_listen_qw 0\ncl_loopbackprotocol dpp7\ndpcompat_nopreparse 1\n" - , RESTRICT_LOCAL, false); - return; - } - - if (!stricmp("tenebrae", arg)) - { //for the luls. combine with the tenebrae mod for maximum effect. - Cbuf_InsertText( - "fps_preset nq\n" - "set r_shadow_realtime_world 1\n" - "set r_shadow_realtime_dlight 1\n" - "set r_shadow_bumpscale_basetexture 4\n" - "set r_shadow_shadowmapping 0\n" - "set gl_specular 1\n" - "set gl_specular_power 16\n" - "set gl_specular_fallback 1\n" - "set mod_litsprites_force 1\n" - "set r_nolerp 1\n" //well, that matches tenebrae. for the luls, right? - , RESTRICT_LOCAL, false); - return; - } - - if (!stricmp("timedemo", arg)) - { - //some extra things to pwn timedemos. - Cbuf_InsertText( - "fps_preset fast\n" - "set r_renderscale 1\n" - "set contrast 1\n" - "set gamma 1\n" - "set brightness 0\n" - "set scr_autoid 0\n" - "set scr_autoid_team 0\n" - "set r_dynamic 0\n" - "set sbar_teamstatus 2\n" - "set gl_polyblend 0\n" -#if 1 - //these are cheaty settings. - "set gl_flashblend 0\n" - "set cl_predict_players 0\n" //very cheaty. you won't realise its off, but noone would disable it for actual play. -#else - //to make things fair - "set gl_flashblend 1\n" - "set r_part_density 1\n" -#endif - , RESTRICT_LOCAL, false); - return; - } - for (i = 0; i < PRESET_NUM; i++) { if (!stricmp(presetname[i], arg)) @@ -1287,10 +1278,53 @@ void FPS_Preset_f (void) } } + for (i = 0; i < countof(builtinpresets); i++) + { + if (!stricmp(builtinpresets[i].name, arg)) + { + if (doreload) + Cbuf_InsertText("\nfs_restart\nvid_reload\n", RESTRICT_LOCAL, false); + Cbuf_InsertText(builtinpresets[i].settings, RESTRICT_LOCAL, false); + return; + } + } + Con_Printf("Preset %s not recognised\n", arg); Con_Printf("Valid presests:\n"); for (i = 0; i < PRESET_NUM; i++) Con_Printf("%s\n", presetname[i]); + for (i = 0; i < countof(builtinpresets); i++) + Con_DPrintf("%s\n", builtinpresets[i].name); +} + +static int QDECL CompletePresetList (const char *name, qofs_t flags, time_t mtime, void *parm, searchpathfuncs_t *spath) +{ + struct xcommandargcompletioncb_s *ctx = parm; + if (!Q_strncasecmp(name, "configs/preset_", 15)) + { + char preset[MAX_QPATH]; + COM_StripExtension(name+15, preset, sizeof(preset)); + ctx->cb(preset, NULL, NULL, ctx); + } + return true; +} +void FPS_Preset_c(int argn, const char *partial, struct xcommandargcompletioncb_s *ctx) +{ + if (argn == 1) + { + int i; + size_t partiallen = strlen(partial); + + COM_EnumerateFiles(va("configs/preset_%s*.cfg", partial), CompletePresetList, ctx); + + for (i = 0; i < PRESET_NUM; i++) + if (!Q_strncasecmp(partial, presetname[i], partiallen)) + ctx->cb(presetname[i], NULL, NULL, ctx); + + for (i = 0; i < countof(builtinpresets); i++) + if (!Q_strncasecmp(partial, builtinpresets[i].name, partiallen)) + ctx->cb(builtinpresets[i].name, builtinpresets[i].desc, NULL, ctx); + } } qboolean M_PresetApply (union menuoption_s *op, struct emenu_s *menu, int key) diff --git a/engine/client/m_single.c b/engine/client/m_single.c index 693cf19fb..78cbe7289 100644 --- a/engine/client/m_single.c +++ b/engine/client/m_single.c @@ -1158,24 +1158,29 @@ void M_Menu_MediaFiles_f (void) // info->ext[info->numext] = ".m3u"; // info->command[info->numext] = "mediaplaylist"; // info->numext++; -#if defined(AVAIL_MP3_ACM) || defined(FTE_TARGET_WEB) - info->ext[info->numext] = ".mp3"; - info->command[info->numext] = "media_add"; - info->numext++; -#endif info->ext[info->numext] = ".wav"; info->command[info->numext] = "media_add"; info->numext++; -#if defined(AVAIL_OGGOPUS) || defined(FTE_TARGET_WEB) +#if defined(AVAIL_OGGOPUS) || defined(FTE_TARGET_WEB) || defined(PLUGINS) info->ext[info->numext] = ".opus"; info->command[info->numext] = "media_add"; info->numext++; #endif -#if defined(AVAIL_OGGVORBIS) || defined(FTE_TARGET_WEB) +#if defined(AVAIL_OGGVORBIS) || defined(FTE_TARGET_WEB) || defined(PLUGINS) info->ext[info->numext] = ".ogg"; info->command[info->numext] = "media_add"; info->numext++; #endif +#if defined(AVAIL_MP3_ACM) || defined(FTE_TARGET_WEB) || defined(PLUGINS) + info->ext[info->numext] = ".mp3"; + info->command[info->numext] = "media_add"; + info->numext++; +#endif +#if defined(PLUGINS) + info->ext[info->numext] = ".flac"; + info->command[info->numext] = "media_add"; + info->numext++; +#endif #endif #ifdef HAVE_MEDIA_DECODER diff --git a/engine/client/menu.c b/engine/client/menu.c index f8de47287..f50fddefe 100644 --- a/engine/client/menu.c +++ b/engine/client/menu.c @@ -1430,6 +1430,7 @@ void M_Reinit(void) } void FPS_Preset_f(void); +void FPS_Preset_c(int argn, const char *partial, struct xcommandargcompletioncb_s *ctx); void M_MenuPop_f(void); //menu.dat is loaded later... after the video and everything is up. @@ -1438,7 +1439,7 @@ void M_Init (void) Cmd_AddCommand("menu_restart", M_Restart_f); Cmd_AddCommand("togglemenu", M_ToggleMenu_f); Cmd_AddCommand("closemenu", M_CloseMenu_f); - Cmd_AddCommand("fps_preset", FPS_Preset_f); + Cmd_AddCommandAD("fps_preset", FPS_Preset_f, FPS_Preset_c, "Apply a preset"); Cmd_AddCommand("menupop", M_MenuPop_f); //server browser is kinda complex, and has clipboard integration which we need to sandbox a little diff --git a/engine/client/quakedef.h b/engine/client/quakedef.h index 1cb014166..9a13937e6 100644 --- a/engine/client/quakedef.h +++ b/engine/client/quakedef.h @@ -232,9 +232,9 @@ extern "C" { #endif #ifdef _WIN64 - #define PRIxSIZE "Ix" - #define PRIuSIZE "Iu" - #define PRIiSIZE "Ii" + #define PRIxSIZE PRIx64 + #define PRIuSIZE PRIu64 + #define PRIiSIZE PRIi64 #else //don't use I, for the sake of older libcs #define PRIxSIZE "x" diff --git a/engine/client/r_2d.c b/engine/client/r_2d.c index 21181c032..7bd2b8f7f 100644 --- a/engine/client/r_2d.c +++ b/engine/client/r_2d.c @@ -238,8 +238,17 @@ void R2D_Init(void) } - glossval = min(gl_specular_fallback.value*255, 255); - glossval *= 0x10101; + if (strchr(gl_specular_fallback.string, ' ')) + { + glossval = bound(0, (int)(gl_specular_fallback.vec4[0]*255), 255)<<0; + glossval |= bound(0, (int)(gl_specular_fallback.vec4[1]*255), 255)<<8; + glossval |= bound(0, (int)(gl_specular_fallback.vec4[2]*255), 255)<<16; + } + else + { + glossval = min(gl_specular_fallback.value*255, 255); + glossval *= 0x10101; + } glossval |= 0x01000000 * bound(0, (int)(gl_specular_fallbackexp.value*255), 255); glossval = LittleLong(glossval); normval = 0xffff8080; diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index 0e9d0087e..b183497ea 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -29,6 +29,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #if (defined(GLQUAKE) || defined(VKQUAKE)) && defined(MULTITHREAD) #define THREADEDWORLD +int webo_blocklightmapupdates; //0 no webo, &1=using threadedworld, &2=already uploaded. so update when !=3 #endif #ifdef BEF_PUSHDEPTH qboolean r_pushdepth; @@ -1776,7 +1777,7 @@ static void Surf_BuildLightMap_Worker (model_t *wmodel, msurface_t *surf, int sh } } } - else switch(cl.worldmodel->lightmaps.fmt) + else switch(wmodel->lightmaps.fmt) { case LM_E5BGR9: for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) @@ -1876,7 +1877,7 @@ static void Surf_BuildLightMap_Worker (model_t *wmodel, msurface_t *surf, int sh // add all the lightmaps if (src) { - switch(cl.worldmodel->lightmaps.fmt) + switch(wmodel->lightmaps.fmt) { case LM_E5BGR9: for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) @@ -2882,7 +2883,7 @@ void Surf_GenBrushBatches(batch_t **batches, entity_t *ent) // calculate dynamic lighting for bmodel if it's not an // instanced model - if (model->fromgame != fg_quake3 && model->fromgame != fg_doom3 && lightmap && !r_temporalscenecache.ival) + if (model->fromgame != fg_quake3 && model->fromgame != fg_doom3 && lightmap && webo_blocklightmapupdates!=3) { int k; @@ -2981,12 +2982,12 @@ void Surf_GenBrushBatches(batch_t **batches, entity_t *ent) if (!b->shader) b->shader = R_TextureAnimation(ent->framestate.g[FS_REG].frame[0], b->texture)->shader; - if (bef & BEF_FORCEADDITIVE) + if (bef & BEF_FORCEADDITIVE && b->shader->sort==SHADER_SORT_OPAQUE) { b->next = batches[SHADER_SORT_ADDITIVE]; batches[SHADER_SORT_ADDITIVE] = b; } - else if (bef & BEF_FORCETRANSPARENT) + else if (bef & BEF_FORCETRANSPARENT && b->shader->sort==SHADER_SORT_OPAQUE) { b->next = batches[SHADER_SORT_BLEND]; batches[SHADER_SORT_BLEND] = b; @@ -3025,6 +3026,7 @@ struct webostate_s { size_t numidx; size_t maxidx; + size_t firstidx; //offset into the final ebo index_t *idxbuffer; batch_t b; mesh_t m; @@ -3035,12 +3037,15 @@ struct webostate_s static struct webostate_s *webostates; static struct webostate_s *webogenerating; static int webogeneratingstate; //1 if generating, 0 if not, for waiting for sync. -int webo_blocklightmapupdates; //0 no webo, &1=using threadedworld, &2=already uploaded. static void R_DestroyWorldEBO(struct webostate_s *es) { + int i; if (!es) return; + for (i = 0; i < es->numbatches; i++) + BZ_Free(es->batches[i].idxbuffer); + #ifdef GLQUAKE if (qrenderer == QR_OPENGL) qglDeleteBuffersARB(1, &es->ebo.gl.vbo); @@ -3077,14 +3082,16 @@ void R_GeneratedWorldEBO(void *ctx, void *data, size_t a_, size_t b_) GL_DeselectVAO(); webostate->ebo.gl.addr = NULL; - qglGenBuffersARB(1, &webostate->ebo.gl.vbo); + if (!webostate->ebo.gl.vbo) + qglGenBuffersARB(1, &webostate->ebo.gl.vbo); GL_SelectEBO(webostate->ebo.gl.vbo); qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, idxcount*sizeof(index_t), NULL, GL_STATIC_DRAW_ARB); for (i = 0, idxcount = 0; i < webostate->numbatches; i++) { qglBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, idxcount*sizeof(index_t), webostate->batches[i].numidx*sizeof(index_t), webostate->batches[i].idxbuffer); - BZ_Free(webostate->batches[i].idxbuffer); - webostate->batches[i].idxbuffer = (index_t*)NULL + idxcount; +// BZ_Free(webostate->batches[i].idxbuffer); +// webostate->batches[i].idxbuffer = NULL; + webostate->batches[i].firstidx = idxcount; idxcount += webostate->batches[i].numidx; } } @@ -3094,12 +3101,16 @@ void R_GeneratedWorldEBO(void *ctx, void *data, size_t a_, size_t b_) { //this malloc is stupid. //with vulkan we really should be doing this on the worker instead, at least the staging part. index_t *indexes = malloc(sizeof(*indexes) * idxcount); + BE_VBO_Destroy(&webostate->ebo, webostate->ebomem); + memset(&webostate->ebo, 0, sizeof(webostate->ebo)); + webostate->ebomem = NULL; webostate->ebo.vk.offs = 0; for (i = 0, idxcount = 0; i < webostate->numbatches; i++) { memcpy(indexes + idxcount, webostate->batches[i].idxbuffer, webostate->batches[i].numidx*sizeof(index_t)); - BZ_Free(webostate->batches[i].idxbuffer); - webostate->batches[i].idxbuffer = (index_t*)NULL + idxcount; +// BZ_Free(webostate->batches[i].idxbuffer); +// webostate->batches[i].idxbuffer = NULL; + webostate->batches[i].firstidx = idxcount; idxcount += webostate->batches[i].numidx; } if (idxcount) @@ -3144,7 +3155,7 @@ void R_GeneratedWorldEBO(void *ctx, void *data, size_t a_, size_t b_) b->mesh = &webostate->batches[i].pm; b->meshes = 1; m->numindexes = webostate->batches[i].numidx; - m->vbofirstelement = webostate->batches[i].idxbuffer - (index_t*)NULL; + m->vbofirstelement = webostate->batches[i].firstidx; m->vbofirstvert = 0; m->indexes = NULL; b->vbo = &webostate->batches[i].vbo; @@ -3277,13 +3288,25 @@ void R_GenWorldEBO(void *ctx, void *data, size_t a, size_t b) struct webostate_s *es = ctx; qbyte *pvs; - es->numbatches = es->wmodel->numbatches; - - for (i = 0; i < es->numbatches; i++) + if (!es->numbatches) { - es->batches[i].numidx = 0; - es->batches[i].maxidx = 0; - es->batches[i].idxbuffer = NULL; + es->numbatches = es->wmodel->numbatches; + + for (i = 0; i < es->numbatches; i++) + { + es->batches[i].firstidx = 0; + es->batches[i].numidx = 0; + es->batches[i].maxidx = 0; + es->batches[i].idxbuffer = NULL; + } + } + else + { + for (i = 0; i < es->numbatches; i++) + { + es->batches[i].firstidx = 0; + es->batches[i].numidx = 0; + } } //maybe we should just use fatpvs instead, and wait for completion when outside? @@ -3351,19 +3374,19 @@ void Surf_DrawWorld (void) #ifdef THREADEDWORLD if ((r_temporalscenecache.ival || currentmodel->numbatches) && !r_refdef.recurse && currentmodel->type == mod_brush) { - struct webostate_s *webostate, *best = NULL, *kill; + struct webostate_s *webostate, *best = NULL, *kill, **link; vec_t bestdist = FLT_MAX; for (webostate = webostates; webostate; webostate = webostate->next) { if (webostate->wmodel != currentmodel) continue; - kill = webostate->next; - if (kill && kill->lastvalid < cls.framecount-5) - { - webostate->next = kill->next; - R_DestroyWorldEBO(kill); - } +// kill = webostate->next; +// if (kill && kill->lastvalid < cls.framecount-5) +// { +// webostate->next = kill->next; +// R_DestroyWorldEBO(kill); +// } if (webostate->cluster[0] == r_viewcluster && webostate->cluster[1] == r_viewcluster2) { @@ -3438,8 +3461,31 @@ void Surf_DrawWorld (void) } /*TODO submodels too*/ } + webogeneratingstate = true; - webogenerating = BZ_Malloc(sizeof(*webogenerating) + sizeof(webogenerating->batches[0]) * (currentmodel->numbatches-1) + currentmodel->pvsbytes); + + webogenerating = NULL; + if (webostate) + webostate->lastvalid = cls.framecount; + for (link = &webostates; (kill=*link); ) + { + if (kill->lastvalid < cls.framecount-5 && kill->wmodel == currentmodel) + { //this one looks old... kill it. + if (webogenerating) + R_DestroyWorldEBO(webogenerating); //can't use more than one! + webogenerating = kill; + *link = kill->next; + } + else + link = &(*link)->next; + } + if (!webogenerating) + { + webogenerating = BZ_Malloc(sizeof(*webogenerating) + sizeof(webogenerating->batches[0]) * (currentmodel->numbatches-1) + currentmodel->pvsbytes); + memset(&webogenerating->ebo, 0, sizeof(webogenerating->ebo)); + webogenerating->ebomem = NULL; + webogenerating->numbatches = 0; + } webogenerating->wmodel = currentmodel; webogenerating->cluster[0] = r_viewcluster; webogenerating->cluster[1] = r_viewcluster2; @@ -3912,7 +3958,7 @@ int Surf_NewLightmaps(int count, int width, int height, uploadfmt_t fmt, qboolea extern cvar_t gl_pbolightmaps; //we might as well use a pbo for our staging memory. if (qrenderer == QR_OPENGL && qglBufferStorage && qglMapBufferRange && gl_pbolightmaps.ival && Sys_IsMainThread()) - { //glBufferStorage and GL_MAP_PERSISTENT_BIT generally means gl4.4+ + { //glBufferStorage and GL_MAP_PERSISTENT_BIT generally means gl4.4+ (we need persistent for scenecache) //pbos are 2.1 if (deluxe && ((i - numlightmaps)&1)) { diff --git a/engine/client/renderer.c b/engine/client/renderer.c index 43418bb5a..398c93d3d 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -173,7 +173,7 @@ cvar_t r_drawviewmodel = CVARF ("r_drawviewmodel", "1", CVAR_ARCHIVE); cvar_t r_drawviewmodelinvis = CVAR ("r_drawviewmodelinvis", "0"); cvar_t r_dynamic = CVARFD ("r_dynamic", IFMINIMAL("0","1"), CVAR_ARCHIVE, "0: no standard dlights at all.\n1: coloured dlights will be used, they may show through walls. These are not realtime things.\n2: The dlights will be forced to monochrome (this does not affect coronas/flashblends/rtlights attached to the same light)."); -cvar_t r_temporalscenecache = CVARFD ("r_temporalscenecache", "0", CVAR_ARCHIVE, "Controls whether to generate+reuse a scene cache over multiple frames. This is generated on a separate thread to avoid any associated costs. This can significantly boost framerates on complex maps, but can also stress the gpu more (performance tradeoff that varies per map). An outdated cache may be used if the cache takes too long to build (eg: lightmap animations), which could cause the odd glitch when moving fast (but retain more consistent framerates - another tradeoff).\n0: Tranditional quake rendering.\n1: Generate+Use the scene cache."); +cvar_t r_temporalscenecache = CVARFD ("r_temporalscenecache", "", CVAR_ARCHIVE, "Controls whether to generate+reuse a scene cache over multiple frames. This is generated on a separate thread to avoid any associated costs. This can significantly boost framerates on complex maps, but can also stress the gpu more (performance tradeoff that varies per map). An outdated cache may be used if the cache takes too long to build (eg: lightmap animations), which could cause the odd glitch when moving fast (but retain more consistent framerates - another tradeoff).\n0: Tranditional quake rendering.\n1: Generate+Use the scene cache."); cvar_t r_fastturb = CVARF ("r_fastturb", "0", CVAR_SHADERSYSTEM); cvar_t r_skycloudalpha = CVARFD ("r_skycloudalpha", "1", CVAR_RENDERERLATCH, "Controls how opaque the front layer of legacy scrolling skies should be."); @@ -455,7 +455,7 @@ cvar_t gl_smoothcrosshair = CVAR ("gl_smoothcrosshair", "1"); cvar_t gl_maxdist = CVARAD ("gl_maxdist", "0", "gl_farclip", "The distance of the far clip plane. If set to 0, some fancy maths will be used to place it at an infinite distance."); #ifdef SPECULAR -cvar_t gl_specular = CVARF ("gl_specular", "0.3", CVAR_ARCHIVE|CVAR_SHADERSYSTEM); +cvar_t gl_specular = CVARFD ("gl_specular", "0.3", CVAR_ARCHIVE|CVAR_SHADERSYSTEM, "Multiplier for specular effects."); cvar_t gl_specular_power = CVARF ("gl_specular_power", "32", CVAR_ARCHIVE|CVAR_SHADERSYSTEM); cvar_t gl_specular_fallback = CVARF ("gl_specular_fallback", "0.05", CVAR_ARCHIVE|CVAR_RENDERERLATCH); cvar_t gl_specular_fallbackexp = CVARF ("gl_specular_fallbackexp", "1", CVAR_ARCHIVE|CVAR_RENDERERLATCH); @@ -505,6 +505,7 @@ cvar_t r_shadow_bumpscale_bumpmap = CVARD ("r_shadow_bumpscale_bumpmap", "4", cvar_t r_shadow_heightscale_basetexture = CVARD ("r_shadow_heightscale_basetexture", "0", "scaler for generation of height maps from legacy paletted content."); cvar_t r_shadow_heightscale_bumpmap = CVARD ("r_shadow_heightscale_bumpmap", "1", "height scaler for 8bit _bump textures"); +cvar_t r_glsl_pbr = CVARFD ("r_glsl_pbr", "0", CVAR_ARCHIVE|CVAR_SHADERSYSTEM, "Force PBR shading."); cvar_t r_glsl_offsetmapping = CVARFD ("r_glsl_offsetmapping", "0", CVAR_ARCHIVE|CVAR_SHADERSYSTEM, "Enables the use of paralax mapping, adding fake depth to textures."); cvar_t r_glsl_offsetmapping_scale = CVAR ("r_glsl_offsetmapping_scale", "0.04"); cvar_t r_glsl_offsetmapping_reliefmapping = CVARFD("r_glsl_offsetmapping_reliefmapping", "0", CVAR_ARCHIVE|CVAR_SHADERSYSTEM, "Changes the paralax sampling mode to be a bit nicer, but noticably more expensive at high resolutions. r_glsl_offsetmapping must be set."); @@ -904,6 +905,7 @@ void Renderer_Init(void) Cvar_Register (&r_coronas_fadedist, GRAPHICALNICETIES); Cvar_Register (&r_flashblend, GRAPHICALNICETIES); Cvar_Register (&r_flashblendscale, GRAPHICALNICETIES); + Cvar_Register (&r_glsl_pbr, GRAPHICALNICETIES); Cvar_Register (&gl_specular, GRAPHICALNICETIES); Cvar_Register (&gl_specular_power, GRAPHICALNICETIES); Cvar_Register (&gl_specular_fallback, GRAPHICALNICETIES); diff --git a/engine/client/snd_alsa.c b/engine/client/snd_alsa.c index bda00b5b4..b4c4d0e55 100755 --- a/engine/client/snd_alsa.c +++ b/engine/client/snd_alsa.c @@ -306,13 +306,20 @@ static qboolean QDECL ALSA_InitCard (soundcardinfo_t *sc, const char *pcmname) #if 1 if (!sc->sn.sampleformat) - sc->sn.sampleformat = (sc->sn.samplebytes==1)?QSF_U8:QSF_S16; + { + if (sc->sn.samplebytes >= 4) + sc->sn.sampleformat = QSF_F32; + else if (sc->sn.samplebytes != 1) + sc->sn.sampleformat = QSF_S16; + else + sc->sn.sampleformat = QSF_U8; + } switch(sc->sn.sampleformat) { - case QSF_U8: err = SND_PCM_FORMAT_U8; break; - case QSF_S8: err = SND_PCM_FORMAT_S8; break; - case QSF_S16: err = SND_PCM_FORMAT_S16; break; - case QSF_F32: err = SND_PCM_FORMAT_FLOAT; break; + case QSF_U8: err = SND_PCM_FORMAT_U8; sc->sn.samplebytes=1; break; + case QSF_S8: err = SND_PCM_FORMAT_S8; sc->sn.samplebytes=1; break; + case QSF_S16: err = SND_PCM_FORMAT_S16; sc->sn.samplebytes=2; break; + case QSF_F32: err = SND_PCM_FORMAT_FLOAT; sc->sn.samplebytes=4; break; default: Con_Printf (CON_ERROR "ALSA: unsupported sample format %i\n", sc->sn.sampleformat); goto error; diff --git a/engine/client/snd_dma.c b/engine/client/snd_dma.c index 21b0fe224..76618cdc5 100644 --- a/engine/client/snd_dma.c +++ b/engine/client/snd_dma.c @@ -89,7 +89,7 @@ cvar_t nosound = CVARFD( "nosound", "0", CVAR_ARCHIVE, "Disable all sound from the engine. Cannot be overriden by configs or anything if set via the -nosound commandline argument."); cvar_t snd_precache = CVARAF( "s_precache", "1", "precache", 0); -cvar_t loadas8bit = CVARAFD( "s_loadas8bit", "0", +cvar_t snd_loadas8bit = CVARAFD( "s_loadas8bit", "0", "loadas8bit", CVAR_ARCHIVE, "Downsample sounds on load as lower quality 8-bit sound, to save memory."); #ifdef FTE_TARGET_WEB @@ -2315,7 +2315,7 @@ void S_Init (void) Cvar_Register(&mastervolume, "Sound controls"); Cvar_Register(&volume, "Sound controls"); Cvar_Register(&snd_precache, "Sound controls"); - Cvar_Register(&loadas8bit, "Sound controls"); + Cvar_Register(&snd_loadas8bit, "Sound controls"); Cvar_Register(&snd_loadasstereo, "Sound controls"); Cvar_Register(&bgmvolume, "Sound controls"); Cvar_Register(&snd_nominaldistance, "Sound controls"); @@ -2857,8 +2857,9 @@ static void SND_Spatialize(soundcardinfo_t *sc, channel_t *ch) scale = 1; scale = (1.0 - dist) * scale; v = ch->master_vol * scale * volscale; + v = bound(0, v, 255); for (i = 0; i < sc->sn.numchannels; i++) - ch->vol[i] = bound(0, v, 255); + ch->vol[i] = v; return; } @@ -2890,7 +2891,8 @@ static void SND_Spatialize(soundcardinfo_t *sc, channel_t *ch) scale = 1 + DotProduct(listener_vec, sc->speakerdir[i]); scale = (1.0 - dist) * scale * sc->dist[i]; v = ch->master_vol * scale * volscale; - ch->vol[i] = bound(0, v, 255); + v = bound(0, v, 255); + ch->vol[i] = v; } } diff --git a/engine/client/snd_mem.c b/engine/client/snd_mem.c index 62eba444d..e0284d6c0 100644 --- a/engine/client/snd_mem.c +++ b/engine/client/snd_mem.c @@ -569,9 +569,9 @@ static qboolean ResampleSfx (sfx_t *sfx, int inrate, int inchannels, qaudiofmt_t scale = snd_speed / (double)inrate; outsamps = insamps * scale; - if (loadas8bit.ival < 0) + if (snd_loadas8bit.ival < 0) outformat = QAF_S16; - else if (loadas8bit.ival) + else if (snd_loadas8bit.ival) outformat = QAF_S8; else outformat = informat; @@ -789,7 +789,7 @@ static qboolean QDECL S_LoadWavSound (sfx_t *s, qbyte *data, size_t datalen, int format = QAF_F32; } #else - else if (info.format == 3 && info.bitwidth == 4) //signed floats + else if (info.format == 3 && info.bitwidth == 32) //signed floats { short *out = (short *)(data + info.dataofs); float *in = (float *)(data + info.dataofs); diff --git a/engine/client/snd_mix.c b/engine/client/snd_mix.c index 12a5ff62b..f51ed9e8d 100644 --- a/engine/client/snd_mix.c +++ b/engine/client/snd_mix.c @@ -23,25 +23,42 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifdef HAVE_MIXER + +//#define MIXER_PAINT_F32 +#ifdef MIXER_PAINT_F32 + #define MIX_16_8(val) ((val)/(float)(1<<(15+8))) + #define MIX_8_8(val) ((val)/(float)(1<<(7+8))) + typedef struct { + float s[MAXSOUNDCHANNELS]; + } portable_samplegroup_t; +#else + #define MIX_16_8(val) ((val)>>8) //value is a 16bit*8bit value (audio*vol) value. discard the lower 8 bits to treat the volume as a fraction + #define MIX_8_8(val) (val) //value is a 8bit*8bit value (audio*vol) value. result is 16bit. + + typedef struct { + int s[MAXSOUNDCHANNELS]; //signed, 1=0x7fff ish. will be clamped to allow oversaturation + } portable_samplegroup_t; +#endif + #define PAINTBUFFER_SIZE 2048 -portable_samplegroup_t paintbuffer[PAINTBUFFER_SIZE]; //FIXME: we really ought to be using SSE and floats or something. - -int *snd_p, snd_vol; -short *snd_out; +static portable_samplegroup_t paintbuffer[PAINTBUFFER_SIZE]; //FIXME: we really ought to be using SSE and floats or something. void S_TransferPaintBuffer(soundcardinfo_t *sc, int endtime) { unsigned int out_idx; unsigned int count; unsigned int outlimit; - int *p; +#ifdef MIXER_PAINT_F32 + float *p = (float *fte_restrict)paintbuffer; +#else + int *p = (int *fte_restrict) paintbuffer; +#endif int val; // int snd_vol; - short *pbuf; + void *pbuf; int i, numc; - p = (int *) paintbuffer; count = (endtime - sc->paintedtime) * sc->sn.numchannels; outlimit = sc->sn.samples; out_idx = (sc->paintedtime * sc->sn.numchannels) % outlimit; @@ -64,12 +81,21 @@ void S_TransferPaintBuffer(soundcardinfo_t *sc, int endtime) { for (i = 0; i < numc; i++) { - val = *p++;// * snd_vol) >> 8; +#ifdef MIXER_PAINT_F32 + val = (*p++ + 1)*128; + if (val > 255) + val = 255; + else if (val < 0) + val = 0; + out[out_idx] = val; +#else + val = *p++; if (val > 0x7fff) val = 0x7fff; else if (val < (short)0x8000) val = (short)0x8000; out[out_idx] = (val>>8) + 128; +#endif out_idx = (out_idx + 1) % outlimit; } p += MAXSOUNDCHANNELS - numc; @@ -84,12 +110,21 @@ void S_TransferPaintBuffer(soundcardinfo_t *sc, int endtime) { for (i = 0; i < numc; i++) { - val = *p++;// * snd_vol) >> 8; +#ifdef MIXER_PAINT_F32 + val = *p++*128; + if (val > 127) + val = 127; + else if (val < -128) + val = -128; + out[out_idx] = val; +#else + val = *p++; if (val > 0x7fff) val = 0x7fff; else if (val < (short)0x8000) val = (short)0x8000; out[out_idx] = (val>>8); +#endif out_idx = (out_idx + 1) % outlimit; } p += MAXSOUNDCHANNELS - numc; @@ -104,7 +139,11 @@ void S_TransferPaintBuffer(soundcardinfo_t *sc, int endtime) { for (i = 0; i < numc; i++) { - val = *p++;// * snd_vol) >> 8; +#ifdef MIXER_PAINT_F32 + val = *p++*0x7fff; +#else + val = *p++; +#endif if (val > 0x7fff) val = 0x7fff; else if (val < (short)0x8000) @@ -124,7 +163,11 @@ void S_TransferPaintBuffer(soundcardinfo_t *sc, int endtime) { for (i = 0; i < numc; i++) { +#ifdef MIXER_PAINT_F32 //FIXME: replace with a memcpy. + out[out_idx] = *p++; +#else out[out_idx] = *p++ * (1.0 / 32768); +#endif out_idx = (out_idx + 1) % outlimit; } p += MAXSOUNDCHANNELS - numc; @@ -375,23 +418,23 @@ static void SND_PaintChannel8_O2I1 (channel_t *ch, sfxcache_t *sc, int starttime if (rate != (1<data; + sfx = (signed char *fte_restrict)sc->data; for (i=0 ; i>PITCHSHIFT]; pos += rate; - paintbuffer[starttime+i].s[0] += ch->vol[0] * data; - paintbuffer[starttime+i].s[1] += ch->vol[1] * data; + paintbuffer[starttime+i].s[0] += MIX_8_8(ch->vol[0] * data); + paintbuffer[starttime+i].s[1] += MIX_8_8(ch->vol[1] * data); } } else { - sfx = (signed char *)sc->data + (pos>>PITCHSHIFT); + sfx = (signed char *fte_restrict)sc->data + (pos>>PITCHSHIFT); for (i=0 ; ivol[0] * data; - paintbuffer[starttime+i].s[1] += ch->vol[1] * data; + paintbuffer[starttime+i].s[0] += MIX_8_8(ch->vol[0] * data); + paintbuffer[starttime+i].s[1] += MIX_8_8(ch->vol[1] * data); } } } @@ -405,21 +448,21 @@ static void SND_PaintChannel8_O2I2 (channel_t *ch, sfxcache_t *sc, int starttime if (rate != (1<data; + sfx = (signed char *fte_restrict)sc->data; for (i=0 ; ivol[0] * sfx[(pos>>(PITCHSHIFT-1))&~1]; - paintbuffer[starttime+i].s[1] += ch->vol[1] * sfx[(pos>>(PITCHSHIFT-1))|1]; + paintbuffer[starttime+i].s[0] += MIX_8_8(ch->vol[0] * sfx[(pos>>(PITCHSHIFT-1))&~1]); + paintbuffer[starttime+i].s[1] += MIX_8_8(ch->vol[1] * sfx[(pos>>(PITCHSHIFT-1))|1]); pos += rate; } } else { - sfx = (signed char *)sc->data + (pos>>PITCHSHIFT)*2; + sfx = (signed char *fte_restrict)sc->data + (pos>>PITCHSHIFT)*2; for (i=0 ; ivol[0] * sfx[(i<<1)]; - paintbuffer[starttime+i].s[1] += ch->vol[1] * sfx[(i<<1)+1]; + paintbuffer[starttime+i].s[0] += MIX_8_8(ch->vol[0] * sfx[(i<<1)]); + paintbuffer[starttime+i].s[1] += MIX_8_8(ch->vol[1] * sfx[(i<<1)+1]); } } } @@ -433,26 +476,26 @@ static void SND_PaintChannel8_O4I1 (channel_t *ch, sfxcache_t *sc, int count, in if (rate != (1<data; + sfx = (signed char *fte_restrict)sc->data; for (i=0 ; i>PITCHSHIFT]; pos += rate; - paintbuffer[i].s[0] += ch->vol[0] * data; - paintbuffer[i].s[1] += ch->vol[1] * data; - paintbuffer[i].s[2] += ch->vol[2] * data; - paintbuffer[i].s[3] += ch->vol[3] * data; + paintbuffer[i].s[0] += MIX_8_8(ch->vol[0] * data); + paintbuffer[i].s[1] += MIX_8_8(ch->vol[1] * data); + paintbuffer[i].s[2] += MIX_8_8(ch->vol[2] * data); + paintbuffer[i].s[3] += MIX_8_8(ch->vol[3] * data); } } else { - sfx = (signed char *)sc->data + (pos>>PITCHSHIFT); + sfx = (signed char *fte_restrict)sc->data + (pos>>PITCHSHIFT); for (i=0 ; ivol[0] * sfx[i]; - paintbuffer[i].s[1] += ch->vol[1] * sfx[i]; - paintbuffer[i].s[2] += ch->vol[2] * sfx[i]; - paintbuffer[i].s[3] += ch->vol[3] * sfx[i]; + paintbuffer[i].s[0] += MIX_8_8(ch->vol[0] * sfx[i]); + paintbuffer[i].s[1] += MIX_8_8(ch->vol[1] * sfx[i]); + paintbuffer[i].s[2] += MIX_8_8(ch->vol[2] * sfx[i]); + paintbuffer[i].s[3] += MIX_8_8(ch->vol[3] * sfx[i]); } } } @@ -466,30 +509,30 @@ static void SND_PaintChannel8_O6I1 (channel_t *ch, sfxcache_t *sc, int count, in if (rate != (1<data; + sfx = (signed char *fte_restrict)sc->data; for (i=0 ; i>PITCHSHIFT]; pos += rate; - paintbuffer[i].s[0] += ch->vol[0] * data; - paintbuffer[i].s[1] += ch->vol[1] * data; - paintbuffer[i].s[2] += ch->vol[2] * data; - paintbuffer[i].s[3] += ch->vol[3] * data; - paintbuffer[i].s[4] += ch->vol[4] * data; - paintbuffer[i].s[5] += ch->vol[5] * data; + paintbuffer[i].s[0] += MIX_8_8(ch->vol[0] * data); + paintbuffer[i].s[1] += MIX_8_8(ch->vol[1] * data); + paintbuffer[i].s[2] += MIX_8_8(ch->vol[2] * data); + paintbuffer[i].s[3] += MIX_8_8(ch->vol[3] * data); + paintbuffer[i].s[4] += MIX_8_8(ch->vol[4] * data); + paintbuffer[i].s[5] += MIX_8_8(ch->vol[5] * data); } } else { - sfx = (signed char *)sc->data + (pos>>PITCHSHIFT); + sfx = (signed char *fte_restrict)sc->data + (pos>>PITCHSHIFT); for (i=0 ; ivol[0] * sfx[i]; - paintbuffer[i].s[1] += ch->vol[1] * sfx[i]; - paintbuffer[i].s[2] += ch->vol[2] * sfx[i]; - paintbuffer[i].s[3] += ch->vol[3] * sfx[i]; - paintbuffer[i].s[4] += ch->vol[4] * sfx[i]; - paintbuffer[i].s[5] += ch->vol[5] * sfx[i]; + paintbuffer[i].s[0] += MIX_8_8(ch->vol[0] * sfx[i]); + paintbuffer[i].s[1] += MIX_8_8(ch->vol[1] * sfx[i]); + paintbuffer[i].s[2] += MIX_8_8(ch->vol[2] * sfx[i]); + paintbuffer[i].s[3] += MIX_8_8(ch->vol[3] * sfx[i]); + paintbuffer[i].s[4] += MIX_8_8(ch->vol[4] * sfx[i]); + paintbuffer[i].s[5] += MIX_8_8(ch->vol[5] * sfx[i]); } } } @@ -503,34 +546,34 @@ static void SND_PaintChannel8_O8I1 (channel_t *ch, sfxcache_t *sc, int count, in if (rate != (1<data; + sfx = (signed char *fte_restrict)sc->data; for (i=0 ; i>PITCHSHIFT]; pos += rate; - paintbuffer[i].s[0] += ch->vol[0] * data; - paintbuffer[i].s[1] += ch->vol[1] * data; - paintbuffer[i].s[2] += ch->vol[2] * data; - paintbuffer[i].s[3] += ch->vol[3] * data; - paintbuffer[i].s[4] += ch->vol[4] * data; - paintbuffer[i].s[5] += ch->vol[5] * data; - paintbuffer[i].s[6] += ch->vol[6] * data; - paintbuffer[i].s[7] += ch->vol[7] * data; + paintbuffer[i].s[0] += MIX_8_8(ch->vol[0] * data); + paintbuffer[i].s[1] += MIX_8_8(ch->vol[1] * data); + paintbuffer[i].s[2] += MIX_8_8(ch->vol[2] * data); + paintbuffer[i].s[3] += MIX_8_8(ch->vol[3] * data); + paintbuffer[i].s[4] += MIX_8_8(ch->vol[4] * data); + paintbuffer[i].s[5] += MIX_8_8(ch->vol[5] * data); + paintbuffer[i].s[6] += MIX_8_8(ch->vol[6] * data); + paintbuffer[i].s[7] += MIX_8_8(ch->vol[7] * data); } } else { - sfx = (signed char *)sc->data + (pos>>PITCHSHIFT); + sfx = (signed char *fte_restrict)sc->data + (pos>>PITCHSHIFT); for (i=0 ; ivol[0] * sfx[i]; - paintbuffer[i].s[1] += ch->vol[1] * sfx[i]; - paintbuffer[i].s[2] += ch->vol[2] * sfx[i]; - paintbuffer[i].s[3] += ch->vol[3] * sfx[i]; - paintbuffer[i].s[4] += ch->vol[4] * sfx[i]; - paintbuffer[i].s[5] += ch->vol[5] * sfx[i]; - paintbuffer[i].s[6] += ch->vol[6] * sfx[i]; - paintbuffer[i].s[7] += ch->vol[7] * sfx[i]; + paintbuffer[i].s[0] += MIX_8_8(ch->vol[0] * sfx[i]); + paintbuffer[i].s[1] += MIX_8_8(ch->vol[1] * sfx[i]); + paintbuffer[i].s[2] += MIX_8_8(ch->vol[2] * sfx[i]); + paintbuffer[i].s[3] += MIX_8_8(ch->vol[3] * sfx[i]); + paintbuffer[i].s[4] += MIX_8_8(ch->vol[4] * sfx[i]); + paintbuffer[i].s[5] += MIX_8_8(ch->vol[5] * sfx[i]); + paintbuffer[i].s[6] += MIX_8_8(ch->vol[6] * sfx[i]); + paintbuffer[i].s[7] += MIX_8_8(ch->vol[7] * sfx[i]); } } } @@ -539,7 +582,6 @@ static void SND_PaintChannel8_O8I1 (channel_t *ch, sfxcache_t *sc, int count, in static void SND_PaintChannel16_O2I1 (channel_t *ch, sfxcache_t *sc, int starttime, int count, int rate) { int data; - int left, right; int leftvol, rightvol; signed short *sfx; int i; @@ -551,26 +593,24 @@ static void SND_PaintChannel16_O2I1 (channel_t *ch, sfxcache_t *sc, int starttim if (rate != (1<data; + sfx = (signed short *fte_restrict)sc->data; for (i=0 ; i>PITCHSHIFT] * ((1<>PITCHSHIFT)+1] * frac; pos += rate; - paintbuffer[starttime+i].s[0] += (leftvol * data)>>(PITCHSHIFT+8); - paintbuffer[starttime+i].s[1] += (rightvol * data)>>(PITCHSHIFT+8); + paintbuffer[starttime+i].s[0] += MIX_16_8((leftvol * data)>>PITCHSHIFT); + paintbuffer[starttime+i].s[1] += MIX_16_8((rightvol * data)>>PITCHSHIFT); } } else { - sfx = (signed short *)sc->data + (pos>>PITCHSHIFT); + sfx = (signed short *fte_restrict)sc->data + (pos>>PITCHSHIFT); for (i=0 ; i> 8; - right = (data * rightvol) >> 8; - paintbuffer[starttime+i].s[0] += left; - paintbuffer[starttime+i].s[1] += right; + paintbuffer[starttime+i].s[0] += MIX_16_8(data * leftvol); + paintbuffer[starttime+i].s[1] += MIX_16_8(data * rightvol); } } } @@ -588,23 +628,23 @@ static void SND_PaintChannel16_O2I2 (channel_t *ch, sfxcache_t *sc, int starttim if (rate != (1<data; + sfx = (signed short *fte_restrict)sc->data; for (i=0 ; i>(PITCHSHIFT-1))&~1]; r = sfx[(pos>>(PITCHSHIFT-1))|1]; pos += rate; - paintbuffer[starttime+i].s[0] += (ch->vol[0] * l)>>8; - paintbuffer[starttime+i].s[1] += (ch->vol[1] * r)>>8; + paintbuffer[starttime+i].s[0] += MIX_16_8(ch->vol[0] * l); + paintbuffer[starttime+i].s[1] += MIX_16_8(ch->vol[1] * r); } } else { - sfx = (signed short *)sc->data + (pos>>PITCHSHIFT)*2; + sfx = (signed short *fte_restrict)sc->data + (pos>>PITCHSHIFT)*2; for (i=0 ; i> 8; - paintbuffer[starttime+i].s[1] += (*sfx++ * rightvol) >> 8; + paintbuffer[starttime+i].s[0] += MIX_16_8(*sfx++ * leftvol); + paintbuffer[starttime+i].s[1] += MIX_16_8(*sfx++ * rightvol); } } } @@ -624,26 +664,26 @@ static void SND_PaintChannel16_O4I1 (channel_t *ch, sfxcache_t *sc, int count, i if (rate != (1<data; + sfx = (signed short *fte_restrict)sc->data; for (i=0 ; i>PITCHSHIFT]; pos += rate; - paintbuffer[i].s[0] += (vol[0] * data)>>8; - paintbuffer[i].s[1] += (vol[1] * data)>>8; - paintbuffer[i].s[2] += (vol[2] * data)>>8; - paintbuffer[i].s[3] += (vol[3] * data)>>8; + paintbuffer[i].s[0] += MIX_16_8(vol[0] * data); + paintbuffer[i].s[1] += MIX_16_8(vol[1] * data); + paintbuffer[i].s[2] += MIX_16_8(vol[2] * data); + paintbuffer[i].s[3] += MIX_16_8(vol[3] * data); } } else { - sfx = (signed short *)sc->data + (pos>>PITCHSHIFT); + sfx = (signed short *fte_restrict)sc->data + (pos>>PITCHSHIFT); for (i=0 ; i> 8; - paintbuffer[i].s[1] += (sfx[i] * vol[1]) >> 8; - paintbuffer[i].s[2] += (sfx[i] * vol[2]) >> 8; - paintbuffer[i].s[3] += (sfx[i] * vol[3]) >> 8; + paintbuffer[i].s[0] += MIX_16_8(sfx[i] * vol[0]); + paintbuffer[i].s[1] += MIX_16_8(sfx[i] * vol[1]); + paintbuffer[i].s[2] += MIX_16_8(sfx[i] * vol[2]); + paintbuffer[i].s[3] += MIX_16_8(sfx[i] * vol[3]); } } } @@ -665,30 +705,30 @@ static void SND_PaintChannel16_O6I1 (channel_t *ch, sfxcache_t *sc, int count, i if (rate != (1<data; + sfx = (signed short *fte_restrict)sc->data; for (i=0 ; i>PITCHSHIFT]; pos += rate; - paintbuffer[i].s[0] += (vol[0] * data)>>8; - paintbuffer[i].s[1] += (vol[1] * data)>>8; - paintbuffer[i].s[2] += (vol[2] * data)>>8; - paintbuffer[i].s[3] += (vol[3] * data)>>8; - paintbuffer[i].s[4] += (vol[4] * data)>>8; - paintbuffer[i].s[5] += (vol[5] * data)>>8; + paintbuffer[i].s[0] += MIX_16_8(vol[0] * data); + paintbuffer[i].s[1] += MIX_16_8(vol[1] * data); + paintbuffer[i].s[2] += MIX_16_8(vol[2] * data); + paintbuffer[i].s[3] += MIX_16_8(vol[3] * data); + paintbuffer[i].s[4] += MIX_16_8(vol[4] * data); + paintbuffer[i].s[5] += MIX_16_8(vol[5] * data); } } else { - sfx = (signed short *)sc->data + (pos>>PITCHSHIFT); + sfx = (signed short *fte_restrict)sc->data + (pos>>PITCHSHIFT); for (i=0 ; i> 8; - paintbuffer[i].s[1] += (sfx[i] * vol[1]) >> 8; - paintbuffer[i].s[2] += (sfx[i] * vol[2]) >> 8; - paintbuffer[i].s[3] += (sfx[i] * vol[3]) >> 8; - paintbuffer[i].s[4] += (sfx[i] * vol[4]) >> 8; - paintbuffer[i].s[5] += (sfx[i] * vol[5]) >> 8; + paintbuffer[i].s[0] += MIX_16_8(sfx[i] * vol[0]); + paintbuffer[i].s[1] += MIX_16_8(sfx[i] * vol[1]); + paintbuffer[i].s[2] += MIX_16_8(sfx[i] * vol[2]); + paintbuffer[i].s[3] += MIX_16_8(sfx[i] * vol[3]); + paintbuffer[i].s[4] += MIX_16_8(sfx[i] * vol[4]); + paintbuffer[i].s[5] += MIX_16_8(sfx[i] * vol[5]); } } } @@ -712,34 +752,34 @@ static void SND_PaintChannel16_O8I1 (channel_t *ch, sfxcache_t *sc, int count, i if (rate != (1<data; + sfx = (signed short *fte_restrict)sc->data; for (i=0 ; i>PITCHSHIFT]; pos += rate; - paintbuffer[i].s[0] += (vol[0] * data)>>8; - paintbuffer[i].s[1] += (vol[1] * data)>>8; - paintbuffer[i].s[2] += (vol[2] * data)>>8; - paintbuffer[i].s[3] += (vol[3] * data)>>8; - paintbuffer[i].s[4] += (vol[4] * data)>>8; - paintbuffer[i].s[5] += (vol[5] * data)>>8; - paintbuffer[i].s[6] += (vol[6] * data)>>8; - paintbuffer[i].s[7] += (vol[7] * data)>>8; + paintbuffer[i].s[0] += MIX_16_8(vol[0] * data); + paintbuffer[i].s[1] += MIX_16_8(vol[1] * data); + paintbuffer[i].s[2] += MIX_16_8(vol[2] * data); + paintbuffer[i].s[3] += MIX_16_8(vol[3] * data); + paintbuffer[i].s[4] += MIX_16_8(vol[4] * data); + paintbuffer[i].s[5] += MIX_16_8(vol[5] * data); + paintbuffer[i].s[6] += MIX_16_8(vol[6] * data); + paintbuffer[i].s[7] += MIX_16_8(vol[7] * data); } } else { - sfx = (signed short *)sc->data + (pos>>PITCHSHIFT); + sfx = (signed short *fte_restrict)sc->data + (pos>>PITCHSHIFT); for (i=0 ; i> 8; - paintbuffer[i].s[1] += (sfx[i] * vol[1]) >> 8; - paintbuffer[i].s[2] += (sfx[i] * vol[2]) >> 8; - paintbuffer[i].s[3] += (sfx[i] * vol[3]) >> 8; - paintbuffer[i].s[4] += (sfx[i] * vol[4]) >> 8; - paintbuffer[i].s[5] += (sfx[i] * vol[5]) >> 8; - paintbuffer[i].s[6] += (sfx[i] * vol[6]) >> 8; - paintbuffer[i].s[7] += (sfx[i] * vol[7]) >> 8; + paintbuffer[i].s[0] += MIX_16_8(sfx[i] * vol[0]); + paintbuffer[i].s[1] += MIX_16_8(sfx[i] * vol[1]); + paintbuffer[i].s[2] += MIX_16_8(sfx[i] * vol[2]); + paintbuffer[i].s[3] += MIX_16_8(sfx[i] * vol[3]); + paintbuffer[i].s[4] += MIX_16_8(sfx[i] * vol[4]); + paintbuffer[i].s[5] += MIX_16_8(sfx[i] * vol[5]); + paintbuffer[i].s[6] += MIX_16_8(sfx[i] * vol[6]); + paintbuffer[i].s[7] += MIX_16_8(sfx[i] * vol[7]); } } } @@ -759,7 +799,7 @@ static void SND_PaintChannel32F_O2I1 (channel_t *ch, sfxcache_t *sc, int startti if (rate != (1<data; + sfx = (float *fte_restrict)sc->data; for (i=0 ; idata + (pos>>PITCHSHIFT); + sfx = (float *fte_restrict)sc->data + (pos>>PITCHSHIFT); for (i=0 ; idata; + sfx = (float *fte_restrict)sc->data; for (i=0 ; i>(PITCHSHIFT-1))&~1]; @@ -808,7 +848,7 @@ static void SND_PaintChannel32F_O2I2 (channel_t *ch, sfxcache_t *sc, int startti } else { - sfx = (float *)sc->data + (pos>>PITCHSHIFT)*2; + sfx = (float *fte_restrict)sc->data + (pos>>PITCHSHIFT)*2; for (i=0 ; idata; + sfx = (float *fte_restrict)sc->data; for (i=0 ; i>PITCHSHIFT]; @@ -845,7 +885,7 @@ static void SND_PaintChannel32F_O4I1 (channel_t *ch, sfxcache_t *sc, int count, } else { - sfx = (float *)sc->data + (pos>>PITCHSHIFT); + sfx = (float *fte_restrict)sc->data + (pos>>PITCHSHIFT); for (i=0 ; idata; + sfx = (float *fte_restrict)sc->data; for (i=0 ; i>PITCHSHIFT]; @@ -888,7 +928,7 @@ static void SND_PaintChannel32F_O6I1 (channel_t *ch, sfxcache_t *sc, int count, } else { - sfx = (float *)sc->data + (pos>>PITCHSHIFT); + sfx = (float *fte_restrict)sc->data + (pos>>PITCHSHIFT); for (i=0 ; idata; + sfx = (float *fte_restrict)sc->data; for (i=0 ; i>PITCHSHIFT]; @@ -938,7 +978,7 @@ static void SND_PaintChannel32F_O8I1 (channel_t *ch, sfxcache_t *sc, int count, } else { - sfx = (float *)sc->data + (pos>>PITCHSHIFT); + sfx = (float *fte_restrict)sc->data + (pos>>PITCHSHIFT); for (i=0 ; i>PITCHSHIFT)/KHZ*/ struct sfx_s; -typedef struct -{ - int s[MAXSOUNDCHANNELS]; -} portable_samplegroup_t; typedef struct { struct sfxcache_s *(QDECL *decodedata) (struct sfx_s *sfx, struct sfxcache_s *buf, ssamplepos_t start, int length); //return true when done. @@ -135,7 +131,7 @@ typedef struct typedef struct { sfx_t *sfx; // sfx number - int vol[MAXSOUNDCHANNELS]; // volume, .8 fixed point. + int vol[MAXSOUNDCHANNELS]; // volume, 0.8 fixed point. ssamplepos_t pos; // sample position in sfx, <0 means delay sound start (shifted up by PITCHSHIFT) int rate; // fixed point rate scaling int flags; // cf_ flags @@ -308,7 +304,7 @@ extern int snd_speed; extern cvar_t snd_nominaldistance; -extern cvar_t loadas8bit; +extern cvar_t snd_loadas8bit; extern cvar_t bgmvolume; extern cvar_t volume, mastervolume; extern cvar_t snd_capture; diff --git a/engine/client/sys_linux.c b/engine/client/sys_linux.c index 2d4ba6f53..093dba074 100644 --- a/engine/client/sys_linux.c +++ b/engine/client/sys_linux.c @@ -292,17 +292,32 @@ void Sys_Quit (void) static void Sys_Register_File_Associations_f(void) { char xdgbase[MAX_OSPATH]; + char confbase[MAX_OSPATH]; if (1) - { - const char *e = getenv("XDG_DATA_HOME"); - if (e && *e) - Q_strncpyz(xdgbase, e, sizeof(xdgbase)); + { //user + const char *data = getenv("XDG_DATA_HOME"); + const char *config = getenv("XDG_CONFIG_HOME"); + const char *home = getenv("HOME"); + if (data && *data) + Q_strncpyz(xdgbase, data, sizeof(xdgbase)); else { - e = getenv("HOME"); - if (e && *e) - Q_snprintfz(xdgbase, sizeof(xdgbase), "%s/.local/share", e); + if (home && *home) + Q_snprintfz(xdgbase, sizeof(xdgbase), "%s/.local/share", home); + else + { + Con_Printf("homedir not known\n"); + return; + } + } + + if (config && *config) + Q_strncpyz(confbase, config, sizeof(confbase)); + else + { + if (home && *home) + Q_snprintfz(confbase, sizeof(confbase), "%s/.config", home); else { Con_Printf("homedir not known\n"); @@ -311,20 +326,33 @@ static void Sys_Register_File_Associations_f(void) } } else - { - const char *e = getenv("XDG_DATA_DIRS"); - while (e && *e == ':') - e++; - if (e && *e) + { //system... gotta be root... + const char *data = getenv("XDG_DATA_DIRS"); + const char *config = getenv("XDG_CONFIG_DIRS"); + while (data && *data == ':') + data++; + if (data && *data) { char *c; - Q_strncpyz(xdgbase, e, sizeof(xdgbase)); + Q_strncpyz(xdgbase, data, sizeof(xdgbase)); c = strchr(xdgbase, ':'); if (*c) *c = 0; } else Q_strncpyz(xdgbase, "/usr/local/share/", sizeof(xdgbase)); + while (config && *config == ':') + config++; + if (config && *config) + { + char *c; + Q_strncpyz(confbase, config, sizeof(confbase)); + c = strchr(confbase, ':'); + if (*c) + *c = 0; + } + else + Q_strncpyz(confbase, "/etc/xdg/", sizeof(confbase)); } //we need to create some .desktop file first, so stuff knows how to start us up. @@ -349,7 +377,7 @@ static void Sys_Register_File_Associations_f(void) if (!strcmp(iconname, "afterquake") || !strcmp(iconname, "nq")) //hacks so that we don't need to create icons. iconname = "quake"; - if (FS_NativePath("icon.png", FS_GAME, iconsyspath, sizeof(iconsyspath))) + if (FS_NativePath("icon.png", FS_PUBBASEGAMEONLY, iconsyspath, sizeof(iconsyspath))) iconname = iconsyspath; desktopfile = va(desktopfile, @@ -366,11 +394,11 @@ static void Sys_Register_File_Associations_f(void) //write out a new file and rename the new over the top of the old { char *foundassoc = NULL; - vfsfile_t *out = FS_OpenVFS(va("%s/applications/.mimeapps.list.new", xdgbase), "wb", FS_SYSTEM); + vfsfile_t *out = FS_OpenVFS(va("%s/.mimeapps.list.new", confbase), "wb", FS_SYSTEM); if (out) { qofs_t insize; - char *in = FS_MallocFile(va("%s/applications/mimeapps.list", xdgbase), FS_SYSTEM, &insize); + char *in = FS_MallocFile(va("%s/mimeapps.list", confbase), FS_SYSTEM, &insize); if (in) { qboolean inadded = false; @@ -404,7 +432,7 @@ static void Sys_Register_File_Associations_f(void) if (foundassoc) { //if we found it, or somewhere to insert it, then insert it. VFS_WRITE(out, in, foundassoc-in); - VFS_PRINTF(out, "x-scheme-handler/qw=fte-%s.desktop\n", fs_manifest->installation); + VFS_PRINTF(out, "x-scheme-handler/qw=fte-%s.desktop;\n", fs_manifest->installation); VFS_WRITE(out, foundassoc, insize - (foundassoc-in)); } else @@ -414,11 +442,11 @@ static void Sys_Register_File_Associations_f(void) if (!foundassoc) { //if file not found, or no appropriate section, just concat it on the end. VFS_PRINTF(out, "[Added Associations]\n"); - VFS_PRINTF(out, "x-scheme-handler/qw=fte-%s.desktop\n", fs_manifest->installation); + VFS_PRINTF(out, "x-scheme-handler/qw=fte-%s.desktop;\n", fs_manifest->installation); } VFS_FLUSH(out); VFS_CLOSE(out); - FS_Rename2(va("%s/applications/.mimeapps.list.new", xdgbase), va("%s/applications/mimeapps.list", xdgbase), FS_SYSTEM, FS_SYSTEM); + FS_Rename2(va("%s/.mimeapps.list.new", confbase), va("%s/mimeapps.list", confbase), FS_SYSTEM, FS_SYSTEM); } } } diff --git a/engine/client/valid.c b/engine/client/valid.c index 18524515f..ec40dd854 100644 --- a/engine/client/valid.c +++ b/engine/client/valid.c @@ -637,6 +637,8 @@ static rulesetrule_t rulesetrules_strict[] = { {"ruleset_allow_sensitive_texture_replacements", "0"}, {"ruleset_allow_localvolume", "0"}, {"ruleset_allow_fbmodels", "0"}, + {"r_particlesystem", "classic"}, /*block custom particles*/ + {"r_part_density", "1"}, /*don't let people thin them out*/ {"scr_autoid_team", "0"}, /*sort of a wallhack*/ {"tp_disputablemacros", "0"}, {"cl_instantrotate", "0"}, @@ -645,6 +647,34 @@ static rulesetrule_t rulesetrules_strict[] = { {"ruleset_allow_in", "0"}, {"r_projection", "0"}, {"gl_shadeq1_name", "*"}, + {"cl_rollalpha", "20"}, + {"cl_iDrive", "0"}, + {NULL} +}; + +static rulesetrule_t rulesetrules_thunderdome[] = { + {"ruleset_allow_shaders", "0"}, /*users can potentially create all sorts of wallhacks or spiked models with this*/ + {"ruleset_allow_watervis", "0"}, /*oh noes! users might be able to see underwater if they're already in said water. oh wait. what? why do we care, dude*/ + {"r_vertexlight", "0"}, + {"ruleset_allow_playercount", "0"}, + {"ruleset_allow_frj", "0"}, + {"ruleset_allow_packet", "0"}, + {"ruleset_allow_particle_lightning", "0"}, + {"ruleset_allow_overlong_sounds", "0"}, + {"ruleset_allow_larger_models", "0"}, + {"ruleset_allow_modified_eyes", "0"}, + {"ruleset_allow_sensitive_texture_replacements", "0"}, + {"ruleset_allow_localvolume", "0"}, + {"ruleset_allow_fbmodels", "0"}, + {"scr_autoid_team", "0"}, /*sort of a wallhack*/ + {"tp_disputablemacros", "0"}, + {"cl_instantrotate", "0"}, + {"v_projectionmode", "0"}, /*no extended fovs*/ + {"r_shadow_realtime_world", "0"}, /*static lighting can be used to cast shadows around corners*/ + {"ruleset_allow_in", "0"}, + {"r_projection", "0"}, + {"gl_shadeq1_name", "*"}, +// {"cl_rollalpha", "20"}, {"cl_iDrive", "0"}, {NULL} }; @@ -673,9 +703,12 @@ static rulesetrule_t rulesetrules_nqr[] = { static ruleset_t rulesets[] = { - {"strict", rulesetrules_strict}, - {"nqr", rulesetrules_nqr}, - //{"eql", rulesetrules_nqr}, + {"strict", rulesetrules_strict}, + {"qcon", rulesetrules_strict}, //not authorised but oh well. imported configs tend to piss people off. + {"smackdown", rulesetrules_strict}, //officially, smackdown cannot authorise this, thus we do not use that name. however, imported configs tend to piss people off. + {"thunderdome", rulesetrules_thunderdome}, //more permissive (doesn't block particles. + {"nqr", rulesetrules_nqr}, + //{"eql", rulesetrules_nqr}, {NULL} }; diff --git a/engine/client/view.c b/engine/client/view.c index 936900dfe..bcfab9c7e 100644 --- a/engine/client/view.c +++ b/engine/client/view.c @@ -2013,14 +2013,26 @@ void R_DrawNameTags(void) #if defined(CSQC_DAT) || !defined(CLIENTONLY) if (r_showshaders.ival && cl.worldmodel && cl.worldmodel->loadstate == MLS_LOADED) { +#ifdef CSQC_DAT + extern world_t csqc_world; +#endif trace_t trace; char *str; vec3_t targ; vec2_t scale = {12,12}; msurface_t *surf; VectorMA(r_refdef.vieworg, 8192, vpn, targ); - //FIXME: should probably do a general trace, to hit (networked) submodels too - cl.worldmodel->funcs.NativeTrace(cl.worldmodel, 0, PE_FRAMESTATE, NULL, r_refdef.vieworg, targ, vec3_origin, vec3_origin, false, ~0, &trace); +#ifdef CSQC_DAT + if (csqc_world.progs) + { + int oldhit = csqc_world.edicts->xv->hitcontentsmaski; + csqc_world.edicts->xv->hitcontentsmaski = ~0; + trace = World_Move(&csqc_world, r_refdef.vieworg, vec3_origin, vec3_origin, targ, MOVE_EVERYTHING, csqc_world.edicts); + csqc_world.edicts->xv->hitcontentsmaski = oldhit; + } + else +#endif + cl.worldmodel->funcs.NativeTrace(cl.worldmodel, 0, PE_FRAMESTATE, NULL, r_refdef.vieworg, targ, vec3_origin, vec3_origin, false, ~0, &trace); surf = Mod_GetSurfaceNearPoint(cl.worldmodel, trace.endpos); if (surf) diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index 5be1d9ba7..aab71651c 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -707,8 +707,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #endif #if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) #define FTE_DEPRECATED __attribute__((__deprecated__)) //no idea about the actual gcc version - #ifdef _WIN32 - #define LIKEPRINTF(x) __attribute__((format(ms_printf,x,x+1))) + #if defined(_WIN32) + #include + #ifdef __MINGW_PRINTF_FORMAT + #define LIKEPRINTF(x) __attribute__((format(__MINGW_PRINTF_FORMAT,x,x+1))) + #else + #define LIKEPRINTF(x) __attribute__((format(ms_printf,x,x+1))) + #endif #else #define LIKEPRINTF(x) __attribute__((format(printf,x,x+1))) #endif diff --git a/engine/common/cmd.c b/engine/common/cmd.c index c1ea4a8f5..e1e475797 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -805,37 +805,56 @@ static void Cmd_Exec_f (void) #ifndef QUAKETC //hack to try to work around nquake's b0rkedness if (!strncmp(s, "// This is nQuake's Frogbot config", 33)) - s = "echo Refusing to exec nQuake's Frogbot config"; //otherwise many people with nquake installed will be fucked over whenever they try playing singleplayer - else if (!strncmp(s, "// ", 3)) { - char *eol = strstr(s, "\n"); - if (eol) - { - *eol = 0; - s = eol+1; - if (strstr(f, "nQuake")) - { //this is evil, but if we're running quake then com_parseutf8 will be 0 and we can just convert to quake chars. - char *in = s; - char *out = s; - int foundone = 0; - while (*in) - { - if (*in == '^') - { - *out++ = 0x80|*++in; - foundone++; - } - else - *out++ = *in; - in++; - } - if (foundone) - Cbuf_InsertText(va("echo fixups for nquake config %s: %i replacements\n", buf, foundone), level, false); - } - } + s = "echo Refusing to exec nQuake's Frogbot config"; //otherwise many people with nquake installed will be fucked over whenever they try playing singleplayer + Cbuf_InsertText (s, level, true); } -#endif + else + { + int foundone = 0; + while (!strncmp(s, "//", 2)) + { + char *eol = strstr(s, "\n"); + if (eol) + { + *eol++ = 0; + if (strstr(s, "nQuake") || strstr(s, "N Q U A K E")) + { //this is evil, but if we're running quake then com_parseutf8 will be 0 and we can just convert to quake chars (less text). + char *out = s = eol; + const char *in = s; + while (*in) + { + if (*in == '\n' && !strncmp(in,"\nexec configs/config.cfg", 24)) + { //ezquake writes its configs elsewhere, and nquake stomps on everything in its autoexec.cfg, so we need to try to work around its breakages + memmove(out, in, 6);out+=6;in+=6; + in += 8; + foundone++; + continue; + } + if (*in == '^') + { + *out++ = 0x80|*++in; + foundone++; + } + else + *out++ = *in; + in++; + } + *out = 0; + break; + } + s = eol; + continue; + } + break; + } + Cbuf_InsertText (s, level, true); + if (foundone) + Cbuf_InsertText(va("\necho \""CON_ERROR"fixups for nquake config %s: %i replacements\"\n", buf, foundone), level, false); + } +#else Cbuf_InsertText (s, level, true); +#endif if (cvar_watched) Cbuf_InsertText (va("echo BEGIN %s", buf), level, true); BZ_Free(f); diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c index e9ddfee6a..b033fa340 100644 --- a/engine/common/com_mesh.c +++ b/engine/common/com_mesh.c @@ -23,6 +23,7 @@ cvar_t r_lerpmuzzlehack = CVARF ("r_lerpmuzzlehack", "1", CVAR_ARCHIVE); #ifdef MD1MODELS cvar_t mod_h2holey_bugged = CVARD ("mod_h2holey_bugged", "0", "Hexen2's holey-model flag uses index 0 as transparent (and additionally 255 in gl, due to a bug). GLQuake engines tend to have bugs that use ONLY index 255, resulting in a significant compatibility issue that can be resolved only with this shitty cvar hack."); cvar_t mod_halftexel = CVARD ("mod_halftexel", "1", "Offset texture coords by a half-texel, for compatibility with glquake and the majority of engine forks."); +cvar_t mod_nomipmap = CVARD ("mod_nomipmap", "0", "Disables the use of mipmaps on quake1 mdls, consistent with its original software renderer."); #endif static void QDECL r_meshpitch_callback(cvar_t *var, char *oldvalue) { @@ -3150,6 +3151,8 @@ void Mod_LoadAliasShaders(model_t *mod) if (!ruleset_allow_sensitive_texture_replacements.ival) imageflags |= IF_NOREPLACE; } + if (mod->fromgame == fg_quake && mod_nomipmap.ival) + imageflags |= IF_NOMIPMAP; slash = COM_SkipPath(mod->name); if (slash != mod->name && slash-mod->name < sizeof(alttexpath)) diff --git a/engine/common/cvar.c b/engine/common/cvar.c index a0ed9ecc8..86fcab579 100644 --- a/engine/common/cvar.c +++ b/engine/common/cvar.c @@ -24,8 +24,94 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. cvar_group_t *cvar_groups; -hashtable_t cvar_hash; -bucket_t *cvar_buckets[1024]; +//static bucket_t *cvar_buckets[1024]; +//static hashtable_t cvar_hash; + +typedef struct { + size_t maxentries; + size_t numentries; + struct + { + const char *string; + void *data; + } entry[1]; +} abucket_t; +typedef struct { + abucket_t **bucket; + unsigned int numbuckets; +} ahashtable_t; //not thread-safe + +static abucket_t *cvar_buckets[1024]; +static ahashtable_t cvar_hash = {cvar_buckets, countof(cvar_buckets)}; + +unsigned int Hash_KeyInsensitive(const char *name, unsigned int modulus); +void *AHash_GetInsensitive(ahashtable_t *table, const char *name) +{ + abucket_t *b = table->bucket[Hash_KeyInsensitive(name, table->numbuckets)]; + size_t i; + if (b) + for (i = 0; i < b->numentries; i++) + { + if (!strcasecmp(b->entry[i].string, name)) + return b->entry[i].data; + } + return NULL; +} + +void AHash_RemoveDataInsensitive(ahashtable_t *table, const char *name, void *data) +{ + abucket_t *b = table->bucket[Hash_KeyInsensitive(name, table->numbuckets)]; + size_t i; + for (i = 0; i < b->numentries; i++) + { + if (b->entry[i].data == data && !strcasecmp(b->entry[i].string, name)) + { + //strip it. + b->numentries--; + //shift everything down. + if (b->numentries > i) + memmove(&b->entry[i], &b->entry[i+1], b->numentries-1); + break; + } + } +} +void AHash_AddInsensitive(ahashtable_t *table, const char *name, void *data) +{ + unsigned int idx = Hash_KeyInsensitive(name, table->numbuckets); + abucket_t *b = table->bucket[idx]; + if (!b) + { //nothing there!... + b = table->bucket[idx] = BZ_Malloc(sizeof(*b)); + b->numentries = 0; + b->maxentries = countof(b->entry); + } + else if (b->numentries == b->maxentries) + { //can't add anything new + size_t n = b->maxentries*2; + table->bucket[idx] = BZ_Malloc(sizeof(*b)-sizeof(b->entry) + sizeof(b->entry)*n); + memcpy(table->bucket[idx]->entry, b->entry, sizeof(b->entry[0])*b->numentries); + table->bucket[idx]->numentries = b->numentries; + table->bucket[idx]->maxentries = n; + BZ_Free(b); + b = table->bucket[idx]; + } + b->entry[b->numentries].data = data; + b->entry[b->numentries].string = name; + b->numentries++; +} +void AHash_Cleanup(ahashtable_t *table) +{ + size_t i; + for (i = 0; i < table->numbuckets; i++) + { + if (table->bucket[i] && !table->bucket[i]->numentries) + { + BZ_Free(table->bucket[i]); + table->bucket[i] = NULL; + } + } +} + int cvar_watched; //cvar_t *cvar_vars; @@ -69,7 +155,7 @@ Cvar_FindVar */ cvar_t *Cvar_FindVar (const char *var_name) { - return Hash_GetInsensitive(&cvar_hash, var_name); + return AHash_GetInsensitive(&cvar_hash, var_name); /* cvar_group_t *grp; cvar_t *var; @@ -1126,9 +1212,9 @@ unlinked: Cvar_DefaultFree(tbf->defaultstr); if (tbf->latched_string) Z_Free(tbf->latched_string); - Hash_RemoveData(&cvar_hash, tbf->name, tbf); + AHash_RemoveDataInsensitive(&cvar_hash, tbf->name, tbf); if (tbf->name2) - Hash_RemoveData(&cvar_hash, tbf->name2, tbf); + AHash_RemoveDataInsensitive(&cvar_hash, tbf->name2, tbf); Z_Free(tbf); } @@ -1190,9 +1276,9 @@ qboolean Cvar_Register (cvar_t *variable, const char *groupname) Cvar_Free(old); - Hash_AddInsensitive(&cvar_hash, variable->name, variable, &variable->hbn1); + AHash_AddInsensitive(&cvar_hash, variable->name, variable); if (variable->name2) - Hash_AddInsensitive(&cvar_hash, variable->name2, variable, &variable->hbn2); + AHash_AddInsensitive(&cvar_hash, variable->name2, variable); return true; } @@ -1220,9 +1306,9 @@ qboolean Cvar_Register (cvar_t *variable, const char *groupname) variable->restriction = 0; //exe registered vars group->cvars = variable; - Hash_AddInsensitive(&cvar_hash, variable->name, variable, &variable->hbn1); + AHash_AddInsensitive(&cvar_hash, variable->name, variable); if (variable->name2) - Hash_AddInsensitive(&cvar_hash, variable->name2, variable, &variable->hbn2); + AHash_AddInsensitive(&cvar_hash, variable->name2, variable); variable->string = NULL; @@ -1588,7 +1674,7 @@ void QDECL Cvar_Limiter_ZeroToOne_Callback(struct cvar_s *var, char *oldvalue) void Cvar_Init(void) { memset(cvar_buckets, 0, sizeof(cvar_buckets)); - Hash_InitTable(&cvar_hash, sizeof(cvar_buckets)/Hash_BytesForBuckets(1), cvar_buckets); + //Hash_InitTable(&cvar_hash, sizeof(cvar_buckets)/Hash_BytesForBuckets(1), cvar_buckets); } void Cvar_Shutdown(void) @@ -1622,4 +1708,5 @@ void Cvar_Shutdown(void) cvar_groups = grp->next; Z_Free(grp); } + AHash_Cleanup(&cvar_hash); } diff --git a/engine/common/cvar.h b/engine/common/cvar.h index 166fe6294..2cebfc617 100644 --- a/engine/common/cvar.h +++ b/engine/common/cvar.h @@ -82,7 +82,6 @@ typedef struct cvar_s #ifdef HLSERVER struct hlcvar_s *hlcvar; #endif - bucket_t hbn1, hbn2; } cvar_t; #ifdef MINIMAL diff --git a/engine/common/fs_zip.c b/engine/common/fs_zip.c index 62e8aa76f..3c02e6b65 100644 --- a/engine/common/fs_zip.c +++ b/engine/common/fs_zip.c @@ -1584,7 +1584,7 @@ static qboolean FSZIP_ReadCentralEntry(zipfile_t *zip, qbyte *data, struct zipce entry->gflags = LittleU2FromPtr(data+8); entry->cmethod = LittleU2FromPtr(data+10); entry->lastmodfiletime = LittleU2FromPtr(data+12); - entry->lastmodfiledate = LittleU2FromPtr(data+12); + entry->lastmodfiledate = LittleU2FromPtr(data+14); entry->crc32 = LittleU4FromPtr(data+16); entry->csize = LittleU4FromPtr(data+20); entry->usize = LittleU4FromPtr(data+24); diff --git a/engine/common/q1bsp.c b/engine/common/q1bsp.c index 4c3a60f2a..cbe6e9c3d 100644 --- a/engine/common/q1bsp.c +++ b/engine/common/q1bsp.c @@ -94,7 +94,7 @@ size_t Fragment_ClipPlaneToBrush(vecV_t *points, size_t maxpoints, void *planes, vec3_t right, forward; double t; float *plane; - + // if (face[2] != 1) // return 0; @@ -142,7 +142,7 @@ size_t Fragment_ClipPlaneToBrush(vecV_t *points, size_t maxpoints, void *planes, numverts = Fragment_ClipPolyToPlane((float*)verts, (float*)verts2, numverts, norm, -plane[3]); else numverts = Fragment_ClipPolyToPlane((float*)verts2, (float*)verts, numverts, norm, -plane[3]); - + if (numverts < 3) //totally clipped. return 0; } @@ -621,7 +621,8 @@ void Mod_ClipDecal(struct model_s *mod, vec3_t center, vec3_t normal, vec3_t tan if (!mod || mod->loadstate != MLS_LOADED) return; - + else if (mod->type != mod_brush) + ; #ifdef Q1BSPS else if (mod->fromgame == fg_quake || mod->fromgame == fg_halflife) Q1BSP_ClipDecalToNodes(mod, &dec, mod->rootnode); @@ -1498,7 +1499,7 @@ void Q1BSP_LoadBrushes(model_t *model, bspx_header_t *bspx, void *mod_base) brush->planes[brush->numplanes].dist = -perbrush->mins[pl]; brush->numplanes++; } - + /*link it in to the bsp tree*/ Q1BSP_InsertBrush(rootnode, brush, perbrush->mins, perbrush->maxs); @@ -1807,7 +1808,7 @@ static qbyte *Q1BSP_ClusterPVS (model_t *model, int cluster, pvsbuffer_t *buffer static void SV_Q1BSP_AddToFatPVS (model_t *mod, const vec3_t org, mnode_t *node, pvsbuffer_t *pvsbuffer) { mplane_t *plane; - float d; + float d; while (1) { @@ -2760,7 +2761,7 @@ void Mod_FindCubemaps_f(void) size_t nenvmap = 0; unsigned int *envmapidx = NULL; //*numsurfaces size_t nenvmapidx = 0, i; - + //find targetnames, and store their origins so that we can deal with spotlights. for (lmp = entlump; ;) { @@ -2808,7 +2809,7 @@ void Mod_FindCubemaps_f(void) else if (!strcmp("size", key)) sscanf(value, "%f", &size); } - + if (isenvmap) { int e = nenvmap; diff --git a/engine/gl/gl_font.c b/engine/gl/gl_font.c index 860633bed..6859f9baa 100644 --- a/engine/gl/gl_font.c +++ b/engine/gl/gl_font.c @@ -218,6 +218,16 @@ static const char *imgs[] = //they're provided as fallbacks. #define MAX_FACES 32 +enum fontfmt_e +{ + FMT_AUTO, //freetype, or quake + FMT_QUAKE, //first is default + FMT_ISO88591, //latin-1 (first 256 chars of unicode too, c1 glyphs are usually invisible) + FMT_WINDOWS1252,//variation of latin-1 with extra glyphs + FMT_KOI8U, //image is 16*16 koi8-u codepage. + FMT_HORIZONTAL, //unicode, charcount=width/(height-2). single strip of chars, like halflife. +}; + typedef struct fontface_s { struct fontface_s *fnext; @@ -228,8 +238,11 @@ typedef struct fontface_s struct { qbyte *data; - size_t width; - size_t height; + size_t rows; //urgh. + size_t stride; + size_t charheight; + enum fontfmt_e codepage; + qboolean paletted; } horiz; #ifdef HALFLIFEMODELS @@ -997,6 +1010,164 @@ static struct charcache_s *Font_LoadPlaceholderGlyph(font_t *f, CHARIDXTYPE char return c; } +static struct charcache_s *Font_TryLoadGlyphRaster(font_t *f, fontface_t *qface, CHARIDXTYPE charidx) +{ + size_t maxchar = 256; + const unsigned short *c1tab; + size_t c1tabsize; + size_t glyph = charidx; + + safeswitch(qface->horiz.codepage) + { + safedefault: + case FMT_AUTO: //shouldn't happen. + case FMT_ISO88591: //all identity. + case FMT_HORIZONTAL: //erk... + c1tab = NULL; + c1tabsize = 0; + break; + case FMT_WINDOWS1252: + { + static const unsigned short win1252[] = { + 0x20ac, 0x81,0x201a,0x0192, 0x201e,0x2026,0x2020,0x2021, 0x02c6,0x2030,0x0160,0x2039, 0x0152, 0x8d,0x017d, 0x8f, + 0x90,0x2018,0x2019,0x101c, 0x201d,0x2022,0x2013,0x2014, 0x02dc,0x2122,0x0161,0x203a, 0x0153, 0x9d,0x017e,0x0178}; + c1tab = win1252; + c1tabsize = sizeof(win1252); + } + break; + case FMT_KOI8U: + { + static const unsigned short koi8u[] = { + 0x2500,0x2502,0x250C,0x2510, 0x2514,0x2518,0x251C,0x2524, 0x252C,0x2534,0x253C,0x2580, 0x2584,0x2588,0x258C,0x2590, + 0x2591,0x2592,0x2593,0x2320, 0x25A0,0x2219,0x221A,0x2248, 0x2264,0x2265,0x00A0,0x2321, 0x00B0,0x00B2,0x00B7,0x00F7, + 0x2550,0x2551,0x2552,0x0451, 0x0454,0x2554,0x0456,0x0457, 0x2557,0x2558,0x2559,0x255A, 0x255B,0x0491,0x255D,0x255E, + 0x255F,0x2560,0x2561,0x0401, 0x0404,0x2563,0x0406,0x0407, 0x2566,0x2567,0x2568,0x2569, 0x256A,0x0490,0x256C,0x00A9, + 0x044E,0x0430,0x0431,0x0446, 0x0434,0x0435,0x0444,0x0433, 0x0445,0x0438,0x0439,0x043A, 0x043B,0x043C,0x043D,0x043E, + 0x043F,0x044F,0x0440,0x0441, 0x0442,0x0443,0x0436,0x0432, 0x044C,0x044B,0x0437,0x0448, 0x044D,0x0449,0x0447,0x044A, + 0x042E,0x0410,0x0411,0x0426, 0x0414,0x0415,0x0424,0x0413, 0x0425,0x0418,0x0419,0x041A, 0x041B,0x041C,0x041D,0x041E, + 0x041F,0x042F,0x0420,0x0421, 0x0422,0x0423,0x0416,0x0412, 0x042C,0x042B,0x0417,0x0428, 0x042D,0x0429,0x0427,0x042A}; + c1tab = koi8u; + c1tabsize = sizeof(koi8u); + } + break; + case FMT_QUAKE: + { + c1tab = NULL; + c1tabsize = 0; + if (glyph >= 0xe000 && glyph < 0xe100) + glyph -= 0xe000; + else if (glyph < 32 || glyph >= 0x80) + return NULL; + } + break; + } + if (glyph >= maxchar) + return NULL; + if (glyph >= 0x80 && glyph < 0x80+c1tabsize) + { + int i; + for (i = 0; ; i++) + { + if (i == c1tabsize) + return NULL; + if (glyph == c1tab[i]) + { + glyph = 0x80+i; + break; + } + } + } + + { + int gw = (qface->horiz.stride)/(maxchar/qface->horiz.rows); + int gr = glyph / (maxchar/qface->horiz.rows); + int gc = glyph - (gr*(maxchar/qface->horiz.rows)); + int gs = qface->horiz.stride; + int gh = qface->horiz.charheight; + struct charcache_s *c; + if (qface->horiz.paletted) + { + qbyte *in = (qbyte*)qface->horiz.data + gc*gw + gr*gs*gh; + /*while (gw >= 1) + { + int y; + gw--; //see if we can strip this column + for (y = 0; y < gh; y++) + if (in[gw+y*gs]) + break; + if (y < gh) + { + gw++; + break; + } + }*/ + { + int ngw = (gw * f->charheight) / gh; + int ngh = f->charheight; + int x, y; + unsigned int *out2 = alloca(ngw*ngh*4); + if (ngw&&ngh) + { + unsigned int *out1 = alloca(gw*gh*4); + for (y = 0; y < gh; y++) + for (x = 0; x < gw; x++) + out1[x+y*gw] = in[x+y*gs]?d_8to24rgbtable[in[x+y*gs]]:0; + Image_ResampleTexture(PTI_RGBA8, out1, gw, gh, out2, ngw, ngh); + } + c = Font_LoadGlyphData(f, charidx, FT_PIXEL_MODE_RGBA, out2, ngw, ngh, ngw*4); + gw = ngw; + } + } + else + { + unsigned int *in = (unsigned int*)qface->horiz.data + gc*gw + gr*gs*gh; + while (gw >= 1) + { + int y; + gw--; //see if we can strip this column + for (y = 0; y < gh; y++) + if (in[gw+y*gs] & 0x00ffffff) + break; + if (y < gh) + { + gw++; + break; + } + } + if (f->charheight != gh) + { + int ngw = (gw * f->charheight) / gh; + int ngh = f->charheight; + int x, y; + unsigned int *out2 = alloca(ngw*ngh*4); + if (ngw&&ngh) + { //we need to repack the input, because Image_ResampleTexture can't handle strides + unsigned int *out1 = alloca(gw*gh*4); + for (y = 0; y < gh; y++) + for (x = 0; x < gw; x++) + out1[x+y*gw] = in[x+y*gs]; + Image_ResampleTexture(PTI_RGBA8, out1, gw, gh, out2, ngw, ngh); + } + c = Font_LoadGlyphData(f, charidx, FT_PIXEL_MODE_RGBA, out2, ngw, ngh, ngw*4); + gw = ngw; + } + else + c = Font_LoadGlyphData(f, charidx, FT_PIXEL_MODE_RGBA, in, gw, gh, gs*4); + } + if (!gw) //for invisble glyphs (eg: space), we attempt to ensure that there's some substance there. missing spaces is weird. + gw = gh/3; + if (c) + { + c->advance = gw; + c->left = 0; + c->top = 0; + c->flags &= ~CHARF_FORCEWHITE; + return c; + } + } + return NULL; +} + //loads the given charidx for the given font, importing from elsewhere if needed. static struct charcache_s *Font_TryLoadGlyph(font_t *f, CHARIDXTYPE charidx) { @@ -1265,62 +1436,9 @@ static struct charcache_s *Font_TryLoadGlyph(font_t *f, CHARIDXTYPE charidx) #endif if (qface->horiz.data) { -#if 1 - size_t maxchar = 256; - int gw = qface->horiz.width/maxchar; -#else - int gw = qface->horiz.height-(qface->horiz.height/12); - size_t maxchar = qface->horiz.width / gw; -#endif - size_t glyph = charidx /* - qface->horiz.firstcodepoint*/; - if (glyph < maxchar) - { - unsigned int *glyphdata = (unsigned int*)qface->horiz.data + glyph*gw; - int gh = qface->horiz.height; - int gs = qface->horiz.width; - unsigned int *out = glyphdata; - while (gw >= 1) - { - int y; - gw--; //see if we can strip this column - for (y = 0; y < gh; y++) - if (glyphdata[gw+y*gs] & 0x00ffffff) - break; - if (y < gh) - { - gw++; - break; - } - } - if (f->charheight != gh) - { - int ngw = (gw * f->charheight) / gh; - int ngh = f->charheight; - int x, y; - unsigned int *out2 = alloca(ngw*ngh*4); - if (ngw&&ngh) - { //we need to repack the input, because Image_ResampleTexture can't handle strides - unsigned int *out1 = alloca(gw*gh*4); - for (y = 0; y < gh; y++) - for (x = 0; x < gw; x++) - out1[x+y*gw] = out[x+y*gs]; - Image_ResampleTexture(PTI_RGBA8, out1, gw, gh, out2, ngw, ngh); - } - c = Font_LoadGlyphData(f, charidx, FT_PIXEL_MODE_RGBA, out2, ngw, ngh, ngw*4); - gw = ngw; - } - else - c = Font_LoadGlyphData(f, charidx, FT_PIXEL_MODE_RGBA, out, gw, gh, gs*4); - if (!gw) //for invisble glyphs (eg: space), we attempt to ensure that there's some substance there. missing spaces is weird. - gw = gh/3; - if (c) - { - c->advance = gw; - c->left = 0; - c->top = 0; - return c; - } - } + c = Font_TryLoadGlyphRaster(f, qface, charidx); + if (c) + return c; } } } @@ -1447,8 +1565,11 @@ qboolean Font_LoadHorizontalFont(struct font_s *f, int fheight, const char *font if (qface->fnext) qface->fnext->flink = &qface->fnext; qface->horiz.data = rgbadata; - qface->horiz.width = width; - qface->horiz.height = height; + qface->horiz.stride = width; + qface->horiz.charheight = height; + qface->horiz.rows = 1; + qface->horiz.paletted = false; + qface->horiz.codepage = FMT_ISO88591; qface->refs++; Q_strncpyz(qface->name, fontfilename, sizeof(qface->name)); @@ -1707,28 +1828,6 @@ static texid_t Font_LoadReplacementConchars(void) return tex; return r_nulltex; } -static texid_t Font_LoadQuakeConchars(void) -{ - /*unsigned int i; - qbyte *lump; - lump = W_SafeGetLumpName ("conchars"); - if (lump) - { - // add ocrana leds - if (con_ocranaleds.ival) - { - if (con_ocranaleds.ival != 2 || QCRC_Block(lump, 128*128) == 798) - AddOcranaLEDsIndexed (lump, 128, 128); - } - - for (i=0 ; i<128*128 ; i++) - if (lump[i] == 0) - lump[i] = 255; // proper transparent color - - return R_LoadTexture8("charset", 128, 128, (void*)lump, IF_LOADNOW|IF_UIPIC|IF_NOMIPMAP|IF_NOGAMMA, 1); - }*/ - return r_nulltex; -} #ifdef HEXEN2 static texid_t Font_LoadHexen2Conchars(qboolean iso88591) @@ -1875,16 +1974,6 @@ static texid_t Font_LoadFallbackConchars(void) return tex; } -enum fontfmt_e -{ - FMT_AUTO, //freetype, or quake - FMT_QUAKE, //first is default - FMT_ISO88591, //latin-1 (first 256 chars of unicode too, c1 glyphs are usually invisible) - FMT_WINDOWS1252,//variation of latin-1 with extra glyphs - FMT_KOI8U, //image is 16*16 koi8-u codepage. - FMT_HORIZONTAL, //unicode, charcount=width/(height-2). single strip of chars, like halflife. -}; - /*loads a fallback image. not allowed to fail (use syserror if needed)*/ static texid_t Font_LoadDefaultConchars(enum fontfmt_e *fmt) { @@ -1892,11 +1981,6 @@ static texid_t Font_LoadDefaultConchars(enum fontfmt_e *fmt) tex = Font_LoadReplacementConchars(); if (TEXLOADED(tex)) return tex; - tex = Font_LoadQuakeConchars(); - if (tex && tex->status == TEX_LOADING) - COM_WorkerPartialSync(tex, &tex->status, TEX_LOADING); - if (TEXLOADED(tex)) - return tex; #ifdef HEXEN2 tex = Font_LoadHexen2Conchars(true); if (tex && tex->status == TEX_LOADING) @@ -1959,6 +2043,54 @@ void Doom_ExpandPatch(doompatch_t *p, unsigned char *b, int stride) } } +static qboolean Font_LoadFontLump(font_t *f, const char *facename) +{ + size_t lumpsize = 0; + qbyte lumptype = 0; + void *lumpdata; + + if (f->faces == MAX_FACES) + return false; //can't store it... + lumpdata = W_GetLumpName(facename, &lumpsize, &lumptype); + if (!lumpdata) + return false; + if ((lumptype == TYP_MIPTEX && lumpsize==(8*8)*(16*16)) || //proper format + (lumptype == TYP_QPIC && lumpsize==(8*8)*(16*16)+8)) //fucked up buggy format used by some people + { + fontface_t *fa = Z_Malloc(sizeof(*fa)); + fa->horiz.data = lumpdata; + fa->horiz.stride = 8*16; + fa->horiz.charheight = 8; + fa->horiz.codepage = FMT_QUAKE; + fa->horiz.paletted = true; + fa->horiz.rows = 16; + + if (con_ocranaleds.ival) + { + if (con_ocranaleds.ival != 2 || QCRC_Block(lumpdata, 128*128) == 798) + AddOcranaLEDsIndexed (lumpdata, 128, 128); + } + + fa->flink = &fa->fnext; + fa->refs = 1; + f->face[f->faces++] = fa; + return true; + } +#ifdef HALFLIFEMODELS + else if (lumptype == TYP_HLFONT) + { + fontface_t *fa = Z_Malloc(sizeof(*fa)); + fa->halflife = lumpdata; + fa->flink = &fa->fnext; + fa->refs = 1; + f->face[f->faces++] = fa; +// f->charheight = fa->halflife->fontheight1; //force the font to a specific size. + return true; + } +#endif + return false; //doesn't match a valid known format +} + //creates a new font object from the given file, with each text row with the given height. //width is implicit and scales with height and choice of font. struct font_s *Font_LoadFont(const char *fontfilename, float vheight, float scale, int outline) @@ -2226,9 +2358,18 @@ struct font_s *Font_LoadFont(const char *fontfilename, float vheight, float scal if (fmt == FMT_HORIZONTAL) Font_LoadHorizontalFont(f, height, start); #ifdef AVAIL_FREETYPE - else if (fmt == FMT_AUTO) - Font_LoadFreeTypeFont(f, height, start); + else if (fmt == FMT_AUTO && Font_LoadFreeTypeFont(f, height, start)) + ; #endif + else if (!TEXLOADED(f->singletexture) && *start) + { + f->singletexture = R_LoadHiResTexture(start, "fonts:charsets", IF_PREMULTIPLYALPHA|(r_font_linear.ival?IF_LINEAR:IF_NEAREST)|IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP|IF_NOPURGE|IF_LOADNOW); + if (f->singletexture->status == TEX_LOADING) + COM_WorkerPartialSync(f->singletexture, &f->singletexture->status, TEX_LOADING); + + if (!TEXLOADED(f->singletexture) && f->faces < MAX_FACES) + Font_LoadFontLump(f, start); + } if (end) { @@ -2240,42 +2381,8 @@ struct font_s *Font_LoadFont(const char *fontfilename, float vheight, float scal } } -#ifdef HALFLIFEMODELS - if (!f->faces) - { - if (f->faces < MAX_FACES) - { - size_t lumpsize; - qbyte lumptype = 0; - void *lumpdata = NULL; - if ((!lumpdata || lumptype != TYP_HLFONT) && *fontfilename) - lumpdata = W_GetLumpName(fontfilename, &lumpsize, &lumptype); - if (!lumpdata || lumptype != TYP_HLFONT) - lumpdata = W_GetLumpName("conchars", &lumpsize, &lumptype); - if (lumpdata && lumptype == TYP_HLFONT) - { - fontface_t *fa = Z_Malloc(sizeof(*fa)); - fa->halflife = lumpdata; - fa->flink = &fa->fnext; - fa->refs = 1; - f->face[f->faces++] = fa; -// f->charheight = fa->halflife->fontheight1; //force the font to a specific size. - return f; - } - } - } -#endif - - if (!f->faces) - { - //default to only map the ascii-compatible chars from the quake font. - if (*fontfilename) - { - f->singletexture = R_LoadHiResTexture(fontfilename, "fonts:charsets", IF_PREMULTIPLYALPHA|(r_font_linear.ival?IF_LINEAR:IF_NEAREST)|IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP|IF_NOPURGE); - if (f->singletexture->status == TEX_LOADING) - COM_WorkerPartialSync(f->singletexture, &f->singletexture->status, TEX_LOADING); - } - } + if (!f->faces && !TEXLOADED(f->singletexture) && r_font_linear.ival) + Font_LoadFontLump(f, "conchars"); defaultplane = INVALIDPLANE;/*assume the bitmap plane - don't use the fallback as people don't think to use com_parseutf8*/ if (TEXLOADED(f->singletexture)) diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index e9095386f..0f46b53e7 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -327,6 +327,8 @@ static qboolean Shader_EvaluateCondition(shader_t *shader, const char **ptr) lhs = r_deluxemapping; else if (!Q_stricmp(token, "softwarebanding")) lhs = r_softwarebanding; + else if (!Q_stricmp(token, "unmaskedsky")) + lhs = cls.allow_unmaskedskyboxes; //can/should skip writing depth values for sky surfaces. //normalmaps are generated if they're not already known. else if (!Q_stricmp(token, "normalmap")) @@ -1372,7 +1374,7 @@ struct programpermu_s *Shader_LoadPermutation(program_t *prog, unsigned int p) size_t offset; qboolean fail = false; - extern cvar_t gl_specular, gl_specular_power; + extern cvar_t r_glsl_pbr, gl_specular, gl_specular_power; if (~prog->supportedpermutations & p) return NULL; //o.O @@ -1384,6 +1386,8 @@ struct programpermu_s *Shader_LoadPermutation(program_t *prog, unsigned int p) Q_strlcatfz(defines, &offset, sizeof(defines), "#define MAX_GPU_BONES %i\n", sh_config.max_gpu_bones); if (gl_specular.value) Q_strlcatfz(defines, &offset, sizeof(defines), "#define SPECULAR\n#define SPECULAR_BASE_MUL %f\n#define SPECULAR_BASE_POW %f\n", 1.0*gl_specular.value, max(1,gl_specular_power.value)); + if (r_glsl_pbr.ival) + Q_strlcatfz(defines, &offset, sizeof(defines), "#define PBR\n"); #ifdef RTLIGHTS if (r_fakeshadows) Q_strlcatfz(defines, &offset, sizeof(defines), "#define FAKESHADOWS\n%s", @@ -1932,7 +1936,7 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip break; while (*script && *script != '\n') script++; - }; + } prog->shadertext = Z_StrDup(script); if (qrenderer == qrtype && ver < 150) @@ -6584,6 +6588,9 @@ char *Shader_DefaultBSPWater(parsestate_t *ps, const char *shortname, char *buff "{\n" "surfaceparm nodlight\n" "surfaceparm nomarks\n" + "if %g < 1\n" + "sort underwater\n" + "endif\n" "{\n" "program defaultwarp%s\n" "map $diffuse\n" @@ -6595,7 +6602,7 @@ char *Shader_DefaultBSPWater(parsestate_t *ps, const char *shortname, char *buff "}\n" "surfaceparm hasdiffuse\n" "}\n" - , (explicitalpha||alpha==1)?"":va("#ALPHA=%g",alpha), alpha, alpha); + , alpha, (explicitalpha||alpha==1)?"":va("#ALPHA=%g",alpha), alpha, alpha); return buffer; case 2: //refraction of the underwater surface, with a fresnel return ( diff --git a/engine/gl/gl_warp.c b/engine/gl/gl_warp.c index bf8e7fcda..09ecb1857 100644 --- a/engine/gl/gl_warp.c +++ b/engine/gl/gl_warp.c @@ -94,12 +94,20 @@ void R_SetSky(const char *sky) COM_WorkerPartialSync(tex.reflectcube, &tex.reflectcube->status, TEX_LOADING); if (tex.reflectcube->width && TEXLOADED(tex.reflectcube)) { - /* FIXME: Q2/HL require the skybox to not draw over geometry, shouldn't we force it? --eukara */ - if (cls.allow_skyboxes) { - forcedsky = R_RegisterShader(va("skybox_%s", sky), 0, "{\nsort sky\nprogram defaultskybox\n{\nmap \"$cube:$reflectcube\"\ntcgen skybox\n}\nsurfaceparm nodlight\nsurfaceparm sky\n}"); - } else { - forcedsky = R_RegisterShader(va("skybox_%s", sky), 0, "{\nsort sky\nprogram defaultskybox\n{\ndepthwrite\nmap \"$cube:$reflectcube\"\ntcgen skybox\n}\nsurfaceparm nodlight\nsurfaceparm sky\n}"); - } + forcedsky = R_RegisterShader(va("skybox_%s", sky), 0, + "{\n" + "sort sky\n" + "program defaultskybox\n" + "{\n" + "if !$unmaskedsky\n" /* Q2/HL require the skybox to not draw over geometry, shouldn't we force it? --eukara */ + "depthwrite\n" + "endif\n" + "map \"$cube:$reflectcube\"\n" + "tcgen skybox\n" + "}\n" + "surfaceparm nodlight\n" + "surfaceparm sky\n" + "}"); R_BuildDefaultTexnums(&tex, forcedsky, IF_WORLDTEX); return; } @@ -222,7 +230,7 @@ qboolean R_DrawSkyroom(shader_t *skyshader) //q3 mustn't mask sky (breaks q3map2's invisible skyportals), whereas q1 must (or its a cheat). halflife doesn't normally expect masking. //we also MUST mask any sky inside skyrooms, or you'll see all the entities outside of the skyroom through the room's own sky (q3map2 skyportals are hopefully irrelevant in this case). -#define SKYMUSTBEMASKED (r_worldentity.model->fromgame != fg_quake3 || ((r_refdef.flags & RDF_DISABLEPARTICLES) && r_ignoreentpvs.ival)) +#define SKYMUSTBEMASKED (r_worldentity.model->fromgame != fg_quake3 || ((r_refdef.flags & RDF_DISABLEPARTICLES) && r_ignoreentpvs.ival) || !cls.allow_unmaskedskyboxes) /* ================= @@ -691,7 +699,7 @@ static void gl_skyspherecalc(int skytype) static void GL_SkyForceDepth(batch_t *batch) { - if (!cls.allow_skyboxes && batch->texture) //allow a little extra fps. + if (!cls.allow_unmaskedskyboxes && batch->texture) //allow a little extra fps. { BE_SelectMode(BEM_DEPTHONLY); BE_DrawMesh_List(batch->shader, batch->meshes-batch->firstmesh, batch->mesh+batch->firstmesh, batch->vbo, NULL, batch->flags); diff --git a/engine/gl/r_bishaders.h b/engine/gl/r_bishaders.h index 3aa926815..ac6912023 100644 --- a/engine/gl/r_bishaders.h +++ b/engine/gl/r_bishaders.h @@ -3004,7 +3004,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "affine varying vec2 tc;\n" "varying vec4 light;\n" -"#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)\n" +"#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) || defined(PBR)\n" "varying vec3 eyevector;\n" "#endif\n" "#if defined(PBR)||defined(REFLECTCUBEMASK)\n" @@ -3039,9 +3039,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "#endif\n" "#endif\n" -"#if defined(PBR)\n" -"eyevector = e_eyepos - w.xyz;\n" -"#elif defined(SPECULAR)||defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)\n" +"#if defined(SPECULAR)||defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) || defined(PBR)\n" "vec3 eyeminusvertex = e_eyepos - w.xyz;\n" "eyevector.x = dot(eyeminusvertex, s.xyz);\n" "eyevector.y = dot(eyeminusvertex, t.xyz);\n" @@ -3086,7 +3084,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "affine out vec2 t_tc[];\n" "in vec4 light[];\n" "out vec4 t_light[];\n" -"#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)\n" +"#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) || defined(PBR)\n" "in vec3 eyevector[];\n" "out vec3 t_eyevector[];\n" "#endif\n" @@ -3102,7 +3100,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "t_normal[id] = normal[id];\n" "t_tc[id] = tc[id];\n" "t_light[id] = light[id];\n" -"#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)\n" +"#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) || defined(PBR)\n" "t_eyevector[id] = eyevector[id];\n" "#endif\n" "#ifdef REFLECTCUBEMASK\n" @@ -3135,7 +3133,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "affine out vec2 tc;\n" "in vec4 t_light[];\n" "out vec4 light;\n" -"#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)\n" +"#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) || defined(PBR)\n" "in vec3 t_eyevector[];\n" "out vec3 eyevector;\n" "#endif\n" @@ -3158,7 +3156,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND //FIXME: we should be recalcing these here, instead of just lerping them "light = LERP(t_light);\n" -"#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)\n" +"#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) || defined(PBR)\n" "eyevector = LERP(t_eyevector);\n" "#endif\n" "#ifdef REFLECTCUBEMASK\n" @@ -3198,7 +3196,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "affine varying vec2 tc;\n" "varying vec4 light;\n" -"#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)\n" +"#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) || defined(PBR)\n" "varying vec3 eyevector;\n" "#endif\n" "#if defined(PBR) || defined(REFLECTCUBEMASK)\n" @@ -3292,7 +3290,8 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "#endif\n" "#else\n" "#define roughness 0.3\n" -"#define specrgb 1.0 //vec3(dielectricSpecular)\n" +"#define specrgb vec3(1.0) //vec3(dielectricSpecular)\n" +"#define ambientrgb col.rgb\n" "#endif\n" "#ifdef BUMP\n" @@ -5668,7 +5667,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "#include \"sys/fog.h\"\n" "#if !defined(TESS_CONTROL_SHADER)\n" -"#if defined(OFFSETMAPPING) || defined(SPECULAR) || defined(REFLECTCUBEMASK)\n" +"#if defined(OFFSETMAPPING) || defined(SPECULAR) || defined(REFLECTCUBEMASK) || defined(PBR)\n" "varying vec3 eyevector;\n" "#endif\n" @@ -5700,7 +5699,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "#endif\n" "void main ()\n" "{\n" -"#if defined(OFFSETMAPPING) || defined(SPECULAR) || defined(REFLECTCUBEMASK)\n" +"#if defined(OFFSETMAPPING) || defined(SPECULAR) || defined(REFLECTCUBEMASK) || defined(PBR)\n" "vec3 eyeminusvertex = e_eyepos - v_position.xyz;\n" "eyevector.x = dot(eyeminusvertex, v_svector.xyz);\n" "eyevector.y = dot(eyeminusvertex, v_tvector.xyz);\n" @@ -5751,7 +5750,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "out vec3 t_vertex[];\n" "in vec3 normal[];\n" "out vec3 t_normal[];\n" -"#if defined(OFFSETMAPPING) || defined(SPECULAR) || defined(REFLECTCUBEMASK)\n" +"#if defined(OFFSETMAPPING) || defined(SPECULAR) || defined(REFLECTCUBEMASK) || defined(PBR)\n" "in vec3 eyevector[];\n" "out vec3 t_eyevector[];\n" "#endif\n" @@ -5793,7 +5792,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "#endif\n" "#endif\n" -"#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)\n" +"#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) || defined(PBR)\n" "t_eyevector[id] = eyevector[id];\n" "#endif\n" @@ -5817,7 +5816,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "in vec3 t_vertex[];\n" "in vec3 t_normal[];\n" -"#if defined(OFFSETMAPPING) || defined(SPECULAR) || defined(REFLECTCUBEMASK)\n" +"#if defined(OFFSETMAPPING) || defined(SPECULAR) || defined(REFLECTCUBEMASK) || defined(PBR)\n" "in vec3 t_eyevector[];\n" "#endif\n" "#ifdef REFLECTCUBEMASK\n" @@ -5867,7 +5866,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "#ifdef REFLECTCUBEMASK\n" "invsurface = LERP(t_invsurface);\n" "#endif\n" -"#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)\n" +"#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) || defined(PBR)\n" "eyevector = LERP(t_eyevector);\n" "#endif\n" @@ -5973,27 +5972,47 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "#define gloss (1.0-roughness)\n" "#define ambientrgb (specrgb+col.rgb)\n" "vec3 specrgb = mix(vec3(dielectricSpecular), col.rgb, metalness);\n" -"col.rgb = col.rgb * (1.0 - dielectricSpecular) * (1.0-metalness);\n" +"vec3 albedorgb = col.rgb * (1.0 - dielectricSpecular) * (1.0-metalness);\n" "#elif defined(SG) //pbr-style specular+glossiness\n" //occlusion needs to be baked in. :( "#define roughness (1.0-specs.a)\n" "#define gloss specs.a\n" "#define specrgb specs.rgb\n" "#define ambientrgb (specs.rgb+col.rgb)\n" -"#else //blinn-phong\n" -"#define roughness (1.0-specs.a)\n" +"#define albedorgb col.rgb\n" +"#elif defined(PBR) //PBR using legacy texturemaps\n" "#define gloss specs.a\n" -"#define specrgb specs.rgb\n" +"#define roughness (1.0-gloss)\n" +//metalness not relevant + +//our pbr stuff doesn't much like our inputs. +"vec3 specrgb, albedorgb;\n" +//if (1==0) +//{ //metal +// specrgb = col.rgb;//+specs.rgb; +// albedorgb = vec3(0.0); +//} +//else +//{ //non-metal +"specrgb = vec3(dielectricSpecular);\n" +"albedorgb = col.rgb;//+specs.rgb;\n" +//} "#define ambientrgb col.rgb\n" +"#else //blinn-phong\n" +"#define gloss specs.a\n" +//occlusion not defined +"#define specrgb specs.rgb\n" "#endif\n" "#else\n" +//no specular map specified. doesn't mean we shouldn't have any though, at least with pbr enabled. "#define roughness 0.3\n" "#define specrgb 1.0 //vec3(dielectricSpecular)\n" +"#define albedorgb col.rgb\n" "#endif\n" //add in specular, if applicable. "#ifdef PBR\n" -"col.rgb = DoPBR(norm, normalize(eyevector), deluxe, roughness, col.rgb, specrgb, vec3(0.0,1.0,1.0));//*e_light_mul + e_light_ambient*.25*ambientrgb;\n" +"col.rgb = DoPBR(norm, normalize(eyevector), deluxe, roughness, albedorgb, specrgb, vec3(0.0,1.0,1.0));//*e_light_mul + e_light_ambient*.25*ambientrgb;\n" "#elif defined(gloss)\n" "vec3 halfdir = normalize(normalize(eyevector) + deluxe); //this norm should be the deluxemap info instead\n" "float spec = pow(max(dot(halfdir, norm), 0.0), FTE_SPECULAR_EXPONENT * gloss);\n" @@ -11124,7 +11143,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "#if defined(VERTEXCOLOURS)\n" "varying vec4 vc;\n" "#endif\n" -"#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)\n" +"#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) || defined(PBR)\n" "varying vec3 eyevector;\n" "#endif\n" "#ifdef REFLECTCUBEMASK\n" @@ -11169,7 +11188,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "#if defined(VERTEXCOLOURS)\n" "vc = v_colour;\n" "#endif\n" -"#if defined(SPECULAR)||defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)\n" +"#if defined(SPECULAR)||defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) || defined(PBR)\n" "vec3 eyeminusvertex = e_eyepos - w.xyz;\n" "eyevector.x = dot(eyeminusvertex, s.xyz);\n" "eyevector.y = dot(eyeminusvertex, t.xyz);\n" @@ -11210,7 +11229,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "in vec4 vc[];\n" "out vec4 t_vc[];\n" "#endif\n" -"#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)\n" +"#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) || defined(PBR)\n" "in vec3 eyevector[];\n" "out vec3 t_eyevector[];\n" "#endif\n" @@ -11225,7 +11244,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "#if defined(VERTEXCOLOURS)\n" "t_vc[id] = vc[id];\n" "#endif\n" -"#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)\n" +"#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) || defined(PBR)\n" "t_eyevector[id] = eyevector[id];\n" "#endif\n" @@ -11254,7 +11273,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "#if defined(VERTEXCOLOURS)\n" "in vec4 t_vc[];\n" "#endif\n" -"#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)\n" +"#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) || defined(PBR)\n" "in vec3 t_eyevector[];\n" "#endif\n" @@ -11280,7 +11299,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "#if defined(VERTEXCOLOURS)\n" "vc = LERP(t_vc);\n" "#endif\n" -"#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)\n" +"#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) || defined(PBR)\n" "eyevector = LERP(t_eyevector);\n" "#endif\n" @@ -11347,7 +11366,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "vec4 lc = texture2D(s_lower, tcbase);\n" "bases.rgb += lc.rgb*e_lowercolour*lc.a;\n" "#endif\n" -"#if defined(BUMP) || defined(SPECULAR) || defined(REFLECTCUBEMASK)\n" +"#if defined(BUMP) || defined(SPECULAR) || defined(REFLECTCUBEMASK) || defined(PBR)\n" "vec3 bumps = normalize(vec3(texture2D(s_normalmap, tcbase)) - 0.5);\n" "#elif defined(REFLECTCUBEMASK)\n" "vec3 bumps = vec3(0.0,0.0,1.0);\n" @@ -11380,7 +11399,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "#endif\n" "#else\n" "#define roughness 0.3\n" -"#define specrgb 1.0 //vec3(dielectricSpecular)\n" +"#define specrgb bases.rgb //vec3(dielectricSpecular)\n" "#endif\n" "#ifdef PBR\n" diff --git a/engine/qclib/cmdlib.h b/engine/qclib/cmdlib.h index 08eb38f9b..9ab845f90 100644 --- a/engine/qclib/cmdlib.h +++ b/engine/qclib/cmdlib.h @@ -49,37 +49,15 @@ pbool QC_strlcpy(char *dest, const char *src, size_t destsize) WARN_UNUSED_RESUL pbool QC_strnlcpy(char *dest, const char *src, size_t srclen, size_t destsize) WARN_UNUSED_RESULT; char *QC_strcasestr(const char *haystack, const char *needle); -#ifdef _MSC_VER -#define QC_vsnprintf _vsnprintf -static void VARGS QC_snprintfz (char *dest, size_t size, const char *fmt, ...) -{ - va_list args; - va_start (args, fmt); - _vsnprintf (dest, size-1, fmt, args); - va_end (args); - //make sure its terminated. - dest[size-1] = 0; -} -#else -#define QC_vsnprintf vsnprintf -#define QC_snprintfz snprintf -#endif - -#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) - #ifndef LIKEPRINTF - #define LIKEPRINTF(x) __attribute__((format(printf,x,x+1))) - #endif -#endif -#ifndef LIKEPRINTF -#define LIKEPRINTF(x) -#endif - - - #if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) #define FTE_DEPRECATED __attribute__((__deprecated__)) //no idea about the actual gcc version - #ifdef _WIN32 - #define LIKEPRINTF(x) __attribute__((format(ms_printf,x,x+1))) + #if defined(_WIN32) + #include + #ifdef __MINGW_PRINTF_FORMAT + #define LIKEPRINTF(x) __attribute__((format(__MINGW_PRINTF_FORMAT,x,x+1))) + #else + #define LIKEPRINTF(x) __attribute__((format(ms_printf,x,x+1))) + #endif #else #define LIKEPRINTF(x) __attribute__((format(printf,x,x+1))) #endif @@ -90,6 +68,25 @@ static void VARGS QC_snprintfz (char *dest, size_t size, const char *fmt, ...) #ifndef NORETURN #define NORETURN #endif +#ifndef LIKEPRINTF + #define LIKEPRINTF(x) +#endif + +#ifdef _MSC_VER +#define QC_vsnprintf _vsnprintf +static void VARGS QC_snprintfz (char *dest, size_t size, const char *fmt, ...) LIKEPRINTF(3) +{ + va_list args; + va_start (args, fmt); + _vsnprintf (dest, size-1, fmt, args); + va_end (args); + //make sure its terminated. + dest[size-1] = 0; +} +#else + #define QC_vsnprintf vsnprintf + #define QC_snprintfz snprintf +#endif double I_FloatTime (void); diff --git a/engine/qclib/hash.c b/engine/qclib/hash.c index b8f8870a5..09c9c5de9 100644 --- a/engine/qclib/hash.c +++ b/engine/qclib/hash.c @@ -54,7 +54,7 @@ unsigned int Hash_Key(const char *name, unsigned int modulus) return (key%modulus); } -static unsigned int Hash_KeyInsensitive(const char *name, unsigned int modulus) +unsigned int Hash_KeyInsensitive(const char *name, unsigned int modulus) { //fixme: optimize. unsigned int key; for (key=0;*name; name++) diff --git a/engine/qclib/packager.c b/engine/qclib/packager.c index 8b023a000..2da525932 100644 --- a/engine/qclib/packager.c +++ b/engine/qclib/packager.c @@ -1,8 +1,13 @@ #include "qcc.h" #if !defined(MINIMAL) && !defined(OMIT_QCC) #include -#ifndef _WIN32 +#ifdef _WIN32 +#include +#include +#else #include +#include +#include #endif void QCC_Canonicalize(char *fullname, size_t fullnamesize, const char *newfile, const char *base); @@ -79,6 +84,7 @@ struct pkgctx_s struct oldpack_s *next; char filename[128]; size_t numfiles; + unsigned int part; struct { char name[128]; @@ -194,7 +200,7 @@ static struct class_s *PKG_FindClass(struct pkgctx_s *ctx, char *code) } return NULL; } -static struct dataset_s *PKG_FindDataset(struct pkgctx_s *ctx, char *code) +static struct dataset_s *PKG_FindDataset(struct pkgctx_s *ctx, const char *code) { struct dataset_s *o; for (o = ctx->datasets; o; o = o->next) @@ -204,7 +210,7 @@ static struct dataset_s *PKG_FindDataset(struct pkgctx_s *ctx, char *code) } return NULL; } -static struct dataset_s *PKG_GetDataset(struct pkgctx_s *ctx, char *code) +static struct dataset_s *PKG_GetDataset(struct pkgctx_s *ctx, const char *code) { struct dataset_s *s = PKG_FindDataset(ctx, code); if (!s) @@ -373,6 +379,37 @@ static void PKG_CreateOutput(struct pkgctx_s *ctx, struct dataset_s *s, const ch QCC_Canonicalize(o->filename, sizeof(o->filename), path, ctx->gamepath); o->next = s->outputs; s->outputs = o; + + + if (diff) + { + char *end = path + strlen(path)-2; + unsigned int i; + for (i = 0; i <= 99; i++) + { +#ifdef _WIN32 + struct _stat statbuf; +#else + struct stat statbuf; +#endif + sprintf(end, "%02u", i+1); +#ifdef _WIN32 + //FIXME: use the utf16 version because microsoft suck and don't allow utf-8 + if (_stat(path, &statbuf) == 0) +#else + if (stat(path, &statbuf) == 0) +#endif + { + struct oldpack_s *span = malloc(sizeof(*span)); + strcpy(span->filename, path); + span->numfiles = 0; + span->file = NULL; + span->next = o->oldparts; + span->part = i; + o->oldparts = span; + } + } + } } static void PKG_ParseOutput(struct pkgctx_s *ctx, pbool diff) @@ -440,6 +477,7 @@ static void PKG_AddOldPack(struct pkgctx_s *ctx, const char *fname) ctx->oldpacks = pack; } #endif + static void PKG_ParseOldPack(struct pkgctx_s *ctx) { char token[MAX_OSPATH]; @@ -596,7 +634,6 @@ static void PKG_ParseRule(struct pkgctx_s *ctx) r->next = ctx->rules; ctx->rules = r; } -#ifdef _WIN32 static void PKG_AddClassFile(struct pkgctx_s *ctx, struct class_s *c, const char *fname, time_t mtime) { struct file_s *f; @@ -618,7 +655,6 @@ static void PKG_AddClassFile(struct pkgctx_s *ctx, struct class_s *c, const char f->next = c->files; c->files = f; } -#endif static void PKG_AddClassFiles(struct pkgctx_s *ctx, struct class_s *c, const char *fname) { #ifdef _WIN32 @@ -638,7 +674,45 @@ static void PKG_AddClassFiles(struct pkgctx_s *ctx, struct class_s *c, const cha } while(FindNextFile(h, &fd)); } #else - ctx->messagecallback(ctx->userctx, "no wildcard support, sorry\n"); + DIR *dir; + struct dirent *ent; + char basepath[MAX_OSPATH], tmppath[MAX_OSPATH]; + struct stat statbuf; + + QCC_Canonicalize(basepath, sizeof(basepath), fname, ctx->sourcepath); + QC_strlcat(basepath, "/", sizeof(basepath)); + dir = opendir(basepath); + if (!dir) + { + ctx->messagecallback(ctx->userctx, "unable to open dir %s\n", basepath); + return; + } + while ((ent = readdir(dir))) + { + if (*ent->d_name == '.') + continue; + QCC_Canonicalize(basepath, sizeof(basepath), ent->d_name, fname); + QCC_Canonicalize(tmppath, sizeof(tmppath), basepath, ctx->sourcepath); + if (stat(tmppath, &statbuf)!=0) + continue; + + switch (statbuf.st_mode & S_IFMT) + { + default: //some weird file type. shouldn't be a symlink sadly. +// ctx->messagecallback(ctx->userctx, "found weird %s\n", basepath); + break; + case S_IFDIR: + QC_strlcat(basepath, "/", sizeof(basepath)); +// ctx->messagecallback(ctx->userctx, "found dir %s\n", basepath); + PKG_AddClassFiles(ctx, c, basepath); + break; + case S_IFREG: +// ctx->messagecallback(ctx->userctx, "found file %s\n", basepath); + PKG_AddClassFile(ctx, c, basepath, statbuf.st_mtime); + break; + } + } + closedir(dir); #endif } static void PKG_ParseClass(struct pkgctx_s *ctx, char *output) @@ -887,6 +961,7 @@ static void *PKG_OpenSourceFile(struct pkgctx_s *ctx, struct file_s *file, size_ QCC_Canonicalize(fullname, sizeof(fullname), file->name, ctx->sourcepath); strcpy(file->write.name, file->name); + //WIN32 FIXME: use the utf16 version because microsoft suck and don't allow utf-8 f = fopen(fullname, "rb"); if (!f) return NULL; @@ -1010,7 +1085,7 @@ static void *PKG_OpenSourceFile(struct pkgctx_s *ctx, struct file_s *file, size_ return data; } -static void PKG_WritePackageData(struct pkgctx_s *ctx, struct output_s *out, unsigned int index, pbool directoryonly) +static pbool PKG_WritePackageData(struct pkgctx_s *ctx, struct output_s *out, unsigned int index, pbool directoryonly) { //helpers to deal with misaligned data. writes little-endian. #define misbyte(ptr,ofs,data) ((unsigned char*)(ptr))[ofs] = (data)&0xff @@ -1044,12 +1119,27 @@ static void PKG_WritePackageData(struct pkgctx_s *ctx, struct output_s *out, uns #else #define compmethod 0/*Z_RAW*/ #endif - if (!compmethod && !directoryonly) + if (!compmethod && !directoryonly && !index) pak = true; //might as well boost compat... ext = strrchr(out->filename, '.'); if (ext && !QC_strcasecmp(ext, ".pak") && !index) pak = true; + if (!directoryonly) + { + for (f = out->files; f ; f=f->write.nextwrite) + { + if (index != f->write.zdisk) + continue; //not in this disk... + break; + } + if (!f) + { + ctx->messagecallback(ctx->userctx, "\t\tNo files to write to %s\n", out->filename); + return false; + } + } + if (out->usediffs && !directoryonly) { char newname[MAX_OSPATH]; @@ -1068,8 +1158,8 @@ static void PKG_WritePackageData(struct pkgctx_s *ctx, struct output_s *out, uns outf = fopen(out->filename, "wb"); if (!outf) { - ctx->messagecallback(ctx->userctx, "Unable to open %s\n", out->filename); - return; + ctx->messagecallback(ctx->userctx, "\t\tUnable to open %s\n", out->filename); + return false; } if (pak) //reserve space for the pak header @@ -1080,7 +1170,7 @@ static void PKG_WritePackageData(struct pkgctx_s *ctx, struct output_s *out, uns for (f = out->files; f ; f=f->write.nextwrite) { char header[32+sizeof(f->write.name)]; - size_t fnamelen = strlen(f->write.name); + size_t fnamelen; size_t hofs; unsigned short gpflags = GPF_UTF8; @@ -1090,8 +1180,9 @@ static void PKG_WritePackageData(struct pkgctx_s *ctx, struct output_s *out, uns filedata = PKG_OpenSourceFile(ctx, f, &f->write.rawsize); if (!filedata) { - ctx->messagecallback(ctx->userctx, "Unable to open %s\n", f->name); + ctx->messagecallback(ctx->userctx, "\t\tUnable to open %s\n", f->name); } + fnamelen = strlen(f->write.name); f->write.zcrc = QC_encodecrc(f->write.rawsize, filedata); misint (header, 0, 0x04034b50); @@ -1104,10 +1195,10 @@ static void PKG_WritePackageData(struct pkgctx_s *ctx, struct output_s *out, uns misint (header, 18, f->write.rawsize);//compressed size misint (header, 22, f->write.rawsize);//uncompressed size misshort(header, 26, fnamelen);//filename length - misshort(header, 28, 0);//extradata length - strcpy(header+30, f->write.name); + misshort(header, 28, 0);//extradata length (filled in later) + memcpy(header+30, f->write.name, fnamelen); hofs = 30+fnamelen; - + //Write extra data here... misshort(header, 28, hofs-(30+fnamelen));//extradata length f->write.zhdrofs = ftell(outf); fwrite(header, 1, hofs, outf); @@ -1170,8 +1261,8 @@ static void PKG_WritePackageData(struct pkgctx_s *ctx, struct output_s *out, uns struct { char name[56]; - unsigned int size; unsigned int offset; + unsigned int size; } pakentry; pakheader.tabofs = ftell(outf); @@ -1216,7 +1307,7 @@ static void PKG_WritePackageData(struct pkgctx_s *ctx, struct output_s *out, uns misint (centralheader, 20, f->write.zipsize);//compressed size misint (centralheader, 24, f->write.rawsize);//uncompressed size misshort(centralheader, 28, fnamelen);//filename length - misshort(centralheader, 30, 0);//extradata length + misshort(centralheader, 30, 0);//extradata length (filled in later) misshort(centralheader, 32, 0);//comment length misshort(centralheader, 34, f->write.zdisk);//first disk number misshort(centralheader, 36, 0);//internal file attribs @@ -1292,6 +1383,8 @@ static void PKG_WritePackageData(struct pkgctx_s *ctx, struct output_s *out, uns fwrite(centralheader, 1, 22, outf); fclose(outf); + + return true; } /* @@ -1337,7 +1430,7 @@ static void PKG_ReadPackContents(struct pkgctx_s *ctx, struct oldpack_s *old) if (header[0] == 'P' && header[1] == 'K' && header[2] == 5 && header[3] == 6) { - //thisdisk = shortfromptr(header+4); + old->part = shortfromptr(header+4); //centraldirstart = shortfromptr(header+6); old->numfiles = shortfromptr(header+8); //numfiles_all = shortfromptr(header+10); @@ -1360,7 +1453,7 @@ static void PKG_ReadPackContents(struct pkgctx_s *ctx, struct oldpack_s *old) //gflags = shortfromptr(header+8); old->file[u].zmethod = shortfromptr(header+10); old->file[u].dostime = shortfromptr(header+12); - old->file[u].dosdate = shortfromptr(header+12); + old->file[u].dosdate = shortfromptr(header+14); old->file[u].zcrc = longfromptr(header+16); old->file[u].zipsize = longfromptr(header+20); old->file[u].rawsize = longfromptr(header+24); @@ -1462,8 +1555,13 @@ static void PKG_WriteDataset(struct pkgctx_s *ctx, struct dataset_s *set) for (out = set->outputs; out; out = out->next) { if(out->usediffs) - { //FIXME: look for old parts - + { + for (old = out->oldparts; old; old = old->next) + { + PKG_ReadPackContents(ctx, old); + if (out->numparts <= old->part) + out->numparts = old->part + 1; + } } } } @@ -1514,7 +1612,10 @@ static void PKG_WriteDataset(struct pkgctx_s *ctx, struct dataset_s *set) for (old = out->oldparts; old; old = old->next) { if (!PKG_FileIsModified(ctx, old, file)) + { + file->write.zdisk = old->part; break; + } } file->write.nextwrite = out->files; @@ -1545,11 +1646,12 @@ static void PKG_WriteDataset(struct pkgctx_s *ctx, struct dataset_s *set) else { ctx->messagecallback(ctx->userctx, "\tGenerating %s[%s] \"%s\"\n", out->code, set->name, out->filename); - PKG_WritePackageData(ctx, out, out->numparts, false); + if (PKG_WritePackageData(ctx, out, out->numparts, false)) + { + if(out->usediffs) + PKG_WritePackageData(ctx, out, out->numparts+1, true); + } } - - if(out->usediffs) - PKG_WritePackageData(ctx, out, out->numparts+1, true); } } void Packager_WriteDataset(struct pkgctx_s *ctx, char *setname) @@ -1647,5 +1749,46 @@ void Packager_ParseFile(struct pkgctx_s *ctx, char *scriptname) void Packager_Destroy(struct pkgctx_s *ctx) { + free(ctx); +} + +pbool Packager_CompressDir(const char *dirname, enum pkgtype_e type, void (*messagecallback)(void *userctx, const char *message, ...), void *userctx) +{ + char *ext; + char filename[MAX_QPATH]; + struct pkgctx_s *ctx = Packager_Create(messagecallback, userctx); + struct dataset_s *s; + struct class_s *c; + QC_strlcpy(ctx->sourcepath, dirname, sizeof(ctx->sourcepath)); + ext = strrchr(ctx->sourcepath, '/'); + if (*ctx->sourcepath && (!ext || ext[1])) + QC_strlcat(ctx->sourcepath, "/", sizeof(ctx->sourcepath)); + + QC_strlcpy(filename, dirname, sizeof(filename)); + for (;(ext = strrchr(filename, '/')) && !ext[1]; *ext = 0) + ; + ext = strrchr(filename, '.'); + if (ext) + *ext = 0; + if (type == PACKAGER_PAK) + QC_strlcat(filename, ".pak", sizeof(filename)); + else + QC_strlcat(filename, ".pk3", sizeof(filename)); + + s = PKG_GetDataset(ctx, "default"); + PKG_CreateOutput(ctx, s, "default", filename, type == PACKAGER_PK3_SPANNED); + + c = malloc(sizeof(*c)); + memset(c, 0, sizeof(*c)); + strcpy(c->name, "file"); + strcpy(c->outname, "default"); + c->next = ctx->classes; + ctx->classes = c; + PKG_AddClassFiles(ctx, c, ""); + + Packager_WriteDataset(ctx, NULL); + Packager_Destroy(ctx); + + return true; } #endif diff --git a/engine/qclib/pr_exec.c b/engine/qclib/pr_exec.c index 7e66c764e..d7753964c 100644 --- a/engine/qclib/pr_exec.c +++ b/engine/qclib/pr_exec.c @@ -498,7 +498,7 @@ PR_EnterFunction Returns the new program statement counter ==================== */ -int ASMCALL PR_EnterFunction (progfuncs_t *progfuncs, mfunction_t *f, int progsnum) +static int ASMCALL PR_EnterFunction (progfuncs_t *progfuncs, mfunction_t *f, int progsnum) { int i, j, c, o; prstack_t *st; @@ -562,7 +562,7 @@ int ASMCALL PR_EnterFunction (progfuncs_t *progfuncs, mfunction_t *f, int progsn PR_LeaveFunction ==================== */ -int ASMCALL PR_LeaveFunction (progfuncs_t *progfuncs) +static int ASMCALL PR_LeaveFunction (progfuncs_t *progfuncs) { int i, c; prstack_t *st; diff --git a/engine/qclib/progslib.h b/engine/qclib/progslib.h index 745702c96..2f46aa864 100644 --- a/engine/qclib/progslib.h +++ b/engine/qclib/progslib.h @@ -8,8 +8,13 @@ #define VARGS __cdecl #endif #if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) - #ifdef _WIN32 - #define LIKEPRINTF(x) __attribute__((format(ms_printf,x,x+1))) + #if defined(_WIN32) + #include + #ifdef __MINGW_PRINTF_FORMAT + #define LIKEPRINTF(x) __attribute__((format(__MINGW_PRINTF_FORMAT,x,x+1))) + #else + #define LIKEPRINTF(x) __attribute__((format(ms_printf,x,x+1))) + #endif #else #define LIKEPRINTF(x) __attribute__((format(printf,x,x+1))) #endif diff --git a/engine/qclib/qcc.h b/engine/qclib/qcc.h index a295b4832..ed33c2320 100644 --- a/engine/qclib/qcc.h +++ b/engine/qclib/qcc.h @@ -1189,10 +1189,16 @@ int WriteSourceFiles(qcc_cachedsourcefile_t *filelist, int h, pbool sourceaswell struct pkgctx_s; +enum pkgtype_e +{ + PACKAGER_PAK, + PACKAGER_PK3, + PACKAGER_PK3_SPANNED, +}; +pbool Packager_CompressDir(const char *dirname, enum pkgtype_e type, void (*messagecallback)(void *userctx, const char *message, ...), void *userctx); struct pkgctx_s *Packager_Create(void (*messagecallback)(void *userctx, const char *message, ...), void *userctx); void Packager_ParseFile(struct pkgctx_s *ctx, char *scriptfilename); void Packager_ParseText(struct pkgctx_s *ctx, char *scripttext); -void Packager_WriteDataset(struct pkgctx_s *ctx, char *setname); void Packager_Destroy(struct pkgctx_s *ctx); diff --git a/engine/qclib/qcc_pr_comp.c b/engine/qclib/qcc_pr_comp.c index 323019b73..13189d7d4 100644 --- a/engine/qclib/qcc_pr_comp.c +++ b/engine/qclib/qcc_pr_comp.c @@ -6914,7 +6914,7 @@ QCC_sref_t QCC_PR_GenerateFunctionCallRef (QCC_sref_t newself, QCC_sref_t func, if (QCC_OPCodeValid(&pr_opcodes[OP_LOADA_V])) { copyop[2] = OP_LOADA_V; -// copyop[1] = OP_LOADA_L; +// copyop[1] = OP_LOADA_I64; copyop[0] = OP_LOADA_F; copyop_idx = -1; copyop_index = arglist[i]->index; @@ -8551,6 +8551,7 @@ void QCC_PR_EmitClassFromFunction(QCC_def_t *scope, QCC_type_t *basetype) static QCC_sref_t QCC_PR_ExpandField(QCC_sref_t ent, QCC_sref_t field, QCC_type_t *fieldtype, unsigned int preserveflags) { + QCC_type_t *basicfieldtype; QCC_sref_t r; if (!fieldtype) { @@ -8563,20 +8564,26 @@ static QCC_sref_t QCC_PR_ExpandField(QCC_sref_t ent, QCC_sref_t field, QCC_type_ fieldtype = type_variant; } } + basicfieldtype = fieldtype; + while(basicfieldtype->type == ev_accessor || basicfieldtype->type == ev_boolean || basicfieldtype->type == ev_enum) + basicfieldtype = (basicfieldtype->type == ev_enum)?basicfieldtype->aux_type:basicfieldtype->parentclass; + //FIXME: class.staticmember should directly read staticmember instead of trying to dereference - switch(fieldtype->type) + switch(basicfieldtype->type) { case ev_struct: case ev_union: - case ev_enum: { - int i; + int i = 0; QCC_type_t *type = fieldtype; QCC_sref_t dest = QCC_GetTemp(type); QCC_sref_t source = field; //don't bother trying to optimise any temps here, its not likely to happen anyway. - for (i = 0; i+2 < type->size; i+=3, dest.ofs += 3, source.ofs += 3) + for (; i+2 < type->size; i+=3, dest.ofs += 3, source.ofs += 3) QCC_PR_SimpleStatement(&pr_opcodes[OP_LOAD_V], ent, source, dest, false); + if (QCC_OPCodeValid(&pr_opcodes[OP_LOAD_I64])) + for (; i+1 < type->size; i+=2, dest.ofs += 2, source.ofs += 2) + QCC_PR_SimpleStatement(&pr_opcodes[OP_LOAD_I64], ent, source, dest, false); for (; i < type->size; i++, dest.ofs++, source.ofs++) QCC_PR_SimpleStatement(&pr_opcodes[OP_LOAD_F], ent, source, dest, false); source.ofs -= type->size; @@ -8586,15 +8593,20 @@ static QCC_sref_t QCC_PR_ExpandField(QCC_sref_t ent, QCC_sref_t field, QCC_type_ if (!(preserveflags & STFL_PRESERVEB)) QCC_FreeTemp(field); - QCC_PR_ParseWarning(WARN_UNDESIRABLECONVENTION, "QCC_PR_ExpandField: inefficient"); + if (type->size > 3) + QCC_PR_ParseWarning(WARN_UNDESIRABLECONVENTION, "inefficient - copying %u words to a temp", type->size); return dest; } break; case ev_void: case ev_accessor: case ev_boolean: + case ev_enum: default: - QCC_PR_ParseErrorPrintSRef(ERR_INTERNAL, field, "QCC_PR_ExpandField: invalid field type"); + { + char temp[256]; + QCC_PR_ParseErrorPrintSRef(ERR_INTERNAL, field, "QCC_PR_ExpandField: invalid field type %s%s%s", col_type,TypeName(fieldtype, temp, sizeof(temp)),col_none); + } r = field; break; case ev_integer: diff --git a/engine/qclib/qcc_pr_lex.c b/engine/qclib/qcc_pr_lex.c index 6ebf88033..8bff74b27 100644 --- a/engine/qclib/qcc_pr_lex.c +++ b/engine/qclib/qcc_pr_lex.c @@ -4926,6 +4926,7 @@ QCC_type_t *QCC_PR_ParseFunctionType (int newtype, QCC_type_t *returntype) t = QCC_PR_FieldType(t); t = QCC_PR_FieldType(t); paramlist[numparms].type = t; + foundinout = false; } } else diff --git a/engine/qclib/qccguiqt.cpp b/engine/qclib/qccguiqt.cpp index e6d82a901..2d30e7370 100644 --- a/engine/qclib/qccguiqt.cpp +++ b/engine/qclib/qccguiqt.cpp @@ -51,6 +51,9 @@ extern int sourcefilesnumdefs; }; static char *cmdlineargs; +static progfuncs_t guiprogfuncs; +static progexterns_t guiprogexterns; + #undef NULL #define NULL nullptr @@ -541,6 +544,7 @@ private: time_t filemodifiedtime; bool modified; int cursorline; + int cursorindex; enum endings_e endings; //line endings for this file. int savefmt; //encoding to save as QsciDocument doc; @@ -564,6 +568,10 @@ private: return; dl.curdoc = oldval; dl.s->setDocument(dl.curdoc->doc); + + //annoying, but it completely loses your position otherwise. + dl.s->setCursorPosition(dl.curdoc->cursorline-1, dl.curdoc->cursorindex); + dl.s->ensureCursorVisible(); } }; @@ -615,6 +623,7 @@ public: if (curdoc) { curdoc->cursorline = line+1; + curdoc->cursorindex = index; UpdateTitle(); } }); @@ -1381,6 +1390,7 @@ public: //UpdateEditorTitle(d); } + UpdateTitle(); return true; } @@ -2079,27 +2089,25 @@ void RunCompiler(const char *args, pbool quick) static FILE *logfile; const char *argv[128]; int argc; - progexterns_t ext; - progfuncs_t funcs; mainwnd->docs.saveAll(); - memset(&funcs, 0, sizeof(funcs)); - funcs.funcs.parms = &ext; - memset(&ext, 0, sizeof(ext)); - ext.ReadFile = GUIReadFile; - ext.FileSize = GUIFileSize; - ext.WriteFile = QCC_WriteFile; - ext.Sys_Error = Sys_Error; + memset(&guiprogfuncs, 0, sizeof(guiprogfuncs)); + guiprogfuncs.funcs.parms = &guiprogexterns; + memset(&guiprogexterns, 0, sizeof(guiprogexterns)); + guiprogexterns.ReadFile = GUIReadFile; + guiprogexterns.FileSize = GUIFileSize; + guiprogexterns.WriteFile = QCC_WriteFile; + guiprogexterns.Sys_Error = Sys_Error; if (quick) - ext.Printf = Dummyprintf; + guiprogexterns.Printf = Dummyprintf; else { - ext.Printf = GUIprintf; + guiprogexterns.Printf = GUIprintf; GUIprintf(""); } - ext.DPrintf = ext.Printf; + guiprogexterns.DPrintf = guiprogexterns.Printf; if (logfile) fclose(logfile); @@ -2110,7 +2118,7 @@ void RunCompiler(const char *args, pbool quick) argc = GUI_BuildParms(args, argv, quick); - if (CompileParams(&funcs, NULL, argc, argv)) + if (CompileParams(&guiprogfuncs, NULL, argc, argv)) { if (!quick) { @@ -2151,18 +2159,16 @@ void GUI_DoDecompile(void *buf, size_t size) { int h = SafeOpenWrite(fname.toUtf8().data(), -1); - progfuncs_t funcs; - progexterns_t ext; - memset(&funcs, 0, sizeof(funcs)); - funcs.funcs.parms = &ext; - memset(&ext, 0, sizeof(ext)); - ext.ReadFile = GUIReadFile; - ext.FileSize = GUIFileSize; - ext.WriteFile = QCC_WriteFile; - ext.Sys_Error = Sys_Error; - ext.Printf = GUIprintf; + memset(&guiprogfuncs, 0, sizeof(guiprogfuncs)); + guiprogfuncs.funcs.parms = &guiprogexterns; + memset(&guiprogexterns, 0, sizeof(guiprogexterns)); + guiprogexterns.ReadFile = GUIReadFile; + guiprogexterns.FileSize = GUIFileSize; + guiprogexterns.WriteFile = QCC_WriteFile; + guiprogexterns.Sys_Error = Sys_Error; + guiprogexterns.Printf = GUIprintf; - qccprogfuncs = &funcs; + qccprogfuncs = &guiprogfuncs; WriteSourceFiles(qcc_vfiles, h, true, false); qccprogfuncs = NULL; diff --git a/engine/qclib/qccguistuff.c b/engine/qclib/qccguistuff.c index 63ff5a7de..4e599901e 100644 --- a/engine/qclib/qccguistuff.c +++ b/engine/qclib/qccguistuff.c @@ -380,7 +380,7 @@ static char *GUI_ParseInPlace(char **state) { if (*end == '\"') { - end++; + *end++ = 0; break; } else if (*end == '\'' && end[1] == '\\') diff --git a/engine/qclib/qccmain.c b/engine/qclib/qccmain.c index 297b2703a..1de73d626 100644 --- a/engine/qclib/qccmain.c +++ b/engine/qclib/qccmain.c @@ -406,7 +406,7 @@ compiler_flag_t compiler_flag[] = { {&pr_subscopedlocals, FLAG_MIDCOMPILE,"subscope", "Subscoped Locals", "Restrict the scope of locals to the block they are actually defined within, as in C."}, {&verbose, FLAG_MIDCOMPILE,"verbose", "Verbose", "Lots of extra compiler messages."}, {&flag_typeexplicit, FLAG_MIDCOMPILE,"typeexplicit", "Explicit types", "All type conversions must be explicit or directly supported by instruction set."}, - {&flag_boundchecks, defaultflag, "boundchecks", "Disable Bound Checks", "Disable array index checks, speeding up array access but can result in your code misbehaving."}, + {&flag_boundchecks, defaultflag, "boundchecks", "Enforce Bound Checks", "Enforce array index checks to avoid accessing arrays out of bounds. This can be disabled for a speedup (the qcvm will still verify that the access is within the qcvm's memory, but it can't verify that its within the intended array)."}, {&flag_attributes, hideflag, "attributes", "[[attributes]]", "WARNING: This syntax conflicts with vector constructors."}, {&flag_assumevar, hideflag, "assumevar", "explicit consts", "Initialised globals will be considered non-const by default."}, {&flag_dblstarexp, hideflag, "ssp", "** exponent", "Treat ** as an operator for exponents, instead of multiplying by a dereferenced pointer."}, @@ -4114,7 +4114,7 @@ static void QCC_CopyFiles (void) return; } - for ( p = 0; p < 5; p++) + for ( p = 0; p < countof(QCC_Packname); p++) { s = QCC_Packname[p]; if (!*s) diff --git a/engine/qclib/qcctui.c b/engine/qclib/qcctui.c index f40c54e73..0d2fd7026 100644 --- a/engine/qclib/qcctui.c +++ b/engine/qclib/qcctui.c @@ -115,6 +115,89 @@ static int logprintf(const char *format, ...) return 0; } +static size_t totalsize, filecount; +static void QCC_FileList(const char *name, const void *compdata, size_t compsize, int method, size_t plainsize) +{ + totalsize += plainsize; + filecount += 1; + if (!method && compsize==plainsize) + externs->Printf("%8u %s\n", (unsigned)plainsize, name); + else + externs->Printf("%8u %3u%% %s\n", (unsigned)plainsize, plainsize?(unsigned)((100*compsize)/plainsize):100u, name); +} +#include +#ifdef __unix__ +#include +void QCC_Mkdir(const char *path) +{ + char buf[MAX_OSPATH], *sl; + if (!strchr(path, '/')) + return; //no need to create anything + memcpy(buf, path, MAX_OSPATH); + while((sl=strrchr(buf, '/'))) + { + *sl = 0; + mkdir(buf, 0777); + } +} +#else +void QCC_Mkdir(const char *path) +{ + //unsupported. +} +#endif +static const char *extractonly; +static pbool extractonlyfound; +static void QCC_FileExtract(const char *name, const void *compdata, size_t compsize, int method, size_t plainsize) +{ + if (extractonly) + { + const char *sl = strrchr(extractonly, '/'); + if (sl && !sl[1]) + { //trailing / - extract the entire dir. + if (!strcmp(name, extractonly)) + return; //ignore the dir itself... + if (strncmp(name, extractonly, strlen(extractonly))) + return; + } + else + if (strcmp(name, extractonly)) + return; //ignore it if its not the one we're going for. + } + extractonlyfound = true; + externs->Printf("Extracting %s...", name); + if (plainsize <= INT_MAX) + { + void *buffer = malloc(plainsize); + if (buffer && QC_decode(progfuncs, compsize, plainsize, method, compdata, buffer)) + { + QCC_Mkdir(name); + if (!QCC_WriteFile(name, buffer, plainsize)) + externs->Printf(" write failure\n"); + else + externs->Printf(" done\n"); + } + else + externs->Printf(" read failure\n"); + + free(buffer); + } + else + externs->Printf(" too large\n"); +} + +static void QCC_PR_PackagerMessage(void *userctx, const char *message, ...) +{ + va_list argptr; + char string[1024]; + + va_start (argptr,message); + QC_vsnprintf (string,sizeof(string)-1,message,argptr); + va_end (argptr); + + externs->Printf ("%s", string); +} + int main (int argc, const char **argv) { unsigned int i; @@ -137,6 +220,52 @@ int main (int argc, const char **argv) funcs.funcs.parms->Printf = logprintf; funcs.funcs.parms->Sys_Error = Sys_Error; + if ((argc == 3 && !strcmp(argv[1], "-l")) || (argc >= 3 && !strcmp(argv[1], "-x"))) + { + size_t blobsize; + void *blob = QCC_ReadFile(argv[2], NULL, NULL, &blobsize, false); + if (!blob) + { + logprintf("Unable to read %s\n", argv[2]); + return EXIT_FAILURE; + } + if (argc > 3) + { + for (i = 3; i < argc; i++) + { + extractonly = argv[i]; + extractonlyfound = false; + QC_EnumerateFilesFromBlob(blob, blobsize, QCC_FileExtract); + if (!extractonlyfound) + externs->Printf("Unable to find file %s\n", extractonly); + } + extractonly = NULL; + } + else if (argv[1][1] == 'x') + QC_EnumerateFilesFromBlob(blob, blobsize, QCC_FileExtract); + else + { + QC_EnumerateFilesFromBlob(blob, blobsize, QCC_FileList); + externs->Printf("Total size %u bytes, %u files\n", (unsigned)totalsize, (unsigned)filecount); + } + free(blob); + return EXIT_SUCCESS; + } + if (argc == 3 && (!strncmp(argv[1], "-z", 2) || !strcmp(argv[1], "-0") || !strcmp(argv[1], "-9"))) + { //exe -0 foo.pk3dir + enum pkgtype_e t; + if (argv[1][1] == '9') + t = PACKAGER_PK3; + else if (argv[1][1] == '0') + t = PACKAGER_PAK; //not really any difference but oh well + else + t = PACKAGER_PK3_SPANNED; + + if (Packager_CompressDir(argv[2], t, QCC_PR_PackagerMessage, NULL)) + return EXIT_SUCCESS; + else + return EXIT_FAILURE; + } for (i = 0; i < argc; i++) { if (!argv[i]) diff --git a/engine/qclib/qcd_main.c b/engine/qclib/qcd_main.c index 70371ab9e..29d254bc4 100644 --- a/engine/qclib/qcd_main.c +++ b/engine/qclib/qcd_main.c @@ -257,13 +257,14 @@ int QC_EnumerateFilesFromBlob(const void *blob, size_t blobsize, void (*cb)(cons continue; if (nl != QC_ReadRawShort(le+26)) continue; //name is weird... - if (el != QC_ReadRawShort(le+28)) - continue; //name is weird... +// if (el != QC_ReadRawShort(le+28)) +// continue; //extradata is weird... csize = QC_ReadRawInt(le+18); usize = QC_ReadRawInt(le+22); - if (!QC_strlcpy(name, cd+46, (nl+1= sizeof(name)) + continue; //name is too long + QC_strlcpy(name, cd+46, (nl+1players[0].parmstr = Z_StrDup(token); + } + else if (idx >= 1 && idx <= countof(loadinfo->players->parm)) + { //regular parm + l = COM_ParseTokenOut(l, NULL, token, sizeof(token), &tt);if (tt != TTP_RAWTOKEN)return false; + loadinfo->players[0].parm[idx-1].f = atof(token); + } + } + //strbuffer+hashtable+etc junk else if (PR_Common_LoadGame(svprogfuncs, token, &l)) ; - /* - else if (!strcmp(token, "buffer")) - { - l = COM_ParseTokenOut(l, NULL, token, sizeof(token), &tt);if (tt != TTP_RAWTOKEN)return false; - //buffer = atoi(token); - l = COM_ParseTokenOut(l, NULL, token, sizeof(token), &tt);if (tt != TTP_RAWTOKEN)return false; - //flags = atoi(token); - l = COM_ParseTokenOut(l, NULL, token, sizeof(token), &tt);if (tt != TTP_STRING)return false; - //"string" == token - return false; - } - else if (!strcmp(token, "bufstr")) - { - l = COM_ParseTokenOut(l, NULL, token, sizeof(token), &tt);if (tt != TTP_RAWTOKEN)return false; - //buffer = atoi(token); - l = COM_ParseTokenOut(l, NULL, token, sizeof(token), &tt);if (tt != TTP_RAWTOKEN)return false; - //idx = atoi(token); - l = COM_ParseTokenOut(l, NULL, token, sizeof(token), &tt);if (tt != TTP_STRING)return false; - return false; - }*/ else return false; *ptr = l; @@ -312,8 +340,25 @@ static qboolean SV_LegacySavegame (const char *savename, qboolean verbose) for (i=1 ; i < countof(sv.strings.sound_precache); i++) { if (sv.strings.sound_precache[i]) - VFS_PRINTF(f, "sv.lightstyles %i %s\n", i, sv.strings.sound_precache[i]); + VFS_PRINTF(f, "sv.sound_precache %i %s\n", i, sv.strings.sound_precache[i]); } + for (i=1 ; i < countof(sv.strings.particle_precache); i++) + { + if (sv.strings.particle_precache[i]) + VFS_PRINTF(f, "sv.particle_precache %i %s\n", i, sv.strings.particle_precache[i]); + } + VFS_PRINTF(f, "sv.serverflags %i\n", svs.serverflags); //zomg! a fix for losing runes on load;restart! +// VFS_PRINTF(f, "sv.startspot %s\n", InfoBuf_ValueForKey(&svs.info, "*startspot")); //startspot, for restarts. + if (svs.clients->spawn_parmstring) + { + size_t maxlen = strlen(svs.clients->spawn_parmstring)*2+4 + 1; + char *buffer = BZ_Malloc(maxlen); + VFS_PRINTF(f, "spawnparm 0 %s\n", COM_QuotedString(svs.clients->spawn_parmstring, buffer, sizeof(maxlen), false)); + BZ_Free(buffer); + } + if (version == SAVEGAME_VERSION_NQ || version == SAVEGAME_VERSION_QW) + for (i=16 ; i < countof(svs.clients->spawn_parms); i++) + VFS_PRINTF(f, "spawnparm %i %g\n", i+1, svs.clients->spawn_parms[i]); // sv.buffer %i %i "string" // sv.bufstr %i %i "%s" VFS_PUTS(f, "*/\n"); @@ -1396,18 +1441,6 @@ void SV_AutoSave(void) #endif } -typedef struct -{ - char name[32]; - union - { - int i; - float f; - } parm[NUM_SPAWN_PARMS]; - char *parmstr; - - client_t *source; -} loadplayer_t; static void SV_SwapPlayers(client_t *a, client_t *b) { size_t i; @@ -1671,6 +1704,10 @@ static qboolean SV_Loadgame_Legacy(const char *savename, const char *filename, v char *modelnames[MAX_PRECACHE_MODELS]; char *soundnames[MAX_PRECACHE_SOUNDS]; loadplayer_t lp[255]; + struct loadinfo_s loadinfo; + + loadinfo.numplayers = countof(lp); + loadinfo.players = lp; if (version != SAVEGAME_VERSION_FTE_LEG && version != SAVEGAME_VERSION_NQ && version != SAVEGAME_VERSION_QW) { @@ -1867,7 +1904,7 @@ static qboolean SV_Loadgame_Legacy(const char *savename, const char *filename, v strcpy(file, "loadgame"); clnum=VFS_READ(f, file+8, filelen); file[filelen+8]='\0'; - sv.world.edict_size=svprogfuncs->load_ents(svprogfuncs, file, NULL, NULL, SV_ExtendedSaveData); + sv.world.edict_size=svprogfuncs->load_ents(svprogfuncs, file, &loadinfo, NULL, SV_ExtendedSaveData); BZ_Free(file); PR_LoadGlabalStruct(false); diff --git a/engine/server/server.h b/engine/server/server.h index 7529cd6f0..d5db73409 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -505,7 +505,7 @@ typedef struct client_s usercmd_t lastcmd; // for filling in big drops and partial predictions double localtime; // of last message qboolean jump_held; - qboolean lockangles; //mod is spamming angle changes, don't do relative changes + unsigned int lockanglesseq; //mod is spamming angle changes, don't do relative changes. outgoing sequence. v_angles isn't really known until netchan.incoming_acknowledged>=lockangles float maxspeed; // localized maxspeed float entgravity; // localized ent gravity diff --git a/engine/server/sv_ccmds.c b/engine/server/sv_ccmds.c index 4d30f298d..35420d63d 100644 --- a/engine/server/sv_ccmds.c +++ b/engine/server/sv_ccmds.c @@ -87,6 +87,12 @@ client_t *SV_GetClientForString(const char *name, int *id) int first=0; if (id && *id != -1) first = *id; + if (first < 0) + { + if (id) + *id=sv.allocated_client_slots; + return NULL; + } if (!strcmp(name, "*")) //match with all { @@ -95,10 +101,12 @@ client_t *SV_GetClientForString(const char *name, int *id) if (cl->state<=cs_loadzombie) continue; - *id=i+1; + if (id) + *id=i+1; return cl; } - *id=sv.allocated_client_slots; + if (id) + *id=sv.allocated_client_slots; return NULL; } @@ -114,7 +122,7 @@ client_t *SV_GetClientForString(const char *name, int *id) if (!*s) { int uid = Q_atoi(name); - for (i = first, cl = svs.clients; i < sv.allocated_client_slots; i++, cl++) + for (i = first, cl = svs.clients+first; i < sv.allocated_client_slots; i++, cl++) { if (cl->state<=cs_loadzombie) continue; @@ -585,7 +593,7 @@ void SV_Map_f (void) Con_DPrintf ("map_restart delay not implemented yet\n"); } Q_strncpyz (level, ".", sizeof(level)); - startspot = NULL; + startspot = NULL; //FIXME: startspot forgotten on restart //FIXME: if precaches+statics don't change, don't do the whole networking thing. } diff --git a/engine/server/sv_ents.c b/engine/server/sv_ents.c index 3bf90bc3d..2a0da35de 100644 --- a/engine/server/sv_ents.c +++ b/engine/server/sv_ents.c @@ -3827,9 +3827,10 @@ void SV_Snapshot_BuildQ1(client_t *client, packet_entities_t *pack, pvscamera_t if (cameras && tracecullent && !((unsigned int)ent->v->effects & (EF_DIMLIGHT|EF_BLUE|EF_RED|EF_BRIGHTLIGHT|EF_BRIGHTFIELD|EF_NODEPTHTEST))) { //more expensive culling - if ((e <= sv.allocated_client_slots && sv_cullplayers_trace.value) || sv_cullentities_trace.value) - if (Cull_Traceline(e < client->lastseen_count?&client->lastseen_time[e]:NULL, cameras, tracecullent)) - continue; + if (!(pvsflags & PVSF_MODE_MASK)) + if ((e <= sv.allocated_client_slots && sv_cullplayers_trace.value) || sv_cullentities_trace.value) + if (Cull_Traceline(e < client->lastseen_count?&client->lastseen_time[e]:NULL, cameras, tracecullent)) + continue; } //EXT_CSQC diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 6803dc613..130a42837 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -187,7 +187,7 @@ cvar_t skill = CVARF("skill", "" , CVAR_SERVERINFO); // 0, 1, 2 or 3 cvar_t spawn = CVARF("spawn", "" , CVAR_SERVERINFO); cvar_t watervis = CVARF("watervis", "" , CVAR_SERVERINFO); #pragma warningmsg("Remove this some time") -cvar_t allow_skybox = CVARF("allow_skybox", "", CVAR_SERVERINFO); +cvar_t allow_skybox = CVARFD("allow_skybox", "", CVAR_SERVERINFO, "This setting says whether clients should skip writing skybox depth when rendering skyboxes/skydomes. Skipping depth writes is required for halflife, quake2, and quake3 compat, but q1 content generally requires depth masking. Empty uses format-specific defaults."); cvar_t sv_allow_splitscreen = CVARFD("allow_splitscreen","",CVAR_SERVERINFO, "Specifies whether clients can use splitscreen extensions to dynamically add additional clients. This only affects remote clients and not the built-in client.\nClients may need to reconnect in order to add seats when this is changed."); cvar_t fbskins = CVARF("fbskins", "", CVAR_SERVERINFO); //to get rid of lame fuhquake fbskins diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index 917cf3c3b..3246b5db4 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -349,32 +349,10 @@ static void WPhys_PortalTransform(world_t *w, wedict_t *ent, wedict_t *portal, v if (ent->entnum > 0 && ent->entnum <= svs.allocated_client_slots) { client_t *cl = &svs.clients[ent->entnum-1]; - int i; - vec3_t delta; ent->v->angles[0] *= r_meshpitch.value; - if (!cl->lockangles && (cl->fteprotocolextensions2 & PEXT2_SETANGLEDELTA)) - { - cl = ClientReliableWrite_BeginSplit(cl, svcfte_setangledelta, 7); - - VectorSubtract(ent->v->angles, ent->v->v_angle, delta); - delta[2] = anglemod(delta[2]); - if (delta[2] > 90 && delta[2] < 270) - { - delta[2] -= 180; - delta[1] -= 180; - delta[0] -= -180; - } - for (i=0 ; i < 3 ; i++) - ClientReliableWrite_Angle16 (cl, delta[i]); - } - else - { - cl = ClientReliableWrite_BeginSplit (cl, svc_setangle, 7); - for (i=0 ; i < 3 ; i++) - ClientReliableWrite_Angle (cl, ent->v->angles[i]); - } VectorCopy(ent->v->angles, ent->v->v_angle); ent->v->angles[0] *= r_meshpitch.value; + SV_SendFixAngle(cl, NULL, FIXANGLE_AUTO, true); } #endif diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index 6ac14a816..4fa0bec7d 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -1637,7 +1637,7 @@ void SV_SendFixAngle(client_t *client, sizebuf_t *msg, int fixtype, qboolean rol if (fixtype == FIXANGLE_AUTO) { - if (!client->lockangles && controller->delta_sequence != -1 && !client->viewent) + if (client->lockanglesseqnetchan.incoming_acknowledged && controller->delta_sequence != -1 && !client->viewent) fixtype = FIXANGLE_DELTA; else fixtype = FIXANGLE_FIXED; @@ -1645,7 +1645,7 @@ void SV_SendFixAngle(client_t *client, sizebuf_t *msg, int fixtype, qboolean rol if (fixtype == FIXANGLE_DELTA && !(controller->fteprotocolextensions2 & PEXT2_SETANGLEDELTA)) fixtype = FIXANGLE_FIXED; //sorry, can't do it. - if (!client->lockangles && controller->netchan.message.cursize < controller->netchan.message.maxsize/2) + if (client->lockanglesseq>=controller->netchan.incoming_acknowledged && controller->netchan.message.cursize < controller->netchan.message.maxsize/2) msg = NULL; //try to keep them vaugely reliable, where feasable. if (!msg) msg = ClientReliable_StartWrite(client, 10); @@ -1673,7 +1673,7 @@ void SV_SendFixAngle(client_t *client, sizebuf_t *msg, int fixtype, qboolean rol for (i=0 ; i < 3 ; i++) MSG_WriteAngle (msg, (i==2&&!roll)?0:ang[i]); } - client->lockangles = true; //so that spammed fixangles use absolute values, locking the camera in place. + client->lockanglesseq = controller->netchan.outgoing_sequence+1; //so that spammed fixangles use absolute values, locking the camera in place. } void SV_WriteEntityDataToMessage (client_t *client, sizebuf_t *msg, int pnum) @@ -1723,8 +1723,6 @@ void SV_WriteEntityDataToMessage (client_t *client, sizebuf_t *msg, int pnum) SV_SendFixAngle(client, msg, ent->v->fixangle, true); ent->v->fixangle = FIXANGLE_NO; } - else - client->lockangles = false; } /*sends the a centerprint string directly to the client*/ diff --git a/engine/server/world.c b/engine/server/world.c index eea46dd5f..ad17fad48 100644 --- a/engine/server/world.c +++ b/engine/server/world.c @@ -2432,6 +2432,8 @@ static void World_ClipToNetwork (world_t *w, moveclip_t *clip) if (touch->modelindex <= 0 || touch->modelindex >= MAX_PRECACHE_MODELS) continue; //erk model = cl.model_precache[touch->modelindex]; + if (!model) + continue; VectorCopy(model->mins, bmins); VectorCopy(model->maxs, bmaxs); } diff --git a/engine/shaders/glsl/defaultskin.glsl b/engine/shaders/glsl/defaultskin.glsl index 86aab0e72..f8f815f16 100644 --- a/engine/shaders/glsl/defaultskin.glsl +++ b/engine/shaders/glsl/defaultskin.glsl @@ -57,7 +57,7 @@ affine varying vec2 tc; varying vec4 light; -#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) +#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) || defined(PBR) varying vec3 eyevector; #endif #if defined(PBR)||defined(REFLECTCUBEMASK) @@ -92,9 +92,7 @@ void main () #endif #endif -#if defined(PBR) - eyevector = e_eyepos - w.xyz; -#elif defined(SPECULAR)||defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) +#if defined(SPECULAR)||defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) || defined(PBR) vec3 eyeminusvertex = e_eyepos - w.xyz; eyevector.x = dot(eyeminusvertex, s.xyz); eyevector.y = dot(eyeminusvertex, t.xyz); @@ -139,7 +137,7 @@ affine in vec2 tc[]; affine out vec2 t_tc[]; in vec4 light[]; out vec4 t_light[]; -#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) +#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) || defined(PBR) in vec3 eyevector[]; out vec3 t_eyevector[]; #endif @@ -155,7 +153,7 @@ void main() t_normal[id] = normal[id]; t_tc[id] = tc[id]; t_light[id] = light[id]; -#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) +#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) || defined(PBR) t_eyevector[id] = eyevector[id]; #endif #ifdef REFLECTCUBEMASK @@ -188,7 +186,7 @@ affine in vec2 t_tc[]; affine out vec2 tc; in vec4 t_light[]; out vec4 light; -#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) +#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) || defined(PBR) in vec3 t_eyevector[]; out vec3 eyevector; #endif @@ -211,7 +209,7 @@ void main() //FIXME: we should be recalcing these here, instead of just lerping them light = LERP(t_light); -#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) +#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) || defined(PBR) eyevector = LERP(t_eyevector); #endif #ifdef REFLECTCUBEMASK @@ -251,7 +249,7 @@ uniform float cvar_gl_specular; affine varying vec2 tc; varying vec4 light; -#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) +#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) || defined(PBR) varying vec3 eyevector; #endif #if defined(PBR) || defined(REFLECTCUBEMASK) @@ -345,7 +343,8 @@ void main () #endif #else #define roughness 0.3 - #define specrgb 1.0 //vec3(dielectricSpecular) + #define specrgb vec3(1.0) //vec3(dielectricSpecular) + #define ambientrgb col.rgb #endif #ifdef BUMP diff --git a/engine/shaders/glsl/defaultwall.glsl b/engine/shaders/glsl/defaultwall.glsl index e86f46854..4bef439dd 100644 --- a/engine/shaders/glsl/defaultwall.glsl +++ b/engine/shaders/glsl/defaultwall.glsl @@ -36,7 +36,7 @@ #include "sys/fog.h" #if !defined(TESS_CONTROL_SHADER) - #if defined(OFFSETMAPPING) || defined(SPECULAR) || defined(REFLECTCUBEMASK) + #if defined(OFFSETMAPPING) || defined(SPECULAR) || defined(REFLECTCUBEMASK) || defined(PBR) varying vec3 eyevector; #endif @@ -68,7 +68,7 @@ varying vec3 vertex, normal; #endif void main () { -#if defined(OFFSETMAPPING) || defined(SPECULAR) || defined(REFLECTCUBEMASK) +#if defined(OFFSETMAPPING) || defined(SPECULAR) || defined(REFLECTCUBEMASK) || defined(PBR) vec3 eyeminusvertex = e_eyepos - v_position.xyz; eyevector.x = dot(eyeminusvertex, v_svector.xyz); eyevector.y = dot(eyeminusvertex, v_tvector.xyz); @@ -119,7 +119,7 @@ in vec3 vertex[]; out vec3 t_vertex[]; in vec3 normal[]; out vec3 t_normal[]; -#if defined(OFFSETMAPPING) || defined(SPECULAR) || defined(REFLECTCUBEMASK) +#if defined(OFFSETMAPPING) || defined(SPECULAR) || defined(REFLECTCUBEMASK) || defined(PBR) in vec3 eyevector[]; out vec3 t_eyevector[]; #endif @@ -161,7 +161,7 @@ void main() #endif #endif - #if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) + #if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) || defined(PBR) t_eyevector[id] = eyevector[id]; #endif @@ -185,7 +185,7 @@ layout(triangles) in; in vec3 t_vertex[]; in vec3 t_normal[]; -#if defined(OFFSETMAPPING) || defined(SPECULAR) || defined(REFLECTCUBEMASK) +#if defined(OFFSETMAPPING) || defined(SPECULAR) || defined(REFLECTCUBEMASK) || defined(PBR) in vec3 t_eyevector[]; #endif #ifdef REFLECTCUBEMASK @@ -235,7 +235,7 @@ void main() #ifdef REFLECTCUBEMASK invsurface = LERP(t_invsurface); #endif -#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) +#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) || defined(PBR) eyevector = LERP(t_eyevector); #endif @@ -331,37 +331,57 @@ void main () #endif // col *= factor_base; - #define dielectricSpecular 0.04 - #ifdef SPECULAR - vec4 specs = texture2D(s_specular, tc);//*factor_spec; - #ifdef ORM - #define occlusion specs.r - #define roughness specs.g - #define metalness specs.b - #define gloss (1.0-roughness) - #define ambientrgb (specrgb+col.rgb) - vec3 specrgb = mix(vec3(dielectricSpecular), col.rgb, metalness); - col.rgb = col.rgb * (1.0 - dielectricSpecular) * (1.0-metalness); - #elif defined(SG) //pbr-style specular+glossiness - //occlusion needs to be baked in. :( - #define roughness (1.0-specs.a) - #define gloss specs.a - #define specrgb specs.rgb - #define ambientrgb (specs.rgb+col.rgb) - #else //blinn-phong - #define roughness (1.0-specs.a) - #define gloss specs.a - #define specrgb specs.rgb - #define ambientrgb col.rgb - #endif - #else - #define roughness 0.3 - #define specrgb 1.0 //vec3(dielectricSpecular) - #endif + #define dielectricSpecular 0.04 + #ifdef SPECULAR + vec4 specs = texture2D(s_specular, tc);//*factor_spec; + #ifdef ORM + #define occlusion specs.r + #define roughness specs.g + #define metalness specs.b + #define gloss (1.0-roughness) + #define ambientrgb (specrgb+col.rgb) + vec3 specrgb = mix(vec3(dielectricSpecular), col.rgb, metalness); + vec3 albedorgb = col.rgb * (1.0 - dielectricSpecular) * (1.0-metalness); + #elif defined(SG) //pbr-style specular+glossiness + //occlusion needs to be baked in. :( + #define roughness (1.0-specs.a) + #define gloss specs.a + #define specrgb specs.rgb + #define ambientrgb (specs.rgb+col.rgb) + #define albedorgb col.rgb + #elif defined(PBR) //PBR using legacy texturemaps + #define gloss specs.a + #define roughness (1.0-gloss) + //metalness not relevant + + //our pbr stuff doesn't much like our inputs. + vec3 specrgb, albedorgb; + //if (1==0) + //{ //metal + // specrgb = col.rgb;//+specs.rgb; + // albedorgb = vec3(0.0); + //} + //else + //{ //non-metal + specrgb = vec3(dielectricSpecular); + albedorgb = col.rgb;//+specs.rgb; + //} + #define ambientrgb col.rgb + #else //blinn-phong + #define gloss specs.a + //occlusion not defined + #define specrgb specs.rgb + #endif + #else + //no specular map specified. doesn't mean we shouldn't have any though, at least with pbr enabled. + #define roughness 0.3 + #define specrgb 1.0 //vec3(dielectricSpecular) + #define albedorgb col.rgb + #endif //add in specular, if applicable. #ifdef PBR - col.rgb = DoPBR(norm, normalize(eyevector), deluxe, roughness, col.rgb, specrgb, vec3(0.0,1.0,1.0));//*e_light_mul + e_light_ambient*.25*ambientrgb; + col.rgb = DoPBR(norm, normalize(eyevector), deluxe, roughness, albedorgb, specrgb, vec3(0.0,1.0,1.0));//*e_light_mul + e_light_ambient*.25*ambientrgb; #elif defined(gloss) vec3 halfdir = normalize(normalize(eyevector) + deluxe); //this norm should be the deluxemap info instead float spec = pow(max(dot(halfdir, norm), 0.0), FTE_SPECULAR_EXPONENT * gloss); diff --git a/engine/shaders/glsl/rtlight.glsl b/engine/shaders/glsl/rtlight.glsl index 822975dbe..c2ee89503 100644 --- a/engine/shaders/glsl/rtlight.glsl +++ b/engine/shaders/glsl/rtlight.glsl @@ -52,7 +52,7 @@ #if defined(VERTEXCOLOURS) varying vec4 vc; #endif - #if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) + #if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) || defined(PBR) varying vec3 eyevector; #endif #ifdef REFLECTCUBEMASK @@ -97,7 +97,7 @@ t = normalize(t); #if defined(VERTEXCOLOURS) vc = v_colour; #endif -#if defined(SPECULAR)||defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) +#if defined(SPECULAR)||defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) || defined(PBR) vec3 eyeminusvertex = e_eyepos - w.xyz; eyevector.x = dot(eyeminusvertex, s.xyz); eyevector.y = dot(eyeminusvertex, t.xyz); @@ -138,7 +138,7 @@ out vec3 t_lightvector[]; in vec4 vc[]; out vec4 t_vc[]; #endif -#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) +#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) || defined(PBR) in vec3 eyevector[]; out vec3 t_eyevector[]; #endif @@ -153,7 +153,7 @@ void main() #if defined(VERTEXCOLOURS) t_vc[id] = vc[id]; #endif -#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) +#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) || defined(PBR) t_eyevector[id] = eyevector[id]; #endif @@ -182,7 +182,7 @@ in vec3 t_lightvector[]; #if defined(VERTEXCOLOURS) in vec4 t_vc[]; #endif -#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) +#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) || defined(PBR) in vec3 t_eyevector[]; #endif @@ -208,7 +208,7 @@ void main() #if defined(VERTEXCOLOURS) vc = LERP(t_vc); #endif -#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) +#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) || defined(PBR) eyevector = LERP(t_eyevector); #endif @@ -275,7 +275,7 @@ void main () vec4 lc = texture2D(s_lower, tcbase); bases.rgb += lc.rgb*e_lowercolour*lc.a; #endif -#if defined(BUMP) || defined(SPECULAR) || defined(REFLECTCUBEMASK) +#if defined(BUMP) || defined(SPECULAR) || defined(REFLECTCUBEMASK) || defined(PBR) vec3 bumps = normalize(vec3(texture2D(s_normalmap, tcbase)) - 0.5); #elif defined(REFLECTCUBEMASK) vec3 bumps = vec3(0.0,0.0,1.0); @@ -308,7 +308,7 @@ void main () #endif #else #define roughness 0.3 - #define specrgb 1.0 //vec3(dielectricSpecular) + #define specrgb bases.rgb //vec3(dielectricSpecular) #endif #ifdef PBR