r_data.c
  1  //
  2  // Copyright(C) 1993-1996 Id Software, Inc.
  3  // Copyright(C) 2005-2014 Simon Howard
  4  //
  5  // This program is free software; you can redistribute it and/or
  6  // modify it under the terms of the GNU General Public License
  7  // as published by the Free Software Foundation; either version 2
  8  // of the License, or (at your option) any later version.
  9  //
 10  // This program is distributed in the hope that it will be useful,
 11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13  // GNU General Public License for more details.
 14  //
 15  // DESCRIPTION:
 16  //	Preparation of data for rendering,
 17  //	generation of lookups, caching, retrieval by name.
 18  //
 19  
 20  #include <stdio.h>
 21  
 22  #include "deh_main.h"
 23  #include "i_swap.h"
 24  #include "i_system.h"
 25  #include "z_zone.h"
 26  
 27  
 28  #include "w_wad.h"
 29  
 30  #include "doomdef.h"
 31  #include "m_misc.h"
 32  #include "r_local.h"
 33  #include "p_local.h"
 34  
 35  #include "doomstat.h"
 36  #include "r_sky.h"
 37  
 38  
 39  #include "r_data.h"
 40  
 41  
 42  
 43  //
 44  // Graphics.
 45  // DOOM graphics for walls and sprites
 46  // is stored in vertical runs of opaque pixels (posts).
 47  // A column is composed of zero or more posts,
 48  // a patch or sprite is composed of zero or more columns.
 49  // 
 50  
 51  
 52  
 53  //
 54  // Texture definition.
 55  // Each texture is composed of one or more patches,
 56  // with patches being lumps stored in the WAD.
 57  // The lumps are referenced by number, and patched
 58  // into the rectangular texture space using origin
 59  // and possibly other attributes.
 60  //
 61  typedef struct
 62  {
 63      short	originx;
 64      short	originy;
 65      short	patch;
 66      short	stepdir;
 67      short	colormap;
 68  } PACKEDATTR mappatch_t;
 69  
 70  
 71  //
 72  // Texture definition.
 73  // A DOOM wall texture is a list of patches
 74  // which are to be combined in a predefined order.
 75  //
 76  typedef struct
 77  {
 78      char		name[8];
 79      int			masked;	
 80      short		width;
 81      short		height;
 82      int                 obsolete;
 83      short		patchcount;
 84      mappatch_t	patches[1];
 85  } PACKEDATTR maptexture_t;
 86  
 87  
 88  // A single patch from a texture definition,
 89  //  basically a rectangular area within
 90  //  the texture rectangle.
 91  typedef struct
 92  {
 93      // Block origin (allways UL),
 94      // which has allready accounted
 95      // for the internal origin of the patch.
 96      short	originx;	
 97      short	originy;
 98      int		patch;
 99  } texpatch_t;
