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