summaryrefslogtreecommitdiff
path: root/src/r_data.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/r_data.c')
-rw-r--r--src/r_data.c852
1 files changed, 852 insertions, 0 deletions
diff --git a/src/r_data.c b/src/r_data.c
new file mode 100644
index 00000000..0d3d8873
--- /dev/null
+++ b/src/r_data.c
@@ -0,0 +1,852 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// $Id: r_data.c 4 2005-07-23 16:19:41Z fraggle $
+//
+// Copyright (C) 1993-1996 by id Software, Inc.
+//
+// This source is available for distribution and/or modification
+// only under the terms of the DOOM Source Code License as
+// published by id Software. All rights reserved.
+//
+// The source is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
+// for more details.
+//
+// $Log$
+// Revision 1.1 2005/07/23 16:19:46 fraggle
+// Initial revision
+//
+//
+// Revision 1.3 1997/01/29 20:10
+// DESCRIPTION:
+// Preparation of data for rendering,
+// generation of lookups, caching, retrieval by name.
+//
+//-----------------------------------------------------------------------------
+
+
+static const char
+rcsid[] = "$Id: r_data.c 4 2005-07-23 16:19:41Z fraggle $";
+
+#include "i_system.h"
+#include "z_zone.h"
+
+#include "m_swap.h"
+
+#include "w_wad.h"
+
+#include "doomdef.h"
+#include "r_local.h"
+#include "p_local.h"
+
+#include "doomstat.h"
+#include "r_sky.h"
+
+#ifdef LINUX
+#include <alloca.h>
+#endif
+
+
+#include "r_data.h"
+
+//
+// Graphics.
+// DOOM graphics for walls and sprites
+// is stored in vertical runs of opaque pixels (posts).
+// A column is composed of zero or more posts,
+// a patch or sprite is composed of zero or more columns.
+//
+
+
+
+//
+// Texture definition.
+// Each texture is composed of one or more patches,
+// with patches being lumps stored in the WAD.
+// The lumps are referenced by number, and patched
+// into the rectangular texture space using origin
+// and possibly other attributes.
+//
+typedef struct
+{
+ short originx;
+ short originy;
+ short patch;
+ short stepdir;
+ short colormap;
+} mappatch_t;
+
+
+//
+// Texture definition.
+// A DOOM wall texture is a list of patches
+// which are to be combined in a predefined order.
+//
+typedef struct
+{
+ char name[8];
+ boolean masked;
+ short width;
+ short height;
+ void **columndirectory; // OBSOLETE
+ short patchcount;
+ mappatch_t patches[1];
+} maptexture_t;
+
+
+// A single patch from a texture definition,
+// basically a rectangular area within
+// the texture rectangle.
+typedef struct
+{
+ // Block origin (allways UL),
+ // which has allready accounted
+ // for the internal origin of the patch.
+ int originx;
+ int originy;
+ 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
+{
+ // Keep name for switch changing, etc.
+ char name[8];
+ short width;
+ short height;
+
+ // All the patches[patchcount]
+ // are drawn back to front into the cached texture.
+ short patchcount;
+ texpatch_t patches[1];
+
+} texture_t;
+
+
+
+int firstflat;
+int lastflat;
+int numflats;
+
+int firstpatch;
+int lastpatch;
+int numpatches;
+
+int firstspritelump;
+int lastspritelump;
+int numspritelumps;
+
+int numtextures;
+texture_t** textures;
+
+
+int* texturewidthmask;
+// needed for texture pegging
+fixed_t* textureheight;
+int* texturecompositesize;
+short** texturecolumnlump;
+unsigned short** texturecolumnofs;
+byte** texturecomposite;
+
+// for global animation
+int* flattranslation;
+int* texturetranslation;
+
+// needed for pre rendering
+fixed_t* spritewidth;
+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;
+ int position;
+ byte* source;
+ byte* 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
+// Using the texture definition,
+// the composite texture is created from the patches,
+// and each column is cached.
+//
+void R_GenerateComposite (int texnum)
+{
+ byte* block;
+ texture_t* texture;
+ texpatch_t* patch;
+ patch_t* realpatch;
+ int x;
+ int x1;
+ int 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++)
+ {
+ // Column does not have multiple patches?
+ if (collump[x] >= 0)
+ continue;
+
+ 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 in column cache,
+ // it is purgable from zone memory.
+ Z_ChangeTag (block, PU_CACHE);
+}
+
+
+
+//
+// R_GenerateLookup
+//
+void R_GenerateLookup (int texnum)
+{
+ texture_t* texture;
+ byte* patchcount; // patchcount[texture->width]
+ texpatch_t* patch;
+ patch_t* realpatch;
+ int x;
+ int x1;
+ int x2;
+ int i;
+ short* collump;
+ unsigned short* colofs;
+
+ texture = textures[texnum];
+
+ // Composited texture not created yet.
+ texturecomposite[texnum] = 0;
+
+ texturecompositesize[texnum] = 0;
+ collump = texturecolumnlump[texnum];
+ colofs = texturecolumnofs[texnum];
+
+ // Now 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 *)alloca (texture->width);
+ 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])
+ {
+ printf ("R_GenerateLookup: column without a patch (%s)\n",
+ texture->name);
+ return;
+ }
+ // I_Error ("R_GenerateLookup: column without a patch");
+
+ if (patchcount[x] > 1)
+ {
+ // Use the cached block.
+ collump[x] = -1;
+ colofs[x] = texturecompositesize[texnum];
+
+ if (texturecompositesize[texnum] > 0x10000-texture->height)
+ {
+ I_Error ("R_GenerateLookup: texture %i is >64k",
+ texnum);
+ }
+
+ texturecompositesize[texnum] += texture->height;
+ }
+ }
+}
+
+
+
+
+//
+// R_GetColumn
+//
+byte*
+R_GetColumn
+( int tex,
+ int col )
+{
+ int lump;
+ int 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;
+ int j;
+
+ int* maptex;
+ int* maptex2;
+ int* maptex1;
+
+ char name[9];
+ char* names;
+ char* name_p;
+
+ int* patchlookup;
+
+ int totalwidth;
+ int nummappatches;
+ int offset;
+ int maxoff;
+ int maxoff2;
+ int numtextures1;
+ int numtextures2;
+
+ int* directory;
+
+ int temp1;
+ int temp2;
+ int temp3;
+
+
+ // 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 = alloca (nummappatches*sizeof(*patchlookup));
+
+ for (i=0 ; i<nummappatches ; i++)
+ {
+ strncpy (name,name_p+i*8, 8);
+ patchlookup[i] = W_CheckNumForName (name);
+ }
+ Z_Free (names);
+
+ // Load the map texture definitions from textures.lmp.
+ // The data is contained in one or two lumps,
+ // TEXTURE1 for shareware, plus TEXTURE2 for commercial.
+ 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*4, PU_STATIC, 0);
+ texturecolumnlump = Z_Malloc (numtextures*4, PU_STATIC, 0);
+ texturecolumnofs = Z_Malloc (numtextures*4, PU_STATIC, 0);
+ texturecomposite = Z_Malloc (numtextures*4, PU_STATIC, 0);
+ texturecompositesize = Z_Malloc (numtextures*4, PU_STATIC, 0);
+ texturewidthmask = Z_Malloc (numtextures*4, PU_STATIC, 0);
+ textureheight = Z_Malloc (numtextures*4, PU_STATIC, 0);
+
+ totalwidth = 0;
+
+ // Really complex printing shit...
+ temp1 = W_GetNumForName ("S_START"); // P_???????
+ temp2 = W_GetNumForName ("S_END") - 1;
+ temp3 = ((temp2-temp1+63)/64) + ((numtextures+63)/64);
+ printf("[");
+ for (i = 0; i < temp3; i++)
+ printf(" ");
+ printf(" ]");
+ for (i = 0; i < temp3; i++)
+ printf("\x8");
+ printf("\x8\x8\x8\x8\x8\x8\x8\x8\x8\x8");
+
+ for (i=0 ; i<numtextures ; i++, directory++)
+ {
+ if (!(i&63))
+ printf (".");
+
+ 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*2, PU_STATIC,0);
+ texturecolumnofs[i] = Z_Malloc (texture->width*2, 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 (maptex1);
+ if (maptex2)
+ Z_Free (maptex2);
+
+ // Precalculate whatever possible.
+ for (i=0 ; i<numtextures ; i++)
+ R_GenerateLookup (i);
+
+ // Create translation table for global animation.
+ texturetranslation = Z_Malloc ((numtextures+1)*4, 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;
+
+ // Create translation table for global animation.
+ flattranslation = Z_Malloc ((numflats+1)*4, 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 does not need to be cached completely
+// just for having the header info ready 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*4, PU_STATIC, 0);
+ spriteoffset = Z_Malloc (numspritelumps*4, PU_STATIC, 0);
+ spritetopoffset = Z_Malloc (numspritelumps*4, PU_STATIC, 0);
+
+ for (i=0 ; i< numspritelumps ; i++)
+ {
+ if (!(i&63))
+ printf (".");
+
+ 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) + 255;
+ colormaps = Z_Malloc (length, PU_STATIC, 0);
+ colormaps = (byte *)( ((int)colormaps + 255)&~0xff);
+ 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 ();
+ printf ("\nInitTextures");
+ R_InitFlats ();
+ printf ("\nInitFlats");
+ R_InitSpriteLumps ();
+ printf ("\nInitSprites");
+ R_InitColormaps ();
+ printf ("\nInitColormaps");
+}
+
+
+
+//
+// R_FlatNumForName
+// Retrieval, get a flat number for a flat name.
+//
+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
+// Check whether texture is available.
+// Filter out NoTexture indicator.
+//
+int R_CheckTextureNumForName (char *name)
+{
+ int i;
+
+ // "NoTexture" marker.
+ if (name[0] == '-')
+ return 0;
+
+ for (i=0 ; i<numtextures ; i++)
+ if (!strncasecmp (textures[i]->name, name, 8) )
+ return i;
+
+ return -1;
+}
+
+
+
+//
+// R_TextureNumForName
+// Calls R_CheckTextureNumForName,
+// aborts with error message.
+//
+int R_TextureNumForName (char* name)
+{
+ int i;
+
+ i = R_CheckTextureNumForName (name);
+
+ if (i==-1)
+ {
+ I_Error ("R_TextureNumForName: %s not found",
+ name);
+ }
+ return i;
+}
+
+
+
+
+//
+// R_PrecacheLevel
+// Preloads all relevant graphics for the level.
+//
+int flatmemory;
+int texturememory;
+int spritememory;
+
+void R_PrecacheLevel (void)
+{
+ char* flatpresent;
+ char* texturepresent;
+ char* spritepresent;
+
+ int i;
+ int j;
+ int k;
+ int lump;
+
+ texture_t* texture;
+ thinker_t* th;
+ spriteframe_t* sf;
+
+ if (demoplayback)
+ return;
+
+ // Precache flats.
+ flatpresent = alloca(numflats);
+ 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);
+ }
+ }
+
+ // Precache textures.
+ texturepresent = alloca(numtextures);
+ 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;
+ }
+
+ // Sky texture is always present.
+ // Note that F_SKY1 is the name used to
+ // indicate a sky floor/ceiling as a flat,
+ // while the sky texture is stored like
+ // a wall texture, with an episode dependend
+ // name.
+ texturepresent[skytexture] = 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);
+ }
+ }
+
+ // Precache sprites.
+ spritepresent = alloca(numsprites);
+ memset (spritepresent,0, numsprites);
+
+ for (th = thinkercap.next ; th != &thinkercap ; th=th->next)
+ {
+ if (th->function.acp1 == (actionf_p1)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);
+ }
+ }
+ }
+}
+
+
+
+