1 // "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
2 // Ken Silverman's official web site: "http://www.advsys.net/ken"
3 // See the included license file "BUILDLIC.TXT" for license info.
4 //
5 // This file has been modified from Ken Silverman's original release
6 // by Jonathon Fowler (jf@jonof.id.au)
7 // by the EDuke32 team (development@voidpoint.com)
8 
9 #include "compat.h"
10 #include "build.h"
11 #include "engine_priv.h"
12 #include "baselayer.h"
13 #include "colmatch.h"
14 #include "cache1d.h"
15 #include "palette.h"
16 #include "a.h"
17 #include "xxhash.h"
18 
19 #include "vfs.h"
20 
21 uint8_t *basepaltable[MAXBASEPALS] = { palette };
22 uint8_t basepalreset=1;
23 uint8_t curbasepal;
24 int32_t globalblend;
25 
26 XXH64_hash_t g_lastpalettesum = 0;
27 palette_t curpalette[256];			// the current palette, unadjusted for brightness or tint
28 palette_t curpalettefaded[256];		// the current palette, adjusted for brightness and tint (ie. what gets sent to the card)
29 palette_t palfadergb = { 0, 0, 0, 0 };
30 char palfadedelta = 0;
31 
32 int32_t realmaxshade;
33 float frealmaxshade;
34 
35 #if defined(USE_OPENGL)
36 palette_t palookupfog[MAXPALOOKUPS];
37 float palookupfogfactor[MAXPALOOKUPS];
38 #endif
39 
40 // For every pal number, whether tsprite pal should not be taken over from
41 // floor pal.
42 // NOTE: g_noFloorPal[0] is irrelevant as it's never checked.
43 int8_t g_noFloorPal[MAXPALOOKUPS];
44 
45 int32_t curbrightness = 0, gammabrightness = 0;
46 
47 static void paletteSetFade(uint8_t offset);
48 
49 #ifdef USE_OPENGL
fullscreen_tint_gl(uint8_t r,uint8_t g,uint8_t b,uint8_t f)50 void fullscreen_tint_gl(uint8_t r, uint8_t g, uint8_t b, uint8_t f)
51 {
52     glMatrixMode(GL_PROJECTION);
53     glPushMatrix();
54     glLoadIdentity();
55     glMatrixMode(GL_MODELVIEW);
56     glPushMatrix();
57     glLoadIdentity();
58 
59     glDisable(GL_DEPTH_TEST);
60     glDisable(GL_ALPHA_TEST);
61     polymost_setFogEnabled(false);
62 
63     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
64     glEnable(GL_BLEND);
65     glColor4ub(r, g, b, f);
66 
67     polymost_useColorOnly(true);
68     glBegin(GL_TRIANGLES);
69     glVertex2f(-2.5f, 1.f);
70     glVertex2f(2.5f, 1.f);
71     glVertex2f(.0f, -2.5f);
72     glEnd();
73     polymost_useColorOnly(false);
74 
75     glPopMatrix();
76     glMatrixMode(GL_PROJECTION);
77     glPopMatrix();
78 }
79 
80 int32_t tint_blood_r = 0, tint_blood_g = 0, tint_blood_b = 0;
81 
fullscreen_tint_gl_blood(void)82 void fullscreen_tint_gl_blood(void)
83 {
84     if (!(tint_blood_r|tint_blood_g|tint_blood_b))
85         return;
86     glMatrixMode(GL_PROJECTION);
87     glPushMatrix();
88     glLoadIdentity();
89     glMatrixMode(GL_MODELVIEW);
90     glPushMatrix();
91     glLoadIdentity();
92 
93     glDisable(GL_DEPTH_TEST);
94     glDisable(GL_ALPHA_TEST);
95     polymost_setFogEnabled(false);
96 
97     glBlendFunc(GL_ONE, GL_ONE);
98     glEnable(GL_BLEND);
99 
100     polymost_useColorOnly(true);
101     glColor4ub(max(tint_blood_r, 0), max(tint_blood_g, 0), max(tint_blood_b, 0), 255);
102     glBegin(GL_TRIANGLES);
103     glVertex2f(-2.5f, 1.f);
104     glVertex2f(2.5f, 1.f);
105     glVertex2f(.0f, -2.5f);
106     glEnd();
107     glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
108     glColor4ub(max(-tint_blood_r, 0), max(-tint_blood_g, 0), max(-tint_blood_b, 0), 255);
109     glBegin(GL_TRIANGLES);
110     glVertex2f(-2.5f, 1.f);
111     glVertex2f(2.5f, 1.f);
112     glVertex2f(.0f, -2.5f);
113     glEnd();
114     glBlendEquation(GL_FUNC_ADD);
115     glColor4ub(0,0,0,0);
116     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
117     polymost_useColorOnly(false);
118 
119     glPopMatrix();
120     glMatrixMode(GL_PROJECTION);
121     glPopMatrix();
122 }
123 #endif
124 
videoFadeToBlack(int32_t moreopaquep)125 void videoFadeToBlack(int32_t moreopaquep)
126 {
127 #ifdef USE_OPENGL
128     if (videoGetRenderMode() >= REND_POLYMOST)
129         fullscreen_tint_gl(0, 0, 0, moreopaquep ? 168 : 84);
130     else
131 #endif
132     {
133         Bassert(!offscreenrendering);
134 
135         videoBeginDrawing();
136         char *const p = (char *) frameplace;
137         const char *const trans = paletteGetBlendTable(0);
138         const int32_t shiftamnt = ((!!moreopaquep)*8);
139         const int32_t dimprod = xdim*ydim;
140         int32_t i = 0;
141 
142 #ifdef CLASSIC_SLICE_BY_4
143         for (; i<dimprod-4; i+=4)
144         {
145             p[i] = trans[p[i]<<shiftamnt];
146             p[i+1] = trans[p[i+1]<<shiftamnt];
147             p[i+2] = trans[p[i+2]<<shiftamnt];
148             p[i+3] = trans[p[i+3]<<shiftamnt];
149         }
150 #endif
151 
152         for (; i<dimprod; i++)
153             p[i] = trans[p[i]<<shiftamnt];
154         videoEndDrawing();
155     }
156 }
157 
setup_blend(int32_t blend,int32_t doreverse)158 void setup_blend(int32_t blend, int32_t doreverse)
159 {
160     if (blendtable[blend] == NULL)
161         blend = 0;
162 
163     if (globalblend != blend)
164     {
165         globalblend = blend;
166         fixtransluscence(FP_OFF(paletteGetBlendTable(blend)));
167     }
168 
169     if (doreverse)
170         settransreverse();
171     else
172         settransnormal();
173 }
174 
alloc_palookup(int32_t pal)175 static void alloc_palookup(int32_t pal)
176 {
177     // The asm functions vlineasm1, mvlineasm1 (maybe others?) access the next
178     // palookup[...] shade entry for tilesizy==512 tiles.
179     // See DEBUG_TILESIZY_512 and the comment in a.nasm: vlineasm1.
180     palookup[pal] = (char *) Xaligned_alloc(16, (numshades + 1) * 256);
181     memset(palookup[pal], 0, (numshades + 1) * 256);
182 }
183 
184 static void maybe_alloc_palookup(int32_t palnum);
185 
186 void (*paletteLoadFromDisk_replace)(void) = NULL;
187 
188 //
189 // loadpalette (internal)
190 //
paletteLoadFromDisk(void)191 void paletteLoadFromDisk(void)
192 {
193     paletteInitClosestColorScale(30, 59, 11);
194     paletteInitClosestColorGrid();
195 
196 #ifdef USE_OPENGL
197     for (auto & x : glblend)
198         x = defaultglblend;
199 #endif
200 
201     if (paletteLoadFromDisk_replace)
202     {
203         paletteLoadFromDisk_replace();
204         return;
205     }
206 
207     buildvfs_kfd fil;
208     if ((fil = kopen4load("palette.dat", 0)) == buildvfs_kfd_invalid)
209         return;
210 
211 
212     // PALETTE_MAIN
213 
214     if (kread_and_test(fil, palette, 768))
215         return kclose(fil);
216 
217     for (unsigned char & k : palette)
218         k <<= 2;
219 
220     paletteInitClosestColorMap(palette);
221 
222     paletteloaded |= PALETTE_MAIN;
223 
224 
225     // PALETTE_SHADES
226 
227     // Auto-detect LameDuke. Its PALETTE.DAT doesn't have a 'numshades' 16-bit
228     // int after the base palette, but starts directly with the shade tables.
229     int lamedukep = 0;
230     if (kfilelength(fil) == 41600)
231     {
232         numshades = 32;
233         lamedukep = 1;
234     }
235     else
236     {
237         if (kread_and_test(fil, &numshades, 2))
238             return kclose(fil);
239         numshades = B_LITTLE16(numshades);
240 
241         if (numshades <= 1)
242         {
243             initprintf("Warning: Invalid number of shades in \"palette.dat\"!\n");
244             numshades = 0;
245             return kclose(fil);
246         }
247     }
248 
249     // Read base shade table (palookup 0).
250     maybe_alloc_palookup(0);
251     if (kread_and_test(fil, palookup[0], numshades<<8))
252         return kclose(fil);
253 
254     paletteloaded |= PALETTE_SHADE;
255 
256 
257     // PALETTE_TRANSLUC
258 
259     char * const transluc = blendtable[0] = (char *) Xcalloc(256, 256);
260 
261     // Read translucency (blending) table.
262     if (lamedukep)
263     {
264         for (bssize_t i=0; i<255; i++)
265         {
266             // NOTE: LameDuke's table doesn't have the last row or column (i==255).
267 
268             // Read the entries above and on the diagonal, if the table is
269             // thought as being row-major.
270             if (kread_and_test(fil, &transluc[256*i + i + 1], 255-i))
271                 return kclose(fil);
272 
273             // Duplicate the entries below the diagonal.
274             for (bssize_t j=i+1; j<256; j++)
275                 transluc[256*j + i] = transluc[256*i + j];
276         }
277         for (bssize_t i=0; i<256; i++)
278             transluc[256*i + i] = i;
279     }
280     else
281     {
282         if (kread_and_test(fil, transluc, 65536))
283             return kclose(fil);
284     }
285 
286     paletteloaded |= PALETTE_TRANSLUC;
287 
288 
289     // additional blending tables
290 
291     uint8_t magic[12];
292     if (!kread_and_test(fil, magic, sizeof(magic)) && !Bmemcmp(magic, "MoreBlendTab", sizeof(magic)))
293     {
294         uint8_t addblendtabs;
295         if (kread_and_test(fil, &addblendtabs, 1))
296         {
297             initprintf("Warning: failed reading additional blending table count\n");
298             return kclose(fil);
299         }
300 
301         uint8_t blendnum;
302         char *tab = (char *) Xmalloc(256*256);
303         for (bssize_t i=0; i<addblendtabs; i++)
304         {
305             if (kread_and_test(fil, &blendnum, 1))
306             {
307                 initprintf("Warning: failed reading additional blending table index\n");
308                 Xfree(tab);
309                 return kclose(fil);
310             }
311 
312             if (paletteGetBlendTable(blendnum) != NULL)
313                 initprintf("Warning: duplicate blending table index %3d encountered\n", blendnum);
314 
315             if (kread_and_test(fil, tab, 256*256))
316             {
317                 initprintf("Warning: failed reading additional blending table\n");
318                 Xfree(tab);
319                 return kclose(fil);
320             }
321 
322             paletteSetBlendTable(blendnum, tab);
323         }
324         Xfree(tab);
325 
326         // Read log2 of count of alpha blending tables.
327         uint8_t lognumalphatabs;
328         if (!kread_and_test(fil, &lognumalphatabs, 1))
329         {
330             if (!(lognumalphatabs >= 1 && lognumalphatabs <= 7))
331                 initprintf("invalid lognumalphatabs value, must be in [1 .. 7]\n");
332             else
333                 numalphatabs = 1<<lognumalphatabs;
334         }
335     }
336 
337     kclose(fil);
338 
339 #ifdef USE_OPENGL
340     for (int i = 0; i < MAXPALOOKUPS; i++)
341         palookupfogfactor[i] = 1.f;
342 #endif
343 }
344 
345 uint8_t PaletteIndexFullbrights[32];
346 
palettePostLoadTables(void)347 void palettePostLoadTables(void)
348 {
349     globalpal = 0;
350 
351     globalpalwritten = palookup[0];
352     setpalookupaddress(globalpalwritten);
353 
354     fixtransluscence(FP_OFF(blendtable[0]));
355 
356     char const * const palookup0 = palookup[0];
357 
358 #ifdef DEBUG_TILESIZY_512
359     // Bump shade 1 by 16.
360     for (bssize_t i=256; i<512; i++)
361         palookup0[i] = palookup0[i+(16<<8)];
362 #endif
363 
364     blackcol = paletteGetClosestColor(0, 0, 0);
365     whitecol = paletteGetClosestColor(255, 255, 255);
366     redcol = paletteGetClosestColor(255, 0, 0);
367 
368     // Bmemset(PaletteIndexFullbrights, 0, sizeof(PaletteIndexFullbrights));
369     if (!duke64)
370     for (bssize_t c = 0; c < 255; ++c) // skipping transparent color
371     {
372         uint8_t const index = palookup0[c];
373         rgb24_t const & color = *(rgb24_t *)&palette[index*3];
374 
375         // don't consider #000000 fullbright
376         if (EDUKE32_PREDICT_FALSE(color.r == 0 && color.g == 0 && color.b == 0))
377             continue;
378 
379         for (size_t s = c + 256, s_end = 256*numshades; s < s_end; s += 256)
380             if (EDUKE32_PREDICT_FALSE(palookup0[s] != index))
381                 goto PostLoad_NotFullbright;
382 
383         SetPaletteIndexFullbright(c);
384 
385         PostLoad_NotFullbright: ;
386     }
387 
388     if (realmaxshade == 0)
389     {
390         uint8_t const * const blackcolor = &palette[blackcol*3];
391         size_t s;
392         for (s = numshades < 2 ? 0 : numshades-2; s > 0; --s)
393         {
394             for (size_t c = s*256, c_end = c+255; c < c_end; ++c) // skipping transparent color
395             {
396                 uint8_t const index = palookup0[c];
397                 uint8_t const * const color = &palette[index*3];
398                 if (!IsPaletteIndexFullbright(index) && memcmp(blackcolor, color, sizeof(rgb24_t)))
399                     goto PostLoad_FoundShade;
400             }
401         }
402         PostLoad_FoundShade: ;
403         frealmaxshade = (float)(realmaxshade = s+1);
404     }
405 
406     for (size_t i = 0; i<256; i++)
407     {
408         if (editorcolorsdef[i])
409             continue;
410 
411         palette_t *edcol = (palette_t *) &vgapal16[4*i];
412         editorcolors[i] = paletteGetClosestColorWithBlacklist(edcol->b, edcol->g, edcol->r, 254, PaletteIndexFullbrights);
413     }
414 }
415 
paletteFixTranslucencyMask(void)416 void paletteFixTranslucencyMask(void)
417 {
418     for (auto thispalookup : palookup)
419     {
420         if (thispalookup == NULL)
421             continue;
422 
423         for (bssize_t j=0; j<numshades; j++)
424             thispalookup[(j<<8) + 255] = 255;
425     }
426 
427     // fix up translucency table so that transluc(255,x)
428     // and transluc(x,255) is black instead of purple.
429     for (auto transluc : blendtable)
430     {
431         if (transluc == NULL)
432             continue;
433 
434         for (bssize_t j=0; j<255; j++)
435         {
436             transluc[(255<<8) + j] = transluc[(blackcol<<8) + j];
437             transluc[255 + (j<<8)] = transluc[blackcol + (j<<8)];
438         }
439         transluc[(255<<8) + 255] = transluc[(blackcol<<8) + blackcol];
440     }
441 }
442 
443 // Load LOOKUP.DAT, which contains lookup tables and additional base palettes.
444 //
445 // <fp>: kopen4load file handle
446 //
447 // Returns:
448 //  - on success, 0
449 //  - on error, -1 (didn't read enough data)
450 //  - -2: error, we already wrote an error message ourselves
paletteLoadLookupTable(buildvfs_kfd fp)451 int32_t paletteLoadLookupTable(buildvfs_kfd fp)
452 {
453     uint8_t numlookups;
454     char remapbuf[256];
455 
456     if (kread_and_test(fp, &numlookups, 1))
457         return -1;
458 
459     for (bssize_t j=0; j<numlookups; j++)
460     {
461         uint8_t palnum;
462 
463         if (kread_and_test(fp, &palnum, 1))
464             return -1;
465 
466         if (palnum >= 256-RESERVEDPALS)
467         {
468             initprintf("ERROR: attempt to load lookup at reserved pal %d\n", palnum);
469             return -2;
470         }
471 
472         if (kread_and_test(fp, remapbuf, 256))
473             return -1;
474 
475         paletteMakeLookupTable(palnum, remapbuf, 0, 0, 0, 0);
476     }
477 
478     return 0;
479 }
480 
paletteSetupDefaultFog(void)481 void paletteSetupDefaultFog(void)
482 {
483     // Find a gap of four consecutive unused pal numbers to generate fog shade
484     // tables.
485     for (bssize_t j=1; j<=255-3; j++)
486         if (!palookup[j] && !palookup[j+1] && !palookup[j+2] && !palookup[j+3])
487         {
488             paletteMakeLookupTable(j, NULL, 60, 60, 60, 1);
489             paletteMakeLookupTable(j+1, NULL, 60, 0, 0, 1);
490             paletteMakeLookupTable(j+2, NULL, 0, 60, 0, 1);
491             paletteMakeLookupTable(j+3, NULL, 0, 0, 60, 1);
492 
493             break;
494         }
495 }
496 
palettePostLoadLookups(void)497 void palettePostLoadLookups(void)
498 {
499     // Alias remaining unused pal numbers to the base shade table.
500     for (bssize_t j=1; j<MAXPALOOKUPS; j++)
501     {
502         // If an existing lookup is identical to #0, free it.
503         if (palookup[j] && palookup[j] != palookup[0] && !Bmemcmp(palookup[0], palookup[j], 256*numshades))
504             paletteFreeLookupTable(j);
505 
506         if (!palookup[j])
507             paletteMakeLookupTable(j, NULL, 0, 0, 0, 1);
508     }
509 }
510 
palookup_isdefault(int32_t palnum)511 static int32_t palookup_isdefault(int32_t palnum)  // KEEPINSYNC engine.lua
512 {
513     return (palookup[palnum] == NULL || (palnum!=0 && palookup[palnum] == palookup[0]));
514 }
515 
maybe_alloc_palookup(int32_t palnum)516 static void maybe_alloc_palookup(int32_t palnum)
517 {
518     if (palookup_isdefault(palnum))
519     {
520         alloc_palookup(palnum);
521         if (palookup[palnum] == NULL)
522             fatal_exit("NULL palette!\n");
523     }
524 }
525 
paletteSetBlendTable(int32_t blend,const char * tab)526 void paletteSetBlendTable(int32_t blend, const char *tab)
527 {
528     if (blendtable[blend] == NULL)
529         blendtable[blend] = (char *) Xmalloc(256*256);
530 
531     Bmemcpy(blendtable[blend], tab, 256*256);
532 }
paletteFreeBlendTable(int32_t const blend)533 void paletteFreeBlendTable(int32_t const blend)
534 {
535     DO_FREE_AND_NULL(blendtable[blend]);
536 }
537 
538 #ifdef USE_OPENGL
539 glblend_t const nullglblend =
540 {
541     {
542         { 1.f, BLENDFACTOR_ONE, BLENDFACTOR_ZERO, 0 },
543         { 1.f, BLENDFACTOR_ONE, BLENDFACTOR_ZERO, 0 },
544     },
545 };
546 glblend_t const defaultglblend =
547 {
548     {
549         { 2.f/3.f, BLENDFACTOR_SRC_ALPHA, BLENDFACTOR_ONE_MINUS_SRC_ALPHA, 0 },
550         { 1.f/3.f, BLENDFACTOR_SRC_ALPHA, BLENDFACTOR_ONE_MINUS_SRC_ALPHA, 0 },
551     },
552 };
553 
554 glblend_t glblend[MAXBLENDTABS];
555 
handle_blend(uint8_t enable,uint8_t blend,uint8_t def)556 void handle_blend(uint8_t enable, uint8_t blend, uint8_t def)
557 {
558     static GLenum const blendFuncTokens[NUMBLENDFACTORS] =
559     {
560         GL_ZERO,
561         GL_ONE,
562         GL_SRC_COLOR,
563         GL_ONE_MINUS_SRC_COLOR,
564         GL_SRC_ALPHA,
565         GL_ONE_MINUS_SRC_ALPHA,
566         GL_DST_ALPHA,
567         GL_ONE_MINUS_DST_ALPHA,
568         GL_DST_COLOR,
569         GL_ONE_MINUS_DST_COLOR,
570     };
571 
572     if (!enable)
573     {
574         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
575         return;
576     }
577 
578     glblenddef_t const * const glbdef = glblend[blend].def + def;
579     glBlendFunc(blendFuncTokens[glbdef->src], blendFuncTokens[glbdef->dst]);
580 }
581 #endif
582 
paletteSetLookupTable(int32_t palnum,const uint8_t * shtab)583 int32_t paletteSetLookupTable(int32_t palnum, const uint8_t *shtab)
584 {
585     if (shtab != NULL)
586     {
587         maybe_alloc_palookup(palnum);
588         Bmemcpy(palookup[palnum], shtab, 256*numshades);
589     }
590 
591     return 0;
592 }
593 
paletteFreeLookupTable(int32_t const palnum)594 void paletteFreeLookupTable(int32_t const palnum)
595 {
596     if (palnum == 0 && palookup[palnum] != NULL)
597     {
598         for (bssize_t i = 1; i < MAXPALOOKUPS; i++)
599             if (palookup[i] == palookup[palnum])
600                 palookup[i] = NULL;
601 
602         ALIGNED_FREE_AND_NULL(palookup[palnum]);
603     }
604     else if (palookup[palnum] == palookup[0])
605         palookup[palnum] = NULL;
606     else
607         ALIGNED_FREE_AND_NULL(palookup[palnum]);
608 }
609 
610 //
611 // makepalookup
612 //
paletteMakeLookupTable(int32_t palnum,const char * remapbuf,uint8_t r,uint8_t g,uint8_t b,char noFloorPal)613 void paletteMakeLookupTable(int32_t palnum, const char *remapbuf, uint8_t r, uint8_t g, uint8_t b, char noFloorPal)
614 {
615     int32_t i, j;
616 
617     static char idmap[256] = { 1 };
618 
619     if (paletteloaded == 0)
620         return;
621 
622     // NOTE: palnum==0 is allowed
623     if ((unsigned) palnum >= MAXPALOOKUPS)
624         return;
625 
626     g_noFloorPal[palnum] = noFloorPal;
627 
628     if (remapbuf==NULL)
629     {
630         if ((r|g|b) == 0)
631         {
632             palookup[palnum] = palookup[0];  // Alias to base shade table!
633             return;
634         }
635 
636         if (idmap[0]==1)  // init identity map
637             for (i=0; i<256; i++)
638                 idmap[i] = i;
639 
640         remapbuf = idmap;
641     }
642 
643     maybe_alloc_palookup(palnum);
644 
645     if ((r|g|b) == 0)
646     {
647         // "black fog"/visibility case -- only remap color indices
648 
649         for (j=0; j<numshades; j++)
650             for (i=0; i<256; i++)
651             {
652                 const char *src = palookup[0];
653                 palookup[palnum][256*j + i] = src[256*j + remapbuf[i]];
654             }
655     }
656     else
657     {
658         // colored fog case
659 
660         char *ptr2 = palookup[palnum];
661 
662         for (i=0; i<numshades; i++)
663         {
664             int32_t palscale = divscale16(i, numshades-1);
665 
666             for (j=0; j<256; j++)
667             {
668                 const char *ptr = (const char *) &palette[remapbuf[j]*3];
669                 *ptr2++ = paletteGetClosestColor(ptr[0] + mulscale16(r-ptr[0], palscale),
670                     ptr[1] + mulscale16(g-ptr[1], palscale),
671                     ptr[2] + mulscale16(b-ptr[2], palscale));
672             }
673         }
674     }
675 
676 #if defined(USE_OPENGL)
677     palookupfog[palnum].r = r;
678     palookupfog[palnum].g = g;
679     palookupfog[palnum].b = b;
680 #endif
681 }
682 
683 //
684 // setbasepal
685 //
paletteSetColorTable(int32_t id,uint8_t const * const table)686 void paletteSetColorTable(int32_t id, uint8_t const * const table)
687 {
688     if (basepaltable[id] == NULL)
689         basepaltable[id] = (uint8_t *) Xmalloc(768);
690 
691     Bmemcpy(basepaltable[id], table, 768);
692 
693 #ifdef USE_OPENGL
694     if (videoGetRenderMode() >= REND_POLYMOST)
695     {
696         uploadbasepalette(id);
697     }
698 #endif
699 }
700 
paletteFreeColorTable(int32_t const id)701 void paletteFreeColorTable(int32_t const id)
702 {
703     if (id == 0)
704         Bmemset(basepaltable[id], 0, 768);
705     else
706         DO_FREE_AND_NULL(basepaltable[id]);
707 }
708 
709 //
710 // setbrightness
711 //
712 // flags:
713 //  1: don't setpalette(),  DON'T USE THIS FLAG!
714 //  2: don't gltexinvalidateall()
715 //  4: don't calc curbrightness from dabrightness,  DON'T USE THIS FLAG!
716 //  8: don't gltexinvalidate8()
717 // 16: don't reset palfade*
videoSetPalette(char dabrightness,uint8_t dapalid,uint8_t flags)718 void videoSetPalette(char dabrightness, uint8_t dapalid, uint8_t flags)
719 {
720     int32_t i, j;
721     const uint8_t *dapal;
722 
723 #ifdef USE_OPENGL
724     int32_t paldidchange;
725 #endif
726     int32_t palsumdidchange;
727     //    uint32_t lastbright = curbrightness;
728 
729     // Bassert((flags&4)==0); // What is so bad about this flag?
730 
731     if (/*(unsigned)dapalid >= MAXBASEPALS ||*/ basepaltable[dapalid] == NULL)
732         dapalid = 0;
733 #ifdef USE_OPENGL
734     paldidchange = (curbasepal != dapalid || basepalreset);
735 #endif
736     curbasepal = dapalid;
737     basepalreset = 0;
738 
739     dapal = basepaltable[curbasepal];
740 
741     if (!(flags&4))
742     {
743         curbrightness = clamp(dabrightness, 0, 15);
744         //        if (lastbright != (unsigned)curbrightness)
745         //            vid_gamma = 1.0 + ((float)curbrightness / 10.0);
746     }
747 
748     videoSetGamma();
749     j = (!gammabrightness || ((flags & 32) != 0 && videoGetRenderMode() != REND_POLYMOST))?curbrightness:0;
750 
751     for (i=0; i<256; i++)
752     {
753         // save palette without any brightness adjustment
754         curpalette[i].r = dapal[i*3+0];
755         curpalette[i].g = dapal[i*3+1];
756         curpalette[i].b = dapal[i*3+2];
757         curpalette[i].f = 0;
758 
759         // brightness adjust the palette
760         curpalettefaded[i].b = britable[j][curpalette[i].b];
761         curpalettefaded[i].g = britable[j][curpalette[i].g];
762         curpalettefaded[i].r = britable[j][curpalette[i].r];
763         curpalettefaded[i].f = 0;
764     }
765 
766 #ifdef USE_OPENGL
767     if ((flags & 32) != 0 && videoGetRenderMode() == REND_POLYMOST)
768         r_brightnesshack = curbrightness;
769     else
770         r_brightnesshack = 0;
771 #endif
772 
773     if ((flags&16) && palfadedelta)  // keep the fade
774         paletteSetFade(palfadedelta>>2);
775 
776     static XXH64_hash_t lastpalettesum=0;
777     XXH64_hash_t newpalettesum = XXH3_64bits((uint8_t *) curpalettefaded, sizeof(curpalettefaded));
778 
779     palsumdidchange = (newpalettesum != lastpalettesum);
780 
781     if (palsumdidchange || newpalettesum != g_lastpalettesum)
782     {
783         //            if ((flags&1) == 0)
784         videoUpdatePalette(0, 256);
785     }
786 
787     g_lastpalettesum = lastpalettesum = newpalettesum;
788 
789 #ifdef USE_OPENGL
790     if (videoGetRenderMode() >= REND_POLYMOST)
791     {
792         // Only reset the textures if the corresponding preserve flags are clear and
793         // either (a) the new palette is different to the last, or (b) the brightness
794         // changed and we couldn't set it using hardware gamma.
795 
796         // XXX: no-HW-gamma OpenGL platforms will exhibit bad performance with
797         // simultaneous basepal and tint changes?
798         const int32_t doinvalidate = (paldidchange || (palsumdidchange && !gammabrightness));
799 
800         if (!(flags&2) && doinvalidate)
801             gltexinvalidatetype(INVALIDATE_ALL_NON_INDEXED);
802         if (!(flags&8) && doinvalidate)
803             gltexinvalidatetype(INVALIDATE_ART_NON_INDEXED);
804 #ifdef POLYMER
805         if ((videoGetRenderMode() == REND_POLYMER) && doinvalidate)
806             polymer_texinvalidate();
807 #endif
808     }
809 #endif
810 
811     if ((flags&16)==0)
812     {
813         palfadergb.r = palfadergb.g = palfadergb.b = 0;
814         palfadedelta = 0;
815     }
816 }
817 
paletteGetColor(int32_t col)818 palette_t paletteGetColor(int32_t col)
819 {
820     if (!gammabrightness)
821     {
822         palette_t const p = { britable[curbrightness][curpalette[col].r], britable[curbrightness][curpalette[col].g],
823                               britable[curbrightness][curpalette[col].b], 0 };
824         return p;
825     }
826 
827     return curpalette[col];
828 }
829 
paletteSetFade(uint8_t offset)830 static void paletteSetFade(uint8_t offset)
831 {
832     for (native_t i=0; i<256; i++)
833     {
834         palette_t const p = paletteGetColor(i);
835 
836         curpalettefaded[i].b = p.b + (((palfadergb.b - p.b) * offset) >> 8);
837         curpalettefaded[i].g = p.g + (((palfadergb.g - p.g) * offset) >> 8);
838         curpalettefaded[i].r = p.r + (((palfadergb.r - p.r) * offset) >> 8);
839         curpalettefaded[i].f = 0;
840     }
841 }
842 
843 //#define DEBUG_PALETTEFADE
844 
845 //
846 // setpalettefade
847 //
videoFadePalette(uint8_t r,uint8_t g,uint8_t b,uint8_t offset)848 void videoFadePalette(uint8_t r, uint8_t g, uint8_t b, uint8_t offset)
849 {
850     palfadergb.r = r;
851     palfadergb.g = g;
852     palfadergb.b = b;
853 #ifdef DEBUG_PALETTEFADE
854     if (offset)
855         offset = max(offset, 128);
856 #endif
857     palfadedelta = offset;
858 
859     paletteSetFade(offset);
860 
861     static XXH64_hash_t lastpalettesum=0;
862     XXH64_hash_t newpalettesum = XXH3_64bits((uint8_t *) curpalettefaded, sizeof(curpalettefaded));
863 
864     if (newpalettesum != lastpalettesum || newpalettesum != g_lastpalettesum)
865     {
866         videoUpdatePalette(0, 256);
867     }
868 
869     g_lastpalettesum = lastpalettesum = newpalettesum;
870 }
871 
872 #ifdef USE_OPENGL
videoTintBlood(int32_t r,int32_t g,int32_t b)873 void videoTintBlood(int32_t r, int32_t g, int32_t b)
874 {
875     tint_blood_r = r;
876     tint_blood_g = g;
877     tint_blood_b = b;
878 }
879 #endif
880