1 // SONIC ROBO BLAST 2
2 //-----------------------------------------------------------------------------
3 // Copyright (C) 1993-1996 by id Software, Inc.
4 // Copyright (C) 1998-2000 by DooM Legacy Team.
5 // Copyright (C) 1999-2021 by Sonic Team Junior.
6 //
7 // This program is free software distributed under the
8 // terms of the GNU General Public License, version 2.
9 // See the 'LICENSE' file for more details.
10 //-----------------------------------------------------------------------------
11 /// \file r_draw.c
12 /// \brief span / column drawer functions, for 8bpp and 16bpp
13 /// All drawing to the view buffer is accomplished in this file.
14 /// The other refresh files only know about ccordinates,
15 /// not the architecture of the frame buffer.
16 /// The frame buffer is a linear one, and we need only the base address.
17
18 #include "doomdef.h"
19 #include "doomstat.h"
20 #include "r_local.h"
21 #include "st_stuff.h" // need ST_HEIGHT
22 #include "i_video.h"
23 #include "v_video.h"
24 #include "m_misc.h"
25 #include "w_wad.h"
26 #include "z_zone.h"
27 #include "console.h" // Until buffering gets finished
28
29 #ifdef HWRENDER
30 #include "hardware/hw_main.h"
31 #endif
32
33 // ==========================================================================
34 // COMMON DATA FOR 8bpp AND 16bpp
35 // ==========================================================================
36
37 /** \brief view info
38 */
39 INT32 viewwidth, scaledviewwidth, viewheight, viewwindowx, viewwindowy;
40
41 /** \brief pointer to the start of each line of the screen,
42 */
43 UINT8 *ylookup[MAXVIDHEIGHT*4];
44
45 /** \brief pointer to the start of each line of the screen, for view1 (splitscreen)
46 */
47 UINT8 *ylookup1[MAXVIDHEIGHT*4];
48
49 /** \brief pointer to the start of each line of the screen, for view2 (splitscreen)
50 */
51 UINT8 *ylookup2[MAXVIDHEIGHT*4];
52
53 /** \brief x byte offset for columns inside the viewwindow,
54 so the first column starts at (SCRWIDTH - VIEWWIDTH)/2
55 */
56 INT32 columnofs[MAXVIDWIDTH*4];
57
58 UINT8 *topleft;
59
60 // =========================================================================
61 // COLUMN DRAWING CODE STUFF
62 // =========================================================================
63
64 lighttable_t *dc_colormap;
65 INT32 dc_x = 0, dc_yl = 0, dc_yh = 0;
66
67 fixed_t dc_iscale, dc_texturemid;
68 UINT8 dc_hires; // under MSVC boolean is a byte, while on other systems, it a bit,
69 // soo lets make it a byte on all system for the ASM code
70 UINT8 *dc_source;
71
72 // -----------------------
73 // translucency stuff here
74 // -----------------------
75 #define NUMTRANSTABLES 9 // how many translucency tables are used
76
77 UINT8 *transtables; // translucency tables
78 UINT8 *blendtables[NUMBLENDMAPS];
79
80 /** \brief R_DrawTransColumn uses this
81 */
82 UINT8 *dc_transmap; // one of the translucency tables
83
84 // ----------------------
85 // translation stuff here
86 // ----------------------
87
88
89 /** \brief R_DrawTranslatedColumn uses this
90 */
91 UINT8 *dc_translation;
92
93 struct r_lightlist_s *dc_lightlist = NULL;
94 INT32 dc_numlights = 0, dc_maxlights, dc_texheight;
95
96 // =========================================================================
97 // SPAN DRAWING CODE STUFF
98 // =========================================================================
99
100 INT32 ds_y, ds_x1, ds_x2;
101 lighttable_t *ds_colormap;
102 lighttable_t *ds_translation; // Lactozilla: Sprite splat drawer
103
104 fixed_t ds_xfrac, ds_yfrac, ds_xstep, ds_ystep;
105 INT32 ds_waterofs, ds_bgofs;
106
107 UINT16 ds_flatwidth, ds_flatheight;
108 boolean ds_powersoftwo;
109
110 UINT8 *ds_source; // points to the start of a flat
111 UINT8 *ds_transmap; // one of the translucency tables
112
113 // Vectors for Software's tilted slope drawers
114 floatv3_t *ds_su, *ds_sv, *ds_sz;
115 floatv3_t *ds_sup, *ds_svp, *ds_szp;
116 float focallengthf, zeroheight;
117
118 /** \brief Variable flat sizes
119 */
120
121 UINT32 nflatxshift, nflatyshift, nflatshiftup, nflatmask;
122
123 // =========================================================================
124 // TRANSLATION COLORMAP CODE
125 // =========================================================================
126
127 #define DEFAULT_TT_CACHE_INDEX MAXSKINS
128 #define BOSS_TT_CACHE_INDEX (MAXSKINS + 1)
129 #define METALSONIC_TT_CACHE_INDEX (MAXSKINS + 2)
130 #define ALLWHITE_TT_CACHE_INDEX (MAXSKINS + 3)
131 #define RAINBOW_TT_CACHE_INDEX (MAXSKINS + 4)
132 #define BLINK_TT_CACHE_INDEX (MAXSKINS + 5)
133 #define DASHMODE_TT_CACHE_INDEX (MAXSKINS + 6)
134 #define DEFAULT_STARTTRANSCOLOR 96
135 #define NUM_PALETTE_ENTRIES 256
136
137 static UINT8 **translationtablecache[MAXSKINS + 7] = {NULL};
138 UINT8 skincolor_modified[MAXSKINCOLORS];
139
SkinToCacheIndex(INT32 skinnum)140 static INT32 SkinToCacheIndex(INT32 skinnum)
141 {
142 switch (skinnum)
143 {
144 case TC_DEFAULT: return DEFAULT_TT_CACHE_INDEX;
145 case TC_BOSS: return BOSS_TT_CACHE_INDEX;
146 case TC_METALSONIC: return METALSONIC_TT_CACHE_INDEX;
147 case TC_ALLWHITE: return ALLWHITE_TT_CACHE_INDEX;
148 case TC_RAINBOW: return RAINBOW_TT_CACHE_INDEX;
149 case TC_BLINK: return BLINK_TT_CACHE_INDEX;
150 case TC_DASHMODE: return DASHMODE_TT_CACHE_INDEX;
151 default: break;
152 }
153
154 return skinnum;
155 }
156
CacheIndexToSkin(INT32 ttc)157 static INT32 CacheIndexToSkin(INT32 ttc)
158 {
159 switch (ttc)
160 {
161 case DEFAULT_TT_CACHE_INDEX: return TC_DEFAULT;
162 case BOSS_TT_CACHE_INDEX: return TC_BOSS;
163 case METALSONIC_TT_CACHE_INDEX: return TC_METALSONIC;
164 case ALLWHITE_TT_CACHE_INDEX: return TC_ALLWHITE;
165 case RAINBOW_TT_CACHE_INDEX: return TC_RAINBOW;
166 case BLINK_TT_CACHE_INDEX: return TC_BLINK;
167 case DASHMODE_TT_CACHE_INDEX: return TC_DASHMODE;
168 default: break;
169 }
170
171 return ttc;
172 }
173
174 CV_PossibleValue_t Color_cons_t[MAXSKINCOLORS+1];
175
176 /** \brief Initializes the translucency tables used by the Software renderer.
177 */
R_InitTranslucencyTables(void)178 void R_InitTranslucencyTables(void)
179 {
180 // Load here the transparency lookup tables 'TRANSx0'
181 // NOTE: the TRANSx0 resources MUST BE aligned on 64k for the asm
182 // optimised code (in other words, transtables pointer low word is 0)
183 transtables = Z_MallocAlign(NUMTRANSTABLES*0x10000, PU_STATIC,
184 NULL, 16);
185
186 W_ReadLump(W_GetNumForName("TRANS10"), transtables);
187 W_ReadLump(W_GetNumForName("TRANS20"), transtables+0x10000);
188 W_ReadLump(W_GetNumForName("TRANS30"), transtables+0x20000);
189 W_ReadLump(W_GetNumForName("TRANS40"), transtables+0x30000);
190 W_ReadLump(W_GetNumForName("TRANS50"), transtables+0x40000);
191 W_ReadLump(W_GetNumForName("TRANS60"), transtables+0x50000);
192 W_ReadLump(W_GetNumForName("TRANS70"), transtables+0x60000);
193 W_ReadLump(W_GetNumForName("TRANS80"), transtables+0x70000);
194 W_ReadLump(W_GetNumForName("TRANS90"), transtables+0x80000);
195
196 R_GenerateBlendTables();
197 }
198
199 static colorlookup_t transtab_lut;
200
BlendTab_Translucent(UINT8 * table,int style,UINT8 blendamt)201 static void BlendTab_Translucent(UINT8 *table, int style, UINT8 blendamt)
202 {
203 INT16 bg, fg;
204
205 if (table == NULL)
206 I_Error("BlendTab_Translucent: input table was NULL!");
207
208 for (bg = 0; bg < 0xFF; bg++)
209 {
210 for (fg = 0; fg < 0xFF; fg++)
211 {
212 RGBA_t backrgba = V_GetMasterColor(bg);
213 RGBA_t frontrgba = V_GetMasterColor(fg);
214 RGBA_t result;
215
216 result.rgba = ASTBlendPixel(backrgba, frontrgba, style, 0xFF);
217 result.rgba = ASTBlendPixel(result, frontrgba, AST_TRANSLUCENT, blendamt);
218
219 table[((bg * 0x100) + fg)] = GetColorLUT(&transtab_lut, result.s.red, result.s.green, result.s.blue);
220 }
221 }
222 }
223
BlendTab_Subtractive(UINT8 * table,int style,UINT8 blendamt)224 static void BlendTab_Subtractive(UINT8 *table, int style, UINT8 blendamt)
225 {
226 INT16 bg, fg;
227
228 if (table == NULL)
229 I_Error("BlendTab_Subtractive: input table was NULL!");
230
231 if (blendamt == 0xFF)
232 {
233 memset(table, GetColorLUT(&transtab_lut, 0, 0, 0), 0x10000);
234 return;
235 }
236
237 for (bg = 0; bg < 0xFF; bg++)
238 {
239 for (fg = 0; fg < 0xFF; fg++)
240 {
241 RGBA_t backrgba = V_GetMasterColor(bg);
242 RGBA_t frontrgba = V_GetMasterColor(fg);
243 RGBA_t result;
244
245 result.rgba = ASTBlendPixel(backrgba, frontrgba, style, 0xFF);
246 result.s.red = max(0, result.s.red - blendamt);
247 result.s.green = max(0, result.s.green - blendamt);
248 result.s.blue = max(0, result.s.blue - blendamt);
249
250 table[((bg * 0x100) + fg)] = GetColorLUT(&transtab_lut, result.s.red, result.s.green, result.s.blue);
251 }
252 }
253 }
254
BlendTab_Modulative(UINT8 * table)255 static void BlendTab_Modulative(UINT8 *table)
256 {
257 INT16 bg, fg;
258
259 if (table == NULL)
260 I_Error("BlendTab_Modulative: input table was NULL!");
261
262 for (bg = 0; bg < 0xFF; bg++)
263 {
264 for (fg = 0; fg < 0xFF; fg++)
265 {
266 RGBA_t backrgba = V_GetMasterColor(bg);
267 RGBA_t frontrgba = V_GetMasterColor(fg);
268 RGBA_t result;
269 result.rgba = ASTBlendPixel(backrgba, frontrgba, AST_MODULATE, 0);
270 table[((bg * 0x100) + fg)] = GetColorLUT(&transtab_lut, result.s.red, result.s.green, result.s.blue);
271 }
272 }
273 }
274
275 static INT32 BlendTab_Count[NUMBLENDMAPS] =
276 {
277 NUMTRANSTABLES+1, // blendtab_add
278 NUMTRANSTABLES+1, // blendtab_subtract
279 NUMTRANSTABLES+1, // blendtab_reversesubtract
280 1 // blendtab_modulate
281 };
282
283 static INT32 BlendTab_FromStyle[] =
284 {
285 0, // AST_COPY
286 0, // AST_TRANSLUCENT
287 blendtab_add, // AST_ADD
288 blendtab_subtract, // AST_SUBTRACT
289 blendtab_reversesubtract, // AST_REVERSESUBTRACT
290 blendtab_modulate, // AST_MODULATE
291 0 // AST_OVERLAY
292 };
293
BlendTab_GenerateMaps(INT32 tab,INT32 style,void (* genfunc)(UINT8 *,int,UINT8))294 static void BlendTab_GenerateMaps(INT32 tab, INT32 style, void (*genfunc)(UINT8 *, int, UINT8))
295 {
296 INT32 i = 0, num = BlendTab_Count[tab];
297 const float amtmul = (256.0f / (float)(NUMTRANSTABLES + 1));
298 for (; i < num; i++)
299 {
300 const size_t offs = (0x10000 * i);
301 const UINT16 alpha = min(amtmul * i, 0xFF);
302 genfunc(blendtables[tab] + offs, style, alpha);
303 }
304 }
305
R_GenerateBlendTables(void)306 void R_GenerateBlendTables(void)
307 {
308 INT32 i;
309
310 for (i = 0; i < NUMBLENDMAPS; i++)
311 blendtables[i] = Z_MallocAlign(BlendTab_Count[i] * 0x10000, PU_STATIC, NULL, 16);
312
313 InitColorLUT(&transtab_lut, pMasterPalette, false);
314
315 // Additive
316 BlendTab_GenerateMaps(blendtab_add, AST_ADD, BlendTab_Translucent);
317
318 // Subtractive
319 #if 1
320 BlendTab_GenerateMaps(blendtab_subtract, AST_SUBTRACT, BlendTab_Subtractive);
321 #else
322 BlendTab_GenerateMaps(blendtab_subtract, AST_SUBTRACT, BlendTab_Translucent);
323 #endif
324
325 // Reverse subtractive
326 BlendTab_GenerateMaps(blendtab_reversesubtract, AST_REVERSESUBTRACT, BlendTab_Translucent);
327
328 // Modulative blending only requires a single table
329 BlendTab_Modulative(blendtables[blendtab_modulate]);
330 }
331
332 #define ClipBlendLevel(style, trans) max(min((trans), BlendTab_Count[BlendTab_FromStyle[style]]-1), 0)
333 #define ClipTransLevel(trans) max(min((trans), NUMTRANSMAPS-2), 0)
334
R_GetTranslucencyTable(INT32 alphalevel)335 UINT8 *R_GetTranslucencyTable(INT32 alphalevel)
336 {
337 return transtables + (ClipTransLevel(alphalevel-1) << FF_TRANSSHIFT);
338 }
339
R_GetBlendTable(int style,INT32 alphalevel)340 UINT8 *R_GetBlendTable(int style, INT32 alphalevel)
341 {
342 size_t offs;
343
344 if (style == AST_COPY || style == AST_OVERLAY)
345 return NULL;
346
347 offs = (ClipBlendLevel(style, alphalevel) << FF_TRANSSHIFT);
348
349 // Lactozilla: Returns the equivalent to AST_TRANSLUCENT
350 // if no alpha style matches any of the blend tables.
351 switch (style)
352 {
353 case AST_ADD:
354 return blendtables[blendtab_add] + offs;
355 case AST_SUBTRACT:
356 return blendtables[blendtab_subtract] + offs;
357 case AST_REVERSESUBTRACT:
358 return blendtables[blendtab_reversesubtract] + offs;
359 case AST_MODULATE:
360 return blendtables[blendtab_modulate];
361 default:
362 break;
363 }
364
365 // Return a normal translucency table
366 if (--alphalevel >= 0)
367 return transtables + (ClipTransLevel(alphalevel) << FF_TRANSSHIFT);
368 else
369 return NULL;
370 }
371
R_BlendLevelVisible(INT32 blendmode,INT32 alphalevel)372 boolean R_BlendLevelVisible(INT32 blendmode, INT32 alphalevel)
373 {
374 if (blendmode == AST_COPY || blendmode == AST_SUBTRACT || blendmode == AST_MODULATE || blendmode == AST_OVERLAY)
375 return true;
376
377 return (alphalevel < BlendTab_Count[BlendTab_FromStyle[blendmode]]);
378 }
379
380 // Define for getting accurate color brightness readings according to how the human eye sees them.
381 // https://en.wikipedia.org/wiki/Relative_luminance
382 // 0.2126 to red
383 // 0.7152 to green
384 // 0.0722 to blue
385 // (See this same define in hw_md2.c!)
386 #define SETBRIGHTNESS(brightness,r,g,b) \
387 brightness = (UINT8)(((1063*((UINT16)r)/5000) + (3576*((UINT16)g)/5000) + (361*((UINT16)b)/5000)) / 3)
388
389 /** \brief Generates the rainbow colourmaps that are used when a player has the invincibility power... stolen from kart, with permission
390
391 \param dest_colormap colormap to populate
392 \param skincolor translation color
393 */
R_RainbowColormap(UINT8 * dest_colormap,UINT16 skincolor)394 static void R_RainbowColormap(UINT8 *dest_colormap, UINT16 skincolor)
395 {
396 INT32 i;
397 RGBA_t color;
398 UINT8 brightness;
399 INT32 j;
400 UINT8 colorbrightnesses[16];
401 UINT16 brightdif;
402 INT32 temp;
403
404 // first generate the brightness of all the colours of that skincolour
405 for (i = 0; i < 16; i++)
406 {
407 color = V_GetColor(skincolors[skincolor].ramp[i]);
408 SETBRIGHTNESS(colorbrightnesses[i], color.s.red, color.s.green, color.s.blue);
409 }
410
411 // next, for every colour in the palette, choose the transcolor that has the closest brightness
412 for (i = 0; i < NUM_PALETTE_ENTRIES; i++)
413 {
414 if (i == 0 || i == 31) // pure black and pure white don't change
415 {
416 dest_colormap[i] = (UINT8)i;
417 continue;
418 }
419 color = V_GetColor(i);
420 SETBRIGHTNESS(brightness, color.s.red, color.s.green, color.s.blue);
421 brightdif = 256;
422 for (j = 0; j < 16; j++)
423 {
424 temp = abs((INT16)brightness - (INT16)colorbrightnesses[j]);
425 if (temp < brightdif)
426 {
427 brightdif = (UINT16)temp;
428 dest_colormap[i] = skincolors[skincolor].ramp[j];
429 }
430 }
431 }
432 }
433
434 #undef SETBRIGHTNESS
435
436 /** \brief Generates a translation colormap.
437
438 \param dest_colormap colormap to populate
439 \param skinnum skin number, or a translation mode
440 \param color translation color
441
442 \return void
443 */
R_GenerateTranslationColormap(UINT8 * dest_colormap,INT32 skinnum,UINT16 color)444 static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, UINT16 color)
445 {
446 INT32 i, starttranscolor, skinramplength;
447
448 // Handle a couple of simple special cases
449 if (skinnum < TC_DEFAULT)
450 {
451 switch (skinnum)
452 {
453 case TC_ALLWHITE:
454 memset(dest_colormap, 0, NUM_PALETTE_ENTRIES * sizeof(UINT8));
455 return;
456 case TC_RAINBOW:
457 if (color >= numskincolors)
458 I_Error("Invalid skin color #%hu.", (UINT16)color);
459 if (color != SKINCOLOR_NONE)
460 {
461 R_RainbowColormap(dest_colormap, color);
462 return;
463 }
464 break;
465 case TC_BLINK:
466 if (color >= numskincolors)
467 I_Error("Invalid skin color #%hu.", (UINT16)color);
468 if (color != SKINCOLOR_NONE)
469 {
470 memset(dest_colormap, skincolors[color].ramp[3], NUM_PALETTE_ENTRIES * sizeof(UINT8));
471 return;
472 }
473 break;
474 default:
475 break;
476 }
477
478 for (i = 0; i < NUM_PALETTE_ENTRIES; i++)
479 dest_colormap[i] = (UINT8)i;
480
481 // White!
482 if (skinnum == TC_BOSS)
483 {
484 for (i = 0; i < 16; i++)
485 dest_colormap[31-i] = i;
486 }
487 else if (skinnum == TC_METALSONIC)
488 {
489 for (i = 0; i < 6; i++)
490 {
491 dest_colormap[skincolors[SKINCOLOR_BLUE].ramp[12-i]] = skincolors[SKINCOLOR_BLUE].ramp[i];
492 }
493 dest_colormap[159] = dest_colormap[253] = dest_colormap[254] = 0;
494 for (i = 0; i < 16; i++)
495 dest_colormap[96+i] = dest_colormap[skincolors[SKINCOLOR_COBALT].ramp[i]];
496 }
497 else if (skinnum == TC_DASHMODE) // This is a long one, because MotorRoach basically hand-picked the indices
498 {
499 // greens -> ketchups
500 dest_colormap[96] = dest_colormap[97] = 48;
501 dest_colormap[98] = 49;
502 dest_colormap[99] = 51;
503 dest_colormap[100] = 52;
504 dest_colormap[101] = dest_colormap[102] = 54;
505 dest_colormap[103] = 34;
506 dest_colormap[104] = 37;
507 dest_colormap[105] = 39;
508 dest_colormap[106] = 41;
509 for (i = 0; i < 5; i++)
510 dest_colormap[107 + i] = 43 + i;
511
512 // reds -> steel blues
513 dest_colormap[32] = 146;
514 dest_colormap[33] = 147;
515 dest_colormap[34] = dest_colormap[35] = 170;
516 dest_colormap[36] = 171;
517 dest_colormap[37] = dest_colormap[38] = 172;
518 dest_colormap[39] = dest_colormap[40] = dest_colormap[41] = 173;
519 dest_colormap[42] = dest_colormap[43] = dest_colormap[44] = 174;
520 dest_colormap[45] = dest_colormap[46] = dest_colormap[47] = 175;
521 dest_colormap[71] = 139;
522
523 // steel blues -> oranges
524 dest_colormap[170] = 52;
525 dest_colormap[171] = 54;
526 dest_colormap[172] = 56;
527 dest_colormap[173] = 42;
528 dest_colormap[174] = 45;
529 dest_colormap[175] = 47;
530 }
531 return;
532 }
533 else if (color == SKINCOLOR_NONE)
534 {
535 for (i = 0; i < NUM_PALETTE_ENTRIES; i++)
536 dest_colormap[i] = (UINT8)i;
537 return;
538 }
539
540 if (color >= numskincolors)
541 I_Error("Invalid skin color #%hu.", (UINT16)color);
542
543 if (skinnum < 0 && skinnum > TC_DEFAULT)
544 I_Error("Invalid translation colormap index %d.", skinnum);
545
546 starttranscolor = (skinnum != TC_DEFAULT) ? skins[skinnum].starttranscolor : DEFAULT_STARTTRANSCOLOR;
547
548 if (starttranscolor >= NUM_PALETTE_ENTRIES)
549 I_Error("Invalid startcolor #%d.", starttranscolor);
550
551 // Fill in the entries of the palette that are fixed
552 for (i = 0; i < starttranscolor; i++)
553 dest_colormap[i] = (UINT8)i;
554
555 i = starttranscolor + 16;
556 if (i < NUM_PALETTE_ENTRIES)
557 {
558 for (i = (UINT8)i; i < NUM_PALETTE_ENTRIES; i++)
559 dest_colormap[i] = (UINT8)i;
560 skinramplength = 16;
561 }
562 else
563 skinramplength = i - NUM_PALETTE_ENTRIES; // shouldn't this be NUM_PALETTE_ENTRIES - starttranscolor?
564
565 // Build the translated ramp
566 for (i = 0; i < skinramplength; i++)
567 dest_colormap[starttranscolor + i] = (UINT8)skincolors[color].ramp[i];
568 }
569
570
571 /** \brief Retrieves a translation colormap from the cache.
572
573 \param skinnum number of skin, TC_DEFAULT or TC_BOSS
574 \param color translation color
575 \param flags set GTC_CACHE to use the cache
576
577 \return Colormap. If not cached, caller should Z_Free.
578 */
R_GetTranslationColormap(INT32 skinnum,skincolornum_t color,UINT8 flags)579 UINT8* R_GetTranslationColormap(INT32 skinnum, skincolornum_t color, UINT8 flags)
580 {
581 UINT8* ret;
582 INT32 skintableindex = SkinToCacheIndex(skinnum); // Adjust if we want the default colormap
583 INT32 i;
584
585 if (flags & GTC_CACHE)
586 {
587 // Allocate table for skin if necessary
588 if (!translationtablecache[skintableindex])
589 translationtablecache[skintableindex] = Z_Calloc(MAXSKINCOLORS * sizeof(UINT8**), PU_STATIC, NULL);
590
591 // Get colormap
592 ret = translationtablecache[skintableindex][color];
593
594 // Rebuild the cache if necessary
595 if (skincolor_modified[color])
596 {
597 for (i = 0; i < (INT32)(sizeof(translationtablecache) / sizeof(translationtablecache[0])); i++)
598 if (translationtablecache[i] && translationtablecache[i][color])
599 R_GenerateTranslationColormap(translationtablecache[i][color], CacheIndexToSkin(i), color);
600
601 skincolor_modified[color] = false;
602 }
603 }
604 else ret = NULL;
605
606 // Generate the colormap if necessary
607 if (!ret)
608 {
609 ret = Z_MallocAlign(NUM_PALETTE_ENTRIES, (flags & GTC_CACHE) ? PU_LEVEL : PU_STATIC, NULL, 8);
610 R_GenerateTranslationColormap(ret, skinnum, color);
611
612 // Cache the colormap if desired
613 if (flags & GTC_CACHE)
614 translationtablecache[skintableindex][color] = ret;
615 }
616
617 return ret;
618 }
619
620 /** \brief Flushes cache of translation colormaps.
621
622 Flushes cache of translation colormaps, but doesn't actually free the
623 colormaps themselves. These are freed when PU_LEVEL blocks are purged,
624 at or before which point, this function should be called.
625
626 \return void
627 */
R_FlushTranslationColormapCache(void)628 void R_FlushTranslationColormapCache(void)
629 {
630 INT32 i;
631
632 for (i = 0; i < (INT32)(sizeof(translationtablecache) / sizeof(translationtablecache[0])); i++)
633 if (translationtablecache[i])
634 memset(translationtablecache[i], 0, MAXSKINCOLORS * sizeof(UINT8**));
635 }
636
R_GetColorByName(const char * name)637 UINT16 R_GetColorByName(const char *name)
638 {
639 UINT16 color = (UINT16)atoi(name);
640 if (color > 0 && color < numskincolors)
641 return color;
642 for (color = 1; color < numskincolors; color++)
643 if (!stricmp(skincolors[color].name, name))
644 return color;
645 return SKINCOLOR_NONE;
646 }
647
R_GetSuperColorByName(const char * name)648 UINT16 R_GetSuperColorByName(const char *name)
649 {
650 UINT16 i, color = SKINCOLOR_NONE;
651 char *realname = Z_Malloc(MAXCOLORNAME+1, PU_STATIC, NULL);
652 snprintf(realname, MAXCOLORNAME+1, "Super %s 1", name);
653 for (i = 1; i < numskincolors; i++)
654 if (!stricmp(skincolors[i].name, realname)) {
655 color = i;
656 break;
657 }
658 Z_Free(realname);
659 return color;
660 }
661
662 // ==========================================================================
663 // COMMON DRAWER FOR 8 AND 16 BIT COLOR MODES
664 // ==========================================================================
665
666 // in a perfect world, all routines would be compatible for either mode,
667 // and optimised enough
668 //
669 // in reality, the few routines that can work for either mode, are
670 // put here
671
672 /** \brief The R_InitViewBuffer function
673
674 Creates lookup tables for getting the framebuffer address
675 of a pixel to draw.
676
677 \param width witdh of buffer
678 \param height hieght of buffer
679
680 \return void
681
682
683 */
684
R_InitViewBuffer(INT32 width,INT32 height)685 void R_InitViewBuffer(INT32 width, INT32 height)
686 {
687 INT32 i, bytesperpixel = vid.bpp;
688
689 if (width > MAXVIDWIDTH)
690 width = MAXVIDWIDTH;
691 if (height > MAXVIDHEIGHT)
692 height = MAXVIDHEIGHT;
693 if (bytesperpixel < 1 || bytesperpixel > 4)
694 I_Error("R_InitViewBuffer: wrong bytesperpixel value %d\n", bytesperpixel);
695
696 // Handle resize, e.g. smaller view windows with border and/or status bar.
697 viewwindowx = (vid.width - width) >> 1;
698
699 // Column offset for those columns of the view window, but relative to the entire screen
700 for (i = 0; i < width; i++)
701 columnofs[i] = (viewwindowx + i) * bytesperpixel;
702
703 // Same with base row offset.
704 if (width == vid.width)
705 viewwindowy = 0;
706 else
707 viewwindowy = (vid.height - height) >> 1;
708
709 // Precalculate all row offsets.
710 for (i = 0; i < height; i++)
711 {
712 ylookup[i] = ylookup1[i] = screens[0] + (i+viewwindowy)*vid.width*bytesperpixel;
713 ylookup2[i] = screens[0] + (i+(vid.height>>1))*vid.width*bytesperpixel; // for splitscreen
714 }
715 }
716
717 /** \brief viewborder patches lump numbers
718 */
719 lumpnum_t viewborderlump[8];
720
721 /** \brief Store the lumpnumber of the viewborder patches
722 */
723
R_InitViewBorder(void)724 void R_InitViewBorder(void)
725 {
726 viewborderlump[BRDR_T] = W_GetNumForName("brdr_t");
727 viewborderlump[BRDR_B] = W_GetNumForName("brdr_b");
728 viewborderlump[BRDR_L] = W_GetNumForName("brdr_l");
729 viewborderlump[BRDR_R] = W_GetNumForName("brdr_r");
730 viewborderlump[BRDR_TL] = W_GetNumForName("brdr_tl");
731 viewborderlump[BRDR_BL] = W_GetNumForName("brdr_bl");
732 viewborderlump[BRDR_TR] = W_GetNumForName("brdr_tr");
733 viewborderlump[BRDR_BR] = W_GetNumForName("brdr_br");
734 }
735
736 #if 0
737 /** \brief R_FillBackScreen
738
739 Fills the back screen with a pattern for variable screen sizes
740 Also draws a beveled edge.
741 */
742 void R_FillBackScreen(void)
743 {
744 UINT8 *src, *dest;
745 patch_t *patch;
746 INT32 x, y, step, boff;
747
748 // quickfix, don't cache lumps in both modes
749 if (rendermode != render_soft)
750 return;
751
752 // draw pattern around the status bar too (when hires),
753 // so return only when in full-screen without status bar.
754 if (scaledviewwidth == vid.width && viewheight == vid.height)
755 return;
756
757 src = scr_borderpatch;
758 dest = screens[1];
759
760 for (y = 0; y < vid.height; y++)
761 {
762 for (x = 0; x < vid.width/128; x++)
763 {
764 M_Memcpy (dest, src+((y&127)<<7), 128);
765 dest += 128;
766 }
767
768 if (vid.width&127)
769 {
770 M_Memcpy(dest, src+((y&127)<<7), vid.width&127);
771 dest += (vid.width&127);
772 }
773 }
774
775 // don't draw the borders when viewwidth is full vid.width.
776 if (scaledviewwidth == vid.width)
777 return;
778
779 step = 8;
780 boff = 8;
781
782 patch = W_CacheLumpNum(viewborderlump[BRDR_T], PU_CACHE);
783 for (x = 0; x < scaledviewwidth; x += step)
784 V_DrawPatch(viewwindowx + x, viewwindowy - boff, 1, patch);
785
786 patch = W_CacheLumpNum(viewborderlump[BRDR_B], PU_CACHE);
787 for (x = 0; x < scaledviewwidth; x += step)
788 V_DrawPatch(viewwindowx + x, viewwindowy + viewheight, 1, patch);
789
790 patch = W_CacheLumpNum(viewborderlump[BRDR_L], PU_CACHE);
791 for (y = 0; y < viewheight; y += step)
792 V_DrawPatch(viewwindowx - boff, viewwindowy + y, 1, patch);
793
794 patch = W_CacheLumpNum(viewborderlump[BRDR_R],PU_CACHE);
795 for (y = 0; y < viewheight; y += step)
796 V_DrawPatch(viewwindowx + scaledviewwidth, viewwindowy + y, 1,
797 patch);
798
799 // Draw beveled corners.
800 V_DrawPatch(viewwindowx - boff, viewwindowy - boff, 1,
801 W_CacheLumpNum(viewborderlump[BRDR_TL], PU_CACHE));
802 V_DrawPatch(viewwindowx + scaledviewwidth, viewwindowy - boff, 1,
803 W_CacheLumpNum(viewborderlump[BRDR_TR], PU_CACHE));
804 V_DrawPatch(viewwindowx - boff, viewwindowy + viewheight, 1,
805 W_CacheLumpNum(viewborderlump[BRDR_BL], PU_CACHE));
806 V_DrawPatch(viewwindowx + scaledviewwidth, viewwindowy + viewheight, 1,
807 W_CacheLumpNum(viewborderlump[BRDR_BR], PU_CACHE));
808 }
809 #endif
810
811 /** \brief The R_VideoErase function
812
813 Copy a screen buffer.
814
815 \param ofs offest from buffer
816 \param count bytes to erase
817
818 \return void
819
820
821 */
R_VideoErase(size_t ofs,INT32 count)822 void R_VideoErase(size_t ofs, INT32 count)
823 {
824 // LFB copy.
825 // This might not be a good idea if memcpy
826 // is not optimal, e.g. byte by byte on
827 // a 32bit CPU, as GNU GCC/Linux libc did
828 // at one point.
829 M_Memcpy(screens[0] + ofs, screens[1] + ofs, count);
830 }
831
832 #if 0
833 /** \brief The R_DrawViewBorder
834
835 Draws the border around the view
836 for different size windows?
837 */
838 void R_DrawViewBorder(void)
839 {
840 INT32 top, side, ofs;
841
842 if (rendermode == render_none)
843 return;
844 #ifdef HWRENDER
845 if (rendermode != render_soft)
846 {
847 HWR_DrawViewBorder(0);
848 return;
849 }
850 else
851 #endif
852
853 #ifdef DEBUG
854 fprintf(stderr,"RDVB: vidwidth %d vidheight %d scaledviewwidth %d viewheight %d\n",
855 vid.width, vid.height, scaledviewwidth, viewheight);
856 #endif
857
858 if (scaledviewwidth == vid.width)
859 return;
860
861 top = (vid.height - viewheight)>>1;
862 side = (vid.width - scaledviewwidth)>>1;
863
864 // copy top and one line of left side
865 R_VideoErase(0, top*vid.width+side);
866
867 // copy one line of right side and bottom
868 ofs = (viewheight+top)*vid.width - side;
869 R_VideoErase(ofs, top*vid.width + side);
870
871 // copy sides using wraparound
872 ofs = top*vid.width + vid.width-side;
873 side <<= 1;
874
875 // simpler using our VID_Blit routine
876 VID_BlitLinearScreen(screens[1] + ofs, screens[0] + ofs, side, viewheight - 1,
877 vid.width, vid.width);
878 }
879 #endif
880
881 // ==========================================================================
882 // INCLUDE 8bpp DRAWING CODE HERE
883 // ==========================================================================
884
885 #include "r_draw8.c"
886 #include "r_draw8_npo2.c"
887
888 // ==========================================================================
889 // INCLUDE 16bpp DRAWING CODE HERE
890 // ==========================================================================
891
892 #ifdef HIGHCOLOR
893 #include "r_draw16.c"
894 #endif
895