1 /*
2 ** r_translate.cpp
3 ** Translatioo table handling
4 **
5 **---------------------------------------------------------------------------
6 ** Copyright 1998-2006 Randy Heit
7 ** All rights reserved.
8 **
9 ** Redistribution and use in source and binary forms, with or without
10 ** modification, are permitted provided that the following conditions
11 ** are met:
12 **
13 ** 1. Redistributions of source code must retain the above copyright
14 **    notice, this list of conditions and the following disclaimer.
15 ** 2. Redistributions in binary form must reproduce the above copyright
16 **    notice, this list of conditions and the following disclaimer in the
17 **    documentation and/or other materials provided with the distribution.
18 ** 3. The name of the author may not be used to endorse or promote products
19 **    derived from this software without specific prior written permission.
20 **
21 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 **---------------------------------------------------------------------------
32 **
33 */
34 
35 #include <stddef.h>
36 
37 #include "templates.h"
38 //#include "r_draw.h"
39 //#include "r_main.h"
40 #include "r_translate.h"
41 //#include "v_video.h"
42 //#include "g_game.h"
43 #include "colormatcher.h"
44 //#include "d_netinf.h"
45 #include "v_palette.h"
46 #include "scanner.h"
47 //#include "sc_man.h"
48 #include "doomerrors.h"
49 //#include "i_system.h"
50 #include "w_wad.h"
51 #include "farchive.h"
52 
53 //#include "gi.h"
54 //#include "stats.h"
55 #include "zdoomsupport.h"
56 
57 TAutoGrowArray<FRemapTablePtr, FRemapTable *> translationtables[NUM_TRANSLATION_TABLES];
58 
59 BYTE identitymap[256];
60 
61 const BYTE IcePalette[16][3] =
62 {
63 	{  10,  8, 18 },
64 	{  15, 15, 26 },
65 	{  20, 16, 36 },
66 	{  30, 26, 46 },
67 	{  40, 36, 57 },
68 	{  50, 46, 67 },
69 	{  59, 57, 78 },
70 	{  69, 67, 88 },
71 	{  79, 77, 99 },
72 	{  89, 87,109 },
73 	{  99, 97,120 },
74 	{ 109,107,130 },
75 	{ 118,118,141 },
76 	{ 128,128,151 },
77 	{ 138,138,162 },
78 	{ 148,148,172 }
79 };
80 
81 /****************************************************/
82 /****************************************************/
83 
FRemapTable(int count)84 FRemapTable::FRemapTable(int count)
85 {
86 	assert(count <= 256);
87 	Inactive = false;
88 	Alloc(count);
89 
90 	// Note that the tables are left uninitialized. It is assumed that
91 	// the caller will do that next, if only by calling MakeIdentity().
92 }
93 
94 //----------------------------------------------------------------------------
95 //
96 //
97 //
98 //----------------------------------------------------------------------------
99 
~FRemapTable()100 FRemapTable::~FRemapTable()
101 {
102 	Free();
103 }
104 
105 //----------------------------------------------------------------------------
106 //
107 //
108 //
109 //----------------------------------------------------------------------------
110 
Alloc(int count)111 void FRemapTable::Alloc(int count)
112 {
113 	Remap = (BYTE *)M_Malloc(count*sizeof(*Remap) + count*sizeof(*Palette));
114 	assert (Remap != NULL);
115 	Palette = (PalEntry *)(Remap + count*(sizeof(*Remap)));
116 	NumEntries = count;
117 }
118 
119 //----------------------------------------------------------------------------
120 //
121 //
122 //
123 //----------------------------------------------------------------------------
124 
Free()125 void FRemapTable::Free()
126 {
127 	if (Remap != NULL)
128 	{
129 		M_Free(Remap);
130 		Remap = NULL;
131 		Palette = NULL;
132 		NumEntries = 0;
133 	}
134 }
135 
136 //----------------------------------------------------------------------------
137 //
138 //
139 //
140 //----------------------------------------------------------------------------
141 
FRemapTable(const FRemapTable & o)142 FRemapTable::FRemapTable(const FRemapTable &o)
143 {
144 	Remap = NULL;
145 	NumEntries = 0;
146 	operator= (o);
147 }
148 
149 //----------------------------------------------------------------------------
150 //
151 //
152 //
153 //----------------------------------------------------------------------------
154 
operator =(const FRemapTable & o)155 FRemapTable &FRemapTable::operator=(const FRemapTable &o)
156 {
157 	if (&o == this)
158 	{
159 		return *this;
160 	}
161 	if (o.NumEntries != NumEntries)
162 	{
163 		Free();
164 	}
165 	if (Remap == NULL)
166 	{
167 		Alloc(o.NumEntries);
168 	}
169 	Inactive = o.Inactive;
170 	memcpy(Remap, o.Remap, NumEntries*sizeof(*Remap) + NumEntries*sizeof(*Palette));
171 	return *this;
172 }
173 
174 //----------------------------------------------------------------------------
175 //
176 //
177 //
178 //----------------------------------------------------------------------------
179 
operator ==(const FRemapTable & o)180 bool FRemapTable::operator==(const FRemapTable &o)
181 {
182 	// Two translations are identical when they have the same amount of colors
183 	// and the palette values for both are identical.
184 	if (&o == this) return true;
185 	if (o.NumEntries != NumEntries) return false;
186 	return !memcmp(o.Palette, Palette, NumEntries * sizeof(*Palette));
187 }
188 
189 //----------------------------------------------------------------------------
190 //
191 //
192 //
193 //----------------------------------------------------------------------------
194 
Serialize(FArchive & arc)195 void FRemapTable::Serialize(FArchive &arc)
196 {
197 	int n = NumEntries;
198 
199 	arc << NumEntries;
200 	if (arc.IsStoring())
201 	{
202 		arc.Write (Remap, NumEntries);
203 	}
204 	else
205 	{
206 		if (n != NumEntries)
207 		{
208 			Free();
209 			Alloc(NumEntries);
210 		}
211 		arc.Read (Remap, NumEntries);
212 	}
213 	for (int j = 0; j < NumEntries; ++j)
214 	{
215 		arc << Palette[j];
216 	}
217 }
218 
219 //----------------------------------------------------------------------------
220 //
221 //
222 //
223 //----------------------------------------------------------------------------
224 
MakeIdentity()225 void FRemapTable::MakeIdentity()
226 {
227 	int i;
228 
229 	for (i = 0; i < NumEntries; ++i)
230 	{
231 		Remap[i] = i;
232 	}
233 	for (i = 0; i < NumEntries; ++i)
234 	{
235 		Palette[i] = GPalette.BaseColors[i];
236 	}
237 	for (i = 1; i < NumEntries; ++i)
238 	{
239 		Palette[i].a = 255;
240 	}
241 }
242 
243 //----------------------------------------------------------------------------
244 //
245 //
246 //
247 //----------------------------------------------------------------------------
248 
IsIdentity() const249 bool FRemapTable::IsIdentity() const
250 {
251 	for (int j = 0; j < 256; ++j)
252 	{
253 		if (Remap[j] != j)
254 		{
255 			return false;
256 		}
257 	}
258 	return true;
259 }
260 
261 //----------------------------------------------------------------------------
262 //
263 //
264 //
265 //----------------------------------------------------------------------------
266 
AddIndexRange(int start,int end,int pal1,int pal2)267 void FRemapTable::AddIndexRange(int start, int end, int pal1, int pal2)
268 {
269 	fixed_t palcol, palstep;
270 
271 	if (start > end)
272 	{
273 		swapvalues (start, end);
274 		swapvalues (pal1, pal2);
275 	}
276 	else if (start == end)
277 	{
278 		start = GPalette.Remap[start];
279 		pal1 = GPalette.Remap[pal1];
280 		Remap[start] = pal1;
281 		Palette[start] = GPalette.BaseColors[pal1];
282 		Palette[start].a = start == 0 ? 0 : 255;
283 		return;
284 	}
285 	palcol = pal1 << FRACBITS;
286 	palstep = ((pal2 << FRACBITS) - palcol) / (end - start);
287 	for (int i = start; i <= end; palcol += palstep, ++i)
288 	{
289 		int j = GPalette.Remap[i], k = GPalette.Remap[palcol >> FRACBITS];
290 		Remap[j] = k;
291 		Palette[j] = GPalette.BaseColors[k];
292 		Palette[j].a = j == 0 ? 0 : 255;
293 	}
294 }
295 
296 //----------------------------------------------------------------------------
297 //
298 //
299 //
300 //----------------------------------------------------------------------------
301 
AddColorRange(int start,int end,int _r1,int _g1,int _b1,int _r2,int _g2,int _b2)302 void FRemapTable::AddColorRange(int start, int end, int _r1,int _g1, int _b1, int _r2, int _g2, int _b2)
303 {
304 	fixed_t r1 = _r1 << FRACBITS;
305 	fixed_t g1 = _g1 << FRACBITS;
306 	fixed_t b1 = _b1 << FRACBITS;
307 	fixed_t r2 = _r2 << FRACBITS;
308 	fixed_t g2 = _g2 << FRACBITS;
309 	fixed_t b2 = _b2 << FRACBITS;
310 	fixed_t r, g, b;
311 	fixed_t rs, gs, bs;
312 
313 	if (start > end)
314 	{
315 		swapvalues (start, end);
316 		r = r2;
317 		g = g2;
318 		b = b2;
319 		rs = r1 - r2;
320 		gs = g1 - g2;
321 		bs = b1 - b2;
322 	}
323 	else
324 	{
325 		r = r1;
326 		g = g1;
327 		b = b1;
328 		rs = r2 - r1;
329 		gs = g2 - g1;
330 		bs = b2 - b1;
331 	}
332 	if (start == end)
333 	{
334 		start = GPalette.Remap[start];
335 		Remap[start] = ColorMatcher.Pick(r >> FRACBITS, g >> FRACBITS, b >> FRACBITS);
336 		Palette[start] = PalEntry(r >> FRACBITS, g >> FRACBITS, b >> FRACBITS);
337 		Palette[start].a = start == 0 ? 0 : 255;
338 	}
339 	else
340 	{
341 		rs /= (end - start);
342 		gs /= (end - start);
343 		bs /= (end - start);
344 		for (int i = start; i <= end; ++i)
345 		{
346 			int j = GPalette.Remap[i];
347 			Remap[j] = ColorMatcher.Pick(r >> FRACBITS, g >> FRACBITS, b >> FRACBITS);
348 			Palette[j] = PalEntry(j == 0 ? 0 : 255, r >> FRACBITS, g >> FRACBITS, b >> FRACBITS);
349 			r += rs;
350 			g += gs;
351 			b += bs;
352 		}
353 	}
354 }
355 
356 //----------------------------------------------------------------------------
357 //
358 //
359 //
360 //----------------------------------------------------------------------------
361 
AddDesaturation(int start,int end,double r1,double g1,double b1,double r2,double g2,double b2)362 void FRemapTable::AddDesaturation(int start, int end, double r1, double g1, double b1, double r2, double g2, double b2)
363 {
364 	r1 = clamp(r1, 0.0, 2.0);
365 	g1 = clamp(g1, 0.0, 2.0);
366 	b1 = clamp(b1, 0.0, 2.0);
367 	r2 = clamp(r2, 0.0, 2.0);
368 	g2 = clamp(g2, 0.0, 2.0);
369 	b2 = clamp(b2, 0.0, 2.0);
370 
371 	if (start > end)
372 	{
373 		swapvalues(start, end);
374 		swapvalues(r1, r2);
375 		swapvalues(g1, g2);
376 		swapvalues(b1, b2);
377 	}
378 
379 	r2 -= r1;
380 	g2 -= g1;
381 	b2 -= b1;
382 	r1 *= 255;
383 	g1 *= 255;
384 	b1 *= 255;
385 
386 	for(int c = start; c <= end; c++)
387 	{
388 		double intensity = (GPalette.BaseColors[c].r * 77 +
389 							GPalette.BaseColors[c].g * 143 +
390 							GPalette.BaseColors[c].b * 37) / 256.0;
391 
392 		PalEntry pe = PalEntry(	MIN(255, int(r1 + intensity*r2)),
393 								MIN(255, int(g1 + intensity*g2)),
394 								MIN(255, int(b1 + intensity*b2)));
395 
396 		int cc = GPalette.Remap[c];
397 
398 		Remap[cc] = ColorMatcher.Pick(pe);
399 		Palette[cc] = pe;
400 		Palette[cc].a = cc == 0 ? 0:255;
401 	}
402 }
403 
404 //----------------------------------------------------------------------------
405 //
406 //
407 //
408 //----------------------------------------------------------------------------
409 
AddToTranslation(const char * range)410 void FRemapTable::AddToTranslation(const char * range)
411 {
412 	int start,end;
413 	bool desaturated = false;
414 	Scanner sc(range, int(strlen(range)));
415 	sc.SetScriptIdentifier("Translation");
416 
417 	try
418 	{
419 		sc.MustGetToken(TK_IntConst);
420 		start = sc->number;
421 		sc.MustGetToken(':');
422 		sc.MustGetToken(TK_IntConst);
423 		end = sc->number;
424 		sc.MustGetToken('=');
425 		if (start < 0 || start > 255 || end < 0 || end > 255)
426 		{
427 			sc.ScriptMessage(Scanner::ERROR, "Palette index out of range");
428 			return;
429 		}
430 
431 		sc.GetNextToken();
432 
433 		if (sc->token != '[' && sc->token != '%')
434 		{
435 			int pal1,pal2;
436 
437 			if(sc->token != TK_IntConst)
438 				sc.ScriptMessage(Scanner::ERROR, "Expected integer constant.");
439 			pal1 = sc->number;
440 			sc.MustGetToken(':');
441 			sc.MustGetToken(TK_IntConst);
442 			pal2 = sc->number;
443 			AddIndexRange(start, end, pal1, pal2);
444 		}
445 		else if (sc->token == '[')
446 		{
447 			// translation using RGB values
448 			int r1,g1,b1,r2,g2,b2;
449 
450 			sc.MustGetToken(TK_IntConst);
451 			r1 = sc->number;
452 			sc.MustGetToken(',');
453 
454 			sc.MustGetToken(TK_IntConst);
455 			g1 = sc->number;
456 			sc.MustGetToken(',');
457 
458 			sc.MustGetToken(TK_IntConst);
459 			b1 = sc->number;
460 			sc.MustGetToken(']');
461 			sc.MustGetToken(':');
462 			sc.MustGetToken('[');
463 
464 			sc.MustGetToken(TK_IntConst);
465 			r2 = sc->number;
466 			sc.MustGetToken(',');
467 
468 			sc.MustGetToken(TK_IntConst);
469 			g2 = sc->number;
470 			sc.MustGetToken(',');
471 
472 			sc.MustGetToken(TK_IntConst);
473 			b2 = sc->number;
474 			sc.MustGetToken(']');
475 
476 			AddColorRange(start, end, r1, g1, b1, r2, g2, b2);
477 		}
478 		else if (sc->token == '%')
479 		{
480 			// translation using RGB values
481 			double r1,g1,b1,r2,g2,b2;
482 
483 			sc.MustGetToken('[');
484 			sc.GetNextToken();
485 			if (sc->token != TK_IntConst && sc->token != TK_FloatConst) sc.ScriptMessage(Scanner::ERROR, "Expected floating point constant.");
486 			r1 = sc->decimal;
487 			sc.MustGetToken(',');
488 
489 			sc.GetNextToken();
490 			if (sc->token != TK_IntConst && sc->token != TK_FloatConst) sc.ScriptMessage(Scanner::ERROR, "Expected floating point constant.");
491 			g1 = sc->decimal;
492 			sc.MustGetToken(',');
493 
494 			sc.GetNextToken();
495 			if (sc->token != TK_IntConst && sc->token != TK_FloatConst) sc.ScriptMessage(Scanner::ERROR, "Expected floating point constant.");
496 			b1 = sc->decimal;
497 			sc.MustGetToken(']');
498 			sc.MustGetToken(':');
499 			sc.MustGetToken('[');
500 
501 			sc.GetNextToken();
502 			if (sc->token != TK_IntConst && sc->token != TK_FloatConst) sc.ScriptMessage(Scanner::ERROR, "Expected floating point constant.");
503 			r2 = sc->decimal;
504 			sc.MustGetToken(',');
505 
506 			sc.GetNextToken();
507 			if (sc->token != TK_IntConst && sc->token != TK_FloatConst) sc.ScriptMessage(Scanner::ERROR, "Expected floating point constant.");
508 			g2 = sc->decimal;
509 			sc.MustGetToken(',');
510 
511 			sc.GetNextToken();
512 			if (sc->token != TK_IntConst && sc->token != TK_FloatConst) sc.ScriptMessage(Scanner::ERROR, "Expected floating point constant.");
513 			b2 = sc->decimal;
514 			sc.MustGetToken(']');
515 
516 			AddDesaturation(start, end, r1, g1, b1, r2, g2, b2);
517 		}
518 	}
519 	catch (CRecoverableError &err)
520 	{
521 		Printf("Error in translation '%s':\n%s\n", range, err.GetMessage());
522 	}
523 }
524 
525 //----------------------------------------------------------------------------
526 //
527 // Stores a copy of this translation in the DECORATE translation table
528 //
529 //----------------------------------------------------------------------------
530 
StoreTranslation()531 int FRemapTable::StoreTranslation()
532 {
533 	unsigned int i;
534 
535 	for (i = 0; i < translationtables[TRANSLATION_Decorate].Size(); i++)
536 	{
537 		if (*this == *translationtables[TRANSLATION_Decorate][i])
538 		{
539 			// A duplicate of this translation already exists
540 			return TRANSLATION(TRANSLATION_Decorate, i);
541 		}
542 	}
543 	if (translationtables[TRANSLATION_Decorate].Size() >= MAX_DECORATE_TRANSLATIONS)
544 	{
545 		I_Error("Too many DECORATE translations");
546 	}
547 	FRemapTable *newtrans = new FRemapTable;
548 	*newtrans = *this;
549 	i = translationtables[TRANSLATION_Decorate].Push(newtrans);
550 	return TRANSLATION(TRANSLATION_Decorate, i);
551 }
552 
553 
554 //----------------------------------------------------------------------------
555 //
556 //
557 //
558 //----------------------------------------------------------------------------
559 
560 TArray<PalEntry> BloodTranslationColors;
561 
CreateBloodTranslation(PalEntry color)562 int CreateBloodTranslation(PalEntry color)
563 {
564 	unsigned int i;
565 
566 	if (BloodTranslationColors.Size() == 0)
567 	{
568 		// Don't use the first slot.
569 		translationtables[TRANSLATION_Blood].Push(NULL);
570 		BloodTranslationColors.Push(0);
571 	}
572 
573 	for (i = 1; i < BloodTranslationColors.Size(); i++)
574 	{
575 		if (color.r == BloodTranslationColors[i].r &&
576 			color.g == BloodTranslationColors[i].g &&
577 			color.b == BloodTranslationColors[i].b)
578 		{
579 			// A duplicate of this translation already exists
580 			return i;
581 		}
582 	}
583 	if (BloodTranslationColors.Size() >= MAX_DECORATE_TRANSLATIONS)
584 	{
585 		I_Error("Too many blood colors");
586 	}
587 	FRemapTable *trans = new FRemapTable;
588 	for (i = 0; i < 256; i++)
589 	{
590 		int bright = MAX(MAX(GPalette.BaseColors[i].r, GPalette.BaseColors[i].g), GPalette.BaseColors[i].b);
591 		PalEntry pe = PalEntry(color.r*bright/255, color.g*bright/255, color.b*bright/255);
592 		int entry = ColorMatcher.Pick(pe.r, pe.g, pe.b);
593 
594 		trans->Palette[i] = pe;
595 		trans->Remap[i] = entry;
596 	}
597 	translationtables[TRANSLATION_Blood].Push(trans);
598 	return BloodTranslationColors.Push(color);
599 }
600 
601 //----------------------------------------------------------------------------
602 //
603 //
604 //
605 //----------------------------------------------------------------------------
606 
TranslationToTable(int translation)607 FRemapTable *TranslationToTable(int translation)
608 {
609 	unsigned int type = GetTranslationType(translation);
610 	unsigned int index = GetTranslationIndex(translation);
611 	TAutoGrowArray<FRemapTablePtr, FRemapTable *> *slots;
612 
613 	if (type <= 0 || type >= NUM_TRANSLATION_TABLES)
614 	{
615 		return NULL;
616 	}
617 	slots = &translationtables[type];
618 	if (index >= slots->Size())
619 	{
620 		return NULL;
621 	}
622 	return slots->operator[](index);
623 }
624 
625 //----------------------------------------------------------------------------
626 //
627 //
628 //
629 //----------------------------------------------------------------------------
630 
PushIdentityTable(int slot)631 static void PushIdentityTable(int slot)
632 {
633 	FRemapTable *table = new FRemapTable;
634 	table->MakeIdentity();
635 	translationtables[slot].Push(table);
636 }
637 
638 //----------------------------------------------------------------------------
639 //
640 // R_InitTranslationTables
641 // Creates the translation tables to map the green color ramp to gray,
642 // brown, red. Assumes a given structure of the PLAYPAL.
643 //
644 //----------------------------------------------------------------------------
645 
R_InitTranslationTables()646 void R_InitTranslationTables ()
647 {
648 	int i;//, j;
649 
650 	// Each player gets two translations. Doom and Strife don't use the
651 	// extra ones, but Heretic and Hexen do. These are set up during
652 	// netgame arbitration and as-needed, so they just get to be identity
653 	// maps until then so they won't be invalid.
654 	for (i = 0; i < MAXPLAYERS; ++i)
655 	{
656 		PushIdentityTable(TRANSLATION_Players);
657 		PushIdentityTable(TRANSLATION_PlayersExtra);
658 	}
659 	// The menu player also gets a separate translation table
660 	PushIdentityTable(TRANSLATION_Players);
661 
662 	// The three standard translations from Doom or Heretic (seven for Strife),
663 	// plus the generic ice translation.
664 	for (i = 0; i < 8; ++i)
665 	{
666 		PushIdentityTable(TRANSLATION_Standard);
667 	}
668 
669 	// Each player corpse has its own translation so they won't change
670 	// color if the player who created them changes theirs.
671 	for (i = 0; i < BODYQUESIZE; ++i)
672 	{
673 		PushIdentityTable(TRANSLATION_PlayerCorpses);
674 	}
675 
676 	// Create the standard translation tables
677 	for (i = 0x70; i < 0x80; i++)
678 	{ // map green ramp to gray, brown, red
679 		translationtables[TRANSLATION_Standard][0]->Remap[i] = 0x60 + (i&0xf);
680 		translationtables[TRANSLATION_Standard][1]->Remap[i] = 0x40 + (i&0xf);
681 		translationtables[TRANSLATION_Standard][2]->Remap[i] = 0x20 + (i&0xf);
682 
683 		translationtables[TRANSLATION_Standard][0]->Palette[i] = GPalette.BaseColors[0x60 + (i&0xf)] | MAKEARGB(255,0,0,0);
684 		translationtables[TRANSLATION_Standard][1]->Palette[i] = GPalette.BaseColors[0x40 + (i&0xf)] | MAKEARGB(255,0,0,0);
685 		translationtables[TRANSLATION_Standard][2]->Palette[i] = GPalette.BaseColors[0x20 + (i&0xf)] | MAKEARGB(255,0,0,0);
686 	}
687 
688 	// Create the ice translation table, based on Hexen's. Alas, the standard
689 	// Doom palette has no good substitutes for these bluish-tinted grays, so
690 	// they will just look gray unless you use a different PLAYPAL with Doom.
691 
692 	BYTE IcePaletteRemap[16];
693 	for (i = 0; i < 16; ++i)
694 	{
695 		IcePaletteRemap[i] = ColorMatcher.Pick (IcePalette[i][0], IcePalette[i][1], IcePalette[i][2]);
696 	}
697 	FRemapTable *remap = translationtables[TRANSLATION_Standard][7];
698 	for (i = 0; i < 256; ++i)
699 	{
700 		int r = GPalette.BaseColors[i].r;
701 		int g = GPalette.BaseColors[i].g;
702 		int b = GPalette.BaseColors[i].b;
703 		int v = (r*77 + g*143 + b*37) >> 12;
704 		remap->Remap[i] = IcePaletteRemap[v];
705 		remap->Palette[i] = PalEntry(255, IcePalette[v][0], IcePalette[v][1], IcePalette[v][2]);
706 	}
707 
708 	// set up shading tables for shaded columns
709 	// 16 colormap sets, progressing from full alpha to minimum visible alpha
710 
711 	/*BYTE *table = shadetables;
712 
713 	// Full alpha
714 	for (i = 0; i < 16; ++i)
715 	{
716 		ShadeFakeColormap[i].Color = ~0u;
717 		ShadeFakeColormap[i].Desaturate = ~0u;
718 		ShadeFakeColormap[i].Next = NULL;
719 		ShadeFakeColormap[i].Maps = table;
720 
721 		for (j = 0; j < NUMCOLORMAPS; ++j)
722 		{
723 			int a = (NUMCOLORMAPS - j) * 256 / NUMCOLORMAPS * (16-i);
724 			for (int k = 0; k < 256; ++k)
725 			{
726 				BYTE v = (((k+2) * a) + 256) >> 14;
727 				table[k] = MIN<BYTE> (v, 64);
728 			}
729 			table += 256;
730 		}
731 	}
732 	for (i = 0; i < NUMCOLORMAPS*16*256; ++i)
733 	{
734 		assert(shadetables[i] <= 64);
735 	}*/
736 
737 	// Set up a guaranteed identity map
738 	for (i = 0; i < 256; ++i)
739 	{
740 		identitymap[i] = i;
741 	}
742 }
743 
744 //----------------------------------------------------------------------------
745 //
746 //
747 //
748 //----------------------------------------------------------------------------
749 
R_DeinitTranslationTables()750 void R_DeinitTranslationTables()
751 {
752 	for (int i = 0; i < NUM_TRANSLATION_TABLES; ++i)
753 	{
754 		for (unsigned int j = 0; j < translationtables[i].Size(); ++j)
755 		{
756 			if (translationtables[i][j] != NULL)
757 			{
758 				delete translationtables[i][j];
759 				translationtables[i][j] = NULL;
760 			}
761 		}
762 		translationtables[i].Clear();
763 	}
764 	BloodTranslationColors.Clear();
765 }
766 
767 //----------------------------------------------------------------------------
768 //
769 // [RH] Create a player's translation table based on a given mid-range color.
770 // [GRB] Split to 2 functions (because of player setup menu)
771 //
772 //----------------------------------------------------------------------------
773 
SetRemap(FRemapTable * table,int i,float r,float g,float b)774 static void SetRemap(FRemapTable *table, int i, float r, float g, float b)
775 {
776 	int ir = clamp (int(r * 255.f), 0, 255);
777 	int ig = clamp (int(g * 255.f), 0, 255);
778 	int ib = clamp (int(b * 255.f), 0, 255);
779 	table->Remap[i] = ColorMatcher.Pick (ir, ig, ib);
780 	table->Palette[i] = PalEntry(255, ir, ig, ib);
781 }
782