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