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