/* R_data.c */ #include "doomdef.h" #include "r_local.h" #include "p_local.h" #ifdef HAVE_ALLOCA_H #include #endif #ifdef GL_HERETIC #include "gl_struct.h" #endif /* extern void CheckAbortStartup(void); */ /* * Graphics. * Heretic 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. */ #ifndef GL_HERETIC 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; #endif 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]); #ifdef GL_HERETIC memset(block,205,texturecompositesize[texnum]); #endif collump = texturecolumnlump[texnum]; colofs = texturecolumnofs[texnum]; /* * composite the columns together */ patch = texture->patches; for (i=0 , patch = texture->patches; ipatchcount ; 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= 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 *)alloca (texture->width); memset (patchcount, 0, texture->width); patch = texture->patches; for (i=0 , patch = texture->patches; ipatchcount ; 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 ( ; xpatch; colofs[x] = LONG(realpatch->columnofs[x-x1])+3; } } for (x=0 ; xwidth ; x++) { if (!patchcount[x]) { printf ("R_GenerateLookup: column without a patch (%s)\n", texture->name); return; } /* I_Error ("R_GenerateLookup: column without a patch"); */ #ifndef GL_HERETIC if (patchcount[x] > 1) #else if (patchcount[x] >= 1) #endif { 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; } } } /* ================ = = 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; 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 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 ; 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] = 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<width; } Z_Free (maptex1); if (maptex2) Z_Free (maptex2); /* * precalculate whatever possible */ for(i = 0; i < numtextures; i++) { R_GenerateLookup(i); /* CheckAbortStartup(); */ } /* * translation table for global animation */ texturetranslation = Z_Malloc((numtextures + 1) * sizeof(void *), PU_STATIC, 0); for (i=0 ; iwidth)<leftoffset)<topoffset)<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 textures */ texturepresent = alloca(numtextures); memset (texturepresent,0, numtextures); for (i=0 ; ipatchcount ; j++) { lump = texture->patches[j].patch; texturememory += lumpinfo[lump].size; W_CacheLumpNum(lump , PU_CACHE); } #ifdef GL_HERETIC fn_vCheckIfTextureIsAnimated(i); fn_vRegisterWallTextures(i,texture); #endif } /* * precache flats */ flatpresent = alloca(numflats); memset (flatpresent,0,numflats); #ifndef GL_HERETIC for (i=0 ; inext) { if ((th->function.acp1 == (actionf_p1)P_MobjThinker) &&(((mobj_t *)th)->type!=MT_PLAYER)) /* !! Player sprites removed for OpenGL !! */ spritepresent[((mobj_t *)th)->sprite] = 1; } spritememory = 0; for (i=0 ; ilump[k]; spritememory += lumpinfo[lump].size; patch = W_CacheLumpNum(lump , PU_CACHE); #ifdef GL_HERETIC #ifndef OPTI_SPRITE fn_vRegisterSprite(lump-firstspritelump,patch); #else fn_vAddSpriteToList(lump-firstspritelump,patch); #endif /* OPTI_SPRITE */ #endif /* GL_HERETIC */ } } } #ifdef GL_HERETIC fn_vOptimizeSpriteMemory(); fn_vInitGLTextures(); #endif }