0,0 → 1,860 |
// Emacs style mode select -*- C++ -*- |
//----------------------------------------------------------------------------- |
// |
// $Id:$ |
// |
// 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.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,v 1.4 1997/02/03 16:47:55 b1 Exp $"; |
|
#ifdef __BEOS__ |
#ifdef __GNUC__ |
extern void *alloca(int); |
#else |
#include <alloca.h> |
#endif |
#endif /* __BEOS__ */ |
|
#include "m_swap.h" |
|
#include "i_system.h" |
#include "z_zone.h" |
|
#include "w_wad.h" |
|
#include "doomdef.h" |
#include "r_local.h" |
#include "p_local.h" |
|
#include "doomstat.h" |
#include "r_sky.h" |
|
#include "r_data.h" |
#include <malloc.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]; |
int 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 int width; |
short int 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() generates a BUS error on Solaris with optimization on */ |
#if 1 |
memcpy (texture->name, mtexture->name, sizeof(texture->name)); |
#else |
{ char *src; char *dst; |
src = (char *)mtexture->name; |
dst = (char *)texture->name; |
for (j=0; j<sizeof(texture->name); ++j ) |
*dst++ = *src++; |
} |
#endif |
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 (!I_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); |
} |
} |
} |
} |
|
|
|
|