1 //
2 // Copyright(C) 1993-1996 Id Software, Inc.
3 // Copyright(C) 1993-2008 Raven Software
4 // Copyright(C) 2005-2014 Simon Howard
5 //
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 //
16 
17 
18 #include "h2def.h"
19 #include "i_system.h"
20 #include "i_swap.h"
21 #include "m_misc.h"
22 #include "r_local.h"
23 #include "p_local.h"
24 
25 typedef struct
26 {
27     int originx;                // block origin (allways UL), which has allready
28     int originy;                // accounted  for the patch's internal origin
29     int patch;
30 } texpatch_t;
31 
32 // a maptexturedef_t describes a rectangular texture, which is composed of one
33 // or more mappatch_t structures that arrange graphic patches
34 typedef struct
35 {
36     char name[8];               // for switch changing, etc
37     short width;
38     short height;
39     short patchcount;
40     texpatch_t patches[1];      // [patchcount] drawn back to front
41     //  into the cached texture
42 } texture_t;
43 
44 
45 
46 int firstflat, lastflat, numflats;
47 int firstpatch, lastpatch, numpatches;
48 int firstspritelump, lastspritelump, numspritelumps;
49 
50 int numtextures;
51 texture_t **textures;
52 int *texturewidthmask;
53 fixed_t *textureheight;         // needed for texture pegging
54 int *texturecompositesize;
55 short **texturecolumnlump;
56 unsigned short **texturecolumnofs;
57 byte **texturecomposite;
58 
59 int *flattranslation;           // for global animation
60 int *texturetranslation;        // for global animation
61 
62 fixed_t *spritewidth;           // needed for pre rendering
63 fixed_t *spriteoffset;
64 fixed_t *spritetopoffset;
65 
66 lighttable_t *colormaps;
67 
68 
69 /*
70 ==============================================================================
71 
72 						MAPTEXTURE_T CACHING
73 
74 when a texture is first needed, it counts the number of composite columns
75 required in the texture and allocates space for a column directory and any
76 new columns.  The directory will simply point inside other patches if there
77 is only one patch in a given column, but any columns with multiple patches
78 will have new column_ts generated.
79 
80 ==============================================================================
81 */
82 
83 /*
84 ===================
85 =
86 = R_DrawColumnInCache
87 =
88 = Clip and draw a column from a patch into a cached post
89 =
90 ===================
91 */
92 
R_DrawColumnInCache(column_t * patch,byte * cache,int originy,int cacheheight)93 void R_DrawColumnInCache(column_t * patch, byte * cache, int originy,
94                          int cacheheight)
95 {
96     int count, position;
97     byte *source;
98 
99     while (patch->topdelta != 0xff)
100     {
101         source = (byte *) patch + 3;
102         count = patch->length;
103         position = originy + patch->topdelta;
104         if (position < 0)
105         {
106             count += position;
107             position = 0;
108         }
109         if (position + count > cacheheight)
110             count = cacheheight - position;
111         if (count > 0)
112             memcpy(cache + position, source, count);
113 
114         patch = (column_t *) ((byte *) patch + patch->length + 4);
115     }
116 }
117 
118 
119 /*
120 ===================
121 =
122 = R_GenerateComposite
123 =
124 ===================
125 */
126 
R_GenerateComposite(int texnum)127 void R_GenerateComposite(int texnum)
128 {
129     byte *block;
130     texture_t *texture;
131     texpatch_t *patch;
132     patch_t *realpatch;
133     int x, x1, x2;
134     int i;
135     column_t *patchcol;
136     short *collump;
137     unsigned short *colofs;
138 
139     texture = textures[texnum];
140     block = Z_Malloc(texturecompositesize[texnum], PU_STATIC,
141                      &texturecomposite[texnum]);
142     collump = texturecolumnlump[texnum];
143     colofs = texturecolumnofs[texnum];
144 
145 //
146 // composite the columns together
147 //
148     for (i = 0, patch = texture->patches; i < texture->patchcount;
149          i++, patch++)
150     {
151         realpatch = W_CacheLumpNum(patch->patch, PU_CACHE);
152         x1 = patch->originx;
153         x2 = x1 + SHORT(realpatch->width);
154 
155         if (x1 < 0)
156             x = 0;
157         else
158             x = x1;
159         if (x2 > texture->width)
160             x2 = texture->width;
161 
162         for (; x < x2; x++)
163         {
164             if (collump[x] >= 0)
165                 continue;       // column does not have multiple patches
166             patchcol = (column_t *) ((byte *) realpatch +
167                                      LONG(realpatch->columnofs[x - x1]));
168             R_DrawColumnInCache(patchcol, block + colofs[x], patch->originy,
169                                 texture->height);
170         }
171 
172     }
173 
174 // now that the texture has been built, it is purgable
175     Z_ChangeTag(block, PU_CACHE);
176 }
177 
178 
179 /*
180 ===================
181 =
182 = R_GenerateLookup
183 =
184 ===================
185 */
186 
R_GenerateLookup(int texnum)187 void R_GenerateLookup(int texnum)
188 {
189     texture_t *texture;
190     byte *patchcount;           // [texture->width]
191     texpatch_t *patch;
192     patch_t *realpatch;
193     int x, x1, x2;
194     int i;
195     short *collump;
196     unsigned short *colofs;
197 
198     texture = textures[texnum];
199 
200     texturecomposite[texnum] = 0;       // composited not created yet
201     texturecompositesize[texnum] = 0;
202     collump = texturecolumnlump[texnum];
203     colofs = texturecolumnofs[texnum];
204 
205 //
206 // count the number of columns that are covered by more than one patch
207 // fill in the lump / offset, so columns with only a single patch are
208 // all done
209 //
210     patchcount = (byte *) Z_Malloc(texture->width, PU_STATIC, &patchcount);
211     memset(patchcount, 0, texture->width);
212     for (i = 0, patch = texture->patches; i < texture->patchcount;
213          i++, patch++)
214     {
215         realpatch = W_CacheLumpNum(patch->patch, PU_CACHE);
216         x1 = patch->originx;
217         x2 = x1 + SHORT(realpatch->width);
218         if (x1 < 0)
219             x = 0;
220         else
221             x = x1;
222         if (x2 > texture->width)
223             x2 = texture->width;
224         for (; x < x2; x++)
225         {
226             patchcount[x]++;
227             collump[x] = patch->patch;
228             colofs[x] = LONG(realpatch->columnofs[x - x1]) + 3;
229         }
230     }
231 
232     for (x = 0; x < texture->width; x++)
233     {
234         if (!patchcount[x])
235         {
236             ST_Message("R_GenerateLookup: column without a patch (%s)\n",
237                        texture->name);
238             return;
239         }
240 //                      I_Error ("R_GenerateLookup: column without a patch");
241         if (patchcount[x] > 1)
242         {
243             collump[x] = -1;    // use the cached block
244             colofs[x] = texturecompositesize[texnum];
245             if (texturecompositesize[texnum] > 0x10000 - texture->height)
246                 I_Error("R_GenerateLookup: texture %i is >64k", texnum);
247             texturecompositesize[texnum] += texture->height;
248         }
249     }
250 
251     Z_Free(patchcount);
252 }
253 
254 
255 /*
256 ================
257 =
258 = R_GetColumn
259 =
260 ================
261 */
262 
R_GetColumn(int tex,int col)263 byte *R_GetColumn(int tex, int col)
264 {
265     int lump, ofs;
266 
267     col &= texturewidthmask[tex];
268     lump = texturecolumnlump[tex][col];
269     ofs = texturecolumnofs[tex][col];
270     if (lump > 0)
271         return (byte *) W_CacheLumpNum(lump, PU_CACHE) + ofs;
272     if (!texturecomposite[tex])
273         R_GenerateComposite(tex);
274     return texturecomposite[tex] + ofs;
275 }
276 
277 
278 /*
279 ==================
280 =
281 = R_InitTextures
282 =
283 = Initializes the texture list with the textures from the world map
284 =
285 ==================
286 */
287 
R_InitTextures(void)288 void R_InitTextures(void)
289 {
290     maptexture_t *mtexture;
291     texture_t *texture;
292     mappatch_t *mpatch;
293     texpatch_t *patch;
294     int i, j;
295     int *maptex, *maptex2, *maptex1;
296     char name[9], *names, *name_p;
297     int *patchlookup;
298     int totalwidth;
299     int nummappatches;
300     int offset, maxoff, maxoff2;
301     int numtextures1, numtextures2;
302     int *directory;
303 
304 //
305 // load the patch names from pnames.lmp
306 //
307     names = W_CacheLumpName("PNAMES", PU_STATIC);
308     nummappatches = LONG(*((int *) names));
309     name_p = names + 4;
310     patchlookup = Z_Malloc(nummappatches * sizeof(*patchlookup), PU_STATIC, NULL);
311     for (i = 0; i < nummappatches; i++)
312     {
313         M_StringCopy(name, name_p + i * 8, sizeof(name));
314         patchlookup[i] = W_CheckNumForName(name);
315     }
316     W_ReleaseLumpName("PNAMES");
317 
318 //
319 // load the map texture definitions from textures.lmp
320 //
321     maptex = maptex1 = W_CacheLumpName("TEXTURE1", PU_STATIC);
322     numtextures1 = LONG(*maptex);
323     maxoff = W_LumpLength(W_GetNumForName("TEXTURE1"));
324     directory = maptex + 1;
325 
326     if (W_CheckNumForName("TEXTURE2") != -1)
327     {
328         maptex2 = W_CacheLumpName("TEXTURE2", PU_STATIC);
329         numtextures2 = LONG(*maptex2);
330         maxoff2 = W_LumpLength(W_GetNumForName("TEXTURE2"));
331     }
332     else
333     {
334         maptex2 = NULL;
335         numtextures2 = 0;
336         maxoff2 = 0;
337     }
338     numtextures = numtextures1 + numtextures2;
339 
340     textures = Z_Malloc(numtextures * sizeof(texture_t *), PU_STATIC, 0);
341     texturecolumnlump = Z_Malloc(numtextures * sizeof(short *), PU_STATIC, 0);
342     texturecolumnofs = Z_Malloc(numtextures * sizeof(short *), PU_STATIC, 0);
343     texturecomposite = Z_Malloc(numtextures * sizeof(byte *), PU_STATIC, 0);
344     texturecompositesize = Z_Malloc(numtextures * sizeof(int), PU_STATIC, 0);
345     texturewidthmask = Z_Malloc(numtextures * sizeof(int), PU_STATIC, 0);
346     textureheight = Z_Malloc(numtextures * sizeof(fixed_t), PU_STATIC, 0);
347 
348     totalwidth = 0;
349 
350     for (i = 0; i < numtextures; i++, directory++)
351     {
352         if (i == numtextures1)
353         {                       // start looking in second texture file
354             maptex = maptex2;
355             maxoff = maxoff2;
356             directory = maptex + 1;
357         }
358 
359         offset = LONG(*directory);
360         if (offset > maxoff)
361             I_Error("R_InitTextures: bad texture directory");
362         mtexture = (maptexture_t *) ((byte *) maptex + offset);
363         texture = textures[i] = Z_Malloc(sizeof(texture_t)
364                                          +
365                                          sizeof(texpatch_t) *
366                                          (SHORT(mtexture->patchcount) - 1),
367                                          PU_STATIC, 0);
368         texture->width = SHORT(mtexture->width);
369         texture->height = SHORT(mtexture->height);
370         texture->patchcount = SHORT(mtexture->patchcount);
371         memcpy(texture->name, mtexture->name, sizeof(texture->name));
372         mpatch = &mtexture->patches[0];
373         patch = &texture->patches[0];
374         for (j = 0; j < texture->patchcount; j++, mpatch++, patch++)
375         {
376             patch->originx = SHORT(mpatch->originx);
377             patch->originy = SHORT(mpatch->originy);
378             patch->patch = patchlookup[SHORT(mpatch->patch)];
379             if (patch->patch == -1)
380                 I_Error("R_InitTextures: Missing patch in texture %s",
381                         texture->name);
382         }
383         texturecolumnlump[i] = Z_Malloc(texture->width * sizeof(short), PU_STATIC, 0);
384         texturecolumnofs[i] = Z_Malloc(texture->width * sizeof(short), PU_STATIC, 0);
385         j = 1;
386         while (j * 2 <= texture->width)
387             j <<= 1;
388         texturewidthmask[i] = j - 1;
389         textureheight[i] = texture->height << FRACBITS;
390 
391         totalwidth += texture->width;
392     }
393 
394     Z_Free(patchlookup);
395 
396     W_ReleaseLumpName("TEXTURE1");
397     if (maptex2)
398         W_ReleaseLumpName("TEXTURE2");
399 
400 //
401 // precalculate whatever possible
402 //
403     for (i = 0; i < numtextures; i++)
404     {
405         R_GenerateLookup(i);
406         if (!(i & 31))
407             ST_Progress();
408     }
409 
410 //
411 // translation table for global animation
412 //
413     texturetranslation = Z_Malloc((numtextures + 1) * sizeof(int), PU_STATIC, 0);
414     for (i = 0; i < numtextures; i++)
415         texturetranslation[i] = i;
416 }
417 
418 
419 /*
420 ================
421 =
422 = R_InitFlats
423 =
424 =================
425 */
426 
R_InitFlats(void)427 void R_InitFlats(void)
428 {
429     int i;
430 
431     firstflat = W_GetNumForName("F_START") + 1;
432     lastflat = W_GetNumForName("F_END") - 1;
433     numflats = lastflat - firstflat + 1;
434 
435 // translation table for global animation
436     flattranslation = Z_Malloc((numflats + 1) * sizeof(int), PU_STATIC, 0);
437     for (i = 0; i < numflats; i++)
438         flattranslation[i] = i;
439 }
440 
441 
442 /*
443 ================
444 =
445 = R_InitSpriteLumps
446 =
447 = Finds the width and hoffset of all sprites in the wad, so the sprite doesn't
448 = need to be cached just for the header during rendering
449 =================
450 */
451 
R_InitSpriteLumps(void)452 void R_InitSpriteLumps(void)
453 {
454     int i;
455     patch_t *patch;
456 
457     firstspritelump = W_GetNumForName("S_START") + 1;
458     lastspritelump = W_GetNumForName("S_END") - 1;
459     numspritelumps = lastspritelump - firstspritelump + 1;
460     spritewidth = Z_Malloc(numspritelumps * sizeof(fixed_t), PU_STATIC, 0);
461     spriteoffset = Z_Malloc(numspritelumps * sizeof(fixed_t), PU_STATIC, 0);
462     spritetopoffset = Z_Malloc(numspritelumps * sizeof(fixed_t), PU_STATIC, 0);
463 
464     for (i = 0; i < numspritelumps; i++)
465     {
466         if (!(i & 127))
467             ST_Progress();
468         patch = W_CacheLumpNum(firstspritelump + i, PU_CACHE);
469         spritewidth[i] = SHORT(patch->width) << FRACBITS;
470         spriteoffset[i] = SHORT(patch->leftoffset) << FRACBITS;
471         spritetopoffset[i] = SHORT(patch->topoffset) << FRACBITS;
472     }
473 }
474 
475 
476 /*
477 ================
478 =
479 = R_InitColormaps
480 =
481 =================
482 */
483 
R_InitColormaps(void)484 void R_InitColormaps(void)
485 {
486     int lump, length;
487 //
488 // load in the light tables
489 // 256 byte align tables
490 //
491     lump = W_GetNumForName("COLORMAP");
492     length = W_LumpLength(lump);
493     colormaps = Z_Malloc(length, PU_STATIC, 0);
494     W_ReadLump(lump, colormaps);
495 }
496 
497 
498 /*
499 ================
500 =
501 = R_InitData
502 =
503 = Locates all the lumps that will be used by all views
504 = Must be called after W_Init
505 =================
506 */
507 
R_InitData(void)508 void R_InitData(void)
509 {
510     R_InitTextures();
511     R_InitFlats();
512     R_InitSpriteLumps();
513     R_InitColormaps();
514 }
515 
516 //=============================================================================
517 
518 /*
519 ================
520 =
521 = R_FlatNumForName
522 =
523 ================
524 */
525 
R_FlatNumForName(const char * name)526 int R_FlatNumForName(const char *name)
527 {
528     int i;
529     char namet[9];
530 
531     i = W_CheckNumForName(name);
532     if (i == -1)
533     {
534         namet[8] = 0;
535         memcpy(namet, name, 8);
536         I_Error("R_FlatNumForName: %s not found", namet);
537     }
538     return i - firstflat;
539 }
540 
541 
542 /*
543 ================
544 =
545 = R_CheckTextureNumForName
546 =
547 ================
548 */
549 
R_CheckTextureNumForName(const char * name)550 int R_CheckTextureNumForName(const char *name)
551 {
552     int i;
553 
554     if (name[0] == '-')         // no texture marker
555         return 0;
556 
557     for (i = 0; i < numtextures; i++)
558         if (!strncasecmp(textures[i]->name, name, 8))
559             return i;
560 
561     return -1;
562 }
563 
564 
565 /*
566 ================
567 =
568 = R_TextureNumForName
569 =
570 ================
571 */
572 
R_TextureNumForName(const char * name)573 int R_TextureNumForName(const char *name)
574 {
575     int i;
576     //char  namet[9];
577 
578     i = R_CheckTextureNumForName(name);
579     if (i == -1)
580         I_Error("R_TextureNumForName: %s not found", name);
581 
582     return i;
583 }
584 
585 
586 /*
587 =================
588 =
589 = R_PrecacheLevel
590 =
591 = Preloads all relevent graphics for the level
592 =================
593 */
594 
595 int flatmemory, texturememory, spritememory;
596 
R_PrecacheLevel(void)597 void R_PrecacheLevel(void)
598 {
599     char *flatpresent;
600     char *texturepresent;
601     char *spritepresent;
602     int i, j, k, lump;
603     texture_t *texture;
604     thinker_t *th;
605     spriteframe_t *sf;
606 
607     if (demoplayback)
608         return;
609 
610 //
611 // precache flats
612 //
613     flatpresent = Z_Malloc(numflats, PU_STATIC, NULL);
614     memset(flatpresent, 0, numflats);
615     for (i = 0; i < numsectors; i++)
616     {
617         flatpresent[sectors[i].floorpic] = 1;
618         flatpresent[sectors[i].ceilingpic] = 1;
619     }
620 
621     flatmemory = 0;
622     for (i = 0; i < numflats; i++)
623         if (flatpresent[i])
624         {
625             lump = firstflat + i;
626             flatmemory += lumpinfo[lump]->size;
627             W_CacheLumpNum(lump, PU_CACHE);
628         }
629 
630     Z_Free(flatpresent);
631 
632 //
633 // precache textures
634 //
635     texturepresent = Z_Malloc(numtextures, PU_STATIC, NULL);
636     memset(texturepresent, 0, numtextures);
637 
638     for (i = 0; i < numsides; i++)
639     {
640         texturepresent[sides[i].toptexture] = 1;
641         texturepresent[sides[i].midtexture] = 1;
642         texturepresent[sides[i].bottomtexture] = 1;
643     }
644 
645     texturepresent[Sky1Texture] = 1;
646     texturepresent[Sky2Texture] = 1;
647 
648     texturememory = 0;
649     for (i = 0; i < numtextures; i++)
650     {
651         if (!texturepresent[i])
652             continue;
653         texture = textures[i];
654         for (j = 0; j < texture->patchcount; j++)
655         {
656             lump = texture->patches[j].patch;
657             texturememory += lumpinfo[lump]->size;
658             W_CacheLumpNum(lump, PU_CACHE);
659         }
660     }
661 
662     Z_Free(texturepresent);
663 
664 //
665 // precache sprites
666 //
667     spritepresent = Z_Malloc(numsprites, PU_STATIC, NULL);
668     memset(spritepresent, 0, numsprites);
669 
670     for (th = thinkercap.next; th != &thinkercap; th = th->next)
671     {
672         if (th->function == P_MobjThinker)
673             spritepresent[((mobj_t *) th)->sprite] = 1;
674     }
675 
676     spritememory = 0;
677     for (i = 0; i < numsprites; i++)
678     {
679         if (!spritepresent[i])
680             continue;
681         for (j = 0; j < sprites[i].numframes; j++)
682         {
683             sf = &sprites[i].spriteframes[j];
684             for (k = 0; k < 8; k++)
685             {
686                 lump = firstspritelump + sf->lump[k];
687                 spritememory += lumpinfo[lump]->size;
688                 W_CacheLumpNum(lump, PU_CACHE);
689             }
690         }
691     }
692 
693     Z_Free(spritepresent);
694 }
695