1 // Emacs style mode select   -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: hw_main.c 1525 2020-05-09 12:07:29Z wesleyjohnson $
5 //
6 // Copyright (C) 1998-2016 by DooM Legacy Team.
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License
10 // as published by the Free Software Foundation; either version 2
11 // of the License, or (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17 //
18 //
19 // $Log: hw_main.c,v $
20 // Revision 1.115  2004/05/16 19:11:44  hurdler
21 // that should fix issues some people were having in 1280x1024 mode (and now support up to 1600x1200)
22 //
23 // Revision 1.114  2003/08/12 12:29:59  hurdler
24 // better translucent hud
25 //
26 // Revision 1.113  2003/07/13 13:16:15  hurdler
27 //
28 // Revision 1.112  2003/07/10 20:51:43  bock
29 // Small types fix
30 //
31 // Revision 1.111  2003/06/10 21:48:05  ssntails
32 // Variable flat size support (32x32 to 2048x2048)
33 //
34 // Revision 1.110  2002/05/19 19:37:27  hurdler
35 // adding some math functions to FraggleScript
36 //
37 // Revision 1.109  2002/01/12 02:26:47  stroggonmeth
38 //
39 // Revision 1.108  2002/01/05 01:08:51  hurdler
40 // fix a crashing bug with phobx in splitwall (is it ok ?)
41 //
42 // Revision 1.107  2001/12/31 13:47:46  hurdler
43 // Add setcorona FS command and prepare the code for beta 4
44 //
45 // Revision 1.106  2001/12/28 13:27:54  hurdler
46 // Manage translucent walls
47 //
48 // Revision 1.105  2001/12/27 22:50:26  hurdler
49 // fix a colormap bug, add scrolling floor/ceiling in hw mode
50 //
51 // Revision 1.104  2001/12/26 17:24:47  hurdler
52 // Update Linux version
53 //
54 // Revision 1.103  2001/12/26 15:56:11  hurdler
55 // Manage transparent wall a little better
56 //
57 // Revision 1.102  2001/12/15 18:41:36  hurdler
58 // small commit, mainly splitscreen fix
59 //
60 // Revision 1.101  2001/09/03 21:06:52  hurdler
61 //
62 // Revision 1.100  2001/08/27 19:59:35  hurdler
63 // Fix colormap in heretic + opengl, fixedcolormap and NEWCORONA
64 //
65 // Revision 1.99  2001/08/26 15:27:29  bpereira
66 // added fov for glide and fixed newcoronas code
67 //
68 // Revision 1.98  2001/08/19 20:41:04  hurdler
69 //
70 // Revision 1.97  2001/08/19 15:40:07  bpereira
71 // added Treansform (and lighting) to glide
72 //
73 // Revision 1.96  2001/08/14 00:36:26  hurdler
74 // Revision 1.95  2001/08/13 22:53:54  stroggonmeth
75 // Revision 1.94  2001/08/13 17:23:17  hurdler
76 //
77 // Revision 1.93  2001/08/13 17:01:40  hurdler
78 // Fix some coloured sector issue
79 //
80 // Revision 1.92  2001/08/13 16:27:45  hurdler
81 // Added translucency to linedef 300 and colormap to 3d-floors
82 //
83 // Revision 1.91  2001/08/12 22:08:40  hurdler
84 // Add alpha value for 3d water
85 //
86 // Revision 1.90  2001/08/12 19:05:56  hurdler
87 // fix a small bug with 3d water
88 //
89 // Revision 1.89  2001/08/12 17:57:16  hurdler
90 // Beter support of sector coloured lighting in hw mode
91 //
92 // Revision 1.88  2001/08/12 15:21:04  bpereira
93 // see my log
94 //
95 // Revision 1.87  2001/08/11 16:43:07  hurdler
96 // Add sector colormap in hw mode (3rd attempt)
97 //
98 // Revision 1.86  2001/08/11 15:36:56  hurdler
99 // Add sector colormap in hw mode (2nd attempt)
100 //
101 // Revision 1.85  2001/08/11 15:18:02  hurdler
102 // Add sector colormap in hw mode (first attempt)
103 //
104 // Revision 1.84  2001/08/11 00:51:59  hurdler
105 // Sort 3D water for better alpha blending
106 //
107 // Revision 1.83  2001/08/09 21:35:23  hurdler
108 // Add translucent 3D water in hw mode
109 //
110 // Revision 1.82  2001/08/08 20:34:43  hurdler
111 // Big TANDL update
112 //
113 // Revision 1.81  2001/08/07 00:44:05  hurdler
114 // MD2 implementation is getting better but still need lots of work
115 //
116 // Revision 1.80  2001/08/06 23:55:02  stroggonmeth
117 // Removed portal code, improved 3D floors in hardware mode.
118 //
119 // Revision 1.79  2001/08/06 14:13:46  hurdler
120 // Crappy MD2 implementation (still need lots of work)
121 //
122 // Revision 1.78  2001/08/03 15:16:11  hurdler
123 // Fix small bugs (win2k timer + status bar)
124 //
125 // Revision 1.77  2001/06/16 08:07:55  bpereira
126 // Revision 1.76  2001/05/27 13:42:48  bpereira
127 // Revision 1.75  2001/05/16 21:21:15  bpereira
128 //
129 // Revision 1.74  2001/05/14 19:02:58  metzgermeister
130 //   * Fixed floor not moving up with player on E3M1
131 //   * Fixed crash due to oversized string in screen message ... bad bug!
132 //   * Corrected some typos
133 //   * fixed sound bug in SDL
134 //
135 // Revision 1.73  2001/05/07 20:27:16  stroggonmeth
136 //
137 // Revision 1.72  2001/05/03 21:52:23  hurdler
138 // fix bis
139 //
140 // Revision 1.71  2001/05/03 20:05:56  hurdler
141 // small opengl fix
142 //
143 // Revision 1.70  2001/05/01 20:38:34  hurdler
144 // some fix/hack for the beta release
145 //
146 // Revision 1.69  2001/04/30 21:00:10  stroggonmeth
147 // Another HWR fix
148 //
149 // Revision 1.68  2001/04/30 17:19:25  stroggonmeth
150 // HW fix and misc. changes
151 //
152 // Revision 1.67  2001/04/27 13:32:14  bpereira
153 //
154 // Revision 1.66  2001/04/18 23:22:00  hurdler
155 // Until SoM fix it more properly than me ;)
156 //
157 // Revision 1.65  2001/04/18 22:53:55  hurdler
158 // Until SoM fix it more properly than me ;)
159 //
160 // Revision 1.64  2001/04/16 21:40:06  hurdler
161 // Fix misaligned midtexture problem (to verify!)
162 //
163 // Revision 1.63  2001/04/16 15:16:45  hurdler
164 // Revision 1.62  2001/04/09 23:26:05  hurdler
165 // Revision 1.61  2001/04/09 20:24:28  metzgermeister
166 // Revision 1.60  2001/04/09 14:18:21  hurdler
167 // Revision 1.59  2001/04/08 10:15:54  bpereira
168 //
169 // Revision 1.58  2001/04/03 23:15:39  hurdler
170 // FIXME: this code adds basic 3D-floors support in hw mode
171 //
172 // Revision 1.57  2001/03/25 18:11:24  metzgermeister
173 //   * SDL sound bug with swapped stereo channels fixed
174 //   * separate hw_trick.c now for HW_correctSWTrick(.)
175 //
176 // Revision 1.56  2001/03/20 21:26:21  hurdler
177 // use PI instead of M_PI as it  is defined in hw_defs.h (M_PI undefined under win32 by default)
178 //
179 // Revision 1.55  2001/03/19 21:18:48  metzgermeister
180 //   * missing textures in HW mode are replaced by default texture
181 //   * fixed crash bug with P_SpawnMissile(.) returning NULL
182 //   * deep water trick and other nasty thing work now in HW mode (tested with tnt/map02 eternal/map02)
183 //   * added cvar gr_correcttricks
184 //
185 // Revision 1.54  2001/03/19 18:15:59  hurdler
186 // fix a fog problem
187 //
188 // Revision 1.53  2001/03/13 22:14:21  stroggonmeth
189 // Long time no commit. 3D floors, FraggleScript, portals, ect.
190 //
191 // Revision 1.52  2001/02/24 13:35:22  bpereira
192 // Revision 1.51  2001/02/10 12:27:14  bpereira
193 //
194 // Revision 1.50  2001/01/31 17:15:09  hurdler
195 // Add cv_scalestatusbar in hardware mode
196 //
197 // Revision 1.49  2001/01/25 18:56:27  bpereira
198 // Revision 1.48  2000/11/18 15:51:25  bpereira
199 //
200 // Revision 1.47  2000/11/12 21:04:28  hurdler
201 // Fix a bug with validcount and boom code (dyn.light looked ugly with boom water)
202 //
203 // Revision 1.46  2000/11/11 13:59:47  bpereira
204 // Revision 1.45  2000/11/02 22:14:02  bpereira
205 // Revision 1.44  2000/11/02 21:54:26  bpereira
206 // Revision 1.43  2000/11/02 19:49:39  bpereira
207 //
208 // Revision 1.42  2000/10/22 14:16:41  hurdler
209 // Prepare code for TANDL
210 //
211 // Revision 1.41  2000/10/21 08:43:32  bpereira
212 // Revision 1.40  2000/10/04 16:21:57  hurdler
213 // Revision 1.39  2000/10/02 18:25:46  bpereira
214 // Revision 1.38  2000/10/01 15:18:38  hurdler
215 // Revision 1.37  2000/10/01 10:18:23  bpereira
216 //
217 // Revision 1.36  2000/10/01 09:10:19  hurdler
218 // Put the md2 code in #ifdef TANDL
219 //
220 // Revision 1.35  2000/10/01 01:22:35  hurdler
221 // remove polysky, enable PF_Environment for sprites
222 //
223 // Revision 1.34  2000/09/28 20:57:20  bpereira
224 // Revision 1.33  2000/09/21 16:45:11  bpereira
225 // Revision 1.32  2000/08/31 14:30:57  bpereira
226 //
227 // Revision 1.31  2000/08/21 21:13:58  metzgermeister
228 // crash on polys>256verts fixed
229 //
230 // Revision 1.30  2000/08/11 19:11:57  metzgermeister
231 // Revision 1.29  2000/08/03 17:57:42  bpereira
232 // Revision 1.28  2000/07/01 09:23:50  bpereira
233 //
234 // Revision 1.27  2000/06/08 19:40:34  hurdler
235 // my changes before splitting (can be reverted in development branch)
236 //
237 // Revision 1.26  2000/05/30 18:03:22  kegetys
238 // Wall, floor and ceiling lighting is now done by changing only the RGB, not the alpha
239 //
240 // Revision 1.25  2000/05/10 17:45:35  kegetys
241 // Revision 1.24  2000/05/05 18:00:05  bpereira
242 // Revision 1.23  2000/04/30 10:30:10  bpereira
243 //
244 // Revision 1.22  2000/04/27 23:41:16  hurdler
245 // better splitscreen support in OpenGL mode
246 //
247 // Revision 1.21  2000/04/27 17:48:47  hurdler
248 // colormap code in hardware mode is now the default
249 //
250 // Revision 1.20  2000/04/24 20:24:38  bpereira
251 //
252 // Revision 1.19  2000/04/24 15:46:34  hurdler
253 // Support colormap for text
254 //
255 // Revision 1.18  2000/04/23 16:19:52  bpereira
256 //
257 // Revision 1.17  2000/04/23 12:50:32  hurdler
258 // support filter mode in OpenGL
259 //
260 // Revision 1.16  2000/04/22 21:08:23  hurdler
261 //
262 // Revision 1.15  2000/04/22 16:09:14  hurdler
263 // support skin color in hardware mode
264 //
265 // Revision 1.14  2000/04/18 16:07:16  hurdler
266 // better support of decals
267 //
268 // Revision 1.13  2000/04/18 12:52:21  hurdler
269 //
270 // Revision 1.11  2000/04/14 16:34:26  hurdler
271 // some nice changes for coronas
272 //
273 // Revision 1.10  2000/04/12 16:03:51  hurdler
274 // ready for T&L code and true static lighting
275 //
276 // Revision 1.9  2000/04/09 01:59:06  hurdler
277 //
278 // Revision 1.8  2000/04/08 11:28:46  hurdler
279 // added boom water support
280 //
281 // Revision 1.7  2000/03/29 19:39:49  bpereira
282 //
283 // Revision 1.6  2000/03/08 17:02:05  hurdler
284 // fix the joiningame problem under Linux
285 //
286 // Revision 1.5  2000/03/07 14:22:48  hurdler
287 //
288 // Revision 1.4  2000/03/06 16:52:06  hurdler
289 // hack for OpenGL / Open Entry problem
290 //
291 // Revision 1.3  2000/03/05 17:10:56  bpereira
292 // Revision 1.2  2000/02/27 00:42:11  hurdler
293 // Revision 1.1.1.1  2000/02/22 20:32:33  hurdler
294 // Initial import into CVS (v1.29 pr3)
295 //
296 //
297 // DESCRIPTION:
298 //      hardware renderer, using the standard HardwareRender driver DLL for Doom Legacy
299 //
300 //-----------------------------------------------------------------------------
301 
302 #include <math.h>
303 
304 #include "doomincl.h"
305 
306 #include "hw_glob.h"
307 #include "hw_light.h"
308 
309 #include "doomstat.h"
310 #include "i_video.h"
311   // added by Hurdler for rendermode == render_glide
312 #include "v_video.h"
313 #include "p_local.h"
314 #include "p_setup.h"
315 #include "r_local.h"
316 #include "d_clisrv.h"
317 #include "w_wad.h"
318 #include "z_zone.h"
319 #include "r_splats.h"
320 #include "t_func.h"
321 #include "st_stuff.h"
322 
323 
324 
325 //#define SPRITE_NEAR_CLIP_DIST     4.0f
326 #define SPRITE_NEAR_CLIP_DIST     1.01f
327 #define R_FAKEFLOORS
328 
329 
330 // BP: test of draw sky by polygon like in software with visplane ...
331 // [WDJ] Looks bad because R_SKY2 is not a plane, it is distant wall texture.
332 //#define POLYSKY
333 
334 // BP: test change fov when looking up/down but bsp projection messup :(
335 //#define NO_MLOOK_EXTENDS_FOV
336 
337 #define EN_drawtextured  true
338 //static  boolean     EN_drawtextured = false;
339 
340 #ifdef CORONA_CHOICE
341 // mirror corona choice, with auto modifications
342 byte  corona_draw_choice;
343 #endif
344 
345 // Sky upper and lower halfs.
346 typedef enum { DSB_none, DSB_upper, DSB_lower, DSB_all }  DSB_e;
347 
348 
349 // ==========================================================================
350 // the hardware driver object
351 // ==========================================================================
352 struct hwdriver_s hwdriver;
353 
354 // ==========================================================================
355 //                                                                     PROTOS
356 // ==========================================================================
357 
358 static void HWR_AddSprites(sector_t* sec, lightlev_t lightlevel);
359 static void HWR_ProjectSprite(mobj_t * thing);
360 static void HWR_Add3DWater(int picnum, poly_subsector_t * xsub, fixed_t fixedheight, int lightlevel, int alpha);
361 static void HWR_Render3DWater();
362 static void HWR_RenderSorted( void );
363 
364 
365 // ==========================================================================
366 //                                          3D ENGINE COMMANDS & CONSOLE VARS
367 // ==========================================================================
368 
369 CV_PossibleValue_t grmlook_extends_fov_cons_t[] = { {0, "Off"}, {1, "On"}, {2, "Full"}, {0, NULL} };
370 CV_PossibleValue_t grgamma_cons_t[] = { {1, "MIN"}, {255, "MAX"}, {0, NULL} };
371 CV_PossibleValue_t grfov_cons_t[] = { {0, "MIN"}, {179, "MAX"}, {0, NULL} };
372 CV_PossibleValue_t grfiltermode_cons_t[] = {
373 {HWD_SET_TEXTUREFILTER_POINTSAMPLED, "Nearest"},
374 {HWD_SET_TEXTUREFILTER_BILINEAR, "Bilinear"},
375 {HWD_SET_TEXTUREFILTER_TRILINEAR, "Trilinear"},
376 {HWD_SET_TEXTUREFILTER_MIXED1, "Linear_Nearest"},
377 {HWD_SET_TEXTUREFILTER_MIXED2, "Nearest_Linear"},
378 {0, NULL}
379 };
380 
381 // BP: change directly the palette to see the change
CV_Gammaxxx_ONChange(void)382 void CV_Gammaxxx_ONChange(void)
383 {
384     V_SetPalette(0);
385 }
386 
387 void CV_filtermode_ONChange(void);
388 void CV_FogDensity_ONChange(void);
389 //static void CV_grFogColor_OnChange (void);
390 static void CV_grFov_OnChange(void);
391 //static void CV_grMonsterDL_OnChange (void);
392 static void CV_grPolygonSmooth_OnChange(void);
393 
394 consvar_t cv_grrounddown = { "gr_rounddown", "Off", 0, CV_OnOff };
395 consvar_t cv_grmlook_extends_fov = { "gr_mlook", "Full", CV_SAVE, grmlook_extends_fov_cons_t };
396 consvar_t cv_grfov = { "gr_fov", "90", CV_SAVE | CV_CALL, grfov_cons_t, CV_grFov_OnChange };
397 //consvar_t cv_grsky = { "gr_sky", "On", 0, CV_OnOff };
398 consvar_t cv_grfog = { "gr_fog", "On", CV_SAVE, CV_OnOff };
399 consvar_t cv_grfogcolor = { "gr_fogcolor", "000000", CV_SAVE, NULL };
400 consvar_t cv_grfogdensity = { "gr_fogdensity", "100", CV_SAVE | CV_CALL | CV_NOINIT, CV_Unsigned, CV_FogDensity_ONChange };
401 consvar_t cv_grgammared = { "gr_gammared", "127", CV_SAVE | CV_CALL, grgamma_cons_t, CV_Gammaxxx_ONChange };
402 consvar_t cv_grgammagreen = { "gr_gammagreen", "127", CV_SAVE | CV_CALL, grgamma_cons_t, CV_Gammaxxx_ONChange };
403 consvar_t cv_grgammablue = { "gr_gammablue", "127", CV_SAVE | CV_CALL, grgamma_cons_t, CV_Gammaxxx_ONChange };
404 consvar_t cv_grfiltermode = { "gr_filtermode", "Bilinear", CV_SAVE | CV_CALL, grfiltermode_cons_t, CV_filtermode_ONChange };
405 consvar_t cv_grzbuffer = { "gr_zbuffer", "On", 0, CV_OnOff };
406 consvar_t cv_grcorrecttricks = { "gr_correcttricks", "On", 0, CV_OnOff };
407 
408 consvar_t cv_grsolvetjoin = { "gr_solvetjoin", "On", 0, CV_OnOff };
409 consvar_t cv_grpolytile = { "gr_polytile", "On", 0, CV_OnOff };
410 
411 CV_PossibleValue_t grpolyshape_cons_t[] = {
412   {0, "Subsector"},
413   {1, "Fat"},
414   {2, "Trim"},
415   {3, "NotConvex"},
416   {0, NULL}
417 };
418 consvar_t cv_grpolyshape = { "gr_polygon_shape", "Trim", CV_SAVE, grpolyshape_cons_t };
419 
420 // console variables in development
421 consvar_t cv_grpolygonsmooth = { "gr_polygonsmooth", "Off", CV_CALL, CV_OnOff, CV_grPolygonSmooth_OnChange };
422 consvar_t cv_grmd2 = { "gr_md2", "Off", 0, CV_OnOff };
423 
424 #ifdef TRANSWALL_CHOICE
425 // three choices for debugging
426 CV_PossibleValue_t grtranswall_cons_t[] = { {2, "Sorted"}, {3, "SortX3"}, {0, NULL} };
427 consvar_t cv_grtranswall = { "gr_transwall", "Sorted", 0, grtranswall_cons_t };
428 #endif
429 
430 // faB : needs fix : walls are incorrectly clipped one column less
431 consvar_t cv_grclipwalls = { "gr_clipwalls", "Off", 0, CV_OnOff };
432 
433 //development variables for diverse uses
434 consvar_t cv_gralpha = { "gr_alpha", "160", 0, CV_Unsigned };
435 consvar_t cv_grbeta = { "gr_beta", "0", 0, CV_Unsigned };
436 consvar_t cv_grgamma = { "gr_gamma", "0", 0, CV_Unsigned };
437 
CV_FogDensity_ONChange(void)438 void CV_FogDensity_ONChange(void)
439 {
440     if( HWD.pfnSetSpecialState )
441         HWD.pfnSetSpecialState(HWD_SET_FOG_DENSITY, cv_grfogdensity.value);
442 }
443 
CV_filtermode_ONChange(void)444 void CV_filtermode_ONChange(void)
445 {
446     if( HWD.pfnSetSpecialState )
447         HWD.pfnSetSpecialState(HWD_SET_TEXTUREFILTERMODE, cv_grfiltermode.value);
448 }
449 
450 // ==========================================================================
451 //                                                               VIEW GLOBALS
452 // ==========================================================================
453 // Fineangles in the SCREENWIDTH wide window.
454 #define FIELDOFVIEW      ANG90
455 
456 angle_t gr_clipangle, gr_clipangle_x_2;
457 
458 // The gr_viewangle_to_x[viewangle + FINE_ANG90] lookup
459 // maps the visible view angles to screen X coordinates,
460 // flattening the arc to a flat projection plane.
461 // There will be many angles mapped to the same X.
462 int gr_viewangle_to_x[FINE_ANG180];
463 
464 // The gr_x_to_viewangle[] table maps a screen pixel
465 // to the lowest viewangle that maps back to x ranges
466 // from clipangle to -clipangle.
467 angle_t gr_x_to_viewangle[MAXVIDWIDTH + 1];
468 
469 // ==========================================================================
470 //                                                                    GLOBALS
471 // ==========================================================================
472 
473 // base values set at SetViewSize
474 float gr_basecentery;
475 float gr_baseviewwindowy;
476 float gr_basewindowcentery;
477 
478 float gr_viewwidth;             // viewport clipping boundaries (screen coords)
479 float gr_viewheight;
480 float gr_centerx;
481 float gr_centery;
482 float gr_viewwindowx;           // top left corner of view window
483 float gr_viewwindowy;
484 float gr_windowcenterx;         // center of view window, for projection
485 float gr_windowcentery;
486 
487 float gr_pspritexscale;
488 float gr_pspriteyscale;
489 
490 seg_t *gr_curline;
491 side_t *gr_sidedef;
492 line_t *gr_linedef;
493 sector_t *gr_frontsector;
494 sector_t *gr_backsector;
495 //RGBA_float_t  gr_cursectorlight;      // colour & intensity of current sector's lighting
496 
497 // --------------------------------------------------------------------------
498 //                                              STUFF FOR THE PROJECTION CODE
499 // --------------------------------------------------------------------------
500 
501 FTransform_t atransform;
502 // duplicates of the main code, set after R_SetupFrame() passed them into sharedstruct,
503 // copied here for local use
504 static angle_t dup_viewangle;
505 
506 static float gr_viewx;
507 static float gr_viewy;
508 static float gr_viewz;
509 static float gr_viewsin;
510 static float gr_viewcos;
511 
512 //04/01/00: Maybe not necessary with the new T&L code (need to be checked!)
513 static float gr_viewludsin;     //look up down kik test
514 static float gr_viewludcos;
515 
516 static float gr_fovlud;
517 
518 // ==========================================================================
519 //                                    Transforms
520 // ==========================================================================
521 
522 // The only terms needed, the other terms are 0.
523 // Don't try to make this a matrix, this is much easier to understand and maintain.
524 static float world_trans_x_to_x, world_trans_y_to_x,
525   world_trans_x_to_y, world_trans_y_to_y, world_trans_z_to_y,
526   world_trans_x_to_z, world_trans_y_to_z, world_trans_z_to_z;
527 static float sprite_trans_x_to_x, sprite_trans_y_to_y, sprite_trans_z_to_y,
528   sprite_trans_z_to_z, sprite_trans_y_to_z;
529 
HWR_set_view_transform(void)530 void HWR_set_view_transform( void )
531 {
532     // Combined transforms for position, direction, look up/down, and scaling
533     // translation is separate and done first
534     // In order:
535     //   rotation around vertical y axis
536     //   look up/down
537     //   scale y before frustum so that frustum can be scaled to screen height
538     world_trans_x_to_x = gr_viewsin * gr_fovlud;
539     world_trans_y_to_x = -gr_viewcos * gr_fovlud;
540     world_trans_x_to_y = gr_viewcos * gr_viewludcos * ORIGINAL_ASPECT * gr_fovlud;
541     world_trans_y_to_y = gr_viewsin * gr_viewludcos * ORIGINAL_ASPECT * gr_fovlud;
542     world_trans_z_to_y = gr_viewludsin * ORIGINAL_ASPECT * gr_fovlud;
543     world_trans_x_to_z = gr_viewcos * gr_viewludsin;
544     world_trans_y_to_z = gr_viewsin * gr_viewludsin;
545     world_trans_z_to_z = -gr_viewludcos;
546 
547     // look up/down and scaling
548     sprite_trans_x_to_x = gr_fovlud;
549     sprite_trans_y_to_y = gr_viewludsin * ORIGINAL_ASPECT * gr_fovlud;
550     sprite_trans_z_to_y = gr_viewludcos * ORIGINAL_ASPECT * gr_fovlud;
551     sprite_trans_z_to_z = gr_viewludsin;
552     sprite_trans_y_to_z = -gr_viewludcos;
553 }
554 
555 #if 0
556 // unused because of confused wall drawing
557 // wx,wy,wz in world coord, to screen vxtx3d_t
558 void HWR_transform_world_FOut(float wx, float wy, float wz, vxtx3d_t * fovp)
559 {
560     // Combined transforms for position, direction, look up/down, and scaling.
561     // translation
562     // x world, to x screen
563     // vert z world, to vert y screen
564     // y world, to screen depth
565     float tr_x = wx - gr_viewx;
566     float tr_y = wy - gr_viewy;
567     float tr_z = wz - gr_viewz;
568     fovp->x = (tr_x * world_trans_x_to_x)
569        + (tr_y * world_trans_y_to_x);
570     fovp->y = (tr_x * world_trans_x_to_y )
571        + (tr_y * world_trans_y_to_y )
572        + (tr_z * world_trans_z_to_y );
573     fovp->z = (tr_x * world_trans_x_to_z )
574        + (tr_y * world_trans_y_to_z )
575        + (tr_z * world_trans_z_to_z );
576 }
577 #endif
578 
579 #if 0
580 // unused
581 void HWR_transform_sprite_FOut(float cx, float cy, float cz, vxtx3d_t * fovp)
582 {
583     // Combined transforms for look up/down, and scaling
584    fovp->y = (cy * sprite_trans_y_to_y) + (cz * sprite_trans_z_to_y);
585    fovp->z = (cy * sprite_trans_y_to_z) + (cz * sprite_trans_z_to_z);
586    fovp->x = (cx * sprite_trans_x_to_x);
587 }
588 #endif
589 
590 
591 // ==========================================================================
592 //                                    LIGHT stuffs
593 // ==========================================================================
594 
595 static byte lightleveltonumlut[256];
596 
597 // added to Doom's sector lightlevel to make things a bit brighter (sprites/walls/planes)
LightLevelToLum(lightlev_t l)598 byte LightLevelToLum(lightlev_t l)
599 {
600     if (fixedcolormap)
601         return 255;
602     l = lightleveltonumlut[l];
603     l += extralight;	// from guns
604     if (l > 255)
605         l = 255;
606     return l;
607 }
608 
609 // Need to select extra
LightLevelToLum_extra(lightlev_t l,lightlev_t extra)610 byte LightLevelToLum_extra(lightlev_t l, lightlev_t extra)
611 {
612     if (fixedcolormap)
613         return 255;
614     l = lightleveltonumlut[l];
615     l += extra;	// from guns, etc..
616     if (l > 255)
617         l = 255;
618     return l;
619 }
620 
621 
Init_LumLut()622 static void Init_LumLut()
623 {
624     int i, k;
625     for (i = 0; i < 256; i++)
626     {
627         // this polygon is the solution of equ : f(0)=0, f(1)=1 f(.5)=.5, f'(0)=0, f'(1)=0), f'(.5)=K
628 //#define K   2
629 // [WDJ] Match software renderer brightness,
630 // with single rgba use 1.25, with rgba[] use 1.9 to 2.1
631 #define K   1.95f
632 #define A  (-24+16*K)
633 #define B  ( 60-40*K)
634 #define C  (32*K-50)
635 #define D  (-8*K+15)
636         float x = (float) i / 255;
637         float xx, xxx;
638         xx = x * x;
639         xxx = x * xx;
640         k = 255 * (A * xx * xxx + B * xx * xx + C * xxx + D * xx);
641 
642         lightleveltonumlut[i] = min(255, k);
643     }
644 }
645 
646 
647 // [WDJ] Handle the extra_colormap, transforming into GL surface info.
648 // Smaller when inline, but easier to alter in this function.
649 // This function is only going to get more complicated.
650 static
Extracolormap_to_Surf(extracolormap_t * extracmap,byte lightlum,FSurfaceInfo_t * surfp)651 void Extracolormap_to_Surf( /*IN*/ extracolormap_t * extracmap, byte lightlum,
652                             /*OUT*/ FSurfaceInfo_t * surfp )
653 {
654     RGBA_t temp;
655     unsigned int light = lightlum; // prevent sign extension
656 
657     if( view_extracolormap )
658     {
659         // Boom global colormap override
660         extracmap = view_extracolormap;
661     }
662 
663     // [WDJ] the rgba color can change according to light level
664     // This accomodates the fade in Create_Colormap, and Colormap_Analyze.
665     temp.rgba = extracmap->rgba[ light >> LIGHT_TO_RGBA_SHIFT ].rgba;
666     // prevent sign extension
667     // alpha -> 1..256, so can >> 8
668     unsigned int alpha = ((unsigned int)temp.s.alpha) + 1;
669     surfp->FlatColor.s.red = ((256 - alpha) * light + alpha * temp.s.red) >> 8;
670     surfp->FlatColor.s.blue = ((256 - alpha) * light + alpha * temp.s.blue) >> 8;
671     surfp->FlatColor.s.green = ((256 - alpha) * light + alpha * temp.s.green) >> 8;
672     surfp->FlatColor.s.alpha = 0xff;
673 }
674 
675 // ==========================================================================
676 //                                   FLOOR/CEILING GENERATION FROM SUBSECTORS
677 // ==========================================================================
678 
679 
680 //what is the maximum number of verts around a convex floor/ceiling polygon?
681 // Note: gothic2 map02 has a 304 vertex poly!!!!
682 #define MAXPLANEVERTICES   512
683 static vxtx3d_t planeVerts[MAXPLANEVERTICES];
684 
685 // Indexed by flat size_index.
686 static float  flat_flatsize_tab[ 8 ] =
687 {
688     0.0, // 0
689     32.0f, // 32x32 flat
690     64.0f, // 64x64 flat
691     128.0f, // 128x128 flat
692     256.0f, // 256x256 flat
693     512.0f, // 512x512 flat
694     1024.0f, // 1024x1024 flat
695     2048.0f, // 2048x2048 flat
696 };
697 
698 
699 // Indexed by flat size_index.
700 static uint32_t  flat_flatmask_tab[ 8 ] =
701 {
702    ~ 0, // 0
703    ~( 32 - 1 ), // 32x32 flat
704    ~( 64 - 1 ), // 64x64 flat
705    ~( 128 - 1 ), // 128x128 flat
706    ~( 256 - 1 ), // 256x256 flat
707    ~( 512 - 1 ), // 512x512 flat
708    ~( 1024 - 1 ), // 1024x1024 flat
709    ~( 2048 - 1 ), // 2048x2048 flat
710 };
711 
712 
713 
714 // -----------------+
715 // HWR_RenderPlane  : Render a floor or ceiling convex polygon
716 // -----------------+
717 // Preceded by HWR_GetFlat( levelflats[picnum].lumpnum );
718 // Parameter static global
719 //   planeVerts : polygon verts
720 // Parameters:
721 //   lightlevel : SoM: 3D floors light level
722 //   picnum : index to levelflats
723 // Called from HWR_Subsector, HWR_Render3DWater
724 static
HWR_RenderPlane(poly_subsector_t * xsub,fixed_t fixedheight,FBITFIELD PolyFlags,extracolormap_t * planecolormap,int lightlevel,int picnum)725 void HWR_RenderPlane(poly_subsector_t * xsub, fixed_t fixedheight,
726                      FBITFIELD PolyFlags, extracolormap_t* planecolormap,
727                      int lightlevel, int picnum)
728 {
729     polyvertex_t *pv;
730     vxtx3d_t * v3d;
731     int nrPlaneVerts;           //verts original define of convex flat polygon
732     float height;               //constant y for all points on the convex flat polygon
733     float flatxref, flatyref;
734     double flatsize, flatscrollinc;
735     int32_t flatmask;  // cannot be uint as the result will be unsigned
736     int i;
737     byte lightlum;  // 0..255
738 
739     FSurfaceInfo_t Surf;
740 
741     // no convex poly were generated for this subsector
742     if (!xsub->planepoly)
743         return;
744 
745     height = FIXED_TO_FLOAT( fixedheight );
746 
747     pv = xsub->planepoly->pts;
748     nrPlaneVerts = xsub->planepoly->numpts;
749 
750     if (nrPlaneVerts < 3)       //not even a triangle ?
751         return;
752 
753     if (nrPlaneVerts > MAXPLANEVERTICES)
754     {
755         // Too many verts for planeVerts
756         I_SoftError("HWR_RenderPlane: polygon size %d exceeds max value of %d vertices\n", nrPlaneVerts, MAXPLANEVERTICES);
757         nrPlaneVerts = MAXPLANEVERTICES;  // cut off polygon side
758     }
759 
760     int sizeindex = levelflats[picnum].size_index;
761     flatsize = flat_flatsize_tab[sizeindex];
762     flatmask = flat_flatmask_tab[sizeindex];
763 
764     //reference point for flat texture coord for each vertex around the polygon
765     flatxref = (((int32_t) pv->x) & flatmask) / flatsize;
766     flatyref = (((int32_t) pv->y) & flatmask) / flatsize;
767 
768     // transform
769     flatscrollinc = (FIXED_TO_FLOAT_MULT / flatsize);
770     v3d = planeVerts;  // static global
771     for (i = 0; i < nrPlaneVerts; i++, v3d++, pv++)
772     {
773         v3d->y = height;
774         v3d->x = pv->x;
775         v3d->z = pv->y;
776         v3d->sow = (pv->x / flatsize) - flatxref;
777         v3d->tow = flatyref - (pv->y / flatsize);
778         // Hurdler: add scrolling texture on floor/ceiling
779         if (gr_frontsector)
780         {
781             if (fixedheight < viewz)
782             {  // it's a floor
783                 v3d->sow += gr_frontsector->floor_xoffs * flatscrollinc;
784                 v3d->tow += gr_frontsector->floor_yoffs * flatscrollinc;
785             }
786             else
787             {
788                 v3d->sow += gr_frontsector->ceiling_xoffs * flatscrollinc;
789                 v3d->tow += gr_frontsector->ceiling_yoffs * flatscrollinc;
790             }
791         }
792     }
793 
794     // only useful for flat coloured triangles
795     //Surf.FlatColor = 0xff804020;
796 
797     //  use different light tables
798     //  for horizontal / vertical / diagonal
799     //  note: try to get the same visual feel as the original
800     lightlum = LightLevelToLum(lightlevel);        // SoM: Don't take from the frontsector
801     Surf.FlatColor.s.red = Surf.FlatColor.s.green = Surf.FlatColor.s.blue = lightlum;
802 
803     //Hurdler: colormap test
804     if ( !fixedcolormap )
805     {
806         if ( view_extracolormap )
807         {
808             Extracolormap_to_Surf( /*IN*/ view_extracolormap, lightlum,
809                                    /*OUT*/ & Surf );
810         }
811         else if ( gr_frontsector )
812         {
813             sector_t *sector = gr_frontsector;
814 
815             if (gr_frontsector->ffloors)
816             {
817                 ffloor_t * caster =
818                   R_GetPlaneLight(gr_frontsector, fixedheight)->caster;
819                 sector = caster ? &sectors[caster->model_secnum] : gr_frontsector;
820             }
821             if (sector && sector->extra_colormap && planecolormap == NULL)
822                 planecolormap = sector->extra_colormap;
823             if (planecolormap)
824             {
825                 Extracolormap_to_Surf( /*IN*/ planecolormap, lightlum,
826                                        /*OUT*/ & Surf );
827             }
828         }
829     }
830 
831     if ((PolyFlags & PF_Translucent) && !fixedcolormap)
832     {
833         // get alpha from HWR_Render3DWater
834         // PolyFlags = PF_Translucent | (planeinfo[i].alpha << 24);
835         Surf.FlatColor.s.alpha = PolyFlags >> 24;
836         HWD.pfnDrawPolygon(&Surf, planeVerts, nrPlaneVerts,
837                            PF_Translucent | PF_Modulated | PF_Occlude | PF_Clip);
838     }
839     else
840     {
841         Surf.FlatColor.s.alpha = 0xff;
842         HWD.pfnDrawPolygon(&Surf, planeVerts, nrPlaneVerts,
843                            PolyFlags | PF_Masked | PF_Modulated | PF_Clip);
844     }
845 
846     //12/11/99: Hurdler: add here code for dynamic lighting on planes
847     HWR_PlaneLighting(planeVerts, nrPlaneVerts);
848 
849     //experimental code: shadow of the player: should be done only on floor
850     //HWR_DynamicShadowing(planeVerts, nrPlaneVerts, plVerts, plyr);
851 }
852 
853 #ifdef POLYSKY
854 // [WDJ] When I got this working, the low sky plane cut off the tops of trees.
855 // It appears:
856 // The software render draws sky planes, but without object clipping.
857 // In sky sectors it draws upper textures as sky.
858 
859 // this don't draw anything it only update the z-buffer so there isn't problem with
860 // wall/things upper that sky (map12)
861 // Parameter static global
862 //   skypoly : the polygon that sky is seen through
863 //   polyheight : height of polygon
864 //   planeVerts : polygon verts
865 // Called from HWR_Subsector
866 static
HWR_RenderSkyPlane(poly_subsector_t * skypoly,fixed_t polyheight)867 void HWR_RenderSkyPlane(poly_subsector_t * skypoly, fixed_t polyheight)
868 //                              FBITFIELD         PolyFlags )
869 {
870     polyvertex_t *pv;
871     float height;               //constant y for all points on the convex flat polygon
872     vxtx3d_t *v3d;
873     int nrPlaneVerts;           //verts original define of convex flat polygon
874     int i;
875     angle_t angle;
876     float f, skysow03, skysow12, skytow01, skytow23;
877     float xsize, ysize;
878     float dx, dy, dz;
879 
880     // no convex poly were generated for this subsector
881     if (!skypoly->planepoly)
882         return;
883 
884     height = FIXED_TO_FLOAT( polyheight );
885     dz = fabs( height - gr_viewz );
886 
887     pv = skypoly->planepoly->pts;
888     nrPlaneVerts = skypoly->planepoly->numpts;
889 
890     if (nrPlaneVerts < 3)       //not even a triangle ?
891         return;
892 
893     HWR_GetTexture (skytexture, 0);
894     xsize = 128;
895     ysize = 256;
896 
897     angle = ((dup_viewangle + gr_x_to_viewangle[0]) % ANG90);
898 
899     // left
900     skysow03 = 1.0f + ((float) angle) / (ANG90 - 1);
901     // right
902     skysow12 = ((float) angle) / (ANG90 - 1);
903 
904     f = 40 + 200 * FIXED_TO_FLOAT(
905         finetangent[(FINE_ANG90 - ((int) aimingangle >> (ANGLETOFINESHIFT + 1))) & FINEMASK] );
906         // finetangent_ANG( -(aimingangle/2) )
907 #if 1
908     if (f < 0)
909         f = 0;
910     if (f > 240 - 127)
911         f = 240 - 127;
912 #endif
913     // up
914     skytow23 = f / 127.0f;
915     // down
916     skytow01 = (f + 127) / 127.0f;   //suppose 256x128 sky...
917 
918     // Sky x,y,z are all -4.0 to 4.0, but here scaled much larger.
919     // transform
920     v3d = planeVerts;  // static global
921     for (i = 0; i < nrPlaneVerts; i++, v3d++, pv++)
922     {
923         v3d->y = height;
924         v3d->x = pv->x;
925         v3d->z = pv->y;
926 //        v3d->sow = (pv->x / xsize);
927 //        v3d->tow = - (pv->y / xsize);
928      // Still not right.
929      // Sky turns with viewer, so clouds are horizontal from all sides.
930      // This keeps cloud orientation fixed with respect to polygon,
931      // which is more correct for a floor sky hole, but does not match the
932      // vanilla doom.
933         dx = (pv->x - gr_viewx);
934         dy = (pv->y - gr_viewy);
935         v3d->sow = skysow03 + ((skysow12 - skysow03) / 2.0f * (dx/dz + 1.0));
936         v3d->tow = skytow01 + ((skytow23 - skytow01) / 2.0f * (dy/dz + 1.0));
937     }
938 
939     HWD.pfnDrawPolygon(NULL, planeVerts, nrPlaneVerts, 0);
940 //    HWD.pfnDrawPolygon(NULL, planeVerts, nrPlaneVerts,
941 //                       PF_Invisible | PF_Occlude | PF_Masked | PF_Clip);
942 }
943 #endif //polysky
944 
945 
946 /*
947    vxtx order is :
948           3--2
949           | /|
950           |/ |
951           0--1
952 */
953 #ifdef WALLSPLATS
954 // Called from HWR_ProjectWall, HWR_RenderWall
HWR_DrawSegsSplats(FSurfaceInfo_t * pSurfin)955 void HWR_DrawSegsSplats(FSurfaceInfo_t * pSurfin)
956 {
957     wallsplat_t *splat;
958     MipPatch_t *gpatch;
959     int blendmode = PF_Translucent;
960     FSurfaceInfo_t pSurf2;
961     fixed_t tmy;
962     // seg bbox
963     fixed_t segbbox[4];
964     vxtx3d_t vxtx[4];
965 
966     M_ClearBox(segbbox);
967     // make box from fixed_t vertex
968 #if 1
969     M_AddToBox(segbbox, gr_curline->v1->x, gr_curline->v1->y );
970     M_AddToBox(segbbox, gr_curline->v2->x, gr_curline->v2->y );
971 #else
972     // convert polyvertex_t back to fixed_t
973     M_AddToBox(segbbox, gr_curline->pv1->x / FIXED_TO_FLOAT_MULT,
974                gr_curline->pv1->y / FIXED_TO_FLOAT_MULT);
975     M_AddToBox(segbbox, gr_curline->pv2->x / FIXED_TO_FLOAT_MULT,
976                gr_curline->pv2->y / FIXED_TO_FLOAT_MULT);
977 #endif
978 
979     // splat are drawn by line but this func is called for eatch segs of a line
980     /*
981        BP: DONT WORK BECAUSE Z-buffer !!!!
982        FIXME : the splat must be stored by segs !
983        if( gr_curline->linedef->splatdrawn == validcount )
984        return;
985        gr_curline->linedef->splatdrawn = validcount;
986      */
987 
988     splat = (wallsplat_t *) gr_curline->linedef->splats;
989     for (; splat; splat = splat->next)
990     {
991         // For each splat
992         //BP: don't draw splat extern to this seg
993         //    this is quick fix best is explain in logboris.txt at 12-4-2000
994         if (!M_PointInBox(segbbox, splat->v1.x, splat->v1.y)
995             && !M_PointInBox(segbbox, splat->v2.x, splat->v2.y))
996             continue;
997 
998         gpatch = W_CachePatchNum(splat->patch, PU_CACHE);
999         HWR_GetPatch(gpatch);
1000 
1001         // Consider unrolling the loop and merge with the first assigns.
1002         vxtx[0].x = vxtx[3].x = FIXED_TO_FLOAT( splat->v1.x );
1003         vxtx[0].z = vxtx[3].z = FIXED_TO_FLOAT( splat->v1.y );
1004         vxtx[2].x = vxtx[1].x = FIXED_TO_FLOAT( splat->v2.x );
1005         vxtx[2].z = vxtx[1].z = FIXED_TO_FLOAT( splat->v2.y );
1006 
1007         tmy = splat->top;
1008         if (splat->yoffset)
1009             tmy += *splat->yoffset;
1010 
1011         vxtx[2].y = vxtx[3].y = FIXED_TO_FLOAT( tmy ) + (gpatch->height >> 1);
1012         vxtx[0].y = vxtx[1].y = FIXED_TO_FLOAT( tmy ) - (gpatch->height >> 1);
1013 
1014         vxtx[3].sow = vxtx[3].tow = vxtx[2].sow = vxtx[0].tow = 0.0f;
1015         vxtx[1].sow = vxtx[1].tow = vxtx[2].tow = vxtx[0].sow = 1.0f;
1016 
1017         memcpy(&pSurf2, pSurfin, sizeof(FSurfaceInfo_t));
1018         switch (splat->flags & SPLATDRAWMODE_MASK)
1019         {
1020             case SPLATDRAWMODE_OPAQUE:
1021                 pSurf2.FlatColor.s.alpha = 0xff;
1022                 blendmode = PF_Translucent;
1023                 break;
1024             case SPLATDRAWMODE_TRANS:
1025                 pSurf2.FlatColor.s.alpha = 128;
1026                 blendmode = PF_Translucent;
1027                 break;
1028             case SPLATDRAWMODE_SHADE:
1029                 pSurf2.FlatColor.s.alpha = 0xff;
1030                 blendmode = PF_Substractive;
1031                 break;
1032         }
1033 
1034         HWD.pfnDrawPolygon(&pSurf2, vxtx, 4,
1035                            blendmode | PF_Modulated | PF_Clip | PF_Decal);
1036     }
1037 }
1038 #endif
1039 
1040 #ifdef R_FAKEFLOORS
1041 // [WDJ] Render a fog sheet
HWR_RenderFog(ffloor_t * fff,sector_t * intosec,int foglight,float dist)1042 void HWR_RenderFog( ffloor_t* fff, sector_t * intosec, int foglight,
1043                   float dist )
1044 {
1045     line_t * fogline = fff->master;
1046     side_t * fogside = & sides[ fogline->sidenum[0] ];
1047     sector_t * modelsec = fogside->sector;
1048 
1049     FSurfaceInfo_t Surf;
1050     vxtx3d_t fVert[4];
1051 
1052     int      texnum;
1053     int      blend;
1054     fixed_t  wclip_top, wclip_bottom;
1055 
1056     float leftoffset = 0.0, rightoffset = FOG_WIDTH;
1057     float tz, tdz, tyhigh, tylow, tranzy, tranzz;
1058     fixed_t h, l;               // 3D sides and 2s middle textures
1059 
1060     // texture num are either 0=no-texture, or valid
1061     texnum = texturetranslation[fogside->midtexture];
1062     if( texnum == 0 )  goto nofog;  // no texture to display
1063 
1064     tdz = 0.0;
1065     tz = dist; // dist to fog
1066     if( dist < 0.1 )
1067     {
1068         // random fog scale
1069         tz = (fog_wave2>>6) + 6;  // 22 .. 6, fogsheet dist
1070         tdz = ((int)fog_wave1>>7) - 4;  // ( 4 .. -4 )
1071         tdz *= sprite_trans_z_to_z;  // fogsheet sway
1072     }
1073 
1074     wclip_top = intosec->ceilingheight;
1075     wclip_bottom = intosec->floorheight;
1076     h = modelsec->ceilingheight;
1077     l = modelsec->floorheight;
1078     if (h < wclip_bottom || l > wclip_top)
1079         goto nofog;
1080     if (h > wclip_top)
1081         h = wclip_top;
1082     if (l < wclip_bottom)
1083         l = wclip_bottom;
1084     //  3--2   vertices ordering
1085     //  |  |
1086     //  0--1
1087     // Combined transforms for look up/down and scaling
1088     // assume viewcos = 1, viewsin = 0
1089     tyhigh = FIXED_TO_FLOAT( h ) - gr_viewz;
1090     tylow  = FIXED_TO_FLOAT( l ) - gr_viewz;
1091     fVert[0].x = fVert[3].x = -gr_centerx;
1092     fVert[1].x = fVert[2].x = gr_centerx;
1093     tranzy = tz * sprite_trans_z_to_y;
1094     fVert[0].y = fVert[1].y = (tylow * sprite_trans_y_to_y) + tranzy;
1095     fVert[2].y = fVert[3].y = (tyhigh * sprite_trans_y_to_y) + tranzy;
1096     tranzz = tz * sprite_trans_z_to_z;
1097     fVert[0].z = fVert[1].z = (tylow * sprite_trans_y_to_z) + tranzz;
1098     fVert[2].z = fVert[3].z = (tyhigh * sprite_trans_y_to_z) + tranzz;
1099     fVert[0].z += tdz;  // sway
1100     fVert[3].z += tdz;
1101     fVert[1].z -= tdz;
1102     fVert[2].z -= tdz;
1103 
1104     Surf.polyflags = 0;
1105     Surf.texflags = 0;
1106 
1107     //  light
1108     Surf.FlatColor.s.alpha = 0xff;
1109     if (fixedcolormap)
1110     {
1111         Surf.FlatColor.s.red = Surf.FlatColor.s.green = Surf.FlatColor.s.blue = 0xff;
1112     }
1113     else
1114     {
1115         byte lightlum = LightLevelToLum_extra(modelsec->lightlevel, foglight);
1116 
1117         // store Surface->FlatColor to modulate wall texture
1118         Surf.FlatColor.s.red = Surf.FlatColor.s.green = Surf.FlatColor.s.blue = lightlum;
1119 
1120         if (modelsec->extra_colormap || view_extracolormap)
1121         {
1122            Extracolormap_to_Surf( /*IN*/ modelsec->extra_colormap, lightlum,
1123                                   /*OUT*/ & Surf );
1124         }
1125     }
1126 
1127     if (fff->flags & FF_FOG)
1128     {
1129         // Legacy Fog (or foggy water) in tagged sector
1130         // add in player movement to fog
1131         int playermov = (viewmobj->x + viewmobj->y + (viewmobj->angle>>6)) >> (FRACBITS+6);
1132         leftoffset = (fog_tic - playermov) % FOG_WIDTH;
1133         rightoffset += leftoffset;
1134         dr_alpha = fweff[fff->fw_effect].fsh_alpha;  // dr_alpha 0..255
1135         Surf.FlatColor.s.alpha = (float)dr_alpha * (251.0f/256.0f) + 5.0f;
1136 //        Surf.FlatColor.s.alpha = (float)dr_alpha * (246.0f/256.0f) + 10.0f;
1137 //        Surf.FlatColor.s.alpha = (float)dr_alpha * (241.0f/256.0f) + 15.0f;
1138 //        Surf.FlatColor.s.alpha = (float)dr_alpha * (226.0f/256.0f) + 20.0f;
1139         Surf.texflags = TF_Fogsheet;
1140         blend = PF_Fog;
1141     }
1142     else
1143         goto nofog;
1144 
1145     // miptex is for the base texture, fog texture has fixed size
1146     // MipTexture_t * miptex = HWR_GetTexture(texnum, Surf.texflags);
1147     HWR_GetTexture(texnum, Surf.texflags);
1148 
1149     fVert[3].tow = fVert[2].tow = fog_bltic * (1.0f / (FOG_HEIGHT * 128.0f * 4.0f));
1150     fVert[0].tow = fVert[1].tow = fVert[3].tow + (1.0f / (FOG_HEIGHT * 128.0f * 4.0f));
1151     fVert[0].sow = fVert[3].sow = leftoffset * (1.0f/FOG_WIDTH);
1152     fVert[2].sow = fVert[1].sow = rightoffset * (1.0f/FOG_WIDTH);
1153 
1154     HWD.pfnDrawPolygon(&Surf, fVert, 4,
1155                        blend | PF_Modulated | PF_NoDepthTest);
1156 
1157 nofog:
1158     return;
1159 }
1160 #endif
1161 
1162 // ==========================================================================
1163 //                                        WALL GENERATION FROM SUBSECTOR SEGS
1164 // ==========================================================================
1165 
1166 // [WDJ] 6/1/2010 Translucent to GL operations table
1167 typedef struct
1168 {
1169     uint32_t  PF_op;
1170     uint32_t  drawflags;
1171     byte alpha_equiv;
1172 } translucent_lookup_t;
1173 
1174 static  translucent_lookup_t  translucent_lookup[] =
1175 {
1176    {0, 0, 0},  // not translucent
1177    {PF_Translucent, 0, 0x78 }, // TRANSLU_med
1178    {PF_Translucent, 0, 0x40 }, // TRANSLU_more
1179    {PF_Translucent, 0, 0x30 }, // TRANSLU_hi
1180    {PF_Additive,    0, 0x80 }, // TRANSLU_fire
1181    {PF_Translucent, TF_Opaquetrans, 0xff, }, // TRANSLU_fx1
1182    {PF_Translucent, 0, 0xB8 }, // TRANSLU_75
1183 };
1184 
1185 // Called from HWR_StoreWallRange, HWR_DrawSprite
1186 // sets pSurf->texflags, polyflags
HWR_TranstableToAlpha(int transtablenum,FSurfaceInfo_t * pSurf)1187 int HWR_TranstableToAlpha(int transtablenum, FSurfaceInfo_t * pSurf)
1188 {
1189     int pfop = PF_Translucent;  // default
1190     if( transtablenum >= TRANSLU_ext )
1191     {
1192         // [WDJ] get substitute map from translu_store
1193         translucent_map_t * tm = & translu_store[ transtablenum - TRANSLU_ext ];
1194 #if 1
1195         if( tm->substitute_error < 30 && tm->substitute_std_translucent <= TRANSLU_fx1 )
1196         {
1197             // use a std translucent tuned operation
1198             transtablenum = tm->substitute_std_translucent;
1199         }
1200         else
1201         {
1202             // use the analyzed alpha
1203             // OpenGL alpha tends to be too strong compared to translucent tables
1204             pSurf->FlatColor.s.alpha = (((int)tm->alpha) * 220) >> 8;
1205             if( tm->opaque > 50 )
1206                pfop = PF_Additive;
1207             goto done;
1208         }
1209 #else
1210         // simple substitution, for testing
1211         // OpenGL drawing order is an issue for translucents
1212         // for instance in hell ground wad and BOOMEDIT.WAD
1213         transtablenum = tm->substitute_std_translucent;
1214 #endif
1215     }
1216     if( transtablenum <= TRANSLU_75 )
1217     {
1218         translucent_lookup_t *  tlup = & translucent_lookup[ transtablenum ];
1219         pSurf->FlatColor.s.alpha = tlup->alpha_equiv;
1220         pfop = tlup->PF_op;
1221         pSurf->polyflags = pfop;  // PF_ flags
1222         pSurf->texflags = tlup->drawflags;  // TF_ flags
1223     }
1224 done:
1225     return pfop;
1226 }
1227 
1228 // v1,v2 : the start & end vertices along the original wall segment, that may have been
1229 //         clipped so that only a visible portion of the wall seg is drawn.
1230 // floorheight, ceilingheight : depend on wall upper/lower/middle, comes from the sectors.
1231 
1232 void HWR_AddTransparentWall(vxtx3d_t * vxtx, FSurfaceInfo_t * pSurf, int texnum, int blend);
1233 
1234 // -----------------+
1235 // HWR_ProjectWall  :
1236 // -----------------+
1237 /*
1238    vxtx order is :
1239           3--2
1240           | /|
1241           |/ |
1242           0--1
1243 */
1244 // Called from HWR_SplitWall, HWR_StoreWallRange
HWR_ProjectWall(vxtx3d_t * vxtx,FSurfaceInfo_t * pSurf,int blendmode)1245 void HWR_ProjectWall(vxtx3d_t * vxtx, FSurfaceInfo_t * pSurf, int blendmode)
1246 {
1247     HWD.pfnDrawPolygon(pSurf, vxtx, 4,
1248                        blendmode | PF_Modulated | PF_Occlude | PF_Clip);
1249 
1250     if (gr_curline->linedef->splats && cv_splats.value)
1251         HWR_DrawSegsSplats(pSurf);
1252 
1253     //Hurdler: TODO: do static lighting using gr_curline->lm
1254     HWR_WallLighting(vxtx);
1255 
1256     //Hurdler: for better dynamic light in dark area, we should draw the light first
1257     //         and then the wall all that with the right blending func
1258     //HWD.pfnDrawPolygon( pSurf, vxtx, 4,
1259     //                    PF_Additive|PF_Modulated|PF_Occlude|PF_Clip);
1260 }
1261 
1262 #if 1
1263 #define HWR_RenderWall  HWR_ProjectWall
1264 #else
1265 // Called from HWR_RenderTransparentWalls
HWR_RenderWall(vxtx3d_t * vxtx,FSurfaceInfo_t * pSurf,int blendmode)1266 void HWR_RenderWall(vxtx3d_t * vxtx, FSurfaceInfo_t * pSurf, int blendmode)
1267 {
1268     HWD.pfnDrawPolygon(pSurf, vxtx, 4,
1269                        blendmode | PF_Modulated | PF_Occlude | PF_Clip);
1270 
1271     if (gr_curline->linedef->splats && cv_splats.value)
1272         HWR_DrawSegsSplats(pSurf);
1273 
1274     //Hurdler: TODO: do static lighting using gr_curline->lm
1275     HWR_WallLighting(vxtx);
1276 }
1277 #endif
1278 
1279 // ==========================================================================
1280 //                                                          BSP , CULL, ETC..
1281 // ==========================================================================
1282 
1283 // return the frac from the interception of the clipping line
1284 // (in fact a clipping plane that has a constant, so can clip with simple 2d)
1285 // with the wall segment
1286 //
1287 static
HWR_ClipViewSegment(int x,polyvertex_t * v1,polyvertex_t * v2)1288 float HWR_ClipViewSegment(int x, polyvertex_t * v1, polyvertex_t * v2)
1289 {
1290     float num;
1291     float den;
1292     float v1x, v1y;
1293     float v1dx, v1dy;
1294     float v2dx, v2dy;
1295 
1296     angle_t clipangle = gr_x_to_viewangle[x];
1297 
1298     // a segment of a polygon
1299     v1x = v1->x;
1300     v1y = v1->y;
1301     v1dx = (v2->x - v1->x);
1302     v1dy = (v2->y - v1->y);
1303 
1304     // the clipping line
1305     clipangle = clipangle + dup_viewangle;      //back to normal angle (non-relative)
1306     v2dx = FIXED_TO_FLOAT( cosine_ANG(clipangle) );
1307     v2dy = FIXED_TO_FLOAT( sine_ANG(clipangle) );
1308 
1309     den = v2dy * v1dx - v2dx * v1dy;
1310     if (den == 0)
1311         return -1;      // parallel
1312 
1313     // calc the frac along the polygon segment,
1314     //num = (v2x - v1x)*v2dy + (v1y - v2y)*v2dx;
1315     //num = -v1x * v2dy + v1y * v2dx;
1316     num = (gr_viewx - v1x) * v2dy + (v1y - gr_viewy) * v2dx;
1317 
1318     return num / den;
1319 }
1320 
1321 //
1322 // HWR_SplitWall
1323 //
1324 static
HWR_SplitWall(sector_t * sector,vxtx3d_t * vxtx,int texnum,FSurfaceInfo_t * Surfp,uint32_t fflags,uint32_t cutflag)1325 void HWR_SplitWall(sector_t * sector, vxtx3d_t * vxtx, int texnum,
1326                    FSurfaceInfo_t * Surfp, uint32_t fflags, uint32_t cutflag)
1327 {
1328     /*
1329        SoM: split up and light walls according to the
1330        lightlist. This may also include leaving out parts
1331        of the wall that can't be seen
1332      */
1333     MipTexture_t * miptex;
1334     float realtop, realbot, top, bot;
1335     float pegt, pegb, pegmul;
1336     float height, bheight = 0;
1337     int solid, i;
1338     byte base_alpha = Surfp->FlatColor.s.alpha;
1339     ff_light_t *ffl_list = sector->lightlist;  // fakefloor lightlist
1340     ffloor_t * caster;
1341 
1342     realtop = top = vxtx[2].y;
1343     realbot = bot = vxtx[0].y;
1344     pegt = vxtx[2].tow;
1345     pegb = vxtx[0].tow;
1346     pegmul = (pegb - pegt) / (top - bot);
1347 
1348     for (i = 1; i < sector->numlights; i++)
1349     {
1350         // check each fake floor for
1351         if (top < realbot)
1352             return;
1353 
1354         Surfp->FlatColor.s.alpha = base_alpha;
1355 
1356         // check each ffloor light for blocking or affecting this wall draw
1357         caster = ffl_list[i].caster;
1358 
1359         //Hurdler: fix a crashing bug, but is it correct?
1360         //if (!list[i].caster)
1361         //    continue;
1362 
1363         if ( caster )
1364         {
1365             solid = caster->flags & cutflag;
1366             if( (fflags & FF_JOIN_SIDES)
1367                 && ( (caster->flags & (FF_TRANSLUCENT|FF_FOG)) == (fflags & (FF_TRANSLUCENT|FF_FOG)) ) )
1368             {
1369 //	        Surfp->FlatColor.s.alpha = base_alpha * 0.4f;  // JOIN
1370                 Surfp->FlatColor.s.alpha = base_alpha * 0.45f;  // JOIN
1371                 solid = false;
1372             }
1373         }
1374         else
1375             solid = false;
1376 
1377         height = FIXED_TO_FLOAT( ffl_list[i].height );
1378         if (solid)
1379             bheight = FIXED_TO_FLOAT( *caster->bottomheight );
1380 
1381         if (height >= top)
1382         {
1383             if (solid && top > bheight)
1384                 top = bheight;
1385             continue;
1386         }
1387 
1388         //Found a break;
1389         bot = height;
1390 
1391         if (bot < realbot)
1392             bot = realbot;
1393 
1394         // draw a portion of the wall
1395         if (!fixedcolormap)
1396         {
1397             sector_t * sector = (ffl_list[i - 1].caster)? &sectors[ ffl_list[i - 1].caster->model_secnum] : gr_frontsector;
1398 
1399             byte lightlum = LightLevelToLum(*ffl_list[i - 1].lightlevel);
1400             // store Surface->FlatColor to modulate wall texture
1401             Surfp->FlatColor.s.red = Surfp->FlatColor.s.green = Surfp->FlatColor.s.blue = lightlum;
1402 
1403             //Hurdler: colormap test
1404             if (sector->extra_colormap || view_extracolormap)
1405             {
1406                 Extracolormap_to_Surf( /*IN*/ sector->extra_colormap, lightlum,
1407                                        /*OUT*/ Surfp );
1408             }
1409         }
1410 
1411         vxtx[3].tow = vxtx[2].tow = pegt + ((realtop - top) * pegmul);
1412         vxtx[0].tow = vxtx[1].tow = pegt + ((realtop - bot) * pegmul);
1413 
1414         // set top/bottom coords
1415         vxtx[2].y = vxtx[3].y = top;
1416         vxtx[0].y = vxtx[1].y = bot;
1417 
1418         miptex = HWR_GetTexture(texnum, Surfp->texflags);
1419         if (miptex->mipmap.tfflags & (TF_TRANSPARENT|TF_Fogsheet)
1420            ||  ( Surfp->polyflags & (PF_Translucent|PF_Fog)) )
1421             HWR_AddTransparentWall(vxtx, Surfp, texnum, Surfp->polyflags);
1422         else
1423             HWR_ProjectWall(vxtx, Surfp, PF_Masked);
1424 
1425         top = (solid)? bheight : height;
1426     }
1427 
1428     bot = realbot;
1429     if (top <= realbot)
1430         return;
1431 
1432     // draw portion of wall below all ffloors
1433     if (!fixedcolormap)
1434     {
1435         sector_t *sector = ffl_list[i - 1].caster ? &sectors[ffl_list[i - 1].caster->model_secnum] : gr_frontsector;
1436 
1437         byte lightlum = LightLevelToLum(*ffl_list[i - 1].lightlevel);
1438         // store Surface->FlatColor to modulate wall texture
1439         Surfp->FlatColor.s.red = Surfp->FlatColor.s.green = Surfp->FlatColor.s.blue = lightlum;
1440 
1441         if (sector->extra_colormap || view_extracolormap)
1442         {
1443             Extracolormap_to_Surf( /*IN*/ sector->extra_colormap, lightlum,
1444                                    /*OUT*/ Surfp );
1445         }
1446     }
1447 
1448     vxtx[3].tow = vxtx[2].tow = pegt + ((realtop - top) * pegmul);
1449     vxtx[0].tow = vxtx[1].tow = pegt + ((realtop - bot) * pegmul);
1450 
1451     // set top/bottom coords
1452     vxtx[2].y = vxtx[3].y = top;
1453     vxtx[0].y = vxtx[1].y = bot;
1454 
1455     miptex = HWR_GetTexture(texnum, Surfp->texflags);
1456     if (miptex->mipmap.tfflags & (TF_TRANSPARENT|TF_Fogsheet)
1457         ||  ( Surfp->polyflags & (PF_Translucent|PF_Fog)) )
1458         HWR_AddTransparentWall(vxtx, Surfp, texnum, Surfp->polyflags);
1459     else
1460         HWR_ProjectWall(vxtx, Surfp, PF_Masked);
1461 }
1462 
1463 //
1464 // HWR_StoreWallRange
1465 // A portion or all of a wall segment will be drawn, from startfrac to endfrac,
1466 //  where 0 is the start of the segment, 1 the end of the segment
1467 // Anything between means the wall segment has been clipped with solidsegs,
1468 //  reducing wall overdraw to a minimum
1469 //
1470 // GLOBAL IN:
1471 //   gr_curline
1472 //   gr_frontsector
1473 //   gr_backsector
1474 // GLOBAL OUT:
1475 //   gr_linedef
1476 //   gr_sidedef
1477 // Called from HWR_ClipSolidWallSegment, HWR_ClipPassWallSegment
HWR_StoreWallRange(float startfrac,float endfrac)1478 static void HWR_StoreWallRange(float startfrac, float endfrac)
1479 {
1480     vxtx3d_t vxtx[4];
1481     v2d_t vs, ve;               // start, end vertices of 2d line (view from above)
1482 
1483     fixed_t worldtop;		// front sector
1484     fixed_t worldbottom;
1485     fixed_t worldbacktop = 0;	// back sector, only used on two sided lines
1486     fixed_t worldbackbottom = 0;
1487     float   skybottom = 2E10;
1488 
1489     MipTexture_t * miptex = NULL;
1490     float cliplow, cliphigh;
1491     int midtexnum;
1492     int blendmode;
1493     fixed_t h, l;               // 3D sides and 2s middle textures
1494 
1495     FSurfaceInfo_t Surf;
1496 
1497     if (startfrac > endfrac)
1498         return;
1499 
1500     gr_sidedef = gr_curline->sidedef;
1501     gr_linedef = gr_curline->linedef;
1502 
1503     // mark the segment as visible for auto map
1504     gr_linedef->flags |= ML_MAPPED;
1505 
1506     worldtop = gr_frontsector->ceilingheight;
1507     worldbottom = gr_frontsector->floorheight;
1508 
1509     vs.x = gr_curline->pv1->x;
1510     vs.y = gr_curline->pv1->y;
1511     ve.x = gr_curline->pv2->x;
1512     ve.y = gr_curline->pv2->y;
1513 
1514     //
1515     // clip the wall segment to solidsegs
1516     //
1517 
1518 /*  BP : removed since there is no more clipwalls !
1519     // clip start of segment
1520     if (startfrac > 0){
1521         if (startfrac>1)
1522         {
1523 #ifdef PARANOIA
1524             CONS_Printf ("startfrac %f\n", startfrac );
1525 #endif
1526             startfrac = 1;
1527         }
1528             vs.x = vs.x + (ve.x - vs.x) * startfrac;
1529             vs.y = vs.y + (ve.y - vs.y) * startfrac;
1530         }
1531 
1532     // clip end of segment
1533     if (endfrac < 1){
1534         if (endfrac<0)
1535         {
1536 #ifdef PARANOIA
1537             CONS_Printf ("  endfrac %f\n", endfrac );
1538 #endif
1539             endfrac=0;
1540         }
1541             ve.x = vs.x + (ve.x - vs.x) * endfrac;
1542             ve.y = vs.y + (ve.y - vs.y) * endfrac;
1543         }
1544 */
1545     // remember vertices ordering
1546     //  3--2
1547     //  | /|
1548     //  |/ |
1549     //  0--1
1550     // make a wall polygon (with 2 triangles), using the floor/ceiling heights,
1551     // and the 2d map coords of start/end vertices
1552     vxtx[0].x = vxtx[3].x = vs.x;
1553     vxtx[0].z = vxtx[3].z = vs.y;
1554     vxtx[2].x = vxtx[1].x = ve.x;
1555     vxtx[2].z = vxtx[1].z = ve.y;
1556 //    vxtx[0].w = vxtx[1].w = vxtx[2].w = vxtx[3].w = 1.0f;
1557 
1558     if (EN_drawtextured)
1559     {
1560         // x offset the texture
1561         fixed_t texturehpeg = gr_sidedef->textureoffset + gr_curline->offset;
1562 
1563         // clip texture s start/end coords with solidsegs
1564         if (startfrac > 0.0 && startfrac < 1.0)
1565             cliplow = texturehpeg + gr_curline->length * startfrac;
1566         else
1567             cliplow = texturehpeg;
1568 
1569         if (endfrac > 0.0 && endfrac < 1.0)
1570             cliphigh = texturehpeg + gr_curline->length * endfrac;
1571         else
1572             cliphigh = texturehpeg + gr_curline->length;
1573     }
1574 
1575     Surf.polyflags = PF_Environment;
1576     Surf.texflags = 0;
1577 
1578     //  use different light tables
1579     //  for horizontal / vertical / diagonal
1580     //  note: try to get the same visual feel as the original
1581     Surf.FlatColor.s.alpha = 0xff;
1582     if (fixedcolormap)
1583     {
1584         // TODO: better handling of fixedcolormap
1585         Surf.FlatColor.s.red = Surf.FlatColor.s.green = Surf.FlatColor.s.blue = 0xff;
1586         // See PrBoom use of
1587         // glDisable(GL_SHARED_TEXTURE_PALETTE_EXT);
1588         // glEnable(GL_TEXTURE_GEN_S);
1589         // glEnable(GL_TEXTURE_GEN_T);
1590         // glEnable(GL_TEXTURE_GEN_Q);
1591         // glColor4fv(gl_whitecolor);
1592     }
1593     else
1594     {
1595         byte lightlum = LightLevelToLum(gr_frontsector->lightlevel);
1596 
1597         // wall orient light
1598         if ((vs.y == ve.y) && lightlum >= (255 / LIGHTLEVELS))
1599             lightlum -= (255 / LIGHTLEVELS);
1600         else if ((vs.x == ve.x) && lightlum < (255 - (255 / LIGHTLEVELS)))
1601             lightlum += (255 / LIGHTLEVELS);
1602 
1603         // store Surface->FlatColor to modulate wall texture
1604         Surf.FlatColor.s.red = Surf.FlatColor.s.green = Surf.FlatColor.s.blue = lightlum;
1605 
1606         //Hurdler: it seems to be better here :)
1607         if ( view_extracolormap )
1608         {
1609             Extracolormap_to_Surf( /*IN*/ view_extracolormap, lightlum,
1610                                    /*OUT*/ & Surf );
1611         }
1612         else if (gr_frontsector)
1613         {
1614             sector_t *sector = gr_frontsector;
1615 
1616             //Hurdler: colormap test
1617             if (sector->ffloors)
1618             {
1619                 ffloor_t *caster =
1620                   R_GetPlaneLight(sector, sector->floorheight)->caster;
1621                 sector = caster ? &sectors[caster->model_secnum] : sector;
1622             }
1623             if (sector->extra_colormap)
1624             {
1625                 Extracolormap_to_Surf( /*IN*/ sector->extra_colormap, lightlum,
1626                                        /*OUT*/ & Surf );
1627             }
1628         }
1629     }
1630 
1631     if (gr_backsector)
1632     {
1633         // two sided line
1634         worldbacktop = gr_backsector->ceilingheight;
1635         worldbackbottom = gr_backsector->floorheight;
1636 
1637         // hack to allow height changes in outdoor areas
1638         if (gr_frontsector->ceilingpic == sky_flatnum && gr_backsector->ceilingpic == sky_flatnum)
1639         {
1640             worldtop = worldbacktop;
1641         }
1642 
1643         // check TOP TEXTURE
1644         // texture num are either 0=no-texture, or valid
1645         int toptexnum = texturetranslation[gr_sidedef->toptexture];
1646         if (worldbacktop < worldtop && toptexnum)
1647         {
1648             if (EN_drawtextured)
1649             {
1650                 fixed_t texturevpegtop; //top
1651 
1652                 miptex = HWR_GetTexture(toptexnum, 0);
1653 
1654                 // PEGGING
1655                 if (gr_linedef->flags & ML_DONTPEGTOP)
1656                     texturevpegtop = 0;
1657                 else
1658                 {
1659                     // [WDJ] sometimes maybe textureheight[gr_sidedef->toptexture] != textureheight[toptexnum]
1660 //                    texturevpegtop = worldbacktop + textureheight[gr_sidedef->toptexture] - worldtop;
1661                     texturevpegtop = worldbacktop + textureheight[toptexnum] - worldtop;
1662                 }
1663 
1664                 texturevpegtop += gr_sidedef->rowoffset;
1665 
1666                 vxtx[3].tow = vxtx[2].tow = texturevpegtop * miptex->scaleY;
1667                 vxtx[0].tow = vxtx[1].tow = (texturevpegtop + worldtop - worldbacktop) * miptex->scaleY;
1668                 vxtx[0].sow = vxtx[3].sow = cliplow * miptex->scaleX;
1669                 vxtx[2].sow = vxtx[1].sow = cliphigh * miptex->scaleX;
1670             }
1671 
1672             // set top/bottom coords
1673             vxtx[2].y = vxtx[3].y = skybottom = FIXED_TO_FLOAT( worldtop );
1674             vxtx[0].y = vxtx[1].y = FIXED_TO_FLOAT( worldbacktop );
1675 
1676             Surf.polyflags = PF_Environment;
1677             if (gr_frontsector->numlights)
1678                 HWR_SplitWall(gr_frontsector, vxtx, toptexnum, &Surf,
1679                               0, FF_CUTSOLIDS);
1680             else if (miptex->mipmap.tfflags & TF_TRANSPARENT)
1681                 HWR_AddTransparentWall(vxtx, &Surf, toptexnum, PF_Environment);
1682             else
1683                 HWR_ProjectWall(vxtx, &Surf, PF_Masked);
1684         }
1685 
1686         // check BOTTOM TEXTURE
1687         // texture num are either 0=no-texture, or valid
1688         int bottomtexnum = texturetranslation[gr_sidedef->bottomtexture];
1689         if (worldbackbottom > worldbottom && bottomtexnum)    //only if VISIBLE!!!
1690         {
1691             if (EN_drawtextured)
1692             {
1693                 fixed_t texturevpegbottom = 0;  //bottom
1694 
1695                 miptex = HWR_GetTexture(bottomtexnum, 0);
1696 
1697                 // PEGGING
1698                 if (gr_linedef->flags & ML_DONTPEGBOTTOM)
1699                     texturevpegbottom = worldtop - worldbackbottom;
1700                 else
1701                     texturevpegbottom = 0;
1702 
1703                 texturevpegbottom += gr_sidedef->rowoffset;
1704 
1705                 vxtx[3].tow = vxtx[2].tow = texturevpegbottom * miptex->scaleY;
1706                 vxtx[0].tow = vxtx[1].tow = (texturevpegbottom + worldbackbottom - worldbottom) * miptex->scaleY;
1707                 vxtx[0].sow = vxtx[3].sow = cliplow * miptex->scaleX;
1708                 vxtx[2].sow = vxtx[1].sow = cliphigh * miptex->scaleX;
1709             }
1710 
1711             // set top/bottom coords
1712             vxtx[2].y = vxtx[3].y = FIXED_TO_FLOAT( worldbackbottom );
1713             vxtx[0].y = vxtx[1].y = FIXED_TO_FLOAT( worldbottom );
1714 
1715             Surf.polyflags = PF_Environment;
1716             if (gr_frontsector->numlights)
1717                 HWR_SplitWall(gr_frontsector, vxtx, bottomtexnum, &Surf,
1718                               0, FF_CUTSOLIDS);
1719             else if (miptex->mipmap.tfflags & TF_TRANSPARENT)
1720                 HWR_AddTransparentWall(vxtx, &Surf, bottomtexnum, PF_Environment);
1721             else
1722                 HWR_ProjectWall(vxtx, &Surf, PF_Masked);
1723         }
1724         // texture num are either 0=no-texture, or valid
1725         midtexnum = texturetranslation[gr_sidedef->midtexture];
1726         if (midtexnum)
1727         {
1728             int  clip_disable = (gr_linedef->flags & ML_DONTDRAW);
1729             fixed_t opentop, openbottom, polytop, polybottom;
1730 
1731             blendmode = PF_Masked;
1732             if(gr_linedef->translu_eff)  // Boom 260: make translucent
1733             {
1734                 blendmode = HWR_TranstableToAlpha(gr_linedef->translu_eff, &Surf);
1735             }
1736             // set alpha for transparent walls (new boom and legacy linedef types)
1737             switch (gr_linedef->special)
1738             {
1739                 case 260:  // Boom make translucent
1740                       // see test on translu_eff
1741 //                    blendmode = HWR_TranstableToAlpha(gr_linedef->translu_eff, &Surf);
1742                     break;
1743                            // Legacy translucent  284 to 288
1744                 case 284:  // Legacy translucent, brighten (greenish)
1745                     blendmode = HWR_TranstableToAlpha(TRANSLU_med, &Surf);
1746                     break;
1747                 case 285:  // Legacy translucent, brighten (less greenish)
1748                     blendmode = HWR_TranstableToAlpha(TRANSLU_more, &Surf);
1749                     break;
1750                 case 286:  // Legacy translucent, darkens
1751                     blendmode = HWR_TranstableToAlpha(TRANSLU_hi, &Surf);
1752                     break;
1753                 case 287:  // Legacy translucent, brightens
1754                     blendmode = HWR_TranstableToAlpha(TRANSLU_fire, &Surf);
1755                     break;
1756                 case 288:  // Legacy selective translucent, on selected colors
1757                     // sets TF_Opaquetrans in texflags
1758                     blendmode = HWR_TranstableToAlpha(TRANSLU_fx1, &Surf);
1759                     break;
1760                 case 283:  // Legacy fog sheet
1761                     blendmode = PF_Fog;
1762                     Surf.FlatColor.s.alpha = 64;
1763                     Surf.texflags = TF_Fogsheet;
1764                     break;
1765                 default:
1766                     // do not override Boom 260 tagged assign of blendmode
1767 //                    blendmode = PF_Masked;
1768                     break;
1769             }
1770 
1771             if (EN_drawtextured)
1772             {
1773                 // TRANSLU_fx1 requires TF_Opaquetrans flag to draw texture
1774                 miptex = HWR_GetTexture(midtexnum, Surf.texflags);
1775 
1776                 if (miptex && (miptex->mipmap.tfflags & TF_TRANSPARENT))
1777                 {
1778                     blendmode = PF_Environment;
1779                     clip_disable = 1;  // full height, no (h-l) clipping
1780                 }
1781             }
1782 
1783 #if 1
1784             {
1785                 // [WDJ] ic2005.wad has three textures that are pegged
1786                 // to moving DeepWater sectors.
1787                 // 1) translucent over DeepWater door, yoffset=+120
1788                 //    tried if( blendmode != PF_Masked )
1789                 // 2) transparent electric arc, under DeepWater ceiling.
1790                 //    tried if(miptex->mipmap.tfflags & TF_TRANSPARENT)
1791                 // 3) small texture grid, with moving DeepWater ceiling and floor
1792                 //    no test
1793                 //
1794                 // These must peg to the actual sectors, ignoring DeepWater
1795                 worldtop = gr_linedef->frontsector->ceilingheight;
1796                 worldbottom = gr_linedef->frontsector->floorheight;
1797                 worldbacktop = gr_linedef->backsector->ceilingheight;
1798                 worldbackbottom = gr_linedef->backsector->floorheight;
1799             }
1800 #endif
1801 
1802             // SoM: a little note: This code re-arranging will
1803             // fix the bug in Nimrod map02. opentop and openbottom
1804             // record the limits the texture can be displayed in.
1805             // polytop and polybottom, are the ideal (i.e. unclipped)
1806             // heights of the polygon, and h & l, are the final (clipped)
1807             // poly coords.
1808 
1809             opentop = (worldtop < worldbacktop) ? worldtop : worldbacktop;
1810             openbottom = (worldbottom > worldbackbottom) ? worldbottom : worldbackbottom;
1811 
1812             if (gr_linedef->flags & ML_DONTPEGBOTTOM)
1813             {
1814                 polybottom = openbottom + gr_sidedef->rowoffset;
1815                 polytop = polybottom + textureheight[midtexnum];
1816             }
1817             else
1818             {
1819                 polytop = opentop + gr_sidedef->rowoffset;
1820                 polybottom = polytop - textureheight[midtexnum];
1821             }
1822             if ((gr_frontsector->ceilingheight == gr_backsector->ceilingheight)
1823                 || clip_disable )
1824                 h = polytop;
1825             else
1826                 h = (polytop < opentop) ? polytop : opentop;
1827 
1828             if ((gr_frontsector->floorheight == gr_backsector->floorheight)
1829                 || clip_disable )
1830                 l = polybottom;
1831             else
1832                 l = (polybottom > openbottom) ? polybottom : openbottom;
1833 
1834             if (EN_drawtextured)
1835             {
1836                 fixed_t texturevpeg;
1837                 // PEGGING
1838                 if (gr_linedef->flags & ML_DONTPEGBOTTOM)
1839                     texturevpeg = l + textureheight[gr_sidedef->midtexture] - h + polybottom - l;
1840                 else
1841                     texturevpeg = polytop - h;
1842 
1843                 vxtx[3].tow = vxtx[2].tow = texturevpeg * miptex->scaleY;
1844                 vxtx[0].tow = vxtx[1].tow = (h - l + texturevpeg) * miptex->scaleY;
1845                 vxtx[0].sow = vxtx[3].sow = cliplow * miptex->scaleX;
1846                 vxtx[2].sow = vxtx[1].sow = cliphigh * miptex->scaleX;
1847             }
1848             // set top/bottom coords
1849             vxtx[2].y = vxtx[3].y = FIXED_TO_FLOAT( h );
1850             vxtx[0].y = vxtx[1].y = FIXED_TO_FLOAT( l );
1851 #if 0
1852             // [WDJ] Causes transparent signs to block wall behind.
1853             if( skybottom > 1E10)
1854                 skybottom = vxtx[2].y;
1855 #endif
1856 
1857             if (blendmode != PF_Masked)
1858                 HWR_AddTransparentWall(vxtx, &Surf, midtexnum, blendmode);
1859             else
1860                 HWR_ProjectWall(vxtx, &Surf, blendmode);
1861         }
1862     }
1863     else
1864     {
1865         // Single sided line... Deal only with the middletexture (if one exists)
1866         midtexnum = texturetranslation[gr_sidedef->midtexture];
1867         if (midtexnum)
1868         {
1869             if (EN_drawtextured)
1870             {
1871                 fixed_t texturevpeg;
1872                 // PEGGING
1873                 if ((unsigned short)gr_linedef->flags & ML_DONTPEGBOTTOM)
1874                     texturevpeg = worldbottom + textureheight[gr_sidedef->midtexture] - worldtop + gr_sidedef->rowoffset;
1875                 else
1876                     // top of texture at top
1877                     texturevpeg = gr_sidedef->rowoffset;
1878 
1879                 miptex = HWR_GetTexture(midtexnum, 0);
1880 
1881                 vxtx[3].tow = vxtx[2].tow = texturevpeg * miptex->scaleY;
1882                 vxtx[0].tow = vxtx[1].tow = (texturevpeg + worldtop - worldbottom) * miptex->scaleY;
1883                 vxtx[0].sow = vxtx[3].sow = cliplow * miptex->scaleX;
1884                 vxtx[2].sow = vxtx[1].sow = cliphigh * miptex->scaleX;
1885             }
1886             // set top/bottom coords
1887             vxtx[2].y = vxtx[3].y = skybottom = FIXED_TO_FLOAT( worldtop );
1888             vxtx[0].y = vxtx[1].y = FIXED_TO_FLOAT( worldbottom );
1889 
1890             // I don't think that solid walls can use translucent linedef types...
1891             Surf.polyflags = PF_Environment;
1892             if (gr_frontsector->numlights)
1893                 HWR_SplitWall(gr_frontsector, vxtx, midtexnum, &Surf,
1894                               0, FF_CUTSOLIDS);
1895             else
1896             {
1897                 if (miptex->mipmap.tfflags & TF_TRANSPARENT)
1898                     HWR_AddTransparentWall(vxtx, &Surf, midtexnum, PF_Environment);
1899                 else
1900                     HWR_ProjectWall(vxtx, &Surf, PF_Masked);
1901             }
1902         }
1903         else
1904         {
1905             skybottom = FIXED_TO_FLOAT( worldbottom );
1906         }
1907     }
1908 
1909     if( (gr_frontsector->ceilingpic == sky_flatnum)
1910         && (skybottom < 1E10) )
1911     {
1912         // [WDJ] Above upper texture is sky
1913         vxtx[2].y = vxtx[3].y = skybottom;
1914         vxtx[0].y = vxtx[1].y = 2E10;
1915 
1916         // [WDJ] Does not have skyflat detection, nor colormap,
1917         // so no place to apply cv_invul_skymap.EV.
1918         // See PrBoom use of
1919         // glDisable(GL_SHARED_TEXTURE_PALETTE_EXT);
1920         // glEnable(GL_TEXTURE_GEN_S);
1921         // glEnable(GL_TEXTURE_GEN_T);
1922         // glEnable(GL_TEXTURE_GEN_Q);
1923         // glColor4fv(gl_whitecolor);
1924 
1925         // Transparent, to set z buffer to block more distant draws.
1926         Surf.polyflags = PF_Environment;
1927         HWD.pfnDrawPolygon(&Surf, vxtx, 4,
1928                            PF_Invisible | PF_Occlude | PF_Masked | PF_Clip );
1929     }
1930 
1931     //Hurdler: 3d-floors test
1932 #ifdef R_FAKEFLOORS
1933     if (gr_frontsector && gr_backsector
1934         && gr_frontsector->tag != gr_backsector->tag
1935         && (gr_backsector->ffloors || gr_frontsector->ffloors))
1936     {
1937         ffloor_t * fff, * bff;
1938         fixed_t highcut, lowcut;
1939 
1940         highcut = gr_frontsector->ceilingheight < gr_backsector->ceilingheight ? gr_frontsector->ceilingheight : gr_backsector->ceilingheight;
1941         lowcut = gr_frontsector->floorheight > gr_backsector->floorheight ? gr_frontsector->floorheight : gr_backsector->floorheight;
1942 
1943         if (gr_backsector->ffloors)
1944         {
1945             for (bff = gr_backsector->ffloors; bff; bff = bff->next)
1946             {
1947                 if (!(bff->flags & FF_OUTER_SIDES) || !(bff->flags & FF_EXISTS))
1948                     continue;
1949                 // outer sides backsector
1950                 if (*bff->topheight < lowcut || *bff->bottomheight > highcut)
1951                     continue;
1952 
1953                 h = *bff->topheight;
1954                 l = *bff->bottomheight;
1955                 if (h > highcut)
1956                     h = highcut;
1957                 if (l < lowcut)
1958                     l = lowcut;
1959                 //Hurdler: HW code starts here
1960                 //FIXME: check if peging is correct
1961                 // set top/bottom coords
1962                 vxtx[2].y = vxtx[3].y = FIXED_TO_FLOAT( h );
1963                 vxtx[0].y = vxtx[1].y = FIXED_TO_FLOAT( l );
1964 
1965                 // protect against missing middle texture
1966                 midtexnum = texturetranslation[sides[bff->master->sidenum[0]].midtexture];
1967                 if( midtexnum == 0 ) continue;  // no texture to display (when 3Dslab is missing side texture)
1968 
1969                 if (EN_drawtextured)
1970                 {
1971 //		    if( midtexnum == 0 ) continue;  // no texture to display (when 3Dslab is missing side texture)
1972                     miptex = HWR_GetTexture( midtexnum, 0 );
1973 
1974                     vxtx[3].tow = vxtx[2].tow = (*bff->topheight - h) * miptex->scaleY;
1975                     vxtx[0].tow = vxtx[1].tow = (h - l + (*bff->topheight - h)) * miptex->scaleY;
1976                     vxtx[0].sow = vxtx[3].sow = cliplow * miptex->scaleX;
1977                     vxtx[2].sow = vxtx[1].sow = cliphigh * miptex->scaleX;
1978                 }
1979 
1980                 if (bff->flags & FF_FOG)
1981                 {
1982                     // FF_FOG, must also be usable with water
1983                     // Legacy Fog in tagged sector
1984                     blendmode = PF_Fog;
1985                     dr_alpha = fweff[bff->fw_effect].fsh_alpha;  // dr_alpha 0..255
1986                     Surf.FlatColor.s.alpha = (float)dr_alpha * (251.0f/256.0f) + 5.0f;
1987 //		    Surf.FlatColor.s.alpha = (float)dr_alpha * (246.0f/256.0f) + 10.0f;
1988                     Surf.texflags = TF_Fogsheet;
1989                 }
1990                 else
1991                 {
1992                     // NOT Legacy 3D fog in tagged sector
1993                     blendmode = PF_Masked;
1994 
1995                     if (bff->flags & FF_TRANSLUCENT)
1996                     {
1997                         blendmode = PF_Translucent;
1998                         Surf.FlatColor.s.alpha = bff->alpha;
1999                     }
2000                     else if (miptex->mipmap.tfflags & TF_TRANSPARENT)
2001                     {
2002                         blendmode = PF_Environment;
2003                     }
2004                 }
2005 
2006                 if (gr_frontsector->numlights)
2007                 {
2008 //		        if( midtexnum == 0 ) continue;  // no texture to display (when 3Dslab is missing side texture)
2009                     Surf.polyflags = blendmode;
2010                     HWR_SplitWall(gr_frontsector, vxtx, midtexnum, &Surf,
2011                                   bff->flags,
2012                                   bff->flags & FF_EXTRA ? FF_CUTEXTRA : FF_CUTSOLIDS);
2013                 }
2014                 else
2015                 {
2016                     if (blendmode != PF_Masked)
2017                     {
2018 //			    if( midtexnum == 0 ) continue;  // no texture to display (when 3Dslab is missing side texture)
2019                         HWR_AddTransparentWall(vxtx, &Surf, midtexnum, blendmode);
2020                     }
2021                     else
2022                         HWR_ProjectWall(vxtx, &Surf, PF_Masked);
2023                 }
2024             }
2025         }
2026         // [WDJ] must check frontsector floors too, to get translucent sides of water
2027         if (gr_frontsector->ffloors)
2028         {
2029             for (fff = gr_frontsector->ffloors; fff; fff = fff->next)
2030             {
2031                 if (!(fff->flags & FF_INNER_SIDES) || !(fff->flags & FF_EXISTS))
2032                     continue;
2033                 // inner sides of frontsector
2034                 if (*fff->topheight < lowcut || *fff->bottomheight > highcut)
2035                     continue;
2036 
2037                 h = *fff->topheight;
2038                 l = *fff->bottomheight;
2039                 if (h > highcut)
2040                     h = highcut;
2041                 if (l < lowcut)
2042                     l = lowcut;
2043                 //Hurdler: HW code starts here
2044                 //FIXME: check if peging is correct
2045                 // set top/bottom coords
2046                 vxtx[2].y = vxtx[3].y = FIXED_TO_FLOAT( h );
2047                 vxtx[0].y = vxtx[1].y = FIXED_TO_FLOAT( l );
2048 
2049                 // protect against missing middle texture
2050                 midtexnum = texturetranslation[sides[fff->master->sidenum[0]].midtexture];
2051                 if( midtexnum == 0 ) continue;  // no texture to display (when 3Dslab is missing side texture)
2052 
2053                 if (EN_drawtextured)
2054                 {
2055 //		    if( midtexnum == 0 ) continue;  // no texture to display (when 3Dslab is missing side texture)
2056                     miptex = HWR_GetTexture( midtexnum, 0 );
2057 
2058                     vxtx[3].tow = vxtx[2].tow = (*fff->topheight - h) * miptex->scaleY;
2059                     vxtx[0].tow = vxtx[1].tow = (h - l + (*fff->topheight - h)) * miptex->scaleY;
2060                     vxtx[0].sow = vxtx[3].sow = cliplow * miptex->scaleX;
2061                     vxtx[2].sow = vxtx[1].sow = cliphigh * miptex->scaleX;
2062                 }
2063 
2064                 if (fff->flags & FF_FOG)
2065                 {
2066                     // FF_FOG, must also be usable with water
2067                     // Legacy Fog in tagged sector
2068                     dr_alpha = fweff[fff->fw_effect].fsh_alpha;  // dr_alpha 0..255
2069                     // fog alpha needs to be biased, otherwise low alpha become invisible
2070                     Surf.FlatColor.s.alpha = (float)dr_alpha * (251.0f/256.0f) + 5.0f;
2071                     Surf.texflags = TF_Fogsheet;
2072                     blendmode = PF_Fog;
2073                 }
2074                 else
2075                 {
2076                     blendmode = PF_Masked;
2077 
2078                     if (fff->flags & FF_TRANSLUCENT)
2079                     {
2080                         blendmode = PF_Translucent;
2081                         Surf.FlatColor.s.alpha = fff->alpha;
2082                     }
2083                     else if (miptex->mipmap.tfflags & TF_TRANSPARENT)
2084                     {
2085                         blendmode = PF_Environment;
2086                     }
2087                 }
2088 
2089                 if (gr_backsector->numlights)
2090                 {
2091 //		        if( midtexnum == 0 ) continue;  // no texture to display (when 3Dslab is missing side texture)
2092                     Surf.polyflags = blendmode;
2093                     HWR_SplitWall(gr_backsector, vxtx, midtexnum, &Surf,
2094                                   fff->flags,
2095                                   fff->flags & FF_EXTRA ? FF_CUTEXTRA : FF_CUTSOLIDS);
2096                 }
2097                 else
2098                 {
2099                     if (blendmode != PF_Masked)
2100                     {
2101 //			    if( midtexnum == 0 ) continue;  // no texture to display (when 3Dslab is missing side texture)
2102                         HWR_AddTransparentWall(vxtx, &Surf, midtexnum, blendmode);
2103                     }
2104                     else
2105                         HWR_ProjectWall(vxtx, &Surf, PF_Masked);
2106                 }
2107             }
2108         }
2109     }
2110 #endif
2111 //Hurdler: end of 3d-floors test
2112 }
2113 
2114 //
2115 // ClipWallSegment
2116 // Clips the given range of columns
2117 // and includes it in the new clip list.
2118 //
2119 typedef struct
2120 {
2121     int first;
2122     int last;
2123 } cliprange_t;
2124 
2125 //Hurdler: just like in r_bsp.c
2126 #define MAXSEGS         MAXVIDWIDTH/2+1
2127 
2128 // newend is one past the last valid seg
2129 cliprange_t *newend;
2130 cliprange_t gr_solidsegs[MAXSEGS];
2131 
printsolidsegs(void)2132 void printsolidsegs(void)
2133 {
2134     cliprange_t *start;
2135     if (!newend || cv_grbeta.value != 2)
2136         return;
2137     for (start = gr_solidsegs; start != newend; start++)
2138         CONS_Printf("%d-%d|", start->first, start->last);
2139     CONS_Printf("\n\n");
2140 }
2141 
2142 //
2143 //
2144 // Called from HWR_AddLine
HWR_ClipSolidWallSegment(int first,int last)2145 static void HWR_ClipSolidWallSegment(int first, int last)
2146 {
2147     cliprange_t *next;
2148     cliprange_t *start;
2149     float lowfrac, highfrac;
2150     boolean clipwalls_fragment = false;
2151 
2152     // Find the first range that touches the range
2153     //  (adjacent pixels are touching).
2154     start = gr_solidsegs;
2155     while (start->last < first - 1)
2156         start++;
2157 
2158     if (first < start->first)
2159     {
2160         if (last < start->first - 1)
2161         {
2162             // Post is entirely visible (above start),
2163             //  so insert a new clippost.
2164 //            HWR_StoreWallRange(first, last);
2165             HWR_StoreWallRange(0.0, 1.0);
2166 
2167             next = newend;  // use empty at newend
2168             newend++;
2169 
2170             // shuffle up clipposts, start to newend-1
2171             while (next != start)
2172             {
2173                 *next = *(next - 1);
2174                 next--;
2175             }
2176             // insert at start
2177             next->first = first;
2178             next->last = last;
2179             goto done;
2180         }
2181 
2182         // There is a fragment above *start.
2183         if (!cv_grclipwalls.value)
2184         {
2185             if (!clipwalls_fragment)
2186 //                HWR_StoreWallRange(first, last);
2187                 HWR_StoreWallRange(0.0, 1.0);
2188             clipwalls_fragment = true;
2189         }
2190         else
2191         {
2192             highfrac = HWR_ClipViewSegment(start->first + 1,
2193                                            gr_curline->pv1, gr_curline->pv2);
2194             HWR_StoreWallRange(0.0, highfrac);
2195         }
2196         // Now adjust the clip size.
2197         start->first = first;
2198     }
2199 
2200     // Bottom contained in start?
2201     if (last <= start->last)
2202         goto done;
2203 
2204     next = start;
2205     while (last >= (next + 1)->first - 1)
2206     {
2207         // There is a fragment between two posts.
2208         if (!cv_grclipwalls.value)
2209         {
2210             if (!clipwalls_fragment)
2211 //                HWR_StoreWallRange(first, last);
2212                 HWR_StoreWallRange(0.0, 1.0);
2213             clipwalls_fragment = true;
2214         }
2215         else
2216         {
2217             lowfrac = HWR_ClipViewSegment(next->last - 1,
2218                                           gr_curline->pv1, gr_curline->pv2);
2219             highfrac = HWR_ClipViewSegment((next + 1)->first + 1,
2220                                           gr_curline->pv1, gr_curline->pv2);
2221             HWR_StoreWallRange(lowfrac, highfrac);
2222         }
2223         next++;
2224 
2225         if (last <= next->last)
2226         {
2227             // Bottom is contained in next.
2228             // Adjust the clip size.
2229             start->last = next->last;
2230             goto crunch;
2231         }
2232     }
2233 
2234     if (first == next->first + 1)       // 1 line texture
2235     {
2236         if (!cv_grclipwalls.value)
2237         {
2238             if (!clipwalls_fragment)
2239 //                HWR_StoreWallRange(first, last);
2240                 HWR_StoreWallRange(0.0, 1.0);
2241             clipwalls_fragment = true;
2242         }
2243         else
2244             HWR_StoreWallRange(0.0, 1.0);
2245     }
2246     else
2247     {
2248         // There is a fragment after *next.
2249         if (!cv_grclipwalls.value)
2250         {
2251             if (!clipwalls_fragment)
2252 //                HWR_StoreWallRange(first, last);
2253                 HWR_StoreWallRange(0.0, 1.0);
2254             clipwalls_fragment = true;
2255         }
2256         else
2257         {
2258             lowfrac = HWR_ClipViewSegment(next->last - 1,
2259                                           gr_curline->pv1, gr_curline->pv2);
2260             HWR_StoreWallRange(lowfrac, 1);
2261         }
2262     }
2263 
2264     // Adjust the clip size.
2265     start->last = last;
2266 
2267     // Remove start+1 to next from the clip list,
2268     // because start now covers their area.
2269   crunch:
2270     if (next == start)
2271         goto done;  // Post just extended past the bottom of one post.
2272 
2273     while (next++ != newend)
2274     {
2275         // Remove a post.
2276         *++start = *next;
2277     }
2278 
2279     newend = start;
2280 
2281   done:
2282     if( cv_grbeta.value == 2 )
2283        printsolidsegs();  // debug
2284     return;
2285 }
2286 
2287 //
2288 //  handle LineDefs with upper and lower texture (windows)
2289 //
2290 // Called from HWR_AddLine
HWR_ClipPassWallSegment(int first,int last)2291 static void HWR_ClipPassWallSegment(int first, int last)
2292 {
2293     cliprange_t *start;
2294     float lowfrac, highfrac;
2295     //to allow noclipwalls but still solidseg reject of non-visible walls
2296     boolean clipwalls_fragment = false;
2297 
2298     // Find the first range that touches the range
2299     //  (adjacent pixels are touching).
2300     start = gr_solidsegs;
2301     while (start->last < first - 1)
2302         start++;
2303 
2304     if (first < start->first)
2305     {
2306         if (last < start->first - 1)
2307         {
2308             // Post is entirely visible (above start).
2309             HWR_StoreWallRange(0.0, 1.0);
2310             return;
2311         }
2312 
2313         // There is a fragment above *start.
2314         if (!cv_grclipwalls.value)
2315         {
2316             //20/08/99: Changed by Hurdler (taken from faB's code)
2317             if (!clipwalls_fragment)
2318                 HWR_StoreWallRange(0.0, 1.0);
2319             clipwalls_fragment = true;
2320         }
2321         else
2322         {
2323             highfrac = HWR_ClipViewSegment(min(start->first + 1, start->last),
2324                                            gr_curline->pv1, gr_curline->pv2);
2325             HWR_StoreWallRange(0.0, highfrac);
2326         }
2327     }
2328 
2329     // Bottom contained in start?
2330     if (last <= start->last)
2331         return;
2332 
2333     while (last >= (start + 1)->first - 1)
2334     {
2335         // There is a fragment between two posts.
2336         if (!cv_grclipwalls.value)
2337         {
2338             if (!clipwalls_fragment)
2339                 HWR_StoreWallRange(0.0, 1.0);
2340             clipwalls_fragment = true;
2341         }
2342         else
2343         {
2344             lowfrac = HWR_ClipViewSegment(max(start->last - 1, start->first),
2345                                           gr_curline->pv1, gr_curline->pv2);
2346             highfrac = HWR_ClipViewSegment(min((start + 1)->first + 1, (start + 1)->last),
2347                                           gr_curline->pv1, gr_curline->pv2);
2348             HWR_StoreWallRange(lowfrac, highfrac);
2349         }
2350         start++;
2351 
2352         if (last <= start->last)
2353             return;
2354     }
2355 
2356     if (first == start->first + 1)      // 1 line texture
2357     {
2358         if (!cv_grclipwalls.value)
2359         {
2360             if (!clipwalls_fragment)
2361                 HWR_StoreWallRange(0.0, 1.0);
2362             clipwalls_fragment = true;
2363         }
2364         else
2365             HWR_StoreWallRange(0.0, 1.0);
2366     }
2367     else
2368     {
2369         // There is a fragment after *next.
2370         if (!cv_grclipwalls.value)
2371         {
2372             if (!clipwalls_fragment)
2373                 HWR_StoreWallRange(0.0, 1.0);
2374             clipwalls_fragment = true;
2375         }
2376         else
2377         {
2378             lowfrac = HWR_ClipViewSegment(max(start->last - 1, start->first),
2379                                           gr_curline->pv1, gr_curline->pv2);
2380             HWR_StoreWallRange(lowfrac, 1.0);
2381         }
2382     }
2383 }
2384 
2385 // --------------------------------------------------------------------------
2386 //  HWR_ClipToSolidSegs check if it is hide by wall (solidsegs)
2387 // --------------------------------------------------------------------------
HWR_ClipToSolidSegs(int first,int last)2388 static boolean HWR_ClipToSolidSegs(int first, int last)
2389 {
2390     cliprange_t *start;
2391 
2392     // Find the first range that touches the range
2393     //  (adjacent pixels are touching).
2394     start = gr_solidsegs;
2395     while (start->last < first - 1)
2396         start++;
2397 
2398     if (first < start->first)
2399         return true;
2400 
2401     // Bottom contained in start?
2402     if (last <= start->last)
2403         return false;
2404 
2405     return true;
2406 }
2407 
2408 //
2409 // HWR_Clear_ClipSegs
2410 //
HWR_Clear_ClipSegs(void)2411 static void HWR_Clear_ClipSegs(void)
2412 {
2413     gr_solidsegs[0].first = -0x7fffffff;
2414     gr_solidsegs[0].last = -1;
2415     gr_solidsegs[1].first = vid.width;  //viewwidth;
2416     gr_solidsegs[1].last = 0x7fffffff;
2417     newend = gr_solidsegs + 2;
2418 }
2419 
2420 // -----------------+
2421 // HWR_AddLine      : Clips the given segment and adds any visible pieces to the line list.
2422 // Notes            : gr_cursectorlight is set to the current subsector -> sector -> light value
2423 //                  : ( it may be mixed with the wall's own flat colour in the future ... )
2424 // -----------------+
2425 // Called from HWR_Subsector.
HWR_AddLine(seg_t * lineseg)2426 static void HWR_AddLine(seg_t * lineseg)
2427 {
2428     int x1, x2;
2429     angle_t angle1, angle2;
2430     angle_t span;
2431 
2432     // SoM: Backsector needs to be run through R_FakeFlat
2433     sector_t tempsec;
2434 
2435     gr_curline = lineseg;
2436 
2437     // OPTIMIZE: quickly reject orthogonal back sides.
2438 #if 1
2439     // angle calc uses fixed_t math
2440     // Angles here increase to the left.
2441     angle1 = R_PointToAngle( lineseg->v1->x, lineseg->v1->y );  // left
2442     angle2 = R_PointToAngle( lineseg->v2->x, lineseg->v2->y );  // right
2443 #else
2444     // convert polyvertex_t back to fixed_t
2445     angle1 = R_PointToAngle(((polyvertex_t *) lineseg->v1)->x * FRACUNIT, ((polyvertex_t *) lineseg->v1)->y * FRACUNIT);
2446     angle2 = R_PointToAngle(((polyvertex_t *) lineseg->v2)->x * FRACUNIT, ((polyvertex_t *) lineseg->v2)->y * FRACUNIT);
2447 #endif
2448 
2449     // Clip to view edges.
2450     span = angle1 - angle2;  // normally span > 0, (angle1 > angle2)
2451 
2452     // backface culling : span is < ANG180 if ang1 > ang2 : the seg is facing
2453     if (span >= ANG180)
2454         return;
2455 
2456     // Global angle needed by segcalc.
2457     //rw_angle1 = angle1;
2458     // view relative is left 0x20000000, middle 0, right 0xe0000000
2459     angle1 -= dup_viewangle;
2460     angle2 -= dup_viewangle;
2461 
2462     // angle1, angle2 may range from ANG270 to ANG90, unsigned.
2463     // Because of angle wrap, must contrive tests away from 0.
2464     // Trying to use signed tests, like prboom, did not work well.
2465     if ((gr_clipangle + angle1) > gr_clipangle_x_2) // (angle1 > clipangle)
2466     {
2467         // Totally off the left edge?
2468         if ((angle1 - gr_clipangle) >= span)  // (angle1 - clipangle) >= (angle1 - angle2)
2469             return;    // angle2 >= clipangle
2470 
2471         angle1 = gr_clipangle;
2472     }
2473 
2474     if ((gr_clipangle - angle2) > gr_clipangle_x_2)  // (angle2 < -clipangle)
2475     {
2476         // Totally off the right edge?
2477         if ((-angle2 - gr_clipangle) >= span)  //  (-angle2 - clipangle) >= (angle1 - angle2)
2478             return;    // angle1 <= -clipangle
2479 
2480         angle2 = -gr_clipangle;
2481     }
2482 
2483 #if 0
2484     {
2485         float fx1, fx2, fy1, fy2;
2486         //BP: test with a better projection than viewangle_to_x[R_PointToAngle(angle)]
2487         // do not enable this at release 4 mul and 2 div
2488         fx1 = lineseg->pv1->x - gr_viewx;
2489         fy1 = lineseg->pv1->y - gr_viewy;
2490         fy2 = (fx1 * gr_viewcos + fy1 * gr_viewsin);
2491         if (fy2 < 0)
2492             // the point is back
2493             fx1 = 0;
2494         else
2495             fx1 = gr_windowcenterx + (fx1 * gr_viewsin - fy1 * gr_viewcos) * gr_centerx / fy2;
2496 
2497         fx2 = ((polyvertex_t *) (lineseg->v2))->x - gr_viewx;
2498         fy2 = ((polyvertex_t *) (lineseg->v2))->y - gr_viewy;
2499         fy1 = (fx2 * gr_viewcos + fy2 * gr_viewsin);
2500         if (fy1 < 0)
2501             // the point is back
2502             fx2 = vid.width;
2503         else
2504             fx2 = gr_windowcenterx + (fx2 * gr_viewsin - fy2 * gr_viewcos) * gr_centerx / fy1;
2505 
2506         x1 = fx1 + 0.5f;
2507         x2 = fx2 + 0.5f;
2508     }
2509 #else
2510     // The seg is in the view range, but not necessarily visible.
2511     x1 = gr_viewangle_to_x[ ANGLE_TO_FINE(angle1+ANG90) ];  // left
2512     x2 = gr_viewangle_to_x[ ANGLE_TO_FINE(angle2+ANG90) ];  // right
2513 #endif
2514     // Does not cross a pixel?
2515 //    if (x1 == x2)
2516 /*    {
2517         // BP: HERE IS THE MAIN PROBLEM !
2518         //CONS_Printf("tineline\n");
2519         return;
2520     }
2521 */
2522     gr_backsector = lineseg->backsector;
2523 
2524     // Single sided line?
2525     if (!gr_backsector)
2526         goto clipsolid;
2527 
2528     gr_backsector = R_FakeFlat(gr_backsector, &tempsec, true,
2529                                /*OUT*/ NULL, NULL );
2530 
2531 #ifdef DOORCLOSED_FIX
2532     // [WDJ] Improvement on door closed detection from r_bsp
2533     doorclosed = 0; //SoM: 3/25/2000
2534 #endif
2535 
2536     // Closed door.
2537     if (gr_backsector->ceilingheight <= gr_frontsector->floorheight
2538         || gr_backsector->floorheight >= gr_frontsector->ceilingheight)
2539         goto clipsolid;
2540 
2541 #ifdef DOORCLOSED_FIX
2542     //SoM: 3/25/2000: Check for automap fix. Store in doorclosed for r_segs.c
2543     if ((doorclosed = R_DoorClosed()))
2544       goto clipsolid;
2545 #endif
2546 
2547     // Window.
2548     if (gr_backsector->ceilingheight != gr_frontsector->ceilingheight
2549         || gr_backsector->floorheight != gr_frontsector->floorheight)
2550         goto clippass;
2551 
2552 #if 1
2553     // [WDJ] 4/20/2010 From software renderer, to get improvements
2554     // Reject empty lines used for triggers and special events.
2555     // Identical floor and ceiling on both sides,
2556     // identical light levels on both sides, and no middle texture.
2557     if (gr_backsector->ceilingpic == gr_frontsector->ceilingpic
2558         && gr_backsector->floorpic == gr_frontsector->floorpic
2559         && gr_backsector->lightlevel == gr_frontsector->lightlevel
2560         && gr_curline->sidedef->midtexture == 0
2561 
2562         //SoM: 3/22/2000: Check offsets too!
2563         && gr_backsector->floor_xoffs == gr_frontsector->floor_xoffs
2564         && gr_backsector->floor_yoffs == gr_frontsector->floor_yoffs
2565         && gr_backsector->ceiling_xoffs == gr_frontsector->ceiling_xoffs
2566         && gr_backsector->ceiling_yoffs == gr_frontsector->ceiling_yoffs
2567 
2568         //SoM: 3/17/2000: consider altered lighting
2569         && gr_backsector->floorlightsec == gr_frontsector->floorlightsec
2570         && gr_backsector->ceilinglightsec == gr_frontsector->ceilinglightsec
2571         //SoM: 4/3/2000: Consider colormaps
2572         && gr_backsector->extra_colormap == gr_frontsector->extra_colormap
2573         && ((!gr_frontsector->ffloors && !gr_backsector->ffloors) ||
2574            (gr_frontsector->tag == gr_backsector->tag)))
2575     {
2576         return;
2577     }
2578 #else
2579     // Reject empty lines used for triggers and special events.
2580     // Identical floor and ceiling on both sides,
2581     //  identical light levels on both sides,
2582     //  and no middle texture.
2583     if (gr_backsector->ceilingpic == gr_frontsector->ceilingpic
2584         && gr_backsector->floorpic == gr_frontsector->floorpic
2585         && gr_backsector->lightlevel == gr_frontsector->lightlevel
2586         && gr_curline->sidedef->midtexture == 0
2587         && !gr_backsector->ffloors
2588         && !gr_frontsector->ffloors)
2589         // SoM: For 3D sides... Boris, would you like to take a
2590         // crack at rendering 3D sides? You would need to add the
2591         // above check and add code to HWR_StoreWallRange...
2592     {
2593         return;
2594     }
2595 #endif
2596 
2597   clippass:
2598     if (x1 == x2)
2599     {
2600         x2++;
2601         x1 -= 2;
2602     }
2603     HWR_ClipPassWallSegment(x1, x2 - 1);
2604     return;
2605 
2606   clipsolid:
2607     if (x1 == x2)
2608         goto clippass;
2609     HWR_ClipSolidWallSegment(x1, x2 - 1);
2610 }
2611 
2612 // HWR_CheckBBox
2613 // Checks BSP node/subtree bounding box.
2614 // Returns true
2615 //  if some part of the bbox might be visible.
2616 //
2617 // modified to use local variables
2618 
2619 extern int checkcoord[12][4];   //r_bsp.c
2620 
HWR_CheckBBox(fixed_t * bspcoord)2621 static boolean HWR_CheckBBox(fixed_t * bspcoord)
2622 {
2623     int boxpos;
2624     fixed_t x1, y1, x2, y2;
2625     angle_t angle1, angle2;
2626     angle_t span;
2627     int sx1, sx2;
2628 
2629     // Find the corners of the box
2630     // that define the edges from current viewpoint.
2631     if (viewx <= bspcoord[BOXLEFT])
2632         boxpos = 0;
2633     else if (viewx < bspcoord[BOXRIGHT])
2634         boxpos = 1;
2635     else
2636         boxpos = 2;
2637 
2638     if (viewy >= bspcoord[BOXTOP])
2639         boxpos |= 0;
2640     else if (viewy > bspcoord[BOXBOTTOM])
2641         boxpos |= 1 << 2;
2642     else
2643         boxpos |= 2 << 2;
2644 
2645     if (boxpos == 5)
2646         return true;
2647 
2648     x1 = bspcoord[checkcoord[boxpos][0]];
2649     y1 = bspcoord[checkcoord[boxpos][1]];
2650     x2 = bspcoord[checkcoord[boxpos][2]];
2651     y2 = bspcoord[checkcoord[boxpos][3]];
2652 
2653     // check clip list for an open space
2654     // Angles here increase to the left.
2655     angle1 = R_PointToAngle(x1, y1) - dup_viewangle;  // left
2656     angle2 = R_PointToAngle(x2, y2) - dup_viewangle;  // right
2657 
2658     span = angle1 - angle2;  // normally span > 0, (angle1 > angle2)
2659 
2660     // Sitting on a line?
2661     if (span >= ANG180)
2662         return true;
2663 
2664     // angle1, angle2 may range from ANG270 to ANG90, unsigned.
2665     // Because of angle wrap, must contrive tests away from 0.
2666     if ((gr_clipangle + angle1) > gr_clipangle_x_2) // (angle1 > clipangle)
2667     {
2668         // Totally off the left edge?
2669         if ((angle1 - gr_clipangle) >= span)  // (angle1 - clipangle) >= (angle1 - angle2)
2670             return false;    // angle2 >= clipangle
2671 
2672         angle1 = gr_clipangle;
2673     }
2674     if ((gr_clipangle - angle2) > gr_clipangle_x_2)  // (angle2 < -clipangle)
2675     {
2676         // Totally off the right edge?
2677         if ((-angle2 - gr_clipangle) >= span)  //  (-angle2 - clipangle) >= (angle1 - angle2)
2678             return false;    // angle1 <= -clipangle
2679 
2680         angle2 = -gr_clipangle;
2681     }
2682 
2683     // Find the first clippost that touches the source post
2684     //  (adjacent pixels are touching).
2685     sx1 = gr_viewangle_to_x[ ANGLE_TO_FINE(angle1 + ANG90) ];
2686     sx2 = gr_viewangle_to_x[ ANGLE_TO_FINE(angle2 + ANG90) ];
2687 
2688     // Does not cross a pixel.
2689     if (sx1 == sx2)
2690         return false;
2691 
2692     return HWR_ClipToSolidSegs(sx1, sx2 - 1);
2693 }
2694 
2695 
2696 // -----------------+
2697 // HWR_Subsector    : Determine floor/ceiling planes.
2698 //                  : Add sprites of things in sector.
2699 //                  : Draw one or more line segments.
2700 // Notes            : Sets gr_cursectorlight to the light of the parent sector, to modulate wall textures
2701 // -----------------+
2702 #ifdef DCK_WATER_TEST
2703 static lumpnum_t  doomwaterflat;       //set by R_Init_Flats hack
2704 #endif
2705 static byte  need_sky_background;
2706 
2707 // Called from HWR_RenderBSPNode
2708 //  num : subsector number
HWR_Subsector(int num)2709 static void HWR_Subsector(int num)
2710 {
2711     int segcount;
2712     seg_t * lineseg;
2713     subsector_t *sub;
2714     sector_t tempsec;           //SoM: 4/7/2000
2715     lightlev_t  floorlightlevel;
2716     lightlev_t  ceilinglightlevel;
2717     int locFloorHeight, locCeilingHeight;
2718     extracolormap_t * floorcolormap = NULL, * ceilingcolormap = NULL;
2719 
2720 //no risk while developing, enough debugging nights!
2721 #ifdef PARANOIA
2722     if (num >= num_poly_subsector)
2723         I_Error("HWR_Subsector: ss %i with numss = %i, extrass = %d", num, numsubsectors, num_poly_subsector);
2724 
2725     /*
2726        if (num>=numsubsectors)
2727        I_Error ("HWR_Subsector: ss %i with numss = %i",
2728        num,
2729        numsubsectors );
2730      */
2731 #endif
2732 
2733     if (num < numsubsectors)
2734     {
2735         sscount++;
2736         // subsector
2737         sub = &subsectors[num];
2738         // sector
2739         gr_frontsector = sub->sector;
2740         // how many linedefs
2741         segcount = sub->numlines;
2742         // first line seg
2743         lineseg = &segs[sub->firstline];
2744     }
2745     else
2746     {
2747         // there are no segs but only planes
2748         sub = &subsectors[0];
2749         gr_frontsector = sub->sector;
2750         segcount = 0;
2751         lineseg = NULL;
2752     }
2753 
2754     //SoM: 4/7/2000: Test to make Boom water work in Hardware mode.
2755     gr_frontsector = R_FakeFlat(gr_frontsector, &tempsec, false,
2756                                 /*OUT*/ &floorlightlevel, &ceilinglightlevel );
2757     //FIXME: Use floorlightlevel and ceilinglightlevel insted of lightlevel.
2758 
2759     // ------------------------------------------------------------------------
2760     // sector lighting, DISABLED because it's done in HWR_StoreWallRange
2761     // ------------------------------------------------------------------------
2762     // TODO : store a RGBA instead of just intensity, allow coloured sector lighting
2763     //light = (byte)(sub->sector->lightlevel & 0xFF) / 255.0f;
2764     //gr_cursectorlight.red   = light;
2765     //gr_cursectorlight.green = light;
2766     //gr_cursectorlight.blue  = light;
2767     //gr_cursectorlight.alpha = light;
2768 
2769 // ----- for special tricks with HW renderer -----
2770     if (gr_frontsector->pseudoSector)
2771     {
2772         locFloorHeight = gr_frontsector->virtualFloorheight;
2773         locCeilingHeight = gr_frontsector->virtualCeilingheight;
2774     }
2775     else if (gr_frontsector->virtualFloor)
2776     {
2777         locFloorHeight = gr_frontsector->virtualFloorheight;
2778         if (gr_frontsector->virtualCeiling)
2779             locCeilingHeight = gr_frontsector->virtualCeilingheight;
2780         else
2781             locCeilingHeight = gr_frontsector->ceilingheight;
2782     }
2783     else if (gr_frontsector->virtualCeiling)
2784     {
2785         locCeilingHeight = gr_frontsector->virtualCeilingheight;
2786         locFloorHeight = gr_frontsector->floorheight;
2787     }
2788     else
2789     {
2790         locFloorHeight = gr_frontsector->floorheight;
2791         locCeilingHeight = gr_frontsector->ceilingheight;
2792     }
2793 // ----- end special tricks -----
2794 
2795     if (gr_frontsector->ffloors)
2796     {
2797         if (gr_frontsector->moved)
2798         {
2799             gr_frontsector->numlights = sub->sector->numlights = 0;
2800             R_Prep3DFloors(gr_frontsector);
2801             sub->sector->lightlist = gr_frontsector->lightlist;
2802             sub->sector->numlights = gr_frontsector->numlights;
2803             sub->sector->moved = gr_frontsector->moved = false;
2804         }
2805 
2806         // [WDJ] from r_bsp.c 4/22/2010
2807         // adapted to local vars, and may still need a little tuning
2808 //      R_GetPlaneLight(gr_frontsector, gr_frontsector->floorheight);
2809         ff_light_t * ff_light = R_GetPlaneLight(gr_frontsector, locFloorHeight);
2810         if(gr_frontsector->floorlightsec < 0)
2811         {
2812           floorlightlevel = *ff_light->lightlevel;
2813           floorcolormap = ff_light->extra_colormap;
2814         }
2815 //      R_GetPlaneLight(gr_frontsector, gr_frontsector->ceilingheight);
2816         ff_light = R_GetPlaneLight(gr_frontsector, locCeilingHeight);
2817         if(gr_frontsector->ceilinglightsec < 0)
2818         {
2819           ceilinglightlevel = *ff_light->lightlevel;
2820           ceilingcolormap = ff_light->extra_colormap;
2821         }
2822     }
2823 
2824     sub->sector->extra_colormap = gr_frontsector->extra_colormap;
2825 
2826     // Render floor.
2827     // yeah, easy backface cull! :)
2828     if (locFloorHeight < viewz)
2829     {
2830         if (gr_frontsector->floorpic != sky_flatnum)
2831         {
2832             if (sub->validcount != validcount)
2833             {
2834                 HWR_GetFlat(levelflats[gr_frontsector->floorpic].lumpnum);
2835                 HWR_RenderPlane(&poly_subsectors[num], locFloorHeight, PF_Occlude,
2836                                 floorcolormap, floorlightlevel,
2837                                 gr_frontsector->floorpic);
2838             }
2839         }
2840         else
2841         {
2842             // Sky as floor.
2843 #ifdef POLYSKY
2844             HWR_RenderSkyPlane(&poly_subsectors[num], locFloorHeight);
2845 #endif
2846             need_sky_background |= DSB_lower;
2847         }
2848     }
2849 
2850     if (locCeilingHeight > viewz)
2851     {
2852         if (gr_frontsector->ceilingpic != sky_flatnum)
2853         {
2854             if (sub->validcount != validcount)
2855             {
2856                 HWR_GetFlat(levelflats[gr_frontsector->ceilingpic].lumpnum);
2857                 HWR_RenderPlane(&poly_subsectors[num], locCeilingHeight, PF_Occlude,
2858                                 ceilingcolormap, ceilinglightlevel,
2859                                 gr_frontsector->ceilingpic);
2860             }
2861         }
2862         else
2863         {
2864             // Sky as ceiling.
2865 #ifdef POLYSKY
2866             HWR_RenderSkyPlane(&poly_subsectors[num], locCeilingHeight);
2867 #endif
2868             need_sky_background |= DSB_upper;
2869         }
2870     }
2871 
2872 #ifdef R_FAKEFLOORS
2873     if (gr_frontsector->ffloors)
2874     {
2875         // TODO:fix light, xoffs, yoffs, extracolormap ?
2876         ffloor_t *fff;
2877 
2878         R_Prep3DFloors(gr_frontsector);
2879         for (fff = gr_frontsector->ffloors; fff; fff = fff->next)
2880         {
2881             if (!(fff->flags & (FF_OUTER_PLANES|FF_INNER_PLANES))
2882                 || !(fff->flags & FF_EXISTS))
2883                 continue;
2884             if (sub->validcount == validcount)
2885                 continue;
2886 
2887             if (*fff->bottomheight <= gr_frontsector->ceilingheight
2888                 && *fff->bottomheight >= gr_frontsector->floorheight
2889 //                && ((viewz < *fff->bottomheight && (fff->flags & FF_OUTER_PLANES))
2890                 && ((viewz <= *fff->bottomheight && (fff->flags & FF_OUTER_PLANES))
2891                     || (viewz > *fff->bottomheight && (fff->flags & FF_INNER_PLANES))))
2892             {
2893                 if (fff->flags & (FF_TRANSLUCENT | FF_FOG))   // SoM: Flags are more efficient
2894                 {
2895                     ff_light_t * ff_light =
2896                       R_GetPlaneLight_viewz(gr_frontsector, *fff->bottomheight);
2897                     HWR_Add3DWater(*fff->bottompic, &poly_subsectors[num],
2898                                    *fff->bottomheight, *ff_light->lightlevel,
2899                                    fff->alpha);
2900                 }
2901                 else
2902                 {
2903                     HWR_GetFlat(levelflats[*fff->bottompic].lumpnum);
2904                     ff_light_t * ff_light =
2905                       R_GetPlaneLight_viewz(gr_frontsector, *fff->bottomheight);
2906                     HWR_RenderPlane(&poly_subsectors[num], *fff->bottomheight,
2907                                     PF_Occlude, NULL,
2908                                     *ff_light->lightlevel,
2909                                     *fff->bottompic);
2910                 }
2911             }
2912             if (*fff->topheight >= gr_frontsector->floorheight
2913                 && *fff->topheight <= gr_frontsector->ceilingheight
2914 //                && ((viewz > *fff->topheight && (fff->flags & FF_OUTER_PLANES))
2915                 && ((viewz >= *fff->topheight && (fff->flags & FF_OUTER_PLANES))
2916                     || (viewz < *fff->topheight && (fff->flags & FF_INNER_PLANES))))
2917             {
2918                 if (fff->flags & (FF_TRANSLUCENT | FF_FOG))
2919                 {
2920                     ff_light_t * ff_light =
2921                       R_GetPlaneLight_viewz(gr_frontsector, *fff->topheight);
2922                     HWR_Add3DWater(*fff->toppic, &poly_subsectors[num],
2923                                    *fff->topheight, *ff_light->lightlevel,
2924                                    fff->alpha);
2925                 }
2926                 else
2927                 {
2928                     HWR_GetFlat(levelflats[*fff->toppic].lumpnum);
2929                     ff_light_t * ff_light =
2930                       R_GetPlaneLight_viewz(gr_frontsector, *fff->topheight);
2931                     HWR_RenderPlane(&poly_subsectors[num], *fff->topheight,
2932                                     PF_Occlude, NULL,
2933                                     *ff_light->lightlevel,
2934                                     *fff->toppic);
2935                 }
2936             }
2937 
2938         }
2939     }
2940 #endif
2941 
2942 // Hurder ici se passe les choses int�ressantes!
2943 // on vient de tracer le sol et le plafond
2944 // on trace � pr�sent d'abord les sprites et ensuite les murs
2945 // hurdler: faux: on ajoute seulement les sprites, le murs sont trac�s d'abord
2946     if (lineseg != NULL)
2947     {
2948         // draw sprites first , coz they are clipped to the solidsegs of
2949         // subsectors more 'in front'
2950         HWR_AddSprites(gr_frontsector, tempsec.lightlevel);  // ???
2951 //	HWR_AddSprites(gr_frontsector, gr_frontsector->lightlevel);  // ???
2952 
2953         //Hurdler: at this point validcount must be the same, but is not because
2954         //         gr_frontsector doesn't point anymore to sub->sector due to
2955         //         the call gr_frontsector = R_FakeFlat(...)
2956         //         if it's not done, the sprite is drawn more than once,
2957         //         what looks really bad with translucency or dynamic light,
2958         //         without talking about the overdraw of course.
2959         sub->sector->validcount = validcount;   //TODO: fix that in a better way
2960 
2961         while (segcount--)
2962         {
2963             HWR_AddLine(lineseg);
2964             lineseg++;
2965         }
2966     }
2967 
2968 #ifdef DCK_WATER_TEST
2969 // DCK: an obsolete editor for DOS and Win95.
2970 // It only allowed linedefs 0..255, which prevented creating water sectors.
2971 //20/08/99: Changed by Hurdler (taken from faB's code)
2972     // -------------------- WATER IN DEV. TEST ------------------------
2973     //dck hack : use abs(tag) for waterheight
2974     if (gr_frontsector->tag < 0)
2975     {
2976         fixed_t wh;
2977         wh = ((-gr_frontsector->tag) << 16) + (FRACUNIT / 2);
2978         if (wh > gr_frontsector->floorheight && wh < gr_frontsector->ceilingheight)
2979         {
2980             HWR_GetFlat(doomwaterflat_pic.lumpnum);
2981             HWR_RenderPlane(&poly_subsectors[num], wh, PF_Translucent,
2982                             NULL, gr_frontsector->lightlevel, doomwaterflat_pic);
2983         }
2984     }
2985     // -------------------- WATER IN DEV. TEST ------------------------
2986 #endif
2987 
2988     sub->validcount = validcount;
2989 }
2990 
2991 //
2992 // Renders all subsectors below a given node,
2993 //  traversing subtree recursively.
2994 // Just call with BSP root.
2995 
2996 #ifdef coolhack
2997 //t;b;l;r
2998 static fixed_t hackbbox[4];
2999 //BOXTOP,
3000 //BOXBOTTOM,
3001 //BOXLEFT,
3002 //BOXRIGHT
HWR_CheckHackBBox(fixed_t * bb)3003 static boolean HWR_CheckHackBBox(fixed_t * bb)
3004 {
3005     if (bb[BOXTOP] < hackbbox[BOXBOTTOM])       //y up
3006         return false;
3007     if (bb[BOXBOTTOM] > hackbbox[BOXTOP])
3008         return false;
3009     if (bb[BOXLEFT] > hackbbox[BOXRIGHT])
3010         return false;
3011     if (bb[BOXRIGHT] < hackbbox[BOXLEFT])
3012         return false;
3013     return true;
3014 }
3015 #endif
3016 
3017 // BP: big hack for a test in lighning ref:1249753487AB
3018 int *bbox;
3019 
3020 // Recursive walk through BSP tree.
3021 // Called from HWR_RenderPlayerView.
HWR_RenderBSPNode(int bspnum)3022 static void HWR_RenderBSPNode(int bspnum)
3023 {
3024     node_t *bsp;
3025     unsigned int  side;  // 0, 1
3026     unsigned int  subsecnum;  // subsector index
3027 
3028     // [WDJ] From EternityEngine, killough 5/2/98: remove tail recursion
3029     while( ! (bspnum & NF_SUBSECTOR) )
3030     {
3031         // not a subsector, a nodes
3032         bsp = &nodes[bspnum];
3033 
3034         // Decide which side the view point is on.
3035         side = R_PointOnSide(viewx, viewy, bsp);
3036 
3037         // BP: big hack for a test in lighning ref:1249753487AB
3038         bbox = bsp->bbox[side];
3039 
3040         // Recursively divide front space.
3041         HWR_RenderBSPNode(bsp->children[side]);
3042 
3043         // Possibly divide back space.
3044         side = side ^ 0x0001; // XOR bit0, other side
3045         if (! HWR_CheckBBox(bsp->bbox[side]))
3046             return;  // Not in back space
3047 
3048         // BP: big hack for a test in lighning ref:1249753487AB
3049         bbox = bsp->bbox[side];
3050         // [WDJ] Convert tail recursion to loop.
3051         // This does HWR_RenderBSPNode(bsp->children[side]);
3052         bspnum = bsp->children[side];
3053     }
3054 
3055     // Found a subsector
3056     subsecnum = bspnum & (~NF_SUBSECTOR);
3057     if( subsecnum >= numsubsectors )  goto bad_subsector;
3058     //*(gr_drawsubsector_p++) = subsecnum;
3059     HWR_Subsector(subsecnum);
3060     return;
3061 
3062 bad_subsector:
3063     // Error situations, should not get here.
3064     if (bspnum == -1)
3065     {
3066         // [WDJ] Degenerate map with no nodes.
3067         //*(gr_drawsubsector_p++) = 0;
3068         HWR_Subsector(0);
3069     }
3070 }
3071 
3072 /*
3073 //
3074 // Clear 'stack' of subsectors to draw
3075 //
3076 static void HWR_Clear_DrawSubsectors (void)
3077 {
3078     gr_drawsubsector_p = gr_drawsubsectors;
3079 }
3080 
3081 //
3082 // Draw subsectors pushed on the drawsubsectors 'stack', back to front
3083 //
3084 static void HWR_RenderSubsectors (void)
3085 {
3086     while (gr_drawsubsector_p > gr_drawsubsectors)
3087     {
3088         HWR_RenderBSPNode (
3089         lastsubsec->nextsubsec = bspnum & (~NF_SUBSECTOR);
3090     }
3091 }
3092 */
3093 
3094 // ==========================================================================
3095 //                                                              FROM R_MAIN.C
3096 // ==========================================================================
3097 
3098 #ifdef NO_MLOOK_EXTENDS_FOV
3099 static angle_t anglefov = FIELDOFVIEW;
3100 #endif
3101 
3102 //BP : exactly the same as R_Init_TextureMapping
3103 // Called from r_main:R_ExecuteSetViewSize
HWR_Init_TextureMapping(void)3104 void HWR_Init_TextureMapping(void)
3105 {
3106     int i;
3107     int x;
3108     int t;
3109     fixed_t focallength;
3110 
3111     fixed_t grcenterx;
3112     fixed_t grcenterxfrac;
3113     int grviewwidth;
3114 #ifdef NO_MLOOK_EXTENDS_FOV
3115     angle_t clipanglefov;
3116     static angle_t oldclipanglefov = 0;
3117 
3118     clipanglefov = anglefov + 2 * abs((int) aimingangle);
3119     if (clipanglefov == oldclipanglefov)  // same as before
3120         return;
3121     oldclipanglefov = clipanglefov;
3122     int fov_angf = ANGLE_TO_FINE( clipanglefov );
3123     // [WDJ] ANGLE_1 has significant round-off error, but in this usage it does not matter.
3124     if (fov_angf >= ANGLE_TO_FINE(ANG180 - ANGLE_1))
3125         fov_angf = ANGLE_TO_FINE(ANG180 - ANGLE_1);
3126 
3127     CONS_Printf("HW_InitTextureMapping() %d %d %d\n",
3128                 fov_angf, ANGLE_TO_FINE(aimingangle), ANGLE_TO_FINE(anglefov) );
3129 #else
3130 #define fov_angf  ANGLE_TO_FINE(FIELDOFVIEW)
3131 #endif
3132     grviewwidth = vid.width;
3133     grcenterx = grviewwidth / 2;
3134     grcenterxfrac = grcenterx << FRACBITS;
3135 
3136     // Use tangent table to generate viewangle_to_x:
3137     //  viewangle_to_x will give the next greatest x
3138     //  after the view angle.
3139     //
3140     // Calc focallength
3141     //  so FIELDOFVIEW angles covers SCREENWIDTH.
3142     focallength = FixedDiv(grcenterxfrac, finetangent[(fov_angf/2) + FINE_ANG90]);
3143 
3144     for (i = 0; i < FINE_ANG180; i++)
3145     {
3146         if (finetangent[i] > FRACUNIT * 2)
3147             t = -1;
3148         else if (finetangent[i] < -FRACUNIT * 2)
3149             t = grviewwidth + 1;
3150         else
3151         {
3152             t = FixedMul(finetangent[i], focallength);
3153             t = (grcenterxfrac - t + FRACUNIT - 1) >> FRACBITS;
3154 
3155             if (t < -1)
3156                 t = -1;
3157             else if (t > grviewwidth + 1)
3158                 t = grviewwidth + 1;
3159         }
3160         gr_viewangle_to_x[i] = t;
3161     }
3162 
3163     // Scan viewangle_to_x[] to generate x_to_viewangle[]:
3164     //  x_to_viewangle will give the smallest view angle
3165     //  that maps to x.
3166     for (x = 0; x <= grviewwidth; x++)
3167     {
3168         i = 0;
3169         while (gr_viewangle_to_x[i] > x)
3170             i++;
3171         gr_x_to_viewangle[x] = (i << ANGLETOFINESHIFT) - ANG90;
3172     }
3173 
3174     // Take out the fencepost cases from viewangle_to_x.
3175     for (i = 0; i < FINE_ANG180; i++)
3176     {
3177         if (gr_viewangle_to_x[i] == -1)
3178             gr_viewangle_to_x[i] = 0;
3179         else if (gr_viewangle_to_x[i] == grviewwidth + 1)
3180             gr_viewangle_to_x[i] = grviewwidth;
3181     }
3182 
3183     gr_clipangle = gr_x_to_viewangle[0];
3184     gr_clipangle_x_2 = gr_clipangle + gr_clipangle;
3185 }
3186 
3187 // ==========================================================================
3188 // gr_things.c
3189 // ==========================================================================
3190 
3191 // sprites are drawn after all wall and planes are rendered, so that
3192 // sprite translucency effects apply on the rendered view (instead of the background sky!!)
3193 
3194 gr_vissprite_t gr_vissprites[MAXVISSPRITES];
3195 gr_vissprite_t *gr_vissprite_p;
3196 
3197 // --------------------------------------------------------------------------
3198 // HWR_Clear_Sprites
3199 // Called at frame start.
3200 // --------------------------------------------------------------------------
HWR_Clear_Sprites(void)3201 static void HWR_Clear_Sprites(void)
3202 {
3203     gr_vissprite_p = gr_vissprites;
3204 }
3205 
3206 // --------------------------------------------------------------------------
3207 // HWR_NewVisSprite
3208 // --------------------------------------------------------------------------
3209 gr_vissprite_t gr_overflowsprite;
3210 
HWR_NewVisSprite(void)3211 gr_vissprite_t *HWR_NewVisSprite(void)
3212 {
3213     if (gr_vissprite_p == &gr_vissprites[MAXVISSPRITES])
3214         return &gr_overflowsprite;
3215 
3216     gr_vissprite_p++;
3217     return gr_vissprite_p - 1;
3218 }
3219 
3220 // -----------------+
3221 // HWR_DrawSprite   : Draw flat sprites
3222 //                  : (monsters, bonuses, weapons, lights, ...)
3223 // Returns          :
3224 // -----------------+
HWR_DrawSprite(gr_vissprite_t * spr)3225 static void HWR_DrawSprite(gr_vissprite_t * spr)
3226 {
3227     byte lightlum;  // 0..255
3228     vxtx3d_t vxtx[4];
3229     MipPatch_t *gpatch;       //sprite patch converted to hardware
3230     FSurfaceInfo_t Surf;
3231 
3232     // cache sprite graphics
3233     //12/12/99: Hurdler:
3234     //          OK, I don't change anything for MD2 support because I want to be
3235     //          sure to do it the right way. So actually, we keep normal sprite
3236     //          in memory and we add the md2 model if it exists for that sprite
3237 
3238     // convert sprite differently when fxtranslucent is detected
3239     Surf.polyflags = 0;
3240     Surf.texflags = 0;
3241     if ((spr->mobj->frame & FF_TRANSMASK) == (TRANSLU_fx1<<FF_TRANSSHIFT))
3242     {
3243         Surf.texflags = TF_Opaquetrans;
3244     }
3245     // get patch and draw to hardware cache
3246     gpatch = W_CacheMappedPatchNum(spr->patch_lumpnum, Surf.texflags );
3247 
3248     // dynamic lighting
3249     HWR_DL_AddLightSprite(spr, gpatch);
3250 
3251     // create the sprite billboard
3252     //
3253     //  3--2
3254     //  | /|
3255     //  |/ |
3256     //  0--1
3257 
3258     // fastest, use transform terms in optimized shared code
3259     // Combined transforms for look up/down and scaling
3260     float topty = spr->ty - gpatch->height;
3261     vxtx[0].x = vxtx[3].x = (spr->x1 * sprite_trans_x_to_x);
3262     vxtx[1].x = vxtx[2].x = (spr->x2 * sprite_trans_x_to_x);
3263     float tranzy = spr->tz * sprite_trans_z_to_y;
3264     vxtx[0].y = vxtx[1].y = (topty * sprite_trans_y_to_y) + tranzy;
3265     vxtx[2].y = vxtx[3].y = (spr->ty * sprite_trans_y_to_y) + tranzy;
3266     float tranzz = spr->tz * sprite_trans_z_to_z;
3267     vxtx[0].z = vxtx[1].z = (topty * sprite_trans_y_to_z) + tranzz;
3268     vxtx[2].z = vxtx[3].z = (spr->ty * sprite_trans_y_to_z) + tranzz;
3269 
3270     if (spr->flip)
3271     {
3272         vxtx[0].sow = vxtx[3].sow = gpatch->max_s;
3273         vxtx[2].sow = vxtx[1].sow = 0;
3274     }
3275     else
3276     {
3277         vxtx[0].sow = vxtx[3].sow = 0;
3278         vxtx[2].sow = vxtx[1].sow = gpatch->max_s;
3279     }
3280     vxtx[3].tow = vxtx[2].tow = 0;
3281     vxtx[0].tow = vxtx[1].tow = gpatch->max_t;
3282 
3283     // cache the patch in the graphics card memory
3284     //12/12/99: Hurdler: same comment as above (for md2)
3285     //Hurdler: 25/04/2000: now support colormap in hardware mode
3286     HWR_GetMappedPatch(gpatch, spr->colormap);
3287 
3288     // sprite (TODO: coloured-) lighting by modulating the RGB components
3289     // [WDJ] coloured seems to be done below
3290     lightlum = spr->sectorlight;
3291     Surf.FlatColor.s.red = Surf.FlatColor.s.green = Surf.FlatColor.s.blue = lightlum;
3292 
3293     //Hurdler: colormap test
3294     if (!fixedcolormap)
3295     {
3296         sector_t *sector = spr->mobj->subsector->sector;
3297 
3298         if (sector->ffloors)
3299         {
3300             ffloor_t *caster =
3301               R_GetPlaneLight(sector, spr->mobj->z)->caster;
3302             sector = caster ? &sectors[caster->model_secnum] : sector;
3303         }
3304         if (sector->extra_colormap || view_extracolormap)
3305         {
3306             Extracolormap_to_Surf( /*IN*/ sector->extra_colormap, lightlum,
3307                                    /*OUT*/ & Surf );
3308         }
3309     }
3310 
3311     //TODO: do the test earlier
3312     if (!cv_grmd2.value || (md2_models[spr->mobj->sprite].scale < 0.0f))
3313     {
3314         int blend = 0;
3315         if (spr->mobj->frame & FF_TRANSMASK)
3316             blend = HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK) >> FF_TRANSSHIFT, &Surf);
3317         else if (spr->mobj->frame & FF_SMOKESHADE)
3318         {
3319             Surf.FlatColor.s.alpha = 0x80;
3320             blend = PF_Translucent;
3321         }
3322         else if (spr->mobj->flags & MF_SHADOW)
3323         {
3324             Surf.FlatColor.s.alpha = 0x40;
3325             blend = PF_Translucent;
3326         }
3327         else
3328         {
3329             // BP: i agree that is little better in environment but it don't
3330             //     work properly under glide nor with fogcolor to ffffff :(
3331             // Hurdler: PF_Environment would be cool, but we need to fix
3332             //          the issue with the fog before
3333             Surf.FlatColor.s.alpha = 0xFF;
3334             blend = PF_Translucent | PF_Occlude;
3335         }
3336 
3337         HWD.pfnDrawPolygon(&Surf, vxtx, 4, blend | PF_Modulated | PF_Clip);
3338     }
3339 
3340     // draw a corona if this sprite contain light(s)
3341 #ifdef SPDR_CORONAS
3342 #ifdef CORONA_CHOICE
3343     if( corona_draw_choice == 1 )
3344 #else
3345     if( cv_corona.EV )
3346 #endif
3347     {
3348         HWR_DoCoronasLighting(vxtx, spr);
3349     }
3350 #endif
3351 }
3352 
3353 // --------------------------------------------------------------------------
3354 // Sort vissprites by distance
3355 // --------------------------------------------------------------------------
3356 static gr_vissprite_t gr_vsprsortedhead;
3357 
HWR_SortVisSprites(void)3358 static void HWR_SortVisSprites(void)
3359 {
3360     int i;
3361     int count;
3362     gr_vissprite_t *ds;
3363     gr_vissprite_t *best = NULL;        //shut up compiler
3364     gr_vissprite_t unsorted;
3365     float bestdist;
3366 
3367     count = gr_vissprite_p - gr_vissprites;
3368 
3369     unsorted.next = unsorted.prev = &unsorted;
3370 
3371     if (!count)
3372         return;
3373 
3374     for (ds = gr_vissprites; ds < gr_vissprite_p; ds++)
3375     {
3376         ds->next = ds + 1;
3377         ds->prev = ds - 1;
3378     }
3379 
3380     gr_vissprites[0].prev = &unsorted;
3381     unsorted.next = &gr_vissprites[0];
3382     (gr_vissprite_p - 1)->next = &unsorted;
3383     unsorted.prev = gr_vissprite_p - 1;
3384 
3385     // pull the vissprites out by scale
3386     gr_vsprsortedhead.next = gr_vsprsortedhead.prev = &gr_vsprsortedhead;
3387     for (i = 0; i < count; i++)
3388     {
3389         bestdist = SPRITE_NEAR_CLIP_DIST - 1;
3390         for (ds = unsorted.next; ds != &unsorted; ds = ds->next)
3391         {
3392             if (ds->tz > bestdist)
3393             {
3394                 bestdist = ds->tz;
3395                 best = ds;
3396             }
3397         }
3398         best->next->prev = best->prev;
3399         best->prev->next = best->next;
3400         best->next = &gr_vsprsortedhead;
3401         best->prev = gr_vsprsortedhead.prev;
3402         gr_vsprsortedhead.prev->next = best;
3403         gr_vsprsortedhead.prev = best;
3404     }
3405 }
3406 
3407 
3408 // --------------------------------------------------------------------------
3409 //  Draw all MD2
3410 // --------------------------------------------------------------------------
HWR_DrawMD2S(void)3411 static void HWR_DrawMD2S(void)
3412 {
3413     if (gr_vissprite_p > gr_vissprites)
3414     {
3415         gr_vissprite_t *spr;
3416 
3417         // draw all MD2 back to front
3418         for (spr = gr_vsprsortedhead.next; spr != &gr_vsprsortedhead; spr = spr->next)
3419         {
3420             HWR_DrawMD2(spr);
3421         }
3422     }
3423 }
3424 
3425 // --------------------------------------------------------------------------
3426 // HWR_AddSprites
3427 // During BSP traversal, this adds sprites by sector.
3428 // --------------------------------------------------------------------------
3429 static byte  sectorlight;  // Lum
3430 // Does not need separate lightlevel as long as it is called with frontsector.
HWR_AddSprites(sector_t * sec,lightlev_t sprite_lightlevel)3431 static void HWR_AddSprites(sector_t * sec, lightlev_t sprite_lightlevel)
3432 {
3433     mobj_t *thing;
3434 
3435     // BSP is traversed by subsector.
3436     // A sector might have been split into several
3437     //  subsectors during BSP building.
3438     // Thus we check whether its already added.
3439     if (sec->validcount == validcount)
3440         return;
3441 
3442     // Well, now it will be done.
3443     sec->validcount = validcount;
3444 
3445     // sprite lighting
3446     if(!sec->numlights) // when numlights then light in DrawSprite
3447     {
3448       lightlev_t lightlevel = sprite_lightlevel;
3449       if(sec->model < SM_fluid)   lightlevel = sec->lightlevel;
3450       sectorlight = LightLevelToLum(lightlevel); // add extra light
3451     }
3452 
3453     // Handle all things in sector.
3454     for (thing = sec->thinglist; thing; thing = thing->snext)
3455     {
3456         if ((thing->flags2 & MF2_DONTDRAW) == 0)
3457             HWR_ProjectSprite(thing);
3458     }
3459 }
3460 
3461 // --------------------------------------------------------------------------
3462 // HWR_ProjectSprite
3463 //  Generates a vissprite for a thing if it might be visible.
3464 // --------------------------------------------------------------------------
3465 // BP why not use x_to_viewangle/viewangle_to_x like in bsp ?....
HWR_ProjectSprite(mobj_t * thing)3466 static void HWR_ProjectSprite(mobj_t * thing)
3467 {
3468     gr_vissprite_t *vis;
3469 
3470     float tr_x, tr_y;
3471     float tx, tz;
3472     float tx1, tx2;  // edges
3473     float px1, px2;  // projected
3474 
3475     spritedef_t * sprdef;
3476     spriteframe_t * sprframe;
3477     sprite_frot_t * sprfrot;
3478     spritelump_t * sprlump;
3479     unsigned int rot, fr;
3480     angle_t ang;
3481 
3482     // Calculate view of sprite, relative to player, in world dimensions.
3483     // transform the origin point
3484     tr_x = FIXED_TO_FLOAT( thing->x ) - gr_viewx;  // relative position
3485     tr_y = FIXED_TO_FLOAT( thing->y ) - gr_viewy;
3486 
3487     // rotation around vertical axis
3488     tz = (tr_x * gr_viewcos) + (tr_y * gr_viewsin);  // view depth
3489 
3490     // thing is behind view plane?
3491     if (tz < SPRITE_NEAR_CLIP_DIST)
3492         return;
3493 
3494     tx = (tr_x * gr_viewsin) - (tr_y * gr_viewcos);  // view x
3495 
3496     // decide which patch to use for sprite relative to player
3497 #ifdef RANGECHECK
3498     if ((unsigned) thing->sprite >= numsprites)
3499     {
3500         I_SoftError("HWR_ProjectSprite: invalid sprite number %i ", thing->sprite);
3501         return;
3502     }
3503 #endif
3504 
3505     //Fab:02-08-98: 'skin' override spritedef currently used for skin
3506     if (thing->skin)
3507         sprdef = &((skin_t *) thing->skin)->spritedef;
3508     else
3509         sprdef = &sprites[thing->sprite];
3510 
3511     fr = thing->frame & FF_FRAMEMASK;
3512 #ifdef RANGECHECK
3513     if(fr >= sprdef->numframes)
3514     {
3515         I_SoftError("HWR_ProjectSprite: invalid sprite frame %i : %i for %s",
3516                     thing->sprite, thing->frame, sprnames[thing->sprite]);
3517         return;
3518     }
3519 #endif
3520     sprframe = get_spriteframe( sprdef, fr );
3521 
3522     if( sprframe->rotation_pattern == SRP_1 )
3523     {
3524         // use single rotation for all views
3525         rot = 0;                        //Fab: for vis->patch below
3526     }
3527     else
3528     {
3529         // choose a different rotation based on player view
3530         ang = R_PointToAngle(thing->x, thing->y);       // uses viewx,viewy
3531 
3532         if( sprframe->rotation_pattern == SRP_8)
3533         {
3534             // 8 direction rotation pattern
3535             rot = (ang - thing->angle + (unsigned) (ANG45/2) * 9) >> 29;
3536         }
3537 #ifdef ROT16
3538         else if( sprframe->rotation_pattern == SRP_16)
3539         {
3540             // 16 direction rotation pattern
3541             rot = (ang - thing->angle + (unsigned) (ANG45/4) * 17) >> 28;
3542         }
3543 #endif
3544         else return;
3545 
3546     }
3547 
3548     sprfrot = get_framerotation( sprdef, fr, rot );
3549 
3550     //Fab: [WDJ] spritelump_id is the index
3551     sprlump = &spritelumps[sprfrot->spritelump_id];
3552 
3553     // The sprite patch is in world dimensions, offsets in world dimensions.
3554     // calculate edges of the shape
3555     tx1 = tx - FIXED_TO_FLOAT( sprlump->leftoffset );
3556 
3557     // project x
3558     px1 = gr_windowcenterx + (tx1 * gr_centerx / tz);
3559 
3560     // BP: FOV des sprites, c'est ici que sa ce passe
3561     // left edge off the right side?
3562 #ifdef NO_MLOOK_EXTENDS_FOV
3563     if (px1 > gr_viewwidth)
3564 #else
3565     if ((px1 > gr_viewwidth) && !cv_grmlook_extends_fov.value)
3566         //if ((px1 > gr_viewwidth) && (cv_grfov.value<=90) /*&& !cv_grmd2.value*/)
3567 #endif
3568         return;
3569 
3570     tx2 = tx1 + FIXED_TO_FLOAT( sprlump->width );
3571     px2 = gr_windowcenterx + (tx2 * gr_centerx / tz);
3572 
3573     // BP: FOV des sprites, ici aussi
3574     // right edge off the left side
3575 #ifdef NO_MLOOK_EXTENDS_FOV
3576     if (px2 < 0)
3577 #else
3578     if ((px2 < 0) && !cv_grmlook_extends_fov.value)
3579         //if ((px2 < 0) && (cv_grfov.value<=90) /*&& !cv_grmd2.value*/)
3580 #endif
3581         return;
3582 
3583     // sprite completely hidden ?
3584 #ifdef NO_MLOOK_EXTENDS_FOV
3585     if (!HWR_ClipToSolidSegs((int) px1, (int) px2))
3586 #else
3587     if ((!HWR_ClipToSolidSegs((int) px1, (int) px2)) && !cv_grmlook_extends_fov.value)
3588         //if ((!HWR_ClipToSolidSegs((int)px1,(int)px2)) && (cv_grfov.value<=90) /*&& !cv_grmd2.value*/)
3589 #endif
3590         return;
3591 
3592 #define FEET_IN_GROUND_TOPOFFSET_FIX
3593 #ifdef FEET_IN_GROUND_TOPOFFSET_FIX
3594     // [WDJ] Feet-in-ground adjustment moved here from r_things.
3595     // There it changed topoffset at lump load time, but did not adapt to changing drawmode.
3596     // spritelump is just patch header.
3597     //BP: we cannot use special trick in hardware mode because feet in ground caused by z-buffer
3598     // topoffset may be negative, use signed compare
3599     fixed_t fig_topoffset =
3600         ( (sprlump->topoffset > 0) && (sprlump->topoffset < sprlump->height) )? // not for psprite
3601            // perfect is patch.height but sometime it is too high
3602            min(sprlump->topoffset + (4<<FRACBITS), sprlump->height)
3603          : sprlump->topoffset;
3604 #endif
3605    {
3606    // [WDJ] from r_things.c
3607    // This fixes the thing lighting in special sectors
3608     sector_t*		thingsector;	 // [WDJ] 11/14/2009
3609     int                 thingmodelsec;
3610     boolean	        thing_has_model;  // has a model, such as water
3611 #ifdef FEET_IN_GROUND_TOPOFFSET_FIX
3612     fixed_t  gz_top = thing->z + fig_topoffset;  // Adjusted topoffset.
3613 #else
3614     // Has feet-in-ground problem, due to z-buffer.
3615     fixed_t  gz_top = thing->z + sprlump->topoffset;
3616 #endif
3617     thingsector = thing->subsector->sector;	 // [WDJ] 11/14/2009
3618     if(thingsector->numlights)
3619     {
3620       ff_light_t * ff_light = R_GetPlaneLight(thingsector, gz_top);
3621       lightlev_t lightlevel = *ff_light->lightlevel;
3622       if(ff_light->caster && (ff_light->caster->flags & FF_FOG))
3623         sectorlight = LightLevelToLum_extra(lightlevel, extralight_fog); // add extralight
3624       else
3625         sectorlight = LightLevelToLum_extra(lightlevel, 0);  // extralight=0
3626     }
3627 
3628     thingmodelsec = thingsector->modelsec;
3629     thing_has_model = thingsector->model > SM_fluid; // water
3630 
3631     if (thing_has_model)   // only clip things which are in special sectors
3632     {
3633       sector_t * thingmodsecp = & sectors[thingmodelsec];
3634 
3635       // [WDJ] Could use viewer_at_water to force view of objects above and
3636       // below to be seen simultaneously.
3637       // Instead have choosen to have objects underwater not be seen until
3638       // viewer_underwater.
3639       // When at viewer_at_water, will not see objects above nor below the water.
3640       // As this has some validity in reality, and does not generate HOM,
3641       // will live with it.  It is transient, and most players will not notice.
3642       if (viewer_has_model)
3643       {
3644           if( viewer_underwater ?
3645               (thing->z >= thingmodsecp->floorheight)
3646               : (gz_top < thingmodsecp->floorheight)
3647               )
3648               return;
3649           if( viewer_overceiling ?
3650               ((gz_top < thingmodsecp->ceilingheight) && (viewz > thingmodsecp->ceilingheight))
3651               : (thing->z >= thingmodsecp->ceilingheight)
3652               )
3653               return;
3654       }
3655     }
3656    }
3657 #if 0
3658     // gr vis does not have a heightsec (yet ??)
3659     // [WDJ] Only pass water models, not colormap model sectors
3660     vis->modelsec = thing_has_model ? thingmodelsec : -1 ; //SoM: 3/17/2000
3661 #endif
3662 
3663     //
3664     // store information in a vissprite
3665     //
3666     vis = HWR_NewVisSprite();
3667     vis->x1 = tx1;  // left of sprite in view, world coord
3668     vis->x2 = tx2;  // right of sprite in view, world coord
3669     vis->tz = tz;   // away depth
3670     vis->patch_lumpnum = sprfrot->pat_lumpnum;
3671     vis->flip = sprfrot->flip;
3672     vis->mobj = thing;
3673 
3674     //Hurdler: 25/04/2000: now support colormap in hardware mode
3675     if (thing->tflags & MFT_TRANSLATION6)
3676     {
3677         vis->colormap = MFT_TO_SKINMAP( thing->tflags ); // skins 1..
3678     }
3679     else
3680     {
3681         vis->colormap = & reg_colormaps[0];
3682     }
3683 
3684     // set top/bottom coords
3685 #ifdef FEET_IN_GROUND_TOPOFFSET_FIX
3686     vis->ty = FIXED_TO_FLOAT( thing->z + fig_topoffset ) - gr_viewz;
3687 #else
3688     vis->ty = FIXED_TO_FLOAT( thing->z + sprlump->topoffset ) - gr_viewz;
3689 #endif
3690 
3691     //CONS_Printf("------------------\nH: sprite  : %d\nH: frame   : %x\nH: type    : %d\nH: sname   : %s\n\n",
3692     //            thing->sprite, thing->frame, thing->type, sprnames[thing->sprite]);
3693 
3694     if (thing->state->frame & FF_FULLBRIGHT)
3695     {
3696         // TODO: disable also the fog
3697         vis->sectorlight = 0xff;
3698     }
3699     else
3700     {
3701         vis->sectorlight = sectorlight;
3702     }
3703 }
3704 
3705 #define BASEYCENTER           (BASEVIDHEIGHT/2)
3706 // -----------------+
3707 // HWR_DrawPSprite  : Draw 'player sprites' : weapons, etc.
3708 //                  : fSectorLight ranges 0...1
3709 // -----------------+
3710 // Draw parts of the viewplayer weapon
HWR_DrawPSprite(pspdef_t * psp,byte lightlum)3711 void HWR_DrawPSprite(pspdef_t * psp,  byte lightlum)
3712 {
3713     spritedef_t * sprdef;
3714 //    spriteframe_t * sprframe;
3715     sprite_frot_t * sprfrot;
3716     spritelump_t * sprlump = NULL;
3717 
3718     vxtx3d_t vxtx[4];
3719     int i, fr;
3720     float tx, ty;
3721 //    float x1, x2;
3722 
3723     MipPatch_t *gpatch;       //sprite patch converted to hardware
3724 
3725     FSurfaceInfo_t Surf;
3726 
3727     // [WDJ] 11/14/2012 use viewer variables, which will be for viewplayer
3728 
3729     // decide which patch to use
3730 #ifdef RANGECHECK
3731     if ((unsigned) psp->state->sprite >= numsprites)
3732     {
3733         I_SoftError("HWR_ProjectSprite: invalid sprite number %i ", psp->state->sprite);
3734         return;
3735     }
3736 #endif
3737 
3738     sprdef = &sprites[psp->state->sprite];
3739 #ifdef RANGECHECK
3740     if ((psp->state->frame & FF_FRAMEMASK) >= sprdef->numframes)
3741     {
3742         I_SoftError("HWR_ProjectSprite: invalid sprite frame %i : %i ", psp->state->sprite, psp->state->frame);
3743         return;
3744     }
3745 #endif
3746 
3747     fr = psp->state->frame & FF_FRAMEMASK;
3748 //    sprframe = get_spriteframe( sprdef, fr );
3749 
3750     // use single rotation for all views
3751     sprfrot = get_framerotation( sprdef, fr, 0 );
3752 
3753     sprlump = &spritelumps[sprfrot->spritelump_id];
3754 
3755     // calculate edges of the shape
3756 
3757     tx = FIXED_TO_FLOAT( (psp->sx - ((BASEVIDWIDTH / 2) << FRACBITS)) );
3758     tx -= FIXED_TO_FLOAT( sprlump->leftoffset );
3759 //    x1 = gr_windowcenterx + (tx * gr_pspritexscale);
3760 
3761     vxtx[3].x = vxtx[0].x = tx;
3762 
3763     tx += FIXED_TO_FLOAT( sprlump->width );
3764 //    x2 = gr_windowcenterx + (tx * gr_pspritexscale) - 1;
3765 
3766     vxtx[2].x = vxtx[1].x = tx;
3767 
3768     //  3--2
3769     //  | /|
3770     //  |/ |
3771     //  0--1
3772     vxtx[0].z = vxtx[1].z = vxtx[2].z = vxtx[3].z = 1;
3773 //    vxtx[0].w = vxtx[1].w = vxtx[2].w = vxtx[3].w = 1;  // unused
3774 
3775     // cache sprite graphics
3776     gpatch = W_CachePatchNum(sprfrot->pat_lumpnum, PU_CACHE);
3777     HWR_GetPatch(gpatch);
3778 
3779     // set top/bottom coords
3780     ty = FIXED_TO_FLOAT( psp->sy - sprlump->topoffset );
3781     if (cv_splitscreen.value && (cv_grfov.value == 90))
3782         ty -= 20;       //Hurdler: so it's a bit higher
3783     if (EN_heretic_hexen)
3784     {
3785         if (rdraw_viewheight == vid.height
3786             || (!cv_scalestatusbar.value && vid.dupy > 1) )
3787             ty += FIXED_TO_FLOAT( PSpriteSY[viewplayer->readyweapon] );
3788     }
3789 
3790     vxtx[3].y = vxtx[2].y = (float) BASEYCENTER - ty;
3791 
3792     ty += gpatch->height;
3793     vxtx[0].y = vxtx[1].y = (float) BASEYCENTER - ty;
3794 
3795     if( sprfrot->flip )
3796     {
3797         vxtx[0].sow = vxtx[3].sow = gpatch->max_s;
3798         vxtx[2].sow = vxtx[1].sow = 0.0f;
3799     }
3800     else
3801     {
3802         vxtx[0].sow = vxtx[3].sow = 0.0f;
3803         vxtx[2].sow = vxtx[1].sow = gpatch->max_s;
3804     }
3805     vxtx[3].tow = vxtx[2].tow = 0.0f;
3806     vxtx[0].tow = vxtx[1].tow = gpatch->max_t;
3807 
3808     // project clipped vertices, [WDJ] can be done on one set of verts
3809     for (i = 0; i < 4; i++)
3810     {
3811         //Hurdler: sorry, I had to multiply all by 4 for correct splitscreen mode
3812         vxtx[i].x /= 40.0f;
3813         vxtx[i].y /= 25.0f;
3814         vxtx[i].z = 4.0f;
3815     }
3816 
3817     // clip 2d polygon to view window
3818     //wClipVerts = ClipToView (vxtx, outVerts, 4 );
3819 
3820     // set transparency and light level
3821 
3822     if (viewmobj->flags & MF_SHADOW)
3823     {
3824         if (viewplayer->powers[pw_invisibility] > 4 * TICRATE || viewplayer->powers[pw_invisibility] & 8)
3825             Surf.FlatColor.s.alpha = 0xff / 3;
3826         else
3827             Surf.FlatColor.s.alpha = 2 * 0xff / 3;
3828     }
3829     else
3830         Surf.FlatColor.s.alpha = 0xff;
3831 
3832     if (psp->state->frame & FF_FULLBRIGHT)
3833     {
3834         // TODO: remove fog for this sprite !
3835         Surf.FlatColor.s.red = Surf.FlatColor.s.green = Surf.FlatColor.s.blue = 0xff;
3836     }
3837     else
3838     {
3839         sector_t *sector = viewer_sector;
3840 
3841         // default opaque mode using alpha 0 for holes
3842         Surf.FlatColor.s.red = Surf.FlatColor.s.green = Surf.FlatColor.s.blue = lightlum;
3843         //Hurdler: colormap test
3844 
3845         if (!fixedcolormap)
3846         {
3847             if (sector->ffloors)
3848             {
3849                 ffloor_t * caster = R_GetPlaneLight(sector, viewz)->caster;
3850                 sector = caster ? &sectors[caster->model_secnum] : sector;
3851             }
3852             if (sector->extra_colormap || view_extracolormap)
3853             {
3854                 Extracolormap_to_Surf( /*IN*/ sector->extra_colormap, lightlum,
3855                                        /*OUT*/ & Surf );
3856             }
3857         }
3858     }
3859 
3860     // invis player doesnt look good with PF_Environment so use PF_Translucent instead
3861     if (viewplayer->powers[pw_invisibility])
3862         HWD.pfnDrawPolygon(&Surf, vxtx, 4,
3863                            PF_Modulated | PF_Translucent | PF_NoDepthTest);
3864     else
3865         HWD.pfnDrawPolygon(&Surf, vxtx, 4,
3866                            PF_Modulated | PF_Environment | PF_NoDepthTest | PF_Occlude);
3867 }
3868 
3869 // --------------------------------------------------------------------------
3870 // HWR_DrawPlayerSprites
3871 // --------------------------------------------------------------------------
3872 // Draw the viewplayer weapon
HWR_DrawPlayerSprites(void)3873 static void HWR_DrawPlayerSprites(void)
3874 {
3875     int i;
3876     pspdef_t *psp;
3877     byte lightlum;
3878 
3879     // [WDJ] 11/14/2012 use viewer variables for viewplayer
3880 
3881     if (viewer_sector->numlights)
3882     {
3883         ff_light_t * ff_light =
3884           R_GetPlaneLight(viewer_sector, viewmobj->z + viewmobj->info->height);
3885         lightlum = LightLevelToLum(*ff_light->lightlevel);
3886     }
3887     else
3888     {
3889         // get light level
3890         lightlum = LightLevelToLum(viewer_sector->lightlevel);
3891     }
3892 
3893     // add all active psprites
3894     for (i = 0, psp = viewplayer->psprites; i < NUMPSPRITES; i++, psp++)
3895     {
3896         if (psp->state)
3897             HWR_DrawPSprite(psp, lightlum);
3898     }
3899 }
3900 
3901 // ==========================================================================
3902 //
3903 // ==========================================================================
3904 //  upper_lower : DSB_e
HWR_DrawSkyBackground(player_t * player,byte upper_lower)3905 void HWR_DrawSkyBackground(player_t * player, byte upper_lower)
3906 {
3907     vxtx3d_t v[4];
3908     angle_t angle;
3909     float f;
3910 //    float horizon;
3911 
3912 //  3--2
3913 //  | /|
3914 //  |/ |
3915 //  0--1
3916     HWR_GetTexture(sky_texture, 0);
3917 
3918     //Hurdler: the sky is the only texture who need 4.0f instead of 1.0
3919     //         because it's called just after clearing the screen
3920     //         and thus, the near clipping plane is set to 3.99
3921     v[0].x = v[3].x = -4.0f;
3922     v[1].x = v[2].x = 4.0f;
3923     v[0].y = v[1].y = -4.0f;
3924     v[2].y = v[3].y = 4.0f;
3925 
3926     v[0].z = v[1].z = v[2].z = v[3].z = 4.0f;
3927 
3928 #define WRAPANGLE (ANGLE_MAX/4)
3929     // ANGLE_MAX = 0xffffffff
3930     // ANGLE_MAX/4 = 0x3fffffff
3931     // ANG90 = 0x40000000
3932     angle = ((dup_viewangle + gr_x_to_viewangle[0]) % WRAPANGLE);
3933 
3934     v[0].sow = v[3].sow = 1.0f + ((float) angle) / (WRAPANGLE - 1);
3935     v[2].sow = v[1].sow = ((float) angle) / (WRAPANGLE - 1);
3936 
3937 #if 0
3938     // View angle effect on screen.
3939     // -1.0 when looking straight up.
3940     // 0 when look at horizon.
3941     float vpf = FIXED_TO_FLOAT(
3942         finetangent[(FINE_ANG90 - ((int) aimingangle >> (ANGLETOFINESHIFT + 1))) & FINEMASK] );
3943 #endif
3944     // Doom2 sky texture is 256w x 128h.
3945     // Heretic and Hexen sky texture are 256w x 200h.
3946     // Expanded texture for free-look is 256w x 240h.
3947     // When view is at horizon, draw sky texture [40] as top.
3948     // When aiming angle > 0x10480000, then sky repeats at top.
3949     //   horizon = -0.2017
3950     //   f = -0.338
3951     // When aiming angle > 0x38c00000, then sky repeats at top again.
3952     //   horizon = -0.83
3953     //   f = -127.0
3954     f = 40 + 200 * FIXED_TO_FLOAT(
3955         finetangent[(FINE_ANG90 - ((int) aimingangle >> (ANGLETOFINESHIFT + 1))) & FINEMASK] );
3956         // finetangent_ANG( -(aimingangle/2) )
3957 #if 1
3958     if (f < 0)
3959         f = 0;
3960     if (f > 240 - 127)
3961         f = 240 - 127;
3962 #endif
3963 
3964     // The view of the sky texture is 128 pixels high.
3965     v[3].tow = v[2].tow = f / 127.0f;
3966     v[0].tow = v[1].tow = (f + 127) / 127.0f;   //suppose 256x128 sky...
3967 
3968 #if 0
3969     // FIXME: This does not handle free-look.
3970     // FIXME: This does not handle f hitting the limits.
3971     switch( upper_lower )
3972     {
3973      case DSB_upper:
3974         v[0].y = v[1].y = 8.0f * anglef;
3975 //        v[0].tow = v[1].tow = (f + 64) / 127.0f;
3976         break;
3977      case DSB_lower:
3978         v[2].y = v[3].y = 0.0f;
3979         v[3].tow = v[2].tow = (f - 64) / 127.0f;
3980         break;
3981      default:
3982         break;
3983     }
3984 #endif
3985 
3986     HWD.pfnDrawPolygon(NULL, v, 4, 0);
3987 }
3988 
3989 // -----------------+
3990 // HWR_Clear_View : clear the viewwindow, with maximum z value
3991 // -----------------+
HWR_Clear_View(void)3992 void HWR_Clear_View(void)
3993 {
3994     //  3--2
3995     //  | /|
3996     //  |/ |
3997     //  0--1
3998 
3999     //FIXTHIS faB - enable depth mask, disable color mask
4000 
4001     HWD.pfnGClipRect((int) gr_viewwindowx, (int) gr_viewwindowy, (int) (gr_viewwindowx + gr_viewwidth), (int) (gr_viewwindowy + gr_viewheight), 3.99f);
4002     HWD.pfnClearBuffer(false, true, 0);
4003 
4004     //disable clip window - set to full size
4005     // rem by Hurdler
4006     // HWD.pfnGClipRect (0,0,vid.width,vid.height );
4007 }
4008 
4009 static byte  viewsv_viewnumber;
4010 
4011 // -----------------+
4012 // HWR_SetViewSize  : set projection and scaling values depending on the
4013 //                  : view window size
4014 // -----------------+
HWR_SetViewSize(int blocks)4015 void HWR_SetViewSize(int blocks)
4016 {
4017     // setup view size
4018 
4019     // clamping viewsize is normally not needed coz it's done in R_ExecuteSetViewSize()
4020     // BEFORE calling here
4021     if (blocks < 3 || blocks > 12)
4022         blocks = 10;
4023     if (blocks > 10 || (blocks == 10 && (!cv_scalestatusbar.value || cv_grtranslucenthud.value < 255)))
4024     {
4025         gr_viewwidth = (float) vid.width;
4026         gr_viewheight = (float) vid.height;
4027     }
4028     else
4029     {
4030         gr_viewwidth = (float) ((blocks * vid.width / 10) & ~7);
4031         gr_viewheight = (float) ((blocks * (vid.height - stbar_height / 2) / 10) & ~1);
4032     }
4033 
4034     if (cv_splitscreen.value)
4035         gr_viewheight /= 2;
4036 
4037     gr_centerx = gr_viewwidth / 2;
4038     gr_basecentery = gr_viewheight / 2; //note: this is (gr_centerx * gr_viewheight / gr_viewwidth)
4039 
4040     gr_viewwindowx = (vid.width - gr_viewwidth) / 2;
4041     gr_windowcenterx = (float) (vid.width / 2);
4042     if (gr_viewwidth == vid.width)
4043     {
4044         // window top left corner at 0,0
4045         gr_baseviewwindowy = 0;
4046         gr_basewindowcentery = gr_viewheight / 2;
4047     }
4048     else
4049     {
4050         gr_baseviewwindowy = (vid.height - stbar_height - gr_viewheight) / 2;
4051         gr_basewindowcentery = (float) ((vid.height - stbar_height) / 2);
4052     }
4053 
4054     gr_pspritexscale = gr_viewwidth / BASEVIDWIDTH;
4055     gr_pspriteyscale = ((vid.height * gr_pspritexscale * BASEVIDWIDTH) / BASEVIDHEIGHT) / vid.width;
4056 
4057     viewsv_viewnumber = 255;  // force init of render
4058 }
4059 
4060 
4061 //Hurdler: 3D water stuffs
4062 static int numplanes = 0;
4063 static int num_late_walls = 0;  // drawn late, transparent walls
4064 
4065 
4066 // ==========================================================================
4067 //
4068 // ==========================================================================
4069 // Split player saved settings.
4070 // indexed from viewnumber, when 0,1.
4071 static byte viewsv_need_sky[2];
4072 
4073 
4074 //  viewnumber : splitscreen 0=upper, 1=lower. Single player is always 0.
4075 //
4076 //  pind : splitscreen 0=upper, 1=lower, 2=init. Single player is always 0.
HWR_RenderPlayerView(byte pind,player_t * player)4077 void HWR_RenderPlayerView(byte pind, player_t * player)
4078 {
4079     // viewnumber = pind, because [0] is upper splitscreen
4080     //static float    distance = BASEVIDWIDTH;
4081 
4082     // Palette moved to R_SetupFrame.
4083 
4084     // Is also forced upon first Render, by init of viewsv_viewnumber.
4085     if(viewsv_viewnumber != pind)
4086     {
4087         if( viewsv_viewnumber < 2 )
4088         {
4089             // swap split window settings
4090             viewsv_need_sky[viewsv_viewnumber] = need_sky_background;
4091             need_sky_background = viewsv_need_sky[pind];
4092         }
4093         else
4094         {
4095             // Initial values.
4096             need_sky_background = DSB_all;
4097             viewsv_need_sky[0] = viewsv_need_sky[1] = DSB_all;
4098         }
4099         viewsv_viewnumber = pind;
4100         HWR_Set_Lights(pind);
4101     }
4102 
4103     // note: sets viewangle, viewx, viewy, viewz
4104     R_SetupFrame(pind, player);
4105 
4106     // copy view cam position for local use
4107     dup_viewangle = viewangle;
4108 
4109     // set window position
4110     gr_centery = gr_basecentery;
4111     gr_viewwindowy = gr_baseviewwindowy;
4112     gr_windowcentery = gr_basewindowcentery;
4113     if (cv_splitscreen.value && (pind == 1))
4114     {
4115         // lower screen
4116         //gr_centery += (vid.height/2 );
4117         gr_viewwindowy += (vid.height / 2);
4118         gr_windowcentery += (vid.height / 2);
4119     }
4120 
4121     // hmm solidsegs probably useless here
4122     //R_Clear_DrawSegs ( );
4123     // useless
4124     //R_Clear_Planes (player );
4125     //HWR_Clear_Sprites ( );
4126 
4127     // check for new console commands.
4128     NetUpdate();
4129 
4130     gr_viewx = FIXED_TO_FLOAT( viewx );
4131     gr_viewy = FIXED_TO_FLOAT( viewy );
4132     gr_viewz = FIXED_TO_FLOAT( viewz );
4133     gr_viewsin = FIXED_TO_FLOAT( viewsin );
4134     gr_viewcos = FIXED_TO_FLOAT( viewcos );
4135 
4136     // viewludsin( aimingangle ) instead of viewsin( viewangle )
4137     gr_viewludsin = FIXED_TO_FLOAT(cosine_ANG(aimingangle));
4138     gr_viewludcos = FIXED_TO_FLOAT(-sine_ANG(aimingangle));
4139 
4140     //04/01/2000: Hurdler: added for T&L
4141     //                     It should replace all other gr_viewxxx when finished
4142     atransform.anglex = (float) ANGLE_TO_FINE(aimingangle) * (360.0f / (float) FINEANGLES);
4143     atransform.angley = (float) ANGLE_TO_FINE(viewangle) * (360.0f / (float) FINEANGLES);
4144     atransform.x = gr_viewx;    // FIXED_TO_FLOAT( viewx )
4145     atransform.y = gr_viewy;    // FIXED_TO_FLOAT( viewy )
4146     atransform.z = gr_viewz;    // FIXED_TO_FLOAT( viewz )
4147     atransform.scalex = 1;
4148     atransform.scaley = ORIGINAL_ASPECT;
4149     atransform.scalez = 1;
4150     atransform.fovxangle = cv_grfov.value;
4151     atransform.fovyangle = cv_grfov.value;
4152     atransform.splitscreen = cv_splitscreen.value;
4153     gr_fovlud = 1 / tan(cv_grfov.value * PI / 360);
4154 
4155 #ifdef NO_MLOOK_EXTENDS_FOV
4156     // enlage fOV when looking up/down
4157     HWR_Init_TextureMapping();
4158 #endif
4159 
4160     //------------------------------------------------------------------------
4161     HWR_Clear_View();
4162 
4163     if (cv_grfog.value)
4164         HWR_FoggingOn();
4165 
4166     // Needs to be drawn early.  Is drawn with different transform.
4167     // Translucents are drawn over it.
4168     // Enable when detected sky sectors in previous frame draw.
4169     if (need_sky_background)
4170         HWR_DrawSkyBackground(player, need_sky_background);
4171 
4172     need_sky_background = DSB_none;
4173 
4174     // added by Hurdler for FOV 120
4175 //    if (cv_grfov.value != 90)
4176 //        HWD.pfnSetSpecialState(HWD_SET_FOV, cv_grfov.value);
4177 
4178     //14/11/99: Hurdler: we will add lights while processing sprites
4179     //it doesn't work with all subsectors (if we use AddSprites to do that).
4180     //TOO bad, that's why I removed this line (until this is fixed).
4181 //    HWR_Reset_Lights();
4182 
4183     HWR_Clear_Sprites();
4184 
4185     HWR_Clear_ClipSegs();
4186 
4187     //04/01/2000: Hurdler: added for T&L
4188     //                     Actually it only works on Walls and Planes
4189     HWD.pfnSetTransform(&atransform);
4190     // [WDJ] transform upgrade
4191     HWR_set_view_transform();
4192 
4193     validcount++;
4194     HWR_RenderBSPNode(numnodes - 1);
4195 
4196 #ifndef NO_MLOOK_EXTENDS_FOV
4197     if (cv_grmlook_extends_fov.value && (aimingangle || cv_grfov.value > 90))
4198     {
4199         dup_viewangle += ANG90;
4200         HWR_Clear_ClipSegs();
4201         HWR_RenderBSPNode(numnodes - 1);        //left
4202 
4203         dup_viewangle += ANG90;
4204         if (cv_grmlook_extends_fov.value == 2 && ((int) aimingangle > ANG45 || (int) aimingangle < -ANG45))
4205         {
4206             HWR_Clear_ClipSegs();
4207             HWR_RenderBSPNode(numnodes - 1);    //back
4208         }
4209 
4210         dup_viewangle += ANG90;
4211         HWR_Clear_ClipSegs();
4212         HWR_RenderBSPNode(numnodes - 1);        //right
4213 
4214         dup_viewangle += ANG90;
4215     }
4216 #endif
4217 
4218     // Check for new console commands.
4219     NetUpdate();
4220 
4221     //14/11/99: Hurdler: moved here because it doesn't work with
4222     // subsector, see other comments;
4223     HWR_Reset_Lights();
4224 
4225     // Draw MD2 and sprites
4226     HWR_SortVisSprites();
4227     HWR_DrawMD2S();
4228 #ifdef CORONA_CHOICE
4229     // mirror corona choice, with auto -> sprite draw
4230     corona_draw_choice = (cv_corona.EV==0)? 0 : ((cv_grcorona_draw.value == 3)?  1 : cv_grcorona_draw.value);
4231 #endif
4232     HWR_RenderSorted();
4233     HWD.pfnSetTransform(NULL);
4234 
4235     // Check for new console commands.
4236     NetUpdate();
4237 
4238     if( view_fogfloor
4239         && ( view_fogfloor->flags & FF_FOGFACE  ) )
4240     {
4241         int fog_extralight = (player->extralight * view_fogfloor->alpha) >> 7;
4242         // fog drawn over eyes, using sprite transforms
4243         if( extralight )
4244            HWR_RenderFog( view_fogfloor, viewer_sector, fog_extralight, 4.0f );
4245         HWR_RenderFog( view_fogfloor, viewer_sector, fog_extralight, 0.0 );  // random scale
4246     }
4247 
4248     // draw the psprites on top of everything
4249     //  but does not draw on side views
4250     if (!viewangleoffset && !camera.chase && cv_psprites.value && script_camera_on == false)
4251         HWR_DrawPlayerSprites();
4252 
4253     //------------------------------------------------------------------------
4254     // put it off for menus etc
4255     if (cv_grfog.value)
4256         HWD.pfnSetSpecialState(HWD_SET_FOG_MODE, 0);
4257 
4258     // added by Hurdler for correct splitscreen
4259     // moved here by hurdler so it works with the new near clipping plane
4260     HWD.pfnGClipRect(0, 0, vid.width, vid.height, NEAR_CLIP_DIST);
4261 }
4262 
4263 // ==========================================================================
4264 //                                                                        FOG
4265 // ==========================================================================
4266 
4267 static
hex_val(const char * str)4268 unsigned int hex_val(const char *str)
4269 {
4270     unsigned int val = 0;
4271     int i, d;
4272     const char * sc;
4273     char c;
4274 
4275     sc = str;
4276     for(i = 0; i < 6; i++)
4277     {
4278         c = *(sc++);
4279         if (c >= '0' && c <= '9')
4280             d = c - '0';
4281         else if (c >= 'a' && c <= 'f')
4282             d = c - 'a' + 10;
4283         else if (c >= 'A' && c <= 'F')
4284             d = c - 'A' + 10;
4285         else
4286             break;
4287         val = (val << 4) | d;
4288     }
4289     //CONS_Printf ("col %x\n", val);
4290     return val;
4291 }
4292 
HWR_FoggingOn(void)4293 void HWR_FoggingOn(void)
4294 {
4295     HWD.pfnSetSpecialState(HWD_SET_FOG_COLOR, hex_val(cv_grfogcolor.string));
4296     HWD.pfnSetSpecialState(HWD_SET_FOG_DENSITY, cv_grfogdensity.value);
4297     HWD.pfnSetSpecialState(HWD_SET_FOG_MODE, 1);
4298 }
4299 
4300 // ==========================================================================
4301 //                                                         3D ENGINE COMMANDS
4302 // ==========================================================================
4303 
CV_grFov_OnChange(void)4304 static void CV_grFov_OnChange(void)
4305 {
4306     // autoset mlook when FOV > 90
4307     if ((!cv_grmlook_extends_fov.value) && (cv_grfov.value > 90))
4308         CV_SetValue(&cv_grmlook_extends_fov, 1);
4309 }
4310 
CV_grPolygonSmooth_OnChange(void)4311 static void CV_grPolygonSmooth_OnChange(void)
4312 {
4313     if( HWD.pfnSetSpecialState )
4314         HWD.pfnSetSpecialState(HWD_SET_POLYGON_SMOOTH, cv_grpolygonsmooth.value);
4315 }
4316 
4317 /*
4318 static void CV_grFogColor_OnChange (void)
4319 {
4320     //HWD.pfnSetSpecialState (HWD_SET_FOG_COLOR, hex_val(cv_grfogcolor.string));
4321 }
4322 */
Command_GrStats_f(void)4323 static void Command_GrStats_f(void)
4324 {
4325     //debug
4326     Z_CheckHeap(9875);
4327 
4328     CONS_Printf("Patch info headers : %7d kb\n", Z_TagUsage(PU_HWRPATCHINFO) >> 10);
4329     CONS_Printf("3D Texture cache   : %7d kb\n", Z_TagUsage(PU_HWRCACHE) >> 10);
4330     CONS_Printf("Plane polygon      : %7d kb\n", Z_TagUsage(PU_HWRPLANE) >> 10);
4331 }
4332 
4333 // **************************************************************************
4334 //                                                            3D ENGINE SETUP
4335 // **************************************************************************
4336 
4337 // --------------------------------------------------------------------------
4338 // Register hardware engine commands & consvars
4339 // --------------------------------------------------------------------------
4340 //added by Hurdler: console variable that are saved
HWR_Register_Gr1Commands(void)4341 void HWR_Register_Gr1Commands(void)
4342 {
4343     // [WDJ] Any cv_ with CV_SAVE needs to be registered, even if it is not used.
4344     // Otherwise there will be error messages when config is loaded.
4345     CV_RegisterVar(&cv_grgammablue);
4346     CV_RegisterVar(&cv_grgammagreen);
4347     CV_RegisterVar(&cv_grgammared);
4348     //CV_RegisterVar (&cv_grcontrast);
4349     //CV_RegisterVar (&cv_grpolygonsmooth); // moved below
4350     CV_RegisterVar(&cv_grmd2);
4351     CV_RegisterVar(&cv_grstaticlighting);
4352     CV_RegisterVar(&cv_grdynamiclighting);
4353     CV_RegisterVar(&cv_grcorona_draw);
4354     CV_RegisterVar(&cv_grfov);
4355     CV_RegisterVar(&cv_grfogdensity);
4356     CV_RegisterVar(&cv_grfogcolor);
4357     CV_RegisterVar(&cv_grfog);
4358     CV_RegisterVar(&cv_grmlook_extends_fov);
4359     CV_RegisterVar(&cv_grfiltermode);
4360     CV_RegisterVar(&cv_grcorrecttricks);
4361     CV_RegisterVar(&cv_grsolvetjoin);
4362     CV_RegisterVar(&cv_grpolytile);
4363     CV_RegisterVar(&cv_grpolyshape);
4364 }
4365 
4366 // HWR Engine state and modes.
HWR_Register_Gr2Commands(void)4367 void HWR_Register_Gr2Commands(void)
4368 {
4369     CV_RegisterVar(&cv_grpolygonsmooth);
4370 
4371     // engine state variables
4372     //CV_RegisterVar (&cv_grsky);
4373     //CV_RegisterVar (&cv_grzbuffer);
4374     //CV_RegisterVar (&cv_grclipwalls);
4375     CV_RegisterVar(&cv_grrounddown);
4376 
4377     // engine development mode variables
4378     // - usage may vary from version to version..
4379     CV_RegisterVar(&cv_gralpha);
4380     CV_RegisterVar(&cv_grbeta);
4381     CV_RegisterVar(&cv_grgamma);
4382     CV_RegisterVar(&cv_grzbuffer);
4383 #ifdef TRANSWALL_CHOICE
4384     CV_RegisterVar(&cv_grtranswall);
4385 #endif
4386     CV_RegisterVar(&cv_grclipwalls);
4387 
4388     // engine commands
4389     COM_AddCommand("gr_stats", Command_GrStats_f, CC_info);
4390 }
4391 
4392 // --------------------------------------------------------------------------
4393 // Setup the hardware renderer
4394 // --------------------------------------------------------------------------
HWR_Startup_Render(void)4395 void HWR_Startup_Render(void)
4396 {
4397     static int startupdone = 0;
4398 
4399     CONS_Printf("HWR_Startup()\n");
4400 
4401     // initialize light lut translation
4402     Init_LumLut();
4403 
4404     // do this once
4405     if (!startupdone)
4406     {
4407         // add console cmds & vars
4408         HWR_Register_Gr2Commands();
4409 
4410         HWR_Init_PolyPool();
4411         HWR_Init_TextureCache();
4412 
4413 #ifdef DCK_WATER_TEST
4414         // for test water translucent surface
4415         doomwaterflat = W_CheckNumForName("FWATER1");
4416         if( ! VALID_LUMP(doomwaterflat) )        // if FWATER1 not found (in doom shareware)
4417             doomwaterflat = W_GetNumForName("WATER0");
4418 #endif
4419 
4420         HWR_Init_MD2();
4421     }
4422 
4423     HWR_Init_Light();
4424 
4425     if (rendermode == render_opengl)
4426         textureformat = patchformat = GR_RGBA;
4427 
4428     // The hardware draw modes that can use the flash palette call.
4429     EN_HWR_flashpalette = (rendermode == render_opengl) || (rendermode == render_d3d);
4430 
4431     startupdone = 1;
4432 }
4433 
4434 
4435 // Called after setup level, and when change drawmode to HWR draw.
HWR_SetupLevel(void)4436 void  HWR_SetupLevel( void )
4437 {
4438     // Setup structures needed for HWR draw.
4439     // BP: reset light between levels (we draw preview frame lights on current frame)
4440     HWR_Reset_Lights();
4441     // Correct missing sidedefs & deep water trick
4442     HWR_CorrectSWTricks();
4443     HWR_Create_PlanePolygons();
4444 }
4445 
4446 // Called after setup level, and when change drawmode to HWR draw.
HWR_Preload_Graphics(void)4447 void  HWR_Preload_Graphics( void )
4448 {
4449     HWR_Prep_LevelCache (numtextures);
4450     HWR_Create_StaticLightmaps();
4451 }
4452 
4453 // --------------------------------------------------------------------------
4454 // Free resources allocated by the hardware renderer
4455 // --------------------------------------------------------------------------
HWR_Shutdown_Render(void)4456 void HWR_Shutdown_Render(void)
4457 {
4458     CONS_Printf("HWR_Shutdown()\n");
4459     HWR_Free_PolyPool();
4460     HWR_Free_TextureCache();
4461 }
4462 
4463 
4464 // temporary, to supply old call
transform_world_to_gr(float wx,float wy,float wz,float * gx,float * gy,float * gz)4465 void transform_world_to_gr(float wx, float wy, float wz, /*OUT*/ float *gx, float *gy, float *gz )
4466 {
4467     // translation
4468     // Combined transforms for position, direction, look up/down, and scaling
4469     float tr_x = wx - gr_viewx;
4470     float tr_y = wz - gr_viewy;
4471     float tr_z = wy - gr_viewz;
4472     *gx = (tr_x * world_trans_x_to_x)
4473        + (tr_y * world_trans_y_to_x);
4474     *gy = (tr_x * world_trans_x_to_y )
4475        + (tr_y * world_trans_y_to_y )
4476        + (tr_z * world_trans_z_to_y );
4477     *gz = (tr_x * world_trans_x_to_z )
4478        + (tr_y * world_trans_y_to_z )
4479        + (tr_z * world_trans_z_to_z );
4480 }
4481 
4482 #if 0
4483 // for reference
4484 void transform_world_to_gr(float *cx, float *cy, float *cz)
4485 {
4486     float tr_x, tr_y;
4487     // translation
4488     tr_x = *cx - gr_viewx;
4489     tr_y = *cz - gr_viewy;
4490 //   *cy = *cy;
4491 
4492     // rotation around vertical y axis
4493     *cx = (tr_x * gr_viewsin) - (tr_y * gr_viewcos);
4494     tr_x = (tr_x * gr_viewcos) + (tr_y * gr_viewsin);
4495 
4496     //look up/down
4497     tr_y = *cy - gr_viewz;
4498 
4499     *cy = (tr_x * gr_viewludcos) + (tr_y * gr_viewludsin);
4500     *cz = (tr_x * gr_viewludsin) - (tr_y * gr_viewludcos);
4501 
4502     //scale y before frustum so that frustum can be scaled to screen height
4503     *cy *= ORIGINAL_ASPECT * gr_fovlud;
4504     *cx *= gr_fovlud;
4505 }
4506 #endif
4507 
4508 //Hurdler: 3D Water stuff
4509 #define ABS(x) ((x) < 0 ? -(x) : (x))
4510 
4511 #define PLANEINFO_INC 512
4512 static planeinfo_t *planeinfo = NULL;
4513 static int planeinfo_len = 0;  // num allocated
4514 
4515 
4516 // Add translucent plane, called for each plane visible
4517 //  picnum : index to levelflats
HWR_Add3DWater(int picnum,poly_subsector_t * xsub,fixed_t fixedheight,int lightlevel,int alpha)4518 void HWR_Add3DWater(int picnum, poly_subsector_t * xsub, fixed_t fixedheight, int lightlevel, int alpha)
4519 {
4520     planeinfo_t * pl;
4521 
4522     if (numplanes >= planeinfo_len)
4523     {
4524         // expand number of planeinfo
4525         size_t planeinfo_req = planeinfo_len + PLANEINFO_INC;
4526         pl = (planeinfo_t *) realloc(planeinfo, planeinfo_req * sizeof(planeinfo_t));
4527         if( pl == NULL )
4528         {
4529             // Missing some planes for a while, but player can finish level.
4530             I_SoftError( "Planeinfo: cannot alloc %i\n", planeinfo_req );
4531             return;
4532         }
4533         planeinfo = pl;
4534         planeinfo_len = planeinfo_req;
4535     }
4536 
4537     // [WDJ] Merge sort is faster than bubble-sort or quicksort, because
4538     // the tests can be made simpler, takes advantage of already sorted list,
4539     // and it moves all closer entries at once, and only once.
4540     planeinfo_t * plnew = & planeinfo[numplanes];
4541     // merge sort farthest to closest
4542     fixed_t dist_abs = ABS(viewz - fixedheight);
4543     fixed_t dist_min = viewz - dist_abs;  // test
4544     fixed_t dist_max = viewz + dist_abs;  // test
4545     for( pl = & planeinfo[0]; pl < plnew; pl++ )
4546     {
4547         // test for plane closer
4548         if( pl->fixedheight > dist_min && pl->fixedheight < dist_max )
4549            break; // entry is closer than new plane
4550     }
4551     if( pl < plnew )
4552     {
4553         // move all closer entries at once
4554         memmove( pl+1, pl, (byte*)plnew-(byte*)pl );
4555         plnew = pl;
4556     }
4557 
4558     // The new water plane
4559     plnew->fixedheight = fixedheight;
4560     plnew->lightlevel = lightlevel;
4561     plnew->picnum = picnum;
4562     plnew->xsub = xsub;
4563     plnew->alpha = alpha;
4564 
4565     numplanes++;
4566 }
4567 
4568 
HWR_Render3DWater()4569 void HWR_Render3DWater()
4570 {
4571     int i;
4572 
4573     //[WDJ] Do merge sort during insert of plane, then fewest operations,
4574     // one calc of dist, and one memcpy
4575 
4576     gr_frontsector = NULL;      //Hurdler: gr_frontsector is no longer valid
4577     for (i = 0; i < numplanes; i++)
4578     {
4579         // pass alpha to HWR_RenderPlane
4580         FBITFIELD PolyFlags = PF_Translucent | (planeinfo[i].alpha << 24);
4581 
4582         HWR_GetFlat(levelflats[planeinfo[i].picnum].lumpnum);
4583         HWR_RenderPlane(planeinfo[i].xsub, planeinfo[i].fixedheight, PolyFlags,
4584                         NULL, planeinfo[i].lightlevel, planeinfo[i].picnum);
4585     }
4586     numplanes = 0;
4587 }
4588 
4589 //Hurdler: manage transparent texture a little better
4590 #define ABS(x) ((x) < 0 ? -(x) : (x))
4591 #define LATE_WALLINFO_INC  128
4592 
4593 typedef struct
4594 {
4595     vxtx3d_t vxtx[4];
4596     FSurfaceInfo_t Surf;
4597     int texnum;
4598     int blend;
4599     int next_nearer;  // -1 end of list
4600     float dist1, dist2;
4601 } late_wallinfo_t;
4602 
4603 static late_wallinfo_t * late_wallinfo = NULL;
4604 static int late_wallinfo_size = 0;
4605 static int late_wall_farthest = -1;
4606 
4607 // return index of next free
expand_late_wallinfo(void)4608 int  expand_late_wallinfo( void )
4609 {
4610     int lw_size = late_wallinfo_size + LATE_WALLINFO_INC;
4611     late_wallinfo_t * lw_p =
4612      (late_wallinfo_t *) realloc(late_wallinfo, lw_size * sizeof(late_wallinfo_t));
4613     if( lw_p )  // normal
4614     {
4615         late_wallinfo = lw_p;
4616         late_wallinfo_size = lw_size;
4617         return num_late_walls;  // next free
4618     }
4619     // failure
4620     if( num_late_walls <= 0 )
4621        I_Error( "Late wallinfo alloc failed\n" );  // no alloc
4622     I_SoftError( "Late wallinfo realloc failed, %i\n", lw_size );
4623     num_late_walls -= 1;
4624     return late_wall_farthest;  // reuse farthest, but keep running
4625 }
4626 
4627 // [WDJ] To sort transparent walls
4628 // vxtx is in world coord with y up
4629 static
late_wall_dist(vxtx3d_t * wVs,late_wallinfo_t * lw_p)4630 void  late_wall_dist( vxtx3d_t * wVs, late_wallinfo_t * lw_p )
4631 {
4632     float tr_x = wVs[0].x - gr_viewx;
4633     float tr_y = wVs[0].z - gr_viewy;
4634     float tr_z = wVs[0].y - gr_viewz;
4635     lw_p->dist1 = (tr_x * world_trans_x_to_z )
4636         + (tr_y * world_trans_y_to_z )
4637         + (tr_z * world_trans_z_to_z );
4638     tr_x = wVs[2].x - gr_viewx;
4639     tr_y = wVs[2].z - gr_viewy;
4640     tr_z = wVs[2].y - gr_viewz;
4641     lw_p->dist2 = (tr_x * world_trans_x_to_z )
4642         + (tr_y * world_trans_y_to_z )
4643         + (tr_z * world_trans_z_to_z );
4644 }
4645 
4646 // Called from HWR_SplitWall, HWR_StoreWallRange
4647 // vxtx is in world coord with y up
HWR_AddTransparentWall(vxtx3d_t * vxtx,FSurfaceInfo_t * pSurf,int texnum,int blend)4648 void HWR_AddTransparentWall(vxtx3d_t * vxtx, FSurfaceInfo_t * pSurf, int texnum, int blend)
4649 {
4650     late_wallinfo_t *  lw_p;
4651     int lwi, prev_lwi;
4652     int new_lwi = num_late_walls;
4653     if( new_lwi >= late_wallinfo_size )
4654     {
4655         new_lwi = expand_late_wallinfo();  // may have to reuse farthest
4656     }
4657 
4658     // New late wall record.
4659     lw_p = & late_wallinfo[new_lwi];
4660     memcpy( lw_p->vxtx, vxtx, sizeof(lw_p->vxtx));
4661     memcpy( & lw_p->Surf, pSurf, sizeof(FSurfaceInfo_t));
4662     lw_p->texnum = texnum;
4663     lw_p->blend = blend;
4664 
4665     // [WDJ] merge sort into the late_wallinfo
4666     late_wall_dist( vxtx, lw_p );  // set dist1, dist2
4667     prev_lwi = -1;
4668     lwi = late_wall_farthest;
4669     while( lwi >= 0 )  // from farthest to nearest
4670     {
4671         register late_wallinfo_t * wp = & late_wallinfo[lwi];
4672         // they may share a vertex or two
4673         if( wp->dist1 < lw_p->dist1 )
4674             break;  // new wall is farther
4675         else if( wp->dist1 == lw_p->dist1 )
4676         {
4677             if( wp->dist2 < lw_p->dist2 )
4678                 break;  // new wall is farther
4679             else if( wp->dist2 == lw_p->dist2 ) {
4680                 break; // no longer matters, they must overlap
4681             }
4682         }
4683         prev_lwi = lwi;
4684         lwi = late_wallinfo[lwi].next_nearer;
4685     }
4686     lw_p->next_nearer = lwi;
4687     if( prev_lwi >= 0 )
4688     {
4689         // link in before nearer
4690         late_wallinfo[prev_lwi].next_nearer = new_lwi;
4691     }
4692     else
4693     {
4694         // new is farthest
4695         late_wall_farthest = new_lwi;
4696     }
4697     num_late_walls++;
4698 }
4699 
4700 //#define DEBUG_DRAWSORTED
4701 static
HWR_RenderSorted(void)4702 void HWR_RenderSorted( void )
4703 {
4704 #ifdef DEBUG_DRAWSORTED
4705     int   neg_dist_cnt = 0;
4706     int   transform_load_cnt = 0;
4707 #endif
4708     byte  affine_transform = 255;
4709     // transparent walls
4710     int lwi = -1;
4711     late_wallinfo_t * lw_p = NULL;
4712     // sprites
4713     gr_vissprite_t * spr = NULL;
4714     float spr_dist = -1000.0f;
4715     float tranwall_dist = -1000.0f;
4716 
4717     // sprites
4718     if (gr_vissprite_p > gr_vissprites)
4719     {
4720         spr = gr_vsprsortedhead.next;
4721         if( spr )
4722             spr_dist = spr->tz;
4723     }
4724     if (num_late_walls)
4725     {
4726         lwi = late_wall_farthest;
4727         if( lwi >= 0 )
4728         {
4729             lw_p = & late_wallinfo[lwi];
4730             tranwall_dist = lw_p->dist1;
4731         }
4732     }
4733 
4734 
4735     for(;;)
4736     {
4737         if( spr && ( spr_dist > tranwall_dist ))
4738         {
4739 #ifdef DEBUG_DRAWSORTED
4740             if( spr_dist < 0 )  neg_dist_cnt++;
4741 #else
4742             if( spr_dist < -200.0f )  break;
4743                // farther back and cannot even contribute light
4744 #endif
4745             // sprite
4746             if( affine_transform != 0 )
4747             {
4748                 HWD.pfnSetTransform(NULL);
4749                 affine_transform = 0;
4750 #ifdef DEBUG_DRAWSORTED
4751                 transform_load_cnt ++;
4752 #endif
4753             }
4754             HWR_DrawSprite(spr);
4755             // draw vissprites back to front
4756             spr = spr->next;
4757             spr_dist = spr->tz;
4758             if(spr == &gr_vsprsortedhead)
4759             {
4760                 spr = NULL;   // stop sprites
4761                 spr_dist = -1000.0f;
4762             }
4763         }
4764         else if( lw_p )
4765         {
4766 #ifdef DEBUG_DRAWSORTED
4767             if( tranwall_dist < 0 )  neg_dist_cnt++;
4768 #else
4769             // [WDJ] this test has been culling left side visible walls
4770 //	    if( tranwall_dist < -200.0f )  break;
4771             if( tranwall_dist < -2000.0f )  break;
4772                // farther back and cannot even contribute light
4773 #endif
4774             // transparent wall
4775             if( affine_transform != 1 )
4776             {
4777                 HWD.pfnSetTransform(&atransform);
4778                 affine_transform = 1;
4779 #ifdef DEBUG_DRAWSORTED
4780                 transform_load_cnt ++;
4781 #endif
4782             }
4783             // with TF_Opaquetrans, TF_Fogsheet flag
4784             HWR_GetTexture(lw_p->texnum, lw_p->Surf.texflags);
4785             HWR_RenderWall(lw_p->vxtx, &lw_p->Surf, lw_p->blend);
4786             lwi = lw_p->next_nearer;
4787             if( lwi >= 0 )
4788             {
4789                 lw_p = & late_wallinfo[lwi];
4790                 tranwall_dist = lw_p->dist1;
4791             }
4792             else
4793             {
4794                 lw_p = NULL;
4795                 tranwall_dist = -10000.0f;
4796             }
4797         }
4798         else
4799             break; // done
4800     }
4801     num_late_walls = 0;
4802     late_wall_farthest = -1;
4803 
4804 #ifdef DYLT_CORONAS
4805     HWD.pfnSetTransform(NULL);
4806 #ifdef CORONA_CHOICE
4807     if( corona_draw_choice == 2 )
4808 #else
4809     if( cv_corona.EV )
4810 #endif
4811     {
4812         //Hurdler: they must be drawn before translucent planes, what about gl fog?
4813         HWR_DL_Draw_Coronas();
4814     }
4815 #endif
4816 
4817     if (numplanes)
4818     {
4819         HWD.pfnSetTransform(&atransform);
4820         if (numplanes)
4821             HWR_Render3DWater();
4822         HWD.pfnSetTransform(NULL);
4823     }
4824 #ifdef DEBUG_DRAWSORTED
4825     fprintf( stderr, "Neg dist count %i, Transforms %i\n", neg_dist_cnt, transform_load_cnt );
4826 #endif
4827 }
4828