diff options
Diffstat (limited to 'src/hexen/r_data.c')
-rw-r--r-- | src/hexen/r_data.c | 708 |
1 files changed, 708 insertions, 0 deletions
diff --git a/src/hexen/r_data.c b/src/hexen/r_data.c new file mode 100644 index 00000000..b82c0ff6 --- /dev/null +++ b/src/hexen/r_data.c @@ -0,0 +1,708 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 1993-2008 Raven Software +// Copyright(C) 2008 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// +//----------------------------------------------------------------------------- + + +#include "h2def.h" +#include "i_system.h" +#include "i_swap.h" +#include "r_local.h" +#include "p_local.h" + +typedef struct +{ + int originx; // block origin (allways UL), which has allready + int originy; // accounted for the patch's internal origin + int patch; +} texpatch_t; + +// a maptexturedef_t describes a rectangular texture, which is composed of one +// or more mappatch_t structures that arrange graphic patches +typedef struct +{ + char name[8]; // for switch changing, etc + short width; + short height; + short patchcount; + texpatch_t patches[1]; // [patchcount] drawn back to front + // into the cached texture +} texture_t; + + + +int firstflat, lastflat, numflats; +int firstpatch, lastpatch, numpatches; +int firstspritelump, lastspritelump, numspritelumps; + +int numtextures; +texture_t **textures; +int *texturewidthmask; +fixed_t *textureheight; // needed for texture pegging +int *texturecompositesize; +short **texturecolumnlump; +unsigned short **texturecolumnofs; +byte **texturecomposite; + +int *flattranslation; // for global animation +int *texturetranslation; // for global animation + +fixed_t *spritewidth; // needed for pre rendering +fixed_t *spriteoffset; +fixed_t *spritetopoffset; + +lighttable_t *colormaps; + + +/* +============================================================================== + + MAPTEXTURE_T CACHING + +when a texture is first needed, it counts the number of composite columns +required in the texture and allocates space for a column directory and any +new columns. The directory will simply point inside other patches if there +is only one patch in a given column, but any columns with multiple patches +will have new column_ts generated. + +============================================================================== +*/ + +/* +=================== += += R_DrawColumnInCache += += Clip and draw a column from a patch into a cached post += +=================== +*/ + +void R_DrawColumnInCache(column_t * patch, byte * cache, int originy, + int cacheheight) +{ + int count, position; + byte *source, *dest; + + dest = (byte *) cache + 3; + + while (patch->topdelta != 0xff) + { + source = (byte *) patch + 3; + count = patch->length; + position = originy + patch->topdelta; + if (position < 0) + { + count += position; + position = 0; + } + if (position + count > cacheheight) + count = cacheheight - position; + if (count > 0) + memcpy(cache + position, source, count); + + patch = (column_t *) ((byte *) patch + patch->length + 4); + } +} + + +/* +=================== += += R_GenerateComposite += +=================== +*/ + +void R_GenerateComposite(int texnum) +{ + byte *block; + texture_t *texture; + texpatch_t *patch; + patch_t *realpatch; + int x, x1, x2; + int i; + column_t *patchcol; + short *collump; + unsigned short *colofs; + + texture = textures[texnum]; + block = Z_Malloc(texturecompositesize[texnum], PU_STATIC, + &texturecomposite[texnum]); + collump = texturecolumnlump[texnum]; + colofs = texturecolumnofs[texnum]; + +// +// composite the columns together +// + patch = texture->patches; + + for (i = 0, patch = texture->patches; i < texture->patchcount; + i++, patch++) + { + realpatch = W_CacheLumpNum(patch->patch, PU_CACHE); + x1 = patch->originx; + x2 = x1 + SHORT(realpatch->width); + + if (x1 < 0) + x = 0; + else + x = x1; + if (x2 > texture->width) + x2 = texture->width; + + for (; x < x2; x++) + { + if (collump[x] >= 0) + continue; // column does not have multiple patches + patchcol = (column_t *) ((byte *) realpatch + + LONG(realpatch->columnofs[x - x1])); + R_DrawColumnInCache(patchcol, block + colofs[x], patch->originy, + texture->height); + } + + } + +// now that the texture has been built, it is purgable + Z_ChangeTag(block, PU_CACHE); +} + + +/* +=================== += += R_GenerateLookup += +=================== +*/ + +void R_GenerateLookup(int texnum) +{ + texture_t *texture; + byte *patchcount; // [texture->width] + texpatch_t *patch; + patch_t *realpatch; + int x, x1, x2; + int i; + short *collump; + unsigned short *colofs; + + texture = textures[texnum]; + + texturecomposite[texnum] = 0; // composited not created yet + texturecompositesize[texnum] = 0; + collump = texturecolumnlump[texnum]; + colofs = texturecolumnofs[texnum]; + +// +// count the number of columns that are covered by more than one patch +// fill in the lump / offset, so columns with only a single patch are +// all done +// + patchcount = (byte *) Z_Malloc(texture->width, PU_STATIC, &patchcount); + memset(patchcount, 0, texture->width); + patch = texture->patches; + + for (i = 0, patch = texture->patches; i < texture->patchcount; + i++, patch++) + { + realpatch = W_CacheLumpNum(patch->patch, PU_CACHE); + x1 = patch->originx; + x2 = x1 + SHORT(realpatch->width); + if (x1 < 0) + x = 0; + else + x = x1; + if (x2 > texture->width) + x2 = texture->width; + for (; x < x2; x++) + { + patchcount[x]++; + collump[x] = patch->patch; + colofs[x] = LONG(realpatch->columnofs[x - x1]) + 3; + } + } + + for (x = 0; x < texture->width; x++) + { + if (!patchcount[x]) + { + ST_Message("R_GenerateLookup: column without a patch (%s)\n", + texture->name); + return; + } +// I_Error ("R_GenerateLookup: column without a patch"); + if (patchcount[x] > 1) + { + collump[x] = -1; // use the cached block + colofs[x] = texturecompositesize[texnum]; + if (texturecompositesize[texnum] > 0x10000 - texture->height) + I_Error("R_GenerateLookup: texture %i is >64k", texnum); + texturecompositesize[texnum] += texture->height; + } + } + + Z_Free(patchcount); +} + + +/* +================ += += R_GetColumn += +================ +*/ + +byte *R_GetColumn(int tex, int col) +{ + int lump, ofs; + + col &= texturewidthmask[tex]; + lump = texturecolumnlump[tex][col]; + ofs = texturecolumnofs[tex][col]; + if (lump > 0) + return (byte *) W_CacheLumpNum(lump, PU_CACHE) + ofs; + if (!texturecomposite[tex]) + R_GenerateComposite(tex); + return texturecomposite[tex] + ofs; +} + + +/* +================== += += R_InitTextures += += Initializes the texture list with the textures from the world map += +================== +*/ + +void R_InitTextures(void) +{ + maptexture_t *mtexture; + texture_t *texture; + mappatch_t *mpatch; + texpatch_t *patch; + int i, j; + int *maptex, *maptex2, *maptex1; + char name[9], *names, *name_p; + int *patchlookup; + int totalwidth; + int nummappatches; + int offset, maxoff, maxoff2; + int numtextures1, numtextures2; + int *directory; + +// +// load the patch names from pnames.lmp +// + name[8] = 0; + names = W_CacheLumpName("PNAMES", PU_STATIC); + nummappatches = LONG(*((int *) names)); + name_p = names + 4; + patchlookup = Z_Malloc(nummappatches * sizeof(*patchlookup), PU_STATIC, NULL); + for (i = 0; i < nummappatches; i++) + { + strncpy(name, name_p + i * 8, 8); + patchlookup[i] = W_CheckNumForName(name); + } + W_ReleaseLumpName("PNAMES"); + +// +// load the map texture definitions from textures.lmp +// + maptex = maptex1 = W_CacheLumpName("TEXTURE1", PU_STATIC); + numtextures1 = LONG(*maptex); + maxoff = W_LumpLength(W_GetNumForName("TEXTURE1")); + directory = maptex + 1; + + if (W_CheckNumForName("TEXTURE2") != -1) + { + maptex2 = W_CacheLumpName("TEXTURE2", PU_STATIC); + numtextures2 = LONG(*maptex2); + maxoff2 = W_LumpLength(W_GetNumForName("TEXTURE2")); + } + else + { + maptex2 = NULL; + numtextures2 = 0; + maxoff2 = 0; + } + numtextures = numtextures1 + numtextures2; + + textures = Z_Malloc(numtextures * sizeof(texture_t *), PU_STATIC, 0); + texturecolumnlump = Z_Malloc(numtextures * sizeof(short *), PU_STATIC, 0); + texturecolumnofs = Z_Malloc(numtextures * sizeof(short *), PU_STATIC, 0); + texturecomposite = Z_Malloc(numtextures * sizeof(byte *), PU_STATIC, 0); + texturecompositesize = Z_Malloc(numtextures * sizeof(int), PU_STATIC, 0); + texturewidthmask = Z_Malloc(numtextures * sizeof(int), PU_STATIC, 0); + textureheight = Z_Malloc(numtextures * sizeof(fixed_t), PU_STATIC, 0); + + totalwidth = 0; + + for (i = 0; i < numtextures; i++, directory++) + { + if (i == numtextures1) + { // start looking in second texture file + maptex = maptex2; + maxoff = maxoff2; + directory = maptex + 1; + } + + offset = LONG(*directory); + if (offset > maxoff) + I_Error("R_InitTextures: bad texture directory"); + mtexture = (maptexture_t *) ((byte *) maptex + offset); + texture = textures[i] = Z_Malloc(sizeof(texture_t) + + + sizeof(texpatch_t) * + (SHORT(mtexture->patchcount) - 1), + PU_STATIC, 0); + texture->width = SHORT(mtexture->width); + texture->height = SHORT(mtexture->height); + texture->patchcount = SHORT(mtexture->patchcount); + memcpy(texture->name, mtexture->name, sizeof(texture->name)); + mpatch = &mtexture->patches[0]; + patch = &texture->patches[0]; + for (j = 0; j < texture->patchcount; j++, mpatch++, patch++) + { + patch->originx = SHORT(mpatch->originx); + patch->originy = SHORT(mpatch->originy); + patch->patch = patchlookup[SHORT(mpatch->patch)]; + if (patch->patch == -1) + I_Error("R_InitTextures: Missing patch in texture %s", + texture->name); + } + texturecolumnlump[i] = Z_Malloc(texture->width * sizeof(short), PU_STATIC, 0); + texturecolumnofs[i] = Z_Malloc(texture->width * sizeof(short), PU_STATIC, 0); + j = 1; + while (j * 2 <= texture->width) + j <<= 1; + texturewidthmask[i] = j - 1; + textureheight[i] = texture->height << FRACBITS; + + totalwidth += texture->width; + } + + Z_Free(patchlookup); + + W_ReleaseLumpName("TEXTURE1"); + if (maptex2) + W_ReleaseLumpName("TEXTURE2"); + +// +// precalculate whatever possible +// + for (i = 0; i < numtextures; i++) + { + R_GenerateLookup(i); + if (!(i & 31)) + ST_Progress(); + } + +// +// translation table for global animation +// + texturetranslation = Z_Malloc((numtextures + 1) * sizeof(int), PU_STATIC, 0); + for (i = 0; i < numtextures; i++) + texturetranslation[i] = i; +} + + +/* +================ += += R_InitFlats += +================= +*/ + +void R_InitFlats(void) +{ + int i; + + firstflat = W_GetNumForName("F_START") + 1; + lastflat = W_GetNumForName("F_END") - 1; + numflats = lastflat - firstflat + 1; + +// translation table for global animation + flattranslation = Z_Malloc((numflats + 1) * sizeof(int), PU_STATIC, 0); + for (i = 0; i < numflats; i++) + flattranslation[i] = i; +} + + +/* +================ += += R_InitSpriteLumps += += Finds the width and hoffset of all sprites in the wad, so the sprite doesn't += need to be cached just for the header during rendering +================= +*/ + +void R_InitSpriteLumps(void) +{ + int i; + patch_t *patch; + + firstspritelump = W_GetNumForName("S_START") + 1; + lastspritelump = W_GetNumForName("S_END") - 1; + numspritelumps = lastspritelump - firstspritelump + 1; + spritewidth = Z_Malloc(numspritelumps * sizeof(fixed_t), PU_STATIC, 0); + spriteoffset = Z_Malloc(numspritelumps * sizeof(fixed_t), PU_STATIC, 0); + spritetopoffset = Z_Malloc(numspritelumps * sizeof(fixed_t), PU_STATIC, 0); + + for (i = 0; i < numspritelumps; i++) + { + if (!(i & 127)) + ST_Progress(); + patch = W_CacheLumpNum(firstspritelump + i, PU_CACHE); + spritewidth[i] = SHORT(patch->width) << FRACBITS; + spriteoffset[i] = SHORT(patch->leftoffset) << FRACBITS; + spritetopoffset[i] = SHORT(patch->topoffset) << FRACBITS; + } +} + + +/* +================ += += R_InitColormaps += +================= +*/ + +void R_InitColormaps(void) +{ + int lump, length; +// +// load in the light tables +// 256 byte align tables +// + lump = W_GetNumForName("COLORMAP"); + length = W_LumpLength(lump); + colormaps = Z_Malloc(length, PU_STATIC, 0); + W_ReadLump(lump, colormaps); +} + + +/* +================ += += R_InitData += += Locates all the lumps that will be used by all views += Must be called after W_Init +================= +*/ + +void R_InitData(void) +{ + R_InitTextures(); + R_InitFlats(); + R_InitSpriteLumps(); + R_InitColormaps(); +} + +//============================================================================= + +/* +================ += += R_FlatNumForName += +================ +*/ + +int R_FlatNumForName(char *name) +{ + int i; + char namet[9]; + + i = W_CheckNumForName(name); + if (i == -1) + { + namet[8] = 0; + memcpy(namet, name, 8); + I_Error("R_FlatNumForName: %s not found", namet); + } + return i - firstflat; +} + + +/* +================ += += R_CheckTextureNumForName += +================ +*/ + +int R_CheckTextureNumForName(char *name) +{ + int i; + + if (name[0] == '-') // no texture marker + return 0; + + for (i = 0; i < numtextures; i++) + if (!strncasecmp(textures[i]->name, name, 8)) + return i; + + return -1; +} + + +/* +================ += += R_TextureNumForName += +================ +*/ + +int R_TextureNumForName(char *name) +{ + int i; + //char namet[9]; + + i = R_CheckTextureNumForName(name); + if (i == -1) + I_Error("R_TextureNumForName: %s not found", name); + + return i; +} + + +/* +================= += += R_PrecacheLevel += += Preloads all relevent graphics for the level +================= +*/ + +int flatmemory, texturememory, spritememory; + +void R_PrecacheLevel(void) +{ + char *flatpresent; + char *texturepresent; + char *spritepresent; + int i, j, k, lump; + texture_t *texture; + thinker_t *th; + spriteframe_t *sf; + + if (demoplayback) + return; + +// +// precache flats +// + flatpresent = Z_Malloc(numflats, PU_STATIC, NULL); + memset(flatpresent, 0, numflats); + for (i = 0; i < numsectors; i++) + { + flatpresent[sectors[i].floorpic] = 1; + flatpresent[sectors[i].ceilingpic] = 1; + } + + flatmemory = 0; + for (i = 0; i < numflats; i++) + if (flatpresent[i]) + { + lump = firstflat + i; + flatmemory += lumpinfo[lump].size; + W_CacheLumpNum(lump, PU_CACHE); + } + + Z_Free(flatpresent); + +// +// precache textures +// + texturepresent = Z_Malloc(numtextures, PU_STATIC, NULL); + memset(texturepresent, 0, numtextures); + + for (i = 0; i < numsides; i++) + { + texturepresent[sides[i].toptexture] = 1; + texturepresent[sides[i].midtexture] = 1; + texturepresent[sides[i].bottomtexture] = 1; + } + + texturepresent[Sky1Texture] = 1; + texturepresent[Sky2Texture] = 1; + + texturememory = 0; + for (i = 0; i < numtextures; i++) + { + if (!texturepresent[i]) + continue; + texture = textures[i]; + for (j = 0; j < texture->patchcount; j++) + { + lump = texture->patches[j].patch; + texturememory += lumpinfo[lump].size; + W_CacheLumpNum(lump, PU_CACHE); + } + } + + Z_Free(texturepresent); + +// +// precache sprites +// + spritepresent = Z_Malloc(numsprites, PU_STATIC, NULL); + memset(spritepresent, 0, numsprites); + + for (th = thinkercap.next; th != &thinkercap; th = th->next) + { + if (th->function == P_MobjThinker) + spritepresent[((mobj_t *) th)->sprite] = 1; + } + + spritememory = 0; + for (i = 0; i < numsprites; i++) + { + if (!spritepresent[i]) + continue; + for (j = 0; j < sprites[i].numframes; j++) + { + sf = &sprites[i].spriteframes[j]; + for (k = 0; k < 8; k++) + { + lump = firstspritelump + sf->lump[k]; + spritememory += lumpinfo[lump].size; + W_CacheLumpNum(lump, PU_CACHE); + } + } + } + + Z_Free(spritepresent); +} |