100  
101  
102  // A maptexturedef_t describes a rectangular texture,
103  //  which is composed of one or more mappatch_t structures
104  //  that arrange graphic patches.
105  
106  typedef struct texture_s texture_t;
107  
108  struct texture_s
109  {
110      // Keep name for switch changing, etc.
111      char	name[8];		
112      short	width;
113      short	height;
114  
115      // Index in textures list
116  
117      int         index;
118  
119      // Next in hash table chain
120  
121      texture_t  *next;
122      
123      // All the patches[patchcount]
124      //  are drawn back to front into the cached texture.
125      short	patchcount;
126      texpatch_t	patches[1];		
127  };
128  
129  
130  
131  int		firstflat;
132  int		lastflat;
133  int		numflats;
134  
135  int		firstpatch;
136  int		lastpatch;
137  int		numpatches;
138  
139  int		firstspritelump;
140  int		lastspritelump;
141  int		numspritelumps;
142  
143  int		numtextures;
144  texture_t**	textures;
145  texture_t**     textures_hashtable;
146  
147  
148  int*			texturewidthmask;
149  // needed for texture pegging
150  fixed_t*		textureheight;		
151  int*			texturecompositesize;
152  short**			texturecolumnlump;
153  unsigned short**	texturecolumnofs;
154  byte**			texturecomposite;
155  
156  // for global animation
157  int*		flattranslation;
158  int*		texturetranslation;
159  
160  // needed for pre rendering
161  fixed_t*	spritewidth;	
162  fixed_t*	spriteoffset;
163  fixed_t*	spritetopoffset;
164  
165  lighttable_t	*colormaps;
166  
167  
168  //
169  // MAPTEXTURE_T CACHING
170  // When a texture is first needed,
171  //  it counts the number of composite columns
172  //  required in the texture and allocates space
173  //  for a column directory and any new columns.
174  // The directory will simply point inside other patches
175  //  if there is only one patch in a given column,
176  //  but any columns with multiple patches
177  //  will have new column_ts generated.
178  //
179  
180  
181  
182  //
183  // R_DrawColumnInCache
184  // Clip and draw a column
185  //  from a patch into a cached post.
186  //
187  void
188  R_DrawColumnInCache
189  ( column_t*	patch,
190    byte*		cache,
191    int		originy,
192    int		cacheheight )
193  {
194      int		count;
195      int		position;
196      byte*	source;
197  
198      while (patch->topdelta != 0xff)
199      {
200  	source = (byte *)patch + 3;
201  	count = patch->length;
202  	position = originy + patch->topdelta;
203  
204  	if (position < 0)
205  	{
206  	    count += position;
207  	    position = 0;
208  	}
209  
210  	if (position + count > cacheheight)
211  	    count = cacheheight - position;
212  
213  	if (count > 0)
214  	    memcpy (cache + position, source, count);
215  		
216  	patch = (column_t *)(  (byte *)patch + patch->length + 4); 
217      }
218  }
219  
220  
221  
222  //
223  // R_GenerateComposite
224  // Using the texture definition,
225  //  the composite texture is created from the patches,
226  //  and each column is cached.
227  //
228  void R_GenerateComposite (int texnum)
229  {
230      byte*		block;
231      texture_t*		texture;
232      texpatch_t*		patch;	
233      patch_t*		realpatch;
234      int			x;
235      int			x1;
236      int			x2;
237      int			i;
238      column_t*		patchcol;
239      short*		collump;
240      unsigned short*	colofs;
241  	
242      texture = textures[texnum];
243  
244      block = Z_Malloc (texturecompositesize[texnum],
245  		      PU_STATIC, 
246  		      &texturecomposite[texnum]);	
247  
248      collump = texturecolumnlump[texnum];
249      colofs = texturecolumnofs[texnum];
250      
251      // Composite the columns together.
252      patch = texture->patches;
253  		
254      for (i=0 , patch = texture->patches;
255  	 i<texture->patchcount;
256  	 i++, patch++)
257      {
258  	realpatch = W_CacheLumpNum (patch->patch, PU_CACHE);
259  	x1 = patch->originx;
260  	x2 = x1 + SHORT(realpatch->width);
261  
262  	if (x1<0)
263  	    x = 0;
264  	else
265  	    x = x1;
266  	
267  	if (x2 > texture->width)
268  	    x2 = texture->width;
269  
270  	for ( ; x<x2 ; x++)
271  	{
272  	    // Column does not have multiple patches?
273  	    if (collump[x] >= 0)
274  		continue;
275  	    
276  	    patchcol = (column_t *)((byte *)realpatch
277  				    + LONG(realpatch->columnofs[x-x1]));
278  	    R_DrawColumnInCache (patchcol,
279  				 block + colofs[x],
280  				 patch->originy,
281  				 texture->height);
282  	}
283  						
284      }
285  
286      // Now that the texture has been built in column cache,
287      //  it is purgable from zone memory.
288      Z_ChangeTag (block, PU_CACHE);
289  }
290  
291  
292  
293  //
294  // R_GenerateLookup
295  //
296  void R_GenerateLookup (int texnum)
297  {
298      texture_t*		texture;
299      byte*		patchcount;	// patchcount[texture->width]
300      texpatch_t*		patch;	
301      patch_t*		realpatch;
302      int			x;
303      int			x1;
304      int			x2;
305      int			i;
306      short*		collump;
307      unsigned short*	colofs;
308  	
309      texture = textures[texnum];
310  
311      // Composited texture not created yet.
312      texturecomposite[texnum] = 0;
313      
314      texturecompositesize[texnum] = 0;
315      collump = texturecolumnlump[texnum];
316      colofs = texturecolumnofs[texnum];
317      
318      // Now count the number of columns
319      //  that are covered by more than one patch.
320      // Fill in the lump / offset, so columns
321      //  with only a single patch are all done.
322      patchcount = (byte *) Z_Malloc(texture->width, PU_STATIC, &patchcount);
323      memset (patchcount, 0, texture->width);
324      patch = texture->patches;
325  
326      for (i=0 , patch = texture->patches;
327  	 i<texture->patchcount;
328  	 i++, patch++)
329      {
330  	realpatch = W_CacheLumpNum (patch->patch, PU_CACHE);
331  	x1 = patch->originx;
332  	x2 = x1 + SHORT(realpatch->width);
333  	
334  	if (x1 < 0)
335  	    x = 0;
336  	else
337  	    x = x1;
338  
339  	if (x2 > texture->width)
340  	    x2 = texture->width;
341  	for ( ; x<x2 ; x++)
342  	{
343  	    patchcount[x]++;
344  	    collump[x] = patch->patch;
345  	    colofs[x] = LONG(realpatch->columnofs[x-x1])+3;
346  	}
347      }
348  	
349      for (x=0 ; x<texture->width ; x++)
350      {
351  	if (!patchcount[x])
352  	{
353  	    printf ("R_GenerateLookup: column without a patch (%s)\n",
354  		    texture->name);
355  	    return;
356  	}
357  	// I_Error ("R_GenerateLookup: column without a patch");
358  	
359  	if (patchcount[x] > 1)
360  	{
361  	    // Use the cached block.
362  	    collump[x] = -1;	
363  	    colofs[x] = texturecompositesize[texnum];
364  	    
365  	    if (texturecompositesize[texnum] > 0x10000-texture->height)
366  	    {
367  		I_Error ("R_GenerateLookup: texture %i is >64k",
368  			 texnum);
369  	    }
370  	    
371  	    texturecompositesize[texnum] += texture->height;
372  	}
373      }
374  
375      Z_Free(patchcount);
376  }
377  
378  
379  
380  
381  //
382  // R_GetColumn
383  //
384  byte*
385  R_GetColumn
386  ( int		tex,
387    int		col )
388  {
389      int		lump;
390      int		ofs;
391  	
392      col &= texturewidthmask[tex];
393      lump = texturecolumnlump[tex][col];
394      ofs = texturecolumnofs[tex][col];
395      
396      if (lump > 0)
397  	return (byte *)W_CacheLumpNum(lump,PU_CACHE)+ofs;
398  
399      if (!texturecomposite[tex])
400  	R_GenerateComposite (tex);
401  
402      return texturecomposite[tex] + ofs;
403  }
404  
405  
406  static void GenerateTextureHashTable(void)
407  {
408      texture_t **rover;
409      int i;
410      int key;
411  
412      textures_hashtable 
413              = Z_Malloc(sizeof(texture_t *) * numtextures, PU_STATIC, 0);
414  
415      memset(textures_hashtable, 0, sizeof(texture_t *) * numtextures);
416  
417      // Add all textures to hash table
418  
419      for (i=0; i<numtextures; ++i)
420      {
421          // Store index
422  
423          textures[i]->index = i;
424  
425          // Vanilla Doom does a linear search of the texures array
426          // and stops at the first entry it finds.  If there are two
427          // entries with the same name, the first one in the array
428          // wins. The new entry must therefore be added at the end
429          // of the hash chain, so that earlier entries win.
430  
431          key = W_LumpNameHash(textures[i]->name) % numtextures;
432  
433          rover = &textures_hashtable[key];
434  
435          while (*rover != NULL)
436          {
437              rover = &(*rover)->next;
438          }
439  
440          // Hook into hash table
441  
442          textures[i]->next = NULL;
443          *rover = textures[i];
444      }
445  }
446  
447  
448  //
449  // R_InitTextures
450  // Initializes the texture list
451  //  with the textures from the world map.
452  //
453  void R_InitTextures (void)
454  {
455      maptexture_t*	mtexture;
456      texture_t*		texture;
457      mappatch_t*		mpatch;
458      texpatch_t*		patch;
459  
460      int			i;
461      int			j;
462  
463      int*		maptex;
464      int*		maptex2;
465      int*		maptex1;
466      
467      char		name[9];
468      char*		names;
469      char*		name_p;
470      
471      int*		patchlookup;
472      
473      int			totalwidth;
474      int			nummappatches;
475      int			offset;
476      int			maxoff;
477      int			maxoff2;
478      int			numtextures1;
479      int			numtextures2;
480  
481      int*		directory;
482      
483      int			temp1;
484      int			temp2;
485      int			temp3;
486  
487  
488      // Load the patch names from pnames.lmp.
489      name[8] = 0;
490      names = W_CacheLumpName (DEH_String("PNAMES"), PU_STATIC);
491      nummappatches = LONG ( *((int *)names) );
492      name_p = names + 4;
493      patchlookup = Z_Malloc(nummappatches*sizeof(*patchlookup), PU_STATIC, NULL);  
494  
495      for (i = 0; i < nummappatches; i++)
496      {
497          M_StringCopy(name, name_p + i * 8, sizeof(name));
498          patchlookup[i] = W_CheckNumForName(name);
499      }
500      W_ReleaseLumpName(DEH_String("PNAMES"));
501  
502  
503      // Load the map texture definitions from textures.lmp.
504      // The data is contained in one or two lumps,
505      //  TEXTURE1 for shareware, plus TEXTURE2 for commercial.
506      maptex = maptex1 = W_CacheLumpName (DEH_String("TEXTURE1"), PU_STATIC);
507      numtextures1 = LONG(*maptex);
508      maxoff = W_LumpLength (W_GetNumForName (DEH_String("TEXTURE1")));
509      directory = maptex+1;
510  	
511      if (W_CheckNumForName (DEH_String("TEXTURE2")) != -1)
512      {
513  	maptex2 = W_CacheLumpName (DEH_String("TEXTURE2"), PU_STATIC);
514  	numtextures2 = LONG(*maptex2);
515  	maxoff2 = W_LumpLength (W_GetNumForName (DEH_String("TEXTURE2")));
516      }
517      else
518      {
519  	maptex2 = NULL;
520  	numtextures2 = 0;
521  	maxoff2 = 0;
522      }
523      numtextures = numtextures1 + numtextures2;
524  	
525      textures = Z_Malloc (numtextures * sizeof(*textures), PU_STATIC, 0);
526      texturecolumnlump = Z_Malloc (numtextures * sizeof(*texturecolumnlump), PU_STATIC, 0);
527      texturecolumnofs = Z_Malloc (numtextures * sizeof(*texturecolumnofs), PU_STATIC, 0);
528      texturecomposite = Z_Malloc (numtextures * sizeof(*texturecomposite), PU_STATIC, 0);
529      texturecompositesize = Z_Malloc (numtextures * sizeof(*texturecompositesize), PU_STATIC, 0);
530      texturewidthmask = Z_Malloc (numtextures * sizeof(*texturewidthmask), PU_STATIC, 0);
531      textureheight = Z_Malloc (numtextures * sizeof(*textureheight), PU_STATIC, 0);
532  
533      totalwidth = 0;
534      
535      //	Really complex printing shit...
536      temp1 = W_GetNumForName (DEH_String("S_START"));  // P_???????
537      temp2 = W_GetNumForName (DEH_String("S_END")) - 1;
538      temp3 = ((temp2-temp1+63)/64) + ((numtextures+63)/64);
539  
540      // If stdout is a real console, use the classic vanilla "filling
541      // up the box" effect, which uses backspace to "step back" inside
542      // the box.  If stdout is a file, don't draw the box.
543  
544      if (I_ConsoleStdout())
545      {
546          printf("[");
547          for (i = 0; i < temp3 + 9; i++)
548              printf(" ");
549          printf("]");
550          for (i = 0; i < temp3 + 10; i++)
551              printf("\b");
552      }
553  	
554      for (i=0 ; i<numtextures ; i++, directory++)
555      {
556  	if (!(i&63))
557  	    printf (".");
558  
559  	if (i == numtextures1)
560  	{
561  	    // Start looking in second texture file.
562  	    maptex = maptex2;
563  	    maxoff = maxoff2;
564  	    directory = maptex+1;
565  	}
566  		
567  	offset = LONG(*directory);
568  
569  	if (offset > maxoff)
570  	    I_Error ("R_InitTextures: bad texture directory");
571  	
572  	mtexture = (maptexture_t *) ( (byte *)maptex + offset);
573  
574  	texture = textures[i] =
575  	    Z_Malloc (sizeof(texture_t)
576  		      + sizeof(texpatch_t)*(SHORT(mtexture->patchcount)-1),
577  		      PU_STATIC, 0);
578  	
579  	texture->width = SHORT(mtexture->width);
580  	texture->height = SHORT(mtexture->height);
581  	texture->patchcount = SHORT(mtexture->patchcount);
582  	
583  	memcpy (texture->name, mtexture->name, sizeof(texture->name));
584  	mpatch = &mtexture->patches[0];
585  	patch = &texture->patches[0];
586  
587  	for (j=0 ; j<texture->patchcount ; j++, mpatch++, patch++)
588  	{
589  	    patch->originx = SHORT(mpatch->originx);
590  	    patch->originy = SHORT(mpatch->originy);
591  	    patch->patch = patchlookup[SHORT(mpatch->patch)];
592  	    if (patch->patch == -1)
593  	    {
594  		I_Error ("R_InitTextures: Missing patch in texture %s",
595  			 texture->name);
596  	    }
597  	}		
598  	texturecolumnlump[i] = Z_Malloc (texture->width*sizeof(**texturecolumnlump), PU_STATIC,0);
599  	texturecolumnofs[i] = Z_Malloc (texture->width*sizeof(**texturecolumnofs), PU_STATIC,0);
600  
601  	j = 1;
602  	while (j*2 <= texture->width)
603  	    j<<=1;
604  
605  	texturewidthmask[i] = j-1;
606  	textureheight[i] = texture->height<<FRACBITS;
607  		
608  	totalwidth += texture->width;
609      }
610  
611      Z_Free(patchlookup);
612  
613      W_ReleaseLumpName(DEH_String("TEXTURE1"));
614      if (maptex2)
615          W_ReleaseLumpName(DEH_String("TEXTURE2"));
616      
617      // Precalculate whatever possible.	
618  
619      for (i=0 ; i<numtextures ; i++)
620  	R_GenerateLookup (i);
621      
622      // Create translation table for global animation.
623      texturetranslation = Z_Malloc ((numtextures+1)*sizeof(*texturetranslation), PU_STATIC, 0);
624      
625      for (i=0 ; i<numtextures ; i++)
626  	texturetranslation[i] = i;
627  
628      GenerateTextureHashTable();
629  }
630  
631  
632  
633  //
634  // R_InitFlats
635  //
636  void R_InitFlats (void)
637  {
638      int		i;
639  	
640      firstflat = W_GetNumForName (DEH_String("F_START")) + 1;
641      lastflat = W_GetNumForName (DEH_String("F_END")) - 1;
642      numflats = lastflat - firstflat + 1;
643  	
644      // Create translation table for global animation.
645      flattranslation = Z_Malloc ((numflats+1)*sizeof(*flattranslation), PU_STATIC, 0);
646      
647      for (i=0 ; i<numflats ; i++)
648  	flattranslation[i] = i;
649  }
650  
651  
652  //
653  // R_InitSpriteLumps
654  // Finds the width and hoffset of all sprites in the wad,
655  //  so the sprite does not need to be cached completely
656  //  just for having the header info ready during rendering.
657  //
658  void R_InitSpriteLumps (void)
659  {
660      int		i;
661      patch_t	*patch;
662  	
663      firstspritelump = W_GetNumForName (DEH_String("S_START")) + 1;
664      lastspritelump = W_GetNumForName (DEH_String("S_END")) - 1;
665      
666      numspritelumps = lastspritelump - firstspritelump + 1;
667      spritewidth = Z_Malloc (numspritelumps*sizeof(*spritewidth), PU_STATIC, 0);
668      spriteoffset = Z_Malloc (numspritelumps*sizeof(*spriteoffset), PU_STATIC, 0);
669      spritetopoffset = Z_Malloc (numspritelumps*sizeof(*spritetopoffset), PU_STATIC, 0);
670  	
671      for (i=0 ; i< numspritelumps ; i++)
672      {
673  	if (!(i&63))
674  	    printf (".");
675  
676  	patch = W_CacheLumpNum (firstspritelump+i, PU_CACHE);
677  	spritewidth[i] = SHORT(patch->width)<<FRACBITS;
678  	spriteoffset[i] = SHORT(patch->leftoffset)<<FRACBITS;
679  	spritetopoffset[i] = SHORT(patch->topoffset)<<FRACBITS;
680      }
681  }
682  
683  
684  
685  //
686  // R_InitColormaps
687  //
688  void R_InitColormaps (void)
689  {
690      int	lump;
691  
692      // Load in the light tables, 
693      //  256 byte align tables.
694      lump = W_GetNumForName(DEH_String("COLORMAP"));
695      colormaps = W_CacheLumpNum(lump, PU_STATIC);
696  }
697  
698  
699  
700  //
701  // R_InitData
702  // Locates all the lumps
703  //  that will be used by all views
704  // Must be called after W_Init.
705  //
706  void R_InitData (void)
707  {
708      R_InitTextures ();    
709      printf (".");
710      R_InitFlats ();
711      printf (".");
712      R_InitSpriteLumps ();
713      printf (".");
714      R_InitColormaps ();
715  }
716  
717  
718  
719  //
720  // R_FlatNumForName
721  // Retrieval, get a flat number for a flat name.
722  //
723  int R_FlatNumForName (char* name)
724  {
725      int		i;
726      char	namet[9];
727  
728      i = W_CheckNumForName (name);
729  
730      if (i == -1)
731      {
732  	namet[8] = 0;
733  	memcpy (namet, name,8);
734  	I_Error ("R_FlatNumForName: %s not found",namet);
735      }
736      return i - firstflat;
737  }
738  
739  
740  
741  
742  //
743  // R_CheckTextureNumForName
744  // Check whether texture is available.
745  // Filter out NoTexture indicator.
746  //
747  int	R_CheckTextureNumForName (char *name)
748  {
749      texture_t *texture;
750      int key;
751  
752      // "NoTexture" marker.
753      if (name[0] == '-')		
754  	return 0;
755  		
756      key = W_LumpNameHash(name) % numtextures;
757  
758      texture=textures_hashtable[key]; 
759      
760      while (texture != NULL)
761      {
762  	if (!strncasecmp (texture->name, name, 8) )
763  	    return texture->index;
764  
765          texture = texture->next;
766      }
767      
768      return -1;
769  }
770  
771  
772  
773  //
774  // R_TextureNumForName
775  // Calls R_CheckTextureNumForName,
776  //  aborts with error message.
777  //
778  int	R_TextureNumForName (char* name)
779  {
780      int		i;
781  	
782      i = R_CheckTextureNumForName (name);
783  
784      if (i==-1)
785      {
786  	I_Error ("R_TextureNumForName: %s not found",
787  		 name);
788      }
789      return i;
790  }
791  
792  
793  
794  
795  //
796  // R_PrecacheLevel
797  // Preloads all relevant graphics for the level.
798  //
799  int		flatmemory;
800  int		texturememory;
801  int		spritememory;
802  
803  void R_PrecacheLevel (void)
804  {
805      char*		flatpresent;
806      char*		texturepresent;
807      char*		spritepresent;
808  
809      int			i;
810      int			j;
811      int			k;
812      int			lump;
813      
814      texture_t*		texture;
815      thinker_t*		th;
816      spriteframe_t*	sf;
817  
818      if (demoplayback)
819  	return;
820      
821      // Precache flats.
822      flatpresent = Z_Malloc(numflats, PU_STATIC, NULL);
823      memset (flatpresent,0,numflats);	
824  
825      for (i=0 ; i<numsectors ; i++)
826      {
827  	flatpresent[sectors[i].floorpic] = 1;
828  	flatpresent[sectors[i].ceilingpic] = 1;
829      }
830  	
831      flatmemory = 0;
832  
833      for (i=0 ; i<numflats ; i++)
834      {
835  	if (flatpresent[i])
836  	{
837  	    lump = firstflat + i;
838  	    flatmemory += lumpinfo[lump].size;
839  	    W_CacheLumpNum(lump, PU_CACHE);
840  	}
841      }
842  
843      Z_Free(flatpresent);
844      
845      // Precache textures.
846      texturepresent = Z_Malloc(numtextures, PU_STATIC, NULL);
847      memset (texturepresent,0, numtextures);
848  	
849      for (i=0 ; i<numsides ; i++)
850      {
851  	texturepresent[sides[i].toptexture] = 1;
852  	texturepresent[sides[i].midtexture] = 1;
853  	texturepresent[sides[i].bottomtexture] = 1;
854      }
855  
856      // Sky texture is always present.
857      // Note that F_SKY1 is the name used to
858      //  indicate a sky floor/ceiling as a flat,
859      //  while the sky texture is stored like
860      //  a wall texture, with an episode dependend
861      //  name.
862      texturepresent[skytexture] = 1;
863  	
864      texturememory = 0;
865      for (i=0 ; i<numtextures ; i++)
866      {
867  	if (!texturepresent[i])
868  	    continue;
869  
870  	texture = textures[i];
871  	
872  	for (j=0 ; j<texture->patchcount ; j++)
873  	{
874  	    lump = texture->patches[j].patch;
875  	    texturememory += lumpinfo[lump].size;
876  	    W_CacheLumpNum(lump , PU_CACHE);
877  	}
878      }
879  
880      Z_Free(texturepresent);
881      
882      // Precache sprites.
883      spritepresent = Z_Malloc(numsprites, PU_STATIC, NULL);
884      memset (spritepresent,0, numsprites);
885  	
886      for (th = thinkercap.next ; th != &thinkercap ; th=th->next)
887      {
888  	if (th->function.acp1 == (actionf_p1)P_MobjThinker)
889  	    spritepresent[((mobj_t *)th)->sprite] = 1;
890      }
891  	
892      spritememory = 0;
893      for (i=0 ; i<numsprites ; i++)
894      {
895  	if (!spritepresent[i])
896  	    continue;
897  
898  	for (j=0 ; j<sprites[i].numframes ; j++)
899  	{
900  	    sf = &sprites[i].spriteframes[j];
901  	    for (k=0 ; k<8 ; k++)
902  	    {
903  		lump = firstspritelump + sf->lump[k];
904  		spritememory += lumpinfo[lump].size;
905  		W_CacheLumpNum(lump , PU_CACHE);
906  	    }
907  	}
908      }
909  
910      Z_Free(spritepresent);
911  }
912  
913  
914  
915