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-2020 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 v_video.c
12 /// \brief Gamma correction LUT stuff
13 /// Functions to draw patches (by post) directly to screen.
14 /// Functions to blit a block to the screen.
15
16 #include "doomdef.h"
17 #include "r_local.h"
18 #include "p_local.h" // stplyr
19 #include "g_game.h" // players
20 #include "v_video.h"
21 #include "st_stuff.h"
22 #include "hu_stuff.h"
23 #include "f_finale.h"
24 #include "r_draw.h"
25 #include "console.h"
26
27 #include "i_video.h" // rendermode
28 #include "z_zone.h"
29 #include "m_misc.h"
30 #include "m_random.h"
31 #include "doomstat.h"
32
33 #ifdef HWRENDER
34 #include "hardware/hw_glob.h"
35 #endif
36
37 // Each screen is [vid.width*vid.height];
38 UINT8 *screens[5];
39 // screens[0] = main display window
40 // screens[1] = back screen, alternative blitting
41 // screens[2] = screenshot buffer, gif movie buffer
42 // screens[3] = fade screen start
43 // screens[4] = fade screen end, postimage tempoarary buffer
44
45 static CV_PossibleValue_t ticrate_cons_t[] = {{0, "No"}, {1, "Full"}, {2, "Compact"}, {0, NULL}};
46 consvar_t cv_ticrate = CVAR_INIT ("showfps", "No", CV_SAVE, ticrate_cons_t, NULL);
47
48 static void CV_palette_OnChange(void);
49
50 static CV_PossibleValue_t gamma_cons_t[] = {{-15, "MIN"}, {5, "MAX"}, {0, NULL}};
51 consvar_t cv_globalgamma = CVAR_INIT ("gamma", "0", CV_SAVE|CV_CALL, gamma_cons_t, CV_palette_OnChange);
52
53 static CV_PossibleValue_t saturation_cons_t[] = {{0, "MIN"}, {10, "MAX"}, {0, NULL}};
54 consvar_t cv_globalsaturation = CVAR_INIT ("saturation", "10", CV_SAVE|CV_CALL, saturation_cons_t, CV_palette_OnChange);
55
56 #define huecoloursteps 4
57
58 static CV_PossibleValue_t hue_cons_t[] = {{0, "MIN"}, {(huecoloursteps*6)-1, "MAX"}, {0, NULL}};
59 consvar_t cv_rhue = CVAR_INIT ("rhue", "0", CV_SAVE|CV_CALL, hue_cons_t, CV_palette_OnChange);
60 consvar_t cv_yhue = CVAR_INIT ("yhue", "4", CV_SAVE|CV_CALL, hue_cons_t, CV_palette_OnChange);
61 consvar_t cv_ghue = CVAR_INIT ("ghue", "8", CV_SAVE|CV_CALL, hue_cons_t, CV_palette_OnChange);
62 consvar_t cv_chue = CVAR_INIT ("chue", "12", CV_SAVE|CV_CALL, hue_cons_t, CV_palette_OnChange);
63 consvar_t cv_bhue = CVAR_INIT ("bhue", "16", CV_SAVE|CV_CALL, hue_cons_t, CV_palette_OnChange);
64 consvar_t cv_mhue = CVAR_INIT ("mhue", "20", CV_SAVE|CV_CALL, hue_cons_t, CV_palette_OnChange);
65
66 consvar_t cv_rgamma = CVAR_INIT ("rgamma", "0", CV_SAVE|CV_CALL, gamma_cons_t, CV_palette_OnChange);
67 consvar_t cv_ygamma = CVAR_INIT ("ygamma", "0", CV_SAVE|CV_CALL, gamma_cons_t, CV_palette_OnChange);
68 consvar_t cv_ggamma = CVAR_INIT ("ggamma", "0", CV_SAVE|CV_CALL, gamma_cons_t, CV_palette_OnChange);
69 consvar_t cv_cgamma = CVAR_INIT ("cgamma", "0", CV_SAVE|CV_CALL, gamma_cons_t, CV_palette_OnChange);
70 consvar_t cv_bgamma = CVAR_INIT ("bgamma", "0", CV_SAVE|CV_CALL, gamma_cons_t, CV_palette_OnChange);
71 consvar_t cv_mgamma = CVAR_INIT ("mgamma", "0", CV_SAVE|CV_CALL, gamma_cons_t, CV_palette_OnChange);
72
73 consvar_t cv_rsaturation = CVAR_INIT ("rsaturation", "10", CV_SAVE|CV_CALL, saturation_cons_t, CV_palette_OnChange);
74 consvar_t cv_ysaturation = CVAR_INIT ("ysaturation", "10", CV_SAVE|CV_CALL, saturation_cons_t, CV_palette_OnChange);
75 consvar_t cv_gsaturation = CVAR_INIT ("gsaturation", "10", CV_SAVE|CV_CALL, saturation_cons_t, CV_palette_OnChange);
76 consvar_t cv_csaturation = CVAR_INIT ("csaturation", "10", CV_SAVE|CV_CALL, saturation_cons_t, CV_palette_OnChange);
77 consvar_t cv_bsaturation = CVAR_INIT ("bsaturation", "10", CV_SAVE|CV_CALL, saturation_cons_t, CV_palette_OnChange);
78 consvar_t cv_msaturation = CVAR_INIT ("msaturation", "10", CV_SAVE|CV_CALL, saturation_cons_t, CV_palette_OnChange);
79
80 static CV_PossibleValue_t constextsize_cons_t[] = {
81 {V_NOSCALEPATCH, "Small"}, {V_SMALLSCALEPATCH, "Medium"}, {V_MEDSCALEPATCH, "Large"}, {0, "Huge"},
82 {0, NULL}};
83 static void CV_constextsize_OnChange(void);
84 consvar_t cv_constextsize = CVAR_INIT ("con_textsize", "Medium", CV_SAVE|CV_CALL, constextsize_cons_t, CV_constextsize_OnChange);
85
86 // local copy of the palette for V_GetColor()
87 RGBA_t *pLocalPalette = NULL;
88 RGBA_t *pMasterPalette = NULL;
89
90 /*
91 The following was an extremely helpful resource when developing my Colour Cube LUT.
92 http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter24.html
93 Please check it out if you're trying to maintain this.
94 toast 18/04/17
95 */
96 float Cubepal[2][2][2][3];
97 boolean Cubeapply = false;
98
99 // returns whether to apply cube, selectively avoiding expensive operations
InitCube(void)100 static boolean InitCube(void)
101 {
102 boolean apply = false;
103 UINT8 q;
104 float working[2][2][2][3] = // the initial positions of the corners of the colour cube!
105 {
106 {
107 {
108 {0.0, 0.0, 0.0}, // black corner
109 {0.0, 0.0, 1.0} // blue corner
110 },
111 {
112 {0.0, 1.0, 0.0}, // green corner
113 {0.0, 1.0, 1.0} // cyan corner
114 }
115 },
116 {
117 {
118 {1.0, 0.0, 0.0}, // red corner
119 {1.0, 0.0, 1.0} // magenta corner
120 },
121 {
122 {1.0, 1.0, 0.0}, // yellow corner
123 {1.0, 1.0, 1.0} // white corner
124 }
125 }
126 };
127 float desatur[3]; // grey
128 float globalgammamul, globalgammaoffs;
129 boolean doinggamma;
130
131 #define diffcons(cv) (cv.value != atoi(cv.defaultvalue))
132
133 doinggamma = diffcons(cv_globalgamma);
134
135 #define gammascale 8
136 globalgammamul = (cv_globalgamma.value ? ((255 - (gammascale*abs(cv_globalgamma.value)))/255.0) : 1.0);
137 globalgammaoffs = ((cv_globalgamma.value > 0) ? ((gammascale*cv_globalgamma.value)/255.0) : 0.0);
138 desatur[0] = desatur[1] = desatur[2] = globalgammaoffs + (0.33*globalgammamul);
139
140 if (doinggamma
141 || diffcons(cv_rhue)
142 || diffcons(cv_yhue)
143 || diffcons(cv_ghue)
144 || diffcons(cv_chue)
145 || diffcons(cv_bhue)
146 || diffcons(cv_mhue)
147 || diffcons(cv_rgamma)
148 || diffcons(cv_ygamma)
149 || diffcons(cv_ggamma)
150 || diffcons(cv_cgamma)
151 || diffcons(cv_bgamma)
152 || diffcons(cv_mgamma)) // set the gamma'd/hued positions (saturation is done later)
153 {
154 float mod, tempgammamul, tempgammaoffs;
155
156 apply = true;
157
158 working[0][0][0][0] = working[0][0][0][1] = working[0][0][0][2] = globalgammaoffs;
159 working[1][1][1][0] = working[1][1][1][1] = working[1][1][1][2] = globalgammaoffs+globalgammamul;
160
161 #define dohue(hue, gamma, loc) \
162 tempgammamul = (gamma ? ((255 - (gammascale*abs(gamma)))/255.0)*globalgammamul : globalgammamul);\
163 tempgammaoffs = ((gamma > 0) ? ((gammascale*gamma)/255.0) + globalgammaoffs : globalgammaoffs);\
164 mod = ((hue % huecoloursteps)*(tempgammamul)/huecoloursteps);\
165 switch (hue/huecoloursteps)\
166 {\
167 case 0:\
168 default:\
169 loc[0] = tempgammaoffs+tempgammamul;\
170 loc[1] = tempgammaoffs+mod;\
171 loc[2] = tempgammaoffs;\
172 break;\
173 case 1:\
174 loc[0] = tempgammaoffs+tempgammamul-mod;\
175 loc[1] = tempgammaoffs+tempgammamul;\
176 loc[2] = tempgammaoffs;\
177 break;\
178 case 2:\
179 loc[0] = tempgammaoffs;\
180 loc[1] = tempgammaoffs+tempgammamul;\
181 loc[2] = tempgammaoffs+mod;\
182 break;\
183 case 3:\
184 loc[0] = tempgammaoffs;\
185 loc[1] = tempgammaoffs+tempgammamul-mod;\
186 loc[2] = tempgammaoffs+tempgammamul;\
187 break;\
188 case 4:\
189 loc[0] = tempgammaoffs+mod;\
190 loc[1] = tempgammaoffs;\
191 loc[2] = tempgammaoffs+tempgammamul;\
192 break;\
193 case 5:\
194 loc[0] = tempgammaoffs+tempgammamul;\
195 loc[1] = tempgammaoffs;\
196 loc[2] = tempgammaoffs+tempgammamul-mod;\
197 break;\
198 }
199 dohue(cv_rhue.value, cv_rgamma.value, working[1][0][0]);
200 dohue(cv_yhue.value, cv_ygamma.value, working[1][1][0]);
201 dohue(cv_ghue.value, cv_ggamma.value, working[0][1][0]);
202 dohue(cv_chue.value, cv_cgamma.value, working[0][1][1]);
203 dohue(cv_bhue.value, cv_bgamma.value, working[0][0][1]);
204 dohue(cv_mhue.value, cv_mgamma.value, working[1][0][1]);
205 #undef dohue
206 }
207
208 #define dosaturation(a, e) a = ((1 - work)*e + work*a)
209 #define docvsat(cv_sat, hue, gamma, r, g, b) \
210 if diffcons(cv_sat)\
211 {\
212 float work, mod, tempgammamul, tempgammaoffs;\
213 apply = true;\
214 work = (cv_sat.value/10.0);\
215 mod = ((hue % huecoloursteps)*(1.0)/huecoloursteps);\
216 if (hue & huecoloursteps)\
217 mod = 2-mod;\
218 else\
219 mod += 1;\
220 tempgammamul = (gamma ? ((255 - (gammascale*abs(gamma)))/255.0)*globalgammamul : globalgammamul);\
221 tempgammaoffs = ((gamma > 0) ? ((gammascale*gamma)/255.0) + globalgammaoffs : globalgammaoffs);\
222 for (q = 0; q < 3; q++)\
223 dosaturation(working[r][g][b][q], (tempgammaoffs+(desatur[q]*mod*tempgammamul)));\
224 }
225
226 docvsat(cv_rsaturation, cv_rhue.value, cv_rgamma.value, 1, 0, 0);
227 docvsat(cv_ysaturation, cv_yhue.value, cv_ygamma.value, 1, 1, 0);
228 docvsat(cv_gsaturation, cv_ghue.value, cv_ggamma.value, 0, 1, 0);
229 docvsat(cv_csaturation, cv_chue.value, cv_cgamma.value, 0, 1, 1);
230 docvsat(cv_bsaturation, cv_bhue.value, cv_bgamma.value, 0, 0, 1);
231 docvsat(cv_msaturation, cv_mhue.value, cv_mgamma.value, 1, 0, 1);
232
233 #undef gammascale
234
235 if diffcons(cv_globalsaturation)
236 {
237 float work = (cv_globalsaturation.value/10.0);
238
239 apply = true;
240
241 for (q = 0; q < 3; q++)
242 {
243 dosaturation(working[1][0][0][q], desatur[q]);
244 dosaturation(working[0][1][0][q], desatur[q]);
245 dosaturation(working[0][0][1][q], desatur[q]);
246
247 dosaturation(working[1][1][0][q], 2*desatur[q]);
248 dosaturation(working[0][1][1][q], 2*desatur[q]);
249 dosaturation(working[1][0][1][q], 2*desatur[q]);
250 }
251 }
252
253 #undef dosaturation
254
255 #undef diffcons
256
257 if (!apply)
258 return false;
259
260 #define dowork(i, j, k, l) \
261 if (working[i][j][k][l] > 1.0)\
262 working[i][j][k][l] = 1.0;\
263 else if (working[i][j][k][l] < 0.0)\
264 working[i][j][k][l] = 0.0;\
265 Cubepal[i][j][k][l] = working[i][j][k][l]
266 for (q = 0; q < 3; q++)
267 {
268 dowork(0, 0, 0, q);
269 dowork(1, 0, 0, q);
270 dowork(0, 1, 0, q);
271 dowork(1, 1, 0, q);
272 dowork(0, 0, 1, q);
273 dowork(1, 0, 1, q);
274 dowork(0, 1, 1, q);
275 dowork(1, 1, 1, q);
276 }
277 #undef dowork
278
279 return true;
280 }
281
282 #ifdef BACKWARDSCOMPATCORRECTION
283 /*
284 So it turns out that the way gamma was implemented previously, the default
285 colour profile of the game was messed up. Since this bad decision has been
286 around for a long time, and the intent is to keep the base game looking the
287 same, I'm not gonna be the one to remove this base modification.
288 toast 20/04/17
289 ... welp yes i am (27/07/19, see the ifdef around it)
290 */
291 const UINT8 correctiontable[256] =
292 {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
293 17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,
294 33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,
295 49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,
296 65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,
297 81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,
298 97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,
299 113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,
300 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
301 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
302 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
303 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
304 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
305 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
306 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
307 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255};
308 #endif
309
310 // keep a copy of the palette so that we can get the RGB value for a color index at any time.
LoadPalette(const char * lumpname)311 static void LoadPalette(const char *lumpname)
312 {
313 lumpnum_t lumpnum = W_GetNumForName(lumpname);
314 size_t i, palsize = W_LumpLength(lumpnum)/3;
315 UINT8 *pal;
316
317 Cubeapply = InitCube();
318
319 Z_Free(pLocalPalette);
320 Z_Free(pMasterPalette);
321
322 pLocalPalette = Z_Malloc(sizeof (*pLocalPalette)*palsize, PU_STATIC, NULL);
323 pMasterPalette = Z_Malloc(sizeof (*pMasterPalette)*palsize, PU_STATIC, NULL);
324
325 pal = W_CacheLumpNum(lumpnum, PU_CACHE);
326 for (i = 0; i < palsize; i++)
327 {
328 #ifdef BACKWARDSCOMPATCORRECTION
329 pMasterPalette[i].s.red = pLocalPalette[i].s.red = correctiontable[*pal++];
330 pMasterPalette[i].s.green = pLocalPalette[i].s.green = correctiontable[*pal++];
331 pMasterPalette[i].s.blue = pLocalPalette[i].s.blue = correctiontable[*pal++];
332 #else
333 pMasterPalette[i].s.red = pLocalPalette[i].s.red = *pal++;
334 pMasterPalette[i].s.green = pLocalPalette[i].s.green = *pal++;
335 pMasterPalette[i].s.blue = pLocalPalette[i].s.blue = *pal++;
336 #endif
337 pMasterPalette[i].s.alpha = pLocalPalette[i].s.alpha = 0xFF;
338
339 // lerp of colour cubing! if you want, make it smoother yourself
340 if (Cubeapply)
341 V_CubeApply(&pLocalPalette[i].s.red, &pLocalPalette[i].s.green, &pLocalPalette[i].s.blue);
342 }
343 }
344
V_CubeApply(UINT8 * red,UINT8 * green,UINT8 * blue)345 void V_CubeApply(UINT8 *red, UINT8 *green, UINT8 *blue)
346 {
347 float working[4][3];
348 float linear;
349 UINT8 q;
350
351 if (!Cubeapply)
352 return;
353
354 linear = (*red/255.0);
355 #define dolerp(e1, e2) ((1 - linear)*e1 + linear*e2)
356 for (q = 0; q < 3; q++)
357 {
358 working[0][q] = dolerp(Cubepal[0][0][0][q], Cubepal[1][0][0][q]);
359 working[1][q] = dolerp(Cubepal[0][1][0][q], Cubepal[1][1][0][q]);
360 working[2][q] = dolerp(Cubepal[0][0][1][q], Cubepal[1][0][1][q]);
361 working[3][q] = dolerp(Cubepal[0][1][1][q], Cubepal[1][1][1][q]);
362 }
363 linear = (*green/255.0);
364 for (q = 0; q < 3; q++)
365 {
366 working[0][q] = dolerp(working[0][q], working[1][q]);
367 working[1][q] = dolerp(working[2][q], working[3][q]);
368 }
369 linear = (*blue/255.0);
370 for (q = 0; q < 3; q++)
371 {
372 working[0][q] = 255*dolerp(working[0][q], working[1][q]);
373 if (working[0][q] > 255.0)
374 working[0][q] = 255.0;
375 else if (working[0][q] < 0.0)
376 working[0][q] = 0.0;
377 }
378 #undef dolerp
379
380 *red = (UINT8)(working[0][0]);
381 *green = (UINT8)(working[0][1]);
382 *blue = (UINT8)(working[0][2]);
383 }
384
R_GetPalname(UINT16 num)385 const char *R_GetPalname(UINT16 num)
386 {
387 static char palname[9];
388 char newpal[9] = "PLAYPAL";
389
390 if (num > 0 && num <= 10000)
391 snprintf(newpal, 8, "PAL%04u", num-1);
392
393 strncpy(palname, newpal, 8);
394 return palname;
395 }
396
GetPalette(void)397 const char *GetPalette(void)
398 {
399 if (gamestate == GS_LEVEL)
400 return R_GetPalname(mapheaderinfo[gamemap-1]->palette);
401 return "PLAYPAL";
402 }
403
LoadMapPalette(void)404 static void LoadMapPalette(void)
405 {
406 LoadPalette(GetPalette());
407 }
408
409 // -------------+
410 // V_SetPalette : Set the current palette to use for palettized graphics
411 // :
412 // -------------+
V_SetPalette(INT32 palettenum)413 void V_SetPalette(INT32 palettenum)
414 {
415 if (!pLocalPalette)
416 LoadMapPalette();
417
418 #ifdef HWRENDER
419 if (rendermode == render_opengl)
420 HWR_SetPalette(&pLocalPalette[palettenum*256]);
421 #if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL)
422 else
423 #endif
424 #endif
425 if (rendermode != render_none)
426 I_SetPalette(&pLocalPalette[palettenum*256]);
427 }
428
V_SetPaletteLump(const char * pal)429 void V_SetPaletteLump(const char *pal)
430 {
431 LoadPalette(pal);
432 #ifdef HWRENDER
433 if (rendermode == render_opengl)
434 HWR_SetPalette(pLocalPalette);
435 #if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL)
436 else
437 #endif
438 #endif
439 if (rendermode != render_none)
440 I_SetPalette(pLocalPalette);
441 }
442
CV_palette_OnChange(void)443 static void CV_palette_OnChange(void)
444 {
445 // reload palette
446 LoadMapPalette();
447 V_SetPalette(0);
448 }
449
450 #if defined (__GNUC__) && defined (__i386__) && !defined (NOASM) && !defined (__APPLE__) && !defined (NORUSEASM)
451 void VID_BlitLinearScreen_ASM(const UINT8 *srcptr, UINT8 *destptr, INT32 width, INT32 height, size_t srcrowbytes,
452 size_t destrowbytes);
453 #define HAVE_VIDCOPY
454 #endif
455
CV_constextsize_OnChange(void)456 static void CV_constextsize_OnChange(void)
457 {
458 con_recalc = true;
459 }
460
461
462 // --------------------------------------------------------------------------
463 // Copy a rectangular area from one bitmap to another (8bpp)
464 // --------------------------------------------------------------------------
VID_BlitLinearScreen(const UINT8 * srcptr,UINT8 * destptr,INT32 width,INT32 height,size_t srcrowbytes,size_t destrowbytes)465 void VID_BlitLinearScreen(const UINT8 *srcptr, UINT8 *destptr, INT32 width, INT32 height, size_t srcrowbytes,
466 size_t destrowbytes)
467 {
468 #ifdef HAVE_VIDCOPY
469 VID_BlitLinearScreen_ASM(srcptr,destptr,width,height,srcrowbytes,destrowbytes);
470 #else
471 if (srcrowbytes == destrowbytes)
472 M_Memcpy(destptr, srcptr, srcrowbytes * height);
473 else
474 {
475 while (height--)
476 {
477 M_Memcpy(destptr, srcptr, width);
478
479 destptr += destrowbytes;
480 srcptr += srcrowbytes;
481 }
482 }
483 #endif
484 }
485
486 static UINT8 hudplusalpha[11] = { 10, 8, 6, 4, 2, 0, 0, 0, 0, 0, 0};
487 static UINT8 hudminusalpha[11] = { 10, 9, 9, 8, 8, 7, 7, 6, 6, 5, 5};
488
489 static const UINT8 *v_colormap = NULL;
490 static const UINT8 *v_translevel = NULL;
491
standardpdraw(const UINT8 * dest,const UINT8 * source,fixed_t ofs)492 static inline UINT8 standardpdraw(const UINT8 *dest, const UINT8 *source, fixed_t ofs)
493 {
494 (void)dest; return source[ofs>>FRACBITS];
495 }
mappedpdraw(const UINT8 * dest,const UINT8 * source,fixed_t ofs)496 static inline UINT8 mappedpdraw(const UINT8 *dest, const UINT8 *source, fixed_t ofs)
497 {
498 (void)dest; return *(v_colormap + source[ofs>>FRACBITS]);
499 }
translucentpdraw(const UINT8 * dest,const UINT8 * source,fixed_t ofs)500 static inline UINT8 translucentpdraw(const UINT8 *dest, const UINT8 *source, fixed_t ofs)
501 {
502 return *(v_translevel + ((source[ofs>>FRACBITS]<<8)&0xff00) + (*dest&0xff));
503 }
transmappedpdraw(const UINT8 * dest,const UINT8 * source,fixed_t ofs)504 static inline UINT8 transmappedpdraw(const UINT8 *dest, const UINT8 *source, fixed_t ofs)
505 {
506 return *(v_translevel + (((*(v_colormap + source[ofs>>FRACBITS]))<<8)&0xff00) + (*dest&0xff));
507 }
508
509 // Draws a patch scaled to arbitrary size.
V_DrawStretchyFixedPatch(fixed_t x,fixed_t y,fixed_t pscale,fixed_t vscale,INT32 scrn,patch_t * patch,const UINT8 * colormap)510 void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 scrn, patch_t *patch, const UINT8 *colormap)
511 {
512 UINT8 (*patchdrawfunc)(const UINT8*, const UINT8*, fixed_t);
513 UINT32 alphalevel = 0;
514
515 fixed_t col, ofs, colfrac, rowfrac, fdup, vdup;
516 INT32 dupx, dupy;
517 const column_t *column;
518 UINT8 *desttop, *dest, *deststart, *destend;
519 const UINT8 *source, *deststop;
520 fixed_t pwidth; // patch width
521 fixed_t offx = 0; // x offset
522
523 UINT8 perplayershuffle = 0;
524
525 if (rendermode == render_none)
526 return;
527
528 #ifdef HWRENDER
529 //if (rendermode != render_soft && !con_startup) // Why?
530 if (rendermode == render_opengl)
531 {
532 HWR_DrawStretchyFixedPatch(patch, x, y, pscale, vscale, scrn, colormap);
533 return;
534 }
535 #endif
536
537 patchdrawfunc = standardpdraw;
538
539 v_translevel = NULL;
540 if ((alphalevel = ((scrn & V_ALPHAMASK) >> V_ALPHASHIFT)))
541 {
542 if (alphalevel == 13)
543 alphalevel = hudminusalpha[st_translucency];
544 else if (alphalevel == 14)
545 alphalevel = 10 - st_translucency;
546 else if (alphalevel == 15)
547 alphalevel = hudplusalpha[st_translucency];
548
549 if (alphalevel >= 10)
550 return; // invis
551
552 if (alphalevel)
553 {
554 v_translevel = R_GetTranslucencyTable(alphalevel);
555 patchdrawfunc = translucentpdraw;
556 }
557 }
558
559 v_colormap = NULL;
560 if (colormap)
561 {
562 v_colormap = colormap;
563 patchdrawfunc = (v_translevel) ? transmappedpdraw : mappedpdraw;
564 }
565
566 dupx = vid.dupx;
567 dupy = vid.dupy;
568 if (scrn & V_SCALEPATCHMASK) switch ((scrn & V_SCALEPATCHMASK) >> V_SCALEPATCHSHIFT)
569 {
570 case 1: // V_NOSCALEPATCH
571 dupx = dupy = 1;
572 break;
573 case 2: // V_SMALLSCALEPATCH
574 dupx = vid.smalldupx;
575 dupy = vid.smalldupy;
576 break;
577 case 3: // V_MEDSCALEPATCH
578 dupx = vid.meddupx;
579 dupy = vid.meddupy;
580 break;
581 default:
582 break;
583 }
584
585 // only use one dup, to avoid stretching (har har)
586 dupx = dupy = (dupx < dupy ? dupx : dupy);
587 fdup = vdup = FixedMul(dupx<<FRACBITS, pscale);
588 if (vscale != pscale)
589 vdup = FixedMul(dupx<<FRACBITS, vscale);
590 colfrac = FixedDiv(FRACUNIT, fdup);
591 rowfrac = FixedDiv(FRACUNIT, vdup);
592
593 // So it turns out offsets aren't scaled in V_NOSCALESTART unless V_OFFSET is applied ...poo, that's terrible
594 // For now let's just at least give V_OFFSET the ability to support V_FLIP
595 // I'll probably make a better fix for 2.2 where I don't have to worry about breaking existing support for stuff
596 // -- Monster Iestyn 29/10/18
597 {
598 fixed_t offsetx = 0, offsety = 0;
599
600 // left offset
601 if (scrn & V_FLIP)
602 offsetx = FixedMul((patch->width - patch->leftoffset)<<FRACBITS, pscale) + 1;
603 else
604 offsetx = FixedMul(patch->leftoffset<<FRACBITS, pscale);
605
606 // top offset
607 // TODO: make some kind of vertical version of V_FLIP, maybe by deprecating V_OFFSET in future?!?
608 offsety = FixedMul(patch->topoffset<<FRACBITS, vscale);
609
610 if ((scrn & (V_NOSCALESTART|V_OFFSET)) == (V_NOSCALESTART|V_OFFSET)) // Multiply by dupx/dupy for crosshairs
611 {
612 offsetx = FixedMul(offsetx, dupx<<FRACBITS);
613 offsety = FixedMul(offsety, dupy<<FRACBITS);
614 }
615
616 // Subtract the offsets from x/y positions
617 x -= offsetx;
618 y -= offsety;
619 }
620
621 if (splitscreen && (scrn & V_PERPLAYER))
622 {
623 fixed_t adjusty = ((scrn & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)<<(FRACBITS-1);
624 vdup >>= 1;
625 rowfrac <<= 1;
626 y >>= 1;
627 #ifdef QUADS
628 if (splitscreen > 1) // 3 or 4 players
629 {
630 fixed_t adjustx = ((scrn & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)<<(FRACBITS-1));
631 fdup >>= 1;
632 colfrac <<= 1;
633 x >>= 1;
634 if (stplyr == &players[displayplayer])
635 {
636 if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
637 perplayershuffle |= 1;
638 if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
639 perplayershuffle |= 4;
640 scrn &= ~V_SNAPTOBOTTOM|V_SNAPTORIGHT;
641 }
642 else if (stplyr == &players[secondarydisplayplayer])
643 {
644 if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
645 perplayershuffle |= 1;
646 if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
647 perplayershuffle |= 8;
648 x += adjustx;
649 scrn &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT;
650 }
651 else if (stplyr == &players[thirddisplayplayer])
652 {
653 if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
654 perplayershuffle |= 2;
655 if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
656 perplayershuffle |= 4;
657 y += adjusty;
658 scrn &= ~V_SNAPTOTOP|V_SNAPTORIGHT;
659 }
660 else //if (stplyr == &players[fourthdisplayplayer])
661 {
662 if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
663 perplayershuffle |= 2;
664 if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
665 perplayershuffle |= 8;
666 x += adjustx;
667 y += adjusty;
668 scrn &= ~V_SNAPTOTOP|V_SNAPTOLEFT;
669 }
670 }
671 else
672 #endif
673 // 2 players
674 {
675 if (stplyr == &players[displayplayer])
676 {
677 if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
678 perplayershuffle = 1;
679 scrn &= ~V_SNAPTOBOTTOM;
680 }
681 else //if (stplyr == &players[secondarydisplayplayer])
682 {
683 if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
684 perplayershuffle = 2;
685 y += adjusty;
686 scrn &= ~V_SNAPTOTOP;
687 }
688 }
689 }
690
691 desttop = screens[scrn&V_PARAMMASK];
692
693 if (!desttop)
694 return;
695
696 deststop = desttop + vid.rowbytes * vid.height;
697
698 if (scrn & V_NOSCALESTART)
699 {
700 x >>= FRACBITS;
701 y >>= FRACBITS;
702 desttop += (y*vid.width) + x;
703 }
704 else
705 {
706 x = FixedMul(x,dupx<<FRACBITS);
707 y = FixedMul(y,dupy<<FRACBITS);
708 x >>= FRACBITS;
709 y >>= FRACBITS;
710
711 // Center it if necessary
712 if (!(scrn & V_SCALEPATCHMASK))
713 {
714 // if it's meant to cover the whole screen, black out the rest (ONLY IF TOP LEFT ISN'T TRANSPARENT)
715 if (x == 0 && patch->width == BASEVIDWIDTH && y == 0 && patch->height == BASEVIDHEIGHT)
716 {
717 column = (const column_t *)((const UINT8 *)(patch->columns) + (patch->columnofs[0]));
718 if (!column->topdelta)
719 {
720 source = (const UINT8 *)(column) + 3;
721 V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, source[0]);
722 }
723 }
724
725 if (vid.width != BASEVIDWIDTH * dupx)
726 {
727 // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx,
728 // so center this imaginary screen
729 if (scrn & V_SNAPTORIGHT)
730 x += (vid.width - (BASEVIDWIDTH * dupx));
731 else if (!(scrn & V_SNAPTOLEFT))
732 x += (vid.width - (BASEVIDWIDTH * dupx)) / 2;
733 if (perplayershuffle & 4)
734 x -= (vid.width - (BASEVIDWIDTH * dupx)) / 4;
735 else if (perplayershuffle & 8)
736 x += (vid.width - (BASEVIDWIDTH * dupx)) / 4;
737 }
738 if (vid.height != BASEVIDHEIGHT * dupy)
739 {
740 // same thing here
741 if (scrn & V_SNAPTOBOTTOM)
742 y += (vid.height - (BASEVIDHEIGHT * dupy));
743 else if (!(scrn & V_SNAPTOTOP))
744 y += (vid.height - (BASEVIDHEIGHT * dupy)) / 2;
745 if (perplayershuffle & 1)
746 y -= (vid.height - (BASEVIDHEIGHT * dupy)) / 4;
747 else if (perplayershuffle & 2)
748 y += (vid.height - (BASEVIDHEIGHT * dupy)) / 4;
749 }
750 }
751
752 desttop += (y*vid.width) + x;
753 }
754
755 if (pscale != FRACUNIT) // scale width properly
756 {
757 pwidth = patch->width<<FRACBITS;
758 pwidth = FixedMul(pwidth, pscale);
759 pwidth = FixedMul(pwidth, dupx<<FRACBITS);
760 pwidth >>= FRACBITS;
761 }
762 else
763 pwidth = patch->width * dupx;
764
765 deststart = desttop;
766 destend = desttop + pwidth;
767
768 for (col = 0; (col>>FRACBITS) < patch->width; col += colfrac, ++offx, desttop++)
769 {
770 INT32 topdelta, prevdelta = -1;
771 if (scrn & V_FLIP) // offx is measured from right edge instead of left
772 {
773 if (x+pwidth-offx < 0) // don't draw off the left of the screen (WRAP PREVENTION)
774 break;
775 if (x+pwidth-offx >= vid.width) // don't draw off the right of the screen (WRAP PREVENTION)
776 continue;
777 }
778 else
779 {
780 if (x+offx < 0) // don't draw off the left of the screen (WRAP PREVENTION)
781 continue;
782 if (x+offx >= vid.width) // don't draw off the right of the screen (WRAP PREVENTION)
783 break;
784 }
785 column = (const column_t *)((const UINT8 *)(patch->columns) + (patch->columnofs[col>>FRACBITS]));
786
787 while (column->topdelta != 0xff)
788 {
789 topdelta = column->topdelta;
790 if (topdelta <= prevdelta)
791 topdelta += prevdelta;
792 prevdelta = topdelta;
793 source = (const UINT8 *)(column) + 3;
794 dest = desttop;
795 if (scrn & V_FLIP)
796 dest = deststart + (destend - desttop);
797 dest += FixedInt(FixedMul(topdelta<<FRACBITS,vdup))*vid.width;
798
799 for (ofs = 0; dest < deststop && (ofs>>FRACBITS) < column->length; ofs += rowfrac)
800 {
801 if (dest >= screens[scrn&V_PARAMMASK]) // don't draw off the top of the screen (CRASH PREVENTION)
802 *dest = patchdrawfunc(dest, source, ofs);
803 dest += vid.width;
804 }
805 column = (const column_t *)((const UINT8 *)column + column->length + 4);
806 }
807 }
808 }
809
810 // Draws a patch cropped and scaled to arbitrary size.
V_DrawCroppedPatch(fixed_t x,fixed_t y,fixed_t pscale,INT32 scrn,patch_t * patch,fixed_t sx,fixed_t sy,fixed_t w,fixed_t h)811 void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t *patch, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h)
812 {
813 UINT8 (*patchdrawfunc)(const UINT8*, const UINT8*, fixed_t);
814 UINT32 alphalevel = 0;
815 // boolean flip = false;
816
817 fixed_t col, ofs, colfrac, rowfrac, fdup;
818 INT32 dupx, dupy;
819 const column_t *column;
820 UINT8 *desttop, *dest;
821 const UINT8 *source, *deststop;
822
823 UINT8 perplayershuffle = 0;
824
825 if (rendermode == render_none)
826 return;
827
828 #ifdef HWRENDER
829 //if (rendermode != render_soft && !con_startup) // Not this again
830 if (rendermode == render_opengl)
831 {
832 HWR_DrawCroppedPatch(patch,x,y,pscale,scrn,sx,sy,w,h);
833 return;
834 }
835 #endif
836
837 patchdrawfunc = standardpdraw;
838
839 v_translevel = NULL;
840 if ((alphalevel = ((scrn & V_ALPHAMASK) >> V_ALPHASHIFT)))
841 {
842 if (alphalevel == 13)
843 alphalevel = hudminusalpha[st_translucency];
844 else if (alphalevel == 14)
845 alphalevel = 10 - st_translucency;
846 else if (alphalevel == 15)
847 alphalevel = hudplusalpha[st_translucency];
848
849 if (alphalevel >= 10)
850 return; // invis
851
852 if (alphalevel)
853 {
854 v_translevel = R_GetTranslucencyTable(alphalevel);
855 patchdrawfunc = translucentpdraw;
856 }
857 }
858
859 // only use one dup, to avoid stretching (har har)
860 dupx = dupy = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy);
861 fdup = FixedMul(dupx<<FRACBITS, pscale);
862 colfrac = FixedDiv(FRACUNIT, fdup);
863 rowfrac = FixedDiv(FRACUNIT, fdup);
864
865 y -= FixedMul(patch->topoffset<<FRACBITS, pscale);
866 x -= FixedMul(patch->leftoffset<<FRACBITS, pscale);
867
868 if (splitscreen && (scrn & V_PERPLAYER))
869 {
870 fixed_t adjusty = ((scrn & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)<<(FRACBITS-1);
871 fdup >>= 1;
872 rowfrac <<= 1;
873 y >>= 1;
874 sy >>= 1;
875 h >>= 1;
876 #ifdef QUADS
877 if (splitscreen > 1) // 3 or 4 players
878 {
879 fixed_t adjustx = ((scrn & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)<<(FRACBITS-1));
880 colfrac <<= 1;
881 x >>= 1;
882 sx >>= 1;
883 w >>= 1;
884 if (stplyr == &players[displayplayer])
885 {
886 if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
887 perplayershuffle |= 1;
888 if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
889 perplayershuffle |= 4;
890 scrn &= ~V_SNAPTOBOTTOM|V_SNAPTORIGHT;
891 }
892 else if (stplyr == &players[secondarydisplayplayer])
893 {
894 if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
895 perplayershuffle |= 1;
896 if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
897 perplayershuffle |= 8;
898 x += adjustx;
899 sx += adjustx;
900 scrn &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT;
901 }
902 else if (stplyr == &players[thirddisplayplayer])
903 {
904 if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
905 perplayershuffle |= 2;
906 if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
907 perplayershuffle |= 4;
908 y += adjusty;
909 sy += adjusty;
910 scrn &= ~V_SNAPTOTOP|V_SNAPTORIGHT;
911 }
912 else //if (stplyr == &players[fourthdisplayplayer])
913 {
914 if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
915 perplayershuffle |= 2;
916 if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
917 perplayershuffle |= 8;
918 x += adjustx;
919 sx += adjustx;
920 y += adjusty;
921 sy += adjusty;
922 scrn &= ~V_SNAPTOTOP|V_SNAPTOLEFT;
923 }
924 }
925 else
926 #endif
927 // 2 players
928 {
929 if (stplyr == &players[displayplayer])
930 {
931 if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
932 perplayershuffle |= 1;
933 scrn &= ~V_SNAPTOBOTTOM;
934 }
935 else //if (stplyr == &players[secondarydisplayplayer])
936 {
937 if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
938 perplayershuffle |= 2;
939 y += adjusty;
940 sy += adjusty;
941 scrn &= ~V_SNAPTOTOP;
942 }
943 }
944 }
945
946 desttop = screens[scrn&V_PARAMMASK];
947
948 if (!desttop)
949 return;
950
951 deststop = desttop + vid.rowbytes * vid.height;
952
953 if (scrn & V_NOSCALESTART) {
954 x >>= FRACBITS;
955 y >>= FRACBITS;
956 desttop += (y*vid.width) + x;
957 }
958 else
959 {
960 x = FixedMul(x,dupx<<FRACBITS);
961 y = FixedMul(y,dupy<<FRACBITS);
962 x >>= FRACBITS;
963 y >>= FRACBITS;
964
965 // Center it if necessary
966 if (!(scrn & V_SCALEPATCHMASK))
967 {
968 // if it's meant to cover the whole screen, black out the rest
969 // no the patch is cropped do not do this ever
970
971 if (vid.width != BASEVIDWIDTH * dupx)
972 {
973 // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx,
974 // so center this imaginary screen
975 if (scrn & V_SNAPTORIGHT)
976 x += (vid.width - (BASEVIDWIDTH * dupx));
977 else if (!(scrn & V_SNAPTOLEFT))
978 x += (vid.width - (BASEVIDWIDTH * dupx)) / 2;
979 if (perplayershuffle & 4)
980 x -= (vid.width - (BASEVIDWIDTH * dupx)) / 4;
981 else if (perplayershuffle & 8)
982 x += (vid.width - (BASEVIDWIDTH * dupx)) / 4;
983 }
984 if (vid.height != BASEVIDHEIGHT * dupy)
985 {
986 // same thing here
987 if (scrn & V_SNAPTOBOTTOM)
988 y += (vid.height - (BASEVIDHEIGHT * dupy));
989 else if (!(scrn & V_SNAPTOTOP))
990 y += (vid.height - (BASEVIDHEIGHT * dupy)) / 2;
991 if (perplayershuffle & 1)
992 y -= (vid.height - (BASEVIDHEIGHT * dupy)) / 4;
993 else if (perplayershuffle & 2)
994 y += (vid.height - (BASEVIDHEIGHT * dupy)) / 4;
995 }
996 }
997
998 desttop += (y*vid.width) + x;
999 }
1000
1001 for (col = sx<<FRACBITS; (col>>FRACBITS) < patch->width && ((col>>FRACBITS) - sx) < w; col += colfrac, ++x, desttop++)
1002 {
1003 INT32 topdelta, prevdelta = -1;
1004 if (x < 0) // don't draw off the left of the screen (WRAP PREVENTION)
1005 continue;
1006 if (x >= vid.width) // don't draw off the right of the screen (WRAP PREVENTION)
1007 break;
1008 column = (const column_t *)((const UINT8 *)(patch->columns) + (patch->columnofs[col>>FRACBITS]));
1009
1010 while (column->topdelta != 0xff)
1011 {
1012 topdelta = column->topdelta;
1013 if (topdelta <= prevdelta)
1014 topdelta += prevdelta;
1015 prevdelta = topdelta;
1016 source = (const UINT8 *)(column) + 3;
1017 dest = desttop;
1018 if (topdelta-sy > 0)
1019 {
1020 dest += FixedInt(FixedMul((topdelta-sy)<<FRACBITS,fdup))*vid.width;
1021 ofs = 0;
1022 }
1023 else
1024 ofs = (sy-topdelta)<<FRACBITS;
1025
1026 for (; dest < deststop && (ofs>>FRACBITS) < column->length && (((ofs>>FRACBITS) - sy) + topdelta) < h; ofs += rowfrac)
1027 {
1028 if (dest >= screens[scrn&V_PARAMMASK]) // don't draw off the top of the screen (CRASH PREVENTION)
1029 *dest = patchdrawfunc(dest, source, ofs);
1030 dest += vid.width;
1031 }
1032 column = (const column_t *)((const UINT8 *)column + column->length + 4);
1033 }
1034 }
1035 }
1036
1037 //
1038 // V_DrawContinueIcon
1039 // Draw a mini player! If we can, that is. Otherwise we draw a star.
1040 //
V_DrawContinueIcon(INT32 x,INT32 y,INT32 flags,INT32 skinnum,UINT16 skincolor)1041 void V_DrawContinueIcon(INT32 x, INT32 y, INT32 flags, INT32 skinnum, UINT16 skincolor)
1042 {
1043 if (skinnum >= 0 && skinnum < numskins && skins[skinnum].sprites[SPR2_XTRA].numframes > XTRA_CONTINUE)
1044 {
1045 spritedef_t *sprdef = &skins[skinnum].sprites[SPR2_XTRA];
1046 spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_CONTINUE];
1047 patch_t *patch = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH);
1048 const UINT8 *colormap = R_GetTranslationColormap(skinnum, skincolor, GTC_CACHE);
1049
1050 V_DrawMappedPatch(x, y, flags, patch, colormap);
1051 }
1052 else
1053 V_DrawScaledPatch(x - 10, y - 14, flags, W_CachePatchName("CONTINS", PU_PATCH));
1054 }
1055
1056 //
1057 // V_DrawBlock
1058 // Draw a linear block of pixels into the view buffer.
1059 //
V_DrawBlock(INT32 x,INT32 y,INT32 scrn,INT32 width,INT32 height,const UINT8 * src)1060 void V_DrawBlock(INT32 x, INT32 y, INT32 scrn, INT32 width, INT32 height, const UINT8 *src)
1061 {
1062 UINT8 *dest;
1063 const UINT8 *deststop;
1064
1065 #ifdef RANGECHECK
1066 if (x < 0 || x + width > vid.width || y < 0 || y + height > vid.height || (unsigned)scrn > 4)
1067 I_Error("Bad V_DrawBlock");
1068 #endif
1069
1070 dest = screens[scrn] + y*vid.width + x;
1071 deststop = screens[scrn] + vid.rowbytes * vid.height;
1072
1073 while (height--)
1074 {
1075 M_Memcpy(dest, src, width);
1076
1077 src += width;
1078 dest += vid.width;
1079 if (dest > deststop)
1080 return;
1081 }
1082 }
1083
1084 static void V_BlitScaledPic(INT32 px1, INT32 py1, INT32 scrn, pic_t *pic);
1085 // Draw a linear pic, scaled, TOTALLY CRAP CODE!!! OPTIMISE AND ASM!!
1086 //
V_DrawScaledPic(INT32 rx1,INT32 ry1,INT32 scrn,INT32 lumpnum)1087 void V_DrawScaledPic(INT32 rx1, INT32 ry1, INT32 scrn, INT32 lumpnum)
1088 {
1089 #ifdef HWRENDER
1090 if (rendermode != render_soft)
1091 {
1092 HWR_DrawPic(rx1, ry1, lumpnum);
1093 return;
1094 }
1095 #endif
1096
1097 V_BlitScaledPic(rx1, ry1, scrn, W_CacheLumpNum(lumpnum, PU_CACHE));
1098 }
1099
V_BlitScaledPic(INT32 rx1,INT32 ry1,INT32 scrn,pic_t * pic)1100 static void V_BlitScaledPic(INT32 rx1, INT32 ry1, INT32 scrn, pic_t * pic)
1101 {
1102 INT32 dupx, dupy;
1103 INT32 x, y;
1104 UINT8 *src, *dest;
1105 INT32 width, height;
1106
1107 width = SHORT(pic->width);
1108 height = SHORT(pic->height);
1109 scrn &= V_PARAMMASK;
1110
1111 if (pic->mode != 0)
1112 {
1113 CONS_Debug(DBG_RENDER, "pic mode %d not supported in Software\n", pic->mode);
1114 return;
1115 }
1116
1117 dest = screens[scrn] + max(0, ry1 * vid.width) + max(0, rx1);
1118 // y cliping to the screen
1119 if (ry1 + height * vid.dupy >= vid.width)
1120 height = (vid.width - ry1) / vid.dupy - 1;
1121 // WARNING no x clipping (not needed for the moment)
1122
1123 for (y = max(0, -ry1 / vid.dupy); y < height; y++)
1124 {
1125 for (dupy = vid.dupy; dupy; dupy--)
1126 {
1127 src = pic->data + y * width;
1128 for (x = 0; x < width; x++)
1129 {
1130 for (dupx = vid.dupx; dupx; dupx--)
1131 *dest++ = *src;
1132 src++;
1133 }
1134 dest += vid.width - vid.dupx * width;
1135 }
1136 }
1137 }
1138
1139 //
1140 // Fills a box of pixels with a single color, NOTE: scaled to screen size
1141 //
V_DrawFill(INT32 x,INT32 y,INT32 w,INT32 h,INT32 c)1142 void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c)
1143 {
1144 UINT8 *dest;
1145 const UINT8 *deststop;
1146
1147 UINT8 perplayershuffle = 0;
1148
1149 if (rendermode == render_none)
1150 return;
1151
1152 #ifdef HWRENDER
1153 //if (rendermode != render_soft && !con_startup) // Not this again
1154 if (rendermode == render_opengl)
1155 {
1156 HWR_DrawFill(x, y, w, h, c);
1157 return;
1158 }
1159 #endif
1160
1161 if (splitscreen && (c & V_PERPLAYER))
1162 {
1163 fixed_t adjusty = ((c & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)>>1;
1164 h >>= 1;
1165 y >>= 1;
1166 #ifdef QUADS
1167 if (splitscreen > 1) // 3 or 4 players
1168 {
1169 fixed_t adjustx = ((c & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)>>1;
1170 w >>= 1;
1171 x >>= 1;
1172 if (stplyr == &players[displayplayer])
1173 {
1174 if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
1175 perplayershuffle |= 1;
1176 if (!(c & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
1177 perplayershuffle |= 4;
1178 c &= ~V_SNAPTOBOTTOM|V_SNAPTORIGHT;
1179 }
1180 else if (stplyr == &players[secondarydisplayplayer])
1181 {
1182 if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
1183 perplayershuffle |= 1;
1184 if (!(c & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
1185 perplayershuffle |= 8;
1186 x += adjustx;
1187 c &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT;
1188 }
1189 else if (stplyr == &players[thirddisplayplayer])
1190 {
1191 if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
1192 perplayershuffle |= 2;
1193 if (!(c & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
1194 perplayershuffle |= 4;
1195 y += adjusty;
1196 c &= ~V_SNAPTOTOP|V_SNAPTORIGHT;
1197 }
1198 else //if (stplyr == &players[fourthdisplayplayer])
1199 {
1200 if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
1201 perplayershuffle |= 2;
1202 if (!(c & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
1203 perplayershuffle |= 8;
1204 x += adjustx;
1205 y += adjusty;
1206 c &= ~V_SNAPTOTOP|V_SNAPTOLEFT;
1207 }
1208 }
1209 else
1210 #endif
1211 // 2 players
1212 {
1213 if (stplyr == &players[displayplayer])
1214 {
1215 if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
1216 perplayershuffle |= 1;
1217 c &= ~V_SNAPTOBOTTOM;
1218 }
1219 else //if (stplyr == &players[secondarydisplayplayer])
1220 {
1221 if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
1222 perplayershuffle |= 2;
1223 y += adjusty;
1224 c &= ~V_SNAPTOTOP;
1225 }
1226 }
1227 }
1228
1229 if (!(c & V_NOSCALESTART))
1230 {
1231 INT32 dupx = vid.dupx, dupy = vid.dupy;
1232
1233 if (x == 0 && y == 0 && w == BASEVIDWIDTH && h == BASEVIDHEIGHT)
1234 { // Clear the entire screen, from dest to deststop. Yes, this really works.
1235 memset(screens[0], (c&255), vid.width * vid.height * vid.bpp);
1236 return;
1237 }
1238
1239 x *= dupx;
1240 y *= dupy;
1241 w *= dupx;
1242 h *= dupy;
1243
1244 // Center it if necessary
1245 if (vid.width != BASEVIDWIDTH * dupx)
1246 {
1247 // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx,
1248 // so center this imaginary screen
1249 if (c & V_SNAPTORIGHT)
1250 x += (vid.width - (BASEVIDWIDTH * dupx));
1251 else if (!(c & V_SNAPTOLEFT))
1252 x += (vid.width - (BASEVIDWIDTH * dupx)) / 2;
1253 if (perplayershuffle & 4)
1254 x -= (vid.width - (BASEVIDWIDTH * dupx)) / 4;
1255 else if (perplayershuffle & 8)
1256 x += (vid.width - (BASEVIDWIDTH * dupx)) / 4;
1257 }
1258 if (vid.height != BASEVIDHEIGHT * dupy)
1259 {
1260 // same thing here
1261 if (c & V_SNAPTOBOTTOM)
1262 y += (vid.height - (BASEVIDHEIGHT * dupy));
1263 else if (!(c & V_SNAPTOTOP))
1264 y += (vid.height - (BASEVIDHEIGHT * dupy)) / 2;
1265 if (perplayershuffle & 1)
1266 y -= (vid.height - (BASEVIDHEIGHT * dupy)) / 4;
1267 else if (perplayershuffle & 2)
1268 y += (vid.height - (BASEVIDHEIGHT * dupy)) / 4;
1269 }
1270 }
1271
1272 if (x >= vid.width || y >= vid.height)
1273 return; // off the screen
1274 if (x < 0)
1275 {
1276 w += x;
1277 x = 0;
1278 }
1279 if (y < 0)
1280 {
1281 h += y;
1282 y = 0;
1283 }
1284
1285 if (w <= 0 || h <= 0)
1286 return; // zero width/height wouldn't draw anything
1287 if (x + w > vid.width)
1288 w = vid.width - x;
1289 if (y + h > vid.height)
1290 h = vid.height - y;
1291
1292 dest = screens[0] + y*vid.width + x;
1293 deststop = screens[0] + vid.rowbytes * vid.height;
1294
1295 c &= 255;
1296
1297 for (;(--h >= 0) && dest < deststop; dest += vid.width)
1298 memset(dest, c, w * vid.bpp);
1299 }
1300
1301 #ifdef HWRENDER
1302 // This is now a function since it's otherwise repeated 2 times and honestly looks retarded:
V_GetHWConsBackColor(void)1303 static UINT32 V_GetHWConsBackColor(void)
1304 {
1305 UINT32 hwcolor;
1306 switch (cons_backcolor.value)
1307 {
1308 case 0: hwcolor = 0xffffff00; break; // White
1309 case 1: hwcolor = 0x80808000; break; // Black
1310 case 2: hwcolor = 0xdeb88700; break; // Sepia
1311 case 3: hwcolor = 0x40201000; break; // Brown
1312 case 4: hwcolor = 0xfa807200; break; // Pink
1313 case 5: hwcolor = 0xff69b400; break; // Raspberry
1314 case 6: hwcolor = 0xff000000; break; // Red
1315 case 7: hwcolor = 0xffd68300; break; // Creamsicle
1316 case 8: hwcolor = 0xff800000; break; // Orange
1317 case 9: hwcolor = 0xdaa52000; break; // Gold
1318 case 10: hwcolor = 0x80800000; break; // Yellow
1319 case 11: hwcolor = 0x00ff0000; break; // Emerald
1320 case 12: hwcolor = 0x00800000; break; // Green
1321 case 13: hwcolor = 0x4080ff00; break; // Cyan
1322 case 14: hwcolor = 0x4682b400; break; // Steel
1323 case 15: hwcolor = 0x1e90ff00; break; // Periwinkle
1324 case 16: hwcolor = 0x0000ff00; break; // Blue
1325 case 17: hwcolor = 0xff00ff00; break; // Purple
1326 case 18: hwcolor = 0xee82ee00; break; // Lavender
1327 // Default green
1328 default: hwcolor = 0x00800000; break;
1329 }
1330 return hwcolor;
1331 }
1332 #endif
1333
1334
1335 // THANK YOU MPC!!!
1336 // and thanks toaster for cleaning it up.
1337
V_DrawFillConsoleMap(INT32 x,INT32 y,INT32 w,INT32 h,INT32 c)1338 void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c)
1339 {
1340 UINT8 *dest;
1341 const UINT8 *deststop;
1342 INT32 u;
1343 UINT8 *fadetable;
1344 UINT32 alphalevel = 0;
1345 UINT8 perplayershuffle = 0;
1346
1347 if (rendermode == render_none)
1348 return;
1349
1350 #ifdef HWRENDER
1351 if (rendermode == render_opengl)
1352 {
1353 UINT32 hwcolor = V_GetHWConsBackColor();
1354 HWR_DrawConsoleFill(x, y, w, h, c, hwcolor); // we still use the regular color stuff but only for flags. actual draw color is "hwcolor" for this.
1355 return;
1356 }
1357 #endif
1358
1359 if ((alphalevel = ((c & V_ALPHAMASK) >> V_ALPHASHIFT)))
1360 {
1361 if (alphalevel == 13)
1362 alphalevel = hudminusalpha[st_translucency];
1363 else if (alphalevel == 14)
1364 alphalevel = 10 - st_translucency;
1365 else if (alphalevel == 15)
1366 alphalevel = hudplusalpha[st_translucency];
1367
1368 if (alphalevel >= 10)
1369 return; // invis
1370 }
1371
1372 if (splitscreen && (c & V_PERPLAYER))
1373 {
1374 fixed_t adjusty = ((c & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)>>1;
1375 h >>= 1;
1376 y >>= 1;
1377 #ifdef QUADS
1378 if (splitscreen > 1) // 3 or 4 players
1379 {
1380 fixed_t adjustx = ((c & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)>>1;
1381 w >>= 1;
1382 x >>= 1;
1383 if (stplyr == &players[displayplayer])
1384 {
1385 if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
1386 perplayershuffle |= 1;
1387 if (!(c & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
1388 perplayershuffle |= 4;
1389 c &= ~V_SNAPTOBOTTOM|V_SNAPTORIGHT;
1390 }
1391 else if (stplyr == &players[secondarydisplayplayer])
1392 {
1393 if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
1394 perplayershuffle |= 1;
1395 if (!(c & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
1396 perplayershuffle |= 8;
1397 x += adjustx;
1398 c &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT;
1399 }
1400 else if (stplyr == &players[thirddisplayplayer])
1401 {
1402 if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
1403 perplayershuffle |= 2;
1404 if (!(c & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
1405 perplayershuffle |= 4;
1406 y += adjusty;
1407 c &= ~V_SNAPTOTOP|V_SNAPTORIGHT;
1408 }
1409 else //if (stplyr == &players[fourthdisplayplayer])
1410 {
1411 if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
1412 perplayershuffle |= 2;
1413 if (!(c & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
1414 perplayershuffle |= 8;
1415 x += adjustx;
1416 y += adjusty;
1417 c &= ~V_SNAPTOTOP|V_SNAPTOLEFT;
1418 }
1419 }
1420 else
1421 #endif
1422 // 2 players
1423 {
1424 if (stplyr == &players[displayplayer])
1425 {
1426 if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
1427 perplayershuffle |= 1;
1428 c &= ~V_SNAPTOBOTTOM;
1429 }
1430 else //if (stplyr == &players[secondarydisplayplayer])
1431 {
1432 if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
1433 perplayershuffle |= 2;
1434 y += adjusty;
1435 c &= ~V_SNAPTOTOP;
1436 }
1437 }
1438 }
1439
1440 if (!(c & V_NOSCALESTART))
1441 {
1442 INT32 dupx = vid.dupx, dupy = vid.dupy;
1443
1444 x *= dupx;
1445 y *= dupy;
1446 w *= dupx;
1447 h *= dupy;
1448
1449 // Center it if necessary
1450 if (vid.width != BASEVIDWIDTH * dupx)
1451 {
1452 // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx,
1453 // so center this imaginary screen
1454 if (c & V_SNAPTORIGHT)
1455 x += (vid.width - (BASEVIDWIDTH * dupx));
1456 else if (!(c & V_SNAPTOLEFT))
1457 x += (vid.width - (BASEVIDWIDTH * dupx)) / 2;
1458 if (perplayershuffle & 4)
1459 x -= (vid.width - (BASEVIDWIDTH * dupx)) / 4;
1460 else if (perplayershuffle & 8)
1461 x += (vid.width - (BASEVIDWIDTH * dupx)) / 4;
1462 }
1463 if (vid.height != BASEVIDHEIGHT * dupy)
1464 {
1465 // same thing here
1466 if (c & V_SNAPTOBOTTOM)
1467 y += (vid.height - (BASEVIDHEIGHT * dupy));
1468 else if (!(c & V_SNAPTOTOP))
1469 y += (vid.height - (BASEVIDHEIGHT * dupy)) / 2;
1470 if (perplayershuffle & 1)
1471 y -= (vid.height - (BASEVIDHEIGHT * dupy)) / 4;
1472 else if (perplayershuffle & 2)
1473 y += (vid.height - (BASEVIDHEIGHT * dupy)) / 4;
1474 }
1475 }
1476
1477 if (x >= vid.width || y >= vid.height)
1478 return; // off the screen
1479 if (x < 0) {
1480 w += x;
1481 x = 0;
1482 }
1483 if (y < 0) {
1484 h += y;
1485 y = 0;
1486 }
1487
1488 if (w <= 0 || h <= 0)
1489 return; // zero width/height wouldn't draw anything
1490 if (x + w > vid.width)
1491 w = vid.width-x;
1492 if (y + h > vid.height)
1493 h = vid.height-y;
1494
1495 dest = screens[0] + y*vid.width + x;
1496 deststop = screens[0] + vid.rowbytes * vid.height;
1497
1498 c &= 255;
1499
1500 // Jimita (12-04-2018)
1501 if (alphalevel)
1502 {
1503 fadetable = R_GetTranslucencyTable(alphalevel) + (c*256);
1504 for (;(--h >= 0) && dest < deststop; dest += vid.width)
1505 {
1506 u = 0;
1507 while (u < w)
1508 {
1509 dest[u] = fadetable[consolebgmap[dest[u]]];
1510 u++;
1511 }
1512 }
1513 }
1514 else
1515 {
1516 for (;(--h >= 0) && dest < deststop; dest += vid.width)
1517 {
1518 u = 0;
1519 while (u < w)
1520 {
1521 dest[u] = consolebgmap[dest[u]];
1522 u++;
1523 }
1524 }
1525 }
1526 }
1527
1528 //
1529 // If color is 0x00 to 0xFF, draw transtable (strength range 0-9).
1530 // Else, use COLORMAP lump (strength range 0-31).
1531 // c is not color, it is for flags only. transparency flags will be ignored.
1532 // IF YOU ARE NOT CAREFUL, THIS CAN AND WILL CRASH!
1533 // I have kept the safety checks for strength out of this function;
1534 // I don't trust Lua users with it, so it doesn't matter.
1535 //
V_DrawFadeFill(INT32 x,INT32 y,INT32 w,INT32 h,INT32 c,UINT16 color,UINT8 strength)1536 void V_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c, UINT16 color, UINT8 strength)
1537 {
1538 UINT8 *dest;
1539 const UINT8 *deststop;
1540 INT32 u;
1541 UINT8 *fadetable;
1542 UINT8 perplayershuffle = 0;
1543
1544 if (rendermode == render_none)
1545 return;
1546
1547 #ifdef HWRENDER
1548 if (rendermode == render_opengl)
1549 {
1550 // ughhhhh please can someone else do this? thanks ~toast 25/7/19 in 38 degrees centigrade w/o AC
1551 HWR_DrawFadeFill(x, y, w, h, c, color, strength); // toast two days later - left above comment in 'cause it's funny
1552 return;
1553 }
1554 #endif
1555
1556 if (splitscreen && (c & V_PERPLAYER))
1557 {
1558 fixed_t adjusty = ((c & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)>>1;
1559 h >>= 1;
1560 y >>= 1;
1561 #ifdef QUADS
1562 if (splitscreen > 1) // 3 or 4 players
1563 {
1564 fixed_t adjustx = ((c & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)>>1;
1565 w >>= 1;
1566 x >>= 1;
1567 if (stplyr == &players[displayplayer])
1568 {
1569 if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
1570 perplayershuffle |= 1;
1571 if (!(c & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
1572 perplayershuffle |= 4;
1573 c &= ~V_SNAPTOBOTTOM|V_SNAPTORIGHT;
1574 }
1575 else if (stplyr == &players[secondarydisplayplayer])
1576 {
1577 if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
1578 perplayershuffle |= 1;
1579 if (!(c & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
1580 perplayershuffle |= 8;
1581 x += adjustx;
1582 c &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT;
1583 }
1584 else if (stplyr == &players[thirddisplayplayer])
1585 {
1586 if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
1587 perplayershuffle |= 2;
1588 if (!(c & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
1589 perplayershuffle |= 4;
1590 y += adjusty;
1591 c &= ~V_SNAPTOTOP|V_SNAPTORIGHT;
1592 }
1593 else //if (stplyr == &players[fourthdisplayplayer])
1594 {
1595 if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
1596 perplayershuffle |= 2;
1597 if (!(c & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
1598 perplayershuffle |= 8;
1599 x += adjustx;
1600 y += adjusty;
1601 c &= ~V_SNAPTOTOP|V_SNAPTOLEFT;
1602 }
1603 }
1604 else
1605 #endif
1606 // 2 players
1607 {
1608 if (stplyr == &players[displayplayer])
1609 {
1610 if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
1611 perplayershuffle |= 1;
1612 c &= ~V_SNAPTOBOTTOM;
1613 }
1614 else //if (stplyr == &players[secondarydisplayplayer])
1615 {
1616 if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
1617 perplayershuffle |= 2;
1618 y += adjusty;
1619 c &= ~V_SNAPTOTOP;
1620 }
1621 }
1622 }
1623
1624 if (!(c & V_NOSCALESTART))
1625 {
1626 INT32 dupx = vid.dupx, dupy = vid.dupy;
1627
1628 x *= dupx;
1629 y *= dupy;
1630 w *= dupx;
1631 h *= dupy;
1632
1633 // Center it if necessary
1634 if (vid.width != BASEVIDWIDTH * dupx)
1635 {
1636 // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx,
1637 // so center this imaginary screen
1638 if (c & V_SNAPTORIGHT)
1639 x += (vid.width - (BASEVIDWIDTH * dupx));
1640 else if (!(c & V_SNAPTOLEFT))
1641 x += (vid.width - (BASEVIDWIDTH * dupx)) / 2;
1642 if (perplayershuffle & 4)
1643 x -= (vid.width - (BASEVIDWIDTH * dupx)) / 4;
1644 else if (perplayershuffle & 8)
1645 x += (vid.width - (BASEVIDWIDTH * dupx)) / 4;
1646 }
1647 if (vid.height != BASEVIDHEIGHT * dupy)
1648 {
1649 // same thing here
1650 if (c & V_SNAPTOBOTTOM)
1651 y += (vid.height - (BASEVIDHEIGHT * dupy));
1652 else if (!(c & V_SNAPTOTOP))
1653 y += (vid.height - (BASEVIDHEIGHT * dupy)) / 2;
1654 if (perplayershuffle & 1)
1655 y -= (vid.height - (BASEVIDHEIGHT * dupy)) / 4;
1656 else if (perplayershuffle & 2)
1657 y += (vid.height - (BASEVIDHEIGHT * dupy)) / 4;
1658 }
1659 }
1660
1661 if (x >= vid.width || y >= vid.height)
1662 return; // off the screen
1663 if (x < 0) {
1664 w += x;
1665 x = 0;
1666 }
1667 if (y < 0) {
1668 h += y;
1669 y = 0;
1670 }
1671
1672 if (w <= 0 || h <= 0)
1673 return; // zero width/height wouldn't draw anything
1674 if (x + w > vid.width)
1675 w = vid.width-x;
1676 if (y + h > vid.height)
1677 h = vid.height-y;
1678
1679 dest = screens[0] + y*vid.width + x;
1680 deststop = screens[0] + vid.rowbytes * vid.height;
1681
1682 c &= 255;
1683
1684 fadetable = ((color & 0xFF00) // Color is not palette index?
1685 ? ((UINT8 *)colormaps + strength*256) // Do COLORMAP fade.
1686 : ((UINT8 *)R_GetTranslucencyTable((9-strength)+1) + color*256)); // Else, do TRANSMAP** fade.
1687 for (;(--h >= 0) && dest < deststop; dest += vid.width)
1688 {
1689 u = 0;
1690 while (u < w)
1691 {
1692 dest[u] = fadetable[dest[u]];
1693 u++;
1694 }
1695 }
1696 }
1697
1698 //
1699 // Fills a box of pixels using a flat texture as a pattern, scaled to screen size.
1700 //
V_DrawFlatFill(INT32 x,INT32 y,INT32 w,INT32 h,lumpnum_t flatnum)1701 void V_DrawFlatFill(INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatnum)
1702 {
1703 INT32 u, v, dupx, dupy;
1704 fixed_t dx, dy, xfrac, yfrac;
1705 const UINT8 *src, *deststop;
1706 UINT8 *flat, *dest;
1707 size_t size, lflatsize, flatshift;
1708
1709 #ifdef HWRENDER
1710 if (rendermode == render_opengl)
1711 {
1712 HWR_DrawFlatFill(x, y, w, h, flatnum);
1713 return;
1714 }
1715 #endif
1716
1717 size = W_LumpLength(flatnum);
1718
1719 switch (size)
1720 {
1721 case 4194304: // 2048x2048 lump
1722 lflatsize = 2048;
1723 flatshift = 10;
1724 break;
1725 case 1048576: // 1024x1024 lump
1726 lflatsize = 1024;
1727 flatshift = 9;
1728 break;
1729 case 262144:// 512x512 lump
1730 lflatsize = 512;
1731 flatshift = 8;
1732 break;
1733 case 65536: // 256x256 lump
1734 lflatsize = 256;
1735 flatshift = 7;
1736 break;
1737 case 16384: // 128x128 lump
1738 lflatsize = 128;
1739 flatshift = 7;
1740 break;
1741 case 1024: // 32x32 lump
1742 lflatsize = 32;
1743 flatshift = 5;
1744 break;
1745 default: // 64x64 lump
1746 lflatsize = 64;
1747 flatshift = 6;
1748 break;
1749 }
1750
1751 flat = W_CacheLumpNum(flatnum, PU_CACHE);
1752
1753 dupx = dupy = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy);
1754
1755 dest = screens[0] + y*dupy*vid.width + x*dupx;
1756 deststop = screens[0] + vid.rowbytes * vid.height;
1757
1758 // from V_DrawScaledPatch
1759 if (vid.width != BASEVIDWIDTH * dupx)
1760 {
1761 // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx,
1762 // so center this imaginary screen
1763 dest += (vid.width - (BASEVIDWIDTH * dupx)) / 2;
1764 }
1765 if (vid.height != BASEVIDHEIGHT * dupy)
1766 {
1767 // same thing here
1768 dest += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width / 2;
1769 }
1770
1771 w *= dupx;
1772 h *= dupy;
1773
1774 dx = FixedDiv(FRACUNIT, dupx<<(FRACBITS-2));
1775 dy = FixedDiv(FRACUNIT, dupy<<(FRACBITS-2));
1776
1777 yfrac = 0;
1778 for (v = 0; v < h; v++, dest += vid.width)
1779 {
1780 xfrac = 0;
1781 src = flat + (((yfrac>>FRACBITS) & (lflatsize - 1)) << flatshift);
1782 for (u = 0; u < w; u++)
1783 {
1784 if (&dest[u] > deststop)
1785 return;
1786 dest[u] = src[(xfrac>>FRACBITS)&(lflatsize-1)];
1787 xfrac += dx;
1788 }
1789 yfrac += dy;
1790 }
1791 }
1792
1793 //
1794 // V_DrawPatchFill
1795 //
V_DrawPatchFill(patch_t * pat)1796 void V_DrawPatchFill(patch_t *pat)
1797 {
1798 INT32 dupz = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy);
1799 INT32 x, y, pw = pat->width * dupz, ph = pat->height * dupz;
1800
1801 for (x = 0; x < vid.width; x += pw)
1802 {
1803 for (y = 0; y < vid.height; y += ph)
1804 V_DrawScaledPatch(x, y, V_NOSCALESTART, pat);
1805 }
1806 }
1807
1808 //
1809 // Fade all the screen buffer, so that the menu is more readable,
1810 // especially now that we use the small hufont in the menus...
1811 // If color is 0x00 to 0xFF, draw transtable (strength range 0-9).
1812 // Else, use COLORMAP lump (strength range 0-31).
1813 // IF YOU ARE NOT CAREFUL, THIS CAN AND WILL CRASH!
1814 // I have kept the safety checks out of this function;
1815 // the v.fadeScreen Lua interface handles those.
1816 //
V_DrawFadeScreen(UINT16 color,UINT8 strength)1817 void V_DrawFadeScreen(UINT16 color, UINT8 strength)
1818 {
1819 #ifdef HWRENDER
1820 if (rendermode == render_opengl)
1821 {
1822 HWR_FadeScreenMenuBack(color, strength);
1823 return;
1824 }
1825 #endif
1826
1827 {
1828 const UINT8 *fadetable = ((color & 0xFF00) // Color is not palette index?
1829 ? ((UINT8 *)(((color & 0x0F00) == 0x0A00) ? fadecolormap // Do fadecolormap fade.
1830 : (((color & 0x0F00) == 0x0B00) ? fadecolormap + (256 * FADECOLORMAPROWS) // Do white fadecolormap fade.
1831 : colormaps)) + strength*256) // Do COLORMAP fade.
1832 : ((UINT8 *)R_GetTranslucencyTable((9-strength)+1) + color*256)); // Else, do TRANSMAP** fade.
1833 const UINT8 *deststop = screens[0] + vid.rowbytes * vid.height;
1834 UINT8 *buf = screens[0];
1835
1836 // heavily simplified -- we don't need to know x or y
1837 // position when we're doing a full screen fade
1838 for (; buf < deststop; ++buf)
1839 *buf = fadetable[*buf];
1840 }
1841 }
1842
1843 // Simple translucency with one color, over a set number of lines starting from the top.
V_DrawFadeConsBack(INT32 plines)1844 void V_DrawFadeConsBack(INT32 plines)
1845 {
1846 UINT8 *deststop, *buf;
1847
1848 #ifdef HWRENDER // not win32 only 19990829 by Kin
1849 if (rendermode == render_opengl)
1850 {
1851 UINT32 hwcolor = V_GetHWConsBackColor();
1852 HWR_DrawConsoleBack(hwcolor, plines);
1853 return;
1854 }
1855 #endif
1856
1857 // heavily simplified -- we don't need to know x or y position,
1858 // just the stop position
1859 deststop = screens[0] + vid.rowbytes * min(plines, vid.height);
1860 for (buf = screens[0]; buf < deststop; ++buf)
1861 *buf = consolebgmap[*buf];
1862 }
1863
1864 // Very similar to F_DrawFadeConsBack, except we draw from the middle(-ish) of the screen to the bottom.
V_DrawPromptBack(INT32 boxheight,INT32 color)1865 void V_DrawPromptBack(INT32 boxheight, INT32 color)
1866 {
1867 UINT8 *deststop, *buf;
1868
1869 if (color >= 256 && color < 512)
1870 {
1871 if (boxheight < 0)
1872 boxheight = -boxheight;
1873 else // 4 lines of space plus gaps between and some leeway
1874 boxheight = ((boxheight * 4) + (boxheight/2)*5);
1875 V_DrawFill((BASEVIDWIDTH-(vid.width/vid.dupx))/2, BASEVIDHEIGHT-boxheight, (vid.width/vid.dupx),boxheight, (color-256)|V_SNAPTOBOTTOM);
1876 return;
1877 }
1878
1879 boxheight *= vid.dupy;
1880
1881 if (color == INT32_MAX)
1882 color = cons_backcolor.value;
1883
1884 #ifdef HWRENDER
1885 if (rendermode == render_opengl)
1886 {
1887 UINT32 hwcolor;
1888 switch (color)
1889 {
1890 case 0: hwcolor = 0xffffff00; break; // White
1891 case 1: hwcolor = 0x00000000; break; // Black // Note this is different from V_DrawFadeConsBack
1892 case 2: hwcolor = 0xdeb88700; break; // Sepia
1893 case 3: hwcolor = 0x40201000; break; // Brown
1894 case 4: hwcolor = 0xfa807200; break; // Pink
1895 case 5: hwcolor = 0xff69b400; break; // Raspberry
1896 case 6: hwcolor = 0xff000000; break; // Red
1897 case 7: hwcolor = 0xffd68300; break; // Creamsicle
1898 case 8: hwcolor = 0xff800000; break; // Orange
1899 case 9: hwcolor = 0xdaa52000; break; // Gold
1900 case 10: hwcolor = 0x80800000; break; // Yellow
1901 case 11: hwcolor = 0x00ff0000; break; // Emerald
1902 case 12: hwcolor = 0x00800000; break; // Green
1903 case 13: hwcolor = 0x4080ff00; break; // Cyan
1904 case 14: hwcolor = 0x4682b400; break; // Steel
1905 case 15: hwcolor = 0x1e90ff00; break; // Periwinkle
1906 case 16: hwcolor = 0x0000ff00; break; // Blue
1907 case 17: hwcolor = 0xff00ff00; break; // Purple
1908 case 18: hwcolor = 0xee82ee00; break; // Lavender
1909 // Default green
1910 default: hwcolor = 0x00800000; break;
1911 }
1912 HWR_DrawTutorialBack(hwcolor, boxheight);
1913 return;
1914 }
1915 #endif
1916
1917 CON_SetupBackColormapEx(color, true);
1918
1919 // heavily simplified -- we don't need to know x or y position,
1920 // just the start and stop positions
1921 buf = deststop = screens[0] + vid.rowbytes * vid.height;
1922 if (boxheight < 0)
1923 buf += vid.rowbytes * boxheight;
1924 else // 4 lines of space plus gaps between and some leeway
1925 buf -= vid.rowbytes * ((boxheight * 4) + (boxheight/2)*5);
1926 for (; buf < deststop; ++buf)
1927 *buf = promptbgmap[*buf];
1928 }
1929
1930 // Gets string colormap, used for 0x80 color codes
1931 //
V_GetStringColormap(INT32 colorflags)1932 UINT8 *V_GetStringColormap(INT32 colorflags)
1933 {
1934 switch ((colorflags & V_CHARCOLORMASK) >> V_CHARCOLORSHIFT)
1935 {
1936 case 1: // 0x81, magenta
1937 return magentamap;
1938 case 2: // 0x82, yellow
1939 return yellowmap;
1940 case 3: // 0x83, lgreen
1941 return lgreenmap;
1942 case 4: // 0x84, blue
1943 return bluemap;
1944 case 5: // 0x85, red
1945 return redmap;
1946 case 6: // 0x86, gray
1947 return graymap;
1948 case 7: // 0x87, orange
1949 return orangemap;
1950 case 8: // 0x88, sky
1951 return skymap;
1952 case 9: // 0x89, purple
1953 return purplemap;
1954 case 10: // 0x8A, aqua
1955 return aquamap;
1956 case 11: // 0x8B, peridot
1957 return peridotmap;
1958 case 12: // 0x8C, azure
1959 return azuremap;
1960 case 13: // 0x8D, brown
1961 return brownmap;
1962 case 14: // 0x8E, rosy
1963 return rosymap;
1964 case 15: // 0x8F, invert
1965 return invertmap;
1966 default: // reset
1967 return NULL;
1968 }
1969 }
1970
1971 // Writes a single character (draw WHITE if bit 7 set)
1972 //
V_DrawCharacter(INT32 x,INT32 y,INT32 c,boolean lowercaseallowed)1973 void V_DrawCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed)
1974 {
1975 INT32 w, flags;
1976 const UINT8 *colormap = V_GetStringColormap(c);
1977
1978 flags = c & ~(V_CHARCOLORMASK | V_PARAMMASK);
1979 c &= 0x7f;
1980 if (lowercaseallowed)
1981 c -= HU_FONTSTART;
1982 else
1983 c = toupper(c) - HU_FONTSTART;
1984 if (c < 0 || c >= HU_FONTSIZE || !hu_font[c])
1985 return;
1986
1987 w = hu_font[c]->width;
1988 if (x + w > vid.width)
1989 return;
1990
1991 if (colormap != NULL)
1992 V_DrawMappedPatch(x, y, flags, hu_font[c], colormap);
1993 else
1994 V_DrawScaledPatch(x, y, flags, hu_font[c]);
1995 }
1996
1997 // Writes a single character for the chat. (draw WHITE if bit 7 set)
1998 // Essentially the same as the above but it's small or big depending on what resolution you've chosen to huge..
1999 //
V_DrawChatCharacter(INT32 x,INT32 y,INT32 c,boolean lowercaseallowed,UINT8 * colormap)2000 void V_DrawChatCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed, UINT8 *colormap)
2001 {
2002 INT32 w, flags;
2003 //const UINT8 *colormap = V_GetStringColormap(c);
2004
2005 flags = c & ~(V_CHARCOLORMASK | V_PARAMMASK);
2006 c &= 0x7f;
2007 if (lowercaseallowed)
2008 c -= HU_FONTSTART;
2009 else
2010 c = toupper(c) - HU_FONTSTART;
2011 if (c < 0 || c >= HU_FONTSIZE || !hu_font[c])
2012 return;
2013
2014 w = (vid.width < 640 ) ? ((hu_font[c]->width / 2)) : (hu_font[c]->width); // use normal sized characters if we're using a terribly low resolution.
2015 if (x + w > vid.width)
2016 return;
2017
2018 V_DrawFixedPatch(x*FRACUNIT, y*FRACUNIT, (vid.width < 640) ? (FRACUNIT) : (FRACUNIT/2), flags, hu_font[c], colormap);
2019
2020
2021 }
2022
2023 // Precompile a wordwrapped string to any given width.
2024 // This is a muuuch better method than V_WORDWRAP.
V_WordWrap(INT32 x,INT32 w,INT32 option,const char * string)2025 char *V_WordWrap(INT32 x, INT32 w, INT32 option, const char *string)
2026 {
2027 int c;
2028 size_t chw, i, lastusablespace = 0;
2029 size_t slen;
2030 char *newstring = Z_StrDup(string);
2031 INT32 spacewidth = 4, charwidth = 0;
2032
2033 slen = strlen(string);
2034
2035 if (w == 0)
2036 w = BASEVIDWIDTH;
2037 w -= x;
2038 x = 0;
2039
2040 switch (option & V_SPACINGMASK)
2041 {
2042 case V_MONOSPACE:
2043 spacewidth = 8;
2044 /* FALLTHRU */
2045 case V_OLDSPACING:
2046 charwidth = 8;
2047 break;
2048 case V_6WIDTHSPACE:
2049 spacewidth = 6;
2050 default:
2051 break;
2052 }
2053
2054 for (i = 0; i < slen; ++i)
2055 {
2056 c = newstring[i];
2057 if ((UINT8)c & 0x80) //color parsing! -Inuyasha 2.16.09
2058 continue;
2059
2060 if (c == '\n')
2061 {
2062 x = 0;
2063 lastusablespace = 0;
2064 continue;
2065 }
2066
2067 if (!(option & V_ALLOWLOWERCASE))
2068 c = toupper(c);
2069 c -= HU_FONTSTART;
2070
2071 if (c < 0 || c >= HU_FONTSIZE || !hu_font[c])
2072 {
2073 chw = spacewidth;
2074 lastusablespace = i;
2075 }
2076 else
2077 chw = (charwidth ? charwidth : hu_font[c]->width);
2078
2079 x += chw;
2080
2081 if (lastusablespace != 0 && x > w)
2082 {
2083 newstring[lastusablespace] = '\n';
2084 i = lastusablespace;
2085 lastusablespace = 0;
2086 x = 0;
2087 }
2088 }
2089 return newstring;
2090 }
2091
2092 //
2093 // Write a string using the hu_font
2094 // NOTE: the text is centered for screens larger than the base width
2095 //
V_DrawString(INT32 x,INT32 y,INT32 option,const char * string)2096 void V_DrawString(INT32 x, INT32 y, INT32 option, const char *string)
2097 {
2098 INT32 w, c, cx = x, cy = y, dupx, dupy, scrwidth, center = 0, left = 0;
2099 const char *ch = string;
2100 INT32 charflags = (option & V_CHARCOLORMASK);
2101 const UINT8 *colormap = NULL;
2102 INT32 spacewidth = 4, charwidth = 0;
2103
2104 INT32 lowercase = (option & V_ALLOWLOWERCASE);
2105 option &= ~V_FLIP; // which is also shared with V_ALLOWLOWERCASE...
2106
2107 if (option & V_NOSCALESTART)
2108 {
2109 dupx = vid.dupx;
2110 dupy = vid.dupy;
2111 scrwidth = vid.width;
2112 }
2113 else
2114 {
2115 dupx = dupy = 1;
2116 scrwidth = vid.width/vid.dupx;
2117 left = (scrwidth - BASEVIDWIDTH)/2;
2118 scrwidth -= left;
2119 }
2120
2121 if (option & V_NOSCALEPATCH)
2122 scrwidth *= vid.dupx;
2123
2124 switch (option & V_SPACINGMASK)
2125 {
2126 case V_MONOSPACE:
2127 spacewidth = 8;
2128 /* FALLTHRU */
2129 case V_OLDSPACING:
2130 charwidth = 8;
2131 break;
2132 case V_6WIDTHSPACE:
2133 spacewidth = 6;
2134 default:
2135 break;
2136 }
2137
2138 for (;;ch++)
2139 {
2140 if (!*ch)
2141 break;
2142 if (*ch & 0x80) //color parsing -x 2.16.09
2143 {
2144 // manually set flags override color codes
2145 if (!(option & V_CHARCOLORMASK))
2146 charflags = ((*ch & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK;
2147 continue;
2148 }
2149 if (*ch == '\n')
2150 {
2151 cx = x;
2152
2153 if (option & V_RETURN8)
2154 cy += 8*dupy;
2155 else
2156 cy += 12*dupy;
2157
2158 continue;
2159 }
2160
2161 c = *ch;
2162 if (!lowercase)
2163 c = toupper(c);
2164 c -= HU_FONTSTART;
2165
2166 // character does not exist or is a space
2167 if (c < 0 || c >= HU_FONTSIZE || !hu_font[c])
2168 {
2169 cx += spacewidth * dupx;
2170 continue;
2171 }
2172
2173 if (charwidth)
2174 {
2175 w = charwidth * dupx;
2176 center = w/2 - hu_font[c]->width*dupx/2;
2177 }
2178 else
2179 w = hu_font[c]->width * dupx;
2180
2181 if (cx > scrwidth)
2182 continue;
2183 if (cx+left + w < 0) //left boundary check
2184 {
2185 cx += w;
2186 continue;
2187 }
2188
2189 colormap = V_GetStringColormap(charflags);
2190 V_DrawFixedPatch((cx + center)<<FRACBITS, cy<<FRACBITS, FRACUNIT, option, hu_font[c], colormap);
2191
2192 cx += w;
2193 }
2194 }
2195
V_DrawCenteredString(INT32 x,INT32 y,INT32 option,const char * string)2196 void V_DrawCenteredString(INT32 x, INT32 y, INT32 option, const char *string)
2197 {
2198 x -= V_StringWidth(string, option)/2;
2199 V_DrawString(x, y, option, string);
2200 }
2201
V_DrawRightAlignedString(INT32 x,INT32 y,INT32 option,const char * string)2202 void V_DrawRightAlignedString(INT32 x, INT32 y, INT32 option, const char *string)
2203 {
2204 x -= V_StringWidth(string, option);
2205 V_DrawString(x, y, option, string);
2206 }
2207
2208 //
2209 // Write a string using the hu_font, 0.5x scale
2210 // NOTE: the text is centered for screens larger than the base width
2211 //
V_DrawSmallString(INT32 x,INT32 y,INT32 option,const char * string)2212 void V_DrawSmallString(INT32 x, INT32 y, INT32 option, const char *string)
2213 {
2214 INT32 w, c, cx = x, cy = y, dupx, dupy, scrwidth, center = 0, left = 0;
2215 const char *ch = string;
2216 INT32 charflags = 0;
2217 const UINT8 *colormap = NULL;
2218 INT32 spacewidth = 2, charwidth = 0;
2219
2220 INT32 lowercase = (option & V_ALLOWLOWERCASE);
2221 option &= ~V_FLIP; // which is also shared with V_ALLOWLOWERCASE...
2222
2223 if (option & V_NOSCALESTART)
2224 {
2225 dupx = vid.dupx;
2226 dupy = vid.dupy;
2227 scrwidth = vid.width;
2228 }
2229 else
2230 {
2231 dupx = dupy = 1;
2232 scrwidth = vid.width/vid.dupx;
2233 left = (scrwidth - BASEVIDWIDTH)/2;
2234 scrwidth -= left;
2235 }
2236
2237 if (option & V_NOSCALEPATCH)
2238 scrwidth *= vid.dupx;
2239
2240 charflags = (option & V_CHARCOLORMASK);
2241
2242 switch (option & V_SPACINGMASK)
2243 {
2244 case V_MONOSPACE:
2245 spacewidth = 4;
2246 /* FALLTHRU */
2247 case V_OLDSPACING:
2248 charwidth = 4;
2249 break;
2250 case V_6WIDTHSPACE:
2251 spacewidth = 3;
2252 default:
2253 break;
2254 }
2255
2256 for (;;ch++)
2257 {
2258 if (!*ch)
2259 break;
2260 if (*ch & 0x80) //color parsing -x 2.16.09
2261 {
2262 // manually set flags override color codes
2263 if (!(option & V_CHARCOLORMASK))
2264 charflags = ((*ch & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK;
2265 continue;
2266 }
2267 if (*ch == '\n')
2268 {
2269 cx = x;
2270
2271 if (option & V_RETURN8)
2272 cy += 4*dupy;
2273 else
2274 cy += 6*dupy;
2275
2276 continue;
2277 }
2278
2279 c = *ch;
2280 if (!lowercase)
2281 c = toupper(c);
2282 c -= HU_FONTSTART;
2283
2284 if (c < 0 || c >= HU_FONTSIZE || !hu_font[c])
2285 {
2286 cx += spacewidth * dupx;
2287 continue;
2288 }
2289
2290 if (charwidth)
2291 {
2292 w = charwidth * dupx;
2293 center = w/2 - hu_font[c]->width*dupx/4;
2294 }
2295 else
2296 w = hu_font[c]->width * dupx / 2;
2297
2298 if (cx > scrwidth)
2299 continue;
2300 if (cx+left + w < 0) //left boundary check
2301 {
2302 cx += w;
2303 continue;
2304 }
2305
2306 colormap = V_GetStringColormap(charflags);
2307 V_DrawFixedPatch((cx + center)<<FRACBITS, cy<<FRACBITS, FRACUNIT/2, option, hu_font[c], colormap);
2308
2309 cx += w;
2310 }
2311 }
2312
V_DrawCenteredSmallString(INT32 x,INT32 y,INT32 option,const char * string)2313 void V_DrawCenteredSmallString(INT32 x, INT32 y, INT32 option, const char *string)
2314 {
2315 x -= V_SmallStringWidth(string, option)/2;
2316 V_DrawSmallString(x, y, option, string);
2317 }
2318
2319
V_DrawRightAlignedSmallString(INT32 x,INT32 y,INT32 option,const char * string)2320 void V_DrawRightAlignedSmallString(INT32 x, INT32 y, INT32 option, const char *string)
2321 {
2322 x -= V_SmallStringWidth(string, option);
2323 V_DrawSmallString(x, y, option, string);
2324 }
2325
2326 //
2327 // Write a string using the tny_font
2328 // NOTE: the text is centered for screens larger than the base width
2329 //
V_DrawThinString(INT32 x,INT32 y,INT32 option,const char * string)2330 void V_DrawThinString(INT32 x, INT32 y, INT32 option, const char *string)
2331 {
2332 INT32 w, c, cx = x, cy = y, dupx, dupy, scrwidth, left = 0;
2333 const char *ch = string;
2334 INT32 charflags = 0;
2335 const UINT8 *colormap = NULL;
2336 INT32 spacewidth = 2, charwidth = 0;
2337
2338 INT32 lowercase = (option & V_ALLOWLOWERCASE);
2339 option &= ~V_FLIP; // which is also shared with V_ALLOWLOWERCASE...
2340
2341 if (option & V_NOSCALESTART)
2342 {
2343 dupx = vid.dupx;
2344 dupy = vid.dupy;
2345 scrwidth = vid.width;
2346 }
2347 else
2348 {
2349 dupx = dupy = 1;
2350 scrwidth = vid.width/vid.dupx;
2351 left = (scrwidth - BASEVIDWIDTH)/2;
2352 scrwidth -= left;
2353 }
2354
2355 if (option & V_NOSCALEPATCH)
2356 scrwidth *= vid.dupx;
2357
2358 charflags = (option & V_CHARCOLORMASK);
2359
2360 switch (option & V_SPACINGMASK)
2361 {
2362 case V_MONOSPACE:
2363 spacewidth = 5;
2364 /* FALLTHRU */
2365 case V_OLDSPACING:
2366 charwidth = 5;
2367 break;
2368 case V_6WIDTHSPACE:
2369 spacewidth = 3;
2370 default:
2371 break;
2372 }
2373
2374 for (;;ch++)
2375 {
2376 if (!*ch)
2377 break;
2378 if (*ch & 0x80) //color parsing -x 2.16.09
2379 {
2380 // manually set flags override color codes
2381 if (!(option & V_CHARCOLORMASK))
2382 charflags = ((*ch & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK;
2383 continue;
2384 }
2385 if (*ch == '\n')
2386 {
2387 cx = x;
2388
2389 if (option & V_RETURN8)
2390 cy += 8*dupy;
2391 else
2392 cy += 12*dupy;
2393
2394 continue;
2395 }
2396
2397 c = *ch;
2398 if (!lowercase || !tny_font[c-HU_FONTSTART])
2399 c = toupper(c);
2400 c -= HU_FONTSTART;
2401
2402 if (c < 0 || c >= HU_FONTSIZE || !tny_font[c])
2403 {
2404 cx += spacewidth * dupx;
2405 continue;
2406 }
2407
2408 if (charwidth)
2409 w = charwidth * dupx;
2410 else
2411 w = tny_font[c]->width * dupx;
2412
2413 if (cx > scrwidth)
2414 continue;
2415 if (cx+left + w < 0) //left boundary check
2416 {
2417 cx += w;
2418 continue;
2419 }
2420
2421 colormap = V_GetStringColormap(charflags);
2422 V_DrawFixedPatch(cx<<FRACBITS, cy<<FRACBITS, FRACUNIT, option, tny_font[c], colormap);
2423
2424 cx += w;
2425 }
2426 }
2427
V_DrawCenteredThinString(INT32 x,INT32 y,INT32 option,const char * string)2428 void V_DrawCenteredThinString(INT32 x, INT32 y, INT32 option, const char *string)
2429 {
2430 x -= V_ThinStringWidth(string, option)/2;
2431 V_DrawThinString(x, y, option, string);
2432 }
2433
V_DrawRightAlignedThinString(INT32 x,INT32 y,INT32 option,const char * string)2434 void V_DrawRightAlignedThinString(INT32 x, INT32 y, INT32 option, const char *string)
2435 {
2436 x -= V_ThinStringWidth(string, option);
2437 V_DrawThinString(x, y, option, string);
2438 }
2439
2440 //
2441 // Write a string using the tny_font, 0.5x scale
2442 // NOTE: the text is centered for screens larger than the base width
2443 //
2444 // Literally a wrapper. ~Golden
V_DrawSmallThinString(INT32 x,INT32 y,INT32 option,const char * string)2445 void V_DrawSmallThinString(INT32 x, INT32 y, INT32 option, const char *string)
2446 {
2447 x <<= FRACBITS;
2448 y <<= FRACBITS;
2449 V_DrawSmallThinStringAtFixed((fixed_t)x, (fixed_t)y, option, string);
2450 }
2451
V_DrawCenteredSmallThinString(INT32 x,INT32 y,INT32 option,const char * string)2452 void V_DrawCenteredSmallThinString(INT32 x, INT32 y, INT32 option, const char *string)
2453 {
2454 x <<= FRACBITS;
2455 y <<= FRACBITS;
2456 V_DrawCenteredSmallThinStringAtFixed((fixed_t)x, (fixed_t)y, option, string);
2457 }
2458
V_DrawRightAlignedSmallThinString(INT32 x,INT32 y,INT32 option,const char * string)2459 void V_DrawRightAlignedSmallThinString(INT32 x, INT32 y, INT32 option, const char *string)
2460 {
2461 x <<= FRACBITS;
2462 y <<= FRACBITS;
2463 V_DrawRightAlignedSmallThinStringAtFixed((fixed_t)x, (fixed_t)y, option, string);
2464 }
2465
2466 // Draws a string at a fixed_t location.
V_DrawStringAtFixed(fixed_t x,fixed_t y,INT32 option,const char * string)2467 void V_DrawStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
2468 {
2469 fixed_t cx = x, cy = y;
2470 INT32 w, c, dupx, dupy, scrwidth, center = 0, left = 0;
2471 const char *ch = string;
2472 INT32 charflags = 0;
2473 const UINT8 *colormap = NULL;
2474 INT32 spacewidth = 4, charwidth = 0;
2475
2476 INT32 lowercase = (option & V_ALLOWLOWERCASE);
2477 option &= ~V_FLIP; // which is also shared with V_ALLOWLOWERCASE...
2478
2479 if (option & V_NOSCALESTART)
2480 {
2481 dupx = vid.dupx;
2482 dupy = vid.dupy;
2483 scrwidth = vid.width;
2484 }
2485 else
2486 {
2487 dupx = dupy = 1;
2488 scrwidth = vid.width/vid.dupx;
2489 left = (scrwidth - BASEVIDWIDTH)/2;
2490 scrwidth -= left;
2491 }
2492
2493 if (option & V_NOSCALEPATCH)
2494 scrwidth *= vid.dupx;
2495
2496 charflags = (option & V_CHARCOLORMASK);
2497
2498 switch (option & V_SPACINGMASK)
2499 {
2500 case V_MONOSPACE:
2501 spacewidth = 8;
2502 /* FALLTHRU */
2503 case V_OLDSPACING:
2504 charwidth = 8;
2505 break;
2506 case V_6WIDTHSPACE:
2507 spacewidth = 6;
2508 default:
2509 break;
2510 }
2511
2512 for (;;ch++)
2513 {
2514 if (!*ch)
2515 break;
2516 if (*ch & 0x80) //color ignoring
2517 {
2518 // manually set flags override color codes
2519 if (!(option & V_CHARCOLORMASK))
2520 charflags = ((*ch & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK;
2521 continue;
2522 }
2523 if (*ch == '\n')
2524 {
2525 cx = x;
2526
2527 if (option & V_RETURN8)
2528 cy += (8*dupy)<<FRACBITS;
2529 else
2530 cy += (12*dupy)<<FRACBITS;
2531
2532 continue;
2533 }
2534
2535 c = *ch;
2536 if (!lowercase)
2537 c = toupper(c);
2538 c -= HU_FONTSTART;
2539
2540 // character does not exist or is a space
2541 if (c < 0 || c >= HU_FONTSIZE || !hu_font[c])
2542 {
2543 cx += (spacewidth * dupx)<<FRACBITS;
2544 continue;
2545 }
2546
2547 if (charwidth)
2548 {
2549 w = charwidth * dupx;
2550 center = w/2 - hu_font[c]->width*(dupx/2);
2551 }
2552 else
2553 w = hu_font[c]->width * dupx;
2554
2555 if ((cx>>FRACBITS) > scrwidth)
2556 continue;
2557 if ((cx>>FRACBITS)+left + w < 0) //left boundary check
2558 {
2559 cx += w<<FRACBITS;
2560 continue;
2561 }
2562
2563 colormap = V_GetStringColormap(charflags);
2564 V_DrawFixedPatch(cx + (center<<FRACBITS), cy, FRACUNIT, option, hu_font[c], colormap);
2565
2566 cx += w<<FRACBITS;
2567 }
2568 }
2569
V_DrawCenteredStringAtFixed(fixed_t x,fixed_t y,INT32 option,const char * string)2570 void V_DrawCenteredStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
2571 {
2572 x -= (V_StringWidth(string, option) / 2)<<FRACBITS;
2573 V_DrawStringAtFixed(x, y, option, string);
2574 }
2575
V_DrawRightAlignedStringAtFixed(fixed_t x,fixed_t y,INT32 option,const char * string)2576 void V_DrawRightAlignedStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
2577 {
2578 x -= V_StringWidth(string, option)<<FRACBITS;
2579 V_DrawStringAtFixed(x, y, option, string);
2580 }
2581
2582 // Draws a small string at a fixed_t location.
V_DrawSmallStringAtFixed(fixed_t x,fixed_t y,INT32 option,const char * string)2583 void V_DrawSmallStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
2584 {
2585 fixed_t cx = x, cy = y;
2586 INT32 w, c, dupx, dupy, scrwidth, center = 0, left = 0;
2587 const char *ch = string;
2588 INT32 charflags = 0;
2589 const UINT8 *colormap = NULL;
2590 INT32 spacewidth = 2, charwidth = 0;
2591
2592 INT32 lowercase = (option & V_ALLOWLOWERCASE);
2593 option &= ~V_FLIP; // which is also shared with V_ALLOWLOWERCASE...
2594
2595 if (option & V_NOSCALESTART)
2596 {
2597 dupx = vid.dupx;
2598 dupy = vid.dupy;
2599 scrwidth = vid.width;
2600 }
2601 else
2602 {
2603 dupx = dupy = 1;
2604 scrwidth = vid.width/vid.dupx;
2605 left = (scrwidth - BASEVIDWIDTH)/2;
2606 scrwidth -= left;
2607 }
2608
2609 if (option & V_NOSCALEPATCH)
2610 scrwidth *= vid.dupx;
2611
2612 charflags = (option & V_CHARCOLORMASK);
2613
2614 switch (option & V_SPACINGMASK)
2615 {
2616 case V_MONOSPACE:
2617 spacewidth = 4;
2618 /* FALLTHRU */
2619 case V_OLDSPACING:
2620 charwidth = 4;
2621 break;
2622 case V_6WIDTHSPACE:
2623 spacewidth = 3;
2624 default:
2625 break;
2626 }
2627
2628 for (;;ch++)
2629 {
2630 if (!*ch)
2631 break;
2632 if (*ch & 0x80) //color parsing -x 2.16.09
2633 {
2634 // manually set flags override color codes
2635 if (!(option & V_CHARCOLORMASK))
2636 charflags = ((*ch & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK;
2637 continue;
2638 }
2639 if (*ch == '\n')
2640 {
2641 cx = x;
2642
2643 if (option & V_RETURN8)
2644 cy += (4*dupy)<<FRACBITS;
2645 else
2646 cy += (6*dupy)<<FRACBITS;
2647
2648 continue;
2649 }
2650
2651 c = *ch;
2652 if (!lowercase)
2653 c = toupper(c);
2654 c -= HU_FONTSTART;
2655
2656 // character does not exist or is a space
2657 if (c < 0 || c >= HU_FONTSIZE || !hu_font[c])
2658 {
2659 cx += (spacewidth * dupx)<<FRACBITS;
2660 continue;
2661 }
2662
2663 if (charwidth)
2664 {
2665 w = charwidth * dupx;
2666 center = w/2 - hu_font[c]->width*(dupx/4);
2667 }
2668 else
2669 w = hu_font[c]->width * dupx / 2;
2670
2671 if ((cx>>FRACBITS) > scrwidth)
2672 break;
2673 if ((cx>>FRACBITS)+left + w < 0) //left boundary check
2674 {
2675 cx += w<<FRACBITS;
2676 continue;
2677 }
2678
2679 colormap = V_GetStringColormap(charflags);
2680
2681 V_DrawFixedPatch(cx + (center<<FRACBITS), cy, FRACUNIT/2, option, hu_font[c], colormap);
2682
2683 cx += w<<FRACBITS;
2684 }
2685 }
2686
V_DrawCenteredSmallStringAtFixed(fixed_t x,fixed_t y,INT32 option,const char * string)2687 void V_DrawCenteredSmallStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
2688 {
2689 x -= (V_SmallStringWidth(string, option) / 2)<<FRACBITS;
2690 V_DrawSmallStringAtFixed(x, y, option, string);
2691 }
2692
V_DrawRightAlignedSmallStringAtFixed(fixed_t x,fixed_t y,INT32 option,const char * string)2693 void V_DrawRightAlignedSmallStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
2694 {
2695 x -= V_SmallStringWidth(string, option)<<FRACBITS;
2696 V_DrawSmallStringAtFixed(x, y, option, string);
2697 }
2698
2699 // Draws a thin string at a fixed_t location.
V_DrawThinStringAtFixed(fixed_t x,fixed_t y,INT32 option,const char * string)2700 void V_DrawThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
2701 {
2702 fixed_t cx = x, cy = y;
2703 INT32 w, c, dupx, dupy, scrwidth, center = 0, left = 0;
2704 const char *ch = string;
2705 INT32 charflags = 0;
2706 const UINT8 *colormap = NULL;
2707 INT32 spacewidth = 2, charwidth = 0;
2708
2709 INT32 lowercase = (option & V_ALLOWLOWERCASE);
2710 option &= ~V_FLIP; // which is also shared with V_ALLOWLOWERCASE...
2711
2712 if (option & V_NOSCALESTART)
2713 {
2714 dupx = vid.dupx;
2715 dupy = vid.dupy;
2716 scrwidth = vid.width;
2717 }
2718 else
2719 {
2720 dupx = dupy = 1;
2721 scrwidth = vid.width/vid.dupx;
2722 left = (scrwidth - BASEVIDWIDTH)/2;
2723 scrwidth -= left;
2724 }
2725
2726 if (option & V_NOSCALEPATCH)
2727 scrwidth *= vid.dupx;
2728
2729 charflags = (option & V_CHARCOLORMASK);
2730
2731 switch (option & V_SPACINGMASK)
2732 {
2733 case V_MONOSPACE:
2734 spacewidth = 8;
2735 /* FALLTHRU */
2736 case V_OLDSPACING:
2737 charwidth = 8;
2738 break;
2739 case V_6WIDTHSPACE:
2740 spacewidth = 6;
2741 default:
2742 break;
2743 }
2744
2745 for (;;ch++)
2746 {
2747 if (!*ch)
2748 break;
2749 if (*ch & 0x80) //color parsing -x 2.16.09
2750 {
2751 // manually set flags override color codes
2752 if (!(option & V_CHARCOLORMASK))
2753 charflags = ((*ch & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK;
2754 continue;
2755 }
2756 if (*ch == '\n')
2757 {
2758 cx = x;
2759
2760 if (option & V_RETURN8)
2761 cy += (8*dupy)<<FRACBITS;
2762 else
2763 cy += (12*dupy)<<FRACBITS;
2764
2765 continue;
2766 }
2767
2768 c = *ch;
2769 if (!lowercase || !tny_font[c-HU_FONTSTART])
2770 c = toupper(c);
2771 c -= HU_FONTSTART;
2772
2773 // character does not exist or is a space
2774 if (c < 0 || c >= HU_FONTSIZE || !tny_font[c])
2775 {
2776 cx += (spacewidth * dupx)<<FRACBITS;
2777 continue;
2778 }
2779
2780 if (charwidth)
2781 {
2782 w = charwidth * dupx;
2783 center = w/2 - tny_font[c]->width*(dupx/2);
2784 }
2785 else
2786 w = tny_font[c]->width * dupx;
2787
2788 if ((cx>>FRACBITS) > scrwidth)
2789 break;
2790 if ((cx>>FRACBITS)+left + w < 0) //left boundary check
2791 {
2792 cx += w<<FRACBITS;
2793 continue;
2794 }
2795
2796 colormap = V_GetStringColormap(charflags);
2797
2798 V_DrawFixedPatch(cx + (center<<FRACBITS), cy, FRACUNIT, option, tny_font[c], colormap);
2799
2800 cx += w<<FRACBITS;
2801 }
2802 }
2803
V_DrawCenteredThinStringAtFixed(fixed_t x,fixed_t y,INT32 option,const char * string)2804 void V_DrawCenteredThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
2805 {
2806 x -= (V_ThinStringWidth(string, option) / 2)<<FRACBITS;
2807 V_DrawThinStringAtFixed(x, y, option, string);
2808 }
2809
V_DrawRightAlignedThinStringAtFixed(fixed_t x,fixed_t y,INT32 option,const char * string)2810 void V_DrawRightAlignedThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
2811 {
2812 x -= V_ThinStringWidth(string, option)<<FRACBITS;
2813 V_DrawThinStringAtFixed(x, y, option, string);
2814 }
2815
2816 // Draws a small string at a fixed_t location.
V_DrawSmallThinStringAtFixed(fixed_t x,fixed_t y,INT32 option,const char * string)2817 void V_DrawSmallThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
2818 {
2819 fixed_t cx = x, cy = y;
2820 INT32 w, c, dupx, dupy, scrwidth, center = 0, left = 0;
2821 const char *ch = string;
2822 INT32 charflags = 0;
2823 const UINT8 *colormap = NULL;
2824 INT32 spacewidth = 2<<FRACBITS, charwidth = 0;
2825
2826 INT32 lowercase = (option & V_ALLOWLOWERCASE);
2827 option &= ~V_FLIP; // which is also shared with V_ALLOWLOWERCASE...
2828
2829 if (option & V_NOSCALESTART)
2830 {
2831 dupx = vid.dupx<<FRACBITS;
2832 dupy = vid.dupy<<FRACBITS;
2833 scrwidth = vid.width;
2834 }
2835 else
2836 {
2837 dupx = dupy = FRACUNIT;
2838 scrwidth = FixedDiv(vid.width<<FRACBITS, vid.dupx);
2839 left = ((scrwidth - (BASEVIDWIDTH<<FRACBITS))/2);
2840 scrwidth -= left;
2841 }
2842
2843 if (option & V_NOSCALEPATCH)
2844 scrwidth *= vid.dupx;
2845
2846 charflags = (option & V_CHARCOLORMASK);
2847
2848 switch (option & V_SPACINGMASK)
2849 {
2850 case V_MONOSPACE:
2851 spacewidth = 4<<FRACBITS;
2852 /* FALLTHRU */
2853 case V_OLDSPACING:
2854 charwidth = 4<<FRACBITS;
2855 break;
2856 case V_6WIDTHSPACE:
2857 spacewidth = 3<<FRACBITS;
2858 default:
2859 break;
2860 }
2861
2862 for (;;ch++)
2863 {
2864 if (!*ch)
2865 break;
2866 if (*ch & 0x80) //color parsing -x 2.16.09
2867 {
2868 // manually set flags override color codes
2869 if (!(option & V_CHARCOLORMASK))
2870 charflags = ((*ch & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK;
2871 continue;
2872 }
2873 if (*ch == '\n')
2874 {
2875 cx = x;
2876
2877 if (option & V_RETURN8)
2878 cy += 4*dupy;
2879 else
2880 cy += 6*dupy;
2881
2882 continue;
2883 }
2884
2885 c = *ch;
2886 if (!lowercase)
2887 c = toupper(c);
2888 c -= HU_FONTSTART;
2889
2890 // character does not exist or is a space
2891 if (c < 0 || c >= HU_FONTSIZE || !tny_font[c])
2892 {
2893 cx += FixedMul(spacewidth, dupx);
2894 continue;
2895 }
2896
2897 if (charwidth)
2898 {
2899 w = FixedMul(charwidth, dupx);
2900 center = w/2 - tny_font[c]->width*(dupx/4);
2901 }
2902 else
2903 w = tny_font[c]->width * dupx / 2;
2904
2905 if (cx > scrwidth)
2906 break;
2907 if (cx+left + w < 0) //left boundary check
2908 {
2909 cx += w;
2910 continue;
2911 }
2912
2913 colormap = V_GetStringColormap(charflags);
2914
2915 V_DrawFixedPatch(cx + center, cy, FRACUNIT/2, option, tny_font[c], colormap);
2916
2917 cx += w;
2918 }
2919 }
2920
V_DrawCenteredSmallThinStringAtFixed(fixed_t x,fixed_t y,INT32 option,const char * string)2921 void V_DrawCenteredSmallThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
2922 {
2923 x -= V_SmallThinStringWidth(string, option)/4;
2924 V_DrawSmallThinStringAtFixed(x, y, option, string);
2925 }
2926
V_DrawRightAlignedSmallThinStringAtFixed(fixed_t x,fixed_t y,INT32 option,const char * string)2927 void V_DrawRightAlignedSmallThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
2928 {
2929 x -= V_SmallThinStringWidth(string, option)/2;
2930 V_DrawSmallThinStringAtFixed(x, y, option, string);
2931 }
2932
2933 // Draws a tallnum. Replaces two functions in y_inter and st_stuff
V_DrawTallNum(INT32 x,INT32 y,INT32 flags,INT32 num)2934 void V_DrawTallNum(INT32 x, INT32 y, INT32 flags, INT32 num)
2935 {
2936 INT32 w = tallnum[0]->width;
2937 boolean neg;
2938
2939 if (flags & (V_NOSCALESTART|V_NOSCALEPATCH))
2940 w *= vid.dupx;
2941
2942 if ((neg = num < 0))
2943 num = -num;
2944
2945 // draw the number
2946 do
2947 {
2948 x -= w;
2949 V_DrawScaledPatch(x, y, flags, tallnum[num % 10]);
2950 num /= 10;
2951 } while (num);
2952
2953 // draw a minus sign if necessary
2954 if (neg)
2955 V_DrawScaledPatch(x - w, y, flags, tallminus); // Tails
2956 }
2957
2958 // Draws a number with a set number of digits.
2959 // Does not handle negative numbers in a special way, don't try to feed it any.
V_DrawPaddedTallNum(INT32 x,INT32 y,INT32 flags,INT32 num,INT32 digits)2960 void V_DrawPaddedTallNum(INT32 x, INT32 y, INT32 flags, INT32 num, INT32 digits)
2961 {
2962 INT32 w = tallnum[0]->width;
2963
2964 if (flags & (V_NOSCALESTART|V_NOSCALEPATCH))
2965 w *= vid.dupx;
2966
2967 if (num < 0)
2968 num = -num;
2969
2970 // draw the number
2971 do
2972 {
2973 x -= w;
2974 V_DrawScaledPatch(x, y, flags, tallnum[num % 10]);
2975 num /= 10;
2976 } while (--digits);
2977 }
2978
2979 // Draw an act number for a level title
V_DrawLevelActNum(INT32 x,INT32 y,INT32 flags,UINT8 num)2980 void V_DrawLevelActNum(INT32 x, INT32 y, INT32 flags, UINT8 num)
2981 {
2982 if (num > 99)
2983 return; // not supported
2984
2985 while (num > 0)
2986 {
2987 if (num > 9) // if there are two digits, draw second digit first
2988 V_DrawScaledPatch(x + (V_LevelActNumWidth(num) - V_LevelActNumWidth(num%10)), y, flags, ttlnum[num%10]);
2989 else
2990 V_DrawScaledPatch(x, y, flags, ttlnum[num]);
2991 num = num/10;
2992 }
2993 }
2994
2995 // Write a string using the credit font
2996 // NOTE: the text is centered for screens larger than the base width
2997 //
V_DrawCreditString(fixed_t x,fixed_t y,INT32 option,const char * string)2998 void V_DrawCreditString(fixed_t x, fixed_t y, INT32 option, const char *string)
2999 {
3000 INT32 w, c, dupx, dupy, scrwidth = BASEVIDWIDTH;
3001 fixed_t cx = x, cy = y;
3002 const char *ch = string;
3003
3004 // It's possible for string to be a null pointer
3005 if (!string)
3006 return;
3007
3008 if (option & V_NOSCALESTART)
3009 {
3010 dupx = vid.dupx;
3011 dupy = vid.dupy;
3012 scrwidth = vid.width;
3013 }
3014 else
3015 dupx = dupy = 1;
3016
3017 if (option & V_NOSCALEPATCH)
3018 scrwidth *= vid.dupx;
3019
3020 for (;;)
3021 {
3022 c = *ch++;
3023 if (!c)
3024 break;
3025 if (c == '\n')
3026 {
3027 cx = x;
3028 cy += (12*dupy)<<FRACBITS;
3029 continue;
3030 }
3031
3032 c = toupper(c) - CRED_FONTSTART;
3033 if (c < 0 || c >= CRED_FONTSIZE)
3034 {
3035 cx += (16*dupx)<<FRACBITS;
3036 continue;
3037 }
3038
3039 w = cred_font[c]->width * dupx;
3040 if ((cx>>FRACBITS) > scrwidth)
3041 continue;
3042
3043 V_DrawSciencePatch(cx, cy, option, cred_font[c], FRACUNIT);
3044 cx += w<<FRACBITS;
3045 }
3046 }
3047
3048 // Draw a string using the nt_font
3049 // Note that the outline is a seperate font set
V_DrawNameTagLine(INT32 x,INT32 y,INT32 option,fixed_t scale,UINT8 * basecolormap,UINT8 * outlinecolormap,const char * string)3050 static void V_DrawNameTagLine(INT32 x, INT32 y, INT32 option, fixed_t scale, UINT8 *basecolormap, UINT8 *outlinecolormap, const char *string)
3051 {
3052 fixed_t cx, cy, w;
3053 INT32 c, dupx, dupy, scrwidth, left = 0;
3054 const char *ch = string;
3055
3056 if (option & V_CENTERNAMETAG)
3057 x -= FixedInt(FixedMul((V_NameTagWidth(string)/2)*FRACUNIT, scale));
3058 option &= ~V_CENTERNAMETAG; // which is also shared with V_ALLOWLOWERCASE...
3059
3060 cx = x<<FRACBITS;
3061 cy = y<<FRACBITS;
3062
3063 if (option & V_NOSCALESTART)
3064 {
3065 dupx = vid.dupx;
3066 dupy = vid.dupy;
3067 scrwidth = vid.width;
3068 }
3069 else
3070 {
3071 dupx = dupy = 1;
3072 scrwidth = vid.width/vid.dupx;
3073 left = (scrwidth - BASEVIDWIDTH)/2;
3074 scrwidth -= left;
3075 }
3076
3077 if (option & V_NOSCALEPATCH)
3078 scrwidth *= vid.dupx;
3079
3080 for (;;ch++)
3081 {
3082 if (!*ch)
3083 break;
3084 if (*ch == '\n')
3085 {
3086 cx = x<<FRACBITS;
3087 cy += FixedMul((21*dupy)*FRACUNIT, scale);
3088 continue;
3089 }
3090
3091 c = toupper(*ch);
3092 c -= NT_FONTSTART;
3093
3094 // character does not exist or is a space
3095 if (c < 0 || c >= NT_FONTSIZE || !ntb_font[c] || !nto_font[c])
3096 {
3097 cx += FixedMul((4 * dupx)*FRACUNIT, scale);
3098 continue;
3099 }
3100
3101 w = FixedMul(((ntb_font[c]->width)+2 * dupx) * FRACUNIT, scale);
3102
3103 if (FixedInt(cx) > scrwidth)
3104 continue;
3105 if (cx+(left*FRACUNIT) + w < 0) // left boundary check
3106 {
3107 cx += w;
3108 continue;
3109 }
3110
3111 V_DrawFixedPatch(cx, cy, scale, option, nto_font[c], outlinecolormap);
3112 V_DrawFixedPatch(cx, cy, scale, option, ntb_font[c], basecolormap);
3113
3114 cx += w;
3115 }
3116 }
3117
3118 // Looks familiar.
V_DrawNameTag(INT32 x,INT32 y,INT32 option,fixed_t scale,UINT8 * basecolormap,UINT8 * outlinecolormap,const char * string)3119 void V_DrawNameTag(INT32 x, INT32 y, INT32 option, fixed_t scale, UINT8 *basecolormap, UINT8 *outlinecolormap, const char *string)
3120 {
3121 const char *text = string;
3122 const char *first_token = text;
3123 char *last_token = strchr(text, '\n');
3124 const INT32 lbreakheight = 21;
3125 INT32 ntlines;
3126
3127 if (option & V_CENTERNAMETAG)
3128 {
3129 ntlines = V_CountNameTagLines(string);
3130 y -= FixedInt(FixedMul(((lbreakheight/2) * (ntlines-1))*FRACUNIT, scale));
3131 }
3132
3133 // No line breaks?
3134 // Draw entire string
3135 if (!last_token)
3136 V_DrawNameTagLine(x, y, option, scale, basecolormap, outlinecolormap, string);
3137 // Split string by the line break character
3138 else
3139 {
3140 char *str = NULL;
3141 INT32 len;
3142 while (true)
3143 {
3144 // There are still lines left to draw
3145 if (last_token)
3146 {
3147 size_t shift = 0;
3148 // Free this line
3149 if (str)
3150 Z_Free(str);
3151 // Find string length, do a malloc...
3152 len = (last_token-first_token)+1;
3153 str = ZZ_Alloc(len);
3154 // Copy the line
3155 strncpy(str, first_token, len-1);
3156 str[len-1] = '\0';
3157 // Don't leave a line break character
3158 // at the start of the string!
3159 if ((strlen(str) >= 2) && (string[0] == '\n') && (string[1] != '\n'))
3160 shift++;
3161 // Then draw it
3162 V_DrawNameTagLine(x, y, option, scale, basecolormap, outlinecolormap, str+shift);
3163 }
3164 // No line break character was found
3165 else
3166 {
3167 // Don't leave a line break character
3168 // at the start of the string!
3169 if ((strlen(first_token) >= 2) && (first_token[0] == '\n') && (first_token[1] != '\n'))
3170 first_token++;
3171 // Then draw it
3172 V_DrawNameTagLine(x, y, option, scale, basecolormap, outlinecolormap, first_token);
3173 break;
3174 }
3175
3176 // Next line
3177 y += FixedInt(FixedMul(lbreakheight*FRACUNIT, scale));
3178 if ((last_token-text)+1 >= (signed)strlen(text))
3179 last_token = NULL;
3180 else
3181 {
3182 first_token = last_token;
3183 last_token = strchr(first_token+1, '\n');
3184 }
3185 }
3186 // Free this line
3187 if (str)
3188 Z_Free(str);
3189 }
3190 }
3191
3192 // Count the amount of lines in name tag string
V_CountNameTagLines(const char * string)3193 INT32 V_CountNameTagLines(const char *string)
3194 {
3195 INT32 ntlines = 1;
3196 const char *text = string;
3197 const char *first_token = text;
3198 char *last_token = strchr(text, '\n');
3199
3200 // No line breaks?
3201 if (!last_token)
3202 return ntlines;
3203 // Split string by the line break character
3204 else
3205 {
3206 while (true)
3207 {
3208 if (last_token)
3209 ntlines++;
3210 // No line break character was found
3211 else
3212 break;
3213
3214 // Next line
3215 if ((last_token-text)+1 >= (signed)strlen(text))
3216 last_token = NULL;
3217 else
3218 {
3219 first_token = last_token;
3220 last_token = strchr(first_token+1, '\n');
3221 }
3222 }
3223 }
3224 return ntlines;
3225 }
3226
V_NameTagWidth(const char * string)3227 INT32 V_NameTagWidth(const char *string)
3228 {
3229 INT32 c, w = 0;
3230 size_t i;
3231
3232 // It's possible for string to be a null pointer
3233 if (!string)
3234 return 0;
3235
3236 for (i = 0; i < strlen(string); i++)
3237 {
3238 c = toupper(string[i]) - NT_FONTSTART;
3239 if (c < 0 || c >= NT_FONTSIZE || !ntb_font[c] || !nto_font[c])
3240 w += 4;
3241 else
3242 w += (ntb_font[c]->width)+2;
3243 }
3244
3245 return w;
3246 }
3247
3248 // Find string width from cred_font chars
3249 //
V_CreditStringWidth(const char * string)3250 INT32 V_CreditStringWidth(const char *string)
3251 {
3252 INT32 c, w = 0;
3253 size_t i;
3254
3255 // It's possible for string to be a null pointer
3256 if (!string)
3257 return 0;
3258
3259 for (i = 0; i < strlen(string); i++)
3260 {
3261 c = toupper(string[i]) - CRED_FONTSTART;
3262 if (c < 0 || c >= CRED_FONTSIZE)
3263 w += 16;
3264 else
3265 w += cred_font[c]->width;
3266 }
3267
3268 return w;
3269 }
3270
3271 // Write a string using the level title font
3272 // NOTE: the text is centered for screens larger than the base width
3273 //
V_DrawLevelTitle(INT32 x,INT32 y,INT32 option,const char * string)3274 void V_DrawLevelTitle(INT32 x, INT32 y, INT32 option, const char *string)
3275 {
3276 INT32 w, c, cx = x, cy = y, dupx, dupy, scrwidth, left = 0;
3277 const char *ch = string;
3278 INT32 charflags = (option & V_CHARCOLORMASK);
3279 const UINT8 *colormap = NULL;
3280
3281 if (option & V_NOSCALESTART)
3282 {
3283 dupx = vid.dupx;
3284 dupy = vid.dupy;
3285 scrwidth = vid.width;
3286 }
3287 else
3288 {
3289 dupx = dupy = 1;
3290 scrwidth = vid.width/vid.dupx;
3291 left = (scrwidth - BASEVIDWIDTH)/2;
3292 scrwidth -= left;
3293 }
3294
3295 if (option & V_NOSCALEPATCH)
3296 scrwidth *= vid.dupx;
3297
3298 for (;;ch++)
3299 {
3300 if (!*ch)
3301 break;
3302 if (*ch & 0x80) //color parsing -x 2.16.09
3303 {
3304 // manually set flags override color codes
3305 if (!(option & V_CHARCOLORMASK))
3306 charflags = ((*ch & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK;
3307 continue;
3308 }
3309 if (*ch == '\n')
3310 {
3311 cx = x;
3312 cy += 12*dupy;
3313 continue;
3314 }
3315
3316 c = *ch - LT_FONTSTART;
3317 if (c < 0 || c >= LT_FONTSIZE || !lt_font[c])
3318 {
3319 cx += 16*dupx;
3320 continue;
3321 }
3322
3323 w = lt_font[c]->width * dupx;
3324
3325 if (cx > scrwidth)
3326 continue;
3327 if (cx+left + w < 0) //left boundary check
3328 {
3329 cx += w;
3330 continue;
3331 }
3332
3333 colormap = V_GetStringColormap(charflags);
3334 V_DrawFixedPatch(cx<<FRACBITS, cy<<FRACBITS, FRACUNIT, option, lt_font[c], colormap);
3335
3336 cx += w;
3337 }
3338 }
3339
3340 // Find string width from lt_font chars
3341 //
V_LevelNameWidth(const char * string)3342 INT32 V_LevelNameWidth(const char *string)
3343 {
3344 INT32 c, w = 0;
3345 size_t i;
3346
3347 for (i = 0; i < strlen(string); i++)
3348 {
3349 if (string[i] & 0x80)
3350 continue;
3351 c = string[i] - LT_FONTSTART;
3352 if (c < 0 || c >= LT_FONTSIZE || !lt_font[c])
3353 w += 16;
3354 else
3355 w += lt_font[c]->width;
3356 }
3357
3358 return w;
3359 }
3360
3361 // Find max height of the string
3362 //
V_LevelNameHeight(const char * string)3363 INT32 V_LevelNameHeight(const char *string)
3364 {
3365 INT32 c, w = 0;
3366 size_t i;
3367
3368 for (i = 0; i < strlen(string); i++)
3369 {
3370 c = string[i] - LT_FONTSTART;
3371 if (c < 0 || c >= LT_FONTSIZE || !lt_font[c])
3372 continue;
3373
3374 if (lt_font[c]->height > w)
3375 w = lt_font[c]->height;
3376 }
3377
3378 return w;
3379 }
3380
3381 // For ST_drawTitleCard
3382 // Returns the width of the act num patch(es)
V_LevelActNumWidth(UINT8 num)3383 INT16 V_LevelActNumWidth(UINT8 num)
3384 {
3385 INT16 result = 0;
3386
3387 if (num == 0)
3388 result = ttlnum[num]->width;
3389
3390 while (num > 0 && num <= 99)
3391 {
3392 result = result + ttlnum[num%10]->width;
3393 num = num/10;
3394 }
3395
3396 return result;
3397 }
3398
3399 //
3400 // Find string width from hu_font chars
3401 //
V_StringWidth(const char * string,INT32 option)3402 INT32 V_StringWidth(const char *string, INT32 option)
3403 {
3404 INT32 c, w = 0;
3405 INT32 spacewidth = 4, charwidth = 0;
3406 size_t i;
3407
3408 switch (option & V_SPACINGMASK)
3409 {
3410 case V_MONOSPACE:
3411 spacewidth = 8;
3412 /* FALLTHRU */
3413 case V_OLDSPACING:
3414 charwidth = 8;
3415 break;
3416 case V_6WIDTHSPACE:
3417 spacewidth = 6;
3418 default:
3419 break;
3420 }
3421
3422 for (i = 0; i < strlen(string); i++)
3423 {
3424 if (string[i] & 0x80)
3425 continue;
3426 c = toupper(string[i]) - HU_FONTSTART;
3427 if (c < 0 || c >= HU_FONTSIZE || !hu_font[c])
3428 w += spacewidth;
3429 else
3430 w += (charwidth ? charwidth : hu_font[c]->width);
3431 }
3432
3433 if (option & (V_NOSCALESTART|V_NOSCALEPATCH))
3434 w *= vid.dupx;
3435
3436 return w;
3437 }
3438
3439 //
3440 // Find string width from hu_font chars, 0.5x scale
3441 //
V_SmallStringWidth(const char * string,INT32 option)3442 INT32 V_SmallStringWidth(const char *string, INT32 option)
3443 {
3444 INT32 c, w = 0;
3445 INT32 spacewidth = 2, charwidth = 0;
3446 size_t i;
3447
3448 switch (option & V_SPACINGMASK)
3449 {
3450 case V_MONOSPACE:
3451 spacewidth = 4;
3452 /* FALLTHRU */
3453 case V_OLDSPACING:
3454 charwidth = 4;
3455 break;
3456 case V_6WIDTHSPACE:
3457 spacewidth = 3;
3458 default:
3459 break;
3460 }
3461
3462 for (i = 0; i < strlen(string); i++)
3463 {
3464 if (string[i] & 0x80)
3465 continue;
3466 c = toupper(string[i]) - HU_FONTSTART;
3467 if (c < 0 || c >= HU_FONTSIZE || !hu_font[c])
3468 w += spacewidth;
3469 else
3470 w += (charwidth ? charwidth : (hu_font[c]->width / 2));
3471 }
3472
3473 return w;
3474 }
3475
3476 //
3477 // Find string width from tny_font chars
3478 //
V_ThinStringWidth(const char * string,INT32 option)3479 INT32 V_ThinStringWidth(const char *string, INT32 option)
3480 {
3481 INT32 c, w = 0;
3482 INT32 spacewidth = 2, charwidth = 0;
3483 size_t i;
3484
3485 switch (option & V_SPACINGMASK)
3486 {
3487 case V_MONOSPACE:
3488 spacewidth = 5;
3489 /* FALLTHRU */
3490 case V_OLDSPACING:
3491 charwidth = 5;
3492 break;
3493 case V_6WIDTHSPACE:
3494 spacewidth = 3;
3495 default:
3496 break;
3497 }
3498
3499 for (i = 0; i < strlen(string); i++)
3500 {
3501 if (string[i] & 0x80)
3502 continue;
3503 c = toupper(string[i]) - HU_FONTSTART;
3504 if (c < 0 || c >= HU_FONTSIZE || !tny_font[c])
3505 w += spacewidth;
3506 else
3507 w += (charwidth ? charwidth : tny_font[c]->width);
3508 }
3509
3510 return w;
3511 }
3512
3513 //
3514 // Find string width from tny_font chars, 0.5x scale
3515 //
V_SmallThinStringWidth(const char * string,INT32 option)3516 INT32 V_SmallThinStringWidth(const char *string, INT32 option)
3517 {
3518 INT32 w = V_ThinStringWidth(string, option)<<FRACBITS;
3519 return w/2 + FRACUNIT; // +FRACUNIT because otherwise it's offset wrong.
3520 }
3521
3522 boolean *heatshifter = NULL;
3523 INT32 lastheight = 0;
3524 INT32 heatindex[2] = { 0, 0 };
3525
3526 //
3527 // V_DoPostProcessor
3528 //
3529 // Perform a particular image postprocessing function.
3530 //
3531 #include "p_local.h"
V_DoPostProcessor(INT32 view,postimg_t type,INT32 param)3532 void V_DoPostProcessor(INT32 view, postimg_t type, INT32 param)
3533 {
3534 #if NUMSCREENS < 5
3535 // do not enable image post processing for ARM, SH and MIPS CPUs
3536 (void)view;
3537 (void)type;
3538 (void)param;
3539 #else
3540 INT32 height, yoffset;
3541
3542 #ifdef HWRENDER
3543 if (rendermode != render_soft)
3544 return;
3545 #endif
3546
3547 if (view < 0 || view >= 2 || (view == 1 && !splitscreen))
3548 return;
3549
3550 if (splitscreen)
3551 height = vid.height/2;
3552 else
3553 height = vid.height;
3554
3555 if (view == 1)
3556 yoffset = vid.height/2;
3557 else
3558 yoffset = 0;
3559
3560 if (type == postimg_water)
3561 {
3562 UINT8 *tmpscr = screens[4];
3563 UINT8 *srcscr = screens[0];
3564 INT32 y;
3565 angle_t disStart = (leveltime * 128) & FINEMASK; // in 0 to FINEANGLE
3566 INT32 newpix;
3567 INT32 sine;
3568 //UINT8 *transme = R_GetTranslucencyTable(tr_trans50);
3569
3570 for (y = yoffset; y < yoffset+height; y++)
3571 {
3572 sine = (FINESINE(disStart)*5)>>FRACBITS;
3573 newpix = abs(sine);
3574
3575 if (sine < 0)
3576 {
3577 M_Memcpy(&tmpscr[y*vid.width+newpix], &srcscr[y*vid.width], vid.width-newpix);
3578
3579 // Cleanup edge
3580 while (newpix)
3581 {
3582 tmpscr[y*vid.width+newpix] = srcscr[y*vid.width];
3583 newpix--;
3584 }
3585 }
3586 else
3587 {
3588 M_Memcpy(&tmpscr[y*vid.width+0], &srcscr[y*vid.width+sine], vid.width-newpix);
3589
3590 // Cleanup edge
3591 while (newpix)
3592 {
3593 tmpscr[y*vid.width+vid.width-newpix] = srcscr[y*vid.width+(vid.width-1)];
3594 newpix--;
3595 }
3596 }
3597
3598 /*
3599 Unoptimized version
3600 for (x = 0; x < vid.width*vid.bpp; x++)
3601 {
3602 newpix = (x + sine);
3603
3604 if (newpix < 0)
3605 newpix = 0;
3606 else if (newpix >= vid.width)
3607 newpix = vid.width-1;
3608
3609 tmpscr[y*vid.width + x] = srcscr[y*vid.width+newpix]; // *(transme + (srcscr[y*vid.width+x]<<8) + srcscr[y*vid.width+newpix]);
3610 }*/
3611 disStart += 22;//the offset into the displacement map, increment each game loop
3612 disStart &= FINEMASK; //clip it to FINEMASK
3613 }
3614
3615 VID_BlitLinearScreen(tmpscr+vid.width*vid.bpp*yoffset, screens[0]+vid.width*vid.bpp*yoffset,
3616 vid.width*vid.bpp, height, vid.width*vid.bpp, vid.width);
3617 }
3618 else if (type == postimg_motion) // Motion Blur!
3619 {
3620 UINT8 *tmpscr = screens[4];
3621 UINT8 *srcscr = screens[0];
3622 INT32 x, y;
3623
3624 // TODO: Add a postimg_param so that we can pick the translucency level...
3625 UINT8 *transme = R_GetTranslucencyTable(param);
3626
3627 for (y = yoffset; y < yoffset+height; y++)
3628 {
3629 for (x = 0; x < vid.width; x++)
3630 {
3631 tmpscr[y*vid.width + x]
3632 = colormaps[*(transme + (srcscr [y*vid.width+x ] <<8) + (tmpscr[y*vid.width+x]))];
3633 }
3634 }
3635 VID_BlitLinearScreen(tmpscr+vid.width*vid.bpp*yoffset, screens[0]+vid.width*vid.bpp*yoffset,
3636 vid.width*vid.bpp, height, vid.width*vid.bpp, vid.width);
3637 }
3638 else if (type == postimg_flip) // Flip the screen upside-down
3639 {
3640 UINT8 *tmpscr = screens[4];
3641 UINT8 *srcscr = screens[0];
3642 INT32 y, y2;
3643
3644 for (y = yoffset, y2 = yoffset+height - 1; y < yoffset+height; y++, y2--)
3645 M_Memcpy(&tmpscr[y2*vid.width], &srcscr[y*vid.width], vid.width);
3646
3647 VID_BlitLinearScreen(tmpscr+vid.width*vid.bpp*yoffset, screens[0]+vid.width*vid.bpp*yoffset,
3648 vid.width*vid.bpp, height, vid.width*vid.bpp, vid.width);
3649 }
3650 else if (type == postimg_heat) // Heat wave
3651 {
3652 UINT8 *tmpscr = screens[4];
3653 UINT8 *srcscr = screens[0];
3654 INT32 y;
3655
3656 // Make sure table is built
3657 if (heatshifter == NULL || lastheight != height)
3658 {
3659 if (heatshifter)
3660 Z_Free(heatshifter);
3661
3662 heatshifter = Z_Calloc(height * sizeof(boolean), PU_STATIC, NULL);
3663
3664 for (y = 0; y < height; y++)
3665 {
3666 if (M_RandomChance(FRACUNIT/8)) // 12.5%
3667 heatshifter[y] = true;
3668 }
3669
3670 heatindex[0] = heatindex[1] = 0;
3671 lastheight = height;
3672 }
3673
3674 for (y = yoffset; y < yoffset+height; y++)
3675 {
3676 if (heatshifter[heatindex[view]++])
3677 {
3678 // Shift this row of pixels to the right by 2
3679 tmpscr[y*vid.width] = srcscr[y*vid.width];
3680 M_Memcpy(&tmpscr[y*vid.width+vid.dupx], &srcscr[y*vid.width], vid.width-vid.dupx);
3681 }
3682 else
3683 M_Memcpy(&tmpscr[y*vid.width], &srcscr[y*vid.width], vid.width);
3684
3685 heatindex[view] %= height;
3686 }
3687
3688 heatindex[view]++;
3689 heatindex[view] %= vid.height;
3690
3691 VID_BlitLinearScreen(tmpscr+vid.width*vid.bpp*yoffset, screens[0]+vid.width*vid.bpp*yoffset,
3692 vid.width*vid.bpp, height, vid.width*vid.bpp, vid.width);
3693 }
3694 #endif
3695 }
3696
3697 // Generates a RGB565 color look-up table
InitColorLUT(colorlookup_t * lut,RGBA_t * palette,boolean makecolors)3698 void InitColorLUT(colorlookup_t *lut, RGBA_t *palette, boolean makecolors)
3699 {
3700 size_t palsize = (sizeof(RGBA_t) * 256);
3701
3702 if (!lut->init || memcmp(lut->palette, palette, palsize))
3703 {
3704 INT32 i;
3705
3706 lut->init = true;
3707 memcpy(lut->palette, palette, palsize);
3708
3709 for (i = 0; i < 0xFFFF; i++)
3710 lut->table[i] = 0xFFFF;
3711
3712 if (makecolors)
3713 {
3714 UINT8 r, g, b;
3715
3716 for (r = 0; r < 0xFF; r++)
3717 for (g = 0; g < 0xFF; g++)
3718 for (b = 0; b < 0xFF; b++)
3719 {
3720 i = CLUTINDEX(r, g, b);
3721 if (lut->table[i] == 0xFFFF)
3722 lut->table[i] = NearestPaletteColor(r, g, b, palette);
3723 }
3724 }
3725 }
3726 }
3727
GetColorLUT(colorlookup_t * lut,UINT8 r,UINT8 g,UINT8 b)3728 UINT8 GetColorLUT(colorlookup_t *lut, UINT8 r, UINT8 g, UINT8 b)
3729 {
3730 INT32 i = CLUTINDEX(r, g, b);
3731 if (lut->table[i] == 0xFFFF)
3732 lut->table[i] = NearestPaletteColor(r, g, b, lut->palette);
3733 return lut->table[i];
3734 }
3735
GetColorLUTDirect(colorlookup_t * lut,UINT8 r,UINT8 g,UINT8 b)3736 UINT8 GetColorLUTDirect(colorlookup_t *lut, UINT8 r, UINT8 g, UINT8 b)
3737 {
3738 INT32 i = CLUTINDEX(r, g, b);
3739 return lut->table[i];
3740 }
3741
3742 // V_Init
3743 // old software stuff, buffers are allocated at video mode setup
3744 // here we set the screens[x] pointers accordingly
3745 // WARNING: called at runtime (don't init cvar here)
V_Init(void)3746 void V_Init(void)
3747 {
3748 INT32 i;
3749 UINT8 *base = vid.buffer;
3750 const INT32 screensize = vid.rowbytes * vid.height;
3751
3752 LoadMapPalette();
3753
3754 for (i = 0; i < NUMSCREENS; i++)
3755 screens[i] = NULL;
3756
3757 // start address of NUMSCREENS * width*height vidbuffers
3758 if (base)
3759 {
3760 for (i = 0; i < NUMSCREENS; i++)
3761 screens[i] = base + i*screensize;
3762 }
3763
3764 if (vid.direct)
3765 screens[0] = vid.direct;
3766
3767 #ifdef DEBUG
3768 CONS_Debug(DBG_RENDER, "V_Init done:\n");
3769 for (i = 0; i < NUMSCREENS; i++)
3770 CONS_Debug(DBG_RENDER, " screens[%d] = %x\n", i, screens[i]);
3771 #endif
3772 }
3773
V_Recalc(void)3774 void V_Recalc(void)
3775 {
3776 // scale 1,2,3 times in x and y the patches for the menus and overlays...
3777 // calculated once and for all, used by routines in v_video.c and v_draw.c
3778 vid.dupx = vid.width / BASEVIDWIDTH;
3779 vid.dupy = vid.height / BASEVIDHEIGHT;
3780 vid.dupx = vid.dupy = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy);
3781 vid.fdupx = FixedDiv(vid.width*FRACUNIT, BASEVIDWIDTH*FRACUNIT);
3782 vid.fdupy = FixedDiv(vid.height*FRACUNIT, BASEVIDHEIGHT*FRACUNIT);
3783
3784 #ifdef HWRENDER
3785 //if (rendermode != render_opengl && rendermode != render_none) // This was just placing it incorrectly at non aspect correct resolutions in opengl
3786 // 13/11/18:
3787 // The above is no longer necessary, since we want OpenGL to be just like software now
3788 // -- Monster Iestyn
3789 #endif
3790 vid.fdupx = vid.fdupy = (vid.fdupx < vid.fdupy ? vid.fdupx : vid.fdupy);
3791
3792 vid.meddupx = (UINT8)(vid.dupx >> 1) + 1;
3793 vid.meddupy = (UINT8)(vid.dupy >> 1) + 1;
3794 #ifdef HWRENDER
3795 vid.fmeddupx = vid.meddupx*FRACUNIT;
3796 vid.fmeddupy = vid.meddupy*FRACUNIT;
3797 #endif
3798
3799 vid.smalldupx = (UINT8)(vid.dupx / 3) + 1;
3800 vid.smalldupy = (UINT8)(vid.dupy / 3) + 1;
3801 #ifdef HWRENDER
3802 vid.fsmalldupx = vid.smalldupx*FRACUNIT;
3803 vid.fsmalldupy = vid.smalldupy*FRACUNIT;
3804 #endif
3805 }
3806