diff --git a/engine/Makefile b/engine/Makefile index 755a8d135..6d6ac3b58 100644 --- a/engine/Makefile +++ b/engine/Makefile @@ -781,6 +781,7 @@ COMMON_OBJS = \ fs_stdio.o \ fs_pak.o \ fs_zip.o \ + fs_dzip.o \ fs_xz.o \ m_download.o \ mathlib.o \ diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index cb866285d..782bcf272 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -31,8 +31,6 @@ int cls_lasttype; void CL_PlayDemo(char *demoname, qboolean usesystempath); void CL_PlayDemoFile(vfsfile_t *f, char *demoname, qboolean issyspath); -char lastdemoname[256]; -static qboolean lastdemowassystempath; extern cvar_t qtvcl_forceversion1; extern cvar_t qtvcl_eztvextensions; @@ -439,10 +437,10 @@ void CL_DemoJump_f(void) { VFS_SEEK(df, 0); cls.demoinfile = NULL; - CL_PlayDemoFile(df, lastdemoname, lastdemowassystempath); + CL_PlayDemoFile(df, cls.lastdemoname, cls.lastdemowassystempath); } else - CL_PlayDemo(lastdemoname, lastdemowassystempath); + CL_PlayDemo(cls.lastdemoname, cls.lastdemowassystempath); //now fastparse it. cls.demoseektime = newtime; @@ -1247,6 +1245,7 @@ void CLNQ_WriteServerData(sizebuf_t *buf) { default: case CPNQ_ID: protmain = PROTOCOL_VERSION_NQ; break; + case CPNQ_NEHAHRA: protmain = PROTOCOL_VERSION_NEHD; break; case CPNQ_BJP1: protmain = PROTOCOL_VERSION_BJP1; break; case CPNQ_BJP2: protmain = PROTOCOL_VERSION_BJP2; break; case CPNQ_BJP3: protmain = PROTOCOL_VERSION_BJP3; break; @@ -1274,14 +1273,14 @@ void CLNQ_WriteServerData(sizebuf_t *buf) } #endif -void CL_Record_Baseline(sizebuf_t *buf, entity_state_t *state, unsigned int bits) +void CL_Record_Baseline(sizebuf_t *buf, entity_state_t *state, unsigned int fitzbits) { unsigned int j; - if (bits & FITZ_B_LARGEMODEL) + if (fitzbits & FITZ_B_LARGEMODEL) MSG_WriteShort (buf, state->modelindex); else MSG_WriteByte (buf, state->modelindex); - if (bits & FITZ_B_LARGEFRAME) + if (fitzbits & FITZ_B_LARGEFRAME) MSG_WriteShort (buf, state->frame); else MSG_WriteByte (buf, state->frame); @@ -1293,9 +1292,9 @@ void CL_Record_Baseline(sizebuf_t *buf, entity_state_t *state, unsigned int bits MSG_WriteAngle (buf, state->angles[j]); } - if (bits & FITZ_B_ALPHA) + if (fitzbits & FITZ_B_ALPHA) MSG_WriteByte(buf, state->trans); - if (bits & RMQFITZ_B_SCALE) + if (fitzbits & RMQFITZ_B_SCALE) MSG_WriteByte(buf, state->scale); } @@ -1404,40 +1403,40 @@ static int CL_Record_ParticlesStaticsBaselines(sizebuf_t *buf, int seq) else #endif { - unsigned int bits = 0; + unsigned int fitzbits = 0; //must take some consistent form for this to work #ifdef NQPROT if (es->modelindex > 255) - bits |= FITZ_B_LARGEMODEL; + fitzbits |= FITZ_B_LARGEMODEL; if (es->frame > 255) - bits |= FITZ_B_LARGEFRAME; + fitzbits |= FITZ_B_LARGEFRAME; if (es->trans != 255) - bits |= FITZ_B_ALPHA; + fitzbits |= FITZ_B_ALPHA; if (es->scale != 16) - bits |= RMQFITZ_B_SCALE; + fitzbits |= RMQFITZ_B_SCALE; if (cls.protocol == CP_NETQUAKE && CPNQ_IS_BJP) { MSG_WriteByte (buf, svc_spawnbaseline); - bits = FITZ_B_LARGEMODEL; //bjp always uses shorts for models. + fitzbits = FITZ_B_LARGEMODEL; //bjp always uses shorts for models. } - else if (cls.protocol == CP_NETQUAKE && cls.protocol_nq == CPNQ_FITZ666 && bits) + else if (cls.protocol == CP_NETQUAKE && cls.protocol_nq == CPNQ_FITZ666 && fitzbits) { MSG_WriteByte (buf, svcfitz_spawnbaseline2); - MSG_WriteByte (buf, bits); + MSG_WriteByte (buf, fitzbits); } - else if (cls.protocol == CP_NETQUAKE && CPNQ_IS_DP && (bits & (FITZ_B_LARGEMODEL|FITZ_B_LARGEFRAME))) + else if (cls.protocol == CP_NETQUAKE && CPNQ_IS_DP && (fitzbits & (FITZ_B_LARGEMODEL|FITZ_B_LARGEFRAME))) { MSG_WriteByte (buf, svcdp_spawnbaseline2); - bits = FITZ_B_LARGEMODEL|FITZ_B_LARGEFRAME; //dp's baseline2 always has these (regular baseline is unmodified) + fitzbits = FITZ_B_LARGEMODEL|FITZ_B_LARGEFRAME; //dp's baseline2 always has these (regular baseline is unmodified) } else #endif { MSG_WriteByte (buf,svc_spawnbaseline); - bits = 0; + fitzbits = 0; } MSG_WriteEntity (buf, i); - CL_Record_Baseline(buf, es, bits); + CL_Record_Baseline(buf, es, fitzbits); } if (buf->cursize > buf->maxsize/2) CL_WriteRecordDemoMessage (buf, seq++); @@ -1989,6 +1988,9 @@ void CL_DemoList_c(int argn, char *partial, struct xcommandargcompletioncb_s *ct COM_EnumerateFiles(va("%s*.dem", partial), CompleteDemoList, ctx); COM_EnumerateFiles(va("%s*.mvd", partial), CompleteDemoList, ctx); COM_EnumerateFiles(va("%s*.mvd.gz", partial), CompleteDemoList, ctx); + + //fixme: show files in both .zip and .dz +// COM_EnumerateFiles(va("%s*.dz", partial), CompleteDemoList, ctx); } } /* @@ -2172,8 +2174,8 @@ void CL_PlayDemoStream(vfsfile_t *file, char *filename, qboolean issyspath, int } if (filename) { - Q_strncpyz (lastdemoname, filename, sizeof(lastdemoname)); - lastdemowassystempath = issyspath; + Q_strncpyz (cls.lastdemoname, filename, sizeof(cls.lastdemoname)); + cls.lastdemowassystempath = issyspath; Con_Printf ("Playing demo from %s.\n", filename); } @@ -2375,7 +2377,7 @@ void CL_PlayDemo(char *demoname, qboolean usesystempath) TP_ExecTrigger ("f_demoend", true); return; } - Q_strncpyz (lastdemoname, demoname, sizeof(lastdemoname)); + Q_strncpyz (cls.lastdemoname, demoname, sizeof(cls.lastdemoname)); #ifdef AVAIL_GZDEC if (strlen(name) >= 3 && !Q_strcasecmp(name + strlen(name) - 3, ".gz")) diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index e9759b685..48e2f3d4b 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -1700,7 +1700,7 @@ void CLNQ_ParseEntity(unsigned int bits) entity_state_t *base; packet_entities_t *pack; - qboolean isnehahra = CPNQ_IS_BJP;//||(cls.protocol_nq == CPNQ_ID && cls.demoplayback); + qboolean isnehahra = CPNQ_IS_BJP||(cls.protocol_nq == CPNQ_NEHAHRA); if (cls.signon == 4 - 1) { // first update is the final signon stage @@ -1716,17 +1716,18 @@ void CLNQ_ParseEntity(unsigned int bits) bits |= (i<<8); } - if (!isnehahra) + if (bits & DPU_EXTEND1) { - if (bits & DPU_EXTEND1) + if (!isnehahra) { i = MSG_ReadByte (); bits |= (i<<16); - } - if (bits & DPU_EXTEND2) - { - i = MSG_ReadByte (); - bits |= (i<<24); + + if (bits & DPU_EXTEND2) + { + i = MSG_ReadByte (); + bits |= (i<<24); + } } } @@ -1812,6 +1813,8 @@ void CLNQ_ParseEntity(unsigned int bits) if (MSG_ReadFloat() > 0.5) state->effects |= EF_FULLBRIGHT; } + if (!alpha) + alpha = 1; state->trans = bound(0, 255 * alpha, 255); } } @@ -1833,7 +1836,11 @@ void CLNQ_ParseEntity(unsigned int bits) MSG_ReadByte(); } else - { + { //dp tends to leak stuff, so parse as quakedp if the normal protocol doesn't define it as something better. + +// if (bits & DPU_DELTA) //should delta from the previous frame. DP doesn't generate this any more, so whatever. +// Host_EndGame("CLNQ_ParseEntity: DPU_DELTA not supported"); + if (bits & DPU_ALPHA) state->trans = MSG_ReadByte(); diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index cbcf66af5..3f1463ad0 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -330,10 +330,7 @@ void CL_UpdateWindowTitle(void) else #endif if (cls.demoplayback) - { - extern char lastdemoname[]; - Q_snprintfz(title, sizeof(title), "%s: %s", fs_gamename.string, lastdemoname); - } + Q_snprintfz(title, sizeof(title), "%s: %s", fs_gamename.string, cls.lastdemoname); else Q_snprintfz(title, sizeof(title), "%s: %s", fs_gamename.string, cls.servername); break; @@ -2564,7 +2561,7 @@ void CL_Startdemos_f (void) for (i=1 ; i= 0x8000 && i < 0x8000+MAX_PRECACHE_MODELS) { + if (*s == '/') + s++; //*sigh* Q_strncpyz(cl.model_name[i-0x8000], s, MAX_QPATH); if (cl.model_name[i-0x8000][0] == '#') { @@ -4125,14 +4142,17 @@ static void CLQ2_ParseConfigString (void) } cl.model_precache[i-0x8000] = NULL; } - else + else if (cl.contentstage) cl.model_precache[i-0x8000] = Mod_ForName (cl.model_name[i-0x8000], MLV_WARN); return; } else if (i >= 0xc000 && i < 0xc000+MAX_PRECACHE_SOUNDS) { + if (*s == '/') + s++; //*sigh* Q_strncpyz(cl.sound_name[i-0xc000], s, MAX_QPATH); - cl.sound_precache[i-0xc000] = S_PrecacheSound (s); + if (cl.contentstage) + cl.sound_precache[i-0xc000] = S_PrecacheSound (s); return; } @@ -4186,6 +4206,8 @@ static void CLQ2_ParseConfigString (void) } else if (i >= Q2CS_MODELS && i < Q2CS_MODELS+Q2MAX_MODELS) { + if (*s == '/') + s++; //*sigh* Q_strncpyz(cl.model_name[i-Q2CS_MODELS], s, MAX_QPATH); if (cl.model_name[i-Q2CS_MODELS][0] == '#') { @@ -4196,13 +4218,16 @@ static void CLQ2_ParseConfigString (void) } cl.model_precache[i-Q2CS_MODELS] = NULL; } - else + else if (cl.contentstage) cl.model_precache[i-Q2CS_MODELS] = Mod_ForName (cl.model_name[i-Q2CS_MODELS], MLV_WARN); } else if (i >= Q2CS_SOUNDS && i < Q2CS_SOUNDS+Q2MAX_SOUNDS) { + if (*s == '/') + s++; //*sigh* Q_strncpyz(cl.sound_name[i-Q2CS_SOUNDS], s, MAX_QPATH); - cl.sound_precache[i-Q2CS_SOUNDS] = S_PrecacheSound (s); + if (cl.contentstage) + cl.sound_precache[i-Q2CS_SOUNDS] = S_PrecacheSound (s); } else if (i >= Q2CS_IMAGES && i < Q2CS_IMAGES+Q2MAX_IMAGES) { @@ -6273,7 +6298,7 @@ static void CL_ParseStuffCmd(char *msg, int destsplit) //this protects stuffcmds cl_dp_csqc_progscrc = atoi(stufftext+13); //NQ servers/mods like spamming this. Its annoying, but we might as well use it if we can, while also muting it. - else if (!strncmp(stufftext, "cl_fullpitch ", 13) || !strncmp(stufftext, "pq_fullpitch ", 13)) + else if (!strncmp(stufftext, "cl_fullpitch ", 13) || !strncmp(stufftext, "pq_fullpitch ", 13)) { if (!cl.haveserverinfo) { @@ -6284,16 +6309,6 @@ static void CL_ParseStuffCmd(char *msg, int destsplit) //this protects stuffcmds } #endif - else if (!strncmp(stufftext, "//querycmd ", 11)) //for servers to check if a command exists or not. - { - COM_Parse(stufftext + 11); - if (Cmd_Exists(com_token)) - { - Cbuf_AddText ("cmd cmdsupported ", RESTRICT_SERVER+destsplit); - Cbuf_AddText (com_token, RESTRICT_SERVER+destsplit); - Cbuf_AddText ("\n", RESTRICT_SERVER+destsplit); - } - } else if (!strncmp(stufftext, "//paknames ", 11)) //so that the client knows what to download... { //there's a couple of prefixes involved etc Q_strncatz(cl.serverpaknames, stufftext+11, sizeof(cl.serverpaknames)); @@ -6325,6 +6340,43 @@ static void CL_ParseStuffCmd(char *msg, int destsplit) //this protects stuffcmds } } } + else if (cls.demoplayback && !strncmp(stufftext, "playdemo ", 9)) + { //some demos (like speed-demos-archive's marathon runs) chain multiple demos with playdemo commands + //these should still chain properly even when the demo is in some archive(like .dz) or subdir + char newdemo[MAX_OSPATH], temp[MAX_OSPATH], *s; + Cmd_TokenizeString(stufftext, false, false); + s = Cmd_Argv(1); + if (strchr(s, ':') || strchr(s, '/') || strchr(s, '\\')) + Q_strncpyz(newdemo, s, sizeof(newdemo)); + else + { + newdemo[0] = 0; + if (cls.lastdemowassystempath) + Q_strncatz(newdemo, "#", sizeof(newdemo)); + Q_strncatz(newdemo, cls.lastdemoname, sizeof(newdemo)); + *COM_SkipPath(newdemo) = 0; + Q_strncatz(newdemo, Cmd_Argv(1), sizeof(newdemo)); + } + + Cbuf_AddText ("playdemo ", RESTRICT_SERVER+destsplit); + Cbuf_AddText (COM_QuotedString(newdemo, temp, sizeof(temp), false), RESTRICT_SERVER+destsplit); + Cbuf_AddText ("\n", RESTRICT_SERVER+destsplit); + } +#ifdef CSQC_DAT + else if (CSQC_StuffCmd(destsplit, stufftext, msg)) + { + } +#endif + else if (!strncmp(stufftext, "//querycmd ", 11)) //for servers to check if a command exists or not. + { + COM_Parse(stufftext + 11); + if (Cmd_Exists(com_token)) + { + Cbuf_AddText ("cmd cmdsupported ", RESTRICT_SERVER+destsplit); + Cbuf_AddText (com_token, RESTRICT_SERVER+destsplit); + Cbuf_AddText ("\n", RESTRICT_SERVER+destsplit); + } + } else if (!strncmp(stufftext, "//exectrigger ", 14)) //so that mods can add whatever 'alias grabbedarmour' or whatever triggers that users might want to script responses for, without errors about unknown commands { COM_Parse(stufftext + 14); @@ -6405,11 +6457,6 @@ static void CL_ParseStuffCmd(char *msg, int destsplit) //this protects stuffcmds Cmd_TokenizeString(stufftext+2, false, false); Plug_Command_f(); } -#endif -#ifdef CSQC_DAT - else if (CSQC_StuffCmd(destsplit, stufftext, msg)) - { - } #endif else { diff --git a/engine/client/client.h b/engine/client/client.h index a4eca133e..6a0dfa46d 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -448,9 +448,10 @@ typedef struct enum { CPNQ_ID, - CPNQ_BJP1, //16bit models, strict 8bit sounds + CPNQ_NEHAHRA, + CPNQ_BJP1, //16bit models, strict 8bit sounds (otherwise based on nehahra) CPNQ_BJP2, //16bit models, strict 16bit sounds - CPNQ_BJP3, //16bit models, flagged 16bit sounds + CPNQ_BJP3, //16bit models, flagged 16bit sounds, 8bit static sounds. CPNQ_FITZ666, /*and rmqe999 protocol*/ CPNQ_DP5, CPNQ_DP6, @@ -504,6 +505,8 @@ typedef struct qboolean demoseeking; float demoseektime; qboolean timedemo; + char lastdemoname[MAX_OSPATH]; + qboolean lastdemowassystempath; vfsfile_t *demoinfile; float td_lastframe; // to meter out one message a frame int td_startframe; // host_framecount at start diff --git a/engine/client/image.c b/engine/client/image.c index 7a3d62d90..03afb9e6d 100644 --- a/engine/client/image.c +++ b/engine/client/image.c @@ -3062,6 +3062,10 @@ static void Image_GenerateMips(struct pendingtextureinfo *mips, unsigned int fla mips->mipcount = mip+1; } return; + case PTI_RGBA8_SRGB: + case PTI_RGBX8_SRGB: + case PTI_BGRA8_SRGB: + case PTI_BGRX8_SRGB: case PTI_RGBA8: case PTI_RGBX8: case PTI_BGRA8: @@ -4161,6 +4165,37 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag //FIXME: fill alpha channel with 255? } + if (vid.srgb /*&& (flags & IF_SRGB)*/ && !(flags & IF_NOSRGB)) + { //most modern editors write srgb images. + //however, that might not be supported. + int nf = PTI_MAX; + switch(mips->encoding) + { + case PTI_RGBA8: nf = PTI_RGBA8_SRGB; break; + case PTI_RGBX8: nf = PTI_RGBX8_SRGB; break; + case PTI_BGRA8: nf = PTI_BGRA8_SRGB; break; + case PTI_BGRX8: nf = PTI_BGRX8_SRGB; break; + default: + if (freedata) + BZ_Free(rgbadata); + return false; + } + if (sh_config.texfmt[nf]) + mips->encoding = nf; + else + { //srgb->linear + int m = mips->mip[0].width*mips->mip[0].height*4; + if (mips->type == PTI_3D) + m *= mips->mip[0].height; + for (i = 0; i < m; i+=4) + { + ((qbyte*)rgbadata)[i+0] = 255*Image_LinearFloatFromsRGBFloat(((qbyte*)rgbadata)[i+0] * (1.0/255)); + ((qbyte*)rgbadata)[i+1] = 255*Image_LinearFloatFromsRGBFloat(((qbyte*)rgbadata)[i+1] * (1.0/255)); + ((qbyte*)rgbadata)[i+2] = 255*Image_LinearFloatFromsRGBFloat(((qbyte*)rgbadata)[i+2] * (1.0/255)); + } + } + } + Image_RoundDimensions(&mips->mip[0].width, &mips->mip[0].height, flags); if (rgbadata) @@ -4170,7 +4205,7 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag else { mips->mip[0].data = BZ_Malloc(((mips->mip[0].width+3)&~3)*mips->mip[0].height*4); - // memset(mips->mip[0].data, 0, mips->mip[0].width*mips->mip[0].height*4); + //FIXME: should be sRGB-aware, but probably not a common path on hardware that can actually do srgb. Image_ResampleTexture(rgbadata, imgwidth, imgheight, mips->mip[0].data, mips->mip[0].width, mips->mip[0].height); if (freedata) BZ_Free(rgbadata); @@ -4241,6 +4276,17 @@ static qboolean Image_LoadRawTexture(texid_t tex, unsigned int flags, void *rawd tex->width = imgwidth; tex->height = imgheight; + tex->flags &= ~IF_SRGB; + switch(mips->encoding) + { + case PTI_RGBA8_SRGB: + case PTI_RGBX8_SRGB: + case PTI_BGRA8_SRGB: + case PTI_BGRX8_SRGB: + tex->flags |= IF_SRGB; + break; + } + if (flags & IF_NOWORKER) Image_LoadTextureMips(tex, mips, 0, 0); else @@ -4786,7 +4832,7 @@ image_t *Image_FindTexture(const char *identifier, const char *subdir, unsigned tex = Hash_Get(&imagetable, identifier); while(tex) { - if (!((tex->flags ^ flags) & (IF_CLAMP|IF_PALETTIZE))) + if (!((tex->flags ^ flags) & (IF_CLAMP|IF_PALETTIZE|IF_PREMULTIPLYALPHA))) { #ifdef PURGEIMAGES if (!strcmp(subdir, tex->subpath?tex->subpath:"")) diff --git a/engine/client/in_generic.c b/engine/client/in_generic.c index 09e1e48bd..aab1e1a20 100644 --- a/engine/client/in_generic.c +++ b/engine/client/in_generic.c @@ -761,8 +761,8 @@ void IN_MoveMouse(struct mouse_s *mouse, float *movements, int pnum, float frame #ifdef QUAKESTATS if (cl.playerview[pnum].statsf[STAT_VIEWZOOM]) { - mouse_x *= cl.playerview[pnum].statsf[STAT_VIEWZOOM]/255.0f; - mouse_y *= cl.playerview[pnum].statsf[STAT_VIEWZOOM]/255.0f; + mouse_x *= cl.playerview[pnum].statsf[STAT_VIEWZOOM]/STAT_VIEWZOOM_SCALE; + mouse_y *= cl.playerview[pnum].statsf[STAT_VIEWZOOM]/STAT_VIEWZOOM_SCALE; } #endif diff --git a/engine/client/m_single.c b/engine/client/m_single.c index 7211e995d..4ee3b5f25 100644 --- a/engine/client/m_single.c +++ b/engine/client/m_single.c @@ -703,15 +703,19 @@ static qboolean M_DemoKey(menucustom_t *control, menu_t *menu, int key, unsigned { extern int shift_down; int extnum; + const char *ext = COM_GetFileExtension(info->selected->name, NULL); for (extnum = 0; extnum < info->numext; extnum++) - if (!stricmp(info->selected->name + strlen(info->selected->name)-4, info->ext[extnum])) + if (!stricmp(ext, info->ext[extnum])) break; if (extnum == info->numext) //wasn't on our list of extensions. extnum = 0; if (!info->command[extnum]) - return true; //FIXME: archives + { //acceptable archive formats + ShowDemoMenu(menu, va("%s/", info->selected->name)); + return true; + } Cbuf_AddText(va("%s \"%s%s\"\n", info->command[extnum], (info->fs->fsroot==FS_SYSTEM)?"#":"", info->selected->name), RESTRICT_LOCAL); if (!shift_down) @@ -745,7 +749,7 @@ static int QDECL DemoAddItem(const char *filename, qofs_t size, time_t modified, if (i == NULL) { for (extnum = 0; extnum < menu->numext; extnum++) - if (!stricmp(filename + strlen(filename)-4, menu->ext[extnum])) + if (!stricmp(COM_GetFileExtension(filename, NULL), menu->ext[extnum])) break; if (extnum == menu->numext) //wasn't on our list of extensions. @@ -950,7 +954,8 @@ static void ShowDemoMenu (menu_t *menu, const char *path) else { Q_snprintfz(match, sizeof(match), "%s*", info->fs->path); - COM_EnumerateFiles(match, DemoAddItem, info); + CL_ListFilesInPackage(NULL, match, DemoAddItem, info, NULL); +// COM_EnumerateFiles(match, DemoAddItem, info); } M_Demo_Flatten(info); } @@ -1012,14 +1017,22 @@ void M_Menu_Demos_f (void) //we don't support them, but if we were to ask quizmo to decode them for us, we could do. //and some archive formats... for the luls +#ifdef PACKAGE_PK3 info->command[info->numext] = NULL; info->ext[info->numext++] = ".zip"; info->command[info->numext] = NULL; info->ext[info->numext++] = ".pk3"; info->command[info->numext] = NULL; info->ext[info->numext++] = ".pk4"; +#endif +#ifdef PACKAGE_Q1PAK info->command[info->numext] = NULL; info->ext[info->numext++] = ".pak"; +#endif +#ifdef PACKAGE_DZIP + info->command[info->numext] = NULL; + info->ext[info->numext++] = ".dz"; +#endif MC_AddWhiteText(menu, 24, 170, 8, "Choose a Demo", false); MC_AddWhiteText(menu, 16, 170, 24, "^Ue01d^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01f", false); diff --git a/engine/client/merged.h b/engine/client/merged.h index 99386a477..109bbf84b 100644 --- a/engine/client/merged.h +++ b/engine/client/merged.h @@ -272,6 +272,9 @@ typedef struct texid_s texid_tf; #define TEXVALID(t) 1 #endif +#define Image_LinearFloatFromsRGBFloat(c) (((c) <= 0.04045f) ? (c) * (1.0f / 12.92f) : (float)pow(((c) + 0.055f)*(1.0f/1.055f), 2.4f)) +#define Image_sRGBFloatFromLinearFloat(c) (((c) < 0.0031308f) ? (c) * 12.92f : 1.055f * (float)pow((c), 1.0f/2.4f) - 0.055f) + struct pendingtextureinfo { enum @@ -280,6 +283,7 @@ struct pendingtextureinfo PTI_3D, PTI_CUBEMAP //mips are packed (to make d3d11 happy) } type; + enum { //these formats are specified as direct byte access @@ -287,6 +291,10 @@ struct pendingtextureinfo PTI_RGBX8, //rgb pad byte ordering PTI_BGRA8, //alpha channel PTI_BGRX8, //no alpha channel + PTI_RGBA8_SRGB, //rgba byte ordering + PTI_RGBX8_SRGB, //rgb pad byte ordering + PTI_BGRA8_SRGB, //alpha channel + PTI_BGRX8_SRGB, //no alpha channel //these formats are specified in native endian order PTI_RGB565, //16bit alphaless format. PTI_RGBA4444, //16bit format (gl) @@ -311,7 +319,7 @@ struct pendingtextureinfo PTI_DEPTH24, PTI_DEPTH32, PTI_DEPTH24_8, - PTI_MAX + PTI_MAX, } encoding; //0 int mipcount; struct diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index a6ccf3cc3..a6f2f6ef9 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -3327,10 +3327,7 @@ static const char *PF_cs_serverkey_internal(const char *keyname) if (!strcmp(keyname, "ip")) { if (cls.demoplayback) - { - extern char lastdemoname[]; - ret = lastdemoname; - } + ret = cls.lastdemoname; else ret = NET_AdrToString(adr, sizeof(adr), &cls.netchan.remote_address); } diff --git a/engine/client/r_d3.c b/engine/client/r_d3.c index 5e3b21f44..a440cb444 100644 --- a/engine/client/r_d3.c +++ b/engine/client/r_d3.c @@ -89,9 +89,9 @@ static void R_BuildDefaultTexnums_Doom3(shader_t *shader) if ((shader->flags & SHADER_HASNORMALMAP) && r_loadbumpmapping) { if (!TEXVALID(tex->bump) && *mapname && (shader->flags & SHADER_HASNORMALMAP)) - tex->bump = R_LoadHiResTexture(va("%s_local", mapname), NULL, imageflags|IF_TRYBUMP); + tex->bump = R_LoadHiResTexture(va("%s_local", mapname), NULL, imageflags|IF_TRYBUMP|IF_NOSRGB); if (!TEXVALID(tex->bump)) - tex->bump = R_LoadHiResTexture(va("%s_local", imagename), subpath, imageflags|IF_TRYBUMP); + tex->bump = R_LoadHiResTexture(va("%s_local", imagename), subpath, imageflags|IF_TRYBUMP|IF_NOSRGB); } } diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index 83a3c1a6a..c65267143 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -3483,6 +3483,28 @@ void Surf_BuildModelLightmaps (model_t *m) int j; unsigned char *src; unsigned char *dst; + + + //fixup surface lightmaps, and paint + for (i=0; inummodelsurfaces; i++) + { + surf = m->surfaces + i + m->firstmodelsurface; + for (j = 0; j < MAXRLIGHTMAPS; j++) + { + if (surf->lightmaptexturenums[j] < m->lightmaps.first) + { + surf->lightmaptexturenums[j] = -1; + continue; + } + if (surf->lightmaptexturenums[j] >= m->lightmaps.first+m->lightmaps.count) + { + surf->lightmaptexturenums[j] = -1; + continue; + } + surf->lightmaptexturenums[j] = surf->lightmaptexturenums[0] - m->lightmaps.first + newfirst; + } + } + if (!m->submodelof) for (i = 0; i < m->lightmaps.count; i++) { diff --git a/engine/client/render.h b/engine/client/render.h index 3f90352f0..3cf1c1c7c 100644 --- a/engine/client/render.h +++ b/engine/client/render.h @@ -399,17 +399,21 @@ enum imageflags IF_NEAREST = 1<<2, //force nearest IF_LINEAR = 1<<3, //force linear IF_UIPIC = 1<<4, //subject to texturemode2d + //IF_DEPTHCMD=1<<5, //Reserved for d3d11 + IF_SRGB = 1<<6, //texture data is srgb /*WARNING: If the above are changed, be sure to change shader pass flags*/ - IF_NOPICMIP = 1<<5, - IF_NOALPHA = 1<<6, /*hint rather than requirement*/ - IF_NOGAMMA = 1<<7, - IF_3DMAP = 1<<8, /*waning - don't test directly*/ - IF_CUBEMAP = 1<<9, /*waning - don't test directly*/ - IF_TEXTYPE = (1<<8) | (1<<9), /*0=2d, 1=3d, 2=cubeface, 3=?*/ - IF_TEXTYPESHIFT = 8, /*0=2d, 1=3d, 2-7=cubeface*/ - IF_MIPCAP = 1<<10, - IF_PREMULTIPLYALPHA = 1<<12, //rgb *= alpha + IF_NOPICMIP = 1<<7, + IF_NOALPHA = 1<<8, /*hint rather than requirement*/ + IF_NOGAMMA = 1<<9, + IF_3DMAP = 1<<10, /*waning - don't test directly*/ + IF_CUBEMAP = 1<<11, /*waning - don't test directly*/ + IF_TEXTYPE = (1<<10) | (1<<11), /*0=2d, 1=3d, 2=cubeface, 3=?*/ + IF_TEXTYPESHIFT = 10, /*0=2d, 1=3d, 2-7=cubeface*/ + IF_MIPCAP = 1<<12, + IF_PREMULTIPLYALPHA = 1<<13, //rgb *= alpha + + IF_NOSRGB = 1<<20, //ignore srgb when loading. this is guarenteed to be linear, for normalmaps etc. IF_PALETTIZE = 1<<21, IF_NOPURGE = 1<<22, diff --git a/engine/client/renderer.c b/engine/client/renderer.c index 29c5b2e88..8c4ea67dc 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -255,7 +255,7 @@ cvar_t vid_multisample = CVARFD ("vid_multisample", "0", cvar_t vid_refreshrate = CVARF ("vid_displayfrequency", "0", CVAR_ARCHIVE | CVAR_RENDERERLATCH); cvar_t vid_srgb = CVARFD ("vid_srgb", "0", - CVAR_ARCHIVE, "The framebuffer should use sRGB colourspace. This has the effect of brightening the screen"); + CVAR_ARCHIVE, "0: Off. Colour blending will be wrong.\n1: Only the framebuffer should use sRGB colourspace, textures and colours will be assumed to be linear. This has the effect of brightening the screen.\n2: Use sRGB extensions/support to ensure that the sh"); cvar_t vid_wndalpha = CVARD ("vid_wndalpha", "1", "When running windowed, specifies the window's transparency level."); //more readable defaults to match conwidth/conheight. cvar_t vid_width = CVARFD ("vid_width", "0", diff --git a/engine/client/vid.h b/engine/client/vid.h index f81ab1490..14a3efc77 100644 --- a/engine/client/vid.h +++ b/engine/client/vid.h @@ -88,6 +88,7 @@ typedef struct unsigned height; /*virtual 2d screen height*/ int numpages; + qboolean srgb; /*we're forcing linear fragment shaders, both inputs and outputs (and not using srgb as a gamma hack)*/ unsigned rotpixelwidth; /*width after rotation in pixels*/ unsigned rotpixelheight; /*pixel after rotation in pixels*/ diff --git a/engine/client/view.c b/engine/client/view.c index d67a5a170..e3aa728ef 100644 --- a/engine/client/view.c +++ b/engine/client/view.c @@ -1170,11 +1170,13 @@ void V_ApplyAFov(playerview_t *pv) float afov = r_refdef.afov; if (!afov) //make sure its sensible. + { afov = scr_fov.value; #ifdef QUAKESTATS - if (pv && pv->statsf[STAT_VIEWZOOM]) - afov *= pv->statsf[STAT_VIEWZOOM]/255.0f; + if (pv && pv->statsf[STAT_VIEWZOOM]) //match dp - viewzoom only happens when defaulted. + afov *= pv->statsf[STAT_VIEWZOOM]/STAT_VIEWZOOM_SCALE; #endif + } afov = bound(0.001, afov, 170); ws = 1; diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index 67ae70987..b8ec1ff7b 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -281,6 +281,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // #define HLCLIENT 7 //we can run HL gamecode (not protocol compatible, set to 6 or 7) // #define HLSERVER 140 //we can run HL gamecode (not protocol compatible, set to 138 or 140) #define NQPROT //server and client are capable of using quake1/netquake protocols. (qw is still prefered. uses the command 'nqconnect') + #define PACKAGE_DZIP //support for the dzip format, common with the speed-demos-archive site // #define WEBSERVER //http server #define FTPSERVER //ftp server #define WEBCLIENT //http clients. @@ -587,6 +588,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #undef QWOVERQ3 #endif +#if !defined(NQPROT) || defined(SERVERONLY) || !defined(AVAIL_ZLIB) || defined(DYNAMIC_ZLIB) + #undef PACKAGE_DZIP +#endif + //fix things a little... #ifdef NPQTV #define NPFTE @@ -981,6 +986,7 @@ STAT_MATCHSTARTTIME = 18, STAT_VIEW2 = 20, #endif STAT_VIEWZOOM = 21, // DP +#define STAT_VIEWZOOM_SCALE 255 //STAT_UNUSED = 22, //STAT_UNUSED = 23, //STAT_UNUSED = 24, diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c index 5c5c68b35..31d21e4c9 100644 --- a/engine/common/com_mesh.c +++ b/engine/common/com_mesh.c @@ -3364,7 +3364,7 @@ static void *Q1MDL_LoadSkins_GL (galiasinfo_t *galias, dmdl_t *pq1inmodel, model if (r_loadbumpmapping) { Q_snprintfz(skinname, sizeof(skinname), "%s_%i_norm.lmp", slash, i); - frames[0].texnums.bump = R_LoadReplacementTexture(skinname, alttexpath, texflags|IF_TRYBUMP, frames[0].texels, outskin->skinwidth, outskin->skinheight, TF_HEIGHT8PAL); + frames[0].texnums.bump = R_LoadReplacementTexture(skinname, alttexpath, texflags|IF_TRYBUMP|IF_NOSRGB, frames[0].texels, outskin->skinwidth, outskin->skinheight, TF_HEIGHT8PAL); } Q_snprintfz(skinname, sizeof(skinname), "%s_%i_shirt.lmp", slash, i); frames[0].texnums.upperoverlay = R_LoadReplacementTexture(skinname, alttexpath, texflags, NULL, outskin->skinwidth, outskin->skinheight, TF_INVALID); diff --git a/engine/common/common.c b/engine/common/common.c index baf8079c4..f4ca66b3a 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -2104,7 +2104,7 @@ void COM_CleanUpPath(char *str) while ((dots = strstr(str, ".."))) { criticize = 0; - for (slash = dots-2; slash >= str; slash--) + for (slash = dots-1; slash >= str; slash--) { if (*slash == '/') { diff --git a/engine/common/common.h b/engine/common/common.h index 72e19f3d0..dc78f69ea 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -599,6 +599,7 @@ void FS_PureMode(int mode, char *purenamelist, char *purecrclist, char *refnamel //recursively tries to open files until it can get a zip. vfsfile_t *CL_OpenFileInPackage(searchpathfuncs_t *search, char *name); +qboolean CL_ListFilesInPackage(searchpathfuncs_t *search, char *name, int (QDECL *func)(const char *fname, qofs_t fsize, time_t mtime, void *parm, searchpathfuncs_t *spath), void *parm, void *recursioninfo); qbyte *QDECL COM_LoadStackFile (const char *path, void *buffer, int bufsize, size_t *fsize); qbyte *COM_LoadTempFile (const char *path, size_t *fsize); diff --git a/engine/common/fs.c b/engine/common/fs.c index c1348e53c..42b3cfbfe 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -1717,6 +1717,7 @@ qboolean FS_NativePath(const char *fname, enum fs_relative relativeto, char *out last = fs_manifest->gamepath[i].path; if (*last == '*') last++; + break; } } if (!last) @@ -1735,6 +1736,7 @@ qboolean FS_NativePath(const char *fname, enum fs_relative relativeto, char *out if (*fs_manifest->gamepath[i].path == '*') continue; last = fs_manifest->gamepath[i].path; + break; } } if (!last) @@ -1753,6 +1755,7 @@ qboolean FS_NativePath(const char *fname, enum fs_relative relativeto, char *out if (*fs_manifest->gamepath[i].path == '*') continue; last = fs_manifest->gamepath[i].path; + break; } } if (!last) @@ -2435,11 +2438,11 @@ void FS_AddHashedPackage(searchpath_t **oldpaths, const char *parentpath, const { if (search->handle->FindFile(search->handle, &loc, pakpath+ptlen+1, NULL)) { - vfs = search->handle->OpenVFS(search->handle, &loc, "r"); + vfs = search->handle->OpenVFS(search->handle, &loc, "rb"); snprintf (lname, sizeof(lname), "%s", lname2); } else if (search->handle->FindFile(search->handle, &loc, pname+ptlen+1, NULL)) - vfs = search->handle->OpenVFS(search->handle, &loc, "r"); + vfs = search->handle->OpenVFS(search->handle, &loc, "rb"); } else { @@ -2594,7 +2597,7 @@ static void FS_AddDataFiles(searchpath_t **oldpaths, const char *purepath, const handle = FS_GetOldPath(oldpaths, pakfile, &keptflags); if (!handle) { - vfs = search->handle->OpenVFS(search->handle, &loc, "r"); + vfs = search->handle->OpenVFS(search->handle, &loc, "rb"); if (!vfs) break; handle = searchpathformats[j].OpenNew (vfs, pakfile, ""); @@ -3018,6 +3021,8 @@ void COM_Gamedir (const char *dir, const struct gamepacks *packagespaths) /*quake requires a few settings for compatibility*/ #define EZQUAKECOMPETITIVE "set ruleset_allow_fbmodels 1\n" #define QCFG "set com_parseutf8 0\nset allow_download_refpackages 0\nset sv_bigcoords \"\"\nmap_autoopenportals 1\n" "sv_port "STRINGIFY(PORT_QWSERVER)" "STRINGIFY(PORT_NQSERVER)"\n" ZFIXHACK EZQUAKECOMPETITIVE +//nehahra has to be weird with extra cvars, and buggy fullbrights. +#define NEHCFG QCFG "set nospr32 0\nset cutscene 1\nalias startmap_sp \"map nehstart\"\nr_fb_bmodels 0\nr_fb_models 0\n" /*stuff that makes dp-only mods work a bit better*/ #define DPCOMPAT QCFG "set _cl_playermodel \"\"\n set dpcompat_set 1\nset dpcompat_corruptglobals 1\nset vid_pixelheight 1\n" /*nexuiz/xonotic has a few quirks/annoyances...*/ @@ -3084,6 +3089,10 @@ const gamemode_info_t gamemode_info[] = { {"-hipnotic", "hipnotic", "FTE-Hipnotic",{"id1/pak0.pak","id1/quake.rc"},QCFG, {"id1", "qw", "hipnotic", "*fte"}, "Quake: Scourge of Armagon"}, {"-rogue", "rogue", "FTE-Rogue", {"id1/pak0.pak","id1/quake.rc"},QCFG, {"id1", "qw", "rogue", "*fte"}, "Quake: Dissolution of Eternity"}, + //various quake-dependant non-standalone mods that require hacks + //quoth needed an extra arg just to enable hipnotic hud drawing, it doesn't actually do anything weird, but most engines have a -quoth arg, so lets have one too. + {"-quoth", "quoth", "FTE-Quake", {"id1/pak0.pak","id1/quake.rc"},QCFG, {"id1", "qw", "quoth", "*fte"}, "Quake: Quoth"}, + {"-nehahra", "nehahra", "FTE-Quake", {"id1/pak0.pak","id1/quake.rc"},NEHCFG, {"id1", "qw", "nehahra", "*fte"}, "Quake: Seal Of Nehahra"}, //various quake-based standalone mods. {"-nexuiz", "nexuiz", "Nexuiz", {"nexuiz.exe"}, NEXCFG, {"data", "*ftedata"}, "Nexuiz"}, {"-xonotic", "xonotic", "Xonotic", {"xonotic.exe"}, NEXCFG, {"data", "*ftedata"}, "Xonotic"}, @@ -3327,6 +3336,113 @@ vfsfile_t *CL_OpenFileInPackage(searchpathfuncs_t *search, char *name) return NULL; } +//some annoying struct+func to prefix the enumerated file name properly. +struct CL_ListFilesInPackageCB_s +{ + char *nameprefix; + size_t nameprefixlen; + + int (QDECL *func)(const char *fname, qofs_t fsize, time_t mtime, void *parm, searchpathfuncs_t *spath); + void *parm; + searchpathfuncs_t *spath; +}; +static int QDECL CL_ListFilesInPackageCB(const char *fname, qofs_t fsize, time_t mtime, void *parm, searchpathfuncs_t *spath) +{ + struct CL_ListFilesInPackageCB_s *cb = parm; + char name[MAX_OSPATH]; + if (cb->nameprefixlen) + { + memcpy(name, cb->nameprefix, cb->nameprefixlen-1); + name[cb->nameprefixlen-1] = '/'; + Q_strncpyz(name+cb->nameprefixlen, fname, sizeof(name)-(cb->nameprefixlen)); + return cb->func(name, fsize, mtime, cb->parm, cb->spath); + } + else + return cb->func(fname, fsize, mtime, cb->parm, cb->spath); +} + +//'small' wrapper to list foo.zip/* to list files within zips that are not part of the gamedir. +//same rules as CL_OpenFileInPackage, except that wildcards should only be in the final part +qboolean CL_ListFilesInPackage(searchpathfuncs_t *search, char *name, int (QDECL *func)(const char *fname, qofs_t fsize, time_t mtime, void *parm, searchpathfuncs_t *spath), void *parm, void *recursioninfo) +{ + int found; + vfsfile_t *f; + flocation_t loc; + char e, *n; + char ext[8]; + char *end; + int i; + qboolean ret = false; + struct CL_ListFilesInPackageCB_s cb; + cb.nameprefix = recursioninfo?recursioninfo:name; + cb.nameprefixlen = name-cb.nameprefix; + cb.func = func; + cb.parm = parm; + + //keep chopping off the last part of the filename until we get an actual package + //once we do, recurse into that package + + end = name + strlen(name); + + while (end > name) + { + e = *end; + *end = 0; + + COM_FileExtension(name, ext, sizeof(ext)); + for (i = 0; i < countof(searchpathformats); i++) + { + if (!searchpathformats[i].extension || !searchpathformats[i].OpenNew) + continue; + if (!strcmp(ext, searchpathformats[i].extension)) + { + loc.search = NULL; + if (search) + found = search->FindFile(search, &loc, name, NULL); + else + found = FS_FLocateFile(name, FSLF_IFFOUND, &loc); + if (found) + { + f = (search?search:loc.search->handle)->OpenVFS(search?search:loc.search->handle, &loc, "rb"); + if (f) + { + searchpathfuncs_t *newsearch = searchpathformats[i].OpenNew(f, name, ""); + if (newsearch) + { + ret = CL_ListFilesInPackage(newsearch, end+1, func, parm, cb.nameprefix); + newsearch->ClosePath(newsearch); + if (ret) + { + *end = e; + return ret; + } + } + else + VFS_CLOSE(f); + } + } + break; + } + } + + n = COM_SkipPath(name); + *end = e; + end = n-1; + } + + //always open the last file properly. + loc.search = NULL; + if (search) + ret = search->EnumerateFiles(search, name, CL_ListFilesInPackageCB, &cb); + else + { + ret = true; + if (ret) + COM_EnumerateFiles(name, CL_ListFilesInPackageCB, &cb); + } + return ret; +} + void FS_PureMode(int puremode, char *purenamelist, char *purecrclist, char *refnamelist, char *refcrclist, int pureseed) { qboolean pureflush; @@ -5930,6 +6046,9 @@ extern searchpathfuncs_t *(QDECL FSDWD_LoadArchive) (vfsfile_t *packhandle, cons #endif void FS_RegisterDefaultFileSystems(void) { +#ifdef PACKAGE_DZIP + FS_RegisterFileSystemType(NULL, "dz", FSDZ_LoadArchive, false); +#endif #ifdef PACKAGE_Q1PAK FS_RegisterFileSystemType(NULL, "pak", FSPAK_LoadArchive, true); #if !defined(_WIN32) && !defined(ANDROID) diff --git a/engine/common/fs.h b/engine/common/fs.h index c2dc08d1e..162923754 100644 --- a/engine/common/fs.h +++ b/engine/common/fs.h @@ -60,6 +60,7 @@ extern searchpathfuncs_t *(QDECL VFSOS_OpenPath) (vfsfile_t *file, const char *d extern searchpathfuncs_t *(QDECL FSZIP_LoadArchive) (vfsfile_t *packhandle, const char *desc, const char *prefix); extern searchpathfuncs_t *(QDECL FSPAK_LoadArchive) (vfsfile_t *packhandle, const char *desc, const char *prefix); extern searchpathfuncs_t *(QDECL FSDWD_LoadArchive) (vfsfile_t *packhandle, const char *desc, const char *prefix); +extern searchpathfuncs_t *(QDECL FSDZ_LoadArchive) (vfsfile_t *file, const char *desc, const char *prefix); vfsfile_t *QDECL VFSOS_Open(const char *osname, const char *mode); vfsfile_t *FS_DecompressGZip(vfsfile_t *infile, vfsfile_t *outfile); diff --git a/engine/common/fs_dzip.c b/engine/common/fs_dzip.c new file mode 100644 index 000000000..f3681387e --- /dev/null +++ b/engine/common/fs_dzip.c @@ -0,0 +1,1484 @@ +/* +Copyright notice from dzip (zlib license): + + (C) 2000-2002 Stefan Schwoon, Nolan Pflug + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Stefan Schwoon Nolan Pflug + schwoon@in.tum.de radix@planetquake.com +*/ +/* +Additionally, portions of this code are copy-righted by id software and provided under the gpl v2 or later. +*/ + +/* +dzip has two primary components: +the first/outer part is that it is some alternative to a .zip, one that stores paks weirdly... +the second part is some entropy differences that just allows zlib to work more effectively, or something. + +I've rewritten the archive/outer part to plug it in to fte more nicely +the demo/inner part should mostly be the same as dzip, just with some minor tweaks to make it thread-safe (the 'dc' pointer stuff, in case that's ever an issue). +*/ + +#include "quakedef.h" +#include "fs.h" + +#ifdef PACKAGE_DZIP + +//handle to a file's metadata +typedef struct +{ + fsbucket_t bucket; + + char name[MAX_QPATH]; + qofs_t filepos; + size_t filelen; //aka: memory size + size_t isize; + size_t csize; + unsigned int ztype; + time_t mtime; + unsigned int subfiles; + + //FIXME: flag files as in paks or whatever. +} mdzfile_t; + +//handle to the archive itself. +typedef struct +{ + searchpathfuncs_t pub; + char descname[MAX_OSPATH]; + int numfiles; + mdzfile_t *files; + + int major_version; + + void *mutex; + vfsfile_t *handle; + unsigned int filepos; //the pos the subfiles left it at (to optimize calls to vfs_seek) + int references; //seeing as all vfiles from a pak file use the parent's vfsfile, we need to keep the parent open until all subfiles are closed. +} dzarchive_t; + +//a file that's actively being read +typedef struct { + vfsfile_t funcs; + size_t length; + size_t currentpos; + + qbyte data[1]; +} vfsdz_t; + +// +// on disk +// +typedef struct +{ + //v1 + unsigned int offset; + unsigned int size; + unsigned int realsize; + unsigned short namelen; + unsigned short pak; + unsigned int crc; + unsigned int type; + + //only in v2 + unsigned int date; + unsigned int intersize; + + //name follows for namelen bytes +} dpackfile_t; + +typedef struct +{ + char id[2]; //DZ + unsigned char major_ver; //2 + unsigned char minor_ver; //9 + int dirofs; + int dirlen; +} dpackheader_t; + + +//defs copied from dzip.h +enum { TYPE_NORMAL, TYPE_DEMV1, TYPE_TXT, TYPE_PAK, TYPE_DZ, TYPE_DEM, TYPE_NEHAHRA, TYPE_DIR, TYPE_STORE }; + +//stuff to decode +enum { + DEM_bad, DEM_nop, DEM_disconnect, DEM_updatestat, DEM_version, + DEM_setview, DEM_sound, DEM_time, DEM_print, DEM_stufftext, + DEM_setangle, DEM_serverinfo, DEM_lightstyle, DEM_updatename, + DEM_updatefrags, DEM_clientdata, DEM_stopsound, DEM_updatecolors, + DEM_particle, DEM_damage, DEM_spawnstatic, DEM_spawnbinary, + DEM_spawnbaseline, DEM_temp_entity, DEM_setpause, DEM_signonnum, + DEM_centerprint, DEM_killedmonster, DEM_foundsecret, + DEM_spawnstaticsound, DEM_intermission, DEM_finale, + DEM_cdtrack, DEM_sellscreen, DEM_cutscene, DZ_longtime, +/* nehahra */ + DEM_showlmp = 35, DEM_hidelmp, DEM_skybox, DZ_showlmp +}; + +//basic types +#define long int //gah! +typedef unsigned int uInt; //gah! +typedef qbyte uchar; + +typedef struct { + uchar voz, pax; + uchar ang0, ang1, ang2; + uchar vel0, vel1, vel2; + long items; + uchar uk10, uk11, invbit; + uchar wpf, av, wpm; + int health; + uchar am, sh, nl, rk, ce, wp; + int force; +} cdata_t; +typedef struct { + uchar modelindex, frame; + uchar colormap, skin; + uchar effects; + uchar ang0, ang1, ang2; + uchar newbit, present, active; + uchar fullbright; /* nehahra */ + int org0, org1, org2; + int od0, od1, od2; + int force; + float alpha; /* nehahra */ +} ent_t; + +//the 'globals' +typedef struct +{ + int dem_decode_type; + qbyte *out; + qbyte *outend; + +#define MAX_ENT 1024 +#define p_blocksize 32768 + + uchar dem_updateframe; + uchar copybaseline; + int maxent, lastent, sble; + int entlink[MAX_ENT]; + long dem_gametime; + long outlen; + long cam0, cam1, cam2; + uchar inblk[p_blocksize], outblk[p_blocksize], *inptr; + cdata_t oldcd, newcd; + ent_t base[MAX_ENT], oldent[MAX_ENT], newent[MAX_ENT]; + +} decodectx_t; + +static void Outfile_Write(decodectx_t *dc, void *outblk, size_t outlen) +{ //throw the data at the file + if (dc->out + outlen <= dc->outend) + { + memcpy(dc->out, outblk, outlen); + dc->out += outlen; + } +} + +static copy_msg(decodectx_t *dc, size_t bytes) +{ //just copy the data over + memcpy(dc->outblk+dc->outlen, dc->inptr, bytes); + dc->outlen += bytes; + dc->inptr += bytes; +} +static insert_msg (decodectx_t *dc, void *data, size_t bytes) +{ + memcpy(dc->outblk+dc->outlen, data, bytes); + dc->outlen += bytes; +} +static discard_msg (decodectx_t *dc, size_t bytes) +{ + dc->inptr += bytes; +} + +#define Outfile_Write(d,b) Outfile_Write(dc,d,b) +#define copy_msg(b) copy_msg(dc,b) +#define insert_msg(d,b) insert_msg(dc,d,b) +#define discard_msg(b) discard_msg(dc,b) +#define dem_decode_type dc->dem_decode_type +#define copybaseline dc->copybaseline +#define maxent dc->maxent +#define lastent dc->lastent +#define sble dc->sble +#define entlink dc->entlink +#define dem_gametime dc->dem_gametime +#define outlen dc->outlen +#define cam0 dc->cam0 +#define cam1 dc->cam1 +#define cam2 dc->cam2 +#define inblk dc->inblk +#define outblk dc->outblk +#define inptr dc->inptr +#define oldcd dc->oldcd +#define newcd dc->newcd +#define base dc->base +#define oldent dc->oldent +#define newent dc->newent +#define dem_updateframe dc->dem_updateframe + +#define GUI //because it disables v1 + +#define getshort(x) LittleShort(*(short*)(x)) +#define getlong(x) LittleLong(*(long*)(x)) +#define getfloat(x) LittleFloat(*(float*)(x)) +#define cnvlong(x) LittleLong(x) + +void dem_copy_ue(decodectx_t *dc) +{ + uchar mask = inptr[0] & 0x7f; + uchar topmask; + int len = 1; + + topmask = (mask & 0x01)? inptr[len++] : 0x00; + if (topmask & 0x40) len += 2; else len++; + if (topmask & 0x04) len++; + if (mask & 0x40) len++; + if (topmask & 0x08) len++; + if (topmask & 0x10) len++; + if (topmask & 0x20) len++; + if (mask & 0x02) len += 2; + if (topmask & 0x01) len++; + if (mask & 0x04) len += 2; + if (mask & 0x10) len++; + if (mask & 0x08) len += 2; + if (topmask & 0x02) len++; +// if (topmask & 0x80) /* this should be a bailout */ +// error("dem_copy_ue(): topmask & 0x80"); + copy_msg(len); +} +const uchar te_size[] = {8, 8, 8, 8, 8, 16, 16, 8, 8, 16, + 8, 8, 10, 16, 8, 8, 14}; + +///////////////////////////////////////////////////////////////////////// +//Start decode.c + +void demx_nop(decodectx_t *dc) +{ + copy_msg(1); +} + +void demx_disconnect(decodectx_t *dc) +{ + copy_msg(1); +} + +void demx_updatestat(decodectx_t *dc) +{ + copy_msg(6); +} + +void demx_version(decodectx_t *dc) +{ + copy_msg(5); +} + +void demx_setview(decodectx_t *dc) +{ + copy_msg(3); +} + +void demx_sound(decodectx_t *dc) +{ + int c, len; + uInt entity; + uchar mask = inptr[1]; + uchar channel; + + if (*inptr > DEM_sound) + { + len = 10; + mask = *inptr & 3; + } + else + len = 11; + if (mask & 0x01) len++; + if (mask & 0x02) len++; + +#ifndef GUI + if (dem_decode_type == TYPE_DEMV1) { copy_msg(len); return; } +#endif + *inptr = DEM_sound; + insert_msg(inptr,1); + + *inptr = mask; + channel = inptr[len-9] & 7; + inptr[len-9] = (inptr[len-9] & 0xf8) + ((2 - channel) & 7); + + if ((entity = getshort(inptr+len-9) >> 3) < MAX_ENT) + { + c = getshort(inptr+len-6); c += newent[entity].org0; + c = cnvlong(c); memcpy(inptr+len-6,&c,2); + c = getshort(inptr+len-4); c += newent[entity].org1; + c = cnvlong(c); memcpy(inptr+len-4,&c,2); + c = getshort(inptr+len-2); c += newent[entity].org2; + c = cnvlong(c); memcpy(inptr+len-2,&c,2); + } + + copy_msg(len); +} + +void demx_longtime(decodectx_t *dc) +{ + long tmp = getlong(inptr+1); + dem_gametime += tmp; + tmp = cnvlong(dem_gametime); + *inptr = DEM_time; + memcpy(inptr+1,&tmp,4); + copy_msg(5); +} + +void demx_time(decodectx_t *dc) +{ + uchar buf[5]; + long tmp = getshort(inptr+1) & 0xffff; + +#ifndef GUI + if (dem_decode_type == TYPE_DEMV1) { demx_longtime(); return; } +#endif + dem_gametime += tmp; + tmp = cnvlong(dem_gametime); + buf[0] = DEM_time; + memcpy(buf+1,&tmp,4); + insert_msg(buf,5); + discard_msg(3); +} + +/* used by lots of msgs */ +void demx_string(decodectx_t *dc) +{ + uchar *ptr = inptr + 1; + while (*ptr++); + copy_msg(ptr-inptr); +} + +void demx_setangle(decodectx_t *dc) +{ + copy_msg(4); +} + +void demx_serverinfo(decodectx_t *dc) +{ + uchar *ptr = inptr + 7; + uchar *start_ptr; + while (*ptr++); + do { + start_ptr = ptr; + while (*ptr++); + } while (ptr - start_ptr > 1); + do { + start_ptr = ptr; + while (*ptr++); + } while (ptr - start_ptr > 1); + copy_msg(ptr-inptr); + sble = 0; +} + +void demx_lightstyle(decodectx_t *dc) +{ + uchar *ptr = inptr + 2; + while (*ptr++); + copy_msg(ptr-inptr); +} + +void demx_updatename(decodectx_t *dc) +{ + uchar *ptr = inptr + 2; + while (*ptr++); + copy_msg(ptr-inptr); +} + +void demx_updatefrags(decodectx_t *dc) +{ + copy_msg(4); +} + +static int bplus(int x, int y) +{ + if (x >= 128) x -= 256; + return y + x; +} + +void create_clientdata_msg(decodectx_t *dc) +{ + uchar buf[32]; + uchar *ptr = buf+3; + int mask = newcd.invbit? 0 : 0x0200; + long tmp; + + buf[0] = DEM_clientdata; + + #define CMADD(x,def,bit,bit2) if (newcd.x != def || newcd.force & bit2)\ + { mask |= bit; *ptr++ = newcd.x; } + + CMADD(voz,22,0x0001,0x0800); + CMADD(pax,0,0x0002,0x1000); + CMADD(ang0,0,0x0004,0x0100); + CMADD(vel0,0,0x0020,0x0001); + CMADD(ang1,0,0x0008,0x0200); + CMADD(vel1,0,0x0040,0x0002); + CMADD(ang2,0,0x0010,0x0400); + CMADD(vel2,0,0x0080,0x0004); + tmp = cnvlong(newcd.items); memcpy(ptr,&tmp,4); ptr += 4; + if (newcd.uk10) mask |= 0x0400; + if (newcd.uk11) mask |= 0x0800; + CMADD(wpf,0,0x1000,0x2000); + CMADD(av,0,0x2000,0x4000); + CMADD(wpm,0,0x4000,0x8000); + tmp = cnvlong(newcd.health); memcpy(ptr,&tmp,2); ptr += 2; + *ptr++ = newcd.am; + *ptr++ = newcd.sh; + *ptr++ = newcd.nl; + *ptr++ = newcd.rk; + *ptr++ = newcd.ce; + *ptr++ = newcd.wp; + mask = cnvlong(mask); + memcpy(buf+1,&mask,2); + insert_msg(buf,ptr-buf); + + oldcd = newcd; +} + +#define CPLUS(x,bit) if (mask & bit) { newcd.x = bplus(*ptr++,oldcd.x); } + +void demx_clientdata(decodectx_t *dc) +{ + uchar *ptr = inptr; + int mask = *ptr++; + + newcd = oldcd; + +#ifndef GUI + if (dem_decode_type == TYPE_DEMV1) { demv1_clientdata(); return; } +#endif + if (mask & 0x08) mask += *ptr++ << 8; + if (mask & 0x8000) mask += *ptr++ << 16; + if (mask & 0x800000) mask += *ptr++ << 24; + + CPLUS(vel2,0x00000001); + CPLUS(vel0,0x00000002); + CPLUS(vel1,0x00000004); + + CPLUS(wpf,0x00000100); + if (mask & 0x00000200) newcd.uk10 = !oldcd.uk10; + CPLUS(ang0,0x00000400); + CPLUS(am,0x00000800); + if (mask & 0x00001000) { newcd.health += getshort(ptr); ptr += 2; } + if (mask & 0x00002000) { newcd.items ^= getlong(ptr); ptr += 4; } + CPLUS(av,0x00004000); + + CPLUS(pax,0x00010000); + CPLUS(sh,0x00020000); + CPLUS(nl,0x00040000); + CPLUS(rk,0x00080000); + CPLUS(wpm,0x00100000); + CPLUS(wp,0x00200000); + if (mask & 0x00400000) newcd.uk11 = !oldcd.uk11; + + CPLUS(voz,0x01000000); + CPLUS(ce,0x02000000); + CPLUS(ang1,0x04000000); + CPLUS(ang2,0x08000000); + if (mask & 0x10000000) newcd.invbit = !oldcd.invbit; + + discard_msg(ptr-inptr); + + if ((*ptr & 0xf0) == 0x50) + { + mask = *ptr++; + if (mask & 0x08) mask |= *ptr++ << 8; + newcd.force ^= mask & 0xff07; + discard_msg(ptr-inptr); + } + + create_clientdata_msg(dc); +} + +void demx_stopsound(decodectx_t *dc) +{ + copy_msg(3); +} + +void demx_updatecolors(decodectx_t *dc) +{ + copy_msg(3); +} + +void demx_particle(decodectx_t *dc) +{ + copy_msg(12); +} + +void demx_damage(decodectx_t *dc) +{ + copy_msg(9); +} + +void demx_spawnstatic(decodectx_t *dc) +{ + copy_msg(14); +} + +void demx_spawnbinary(decodectx_t *dc) +{ + copy_msg(1); +} + +void demx_spawnbaseline(decodectx_t *dc) +{ + uchar buf[16], *ptr = inptr+3; + ent_t ent; + int mask = getshort(inptr+1); + + sble = (sble + (mask & 0x03ff)) % 0x400; + memset(&ent,0,sizeof(ent_t)); + ent.modelindex = *ptr++; + if (mask & 0x0400) ent.frame = *ptr++; + if (mask & 0x0800) ent.colormap = *ptr++; + if (mask & 0x1000) ent.skin = *ptr++; + if (mask & 0x2000) + { + ent.org0 = getshort(ptr); ptr += 2; + ent.org1 = getshort(ptr); ptr += 2; + ent.org2 = getshort(ptr); ptr += 2; + } + if (mask & 0x4000) ent.ang1 = *ptr++; + if (mask & 0x8000) { ent.ang0 = *ptr++; ent.ang2 = *ptr++; } + discard_msg(ptr-inptr); + + buf[0] = DEM_spawnbaseline; + mask = cnvlong(sble); memcpy(buf+1,&mask,2); + buf[3] = ent.modelindex; + buf[4] = ent.frame; + buf[5] = ent.colormap; + buf[6] = ent.skin; + mask = cnvlong(ent.org0); memcpy(buf+7,&mask,2); + buf[9] = ent.ang0; + mask = cnvlong(ent.org1); memcpy(buf+10,&mask,2); + buf[12] = ent.ang1; + mask = cnvlong(ent.org2); memcpy(buf+13,&mask,2); + buf[15] = ent.ang2; + insert_msg(buf,16); + + base[sble] = ent; + copybaseline = 1; +} + +void demx_temp_entity(decodectx_t *dc) +{ + if (inptr[1] == 17) + copy_msg(strlen(inptr + 2) + 17); + else + copy_msg(te_size[inptr[1]]); +} + +void demx_setpause(decodectx_t *dc) +{ + copy_msg(2); +} + +void demx_signonnum(decodectx_t *dc) +{ + copy_msg(2); +} + +void demx_killedmonster(decodectx_t *dc) +{ + copy_msg(1); +} + +void demx_foundsecret(decodectx_t *dc) +{ + copy_msg(1); +} + +void demx_spawnstaticsound(decodectx_t *dc) +{ + copy_msg(10); +} + +void demx_intermission(decodectx_t *dc) +{ + copy_msg(1); +} + +void demx_cdtrack(decodectx_t *dc) +{ + copy_msg(3); +} + +void demx_sellscreen(decodectx_t *dc) +{ + copy_msg(1); +} + +/* nehahra */ +void demx_showlmp(decodectx_t *dc) +{ + uchar *ptr = inptr + 1; + while (*ptr++); + while (*ptr++); + ptr += 2; + *inptr = DEM_showlmp; + copy_msg(ptr-inptr); +} + +void demx_updateentity(decodectx_t *dc) +{ + uchar buf[32], *ptr; + int mask, i, entity; + int baseval = 0, prev; + ent_t n, o; + long tmp; + +#ifndef GUI + if (dem_decode_type == TYPE_DEMV1) { demv1_updateentity(); return; } +#endif + lastent = 0; + for (ptr = inptr+1; *ptr; ptr++) + { + if (*ptr == 0xff) { baseval += 0xfe; continue; } + entity = baseval + *ptr; + newent[entity].active = 1; + while (entlink[lastent] <= entity) lastent = entlink[lastent]; + if (lastent < entity) + { + entlink[entity] = entlink[lastent]; + entlink[lastent] = entity; + } + } + + for (prev = 0, i = entlink[0], ptr++; i < MAX_ENT; i = entlink[i]) + { + newent[i].org0 += newent[i].od0; + newent[i].org1 += newent[i].od1; + newent[i].org2 += newent[i].od2; + + if (!newent[i].active) { prev = i; continue; } + + mask = *ptr++; + + if (mask == 0x80) + { + oldent[i] = newent[i] = base[i]; + entlink[prev] = entlink[i]; + continue; + } + + prev = i; + + if (mask == 0x00) { newent[i].active = 0; continue; } + + if (mask & 0x80) mask += (*ptr++) << 8; + if (mask & 0x8000) mask += (*ptr++) << 16; + + n = newent[i]; + o = oldent[i]; + + if (mask & 0x000001) { n.od2 = bplus(*ptr++,o.od2); + n.org2 = o.org2 + n.od2; } + if (mask & 0x000800) { n.org2 = getshort(ptr); ptr += 2; + n.od2 = n.org2 - o.org2; } + if (mask & 0x000002) { n.od1 = bplus(*ptr++,o.od1); + n.org1 = o.org1 + n.od1; } + if (mask & 0x000400) { n.org1 = getshort(ptr); ptr += 2; + n.od1 = n.org1 - o.org1; } + if (mask & 0x000004) { n.od0 = bplus(*ptr++,o.od0); + n.org0 = o.org0 + n.od0; } + if (mask & 0x000200) { n.org0 = getshort(ptr); ptr += 2; + n.od0 = n.org0 - o.org0; } + + if (mask & 0x000008) n.ang0 = bplus(*ptr++,o.ang0); + if (mask & 0x000010) n.ang1 = bplus(*ptr++,o.ang1); + if (mask & 0x000020) n.ang2 = bplus(*ptr++,o.ang2); + if (mask & 0x000040) n.frame = o.frame+1; + if (mask & 0x000100) n.frame = bplus(*ptr++,o.frame); + + if (mask & 0x001000) n.effects = *ptr++; + if (mask & 0x002000) n.modelindex = *ptr++; + if (mask & 0x004000) n.newbit = !o.newbit; + if (mask & 0x010000) n.colormap = *ptr++; + if (mask & 0x020000) n.skin = *ptr++; + /* nehahra */ + if (mask & 0x040000) { n.alpha = getfloat(ptr); ptr += 4; } + if (mask & 0x080000) n.fullbright = *ptr++; + + newent[i] = n; + } + + if (*ptr == 0x31) + { + ptr++; + while ((mask = getshort(ptr))) + { + ptr += 2; + mask &= 0xffff; + if (mask & 0x8000) mask |= *ptr++ << 16; + entity = mask & 0x3ff; + newent[entity].force ^= mask & 0xfffc00; + } + ptr += 2; + } + + discard_msg(ptr-inptr); + + for (i = entlink[0]; i < MAX_ENT; i = entlink[i]) + { + ent_t n = newent[i], b = base[i]; + + ptr = buf+2; + mask = 0x80; + + if (i > 0xff || (n.force & 0x400000)) + { + tmp = cnvlong(i); + memcpy(ptr,&tmp,2); + ptr += 2; + mask |= 0x4000; + } + else + *ptr++ = i; + + #define BDIFF(x,bit,bit2) \ + if (n.x != b.x || n.force & bit2) \ + { *ptr++ = n.x; mask |= bit; } + + BDIFF(modelindex,0x0400,0x040000); + BDIFF(frame,0x0040,0x4000); + BDIFF(colormap,0x0800,0x080000); + BDIFF(skin,0x1000,0x100000); + BDIFF(effects,0x2000,0x200000); + if (n.org0 != b.org0 || n.force & 0x010000) + { mask |= 0x0002; tmp = cnvlong(n.org0); + memcpy(ptr,&tmp,2); ptr += 2; } + BDIFF(ang0,0x0100,0x0800); + if (n.org1 != b.org1 || n.force & 0x0400) + { mask |= 0x0004; tmp = cnvlong(n.org1); + memcpy(ptr,&tmp,2); ptr += 2; } + BDIFF(ang1,0x0010,0x1000); + if (n.org2 != b.org2 || n.force & 0x020000) + { mask |= 0x0008; tmp = cnvlong(n.org2); + memcpy(ptr,&tmp,2); ptr += 2; } + BDIFF(ang2,0x0200,0x2000); +/* nehahra */ + if (n.force & 0x800000) + { + float f = 1; + + if (n.fullbright) + f = 2; + tmp = cnvlong(*(int *)&f); + memcpy(ptr, &tmp, 4); + tmp = cnvlong(*(int *)&n.alpha); + memcpy(ptr + 4, &tmp, 4); + ptr += 8; + if (f == 2) + { + f = (char)(n.fullbright - 1); + tmp = cnvlong(*(int *)&f); + memcpy(ptr, &tmp, 4); + ptr += 4; + } + mask |= 0x8000; + } + + if (n.newbit) mask |= 0x20; + if (mask & 0xff00) mask |= 0x01; + buf[0] = mask & 0xff; + buf[1] = (mask & 0xff00) >> 8; + if (!(mask & 0x01)) { memcpy(buf+1,buf+2,ptr-buf-2); ptr--; } + insert_msg(buf,ptr-buf); + + oldent[i] = newent[i]; + } + +} + +void (* const demx_message[])(decodectx_t *dc) = { + demx_nop, demx_disconnect, demx_updatestat, demx_version, + demx_setview, demx_sound, demx_time, demx_string, demx_string, + demx_setangle, demx_serverinfo, demx_lightstyle, demx_updatename, + demx_updatefrags, demx_clientdata, demx_stopsound, demx_updatecolors, + demx_particle, demx_damage, demx_spawnstatic, demx_spawnbinary, + demx_spawnbaseline, demx_temp_entity, demx_setpause, demx_signonnum, + demx_string, demx_killedmonster, demx_foundsecret, + demx_spawnstaticsound, demx_intermission, demx_string, + demx_cdtrack, demx_sellscreen, demx_string, demx_longtime, + demx_string, demx_string, demx_showlmp /* nehahra */ +}; + +void dem_uncompress_init (decodectx_t *dc, int type) +{ + dem_decode_type = -type; + memset(&base,0,sizeof(ent_t)*MAX_ENT); + memset(&oldent,0,sizeof(ent_t)*MAX_ENT); + memset(&oldcd,0,sizeof(cdata_t)); + oldcd.voz = 22; + oldcd.items = 0x4001; + entlink[0] = MAX_ENT; + cam0 = cam1 = cam2 = 0; + copybaseline = 0; + dem_gametime = 0; + maxent = 0; + sble = 0; +} + +uInt dem_uncompress_block(decodectx_t *dc) +{ + long a1; + uchar cfields; +#ifdef GUI + int uemask = 0x30, cdmask = 0x40; +#else + int uemask = (dem_decode_type == TYPE_DEMV1)? 0x80 : 0x30; + int cdmask = (dem_decode_type == TYPE_DEMV1)? 0xf0 : 0x40; +#endif + cfields = *inptr++; + + if (cfields & 1) { cam0 += getlong(inptr); inptr += 4; } + if (cfields & 2) { cam1 += getlong(inptr); inptr += 4; } + if (cfields & 4) { cam2 += getlong(inptr); inptr += 4; } + + outlen = 0; + insert_msg(&a1,4); + a1 = cnvlong(cam0); insert_msg(&a1,4); + a1 = cnvlong(cam1); insert_msg(&a1,4); + a1 = cnvlong(cam2); insert_msg(&a1,4); + + dem_updateframe = 0; + while (*inptr) + { + if ((*inptr & 0xf8) == uemask) + demx_updateentity(dc); + else + { +#ifndef GUI + if (dem_updateframe) + { demv1_dxentities(); dem_updateframe = 0; } +#endif + if (*inptr && *inptr <= DZ_showlmp) + demx_message[*inptr - 1](dc); + else if ((*inptr & 0xf0) == cdmask) + demx_clientdata(dc); + else if ((*inptr & 0xf8) == 0x38) + demx_sound(dc); + else if (*inptr >= 0x80) + dem_copy_ue(dc); + else + return 0; + } + } +#ifndef GUI + if (dem_updateframe) demv1_dxentities(); +#endif + outlen -= 16; + outlen = cnvlong(outlen); + memcpy(outblk,&outlen,4); + Outfile_Write(outblk,cnvlong(outlen)+16); + + if (copybaseline) + { + copybaseline = 0; + memcpy(oldent,base,sizeof(ent_t)*MAX_ENT); + memcpy(newent,base,sizeof(ent_t)*MAX_ENT); + } + + return inptr-inblk+1; +} + +uInt dem_uncompress (decodectx_t *dc, uInt maxsize) +{ + uInt blocksize = 0; + inptr = inblk; + if (dem_decode_type < 0) + { + dem_decode_type = -dem_decode_type; + while (inptr[blocksize] != '\n' && blocksize < 12) + blocksize++; + + if (blocksize == 12) /* seriously corrupt! */ + return 0; + + Outfile_Write(inblk, ++blocksize); + inptr += blocksize; + } + while (blocksize < 16000 && blocksize < maxsize) + { + if (*inptr == 0xff) + { + uInt len = getlong(inptr+1); + if (p_blocksize - blocksize - 5 < len) + return blocksize; + Outfile_Write(inptr + 5,len); + blocksize = inptr - inblk + len + 5; + } + else + blocksize = dem_uncompress_block(dc); + if (!blocksize) + return 0; /* corrupt encoding */ + inptr++; + } + return blocksize; +} + + +//End decode.c +///////////////////////////////////////////////////////////////////////// +#undef outlen + +#undef copy_msg +#undef insert_msg +#undef discard_msg +#undef inptr +#undef dem_decode_type +#undef copybaseline +#undef maxent +#undef lastent +#undef sble +#undef entlink +#undef dem_gametime +#undef outlen +#undef cam0 +#undef cam1 +#undef cam2 +#undef inblk +#undef outblk +#undef inptr +#undef oldcd +#undef newcd +#undef base +#undef oldent +#undef newent +#undef dem_updateframe + +#include +//pack mutex must be held for this function. +qboolean FSDZ_ExtractFile(qbyte *out, size_t outsize, dzarchive_t *pack, mdzfile_t *src) +{ + qboolean dedemo = false; + switch(src->ztype) + { + case TYPE_PAK: + { + unsigned int i; + unsigned int dirsize = src->subfiles * 64; + unsigned int diroffset = src->filelen - dirsize; + size_t ofs; + qbyte *ftab = out + diroffset; + out[0] = 'P'; + out[1] = 'A'; + out[2] = 'C'; + out[3] = 'K'; + ((int*)out)[2] = LittleLong(dirsize);//size; + ((int*)out)[1] = LittleLong(src->filelen - dirsize);//offset; + + for (ofs = 12, i = 1; i <= src->subfiles; i++) + { + if (ofs + src[i].filelen > diroffset) + return false; //panic! + FSDZ_ExtractFile(out+ofs, src[i].filelen, pack, src+i); + + Q_strncpyz(ftab, src[i].name, 56); + *(int*)&(ftab[56]) = ofs; + *(int*)&(ftab[60]) = src[i].filelen; + ftab += 64; + + ofs += src[i].filelen; + } + } + return true; + + case TYPE_STORE: //no compression or anything + VFS_SEEK(pack->handle, src->filepos); + return outsize == VFS_READ(pack->handle, out, outsize); + + //not actually a file... we shouldn't be here. + case TYPE_DIR: + return false; + case TYPE_DEMV1: //dz v1 == solid archive. really messy, we don't support them. + return false; + + case TYPE_NORMAL: + case TYPE_TXT: + case TYPE_DZ: //its defined. its weird, but its defined. + case TYPE_DEM: + case TYPE_NEHAHRA: + { + //decodectx_t *dc = NULL; + unsigned char inbuffer[p_blocksize]; + int ret; + size_t inremaining = src->csize; + size_t decompressed = 0; + decodectx_t *dc = NULL; + + z_stream strm = { + inbuffer, + 0, + 0, + + out, + src->isize, + 0 + }; + strm.data_type = Z_UNKNOWN; + + if (src->ztype == TYPE_DEM||src->ztype == TYPE_NEHAHRA) + { + dc = Z_Malloc(sizeof(*dc)); + dc->out = out; + dc->outend = out + outsize; + dem_uncompress_init(dc, src->ztype); + + strm.next_out = dc->inblk; + strm.avail_out = sizeof(dc->inblk); + } + + VFS_SEEK(pack->handle, src->filepos); + + strm.avail_in = 0; + strm.next_in = inbuffer; + + inflateInit(&strm); + + while ((ret=inflate(&strm, Z_SYNC_FLUSH)) != Z_STREAM_END) + { + if (strm.avail_in == 0 || strm.avail_out == 0) + { //keep feeding the beast + if (strm.avail_in == 0) + { + size_t chunk = inremaining; + if (chunk > sizeof(inbuffer)) + chunk = sizeof(inbuffer); + strm.avail_in = VFS_READ(pack->handle, inbuffer, chunk); + inremaining -= strm.avail_in; + strm.next_in = inbuffer; + if (!strm.avail_in) + break; + } + + //and cleaning up its excrement + if (strm.avail_out == 0) + { + if (dc) + { + int chunk = dem_uncompress(dc, strm.next_out - dc->inblk); + int remaining = strm.next_out-(dc->inblk+chunk); + if (!chunk) + break; //made no progress. that's bad + memmove(dc->inblk, dc->inblk+chunk, remaining); + + strm.next_out = dc->inblk+remaining; + strm.avail_out = sizeof(dc->inblk)-remaining; + } + else + break; //eep + } + continue; + } + + //doh, it terminated for no reason + if (ret != Z_STREAM_END) + break; + } + + if (dc) + { + while(1) + { + int chunk = dem_uncompress(dc, strm.next_out - dc->inblk); + int remaining = strm.next_out-(dc->inblk+chunk); + if (!chunk || !remaining) + break; //made no progress. that's bad + memmove(dc->inblk, dc->inblk+chunk, remaining); + strm.next_out = dc->inblk+remaining; + } + Z_Free(dc); + dc = NULL; + } + + inflateEnd(&strm); + return strm.total_out == src->isize && !inremaining && ret == Z_STREAM_END; + } + return false; + + default: //unknown file types can just fail. + return false; + } +} + + +static void QDECL FSDZ_GetPathDetails(searchpathfuncs_t *handle, char *out, size_t outlen) +{ + dzarchive_t *pak = (dzarchive_t*)handle; + + *out = 0; + if (pak->references != 1) + Q_snprintfz(out, outlen, "(%i)", pak->references-1); +} +static void QDECL FSDZ_ClosePath(searchpathfuncs_t *handle) +{ + qboolean stillopen; + dzarchive_t *pak = (void*)handle; + + if (!Sys_LockMutex(pak->mutex)) + return; //ohnoes + stillopen = --pak->references > 0; + Sys_UnlockMutex(pak->mutex); + if (stillopen) + return; //not free yet + + + VFS_CLOSE (pak->handle); + + Sys_DestroyMutex(pak->mutex); + if (pak->files) + Z_Free(pak->files); + Z_Free(pak); +} +static void QDECL FSDZ_BuildHash(searchpathfuncs_t *handle, int depth, void (QDECL *AddFileHash)(int depth, const char *fname, fsbucket_t *filehandle, void *pathhandle)) +{ + dzarchive_t *pak = (void*)handle; + int i; + + for (i = 0; i < pak->numfiles; i++) + { + AddFileHash(depth, pak->files[i].name, &pak->files[i].bucket, &pak->files[i]); + } +} +static unsigned int QDECL FSDZ_FLocate(searchpathfuncs_t *handle, flocation_t *loc, const char *filename, void *hashedresult) +{ + mdzfile_t *pf = hashedresult; + int i; + dzarchive_t *pak = (void*)handle; + +// look through all the pak file elements + + if (pf) + { //is this a pointer to a file in this pak? + if (pf < pak->files || pf > pak->files + pak->numfiles) + return FF_NOTFOUND; //was found in a different path + } + else + { + for (i=0 ; inumfiles ; i++) //look for the file + { + if (!Q_strcasecmp (pak->files[i].name, filename)) + { + pf = &pak->files[i]; + break; + } + } + } + + if (pf) + { + if (loc) + { + loc->fhandle = pf; + snprintf(loc->rawname, sizeof(loc->rawname), "%s", pak->descname); + loc->offset = pf->filepos; + loc->len = pf->filelen; + } + return FF_FOUND; + } + return FF_NOTFOUND; +} +static int QDECL FSDZ_EnumerateFiles (searchpathfuncs_t *handle, const char *match, int (QDECL *func)(const char *, qofs_t, time_t mtime, void *, searchpathfuncs_t *spath), void *parm) +{ + dzarchive_t *pak = (dzarchive_t*)handle; + int num; + + for (num = 0; num<(int)pak->numfiles; num++) + { + if (wildcmp(match, pak->files[num].name)) + { + if (!func(pak->files[num].name, pak->files[num].filelen, pak->files[num].mtime, parm, handle)) + return false; + } + } + + return true; +} + +static int QDECL FSDZ_GeneratePureCRC(searchpathfuncs_t *handle, int seed, int crctype) +{ + dzarchive_t *pak = (void*)handle; + + int result; + int *filecrcs; + int numcrcs=0; + int i; + + filecrcs = BZ_Malloc((pak->numfiles+1)*sizeof(int)); + filecrcs[numcrcs++] = seed; + + for (i = 0; i < pak->numfiles; i++) + { + if (pak->files[i].filelen > 0) + { + filecrcs[numcrcs++] = pak->files[i].filepos ^ pak->files[i].filelen ^ QCRC_Block(pak->files[i].name, sizeof(56)); + } + } + + if (crctype) + result = Com_BlockChecksum(filecrcs, numcrcs*sizeof(int)); + else + result = Com_BlockChecksum(filecrcs+1, (numcrcs-1)*sizeof(int)); + + BZ_Free(filecrcs); + return result; +} + +static int QDECL VFSDZ_ReadBytes (struct vfsfile_s *vfs, void *buffer, int bytestoread) +{ + vfsdz_t *vfsp = (vfsdz_t*)vfs; + + if (bytestoread == 0) + return 0; + + if (vfsp->currentpos + bytestoread > vfsp->length) + bytestoread = vfsp->length - vfsp->currentpos; + if (bytestoread <= 0) + return -1; + + memcpy(buffer, vfsp->data + vfsp->currentpos, bytestoread); + vfsp->currentpos += bytestoread; + + return bytestoread; +} +static int QDECL VFSDZ_WriteBytes (struct vfsfile_s *vfs, const void *buffer, int bytestoread) +{ //not supported. + Sys_Error("Cannot write to dz files\n"); + return 0; +} +static qboolean QDECL VFSDZ_Seek (struct vfsfile_s *vfs, qofs_t pos) +{ + vfsdz_t *vfsp = (vfsdz_t*)vfs; + if (pos > vfsp->length) + return false; + vfsp->currentpos = pos; + + return true; +} +static qofs_t QDECL VFSDZ_Tell (struct vfsfile_s *vfs) +{ + vfsdz_t *vfsp = (vfsdz_t*)vfs; + return vfsp->currentpos; +} +static qofs_t QDECL VFSDZ_GetLen (struct vfsfile_s *vfs) +{ + vfsdz_t *vfsp = (vfsdz_t*)vfs; + return vfsp->length; +} +static qboolean QDECL VFSDZ_Close(vfsfile_t *vfs) +{ + vfsdz_t *vfsp = (vfsdz_t*)vfs; + Z_Free(vfsp); //free ourselves. + return true; +} +static vfsfile_t *QDECL FSDZ_OpenVFS(searchpathfuncs_t *handle, flocation_t *loc, const char *mode) +{ + dzarchive_t *pack = (dzarchive_t*)handle; + vfsdz_t *vfs; + mdzfile_t *pf = loc->fhandle; + + if (strcmp(mode, "rb") && strcmp(mode, "r") && strcmp(mode, "rt")) + return NULL; //urm, unable to write/append + + vfs = Z_Malloc(sizeof(vfsdz_t) + pf->filelen); + + if (!Sys_LockMutex(pack->mutex)) + { + Z_Free(vfs); + return NULL; + } + + if (!FSDZ_ExtractFile(vfs->data, pf->filelen, pack, pf)) + { + Sys_UnlockMutex(pack->mutex); + Z_Free(vfs); + return NULL; + } + Sys_UnlockMutex(pack->mutex); + + vfs->length = loc->len; + vfs->currentpos = 0; + +#ifdef _DEBUG + Q_strncpyz(vfs->funcs.dbgname, pf->name, sizeof(vfs->funcs.dbgname)); +#endif + vfs->funcs.Close = VFSDZ_Close; + vfs->funcs.GetLen = VFSDZ_GetLen; + vfs->funcs.ReadBytes = VFSDZ_ReadBytes; + vfs->funcs.Seek = VFSDZ_Seek; + vfs->funcs.Tell = VFSDZ_Tell; + vfs->funcs.WriteBytes = VFSDZ_WriteBytes; //not supported + + return (vfsfile_t *)vfs; +} + +static void QDECL FSDZ_ReadFile(searchpathfuncs_t *handle, flocation_t *loc, char *buffer) +{ + vfsfile_t *f; + f = FSDZ_OpenVFS(handle, loc, "rb"); + if (!f) //err... + return; + VFS_READ(f, buffer, loc->len); + VFS_CLOSE(f); +} + + +/* +================= +COM_LoadPackFile + +Takes an explicit (not game tree related) path to a pak file. + +Loads the header and directory, adding the files at the beginning +of the list so they override previous pack files. +================= +*/ +searchpathfuncs_t *QDECL FSDZ_LoadArchive (vfsfile_t *file, const char *desc, const char *prefix) +{ + dpackheader_t header; + int i; +// int j; + mdzfile_t *newfiles; + int numpackfiles; + dzarchive_t *pack; + vfsfile_t *packhandle; + dpackfile_t info; + int read; + struct tm t; +// unsigned short crc; + + memset(&t, 0, sizeof(t)); + + packhandle = file; + if (packhandle == NULL) + return NULL; + + if (prefix && *prefix) + return NULL; //not supported at this time + + read = VFS_READ(packhandle, &header, sizeof(header)); + if (read < sizeof(header) || header.id[0] != 'D' || header.id[1] != 'Z') + { + Con_Printf("%s is not a dz - %c%c\n", desc); + return NULL; + } + if (header.major_ver > 2/* || (header.major_ver == 2 && header.minor_ver > 9)*/) + { //ignore minor versions, assume they've got only additions. + Con_Printf("%s uses too recent a version. %i.%i > 2.9\n", desc, header.major_ver, header.minor_ver); + return NULL; + } + if (header.major_ver < 2) + { + Con_Printf("%s uses too old a version. %i.%i < 2.0\n", desc, header.major_ver, header.minor_ver); + return NULL; + } + header.dirofs = LittleLong (header.dirofs); + header.dirlen = LittleLong (header.dirlen); + + numpackfiles = header.dirlen; + + newfiles = (mdzfile_t*)Z_Malloc (numpackfiles * sizeof(mdzfile_t)); + + VFS_SEEK(packhandle, header.dirofs); + + pack = (dzarchive_t*)Z_Malloc (sizeof (dzarchive_t)); +// parse the directory + for (i=0 ; i= sizeof(newfiles[i].name) || info.type==TYPE_PAK) + { + //ignore dzip's paks. this allows us to just directly read the demos inside without extra subdirs. + VFS_SEEK(packhandle, VFS_TELL(packhandle)+info.namelen); + numpackfiles--; + i--; //counter the ++ + continue; + } + newfiles[i].name[info.namelen] = 0; //paranoid + if (info.namelen != VFS_READ(packhandle, &newfiles[i].name, info.namelen)) + { + Con_Printf("DZIP file table truncated, only found %i files out of %i\n", i, numpackfiles); + numpackfiles = i; + break; + } + COM_CleanUpPath(newfiles[i].name); //this fixes silly people using backslashes in paths. + newfiles[i].filepos = LittleLong(info.offset); + newfiles[i].filelen = LittleLong(info.realsize); + newfiles[i].isize = LittleLong(info.intersize); + newfiles[i].csize = LittleLong(info.size); + newfiles[i].ztype = info.type; + newfiles[i].subfiles = (unsigned short)LittleShort(info.pak); + + //lame, but whatever + //fixme: make sure they're all correct... + t.tm_year = ((info.date >> 25) & 0x7f) + 1980 - 1900; + t.tm_mon = ((info.date >> 21) & 0x0f); + t.tm_mday = (info.date >> 16) & 0x1f; + t.tm_hour = ((info.date >> 11) & 0x1f)-1; + t.tm_min = (info.date >> 5) & 0x3f; + t.tm_sec = (info.date & 0x1f) << 1; + newfiles[i].mtime = mktime(&t); + } + + strcpy (pack->descname, desc); + pack->handle = packhandle; + pack->numfiles = numpackfiles; + pack->files = newfiles; + pack->filepos = 0; + VFS_SEEK(packhandle, pack->filepos); + + pack->references++; + + pack->mutex = Sys_CreateMutex(); + +// Con_TPrintf ("Added packfile %s (%i files)\n", desc, numpackfiles); + + pack->pub.fsver = FSVER; + pack->pub.GetPathDetails = FSDZ_GetPathDetails; + pack->pub.ClosePath = FSDZ_ClosePath; + pack->pub.BuildHash = FSDZ_BuildHash; + pack->pub.FindFile = FSDZ_FLocate; + pack->pub.ReadFile = FSDZ_ReadFile; + pack->pub.EnumerateFiles = FSDZ_EnumerateFiles; + pack->pub.GeneratePureCRC = FSDZ_GeneratePureCRC; + pack->pub.OpenVFS = FSDZ_OpenVFS; + return &pack->pub; +} + +#endif diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index d7720cf8a..89dc82a21 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -2882,6 +2882,7 @@ static qboolean CModQ3_LoadRFaces (model_t *mod, qbyte *mod_base, lump_t *l) mod->surfaces = out; mod->numsurfaces = count; + mod->lightmaps.first = 0; for (surfnum = 0; surfnum < count; surfnum++, out++, in++, pl++) { diff --git a/engine/d3d/d3d11_backend.c b/engine/d3d/d3d11_backend.c index 674591ef4..9568baf25 100644 --- a/engine/d3d/d3d11_backend.c +++ b/engine/d3d/d3d11_backend.c @@ -242,7 +242,7 @@ typedef struct unsigned int texflags[MAX_TMUS]; unsigned int tmuflags[MAX_TMUS]; ID3D11SamplerState *cursamplerstate[MAX_TMUS]; - ID3D11SamplerState *sampstate[(SHADER_PASS_IMAGE_FLAGS|SHADER_PASS_DEPTHCMP)+1]; + ID3D11SamplerState *sampstate[SHADER_PASS_IMAGE_FLAGS_D3D11+1]; ID3D11DepthStencilState *depthstates[1u<<4]; //index, its fairly short. blendstates_t *blendstates; //list. this could get big. @@ -305,7 +305,7 @@ void D3D11_UpdateFiltering(image_t *imagelist, int filtermip[3], int filterpic[3 { D3D11_SAMPLER_DESC sampdesc; int flags; - for (flags = 0; flags <= (SHADER_PASS_IMAGE_FLAGS|SHADER_PASS_DEPTHCMP); flags++) + for (flags = 0; flags <= (SHADER_PASS_IMAGE_FLAGS_D3D11); flags++) { int *filter; sampdesc.Filter = 0; @@ -386,7 +386,7 @@ static void BE_DestroyVariousStates(void) if (d3ddevctx && i) ID3D11DeviceContext_PSSetSamplers(d3ddevctx, 0, i, shaderstate.cursamplerstate); - for (flags = 0; flags <= (SHADER_PASS_IMAGE_FLAGS|SHADER_PASS_DEPTHCMP); flags++) + for (flags = 0; flags <= SHADER_PASS_IMAGE_FLAGS_D3D11; flags++) { if (shaderstate.sampstate[flags]) ID3D11SamplerState_Release(shaderstate.sampstate[flags]); @@ -459,7 +459,7 @@ static void BE_ApplyTMUState(unsigned int tu, unsigned int flags) { ID3D11SamplerState *nstate; - flags = (flags & (SHADER_PASS_IMAGE_FLAGS|SHADER_PASS_DEPTHCMP)); + flags = (flags & SHADER_PASS_IMAGE_FLAGS_D3D11); flags |= shaderstate.texflags[tu]; nstate = shaderstate.sampstate[flags]; if (nstate != shaderstate.cursamplerstate[tu]) @@ -958,7 +958,7 @@ static void BindTexture(unsigned int tu, const texid_t id) shaderstate.textureschanged = true; shaderstate.pendingtextures[tu] = view; if (id) - shaderstate.texflags[tu] = id->flags&SHADER_PASS_IMAGE_FLAGS; + shaderstate.texflags[tu] = id->flags&SHADER_PASS_IMAGE_FLAGS_D3D11; } } diff --git a/engine/d3d/d3d11_image.c b/engine/d3d/d3d11_image.c index 71434d49b..268b23b7b 100644 --- a/engine/d3d/d3d11_image.c +++ b/engine/d3d/d3d11_image.c @@ -213,6 +213,23 @@ qboolean D3D11_LoadTextureMips(image_t *tex, struct pendingtextureinfo *mips) bytesperpixel = 4; break; + case PTI_RGBA8_SRGB: + tdesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + bytesperpixel = 4; + break; + case PTI_RGBX8_SRGB: //d3d11 has no alphaless format. be sure to proprly disable alpha in the shader. + tdesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + bytesperpixel = 4; + break; + case PTI_BGRA8_SRGB: + tdesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; + bytesperpixel = 4; + break; + case PTI_BGRX8_SRGB: + tdesc.Format = DXGI_FORMAT_B8G8R8X8_UNORM_SRGB; + bytesperpixel = 4; + break; + case PTI_S3RGB1: //d3d11 provides no way to disable alpha with dxt1. be sure to proprly disable alpha in the shader. case PTI_S3RGBA1: tdesc.Format = DXGI_FORMAT_BC1_UNORM; diff --git a/engine/d3d/d3d8_backend.c b/engine/d3d/d3d8_backend.c index f2d2d0d0b..2bc1f1ece 100644 --- a/engine/d3d/d3d8_backend.c +++ b/engine/d3d/d3d8_backend.c @@ -535,7 +535,7 @@ static void BindTexture(unsigned int tu, texid_t tex) if (tex) { dt = tex->ptr; - shaderstate.curtexflags[tu] = tex->flags & SHADER_PASS_IMAGE_FLAGS; + shaderstate.curtexflags[tu] = tex->flags & SHADER_PASS_IMAGE_FLAGS_D3D8; } else dt = NULL; diff --git a/engine/d3d/d3d_backend.c b/engine/d3d/d3d_backend.c index 7020b804d..faa421843 100644 --- a/engine/d3d/d3d_backend.c +++ b/engine/d3d/d3d_backend.c @@ -53,6 +53,7 @@ extern LPDIRECT3DDEVICE9 pD3DDev9; #define MAX_TC_TMUS 4 +extern texid_t r_whiteimage; extern float d3d_trueprojection[16]; static void BE_RotateForEntity (const entity_t *e, const model_t *mod); @@ -265,6 +266,8 @@ static void BE_ApplyTMUState(unsigned int tu, unsigned int flags) unsigned int delta = shaderstate.tmuflags[tu] ^ flags; if (!delta) return; + if (delta & SHADER_PASS_SRGB) + IDirect3DDevice9_SetSamplerState(pD3DDev9, tu, D3DSAMP_SRGBTEXTURE, (flags & SHADER_PASS_SRGB)?TRUE:FALSE); if (delta & SHADER_PASS_CLAMP) { if (flags & SHADER_PASS_CLAMP) @@ -715,11 +718,14 @@ static unsigned int allocindexbuffer(void **dest, unsigned int entries) static void BindTexture(unsigned int tu, texid_t tex) { + extern texid_t r_whiteimage; IDirect3DTexture9 *dt; if (tex) { dt = tex->ptr; - shaderstate.curtexflags[tu] = tex->flags & SHADER_PASS_IMAGE_FLAGS; + if (!dt) + dt = r_whiteimage->ptr; + shaderstate.curtexflags[tu] = tex->flags & SHADER_PASS_IMAGE_FLAGS_D3D9; } else dt = NULL; diff --git a/engine/d3d/d3d_image.c b/engine/d3d/d3d_image.c index 923ab2e05..b2b2bda96 100644 --- a/engine/d3d/d3d_image.c +++ b/engine/d3d/d3d_image.c @@ -48,19 +48,23 @@ qboolean D3D9_LoadTextureMips(image_t *tex, struct pendingtextureinfo *mips) pixelsize = 2; fmt = D3DFMT_A1R5G5B5; break; + case PTI_RGBA8_SRGB: case PTI_RGBA8: // fmt = D3DFMT_A8B8G8R8; /*how do we check fmt = D3DFMT_A8R8G8B8; swap = true; break; + case PTI_RGBX8_SRGB: case PTI_RGBX8: // fmt = D3DFMT_X8B8G8R8; fmt = D3DFMT_X8R8G8B8; swap = true; break; + case PTI_BGRA8_SRGB: case PTI_BGRA8: fmt = D3DFMT_A8R8G8B8; break; + case PTI_BGRX8_SRGB: case PTI_BGRX8: fmt = D3DFMT_X8R8G8B8; break; diff --git a/engine/d3d/d3d_shader.c b/engine/d3d/d3d_shader.c index fcab1d810..bc81beb6d 100644 --- a/engine/d3d/d3d_shader.c +++ b/engine/d3d/d3d_shader.c @@ -473,15 +473,6 @@ void D3D9Shader_Init(void) sh_config.nv_tex_env_combine4 = 1; sh_config.env_add = 1; - //FIXME: check caps - sh_config.texfmt[PTI_RGBX8] = true; //fixme: shouldn't support - sh_config.texfmt[PTI_RGBA8] = true; //fixme: shouldn't support - sh_config.texfmt[PTI_BGRX8] = true; - sh_config.texfmt[PTI_BGRA8] = true; - sh_config.texfmt[PTI_RGB565] = true; - sh_config.texfmt[PTI_ARGB1555] = true; - sh_config.texfmt[PTI_ARGB4444] = true; - sh_config.can_mipcap = true; //at creation time, I think. IDirect3DDevice9_GetDeviceCaps(pD3DDev9, &caps); diff --git a/engine/d3d/vid_d3d.c b/engine/d3d/vid_d3d.c index 15e9022b0..15ad9a5ed 100644 --- a/engine/d3d/vid_d3d.c +++ b/engine/d3d/vid_d3d.c @@ -14,6 +14,9 @@ #endif #include +#ifndef D3DPRESENT_LINEAR_CONTENT +#define D3DPRESENT_LINEAR_CONTENT 2 +#endif //#pragma comment(lib, "../libs/dxsdk9/lib/d3d9.lib") @@ -65,6 +68,7 @@ extern qboolean scr_con_forcedraw; static qboolean d3d_resized; extern cvar_t vid_hardwaregamma; +extern cvar_t vid_srgb; //sound/error code needs this @@ -434,7 +438,15 @@ static LRESULT WINAPI D3D9_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA static void D3D9_VID_SwapBuffers(void) { - IDirect3DDevice9_Present(pD3DDev9, NULL, NULL, NULL, NULL); + if (d3dpp.Windowed && (vid_srgb.ival==1 || vid.srgb)) + { + IDirect3DSwapChain9 *swapchain; + IDirect3DDevice9_GetSwapChain(pD3DDev9, 0, &swapchain); + IDirect3DSwapChain9_Present(swapchain, NULL, NULL, NULL, NULL, D3DPRESENT_LINEAR_CONTENT); + IDirect3DSwapChain9_Release(swapchain); + } + else + IDirect3DDevice9_Present(pD3DDev9, NULL, NULL, NULL, NULL); } static void resetD3D9(void) @@ -452,7 +464,7 @@ static void resetD3D9(void) IDirect3DDevice9_BeginScene(pD3DDev9); IDirect3DDevice9_Clear(pD3DDev9, 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0); IDirect3DDevice9_EndScene(pD3DDev9); - IDirect3DDevice9_Present(pD3DDev9, NULL, NULL, NULL, NULL); + D3D9_VID_SwapBuffers(); @@ -587,6 +599,36 @@ static qboolean initD3D9Device(HWND hWnd, rendererstate_t *info, unsigned int de MoveWindow(d3dpp.hDeviceWindow, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, false); } D3D9Shader_Init(); + + { + int i; + struct { + unsigned int pti; + unsigned int d3d9; + unsigned int usage; + } fmts[] = + { + {PTI_BGRX8, D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_FILTER}, + {PTI_BGRA8, D3DFMT_A8R8G8B8, D3DUSAGE_QUERY_FILTER}, + {PTI_RGB565, D3DFMT_R5G6B5, D3DUSAGE_QUERY_FILTER}, + {PTI_ARGB1555, D3DFMT_A1R5G5B5, D3DUSAGE_QUERY_FILTER}, + {PTI_ARGB4444, D3DFMT_A4R4G4B4, D3DUSAGE_QUERY_FILTER}, + + {PTI_BGRX8_SRGB, D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_SRGBREAD}, + {PTI_BGRA8_SRGB, D3DFMT_A8R8G8B8, D3DUSAGE_QUERY_SRGBREAD}, + }; + for (i = 0; i < countof(fmts); i++) + if (SUCCEEDED(IDirect3D9_CheckDeviceFormat(pD3D, devno, devtype, d3dpp.BackBufferFormat, fmts[i].usage, D3DRTYPE_TEXTURE, fmts[i].d3d9))) + sh_config.texfmt[fmts[i].pti] = true; + } + + //fixme: the engine kinda insists on rgba textures, which d3d9 does NOT support. + //we currently have some swapping, so these load, just slowly. + sh_config.texfmt[PTI_RGBX8] = sh_config.texfmt[PTI_BGRX8]; + sh_config.texfmt[PTI_RGBA8] = sh_config.texfmt[PTI_BGRA8]; + sh_config.texfmt[PTI_RGBX8_SRGB] = sh_config.texfmt[PTI_BGRX8_SRGB]; + sh_config.texfmt[PTI_RGBA8_SRGB] = sh_config.texfmt[PTI_BGRA8_SRGB]; + return true; //successful } else @@ -726,7 +768,7 @@ static qboolean D3D9_VID_Init(rendererstate_t *info, unsigned char *palette) IDirect3DDevice9_Clear(pD3DDev9, 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0); IDirect3DDevice9_BeginScene(pD3DDev9); IDirect3DDevice9_EndScene(pD3DDev9); - IDirect3DDevice9_Present(pD3DDev9, NULL, NULL, NULL, NULL); + D3D9_VID_SwapBuffers(); D3D9_Set2D(); @@ -947,6 +989,12 @@ static qboolean (D3D9_SCR_UpdateScreen) (void) Cvar_ForceCallback(&vid_conwidth); } + if (vid_srgb.modified) + { + vid_srgb.modified = false; + IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_SRGBWRITEENABLE, (vid_srgb.ival==1 || vid.srgb) && !d3dpp.Windowed); + } + switch (IDirect3DDevice9_TestCooperativeLevel(pD3DDev9)) { case D3DERR_DEVICELOST: @@ -992,7 +1040,7 @@ static qboolean (D3D9_SCR_UpdateScreen) (void) if (R2D_Flush) R2D_Flush(); IDirect3DDevice9_EndScene(pD3DDev9); - IDirect3DDevice9_Present(pD3DDev9, NULL, NULL, NULL, NULL); + D3D9_VID_SwapBuffers(); return true; } } @@ -1031,7 +1079,7 @@ static qboolean (D3D9_SCR_UpdateScreen) (void) Media_RecordFrame(); // R2D_BrightenScreen(); IDirect3DDevice9_EndScene(pD3DDev9); - IDirect3DDevice9_Present(pD3DDev9, NULL, NULL, NULL, NULL); + D3D9_VID_SwapBuffers(); return true; } @@ -1091,7 +1139,7 @@ static qboolean (D3D9_SCR_UpdateScreen) (void) d3d9error(IDirect3DDevice9_EndScene(pD3DDev9)); { RSpeedMark(); - d3d9error(IDirect3DDevice9_Present(pD3DDev9, NULL, NULL, NULL, NULL)); + D3D9_VID_SwapBuffers(); RSpeedEnd(RSPEED_PRESENT); } @@ -1111,6 +1159,9 @@ static qboolean (D3D9_SCR_UpdateScreen) (void) static void (D3D9_Draw_Init) (void) { + vid.srgb = vid_srgb.ival>1; + IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_SRGBWRITEENABLE, (vid_srgb.ival==1 || vid.srgb) && !d3dpp.Windowed); + R2D_Init(); } static void (D3D9_Draw_Shutdown) (void) @@ -1245,7 +1296,6 @@ static void (D3D9_R_RenderView) (void) D3D9_Set2D (); } -void (D3D9_R_NewMap) (void); void (D3D9_R_PreNewMap) (void); void (D3D9_R_PushDlights) (void); diff --git a/engine/d3d/vid_d3d11.c b/engine/d3d/vid_d3d11.c index c09b413c9..22606b235 100644 --- a/engine/d3d/vid_d3d11.c +++ b/engine/d3d/vid_d3d11.c @@ -845,12 +845,16 @@ static qboolean initD3D11Device(HWND hWnd, rendererstate_t *info, PFN_D3D11_CREA //11.1 formats #define DXGI_FORMAT_B4G4R4A4_UNORM 115 + //why does d3d11 have no rgbx format? anyone else think that weird? ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_B5G6R5_UNORM, &support); sh_config.texfmt[PTI_RGB565] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_B5G5R5A1_UNORM, &support); sh_config.texfmt[PTI_ARGB1555] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_B4G4R4A4_UNORM, &support); sh_config.texfmt[PTI_ARGB4444] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_R8G8B8A8_UNORM, &support); sh_config.texfmt[PTI_RGBA8] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_B8G8R8A8_UNORM, &support); sh_config.texfmt[PTI_BGRA8] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_B8G8R8X8_UNORM, &support); sh_config.texfmt[PTI_BGRX8] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, &support); sh_config.texfmt[PTI_RGBA8_SRGB] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, &support); sh_config.texfmt[PTI_BGRA8_SRGB] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); + ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_B8G8R8X8_UNORM_SRGB, &support); sh_config.texfmt[PTI_BGRX8_SRGB] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC1_UNORM, &support); sh_config.texfmt[PTI_S3RGBA1] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC2_UNORM, &support); sh_config.texfmt[PTI_S3RGBA3] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); ID3D11Device_CheckFormatSupport(pD3DDev11, DXGI_FORMAT_BC3_UNORM, &support); sh_config.texfmt[PTI_S3RGBA5] = !!(support & D3D11_FORMAT_SUPPORT_TEXTURE2D); @@ -859,6 +863,8 @@ static qboolean initD3D11Device(HWND hWnd, rendererstate_t *info, PFN_D3D11_CREA sh_config.texfmt[PTI_RGBX8] = sh_config.texfmt[PTI_RGBA8]; sh_config.texfmt[PTI_S3RGB1] = sh_config.texfmt[PTI_S3RGBA1]; + vid.srgb = info->srgb>1; + vid.numpages = scd.BufferCount; if (!D3D11Shader_Init(flevel)) { diff --git a/engine/d3d/vid_d3d8.c b/engine/d3d/vid_d3d8.c index 40ee276fa..044827c35 100644 --- a/engine/d3d/vid_d3d8.c +++ b/engine/d3d/vid_d3d8.c @@ -734,6 +734,7 @@ static qboolean D3D8_VID_Init(rendererstate_t *info, unsigned char *palette) vid.pixelheight = 480; vid.width = 640; vid.height = 480; + vid.srgb = false; vid_initializing = false; @@ -820,6 +821,8 @@ static qboolean D3D8_VID_Init(rendererstate_t *info, unsigned char *palette) vid.width = width; vid.height = height; + vid.srgb = false; + vid_initializing = false; IDirect3DDevice8_SetRenderState(pD3DDev8, D3DRS_LIGHTING, FALSE); @@ -1341,7 +1344,6 @@ static void (D3D8_R_RenderView) (void) D3D8_Set2D (); } -void (D3D8_R_NewMap) (void); void (D3D8_R_PreNewMap) (void); void (D3D8_R_PushDlights) (void); diff --git a/engine/dotnet2005/ftequake.vcproj b/engine/dotnet2005/ftequake.vcproj index 029772092..4e92e8b40 100644 --- a/engine/dotnet2005/ftequake.vcproj +++ b/engine/dotnet2005/ftequake.vcproj @@ -27505,7 +27505,6 @@ + + diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index 4c14bebb9..44b21ecd0 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -4984,7 +4984,7 @@ static void BE_UpdateLightmaps(void) lightmapinfo_t *lm; int lmidx; int glformat, gltype; - int internalformat = GL_RGBA; + int internalformat = /*vid.srgb?GL_SRGB8_ALPHA8_EXT:*/GL_RGBA; switch (lightmap_fmt) { case TF_INVALID: return; diff --git a/engine/gl/gl_draw.c b/engine/gl/gl_draw.c index 293215276..8857daf08 100644 --- a/engine/gl/gl_draw.c +++ b/engine/gl/gl_draw.c @@ -66,6 +66,18 @@ void GLDraw_Init (void) if (gl_config.gles && gl_config.glversion < 3.0) r_softwarebanding = false; + if (!gl_config.gles) + { + extern cvar_t vid_srgb; + GLint srgb; + qglGetIntegerv(GL_FRAMEBUFFER_SRGB_CAPABLE, &srgb); + vid.srgb = vid_srgb.ival>1 && srgb; + if (vid.srgb) + qglEnable(GL_FRAMEBUFFER_SRGB); + } + else + vid.srgb = false; + R2D_Init(); qglDisable(GL_SCISSOR_TEST); @@ -381,8 +393,8 @@ qboolean GL_LoadTextureMips(texid_t tex, struct pendingtextureinfo *mips) case PTI_BGRX8: qglTexImage3D(targface, i, GL_RGB, size, size, size, 0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, mips->mip[i].data); break; - case PTI_BGRA8: default: + case PTI_BGRA8: qglTexImage3D(targface, i, GL_RGBA, size, size, size, 0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, mips->mip[i].data); break; case PTI_RGBA4444: @@ -442,10 +454,23 @@ qboolean GL_LoadTextureMips(texid_t tex, struct pendingtextureinfo *mips) case PTI_BGRX8: qglTexImage2D(targface, j, GL_RGB, mips->mip[i].width, mips->mip[i].height, 0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, mips->mip[i].data); break; - case PTI_BGRA8: default: + case PTI_BGRA8: qglTexImage2D(targface, j, GL_RGBA, mips->mip[i].width, mips->mip[i].height, 0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, mips->mip[i].data); break; + case PTI_RGBX8_SRGB: + qglTexImage2D(targface, j, GL_SRGB_EXT, mips->mip[i].width, mips->mip[i].height, 0, GL_RGBA, GL_UNSIGNED_BYTE, mips->mip[i].data); + break; + case PTI_RGBA8_SRGB: + qglTexImage2D(targface, j, GL_SRGB_ALPHA_EXT, mips->mip[i].width, mips->mip[i].height, 0, gl_config.gles?GL_SRGB_ALPHA_EXT:GL_RGBA, GL_UNSIGNED_BYTE, mips->mip[i].data); + break; + case PTI_BGRX8_SRGB: + qglTexImage2D(targface, j, GL_SRGB_EXT, mips->mip[i].width, mips->mip[i].height, 0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, mips->mip[i].data); + break; + case PTI_BGRA8_SRGB: + qglTexImage2D(targface, j, GL_SRGB_ALPHA_EXT, mips->mip[i].width, mips->mip[i].height, 0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, mips->mip[i].data); + break; + case PTI_RGBA16F: qglTexImage2D(targface, j, GL_RGBA16F_ARB, mips->mip[i].width, mips->mip[i].height, 0, GL_RGBA, GL_UNSIGNED_BYTE, mips->mip[i].data); break; diff --git a/engine/gl/gl_rlight.c b/engine/gl/gl_rlight.c index eed444a0c..f6c69a205 100644 --- a/engine/gl/gl_rlight.c +++ b/engine/gl/gl_rlight.c @@ -1548,7 +1548,7 @@ int R_LightPoint (vec3_t p) if (r_refdef.flags & 1) return 255; - if (!cl.worldmodel || !cl.worldmodel->lightdata) + if (!cl.worldmodel || cl.worldmodel->loadstate != MLS_LOADED || !cl.worldmodel->lightdata) return 255; if (cl.worldmodel->fromgame == fg_quake3) diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c index a5a31a712..fe5b60255 100644 --- a/engine/gl/gl_rmain.c +++ b/engine/gl/gl_rmain.c @@ -626,8 +626,8 @@ void R_SetupGL (float stereooffset, int i) if (vid_srgb.modified && !gl_config_gles) { vid_srgb.modified = false; - if (vid_srgb.ival) - qglEnable(GL_FRAMEBUFFER_SRGB); + if (vid_srgb.ival == 1 || vid.srgb) + qglEnable(GL_FRAMEBUFFER_SRGB); //specifies that the glsl is writing colours in the linear colour space, even if the framebuffer is not sRGB. else qglDisable(GL_FRAMEBUFFER_SRGB); } diff --git a/engine/gl/gl_rsurf.c b/engine/gl/gl_rsurf.c index 76e5b0cd6..fd49434e6 100644 --- a/engine/gl/gl_rsurf.c +++ b/engine/gl/gl_rsurf.c @@ -549,10 +549,10 @@ void GLBE_UploadAllLightmaps(void) switch(lightmap_fmt) //bgra32, rgba32, rgb24, lum8 { default: Sys_Error("Bad lightmap_fmt\n"); break; - case TF_BGRA32: qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, lm->width, lm->height, 0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV,lightmap[i]->lightmaps); break; + case TF_BGRA32: qglTexImage2D(GL_TEXTURE_2D, 0, /*vid.srgb?GL_SRGB8_ALPHA8_EXT:*/GL_RGBA, lm->width, lm->height, 0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV,lightmap[i]->lightmaps); break; // case TF_RGBA32: qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, lm->width, lm->height, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV,lightmap[i]->lightmaps); break; // case TF_BGR24: qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, lm->width, lm->height, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, lightmap[i]->lightmaps); break; - case TF_RGB24: qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, lm->width, lm->height, 0, GL_RGB, GL_UNSIGNED_BYTE, lightmap[i]->lightmaps); break; + case TF_RGB24: qglTexImage2D(GL_TEXTURE_2D, 0, /*vid.srgb?GL_SRGB8_EXT:*/GL_RGB, lm->width, lm->height, 0, GL_RGB, GL_UNSIGNED_BYTE, lightmap[i]->lightmaps); break; case TF_LUM8: qglTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, lm->width, lm->height, 0, GL_LUMINANCE,GL_UNSIGNED_BYTE, lightmap[i]->lightmaps); break; } //for completeness. diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index 1a4281b87..1d7a634ca 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -1766,7 +1766,7 @@ static void Shader_LoadGeneric(sgeneric_t *g, int qrtype) if (file) { - Con_DPrintf("Loaded %s from disk\n", va(sh_config.progpath, basicname)); + Con_DPrintf("Loaded %s from disk\n", sh_config.progpath?va(sh_config.progpath, basicname):basicname); g->failed = !Shader_LoadPermutations(g->name, &g->prog, file, qrtype, 0, blobname); FS_FreeFile(file); return; @@ -2280,7 +2280,7 @@ static void Shader_NormalMap(shader_t *shader, shaderpass_t *pass, char **ptr) { char *token = Shader_ParseString(ptr); unsigned int flags = Shader_SetImageFlags (shader, NULL, &token); - shader->defaulttextures->bump = Shader_FindImage(token, flags|IF_TRYBUMP); + shader->defaulttextures->bump = Shader_FindImage(token, flags|IF_TRYBUMP|IF_NOSRGB); } static void Shader_FullbrightMap(shader_t *shader, shaderpass_t *pass, char **ptr) { @@ -5084,9 +5084,9 @@ void QDECL R_BuildDefaultTexnums(texnums_t *src, shader_t *shader) if (r_loadbumpmapping || (shader->flags & SHADER_HASNORMALMAP)) { if (!TEXVALID(tex->bump) && *mapname && (shader->flags & SHADER_HASNORMALMAP)) - tex->bump = R_LoadHiResTexture(va("%s_norm", mapname), NULL, imageflags|IF_TRYBUMP); + tex->bump = R_LoadHiResTexture(va("%s_norm", mapname), NULL, imageflags|IF_TRYBUMP|IF_NOSRGB); if (!TEXVALID(tex->bump)) - tex->bump = R_LoadHiResTexture(va("%s_norm", imagename), subpath, imageflags|IF_TRYBUMP); + tex->bump = R_LoadHiResTexture(va("%s_norm", imagename), subpath, imageflags|IF_TRYBUMP|IF_NOSRGB); } } @@ -5277,9 +5277,9 @@ void QDECL R_BuildLegacyTexnums(shader_t *shader, const char *fallbackname, cons { extern cvar_t r_shadow_bumpscale_basetexture; if (!TEXVALID(tex->bump) && *mapname) - tex->bump = R_LoadHiResTexture(va("%s_norm", mapname), NULL, imageflags|IF_TRYBUMP); + tex->bump = R_LoadHiResTexture(va("%s_norm", mapname), NULL, imageflags|IF_TRYBUMP|IF_NOSRGB); if (!TEXVALID(tex->bump) && (r_shadow_bumpscale_basetexture.ival||*imagename=='#'||gl_load24bit.ival)) - tex->bump = Image_GetTexture(va("%s_norm", imagename), subpath, imageflags|IF_TRYBUMP|(*imagename=='#'?IF_LINEAR:0), (r_shadow_bumpscale_basetexture.ival||*imagename=='#')?mipdata[0]:NULL, palette, width, height, TF_HEIGHT8PAL); + tex->bump = Image_GetTexture(va("%s_norm", imagename), subpath, imageflags|IF_TRYBUMP|IF_NOSRGB|(*imagename=='#'?IF_LINEAR:0), (r_shadow_bumpscale_basetexture.ival||*imagename=='#')?mipdata[0]:NULL, palette, width, height, TF_HEIGHT8PAL); } if (loadflags & SHADER_HASTOPBOTTOM) diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c index e19f9b3be..a1ff3ba6d 100644 --- a/engine/gl/gl_vidcommon.c +++ b/engine/gl/gl_vidcommon.c @@ -2610,7 +2610,7 @@ static void GLSlang_ProgAutoFields(program_t *prog, const char *progname, cvar_t } //the vid routines have initialised a window, and now they are giving us a reference to some of of GetProcAddress to get pointers to the funcs. -void GL_Init(void *(*getglfunction) (char *name)) +void GL_Init(rendererstate_t *info, void *(*getglfunction) (char *name)) { #ifndef GL_STATIC qglBindTexture = (void *)getglcore("glBindTexture"); //for compleateness. core in 1.1. needed by fte. @@ -2830,13 +2830,20 @@ void GL_Init(void *(*getglfunction) (char *name)) if (gl_config.gles) { + qboolean srgb = false;//TEST ME GL_CheckExtension("GL_EXT_sRGB"); + sh_config.texfmt[PTI_RGBX8] = sh_config.texfmt[PTI_RGBA8]; //FIXME: this is faked with PTI_RGBA8 sh_config.texfmt[PTI_RGB565] = !gl_config.webgl_ie; //ie sucks and doesn't support things that webgl requires it to support. sh_config.texfmt[PTI_RGBA4444] = !gl_config.webgl_ie; sh_config.texfmt[PTI_RGBA5551] = !gl_config.webgl_ie; - sh_config.texfmt[PTI_BGRA8] = false; - sh_config.texfmt[PTI_BGRX8] = sh_config.texfmt[PTI_BGRA8]; + sh_config.texfmt[PTI_BGRX8] = sh_config.texfmt[PTI_BGRA8] = false; + +// sh_config.texfmt[PTI_RGBX8_SRGB] = sh_config.texfmt[PTI_RGBX8] && srgb; + sh_config.texfmt[PTI_RGBA8_SRGB] = sh_config.texfmt[PTI_RGBA8] && srgb; +// sh_config.texfmt[PTI_BGRX8_SRGB] = sh_config.texfmt[PTI_BGRX8] && srgb; + sh_config.texfmt[PTI_BGRA8_SRGB] = sh_config.texfmt[PTI_BGRA8] && srgb; + vid.srgb = info->srgb && srgb; sh_config.minver = 100; sh_config.maxver = 100; @@ -2848,6 +2855,7 @@ void GL_Init(void *(*getglfunction) (char *name)) } else { + GLint srgb = gl_config.glversion >= 2.1 || GL_CheckExtension("GL_EXT_texture_sRGB"); //became core in gl 2.1 sh_config.can_mipcap = gl_config.glversion >= 1.2; sh_config.texfmt[PTI_RGBX8] = true; //proper support @@ -2889,6 +2897,11 @@ void GL_Init(void *(*getglfunction) (char *name)) sh_config.blobpath = "glsl/%s.blob"; sh_config.progpath = "glsl/%s.glsl"; sh_config.shadernamefmt = "%s_glsl"; + + sh_config.texfmt[PTI_RGBX8_SRGB] = sh_config.texfmt[PTI_RGBX8] && srgb; + sh_config.texfmt[PTI_RGBA8_SRGB] = sh_config.texfmt[PTI_RGBA8] && srgb; + sh_config.texfmt[PTI_BGRX8_SRGB] = sh_config.texfmt[PTI_BGRX8] && srgb; + sh_config.texfmt[PTI_BGRA8_SRGB] = sh_config.texfmt[PTI_BGRA8] && srgb; } sh_config.progs_supported = gl_config.arb_shader_objects; diff --git a/engine/gl/gl_viddroid.c b/engine/gl/gl_viddroid.c index c47325131..52a4ac861 100644 --- a/engine/gl/gl_viddroid.c +++ b/engine/gl/gl_viddroid.c @@ -84,7 +84,7 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette) vid.activeapp = true; - GL_Init(GLES_GetSymbol); + GL_Init(info, GLES_GetSymbol); return true; } #else @@ -174,7 +174,7 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette) vid.pixelwidth = w; vid.pixelheight = h; - GL_Init(GLES_GetSymbol); + GL_Init(info, GLES_GetSymbol); return true; } diff --git a/engine/gl/gl_vidlinuxglx.c b/engine/gl/gl_vidlinuxglx.c index aa0b2dd5f..2f4aba070 100644 --- a/engine/gl/gl_vidlinuxglx.c +++ b/engine/gl/gl_vidlinuxglx.c @@ -1951,7 +1951,7 @@ qboolean X11VID_Init (rendererstate_t *info, unsigned char *palette, int psl) return false; } - GL_Init(&GLX_GetSymbol); + GL_Init(info, &GLX_GetSymbol); break; #ifdef USE_EGL case PSL_EGL: @@ -1961,7 +1961,7 @@ qboolean X11VID_Init (rendererstate_t *info, unsigned char *palette, int psl) GLVID_Shutdown(); return false; } - GL_Init(&EGL_Proc); + GL_Init(info, &EGL_Proc); break; #endif #endif diff --git a/engine/gl/gl_vidmacos.c b/engine/gl/gl_vidmacos.c index 090f2feb0..8876be915 100644 --- a/engine/gl/gl_vidmacos.c +++ b/engine/gl/gl_vidmacos.c @@ -101,7 +101,7 @@ qboolean GLVID_Init(rendererstate_t *info, unsigned char *palette) if (vid.height < 200) vid.height = 200; - GL_Init(AGL_GetProcAddress); + GL_Init(info, AGL_GetProcAddress); GLVID_SetPalette(palette); diff --git a/engine/gl/gl_vidnt.c b/engine/gl/gl_vidnt.c index 6814301f6..f6ef04af8 100644 --- a/engine/gl/gl_vidnt.c +++ b/engine/gl/gl_vidnt.c @@ -119,8 +119,6 @@ extern cvar_t vid_width; extern cvar_t vid_height; extern cvar_t vid_wndalpha; -typedef enum {MS_WINDOWED, MS_FULLDIB, MS_FULLWINDOW, MS_UNINIT} modestate_t; - static qboolean VID_SetWindowedMode (rendererstate_t *info); //-1 on bpp or hz for default. static qboolean VID_SetFullDIBMode (rendererstate_t *info); //-1 on bpp or hz for default. @@ -162,7 +160,7 @@ viddef_t vid; // global video state //unsigned short d_8to16bgrtable[256]; //unsigned d_8to24bgrtable[256]; -static modestate_t modestate = MS_UNINIT; +static enum {MS_WINDOWED, MS_FULLDIB, MS_FULLWINDOW, MS_UNINIT} modestate = MS_UNINIT; extern float gammapending; @@ -232,6 +230,7 @@ static int (WINAPI *qDescribePixelFormat)(HDC, int, UINT, LPPIXELFORMATDESCRIP static BOOL (WINAPI *qwglSwapIntervalEXT) (int); static BOOL (APIENTRY *qwglChoosePixelFormatARB)(HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats); +static BOOL (APIENTRY *qwglGetPixelFormatAttribfvARB)(HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, FLOAT *pfValues); static HGLRC (APIENTRY *qwglCreateContextAttribsARB)(HDC hDC, HGLRC hShareContext, const int *attribList); #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 @@ -1441,6 +1440,7 @@ static int GLVID_SetMode (rendererstate_t *info, unsigned char *palette) #endif // Set either the fullscreen or windowed mode qwglChoosePixelFormatARB = NULL; + qwglGetPixelFormatAttribfvARB = NULL; qwglCreateContextAttribsARB = NULL; stat = CreateMainWindow(info, true); @@ -1454,7 +1454,7 @@ static int GLVID_SetMode (rendererstate_t *info, unsigned char *palette) { HMODULE oldgl = hInstGL; hInstGL = NULL; //don't close the gl library, just in case - VID_UnSetMode(); + VID_UnSetMode(); //SetPixelFormat may only be used once per window. which means we *MUST* destroy the window if we're using a different pixelformat. hInstGL = oldgl; if (CreateMainWindow(info, true) && VID_AttachGL(info)) @@ -1480,6 +1480,9 @@ static int GLVID_SetMode (rendererstate_t *info, unsigned char *palette) } } + GL_Init(info, getglfunc); + qSwapBuffers(maindc); + #ifdef VKQUAKE if (platform_rendermode == MODE_NVVULKAN && stat) { @@ -1497,7 +1500,7 @@ static int GLVID_SetMode (rendererstate_t *info, unsigned char *palette) stat = EGL_Init (info, palette, mainwindow, maindc); if (stat) - GL_Init(&EGL_Proc); + GL_Init(info, &EGL_Proc); } break; #endif @@ -1950,8 +1953,8 @@ qboolean VID_AttachGL (rendererstate_t *info) } #endif - TRACE(("dbg: VID_AttachGL: GL_Init\n")); - GL_Init(getglfunc); + qwglChoosePixelFormatARB = getglfunc("wglChoosePixelFormatARB"); + qwglGetPixelFormatAttribfvARB = getglfunc("wglGetPixelFormatAttribfvARB"); if (info->stereo) { @@ -1961,19 +1964,12 @@ qboolean VID_AttachGL (rendererstate_t *info) Con_Printf("Unable to create stereoscopic/quad-buffered OpenGL context. Please use a different stereoscopic method.\n"); } - qwglChoosePixelFormatARB = getglfunc("wglChoosePixelFormatARB"); - qwglSwapIntervalEXT = getglfunc("wglSwapIntervalEXT"); if (qwglSwapIntervalEXT && *vid_vsync.string) { TRACE(("dbg: VID_AttachGL: qwglSwapIntervalEXT\n")); qwglSwapIntervalEXT(vid_vsync.value); } - TRACE(("dbg: VID_AttachGL: qSwapBuffers\n")); - qglClearColor(0, 0, 0, 1); - qglClear(GL_COLOR_BUFFER_BIT); - qSwapBuffers(maindc); - return true; } #endif @@ -2234,14 +2230,15 @@ static BOOL CheckForcePixelFormat(rendererstate_t *info) int valid; float fAttribute[] = {0,0}; UINT numFormats; - int pixelformat; + int pixelformats[1]; int iAttributes = 0; int iAttribute[16*2]; + iAttribute[iAttributes++] = WGL_DRAW_TO_WINDOW_ARB; iAttribute[iAttributes++] = GL_TRUE; iAttribute[iAttributes++] = WGL_SUPPORT_OPENGL_ARB; iAttribute[iAttributes++] = GL_TRUE; iAttribute[iAttributes++] = WGL_ACCELERATION_ARB; iAttribute[iAttributes++] = WGL_FULL_ACCELERATION_ARB; - iAttribute[iAttributes++] = WGL_COLOR_BITS_ARB; iAttribute[iAttributes++] = info->bpp; - iAttribute[iAttributes++] = WGL_ALPHA_BITS_ARB; iAttribute[iAttributes++] = 4; + iAttribute[iAttributes++] = WGL_COLOR_BITS_ARB; iAttribute[iAttributes++] = (info->bpp>24)?24:info->bpp; +// iAttribute[iAttributes++] = WGL_ALPHA_BITS_ARB; iAttribute[iAttributes++] = 4; iAttribute[iAttributes++] = WGL_DEPTH_BITS_ARB; iAttribute[iAttributes++] = 16; iAttribute[iAttributes++] = WGL_STENCIL_BITS_ARB; iAttribute[iAttributes++] = 8; iAttribute[iAttributes++] = WGL_DOUBLE_BUFFER_ARB; iAttribute[iAttributes++] = GL_TRUE; @@ -2261,7 +2258,7 @@ static BOOL CheckForcePixelFormat(rendererstate_t *info) TRACE(("dbg: bSetupPixelFormat: attempting wglChoosePixelFormatARB (multisample 4)\n")); hDC = GetDC(mainwindow); - valid = qwglChoosePixelFormatARB(hDC,iAttribute,fAttribute,1,&pixelformat,&numFormats); + valid = qwglChoosePixelFormatARB(hDC,iAttribute,fAttribute,countof(pixelformats),pixelformats,&numFormats); /* while ((!valid || numFormats < 1) && iAttribute[19] > 1) { //failed, switch wgl_samples to 2 iAttribute[19] /= 2; @@ -2269,11 +2266,115 @@ static BOOL CheckForcePixelFormat(rendererstate_t *info) valid = qwglChoosePixelFormatARB(hDC,iAttribute,fAttribute,1,&pixelformat,&numFormats); } */ + +#if 0 + for (iAttributes = -1; iAttributes < (int)numFormats; iAttributes++) + { + int j; + struct + { + char *name; + int id; + } iAttributeTable[] = { + {"WGL_DRAW_TO_WINDOW", WGL_DRAW_TO_WINDOW_ARB}, + {"WGL_DRAW_TO_BITMAP", 0x2002}, + {"WGL_ACCELERATION", WGL_ACCELERATION_ARB}, + {"WGL_NEED_PALETTE", 0x2004}, + {"WGL_NEED_SYSTEM_PALETTE", 0x2005}, + {"WGL_SWAP_LAYER_BUFFERS", WGL_SWAP_LAYER_BUFFERS_ARB}, + {"WGL_SWAP_METHOD", 0x2007}, + {"WGL_NUMBER_OVERLAYS", 0x2008}, + {"WGL_NUMBER_UNDERLAYS", 0x2009}, + {"WGL_TRANSPARENT", 0x200A}, + {"WGL_TRANSPARENT_RED_VALUE", 0x2037}, + {"WGL_TRANSPARENT_GREEN_VALUE", 0x2038}, + {"WGL_TRANSPARENT_BLUE_VALUE", 0x2039}, + {"WGL_TRANSPARENT_ALPHA_VALUE", 0x203a}, + {"WGL_TRANSPARENT_INDEX_VALUE", 0x203B}, + {"WGL_SHARE_DEPTH", 0x200C}, + {"WGL_SHARE_STENCIL", 0x200D}, + {"WGL_SHARE_ACCUM", 0x200E}, + {"WGL_SUPPORT_GDI", 0x200F}, + {"WGL_SUPPORT_OPENGL", WGL_SUPPORT_OPENGL_ARB}, + {"WGL_DOUBLE_BUFFER", WGL_DOUBLE_BUFFER_ARB}, + {"WGL_STEREO", WGL_STEREO_ARB}, + {"WGL_PIXEL_TYPE", 0x2013}, + {"WGL_COLOR_BITS", WGL_COLOR_BITS_ARB}, + {"WGL_RED_BITS", 0x2015}, + {"WGL_RED_SHIFT", 0x2016}, + {"WGL_GREEN_BITS", 0x2017}, + {"WGL_GREEN_SHIFT", 0x2018}, + {"WGL_BLUE_BITS", 0x2019}, + {"WGL_BLUE_SHIFT", 0x201A}, + {"WGL_ALPHA_BITS", WGL_ALPHA_BITS_ARB}, + {"WGL_ALPHA_SHIFT", 0x201C}, + {"WGL_ACCUM_BITS", 0x201D}, + {"WGL_ACCUM_RED_BITS", 0x201E}, + {"WGL_ACCUM_GREEN_BITS", 0x201F}, + {"WGL_ACCUM_BLUE_BITS", 0x2020}, + {"WGL_ACCUM_ALPHA_BITS", 0x2021}, + {"WGL_DEPTH_BITS", WGL_DEPTH_BITS_ARB}, + {"WGL_STENCIL_BITS", WGL_STENCIL_BITS_ARB}, + {"WGL_AUX_BUFFERS", 0x2024}, + + //extra extensions + {"WGL_SAMPLE_BUFFERS_ARB", WGL_SAMPLE_BUFFERS_ARB}, //multisample + {"WGL_SAMPLES_ARB", WGL_SAMPLES_ARB}, //multisample + + {"WGL_DRAW_TO_PBUFFER_ARB", 0x202D}, //pbuffers + {"WGL_MAX_PBUFFER_PIXELS_ARB", 0x202E}, //pbuffers + {"WGL_MAX_PBUFFER_WIDTH_ARB", 0x202F}, //pbuffers + {"WGL_MAX_PBUFFER_HEIGHT_ARB", 0x2030}, //pbuffers + + {"WGL_BIND_TO_TEXTURE_RGB_ARB", 0x2070}, + {"WGL_BIND_TO_TEXTURE_RGBA_ARB", 0x2071}, + {"WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB",WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB}, + {"WGL_COLORSPACE_EXT", 0x309D}, //WGL_EXT_colorspace + + //stuff my drivers don't support +// {"WGL_TYPE_RGBA_FLOAT_ARB", 0x21A0}, +// {"WGL_DEPTH_FLOAT_EXT", 0x2040}, +// {"WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT",0x20A8}, //EXT_packed_float + }; + int iAttributeNames[countof(iAttributeTable)]; + float fAttributeValues[countof(iAttributeTable)]; + float basevalues[countof(iAttributeTable)]; + + for (j = 0; j < countof(iAttributeTable); j++) + iAttributeNames[j] = iAttributeTable[j].id; + + Sys_Printf("Pixel Format %i --------------------------\n", iAttributes<0?currentpixelformat:pixelformats[iAttributes]); + if (qwglGetPixelFormatAttribfvARB(hDC, iAttributes<0?currentpixelformat:pixelformats[iAttributes], 0, countof(iAttributeTable), iAttributeNames, fAttributeValues)) + { + if (iAttributes==-1) + memcpy(basevalues, fAttributeValues, sizeof(basevalues)); + for (j = 0; j < countof(iAttributeTable); j++) + { + if (iAttributes==-1 || fAttributeValues[j] != basevalues[j]) + { + if (iAttributeTable[j].id == 0x2007 && fAttributeValues[j] == 0x2028) + Sys_Printf("%s: exchange\n", iAttributeTable[j].name); + else if (iAttributeTable[j].id == 0x2007 && fAttributeValues[j] == 0x2029) + Sys_Printf("%s: copy\n", iAttributeTable[j].name); + else if (iAttributeTable[j].id == 0x309D && fAttributeValues[j] == 0x3089) + Sys_Printf("%s: WGL_COLORSPACE_SRGB\n", iAttributeTable[j].name); + else if (iAttributeTable[j].id == 0x309D && fAttributeValues[j] == 0x308A) + Sys_Printf("%s: WGL_COLORSPACE_LINEAR\n", iAttributeTable[j].name); + else if (iAttributeTable[j].id == 0x202E) + Sys_Printf("%s: %#x\n", iAttributeTable[j].name, (int)fAttributeValues[j]); + else + Sys_Printf("%s: %g\n", iAttributeTable[j].name, fAttributeValues[j]); + } + } + } + } +#endif + ReleaseDC(mainwindow, hDC); - if (valid && numFormats > 0) + if (valid && numFormats > 0 && pixelformats[0] != currentpixelformat) { shouldforcepixelformat = true; - forcepixelformat = pixelformat; + forcepixelformat = pixelformats[0]; return true; } } diff --git a/engine/gl/gl_vidsdl.c b/engine/gl/gl_vidsdl.c index 81b9ed10a..b7226e4bc 100644 --- a/engine/gl/gl_vidsdl.c +++ b/engine/gl/gl_vidsdl.c @@ -230,7 +230,7 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette) #endif vid.activeapp = true; - GL_Init(GLVID_getsdlglfunction); + GL_Init(info, GLVID_getsdlglfunction); qglViewport (0, 0, vid.pixelwidth, vid.pixelheight); diff --git a/engine/gl/glmod_doom.c b/engine/gl/glmod_doom.c index 895ea90e4..cfa0a18a7 100644 --- a/engine/gl/glmod_doom.c +++ b/engine/gl/glmod_doom.c @@ -26,8 +26,6 @@ int PlaneTypeForNormal ( vec3_t normal ); //(aol suck) -void Doom_SetModelFunc(model_t *mod); -int Doom_SectorNearPoint(vec3_t p); //assumptions: //1. That there is a node, and thus two ssectors. @@ -205,29 +203,6 @@ typedef struct { short rows; } blockmapheader_t; -ddoomnode_t *nodel; -dssector_t *ssectorsl; -dthing_t *thingsl; -mdoomvertex_t *vertexesl; -dgl_seg3_t *segsl; -dlinedef_t *linedefsl; -msidedef_t *sidedefsm; -msector_t *sectorm; -plane_t *nodeplanes; -plane_t *lineplanes; -blockmapheader_t *blockmapl; -unsigned short *blockmapofs; -unsigned int nodec; -unsigned int sectorc; -unsigned int segsc; -unsigned int ssectorsc; -unsigned int thingsc; -unsigned int linedefsc; -unsigned int sidedefsc; -unsigned int vertexesc; -unsigned int vertexsglbase; - - typedef struct { char name[16]; @@ -240,36 +215,74 @@ typedef struct int maxverts; int maxindicies; } doomtexture_t; -doomtexture_t *doomtextures; -int numdoomtextures; +typedef struct doommap_s +{ + model_t *model; + + ddoomnode_t *node; + plane_t *nodeplane; + unsigned int numnodes; + + dssector_t *ssector; //aka: leafs + unsigned int numssectors; + + msector_t *sector; + unsigned int numsectors; + + dthing_t *thing; + unsigned int numthings; + + mdoomvertex_t *vertexes; + unsigned int numvertexes; + + dgl_seg3_t *seg; + unsigned int numsegs; + + dlinedef_t *linedef; + plane_t *lineplane; + unsigned int numlinedefs; + + msidedef_t *sidedef; + unsigned int numsidedefs; + + blockmapheader_t *blockmap; + unsigned short *blockmapofs; + + unsigned int vertexsglbase; + + doomtexture_t *textures; + unsigned int numtextures; +} doommap_t; + +void Doom_SetModelFunc(model_t *mod); //////////////////////////////////////////////////////////////////////////////////////////// //physics /*walk the bsp tree*/ -int Doom_SectorNearPoint(vec3_t p) +int Doom_SectorNearPoint(doommap_t *dm, vec3_t p) { ddoomnode_t *node; plane_t *plane; int num; int seg; float d; - num = nodec-1; + num = dm->numnodes-1; while (1) { if (num & NODE_IS_SSECTOR) { num -= NODE_IS_SSECTOR; - for (seg = ssectorsl[num].first; seg < ssectorsl[num].first + ssectorsl[num].segcount; seg++) - if (segsl[seg].linedef != 0xffff) + for (seg = dm->ssector[num].first; seg < dm->ssector[num].first + dm->ssector[num].segcount; seg++) + if (dm->seg[seg].linedef != 0xffff) break; - return sidedefsm[linedefsl[segsl[seg].linedef].sidedef[segsl[seg].direction]].sector; + return dm->sidedef[dm->linedef[dm->seg[seg].linedef].sidedef[dm->seg[seg].direction]].sector; } - node = nodel + num; - plane = nodeplanes + num; + node = dm->node + num; + plane = dm->nodeplane + num; // if (plane->type < 3) // d = p[plane->type] - plane->dist; @@ -286,10 +299,11 @@ int Doom_SectorNearPoint(vec3_t p) int Doom_PointContents(model_t *model, vec3_t axis[3], vec3_t p) { - int sec = Doom_SectorNearPoint(p); - if (p[2] < sectorm[sec].floorheight) + doommap_t *dm = model->meshinfo; + int sec = Doom_SectorNearPoint(dm, p); + if (p[2] < dm->sector[sec].floorheight) return FTECONTENTS_SOLID; - if (p[2] > sectorm[sec].ceilingheight) + if (p[2] > dm->sector[sec].ceilingheight) return FTECONTENTS_SOLID; return FTECONTENTS_EMPTY; } @@ -320,7 +334,7 @@ qboolean Doom_Trace(model_t *model, int hulloverride, framestate_t *framestate, // Con_Printf("%i\n", sec1); - if (start[2] < sectorm[sec1].floorheight-mins[2]) //whoops, started outside... ? + if (start[2] < dm->sector[sec1].floorheight-mins[2]) //whoops, started outside... ? { trace->fraction = 0; trace->allsolid = trace->startsolid = true; @@ -332,11 +346,11 @@ qboolean Doom_Trace(model_t *model, int hulloverride, framestate_t *framestate, trace->plane.normal[0] = 0; trace->plane.normal[1] = 0; trace->plane.normal[2] = 1; - trace->plane.dist = sectorm[sec1].floorheight-mins[2]; + trace->plane.dist = dm->sector[sec1].floorheight-mins[2]; return false; } - if (start[2] > sectorm[sec1].ceilingheight-maxs[2]) //whoops, started outside... ? + if (start[2] > dm->sector[sec1].ceilingheight-maxs[2]) //whoops, started outside... ? { trace->fraction = 0; trace->allsolid = trace->startsolid = true; @@ -346,7 +360,7 @@ qboolean Doom_Trace(model_t *model, int hulloverride, framestate_t *framestate, trace->plane.normal[0] = 0; trace->plane.normal[1] = 0; trace->plane.normal[2] = -1; - trace->plane.dist = -(sectorm[sec1].ceilingheight-maxs[2]); + trace->plane.dist = -(dm->sector[sec1].ceilingheight-maxs[2]); return false; } @@ -364,28 +378,28 @@ qboolean Doom_Trace(model_t *model, int hulloverride, framestate_t *framestate, trace->fraction = 1; while(1) { - bmi = ((int)p1[0] - blockmapl->xorg)/128 + (((int)p1[1] - blockmapl->yorg)/128)*blockmapl->columns; -// Con_Printf("%i of %i ", bmi, blockmapl->rows*blockmapl->columns); - if (bmi >= 0 && bmi < blockmapl->rows*blockmapl->columns) + bmi = ((int)p1[0] - dm->blockmap->xorg)/128 + (((int)p1[1] - dm->blockmap->yorg)/128)*dm->blockmap->columns; +// Con_Printf("%i of %i ", bmi, dm->blockmap->rows*dm->blockmap->columns); + if (bmi >= 0 && bmi < dm->blockmap->rows*dm->blockmap->columns) if (bmi != obmi) { #if 1 short dummy; linedefs = &dummy; - for (dummy = 0; dummy < linedefsc; dummy++) + for (dummy = 0; dummy < dm->numlinedefs; dummy++) #else - for(linedefs = (short*)blockmapl + blockmapofs[bmi]+1; *linedefs != 0xffff; linedefs++) + for(linedefs = (short*)dm->blockmap + dm->blockmapofs[bmi]+1; *linedefs != 0xffff; linedefs++) #endif { - ld = linedefsl + *linedefs; + ld = dm->linedef + *linedefs; if (ld->sidedef[1] != 0xffff) { - if (sectorm[sidedefsm[ld->sidedef[0]].sector].floorheight == sectorm[sidedefsm[ld->sidedef[1]].sector].floorheight && - sectorm[sidedefsm[ld->sidedef[0]].sector].ceilingheight == sectorm[sidedefsm[ld->sidedef[1]].sector].ceilingheight) + if (dm->sector[dm->sidedef[ld->sidedef[0]].sector].floorheight == dm->sector[dm->sidedef[ld->sidedef[1]].sector].floorheight && + dm->sector[dm->sidedef[ld->sidedef[0]].sector].ceilingheight == dm->sector[dm->sidedef[ld->sidedef[1]].sector].ceilingheight) continue; } - lp = lineplanes + *linedefs; + lp = dm->lineplane + *linedefs; if (1) { //figure out how far to move the plane out by @@ -413,8 +427,8 @@ qboolean Doom_Trace(model_t *model, int hulloverride, framestate_t *framestate, planedist = -planedist+lp->dist; if (/*d1 < planedist*-1 &&*/ d1 > planedist*2) { //right, we managed to end up just on the other side of a wall's plane. - v1 = &vertexesl[ld->vert[0]]; - v2 = &vertexesl[ld->vert[1]]; + v1 = &dm->vertexes[ld->vert[0]]; + v2 = &dm->vertexes[ld->vert[1]]; if (!(d1 - d2)) continue; if (d1<0) //back to front. @@ -436,14 +450,14 @@ qboolean Doom_Trace(model_t *model, int hulloverride, framestate_t *framestate, pointonplane[2] = start[2]*c2 + p2[2]*c1; Con_Printf("Started in wall\n"); - j = sidedefsm[ld->sidedef[d1 < planedist]].sector; + j = dm->sidedef[ld->sidedef[d1 < planedist]].sector; //yup, we are in the thing //prevent ourselves from entering the back-sector's floor/ceiling - if (pointonplane[2] < sectorm[j].floorheight-hull->clip_mins[2]) //whoops, started outside... ? + if (pointonplane[2] < dm->sector[j].floorheight-hull->clip_mins[2]) //whoops, started outside... ? { Con_Printf("Started in floor\n"); trace->allsolid = trace->startsolid = false; - trace->endpos[2] = sectorm[j].floorheight-hull->clip_mins[2]; + trace->endpos[2] = dm->sector[j].floorheight-hull->clip_mins[2]; trace->fraction = fabs(trace->endpos[2] - start[2]) / fabs(p2[2] - start[2]); trace->endpos[0] = start[0]+delta[0]*trace->fraction*p2f; trace->endpos[1] = start[1]+delta[1]*trace->fraction*p2f; @@ -452,22 +466,22 @@ qboolean Doom_Trace(model_t *model, int hulloverride, framestate_t *framestate, trace->plane.normal[0] = 0; trace->plane.normal[1] = 0; trace->plane.normal[2] = 1; - trace->plane.dist = sectorm[j].floorheight-hull->clip_mins[2]; + trace->plane.dist = dm->sector[j].floorheight-hull->clip_mins[2]; continue; } - if (pointonplane[2] > sectorm[j].ceilingheight-hull->clip_maxs[2]) //whoops, started outside... ? + if (pointonplane[2] > dm->sector[j].ceilingheight-hull->clip_maxs[2]) //whoops, started outside... ? { Con_Printf("Started in ceiling\n"); trace->allsolid = trace->startsolid = false; trace->endpos[0] = pointonplane[0]; trace->endpos[1] = pointonplane[1]; - trace->endpos[2] = sectorm[j].ceilingheight-hull->clip_maxs[2]; + trace->endpos[2] = dm->sector[j].ceilingheight-hull->clip_maxs[2]; trace->fraction = fabs(trace->endpos[2] - start[2]) / fabs(p2[2] - start[2]); trace->plane.normal[0] = 0; trace->plane.normal[1] = 0; trace->plane.normal[2] = -1; - trace->plane.dist = -(sectorm[j].ceilingheight-hull->clip_maxs[2]); + trace->plane.dist = -(dm->sector[j].ceilingheight-hull->clip_maxs[2]); continue; } } @@ -478,8 +492,8 @@ qboolean Doom_Trace(model_t *model, int hulloverride, framestate_t *framestate, //line crosses plane. - v1 = &vertexesl[ld->vert[0]]; - v2 = &vertexesl[ld->vert[1]]; + v1 = &dm->vertexes[ld->vert[0]]; + v2 = &dm->vertexes[ld->vert[1]]; if (d1<0) //back to front. { @@ -510,13 +524,13 @@ qboolean Doom_Trace(model_t *model, int hulloverride, framestate_t *framestate, msector_t *sec2; if (d1<0) - sec2 = §orm[sidedefsm[ld->sidedef[1]].sector]; + sec2 = &dm->sector[dm->sidedef[ld->sidedef[1]].sector]; else - sec2 = §orm[sidedefsm[ld->sidedef[0]].sector]; + sec2 = &dm->sector[dm->sidedef[ld->sidedef[0]].sector]; if (pointonplane[2] < sec2->floorheight-hull->clip_mins[2]) { //hit the floor first. - c1 = fabs(sectorm[sec1].floorheight-hull->clip_mins[2] - start[2]); + c1 = fabs(dm->sector[sec1].floorheight-hull->clip_mins[2] - start[2]); c2 = fabs(p2[2] - start[2]); if (!c2) c1 = 1; @@ -533,14 +547,14 @@ qboolean Doom_Trace(model_t *model, int hulloverride, framestate_t *framestate, trace->plane.normal[0] = 0; trace->plane.normal[1] = 0; trace->plane.normal[2] = 1; - trace->plane.dist = sectorm[sec1].floorheight-hull->clip_mins[2]; + trace->plane.dist = dm->sector[sec1].floorheight-hull->clip_mins[2]; } continue; } if (pointonplane[2] > sec2->ceilingheight-hull->clip_maxs[2]) { //hit the floor first. - c1 = fabs((sectorm[sec1].ceilingheight-hull->clip_maxs[2]) - start[2]); + c1 = fabs((dm->sector[sec1].ceilingheight-hull->clip_maxs[2]) - start[2]); c2 = fabs(p2[2] - start[2]); if (!c2) c1 = 1; @@ -559,15 +573,15 @@ qboolean Doom_Trace(model_t *model, int hulloverride, framestate_t *framestate, trace->plane.normal[0] = 0; trace->plane.normal[1] = 0; trace->plane.normal[2] = -1; - trace->plane.dist = -(sectorm[sec1].ceilingheight-hull->clip_maxs[2]); + trace->plane.dist = -(dm->sector[sec1].ceilingheight-hull->clip_maxs[2]); } continue; } if (d1<0) - sec2 = §orm[sidedefsm[ld->sidedef[0]].sector]; + sec2 = &dm->sector[dm->sidedef[ld->sidedef[0]].sector]; else - sec2 = §orm[sidedefsm[ld->sidedef[1]].sector]; + sec2 = &dm->sector[dm->sidedef[ld->sidedef[1]].sector]; if(sec2->ceilingheight == sec2->floorheight) sec2->ceilingheight += 64; @@ -629,9 +643,9 @@ qboolean Doom_Trace(model_t *model, int hulloverride, framestate_t *framestate, { if (sec1 == Doom_SectorNearPoint(p2)) //special test. { - if (p2[2] <= sectorm[sec1].floorheight-hull->clip_mins[2]) //whoops, started outside... ? + if (p2[2] <= dm->sector[sec1].floorheight-hull->clip_mins[2]) //whoops, started outside... ? { - p1f = fabs(sectorm[sec1].floorheight-hull->clip_mins[2] - start[2]); + p1f = fabs(dm->sector[sec1].floorheight-hull->clip_mins[2] - start[2]); p2f = fabs(p2[2] - start[2]); if (!p2f) c1 = 1; @@ -647,15 +661,15 @@ qboolean Doom_Trace(model_t *model, int hulloverride, framestate_t *framestate, trace->plane.normal[0] = 0; trace->plane.normal[1] = 0; trace->plane.normal[2] = 1; - trace->plane.dist = sectorm[sec1].floorheight-hull->clip_mins[2]; + trace->plane.dist = dm->sector[sec1].floorheight-hull->clip_mins[2]; } // if (IS_NAN(trace->endpos[2])) // Con_Printf("Nanny\n"); } - if (p2[2] >= sectorm[sec1].ceilingheight-hull->clip_maxs[2]) //whoops, started outside... ? + if (p2[2] >= dm->sector[sec1].ceilingheight-hull->clip_maxs[2]) //whoops, started outside... ? { - p1f = fabs(sectorm[sec1].ceilingheight-hull->clip_maxs[2] - start[2]); + p1f = fabs(dm->sector[sec1].ceilingheight-hull->clip_maxs[2] - start[2]); p2f = fabs(p2[2] - start[2]); if (!p2f) c1 = 1; @@ -671,7 +685,7 @@ qboolean Doom_Trace(model_t *model, int hulloverride, framestate_t *framestate, trace->plane.normal[0] = 0; trace->plane.normal[1] = 0; trace->plane.normal[2] = -1; - trace->plane.dist = -(sectorm[sec1].ceilingheight-hull->clip_maxs[2]); + trace->plane.dist = -(dm->sector[sec1].ceilingheight-hull->clip_maxs[2]); } // if (IS_NAN(trace->endpos[2])) @@ -733,7 +747,7 @@ void Doom_LoadPalette(void) } } #endif -int Doom_LoadFlat(model_t *mod, char *flatname) +int Doom_LoadFlat(doommap_t *dm, char *flatname) { #ifndef SERVERONLY char texname[64]; @@ -741,20 +755,20 @@ int Doom_LoadFlat(model_t *mod, char *flatname) sprintf(texname, "flats/%-.8s", flatname); - for (texnum = 0; texnum < numdoomtextures; texnum++) + for (texnum = 0; texnum < dm->numtextures; texnum++) { - if (!strcmp(doomtextures[texnum].name, texname)) + if (!strcmp(dm->textures[texnum].name, texname)) return texnum; } - doomtextures = BZ_Realloc(doomtextures, sizeof(*doomtextures)*((numdoomtextures+16)&~15)); - memset(doomtextures + numdoomtextures, 0, sizeof(doomtextures[numdoomtextures])); - numdoomtextures++; + dm->textures = BZ_Realloc(dm->textures, sizeof(*dm->textures)*((dm->numtextures+16)&~15)); + memset(dm->textures + dm->numtextures, 0, sizeof(dm->textures[dm->numtextures])); + dm->numtextures++; - Q_strncpyz(doomtextures[texnum].name, texname, sizeof(doomtextures[texnum].name)); + Q_strncpyz(dm->textures[texnum].name, texname, sizeof(dm->textures[texnum].name)); - doomtextures[texnum].width = 64; - doomtextures[texnum].height = 64; + dm->textures[texnum].width = 64; + dm->textures[texnum].height = 64; return texnum; #else @@ -763,9 +777,9 @@ int Doom_LoadFlat(model_t *mod, char *flatname) } #ifndef SERVERONLY -static void R_DrawWall(int texnum, int s, int t, float x1, float y1, float z1, float x2, float y2, float z2, qboolean unpegged, unsigned int colour4b) +static void R_DrawWall(doommap_t *dm, int texnum, int s, int t, float x1, float y1, float z1, float x2, float y2, float z2, qboolean unpegged, unsigned int colour4b) { - doomtexture_t *tex = doomtextures+texnum; + doomtexture_t *tex = dm->textures+texnum; mesh_t *mesh = &tex->mesh; float len = sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2)); float s1, s2; @@ -833,7 +847,7 @@ static void R_DrawWall(int texnum, int s, int t, float x1, float y1, float z1, f mesh->numindexes += 6; } -static void R_DrawFlats(int floortexnum, int floorheight, int ceiltexnum, int ceilheight, int numverts, unsigned short *verts, unsigned int colour4b) +static void R_DrawFlats(doommap_t *dm, int floortexnum, int floorheight, int ceiltexnum, int ceilheight, int numverts, unsigned short *verts, unsigned int colour4b) { mesh_t *mesh; unsigned int col; @@ -841,7 +855,7 @@ static void R_DrawFlats(int floortexnum, int floorheight, int ceiltexnum, int ce //floor { - doomtexture_t *floortex = doomtextures + floortexnum; + doomtexture_t *floortex = dm->textures + floortexnum; mesh = &floortex->mesh; if (mesh->numvertexes+numverts > floortex->maxverts) { @@ -871,8 +885,8 @@ static void R_DrawFlats(int floortexnum, int floorheight, int ceiltexnum, int ce for (i = 0; i < numverts; i++) { v = verts[i]; - VectorSet(mesh->xyz_array[mesh->numvertexes+i], vertexesl[v].xpos, vertexesl[v].ypos, floorheight); - Vector2Set(mesh->st_array[mesh->numvertexes+i], vertexesl[v].xpos/64.0f, vertexesl[v].ypos/64.0f); + VectorSet(mesh->xyz_array[mesh->numvertexes+i], dm->vertexes[v].xpos, dm->vertexes[v].ypos, floorheight); + Vector2Set(mesh->st_array[mesh->numvertexes+i], dm->vertexes[v].xpos/64.0f, dm->vertexes[v].ypos/64.0f); *(unsigned int*)mesh->colors4b_array[mesh->numvertexes+i] = col; } @@ -890,7 +904,7 @@ static void R_DrawFlats(int floortexnum, int floorheight, int ceiltexnum, int ce //ceiling { - doomtexture_t *ceiltex = doomtextures + ceiltexnum; + doomtexture_t *ceiltex = dm->textures + ceiltexnum; mesh = &ceiltex->mesh; if (mesh->numvertexes+numverts > ceiltex->maxverts) { @@ -920,8 +934,8 @@ static void R_DrawFlats(int floortexnum, int floorheight, int ceiltexnum, int ce for (i = 0; i < numverts; i++) { v = verts[numverts-1-i]; - VectorSet(mesh->xyz_array[mesh->numvertexes+i], vertexesl[v].xpos, vertexesl[v].ypos, ceilheight); - Vector2Set(mesh->st_array[mesh->numvertexes+i], vertexesl[v].xpos/64.0f, vertexesl[v].ypos/64.0f); + VectorSet(mesh->xyz_array[mesh->numvertexes+i], dm->vertexes[v].xpos, dm->vertexes[v].ypos, ceilheight); + Vector2Set(mesh->st_array[mesh->numvertexes+i], dm->vertexes[v].xpos/64.0f, dm->vertexes[v].ypos/64.0f); *(unsigned int*)mesh->colors4b_array[mesh->numvertexes+i] = col; } @@ -938,7 +952,7 @@ static void R_DrawFlats(int floortexnum, int floorheight, int ceiltexnum, int ce } } -static void R_DrawSSector(unsigned int ssec) +static void R_DrawSSector(doommap_t *dm, unsigned int ssec) { short v0, v1; int sd; @@ -946,68 +960,72 @@ static void R_DrawSSector(unsigned int ssec) int seg; msector_t *sec, *sec2; - for (seg = ssectorsl[ssec].first + ssectorsl[ssec].segcount-1; seg >= ssectorsl[ssec].first; seg--) - if (segsl[seg].linedef != 0xffff) + for (seg = dm->ssector[ssec].first + dm->ssector[ssec].segcount-1; seg >= dm->ssector[ssec].first; seg--) + if (dm->seg[seg].linedef != 0xffff) break; - sec = sectorm + sidedefsm[linedefsl[segsl[seg].linedef].sidedef[segsl[seg].direction]].sector; + sec = dm->sector + dm->sidedef[dm->linedef[dm->seg[seg].linedef].sidedef[dm->seg[seg].direction]].sector; if (sec->visframe != r_visframecount) { - R_DrawFlats(sec->floortex, sec->floorheight, sec->ceilingtex, sec->ceilingheight, sec->numflattris*3, sec->flats, sec->lightlev); + R_DrawFlats(dm, sec->floortex, sec->floorheight, sec->ceilingtex, sec->ceilingheight, sec->numflattris*3, sec->flats, sec->lightlev); sec->visframe = r_visframecount; } - for (seg = ssectorsl[ssec].first + ssectorsl[ssec].segcount-1; seg >= ssectorsl[ssec].first; seg--) + for (seg = dm->ssector[ssec].first + dm->ssector[ssec].segcount-1; seg >= dm->ssector[ssec].first; seg--) { - if (segsl[seg].linedef == 0xffff) + if (dm->seg[seg].linedef == 0xffff) continue; - v0 = segsl[seg].vert[0]; - v1 = segsl[seg].vert[1]; + v0 = dm->seg[seg].vert[0]; + v1 = dm->seg[seg].vert[1]; if (v0==v1) continue; - ld = linedefsl + segsl[seg].linedef; - sd = ld->sidedef[segsl[seg].direction]; + ld = dm->linedef + dm->seg[seg].linedef; + sd = ld->sidedef[dm->seg[seg].direction]; if (ld->sidedef[1] != 0xffff) //we can see through this linedef { - sec2 = sectorm + sidedefsm[ld->sidedef[1-segsl[seg].direction]].sector; + sec2 = dm->sector + dm->sidedef[ld->sidedef[1-dm->seg[seg].direction]].sector; if (sec->floorheight < sec2->floorheight) { - R_DrawWall(sidedefsm[sd].lowertex, - sidedefsm[ld->sidedef[1-segsl[seg].direction]].texx, - sidedefsm[ld->sidedef[1-segsl[seg].direction]].texy, - vertexesl[v0].xpos, vertexesl[v0].ypos, sec->floorheight, - vertexesl[v1].xpos, vertexesl[v1].ypos, sec2->floorheight, ld->flags & LINEDEF_LOWERUNPEGGED, sec->lightlev); + R_DrawWall(dm, + dm->sidedef[sd].lowertex, + dm->sidedef[ld->sidedef[1-dm->seg[seg].direction]].texx, + dm->sidedef[ld->sidedef[1-dm->seg[seg].direction]].texy, + dm->vertexes[v0].xpos, dm->vertexes[v0].ypos, sec->floorheight, + dm->vertexes[v1].xpos, dm->vertexes[v1].ypos, sec2->floorheight, ld->flags & LINEDEF_LOWERUNPEGGED, sec->lightlev); } if (sec->ceilingheight > sec2->ceilingheight) { - R_DrawWall(sidedefsm[sd].uppertex, - sidedefsm[ld->sidedef[1-segsl[seg].direction]].texx, - sidedefsm[ld->sidedef[1-segsl[seg].direction]].texy, - vertexesl[v0].xpos, vertexesl[v0].ypos, sec2->ceilingheight, - vertexesl[v1].xpos, vertexesl[v1].ypos, sec->ceilingheight, ld->flags & LINEDEF_UPPERUNPEGGED, sec->lightlev); + R_DrawWall(dm, + dm->sidedef[sd].uppertex, + dm->sidedef[ld->sidedef[1-dm->seg[seg].direction]].texx, + dm->sidedef[ld->sidedef[1-dm->seg[seg].direction]].texy, + dm->vertexes[v0].xpos, dm->vertexes[v0].ypos, sec2->ceilingheight, + dm->vertexes[v1].xpos, dm->vertexes[v1].ypos, sec->ceilingheight, ld->flags & LINEDEF_UPPERUNPEGGED, sec->lightlev); } - if (sidedefsm[sd].middletex) + if (dm->sidedef[sd].middletex) { - R_DrawWall(sidedefsm[sd].middletex, - sidedefsm[ld->sidedef[segsl[seg].direction]].texx, - sidedefsm[ld->sidedef[segsl[seg].direction]].texy, - vertexesl[v1].xpos, vertexesl[v1].ypos, (sec2->ceilingheight < sec->ceilingheight)?sec2->ceilingheight:sec->ceilingheight, - vertexesl[v0].xpos, vertexesl[v0].ypos, (sec2->floorheight > sec->floorheight)?sec2->floorheight:sec->floorheight, false, sec->lightlev); + R_DrawWall(dm, + dm->sidedef[sd].middletex, + dm->sidedef[ld->sidedef[dm->seg[seg].direction]].texx, + dm->sidedef[ld->sidedef[dm->seg[seg].direction]].texy, + dm->vertexes[v1].xpos, dm->vertexes[v1].ypos, (sec2->ceilingheight < sec->ceilingheight)?sec2->ceilingheight:sec->ceilingheight, + dm->vertexes[v0].xpos, dm->vertexes[v0].ypos, (sec2->floorheight > sec->floorheight)?sec2->floorheight:sec->floorheight, false, sec->lightlev); } } else { //solid wall, draw full wall. - R_DrawWall(sidedefsm[sd].middletex, - sidedefsm[ld->sidedef[segsl[seg].direction]].texx, - sidedefsm[ld->sidedef[segsl[seg].direction]].texy, - vertexesl[v0].xpos, vertexesl[v0].ypos, sec->floorheight, - vertexesl[v1].xpos, vertexesl[v1].ypos, sec->ceilingheight, false, sec->lightlev); + R_DrawWall(dm, + dm->sidedef[sd].middletex, + dm->sidedef[ld->sidedef[dm->seg[seg].direction]].texx, + dm->sidedef[ld->sidedef[dm->seg[seg].direction]].texy, + dm->vertexes[v0].xpos, dm->vertexes[v0].ypos, sec->floorheight, + dm->vertexes[v1].xpos, dm->vertexes[v1].ypos, sec->ceilingheight, false, sec->lightlev); } } } @@ -1126,41 +1144,41 @@ void R_Set2DFrustum (void) } -static void R_RecursiveDoomNode(unsigned int node) +static void R_RecursiveDoomNode(doommap_t *dm, unsigned int node) { if (node & NODE_IS_SSECTOR) { - R_DrawSSector(node & ~NODE_IS_SSECTOR); + R_DrawSSector(dm, node & ~NODE_IS_SSECTOR); return; } - if (!R_Cull2DBox(nodel[node].x1lower, nodel[node].y1lower, nodel[node].x1upper, nodel[node].y1upper)||1) - R_RecursiveDoomNode(nodel[node].node1); - if (!R_Cull2DBox(nodel[node].x2lower, nodel[node].y2lower, nodel[node].x2upper, nodel[node].y2upper)||1) - R_RecursiveDoomNode(nodel[node].node2); + if (!R_Cull2DBox(dm->node[node].x1lower, dm->node[node].y1lower, dm->node[node].x1upper, dm->node[node].y1upper)||1) + R_RecursiveDoomNode(dm, dm->node[node].node1); + if (!R_Cull2DBox(dm->node[node].x2lower, dm->node[node].y2lower, dm->node[node].x2upper, dm->node[node].y2upper)||1) + R_RecursiveDoomNode(dm, dm->node[node].node2); } -void R_DoomWorld(void) +void R_DoomWorld(doommap_t *dm) { int texnum; doomtexture_t *t; - if (!nodel || !nodec) + if (!dm->node || !dm->numnodes) return; //err... buggy - for (texnum = 0; texnum < numdoomtextures; texnum++) //a hash table might be a good plan. + for (texnum = 0; texnum < dm->numtextures; texnum++) //a hash table might be a good plan. { - t = &doomtextures[texnum]; + t = &dm->textures[texnum]; t->mesh.numindexes = 0; t->mesh.numvertexes = 0; } r_visframecount++; - R_RecursiveDoomNode(nodec-1); + R_RecursiveDoomNode(dm, dm->numnodes-1); memset(cl.worldmodel->batches, 0, sizeof(cl.worldmodel->batches)); - for (texnum = 0; texnum < numdoomtextures; texnum++) //a hash table might be a good plan. + for (texnum = 0; texnum < dm->numtextures; texnum++) //a hash table might be a good plan. { - t = &doomtextures[texnum]; + t = &dm->textures[texnum]; if (t->mesh.numindexes && t->shader) { t->batch.next = cl.worldmodel->batches[t->shader->sort]; @@ -1296,7 +1314,7 @@ static void Triangulate_AddLine(int v1, int v2) //order makes a difference } } -static unsigned short *Triangulate_Finish(int *numtris, unsigned short *old, int oldindexcount) +static unsigned short *Triangulate_Finish(doommap_t *dm, int *numtris, unsigned short *old, int oldindexcount) { unsigned short *out; unsigned int v1, v2, v3, v; @@ -1329,8 +1347,8 @@ static unsigned short *Triangulate_Finish(int *numtris, unsigned short *old, int v1 = polyregions[r].vertex[v]; v2 = polyregions[r].vertex[(v+1)%(polyregions[r].numverts)]; v3 = polyregions[r].vertex[(v+2)%(polyregions[r].numverts)]; - a1 = atan2(vertexesl[v3].ypos - vertexesl[v2].ypos, vertexesl[v3].xpos - vertexesl[v2].xpos); - a2 = atan2(vertexesl[v1].ypos - vertexesl[v2].ypos, vertexesl[v1].xpos - vertexesl[v2].xpos); + a1 = atan2(dm->vertexes[v3].ypos - dm->vertexes[v2].ypos, dm->vertexes[v3].xpos - dm->vertexes[v2].xpos); + a2 = atan2(dm->vertexes[v1].ypos - dm->vertexes[v2].ypos, dm->vertexes[v1].xpos - dm->vertexes[v2].xpos); polyregions[r].angle += fabs(a1 - a2); } } @@ -1358,8 +1376,8 @@ static unsigned short *Triangulate_Finish(int *numtris, unsigned short *old, int } v3 = polyregions[r].vertex[v]; - a1 = atan2(vertexesl[v3].ypos - vertexesl[v2].ypos, vertexesl[v3].xpos - vertexesl[v2].xpos); - a2 = atan2(vertexesl[v1].ypos - vertexesl[v2].ypos, vertexesl[v1].xpos - vertexesl[v2].xpos); + a1 = atan2(dm->vertexes[v3].ypos - dm->vertexes[v2].ypos, dm->vertexes[v3].xpos - dm->vertexes[v2].xpos); + a2 = atan2(dm->vertexes[v1].ypos - dm->vertexes[v2].ypos, dm->vertexes[v1].xpos - dm->vertexes[v2].xpos); if (fabs(a1-a2) > M_PI+0.01) //this would be a reflex angle then.;. { /* indexes[numindexes++] = 0; @@ -1413,86 +1431,86 @@ static unsigned short *Triangulate_Finish(int *numtris, unsigned short *old, int return out; } -static void Triangulate_Sectors(model_t *mod, dsector_t *sectorl, qboolean glbspinuse) +static void Triangulate_Sectors(doommap_t *dm, dsector_t *sectorl, qboolean glbspinuse) { int seg, nsec; int i, sec=-1; - sectorm = Z_Malloc(sectorc * sizeof(*sectorm)); + dm->sector = Z_Malloc(dm->numsectors * sizeof(*dm->sector)); if (glbspinuse) { - for (i = 0; i < ssectorsc; i++) + for (i = 0; i < dm->numssectors; i++) { //only do linedefs. - for (seg = ssectorsl[i].first; seg < ssectorsl[i].first + ssectorsl[i].segcount; seg++) - if (segsl[seg].linedef != 0xffff) + for (seg = dm->ssector[i].first; seg < dm->ssector[i].first + dm->ssector[i].segcount; seg++) + if (dm->seg[seg].linedef != 0xffff) break; - if (seg == ssectorsl[i].first + ssectorsl[i].segcount) //throw a fit. + if (seg == dm->ssector[i].first + dm->ssector[i].segcount) //throw a fit. { Con_Printf("SubSector %i has absolutly no walls\n", i); continue; } - nsec = sidedefsm[linedefsl[segsl[seg].linedef].sidedef[segsl[seg].direction]].sector; + nsec = dm->sidedef[dm->linedef[dm->seg[seg].linedef].sidedef[dm->seg[seg].direction]].sector; if (sec != nsec) { if (sec>=0) - sectorm[sec].flats = Triangulate_Finish(§orm[sec].numflattris, sectorm[sec].flats, sectorm[sec].numflattris); + dm->sector[sec].flats = Triangulate_Finish(dm, &dm->sector[sec].numflattris, dm->sector[sec].flats, dm->sector[sec].numflattris); sec = nsec; } - for (seg = ssectorsl[i].first; seg < ssectorsl[i].first + ssectorsl[i].segcount; seg++) + for (seg = dm->ssector[i].first; seg < dm->ssector[i].first + dm->ssector[i].segcount; seg++) { //ignore direction, it's do do with the intersection rather than the draw direction. - Triangulate_AddLine(segsl[seg].vert[0], segsl[seg].vert[1]); + Triangulate_AddLine(dm->seg[seg].vert[0], dm->seg[seg].vert[1]); } } if (sec>=0) - sectorm[sec].flats = Triangulate_Finish(§orm[sec].numflattris, sectorm[sec].flats, sectorm[sec].numflattris); + dm->sector[sec].flats = Triangulate_Finish(dm, &dm->sector[sec].numflattris, dm->sector[sec].flats, dm->sector[sec].numflattris); } else { - for (sec = 0; sec < sectorc; sec++) + for (sec = 0; sec < dm->numsectors; sec++) { - for (i = 0; i < linedefsc; i++) + for (i = 0; i < dm->numlinedefs; i++) { - if (sidedefsm[linedefsl[i].sidedef[0]].sector == sec) - Triangulate_AddLine(linedefsl[i].vert[0], linedefsl[i].vert[1]); - if (linedefsl[i].sidedef[1] != 0xffff && sidedefsm[linedefsl[i].sidedef[1]].sector == sec) - Triangulate_AddLine(linedefsl[i].vert[1], linedefsl[i].vert[0]); + if (dm->sidedef[dm->linedef[i].sidedef[0]].sector == sec) + Triangulate_AddLine(dm->linedef[i].vert[0], dm->linedef[i].vert[1]); + if (dm->linedef[i].sidedef[1] != 0xffff && dm->sidedef[dm->linedef[i].sidedef[1]].sector == sec) + Triangulate_AddLine(dm->linedef[i].vert[1], dm->linedef[i].vert[0]); } - sectorm[sec].flats = Triangulate_Finish(§orm[sec].numflattris, sectorm[sec].flats, sectorm[sec].numflattris); + dm->sector[sec].flats = Triangulate_Finish(dm, &dm->sector[sec].numflattris, dm->sector[sec].flats, dm->sector[sec].numflattris); } } /* for (i = 0; i < ssectorsc; i++) { //only do linedefs. - seg = ssectorsl[i].first; - nsec = sidedefsm[linedefsl[segsl[seg].linedef].sidedef[segsl[seg].direction]].sector; + seg = dm->ssector[i].first; + nsec = dm->sidedef[dm->linedef[dm->seg[seg].linedef].sidedef[dm->seg[seg].direction]].sector; if (sec != nsec) { if (sec>=0) - sectorm[sec].flats = Triangulate_Finish(§orm[sec].numflattris); + dm->sector[sec].flats = Triangulate_Finish(&dm->sector[sec].numflattris); sec = nsec; } - for (seg = ssectorsl[i].first; seg < ssectorsl[i].first + ssectorsl[i].segcount; seg++) + for (seg = dm->ssector[i].first; seg < dm->ssector[i].first + dm->ssector[i].segcount; seg++) { //ignore direction, it's do do with the intersection rather than the draw direction. - Triangulate_AddLine(segsl[seg].vert[0], segsl[seg].vert[1]); + Triangulate_AddLine(dm->seg[seg].vert[0], dm->seg[seg].vert[1]); } } if (sec>=0) - sectorm[sec].flats = Triangulate_Finish(§orm[sec].numflattris); + dm->sector[sec].flats = Triangulate_Finish(&dm->sector[sec].numflattris); */ - for (i = 0; i < sectorc; i++) + for (i = 0; i < dm->numsectors; i++) { - sectorm[i].ceilingtex = Doom_LoadFlat(mod, sectorl[i].ceilingtexture); - sectorm[i].floortex = Doom_LoadFlat(mod, sectorl[i].floortexture); - sectorm[i].lightlev = sectorl[i].lightlevel; - sectorm[i].specialtype = sectorl[i].specialtype; - sectorm[i].tag = sectorl[i].tag; - sectorm[i].ceilingheight = sectorl[i].ceilingheight; - sectorm[i].floorheight = sectorl[i].floorheight; + dm->sector[i].ceilingtex = Doom_LoadFlat(dm, sectorl[i].ceilingtexture); + dm->sector[i].floortex = Doom_LoadFlat(dm, sectorl[i].floortexture); + dm->sector[i].lightlev = sectorl[i].lightlevel; + dm->sector[i].specialtype = sectorl[i].specialtype; + dm->sector[i].tag = sectorl[i].tag; + dm->sector[i].ceilingheight = sectorl[i].ceilingheight; + dm->sector[i].floorheight = sectorl[i].floorheight; } } @@ -1658,28 +1676,28 @@ static texid_t Doom_LoadPatchFromTexWad(char *name, void *texlump, unsigned shor return r_nulltex; } -static int Doom_LoadPatch(model_t *mod, char *name) +static int Doom_LoadPatch(doommap_t *dm, char *name) { qboolean hasalpha = false; int texnum; size_t nlen = strnlen(name, 8); - for (texnum = 0; texnum < numdoomtextures; texnum++) //a hash table might be a good plan. + for (texnum = 0; texnum < dm->numtextures; texnum++) //a hash table might be a good plan. { - if(!memcmp(name, doomtextures[texnum].name, nlen) && !doomtextures[texnum].name[nlen]) + if(!memcmp(name, dm->textures[texnum].name, nlen) && !dm->textures[texnum].name[nlen]) { return texnum; } } //couldn't find it. -// texnum = numdoomtextures; +// texnum = dm->numtextures; - doomtextures = BZ_Realloc(doomtextures, sizeof(*doomtextures)*((numdoomtextures+16)&~15)); - memset(doomtextures + numdoomtextures, 0, sizeof(doomtextures[numdoomtextures])); - numdoomtextures++; + dm->textures = BZ_Realloc(dm->textures, sizeof(*dm->textures)*((dm->numtextures+16)&~15)); + memset(dm->textures + dm->numtextures, 0, sizeof(dm->textures[dm->numtextures])); + dm->numtextures++; - memcpy(doomtextures[texnum].name, name, nlen); - doomtextures[texnum].name[nlen] = 0; + memcpy(dm->textures[texnum].name, name, nlen); + dm->textures[texnum].name[nlen] = 0; return texnum; } @@ -1687,65 +1705,67 @@ static int Doom_LoadPatch(model_t *mod, char *name) static void Doom_LoadShaders(void *ctx, void *data, size_t a, size_t b) { model_t *mod = ctx; + doommap_t *dm = mod->meshinfo; texnums_t tn; qboolean hasalpha = false; qboolean isflat; int texnum; char tmp[MAX_QPATH]; - for (texnum = 0; texnum < numdoomtextures; texnum++) //a hash table might be a good plan. + for (texnum = 0; texnum < dm->numtextures; texnum++) //a hash table might be a good plan. { - isflat = !strncmp(doomtextures[texnum].name, "flats/", 6); + isflat = !strncmp(dm->textures[texnum].name, "flats/", 6); memset(&tn, 0, sizeof(tn)); if (isflat) { - void *file = FS_LoadMallocFile(va2(tmp, sizeof(tmp), "%s.raw", doomtextures[texnum].name), NULL); + void *file = FS_LoadMallocFile(va2(tmp, sizeof(tmp), "%s.raw", dm->textures[texnum].name), NULL); if (file) { - tn.base = Image_GetTexture(doomtextures[texnum].name, NULL, 0, file, doompalette, 64, 64, TF_8PAL24); + tn.base = Image_GetTexture(dm->textures[texnum].name, NULL, 0, file, doompalette, 64, 64, TF_8PAL24); Z_Free(file); } - doomtextures[texnum].width = 64; - doomtextures[texnum].height = 64; + dm->textures[texnum].width = 64; + dm->textures[texnum].height = 64; } else { if (textures1 && !TEXVALID(tn.base)) - tn.base = Doom_LoadPatchFromTexWad(doomtextures[texnum].name, textures1, &doomtextures[texnum].width, &doomtextures[texnum].height, &hasalpha); + tn.base = Doom_LoadPatchFromTexWad(dm->textures[texnum].name, textures1, &dm->textures[texnum].width, &dm->textures[texnum].height, &hasalpha); if (textures2 && !TEXVALID(tn.base)) - tn.base = Doom_LoadPatchFromTexWad(doomtextures[texnum].name, textures2, &doomtextures[texnum].width, &doomtextures[texnum].height, &hasalpha); + tn.base = Doom_LoadPatchFromTexWad(dm->textures[texnum].name, textures2, &dm->textures[texnum].width, &dm->textures[texnum].height, &hasalpha); } if (!TEXVALID(tn.base)) { - doomtextures[texnum].width = 64; - doomtextures[texnum].height = 64; + dm->textures[texnum].width = 64; + dm->textures[texnum].height = 64; hasalpha = false; } if (hasalpha) - doomtextures[texnum].shader = R_RegisterShader(doomtextures[texnum].name, SUF_NONE, "{\n{\nmap $diffuse\nrgbgen vertex\nalphagen vertex\nalphafunc ge128\n}\n}\n"); + dm->textures[texnum].shader = R_RegisterShader(dm->textures[texnum].name, SUF_NONE, "{\n{\nmap $diffuse\nrgbgen vertex\nalphagen vertex\nalphafunc ge128\n}\n}\n"); else - doomtextures[texnum].shader = R_RegisterShader(doomtextures[texnum].name, SUF_NONE, "{\n{\nmap $diffuse\nrgbgen vertex\nalphagen vertex\n}\n}\n"); + dm->textures[texnum].shader = R_RegisterShader(dm->textures[texnum].name, SUF_NONE, "{\n{\nmap $diffuse\nrgbgen vertex\nalphagen vertex\n}\n}\n"); - R_BuildDefaultTexnums(&tn, doomtextures[texnum].shader); + R_BuildDefaultTexnums(&tn, dm->textures[texnum].shader); } }; static void Doom_Purge (struct model_s *mod) { int texnum; - for (texnum = 0; texnum < numdoomtextures; texnum++) + doommap_t *dm = mod->meshinfo; + for (texnum = 0; texnum < dm->numtextures; texnum++) { - BZ_Free(doomtextures[texnum].mesh.colors4b_array); - BZ_Free(doomtextures[texnum].mesh.st_array); - BZ_Free(doomtextures[texnum].mesh.xyz_array); - BZ_Free(doomtextures[texnum].mesh.indexes); + BZ_Free(dm->textures[texnum].mesh.colors4b_array); + BZ_Free(dm->textures[texnum].mesh.st_array); + BZ_Free(dm->textures[texnum].mesh.xyz_array); + BZ_Free(dm->textures[texnum].mesh.indexes); } - BZ_Free(doomtextures); - doomtextures = NULL; + BZ_Free(dm->textures); + dm->textures = NULL; } #endif -static void CleanWalls(model_t *mod, dsidedef_t *sidedefsl) +static void CleanWalls(doommap_t *dm, dsidedef_t *sidedefsl) { int i; char texname[64]; @@ -1753,62 +1773,62 @@ static void CleanWalls(model_t *mod, dsidedef_t *sidedefsl) char lastlower[9]="-"; char lastupper[9]="-"; int lastmidtex=0, lastuptex=0, lastlowtex=0; - sidedefsm = BZ_Malloc(sidedefsc * sizeof(*sidedefsm)); - for (i = 0; i < sidedefsc; i++) + dm->sidedef = BZ_Malloc(dm->numsidedefs * sizeof(*dm->sidedef)); + for (i = 0; i < dm->numsidedefs; i++) { #if 1//def GLQUAKE strncpy(texname, sidedefsl[i].middletex, 8); texname[8] = '\0'; if (!strcmp(texname, "-")) - sidedefsm[i].middletex = 0; + dm->sidedef[i].middletex = 0; else { if (!strncmp(texname, lastmiddle, 8)) - sidedefsm[i].middletex = lastmidtex; + dm->sidedef[i].middletex = lastmidtex; else { strncpy(lastmiddle, texname, 8); - sidedefsm[i].middletex = lastmidtex = Doom_LoadPatch(mod, texname); + dm->sidedef[i].middletex = lastmidtex = Doom_LoadPatch(dm, texname); } } strncpy(texname, sidedefsl[i].lowertex, 8); texname[8] = '\0'; if (!strcmp(texname, "-")) - sidedefsm[i].lowertex = 0; + dm->sidedef[i].lowertex = 0; else { if (!strncmp(texname, lastlower, 8)) - sidedefsm[i].lowertex = lastlowtex; + dm->sidedef[i].lowertex = lastlowtex; else { strncpy(lastlower, texname, 8); - sidedefsm[i].lowertex = lastlowtex = Doom_LoadPatch(mod, texname); + dm->sidedef[i].lowertex = lastlowtex = Doom_LoadPatch(dm, texname); } } strncpy(texname, sidedefsl[i].uppertex, 8); texname[8] = '\0'; if (!strcmp(texname, "-")) - sidedefsm[i].uppertex = 0; + dm->sidedef[i].uppertex = 0; else { if (!strncmp(texname, lastupper, 8)) - sidedefsm[i].uppertex = lastuptex; + dm->sidedef[i].uppertex = lastuptex; else { strncpy(lastupper, texname, 8); - sidedefsm[i].uppertex = lastuptex = Doom_LoadPatch(mod, texname); + dm->sidedef[i].uppertex = lastuptex = Doom_LoadPatch(dm, texname); } } #endif - sidedefsm[i].sector = sidedefsl[i].sector; - sidedefsm[i].texx = sidedefsl[i].texx; - sidedefsm[i].texy = sidedefsl[i].texy; + dm->sidedef[i].sector = sidedefsl[i].sector; + dm->sidedef[i].texx = sidedefsl[i].texx; + dm->sidedef[i].texy = sidedefsl[i].texy; } } -void QuakifyThings(model_t *mod, dthing_t *thingsl) +void QuakifyThings(doommap_t *dm) { int sector; int spawnflags; @@ -1826,9 +1846,9 @@ void QuakifyThings(model_t *mod, dthing_t *thingsl) "}\n"); ptr += strlen(ptr); - for (i = 0; i < thingsc; i++) + for (i = 0; i < dm->numthings; i++) { - switch(thingsl[i].type) + switch(dm->thing[i].type) { case THING_PLAYER: //fixme: spit out a coop spawn too. name = "info_player_start"; @@ -1866,26 +1886,26 @@ void QuakifyThings(model_t *mod, dthing_t *thingsl) break; default: - name = va2(thingname, sizeof(thingname), "thing_%i", thingsl[i].type); + name = va2(thingname, sizeof(thingname), "thing_%i", dm->thing[i].type); break; } - point[0] = thingsl[i].xpos; - point[1] = thingsl[i].ypos; + point[0] = dm->thing[i].xpos; + point[1] = dm->thing[i].ypos; point[2] = 0; - sector = Doom_SectorNearPoint(point); - zpos = sectorm[sector].floorheight + 24; //things have no z coord, so find the sector they're in + sector = Doom_SectorNearPoint(dm, point); + zpos = dm->sector[sector].floorheight + 24; //things have no z coord, so find the sector they're in spawnflags = SPAWNFLAG_NOT_EASY | SPAWNFLAG_NOT_MEDIUM | SPAWNFLAG_NOT_HARD | SPAWNFLAG_NOT_DEATHMATCH; - if (thingsl[i].flags & THING_EASY) + if (dm->thing[i].flags & THING_EASY) spawnflags -= SPAWNFLAG_NOT_EASY; - if (thingsl[i].flags & THING_MEDIUM) + if (dm->thing[i].flags & THING_MEDIUM) spawnflags -= SPAWNFLAG_NOT_MEDIUM; - if (thingsl[i].flags & THING_HARD) + if (dm->thing[i].flags & THING_HARD) spawnflags -= SPAWNFLAG_NOT_HARD; - if (thingsl[i].flags & THING_DEATHMATCH) + if (dm->thing[i].flags & THING_DEATHMATCH) spawnflags -= SPAWNFLAG_NOT_DEATHMATCH; - if (thingsl[i].flags & THING_DEAF) + if (dm->thing[i].flags & THING_DEAF) spawnflags |= 1; Q_snprintfz(ptr, newlump+sizeof(newlump)-ptr, "{\n" @@ -1895,17 +1915,17 @@ void QuakifyThings(model_t *mod, dthing_t *thingsl) "\"angle\" \"%i\"\n" "}\n", name, - thingsl[i].xpos, thingsl[i].ypos, zpos, + dm->thing[i].xpos, dm->thing[i].ypos, zpos, spawnflags, - thingsl[i].angle + dm->thing[i].angle ); ptr += strlen(ptr); } - Mod_SetEntitiesStringLen(mod, newlump, ptr-newlump); + Mod_SetEntitiesStringLen(dm->model, newlump, ptr-newlump); } -void Doom_GeneratePlanes(ddoomnode_t *nodel) +void Doom_GeneratePlanes(doommap_t *dm) { vec3_t point, up, line; int n; @@ -1913,29 +1933,29 @@ void Doom_GeneratePlanes(ddoomnode_t *nodel) up[1] = 0; up[2] = 1; line[2] = 0; - nodeplanes = BZ_Malloc(sizeof(*nodeplanes)*nodec); - lineplanes = BZ_Malloc(sizeof(*lineplanes)*linedefsc); + dm->nodeplane = BZ_Malloc(sizeof(*dm->nodeplane)*dm->numnodes); + dm->lineplane = BZ_Malloc(sizeof(*dm->lineplane)*dm->numlinedefs); point[2] = 0; - for (n = 0; n < nodec; n++) + for (n = 0; n < dm->numnodes; n++) { - line[0] = nodel[n].dx; - line[1] = nodel[n].dy; - point[0] = nodel[n].x; - point[1] = nodel[n].y; - CrossProduct(line, up, nodeplanes[n].normal); - VectorNormalize(nodeplanes[n].normal); - nodeplanes[n].dist = DotProduct (point, nodeplanes[n].normal); + line[0] = dm->node[n].dx; + line[1] = dm->node[n].dy; + point[0] = dm->node[n].x; + point[1] = dm->node[n].y; + CrossProduct(line, up, dm->nodeplane[n].normal); + VectorNormalize(dm->nodeplane[n].normal); + dm->nodeplane[n].dist = DotProduct (point, dm->nodeplane[n].normal); } - for (n = 0; n < linedefsc; n++) + for (n = 0; n < dm->numlinedefs; n++) { - point[0] = vertexesl[linedefsl[n].vert[0]].xpos; - point[1] = vertexesl[linedefsl[n].vert[0]].ypos; - line[0] = vertexesl[linedefsl[n].vert[1]].xpos-point[0]; - line[1] = vertexesl[linedefsl[n].vert[1]].ypos-point[1]; - CrossProduct(line, up, lineplanes[n].normal); - VectorNormalize(lineplanes[n].normal); - lineplanes[n].dist = DotProduct (point, lineplanes[n].normal); + point[0] = dm->vertexes[dm->linedef[n].vert[0]].xpos; + point[1] = dm->vertexes[dm->linedef[n].vert[0]].ypos; + line[0] = dm->vertexes[dm->linedef[n].vert[1]].xpos-point[0]; + line[1] = dm->vertexes[dm->linedef[n].vert[1]].ypos-point[1]; + CrossProduct(line, up, dm->lineplane[n].normal); + VectorNormalize(dm->lineplane[n].normal); + dm->lineplane[n].dist = DotProduct (point, dm->lineplane[n].normal); } } @@ -1944,7 +1964,7 @@ doom maps have no network limitations, but has +/-32767 map size limits (same as fte defaults to a +/- 4096 world a lot of maps are off-centered and can be moved to get them to fit fte's constraints, so if we can, do so */ -static void MoveWorld(void) +static void MoveWorld(doommap_t *dm) { int v; short adj[2]; @@ -1954,17 +1974,17 @@ static void MoveWorld(void) max[0] = -4096; max[1] = -4096; - for (v = 0; v < vertexesc; v++) + for (v = 0; v < dm->numvertexes; v++) { - if (min[0] > vertexesl[v].xpos) - min[0] = vertexesl[v].xpos; - if (min[1] > vertexesl[v].ypos) - min[1] = vertexesl[v].ypos; + if (min[0] > dm->vertexes[v].xpos) + min[0] = dm->vertexes[v].xpos; + if (min[1] > dm->vertexes[v].ypos) + min[1] = dm->vertexes[v].ypos; - if (max[0] < vertexesl[v].xpos) - max[0] = vertexesl[v].xpos; - if (max[1] < vertexesl[v].ypos) - max[1] = vertexesl[v].ypos; + if (max[0] < dm->vertexes[v].xpos) + max[0] = dm->vertexes[v].xpos; + if (max[1] < dm->vertexes[v].ypos) + max[1] = dm->vertexes[v].ypos; } if (min[0]>=-4096 && max[0]<=4096) @@ -1982,40 +2002,40 @@ static void MoveWorld(void) Con_Printf("Adjusting map (%i %i)\n", -adj[0], -adj[1]); - for (v = 0; v < vertexesc; v++) + for (v = 0; v < dm->numvertexes; v++) { - vertexesl[v].xpos -= adj[0]; - vertexesl[v].ypos -= adj[1]; + dm->vertexes[v].xpos -= adj[0]; + dm->vertexes[v].ypos -= adj[1]; } - for (v = 0; v < nodec; v++) + for (v = 0; v < dm->numnodes; v++) { - nodel[v].x -= adj[0]; - nodel[v].y -= adj[1]; + dm->node[v].x -= adj[0]; + dm->node[v].y -= adj[1]; - nodel[v].x1lower -= adj[0]; - nodel[v].x1upper -= adj[1]; - nodel[v].y1lower -= adj[0]; - nodel[v].y1upper -= adj[1]; + dm->node[v].x1lower -= adj[0]; + dm->node[v].x1upper -= adj[1]; + dm->node[v].y1lower -= adj[0]; + dm->node[v].y1upper -= adj[1]; - nodel[v].x2lower -= adj[0]; - nodel[v].x2upper -= adj[1]; - nodel[v].y2lower -= adj[0]; - nodel[v].y2upper -= adj[1]; + dm->node[v].x2lower -= adj[0]; + dm->node[v].x2upper -= adj[1]; + dm->node[v].y2lower -= adj[0]; + dm->node[v].y2upper -= adj[1]; } - for (v = 0; v < thingsc; v++) + for (v = 0; v < dm->numthings; v++) { - thingsl[v].xpos -= adj[0]; - thingsl[v].ypos -= adj[1]; + dm->thing[v].xpos -= adj[0]; + dm->thing[v].ypos -= adj[1]; } - blockmapl->xorg -= adj[0]; - blockmapl->yorg -= adj[1]; + dm->blockmap->xorg -= adj[0]; + dm->blockmap->yorg -= adj[1]; } -static void Doom_LoadVerticies(char *name) +static void Doom_LoadVerticies(doommap_t *dm, char *name) { ddoomvertex_t *std, *gl1; int stdc, glc; @@ -2047,30 +2067,30 @@ static void Doom_LoadVerticies(char *name) if (stdc) { - vertexesc = stdc + glc; - vertexesl = BZ_Malloc(vertexesc*sizeof(*vertexesl)); + dm->numvertexes = stdc + glc; + dm->vertexes = BZ_Malloc(dm->numvertexes*sizeof(*dm->vertexes)); - vertexsglbase = stdc; + dm->vertexsglbase = stdc; for (i = 0; i < stdc; i++) { - vertexesl[i].xpos = std[i].xpos; - vertexesl[i].ypos = std[i].ypos; + dm->vertexes[i].xpos = std[i].xpos; + dm->vertexes[i].ypos = std[i].ypos; } if (gl1) { for (i = 0; i < glc; i++) { - vertexesl[stdc+i].xpos = gl1[i].xpos; - vertexesl[stdc+i].ypos = gl1[i].ypos; + dm->vertexes[stdc+i].xpos = gl1[i].xpos; + dm->vertexes[stdc+i].ypos = gl1[i].ypos; } } else { for (i = 0; i < glc; i++) { - vertexesl[stdc+i].xpos = (float)gl2[i*2] / 0x10000; - vertexesl[stdc+i].ypos = (float)gl2[i*2+1] / 0x10000; + dm->vertexes[stdc+i].xpos = (float)gl2[i*2] / 0x10000; + dm->vertexes[stdc+i].ypos = (float)gl2[i*2+1] / 0x10000; } } } @@ -2078,18 +2098,18 @@ static void Doom_LoadVerticies(char *name) Z_Free(gl2); } -static void Doom_LoadSSectors(char *name) +static void Doom_LoadSSectors(doommap_t *dm, char *name) { size_t fsize; char tmp[MAX_QPATH]; - ssectorsl = (void *)FS_LoadMallocFile (va2(tmp, sizeof(tmp), "%s.gl_ssect", name), &fsize); - if (!ssectorsl) - ssectorsl = (void *)FS_LoadMallocFile (va2(tmp, sizeof(tmp), "%s.ssectors", name), &fsize); + dm->ssector = (void *)FS_LoadMallocFile (va2(tmp, sizeof(tmp), "%s.gl_ssect", name), &fsize); + if (!dm->ssector) + dm->ssector = (void *)FS_LoadMallocFile (va2(tmp, sizeof(tmp), "%s.ssectors", name), &fsize); //FIXME: "gNd3" means that it's glbsp version 3. - ssectorsc = fsize/sizeof(*ssectorsl); + dm->numssectors = fsize/sizeof(*dm->ssector); } -static void Doom_LoadSSegs(char *name) +static void Doom_LoadSSegs(doommap_t *dm, char *name) { //these skirt the subsectors void *file; @@ -2104,49 +2124,49 @@ static void Doom_LoadSSegs(char *name) if (!file) { s0 = (void *)FS_LoadMallocFile (va2(tmp, sizeof(tmp), "%s.segs", name), &fsize); - segsc = fsize/sizeof(*s0); + dm->numsegs = fsize/sizeof(*s0); - segsl = BZ_Malloc(segsc * sizeof(*segsl)); - for (i = 0; i < segsc; i++) + dm->seg = BZ_Malloc(dm->numsegs * sizeof(*dm->seg)); + for (i = 0; i < dm->numsegs; i++) { - segsl[i].vert[0] = s0[i].vert[0]; - segsl[i].vert[1] = s0[i].vert[1]; - segsl[i].linedef = s0[i].linedef; - segsl[i].direction = s0[i].direction; - segsl[i].Partner = 0xffff; + dm->seg[i].vert[0] = s0[i].vert[0]; + dm->seg[i].vert[1] = s0[i].vert[1]; + dm->seg[i].linedef = s0[i].linedef; + dm->seg[i].direction = s0[i].direction; + dm->seg[i].Partner = 0xffff; } } else if (*(int *)file == *(int *)"gNd3") { s3 = file; - segsc = fsize/sizeof(*s3); + dm->numsegs = fsize/sizeof(*s3); - segsl = s3; + dm->seg = s3; } else if (!file) return; else { s1 = file; - segsc = fsize/sizeof(*s1); + dm->numsegs = fsize/sizeof(*s1); - segsl = BZ_Malloc(segsc * sizeof(*segsl)); - for (i = 0; i < segsc; i++) + dm->seg = BZ_Malloc(dm->numsegs * sizeof(*dm->seg)); + for (i = 0; i < dm->numsegs; i++) { if (s1[i].vert[0] & 0x8000) - segsl[i].vert[0] = (s1[i].vert[0]&0x7fff)+vertexsglbase; + dm->seg[i].vert[0] = (s1[i].vert[0]&0x7fff)+dm->vertexsglbase; else - segsl[i].vert[0] = s1[i].vert[0]; + dm->seg[i].vert[0] = s1[i].vert[0]; if (s1[i].vert[1] & 0x8000) - segsl[i].vert[1] = (s1[i].vert[1]&0x7fff)+vertexsglbase; + dm->seg[i].vert[1] = (s1[i].vert[1]&0x7fff)+dm->vertexsglbase; else - segsl[i].vert[1] = s1[i].vert[1]; - segsl[i].linedef = s1[i].linedef; - segsl[i].direction = s1[i].direction; + dm->seg[i].vert[1] = s1[i].vert[1]; + dm->seg[i].linedef = s1[i].linedef; + dm->seg[i].direction = s1[i].direction; if (s1[i].Partner == 0xffff) - segsl[i].Partner = 0xffffffff; + dm->seg[i].Partner = 0xffffffff; else - segsl[i].Partner = s1[i].Partner; + dm->seg[i].Partner = s1[i].Partner; } } } @@ -2158,6 +2178,7 @@ qboolean QDECL Mod_LoadDoomLevel(model_t *mod, void *buffer, size_t fsize) dsidedef_t *sidedefsl; char name[MAX_QPATH]; char tmp[MAX_QPATH]; + doommap_t *dm; int *gl_nodes; @@ -2167,57 +2188,61 @@ qboolean QDECL Mod_LoadDoomLevel(model_t *mod, void *buffer, size_t fsize) return false; } + dm = Z_Malloc(sizeof(*dm)); + dm->model = mod; + mod->meshinfo = dm; + COM_StripExtension(mod->name, name, sizeof(name)); gl_nodes = (void *)FS_LoadMallocFile (va2(tmp,sizeof(tmp),"%s.gl_nodes", name), &fsize); if (gl_nodes && fsize>0) { - nodel = (void *)gl_nodes; - nodec = fsize/sizeof(*nodel); + dm->node = (void *)gl_nodes; + dm->numnodes = fsize/sizeof(*dm->node); } else { gl_nodes=NULL; - nodel = (void *)FS_LoadMallocFile (va2(tmp,sizeof(tmp),"%s.nodes", name), &fsize); - nodec = fsize/sizeof(*nodel); + dm->node = (void *)FS_LoadMallocFile (va2(tmp,sizeof(tmp),"%s.nodes", name), &fsize); + dm->numnodes = fsize/sizeof(*dm->node); } sectorl = (void *)FS_LoadMallocFile (va2(tmp,sizeof(tmp),"%s.sectors", name), &fsize); - sectorc = fsize/sizeof(*sectorl); + dm->numsectors = fsize/sizeof(*sectorl); #ifndef SERVERONLY - numdoomtextures=0; + dm->numtextures=0; Doom_LoadPalette(); #endif - Doom_LoadVerticies(name); + Doom_LoadVerticies(dm, name); - Doom_LoadSSegs(name); - Doom_LoadSSectors(name); + Doom_LoadSSegs(dm, name); + Doom_LoadSSectors(dm, name); - thingsl = (void *)FS_LoadMallocFile (va2(tmp,sizeof(tmp),"%s.things", name), &fsize); - thingsc = fsize/sizeof(*thingsl); - linedefsl = (void *)FS_LoadMallocFile (va2(tmp,sizeof(tmp),"%s.linedefs", name), &fsize); - linedefsc = fsize/sizeof(*linedefsl); + dm->thing = (void *)FS_LoadMallocFile (va2(tmp,sizeof(tmp),"%s.things", name), &fsize); + dm->numthings = fsize/sizeof(*dm->thing); + dm->linedef = (void *)FS_LoadMallocFile (va2(tmp,sizeof(tmp),"%s.linedefs", name), &fsize); + dm->numlinedefs = fsize/sizeof(*dm->linedef); sidedefsl = (void *)FS_LoadMallocFile (va2(tmp,sizeof(tmp),"%s.sidedefs", name), &fsize); - sidedefsc = fsize/sizeof(*sidedefsl); - blockmapl = (void *)FS_LoadMallocFile (va2(tmp,sizeof(tmp),"%s.blockmap", name), &fsize); + dm->numsidedefs = fsize/sizeof(*sidedefsl); + dm->blockmap = (void *)FS_LoadMallocFile (va2(tmp,sizeof(tmp),"%s.blockmap", name), &fsize); // blockmaps = fsize; #ifndef SERVERONLY Doom_LoadTextureInfos(); #endif - blockmapofs = (unsigned short*)(blockmapl+1); + dm->blockmapofs = (unsigned short*)(dm->blockmap+1); - if (!nodel || !sectorl || !segsl || !ssectorsl || !thingsl || !linedefsl || !sidedefsl || !vertexesl) + if (!dm->node || !sectorl || !dm->seg || !dm->ssector || !dm->thing || !dm->linedef || !sidedefsl || !dm->vertexes) { Sys_Error("Wad map doesn't contain enough lumps\n"); - nodel = NULL; + dm->node = NULL; return false; } - MoveWorld(); + MoveWorld(dm); - Doom_GeneratePlanes(nodel); + Doom_GeneratePlanes(dm); mod->hulls[0].clip_mins[0] = 0; mod->hulls[0].clip_mins[1] = 0; @@ -2236,11 +2261,11 @@ qboolean QDECL Mod_LoadDoomLevel(model_t *mod, void *buffer, size_t fsize) mod->type = mod_brush; mod->nodes = (void*)0x1; - CleanWalls(mod, sidedefsl); + CleanWalls(dm, sidedefsl); - Triangulate_Sectors(mod, sectorl, !!gl_nodes); + Triangulate_Sectors(dm, sectorl, !!gl_nodes); - QuakifyThings(mod, thingsl); + QuakifyThings(dm); COM_AddWork(WG_MAIN, Doom_LoadShaders, mod, NULL, 0, 0); return true; @@ -2248,8 +2273,9 @@ qboolean QDECL Mod_LoadDoomLevel(model_t *mod, void *buffer, size_t fsize) void Doom_LightPointValues(model_t *model, vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir) { + doommap_t *dm = model->meshinfo; msector_t *sec; - sec = sectorm + Doom_SectorNearPoint(point); + sec = dm->sector + Doom_SectorNearPoint(dm, point); res_dir[0] = 0; res_dir[1] = 1; @@ -2263,7 +2289,7 @@ void Doom_LightPointValues(model_t *model, vec3_t point, vec3_t res_diffuse, vec } //return pvs bits for point -unsigned int Doom_FatPVS(struct model_s *model, vec3_t org, qbyte *pvsbuffer, unsigned int buffersize, qboolean merge) +unsigned int Doom_FatPVS(struct model_s *model, vec3_t org, pvsbuffer_t *pvsbuffer, qboolean merge) { //FIXME: use REJECT lump. return 0; diff --git a/engine/gl/glquake.h b/engine/gl/glquake.h index 0c132c4b0..5ac098ec7 100644 --- a/engine/gl/glquake.h +++ b/engine/gl/glquake.h @@ -1079,7 +1079,7 @@ void GL_SelectProgram(int program); -void GL_Init(void *(*getglfunction) (char *name)); +void GL_Init(rendererstate_t *info, void *(*getglfunction) (char *name)); #endif diff --git a/engine/gl/glsupp.h b/engine/gl/glsupp.h index d493caa1f..218efe0da 100644 --- a/engine/gl/glsupp.h +++ b/engine/gl/glsupp.h @@ -610,8 +610,29 @@ typedef void (APIENTRYP PFNGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei #define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20B2 #define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9 #define GL_FRAMEBUFFER_SRGB 0x8DB9 +#define GL_FRAMEBUFFER_SRGB_CAPABLE 0x8DBA #endif +#ifndef GL_EXT_texture_sRGB +#define GL_EXT_texture_sRGB 1 +#define GL_SRGB_EXT 0x8C40 +#define GL_SRGB8_EXT 0x8C41 +#define GL_SRGB_ALPHA_EXT 0x8C42 +#define GL_SRGB8_ALPHA8_EXT 0x8C43 +#define GL_SLUMINANCE_ALPHA_EXT 0x8C44 +#define GL_SLUMINANCE8_ALPHA8_EXT 0x8C45 +#define GL_SLUMINANCE_EXT 0x8C46 +#define GL_SLUMINANCE8_EXT 0x8C47 +#define GL_COMPRESSED_SRGB_EXT 0x8C48 +#define GL_COMPRESSED_SRGB_ALPHA_EXT 0x8C49 +#define GL_COMPRESSED_SLUMINANCE_EXT 0x8C4A +#define GL_COMPRESSED_SLUMINANCE_ALPHA_EXT 0x8C4B +#define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT 0x8C4C +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F +#endif /* GL_EXT_texture_sRGB */ + #ifndef GL_ARB_pixel_buffer_object #define GL_PIXEL_PACK_BUFFER_ARB 0x88EB #define GL_PIXEL_UNPACK_BUFFER_ARB 0x88EC diff --git a/engine/gl/shader.h b/engine/gl/shader.h index 0733bbb2a..6b2ad2fe1 100644 --- a/engine/gl/shader.h +++ b/engine/gl/shader.h @@ -294,17 +294,20 @@ typedef struct shaderpass_s { SHADER_PASS_NEAREST = 1<<2, //needed for d3d's sampler states, MUST MATCH IMAGE FLAGS SHADER_PASS_LINEAR = 1<<3, //needed for d3d's sampler states, MUST MATCH IMAGE FLAGS SHADER_PASS_UIPIC = 1<<4, // MUST MATCH IMAGE FLAGS -#define SHADER_PASS_IMAGE_FLAGS (SHADER_PASS_CLAMP|SHADER_PASS_NOMIPMAP|SHADER_PASS_NEAREST|SHADER_PASS_LINEAR|SHADER_PASS_UIPIC) + SHADER_PASS_DEPTHCMP = 1<<5, //needed for d3d11's sampler states + SHADER_PASS_SRGB = 1<<6, //d3d9 does srgb via samplers. everyone else does it via texture formats +#define SHADER_PASS_IMAGE_FLAGS_D3D8 (SHADER_PASS_CLAMP|SHADER_PASS_NOMIPMAP|SHADER_PASS_NEAREST|SHADER_PASS_LINEAR|SHADER_PASS_UIPIC) +#define SHADER_PASS_IMAGE_FLAGS_D3D9 (SHADER_PASS_CLAMP|SHADER_PASS_NOMIPMAP|SHADER_PASS_NEAREST|SHADER_PASS_LINEAR|SHADER_PASS_UIPIC|SHADER_PASS_SRGB) +#define SHADER_PASS_IMAGE_FLAGS_D3D11 (SHADER_PASS_CLAMP|SHADER_PASS_NOMIPMAP|SHADER_PASS_NEAREST|SHADER_PASS_LINEAR|SHADER_PASS_UIPIC|SHADER_PASS_DEPTHCMP) //NEEDS to be tightly-packed. indexing will bug out otherwise. - SHADER_PASS_DEPTHCMP = 1<<5, //needed for d3d's sampler states - SHADER_PASS_NOCOLORARRAY = 1<<6, + SHADER_PASS_NOCOLORARRAY = 1<<7, //FIXME: remove these - SHADER_PASS_VIDEOMAP = 1 << 7, - SHADER_PASS_DETAIL = 1 << 8, - SHADER_PASS_LIGHTMAP = 1 << 9, - SHADER_PASS_DELUXMAP = 1 << 10, - SHADER_PASS_ANIMMAP = 1 << 11 + SHADER_PASS_VIDEOMAP = 1 << 8, + SHADER_PASS_DETAIL = 1 << 9, + SHADER_PASS_LIGHTMAP = 1 << 10, + SHADER_PASS_DELUXMAP = 1 << 11, + SHADER_PASS_ANIMMAP = 1 << 12 } flags; #if defined(D3D11QUAKE) || defined(VKQUAKE) diff --git a/engine/qclib/decomp.c b/engine/qclib/decomp.c index d95dfc840..653713bfe 100644 --- a/engine/qclib/decomp.c +++ b/engine/qclib/decomp.c @@ -2,8 +2,10 @@ #include "qcc.h" //#include "decomp.h" +//This file is derived from frikdec, but has some extra tweaks to make it more friendly with fte's compiler/opcodes (its not perfect though) //FIXME: there's still a load of mallocs, so we don't allow this more than once per process. //convert vector terms into floats when its revealed that they're using vector ops and not floats +//FIXME: fteqcc converts do {} while(1); into a goto -1; which is a really weeeird construct. #if defined(_WIN32) || defined(__DJGPP__) #include @@ -14,9 +16,8 @@ #undef printf #define printf GUIprintf -#define OPF_FORSTART OP_NUMOPS -#define OP_MARK_END_DO 40000 -#define OP_MARK_END_ELSE 1000 +#define OP_MARK_END_DO 0x00010000 //do{ +#define OP_MARK_END_ELSE 0x00000400 //} #define MAX_REGS 65536 #define dstatement_t QCC_dstatement32_t @@ -571,7 +572,9 @@ int DecompileReadData(char *srcfilename, char *buf, size_t bufsize) else statements[i].a = (unsigned short)statements6[i].a; - if (statements[i].op == OP_IF_I || statements[i].op == OP_IFNOT_I || statements[i].op == OP_IF_F || statements[i].op == OP_IFNOT_F || statements[i].op == OP_IF_S || statements[i].op == OP_IFNOT_S) + if (statements[i].op == OP_IF_I || statements[i].op == OP_IFNOT_I || + statements[i].op == OP_IF_F || statements[i].op == OP_IFNOT_F || + statements[i].op == OP_IF_S || statements[i].op == OP_IFNOT_S) statements[i].b = (signed short)statements6[i].b; else statements[i].b = (unsigned short)statements6[i].b; @@ -801,7 +804,8 @@ DecompileAlreadySeen(char *fname, vfile_t **rfile) ret = 0; if (rfile) { - *rfile = QCC_AddVFile(fname, NULL, 0); + char *header = "//Decompiled code. Please respect the original copyright.\n"; + *rfile = QCC_AddVFile(fname, header, strlen(header)); AddSourceFile("progs.src", fname); } } @@ -1239,6 +1243,7 @@ gofs_t DecompileScaleIndex(dfunction_t *df, gofs_t ofs) if ((nofs < 0) || (nofs > MAX_REGS - 1)) { printf("Fatal Error - Index (%i) out of bounds.\n", nofs); + return 0; exit(1); } @@ -1538,7 +1543,7 @@ void DecompileDecompileStatement(dfunction_t * df, dstatement_t * s, int *indent char *arg1, *arg2, *arg3; int nargs, i, j; dstatement_t *t; - unsigned short dom, doc, ifc, tom; + unsigned int dom, doc, ifc, tom; QCC_type_t *typ1, *typ2, *typ3; QCC_ddef_t *par; dstatement_t *k; @@ -1879,13 +1884,15 @@ void DecompileDecompileStatement(dfunction_t * df, dstatement_t * s, int *indent QCC_CatVFile(Decompileofile, "%s;\n", line); } } - else if (s->op == OP_IF_I || s->op == OP_IFNOT_I || s->op == OP_IF_F || s->op == OP_IFNOT_F/* || s->op == OPQF_IFA || s->op == OPQF_IFB || s->op == OPQF_IFAE || s->op == OPQF_IFBE*/) + else if (s->op == OP_IF_I || s->op == OP_IFNOT_I || + s->op == OP_IF_F || s->op == OP_IFNOT_F || + s->op == OP_IF_S || s->op == OP_IFNOT_S/* || s->op == OPQF_IFA || s->op == OPQF_IFB || s->op == OPQF_IFAE || s->op == OPQF_IFBE*/) { arg1 = DecompileGet(df, s->a, type_float); //FIXME: this isn't quite accurate... arg2 = DecompileGlobal(df, s->a, NULL); - if (s->op == OP_IFNOT_I || s->op == OP_IFNOT_F) + if (s->op == OP_IFNOT_I || s->op == OP_IFNOT_F || s->op == OP_IFNOT_S) { lameifnot: if ((signed int)s->b < 1) @@ -1964,7 +1971,10 @@ void DecompileDecompileStatement(dfunction_t * df, dstatement_t * s, int *indent for (k = t + (signed int)(t->a); k < s; k++) { tom = k->op % OP_MARK_END_ELSE; - if (tom == OP_GOTO || tom == OP_IF_I || tom == OP_IFNOT_I || tom == OP_IF_F || tom == OP_IFNOT_F) + if (tom == OP_GOTO || + tom == OP_IF_I || tom == OP_IFNOT_I || + tom == OP_IF_F || tom == OP_IFNOT_F || + tom == OP_IF_S || tom == OP_IFNOT_S) dum = 0; } if (dum) @@ -2050,7 +2060,7 @@ void DecompileDecompileStatement(dfunction_t * df, dstatement_t * s, int *indent } } - else if (s->op == OPF_FORSTART) + else if (s->op == OPD_GOTO_FORSTART) { DecompileIndent(*indent); QCC_CatVFile(Decompileofile, "do_tail\n", (s-statements) + (signed int)s->a); @@ -2058,6 +2068,12 @@ void DecompileDecompileStatement(dfunction_t * df, dstatement_t * s, int *indent QCC_CatVFile(Decompileofile, "{\n"); (*indent)++; } + else if (s->op == OPD_GOTO_WHILE1) + { + (*indent)--; + DecompileIndent(*indent); + QCC_CatVFile(Decompileofile, "} while(1);\n"); + } else if (s->op == OP_GOTO) { @@ -2592,6 +2608,27 @@ void DecompileFunction(const char *name, int *lastglobal) ts = ds + (signed int)ds->a; ts->op += OP_MARK_END_ELSE; // mark the end of a if/ite construct } + else + { + ts = ds + (signed int)ds->a; + //if its a negative goto then it should normally be the end of a while{} loop. if we can't find the while statement itself, then its an infinite loop + for (k = (ts); k < ds; k++) + { + tom = k->op % OP_MARK_END_ELSE; + if (tom == OP_IF_I || tom == OP_IFNOT_I || + tom == OP_IF_F || tom == OP_IFNOT_F || + tom == OP_IF_S || tom == OP_IFNOT_S) + { + if (k + (signed int)k->b == ds+1) + break; + } + } + if (k == ds) + { + ds->op += OPD_GOTO_WHILE1-OP_GOTO; + ts->op += OP_MARK_END_DO; + } + } } else if (dom == OP_IFNOT_I || dom == OP_IFNOT_F || dom == OP_IFNOT_S) { @@ -2616,7 +2653,10 @@ void DecompileFunction(const char *name, int *lastglobal) for (k = (ts - 1) + (signed int)((ts - 1)->a); k < ds; k++) { tom = k->op % OP_MARK_END_ELSE; - if (tom == OP_GOTO || tom == OP_IF_I || tom == OP_IFNOT_I || tom == OP_IF_F || tom == OP_IFNOT_F) + if (tom == OP_GOTO || + tom == OP_IF_I || tom == OP_IFNOT_I || + tom == OP_IF_F || tom == OP_IFNOT_F || + tom == OP_IF_S || tom == OP_IFNOT_S) dum = 0; } if (!dum) @@ -2637,7 +2677,7 @@ void DecompileFunction(const char *name, int *lastglobal) //if the statement before the 'do' is a forwards goto, and it jumps to within the loop (instead of after), then we have to assume that it is a for loop and not a loop inside an else block. if ((ts-1)->op%OP_MARK_END_ELSE == OP_GOTO && (signed int)(ts-1)->a > 0 && (ts-1)+(signed int)(ts-1)->a <= ds) { - (--ts)->op += OPF_FORSTART - OP_GOTO; + (--ts)->op += OPD_GOTO_FORSTART - OP_GOTO; //because it was earlier, we need to unmark that goto's target as an end_else ts = ts + (signed int)ts->a; ts->op -= OP_MARK_END_ELSE; @@ -2664,7 +2704,10 @@ void DecompileFunction(const char *name, int *lastglobal) for (k = (ts - 1) + (signed int)((ts - 1)->a); k < ds; k++) { tom = k->op % OP_MARK_END_ELSE; - if (tom == OP_GOTO || tom == OP_IF_I || tom == OP_IFNOT_I || tom == OP_IF_F || tom == OP_IFNOT_F) + if (tom == OP_GOTO || + tom == OP_IF_I || tom == OP_IFNOT_I || + tom == OP_IF_F || tom == OP_IFNOT_F || + tom == OP_IF_S || tom == OP_IFNOT_S) dum = 0; } if (!dum) @@ -3031,7 +3074,9 @@ void DecompilePrintStatement(dstatement_t * s) for (; i < 10; i++) printf(" "); - if (s->op == OP_IF_I || s->op == OP_IFNOT_I || s->op == OP_IF_F || s->op == OP_IFNOT_F) + if (s->op == OP_IF_I || s->op == OP_IFNOT_I || + s->op == OP_IF_F || s->op == OP_IFNOT_F || + s->op == OP_IF_S || s->op == OP_IFNOT_S) printf("%sbranch %i", DecompileGlobalString(s->a), s->b); else if (s->op == OP_GOTO) { diff --git a/engine/qclib/pr_comp.h b/engine/qclib/pr_comp.h index 12a407288..c77a6c467 100644 --- a/engine/qclib/pr_comp.h +++ b/engine/qclib/pr_comp.h @@ -422,6 +422,10 @@ enum qcop_e { OP_BITNOT_V, OP_BITXOR_V, + //special/fake opcodes used by the decompiler. + OPD_GOTO_FORSTART, + OPD_GOTO_WHILE1, + OP_NUMOPS }; diff --git a/engine/qclib/qccgui.c b/engine/qclib/qccgui.c index 57b94b9c7..3ee849ee9 100644 --- a/engine/qclib/qccgui.c +++ b/engine/qclib/qccgui.c @@ -22,6 +22,7 @@ void OptionsDialog(void); static void GUI_CreateInstaller_Windows(void); static void GUI_CreateInstaller_Android(void); +static void SetProgsSrcFileAndPath(char *filename); void AddSourceFile(const char *parentsrc, const char *filename); #ifndef TVM_SETBKCOLOR @@ -345,6 +346,18 @@ static pbool QCC_RegSetValue(HKEY base, char *keyname, char *valuename, int type */ static vfile_t *qcc_vfiles; +void QCC_CloseAllVFiles(void) +{ + vfile_t *f; + while(qcc_vfiles) + { + f = qcc_vfiles; + qcc_vfiles = f->next; + + free(f->fdata); + free(f); + } +} vfile_t *QCC_FindVFile(const char *name) { vfile_t *f; @@ -1553,6 +1566,7 @@ HWND CreateAnEditControl(HWND parent, pbool *scintillaokay) enum { IDM_OPENDOCU=32, IDM_OPENNEW, + IDM_OPENPROJECT, IDM_GREP, IDM_GOTODEF, IDM_RETURNDEF, @@ -1595,7 +1609,7 @@ enum { IDI_O_LEVEL3, IDI_O_DEFAULT, IDI_O_DEBUG, - IDI_O_CHANGE_PROGS_SRC, +// IDI_O_CHANGE_PROGS_SRC, IDI_O_ADDITIONALPARAMETERS, IDI_O_OPTIMISATION, IDI_O_COMPILER_FLAG, @@ -1637,6 +1651,29 @@ void GenericMenu(WPARAM wParam) { switch(LOWORD(wParam)) { + case IDM_OPENPROJECT: + { + char filename[MAX_PATH]; + char oldpath[MAX_PATH+10]; + OPENFILENAME ofn; + memset(&ofn, 0, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hInstance = ghInstance; + ofn.lpstrFile = filename; + ofn.lpstrTitle = "Please find progs.src or progs.dat"; + ofn.nMaxFile = sizeof(filename)-1; + ofn.lpstrFilter = "QuakeC Projects\0*.src;*.dat\0All files\0*.*\0"; + memset(filename, 0, sizeof(filename)); + GetCurrentDirectory(sizeof(oldpath)-1, oldpath); + ofn.lpstrInitialDir = oldpath; + if (GetOpenFileName(&ofn)) + { + SetProgsSrcFileAndPath(filename); + } + resetprogssrc = true; + } + break; + case IDM_OPENNEW: QueryOpenFile(); break; @@ -5222,7 +5259,7 @@ static LRESULT CALLBACK OptionsWndProc(HWND hWnd,UINT message, GUI_SaveConfig(); DestroyWindow(hWnd); break; - case IDI_O_CHANGE_PROGS_SRC: +/* case IDI_O_CHANGE_PROGS_SRC: { char filename[MAX_PATH]; char oldpath[MAX_PATH+10]; @@ -5240,10 +5277,10 @@ static LRESULT CALLBACK OptionsWndProc(HWND hWnd,UINT message, if (GetOpenFileName(&ofn)) { SetProgsSrcFileAndPath(filename); + resetprogssrc = true; } - resetprogssrc = true; } - break; + break;*/ case IDI_O_LEVEL0: case IDI_O_LEVEL1: case IDI_O_LEVEL2: @@ -5328,9 +5365,9 @@ static LRESULT CALLBACK OptionsWndProc(HWND hWnd,UINT message, case IDI_O_LEVEL3: MessageBox(hWnd, "Sets a specific optimisation level", "Help", MB_OK|MB_ICONINFORMATION); break; - case IDI_O_CHANGE_PROGS_SRC: - MessageBox(hWnd, "Use this button to change your root source file.\nNote that fteqcc compiles sourcefiles from editors first, rather than saving. This means that changes are saved ONLY when you save them, but means that switching project mid-compile can result in problems.", "Help", MB_OK|MB_ICONINFORMATION); - break; +// case IDI_O_CHANGE_PROGS_SRC: +// MessageBox(hWnd, "Use this button to change your root source file.\nNote that fteqcc compiles sourcefiles from editors first, rather than saving. This means that changes are saved ONLY when you save them, but means that switching project mid-compile can result in problems.", "Help", MB_OK|MB_ICONINFORMATION); +// break; case IDI_O_ADDITIONALPARAMETERS: MessageBox(hWnd, "Type in additional commandline parameters here. Use -Dname to define a named precompiler constant before compiling.", "Help", MB_OK|MB_ICONINFORMATION); break; @@ -5609,14 +5646,14 @@ void OptionsDialog(void) ghInstance, NULL); AddTip(tipwnd, wnd, "Use selected settings and save them to disk so that they're also used the next time you start fteqccgui."); - wnd = CreateWindow("BUTTON","progs.src", + /*wnd = CreateWindow("BUTTON","progs.src", WS_CHILD | WS_VISIBLE, 8+64*2,height-40,64,32, optionsmenu, (HMENU)IDI_O_CHANGE_PROGS_SRC, ghInstance, NULL); - AddTip(tipwnd, wnd, "Change the initial src file."); + AddTip(tipwnd, wnd, "Change the initial src file.");*/ @@ -5766,8 +5803,9 @@ static LRESULT CALLBACK MainWndProc(HWND hWnd,UINT message, rootmenu = CreateMenu(); AppendMenu(rootmenu, MF_POPUP, (UINT_PTR)(m = CreateMenu()), "&File"); - AppendMenu(m, 0, IDM_OPENNEW, "Open new file "); - AppendMenu(m, 0, IDM_SAVE, "&Save\tCtrl+S "); + AppendMenu(m, 0, IDM_OPENPROJECT, "Open Project / Decompile"); + AppendMenu(m, 0, IDM_OPENNEW, "Open File"); + AppendMenu(m, 0, IDM_SAVE, "&Save\tCtrl+S"); // AppendMenu(m, 0, IDM_FIND, "&Find"); AppendMenu(m, 0, IDM_UNDO, "Undo\tCtrl+Z"); AppendMenu(m, 0, IDM_REDO, "Redo\tCtrl+Y"); @@ -5777,10 +5815,10 @@ static LRESULT CALLBACK MainWndProc(HWND hWnd,UINT message, AppendMenu(m, MF_SEPARATOR, 0, NULL); AppendMenu(m, 0, IDM_QUIT, "Exit"); AppendMenu(rootmenu, MF_POPUP, (UINT_PTR)(m = CreateMenu()), "&Navigation"); - AppendMenu(m, 0, IDM_GOTODEF, "Go to definition\tF12"); - AppendMenu(m, 0, IDM_RETURNDEF, "Return from definition\tShift+F12"); - AppendMenu(m, 0, IDM_GREP, "Grep for selection\tCtrl+G"); - AppendMenu(m, 0, IDM_OPENDOCU, "Open selected file"); + AppendMenu(m, 0, IDM_GOTODEF, "Go To Definition\tF12"); + AppendMenu(m, 0, IDM_RETURNDEF, "Return From Definition\tShift+F12"); + AppendMenu(m, 0, IDM_GREP, "Grep For Selection\tCtrl+G"); + AppendMenu(m, 0, IDM_OPENDOCU, "Open Selected File"); AppendMenu(m, 0, IDM_OUTPUT_WINDOW, "Show Output Window\tF6"); AppendMenu(m, (fl_extramargins?MF_CHECKED:MF_UNCHECKED), IDM_UI_SHOWLINENUMBERS, "Show Line Numbers"); AppendMenu(m, ((fl_tabsize>4)?MF_CHECKED:MF_UNCHECKED), IDM_UI_TABSIZE, "Large Tabs"); @@ -6897,12 +6935,9 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin GUI_SetDefaultOpts(); -// if (!QCC_RegGetStringValue(HKEY_CURRENT_USER, "Software\\FTE QuakeWorld\\fteqccgui", "enginebinary", enginebinary, sizeof(enginebinary))) - strcpy(enginebinary, ""); -// if (!QCC_RegGetStringValue(HKEY_CURRENT_USER, "Software\\FTE QuakeWorld\\fteqccgui", "enginebasedir", enginebasedir, sizeof(enginebasedir))) - strcpy(enginebasedir, ""); -// if (!QCC_RegGetStringValue(HKEY_CURRENT_USER, "Software\\FTE QuakeWorld\\fteqccgui", "enginecommandline", enginecommandline, sizeof(enginecommandline))) - strcpy(enginecommandline, ""); + strcpy(enginebinary, ""); + strcpy(enginebasedir, ""); + strcpy(enginecommandline, ""); if(strstr(lpCmdLine, "-stdout")) { @@ -6911,34 +6946,6 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin return 0; } - if (!*lpCmdLine) - { - int len; - FILE *f; - char *s; - - f = fopen("fteqcc.arg", "rb"); - if (f) - { - fseek(f, 0, SEEK_END); - len = ftell(f); - fseek(f, 0, SEEK_SET); - lpCmdLine = malloc(len+1); - fread(lpCmdLine, 1, len, f); - lpCmdLine[len] = '\0'; - fclose(f); - - while((s = strchr(lpCmdLine, '\r'))) - *s = ' '; - while((s = strchr(lpCmdLine, '\n'))) - *s = ' '; - } - } - - GUI_ParseCommandLine(lpCmdLine); - - GUI_RevealOptions(); - for (i = 0, fl_acc = false; compiler_flag[i].enabled; i++) { if (!strcmp("acc", compiler_flag[i].abbrev)) @@ -6957,7 +6964,6 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin strcpy(progssrcname, "progs.src"); if (QCC_RawFileSize(progssrcname)==-1) { - char *s, *s2; char filename[MAX_PATH]; char oldpath[MAX_PATH+10]; OPENFILENAME ofn; @@ -6972,30 +6978,12 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin GetCurrentDirectory(sizeof(oldpath)-1, oldpath); ofn.lpstrInitialDir = oldpath; if (GetOpenFileName(&ofn)) - { - strcpy(progssrcdir, filename); - for(s = progssrcdir; s; s = s2) - { - s2 = strchr(s+1, '\\'); - if (!s2) - break; - s = s2; - } - if (s) - { - *s = '\0'; - strcpy(progssrcname, s+1); - } - else - strcpy(progssrcname, filename); - } + strcpy(progssrcname, filename); else { MessageBox(NULL, "You didn't select a file", "Error", 0); return 0; } - SetCurrentDirectory(progssrcdir); - *progssrcdir = '\0'; } } @@ -7064,71 +7052,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin ShowWindow(mainwindow, SW_SHOWDEFAULT); - { - char *ext = strrchr(progssrcname, '.'); - if (ext && !QC_strcasecmp(ext, ".dat")) - { - FILE *f = fopen(progssrcname, "rb"); - if (f) - { - char *buf; - size_t size; - - fseek(f, 0, SEEK_END); - size = ftell(f); - fseek(f, 0, SEEK_SET); - buf = malloc(size); - fread(buf, 1, size, f); - fclose(f); - if (!QC_EnumerateFilesFromBlob(buf, size, QCC_EnumerateFilesResult)) - { - char *c = ReadProgsCopyright(buf, size); - if (!c || !*c) - c = "COPYRIGHT OWNER NOT KNOWN"; //all work is AUTOMATICALLY copyrighted under the terms of the Berne Convention. It _IS_ copyrighted, even if there's no license etc included. Good luck guessing what rights you have. - if (MessageBox(mainwindow, qcva("The copyright message from this progs is\n%s\n\nPlease respect the wishes and legal rights of the person who created this.", c), "Copyright", MB_OKCANCEL|MB_DEFBUTTON2|MB_ICONSTOP) == IDOK) - { - CreateOutputWindow(true); - compilecb(); - DecompileProgsDat(progssrcname, buf, size); - if (SplitterGet(outputbox)) - { - SendMessage(outputbox, WM_SETREDRAW, TRUE, 0); - RedrawWindow(outputbox, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN); - } - } - } - free(buf); - } - strcpy(progssrcname, "progs.src"); - - for (i = 0; ; i++) - { - if (!strcmp("embedsrc", compiler_flag[i].abbrev)) - { - compiler_flag[i].flags |= FLAG_SETINGUI; - break; - } - } - } - } - - if (fl_compileonstart) - { - CreateOutputWindow(false); - RunCompiler(lpCmdLine, false); - } - else - { - if (!mdibox) - { - GUIprintf("Welcome to FTE QCC\n"); - GUIprintf("Source file: "); - GUIprintf(progssrcname); - GUIprintf("\n"); - - RunCompiler("-?", false); - } - } + resetprogssrc = true; while(mainwindow || editors) { @@ -7136,6 +7060,110 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin if (resetprogssrc) { //this here, with the compiler below, means that we don't run recursivly. + if (projecttree) + TreeView_DeleteAllItems(projecttree); + + //if progssrcname is a path, then change working directory now. + //this shouldn't affect that much, but should ensure well-defined behaviour. + { + char *s, *s2; + strcpy(progssrcdir, progssrcname); + for(s = NULL, s2 = progssrcdir; s2;) + { + char *bs = strchr(s2, '\\'); + char *sl = strchr(s2, '/'); + if (bs) + s2 = bs; + else if (sl) + s2 = sl; + else + break; + s = s2++; + } + if (s) + { + *s = '\0'; + strcpy(progssrcname, s+1); + } + + SetCurrentDirectory(progssrcdir); + *progssrcdir = '\0'; + } + + //reset project/directory options + GUI_SetDefaultOpts(); + GUI_ParseCommandLine(lpCmdLine); + GUI_RevealOptions(); + + //if the project is a .dat or .zip then decompile it now (so we can access the 'source') + { + char *ext = strrchr(progssrcname, '.'); + if (ext && (!QC_strcasecmp(ext, ".dat") || !QC_strcasecmp(ext, ".zip") || !QC_strcasecmp(ext, ".pk3"))) + { + FILE *f = fopen(progssrcname, "rb"); + if (f) + { + char *buf; + size_t size; + + fseek(f, 0, SEEK_END); + size = ftell(f); + fseek(f, 0, SEEK_SET); + buf = malloc(size); + fread(buf, 1, size, f); + fclose(f); + QCC_CloseAllVFiles(); + strcpy(progssrcname, "progs.src"); + if (!QC_EnumerateFilesFromBlob(buf, size, QCC_EnumerateFilesResult) && !QC_strcasecmp(ext, ".dat")) + { + char *c = ReadProgsCopyright(buf, size); + if (!c || !*c) + c = "COPYRIGHT OWNER NOT KNOWN"; //all work is AUTOMATICALLY copyrighted under the terms of the Berne Convention in all major nations. It _IS_ copyrighted, even if there's no license etc included. Good luck guessing what rights you have. + if (MessageBox(mainwindow, qcva("The copyright message from this progs is\n%s\n\nPlease respect the wishes and legal rights of the person who created this.", c), "Copyright", MB_OKCANCEL|MB_DEFBUTTON2|MB_ICONSTOP) == IDOK) + { + CreateOutputWindow(true); + compilecb(); + DecompileProgsDat(progssrcname, buf, size); + if (SplitterGet(outputbox)) + { + SendMessage(outputbox, WM_SETREDRAW, TRUE, 0); + RedrawWindow(outputbox, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN); + } + } + } + free(buf); + } + else + strcpy(progssrcname, "progs.src"); + + for (i = 0; ; i++) + { + if (!strcmp("embedsrc", compiler_flag[i].abbrev)) + { + compiler_flag[i].flags |= FLAG_SETINGUI; + break; + } + } + } + } + + if (fl_compileonstart) + { + CreateOutputWindow(false); + RunCompiler(lpCmdLine, false); + } + else + { + if (!mdibox) + { + GUIprintf("Welcome to FTE QCC\n"); + GUIprintf("Source file: "); + GUIprintf(progssrcname); + GUIprintf("\n"); + + RunCompiler("-?", false); + } + } resetprogssrc = false; UpdateFileList(); } @@ -7150,7 +7178,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin DoTranslateMessage(&msg); } - if (mainwindow) + if (mainwindow) { if (buttons[ID_COMPILE].washit) { diff --git a/engine/qclib/qccguistuff.c b/engine/qclib/qccguistuff.c index f5764420b..338d6f413 100644 --- a/engine/qclib/qccguistuff.c +++ b/engine/qclib/qccguistuff.c @@ -452,12 +452,37 @@ void GUI_ParseCommandLine(char *args) int l, p; char *next; + if (!*args) + { + int len; + FILE *f; + char *s; + + f = fopen("fteqcc.arg", "rb"); + if (f) + { + fseek(f, 0, SEEK_END); + len = ftell(f); + fseek(f, 0, SEEK_SET); + args = _alloca(len+1); + fread(args, 1, len, f); + args[len] = '\0'; + fclose(f); + + while((s = strchr(args, '\r'))) + *s = ' '; + while((s = strchr(args, '\n'))) + *s = ' '; + } + } + //find the first argument while (*args == ' ' || *args == '\t') args++; for (next = args; *next&&*next!=' '&&*next !='\t'; next++) ; + if (*args != '-') { pbool qt = *args == '\"'; diff --git a/engine/server/server.h b/engine/server/server.h index 1dcef38bc..d70e1acc6 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -639,8 +639,10 @@ typedef struct client_s SCP_QUAKE3, //all the below are considered netquake clients. SCP_NETQUAKE, + //bjp1, bjp2 SCP_BJP3, //16bit angles,model+sound indexes. nothing else (assume raised ent limits too). SCP_FITZ666, + //dp5 SCP_DARKPLACES6, SCP_DARKPLACES7 //extra prediction stuff //note, nq is nq+ diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index 9c68a5df4..c181dea2c 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -2201,9 +2201,9 @@ void SV_CalcClientStats(client_t *client, int statsi[MAX_CL_STATS], float statsf #endif if (!ent->xv->viewzoom) - statsi[STAT_VIEWZOOM] = 255; + statsf[STAT_VIEWZOOM] = STAT_VIEWZOOM_SCALE; else - statsi[STAT_VIEWZOOM] = max(1,ent->xv->viewzoom*255); + statsf[STAT_VIEWZOOM] = max(1,ent->xv->viewzoom*STAT_VIEWZOOM_SCALE); #endif #ifdef NQPROT diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index 347645237..e05e5c8ed 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -532,7 +532,7 @@ void SVNQ_New_f (void) {SCP_DARKPLACES6, true}, {SCP_FITZ666, true}, //actually 999... shh... {SCP_FITZ666, false}, - {SCP_BJP3, false} + {SCP_BJP3, false} //should we only use this when we have >255 models/sounds? }; for (i = 0; i < countof(preferedprot); i++) { diff --git a/engine/vk/vk_init.c b/engine/vk/vk_init.c index 7401cee02..c3c22af63 100644 --- a/engine/vk/vk_init.c +++ b/engine/vk/vk_init.c @@ -251,7 +251,7 @@ static qboolean VK_CreateSwapChain(void) uint32_t i, curpri; VkSwapchainKHR newvkswapchain; VkImage *images; - VkDeviceMemory *memories; + VkDeviceMemory *memories; VkImageView attachments[2]; VkFramebufferCreateInfo fb_info = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; @@ -262,7 +262,7 @@ static qboolean VK_CreateSwapChain(void) if (vk.swapchain || vk.backbuf_count) VK_DestroySwapChain(); - vk.backbufformat = vid_srgb.ival?VK_FORMAT_B8G8R8A8_SRGB:VK_FORMAT_B8G8R8A8_UNORM; + vk.backbufformat = (vid.srgb||vid_srgb.ival)?VK_FORMAT_B8G8R8A8_SRGB:VK_FORMAT_B8G8R8A8_UNORM; vk.backbuf_count = 4; swapinfo.imageExtent.width = vid.pixelwidth; @@ -388,8 +388,9 @@ static qboolean VK_CreateSwapChain(void) } } + vk.srgbcapable = false; swapinfo.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; - swapinfo.imageFormat = vid_srgb.ival?VK_FORMAT_B8G8R8A8_SRGB:VK_FORMAT_B8G8R8A8_UNORM; + swapinfo.imageFormat = (vid.srgb||vid_srgb.ival)?VK_FORMAT_B8G8R8A8_SRGB:VK_FORMAT_B8G8R8A8_UNORM; for (i = 0, curpri = 0; i < fmtcount; i++) { uint32_t priority = 0; @@ -397,11 +398,12 @@ static qboolean VK_CreateSwapChain(void) { case VK_FORMAT_B8G8R8A8_UNORM: case VK_FORMAT_R8G8B8A8_UNORM: - priority = 4+!vid_srgb.ival; + priority = 4+!(vid.srgb||vid_srgb.ival); break; case VK_FORMAT_B8G8R8A8_SRGB: case VK_FORMAT_R8G8B8A8_SRGB: - priority = 4+!!vid_srgb.ival; + priority = 4+!!(vid.srgb||vid_srgb.ival); + vk.srgbcapable = true; break; case VK_FORMAT_R16G16B16A16_SFLOAT: //16bit per-channel formats case VK_FORMAT_R16G16B16A16_SNORM: @@ -521,7 +523,7 @@ static qboolean VK_CreateSwapChain(void) depthinfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; depthinfo.queueFamilyIndexCount = 0; depthinfo.pQueueFamilyIndices = NULL; - depthinfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + depthinfo.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; VkAssert(vkCreateImage(vk.device, &depthinfo, vkallocationcb, &vk.backbufs[i].depth.image)); } @@ -575,6 +577,11 @@ static qboolean VK_CreateSwapChain(void) void VK_Draw_Init(void) { + qboolean srgb = vid_srgb.ival > 1 && vk.srgbcapable; + if (vid.srgb != srgb) + vid_srgb.modified = true; + vid.srgb = srgb; + R2D_Init(); } void VK_Draw_Shutdown(void) @@ -710,6 +717,11 @@ vk_image_t VK_CreateTexture2DArray(uint32_t width, uint32_t height, uint32_t lay format = VK_FORMAT_D32_SFLOAT; else if (encoding == PTI_DEPTH24_8) format = VK_FORMAT_D24_UNORM_S8_UINT; + //srgb formats + else if (encoding == PTI_BGRA8_SRGB || encoding == PTI_BGRX8_SRGB) + format = VK_FORMAT_B8G8R8A8_SRGB; + else if (encoding == PTI_RGBA8_SRGB || encoding == PTI_RGBX8_SRGB) + format = VK_FORMAT_R8G8B8A8_SRGB; //standard formats else if (encoding == PTI_BGRA8 || encoding == PTI_BGRX8) format = VK_FORMAT_B8G8R8A8_UNORM; @@ -902,16 +914,26 @@ void *VK_AtFrameEnd(void (*passed)(void *work), size_t worksize) return w; } +#define USE_STAGING_BUFFERS struct texturefence { struct vk_fencework w; int mips; +#ifdef USE_STAGING_BUFFERS + VkBuffer stagingbuffer; + VkDeviceMemory stagingmemory; +#else vk_image_t staging[32]; +#endif }; static void VK_TextureLoaded(void *ctx) { struct texturefence *w = ctx; +#ifdef USE_STAGING_BUFFERS + vkDestroyBuffer(vk.device, w->stagingbuffer, vkallocationcb); + vkFreeMemory(vk.device, w->stagingmemory, vkallocationcb); +#else unsigned int i; for (i = 0; i < w->mips; i++) if (w->staging[i].image != VK_NULL_HANDLE) @@ -919,13 +941,23 @@ static void VK_TextureLoaded(void *ctx) vkDestroyImage(vk.device, w->staging[i].image, vkallocationcb); vkFreeMemory(vk.device, w->staging[i].memory, vkallocationcb); } +#endif } qboolean VK_LoadTextureMips (texid_t tex, struct pendingtextureinfo *mips) { +#ifdef USE_STAGING_BUFFERS + VkBufferCreateInfo bci = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; + VkMemoryRequirements mem_reqs; + VkMemoryAllocateInfo memAllocInfo = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO}; + void *mapdata; +#else + uint32_t y; +#endif + struct texturefence *fence; VkCommandBuffer vkloadcmd; vk_image_t target; - uint32_t i, y; + uint32_t i; uint32_t blocksize; uint32_t blockbytes; uint32_t layers; @@ -950,6 +982,10 @@ qboolean VK_LoadTextureMips (texid_t tex, struct pendingtextureinfo *mips) case PTI_RGBX8: case PTI_BGRA8: case PTI_BGRX8: + case PTI_RGBA8_SRGB: + case PTI_RGBX8_SRGB: + case PTI_BGRA8_SRGB: + case PTI_BGRX8_SRGB: blocksize = 1; //in texels blockbytes = 4; break; @@ -1059,7 +1095,68 @@ qboolean VK_LoadTextureMips (texid_t tex, struct pendingtextureinfo *mips) } } - //create the staging images and fill them +#ifdef USE_STAGING_BUFFERS + //figure out how big our staging buffer needs to be + bci.size = 0; + for (i = 0; i < mips->mipcount; i++) + { + uint32_t blockwidth = (mips->mip[i].width+blocksize-1) / blocksize; + uint32_t blockheight = (mips->mip[i].height+blocksize-1) / blocksize; + + bci.size += blockwidth*blockheight*blockbytes; + } + bci.flags = 0; + bci.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + bci.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + bci.queueFamilyIndexCount = 0; + bci.pQueueFamilyIndices = NULL; + + //create+map the staging buffer + VkAssert(vkCreateBuffer(vk.device, &bci, vkallocationcb, &fence->stagingbuffer)); + vkGetBufferMemoryRequirements(vk.device, fence->stagingbuffer, &mem_reqs); + memAllocInfo.allocationSize = mem_reqs.size; + memAllocInfo.memoryTypeIndex = vk_find_memory_require(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); + VkAssert(vkAllocateMemory(vk.device, &memAllocInfo, vkallocationcb, &fence->stagingmemory)); + VkAssert(vkBindBufferMemory(vk.device, fence->stagingbuffer, fence->stagingmemory, 0)); + VkAssert(vkMapMemory(vk.device, fence->stagingmemory, 0, bci.size, 0, &mapdata)); + if (!mapdata) + Sys_Error("Unable to map staging image\n"); + + bci.size = 0; + for (i = 0; i < mips->mipcount; i++) + { + VkImageSubresource subres = {0}; + VkBufferImageCopy region; + //figure out the number of 'blocks' in the image. + //for non-compressed formats this is just the width directly. + //for compressed formats (ie: s3tc/dxt) we need to round up to deal with npot. + uint32_t blockwidth = (mips->mip[i].width+blocksize-1) / blocksize; + uint32_t blockheight = (mips->mip[i].height+blocksize-1) / blocksize; + + memcpy((char*)mapdata + bci.size, (char*)mips->mip[i].data, blockwidth*blockbytes*blockheight); + + //queue up a buffer->image copy for this mip + region.bufferOffset = bci.size; + region.bufferRowLength = 0;//blockwidth*blockbytes; + region.bufferImageHeight = 0;//blockheight; + region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.imageSubresource.mipLevel = i%(mips->mipcount/layers); + region.imageSubresource.baseArrayLayer = i/(mips->mipcount/layers); + region.imageSubresource.layerCount = 1; + region.imageOffset.x = 0; + region.imageOffset.y = 0; + region.imageOffset.z = 0; + region.imageExtent.width = mips->mip[i].width; + region.imageExtent.height = mips->mip[i].height; + region.imageExtent.depth = 1; + + vkCmdCopyBufferToImage(vkloadcmd, fence->stagingbuffer, target.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + + bci.size += blockwidth*blockheight*blockbytes; + } + vkUnmapMemory(vk.device, fence->stagingmemory); +#else +//create the staging images and fill them for (i = 0; i < mips->mipcount; i++) { VkImageSubresource subres = {0}; @@ -1112,6 +1209,7 @@ qboolean VK_LoadTextureMips (texid_t tex, struct pendingtextureinfo *mips) vkCmdCopyImage(vkloadcmd, fence->staging[i].image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, target.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); } } +#endif //layouts are annoying. and weird. { @@ -2029,7 +2127,7 @@ void VKVID_QueueGetRGBData (void (*gotrgbdata) (void *rgbdata, intptr_t bytest vkCmdCopyImageToBuffer(vk.frame->cbuf, vk.frame->backbuf->colour.image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, capt->buffer, 1, &icpy); - set_image_layout(vk.frame->cbuf, vk.frame->backbuf->colour.image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT); + set_image_layout(vk.frame->cbuf, vk.frame->backbuf->colour.image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT); } char *VKVID_GetRGBInfo (int *bytestride, int *truevidwidth, int *truevidheight, enum uploadfmt *fmt) @@ -2097,7 +2195,7 @@ char *VKVID_GetRGBInfo (int *bytestride, int *truevidwidth, int *truevidheight icpy.extent.depth = 1; vkCmdCopyImage(fence->cbuf, vk.frame->backbuf->colour.image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, tempimage, VK_IMAGE_LAYOUT_GENERAL, 1, &icpy); - set_image_layout(fence->cbuf, vk.frame->backbuf->colour.image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT); + set_image_layout(fence->cbuf, vk.frame->backbuf->colour.image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT); set_image_layout(fence->cbuf, tempimage, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_HOST_READ_BIT); VK_FencedSync(fence); @@ -2902,6 +3000,12 @@ void VK_CheckTextureFormats(void) {PTI_RGBX8, VK_FORMAT_R8G8B8A8_UNORM}, {PTI_BGRA8, VK_FORMAT_B8G8R8A8_UNORM}, {PTI_BGRX8, VK_FORMAT_B8G8R8A8_UNORM}, + + {PTI_RGBA8_SRGB, VK_FORMAT_R8G8B8A8_SRGB, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT}, + {PTI_RGBX8_SRGB, VK_FORMAT_R8G8B8A8_SRGB, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT}, + {PTI_BGRA8_SRGB, VK_FORMAT_B8G8R8A8_SRGB, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT}, + {PTI_BGRX8_SRGB, VK_FORMAT_B8G8R8A8_SRGB, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT}, + {PTI_RGB565, VK_FORMAT_R5G6B5_UNORM_PACK16}, {PTI_RGBA4444, VK_FORMAT_R4G4B4A4_UNORM_PACK16}, {PTI_ARGB4444, VK_FORMAT_B4G4R4A4_UNORM_PACK16}, @@ -2931,7 +3035,7 @@ void VK_CheckTextureFormats(void) for (i = 0; i < countof(texfmt); i++) { - unsigned int need = VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT | texfmt[i].needextra; + unsigned int need = /*VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT |*/ texfmt[i].needextra; VkFormatProperties fmt; vkGetPhysicalDeviceFormatProperties(vk.gpu, texfmt[i].vulkan, &fmt); diff --git a/engine/vk/vkrenderer.h b/engine/vk/vkrenderer.h index 99c9f7b1c..5cc443038 100644 --- a/engine/vk/vkrenderer.h +++ b/engine/vk/vkrenderer.h @@ -84,6 +84,7 @@ VKFunc(CmdCopyImage) \ VKFunc(CmdCopyBuffer) \ VKFunc(CmdCopyImageToBuffer) \ + VKFunc(CmdCopyBufferToImage) \ VKFunc(CmdBlitImage) \ VKFunc(CmdPipelineBarrier) \ VKFunc(CmdSetEvent) \ @@ -312,6 +313,7 @@ extern struct vulkaninfo_s VkFormat depthformat; VkFormat backbufformat; + qboolean srgbcapable; qboolean neednewswapchain; diff --git a/engine/web/gl_vidweb.c b/engine/web/gl_vidweb.c index f1d33fc59..d3ad1ded0 100644 --- a/engine/web/gl_vidweb.c +++ b/engine/web/gl_vidweb.c @@ -287,7 +287,7 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette) vid.activeapp = true; - GL_Init(GLVID_getsdlglfunction); + GL_Init(info, GLVID_getsdlglfunction); qglViewport (0, 0, vid.pixelwidth, vid.pixelheight);