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 ? §ors[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)? §ors[ 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 ? §ors[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 ? §ors[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 ? §ors[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 ? §ors[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