// 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:$ // // DESCRIPTION: // Preparation of data for rendering, // generation of lookups, caching, retrieval by name. // //----------------------------------------------------------------------------- //static const char #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" #include "os.h" #include "cgdoom-alloc.h" #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 originxLE; short originyLE; short patchLE; short stepdirLE; short colormapLE; } 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; int masked; //Carmack, you stupid fucknut, int and boolean DO NOT have the same length!!!! short widthLE; short heightLE; int obsolete; short patchcountLE; 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. short originx; short 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; const 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. // static void R_DrawColumnInCache(const 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. // static void R_GenerateComposite (int texnum) { byte* block; texture_t* texture; texpatch_t* patch; const patch_t* realpatch; int x; int x1; int x2; int i; const column_t* patchcol; short* collump; unsigned short* colofs; texture = textures[texnum]; block = (byte*)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;ipatchcount; i++, patch++) { realpatch = W_CacheLumpNumPatch(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= 0) { continue; } patchcol = (const column_t *)((const byte *)realpatch + INTFromBytes((const byte*)&(realpatch->columnofsLE[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; texpatch_t* patch; const patch_t* realpatch; int x; int x1; int x2; int i; short* collump; unsigned short* colofs; byte patchcount[320];// patchcount[texture->width] 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); ASSERT(texture->width <= 320); memset (patchcount, 0, texture->width); patch = texture->patches; for (i=0 , patch = texture->patches; ipatchcount; i++, patch++) { realpatch = W_CacheLumpNumPatch(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 ( ; xpatch; colofs[x] = (unsigned short)(3 + INTFromBytes((const byte*)&(realpatch->columnofsLE[x-x1]))); } } for (x=0 ; xwidth ; x++) { if (!patchcount[x]) { I_Error ("R_GenerateLookup: column without a patch (%s)\n",texture->name); return; } if (patchcount[x] > 1) { // Use the cached block. collump[x] = -1; colofs[x] = (unsigned short)texturecompositesize[texnum]; if (texturecompositesize[texnum] > 0x10000-texture->height) { I_Error ("R_GenerateLookup: texture %i is >64k",texnum); } texturecompositesize[texnum] += texture->height; } } } // // R_GetColumn // const byte* R_GetColumn ( int tex, int col ) { int lump; int ofs; col &= texturewidthmask[tex]; lump = texturecolumnlump[tex][col]; ofs = texturecolumnofs[tex][col]; /* CGDoom: To save RAM in WADs bound by limited memory, composite textures can be allowed only up to a certain size. Original CGDoom limits to 8192 bytes so that switches can appear, but some other textures fail. */ #if 0 if(lump <= 0 && texturecompositesize[tex] > 8192) { lump = 990; ofs = 267; } #endif if (lump > 0) return (const byte *)W_CacheLumpNumConst(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; const char* maptex; const char* maptex2; const char* maptex1; const char* names; const char* name_p; int* patchlookup; int totalwidth; int nummappatches; int offset; int maxoff; int maxoff2; int numtextures1; int numtextures2; const char* directory; /*int temp1; int temp2; int temp3;*/ // Load the patch names from pnames.lmp. names = (const char *)W_CacheLumpNameConst ("PNAMES", PU_STATIC); nummappatches = INTFromBytes((const byte*)names ); name_p = names+4; patchlookup = (int*)CGD_malloc(nummappatches*sizeof(*patchlookup)); for (i=0 ; i maxoff) I_Error ("R_InitTextures: bad texture directory"); mtexture = (maptexture_t *) ( (byte *)maptex + offset); texture = textures[i] = (texture_t*)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 ; jpatchcount ; 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] = (short*)Z_Malloc (texture->width*2, PU_STATIC,0); texturecolumnofs[i] = (unsigned short*)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<width; } Z_Free (maptex1); if (maptex2) Z_Free (maptex2); // Precalculate whatever possible. for (i=0 ; iwidth)<leftoffset)<topoffset)< int R_FlatNumForName (const char* name) i = W_CheckNumForName (name); if (i == -1) { I_Error ("R_FlatNumForName: %s not found",name); } return i - firstflat; } // // R_CheckTextureNumForName // Check whether texture is available. // Filter out NoTexture indicator. // int R_CheckTextureNumForName (const char *name) { int i; // "NoTexture" marker. if(name[0] == '-') { return 0; } for(i=0 ; iname,name,8)) { return i; } } return -1; } // // R_TextureNumForName // Calls R_CheckTextureNumForName, // aborts with error message. // int R_TextureNumForName (const char* name) { int i; i = R_CheckTextureNumForName (name); if (i==-1) { I_Error ("R_TextureNumForName: %s not found", name); } return i; } #if 0 // // 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; // Precache flats. //flatpresent = alloca(numflats); flatpresent = (char*)CGD_malloc(numflats); memset (flatpresent,0,numflats); for (i=0 ; ipatchcount ; j++) { lump = texture->patches[j].patch; texturememory += lumpinfo[lump].size; W_CacheLumpNum(lump , PU_CACHE); } } // Precache sprites. //spritepresent = alloca(numsprites); spritepresent = (char*)CGD_malloc (numsprites); memset (spritepresent,0, numsprites); for (th = thinkercap.next ; th != &thinkercap ; th=th->next) { if (th->function == TP_MobjThinker) spritepresent[((mobj_t *)th)->sprite] = 1; } spritememory = 0; for (i=0 ; ilump[k]; spritememory += lumpinfo[lump].size; W_CacheLumpNum(lump , PU_CACHE); } } } //Nspire has no alloca() function for temporary memory, so we have to use malloc() and free() to compensate free(flatpresent); free(texturepresent); free(spritepresent); } #endif