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