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