1 // SONIC ROBO BLAST 2
2 //-----------------------------------------------------------------------------
3 // Copyright (C) 1993-1996 by id Software, Inc.
4 // Copyright (C) 1998-2000 by DooM Legacy Team.
5 // Copyright (C) 1999-2021 by Sonic Team Junior.
6 //
7 // This program is free software distributed under the
8 // terms of the GNU General Public License, version 2.
9 // See the 'LICENSE' file for more details.
10 //-----------------------------------------------------------------------------
11 /// \file r_data.c
12 /// \brief Preparation of data for rendering, generation of lookups, caching, retrieval by name
13
14 #include "doomdef.h"
15 #include "g_game.h"
16 #include "i_video.h"
17 #include "r_local.h"
18 #include "r_sky.h"
19 #include "p_local.h"
20 #include "m_misc.h"
21 #include "r_data.h"
22 #include "r_textures.h"
23 #include "r_patch.h"
24 #include "r_picformats.h"
25 #include "w_wad.h"
26 #include "z_zone.h"
27 #include "p_setup.h" // levelflats
28 #include "v_video.h" // pMasterPalette
29 #include "f_finale.h" // wipes
30 #include "byteptr.h"
31 #include "dehacked.h"
32
33 //
34 // Graphics.
35 // SRB2 graphics for walls and sprites
36 // is stored in vertical runs of opaque pixels (posts).
37 // A column is composed of zero or more posts,
38 // a patch or sprite is composed of zero or more columns.
39 //
40
41 size_t numspritelumps, max_spritelumps;
42
43 // needed for pre rendering
44 sprcache_t *spritecachedinfo;
45
46 lighttable_t *colormaps;
47 lighttable_t *fadecolormap;
48
49 // for debugging/info purposes
50 size_t flatmemory, spritememory, texturememory;
51
52 // highcolor stuff
53 INT16 color8to16[256]; // remap color index to highcolor rgb value
54 INT16 *hicolormaps; // test a 32k colormap remaps high -> high
55
56 // Blends two pixels together, using the equation
57 // that matches the specified alpha style.
ASTBlendPixel(RGBA_t background,RGBA_t foreground,int style,UINT8 alpha)58 UINT32 ASTBlendPixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alpha)
59 {
60 RGBA_t output;
61 INT16 fullalpha = (alpha - (0xFF - foreground.s.alpha));
62 if (style == AST_TRANSLUCENT)
63 {
64 if (fullalpha <= 0)
65 output.rgba = background.rgba;
66 else
67 {
68 // don't go too high
69 if (fullalpha >= 0xFF)
70 fullalpha = 0xFF;
71 alpha = (UINT8)fullalpha;
72
73 // if the background pixel is empty,
74 // match software and don't blend anything
75 if (!background.s.alpha)
76 {
77 // ...unless the foreground pixel ISN'T actually translucent.
78 if (alpha == 0xFF)
79 output.rgba = foreground.rgba;
80 else
81 output.rgba = 0;
82 }
83 else
84 {
85 UINT8 beta = (0xFF - alpha);
86 output.s.red = ((background.s.red * beta) + (foreground.s.red * alpha)) / 0xFF;
87 output.s.green = ((background.s.green * beta) + (foreground.s.green * alpha)) / 0xFF;
88 output.s.blue = ((background.s.blue * beta) + (foreground.s.blue * alpha)) / 0xFF;
89 output.s.alpha = 0xFF;
90 }
91 }
92 return output.rgba;
93 }
94 #define clamp(c) max(min(c, 0xFF), 0x00);
95 else
96 {
97 float falpha = ((float)alpha / 256.0f);
98 float fr = ((float)foreground.s.red * falpha);
99 float fg = ((float)foreground.s.green * falpha);
100 float fb = ((float)foreground.s.blue * falpha);
101 if (style == AST_ADD)
102 {
103 output.s.red = clamp((int)(background.s.red + fr));
104 output.s.green = clamp((int)(background.s.green + fg));
105 output.s.blue = clamp((int)(background.s.blue + fb));
106 }
107 else if (style == AST_SUBTRACT)
108 {
109 output.s.red = clamp((int)(background.s.red - fr));
110 output.s.green = clamp((int)(background.s.green - fg));
111 output.s.blue = clamp((int)(background.s.blue - fb));
112 }
113 else if (style == AST_REVERSESUBTRACT)
114 {
115 output.s.red = clamp((int)((-background.s.red) + fr));
116 output.s.green = clamp((int)((-background.s.green) + fg));
117 output.s.blue = clamp((int)((-background.s.blue) + fb));
118 }
119 else if (style == AST_MODULATE)
120 {
121 fr = ((float)foreground.s.red / 256.0f);
122 fg = ((float)foreground.s.green / 256.0f);
123 fb = ((float)foreground.s.blue / 256.0f);
124 output.s.red = clamp((int)(background.s.red * fr));
125 output.s.green = clamp((int)(background.s.green * fg));
126 output.s.blue = clamp((int)(background.s.blue * fb));
127 }
128 // just copy the pixel
129 else if (style == AST_COPY)
130 output.rgba = foreground.rgba;
131
132 output.s.alpha = 0xFF;
133 return output.rgba;
134 }
135 #undef clamp
136 return 0;
137 }
138
139 INT32 ASTTextureBlendingThreshold[2] = {255/11, (10*255/11)};
140
141 // Blends a pixel for a texture patch.
ASTBlendTexturePixel(RGBA_t background,RGBA_t foreground,int style,UINT8 alpha)142 UINT32 ASTBlendTexturePixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alpha)
143 {
144 // Alpha style set to translucent?
145 if (style == AST_TRANSLUCENT)
146 {
147 // Is the alpha small enough for translucency?
148 if (alpha <= ASTTextureBlendingThreshold[1])
149 {
150 // Is the patch way too translucent? Don't blend then.
151 if (alpha < ASTTextureBlendingThreshold[0])
152 return background.rgba;
153
154 return ASTBlendPixel(background, foreground, style, alpha);
155 }
156 else // just copy the pixel
157 return foreground.rgba;
158 }
159 else
160 return ASTBlendPixel(background, foreground, style, alpha);
161 }
162
163 // Blends two palette indexes for a texture patch, then
164 // finds the nearest palette index from the blended output.
ASTBlendPaletteIndexes(UINT8 background,UINT8 foreground,int style,UINT8 alpha)165 UINT8 ASTBlendPaletteIndexes(UINT8 background, UINT8 foreground, int style, UINT8 alpha)
166 {
167 // Alpha style set to translucent?
168 if (style == AST_TRANSLUCENT)
169 {
170 // Is the alpha small enough for translucency?
171 if (alpha <= ASTTextureBlendingThreshold[1])
172 {
173 UINT8 *mytransmap;
174 INT32 trans;
175
176 // Is the patch way too translucent? Don't blend then.
177 if (alpha < ASTTextureBlendingThreshold[0])
178 return background;
179
180 // The equation's not exact but it works as intended. I'll call it a day for now.
181 trans = (8*(alpha) + 255/8)/(255 - 255/11);
182 mytransmap = R_GetTranslucencyTable(trans + 1);
183 if (background != 0xFF)
184 return *(mytransmap + (background<<8) + foreground);
185 }
186 else // just copy the pixel
187 return foreground;
188 }
189 // just copy the pixel
190 else if (style == AST_COPY)
191 return foreground;
192 // use ASTBlendPixel for all other blend modes
193 // and find the nearest colour in the palette
194 else if (style != AST_TRANSLUCENT)
195 {
196 RGBA_t texel;
197 RGBA_t bg = V_GetMasterColor(background);
198 RGBA_t fg = V_GetMasterColor(foreground);
199 texel.rgba = ASTBlendPixel(bg, fg, style, alpha);
200 return NearestColor(texel.s.red, texel.s.green, texel.s.blue);
201 }
202 // fallback if all above fails, somehow
203 // return the background pixel
204 return background;
205 }
206
207 #ifdef EXTRACOLORMAPLUMPS
208 static lumplist_t *colormaplumps = NULL; ///\todo free leak
209 static size_t numcolormaplumps = 0;
210
R_CheckNumForNameList(const char * name,lumplist_t * list,size_t listsize)211 static inline lumpnum_t R_CheckNumForNameList(const char *name, lumplist_t *list, size_t listsize)
212 {
213 size_t i;
214 UINT16 lump;
215
216 for (i = listsize - 1; i < INT16_MAX; i--)
217 {
218 lump = W_CheckNumForNamePwad(name, list[i].wadfile, list[i].firstlump);
219 if (lump == INT16_MAX || lump > (list[i].firstlump + list[i].numlumps))
220 continue;
221 else
222 return (list[i].wadfile<<16)+lump;
223 }
224 return LUMPERROR;
225 }
226
R_InitExtraColormaps(void)227 static void R_InitExtraColormaps(void)
228 {
229 lumpnum_t startnum, endnum;
230 UINT16 cfile, clump;
231 static size_t maxcolormaplumps = 16;
232
233 for (cfile = clump = 0; cfile < numwadfiles; cfile++, clump = 0)
234 {
235 startnum = W_CheckNumForNamePwad("C_START", cfile, clump);
236 if (startnum == INT16_MAX)
237 continue;
238
239 endnum = W_CheckNumForNamePwad("C_END", cfile, clump);
240
241 if (endnum == INT16_MAX)
242 I_Error("R_InitExtraColormaps: C_START without C_END\n");
243
244 // This shouldn't be possible when you use the Pwad function, silly
245 //if (WADFILENUM(startnum) != WADFILENUM(endnum))
246 //I_Error("R_InitExtraColormaps: C_START and C_END in different wad files!\n");
247
248 if (numcolormaplumps >= maxcolormaplumps)
249 maxcolormaplumps *= 2;
250 colormaplumps = Z_Realloc(colormaplumps,
251 sizeof (*colormaplumps) * maxcolormaplumps, PU_STATIC, NULL);
252 colormaplumps[numcolormaplumps].wadfile = cfile;
253 colormaplumps[numcolormaplumps].firstlump = startnum+1;
254 colormaplumps[numcolormaplumps].numlumps = endnum - (startnum + 1);
255 numcolormaplumps++;
256 }
257 CONS_Printf(M_GetText("Number of Extra Colormaps: %s\n"), sizeu1(numcolormaplumps));
258 }
259 #endif
260
261 //
262 // R_InitSpriteLumps
263 // Finds the width and hoffset of all sprites in the wad, so the sprite does not need to be
264 // cached completely, just for having the header info ready during rendering.
265 //
266
267 //
268 // allocate sprite lookup tables
269 //
R_InitSpriteLumps(void)270 static void R_InitSpriteLumps(void)
271 {
272 numspritelumps = 0;
273 max_spritelumps = 8192;
274
275 Z_Malloc(max_spritelumps*sizeof(*spritecachedinfo), PU_STATIC, &spritecachedinfo);
276 }
277
278 //
279 // R_CreateFadeColormaps
280 //
281
R_CreateFadeColormaps(void)282 static void R_CreateFadeColormaps(void)
283 {
284 UINT8 px, fade;
285 RGBA_t rgba;
286 INT32 r, g, b;
287 size_t len, i;
288
289 len = (256 * FADECOLORMAPROWS);
290 fadecolormap = Z_MallocAlign(len*2, PU_STATIC, NULL, 8);
291 for (i = 0; i < len*2; i++)
292 fadecolormap[i] = (i%256);
293
294 // Load in the light tables, now 64k aligned for smokie...
295 {
296 lumpnum_t lump = W_CheckNumForName("FADECMAP");
297 lumpnum_t wlump = W_CheckNumForName("FADEWMAP");
298
299 // to black
300 if (lump != LUMPERROR)
301 W_ReadLumpHeader(lump, fadecolormap, len, 0U);
302 // to white
303 if (wlump != LUMPERROR)
304 W_ReadLumpHeader(wlump, fadecolormap+len, len, 0U);
305
306 // missing "to white" colormap lump
307 if (lump != LUMPERROR && wlump == LUMPERROR)
308 goto makewhite;
309 // missing "to black" colormap lump
310 else if (lump == LUMPERROR && wlump != LUMPERROR)
311 goto makeblack;
312 // both lumps found
313 else if (lump != LUMPERROR && wlump != LUMPERROR)
314 return;
315 }
316
317 #define GETCOLOR \
318 px = colormaps[i%256]; \
319 fade = (i/256) * (256 / FADECOLORMAPROWS); \
320 rgba = V_GetMasterColor(px);
321
322 // to black
323 makeblack:
324 for (i = 0; i < len; i++)
325 {
326 // find pixel and fade amount
327 GETCOLOR;
328
329 // subtractive color blending
330 r = rgba.s.red - FADEREDFACTOR*fade/10;
331 g = rgba.s.green - FADEGREENFACTOR*fade/10;
332 b = rgba.s.blue - FADEBLUEFACTOR*fade/10;
333
334 // clamp values
335 if (r < 0) r = 0;
336 if (g < 0) g = 0;
337 if (b < 0) b = 0;
338
339 // find nearest color in palette
340 fadecolormap[i] = NearestColor(r,g,b);
341 }
342
343 // to white
344 makewhite:
345 for (i = len; i < len*2; i++)
346 {
347 // find pixel and fade amount
348 GETCOLOR;
349
350 // additive color blending
351 r = rgba.s.red + FADEREDFACTOR*fade/10;
352 g = rgba.s.green + FADEGREENFACTOR*fade/10;
353 b = rgba.s.blue + FADEBLUEFACTOR*fade/10;
354
355 // clamp values
356 if (r > 255) r = 255;
357 if (g > 255) g = 255;
358 if (b > 255) b = 255;
359
360 // find nearest color in palette
361 fadecolormap[i] = NearestColor(r,g,b);
362 }
363 #undef GETCOLOR
364 }
365
366 //
367 // R_InitColormaps
368 //
R_InitColormaps(void)369 static void R_InitColormaps(void)
370 {
371 size_t len;
372 lumpnum_t lump;
373
374 // Load in the light tables
375 lump = W_GetNumForName("COLORMAP");
376 len = W_LumpLength(lump);
377 colormaps = Z_MallocAlign(len, PU_STATIC, NULL, 8);
378 W_ReadLump(lump, colormaps);
379
380 // Make colormap for fades
381 R_CreateFadeColormaps();
382
383 // Init Boom colormaps.
384 R_ClearColormaps();
385 #ifdef EXTRACOLORMAPLUMPS
386 R_InitExtraColormaps();
387 #endif
388 }
389
R_ReInitColormaps(UINT16 num)390 void R_ReInitColormaps(UINT16 num)
391 {
392 char colormap[9] = "COLORMAP";
393 lumpnum_t lump;
394 const lumpnum_t basecolormaplump = W_GetNumForName(colormap);
395 if (num > 0 && num <= 10000)
396 snprintf(colormap, 8, "CLM%04u", num-1);
397
398 // Load in the light tables, now 64k aligned for smokie...
399 lump = W_GetNumForName(colormap);
400 if (lump == LUMPERROR)
401 lump = basecolormaplump;
402 else
403 {
404 if (W_LumpLength(lump) != W_LumpLength(basecolormaplump))
405 {
406 CONS_Alert(CONS_WARNING, "%s lump size does not match COLORMAP, results may be unexpected.\n", colormap);
407 }
408 }
409
410 W_ReadLumpHeader(lump, colormaps, W_LumpLength(basecolormaplump), 0U);
411 if (fadecolormap)
412 Z_Free(fadecolormap);
413 R_CreateFadeColormaps();
414
415 // Init Boom colormaps.
416 R_ClearColormaps();
417 }
418
419 //
420 // R_ClearColormaps
421 //
422 // Clears out extra colormaps between levels.
423 //
R_ClearColormaps(void)424 void R_ClearColormaps(void)
425 {
426 // Purged by PU_LEVEL, just overwrite the pointer
427 extra_colormaps = R_CreateDefaultColormap(true);
428 }
429
430 //
431 // R_CreateDefaultColormap()
432 // NOTE: The result colormap is not added to the extra_colormaps chain. You must do that yourself!
433 //
R_CreateDefaultColormap(boolean lighttable)434 extracolormap_t *R_CreateDefaultColormap(boolean lighttable)
435 {
436 extracolormap_t *exc = Z_Calloc(sizeof (*exc), PU_LEVEL, NULL);
437 exc->fadestart = 0;
438 exc->fadeend = 31;
439 exc->flags = 0;
440 exc->rgba = 0;
441 exc->fadergba = 0x19000000;
442 exc->colormap = lighttable ? R_CreateLightTable(exc) : NULL;
443 #ifdef EXTRACOLORMAPLUMPS
444 exc->lump = LUMPERROR;
445 exc->lumpname[0] = 0;
446 #endif
447 exc->next = exc->prev = NULL;
448 return exc;
449 }
450
451 //
452 // R_GetDefaultColormap()
453 //
R_GetDefaultColormap(void)454 extracolormap_t *R_GetDefaultColormap(void)
455 {
456 #ifdef COLORMAPREVERSELIST
457 extracolormap_t *exc;
458 #endif
459
460 if (!extra_colormaps)
461 return (extra_colormaps = R_CreateDefaultColormap(true));
462
463 #ifdef COLORMAPREVERSELIST
464 for (exc = extra_colormaps; exc->next; exc = exc->next);
465 return exc;
466 #else
467 return extra_colormaps;
468 #endif
469 }
470
471 //
472 // R_CopyColormap()
473 // NOTE: The result colormap is not added to the extra_colormaps chain. You must do that yourself!
474 //
R_CopyColormap(extracolormap_t * extra_colormap,boolean lighttable)475 extracolormap_t *R_CopyColormap(extracolormap_t *extra_colormap, boolean lighttable)
476 {
477 extracolormap_t *exc = Z_Calloc(sizeof (*exc), PU_LEVEL, NULL);
478
479 if (!extra_colormap)
480 extra_colormap = R_GetDefaultColormap();
481
482 *exc = *extra_colormap;
483 exc->next = exc->prev = NULL;
484
485 #ifdef EXTRACOLORMAPLUMPS
486 strncpy(exc->lumpname, extra_colormap->lumpname, 9);
487
488 if (exc->lump != LUMPERROR && lighttable)
489 {
490 // aligned on 8 bit for asm code
491 exc->colormap = Z_MallocAlign(W_LumpLength(lump), PU_LEVEL, NULL, 16);
492 W_ReadLump(lump, exc->colormap);
493 }
494 else
495 #endif
496 if (lighttable)
497 exc->colormap = R_CreateLightTable(exc);
498 else
499 exc->colormap = NULL;
500
501 return exc;
502 }
503
504 //
505 // R_AddColormapToList
506 //
507 // Sets prev/next chain for extra_colormaps var
508 // Copypasta from P_AddFFloorToList
509 //
R_AddColormapToList(extracolormap_t * extra_colormap)510 void R_AddColormapToList(extracolormap_t *extra_colormap)
511 {
512 #ifndef COLORMAPREVERSELIST
513 extracolormap_t *exc;
514 #endif
515
516 if (!extra_colormaps)
517 {
518 extra_colormaps = extra_colormap;
519 extra_colormap->next = 0;
520 extra_colormap->prev = 0;
521 return;
522 }
523
524 #ifdef COLORMAPREVERSELIST
525 extra_colormaps->prev = extra_colormap;
526 extra_colormap->next = extra_colormaps;
527 extra_colormaps = extra_colormap;
528 extra_colormap->prev = 0;
529 #else
530 for (exc = extra_colormaps; exc->next; exc = exc->next);
531
532 exc->next = extra_colormap;
533 extra_colormap->prev = exc;
534 extra_colormap->next = 0;
535 #endif
536 }
537
538 //
539 // R_CheckDefaultColormapByValues()
540 //
541 #ifdef EXTRACOLORMAPLUMPS
R_CheckDefaultColormapByValues(boolean checkrgba,boolean checkfadergba,boolean checkparams,INT32 rgba,INT32 fadergba,UINT8 fadestart,UINT8 fadeend,UINT8 flags,lumpnum_t lump)542 boolean R_CheckDefaultColormapByValues(boolean checkrgba, boolean checkfadergba, boolean checkparams,
543 INT32 rgba, INT32 fadergba, UINT8 fadestart, UINT8 fadeend, UINT8 flags, lumpnum_t lump)
544 #else
545 boolean R_CheckDefaultColormapByValues(boolean checkrgba, boolean checkfadergba, boolean checkparams,
546 INT32 rgba, INT32 fadergba, UINT8 fadestart, UINT8 fadeend, UINT8 flags)
547 #endif
548 {
549 return (
550 (!checkparams ? true :
551 (fadestart == 0
552 && fadeend == 31
553 && !flags)
554 )
555 && (!checkrgba ? true : rgba == 0)
556 && (!checkfadergba ? true : fadergba == 0x19000000)
557 #ifdef EXTRACOLORMAPLUMPS
558 && lump == LUMPERROR
559 && extra_colormap->lumpname[0] == 0
560 #endif
561 );
562 }
563
R_CheckDefaultColormap(extracolormap_t * extra_colormap,boolean checkrgba,boolean checkfadergba,boolean checkparams)564 boolean R_CheckDefaultColormap(extracolormap_t *extra_colormap, boolean checkrgba, boolean checkfadergba, boolean checkparams)
565 {
566 if (!extra_colormap)
567 return true;
568
569 #ifdef EXTRACOLORMAPLUMPS
570 return R_CheckDefaultColormapByValues(checkrgba, checkfadergba, checkparams, extra_colormap->rgba, extra_colormap->fadergba, extra_colormap->fadestart, extra_colormap->fadeend, extra_colormap->flags, extra_colormap->lump);
571 #else
572 return R_CheckDefaultColormapByValues(checkrgba, checkfadergba, checkparams, extra_colormap->rgba, extra_colormap->fadergba, extra_colormap->fadestart, extra_colormap->fadeend, extra_colormap->flags);
573 #endif
574 }
575
R_CheckEqualColormaps(extracolormap_t * exc_a,extracolormap_t * exc_b,boolean checkrgba,boolean checkfadergba,boolean checkparams)576 boolean R_CheckEqualColormaps(extracolormap_t *exc_a, extracolormap_t *exc_b, boolean checkrgba, boolean checkfadergba, boolean checkparams)
577 {
578 // Treat NULL as default colormap
579 // We need this because what if one exc is a default colormap, and the other is NULL? They're really both equal.
580 if (!exc_a)
581 exc_a = R_GetDefaultColormap();
582 if (!exc_b)
583 exc_b = R_GetDefaultColormap();
584
585 if (exc_a == exc_b)
586 return true;
587
588 return (
589 (!checkparams ? true :
590 (exc_a->fadestart == exc_b->fadestart
591 && exc_a->fadeend == exc_b->fadeend
592 && exc_a->flags == exc_b->flags)
593 )
594 && (!checkrgba ? true : exc_a->rgba == exc_b->rgba)
595 && (!checkfadergba ? true : exc_a->fadergba == exc_b->fadergba)
596 #ifdef EXTRACOLORMAPLUMPS
597 && exc_a->lump == exc_b->lump
598 && !strncmp(exc_a->lumpname, exc_b->lumpname, 9)
599 #endif
600 );
601 }
602
603 //
604 // R_GetColormapFromListByValues()
605 // NOTE: Returns NULL if no match is found
606 //
607 #ifdef EXTRACOLORMAPLUMPS
R_GetColormapFromListByValues(INT32 rgba,INT32 fadergba,UINT8 fadestart,UINT8 fadeend,UINT8 flags,lumpnum_t lump)608 extracolormap_t *R_GetColormapFromListByValues(INT32 rgba, INT32 fadergba, UINT8 fadestart, UINT8 fadeend, UINT8 flags, lumpnum_t lump)
609 #else
610 extracolormap_t *R_GetColormapFromListByValues(INT32 rgba, INT32 fadergba, UINT8 fadestart, UINT8 fadeend, UINT8 flags)
611 #endif
612 {
613 extracolormap_t *exc;
614 UINT32 dbg_i = 0;
615
616 for (exc = extra_colormaps; exc; exc = exc->next)
617 {
618 if (rgba == exc->rgba
619 && fadergba == exc->fadergba
620 && fadestart == exc->fadestart
621 && fadeend == exc->fadeend
622 && flags == exc->flags
623 #ifdef EXTRACOLORMAPLUMPS
624 && (lump != LUMPERROR && lump == exc->lump)
625 #endif
626 )
627 {
628 CONS_Debug(DBG_RENDER, "Found Colormap %d: rgba(%d,%d,%d,%d) fadergba(%d,%d,%d,%d)\n",
629 dbg_i, R_GetRgbaR(rgba), R_GetRgbaG(rgba), R_GetRgbaB(rgba), R_GetRgbaA(rgba),
630 R_GetRgbaR(fadergba), R_GetRgbaG(fadergba), R_GetRgbaB(fadergba), R_GetRgbaA(fadergba));
631 return exc;
632 }
633 dbg_i++;
634 }
635 return NULL;
636 }
637
R_GetColormapFromList(extracolormap_t * extra_colormap)638 extracolormap_t *R_GetColormapFromList(extracolormap_t *extra_colormap)
639 {
640 #ifdef EXTRACOLORMAPLUMPS
641 return R_GetColormapFromListByValues(extra_colormap->rgba, extra_colormap->fadergba, extra_colormap->fadestart, extra_colormap->fadeend, extra_colormap->flags, extra_colormap->lump);
642 #else
643 return R_GetColormapFromListByValues(extra_colormap->rgba, extra_colormap->fadergba, extra_colormap->fadestart, extra_colormap->fadeend, extra_colormap->flags);
644 #endif
645 }
646
647 #ifdef EXTRACOLORMAPLUMPS
R_ColormapForName(char * name)648 extracolormap_t *R_ColormapForName(char *name)
649 {
650 lumpnum_t lump;
651 extracolormap_t *exc;
652
653 lump = R_CheckNumForNameList(name, colormaplumps, numcolormaplumps);
654 if (lump == LUMPERROR)
655 I_Error("R_ColormapForName: Cannot find colormap lump %.8s\n", name);
656
657 exc = R_GetColormapFromListByValues(0, 0x19000000, 0, 31, 0, lump);
658 if (exc)
659 return exc;
660
661 exc = Z_Calloc(sizeof (*exc), PU_LEVEL, NULL);
662
663 exc->lump = lump;
664 strncpy(exc->lumpname, name, 9);
665 exc->lumpname[8] = 0;
666
667 // aligned on 8 bit for asm code
668 exc->colormap = Z_MallocAlign(W_LumpLength(lump), PU_LEVEL, NULL, 16);
669 W_ReadLump(lump, exc->colormap);
670
671 // We set all params of the colormap to normal because there
672 // is no real way to tell how GL should handle a colormap lump anyway..
673 exc->fadestart = 0;
674 exc->fadeend = 31;
675 exc->flags = 0;
676 exc->rgba = 0;
677 exc->fadergba = 0x19000000;
678
679 R_AddColormapToList(exc);
680
681 return exc;
682 }
683 #endif
684
685 //
686 // R_CreateColormapFromLinedef
687 //
688 // This is a more GL friendly way of doing colormaps: Specify colormap
689 // data in a special linedef's texture areas and use that to generate
690 // custom colormaps at runtime. NOTE: For GL mode, we only need to color
691 // data and not the colormap data.
692 //
693 static double deltas[256][3], map[256][3];
694
695 static int RoundUp(double number);
696
R_CreateLightTable(extracolormap_t * extra_colormap)697 lighttable_t *R_CreateLightTable(extracolormap_t *extra_colormap)
698 {
699 double cmaskr, cmaskg, cmaskb, cdestr, cdestg, cdestb;
700 double maskamt = 0, othermask = 0;
701
702 UINT8 cr = R_GetRgbaR(extra_colormap->rgba),
703 cg = R_GetRgbaG(extra_colormap->rgba),
704 cb = R_GetRgbaB(extra_colormap->rgba),
705 ca = R_GetRgbaA(extra_colormap->rgba),
706 cfr = R_GetRgbaR(extra_colormap->fadergba),
707 cfg = R_GetRgbaG(extra_colormap->fadergba),
708 cfb = R_GetRgbaB(extra_colormap->fadergba);
709 // cfa = R_GetRgbaA(extra_colormap->fadergba); // unused in software
710
711 UINT8 fadestart = extra_colormap->fadestart,
712 fadedist = extra_colormap->fadeend - extra_colormap->fadestart;
713
714 lighttable_t *lighttable = NULL;
715 size_t i;
716
717 /////////////////////
718 // Calc the RGBA mask
719 /////////////////////
720 cmaskr = cr;
721 cmaskg = cg;
722 cmaskb = cb;
723
724 maskamt = (double)(ca/24.0l);
725 othermask = 1 - maskamt;
726 maskamt /= 0xff;
727
728 cmaskr *= maskamt;
729 cmaskg *= maskamt;
730 cmaskb *= maskamt;
731
732 /////////////////////
733 // Calc the RGBA fade mask
734 /////////////////////
735 cdestr = cfr;
736 cdestg = cfg;
737 cdestb = cfb;
738
739 // fade alpha unused in software
740 // maskamt = (double)(cfa/24.0l);
741 // othermask = 1 - maskamt;
742 // maskamt /= 0xff;
743
744 // cdestr *= maskamt;
745 // cdestg *= maskamt;
746 // cdestb *= maskamt;
747
748 /////////////////////
749 // This code creates the colormap array used by software renderer
750 /////////////////////
751 {
752 double r, g, b, cbrightness;
753 int p;
754 char *colormap_p;
755
756 // Initialise the map and delta arrays
757 // map[i] stores an RGB color (as double) for index i,
758 // which is then converted to SRB2's palette later
759 // deltas[i] stores a corresponding fade delta between the RGB color and the final fade color;
760 // map[i]'s values are decremented by after each use
761 for (i = 0; i < 256; i++)
762 {
763 r = pMasterPalette[i].s.red;
764 g = pMasterPalette[i].s.green;
765 b = pMasterPalette[i].s.blue;
766 cbrightness = sqrt((r*r) + (g*g) + (b*b));
767
768 map[i][0] = (cbrightness * cmaskr) + (r * othermask);
769 if (map[i][0] > 255.0l)
770 map[i][0] = 255.0l;
771 deltas[i][0] = (map[i][0] - cdestr) / (double)fadedist;
772
773 map[i][1] = (cbrightness * cmaskg) + (g * othermask);
774 if (map[i][1] > 255.0l)
775 map[i][1] = 255.0l;
776 deltas[i][1] = (map[i][1] - cdestg) / (double)fadedist;
777
778 map[i][2] = (cbrightness * cmaskb) + (b * othermask);
779 if (map[i][2] > 255.0l)
780 map[i][2] = 255.0l;
781 deltas[i][2] = (map[i][2] - cdestb) / (double)fadedist;
782 }
783
784 // Now allocate memory for the actual colormap array itself!
785 // aligned on 8 bit for asm code
786 colormap_p = Z_MallocAlign((256 * 34) + 10, PU_LEVEL, NULL, 8);
787 lighttable = (UINT8 *)colormap_p;
788
789 // Calculate the palette index for each palette index, for each light level
790 // (as well as the two unused colormap lines we inherited from Doom)
791 for (p = 0; p < 34; p++)
792 {
793 for (i = 0; i < 256; i++)
794 {
795 *colormap_p = NearestColor((UINT8)RoundUp(map[i][0]),
796 (UINT8)RoundUp(map[i][1]),
797 (UINT8)RoundUp(map[i][2]));
798 colormap_p++;
799
800 if ((UINT32)p < fadestart)
801 continue;
802 #define ABS2(x) ((x) < 0 ? -(x) : (x))
803 if (ABS2(map[i][0] - cdestr) > ABS2(deltas[i][0]))
804 map[i][0] -= deltas[i][0];
805 else
806 map[i][0] = cdestr;
807
808 if (ABS2(map[i][1] - cdestg) > ABS2(deltas[i][1]))
809 map[i][1] -= deltas[i][1];
810 else
811 map[i][1] = cdestg;
812
813 if (ABS2(map[i][2] - cdestb) > ABS2(deltas[i][1]))
814 map[i][2] -= deltas[i][2];
815 else
816 map[i][2] = cdestb;
817 #undef ABS2
818 }
819 }
820 }
821
822 return lighttable;
823 }
824
R_CreateColormapFromLinedef(char * p1,char * p2,char * p3)825 extracolormap_t *R_CreateColormapFromLinedef(char *p1, char *p2, char *p3)
826 {
827 // default values
828 UINT8 cr = 0, cg = 0, cb = 0, ca = 0, cfr = 0, cfg = 0, cfb = 0, cfa = 25;
829 UINT32 fadestart = 0, fadeend = 31;
830 UINT8 flags = 0;
831 INT32 rgba = 0, fadergba = 0x19000000;
832
833 #define HEX2INT(x) (UINT32)(x >= '0' && x <= '9' ? x - '0' : x >= 'a' && x <= 'f' ? x - 'a' + 10 : x >= 'A' && x <= 'F' ? x - 'A' + 10 : 0)
834 #define ALPHA2INT(x) (x >= 'a' && x <= 'z' ? x - 'a' : x >= 'A' && x <= 'Z' ? x - 'A' : x >= '0' && x <= '9' ? 25 : 0)
835
836 // Get base colormap value
837 // First alpha-only, then full value
838 if (p1[0] >= 'a' && p1[0] <= 'z' && !p1[1])
839 ca = (p1[0] - 'a');
840 else if (p1[0] == '#' && p1[1] >= 'a' && p1[1] <= 'z' && !p1[2])
841 ca = (p1[1] - 'a');
842 else if (p1[0] >= 'A' && p1[0] <= 'Z' && !p1[1])
843 ca = (p1[0] - 'A');
844 else if (p1[0] == '#' && p1[1] >= 'A' && p1[1] <= 'Z' && !p1[2])
845 ca = (p1[1] - 'A');
846 else if (p1[0] == '#')
847 {
848 // For each subsequent value, the value before it must exist
849 // If we don't get every value, then set alpha to max
850 if (p1[1] && p1[2])
851 {
852 cr = ((HEX2INT(p1[1]) * 16) + HEX2INT(p1[2]));
853 if (p1[3] && p1[4])
854 {
855 cg = ((HEX2INT(p1[3]) * 16) + HEX2INT(p1[4]));
856 if (p1[5] && p1[6])
857 {
858 cb = ((HEX2INT(p1[5]) * 16) + HEX2INT(p1[6]));
859
860 if (p1[7] >= 'a' && p1[7] <= 'z')
861 ca = (p1[7] - 'a');
862 else if (p1[7] >= 'A' && p1[7] <= 'Z')
863 ca = (p1[7] - 'A');
864 else
865 ca = 25;
866 }
867 else
868 ca = 25;
869 }
870 else
871 ca = 25;
872 }
873 else
874 ca = 25;
875 }
876
877 #define NUMFROMCHAR(c) (c >= '0' && c <= '9' ? c - '0' : 0)
878
879 // Get parameters like fadestart, fadeend, and flags
880 if (p2[0] == '#')
881 {
882 if (p2[1])
883 {
884 flags = NUMFROMCHAR(p2[1]);
885 if (p2[2] && p2[3])
886 {
887 fadestart = NUMFROMCHAR(p2[3]) + (NUMFROMCHAR(p2[2]) * 10);
888 if (p2[4] && p2[5])
889 fadeend = NUMFROMCHAR(p2[5]) + (NUMFROMCHAR(p2[4]) * 10);
890 }
891 }
892
893 if (fadestart > 30)
894 fadestart = 0;
895 if (fadeend > 31 || fadeend < 1)
896 fadeend = 31;
897 }
898
899 #undef NUMFROMCHAR
900
901 // Get fade (dark) colormap value
902 // First alpha-only, then full value
903 if (p3[0] >= 'a' && p3[0] <= 'z' && !p3[1])
904 cfa = (p3[0] - 'a');
905 else if (p3[0] == '#' && p3[1] >= 'a' && p3[1] <= 'z' && !p3[2])
906 cfa = (p3[1] - 'a');
907 else if (p3[0] >= 'A' && p3[0] <= 'Z' && !p3[1])
908 cfa = (p3[0] - 'A');
909 else if (p3[0] == '#' && p3[1] >= 'A' && p3[1] <= 'Z' && !p3[2])
910 cfa = (p3[1] - 'A');
911 else if (p3[0] == '#')
912 {
913 // For each subsequent value, the value before it must exist
914 // If we don't get every value, then set alpha to max
915 if (p3[1] && p3[2])
916 {
917 cfr = ((HEX2INT(p3[1]) * 16) + HEX2INT(p3[2]));
918 if (p3[3] && p3[4])
919 {
920 cfg = ((HEX2INT(p3[3]) * 16) + HEX2INT(p3[4]));
921 if (p3[5] && p3[6])
922 {
923 cfb = ((HEX2INT(p3[5]) * 16) + HEX2INT(p3[6]));
924
925 if (p3[7] >= 'a' && p3[7] <= 'z')
926 cfa = (p3[7] - 'a');
927 else if (p3[7] >= 'A' && p3[7] <= 'Z')
928 cfa = (p3[7] - 'A');
929 else
930 cfa = 25;
931 }
932 else
933 cfa = 25;
934 }
935 else
936 cfa = 25;
937 }
938 else
939 cfa = 25;
940 }
941 #undef ALPHA2INT
942 #undef HEX2INT
943
944 // Pack rgba values into combined var
945 // OpenGL also uses this instead of lighttables for rendering
946 rgba = R_PutRgbaRGBA(cr, cg, cb, ca);
947 fadergba = R_PutRgbaRGBA(cfr, cfg, cfb, cfa);
948
949 return R_CreateColormap(rgba, fadergba, fadestart, fadeend, flags);
950 }
951
R_CreateColormap(INT32 rgba,INT32 fadergba,UINT8 fadestart,UINT8 fadeend,UINT8 flags)952 extracolormap_t *R_CreateColormap(INT32 rgba, INT32 fadergba, UINT8 fadestart, UINT8 fadeend, UINT8 flags)
953 {
954 extracolormap_t *extra_colormap;
955
956 // Did we just make a default colormap?
957 #ifdef EXTRACOLORMAPLUMPS
958 if (R_CheckDefaultColormapByValues(true, true, true, rgba, fadergba, fadestart, fadeend, flags, LUMPERROR))
959 return NULL;
960 #else
961 if (R_CheckDefaultColormapByValues(true, true, true, rgba, fadergba, fadestart, fadeend, flags))
962 return NULL;
963 #endif
964
965 // Look for existing colormaps
966 #ifdef EXTRACOLORMAPLUMPS
967 extra_colormap = R_GetColormapFromListByValues(rgba, fadergba, fadestart, fadeend, flags, LUMPERROR);
968 #else
969 extra_colormap = R_GetColormapFromListByValues(rgba, fadergba, fadestart, fadeend, flags);
970 #endif
971 if (extra_colormap)
972 return extra_colormap;
973
974 CONS_Debug(DBG_RENDER, "Creating Colormap: rgba(%x) fadergba(%x)\n", rgba, fadergba);
975
976 extra_colormap = Z_Calloc(sizeof(*extra_colormap), PU_LEVEL, NULL);
977
978 extra_colormap->fadestart = (UINT16)fadestart;
979 extra_colormap->fadeend = (UINT16)fadeend;
980 extra_colormap->flags = flags;
981
982 extra_colormap->rgba = rgba;
983 extra_colormap->fadergba = fadergba;
984
985 #ifdef EXTRACOLORMAPLUMPS
986 extra_colormap->lump = LUMPERROR;
987 extra_colormap->lumpname[0] = 0;
988 #endif
989
990 // Having lighttables for alpha-only entries is kind of pointless,
991 // but if there happens to be a matching rgba entry that is NOT alpha-only (but has same rgb values),
992 // then it needs this lighttable because we share matching entries.
993 extra_colormap->colormap = R_CreateLightTable(extra_colormap);
994
995 R_AddColormapToList(extra_colormap);
996
997 return extra_colormap;
998 }
999
1000 //
1001 // R_AddColormaps()
1002 // NOTE: The result colormap is not added to the extra_colormaps chain. You must do that yourself!
1003 //
R_AddColormaps(extracolormap_t * exc_augend,extracolormap_t * exc_addend,boolean subR,boolean subG,boolean subB,boolean subA,boolean subFadeR,boolean subFadeG,boolean subFadeB,boolean subFadeA,boolean subFadeStart,boolean subFadeEnd,boolean ignoreFlags,boolean lighttable)1004 extracolormap_t *R_AddColormaps(extracolormap_t *exc_augend, extracolormap_t *exc_addend,
1005 boolean subR, boolean subG, boolean subB, boolean subA,
1006 boolean subFadeR, boolean subFadeG, boolean subFadeB, boolean subFadeA,
1007 boolean subFadeStart, boolean subFadeEnd, boolean ignoreFlags,
1008 boolean lighttable)
1009 {
1010 INT16 red, green, blue, alpha;
1011
1012 // exc_augend is added (or subtracted) onto by exc_addend
1013 // In Rennaisance times, the first number was considered the augend, the second number the addend
1014 // But since the commutative property was discovered, today they're both called addends!
1015 // So let's be Olde English for a hot second.
1016
1017 exc_augend = R_CopyColormap(exc_augend, false);
1018 if(!exc_addend)
1019 exc_addend = R_GetDefaultColormap();
1020
1021 ///////////////////
1022 // base rgba
1023 ///////////////////
1024
1025 red = max(min(
1026 R_GetRgbaR(exc_augend->rgba)
1027 + (subR ? -1 : 1) // subtract R
1028 * R_GetRgbaR(exc_addend->rgba)
1029 , 255), 0);
1030
1031 green = max(min(
1032 R_GetRgbaG(exc_augend->rgba)
1033 + (subG ? -1 : 1) // subtract G
1034 * R_GetRgbaG(exc_addend->rgba)
1035 , 255), 0);
1036
1037 blue = max(min(
1038 R_GetRgbaB(exc_augend->rgba)
1039 + (subB ? -1 : 1) // subtract B
1040 * R_GetRgbaB(exc_addend->rgba)
1041 , 255), 0);
1042
1043 alpha = R_GetRgbaA(exc_addend->rgba);
1044 alpha = max(min(R_GetRgbaA(exc_augend->rgba) + (subA ? -1 : 1) * alpha, 25), 0);
1045
1046 exc_augend->rgba = R_PutRgbaRGBA(red, green, blue, alpha);
1047
1048 ///////////////////
1049 // fade/dark rgba
1050 ///////////////////
1051
1052 red = max(min(
1053 R_GetRgbaR(exc_augend->fadergba)
1054 + (subFadeR ? -1 : 1) // subtract R
1055 * R_GetRgbaR(exc_addend->fadergba)
1056 , 255), 0);
1057
1058 green = max(min(
1059 R_GetRgbaG(exc_augend->fadergba)
1060 + (subFadeG ? -1 : 1) // subtract G
1061 * R_GetRgbaG(exc_addend->fadergba)
1062 , 255), 0);
1063
1064 blue = max(min(
1065 R_GetRgbaB(exc_augend->fadergba)
1066 + (subFadeB ? -1 : 1) // subtract B
1067 * R_GetRgbaB(exc_addend->fadergba)
1068 , 255), 0);
1069
1070 alpha = R_GetRgbaA(exc_addend->fadergba);
1071 if (alpha == 25 && !R_GetRgbaRGB(exc_addend->fadergba))
1072 alpha = 0; // HACK: fadergba A defaults at 25, so don't add anything in this case
1073 alpha = max(min(R_GetRgbaA(exc_augend->fadergba) + (subFadeA ? -1 : 1) * alpha, 25), 0);
1074
1075 exc_augend->fadergba = R_PutRgbaRGBA(red, green, blue, alpha);
1076
1077 ///////////////////
1078 // parameters
1079 ///////////////////
1080
1081 exc_augend->fadestart = max(min(
1082 exc_augend->fadestart
1083 + (subFadeStart ? -1 : 1) // subtract fadestart
1084 * exc_addend->fadestart
1085 , 31), 0);
1086
1087 exc_augend->fadeend = max(min(
1088 exc_augend->fadeend
1089 + (subFadeEnd ? -1 : 1) // subtract fadeend
1090 * (exc_addend->fadeend == 31 && !exc_addend->fadestart ? 0 : exc_addend->fadeend)
1091 // HACK: fadeend defaults to 31, so don't add anything in this case
1092 , 31), 0);
1093
1094 if (!ignoreFlags) // overwrite flags with new value
1095 exc_augend->flags = exc_addend->flags;
1096
1097 ///////////////////
1098 // put it together
1099 ///////////////////
1100
1101 exc_augend->colormap = lighttable ? R_CreateLightTable(exc_augend) : NULL;
1102 exc_augend->next = exc_augend->prev = NULL;
1103 return exc_augend;
1104 }
1105
1106 // Thanks to quake2 source!
1107 // utils3/qdata/images.c
NearestPaletteColor(UINT8 r,UINT8 g,UINT8 b,RGBA_t * palette)1108 UINT8 NearestPaletteColor(UINT8 r, UINT8 g, UINT8 b, RGBA_t *palette)
1109 {
1110 int dr, dg, db;
1111 int distortion, bestdistortion = 256 * 256 * 4, bestcolor = 0, i;
1112
1113 // Use master palette if none specified
1114 if (palette == NULL)
1115 palette = pMasterPalette;
1116
1117 for (i = 0; i < 256; i++)
1118 {
1119 dr = r - palette[i].s.red;
1120 dg = g - palette[i].s.green;
1121 db = b - palette[i].s.blue;
1122 distortion = dr*dr + dg*dg + db*db;
1123 if (distortion < bestdistortion)
1124 {
1125 if (!distortion)
1126 return (UINT8)i;
1127
1128 bestdistortion = distortion;
1129 bestcolor = i;
1130 }
1131 }
1132
1133 return (UINT8)bestcolor;
1134 }
1135
1136 // Rounds off floating numbers and checks for 0 - 255 bounds
RoundUp(double number)1137 static int RoundUp(double number)
1138 {
1139 if (number > 255.0l)
1140 return 255;
1141 if (number < 0.0l)
1142 return 0;
1143
1144 if ((int)number <= (int)(number - 0.5f))
1145 return (int)number + 1;
1146
1147 return (int)number;
1148 }
1149
1150 #ifdef EXTRACOLORMAPLUMPS
R_NameForColormap(extracolormap_t * extra_colormap)1151 const char *R_NameForColormap(extracolormap_t *extra_colormap)
1152 {
1153 if (!extra_colormap)
1154 return "NONE";
1155
1156 if (extra_colormap->lump == LUMPERROR)
1157 return "INLEVEL";
1158
1159 return extra_colormap->lumpname;
1160 }
1161 #endif
1162
1163 //
1164 // build a table for quick conversion from 8bpp to 15bpp
1165 //
1166
1167 //
1168 // added "static inline" keywords, linking with the debug version
1169 // of allegro, it have a makecol15 function of it's own, now
1170 // with "static inline" keywords,it sloves this problem ;)
1171 //
makecol15(int r,int g,int b)1172 FUNCMATH static inline int makecol15(int r, int g, int b)
1173 {
1174 return (((r >> 3) << 10) | ((g >> 3) << 5) | ((b >> 3)));
1175 }
1176
R_Init8to16(void)1177 static void R_Init8to16(void)
1178 {
1179 UINT8 *palette;
1180 int i;
1181
1182 palette = W_CacheLumpName("PLAYPAL",PU_CACHE);
1183
1184 for (i = 0; i < 256; i++)
1185 {
1186 // PLAYPAL uses 8 bit values
1187 color8to16[i] = (INT16)makecol15(palette[0], palette[1], palette[2]);
1188 palette += 3;
1189 }
1190
1191 // test a big colormap
1192 hicolormaps = Z_Malloc(16384*sizeof(*hicolormaps), PU_STATIC, NULL);
1193 for (i = 0; i < 16384; i++)
1194 hicolormaps[i] = (INT16)(i<<1);
1195 }
1196
1197 //
1198 // R_InitData
1199 //
1200 // Locates all the lumps that will be used by all views
1201 // Must be called after W_Init.
1202 //
R_InitData(void)1203 void R_InitData(void)
1204 {
1205 if (highcolor)
1206 {
1207 CONS_Printf("InitHighColor...\n");
1208 R_Init8to16();
1209 }
1210
1211 CONS_Printf("R_LoadTextures()...\n");
1212 R_LoadTextures();
1213
1214 CONS_Printf("P_InitPicAnims()...\n");
1215 P_InitPicAnims();
1216
1217 CONS_Printf("R_InitSprites()...\n");
1218 R_InitSpriteLumps();
1219 R_InitSprites();
1220
1221 CONS_Printf("R_InitColormaps()...\n");
1222 R_InitColormaps();
1223 }
1224
1225 //
1226 // R_PrecacheLevel
1227 //
1228 // Preloads all relevant graphics for the level.
1229 //
R_PrecacheLevel(void)1230 void R_PrecacheLevel(void)
1231 {
1232 char *texturepresent, *spritepresent;
1233 size_t i, j, k;
1234 lumpnum_t lump;
1235
1236 thinker_t *th;
1237 spriteframe_t *sf;
1238
1239 if (demoplayback)
1240 return;
1241
1242 // do not flush the memory, Z_Malloc twice with same user will cause error in Z_CheckHeap()
1243 if (rendermode != render_soft)
1244 return;
1245
1246 // Precache flats.
1247 flatmemory = P_PrecacheLevelFlats();
1248
1249 //
1250 // Precache textures.
1251 //
1252 // no need to precache all software textures in 3D mode
1253 // (note they are still used with the reference software view)
1254 texturepresent = calloc(numtextures, sizeof (*texturepresent));
1255 if (texturepresent == NULL) I_Error("%s: Out of memory looking up textures", "R_PrecacheLevel");
1256
1257 for (j = 0; j < numsides; j++)
1258 {
1259 // huh, a potential bug here????
1260 if (sides[j].toptexture >= 0 && sides[j].toptexture < numtextures)
1261 texturepresent[sides[j].toptexture] = 1;
1262 if (sides[j].midtexture >= 0 && sides[j].midtexture < numtextures)
1263 texturepresent[sides[j].midtexture] = 1;
1264 if (sides[j].bottomtexture >= 0 && sides[j].bottomtexture < numtextures)
1265 texturepresent[sides[j].bottomtexture] = 1;
1266 }
1267
1268 // Sky texture is always present.
1269 // Note that F_SKY1 is the name used to indicate a sky floor/ceiling as a flat,
1270 // while the sky texture is stored like a wall texture, with a skynum dependent name.
1271 texturepresent[skytexture] = 1;
1272
1273 texturememory = 0;
1274 for (j = 0; j < (unsigned)numtextures; j++)
1275 {
1276 if (!texturepresent[j])
1277 continue;
1278
1279 if (!texturecache[j])
1280 R_GenerateTexture(j);
1281 // pre-caching individual patches that compose textures became obsolete,
1282 // since we cache entire composite textures
1283 }
1284 free(texturepresent);
1285
1286 //
1287 // Precache sprites.
1288 //
1289 spritepresent = calloc(numsprites, sizeof (*spritepresent));
1290 if (spritepresent == NULL) I_Error("%s: Out of memory looking up sprites", "R_PrecacheLevel");
1291
1292 for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
1293 if (th->function.acp1 != (actionf_p1)P_RemoveThinkerDelayed)
1294 spritepresent[((mobj_t *)th)->sprite] = 1;
1295
1296 spritememory = 0;
1297 for (i = 0; i < numsprites; i++)
1298 {
1299 if (!spritepresent[i])
1300 continue;
1301
1302 for (j = 0; j < sprites[i].numframes; j++)
1303 {
1304 sf = &sprites[i].spriteframes[j];
1305 #define cacheang(a) {\
1306 lump = sf->lumppat[a];\
1307 if (devparm)\
1308 spritememory += W_LumpLength(lump);\
1309 W_CachePatchNum(lump, PU_SPRITE);\
1310 }
1311 // see R_InitSprites for more about lumppat,lumpid
1312 switch (sf->rotate)
1313 {
1314 case SRF_SINGLE:
1315 cacheang(0);
1316 break;
1317 case SRF_2D:
1318 cacheang(2);
1319 cacheang(6);
1320 break;
1321 default:
1322 k = (sf->rotate & SRF_3DGE ? 16 : 8);
1323 while (k--)
1324 cacheang(k);
1325 break;
1326 }
1327 #undef cacheang
1328 }
1329 }
1330 free(spritepresent);
1331
1332 // FIXME: this is no longer correct with OpenGL render mode
1333 CONS_Debug(DBG_SETUP, "Precache level done:\n"
1334 "flatmemory: %s k\n"
1335 "texturememory: %s k\n"
1336 "spritememory: %s k\n", sizeu1(flatmemory>>10), sizeu2(texturememory>>10), sizeu3(spritememory>>10));
1337 }
1338