From 2f6242614303296e93bc38a1b2b8ec0634b8d3e1 Mon Sep 17 00:00:00 2001 From: Justin <95296300+Toodles2You@users.noreply.github.com> Date: Fri, 6 Dec 2024 21:23:03 -0800 Subject: [PATCH] Valve BSP, WAD, and external texture support --- Quake/bspfile.h | 4 + Quake/common.c | 10 +- Quake/common.h | 3 + Quake/gl_draw.c | 4 +- Quake/gl_model.c | 297 ++++++++++++++++++++++++++++++++++++++++++++-- Quake/gl_texmgr.c | 159 ++++++++++++++++++++----- Quake/gl_texmgr.h | 2 +- Quake/quakedef.h | 2 + Quake/wad.c | 238 ++++++++++++++++++++++++++++++++++--- Quake/wad.h | 26 +++- 10 files changed, 677 insertions(+), 68 deletions(-) diff --git a/Quake/bspfile.h b/Quake/bspfile.h index 9803b5791..f13c62a75 100644 --- a/Quake/bspfile.h +++ b/Quake/bspfile.h @@ -59,6 +59,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define BSPVERSION 29 +#ifdef BSP29_VALVE +#define BSPVERSION_VALVE 30 +#endif + /* RMQ support (2PSB). 32bits instead of shorts for all but bbox sizes (which * still use shorts) */ #define BSP2VERSION_2PSB (('B' << 24) | ('S' << 16) | ('P' << 8) | '2') diff --git a/Quake/common.c b/Quake/common.c index 69a3d84f5..37767523b 100644 --- a/Quake/common.c +++ b/Quake/common.c @@ -294,6 +294,14 @@ char *q_strupr (char *str) return str; } +char *q_strdup (const char *str) +{ + size_t len = strlen (str) + 1; + char *newstr = (char *)malloc (len); + memcpy (newstr, str, len); + return newstr; +} + /* platform dependant (v)snprintf function names: */ #if defined(_WIN32) #define snprintf_func _snprintf @@ -1138,7 +1146,7 @@ void COM_FileBase (const char *in, char *out, size_t outsize) dot = NULL; while (*s) { - if (*s == '/') + if (*s == '/' || *s == '\\') slash = s + 1; if (*s == '.') dot = s; diff --git a/Quake/common.h b/Quake/common.h index 02b5d5146..228eacc9f 100644 --- a/Quake/common.h +++ b/Quake/common.h @@ -231,6 +231,9 @@ extern char *q_strcasestr(const char *haystack, const char *needle); extern char *q_strlwr (char *str); extern char *q_strupr (char *str); +// strdup that calls malloc +extern char *q_strdup (const char *str); + /* snprintf, vsnprintf : always use our versions. */ extern int q_snprintf (char *str, size_t size, const char *format, ...) FUNC_PRINTF(3,4); extern int q_vsnprintf(char *str, size_t size, const char *format, va_list args) FUNC_PRINTF(3,0); diff --git a/Quake/gl_draw.c b/Quake/gl_draw.c index d60db57e9..acebc1f30 100644 --- a/Quake/gl_draw.c +++ b/Quake/gl_draw.c @@ -249,7 +249,7 @@ qpic_t *Draw_PicFromWad (const char *name) char texturename[64]; //johnfitz q_snprintf (texturename, sizeof(texturename), "%s:%s", WADFILENAME, name); //johnfitz - offset = (src_offset_t)p - (src_offset_t)wad_base + sizeof(int)*2; //johnfitz + offset = (src_offset_t)p - (src_offset_t)gfx.base + sizeof(int)*2; //johnfitz gl.gltexture = TexMgr_LoadImage (NULL, texturename, p->width, p->height, SRC_INDEXED, p->data, WADFILENAME, offset, TEXPREF_ALPHA | TEXPREF_PAD | TEXPREF_NOPICMIP); //johnfitz -- TexMgr @@ -357,7 +357,7 @@ void Draw_LoadPics (void) data = (byte *) W_GetLumpName ("conchars"); if (!data) Sys_Error ("Draw_LoadPics: couldn't load conchars"); - offset = (src_offset_t)data - (src_offset_t)wad_base; + offset = (src_offset_t)data - (src_offset_t)gfx.base; char_texture = TexMgr_LoadImage (NULL, WADFILENAME":conchars", 128, 128, SRC_INDEXED, data, WADFILENAME, offset, TEXPREF_ALPHA | TEXPREF_NEAREST | TEXPREF_NOPICMIP | TEXPREF_CONCHARS); diff --git a/Quake/gl_model.c b/Quake/gl_model.c index cc12d27bf..722e97791 100644 --- a/Quake/gl_model.c +++ b/Quake/gl_model.c @@ -38,6 +38,7 @@ static void Mod_Print (void); static cvar_t external_ents = {"external_ents", "1", CVAR_ARCHIVE}; static cvar_t external_vis = {"external_vis", "1", CVAR_ARCHIVE}; +static cvar_t external_textures = {"external_textures", "1", CVAR_ARCHIVE}; static byte *mod_novis; static int mod_novis_capacity; @@ -62,6 +63,7 @@ void Mod_Init (void) Cvar_RegisterVariable (&gl_subdivide_size); Cvar_RegisterVariable (&external_vis); Cvar_RegisterVariable (&external_ents); + Cvar_RegisterVariable (&external_textures); Cmd_AddCommand ("mcache", Mod_Print); @@ -408,6 +410,156 @@ qmodel_t *Mod_ForName (const char *name, qboolean crash) static byte *mod_base; +/* +============= +Mod_LoadWadFiles + +load all of the wads listed in the worldspawn "wad" field +============= +*/ +static wad_t *Mod_LoadWadFiles (qmodel_t *mod) +{ + char key[128], value[4096]; + const char *data; + + if (!external_textures.value) + return NULL; + + // disregard if this isn't the world model + if (strcmp (mod->name, sv.modelname)) + return NULL; + + data = COM_Parse (mod->entities); + if (!data) + return NULL; // error + if (com_token[0] != '{') + return NULL; // error + while (1) + { + data = COM_Parse (data); + if (!data) + return NULL; // error + if (com_token[0] == '}') + break; // end of worldspawn + if (com_token[0] == '_') + q_strlcpy (key, com_token + 1, sizeof (key)); + else + q_strlcpy (key, com_token, sizeof (key)); + while (key[0] && key[strlen (key) - 1] == ' ') // remove trailing spaces + key[strlen (key) - 1] = 0; + data = COM_ParseEx (data, CPE_ALLOWTRUNC); + if (!data) + return NULL; // error + q_strlcpy (value, com_token, sizeof (value)); + + if (!strcmp ("wad", key)) + { + return W_LoadWadList (value); + } + } + return NULL; +} + +/* +================= +Mod_LoadWadTexture + +look for an external texture in any of the loaded map wads +================= +*/ +static texture_t *Mod_LoadWadTexture (wad_t *wads, const char *name, qboolean *out_pal, int *out_pixels) +{ + int i, pixels, palette; + lumpinfo_t *info; + wad_t *wad; + miptex_t mt; + texture_t *tx; + qboolean pal; + unsigned short colors; + + // look for the lump in any of the loaded wads + info = W_GetLumpinfoList (wads, name, &wad); + + // ensure we're dealing with a miptex + if (!info || (info->type != TYP_MIPTEX && (wad->id != WADID_VALVE || info->type != TYP_MIPTEX_PALETTE))) + { + Con_Warning ("Missing texture %s in %s!\n", name, loadmodel->name); + return NULL; + } + + // override the texture from the bsp file + FS_fseek (&wad->fh, info->filepos, SEEK_SET); + FS_fread (&mt, 1, sizeof (miptex_t), &wad->fh); + + mt.width = LittleLong (mt.width); + mt.height = LittleLong (mt.height); + for (i = 0; i < MIPLEVELS; i++) + mt.offsets[i] = LittleLong (mt.offsets[i]); + + if (mt.width == 0 || mt.height == 0) + { + Con_Warning ("Zero sized texture %s in %s!\n", mt.name, wad->name); + return NULL; + } + + if ( (mt.width & 15) || (mt.height & 15) ) + { + Con_Warning ("Texture %s (%d x %d) is not 16 aligned\n", mt.name, mt.width, mt.height); + return NULL; + } + + pal = wad->id == WADID_VALVE && info->type == TYP_MIPTEX_PALETTE; + + pixels = mt.width*mt.height; // only copy the first mip, the rest are auto-generated + palette = 0; + // valve textures have a color palette immediately following the pixels + if (pal) + { + // the palette is basically garunteed to be 256 colors but, + // we might as well use the value since it *does* exist + FS_fseek (&wad->fh, info->filepos + sizeof (miptex_t) + pixels / 64 * 85, SEEK_SET); + FS_fread (&colors, 1, 2, &wad->fh); + colors = LittleShort (colors); + // add space for the color palette + palette = 2 + colors * 3; + } + tx = (texture_t *)Hunk_AllocName (sizeof (texture_t) + pixels + palette, loadname); + + memcpy (tx->name, mt.name, sizeof (tx->name)); + tx->width = mt.width; + tx->height = mt.height; + // the pixels immediately follow the structures + + // check for pixels extending past the end of the lump + if (pixels > info->size) + { + Con_DPrintf ("Texture %s extends past end of lump\n", mt.name); + pixels = info->size; + } + if (palette && pixels + palette > info->size) + { + Con_DPrintf ("Texture %s extends past end of lump\n", mt.name); + palette = info->size - pixels; + } + + tx->update_warp = false; //johnfitz + tx->warpimage = NULL; //johnfitz + tx->fullbright = NULL; //johnfitz + tx->shift = 0; // Q64 only + + FS_fseek (&wad->fh, info->filepos + sizeof (miptex_t), SEEK_SET); + FS_fread (tx + 1, 1, pixels, &wad->fh); + if (pal) + { + FS_fseek (&wad->fh, info->filepos + sizeof (miptex_t) + pixels / 64 * 85, SEEK_SET); + FS_fread ((byte *)(tx + 1) + pixels, 1, palette, &wad->fh); + } + + *out_pal = pal; + *out_pixels = pixels; + return tx; +} + /* ================= Mod_CheckFullbrights -- johnfitz @@ -424,6 +576,18 @@ static qboolean Mod_CheckFullbrights (byte *pixels, int count) return false; } +/* +================= +Mod_CheckFullbrightsValve +================= +*/ +static qboolean Mod_CheckFullbrightsValve (char *name, byte *pixels, int count) +{ + if (name[0] == '~' || (name[2] == '~' && name[0] == '+')) + return Mod_CheckFullbrights (pixels, count); + return false; +} + /* ================= Mod_CheckAnimTextureArrayQ64 @@ -451,7 +615,7 @@ Mod_LoadTextures */ static void Mod_LoadTextures (lump_t *l) { - int i, j, pixels, num, maxanim, altmax; + int i, j, pixels, num, maxanim, altmax, palette; miptex_t *mt; texture_t *tx, *tx2; texture_t *anims[10]; @@ -467,6 +631,15 @@ static void Mod_LoadTextures (lump_t *l) extern byte *hunk_base; //johnfitz unsigned int flags; + wad_t *wads; + qboolean from_wad; + enum srcformat fmt; + qboolean fbright; + const char *source_file; +#ifdef BSP29_VALVE + int colors; +#endif + qboolean pal = false; //johnfitz -- don't return early if no textures; still need to create dummy texture if (!l->filelen) @@ -486,6 +659,9 @@ static void Mod_LoadTextures (lump_t *l) loadmodel->numtextures = nummiptex + 2; //johnfitz -- need 2 dummy texture chains for missing textures loadmodel->textures = (texture_t **) Hunk_AllocName (loadmodel->numtextures * sizeof(*loadmodel->textures) , loadname); + // load any wads this map may need to load external textures from + wads = Mod_LoadWadFiles (loadmodel); + for (i=0 ; idataofs[i] = LittleLong(m->dataofs[i]); @@ -509,8 +685,35 @@ static void Mod_LoadTextures (lump_t *l) Con_Warning ("Texture %s (%d x %d) is not 16 aligned\n", mt->name, mt->width, mt->height); } +#ifdef BSP29_VALVE + pal = loadmodel->bspversion == BSPVERSION_VALVE; +#endif + // an offset of zero indicates an external texture + from_wad = mt->offsets[0] == 0; + + if (from_wad) + { + tx = (texture_t *)Mod_LoadWadTexture (wads, mt->name, &pal, &pixels); + if (!tx) + continue; + loadmodel->textures[i] = tx; + goto _load_texture; + } + pixels = mt->width*mt->height; // only copy the first mip, the rest are auto-generated - tx = (texture_t *) Hunk_AllocName (sizeof(texture_t) +pixels, loadname ); + palette = 0; +#ifdef BSP29_VALVE + // valve textures have a color palette immediately following the pixels + if (pal) + { + // the palette is basically garunteed to be 256 colors but, + // we might as well use the value since it *does* exist + colors = LittleShort (*(short *)((byte *)(mt + 1) + pixels / 64 * 85)); + // add space for the color palette + palette = 2 + colors * 3; + } +#endif + tx = (texture_t *) Hunk_AllocName (sizeof(texture_t) +pixels + palette, loadname ); loadmodel->textures[i] = tx; memcpy (tx->name, mt->name, sizeof(tx->name)); @@ -527,6 +730,11 @@ static void Mod_LoadTextures (lump_t *l) Con_DPrintf("Texture %s extends past end of lump\n", mt->name); pixels = q_max(0L, (long)((mod_base + l->fileofs + l->filelen) - (byte*)(mt+1))); } + if (palette && ((byte*)(mt+1) + pixels + palette) > (mod_base + l->fileofs + l->filelen)) + { + Con_DPrintf("Texture %s extends past end of lump\n", mt->name); + palette = q_max(0L, (long)((mod_base + l->fileofs + l->filelen) - (byte*)(mt+1) - pixels)); + } tx->update_warp = false; //johnfitz tx->warpimage = NULL; //johnfitz @@ -536,6 +744,8 @@ static void Mod_LoadTextures (lump_t *l) if (loadmodel->bspversion != BSPVERSION_QUAKE64) { memcpy ( tx+1, mt+1, pixels); + if (palette) + memcpy ((byte *)(tx + 1) + pixels, (byte *)(mt + 1) + pixels / 64 * 85, palette); } else { // Q64 bsp @@ -544,17 +754,23 @@ static void Mod_LoadTextures (lump_t *l) memcpy ( tx+1, mt64+1, pixels); } +_load_texture: + //johnfitz -- lots of changes if (!isDedicated) //no texture uploading for dedicated server { +#ifdef BSP29_VALVE + if (loadmodel->bspversion != BSPVERSION_VALVE && !q_strncasecmp(tx->name,"sky",3)) +#else if (!q_strncasecmp(tx->name,"sky",3)) //sky texture //also note -- was Q_strncmp, changed to match qbsp +#endif { if (loadmodel->bspversion == BSPVERSION_QUAKE64) Sky_LoadTextureQ64 (loadmodel, tx); else Sky_LoadTexture (loadmodel, tx); } - else if (tx->name[0] == '*') //warping texture + else if (tx->name[0] == '*' || tx->name[0] == '!') //warping texture { //external textures -- first look in "textures/mapname/" then look in "textures/" mark = Hunk_LowMark(); @@ -577,9 +793,22 @@ static void Mod_LoadTextures (lump_t *l) else //use the texture from the bsp file { q_snprintf (texturename, sizeof(texturename), "%s:%s", loadmodel->name, tx->name); - offset = (src_offset_t)(mt+1) - (src_offset_t)mod_base; + + if (from_wad) + { + source_file = ""; + offset = (src_offset_t)(tx + 1); + } + else + { + source_file = loadmodel->name; + offset = (src_offset_t)(mt+1) - (src_offset_t)mod_base; + } + + fmt = pal ? SRC_INDEXED_PALETTE : SRC_INDEXED; + tx->gltexture = TexMgr_LoadImage (loadmodel, texturename, tx->width, tx->height, - SRC_INDEXED, (byte *)(tx+1), loadmodel->name, offset, TEXPREF_NONE); + fmt, (byte *)(tx+1), source_file, offset, TEXPREF_NONE); } //now create the warpimage, using dummy data from the hunk to create the initial image @@ -638,19 +867,41 @@ static void Mod_LoadTextures (lump_t *l) else //use the texture from the bsp file { q_snprintf (texturename, sizeof(texturename), "%s:%s", loadmodel->name, tx->name); - offset = (src_offset_t)(mt+1) - (src_offset_t)mod_base; - if (Mod_CheckFullbrights ((byte *)(tx+1), pixels)) + + if (from_wad) + { + source_file = ""; + offset = (src_offset_t)(tx + 1); + } + else + { + source_file = loadmodel->name; + offset = (src_offset_t)(mt+1) - (src_offset_t)mod_base; + } + + if (pal) + { + fmt = SRC_INDEXED_PALETTE; + fbright = Mod_CheckFullbrightsValve (tx->name, (byte *)(tx + 1), pixels); + } + else + { + fmt = SRC_INDEXED; + fbright = Mod_CheckFullbrights ((byte *)(tx + 1), pixels); + } + + if (fbright) { tx->gltexture = TexMgr_LoadImage (loadmodel, texturename, tx->width, tx->height, - SRC_INDEXED, (byte *)(tx+1), loadmodel->name, offset, TEXPREF_MIPMAP | TEXPREF_NOBRIGHT | extraflags); + fmt, (byte *)(tx+1), source_file, offset, TEXPREF_MIPMAP | TEXPREF_NOBRIGHT | extraflags); q_snprintf (texturename, sizeof(texturename), "%s:%s_glow", loadmodel->name, tx->name); tx->fullbright = TexMgr_LoadImage (loadmodel, texturename, tx->width, tx->height, - SRC_INDEXED, (byte *)(tx+1), loadmodel->name, offset, TEXPREF_MIPMAP | TEXPREF_FULLBRIGHT | extraflags); + fmt, (byte *)(tx+1), source_file, offset, TEXPREF_MIPMAP | TEXPREF_FULLBRIGHT | extraflags); } else { tx->gltexture = TexMgr_LoadImage (loadmodel, texturename, tx->width, tx->height, - SRC_INDEXED, (byte *)(tx+1), loadmodel->name, offset, TEXPREF_MIPMAP | extraflags); + fmt, (byte *)(tx+1), source_file, offset, TEXPREF_MIPMAP | extraflags); } } Hunk_FreeToLowMark (mark); @@ -659,6 +910,9 @@ static void Mod_LoadTextures (lump_t *l) //johnfitz } + // we no longer need the wads after this point + W_FreeWadList (wads); + //johnfitz -- last 2 slots in array should be filled with dummy textures loadmodel->textures[loadmodel->numtextures-2] = r_notexture_mip; //for lightmapped surfs loadmodel->textures[loadmodel->numtextures-1] = r_notexture_mip2; //for SURF_DRAWTILED surfs @@ -842,6 +1096,16 @@ static void Mod_LoadLighting (lump_t *l) return; } +#ifdef BSP29_VALVE + if (loadmodel->bspversion == BSPVERSION_VALVE) + { + // lightmap samples are already stored as rgb + loadmodel->lightdata = (byte *)Hunk_AllocName (l->filelen, litfilename); + memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen); + return; + } +#endif + loadmodel->lightdata = (byte *) Hunk_AllocName ( l->filelen*3, litfilename); in = loadmodel->lightdata + l->filelen*2; // place the file at the end, so it will not be overwritten until the very last write out = loadmodel->lightdata; @@ -1302,6 +1566,10 @@ static void Mod_LoadFaces (lump_t *l, qboolean bsp2) if (lofs == -1) out->samples = NULL; +#ifdef BSP29_VALVE + else if (loadmodel->bspversion == BSPVERSION_VALVE) + out->samples = loadmodel->lightdata + lofs; // accounts for RGB light data +#endif else out->samples = loadmodel->lightdata + (lofs * 3); //johnfitz -- lit support via lordhavoc (was "+ i") @@ -1311,7 +1579,7 @@ static void Mod_LoadFaces (lump_t *l, qboolean bsp2) out->flags |= (SURF_DRAWSKY | SURF_DRAWTILED); Mod_PolyForUnlitSurface (out); //no more subdivision } - else if (out->texinfo->texture->name[0] == '*') // warp surface + else if (out->texinfo->texture->name[0] == '*' || out->texinfo->texture->name[0] == '!') // warp surface { out->flags |= SURF_DRAWTURB; if (out->texinfo->flags & TEX_SPECIAL) @@ -2199,6 +2467,11 @@ static void Mod_LoadBrushModel (qmodel_t *mod, void *buffer) case BSPVERSION: bsp2 = false; break; +#ifdef BSP29_VALVE + case BSPVERSION_VALVE: + bsp2 = false; + break; +#endif case BSP2VERSION_2PSB: bsp2 = 1; //first iteration break; @@ -2224,6 +2497,7 @@ static void Mod_LoadBrushModel (qmodel_t *mod, void *buffer) Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]); Mod_LoadEdges (&header->lumps[LUMP_EDGES], bsp2); Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]); + Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]); Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]); Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]); Mod_LoadPlanes (&header->lumps[LUMP_PLANES]); @@ -2259,7 +2533,6 @@ static void Mod_LoadBrushModel (qmodel_t *mod, void *buffer) visdone: Mod_LoadNodes (&header->lumps[LUMP_NODES], bsp2); Mod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES], bsp2); - Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]); Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]); Mod_MakeHull0 (); diff --git a/Quake/gl_texmgr.c b/Quake/gl_texmgr.c index b862096ac..7ffeb582a 100644 --- a/Quake/gl_texmgr.c +++ b/Quake/gl_texmgr.c @@ -531,6 +531,80 @@ void TexMgr_LoadPalette (void) Hunk_FreeToLowMark (mark); } +/* +================= +TexMgr_LoadMiptexPalette -- convert a 24bit color palette to 32bit +================= +*/ +static void TexMgr_LoadMiptexPalette (byte *in, byte *out, int numcolors, unsigned flags) +{ + extern cvar_t gl_fullbrights; + int i, numnobright; + + if (numcolors == 0) + return; + + if (!(flags & (TEXPREF_FULLBRIGHT | TEXPREF_NOBRIGHT))) + { + for (i = 0; i < numcolors; i++) + { + *out++ = *in++; + *out++ = *in++; + *out++ = *in++; + *out++ = 255; + } + } + else + { + numnobright = q_min (224, numcolors); + if (flags & TEXPREF_NOBRIGHT) + { + // nobright palette + if (!gl_fullbrights.value) + numnobright = numcolors; + for (i = 0; i < numnobright; i++) + { + *out++ = *in++; + *out++ = *in++; + *out++ = *in++; + *out++ = 255; + } + // 224-255 are black (for additive blending) + for (i = numnobright; i < numcolors; i++) + { + *out++ = 0; + *out++ = 0; + *out++ = 0; + *out++ = 255; + } + } + else + { + // fullbright palette + // 0-223 are black (for additive blending) + for (i = 0; i < numnobright; i++) + { + *out++ = 0; + *out++ = 0; + *out++ = 0; + *out++ = 255; + } + in += numnobright * 3; + for (i = numnobright; i < numcolors; i++) + { + *out++ = *in++; + *out++ = *in++; + *out++ = *in++; + *out++ = 255; + } + } + } + + // 255 is transparent + if (flags & TEXPREF_ALPHA) + out[-1] = 0; +} + /* ================ TexMgr_NewGame @@ -1077,12 +1151,11 @@ static void TexMgr_LoadImage32 (gltexture_t *glt, unsigned *data) TexMgr_LoadImage8 -- handles 8bit source data, then passes it to LoadImage32 ================ */ -static void TexMgr_LoadImage8 (gltexture_t *glt, byte *data) +static void TexMgr_LoadImage8 (gltexture_t *glt, byte *data, unsigned int *usepal) { extern cvar_t gl_fullbrights; qboolean padw = false, padh = false; - byte padbyte; - unsigned int *usepal; + byte padbyte = 0; int i; // HACK HACK HACK -- taken from tomazquake @@ -1107,31 +1180,34 @@ static void TexMgr_LoadImage8 (gltexture_t *glt, byte *data) } // choose palette and padbyte - if (glt->flags & TEXPREF_FULLBRIGHT) - { - if (glt->flags & TEXPREF_ALPHA) - usepal = d_8to24table_fbright_fence; - else - usepal = d_8to24table_fbright; - padbyte = 0; - } - else if (glt->flags & TEXPREF_NOBRIGHT && gl_fullbrights.value) + if (!usepal) { - if (glt->flags & TEXPREF_ALPHA) - usepal = d_8to24table_nobright_fence; + if (glt->flags & TEXPREF_FULLBRIGHT) + { + if (glt->flags & TEXPREF_ALPHA) + usepal = d_8to24table_fbright_fence; + else + usepal = d_8to24table_fbright; + padbyte = 0; + } + else if (glt->flags & TEXPREF_NOBRIGHT && gl_fullbrights.value) + { + if (glt->flags & TEXPREF_ALPHA) + usepal = d_8to24table_nobright_fence; + else + usepal = d_8to24table_nobright; + padbyte = 0; + } + else if (glt->flags & TEXPREF_CONCHARS) + { + usepal = d_8to24table_conchars; + padbyte = 0; + } else - usepal = d_8to24table_nobright; - padbyte = 0; - } - else if (glt->flags & TEXPREF_CONCHARS) - { - usepal = d_8to24table_conchars; - padbyte = 0; - } - else - { - usepal = d_8to24table; - padbyte = 255; + { + usepal = d_8to24table; + padbyte = 255; + } } // pad each dimention, but only if it's not going to be downsampled later @@ -1188,6 +1264,26 @@ static void TexMgr_LoadLightmap (gltexture_t *glt, byte *data) TexMgr_SetFilterModes (glt); } +/* +================ +TexMgr_LoadImage8Valve +================ +*/ +static void TexMgr_LoadImage8Valve (gltexture_t *glt, byte *data) +{ + byte *in, *usepal; + short colors; + + in = data + glt->source_width * glt->source_height; + + memcpy (&colors, in, sizeof (short)); + colors = LittleShort (colors); + + usepal = (byte *)Hunk_Alloc (colors * 4); + TexMgr_LoadMiptexPalette (in + 2, usepal, colors, glt->flags); + TexMgr_LoadImage8 (glt, data, (unsigned *)usepal); +} + /* ================ TexMgr_LoadImage -- the one entry point for loading all textures @@ -1207,6 +1303,7 @@ gltexture_t *TexMgr_LoadImage (qmodel_t *owner, const char *name, int width, int switch (format) { case SRC_INDEXED: + case SRC_INDEXED_PALETTE: crc = CRC_Block(data, width * height); break; case SRC_LIGHTMAP: @@ -1247,7 +1344,7 @@ gltexture_t *TexMgr_LoadImage (qmodel_t *owner, const char *name, int width, int switch (glt->source_format) { case SRC_INDEXED: - TexMgr_LoadImage8 (glt, data); + TexMgr_LoadImage8 (glt, data, NULL); break; case SRC_LIGHTMAP: TexMgr_LoadLightmap (glt, data); @@ -1255,6 +1352,9 @@ gltexture_t *TexMgr_LoadImage (qmodel_t *owner, const char *name, int width, int case SRC_RGBA: TexMgr_LoadImage32 (glt, (unsigned *)data); break; + case SRC_INDEXED_PALETTE: + TexMgr_LoadImage8Valve (glt, data); + break; } Hunk_FreeToLowMark(mark); @@ -1384,7 +1484,7 @@ invalid: Con_Printf ("TexMgr_ReloadImage: invalid source for %s\n", glt->name); switch (glt->source_format) { case SRC_INDEXED: - TexMgr_LoadImage8 (glt, data); + TexMgr_LoadImage8 (glt, data, NULL); break; case SRC_LIGHTMAP: TexMgr_LoadLightmap (glt, data); @@ -1392,6 +1492,9 @@ invalid: Con_Printf ("TexMgr_ReloadImage: invalid source for %s\n", glt->name); case SRC_RGBA: TexMgr_LoadImage32 (glt, (unsigned *)data); break; + case SRC_INDEXED_PALETTE: + TexMgr_LoadImage8Valve (glt, data); + break; } Hunk_FreeToLowMark(mark); diff --git a/Quake/gl_texmgr.h b/Quake/gl_texmgr.h index 91d0562ee..c3bfc83d6 100644 --- a/Quake/gl_texmgr.h +++ b/Quake/gl_texmgr.h @@ -39,7 +39,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define TEXPREF_CONCHARS 0x0400 // use conchars palette #define TEXPREF_WARPIMAGE 0x0800 // resize this texture when warpimagesize changes -enum srcformat {SRC_INDEXED, SRC_LIGHTMAP, SRC_RGBA}; +enum srcformat {SRC_INDEXED, SRC_LIGHTMAP, SRC_RGBA, SRC_INDEXED_PALETTE}; typedef uintptr_t src_offset_t; diff --git a/Quake/quakedef.h b/Quake/quakedef.h index d11f2e8ae..ef337e24b 100644 --- a/Quake/quakedef.h +++ b/Quake/quakedef.h @@ -52,6 +52,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define GAMENAME "id1" // directory to look in by default +#define BSP29_VALVE // enable Half-Life map support + #include "q_stdinc.h" // !!! if this is changed, it must be changed in d_ifacea.h too !!! diff --git a/Quake/wad.c b/Quake/wad.c index aae5f38f1..47bee65ac 100644 --- a/Quake/wad.c +++ b/Quake/wad.c @@ -23,9 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "quakedef.h" -int wad_numlumps; -lumpinfo_t *wad_lumps; -byte *wad_base = NULL; +wad_t gfx; void SwapPic (qpic_t *pic); @@ -75,33 +73,33 @@ void W_LoadWadFile (void) //johnfitz -- filename is now hard-coded for honesty //johnfitz -- modified to use malloc //TODO: use cache_alloc - if (wad_base) - free (wad_base); - wad_base = COM_LoadMallocFile (filename, NULL); - if (!wad_base) + if (gfx.base) + free (gfx.base); + gfx.base = COM_LoadMallocFile (filename, NULL); + if (!gfx.base) Sys_Error ("W_LoadWadFile: couldn't load %s\n\n" "Basedir is: %s\n\n" "Check that this has an " GAMENAME " subdirectory containing pak0.pak and pak1.pak, " "or use the -basedir command-line option to specify another directory.", filename, com_basedir); - header = (wadinfo_t *)wad_base; + header = (wadinfo_t *)gfx.base; if (header->identification[0] != 'W' || header->identification[1] != 'A' || header->identification[2] != 'D' || header->identification[3] != '2') Sys_Error ("Wad file %s doesn't have WAD2 id\n",filename); - wad_numlumps = LittleLong(header->numlumps); + gfx.numlumps = LittleLong(header->numlumps); infotableofs = LittleLong(header->infotableofs); - wad_lumps = (lumpinfo_t *)(wad_base + infotableofs); + gfx.lumps = (lumpinfo_t *)(gfx.base + infotableofs); - for (i=0, lump_p = wad_lumps ; ifilepos = LittleLong(lump_p->filepos); lump_p->size = LittleLong(lump_p->size); W_CleanupName (lump_p->name, lump_p->name); // CAUTION: in-place editing!!! if (lump_p->type == TYP_QPIC) - SwapPic ( (qpic_t *)(wad_base + lump_p->filepos)); + SwapPic ( (qpic_t *)(gfx.base + lump_p->filepos)); } } @@ -111,7 +109,7 @@ void W_LoadWadFile (void) //johnfitz -- filename is now hard-coded for honesty W_GetLumpinfo ============= */ -lumpinfo_t *W_GetLumpinfo (const char *name) +lumpinfo_t *W_GetLumpinfo (wad_t *wad, const char *name) { int i; lumpinfo_t *lump_p; @@ -119,7 +117,7 @@ lumpinfo_t *W_GetLumpinfo (const char *name) W_CleanupName (name, clean); - for (lump_p=wad_lumps, i=0 ; ilumps, i=0 ; inumlumps ; i++,lump_p++) { if (!strcmp(clean, lump_p->name)) return lump_p; @@ -133,23 +131,225 @@ void *W_GetLumpName (const char *name) { lumpinfo_t *lump; - lump = W_GetLumpinfo (name); + lump = W_GetLumpinfo (&gfx, name); if (!lump) return NULL; //johnfitz - return (void *)(wad_base + lump->filepos); + return (void *)(gfx.base + lump->filepos); } void *W_GetLumpNum (int num) { lumpinfo_t *lump; - if (num < 0 || num > wad_numlumps) + if (num < 0 || num > gfx.numlumps) Sys_Error ("W_GetLumpNum: bad number: %i", num); - lump = wad_lumps + num; + lump = gfx.lumps + num; - return (void *)(wad_base + lump->filepos); + return (void *)(gfx.base + lump->filepos); +} + +/* +================= +W_OpenWadFile +================= +*/ +static qboolean W_OpenWadFile (const char *filename, fshandle_t *fh) +{ + FILE *f; + long length; + + length = (long)COM_FOpenFile (filename, &f, NULL); + if (length == -1) + return false; + + fh->file = f; + fh->start = ftell (f); + fh->pos = 0; + fh->length = length; + fh->pak = file_from_pak; + return true; +} + +/* +================= +W_AddWadFile +================= +*/ +static wad_t *W_AddWadFile (const char *name, fshandle_t *fh) +{ + int i, id, numlumps, infotableofs, disksize; + wadinfo_t header; + lumpinfo_t *lumps, *info; + wad_t *wad; + + FS_fread ((void *)&header, 1, sizeof (header), fh); + + id = LittleLong (*(int *)&header.identification[0]); + if (id != WADID && id != WADID_VALVE) + { + Con_Warning ("%s is not a valid WAD\n", name); + return NULL; + } + + numlumps = LittleLong (header.numlumps); + infotableofs = LittleLong (header.infotableofs); + + if (numlumps < 0 || infotableofs < 0) + { + Con_Warning ("%s is not a valid WAD (%i lumps, %i info table offset)\n", name, numlumps, infotableofs); + return NULL; + } + if (!numlumps) + { + Con_DPrintf2 ("WAD file %s has no lumps, ignored\n", name); + return NULL; + } + + lumps = (lumpinfo_t *)malloc (numlumps * sizeof (lumpinfo_t)); + + FS_fseek (fh, infotableofs, SEEK_SET); + FS_fread (lumps, 1, numlumps * sizeof (lumpinfo_t), fh); + + // parse the directory + for (i = 0, info = lumps; i < numlumps; i++, info++) + { + W_CleanupName (info->name, info->name); + info->filepos = LittleLong (info->filepos); + info->size = LittleLong (info->size); + disksize = LittleLong (info->disksize); + + if (info->filepos + info->size > fh->length && !(info->filepos + disksize > fh->length)) + info->size = disksize; + + // ensure lump sanity + if (info->filepos < 0 || info->size < 0 || info->filepos + info->size > fh->length) + { + if (info->filepos > fh->length || info->size < 0) + { + Con_Warning ("WAD file %s lump \"%.16s\" begins %li bytes beyond end of WAD\n", name, info->name, info->filepos - fh->length); + + info->filepos = 0; + info->size = q_max (0, info->size - info->filepos); + } + else + { + Con_Warning ( + "WAD file %s lump \"%.16s\" extends %li bytes beyond end of WAD (lump size is %i)\n", name, info->name, + (info->filepos + info->size) - fh->length, info->size); + + info->size = q_max (0, info->size - info->filepos); + } + } + } + + wad = (wad_t *)malloc (sizeof (wad_t)); + q_strlcpy (wad->name, name, sizeof (wad->name)); + wad->id = id; + wad->fh = *fh; + wad->numlumps = numlumps; + wad->lumps = lumps; + + Con_DPrintf ("%s\n", name); + return wad; +} + +/* +================= +W_LoadWadList +================= +*/ +wad_t *W_LoadWadList (const char *names) +{ + char *newnames = q_strdup (names); + char *name, *e; + wad_t *wad, *wads = NULL; + char filename[MAX_QPATH]; + fshandle_t fh; + + for (name = newnames; name && *name;) + { + e = strchr (name, ';'); + if (e) + *e++ = 0; + + // remove all of the leading garbage left by the map editor + COM_FileBase (name, filename, sizeof (filename)); + COM_AddExtension (filename, ".wad", sizeof (filename)); + + if (!W_OpenWadFile (filename, &fh)) + { + // try the "gfx" directory + memmove (filename + 4, filename, sizeof (filename) - 4); + memcpy (filename, "gfx/", 4); + filename[sizeof (filename) - 1] = 0; + + if (!W_OpenWadFile (filename, &fh)) + { + name = e; + continue; + } + } + + wad = W_AddWadFile (filename, &fh); + if (wad) + { + wad->next = wads; + wads = wad; + } + else + FS_fclose (&fh); + + name = e; + } + free (newnames); + + return wads; +} + +/* +================= +W_FreeWadList +================= +*/ +void W_FreeWadList (wad_t *wads) +{ + wad_t *next; + + while (wads) + { + FS_fclose (&wads->fh); + free (wads->lumps); + + next = wads->next; + free (wads); + wads = next; + } +} + +/* +================= +W_GetLumpinfoList +================= +*/ +lumpinfo_t *W_GetLumpinfoList (wad_t *wads, const char *name, wad_t **out_wad) +{ + lumpinfo_t *info; + + while (wads) + { + info = W_GetLumpinfo (wads, name); + if (info) + { + *out_wad = wads; + return info; + } + + wads = wads->next; + } + + return NULL; } /* diff --git a/Quake/wad.h b/Quake/wad.h index 8838e0eac..67ab7aa23 100644 --- a/Quake/wad.h +++ b/Quake/wad.h @@ -38,8 +38,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define TYP_QTEX 65 #define TYP_QPIC 66 #define TYP_SOUND 67 +#define TYP_MIPTEX_PALETTE 67 #define TYP_MIPTEX 68 +#define WADID ('W' | ('A' << 8) | ('D' << 16) | ('2' << 24)) +#define WADID_VALVE ('W' | ('A' << 8) | ('D' << 16) | ('3' << 24)) + #define WADFILENAME "gfx.wad" //johnfitz -- filename is now hard-coded for honesty typedef struct @@ -66,15 +70,27 @@ typedef struct char name[16]; // must be null terminated } lumpinfo_t; -extern int wad_numlumps; -extern lumpinfo_t *wad_lumps; -extern byte *wad_base; +typedef struct wad_s +{ + char name[MAX_QPATH]; + int id; + fshandle_t fh; + int numlumps; + lumpinfo_t *lumps; + byte *base; + struct wad_s *next; +} wad_t; + +extern wad_t gfx; void W_LoadWadFile (void); //johnfitz -- filename is now hard-coded for honesty void W_CleanupName (const char *in, char *out); -lumpinfo_t *W_GetLumpinfo (const char *name); +lumpinfo_t *W_GetLumpinfo (wad_t *wad, const char *name); void *W_GetLumpName (const char *name); -void *W_GetLumpNum (int num); + +wad_t *W_LoadWadList (const char *names); +void W_FreeWadList (wad_t *wads); +lumpinfo_t *W_GetLumpinfoList (wad_t *wads, const char *name, wad_t **out_wad); void SwapPic (qpic_t *pic);