1 // Emacs style mode select   -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: v_video.c 1564 2020-12-19 06:21:07Z wesleyjohnson $
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 // Portions Copyright (C) 1998-2012 by DooM Legacy Team.
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either version 2
12 // of the License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 // GNU General Public License for more details.
18 //
19 //
20 // $Log: v_video.c,v $
21 // Revision 1.36  2004/07/27 08:19:37  exl
22 // New fmod, fs functions, bugfix or 2, patrol nodes
23 //
24 // Revision 1.35  2004/04/20 00:34:26  andyp
25 // Linux compilation fixes and string cleanups
26 //
27 // Revision 1.34  2003/08/11 13:50:00  hurdler
28 // go final + translucent HUD + fix spawn in net game
29 //
30 // Revision 1.33  2003/07/13 13:16:15  hurdler
31 //
32 // Revision 1.32  2003/06/11 04:45:17  ssntails
33 // High-res patch drawer added.
34 //
35 // Revision 1.31  2003/06/10 23:36:09  ssntails
36 // Variable flat support (32x32 to 2048x2048)
37 //
38 // Revision 1.30  2003/05/04 04:20:19  sburke
39 // Use SHORT macro for big-endian machines.
40 //
41 // Revision 1.29  2001/12/15 18:41:35  hurdler
42 // small commit, mainly splitscreen fix
43 //
44 // Revision 1.28  2001/07/28 16:18:37  bpereira
45 // Revision 1.27  2001/05/16 21:21:14  bpereira
46 // Revision 1.26  2001/04/28 14:33:41  metzgermeister
47 // Revision 1.25  2001/04/17 22:30:40  hurdler
48 // Revision 1.24  2001/04/09 20:20:46  metzgermeister
49 // fixed crash bug
50 //
51 // Revision 1.23  2001/04/01 17:35:07  bpereira
52 // Revision 1.22  2001/03/30 17:12:51  bpereira
53 //
54 // Revision 1.21  2001/03/13 22:14:20  stroggonmeth
55 // Long time no commit. 3D floors, FraggleScript, portals, ect.
56 //
57 // Revision 1.20  2001/02/28 17:50:55  bpereira
58 // Revision 1.19  2001/02/24 13:35:21  bpereira
59 //
60 // Revision 1.18  2001/02/19 17:40:34  hurdler
61 // Fix a bug with "chat on" in hw mode
62 //
63 // Revision 1.17  2001/02/10 13:05:45  hurdler
64 //
65 // Revision 1.16  2001/01/31 17:14:08  hurdler
66 // Add cv_scalestatusbar in hardware mode
67 //
68 // Revision 1.15  2001/01/25 22:15:44  bpereira
69 // added heretic support
70 //
71 // Revision 1.14  2000/11/06 20:52:16  bpereira
72 // Revision 1.13  2000/11/04 16:23:44  bpereira
73 // Revision 1.12  2000/11/02 19:49:37  bpereira
74 //
75 // Revision 1.11  2000/10/04 16:19:24  hurdler
76 // Change all those "3dfx names" to more appropriate names
77 //
78 // Revision 1.10  2000/08/31 14:30:56  bpereira
79 //
80 // Revision 1.9  2000/04/27 17:43:19  hurdler
81 // colormap code in hardware mode is now the default
82 //
83 // Revision 1.8  2000/04/24 20:24:38  bpereira
84 //
85 // Revision 1.7  2000/04/24 15:10:57  hurdler
86 // Support colormap for text
87 //
88 // Revision 1.6  2000/04/22 21:12:15  hurdler
89 //
90 // Revision 1.5  2000/04/06 20:47:08  hurdler
91 // add Boris' changes for coronas in doom3.wad
92 //
93 // Revision 1.4  2000/03/29 20:10:50  hurdler
94 //
95 // Revision 1.3  2000/03/12 23:16:41  linuxcub
96 // Fixed definition of VID_BlitLinearScreen (Well, it now compiles under RH61)
97 //
98 // Revision 1.2  2000/02/27 00:42:11  hurdler
99 // Revision 1.1.1.1  2000/02/22 20:32:33  hurdler
100 // Initial import into CVS (v1.29 pr3)
101 //
102 //
103 // DESCRIPTION:
104 //      Gamma correction LUT stuff.
105 //      Functions to draw patches (by post) directly to screen.
106 //      Functions to blit a block to the screen.
107 //
108 //-----------------------------------------------------------------------------
109 
110 #include "doomincl.h"
111 #include "r_local.h"
112 #include "v_video.h"
113 #include "hu_stuff.h"
114 #include "r_draw.h"
115 #include "r_data.h"
116   // NearestColor
117 #include "console.h"
118 
119 #include "i_video.h"
120   // rendermode
121 #include "i_system.h"
122   // I_GetTime
123 #include "z_zone.h"
124 #include "doomstat.h"
125   // gamemode
126 #include "p_setup.h"
127   // P_flatsize_to_index
128 #include "m_misc.h"
129   // drawmode, configfile functions
130 
131 
132 #ifdef HWRENDER
133 #include "hardware/hw_glob.h"
134 #endif
135 
136 
137 // Enable when DEBUG and cannot see text.
138 //#define DEBUG_FORCE_COLOR
139 #ifdef DEBUG_FORCE_COLOR
140 # if ( defined(DEBUG_WINDOWED) && defined(WIN32) )
141 #  define DEBUG_FORCE_COLOR_WIN
142 # endif
143 #endif
144 
145 
146 #if defined( ENABLE_DRAW15 ) || defined( ENABLE_DRAW16 ) || defined( ENABLE_DRAW24 ) || defined( ENABLE_DRAW32 )
147 #define ENABLE_DRAWEXT
148 #endif
149 
150 // Chexquest Newmaps has black bars and crosshairs which are drawn at (-1,-1).
151 // They are all black, not aligned, and the movement is slight,
152 // so moving the draw is acceptable.
153 // Enables the accurate clipping.  The default is to move the draw instead.
154 //#define ENABLE_CLIP_DRAWSCALED
155 
156 
157 // [WDJ] Interfaces to port video control, common to all
158 
159 // Each screen is vid.screen_size (which may be larger than width * height)
160 // width*height is wrong for the Mac, which pads buffer to power of 2
161 // someone stuck in an extra screen ptr
162 byte *screens[NUMSCREENS+1];
163 
164 rendermode_e   rendermode = render_init;
165 byte  rendermode_recalc = false;  // signal a change
166 
167 byte  drawmode_recalc = false;
168 
169 #ifdef HWRENDER
170 // patches are stored in HWR format, set when HWR rendermode.
171 byte  HWR_patchstore = false;
172 #endif
173 
174 // Request to the drivers.
175 byte  req_drawmode = DRM_none;  // vid_drawmode_e
176 byte  req_bitpp = 0;  // DRM_explicit_bpp param
177 byte  req_alt_bitpp = 0;  // DRM_explicit_bpp param
178 byte  req_command_video_settings;  // command line
179 uint16_t  req_width, req_height;
180 
181 // Driver state
182 byte  graphics_state = VGS_off; // Is used in console.c and screen.c
183 byte  native_bitpp;
184 byte  native_bytepp;
185 byte  native_drawmode; // vid_drawmode_e
186 
187 // To disable fullscreen at startup.
188 byte  allow_fullscreen = false;
189 
190 
191 void Set_drawmode_OnChange( void );
192 
193 // values from vid_drawmode_e
194 CV_PossibleValue_t drawmode_sel_t[] = {
195    {DRM_8pal,"Software 8bit"},
196    {DRM_15,"Software 15bit"},
197    {DRM_16,"Software 16bit"},
198    {DRM_24,"Software 24bit"},
199    {DRM_32,"Software 32bit"},
200    {DRM_native,"Native"},
201 #ifdef HWRENDER
202    {DRM_opengl,"OpenGL"},
203 #ifdef SMIF_WIN_NATIVE
204    {DRM_minigl, "MiniGL"},
205    {DRM_glide, "Glide"},
206    {DRM_d3d,   "D3D"},
207 #endif
208 #endif
209    {0,NULL} };
210 consvar_t cv_drawmode = { "drawmode", "Software 8bit", CV_SAVE | CV_CALL | CV_CFG1, drawmode_sel_t, Set_drawmode_OnChange  };
211 
212 // fullscreen or window
213 const byte vid_mode_table[2] = { MODE_window, MODE_fullscreen };
214 
215 byte set_drawmode = 255;  // vid_drawmode_e
216 const byte num_drawmode_sel = 8;
217 
Set_drawmode_OnChange(void)218 void Set_drawmode_OnChange( void )
219 {
220     drawmode_recalc = true;
221 }
222 
223 
224 // Reverse index into drawmode_sel_t
225 // indexed by vid_drawmode_e
226 byte drawmode_to_drawmode_sel_t[] = {
227    0,  // DRM_none
228    0,  // DRM_8pal
229    1,  // DRM_15,
230    2,  // DRM_16,
231    3,  // DRM_24,
232    4,  // DRM_32,
233    0,  // DRM_explicit_bpp
234    5,  // DRM_native
235 #ifdef HWRENDER
236    6,  // DRM_opengl
237 #ifdef SMIF_WIN_NATIVE
238    7,  // DRM_minigl
239    8,  // DRM_glide
240    9,  // DRM_d3d
241 #else
242    0, 0, 0,
243 #endif
244 #else
245    0, 0, 0, 0,
246 #endif
247    0   // DRM_END
248 };
249 
250 // indexed by vid_drawmode_e
251 byte drawmode_sel_avail[] = {
252    0,  // DRM_none
253    DRM_8pal,  // 8 bit
254 #ifdef ENABLE_DRAW15
255    DRM_15,
256 #else
257    0,
258 #endif
259 #ifdef ENABLE_DRAW16
260    DRM_16,
261 #else
262    0,
263 #endif
264 #ifdef ENABLE_DRAW24
265    DRM_24,
266 #else
267    0,
268 #endif
269 #ifdef ENABLE_DRAW32
270    DRM_32,
271 #else
272    0,
273 #endif
274    DRM_explicit_bpp,  // -bpp -truecolor -highcolor
275    DRM_native,  // Native
276 #ifdef HWRENDER
277    DRM_opengl,  // OpenGL
278 #ifdef SMIF_WIN_NATIVE
279    DRM_minigl,  // MiniGL
280    DRM_glide,   // Glide
281    DRM_d3d,     // D3D
282 #else
283    0, 0,
284 #endif
285 #else
286    0, 0, 0,
287 #endif
288    0,  // DRM_END
289 };
290 
291 // indexed by vid_drawmode_e
292 static
293 byte drawmode_to_bpp[] = {0,8,15,16,24,32, 99,99,99,99,99,99,99};
294 
295 // indexed by vid_drawmode_e
296 static
297 byte drawmode_to_rendermode[] = {
298    render_soft, // none
299    render_soft, // Software 8 bit
300    render_soft, // Software 15 bit
301    render_soft, // Software 16 bit
302    render_soft, // Software 24 bit
303    render_soft, // Software 32 bit
304    render_soft, // Software req_bitpp
305    render_soft, // Software native
306    render_opengl, // OpenGL
307    render_opengl, // MiniGL
308    render_glide,  // Glide
309    render_d3d,    // D3D
310 };
311 
312 #if 0
313 // Indexed by rendermode_e
314 const char * rendermode_name[] = {
315     "",
316     "Software",
317     "OpenGL",
318 #ifdef SMIF_WIN_NATIVE
319     "Glide",
320     "D3D",
321 #else
322      "", "",
323 #endif
324     "None"
325 };
326 #endif
327 
328 
329 
330 // Not used, conflict.
331 // There is a DRM_explicit_bpp config file.
332 // But there is not a DRM_explicit_bpp menu selection.
333 //#define CONVERT_BP_TO_DRM
334 
335 #ifdef CONVERT_BP_TO_DRM
336 // Find the cv_drawmode for a bitpp.
bpp_to_drawmode(byte bitpp)337 static byte  bpp_to_drawmode( byte bitpp )
338 {
339     byte dm;
340     for( dm=0; dm<DRM_END; dm++ )
341     {
342         if( drawmode_to_bpp[dm] == bitpp )
343             return dm;
344     }
345     return 99;  // invalid
346 }
347 #endif
348 
349 
350 // Set rendermode
351 //  drawmode : vid_drawmode_e
352 //  change_config : boolean, save current config file, load another
353 // Called by D_DoomMain, SCR_SetMode
V_switch_drawmode(byte drawmode,byte change_config)354 byte  V_switch_drawmode( byte drawmode, byte change_config )
355 {
356     byte old_drawmode = cv_drawmode.EV;
357     byte old_render = rendermode;
358 
359 #ifdef DEBUG_DRAWMODE
360     GenPrintf( EMSG_debug, "V_switch_drawmode  ( %i )\n", drawmode );
361 #endif
362 
363     if( drawmode >= DRM_END )  return 0;
364     // restore of vs settings is last
365 
366     if( drawmode <= DRM_32 )
367     {
368         req_bitpp = drawmode_to_bpp[drawmode];
369         if( ! V_CanDraw( req_bitpp ) )  goto candraw_reject;
370         if( ! VID_Query_Modelist( drawmode, cv_fullscreen.EV, req_bitpp ) )  goto query_reject;
371         req_drawmode = DRM_explicit_bpp;  // explicit bpp
372         rendermode = render_soft;
373     }
374     else if( drawmode == DRM_native )  // Native
375     {
376         if( ! V_CanDraw( native_bitpp ) )  goto candraw_reject;
377         if( ! VID_Query_Modelist( DRM_native, cv_fullscreen.EV, native_bitpp ) )  goto query_reject;
378         req_drawmode = DRM_native;  // bpp of the default screen
379         rendermode = render_soft;
380     }
381 
382     if( drawmode >= DRM_opengl && drawmode < DRM_END )
383     {
384 #ifdef HWRENDER
385         // Hardware drawmodes use native or some internal drawmode,
386         if( ! VID_Query_Modelist( drawmode, cv_fullscreen.EV, native_bitpp ) )  goto query_reject;
387         req_drawmode = drawmode;  // let driver know which hardware mode
388         rendermode = drawmode_to_rendermode[ drawmode ];
389 #else
390         goto reject;
391 #endif
392     }
393     else if( drawmode == DRM_explicit_bpp )
394     {
395         // command line, bpp, highcolor, truecolor.
396         // req_bitpp and req_alt_bpp have been set by caller
397 
398         // Error reporting uses req_bitpp and req_alt_bitpp,
399         // so don't change them before error checking is done.
400 
401         byte cd = V_CanDraw( req_bitpp );
402         byte cd_alt = V_CanDraw( req_alt_bitpp );
403         if( !cd && !cd_alt )  goto candraw_reject;  // report error on req_
404 
405         if( cd && VID_Query_Modelist( DRM_explicit_bpp, cv_fullscreen.EV, req_bitpp ) )
406         {
407             // use req_bitpp
408         }
409         else if( cd_alt && VID_Query_Modelist( DRM_explicit_bpp, cv_fullscreen.EV, req_alt_bitpp ))
410         {
411             // use the alt
412             req_bitpp = req_alt_bitpp;
413             req_alt_bitpp = 0;
414         }
415         else
416             goto query_reject;
417 
418         req_drawmode = DRM_explicit_bpp;
419         rendermode = render_soft;
420 
421 #ifdef CONVERT_BP_TO_DRM
422         // Convert to drawmode valid for cv_drawmode.
423         drawmode = bpp_to_drawmode( req_bitpp );
424 #endif
425     }
426 
427     // Setup HWR calls so can set values.
428     if( (old_drawmode != drawmode) || (old_render != rendermode) )
429     {
430 #ifdef DEBUG_DRAWMODE
431         GenPrintf( EMSG_debug, "V_switch_drawmode  rendermode= %i\n", rendermode );
432 #endif
433         rendermode_recalc = true;  // the only place this is set
434     }
435 
436     // Any HWR functions triggered by any OnChange functions
437     // must have been setup in I_Rendermode_setup.
438 
439     // Must not execute on first drawmode change.
440     if( change_config )
441     {
442         // Need to change the configfile_drawmode.
443         if( old_drawmode < DRM_END )
444         {
445             M_SaveConfig( CFG_drawmode, configfile_drawmode );
446         }
447 
448         // Remove the config values from the previous drawmode.
449         M_ClearConfig( CFG_drawmode );
450 
451         if( drawmode < DRM_END )
452         {
453 #ifdef DEBUG_DRAWMODE
454             GenPrintf( EMSG_debug, "V_switch_drawmode  LoadConfig\n" );
455 #endif
456             // Change to the new drawmode config file.
457             M_Set_configfile_drawmode( drawmode );
458             // WARNING : this do a "COM_BufExecute()"
459             M_LoadConfig( CFG_drawmode, configfile_drawmode );
460             SCR_apply_video_settings();  // setmodeneeded
461         }
462     }
463 
464     if( drawmode < DRM_END )
465     {
466         // save the new drawmode as temporary
467         cv_drawmode.EV = drawmode;
468         cv_drawmode.state |= CS_EV_PROT;  // protect against restore
469         // To change the save value:  CV_SetValue( &cv_drawmode, cv_drawmode.EV );
470     }
471 
472     return 1;
473 
474 // Error handling
475 candraw_reject:
476     if( verbose )
477     {
478         if( req_alt_bitpp )
479             GenPrintf( EMSG_ver, "Cannot draw %i bitpp, nor %i bitpp.\n", req_bitpp, req_alt_bitpp );
480         else
481             GenPrintf( EMSG_ver, "Cannot draw %i bitpp.\n", req_bitpp );
482     }
483     goto reject;
484 
485 query_reject:
486     if( verbose )
487         GenPrintf( EMSG_ver, "No modes for %s, %i\n", cv_fullscreen.EV ? "Fullscreen":"Window", req_bitpp );
488 
489 reject:
490 #ifdef DEBUG_DRAWMODE
491     GenPrintf( EMSG_debug, "  V_switch_drawmode  ( %i )  REJECT\n", drawmode );
492 #endif
493     return 0;
494 }
495 
496 
497 
498 // Darker background
499 CV_PossibleValue_t darkback_sel_t[] = {
500    {0,"Half"},
501    {1,"Med"},
502    {2,"Dark"},
503    {0,NULL} };
504 consvar_t cv_darkback = { "darkback", "1", CV_SAVE, darkback_sel_t, NULL };
505 
CV_fontsize_OnChange(void)506 void CV_fontsize_OnChange(void)
507 {
508     con_recalc = 1;
509 }
510 
511 CV_PossibleValue_t fontsize_t[] = {
512    {1,"Small"},
513    {2,"Med2"},
514    {3,"Med3"},
515    {4,"Med4"},
516    {5,"Large"},
517    {0,NULL} };
518 consvar_t cv_con_fontsize =
519   { "con_fontsize", "Med2", CV_SAVE|CV_CALL, fontsize_t, CV_fontsize_OnChange };
520 consvar_t cv_msg_fontsize =
521   { "msg_fontsize", "Large", CV_SAVE|CV_CALL, fontsize_t, CV_fontsize_OnChange };
522 
523 // Controls FinalText output.
524 CV_PossibleValue_t textout_sel_t[] = {
525    {0,"Off"},
526    {1,"Vanilla"},
527    {2,"UTF8"},
528    {0,NULL} };
529 consvar_t cv_textout = { "textout", "2", CV_SAVE, textout_sel_t, NULL };
530 
531 
532 CV_PossibleValue_t ticrate_sel_t[] = {
533    {0,"Off"},
534    {1,"Graph"},
535    {2,"Numeric"},
536    {0,NULL} };
537 consvar_t cv_ticrate = { "vid_ticrate", "0", 0, ticrate_sel_t, NULL };
538 
539 
540 // synchronize page flipping with screen refresh
541 // unused and for compatibility reason
542 consvar_t cv_vidwait = {"vid_wait", "1", CV_SAVE, CV_OnOff};
543 
544 
545 
546 void CV_usegamma_OnChange();
547 void CV_gammafunc_OnChange();
548 // In m_menu.c
549 void MenuGammaFunc_dependencies( byte gamma_en,
550                                  byte black_en, byte bright_en );
551 
552 CV_PossibleValue_t gamma_func_t[] = {
553    {0,"Gamma"},
554    {1,"Gamma_black"},
555    {2,"Gamma_full"},  // gamma bright black controls
556    {3,"Linear"},
557    {0,NULL} };
558 consvar_t cv_gammafunc = { "gammafunc", "2", CV_SAVE | CV_CALL, gamma_func_t, CV_gammafunc_OnChange };
559 CV_PossibleValue_t gamma_bl_cons_t[] = { {-12, "MIN"}, {12, "MAX"}, {0, NULL} };
560 consvar_t cv_black = { "black", "0", CV_VALUE | CV_SAVE | CV_CALL, gamma_bl_cons_t, CV_usegamma_OnChange };
561 CV_PossibleValue_t gamma_br_cons_t[] = { {-12, "MIN"}, {12, "MAX"}, {0, NULL} };
562 consvar_t cv_bright = { "bright", "0", CV_VALUE | CV_SAVE | CV_CALL, gamma_br_cons_t, CV_usegamma_OnChange };
563 CV_PossibleValue_t gamma_cons_t[] = { {-12, "MIN"}, {12, "MAX"}, {0, NULL} };
564 consvar_t cv_usegamma = { "gamma", "0", CV_VALUE | CV_SAVE | CV_CALL, gamma_cons_t, CV_usegamma_OnChange };
565 
566 static byte gammatable[256];	// shared by all gamma table generators
567 
put_gammatable(int i,float fv)568 static void put_gammatable( int i, float fv )
569 {
570 #ifdef __USE_ISOC99
571     // roundf is ISOC99
572     int gv = (int) roundf( fv );
573 #else
574     int gv = (int) rint( fv );
575 #endif
576     if( gv < 0 )
577         gv = 0;
578     if( gv > 255 )
579         gv = 255;
580     gammatable[i] = gv;
581 }
582 
583 // Build a gamma table
R_BuildGammaTable(float gamma)584 static void R_BuildGammaTable(float gamma)
585 {
586     int i;
587 
588     // Calculate gammatable anew each time.
589     for (i=0; i<256; i++)
590     {
591         // Split this calculation, and use the put_gammatable function
592         // to control possible errors in non-Linux systems.
593         double di = (double)(i+1) / 256.0;
594         put_gammatable( i, pow( di, gamma) * 255.0f );
595     }
596 }
597 
598 // Declaring table with f literal (1.28f) seems to make no difference.
599 // table of gamma value for each slider position
600 float gamma_lookup_table[25] = {
601     1.48, 1.44, 1.4, 1.36, 1.32, 1.28, 1.24, 1.2, 1.16, 1.12, 1.08, 1.04,
602     1.0,	// doom gamma table 1   // at index 0
603     0.96, 0.92,
604     0.88,	// doom gamma table 2
605     0.836, 0.793,
606     0.75,	// doom gamma table 3
607     0.706, 0.663,
608     0.62,	// doom gamma table 4
609     0.58, 0.54,
610     0.50	// doom gamma table 5
611 };
612 
613 // ind: -12 .. +12
gamma_lookup(int ind)614 static inline float gamma_lookup( int ind )
615 {
616     return gamma_lookup_table[ ind + 12 ];
617 }
618 
619 
620 // Generate a power law table from gamma, plus a black level offset
621 static void
R_Generate_gamma_black_table(void)622   R_Generate_gamma_black_table( void )
623 {
624     int i;
625 //   float b0 = ((float) cv_black.value ) * (16.0 / 12.0); // black
626     float b0 = ((float) cv_black.value ) / 2.0f; // black
627     float pow_max = 255.0f - b0;
628     float gam = gamma_lookup( cv_usegamma.value );  // gamma
629 
630     gammatable[0] = 0;	// absolute black
631 
632     for( i=1; i<=255; i++ )
633     {
634         float fi = ((float) i) / 255.0f;
635         put_gammatable( i, b0 + (powf( fi, gam ) * pow_max) );
636     }
637 }
638 
639 #if 0
640 // Generate a power curve table from gamma,
641 // with a power curve black level adjustment
642 static void
643   R_Generate_gamma_black_adj_table( void )
644 {
645     // limits of black adjustment
646 #  define BLACK_SIZE  48
647     int i, gv;
648     float gvf;
649     float gam = gamma_lookup( cv_usegamma.value );  // gamma
650     float blkgam = gamma_lookup( cv_black.value ); // black
651 
652     gammatable[0] = 0;	// absolute black
653 
654     for( i=1; i<=255; i++ )
655     {
656         float fi = ((float) i) / 255.0f;
657         gvf = powf( fi, gam ) * 255.0f;
658         if( i < BLACK_SIZE )
659         {
660             // Black adjustment, using a power function over the black range.
661             // At neutral, powf = i, so adj = powf - i.
662             fi = ((float) i) / BLACK_SIZE;
663             gvf += (powf( fi, blkgam ) * BLACK_SIZE) - ((float)i);
664         }
665         put_gammatable( i, gvf );
666     }
667 }
668 #endif
669 
670 // Generate a gamma with black adj, and bright adj
671 static void
R_Generate_gamma_bright_black_table(void)672   R_Generate_gamma_bright_black_table( void )
673 {
674 #  define BRIGHT_MIN  60
675 #  define BRIGHT_MID  130
676     int i, di, start_index, end_index;
677     float bf = ((float)cv_bright.value) * (256.0f / 6.0f / 12.0f);
678     float n3 = bf*bf*bf;  // -1728 .. 1728
679     float d2 = bf*bf;  // 144 .. 0 .. 144
680     float gf, w0;
681 
682     R_Generate_gamma_black_table();
683 
684     // The following only modifies the gamma table with brightness.
685     // Linux handles d2=0 without error, but MINGW does not.
686     if( d2 < 0.1 )  return;
687 
688     // bright correct using curve: witch of agnesi
689     // y = (d**3)/(x**2 + d**2)
690     // MIN to MID
691     start_index = BRIGHT_MIN;
692     end_index = BRIGHT_MID;
693     do
694     {
695         di = end_index - start_index;
696         w0 = (n3 / ( (di*di) + d2 )) / di; 	// witch at low point / di
697         for( i=start_index; i<=end_index; i++ )
698         {
699             di = abs(BRIGHT_MID - i);
700             gf = n3 / ( (di*di) + d2 );	// witch of agnesi
701             gf -= w0 * di; // smooth transition on tail
702             // add adjustment to table
703             put_gammatable( i, gammatable[i] + gf );
704         }
705         // MID to 255
706         start_index = BRIGHT_MID + 1;
707         end_index = 255;
708     } while( i < 255 );
709 }
710 
711 static void
R_Generate_smooth5_linear_gamma_table(void)712   R_Generate_smooth5_linear_gamma_table( void )
713 {
714     const int bl_index = 28;
715     const int bl_ref_offset = 20; // (8 .. 28 .. 50);
716     const int wl_index = 128;
717     const int wl_ref_offset = 48; // (60 .. 128 .. 176);
718     float bl_offset = ((float) cv_black.value ) * bl_ref_offset / 12.0f;
719     float wl_offset = ((float) cv_bright.value ) * wl_ref_offset / 12.0f;
720     float b0 = 0.0, lf = 1.0;
721     int i, start_index, end_index, seg = 0;
722 
723     // monotonic checks
724     if( (wl_offset + wl_index) < (bl_offset + bl_index + 5) ) {
725         // enforce monotonic by altering wl
726         wl_offset = bl_offset + bl_index + 5 - wl_index;
727     }
728     if( (wl_offset + wl_index) > 250.0f ) {
729         // enforce monotonic by altering wl
730         wl_offset = 250.0f - wl_index;
731     }
732     // eqn: bl_offset = ( b0 + (lf * bl_index))
733     b0 = bl_offset * 5 / 16;
734     if( b0 < 0.0 ) b0 = 0;
735     gammatable[0] = 0;	// absolute black
736     gammatable[1] = (b0 * 5)/16;	// near black
737     gammatable[2] = (b0 * 11)/16;
738     gammatable[3] = (b0 * 15)/16;
739 
740     // generate rest of table in three linear segments
741     end_index = 3; // start at 4
742     for( seg=0; seg<=2; seg++ )
743     {
744         start_index = end_index + 1;
745         switch( seg )
746         {
747          case 0:
748            // linear from [1] to [bl_index]
749            end_index = bl_index;
750            lf = (bl_offset - b0) / bl_index;
751            break;
752          case 1:
753            // linear from [bl_index+1] to [wl_index]
754            // eqn: bl_index + bl_offset = bl_index + ( b0 + (lf * bl_index))
755            // eqn: wl_index + wl_offset = wl_index + ( b0 + (lf * wl_index))
756            end_index = wl_index;
757            lf = ( wl_offset - bl_offset ) / ( wl_index - bl_index );
758            b0 = bl_offset - (lf * bl_index);
759            break;
760          case 2:
761            // linear from [wl_index+1] to [255]
762            end_index = 255;
763            lf =  - wl_offset / (255 - wl_index);
764            b0 = wl_offset - (lf * wl_index);
765            break;
766         }
767 
768         for( i=start_index; i<=end_index; i++ )
769         {
770             put_gammatable( i, (b0 + ( lf * i ) + i)); // linear
771             // smooth over 5 using weights 3 3 4 3 3
772             gammatable[i-2] = ((gammatable[i-4] + gammatable[i-3]
773                                 + gammatable[i-1] + gammatable[i])*3
774                                + gammatable[i-2]*4 ) / 16;
775         }
776     }
777 }
778 
779 
780 // [WDJ] Default palette for Launch, font1, error messages
781 #define DEFAULT_PALSIZE  (3*9)
782 byte default_pal[ DEFAULT_PALSIZE ] = {
783     0, 0, 0,
784     10, 10, 10,
785     253, 253, 253,
786     250, 0, 0,
787     0, 250, 0,
788     0, 0, 250,
789     120, 0, 0,  // protection for DEBUG_FORCE_COLOR
790     0, 120, 0,
791     0, 0, 120,
792 };
793 
794 // local copy of the palette for V_GetColor()
795 RGBA_t *pLocalPalette = NULL;
796 #ifdef DEBUG_FORCE_COLOR_WIN
797 int    num_palette = 0;
798 #endif
799 
800 // Update working palette when palette loaded, or gamma changes.
801 // Keep a copy of the palette so that we can get the RGB
802 // value for a color index at any time.
LoadPalette(const char * lumpname)803 static void LoadPalette(const char *lumpname)
804 {
805   lumpnum_t ln;
806   int palsize, i;
807   byte * pal;  // stepping through pal lump;
808 
809   if( ! VALID_LUMP( W_CheckNumForName( lumpname ) ) )
810   {
811       // [WDJ] Missing palette lump will be detected later,
812       // but need a palette to print the messages.
813       palsize = DEFAULT_PALSIZE / 3;
814       pal = default_pal;
815   }
816   else
817   {
818       // load the palette from a wad
819       ln = W_GetNumForName(lumpname);
820       // the palsize will be multiples of 256, ( and 3 colors )
821       palsize = W_LumpLength(ln) / 3;
822       pal = W_CacheLumpNum(ln, PU_CACHE);
823   }
824 
825   if (pLocalPalette)
826     Z_Free(pLocalPalette);
827 
828   pLocalPalette = Z_Malloc(sizeof(RGBA_t) * palsize, PU_STATIC, NULL);
829 #ifdef DEBUG_FORCE_COLOR_WIN
830   num_palette = palsize >> 8;  // number of 256 byte palettes
831 #endif
832 
833   for (i = 0; i < palsize; i++)
834   {
835       pLocalPalette[i].s.red = gammatable[*pal++];
836       pLocalPalette[i].s.green = gammatable[*pal++];
837       pLocalPalette[i].s.blue = gammatable[*pal++];
838 //        if( (i&0xff) == HWR_PATCHES_CHROMAKEY_COLORINDEX )
839 //            pLocalPalette[i].s.alpha = 0;
840 //        else
841       pLocalPalette[i].s.alpha = 0xff;
842   }
843 
844   // update our console colors from whatever is available
845   // in palette 0 of pLocalPalette
846   ci_black = NearestColor( 0, 0, 0 );
847   ci_white = NearestColor( 250, 250, 250 );
848   ci_green = NearestColor( 0, 250, 0 );
849   ci_grey = NearestColor( 10, 10, 10 );
850 }
851 
852 // -------------+
853 // V_SetPalette : Set the current palette to use for palettized graphics
854 //              : (that is, most if not all of Doom's original graphics)
855 // -------------+
856 // Called by D_Display, SCR_Startup, SCR_SetMode, SB_PaletteFlash
857 // Called by ST_doPaletteStuff, ST_Stop, CV_usegamma_OnChange, CV_Gammaxxx_ONChange
V_SetPalette(int palettenum)858 void V_SetPalette(int palettenum)
859 {
860     // vid : from video setup
861     if (!pLocalPalette)
862         LoadPalette("PLAYPAL");
863 
864 #ifdef DEBUG_FORCE_COLOR_WIN
865     // Enable when DEBUG and cannot see text.
866     if( palettenum <= num_palette )
867     {
868         // Palette fix during debug, otherwise black text on black background
869         RGBA_t * pp = &pLocalPalette[palettenum * 256];
870         if( pp[6].s.red < 96 )
871             pp[6].s.red = 96;  // at least get red text on black
872         if( pp[7].s.green < 96 )
873             pp[7].s.green = 96;  // at least get green text on black
874     }
875 #endif
876 
877 #ifdef HWRENDER
878     if( rendermode != render_soft )
879         HWR_SetPalette(&pLocalPalette[palettenum * 256]);
880     else
881 #endif
882     {
883 #ifdef ENABLE_DRAWEXT
884         if ( vid.bytepp > 1 )  // highcolor, truecolor
885             R_Init_color8_translate(&pLocalPalette[palettenum * 256]);  // palette change
886         else
887 #endif
888         {
889 #ifdef ENABLE_DRAW8_USING_12
890             R_Init_color12_translate( &pLocalPalette[palettenum * 256] );
891 #endif
892             I_SetPalette(&pLocalPalette[palettenum * 256]);
893         }
894     }
895 }
896 
897 // Called by finale: F_DrawHeretic, F_Responder
V_SetPaletteLump(const char * pal)898 void V_SetPaletteLump(const char *pal)
899 {
900     // vid : from video setup
901     LoadPalette(pal);
902 
903 #ifdef HWRENDER
904     if( rendermode != render_soft )
905         HWR_SetPalette(pLocalPalette);
906     else
907 #endif
908     {
909 #ifdef ENABLE_DRAWEXT
910         if ( vid.bytepp > 1 )  // highcolor, truecolor
911             R_Init_color8_translate(pLocalPalette);  // palette change
912         else
913 #endif
914         {
915 #ifdef ENABLE_DRAW8_USING_12
916             R_Init_color12_translate( pLocalPalette );
917 #endif
918             I_SetPalette(pLocalPalette);
919         }
920     }
921 }
922 
CV_usegamma_OnChange(void)923 void CV_usegamma_OnChange(void)
924 {
925     switch( cv_gammafunc.EV ){
926      case 1:
927         R_Generate_gamma_black_table();
928         break;
929      case 2:
930         R_Generate_gamma_bright_black_table();
931         break;
932      case 3:
933         R_Generate_smooth5_linear_gamma_table();
934         break;
935      case 0:
936      default:
937         R_BuildGammaTable( gamma_lookup( cv_usegamma.value));
938         break;
939 #if 0
940     // old-style gamma levels are defined by gamma == 1-0.125*cv_usegamma.value
941     R_BuildGammaTable(1.0f - 0.125f * cv_usegamma.value);
942 #endif
943     }
944     if( graphics_state >= VGS_active )
945     {
946         // reload palette
947         LoadPalette("PLAYPAL");
948         V_SetPalette(0);
949     }
950 }
951 
952 enum{ GFU_GAMMA = 0x01, GFU_BLACK = 0x02, GFU_BRIGHT = 0x04 };
953 byte  gammafunc_usage[4] =
954 {
955      GFU_GAMMA,  // gamma
956      GFU_GAMMA | GFU_BLACK, // gamma_black
957      GFU_GAMMA | GFU_BLACK | GFU_BRIGHT,  // gamma_bright_black
958      GFU_BLACK | GFU_BRIGHT,  // Linear
959 };
960 
CV_gammafunc_OnChange(void)961 void CV_gammafunc_OnChange(void)
962 {
963     byte gu = gammafunc_usage[cv_gammafunc.EV];
964     MenuGammaFunc_dependencies( gu&GFU_GAMMA, gu&GFU_BLACK, gu&GFU_BRIGHT );
965     CV_usegamma_OnChange();
966 }
967 
968 
969 // [WDJ] Init before calling port video control.
970 // Common init to all port video control.
971 // Register video interface controls
972 // Called once
V_Init_VideoControl(void)973 void V_Init_VideoControl( void )
974 {
975     // vid : from video setup
976     // default size for startup
977     vid.width = INITIAL_WINDOW_WIDTH;
978     vid.height = INITIAL_WINDOW_HEIGHT;
979 
980     vid.display = NULL;
981     vid.screen1 = NULL;
982     vid.buffer = NULL;
983     vid.recalc = true;
984 
985     vid.bytepp = 1; // not optimized yet...
986     vid.bitpp = 8;
987 
988     vid.modenum = (modenum_t){ MODE_window, 0 };
989     rendermode = render_soft;
990 
991     CV_RegisterVar(&cv_vidwait);
992     CV_RegisterVar(&cv_ticrate);
993     CV_RegisterVar(&cv_textout);
994     CV_RegisterVar(&cv_darkback);
995     CV_RegisterVar(&cv_con_fontsize);
996     CV_RegisterVar(&cv_msg_fontsize);
997     CV_RegisterVar(&cv_drawmode);
998     // Needs be done for config loading
999     CV_RegisterVar(&cv_usegamma);
1000     CV_RegisterVar(&cv_black);
1001     CV_RegisterVar(&cv_bright);
1002     CV_RegisterVar(&cv_gammafunc);
1003 
1004     // Screen
1005     CV_RegisterVar(&cv_fullscreen);     // only for opengl so use differant name please and move it to differant place
1006     CV_RegisterVar(&cv_scr_depth);
1007     CV_RegisterVar(&cv_scr_width);
1008     CV_RegisterVar(&cv_scr_height);
1009     CV_RegisterVar(&cv_fuzzymode);
1010 }
1011 
1012 
1013 #ifdef DIRTY_RECT
1014 // [WDJ] Only kept in case want to put game on handheld device, limited CPU.
1015 // V_MarkRect : this used to refresh only the parts of the screen
1016 //              that were modified since the last screen update
1017 //              it is useless today
1018 //
1019 int dirtybox[4];
V_MarkRect(int x,int y,int width,int height)1020 void V_MarkRect(int x, int y, int width, int height)
1021 {
1022     M_AddToBox(dirtybox, x, y);
1023     M_AddToBox(dirtybox, x + width - 1, y + height - 1);
1024 }
1025 #endif
1026 
1027 // [WDJ] 2012-02-06 Draw functions for all bpp, bytepp, and padded lines.
1028 
1029 // Return true if engine can draw using bitpp
V_CanDraw(byte bitpp)1030 boolean V_CanDraw( byte bitpp )
1031 {
1032     if( bitpp==8
1033 #ifdef ENABLE_DRAW15
1034         || (bitpp==15)
1035 #endif
1036 #ifdef ENABLE_DRAW16
1037         || (bitpp==16)
1038 #endif
1039 #ifdef ENABLE_DRAW24
1040         || (bitpp==24)
1041 #endif
1042 #ifdef ENABLE_DRAW32
1043         || (bitpp==32)
1044 #endif
1045        ) return 1;
1046     return 0;
1047 }
1048 
1049 // [WDJ] Common calc of the display buffer address for an x and y
V_GetDrawAddr(int x,int y)1050 byte * V_GetDrawAddr( int x, int y )
1051 {
1052     // vid : from video setup
1053     return  vid.display + (y * vid.ybytes) + (x * vid.bytepp);
1054 }
1055 
1056 #ifdef ENABLE_DRAWEXT
1057 // [WDJ] Draw a palette color to a single pixel
V_DrawPixel(byte * line,int x,byte color)1058 void V_DrawPixel(byte * line, int x, byte color)
1059 {
1060     // vid : from video setup
1061     switch(vid.drawmode)
1062     {
1063      default:
1064      case DRAW8PAL:
1065         line[x] = color;
1066         break;
1067 #if defined( ENABLE_DRAW15 ) || defined( ENABLE_DRAW16 )
1068      case DRAW15:
1069      case DRAW16:
1070         {
1071             register uint16_t * s16 = (uint16_t*) line;
1072             s16[x] = color8.to16[ color ];
1073         }
1074         break;
1075 #endif
1076 #ifdef ENABLE_DRAW24
1077      case DRAW24:
1078         {
1079             pixelunion32_t c32;
1080             c32.ui32 = color8.to32[ color ];
1081             register pixel24_t * s24 = (pixel24_t*) line;
1082             s24[x] = c32.pix24;
1083         }
1084         break;
1085 #endif
1086 #ifdef ENABLE_DRAW32
1087      case DRAW32:
1088         {
1089             register uint32_t * s32 = (uint32_t*) line;
1090             s32[x] = color8.to32[ color ];
1091         }
1092         break;
1093 #endif
1094     }
1095 }
1096 #else
1097 #if 0
1098 // [WDJ] Draw a palette color to a single pixel
1099 void V_DrawPixel(byte * line, int x, byte color)
1100 {
1101    line[x] = color;
1102 }
1103 #else
1104 // Degenerate case when only have DRAW8PAL, and want to save calls locally
1105 # define  V_DrawPixel( line, x, color)     (line)[(x)]=(color)
1106 #endif
1107 #endif
1108 
1109 // [WDJ] Draw a palette src to a screen line
V_DrawPixels(byte * line,int x,int count,byte * src)1110 void V_DrawPixels(byte * line, int x, int count, byte* src)
1111 {
1112     // vid : from video setup
1113     switch(vid.drawmode)
1114     {
1115      default:
1116      case DRAW8PAL:
1117         memcpy( &line[x], src, count );
1118         break;
1119 #if defined( ENABLE_DRAW15 ) || defined( ENABLE_DRAW16 )
1120      case DRAW15:
1121      case DRAW16:
1122         line += x * 2;
1123         while(count--)
1124         {
1125             *(uint16_t*)line = color8.to16[ *(src++) ];
1126             line += 2;
1127         }
1128         break;
1129 #endif
1130 #ifdef ENABLE_DRAW24
1131      case DRAW24:
1132         line += x * 3;  // 3 byte per pixel
1133         while(count--)
1134         {
1135             pixelunion32_t c32;
1136             c32.ui32 = color8.to32[ *(src++) ];
1137             *(pixel24_t*)line = c32.pix24;
1138             line += 3;
1139         }
1140         break;
1141 #endif
1142 #ifdef ENABLE_DRAW32
1143      case DRAW32:
1144         line += x * 4;
1145         while(count--)
1146         {
1147             *(uint32_t*)line = color8.to32[ *(src++) ];
1148             line += 4;
1149         }
1150         break;
1151 #endif
1152     }
1153 }
1154 
1155 
1156 //
1157 // V_CopyRect
1158 //
1159 // position and width is in src pixels
1160 // srcsrcn, destscn include V_SCALESTART flag
V_CopyRect(int srcx,int srcy,int srcscrn,int width,int height,int destx,int desty,int destscrn)1161 void V_CopyRect(int srcx, int srcy, int srcscrn, int width, int height, int destx, int desty, int destscrn)
1162 {
1163     // vid : from video setup
1164     byte *src;
1165     byte *dest;
1166 
1167     // WARNING don't mix
1168     if ((srcscrn & V_SCALESTART) || (destscrn & V_SCALESTART))
1169     {
1170         srcx *= vid.dupx;
1171         srcy *= vid.dupy;
1172         width *= vid.dupx;
1173         height *= vid.dupy;
1174         destx *= vid.dupx;
1175         desty *= vid.dupy;
1176     }
1177     srcscrn &= V_SCREENMASK;
1178     destscrn &= V_SCREENMASK;
1179 
1180 #ifdef RANGECHECK
1181     if (srcx < 0 || srcx + width > vid.width || srcy < 0 || srcy + height > vid.height || destx < 0 || destx + width > vid.width || desty < 0 || desty + height > vid.height || (unsigned) srcscrn > 4
1182         || (unsigned) destscrn > 4)
1183     {
1184         I_Error("Bad V_CopyRect %d %d %d %d %d %d %d %d", srcx, srcy, srcscrn, width, height, destx, desty, destscrn);
1185     }
1186 #endif
1187 #ifdef DIRTY_RECT
1188     V_MarkRect(destx, desty, width, height);
1189 #endif
1190 
1191 #ifdef DEBUG_COPYRECT
1192     CONS_Printf("V_CopyRect: vidwidth %d screen[%d]=%x to screen[%d]=%x\n", vid.width, srcscrn, screens[srcscrn], destscrn, screens[destscrn]);
1193     CONS_Printf("..........: srcx %d srcy %d width %d height %d destx %d desty %d\n", srcx, srcy, width, height, destx, desty);
1194 #endif
1195 
1196     // [WDJ] Copy screens, by line, padded, 8bpp .. 32bpp
1197     src = screens[srcscrn] + (srcy * vid.ybytes) + (srcx * vid.bytepp);
1198     dest = screens[destscrn] + (desty * vid.ybytes) + (destx * vid.bytepp);
1199     width *= vid.bytepp;
1200 
1201     for (; height > 0; height--)
1202     {
1203         memcpy(dest, src, width);
1204         src += vid.ybytes;
1205         dest += vid.ybytes;
1206     }
1207 }
1208 
1209 
1210 #if !defined(USEASM) || defined(WIN_NATIVE)
1211 // --------------------------------------------------------------------------
1212 // Copy a rectangular area from one bitmap to another (8bpp)
1213 // srcPitch, destPitch : width of source and destination bitmaps
1214 // --------------------------------------------------------------------------
1215 // width is in bytes (defined by ASM routine)
VID_BlitLinearScreen(byte * srcptr,byte * destptr,int width,int height,int srcrowbytes,int destrowbytes)1216 void VID_BlitLinearScreen(byte * srcptr, byte * destptr, int width, int height, int srcrowbytes, int destrowbytes)
1217 {
1218     // vid : from video setup
1219     if (srcrowbytes == destrowbytes && width == vid.widthbytes)
1220         memcpy(destptr, srcptr, srcrowbytes * height);
1221     else
1222     {
1223         while (height--)
1224         {
1225             memcpy(destptr, srcptr, width);
1226 
1227             destptr += destrowbytes;
1228             srcptr += srcrowbytes;
1229         }
1230     }
1231 }
1232 #endif
1233 
1234 // clear to black
V_Clear_Display(void)1235 void V_Clear_Display( void )
1236 {
1237     // vid : from video setup
1238 #ifdef HWRENDER
1239     if( rendermode != render_soft )
1240     {
1241         // Screen vid.b
1242         HWR_DrawVidFill(0, 0, vid.width, vid.height, 0);
1243     }
1244     else
1245 #endif
1246     {
1247         if( vid.display )
1248            memset( vid.display, 0, vid.screen_size );
1249     }
1250 }
1251 
1252 // [WDJ] parameterized draw, used by V_DrawScaled, V_DrawMapped
1253 // From V_SetupDraw
1254 drawinfo_t  drawinfo;
1255 
1256 // [WDJ] setup drawinfo for window, scaling and flag options
1257 // Normally, also calls V_SetupFont for Large text.
1258 //  screenflags : combination of drawflags_e
1259 // usage:
1260 //  desttop = drawinfo.drawp + (y * drawinfo.y0bytes) + (x * drawinfo.x0bytes);
1261 //  destend = desttop + (patch->width * drawinfo.xbytes);  // test against desttop
V_SetupDraw(uint32_t screenflags)1262 void V_SetupDraw( uint32_t screenflags )
1263 {
1264     // vid : from video setup
1265     // save current draw
1266     drawinfo.prev_screenflags = drawinfo.screenflags;
1267 
1268     drawinfo.screenflags = screenflags;
1269     drawinfo.effectflags = drawinfo.screen_effectflags = screenflags & V_EFFECTMASK;
1270 
1271     if (screenflags & V_FINESCALEPATCH)
1272     {   // Fine scaling, Scaled text
1273         // Sizing slider factor is set in drawfont.ratio by V_SetFont.
1274         drawinfo.fdupx = (vid.fdupx * drawfont.ratio) + (1.0 - drawfont.ratio);
1275         drawinfo.fdupy = (vid.fdupy * drawfont.ratio) + (1.0f - drawfont.ratio);
1276         drawinfo.dupx = (int)(drawinfo.fdupx + 0.5f);
1277         drawinfo.dupy = (int)(drawinfo.fdupy + 0.5f);
1278     }
1279     else if (screenflags & V_SCALEPATCH)
1280     {   // Scaled patches and Large text.
1281         drawinfo.dupx = vid.dupx;
1282         drawinfo.dupy = vid.dupy;
1283         drawinfo.fdupx = vid.fdupx;
1284         drawinfo.fdupy = vid.fdupy;
1285     }
1286     else
1287     {   // Unscaled and Small text.
1288         drawinfo.dupx = drawinfo.dupy = 1;
1289         drawinfo.fdupx = drawinfo.fdupy = 1.0f;
1290     }
1291     drawinfo.ybytes = drawinfo.dupy * vid.ybytes;  // bytes per source line
1292     drawinfo.xbytes = drawinfo.dupx * vid.bytepp;  // bytes per source pixel
1293     drawinfo.x_unitfrac = FixedDiv(FRACUNIT, drawinfo.dupx << FRACBITS);
1294     drawinfo.y_unitfrac = FixedDiv(FRACUNIT, drawinfo.dupy << FRACBITS);
1295 
1296 
1297     if (screenflags & V_SCALESTART)
1298     {
1299         drawinfo.dupx0 = vid.dupx;  // scaled
1300         drawinfo.dupy0 = vid.dupy;
1301 #ifdef HWRENDER
1302         drawinfo.fdupx0 = vid.fdupx;
1303         drawinfo.fdupy0 = vid.fdupy;
1304 #endif
1305     }
1306     else
1307     {
1308         drawinfo.dupx0 = 1;  // unscaled
1309         drawinfo.dupy0 = 1;
1310 #ifdef HWRENDER
1311         drawinfo.fdupx0 = 1.0f;
1312         drawinfo.fdupy0 = 1.0f;
1313 #endif
1314     }
1315     drawinfo.x0bytes_saved = drawinfo.x0bytes = drawinfo.dupx0 * vid.bytepp;
1316     drawinfo.y0bytes_saved = drawinfo.y0bytes = drawinfo.dupy0 * vid.ybytes;
1317 #ifdef HWRENDER
1318     drawinfo.fdupx0_saved = drawinfo.fdupx0;
1319     drawinfo.fdupy0_saved = drawinfo.fdupy0;
1320 #endif
1321 
1322     // The screen buffer, at an offset
1323     drawinfo.start_offset = 0;
1324     if (screenflags & V_CENTERHORZ)
1325     {
1326         // Center horizontally the finale, and other screens in the fullscreen.
1327         drawinfo.start_offset += (vid.widthbytes - (BASEVIDWIDTH * drawinfo.xbytes)) / 2;
1328     }
1329     if (screenflags & V_CENTERMENU)
1330     {
1331         // Center the menu by adding a left and top margin.
1332         drawinfo.start_offset = vid.centerofs;
1333         // as previously was performed by scaleofs.
1334         // Enabled when the menu is displayed, and crosshairs.
1335         // The menu is scaled, a round multiple of the original pixels to
1336         // keep the graphics clean, then it is centered a little.
1337         // Except the menu, scaled graphics don't have to be centered.
1338     }
1339     drawinfo.screen = screenflags & V_SCREENMASK;  // screen number (usually 0)
1340     drawinfo.screen_start = screens[drawinfo.screen];  // screen buffer [0]
1341     drawinfo.drawp = drawinfo.screen_start + drawinfo.start_offset;
1342 
1343     if ( ! (screenflags & V_FINESCALEPATCH))
1344     {
1345         // Setup the standard scaled font. Pass V_SCALESTART.
1346         V_SetupFont( 0, NULL, screenflags );
1347     }
1348 }
1349 
1350 // [WDJ] Layered drawing routines (such as DrawString) will have a problem
1351 // with V_SCALESTART needing to be applied to their x,y parameters, and not
1352 // to the x,y they generate for drawing individual characters, and the like.
1353 // Provide support for turning off the SCALESTART, temporarily.
1354 // This only supports two layers of drawing. Not using local saved copies
1355 // gains speed, simplicity, and hides the mechanism.
1356 
V_SetupDraw_NO_SCALESTART(void)1357 void  V_SetupDraw_NO_SCALESTART( void )
1358 {
1359     drawinfo.x0bytes = vid.bytepp;
1360     drawinfo.y0bytes = vid.ybytes;
1361 #ifdef HWRENDER
1362     drawinfo.fdupx0  = 1.0f;
1363     drawinfo.fdupy0  = 1.0f;
1364 #endif
1365 }
1366 
1367 
V_SetupDraw_Restore_SCALESTART(void)1368 void  V_SetupDraw_Restore_SCALESTART( void )
1369 {
1370     drawinfo.x0bytes = drawinfo.x0bytes_saved;
1371     drawinfo.y0bytes = drawinfo.y0bytes_saved;
1372 #ifdef HWRENDER
1373     drawinfo.fdupx0 = drawinfo.fdupx0_saved;
1374     drawinfo.fdupy0 = drawinfo.fdupy0_saved;
1375 #endif
1376 }
1377 
1378 
1379 //
1380 //  V_DrawMappedPatch : like V_DrawScaledPatch, but with a colormap.
1381 //  per drawinfo
1382 //
1383 //
1384 //added:05-02-98:
1385 // [WDJ] all patches are cached endian fixed 1/5/2010
1386 //  x, y : drawinfo coordinates
1387 // Called by draw char/string, menu, wi_stuff (screen0, scaled)
1388 // Called by ST_refreshBackground to draw face on status bar (with flags)
V_DrawMappedPatch(int x,int y,patch_t * patch,byte * colormap)1389 void V_DrawMappedPatch(int x, int y, patch_t * patch, byte * colormap)
1390 {
1391     // vid : from video setup
1392     // drawinfo : from V_SetupDraw
1393     column_t *column;
1394     byte *source;  // within column
1395     byte *desttop, *dest;  // within video buffer
1396 
1397     int count;
1398 #ifdef DEEPSEA_TALL_PATCH
1399     // [MB] [WDJ]  Support for DeePsea tall patches.
1400     int cur_topdelta;
1401 #endif
1402     fixed_t col, wf, ofs;
1403 
1404     // draw a hardware converted patch
1405 #ifdef HWRENDER
1406     if( rendermode != render_soft )
1407     {
1408         // Fully subject to drawinfo.
1409         HWR_DrawMappedPatch((MipPatch_t *) patch, x, y, drawinfo.effectflags, colormap);
1410         return;
1411     }
1412 #endif
1413 
1414     // [WDJ] Draw to screens, by line, padded, 8bpp .. 32bpp
1415     desttop = drawinfo.drawp + (y * drawinfo.y0bytes) + (x * drawinfo.x0bytes);
1416     // [WDJ] offsets are subject to DRAWSCALE dup.
1417     desttop -= (patch->topoffset * drawinfo.ybytes) + (patch->leftoffset * drawinfo.xbytes);
1418 //    destend = desttop + (patch->width * drawinfo.xbytes);  // test against desttop
1419 
1420 #ifdef DIRTY_RECT
1421     if (drawinfo.screen == 0)
1422         V_MarkRect(x, y, patch->width * drawinfo.dupx, patch->height * drawinfo.dupy);
1423 #endif
1424 
1425     wf = patch->width << FRACBITS;
1426 
1427     for (col=0; col < wf; col += drawinfo.x_unitfrac)
1428     {
1429         column = (column_t *) ((byte *) patch + patch->columnofs[col >> FRACBITS]);
1430 
1431 #ifdef DEEPSEA_TALL_PATCH
1432         cur_topdelta = -1;
1433 #endif
1434         while (column->topdelta != 0xff)
1435         {
1436             source = (byte *) column + 3;
1437 #ifdef DEEPSEA_TALL_PATCH
1438             // [MB] [WDJ] DeePsea tall patch.
1439             // DeepSea allows the patch to exceed 254 height.
1440             // A Doom patch has monotonic ascending topdelta values, 0..254.
1441             // DeePsea tall patches have an optional relative topdelta.
1442             // When the column topdelta is <= the current topdelta,
1443             // it is a DeePsea tall patch relative topdelta.
1444             if( (int)column->topdelta <= cur_topdelta )
1445             {
1446                 cur_topdelta += column->topdelta;  // DeePsea relative topdelta
1447             }
1448             else
1449             {
1450                 cur_topdelta = column->topdelta;  // Normal Doom patch
1451             }
1452             dest = desttop + (cur_topdelta * drawinfo.ybytes);
1453 #else
1454             dest = desttop + (column->topdelta * drawinfo.ybytes);
1455 #endif
1456             count = column->length * drawinfo.dupy;
1457 
1458             ofs = 0;
1459 #ifdef ENABLE_DRAWEXT
1460             if(vid.drawmode != DRAW8PAL)
1461             {
1462                 while (count--)
1463                 {
1464                     V_DrawPixel( dest, 0, colormap[ source[ofs >> FRACBITS]] );
1465                     dest += vid.ybytes;
1466                     ofs += drawinfo.y_unitfrac;
1467                 }
1468             }
1469             else
1470 #endif
1471             {
1472                 // DRAW8PAL
1473                 while (count--)
1474                 {
1475                     *dest = colormap[ source[ofs >> FRACBITS]];
1476                     dest += vid.ybytes;
1477                     ofs += drawinfo.y_unitfrac;
1478                 }
1479             }
1480             column = (column_t *) ((byte *) column + column->length + 4);
1481         }
1482         desttop += vid.bytepp;
1483     }
1484 
1485 }
1486 
1487 
1488 // Limited by box.
1489 //  x, y : draw at screen coordinates, scaled by drawinfo
1490 //  box_x, box_y : box upper left corner
1491 //  box_w, box_h : box size
V_DrawMappedPatch_Box(int x,int y,patch_t * patch,byte * colormap,int box_x,int box_y,int box_w,int box_h)1492 void V_DrawMappedPatch_Box(int x, int y, patch_t * patch, byte * colormap, int box_x, int box_y, int box_w, int box_h )
1493 {
1494     // vid : from video setup
1495     // drawinfo : from V_SetupDraw
1496     column_t *column;
1497     byte *source;  // within column
1498     byte *dest;  // within video buffer
1499 
1500     int count, draw_x, draw_y, draw_y1, bx1, bx2, by1, by2;
1501 #ifdef DEEPSEA_TALL_PATCH
1502     // [MB] [WDJ]  Support for DeePsea tall patches.
1503     int cur_topdelta;
1504 #endif
1505     fixed_t col, wf, ofs;
1506 
1507     // draw a hardware converted patch
1508 #ifdef HWRENDER
1509     if( rendermode != render_soft )
1510     {
1511         // Fully subject to drawinfo.
1512         HWR_DrawMappedPatch((MipPatch_t *) patch, x, y, drawinfo.effectflags, colormap);
1513         return;
1514     }
1515 #endif
1516 
1517     // [WDJ] Draw to screens, by line, padded, 8bpp .. 32bpp
1518     // Offsets are subject to DRAWSCALE dup.
1519     draw_y1 = (y * drawinfo.y0bytes) - (patch->topoffset * drawinfo.ybytes);
1520     draw_x = (x * drawinfo.x0bytes) - (patch->leftoffset * drawinfo.xbytes);
1521     by1 = (box_y * drawinfo.y0bytes);
1522     by2 = by1 + (box_h * drawinfo.ybytes);
1523     bx1 = (box_x * drawinfo.x0bytes);
1524     bx2 = bx1 + (box_w * drawinfo.xbytes);
1525 
1526 #ifdef DIRTY_RECT
1527     if (drawinfo.screen == 0)
1528         V_MarkRect(box_x, box_y, box_w * drawinfo.dupx, box_h * drawinfo.dupy);
1529 #endif
1530 
1531     col = 0;
1532     if( draw_x < bx1 )  // Left edge of box
1533     {
1534         // Clip at left of box
1535         col = ((bx1 - draw_x) / vid.bytepp) * drawinfo.x_unitfrac;
1536         draw_x = bx1;
1537     }
1538 
1539     wf = patch->width << FRACBITS;
1540 
1541     for ( ; col < wf; col += drawinfo.x_unitfrac)
1542     {
1543         column = (column_t *) ((byte *) patch + patch->columnofs[col >> FRACBITS]);
1544 
1545 #ifdef DEEPSEA_TALL_PATCH
1546         cur_topdelta = -1;
1547 #endif
1548         while (column->topdelta != 0xff)
1549         {
1550             source = (byte *) column + 3;
1551 #ifdef DEEPSEA_TALL_PATCH
1552             // [MB] [WDJ] DeePsea tall patch.
1553             // DeepSea allows the patch to exceed 254 height.
1554             // A Doom patch has monotonic ascending topdelta values, 0..254.
1555             // DeePsea tall patches have an optional relative topdelta.
1556             // When the column topdelta is <= the current topdelta,
1557             // it is a DeePsea tall patch relative topdelta.
1558             if( (int)column->topdelta <= cur_topdelta )
1559             {
1560                 cur_topdelta += column->topdelta;  // DeePsea relative topdelta
1561             }
1562             else
1563             {
1564                 cur_topdelta = column->topdelta;  // Normal Doom patch
1565             }
1566             draw_y = draw_y1 + (cur_topdelta * drawinfo.ybytes);
1567 #else
1568             draw_y = draw_y1 + (column->topdelta * drawinfo.ybytes);
1569 #endif
1570             count = column->length * drawinfo.dupy;
1571             column = (column_t *) ((byte *) column + column->length + 4);  // next column in patch
1572             ofs = 0;
1573 
1574             if( draw_y < by1 )  // Top of box
1575             {
1576                 // Clip at top of box
1577                 int diff = ((by1 - draw_y) / vid.ybytes);  // excess count
1578                 count -= diff;
1579                 if( count <= 0 )  continue;
1580                 ofs = diff * drawinfo.y_unitfrac;
1581                 draw_y += diff * vid.ybytes;
1582             }
1583             if( (draw_y + (count * vid.ybytes)) > by2 )  // Bottom of box
1584             {
1585                 // Clip at bottom of box
1586                 count = (draw_y - by2) / vid.ybytes;
1587                 if( count <= 0 )  continue;
1588             }
1589 
1590             dest = drawinfo.drawp + draw_y + draw_x;
1591 #ifdef ENABLE_DRAWEXT
1592             if(vid.drawmode != DRAW8PAL)
1593             {
1594                 while (count--)
1595                 {
1596                     V_DrawPixel( dest, 0, colormap[ source[ofs >> FRACBITS]] );
1597                     dest += vid.ybytes;
1598                     ofs += drawinfo.y_unitfrac;
1599                 }
1600             }
1601             else
1602 #endif
1603             {
1604                 // DRAW8PAL
1605                 while (count--)
1606                 {
1607                     *dest = colormap[ source[ofs >> FRACBITS]];
1608                     dest += vid.ybytes;
1609                     ofs += drawinfo.y_unitfrac;
1610                 }
1611             }
1612         }
1613         draw_x += vid.bytepp;
1614         if( draw_x > bx2 )  break;  // Right edge of box
1615     }
1616 }
1617 
1618 
1619 //  per drawinfo
1620 // with temp patch load to cache
V_DrawMappedPatch_Name(int x,int y,const char * name,byte * colormap)1621 void V_DrawMappedPatch_Name ( int x, int y, const char* name, byte* colormap )
1622 {
1623    // The patch is used only in this function
1624    V_DrawMappedPatch ( x, y,
1625                        W_CachePatchName( name, PU_CACHE ),  // endian fix
1626                        colormap );
1627 }
1628 
1629 
1630 //
1631 // V_DrawScaledPatch
1632 //   like V_DrawPatch, but scaled 2,3,4 times the original size and position
1633 //   this is used for menu and title screens, with high resolutions
1634 //  per drawinfo, with V_SCALESTART, V_SCALEPATCH
1635 //
1636 //added:05-02-98:
1637 // default params : scale patch and scale start
1638 // [WDJ] all patches are cached endian fixed 1/5/2010
1639 // Called by menu, status bar, and wi_stuff
V_DrawScaledPatch(int x,int y,patch_t * patch)1640 void V_DrawScaledPatch(int x, int y, patch_t * patch)
1641 {
1642     // vid : from video setup
1643     // drawinfo : from V_SetupDraw
1644     int count;
1645 #ifdef DEEPSEA_TALL_PATCH
1646     // [MB] [WDJ]  Support for DeePsea tall patches.
1647     int cur_topdelta;
1648 #endif
1649     fixed_t col = 0;
1650     column_t *column;
1651     byte *source;  // within column
1652     byte *dest, *desttop, *destend;  // within video buffer
1653 
1654     fixed_t ofs;
1655     fixed_t colfrac;
1656 
1657 #ifdef HWRENDER
1658     if( rendermode != render_soft )
1659     {
1660         // Draw a hardware converted patch, using drawinfo scaling.
1661         HWR_DrawPatch((MipPatch_t *) patch, x, y,
1662                       drawinfo.effectflags | V_DRAWINFO );
1663         return;
1664     }
1665 #endif
1666 
1667     colfrac = drawinfo.x_unitfrac;
1668 
1669     // [WDJ] Draw to screens, by line, padded, 8bpp .. 32bpp
1670     desttop = drawinfo.drawp + (y * drawinfo.y0bytes) + (x * drawinfo.x0bytes);
1671     // [WDJ] offsets are subject to DRAWSCALE dup.
1672     desttop -= (patch->topoffset * drawinfo.ybytes) + (patch->leftoffset * drawinfo.xbytes);
1673     destend = desttop + (patch->width * drawinfo.xbytes);  // test against desttop
1674 
1675 #ifndef ENABLE_CLIP_DRAWSCALED
1676     if( desttop < drawinfo.screen_start )
1677     {
1678         // Protect against drawing outside of screen.
1679         if( y < 0 )
1680         {
1681             // Clip y
1682             desttop = drawinfo.drawp + (x * drawinfo.x0bytes);
1683         }
1684         // Compensate for the change in y.
1685         destend = desttop + (patch->width * drawinfo.xbytes);
1686         if( desttop < drawinfo.screen_start )
1687         {
1688             // Clip x too.
1689             desttop = drawinfo.screen_start;
1690         }
1691 
1692 #if 1
1693         if( gamemode == chexquest1 && y == -1 )
1694         {
1695             // Chexquest Newmaps black bars and crosshairs.
1696             // Were designed for OpenGL drawing, looks better when stretched.
1697             x = 0;
1698             y = 0;
1699             colfrac = colfrac * (vid.dupx * BASEVIDWIDTH) / vid.width;
1700             desttop = drawinfo.screen_start;
1701             destend = desttop + vid.ybytes;
1702         }
1703 #endif
1704     }
1705 #endif
1706 
1707     // only used in f_finale:F_CastDrawer
1708     if (drawinfo.effectflags & V_FLIPPEDPATCH)
1709     {
1710         colfrac = -colfrac;
1711         col = (patch->width << FRACBITS) + colfrac;
1712     }
1713     else
1714         col = 0;
1715 
1716     while( desttop < destend )
1717     {
1718         column = (column_t *) ((byte *) patch + patch->columnofs[col >> FRACBITS]);
1719         col += colfrac;
1720 
1721 #ifdef DEEPSEA_TALL_PATCH
1722         cur_topdelta = -1;
1723 #endif
1724         while (column->topdelta != 0xff)
1725         {
1726             source = (byte *) column + 3;
1727 #ifdef DEEPSEA_TALL_PATCH
1728             // [MB] [WDJ] DeePsea tall patch.
1729             // DeepSea allows the patch to exceed 254 height.
1730             // A Doom patch has monotonic ascending topdelta values, 0..254.
1731             // DeePsea tall patches have an optional relative topdelta.
1732             // When the column topdelta is <= the current topdelta,
1733             // it is a DeePsea tall patch relative topdelta.
1734             if( (int)column->topdelta <= cur_topdelta )
1735             {
1736                 cur_topdelta += column->topdelta;  // DeePsea relative topdelta
1737             }
1738             else
1739             {
1740                 cur_topdelta = column->topdelta;  // Normal Doom patch
1741             }
1742             dest = desttop + (cur_topdelta * drawinfo.ybytes);
1743 #else
1744             dest = desttop + (column->topdelta * drawinfo.ybytes);
1745 #endif
1746             count = column->length * drawinfo.dupy;
1747 
1748             ofs = 0;
1749 #ifdef ENABLE_DRAWEXT
1750             if(vid.drawmode != DRAW8PAL)
1751             {
1752                 while (count--)
1753                 {
1754 #ifdef ENABLE_CLIP_DRAWSCALED
1755                     if( dest >= drawinfo.screen_start )
1756                        V_DrawPixel( dest, 0, source[ofs >> FRACBITS] );
1757 #else
1758                     V_DrawPixel( dest, 0, source[ofs >> FRACBITS] );
1759 #endif
1760                     dest += vid.ybytes;
1761                     ofs += drawinfo.y_unitfrac;
1762                 }
1763             }
1764             else
1765 #endif
1766             {
1767                 while (count--)
1768                 {
1769 #ifdef ENABLE_CLIP_DRAWSCALED
1770                     if( dest >= drawinfo.screen_start )
1771                        *dest = source[ofs >> FRACBITS];
1772 #else
1773                     *dest = source[ofs >> FRACBITS];
1774 #endif
1775                     dest += vid.ybytes;
1776                     ofs += drawinfo.y_unitfrac;
1777                 }
1778             }
1779 
1780             column = (column_t *) ((byte *) column + column->length + 4);
1781         }
1782         desttop += vid.bytepp;
1783     }
1784 }
1785 
1786 //  per drawinfo, with V_SCALESTART, V_SCALEPATCH
1787 // with temp patch load to cache
V_DrawScaledPatch_Name(int x,int y,const char * name)1788 void V_DrawScaledPatch_Name(int x, int y, const char * name )
1789 {
1790    // The patch is used only in this function
1791    V_DrawScaledPatch ( x, y,
1792                        W_CachePatchName( name, PU_CACHE ) );  // endian fix
1793 }
1794 
1795 //  per drawinfo, with V_SCALESTART, V_SCALEPATCH
1796 // with temp patch load to cache
V_DrawScaledPatch_Num(int x,int y,int patch_num)1797 void V_DrawScaledPatch_Num(int x, int y, int patch_num )
1798 {
1799    // The patch is used only in this function
1800    V_DrawScaledPatch ( x, y,
1801                        W_CachePatchNum( patch_num, PU_CACHE ) );  // endian fix
1802 }
1803 
1804 #if 0
1805 //[WDJ] 2012-02-06 DrawSmallPatch found to be unused
1806 
1807 void HWR_DrawSmallPatch(MipPatch_t * gpatch, int x, int y, int option, byte * colormap);
1808 // Draws a patch 2x as small. SSNTails 06-10-2003
1809 // [WDJ] all patches are cached endian fixed 1/5/2010
1810 void V_DrawSmallScaledPatch(int x, int y, int scrn, patch_t * patch, byte * colormap)
1811 {
1812     // vid : from video setup
1813     int count;
1814     int col;
1815     column_t *column;
1816     byte *source;  // within column
1817     byte *desttop, *dest, *destend;  // within video buffer
1818 
1819     int dupx=1, dupy=1;
1820     int count_dupy, dup_ybytes;
1821     int ofs;
1822     fixed_t colfrac, rowfrac, colfrac_inc, rowfrac_inc;
1823 //    boolean skippixels = false;
1824 
1825     // draw an hardware converted patch
1826 #ifdef HWRENDER
1827     if( rendermode != render_soft )
1828     {
1829         HWR_DrawSmallPatch((MipPatch_t *) patch, x, y, scrn, colormap);
1830         return;
1831     }
1832 #endif
1833 
1834     colfrac = FixedDiv(FRACUNIT, dupx << FRACBITS);
1835     rowfrac = FixedDiv(FRACUNIT, dupy << FRACBITS);
1836 
1837     if (scrn & V_FLIPPEDPATCH)
1838     {
1839         colfrac = -colfrac;
1840         col = (patch->width << FRACBITS) + colfrac;
1841     }
1842     else
1843         col = 0;
1844 
1845     colfrac_inc = colfrac;
1846     rowfrac_inc = rowfrac;
1847 
1848     desttop = screens[scrn & 0xFF] + (y * vid.ybytes) + (x * vid.bytepp);
1849     // [WDJ] offsets are subject to DRAWSCALE dup.
1850     desttop -= (patch->topoffset * drawinfo.ybytes) + (patch->leftoffset * drawinfo.xbytes);
1851     destend = desttop;
1852 
1853     if (vid.dupx > 1 && vid.dupy > 1)
1854     {
1855         destend += (patch->width * dupx * vid.bytepp);
1856         count_dupy = dupy << 1;  // count_dupy = dupy * 2, will be dupy after >> 1
1857     }
1858     else
1859     {
1860 //        skippixels = true;
1861         // double the inc, halve the count
1862         destend += (patch->width / 2 * dupx * vid.bytepp);
1863         colfrac_inc += colfrac_inc;  // * 2
1864         rowfrac_inc += rowfrac_inc;  // * 2
1865         count_dupy = dupy; // will be dupy/2 after >> 1
1866     }
1867     dup_ybytes = dupy * vid.ybytes;
1868 
1869     // [WDJ] Use same loop for normal and skippixels, with some predefined inc
1870     for (  ; desttop < destend; desttop+=vid.bytepp)
1871     {
1872         column = (column_t *) ((byte *) patch + patch->columnofs[col >> FRACBITS]);
1873         col += colfrac_inc;
1874         while (column->topdelta != 0xff)
1875         {
1876             source = (byte *) column + 3;
1877             dest = desttop + (column->topdelta * dup_ybytes);
1878             count = (column->length * count_dupy) >> 1;  // dupy or dupy/2
1879             ofs = 0;
1880             while (count--)
1881             {
1882                 V_DrawPixel( dest, 0, colormap[source[ofs >> FRACBITS]] );
1883                 dest += vid.ybytes;
1884                 ofs += rowfrac_inc;
1885             }
1886             column = (column_t *) ((byte *) column + column->length + 4);
1887         }
1888     }
1889 }
1890 #endif
1891 
1892 //added:16-02-98: now used for crosshair
1893 //
1894 //  This draws a patch over a background with translucency
1895 //  per drawinfo
1896 //
1897 // [WDJ] all patches are cached endian fixed 1/5/2010
V_DrawTranslucentPatch(int x,int y,patch_t * patch)1898 void V_DrawTranslucentPatch(int x, int y, patch_t * patch)
1899 {
1900     // vid : from video setup
1901     // drawinfo : from V_SetupDraw
1902     int count;
1903 #ifdef DEEPSEA_TALL_PATCH
1904     // [MB] [WDJ]  Support for DeePsea tall patches.
1905     int cur_topdelta;
1906 #endif
1907     column_t *column;
1908     byte *source;  // within column
1909     byte *desttop, *dest;  // within video buffer
1910     fixed_t ofs;
1911     fixed_t col, wf;
1912 
1913     // draw an hardware converted patch
1914 #ifdef HWRENDER
1915     if( rendermode != render_soft )
1916     {
1917         // Enable drawinfo scaling.
1918         HWR_DrawPatch((MipPatch_t *) patch, x, y,
1919                       drawinfo.screenflags|drawinfo.effectflags|V_DRAWINFO );
1920         return;
1921     }
1922 #endif
1923 
1924 
1925 #ifdef DIRTY_RECT
1926     if (!(scrn & 0xff))
1927 //    y -= patch->topoffset * drawinfo.dupy;
1928 //    x -= patch->leftoffset * drawinfo.dupx;
1929         V_MarkRect(x, y, patch->width * drawinfo.dupx, patch->height * drawinfo.dupy);
1930 #endif
1931 
1932     // [WDJ] Draw to screens, by line, padded, 8bpp .. 32bpp
1933     desttop = drawinfo.drawp + (y * drawinfo.y0bytes) + (x * drawinfo.x0bytes);
1934     // [WDJ] offsets are subject to DRAWSCALE dup.
1935     desttop -= (patch->topoffset * drawinfo.ybytes) + (patch->leftoffset * drawinfo.xbytes);
1936 //    destend = desttop + (patch->width * drawinfo.xbytes);  // test against desttop
1937 
1938     wf = patch->width << FRACBITS;
1939 
1940     for ( col=0; col < wf; col += drawinfo.x_unitfrac)
1941     {
1942         column = (column_t *) ((byte *) patch + patch->columnofs[col >> FRACBITS]);
1943 
1944 #ifdef DEEPSEA_TALL_PATCH
1945         cur_topdelta = -1;
1946 #endif
1947         while (column->topdelta != 0xff)
1948         {
1949             source = (byte *) column + 3;
1950 #ifdef DEEPSEA_TALL_PATCH
1951             // [MB] [WDJ] DeePsea tall patch.
1952             // DeepSea allows the patch to exceed 254 height.
1953             // A Doom patch has monotonic ascending topdelta values, 0..254.
1954             // DeePsea tall patches have an optional relative topdelta.
1955             // When the column topdelta is <= the current topdelta,
1956             // it is a DeePsea tall patch relative topdelta.
1957             if( (int)column->topdelta <= cur_topdelta )
1958             {
1959                 cur_topdelta += column->topdelta;  // DeePsea relative topdelta
1960             }
1961             else
1962             {
1963                 cur_topdelta = column->topdelta;  // Normal Doom patch
1964             }
1965             dest = desttop + (cur_topdelta * drawinfo.ybytes);
1966 #else
1967             dest = desttop + (column->topdelta * drawinfo.ybytes);
1968 #endif
1969             count = column->length * drawinfo.dupy;
1970 
1971             ofs = 0;
1972 #ifdef ENABLE_DRAWEXT
1973             switch(vid.drawmode)
1974             {
1975              default:
1976              case DRAW8PAL:
1977                 while (count--)
1978                 {
1979                     register unsigned int color = source[ofs >> FRACBITS];
1980                     *dest = translucenttables[ ((color << 8) & 0xFF00) + (*dest & 0xFF) ];
1981                     dest += vid.ybytes;
1982                     ofs += drawinfo.y_unitfrac;
1983                 }
1984                 break;
1985 #if defined( ENABLE_DRAW15 ) || defined( ENABLE_DRAW16 )
1986              case DRAW15:
1987              case DRAW16:
1988                 while (count--)
1989                 {
1990                     register unsigned int color = source[ofs >> FRACBITS];
1991                     register uint16_t * s16 = (uint16_t*) dest;
1992                     *s16 =( ((color8.to16[color]>>1) & mask_01111) +
1993                             (((*s16)>>1) & mask_01111) );
1994                     dest += vid.ybytes;
1995                     ofs += drawinfo.y_unitfrac;
1996                 }
1997                 break;
1998 #endif
1999 #ifdef ENABLE_DRAW24
2000              case DRAW24:
2001                 while (count--)
2002                 {
2003                     register unsigned int color = source[ofs >> FRACBITS];
2004                     pixelunion32_t c32;
2005                     c32.ui32 = (color8.to32[ color ]>>1) & 0x7F7F7F; // 01111111 on pix24
2006                     register pixel24_t * s24 = (pixel24_t*) dest;
2007                     s24->r = c32.pix24.r + (s24->r>>1);
2008                     s24->g = c32.pix24.g + (s24->g>>1);
2009                     s24->b = c32.pix24.b + (s24->b>>1);
2010                     dest += vid.ybytes;
2011                     ofs += drawinfo.y_unitfrac;
2012                 }
2013                 break;
2014 #endif
2015 #ifdef ENABLE_DRAW32
2016              case DRAW32:
2017                 while (count--)
2018                 {
2019                     register unsigned int color = source[ofs >> FRACBITS];
2020                     register uint32_t * s32 = (uint32_t*) dest;
2021                     *s32 = ((color8.to32[ color ]>>1) & 0x007F7F7F)
2022                          + (((*s32)>>1) & 0x007F7F7F) + (*s32 & 0xFF000000);
2023                     dest += vid.ybytes;
2024                     ofs += drawinfo.y_unitfrac;
2025                 }
2026                 break;
2027 #endif
2028             }
2029 #else
2030             // Degenerate DRAW8PAL only
2031             while (count--)
2032             {
2033                 register unsigned int color = source[ofs >> FRACBITS];
2034                 *dest = translucenttables[ ((color << 8) & 0xFF00) + (*dest & 0xFF) ];
2035                 dest += vid.ybytes;
2036                 ofs += drawinfo.y_unitfrac;
2037             }
2038 #endif
2039 
2040             column = (column_t *) ((byte *) column + column->length + 4);
2041         }
2042         desttop += vid.bytepp;
2043     }
2044 }
2045 
2046 //
2047 // V_DrawPatch
2048 // Masks a column based masked pic to the screen. NO SCALING!!!
2049 //
2050 // [WDJ] all patches are cached endian fixed 1/5/2010
2051 // Called by R_FillBackScreen, map
V_DrawPatch(int x,int y,int scrn,patch_t * patch)2052 void V_DrawPatch(int x, int y, int scrn, patch_t * patch)
2053 {
2054     // vid : from video setup
2055     column_t *column;
2056     byte *source;  // within column
2057     byte *desttop, *dest;  // within video buffer
2058     int count;
2059 #ifdef DEEPSEA_TALL_PATCH
2060     // [MB] [WDJ]  Support for DeePsea tall patches.
2061     int cur_topdelta;
2062 #endif
2063     int col, wi;
2064 
2065     // draw an hardware converted patch
2066 #ifdef HWRENDER
2067     if( rendermode != render_soft )
2068     {
2069         // Vid coordinates.
2070         HWR_DrawPatch((MipPatch_t *) patch, x, y, V_NOSCALE);
2071         return;
2072     }
2073 #endif
2074 
2075     // No scaling, so can apply offsets in the old method.
2076     y -= patch->topoffset;
2077     x -= patch->leftoffset;
2078 #ifdef RANGECHECK
2079     if (x < 0 || x + patch->width > vid.width || y < 0 || y + patch->height > vid.height || (unsigned) scrn > 4)
2080     {
2081         GenPrintf(EMSG_warn, "Patch at %d,%d exceeds LFB\n", x, y);
2082         // No I_Error abort - what is up with TNT.WAD?
2083         GenPrintf(EMSG_warn, "V_DrawPatch: bad patch (ignored)\n");
2084         return;
2085     }
2086 #endif
2087 
2088 #ifdef DIRTY_RECT
2089     if (!scrn)
2090         V_MarkRect(x, y, patch->width, patch->height);
2091 #endif
2092 
2093     desttop = screens[scrn] + (y * vid.ybytes) + (x * vid.bytepp);
2094 
2095     wi = patch->width;
2096 
2097     for ( col=0; col < wi; col++)
2098     {
2099         column = (column_t *) ((byte *) patch + patch->columnofs[col]);
2100 
2101 #ifdef DEEPSEA_TALL_PATCH
2102         cur_topdelta = -1;
2103 #endif
2104 
2105         // step through the posts in a column
2106         while (column->topdelta != 0xff)
2107         {
2108             source = (byte *) column + 3;
2109 #ifdef DEEPSEA_TALL_PATCH
2110             // [MB] [WDJ] DeePsea tall patch.
2111             // DeepSea allows the patch to exceed 254 height.
2112             // A Doom patch has monotonic ascending topdelta values, 0..254.
2113             // DeePsea tall patches have an optional relative topdelta.
2114             // When the column topdelta is <= the current topdelta,
2115             // it is a DeePsea tall patch relative topdelta.
2116             if( (int)column->topdelta <= cur_topdelta )
2117             {
2118                 cur_topdelta += column->topdelta;  // DeePsea relative topdelta
2119             }
2120             else
2121             {
2122                 cur_topdelta = column->topdelta;  // Normal Doom patch
2123             }
2124             dest = desttop + (cur_topdelta * vid.ybytes);
2125 #else
2126             dest = desttop + (column->topdelta * vid.ybytes);
2127 #endif
2128             count = column->length;
2129 
2130             while (count--)
2131             {
2132                 V_DrawPixel(dest, 0, *source++);
2133                 dest += vid.ybytes;
2134             }
2135             column = (column_t *) ((byte *) column + column->length + 4);
2136         }
2137         desttop += vid.bytepp;
2138     }
2139 }
2140 
2141 
2142 #if 0
2143 // [WDJ] Replaced by VID_BlitLinearScreen and V_CopyRect because
2144 // were being used to copy screens
2145 //
2146 // V_DrawBlock
2147 // Draw a linear block of pixels into the view buffer.
2148 //
2149 // src: is not a screen
2150 // dest: scrn is a screen, x,y in pixel coord
2151 void V_DrawBlock(int x, int y, int scrn, int width, int height, byte * src)
2152 {
2153     // vid : from video setup
2154     byte *dest;  // within video buffer
2155 
2156 #ifdef RANGECHECK
2157     if (x < 0 || x + width > vid.width || y < 0 || y + height > vid.height || (unsigned) scrn > 4)
2158     {
2159         I_Error("Bad V_DrawBlock");
2160     }
2161 #endif
2162 
2163 #ifdef DIRTY_RECT
2164     //V_MarkRect (x, y, width, height);
2165 #endif
2166 
2167     // [WDJ] Copy screens, by line, padded, 8bpp .. 32bpp
2168     width *= vid.bytepp;
2169     dest = screens[scrn] + (y * vid.ybytes) + (x * vid.bytepp);
2170 
2171     while (height--)
2172     {
2173         memcpy(dest, src, width);
2174 
2175         src += width;
2176         dest += vid.ybytes;
2177     }
2178 }
2179 
2180 //
2181 // V_GetBlock
2182 // Gets a linear block of pixels from the view buffer.
2183 //
2184 // src: scrn is a screen, x,y in pixel coord
2185 // dest: is not a screen
2186 void V_GetBlock(int x, int y, int scrn, int width, int height, byte * dest)
2187 {
2188     // vid : from video setup
2189     byte *src;  // within video buffer
2190 
2191     if( rendermode != render_soft )
2192         I_Error("V_GetBlock: called in non-software mode");
2193 
2194 #ifdef RANGECHECK
2195     if (x < 0 || x + width > vid.width || y < 0 || y + height > vid.height || (unsigned) scrn > 4)
2196     {
2197         I_Error("Bad V_GetBlock");
2198     }
2199 #endif
2200 
2201     src = screens[scrn] + (y * vid.ybytes) + (x * vid.bytepp);
2202 
2203     while (height--)
2204     {
2205         memcpy(dest, src, width);
2206         src += vid.ybytes;
2207         dest += width;
2208     }
2209 }
2210 #endif
2211 
2212 
2213 
2214 //  per drawinfo, scaled, abs start coord.
2215 // [WDJ] all pic are cached endian fixed 1/5/2010
V_BlitScalePic(int x1,int y1,pic_t * pic)2216 static void V_BlitScalePic(int x1, int y1, pic_t * pic)
2217 {
2218     // vid : from video setup
2219     // drawinfo : from V_SetupDraw
2220     int dupx, dupy;
2221     int x, y;
2222     byte *src, *dest;
2223     int pic_width = pic->width;
2224     int pic_height = pic->height;
2225 
2226     if (pic->mode != 0)
2227     {
2228         CONS_Printf("pic mode %d not supported in Software\n", pic->mode);
2229         return;
2230     }
2231 
2232     // scaled, with x centering
2233     dest = drawinfo.drawp + (max(0, y1) * vid.ybytes) + (max(0, x1) * vid.bytepp);
2234     // y clipping to the screen
2235     if (y1 + (pic_height * vid.dupy) >= vid.height)
2236         pic_height = ((vid.height - y1) / vid.dupy) - 1;
2237     // WARNING no x clipping (not needed for the moment)
2238 
2239     for (y = max(0, -y1 / vid.dupy); y < pic_height; y++)
2240     {
2241         for (dupy = vid.dupy; dupy; dupy--)
2242         {
2243             int xb = 0;
2244             src = pic->data + (y * pic_width);
2245             for (x = 0; x < pic_width; x++)
2246             {
2247                 for (dupx = vid.dupx; dupx; dupx--)
2248                     V_DrawPixel(dest, xb++, *src);
2249                 src++;
2250             }
2251             dest += vid.ybytes;
2252         }
2253     }
2254 }
2255 
2256 //  Draw a linear pic, scaled
2257 //  CURRENTLY USED FOR StatusBarOverlay, scale pic but not starting coords
2258 //  per drawinfo, scaled, abs start coord.
2259 //
V_DrawScalePic_Num(int x1,int y1,lumpnum_t lumpnum)2260 void V_DrawScalePic_Num(int x1, int y1, lumpnum_t lumpnum)
2261 {
2262 #ifdef HWRENDER
2263     if( rendermode != render_soft )
2264     {
2265         HWR_DrawPic(x1, y1, lumpnum);
2266         return;
2267     }
2268 #endif
2269 
2270     // [WDJ] Get pic and fix endian, then display
2271     V_BlitScalePic(x1, y1, W_CachePicNum(lumpnum, PU_CACHE));
2272 }
2273 
2274 // Heretic raw pic
2275 //  per drawinfo, scaled, abs start coord.
V_DrawRawScreen_Num(int x1,int y1,lumpnum_t lumpnum,int width,int height)2276 void V_DrawRawScreen_Num(int x1, int y1, lumpnum_t lumpnum, int width, int height)
2277 {
2278 #ifdef HWRENDER
2279     if( rendermode != render_soft )
2280     {
2281         // save size somewhere and mark lump as a raw pic !
2282         MipPatch_t *grpatch = &(wadfiles[WADFILENUM(lumpnum)]->hwrcache[LUMPNUM(lumpnum)]);
2283         grpatch->width = width;
2284         grpatch->height = height;
2285         grpatch->mipmap.tfflags |= TF_Her_Raw_Pic;  // Heretic Raw Pic
2286         HWR_DrawPic(x1, y1, lumpnum);
2287         return;
2288     }
2289 #endif
2290 
2291     V_BlitScalePic(x1, y1,
2292                    W_CacheRawAsPic(lumpnum, width, height, PU_CACHE));
2293 }
2294 
2295 
2296 //
2297 //  Fills a box of pixels with a single color
2298 //
2299 // Vid range coordinates.
2300 // per drawinfo centering, always screen 0
2301 //  x, y : screen coord. in vid range.
V_DrawVidFill(int x,int y,int w,int h,byte color)2302 void V_DrawVidFill(int x, int y, int w, int h, byte color)
2303 {
2304     // vid : from video setup
2305     // drawinfo : from V_SetupDraw
2306     byte *dest;  // within screen buffer
2307     int u, v;
2308 
2309 #ifdef HWRENDER
2310     if( rendermode != render_soft )
2311     {
2312         HWR_DrawVidFill(x, y, w, h, color);
2313         return;
2314     }
2315 #endif
2316 
2317 #if 0
2318     dest = screens[0] + (y * vid.ybytes) + (x * vid.bytepp);
2319     dest += drawinfo.start_offset;
2320 #else
2321     dest = drawinfo.drawp + (y * vid.ybytes) + (x * vid.bytepp);
2322 #endif
2323 
2324     for (v = 0; v < h; v++, dest += vid.ybytes)
2325     {
2326         for (u = 0; u < w; u++)
2327             V_DrawPixel(dest, u, color);
2328     }
2329 }
2330 
2331 // Scaled to (320,200)
2332 //   x, y, w, h : (320,200)
V_DrawFill(int x,int y,int w,int h,byte color)2333 void V_DrawFill(int x, int y, int w, int h, byte color)
2334 {
2335 #ifdef HWRENDER
2336     if( rendermode != render_soft )
2337     {
2338         HWR_DrawVidFill(x * vid.fdupx, y * vid.fdupy, w * vid.fdupx, h * vid.fdupy, color);
2339         return;
2340     }
2341 #endif
2342     // vid : from video setup
2343     V_DrawVidFill( x * vid.dupx, y * vid.dupy, w * vid.dupx, h * vid.dupy, color);
2344 }
2345 
2346 //  per drawinfo, scaled start and size
2347 //  x, y : screen coord.
V_DrawScaledFill(int x,int y,int w,int h,byte color)2348 void V_DrawScaledFill(int x, int y, int w, int h, byte color)
2349 {
2350     // vid : from video setup
2351     // drawinfo : from V_SetupDraw
2352     byte *dest;  // within screen buffer
2353     int u, v;
2354 
2355 #ifdef HWRENDER
2356     if( rendermode != render_soft )
2357     {
2358         HWR_DrawVidFill( x * drawinfo.fdupx0, y * drawinfo.fdupy0,
2359                          w * drawinfo.fdupx, h * drawinfo.fdupy, color );
2360         return;
2361     }
2362 #endif
2363 
2364     // [WDJ] Draw to screens, by line, padded, 8bpp .. 32bpp
2365     dest = drawinfo.drawp + (y * drawinfo.y0bytes) + (x * drawinfo.x0bytes);
2366     w *= drawinfo.dupx;
2367     h *= drawinfo.dupy;
2368 
2369     for (v = 0; v < h; v++, dest += vid.ybytes)
2370     {
2371         for (u = 0; u < w; u++)
2372             V_DrawPixel(dest, u, color);
2373     }
2374 }
2375 
2376 
2377 
2378 // Indexed by flat size_index.
2379 static byte  fill_sizeshift_tab[ 8 ] =
2380 {
2381     0,  // 0
2382     5,  // 32x32 flat
2383     6,  // 64x64 flat
2384     7,  // 128x128 flat
2385     8,  // 256x256 flat
2386     9,  // 512x512 flat
2387     10,  // 1024x1024 flat
2388     11,  // 2048x2048 flat
2389 };
2390 
2391 // Fill Flat Index mask
2392 // Indexed by flat size_index.
2393 static uint16_t  fill_mask_tab[ 8 ] =
2394 {
2395     0, // 0
2396     32 - 1, // 32x32 flat
2397     64 - 1, // 64x64 flat
2398     128 - 1, // 128x128 flat
2399     256 - 1, // 256x256 flat
2400     512 - 1, // 512x512 flat
2401     1024 - 1, // 1024x1024 flat
2402     2048 - 1, // 2048x2048 flat
2403 };
2404 
2405 //  Fills a box of pixels using a flat texture as a pattern.
2406 //  Per drawinfo, scaled, centering.
2407 //  For fullscreen, set w=vid.width.
2408 //
2409 //   x, y, w, h : drawinfo coordinates (if w=vid.width then vid coordinates)
2410 //   scale : 0..15, where 0=unscaled, 15=full scaled
2411 // Called by M_DrawTextBox
V_DrawFlatFill(int x,int y,int w,int h,int scale,lumpnum_t flatnum)2412 void V_DrawFlatFill(int x, int y, int w, int h, int scale, lumpnum_t flatnum)
2413 {
2414     // vid : from video setup
2415     // drawinfo : from V_SetupDraw
2416     byte *dest;  // within screen buffer
2417     int u, v;
2418     fixed_t dx, dy, xfrac, yfrac;
2419     byte *src;
2420     byte *flat;
2421     int imask, sizeshift;
2422 
2423 #ifdef HWRENDER
2424     if( rendermode != render_soft )
2425     {
2426         if( w == vid.width )
2427             HWR_DrawVidFlatFill(x, y, w, h, scale, flatnum);
2428         else
2429             HWR_DrawVidFlatFill((x * drawinfo.fdupx0), (y * drawinfo.fdupy0),
2430                 (w * drawinfo.fdupx), (h * drawinfo.fdupy), scale, flatnum);
2431         return;
2432     }
2433 #endif
2434 
2435 #if 0
2436     int size = W_LumpLength(flatnum);
2437 
2438     switch (size)
2439     {
2440         case 4194304:  // 2048x2048 lump
2441             flatsize = 2048;
2442             flatshift = 10;
2443             break;
2444         case 1048576:  // 1024x1024 lump
2445             flatsize = 1024;
2446             flatshift = 9;
2447             break;
2448         case 262144:   // 512x512 lump
2449             flatsize = 512;
2450             flatshift = 8;
2451             break;
2452         case 65536:    // 256x256 lump
2453             flatsize = 256;
2454             flatshift = 7;
2455             break;
2456         case 16384:    // 128x128 lump
2457             flatsize = 128;
2458             flatshift = 7;
2459             break;
2460         case 1024:     // 32x32 lump
2461             flatsize = 32;
2462             flatshift = 5;
2463             break;
2464         default:       // 64x64 lump
2465             flatsize = 64;
2466             flatshift = 6;
2467             break;
2468     }
2469 #endif
2470 
2471 //    int sizeindex = levelflats[picnum].size_index;
2472     int sizeindex = P_flatsize_to_index( W_LumpLength(flatnum), NULL );
2473     sizeshift = fill_sizeshift_tab[sizeindex];
2474     imask = fill_mask_tab[sizeindex];
2475     flat = W_CacheLumpNum(flatnum, PU_CACHE);
2476 
2477     if( w == vid.width )
2478     {
2479         // fullscreen, assume that also x=0, y=0
2480         dest = screens[0];
2481 //        dest = screens[0] + (y * vid.ybytes) + (x * vid.bytepp);
2482     }
2483     else
2484     {
2485         // Draw per drawinfo
2486         dest = drawinfo.drawp + (y * drawinfo.y0bytes) + (x * drawinfo.x0bytes);
2487         w *= drawinfo.dupx;
2488         h *= drawinfo.dupy;
2489     }
2490 
2491     // Scale flat proportional, 0..15 => 1..vid.dup
2492     dx = FixedDiv(FRACUNIT,
2493          ((((vid.dupx-1) << (FRACBITS-4)) * scale) + (1<<FRACBITS)) );
2494     dy = FixedDiv(FRACUNIT,
2495          ((((vid.dupy-1) << (FRACBITS-4)) * scale) + (1<<FRACBITS)) );
2496 
2497     yfrac = 0;
2498     for (v = 0; v < h; v++)
2499     {
2500         xfrac = 0;
2501         src = & flat[((yfrac >> (FRACBITS - 1)) & imask) << sizeshift];
2502         for (u = 0; u < w; u++)
2503         {
2504             V_DrawPixel(dest, u, src[(xfrac >> FRACBITS) & imask]);
2505             xfrac += dx;
2506         }
2507         yfrac += dy;
2508         dest += vid.ybytes;
2509     }
2510 }
2511 
2512 
2513 // Fill entire screen with flat.
2514 // Called by WI_slamBackground, F_TextWrite (entire screen), M_DrawTextBox
V_ScreenFlatFill(lumpnum_t flatnum)2515 void V_ScreenFlatFill( lumpnum_t flatnum )
2516 {
2517 #ifdef HWRENDER
2518     if( rendermode != render_soft )
2519     {
2520         HWR_DrawVidFlatFill(0, 0, vid.width, vid.height, 15, flatnum);
2521         return;
2522     }
2523 #endif
2524     V_DrawFlatFill( 0, 0, vid.width, vid.height, 15, flatnum);
2525 }
2526 
2527 
2528 
2529 //  General Fade Rectangle.
2530 //   x1, x2, y2 : affected ranges in pixels,  (always y1 = 0)
2531 //   fade_alpha : 1 (no fade) .. 255 (faded)
2532 //   fade_index : from fadescreen_draw8, or fadecons_draw8 table
2533 //   tint_rgba : added color tint, small color values only
V_FadeRect(int x1,int x2,int y2,uint32_t fade_alpha,unsigned int fade_index,uint32_t tint_rgba)2534 void V_FadeRect(int x1, int x2, int y2,
2535                 uint32_t fade_alpha, unsigned int fade_index,
2536                 uint32_t tint_rgba )
2537 {
2538     // vid : from video setup
2539     RGBA_t tint;
2540     byte * fadetab, * greentab;
2541 #ifdef ENABLE_DRAWEXT
2542     int w4 = x2 - x1;
2543 #endif
2544 #if defined( ENABLE_DRAW15 ) || defined( ENABLE_DRAW16 )
2545     uint32_t mask_g2, mask_r2, mask_b2;
2546     uint32_t tint_g, tint_r, tint_b;
2547 #endif
2548     int x, y;
2549     uint32_t *buf;
2550 
2551 #ifdef HWRENDER
2552     if( rendermode != render_soft )
2553     {
2554         // Note: y1 is always 0.
2555         // OpenGL requires stronger color tint.
2556         HWR_FadeScreenMenuBack( tint_rgba, 0xFF - fade_alpha, y2 );
2557         return;
2558     }
2559 #endif
2560 
2561     tint.rgba = tint_rgba;
2562     switch(vid.drawmode)
2563     {
2564      case DRAW8PAL:
2565         // 8bpp palette, accessed 4 bytes at a time
2566         fadetab = (byte*) ( reg_colormaps )?
2567              & reg_colormaps[ LIGHTTABLE(fade_index) ]
2568            : graymap;  // at startup, before reg_colormaps loaded
2569         // Palette draw only has facility for console green tint.
2570         greentab = ( tint.s.green )?  greenmap : & reg_colormaps[ 0 ];
2571         x1 >>= 2;
2572         x2 >>= 2;
2573         for (y = 0; y < y2; y++)
2574         {
2575             buf = (uint32_t *) V_GetDrawAddr( 0, y );
2576             for (x = x1; x < x2; x++)
2577             {
2578                 register uint32_t quad = buf[x];
2579                 register uint32_t q2 = greentab[fadetab[quad & 0xFF]];
2580                 q2 |= ((uint32_t) greentab[fadetab[(quad >> 8) & 0xFF]]) << 8;
2581                 q2 |= ((uint32_t) greentab[fadetab[(quad >> 16) & 0xFF]]) << 16;
2582                 q2 |= ((uint32_t) greentab[fadetab[quad >> 24]]) << 24;
2583                 buf[x] = q2;
2584             }
2585         }
2586         break;
2587 #ifdef ENABLE_DRAW15
2588      case DRAW15:
2589         // 2 pixels at a time  (5,5,5)
2590         mask_r2 = 0x04000400L;  // 0 00001 00000 00000
2591         mask_g2 = 0x00200020L;  // 0 00000 00001 00000
2592         goto fade15_16;
2593 #endif
2594 #ifdef ENABLE_DRAW16
2595      case DRAW16:
2596         // 2 pixels at a time  (5,6,5)
2597         mask_r2 = 0x08000800L;  // 00001 000000 00000
2598         mask_g2 = 0x00400040L;  // 00000 000010 00000
2599         goto fade15_16;
2600 #endif
2601 #if defined( ENABLE_DRAW15 ) || defined( ENABLE_DRAW16 )
2602      fade15_16:
2603         // 2 pixels at a time
2604         tint_r = (tint.s.red >> 3) * mask_r2;
2605         tint_g = (tint.s.green >> 3) * mask_g2;
2606         tint_b = (uint32_t)(tint.s.blue >> 3) * 0x00010001L;  // 0 00000 00000 00001
2607         // Must do components separately because of carry from one pixel to next.
2608         mask_r2 = ((uint32_t) mask_r << 16 ) | mask_r;
2609         mask_g2 = ((uint32_t) mask_g << 16 ) | mask_g;
2610         mask_b2 = ((uint32_t) mask_b << 16 ) | mask_b;
2611         w4 >>= 1;  // 2 bytes at a time
2612         for (y = 0; y < y2; y++)
2613         {
2614             buf = (uint32_t *) V_GetDrawAddr( x1, y );
2615             for (x = w4; x > 0; x--)
2616             {
2617                 *buf = (((((*buf & mask_g2) >> 8) * fade_alpha) + tint_g) & mask_g2)
2618                      | (((((*buf & mask_r2) >> 8) * fade_alpha) + tint_r) & mask_r2)
2619                      | (((((*buf & mask_b2) * fade_alpha) >> 8) + tint_b) & mask_b2);
2620                 buf++;  // compiler complains when combined above
2621             }
2622         }
2623         break;
2624 #endif
2625 #ifdef ENABLE_DRAW32
2626      case DRAW32:
2627         // RGB
2628         for (y = 0; y < y2; y++)
2629         {
2630             pixel32_t * p32 = (pixel32_t*) V_GetDrawAddr( x1, y );
2631             for (x = w4; x > 0; x--)
2632             {
2633                 p32->b = ((p32->b * fade_alpha) >> 8) + tint.s.blue; // blue
2634                 p32->g = ((p32->g * fade_alpha) >> 8) + tint.s.green; // green
2635                 p32->r = ((p32->r * fade_alpha) >> 8) + tint.s.red; // red
2636                 p32 ++;
2637             }
2638         }
2639         break;
2640 #endif
2641 #ifdef ENABLE_DRAW24
2642      case DRAW24:
2643         // RGB
2644         for (y = 0; y < y2; y++)
2645         {
2646             pixel24_t * p24 = (pixel24_t*) V_GetDrawAddr( x1, y );
2647             for (x = w4; x > 0; x--)
2648             {
2649                 p24->b = ((p24->b * fade_alpha) >> 8) + tint.s.blue; // blue
2650                 p24->g = ((p24->g * fade_alpha) >> 8) + tint.s.green; // green
2651                 p24->r = ((p24->r * fade_alpha) >> 8) + tint.s.red; // red
2652                 p24 ++;
2653             }
2654         }
2655         break;
2656 #endif
2657      default:
2658         break;
2659     }
2660 }
2661 
2662 
2663 // [WDJ] Tables for darkback
2664 // index by cv_darkback
2665 // LIGHTTABLE[ 0 .. 31 ]
2666 byte fadescreen_draw8[3] =
2667 {
2668   16,  // half
2669   20,  // med
2670   24   // dark
2671 };
2672 
2673 // Dark enough that menu is readable.
2674 byte fadescreen_alpha[3] =
2675 {
2676   0x70,  // half
2677   0x44,  // med
2678   0x2C   // dark
2679 };
2680 
2681 
2682 //
2683 //  Fade all the screen buffer, so that the menu is more readable,
2684 //  especially now that we use the small hufont in the menus...
2685 //
V_FadeScreen(void)2686 void V_FadeScreen(void)
2687 {
2688     // vid : from video setup
2689     V_FadeRect( 0, vid.width, vid.height,
2690                 fadescreen_alpha[ cv_darkback.EV ],
2691                 fadescreen_draw8[ cv_darkback.EV ],
2692                 0 );
2693 }
2694 
2695 
2696 //  [WDJ] Tables for darkback
2697 // index by cv_darkback
2698 byte fadecons_draw8[3] =
2699 {
2700    3,  // half
2701   15,  // med
2702   23   // dark
2703 };
2704 
2705 // Dark enough that red text is lighter and easily readable.
2706 byte fadecons_alpha[3] =
2707 {
2708   0x80,  // half
2709   0x40,  // med
2710   0x20   // dark
2711 };
2712 
2713 byte fadecons_green[3] =
2714 {
2715   0x16,  // half
2716   0x12,  // med
2717   0x08   // dark
2718 };
2719 
2720 
2721 // Fade the console background with fade alpha and green tint per cv_darkback.
2722 //
2723 //added:20-03-98: console test
2724 //   x1, x2, y2 : affected ranges in pixels,  (always y1 = 0)
V_FadeConsBack(int x1,int x2,int y2)2725 void V_FadeConsBack(int x1, int x2, int y2)
2726 {
2727     uint32_t tint = RGBA(0, fadecons_green[ cv_darkback.EV ], 0, 0);
2728 
2729 #ifdef HWRENDER
2730     // The green tint is weak for OpenGL.
2731     if( rendermode != render_soft )
2732        tint = tint*2;  // works for small values of green < 127
2733 #endif
2734     V_FadeRect( x1, x2, y2,
2735                 fadecons_alpha[ cv_darkback.EV ],
2736                 fadecons_draw8[ cv_darkback.EV ],
2737                 tint );
2738 }
2739 
2740 
2741 // [WDJ]  Default Font
2742 #define FONT1_WIDTH 7
2743 #define FONT1_HEIGHT 9
2744 #define FONT1_START  32
2745 static byte font1_bits[] = {
2746    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sp
2747    0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x00, // !
2748    0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // "
2749    0x00, 0x14, 0x14, 0x7f, 0x14, 0x7f, 0x14, 0x14, 0x00, // #
2750    0x1c, 0x2a, 0x0a, 0x0c, 0x18, 0x28, 0x2a, 0x1c, 0x00, // $
2751    0x42, 0x25, 0x12, 0x08, 0x08, 0x24, 0x52, 0x21, 0x00, // %
2752    0x08, 0x14, 0x14, 0x08, 0x14, 0x12, 0x22, 0x5c, 0x00, // &
2753    0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // apostrophe
2754    0x08, 0x04, 0x04, 0x02, 0x02, 0x04, 0x04, 0x08, 0x00, // (
2755    0x08, 0x10, 0x10, 0x20, 0x20, 0x10, 0x10, 0x08, 0x00, // )
2756    0x08, 0x49, 0x2a, 0x1c, 0x1c, 0x2a, 0x49, 0x08, 0x00, // *
2757    0x00, 0x08, 0x08, 0x3e, 0x08, 0x08, 0x00, 0x00, 0x00, // +
2758    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x04, // comma
2759    0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, // -
2760    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, // .
2761    0x10, 0x10, 0x08, 0x08, 0x04, 0x04, 0x02, 0x02, 0x00, // /
2762 
2763    0x18, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x18, 0x00, // 0
2764    0x08, 0x0c, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, // 1
2765    0x1c, 0x22, 0x20, 0x10, 0x08, 0x04, 0x02, 0x3e, 0x00,
2766    0x1e, 0x20, 0x20, 0x18, 0x20, 0x20, 0x20, 0x1e, 0x00,
2767    0x10, 0x18, 0x14, 0x12, 0x3e, 0x10, 0x10, 0x10, 0x00,
2768    0x3e, 0x02, 0x02, 0x1e, 0x20, 0x20, 0x20, 0x1e, 0x00,
2769    0x1c, 0x02, 0x02, 0x1e, 0x22, 0x22, 0x22, 0x1c, 0x00,
2770    0x3e, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x00,
2771    0x1c, 0x22, 0x22, 0x1c, 0x22, 0x22, 0x22, 0x1c, 0x00,
2772    0x1c, 0x22, 0x22, 0x3c, 0x20, 0x20, 0x22, 0x1c, 0x00, // 9
2773 
2774    0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, // :
2775    0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x04, // ;
2776    0x00, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x00, // <
2777    0x00, 0x00, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x00, 0x00, // =
2778    0x00, 0x04, 0x08, 0x10, 0x20, 0x10, 0x08, 0x04, 0x00, // >
2779    0x1c, 0x22, 0x20, 0x10, 0x08, 0x08, 0x00, 0x08, 0x00, // ?
2780    0x3e, 0x41, 0x41, 0x5d, 0x55, 0x45, 0x45, 0x39, 0x00, // @
2781 
2782    0x1c, 0x22, 0x22, 0x22, 0x3e, 0x22, 0x22, 0x22, 0x00, // A
2783    0x1e, 0x22, 0x22, 0x1e, 0x22, 0x22, 0x22, 0x1e, 0x00,
2784    0x38, 0x04, 0x02, 0x02, 0x02, 0x02, 0x04, 0x38, 0x00,
2785    0x0e, 0x12, 0x22, 0x22, 0x22, 0x22, 0x12, 0x0e, 0x00,
2786    0x3e, 0x02, 0x02, 0x02, 0x1e, 0x02, 0x02, 0x3e, 0x00,
2787    0x3e, 0x02, 0x02, 0x1e, 0x02, 0x02, 0x02, 0x02, 0x00,
2788    0x1c, 0x22, 0x02, 0x02, 0x32, 0x22, 0x22, 0x1c, 0x00,
2789    0x22, 0x22, 0x22, 0x22, 0x3e, 0x22, 0x22, 0x22, 0x00,
2790    0x1c, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00,
2791    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x1c, 0x00,
2792    0x22, 0x12, 0x0a, 0x06, 0x06, 0x0a, 0x12, 0x22, 0x00,
2793    0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x3e, 0x00,
2794    0x36, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x00,
2795    0x22, 0x26, 0x26, 0x2a, 0x2a, 0x32, 0x32, 0x22, 0x00,
2796    0x0c, 0x12, 0x21, 0x21, 0x21, 0x21, 0x12, 0x0c, 0x00,
2797    0x1e, 0x22, 0x22, 0x22, 0x1e, 0x02, 0x02, 0x02, 0x00,
2798    0x0c, 0x12, 0x21, 0x21, 0x21, 0x29, 0x12, 0x2c, 0x00,
2799    0x1e, 0x22, 0x22, 0x22, 0x1e, 0x0a, 0x12, 0x22, 0x00,
2800    0x1c, 0x22, 0x02, 0x0e, 0x38, 0x20, 0x22, 0x1c, 0x00,
2801    0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00,
2802    0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1c, 0x00,
2803    0x22, 0x22, 0x22, 0x22, 0x14, 0x14, 0x14, 0x08, 0x00,
2804    0x41, 0x41, 0x49, 0x49, 0x49, 0x49, 0x49, 0x36, 0x00,
2805    0x41, 0x22, 0x14, 0x08, 0x08, 0x14, 0x22, 0x41, 0x00,
2806    0x22, 0x22, 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x00,
2807    0x3e, 0x20, 0x10, 0x08, 0x08, 0x04, 0x02, 0x3e, 0x00, // Z
2808 
2809    0x1c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x1c, 0x00, // [
2810    0x02, 0x02, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x00, // backslash
2811    0x1c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1c, 0x00, // ]
2812    0x08, 0x14, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ^
2813    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, // _
2814    0x04, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // accent
2815 
2816    0x00, 0x00, 0x0c, 0x10, 0x1c, 0x12, 0x12, 0x1c, 0x00, // a
2817    0x02, 0x02, 0x02, 0x0e, 0x12, 0x12, 0x12, 0x0e, 0x00,
2818    0x00, 0x00, 0x00, 0x1c, 0x02, 0x02, 0x02, 0x1c, 0x00,
2819    0x10, 0x10, 0x10, 0x1c, 0x12, 0x12, 0x12, 0x1c, 0x00,
2820    0x00, 0x00, 0x00, 0x0c, 0x12, 0x1e, 0x02, 0x1c, 0x00,
2821    0x08, 0x14, 0x04, 0x04, 0x0e, 0x04, 0x04, 0x04, 0x00,
2822    0x00, 0x00, 0x00, 0x0c, 0x12, 0x12, 0x1c, 0x10, 0x0e,
2823    0x02, 0x02, 0x02, 0x0e, 0x12, 0x12, 0x12, 0x12, 0x00,
2824    0x00, 0x00, 0x08, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00,
2825    0x00, 0x00, 0x08, 0x00, 0x08, 0x08, 0x08, 0x08, 0x0c,
2826    0x02, 0x02, 0x02, 0x12, 0x0a, 0x06, 0x0a, 0x12, 0x00,
2827    0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x18, 0x00,
2828    0x00, 0x00, 0x00, 0x36, 0x49, 0x49, 0x49, 0x49, 0x00,
2829    0x00, 0x00, 0x00, 0x1a, 0x26, 0x22, 0x22, 0x22, 0x00,
2830    0x00, 0x00, 0x00, 0x1c, 0x22, 0x22, 0x22, 0x1c, 0x00,
2831    0x00, 0x00, 0x00, 0x0e, 0x12, 0x12, 0x0e, 0x02, 0x02,
2832    0x00, 0x00, 0x00, 0x1c, 0x12, 0x12, 0x1c, 0x10, 0x30,
2833    0x00, 0x00, 0x00, 0x1a, 0x26, 0x02, 0x02, 0x02, 0x00,
2834    0x00, 0x00, 0x00, 0x3c, 0x02, 0x1c, 0x20, 0x1e, 0x00,
2835    0x04, 0x04, 0x04, 0x0e, 0x04, 0x04, 0x24, 0x18, 0x00,
2836    0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x1c, 0x00,
2837    0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x14, 0x08, 0x00,
2838    0x00, 0x00, 0x00, 0x49, 0x49, 0x49, 0x49, 0x36, 0x00,
2839    0x00, 0x00, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00,
2840    0x00, 0x00, 0x00, 0x42, 0x24, 0x18, 0x08, 0x04, 0x02,
2841    0x00, 0x00, 0x00, 0x3e, 0x10, 0x08, 0x04, 0x3e, 0x00, // z
2842 
2843    0x30, 0x08, 0x08, 0x0c, 0x0c, 0x08, 0x08, 0x30, 0x00, // {
2844    0x0c, 0x10, 0x10, 0x30, 0x30, 0x10, 0x10, 0x0c, 0x00, // |
2845    0x08, 0x08, 0x08, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, // }
2846    0x00, 0x06, 0x49, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, // ~
2847    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // DEL
2848 };
2849 
2850 byte use_font1 = 1;
2851 // default console colors
2852 // Will be updated to nearest color at palette load
2853 byte ci_black = 0;
2854 byte ci_white = 4;
2855 byte ci_green = 123;
2856 byte ci_grey = 2;
2857 
2858 fontinfo_t font1_info =
2859   { FONT1_WIDTH, FONT1_HEIGHT, FONT1_WIDTH+1, FONT1_HEIGHT+1 };
2860 
2861 // from console.c
2862 fontinfo_t doomfont_info =
2863   { 7, 7, 8, 8 };
2864 
V_FontInfo(void)2865 fontinfo_t * V_FontInfo( void )
2866 {
2867     return (use_font1)? &font1_info : &doomfont_info;
2868 }
2869 
2870 //  Draw font1 fixed width character
2871 //  NOT FOR OPENGL ***
2872 //  Scaled or Unscaled x, y.
2873 static
V_Drawfont1_char(int x,int y,byte c)2874 int  V_Drawfont1_char(int x, int y, byte c)
2875 {
2876     // vid : from video setup
2877     // drawinfo : from V_SetupDraw
2878     int  fb, fy, i, d, chwidth;
2879     byte fbit;
2880     byte fcolor = (c & 0x80)? ci_white : ci_green;  // white : green
2881     byte * dp;
2882     byte * lbp;
2883     byte lb[FONT1_WIDTH*8];
2884 
2885     chwidth = FONT1_WIDTH * drawinfo.dupx;
2886     c &= 0x7f;
2887     if( c < 33 )  return chwidth;  // space and non-printing
2888 
2889     fb = (c - FONT1_START) * FONT1_HEIGHT;  // in font addressing
2890 
2891     dp = drawinfo.drawp + (y * drawinfo.y0bytes) + (x * drawinfo.x0bytes);
2892 
2893     if(((x * drawinfo.dupx0) + chwidth) > vid.width)
2894         return 0;
2895 
2896 #if 0
2897     // check for overdraw of underline
2898     fy = 0;
2899     if( c == '_' )
2900     {
2901         fy = 6;
2902         dp += fy * vid.ybytes;
2903     }
2904     for( ; fy<FONT1_HEIGHT; fy++ )
2905 #else
2906     for( fy=0; fy<FONT1_HEIGHT; fy++ )
2907 #endif
2908     {
2909         fbit = font1_bits[ fb + fy ];
2910         lbp = &lb[0];
2911         for( i=0; i<FONT1_WIDTH; i++ )  // convert bit map to color bytes
2912         {
2913            for( d=drawinfo.dupx; d>0; d-- )
2914                *(lbp++) = ( fbit & 0x01 )? fcolor : ci_black;
2915            fbit >>= 1;
2916         }
2917         for( d=drawinfo.dupy; d>0; d-- )
2918         {
2919             V_DrawPixels(dp, 0, chwidth, lb);
2920             dp += vid.ybytes;
2921         }
2922     }
2923     return chwidth;
2924 }
2925 
2926 //  Draw font1 fixed width string
2927 //  NOT FOR OPENGL ***
2928 //  Scaled or Unscaled x, y.
2929 //  Called by V_DrawString.
V_Drawfont1_string(int x,int y,int option,const char * string)2930 void V_Drawfont1_string(int x, int y, int option, const char *string)
2931 {
2932     // vid : from video setup
2933     // drawinfo : from V_SetupDraw
2934     int  fb, fy, i, d, chwidth, chwidth_bytes, chspace_bytes, x0, cx;
2935     byte *dp0, *dp;
2936     const char * ch = string;
2937     byte fbit, c;
2938     byte fcolor = (option & V_WHITEMAP)? ci_white : ci_green;  // white : green
2939     byte * lbp;
2940     byte lb[FONT1_WIDTH*MAXVIDWIDTH/BASEVIDWIDTH];  // * max dupx
2941 
2942     if( !string )  return;
2943 
2944     chwidth = FONT1_WIDTH * drawinfo.dupx;
2945     chwidth_bytes = chwidth * vid.bytepp;
2946     chspace_bytes = (FONT1_WIDTH+1) * drawinfo.xbytes;
2947     dp0 = drawinfo.drawp + (y * drawinfo.y0bytes);
2948     x0 = (x * drawinfo.x0bytes);  // scaled x
2949     cx = x0;
2950 
2951     for(;;)
2952     {
2953         c = *ch++;
2954         if (!c)
2955             break;
2956         if (c == '\n')
2957         {
2958             cx = x0;
2959             dp0 += (FONT1_HEIGHT+3) * drawinfo.dupy;
2960             continue;
2961         }
2962 
2963         if((cx + chwidth_bytes) > vid.widthbytes)
2964             break;
2965 
2966         if (c >= 33)
2967         {
2968             dp = dp0 + cx;  // dest of char
2969             fb = ((c & 0x7f) - FONT1_START) * FONT1_HEIGHT;  // in font addressing
2970             for( fy=0; fy<FONT1_HEIGHT; fy++ )  // font lines
2971             {
2972                 fbit = font1_bits[ fb + fy ];
2973                 lbp = &lb[0];
2974                 for( i=0; i<FONT1_WIDTH; i++ )  // convert bit map to color bytes
2975                 {
2976                     for( d=drawinfo.dupx; d>0; d-- )  // dup width
2977                       *(lbp++) = ( fbit & 0x01 )? fcolor : ci_black;
2978                     fbit >>= 1;
2979                 }
2980                 for( d=drawinfo.dupy; d>0; d-- )  // dup height
2981                 {
2982                     V_DrawPixels(dp, 0, chwidth, lb);
2983                     dp += vid.ybytes;
2984                 }
2985             }
2986         }
2987         cx += chspace_bytes;
2988     }
2989 }
2990 
2991 // Current draw font info.
2992 drawfont_t  drawfont;
2993 
2994 // Setup drawfont for DrawCharacter and DrawString.
2995 // Uses V_SetupDraw.
2996 //  option : V_SCALESTART
V_SetupFont(int font_size,fontinfo_t * fip,uint32_t option)2997 void  V_SetupFont( int font_size, fontinfo_t * fip, uint32_t option )
2998 {
2999     // V_SetupDraw calls here with font_size = 0, do not call back.
3000     if( font_size > 0 )
3001     {
3002         // Scale, Large = 5.0, Small = 1.0
3003         drawfont.scale = (float)font_size + 0.000001f;
3004         // Small is not quite at 1.0, let it round down only when it has to.
3005         drawfont.ratio = (drawfont.scale - 0.90f) / (5.0f - 0.90f);  // 0.0 .. 1.0
3006         // V_SetupDraw( V_FINESCALEPATCH ) scales by drawfont.scale.
3007         // Do not pass option V_SCALESTART to draw.  Handled by DrawString.
3008         V_SetupDraw( V_FINESCALEPATCH | option );
3009     }
3010     else
3011     {
3012         drawfont.scale = 5.0f;
3013         drawfont.ratio = 1.0f;
3014     }
3015 
3016     if( fip == NULL )
3017        fip = V_FontInfo();  // default
3018 
3019     drawfont.font_height = fip->height;
3020 
3021 #ifdef HWRENDER
3022     if( rendermode == render_soft )
3023     {
3024         drawfont.xinc = fip->xinc * drawinfo.dupx;
3025         drawfont.yinc = fip->yinc * drawinfo.dupy;
3026     }
3027     else
3028     {
3029         drawfont.xinc = (int) fip->xinc * drawinfo.fdupx;
3030         drawfont.yinc = (int) fip->yinc * drawinfo.fdupy;
3031     }
3032 #else
3033     drawfont.xinc = fip->xinc * drawinfo.dupx;
3034     drawfont.yinc = fip->yinc * drawinfo.dupy;
3035 #endif
3036 
3037     // SCALESTART for font drawing, separate from drawinfo.
3038     if( option & V_SCALESTART )
3039     {
3040         drawfont.dupx0 = vid.dupx;
3041         drawfont.dupy0 = vid.dupy;
3042         drawfont.fdupx0 = vid.fdupx;
3043         drawfont.fdupy0 = vid.fdupy;
3044     }
3045     else
3046     {
3047         drawfont.dupx0 = 1;
3048         drawfont.dupy0 = 1;
3049         drawfont.fdupx0 = 1.0f;
3050         drawfont.fdupy0 = 1.0f;
3051     }
3052 }
3053 
3054 
3055 // Writes a single character (draw WHITE if bit 7 set)
3056 //
3057 //added:20-03-98:
3058 // Return pixel width.
V_DrawCharacter(int x,int y,byte c)3059 int V_DrawCharacter(int x, int y, byte c)
3060 {
3061     // vid : from video setup
3062     // drawinfo : from V_SetupDraw
3063     int w;
3064     boolean white = c & 0x80;
3065     c &= 0x7f;
3066 
3067     if( use_font1 && (rendermode == render_soft))
3068     {
3069          return  V_Drawfont1_char( x, y, c);;
3070     }
3071 
3072     // hufont only has uppercase
3073     c = toupper(c) - HU_FONTSTART;
3074     if (c >= HU_FONTSIZE)
3075         return  4 * drawinfo.dupx;  // space and non-printing chars
3076 
3077     // Hardware or software render, access patch fields.
3078     w = V_patch( hu_font[c] )->width * drawinfo.dupx;  // proportional width
3079     if (((x * drawfont.dupx0) + w) > vid.width)
3080         return 0;
3081 
3082     if (white)
3083         V_DrawMappedPatch(x, y, hu_font[c], whitemap);
3084     else
3085         V_DrawScaledPatch(x, y, hu_font[c]);
3086 
3087     return w + 1;
3088 }
3089 
3090 //
3091 //  Write a string using the hu_font
3092 //  NOTE: the text is centered for screens larger than the base width
3093 //
3094 //added:05-02-98:
3095 // Default is V_SCALESTART and V_SCALEPATCH
3096 // option V_SCALESTART controls spacing
3097 // Can use DrawInfo which is also set to SCALESTART and SCALEPATCH
3098 // Called am_map: option=0
3099 // Called d_main netstats: option = V_WHITEMAP, BASEWIDTH relative
3100 // Called f_finale cast member names: option=0
3101 // Called hu_stuff tips: SetupDraw(SCALESTART, SCALEPATCH)
3102 // Called menu: option=0 or V_WHITEMAP, within SetupDraw(SCALESTART, SCALEPATCH)
3103 // Called st_stuff status overlay: (does its own scaling), option=0
3104 //    within SetupDraw( NOSCALE, SCALEPATCH )
3105 // Called wi_stuff YAH: option 0 or V_WHITEMAP, within SetupDraw(SCALESTART, SCALEPATCH)
V_DrawString(int x,int y,int option,const char * string)3106 void V_DrawString(int x, int y, int option, const char *string)
3107 {
3108     // Save draw SCALESTART setting, and switch to NO SCALESTART drawing.
3109     // The combination of SCALESTART to this DrawString, and NO SCALEPATCH
3110     // drawing, cannot be handled with dup. Must turn off SCALESTART.
3111     // vid : from video setup
3112     // drawinfo : from V_SetupDraw
3113     float w;
3114     const char *ch;
3115     int c;
3116     float cx, cy;  // to support hw_draw
3117     float dupx, dupy; // to fix spacing scaling
3118 
3119 #if 0
3120     // Moved from V_DrawCenteredString, as an option.
3121     // unused
3122     if( option & V_CENTERHORZ )
3123     {
3124        x = (vid.width - V_StringWidth(string)) / 2;
3125        if( x < 0 )   x = 0;
3126     }
3127 #endif
3128 
3129     if ( use_font1 && (rendermode == render_soft))
3130     {
3131          V_Drawfont1_string( x, y, option, string);
3132          return;
3133     }
3134 
3135     ch = string;
3136 
3137 #ifdef HWRENDER
3138     if( rendermode != render_soft )
3139     {
3140         // Character spacing must be scaled here.
3141         dupx = drawinfo.fdupx;
3142         dupy = drawinfo.fdupy;
3143 
3144         // V_SCALESTART to DrawString must be handled here.
3145         cx = x * drawfont.fdupx0;
3146         cy = y * drawfont.fdupy0;
3147     }
3148     else
3149 #endif
3150     {
3151         // Character spacing must be scaled here.
3152         dupx = drawinfo.dupx;
3153         dupy = drawinfo.dupy;
3154 
3155         // V_SCALESTART to DrawString must be handled here.
3156         cx = x * drawfont.dupx0;
3157         cy = y * drawfont.dupy0;
3158     }
3159 
3160     // Change draw to NO SCALESTART, for positioning of characters.
3161     V_SetupDraw_NO_SCALESTART();
3162 
3163     for(;;)
3164     {
3165         c = *ch++;
3166         if (!c)
3167             break;
3168         if (c == '\n')
3169         {
3170             cx = x;
3171             cy += 12 * dupy;
3172             continue;
3173         }
3174 
3175         // hufont only has uppercase
3176         c = toupper(c) - HU_FONTSTART;
3177         if (c < 0 || c >= HU_FONTSIZE)
3178         {
3179             cx += 4 * dupx;
3180             continue;
3181         }
3182 
3183         //[segabor]
3184         // hu_font is endian fixed
3185         // Hardware or software render, access patch fields.
3186         w = V_patch( hu_font[c] )->width * dupx;  // proportional width
3187         if (cx + w > vid.width)
3188             break;
3189         if (option & V_WHITEMAP)
3190             V_DrawMappedPatch( (int)cx, (int)cy, hu_font[c], whitemap);
3191         else
3192             V_DrawScaledPatch( (int)cx, (int)cy, hu_font[c]);
3193         cx += w;
3194     }
3195 
3196     V_SetupDraw_Restore_SCALESTART();  // Restore SetupDraw
3197 }
3198 
3199 
3200 //
3201 // Find string width from hu_font chars
3202 //
3203 // Used extensively
V_StringWidth(const char * string)3204 int V_StringWidth( const char *string)
3205 {
3206     int i;
3207     int sw = 0;
3208     int ln = strlen(string);
3209 
3210     if(use_font1)
3211     {
3212         return ln * (FONT1_WIDTH+1);  // fixed width font
3213     }
3214 
3215     // variable width font, total up chars in string
3216     for (i = 0; i < ln; i++)
3217     {
3218         // hufont only has uppercase
3219         // Prevent using signed char as index.
3220         unsigned char uc = string[i];
3221         int c = toupper(uc) - HU_FONTSTART;
3222         if (c < 0 || c >= HU_FONTSIZE)
3223             sw += 4;
3224         else
3225         {
3226             //[segabor]
3227             // hu_font is endian fixed
3228             // Hardware or software render, access patch fields.
3229             sw += V_patch( hu_font[c] )->width;
3230         }
3231     }
3232 
3233     return sw;
3234 }
3235 
3236 #if 0
3237 // Unused, see V_FontInfo, and drawinfo
3238 //
3239 // Find string height from hu_font chars
3240 //
3241 int V_StringHeight( const char *string)
3242 {
3243     return (hu_font[0]->height);
3244 }
3245 #endif
3246 
3247 //---------------------------------------------------------------------------
3248 //
3249 // PROC MN_DrTextB
3250 //
3251 // Draw text using font B.
3252 //
3253 //---------------------------------------------------------------------------
3254 lumpnum_t  FontBBaseLump;
3255 
3256 // per drawinfo
V_DrawTextB(const char * text,int x,int y)3257 void V_DrawTextB(const char *text, int x, int y)
3258 {
3259     char c;
3260     patch_t *p;
3261 
3262     while ((c = *text++) != 0)
3263     {
3264         if (c < 33)
3265         {
3266             x += 8;
3267         }
3268         else
3269         {
3270             // FontB only has uppercase
3271             p = W_CachePatchNum(FontBBaseLump + toupper(c) - 33, PU_CACHE);  // endian fix
3272             V_DrawScaledPatch(x, y, p);
3273             // Hardware or software render, access patch fields.
3274             x += V_patch(p)->width - 1;
3275         }
3276     }
3277 }
3278 
3279 // per drawinfo
V_DrawTextBGray(const char * text,int x,int y)3280 void V_DrawTextBGray(const char *text, int x, int y)
3281 {
3282     char c;
3283     patch_t *p;
3284 
3285     while ((c = *text++) != 0)
3286     {
3287         if (c < 33)
3288         {
3289             x += 8;
3290         }
3291         else
3292         {
3293             // FontB only has uppercase
3294             p = W_CachePatchNum(FontBBaseLump + toupper(c) - 33, PU_CACHE);  // endian fix
3295             V_DrawMappedPatch(x, y, p, graymap);
3296             // Hardware or software render, access patch fields.
3297             x += V_patch(p)->width - 1;
3298         }
3299     }
3300 }
3301 
3302 //---------------------------------------------------------------------------
3303 //
3304 // FUNC MN_TextBWidth
3305 //
3306 // Returns the pixel width of a string using font B.
3307 //
3308 //---------------------------------------------------------------------------
3309 
V_TextBWidth(const char * text)3310 int V_TextBWidth(const char *text)
3311 {
3312     char c;
3313     int width;
3314     patch_t *p;
3315 
3316     width = 0;
3317     while ((c = *text++) != 0)
3318     {
3319         if (c < 33)
3320         {
3321             width += 5;
3322         }
3323         else
3324         {
3325             // FontB only has uppercase
3326             p = W_CachePatchNum(FontBBaseLump + toupper(c) - 33, PU_CACHE);  // endian fix
3327             // Hardware or software render, access patch fields.
3328             width += V_patch(p)->width - 1;
3329         }
3330     }
3331     return (width);
3332 }
3333 
V_TextBHeight(const char * text)3334 int V_TextBHeight(const char *text)
3335 {
3336     return 16;
3337 }
3338 
3339 // Setup wad loadable video resources.
3340 // Also called before wad is read, to supply defaults.
V_Setup_Wad_VideoResc(void)3341 void V_Setup_Wad_VideoResc(void)
3342 {
3343     LoadPalette("PLAYPAL");
3344     FontBBaseLump = W_CheckNumForName("FONTB_S") + 1;
3345 
3346 #ifdef ENABLE_DRAWEXT
3347     // This is also done, better, by SetPalette
3348     //fab highcolor
3349     if (( vid.bytepp > 1 ) && pLocalPalette )  // highcolor, truecolor
3350     {
3351         R_Init_color8_translate( pLocalPalette );  // no palette change
3352     }
3353 #endif
3354 }
3355 
3356 
3357 // Setup Video and Drawing according to render and vidmode.
3358 // Software stuff, buffers are allocated at video mode setup
3359 // here we set the screens[x] pointers accordingly
3360 // WARNING :
3361 // - called at runtime (don't init cvar here)
3362 // Must be called after every video Init and SetMode.
3363 // Some port video control may call this directly, because of print stmts.
V_Setup_VideoDraw(void)3364 void V_Setup_VideoDraw(void)
3365 {
3366     // vid : from video setup
3367     int i;
3368 
3369     // Must init everything needed by DrawPixel, as that gets used for
3370     // many intro screens, before SCR_SetMode or SCR_Recalc are called.
3371 
3372     // [WDJ] Use vid.draw_ready to indicate that this setup has been done.
3373     // Attempts to test other vars such as screen or drawmode is complicated
3374     // by the odd usage of those vars in video functions, or OpenGL mode
3375     // not using them at all.
3376     // Using vid.draw_ready is less likely to get damaged later.
3377 
3378     // Setup everything needed to draw console, pics, and error messages.
3379 
3380     // scale 1,2,3 times in x and y the patches for the
3381     // menus and overlays... calculated once and for all
3382     // used by routines in v_video.c
3383     // leave it be 1 in hardware accelerated modes
3384     vid.dupx = vid.width / BASEVIDWIDTH;
3385     vid.dupy = vid.height / BASEVIDHEIGHT;
3386     vid.fdupx = (float)vid.width / BASEVIDWIDTH;
3387     vid.fdupy = (float)vid.height / BASEVIDHEIGHT;
3388     //vid.baseratio = FixedDiv(vid.height << FRACBITS, BASEVIDHEIGHT << FRACBITS); //Hurdler: not used anymore
3389     vid.fx_center = (float) vid.width * 0.5f;
3390     vid.fx_scale2 = 2.0f / (float)vid.width;
3391     vid.fy_center = (float) vid.height * 0.5f;
3392     vid.fy_scale2 = 2.0f / (float)vid.height;
3393 
3394     //added:18-02-98: calculate centering offset for the scaled menu
3395     // Adds a left margin and top margin for CENTERMENU
3396     // Fixed to account for video buffer line padding.
3397     vid.centerofs = (((vid.height%BASEVIDHEIGHT)/2) * vid.ybytes) +
3398                     (((vid.width%BASEVIDWIDTH)/2)  * vid.bytepp) ;
3399 
3400 //    if( cv_gammafunc.value != cv_gammafunc.EV )
3401     {
3402         cv_gammafunc.EV = cv_gammafunc.value;
3403         CV_gammafunc_OnChange();
3404     }
3405 
3406 #ifdef HWRENDER
3407     // hardware modes do not use screens[] pointers
3408     if( rendermode != render_soft )
3409     {
3410         // Hardware draw only.
3411         // be sure to cause a NULL read/write error so we detect it, in case of..
3412         for (i = 0; i < NUMSCREENS; i++)
3413             screens[i] = NULL;
3414 
3415         vid.drawmode = DRAWGL;
3416         if( graphics_state >= VGS_active )
3417             vid.draw_ready = 1;
3418 
3419         HWR_Startup_Render();  // hardware render init
3420 
3421         return;
3422     }
3423 #endif
3424 
3425     // Software draw only.
3426     EN_HWR_flashpalette = 0;  // software and default
3427 
3428     if( vid.display == NULL )
3429     {
3430         GenPrintf( EMSG_warn, "V_Setup_VideoDraw: No display\n" );
3431         return;  // allocation failed
3432     }
3433 
3434     // [WDJ] screens usage
3435     // [0] = display or direct video
3436     // [1] = background, status bar
3437     // [2] = wipe start screen, screenshot, (? Horz. draw)
3438     // [3] = wipe end screen
3439     screens[0] = vid.display;  // buffer or direct video
3440     // buffers allocated by port video control, 0..(NUMSCREENS-1)
3441     for (i = 1; i < NUMSCREENS; i++)
3442         screens[i] = vid.screen1 + ((i-1) * vid.screen_size);
3443 
3444     // [WDJ] statusbar buffer was not within driver allocated memory
3445     // and is not used.
3446     //added:26-01-98: statusbar buffer
3447 //    screens[4] = base + NUMSCREENS * screensize;
3448     screens[4] = NULL;
3449 
3450     //!debug
3451 #ifdef DEBUG
3452     CONS_Printf("V_Setup_VideoDraw:\n");
3453     for (i = 0; i < NUMSCREENS + 1; i++)
3454         CONS_Printf(" screens[%d] = %x\n", i, screens[i]);
3455 #endif
3456 
3457     // port video control should check CanDraw before setting vid.bitpp
3458     switch( vid.bitpp )
3459     {
3460      case 8:
3461         vid.drawmode = DRAW8PAL;
3462         break;
3463 #ifdef ENABLE_DRAW15
3464      case 15:
3465         vid.drawmode = DRAW15;
3466         break;
3467 #endif
3468 #ifdef ENABLE_DRAW16
3469      case 16:
3470         vid.drawmode = DRAW16;
3471         break;
3472 #endif
3473 #ifdef ENABLE_DRAW24
3474      case 24:
3475         vid.drawmode = DRAW24;
3476         break;
3477 #endif
3478 #ifdef ENABLE_DRAW32
3479      case 32:
3480         vid.drawmode = DRAW32;
3481         break;
3482 #endif
3483      default:
3484         I_Error ("V_Setup_VideoDraw invalid bits per pixel: %d\n", vid.bitpp);
3485     }
3486 
3487     if( screens[0] && (graphics_state >= VGS_active))
3488         vid.draw_ready = 1;
3489     return;
3490 }
3491 
3492 
3493 // ---- Draw Frame-per-second graph
3494 
3495 #define FPS_POINTS  35
3496 #define FPS_SCALE    4
3497 #define FPS_MAXTICKS 20
3498 #define FPS_SHIFTTIC 10
3499 
3500 static byte fpsgraph[FPS_POINTS];
3501 
3502 // [WDJ] Draw ticrate graph at bottom of screen.
3503 // Removed from port drivers so do not have to maintain 4 copies of it.
V_Draw_ticrate_graph(void)3504 void V_Draw_ticrate_graph( void )
3505 {
3506     // vid : from video setup
3507     static tic_t lasttic;
3508     static tic_t shifttic = 0;
3509     tic_t        tics, nt;
3510     int i;
3511     int k,j;
3512 
3513     nt = I_GetTime();
3514     tics = nt - lasttic;
3515     lasttic = nt;
3516     if (tics > FPS_MAXTICKS) tics = FPS_MAXTICKS;
3517 
3518     // Display a graph of ticrate.
3519     if(cv_ticrate.value == 1)
3520     {
3521         if( nt - shifttic > FPS_SHIFTTIC )
3522         {
3523             // try to get somewhat constant horz. time scale
3524             shifttic += FPS_SHIFTTIC;
3525             // shift it left
3526             memmove( &fpsgraph[0], &fpsgraph[1], (FPS_POINTS-1)*sizeof(fpsgraph[0]));
3527         }
3528         fpsgraph[FPS_POINTS-1]= FPS_MAXTICKS - tics;
3529 
3530         if( rendermode == render_soft )
3531         {
3532             // draw grid of dots
3533             for(j=0; j<=FPS_MAXTICKS*FPS_SCALE*vid.dupy; j+=2*FPS_SCALE*vid.dupy)
3534             {
3535                 byte * dest = V_GetDrawAddr( 0, (vid.height-1-j) );
3536                 for (i=0; i<FPS_POINTS*FPS_SCALE*vid.dupx; i+=2*FPS_SCALE*vid.dupx)
3537                     V_DrawPixel( dest, i, 0xff );
3538             }
3539 
3540             // draw the graph
3541             for (i=0; i<FPS_POINTS; i++)
3542             {
3543                 byte * dest = V_GetDrawAddr( 0, vid.height-1-(fpsgraph[i]*FPS_SCALE*vid.dupy) );
3544                 // draw line at the graph height
3545                 for(k=0; k<FPS_SCALE*vid.dupx; k++)
3546                     V_DrawPixel( dest, (i*FPS_SCALE*vid.dupx)+k, 0xff );
3547             }
3548         }
3549 #ifdef HWRENDER
3550         else
3551         {
3552             fline_t p;
3553             for(j=0; j<=20*FPS_SCALE*vid.dupy; j+=2*FPS_SCALE*vid.dupy)
3554             {
3555                 k=(vid.height-1-j);
3556                 p.a.y = k;
3557                 p.b.y = k;
3558                 for (i=0; i<FPS_POINTS*FPS_SCALE*vid.dupx; i+=2*FPS_SCALE*vid.dupx)
3559                 {
3560                     p.a.x = i;
3561                     p.b.x = i+1;
3562                     HWR_drawAMline(&p, 0xff);
3563                 }
3564             }
3565 
3566             for (i=1; i<FPS_POINTS; i++)
3567             {
3568                 p.a.x = FPS_SCALE * vid.dupx * (i-1);
3569                 p.a.y = vid.height-1-fpsgraph[i-1]*FPS_SCALE*vid.dupy;
3570                 p.b.x = FPS_SCALE * vid.dupx * i;
3571                 p.b.y = vid.height-1-fpsgraph[i]*FPS_SCALE*vid.dupy;
3572                 HWR_drawAMline(&p, 0xff);
3573             }
3574         }
3575 #endif
3576     }
3577     else if(cv_ticrate.value == 2)
3578     {
3579         static byte accum_frame = 0;
3580         int accum_tic = 0;
3581         int i;
3582 
3583         // Sometimes tics = 0, for a frame.
3584         // Use fpsgraph for smoothing the FPS over several frames.
3585         memmove( &fpsgraph[0], &fpsgraph[1], (FPS_POINTS-1)*sizeof(fpsgraph[0]));
3586         fpsgraph[FPS_POINTS-1]= tics;
3587         if( accum_frame < FPS_POINTS )   accum_frame++;  // startup
3588         for( i=0; i<accum_frame; i++ )
3589         {
3590             accum_tic += fpsgraph[i];  // total tics over the frames
3591         }
3592         if( accum_tic > 1 )
3593         {
3594             char buff[20];
3595             sprintf(buff,"FPS: %4i", ((int)accum_frame * TICRATE)/accum_tic );
3596             V_SetupDraw( V_SCALEPATCH | V_SCALESTART );
3597             V_DrawString ( 8, 160, V_WHITEMAP, buff);
3598             V_SetupDraw( drawinfo.prev_screenflags );  // restore
3599         }
3600     }
3601 }
3602 
3603 
3604 //
3605 //
3606 //
3607 typedef struct
3608 {
3609     int px;
3610     int py;
3611 } modelvertex_t;
3612 
3613 void R_DrawSpanNoWrap(void);    //tmap.S
3614 
3615 //
3616 //  Tilts the view like DukeNukem...
3617 //
3618 //added:12-02-98:
3619 #ifdef TILTVIEW
3620 #ifdef HWRENDER
V_DrawTiltView(byte * viewbuffer)3621 void V_DrawTiltView(byte * viewbuffer)  // don't touch direct video I'll find something..
3622 {
3623 }
3624 #else
3625 
3626 static modelvertex_t vertex[4];
3627 
3628 // Called instead of I_FinishUpdate
V_DrawTiltView(byte * viewbuffer)3629 void V_DrawTiltView(byte * viewbuffer)
3630 {
3631     // vid : from video setup
3632     fixed_t leftxfrac;
3633     fixed_t leftyfrac;
3634     fixed_t xstep;
3635     fixed_t ystep;
3636 
3637     int y;
3638 
3639     vertex[0].px = 0;   // tl
3640     vertex[0].py = 53;
3641     vertex[1].px = 212; // tr
3642     vertex[1].py = 0;
3643     vertex[2].px = 264; // br
3644     vertex[2].py = 144;
3645     vertex[3].px = 53;  // bl
3646     vertex[3].py = 199;
3647 
3648     // resize coords to screen
3649     for (y = 0; y < 4; y++)
3650     {
3651         vertex[y].px = (vertex[y].px * vid.width) / BASEVIDWIDTH;
3652         vertex[y].py = (vertex[y].py * vid.height) / BASEVIDHEIGHT;
3653     }
3654 
3655     ds_colormap = fixedcolormap;
3656     ds_source = viewbuffer;
3657 
3658     // starting points top-left and top-right
3659     leftxfrac = vertex[0].px << FRACBITS;
3660     leftyfrac = vertex[0].py << FRACBITS;
3661 
3662     // steps
3663     xstep = ((vertex[3].px - vertex[0].px) << FRACBITS) / vid.height;
3664     ystep = ((vertex[3].py - vertex[0].py) << FRACBITS) / vid.height;
3665 
3666 #if 0
3667     // [WDJ] WRONG, ds_y is y line index, not a ptr
3668     // vid.direct not allowed without locking the video buffer
3669     ds_y = (int) vid.direct;
3670 #else
3671     ds_y = 0;
3672 #endif
3673     ds_x1 = 0;
3674     ds_x2 = vid.width - 1;
3675     ds_xstep = ((vertex[1].px - vertex[0].px) << FRACBITS) / vid.width;
3676     ds_ystep = ((vertex[1].py - vertex[0].py) << FRACBITS) / vid.width;
3677 
3678 //    I_Error("ds_y %d ds_x1 %d ds_x2 %d ds_xstep %x ds_ystep %x \n"
3679 //            "ds_xfrac %x ds_yfrac %x ds_source %x\n", ds_y,
3680 //                      ds_x1,ds_x2,ds_xstep,ds_ystep,leftxfrac,leftyfrac,
3681 //                      ds_source);
3682 
3683     // render spans
3684     for (y = 0; y < vid.height; y++)
3685     {
3686         // FAST ASM routine!
3687         ds_xfrac = leftxfrac;
3688         ds_yfrac = leftyfrac;
3689         R_DrawSpanNoWrap();
3690 #if 0
3691         // [WDJ] WRONG, ds_y is y line index, not a ptr
3692         ds_y += vid.ybytes;
3693 #else
3694         ds_y++;
3695 #endif
3696 
3697         // move along the left and right edges of the polygon
3698         leftxfrac += xstep;
3699         leftyfrac += ystep;
3700     }
3701 
3702 }
3703 #endif
3704 #endif
3705 
3706 
3707 #ifdef PERSPCORRECT
3708 //
3709 // Test 'scrunch perspective correction' tm (c) ect.
3710 //
3711 //added:05-04-98:
3712 
3713 // Called by D_Display
3714 // - instead of I_Finish update with page flip
V_DrawPerspView(byte * viewbuffer,int aiming)3715 void V_DrawPerspView(byte * viewbuffer, int aiming)
3716 {
3717     // vid : from video setup
3718     byte *source;
3719     byte *dest;  // direct screen
3720     int y;
3721     int x1, w;
3722     int offs;
3723 
3724     fixed_t topfrac, bottomfrac, scale, scalestep;
3725     fixed_t xfrac, xfracstep;
3726 
3727     source = viewbuffer;
3728 
3729     //+16 to -16 fixed
3730     offs = ((aiming * 20) << 16) / 100;
3731 
3732     topfrac = ((vid.width - 40) << 16) - (offs * 2);
3733     bottomfrac = ((vid.width - 40) << 16) + (offs * 2);
3734 
3735     scalestep = (bottomfrac - topfrac) / vid.height;
3736     scale = topfrac;
3737 
3738     for (y = 0; y < vid.height; y++)
3739     {
3740         x1 = ((vid.width << 16) - scale) >> 17;
3741     // vid.direct not allowed without locking the video buffer
3742         dest = vid.direct + (y * vid.ybytes) + (x1 * vid.bytepp);
3743 
3744         xfrac = (20 << FRACBITS) + ((!x1) & 0xFFFF);
3745         xfracstep = FixedDiv((vid.width << FRACBITS) - (xfrac << 1), scale);
3746         w = scale >> 16;
3747 #ifdef ENABLE_DRAWEXT
3748         if( vid.bytepp > 1 )
3749         {
3750           while (w--)
3751           {
3752             V_DrawPixel( dest, 0, source[xfrac >> FRACBITS] );
3753             dest += vid.bytepp;
3754             xfrac += xfracstep;
3755           }
3756         }
3757         else
3758 #endif
3759         {
3760           // 8 bit per pixel
3761           while (w--)
3762           {
3763             *dest++ = source[xfrac >> FRACBITS];
3764             xfrac += xfracstep;
3765           }
3766         }
3767 
3768         scale += scalestep;
3769         source += vid.ybytes;
3770     }
3771 
3772 }
3773 #endif
3774