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