1 // SONIC ROBO BLAST 2
2 //-----------------------------------------------------------------------------
3 // Copyright (C) 1998-2000 by DooM Legacy Team.
4 // Copyright (C) 1999-2021 by Sonic Team Junior.
5 //
6 // This program is free software distributed under the
7 // terms of the GNU General Public License, version 2.
8 // See the 'LICENSE' file for more details.
9 //-----------------------------------------------------------------------------
10 /// \file hw_main.c
11 /// \brief hardware renderer, using the standard HardWareRender driver DLL for SRB2
12 
13 #include <math.h>
14 
15 #include "../doomstat.h"
16 
17 #ifdef HWRENDER
18 #include "hw_glob.h"
19 #include "hw_light.h"
20 #include "hw_drv.h"
21 #include "hw_batching.h"
22 
23 #include "../i_video.h" // for rendermode == render_glide
24 #include "../v_video.h"
25 #include "../p_local.h"
26 #include "../p_setup.h"
27 #include "../r_local.h"
28 #include "../r_patch.h"
29 #include "../r_picformats.h"
30 #include "../r_bsp.h"
31 #include "../d_clisrv.h"
32 #include "../w_wad.h"
33 #include "../z_zone.h"
34 #include "../r_splats.h"
35 #include "../g_game.h"
36 #include "../st_stuff.h"
37 #include "../i_system.h"
38 #include "../m_cheat.h"
39 #include "../f_finale.h"
40 #include "../r_things.h" // R_GetShadowZ
41 #include "../p_slopes.h"
42 #include "hw_md2.h"
43 
44 #ifdef NEWCLIP
45 #include "hw_clip.h"
46 #endif
47 
48 #define R_FAKEFLOORS
49 #define HWPRECIP
50 //#define POLYSKY
51 
52 // ==========================================================================
53 // the hardware driver object
54 // ==========================================================================
55 struct hwdriver_s hwdriver;
56 
57 // ==========================================================================
58 //                                                                     PROTOS
59 // ==========================================================================
60 
61 
62 static void HWR_AddSprites(sector_t *sec);
63 static void HWR_ProjectSprite(mobj_t *thing);
64 #ifdef HWPRECIP
65 static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing);
66 #endif
67 
68 void HWR_AddTransparentFloor(levelflat_t *levelflat, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, boolean fogplane, extracolormap_t *planecolormap);
69 void HWR_AddTransparentPolyobjectFloor(levelflat_t *levelflat, polyobj_t *polysector, boolean isceiling, fixed_t fixedheight,
70                              INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, extracolormap_t *planecolormap);
71 
72 boolean drawsky = true;
73 
74 // ==========================================================================
75 //                                                               VIEW GLOBALS
76 // ==========================================================================
77 // Fineangles in the SCREENWIDTH wide window.
78 #define FIELDOFVIEW ANGLE_90
79 #define ABS(x) ((x) < 0 ? -(x) : (x))
80 
81 static angle_t gl_clipangle;
82 
83 // The viewangletox[viewangle + FINEANGLES/4] lookup
84 // maps the visible view angles to screen X coordinates,
85 // flattening the arc to a flat projection plane.
86 // There will be many angles mapped to the same X.
87 static INT32 gl_viewangletox[FINEANGLES/2];
88 
89 // The xtoviewangleangle[] table maps a screen pixel
90 // to the lowest viewangle that maps back to x ranges
91 // from clipangle to -clipangle.
92 static angle_t gl_xtoviewangle[MAXVIDWIDTH+1];
93 
94 // ==========================================================================
95 //                                                                    GLOBALS
96 // ==========================================================================
97 
98 // uncomment to remove the plane rendering
99 #define DOPLANES
100 //#define DOWALLS
101 
102 // test of drawing sky by polygons like in software with visplane, unfortunately
103 // this doesn't work since we must have z for pixel and z for texture (not like now with z = oow)
104 //#define POLYSKY
105 
106 // test change fov when looking up/down but bsp projection messup :(
107 //#define NOCRAPPYMLOOK
108 
109 // base values set at SetViewSize
110 static float gl_basecentery;
111 
112 float gl_baseviewwindowy, gl_basewindowcentery;
113 float gl_viewwidth, gl_viewheight; // viewport clipping boundaries (screen coords)
114 float gl_viewwindowx;
115 
116 static float gl_centerx, gl_centery;
117 static float gl_viewwindowy; // top left corner of view window
118 static float gl_windowcenterx; // center of view window, for projection
119 static float gl_windowcentery;
120 
121 static float gl_pspritexscale, gl_pspriteyscale;
122 
123 static seg_t *gl_curline;
124 static side_t *gl_sidedef;
125 static line_t *gl_linedef;
126 static sector_t *gl_frontsector;
127 static sector_t *gl_backsector;
128 
129 // --------------------------------------------------------------------------
130 //                                              STUFF FOR THE PROJECTION CODE
131 // --------------------------------------------------------------------------
132 
133 FTransform atransform;
134 // duplicates of the main code, set after R_SetupFrame() passed them into sharedstruct,
135 // copied here for local use
136 static fixed_t dup_viewx, dup_viewy, dup_viewz;
137 static angle_t dup_viewangle;
138 
139 static float gl_viewx, gl_viewy, gl_viewz;
140 static float gl_viewsin, gl_viewcos;
141 
142 // Maybe not necessary with the new T&L code (needs to be checked!)
143 static float gl_viewludsin, gl_viewludcos; // look up down kik test
144 static float gl_fovlud;
145 
146 static angle_t gl_aimingangle;
147 static void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean skybox);
148 
149 // Render stats
150 precise_t ps_hw_skyboxtime = 0;
151 precise_t ps_hw_nodesorttime = 0;
152 precise_t ps_hw_nodedrawtime = 0;
153 precise_t ps_hw_spritesorttime = 0;
154 precise_t ps_hw_spritedrawtime = 0;
155 
156 // Render stats for batching
157 int ps_hw_numpolys = 0;
158 int ps_hw_numverts = 0;
159 int ps_hw_numcalls = 0;
160 int ps_hw_numshaders = 0;
161 int ps_hw_numtextures = 0;
162 int ps_hw_numpolyflags = 0;
163 int ps_hw_numcolors = 0;
164 precise_t ps_hw_batchsorttime = 0;
165 precise_t ps_hw_batchdrawtime = 0;
166 
167 boolean gl_init = false;
168 boolean gl_maploaded = false;
169 boolean gl_sessioncommandsadded = false;
170 boolean gl_shadersavailable = true;
171 
172 // ==========================================================================
173 // Lighting
174 // ==========================================================================
175 
HWR_UseShader(void)176 static boolean HWR_UseShader(void)
177 {
178 	return (cv_glshaders.value && gl_shadersavailable);
179 }
180 
HWR_Lighting(FSurfaceInfo * Surface,INT32 light_level,extracolormap_t * colormap)181 void HWR_Lighting(FSurfaceInfo *Surface, INT32 light_level, extracolormap_t *colormap)
182 {
183 	RGBA_t poly_color, tint_color, fade_color;
184 
185 	poly_color.rgba = 0xFFFFFFFF;
186 	tint_color.rgba = (colormap != NULL) ? (UINT32)colormap->rgba : GL_DEFAULTMIX;
187 	fade_color.rgba = (colormap != NULL) ? (UINT32)colormap->fadergba : GL_DEFAULTFOG;
188 
189 	// Crappy backup coloring if you can't do shaders
190 	if (!HWR_UseShader())
191 	{
192 		// be careful, this may get negative for high lightlevel values.
193 		float tint_alpha, fade_alpha;
194 		float red, green, blue;
195 
196 		red = (float)poly_color.s.red;
197 		green = (float)poly_color.s.green;
198 		blue = (float)poly_color.s.blue;
199 
200 		// 48 is just an arbritrary value that looked relatively okay.
201 		tint_alpha = (float)(sqrt(tint_color.s.alpha) * 48) / 255.0f;
202 
203 		// 8 is roughly the brightness of the "close" color in Software, and 16 the brightness of the "far" color.
204 		// 8 is too bright for dark levels, and 16 is too dark for bright levels.
205 		// 12 is the compromise value. It doesn't look especially good anywhere, but it's the most balanced.
206 		// (Also, as far as I can tell, fade_color's alpha is actually not used in Software, so we only use light level.)
207 		fade_alpha = (float)(sqrt(255-light_level) * 12) / 255.0f;
208 
209 		// Clamp the alpha values
210 		tint_alpha = min(max(tint_alpha, 0.0f), 1.0f);
211 		fade_alpha = min(max(fade_alpha, 0.0f), 1.0f);
212 
213 		red = (tint_color.s.red * tint_alpha) + (red * (1.0f - tint_alpha));
214 		green = (tint_color.s.green * tint_alpha) + (green * (1.0f - tint_alpha));
215 		blue = (tint_color.s.blue * tint_alpha) + (blue * (1.0f - tint_alpha));
216 
217 		red = (fade_color.s.red * fade_alpha) + (red * (1.0f - fade_alpha));
218 		green = (fade_color.s.green * fade_alpha) + (green * (1.0f - fade_alpha));
219 		blue = (fade_color.s.blue * fade_alpha) + (blue * (1.0f - fade_alpha));
220 
221 		poly_color.s.red = (UINT8)red;
222 		poly_color.s.green = (UINT8)green;
223 		poly_color.s.blue = (UINT8)blue;
224 	}
225 
226 	// Clamp the light level, since it can sometimes go out of the 0-255 range from animations
227 	light_level = min(max(light_level, 0), 255);
228 
229 	Surface->PolyColor.rgba = poly_color.rgba;
230 	Surface->TintColor.rgba = tint_color.rgba;
231 	Surface->FadeColor.rgba = fade_color.rgba;
232 	Surface->LightInfo.light_level = light_level;
233 	Surface->LightInfo.fade_start = (colormap != NULL) ? colormap->fadestart : 0;
234 	Surface->LightInfo.fade_end = (colormap != NULL) ? colormap->fadeend : 31;
235 }
236 
HWR_FogBlockAlpha(INT32 light,extracolormap_t * colormap)237 UINT8 HWR_FogBlockAlpha(INT32 light, extracolormap_t *colormap) // Let's see if this can work
238 {
239 	RGBA_t realcolor, surfcolor;
240 	INT32 alpha;
241 
242 	realcolor.rgba = (colormap != NULL) ? colormap->rgba : GL_DEFAULTMIX;
243 
244 	if (cv_glshaders.value && gl_shadersavailable)
245 	{
246 		surfcolor.s.alpha = (255 - light);
247 	}
248 	else
249 	{
250 		light = light - (255 - light);
251 
252 		// Don't go out of bounds
253 		if (light < 0)
254 			light = 0;
255 		else if (light > 255)
256 			light = 255;
257 
258 		alpha = (realcolor.s.alpha*255)/25;
259 
260 		// at 255 brightness, alpha is between 0 and 127, at 0 brightness alpha will always be 255
261 		surfcolor.s.alpha = (alpha*light) / (2*256) + 255-light;
262 	}
263 
264 	return surfcolor.s.alpha;
265 }
266 
HWR_CalcWallLight(FUINT lightnum,fixed_t v1x,fixed_t v1y,fixed_t v2x,fixed_t v2y)267 static FUINT HWR_CalcWallLight(FUINT lightnum, fixed_t v1x, fixed_t v1y, fixed_t v2x, fixed_t v2y)
268 {
269 	INT16 finallight = lightnum;
270 
271 	if (cv_glfakecontrast.value != 0)
272 	{
273 		const UINT8 contrast = 8;
274 		fixed_t extralight = 0;
275 
276 		if (cv_glfakecontrast.value == 2) // Smooth setting
277 		{
278 			extralight = (-(contrast<<FRACBITS) +
279 			FixedDiv(AngleFixed(R_PointToAngle2(0, 0,
280 				abs(v1x - v2x),
281 				abs(v1y - v2y))), 90<<FRACBITS)
282 			* (contrast * 2)) >> FRACBITS;
283 		}
284 		else
285 		{
286 			if (v1y == v2y)
287 				extralight = -contrast;
288 			else if (v1x == v2x)
289 				extralight = contrast;
290 		}
291 
292 		if (extralight != 0)
293 		{
294 			finallight += extralight;
295 
296 			if (finallight < 0)
297 				finallight = 0;
298 			if (finallight > 255)
299 				finallight = 255;
300 		}
301 	}
302 
303 	return (FUINT)finallight;
304 }
305 
HWR_CalcSlopeLight(FUINT lightnum,angle_t dir,fixed_t delta)306 static FUINT HWR_CalcSlopeLight(FUINT lightnum, angle_t dir, fixed_t delta)
307 {
308 	INT16 finallight = lightnum;
309 
310 	if (cv_glfakecontrast.value != 0 && cv_glslopecontrast.value != 0)
311 	{
312 		const UINT8 contrast = 8;
313 		fixed_t extralight = 0;
314 
315 		if (cv_glfakecontrast.value == 2) // Smooth setting
316 		{
317 			fixed_t dirmul = abs(FixedDiv(AngleFixed(dir) - (180<<FRACBITS), 180<<FRACBITS));
318 
319 			extralight = -(contrast<<FRACBITS) + (dirmul * (contrast * 2));
320 
321 			extralight = FixedMul(extralight, delta*4) >> FRACBITS;
322 		}
323 		else
324 		{
325 			dir = ((dir + ANGLE_45) / ANGLE_90) * ANGLE_90;
326 
327 			if (dir == ANGLE_180)
328 				extralight = -contrast;
329 			else if (dir == 0)
330 				extralight = contrast;
331 
332 			if (delta >= FRACUNIT/2)
333 				extralight *= 2;
334 		}
335 
336 		if (extralight != 0)
337 		{
338 			finallight += extralight;
339 
340 			if (finallight < 0)
341 				finallight = 0;
342 			if (finallight > 255)
343 				finallight = 255;
344 		}
345 	}
346 
347 	return (FUINT)finallight;
348 }
349 
350 // ==========================================================================
351 //                                   FLOOR/CEILING GENERATION FROM SUBSECTORS
352 // ==========================================================================
353 
354 #ifdef DOPLANES
355 
356 // -----------------+
357 // HWR_RenderPlane  : Render a floor or ceiling convex polygon
358 // -----------------+
HWR_RenderPlane(subsector_t * subsector,extrasubsector_t * xsub,boolean isceiling,fixed_t fixedheight,FBITFIELD PolyFlags,INT32 lightlevel,levelflat_t * levelflat,sector_t * FOFsector,UINT8 alpha,extracolormap_t * planecolormap)359 static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, FBITFIELD PolyFlags, INT32 lightlevel, levelflat_t *levelflat, sector_t *FOFsector, UINT8 alpha, extracolormap_t *planecolormap)
360 {
361 	polyvertex_t *  pv;
362 	float           height; //constant y for all points on the convex flat polygon
363 	FOutVector      *v3d;
364 	INT32             nrPlaneVerts;   //verts original define of convex flat polygon
365 	INT32             i;
366 	float           flatxref,flatyref;
367 	float fflatwidth = 64.0f, fflatheight = 64.0f;
368 	INT32 flatflag = 63;
369 	boolean texflat = false;
370 	float scrollx = 0.0f, scrolly = 0.0f;
371 	angle_t angle = 0;
372 	FSurfaceInfo    Surf;
373 	fixed_t tempxsow, tempytow;
374 	pslope_t *slope = NULL;
375 
376 	static FOutVector *planeVerts = NULL;
377 	static UINT16 numAllocedPlaneVerts = 0;
378 
379 	INT32 shader = SHADER_DEFAULT;
380 
381 	// no convex poly were generated for this subsector
382 	if (!xsub->planepoly)
383 		return;
384 
385 	// Get the slope pointer to simplify future code
386 	if (FOFsector)
387 	{
388 		if (FOFsector->f_slope && !isceiling)
389 			slope = FOFsector->f_slope;
390 		else if (FOFsector->c_slope && isceiling)
391 			slope = FOFsector->c_slope;
392 	}
393 	else
394 	{
395 		if (gl_frontsector->f_slope && !isceiling)
396 			slope = gl_frontsector->f_slope;
397 		else if (gl_frontsector->c_slope && isceiling)
398 			slope = gl_frontsector->c_slope;
399 	}
400 
401 	// Set fixedheight to the slope's height from our viewpoint, if we have a slope
402 	if (slope)
403 		fixedheight = P_GetSlopeZAt(slope, viewx, viewy);
404 
405 	height = FIXED_TO_FLOAT(fixedheight);
406 
407 	pv  = xsub->planepoly->pts;
408 	nrPlaneVerts = xsub->planepoly->numpts;
409 
410 	if (nrPlaneVerts < 3)   //not even a triangle ?
411 		return;
412 
413 	// Allocate plane-vertex buffer if we need to
414 	if (!planeVerts || nrPlaneVerts > numAllocedPlaneVerts)
415 	{
416 		numAllocedPlaneVerts = (UINT16)nrPlaneVerts;
417 		Z_Free(planeVerts);
418 		Z_Malloc(numAllocedPlaneVerts * sizeof (FOutVector), PU_LEVEL, &planeVerts);
419 	}
420 
421 	// set texture for polygon
422 	if (levelflat != NULL)
423 	{
424 		if (levelflat->type == LEVELFLAT_FLAT)
425 		{
426 			size_t len = W_LumpLength(levelflat->u.flat.lumpnum);
427 			switch (len)
428 			{
429 				case 4194304: // 2048x2048 lump
430 					fflatwidth = fflatheight = 2048.0f;
431 					break;
432 				case 1048576: // 1024x1024 lump
433 					fflatwidth = fflatheight = 1024.0f;
434 					break;
435 				case 262144:// 512x512 lump
436 					fflatwidth = fflatheight = 512.0f;
437 					break;
438 				case 65536: // 256x256 lump
439 					fflatwidth = fflatheight = 256.0f;
440 					break;
441 				case 16384: // 128x128 lump
442 					fflatwidth = fflatheight = 128.0f;
443 					break;
444 				case 1024: // 32x32 lump
445 					fflatwidth = fflatheight = 32.0f;
446 					break;
447 				default: // 64x64 lump
448 					fflatwidth = fflatheight = 64.0f;
449 					break;
450 			}
451 			flatflag = ((INT32)fflatwidth)-1;
452 		}
453 		else
454 		{
455 			if (levelflat->type == LEVELFLAT_TEXTURE)
456 			{
457 				fflatwidth = textures[levelflat->u.texture.num]->width;
458 				fflatheight = textures[levelflat->u.texture.num]->height;
459 			}
460 			else if (levelflat->type == LEVELFLAT_PATCH || levelflat->type == LEVELFLAT_PNG)
461 			{
462 				fflatwidth = levelflat->width;
463 				fflatheight = levelflat->height;
464 			}
465 			texflat = true;
466 		}
467 	}
468 	else // set no texture
469 		HWR_SetCurrentTexture(NULL);
470 
471 	// reference point for flat texture coord for each vertex around the polygon
472 	flatxref = (float)(((fixed_t)pv->x & (~flatflag)) / fflatwidth);
473 	flatyref = (float)(((fixed_t)pv->y & (~flatflag)) / fflatheight);
474 
475 	// transform
476 	if (FOFsector != NULL)
477 	{
478 		if (!isceiling) // it's a floor
479 		{
480 			scrollx = FIXED_TO_FLOAT(FOFsector->floor_xoffs)/fflatwidth;
481 			scrolly = FIXED_TO_FLOAT(FOFsector->floor_yoffs)/fflatheight;
482 			angle = FOFsector->floorpic_angle;
483 		}
484 		else // it's a ceiling
485 		{
486 			scrollx = FIXED_TO_FLOAT(FOFsector->ceiling_xoffs)/fflatwidth;
487 			scrolly = FIXED_TO_FLOAT(FOFsector->ceiling_yoffs)/fflatheight;
488 			angle = FOFsector->ceilingpic_angle;
489 		}
490 	}
491 	else if (gl_frontsector)
492 	{
493 		if (!isceiling) // it's a floor
494 		{
495 			scrollx = FIXED_TO_FLOAT(gl_frontsector->floor_xoffs)/fflatwidth;
496 			scrolly = FIXED_TO_FLOAT(gl_frontsector->floor_yoffs)/fflatheight;
497 			angle = gl_frontsector->floorpic_angle;
498 		}
499 		else // it's a ceiling
500 		{
501 			scrollx = FIXED_TO_FLOAT(gl_frontsector->ceiling_xoffs)/fflatwidth;
502 			scrolly = FIXED_TO_FLOAT(gl_frontsector->ceiling_yoffs)/fflatheight;
503 			angle = gl_frontsector->ceilingpic_angle;
504 		}
505 	}
506 
507 
508 	if (angle) // Only needs to be done if there's an altered angle
509 	{
510 
511 		angle = (InvAngle(angle))>>ANGLETOFINESHIFT;
512 
513 		// This needs to be done so that it scrolls in a different direction after rotation like software
514 		/*tempxsow = FLOAT_TO_FIXED(scrollx);
515 		tempytow = FLOAT_TO_FIXED(scrolly);
516 		scrollx = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINECOSINE(angle)) - FixedMul(tempytow, FINESINE(angle))));
517 		scrolly = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINESINE(angle)) + FixedMul(tempytow, FINECOSINE(angle))));*/
518 
519 		// This needs to be done so everything aligns after rotation
520 		// It would be done so that rotation is done, THEN the translation, but I couldn't get it to rotate AND scroll like software does
521 		tempxsow = FLOAT_TO_FIXED(flatxref);
522 		tempytow = FLOAT_TO_FIXED(flatyref);
523 		flatxref = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINECOSINE(angle)) - FixedMul(tempytow, FINESINE(angle))));
524 		flatyref = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINESINE(angle)) + FixedMul(tempytow, FINECOSINE(angle))));
525 	}
526 
527 #define SETUP3DVERT(vert, vx, vy) {\
528 		/* Hurdler: add scrolling texture on floor/ceiling */\
529 		if (texflat)\
530 		{\
531 			vert->s = (float)((vx) / fflatwidth) + scrollx;\
532 			vert->t = -(float)((vy) / fflatheight) + scrolly;\
533 		}\
534 		else\
535 		{\
536 			vert->s = (float)(((vx) / fflatwidth) - flatxref + scrollx);\
537 			vert->t = (float)(flatyref - ((vy) / fflatheight) + scrolly);\
538 		}\
539 \
540 		/* Need to rotate before translate */\
541 		if (angle) /* Only needs to be done if there's an altered angle */\
542 		{\
543 			tempxsow = FLOAT_TO_FIXED(vert->s);\
544 			tempytow = FLOAT_TO_FIXED(vert->t);\
545 			vert->s = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINECOSINE(angle)) - FixedMul(tempytow, FINESINE(angle))));\
546 			vert->t = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINESINE(angle)) + FixedMul(tempytow, FINECOSINE(angle))));\
547 		}\
548 \
549 		vert->x = (vx);\
550 		vert->y = height;\
551 		vert->z = (vy);\
552 \
553 		if (slope)\
554 		{\
555 			fixedheight = P_GetSlopeZAt(slope, FLOAT_TO_FIXED((vx)), FLOAT_TO_FIXED((vy)));\
556 			vert->y = FIXED_TO_FLOAT(fixedheight);\
557 		}\
558 }
559 
560 	for (i = 0, v3d = planeVerts; i < nrPlaneVerts; i++,v3d++,pv++)
561 		SETUP3DVERT(v3d, pv->x, pv->y);
562 
563 	if (slope)
564 		lightlevel = HWR_CalcSlopeLight(lightlevel, R_PointToAngle2(0, 0, slope->normal.x, slope->normal.y), abs(slope->zdelta));
565 
566 	HWR_Lighting(&Surf, lightlevel, planecolormap);
567 
568 	if (PolyFlags & (PF_Translucent|PF_Fog))
569 	{
570 		Surf.PolyColor.s.alpha = (UINT8)alpha;
571 		PolyFlags |= PF_Modulated;
572 	}
573 	else
574 		PolyFlags |= PF_Masked|PF_Modulated;
575 
576 	if (HWR_UseShader())
577 	{
578 		if (PolyFlags & PF_Fog)
579 			shader = SHADER_FOG;
580 		else if (PolyFlags & PF_Ripple)
581 			shader = SHADER_WATER;
582 		else
583 			shader = SHADER_FLOOR;
584 
585 		PolyFlags |= PF_ColorMapped;
586 	}
587 
588 	HWR_ProcessPolygon(&Surf, planeVerts, nrPlaneVerts, PolyFlags, shader, false);
589 
590 	if (subsector)
591 	{
592 		// Horizon lines
593 		FOutVector horizonpts[6];
594 		float dist, vx, vy;
595 		float x1, y1, xd, yd;
596 		UINT8 numplanes, j;
597 		vertex_t v; // For determining the closest distance from the line to the camera, to split render planes for minimum distortion;
598 
599 		const float renderdist = 27000.0f; // How far out to properly render the plane
600 		const float farrenderdist = 32768.0f; // From here, raise plane to horizon level to fill in the line with some texture distortion
601 
602 		seg_t *line = &segs[subsector->firstline];
603 
604 		for (i = 0; i < subsector->numlines; i++, line++)
605 		{
606 			if (!line->glseg && line->linedef->special == HORIZONSPECIAL && R_PointOnSegSide(dup_viewx, dup_viewy, line) == 0)
607 			{
608 				P_ClosestPointOnLine(viewx, viewy, line->linedef, &v);
609 				dist = FIXED_TO_FLOAT(R_PointToDist(v.x, v.y));
610 
611 				x1 = ((polyvertex_t *)line->pv1)->x;
612 				y1 = ((polyvertex_t *)line->pv1)->y;
613 				xd = ((polyvertex_t *)line->pv2)->x - x1;
614 				yd = ((polyvertex_t *)line->pv2)->y - y1;
615 
616 				// Based on the seg length and the distance from the line, split horizon into multiple poly sets to reduce distortion
617 				dist = sqrtf((xd*xd) + (yd*yd)) / dist / 16.0f;
618 				if (dist > 100.0f)
619 					numplanes = 100;
620 				else
621 					numplanes = (UINT8)dist + 1;
622 
623 				for (j = 0; j < numplanes; j++)
624 				{
625 					// Left side
626 					vx = x1 + xd * j / numplanes;
627 					vy = y1 + yd * j / numplanes;
628 					SETUP3DVERT((&horizonpts[1]), vx, vy);
629 
630 					dist = sqrtf(powf(vx - gl_viewx, 2) + powf(vy - gl_viewy, 2));
631 					vx = (vx - gl_viewx) * renderdist / dist + gl_viewx;
632 					vy = (vy - gl_viewy) * renderdist / dist + gl_viewy;
633 					SETUP3DVERT((&horizonpts[0]), vx, vy);
634 
635 					// Right side
636 					vx = x1 + xd * (j+1) / numplanes;
637 					vy = y1 + yd * (j+1) / numplanes;
638 					SETUP3DVERT((&horizonpts[2]), vx, vy);
639 
640 					dist = sqrtf(powf(vx - gl_viewx, 2) + powf(vy - gl_viewy, 2));
641 					vx = (vx - gl_viewx) * renderdist / dist + gl_viewx;
642 					vy = (vy - gl_viewy) * renderdist / dist + gl_viewy;
643 					SETUP3DVERT((&horizonpts[3]), vx, vy);
644 
645 					// Horizon fills
646 					vx = (horizonpts[0].x - gl_viewx) * farrenderdist / renderdist + gl_viewx;
647 					vy = (horizonpts[0].z - gl_viewy) * farrenderdist / renderdist + gl_viewy;
648 					SETUP3DVERT((&horizonpts[5]), vx, vy);
649 					horizonpts[5].y = gl_viewz;
650 
651 					vx = (horizonpts[3].x - gl_viewx) * farrenderdist / renderdist + gl_viewx;
652 					vy = (horizonpts[3].z - gl_viewy) * farrenderdist / renderdist + gl_viewy;
653 					SETUP3DVERT((&horizonpts[4]), vx, vy);
654 					horizonpts[4].y = gl_viewz;
655 
656 					// Draw
657 					HWR_ProcessPolygon(&Surf, horizonpts, 6, PolyFlags, shader, true);
658 				}
659 			}
660 		}
661 	}
662 
663 #ifdef ALAM_LIGHTING
664 	// add here code for dynamic lighting on planes
665 	HWR_PlaneLighting(planeVerts, nrPlaneVerts);
666 #endif
667 }
668 
669 #ifdef POLYSKY
670 // this don't draw anything it only update the z-buffer so there isn't problem with
671 // wall/things upper that sky (map12)
HWR_RenderSkyPlane(extrasubsector_t * xsub,fixed_t fixedheight)672 static void HWR_RenderSkyPlane(extrasubsector_t *xsub, fixed_t fixedheight)
673 {
674 	polyvertex_t *pv;
675 	float height; //constant y for all points on the convex flat polygon
676 	FOutVector *v3d;
677 	INT32 nrPlaneVerts;   //verts original define of convex flat polygon
678 	INT32 i;
679 
680 	// no convex poly were generated for this subsector
681 	if (!xsub->planepoly)
682 		return;
683 
684 	height = FIXED_TO_FLOAT(fixedheight);
685 
686 	pv  = xsub->planepoly->pts;
687 	nrPlaneVerts = xsub->planepoly->numpts;
688 
689 	if (nrPlaneVerts < 3) // not even a triangle?
690 		return;
691 
692 	if (nrPlaneVerts > MAXPLANEVERTICES) // FIXME: exceeds plVerts size
693 	{
694 		CONS_Debug(DBG_RENDER, "polygon size of %d exceeds max value of %d vertices\n", nrPlaneVerts, MAXPLANEVERTICES);
695 		return;
696 	}
697 
698 	// transform
699 	v3d = planeVerts;
700 	for (i = 0; i < nrPlaneVerts; i++,v3d++,pv++)
701 	{
702 		v3d->s = 0.0f;
703 		v3d->t = 0.0f;
704 		v3d->x = pv->x;
705 		v3d->y = height;
706 		v3d->z = pv->y;
707 	}
708 
709 	HWD.pfnDrawPolygon(NULL, planeVerts, nrPlaneVerts, PF_Invisible|PF_NoTexture|PF_Occlude);
710 }
711 #endif //polysky
712 
713 #endif //doplanes
714 
HWR_GetBlendModeFlag(INT32 ast)715 FBITFIELD HWR_GetBlendModeFlag(INT32 ast)
716 {
717 	switch (ast)
718 	{
719 		case AST_COPY:
720 		case AST_OVERLAY:
721 			return PF_Masked;
722 		case AST_ADD:
723 			return PF_Additive;
724 		case AST_SUBTRACT:
725 			return PF_Subtractive;
726 		case AST_REVERSESUBTRACT:
727 			return PF_ReverseSubtract;
728 		case AST_MODULATE:
729 			return PF_Multiplicative;
730 		default:
731 			return PF_Translucent;
732 	}
733 
734 	return 0;
735 }
736 
HWR_GetTranstableAlpha(INT32 transtablenum)737 UINT8 HWR_GetTranstableAlpha(INT32 transtablenum)
738 {
739 	transtablenum = max(min(transtablenum, tr_trans90), 0);
740 
741 	switch (transtablenum)
742 	{
743 		case 0          : return 0xff;
744 		case tr_trans10 : return 0xe6;
745 		case tr_trans20 : return 0xcc;
746 		case tr_trans30 : return 0xb3;
747 		case tr_trans40 : return 0x99;
748 		case tr_trans50 : return 0x80;
749 		case tr_trans60 : return 0x66;
750 		case tr_trans70 : return 0x4c;
751 		case tr_trans80 : return 0x33;
752 		case tr_trans90 : return 0x19;
753 	}
754 
755 	return 0xff;
756 }
757 
HWR_SurfaceBlend(INT32 style,INT32 transtablenum,FSurfaceInfo * pSurf)758 FBITFIELD HWR_SurfaceBlend(INT32 style, INT32 transtablenum, FSurfaceInfo *pSurf)
759 {
760 	if (!transtablenum || style == AST_COPY || style == AST_OVERLAY)
761 	{
762 		pSurf->PolyColor.s.alpha = 0xff;
763 		return PF_Masked;
764 	}
765 
766 	pSurf->PolyColor.s.alpha = HWR_GetTranstableAlpha(transtablenum);
767 	return HWR_GetBlendModeFlag(style);
768 }
769 
HWR_TranstableToAlpha(INT32 transtablenum,FSurfaceInfo * pSurf)770 FBITFIELD HWR_TranstableToAlpha(INT32 transtablenum, FSurfaceInfo *pSurf)
771 {
772 	if (!transtablenum)
773 	{
774 		pSurf->PolyColor.s.alpha = 0x00;
775 		return PF_Masked;
776 	}
777 
778 	pSurf->PolyColor.s.alpha = HWR_GetTranstableAlpha(transtablenum);
779 	return PF_Translucent;
780 }
781 
782 static void HWR_AddTransparentWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, INT32 texnum, FBITFIELD blend, boolean fogwall, INT32 lightlevel, extracolormap_t *wallcolormap);
783 
784 // ==========================================================================
785 // Wall generation from subsector segs
786 // ==========================================================================
787 
788 /*
789    wallVerts order is :
790 		3--2
791 		| /|
792 		|/ |
793 		0--1
794 */
795 
796 //
797 // HWR_ProjectWall
798 //
HWR_ProjectWall(FOutVector * wallVerts,FSurfaceInfo * pSurf,FBITFIELD blendmode,INT32 lightlevel,extracolormap_t * wallcolormap)799 static void HWR_ProjectWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blendmode, INT32 lightlevel, extracolormap_t *wallcolormap)
800 {
801 	INT32 shader = SHADER_DEFAULT;
802 
803 	HWR_Lighting(pSurf, lightlevel, wallcolormap);
804 
805 	if (HWR_UseShader())
806 	{
807 		shader = SHADER_WALL;
808 		blendmode |= PF_ColorMapped;
809 	}
810 
811 	HWR_ProcessPolygon(pSurf, wallVerts, 4, blendmode|PF_Modulated|PF_Occlude, shader, false);
812 }
813 
814 // ==========================================================================
815 //                                                          BSP, CULL, ETC..
816 // ==========================================================================
817 
818 // return the frac from the interception of the clipping line
819 // (in fact a clipping plane that has a constant, so can clip with simple 2d)
820 // with the wall segment
821 //
822 #ifndef NEWCLIP
HWR_ClipViewSegment(INT32 x,polyvertex_t * v1,polyvertex_t * v2)823 static float HWR_ClipViewSegment(INT32 x, polyvertex_t *v1, polyvertex_t *v2)
824 {
825 	float num, den;
826 	float v1x, v1y, v1dx, v1dy, v2dx, v2dy;
827 	angle_t pclipangle = gl_xtoviewangle[x];
828 
829 	// a segment of a polygon
830 	v1x  = v1->x;
831 	v1y  = v1->y;
832 	v1dx = (v2->x - v1->x);
833 	v1dy = (v2->y - v1->y);
834 
835 	// the clipping line
836 	pclipangle = pclipangle + dup_viewangle; //back to normal angle (non-relative)
837 	v2dx = FIXED_TO_FLOAT(FINECOSINE(pclipangle>>ANGLETOFINESHIFT));
838 	v2dy = FIXED_TO_FLOAT(FINESINE(pclipangle>>ANGLETOFINESHIFT));
839 
840 	den = v2dy*v1dx - v2dx*v1dy;
841 	if (den == 0)
842 		return -1; // parallel
843 
844 	// calc the frac along the polygon segment,
845 	//num = (v2x - v1x)*v2dy + (v1y - v2y)*v2dx;
846 	//num = -v1x * v2dy + v1y * v2dx;
847 	num = (gl_viewx - v1x)*v2dy + (v1y - gl_viewy)*v2dx;
848 
849 	return num / den;
850 }
851 #endif
852 
853 //
854 // HWR_SplitWall
855 //
HWR_SplitWall(sector_t * sector,FOutVector * wallVerts,INT32 texnum,FSurfaceInfo * Surf,INT32 cutflag,ffloor_t * pfloor,FBITFIELD polyflags)856 static void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum, FSurfaceInfo* Surf, INT32 cutflag, ffloor_t *pfloor, FBITFIELD polyflags)
857 {
858 	/* SoM: split up and light walls according to the
859 	 lightlist. This may also include leaving out parts
860 	 of the wall that can't be seen */
861 
862 	float realtop, realbot, top, bot;
863 	float pegt, pegb, pegmul;
864 	float height = 0.0f, bheight = 0.0f;
865 
866 	float endrealtop, endrealbot, endtop, endbot;
867 	float endpegt, endpegb, endpegmul;
868 	float endheight = 0.0f, endbheight = 0.0f;
869 
870 	// compiler complains when P_GetSlopeZAt is used in FLOAT_TO_FIXED directly
871 	// use this as a temp var to store P_GetSlopeZAt's return value each time
872 	fixed_t temp;
873 
874 	fixed_t v1x = FLOAT_TO_FIXED(wallVerts[0].x);
875 	fixed_t v1y = FLOAT_TO_FIXED(wallVerts[0].z); // not a typo
876 	fixed_t v2x = FLOAT_TO_FIXED(wallVerts[1].x);
877 	fixed_t v2y = FLOAT_TO_FIXED(wallVerts[1].z); // not a typo
878 
879 	INT32 solid, i;
880 	lightlist_t *  list = sector->lightlist;
881 	const UINT8 alpha = Surf->PolyColor.s.alpha;
882 	FUINT lightnum = HWR_CalcWallLight(sector->lightlevel, v1x, v1y, v2x, v2y);
883 	extracolormap_t *colormap = NULL;
884 
885 	realtop = top = wallVerts[3].y;
886 	realbot = bot = wallVerts[0].y;
887 	pegt = wallVerts[3].t;
888 	pegb = wallVerts[0].t;
889 	pegmul = (pegb - pegt) / (top - bot);
890 
891 	endrealtop = endtop = wallVerts[2].y;
892 	endrealbot = endbot = wallVerts[1].y;
893 	endpegt = wallVerts[2].t;
894 	endpegb = wallVerts[1].t;
895 	endpegmul = (endpegb - endpegt) / (endtop - endbot);
896 
897 	for (i = 0; i < sector->numlights; i++)
898 	{
899 		if (endtop < endrealbot && top < realbot)
900 			return;
901 
902 		if (!(list[i].flags & FF_NOSHADE))
903 		{
904 			if (pfloor && (pfloor->flags & FF_FOG))
905 			{
906 				lightnum = HWR_CalcWallLight(pfloor->master->frontsector->lightlevel, v1x, v1y, v2x, v2y);
907 				colormap = pfloor->master->frontsector->extra_colormap;
908 			}
909 			else
910 			{
911 				lightnum = HWR_CalcWallLight(*list[i].lightlevel, v1x, v1y, v2x, v2y);
912 				colormap = *list[i].extra_colormap;
913 			}
914 		}
915 
916 		solid = false;
917 
918 		if ((sector->lightlist[i].flags & FF_CUTSOLIDS) && !(cutflag & FF_EXTRA))
919 			solid = true;
920 		else if ((sector->lightlist[i].flags & FF_CUTEXTRA) && (cutflag & FF_EXTRA))
921 		{
922 			if (sector->lightlist[i].flags & FF_EXTRA)
923 			{
924 				if ((sector->lightlist[i].flags & (FF_FOG|FF_SWIMMABLE)) == (cutflag & (FF_FOG|FF_SWIMMABLE))) // Only merge with your own types
925 					solid = true;
926 			}
927 			else
928 				solid = true;
929 		}
930 		else
931 			solid = false;
932 
933 		temp = P_GetLightZAt(&list[i], v1x, v1y);
934 		height = FIXED_TO_FLOAT(temp);
935 		temp = P_GetLightZAt(&list[i], v2x, v2y);
936 		endheight = FIXED_TO_FLOAT(temp);
937 		if (solid)
938 		{
939 			temp = P_GetFFloorBottomZAt(list[i].caster, v1x, v1y);
940 			bheight = FIXED_TO_FLOAT(temp);
941 			temp = P_GetFFloorBottomZAt(list[i].caster, v2x, v2y);
942 			endbheight = FIXED_TO_FLOAT(temp);
943 		}
944 
945 		if (endheight >= endtop && height >= top)
946 		{
947 			if (solid && top > bheight)
948 				top = bheight;
949 			if (solid && endtop > endbheight)
950 				endtop = endbheight;
951 		}
952 
953 		if (i + 1 < sector->numlights)
954 		{
955 			temp = P_GetLightZAt(&list[i+1], v1x, v1y);
956 			bheight = FIXED_TO_FLOAT(temp);
957 			temp = P_GetLightZAt(&list[i+1], v2x, v2y);
958 			endbheight = FIXED_TO_FLOAT(temp);
959 		}
960 		else
961 		{
962 			bheight = realbot;
963 			endbheight = endrealbot;
964 		}
965 
966 		if (endbheight >= endtop && bheight >= top)
967 			continue;
968 
969 		//Found a break;
970 		bot = bheight;
971 
972 		if (bot < realbot)
973 			bot = realbot;
974 
975 		endbot = endbheight;
976 
977 		if (endbot < endrealbot)
978 			endbot = endrealbot;
979 
980 		Surf->PolyColor.s.alpha = alpha;
981 
982 		wallVerts[3].t = pegt + ((realtop - top) * pegmul);
983 		wallVerts[2].t = endpegt + ((endrealtop - endtop) * endpegmul);
984 		wallVerts[0].t = pegt + ((realtop - bot) * pegmul);
985 		wallVerts[1].t = endpegt + ((endrealtop - endbot) * endpegmul);
986 
987 		// set top/bottom coords
988 		wallVerts[3].y = top;
989 		wallVerts[2].y = endtop;
990 		wallVerts[0].y = bot;
991 		wallVerts[1].y = endbot;
992 
993 		if (cutflag & FF_FOG)
994 			HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Fog|PF_NoTexture|polyflags, true, lightnum, colormap);
995 		else if (cutflag & FF_TRANSLUCENT)
996 			HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Translucent|polyflags, false, lightnum, colormap);
997 		else
998 			HWR_ProjectWall(wallVerts, Surf, PF_Masked|polyflags, lightnum, colormap);
999 
1000 		top = bot;
1001 		endtop = endbot;
1002 	}
1003 
1004 	bot = realbot;
1005 	endbot = endrealbot;
1006 	if (endtop <= endrealbot && top <= realbot)
1007 		return;
1008 
1009 	Surf->PolyColor.s.alpha = alpha;
1010 
1011 	wallVerts[3].t = pegt + ((realtop - top) * pegmul);
1012 	wallVerts[2].t = endpegt + ((endrealtop - endtop) * endpegmul);
1013 	wallVerts[0].t = pegt + ((realtop - bot) * pegmul);
1014 	wallVerts[1].t = endpegt + ((endrealtop - endbot) * endpegmul);
1015 
1016 	// set top/bottom coords
1017 	wallVerts[3].y = top;
1018 	wallVerts[2].y = endtop;
1019 	wallVerts[0].y = bot;
1020 	wallVerts[1].y = endbot;
1021 
1022 	if (cutflag & FF_FOG)
1023 		HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Fog|PF_NoTexture|polyflags, true, lightnum, colormap);
1024 	else if (cutflag & FF_TRANSLUCENT)
1025 		HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Translucent|polyflags, false, lightnum, colormap);
1026 	else
1027 		HWR_ProjectWall(wallVerts, Surf, PF_Masked|polyflags, lightnum, colormap);
1028 }
1029 
1030 // HWR_DrawSkyWall
1031 // Draw walls into the depth buffer so that anything behind is culled properly
HWR_DrawSkyWall(FOutVector * wallVerts,FSurfaceInfo * Surf)1032 static void HWR_DrawSkyWall(FOutVector *wallVerts, FSurfaceInfo *Surf)
1033 {
1034 	HWR_SetCurrentTexture(NULL);
1035 	// no texture
1036 	wallVerts[3].t = wallVerts[2].t = 0;
1037 	wallVerts[0].t = wallVerts[1].t = 0;
1038 	wallVerts[0].s = wallVerts[3].s = 0;
1039 	wallVerts[2].s = wallVerts[1].s = 0;
1040 	// this no longer sets top/bottom coords, this should be done before caling the function
1041 	HWR_ProjectWall(wallVerts, Surf, PF_Invisible|PF_NoTexture, 255, NULL);
1042 	// PF_Invisible so it's not drawn into the colour buffer
1043 	// PF_NoTexture for no texture
1044 	// PF_Occlude is set in HWR_ProjectWall to draw into the depth buffer
1045 }
1046 
1047 //
1048 // HWR_ProcessSeg
1049 // A portion or all of a wall segment will be drawn, from startfrac to endfrac,
1050 //  where 0 is the start of the segment, 1 the end of the segment
1051 // Anything between means the wall segment has been clipped with solidsegs,
1052 //  reducing wall overdraw to a minimum
1053 //
HWR_ProcessSeg(void)1054 static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
1055 {
1056 	FOutVector wallVerts[4];
1057 	v2d_t vs, ve; // start, end vertices of 2d line (view from above)
1058 
1059 	fixed_t worldtop, worldbottom;
1060 	fixed_t worldhigh = 0, worldlow = 0;
1061 	fixed_t worldtopslope, worldbottomslope;
1062 	fixed_t worldhighslope = 0, worldlowslope = 0;
1063 	fixed_t v1x, v1y, v2x, v2y;
1064 
1065 	GLMapTexture_t *grTex = NULL;
1066 	float cliplow = 0.0f, cliphigh = 0.0f;
1067 	INT32 gl_midtexture;
1068 	fixed_t h, l; // 3D sides and 2s middle textures
1069 	fixed_t hS, lS;
1070 
1071 	FUINT lightnum = 0; // shut up compiler
1072 	extracolormap_t *colormap;
1073 	FSurfaceInfo Surf;
1074 
1075 	gl_sidedef = gl_curline->sidedef;
1076 	gl_linedef = gl_curline->linedef;
1077 
1078 	vs.x = ((polyvertex_t *)gl_curline->pv1)->x;
1079 	vs.y = ((polyvertex_t *)gl_curline->pv1)->y;
1080 	ve.x = ((polyvertex_t *)gl_curline->pv2)->x;
1081 	ve.y = ((polyvertex_t *)gl_curline->pv2)->y;
1082 
1083 	v1x = FLOAT_TO_FIXED(vs.x);
1084 	v1y = FLOAT_TO_FIXED(vs.y);
1085 	v2x = FLOAT_TO_FIXED(ve.x);
1086 	v2y = FLOAT_TO_FIXED(ve.y);
1087 
1088 #define SLOPEPARAMS(slope, end1, end2, normalheight) \
1089 	end1 = P_GetZAt(slope, v1x, v1y, normalheight); \
1090 	end2 = P_GetZAt(slope, v2x, v2y, normalheight);
1091 
1092 	SLOPEPARAMS(gl_frontsector->c_slope, worldtop,    worldtopslope,    gl_frontsector->ceilingheight)
1093 	SLOPEPARAMS(gl_frontsector->f_slope, worldbottom, worldbottomslope, gl_frontsector->floorheight)
1094 
1095 	// remember vertices ordering
1096 	//  3--2
1097 	//  | /|
1098 	//  |/ |
1099 	//  0--1
1100 	// make a wall polygon (with 2 triangles), using the floor/ceiling heights,
1101 	// and the 2d map coords of start/end vertices
1102 	wallVerts[0].x = wallVerts[3].x = vs.x;
1103 	wallVerts[0].z = wallVerts[3].z = vs.y;
1104 	wallVerts[2].x = wallVerts[1].x = ve.x;
1105 	wallVerts[2].z = wallVerts[1].z = ve.y;
1106 
1107 	// x offset the texture
1108 	{
1109 		fixed_t texturehpeg = gl_sidedef->textureoffset + gl_curline->offset;
1110 		cliplow = (float)texturehpeg;
1111 		cliphigh = (float)(texturehpeg + (gl_curline->flength*FRACUNIT));
1112 	}
1113 
1114 	lightnum = HWR_CalcWallLight(gl_frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y);
1115 	colormap = gl_frontsector->extra_colormap;
1116 
1117 	if (gl_frontsector)
1118 		Surf.PolyColor.s.alpha = 255;
1119 
1120 	if (gl_backsector)
1121 	{
1122 		INT32 gl_toptexture = 0, gl_bottomtexture = 0;
1123 		// two sided line
1124 		boolean bothceilingssky = false; // turned on if both back and front ceilings are sky
1125 		boolean bothfloorssky = false; // likewise, but for floors
1126 
1127 		SLOPEPARAMS(gl_backsector->c_slope, worldhigh, worldhighslope, gl_backsector->ceilingheight)
1128 		SLOPEPARAMS(gl_backsector->f_slope, worldlow,  worldlowslope,  gl_backsector->floorheight)
1129 #undef SLOPEPARAMS
1130 
1131 		// hack to allow height changes in outdoor areas
1132 		// This is what gets rid of the upper textures if there should be sky
1133 		if (gl_frontsector->ceilingpic == skyflatnum
1134 			&& gl_backsector->ceilingpic  == skyflatnum)
1135 		{
1136 			bothceilingssky = true;
1137 		}
1138 
1139 		// likewise, but for floors and upper textures
1140 		if (gl_frontsector->floorpic == skyflatnum
1141 			&& gl_backsector->floorpic == skyflatnum)
1142 		{
1143 			bothfloorssky = true;
1144 		}
1145 
1146 		if (!bothceilingssky)
1147 			gl_toptexture = R_GetTextureNum(gl_sidedef->toptexture);
1148 		if (!bothfloorssky)
1149 			gl_bottomtexture = R_GetTextureNum(gl_sidedef->bottomtexture);
1150 
1151 		// check TOP TEXTURE
1152 		if ((worldhighslope < worldtopslope || worldhigh < worldtop) && gl_toptexture)
1153 		{
1154 			{
1155 				fixed_t texturevpegtop; // top
1156 
1157 				grTex = HWR_GetTexture(gl_toptexture);
1158 
1159 				// PEGGING
1160 				if (gl_linedef->flags & ML_DONTPEGTOP)
1161 					texturevpegtop = 0;
1162 				else if (gl_linedef->flags & ML_EFFECT1)
1163 					texturevpegtop = worldhigh + textureheight[gl_sidedef->toptexture] - worldtop;
1164 				else
1165 					texturevpegtop = gl_backsector->ceilingheight + textureheight[gl_sidedef->toptexture] - gl_frontsector->ceilingheight;
1166 
1167 				texturevpegtop += gl_sidedef->rowoffset;
1168 
1169 				// This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway
1170 				texturevpegtop %= (textures[gl_toptexture]->height)<<FRACBITS;
1171 
1172 				wallVerts[3].t = wallVerts[2].t = texturevpegtop * grTex->scaleY;
1173 				wallVerts[0].t = wallVerts[1].t = (texturevpegtop + gl_frontsector->ceilingheight - gl_backsector->ceilingheight) * grTex->scaleY;
1174 				wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX;
1175 				wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX;
1176 
1177 				// Adjust t value for sloped walls
1178 				if (!(gl_linedef->flags & ML_EFFECT1))
1179 				{
1180 					// Unskewed
1181 					wallVerts[3].t -= (worldtop - gl_frontsector->ceilingheight) * grTex->scaleY;
1182 					wallVerts[2].t -= (worldtopslope - gl_frontsector->ceilingheight) * grTex->scaleY;
1183 					wallVerts[0].t -= (worldhigh - gl_backsector->ceilingheight) * grTex->scaleY;
1184 					wallVerts[1].t -= (worldhighslope - gl_backsector->ceilingheight) * grTex->scaleY;
1185 				}
1186 				else if (gl_linedef->flags & ML_DONTPEGTOP)
1187 				{
1188 					// Skewed by top
1189 					wallVerts[0].t = (texturevpegtop + worldtop - worldhigh) * grTex->scaleY;
1190 					wallVerts[1].t = (texturevpegtop + worldtopslope - worldhighslope) * grTex->scaleY;
1191 				}
1192 				else
1193 				{
1194 					// Skewed by bottom
1195 					wallVerts[0].t = wallVerts[1].t = (texturevpegtop + worldtop - worldhigh) * grTex->scaleY;
1196 					wallVerts[3].t = wallVerts[0].t - (worldtop - worldhigh) * grTex->scaleY;
1197 					wallVerts[2].t = wallVerts[1].t - (worldtopslope - worldhighslope) * grTex->scaleY;
1198 				}
1199 			}
1200 
1201 			// set top/bottom coords
1202 			wallVerts[3].y = FIXED_TO_FLOAT(worldtop);
1203 			wallVerts[0].y = FIXED_TO_FLOAT(worldhigh);
1204 			wallVerts[2].y = FIXED_TO_FLOAT(worldtopslope);
1205 			wallVerts[1].y = FIXED_TO_FLOAT(worldhighslope);
1206 
1207 			if (gl_frontsector->numlights)
1208 				HWR_SplitWall(gl_frontsector, wallVerts, gl_toptexture, &Surf, FF_CUTLEVEL, NULL, 0);
1209 			else if (grTex->mipmap.flags & TF_TRANSPARENT)
1210 				HWR_AddTransparentWall(wallVerts, &Surf, gl_toptexture, PF_Environment, false, lightnum, colormap);
1211 			else
1212 				HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
1213 		}
1214 
1215 		// check BOTTOM TEXTURE
1216 		if ((
1217 			worldlowslope > worldbottomslope ||
1218             worldlow > worldbottom) && gl_bottomtexture) //only if VISIBLE!!!
1219 		{
1220 			{
1221 				fixed_t texturevpegbottom = 0; // bottom
1222 
1223 				grTex = HWR_GetTexture(gl_bottomtexture);
1224 
1225 				// PEGGING
1226 				if (!(gl_linedef->flags & ML_DONTPEGBOTTOM))
1227 					texturevpegbottom = 0;
1228 				else if (gl_linedef->flags & ML_EFFECT1)
1229 					texturevpegbottom = worldbottom - worldlow;
1230 				else
1231 					texturevpegbottom = gl_frontsector->floorheight - gl_backsector->floorheight;
1232 
1233 				texturevpegbottom += gl_sidedef->rowoffset;
1234 
1235 				// This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway
1236 				texturevpegbottom %= (textures[gl_bottomtexture]->height)<<FRACBITS;
1237 
1238 				wallVerts[3].t = wallVerts[2].t = texturevpegbottom * grTex->scaleY;
1239 				wallVerts[0].t = wallVerts[1].t = (texturevpegbottom + gl_backsector->floorheight - gl_frontsector->floorheight) * grTex->scaleY;
1240 				wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX;
1241 				wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX;
1242 
1243 				// Adjust t value for sloped walls
1244 				if (!(gl_linedef->flags & ML_EFFECT1))
1245 				{
1246 					// Unskewed
1247 					wallVerts[0].t -= (worldbottom - gl_frontsector->floorheight) * grTex->scaleY;
1248 					wallVerts[1].t -= (worldbottomslope - gl_frontsector->floorheight) * grTex->scaleY;
1249 					wallVerts[3].t -= (worldlow - gl_backsector->floorheight) * grTex->scaleY;
1250 					wallVerts[2].t -= (worldlowslope - gl_backsector->floorheight) * grTex->scaleY;
1251 				}
1252 				else if (gl_linedef->flags & ML_DONTPEGBOTTOM)
1253 				{
1254 					// Skewed by bottom
1255 					wallVerts[0].t = wallVerts[1].t = (texturevpegbottom + worldlow - worldbottom) * grTex->scaleY;
1256 					//wallVerts[3].t = wallVerts[0].t - (worldlow - worldbottom) * grTex->scaleY; // no need, [3] is already this
1257 					wallVerts[2].t = wallVerts[1].t - (worldlowslope - worldbottomslope) * grTex->scaleY;
1258 				}
1259 				else
1260 				{
1261 					// Skewed by top
1262 					wallVerts[0].t = (texturevpegbottom + worldlow - worldbottom) * grTex->scaleY;
1263 					wallVerts[1].t = (texturevpegbottom + worldlowslope - worldbottomslope) * grTex->scaleY;
1264 				}
1265 			}
1266 
1267 			// set top/bottom coords
1268 			wallVerts[3].y = FIXED_TO_FLOAT(worldlow);
1269 			wallVerts[0].y = FIXED_TO_FLOAT(worldbottom);
1270 			wallVerts[2].y = FIXED_TO_FLOAT(worldlowslope);
1271 			wallVerts[1].y = FIXED_TO_FLOAT(worldbottomslope);
1272 
1273 			if (gl_frontsector->numlights)
1274 				HWR_SplitWall(gl_frontsector, wallVerts, gl_bottomtexture, &Surf, FF_CUTLEVEL, NULL, 0);
1275 			else if (grTex->mipmap.flags & TF_TRANSPARENT)
1276 				HWR_AddTransparentWall(wallVerts, &Surf, gl_bottomtexture, PF_Environment, false, lightnum, colormap);
1277 			else
1278 				HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
1279 		}
1280 		gl_midtexture = R_GetTextureNum(gl_sidedef->midtexture);
1281 		if (gl_midtexture)
1282 		{
1283 			FBITFIELD blendmode;
1284 			sector_t *front, *back;
1285 			fixed_t  popentop, popenbottom, polytop, polybottom, lowcut, highcut;
1286 			fixed_t     texturevpeg = 0;
1287 			INT32 repeats;
1288 
1289 			if (gl_linedef->frontsector->heightsec != -1)
1290 				front = &sectors[gl_linedef->frontsector->heightsec];
1291 			else
1292 				front = gl_linedef->frontsector;
1293 
1294 			if (gl_linedef->backsector->heightsec != -1)
1295 				back = &sectors[gl_linedef->backsector->heightsec];
1296 			else
1297 				back = gl_linedef->backsector;
1298 
1299 			if (gl_sidedef->repeatcnt)
1300 				repeats = 1 + gl_sidedef->repeatcnt;
1301 			else if (gl_linedef->flags & ML_EFFECT5)
1302 			{
1303 				fixed_t high, low;
1304 
1305 				if (front->ceilingheight > back->ceilingheight)
1306 					high = back->ceilingheight;
1307 				else
1308 					high = front->ceilingheight;
1309 
1310 				if (front->floorheight > back->floorheight)
1311 					low = front->floorheight;
1312 				else
1313 					low = back->floorheight;
1314 
1315 				repeats = (high - low)/textureheight[gl_sidedef->midtexture];
1316 				if ((high-low)%textureheight[gl_sidedef->midtexture])
1317 					repeats++; // tile an extra time to fill the gap -- Monster Iestyn
1318 			}
1319 			else
1320 				repeats = 1;
1321 
1322 			// SoM: a little note: This code re-arranging will
1323 			// fix the bug in Nimrod map02. popentop and popenbottom
1324 			// record the limits the texture can be displayed in.
1325 			// polytop and polybottom, are the ideal (i.e. unclipped)
1326 			// heights of the polygon, and h & l, are the final (clipped)
1327 			// poly coords.
1328 
1329 			// NOTE: With polyobjects, whenever you need to check the properties of the polyobject sector it belongs to,
1330 			// you must use the linedef's backsector to be correct
1331 			// From CB
1332 			if (gl_curline->polyseg)
1333 			{
1334 				popentop = back->ceilingheight;
1335 				popenbottom = back->floorheight;
1336 			}
1337 			else
1338             {
1339 				popentop = min(worldtop, worldhigh);
1340 				popenbottom = max(worldbottom, worldlow);
1341 			}
1342 
1343 			if (gl_linedef->flags & ML_EFFECT2)
1344 			{
1345 				if (!!(gl_linedef->flags & ML_DONTPEGBOTTOM) ^ !!(gl_linedef->flags & ML_EFFECT3))
1346 				{
1347 					polybottom = max(front->floorheight, back->floorheight) + gl_sidedef->rowoffset;
1348 					polytop = polybottom + textureheight[gl_midtexture]*repeats;
1349 				}
1350 				else
1351 				{
1352 					polytop = min(front->ceilingheight, back->ceilingheight) + gl_sidedef->rowoffset;
1353 					polybottom = polytop - textureheight[gl_midtexture]*repeats;
1354 				}
1355 			}
1356 			else if (!!(gl_linedef->flags & ML_DONTPEGBOTTOM) ^ !!(gl_linedef->flags & ML_EFFECT3))
1357 			{
1358 				polybottom = popenbottom + gl_sidedef->rowoffset;
1359 				polytop = polybottom + textureheight[gl_midtexture]*repeats;
1360 			}
1361 			else
1362 			{
1363 				polytop = popentop + gl_sidedef->rowoffset;
1364 				polybottom = polytop - textureheight[gl_midtexture]*repeats;
1365 			}
1366 			// CB
1367 			// NOTE: With polyobjects, whenever you need to check the properties of the polyobject sector it belongs to,
1368 			// you must use the linedef's backsector to be correct
1369 			if (gl_curline->polyseg)
1370 			{
1371 				lowcut = polybottom;
1372 				highcut = polytop;
1373 			}
1374 			else
1375 			{
1376 				// The cut-off values of a linedef can always be constant, since every line has an absoulute front and or back sector
1377 				lowcut = popenbottom;
1378 				highcut = popentop;
1379 			}
1380 
1381 			h = min(highcut, polytop);
1382 			l = max(polybottom, lowcut);
1383 
1384 			{
1385 				// PEGGING
1386 				if (!!(gl_linedef->flags & ML_DONTPEGBOTTOM) ^ !!(gl_linedef->flags & ML_EFFECT3))
1387 					texturevpeg = textureheight[gl_sidedef->midtexture]*repeats - h + polybottom;
1388 				else
1389 					texturevpeg = polytop - h;
1390 
1391 				grTex = HWR_GetTexture(gl_midtexture);
1392 
1393 				wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY;
1394 				wallVerts[0].t = wallVerts[1].t = (h - l + texturevpeg) * grTex->scaleY;
1395 				wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX;
1396 				wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX;
1397 			}
1398 
1399 			// set top/bottom coords
1400 			// Take the texture peg into account, rather than changing the offsets past
1401 			// where the polygon might not be.
1402 			wallVerts[2].y = wallVerts[3].y = FIXED_TO_FLOAT(h);
1403 			wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(l);
1404 
1405 			// Correct to account for slopes
1406 			{
1407 				fixed_t midtextureslant;
1408 
1409 				if (gl_linedef->flags & ML_EFFECT2)
1410 					midtextureslant = 0;
1411 				else if (!!(gl_linedef->flags & ML_DONTPEGBOTTOM) ^ !!(gl_linedef->flags & ML_EFFECT3))
1412 					midtextureslant = worldlow < worldbottom
1413 							  ? worldbottomslope-worldbottom
1414 							  : worldlowslope-worldlow;
1415 				else
1416 					midtextureslant = worldtop < worldhigh
1417 							  ? worldtopslope-worldtop
1418 							  : worldhighslope-worldhigh;
1419 
1420 				polytop += midtextureslant;
1421 				polybottom += midtextureslant;
1422 
1423 				highcut += worldtop < worldhigh
1424 						 ? worldtopslope-worldtop
1425 						 : worldhighslope-worldhigh;
1426 				lowcut += worldlow < worldbottom
1427 						? worldbottomslope-worldbottom
1428 						: worldlowslope-worldlow;
1429 
1430 				// Texture stuff
1431 				h = min(highcut, polytop);
1432 				l = max(polybottom, lowcut);
1433 
1434 				{
1435 					// PEGGING
1436 					if (!!(gl_linedef->flags & ML_DONTPEGBOTTOM) ^ !!(gl_linedef->flags & ML_EFFECT3))
1437 						texturevpeg = textureheight[gl_sidedef->midtexture]*repeats - h + polybottom;
1438 					else
1439 						texturevpeg = polytop - h;
1440 					wallVerts[2].t = texturevpeg * grTex->scaleY;
1441 					wallVerts[1].t = (h - l + texturevpeg) * grTex->scaleY;
1442 				}
1443 
1444 				wallVerts[2].y = FIXED_TO_FLOAT(h);
1445 				wallVerts[1].y = FIXED_TO_FLOAT(l);
1446 			}
1447 
1448 			// set alpha for transparent walls
1449 			// ooops ! this do not work at all because render order we should render it in backtofront order
1450 			switch (gl_linedef->special)
1451 			{
1452 				//  Translucent
1453 				case 102:
1454 				case 121:
1455 				case 123:
1456 				case 124:
1457 				case 125:
1458 				case 141:
1459 				case 142:
1460 				case 144:
1461 				case 145:
1462 				case 174:
1463 				case 175:
1464 				case 192:
1465 				case 195:
1466 				case 221:
1467 				case 253:
1468 				case 256:
1469 					blendmode = PF_Translucent;
1470 					break;
1471 				default:
1472 					if (gl_linedef->alpha >= 0 && gl_linedef->alpha < FRACUNIT)
1473 						blendmode = HWR_TranstableToAlpha(R_GetLinedefTransTable(gl_linedef->alpha), &Surf);
1474 					else
1475 						blendmode = PF_Masked;
1476 					break;
1477 			}
1478 
1479 			if (gl_curline->polyseg && gl_curline->polyseg->translucency > 0)
1480 			{
1481 				if (gl_curline->polyseg->translucency >= NUMTRANSMAPS) // wall not drawn
1482 				{
1483 					Surf.PolyColor.s.alpha = 0x00; // This shouldn't draw anything regardless of blendmode
1484 					blendmode = PF_Masked;
1485 				}
1486 				else
1487 					blendmode = HWR_TranstableToAlpha(gl_curline->polyseg->translucency, &Surf);
1488 			}
1489 
1490 			// Render midtextures on two-sided lines with a z-buffer offset.
1491 			// This will cause the midtexture appear on top, if a FOF overlaps with it.
1492 			blendmode |= PF_Decal;
1493 
1494 			if (gl_frontsector->numlights)
1495 			{
1496 				if (!(blendmode & PF_Masked))
1497 					HWR_SplitWall(gl_frontsector, wallVerts, gl_midtexture, &Surf, FF_TRANSLUCENT, NULL, PF_Decal);
1498 				else
1499 				{
1500 					HWR_SplitWall(gl_frontsector, wallVerts, gl_midtexture, &Surf, FF_CUTLEVEL, NULL, PF_Decal);
1501 				}
1502 			}
1503 			else if (!(blendmode & PF_Masked))
1504 				HWR_AddTransparentWall(wallVerts, &Surf, gl_midtexture, blendmode, false, lightnum, colormap);
1505 			else
1506 				HWR_ProjectWall(wallVerts, &Surf, blendmode, lightnum, colormap);
1507 		}
1508 
1509 		// Sky culling
1510 		// No longer so much a mess as before!
1511 		if (!gl_curline->polyseg) // Don't do it for polyobjects
1512 		{
1513 			if (gl_frontsector->ceilingpic == skyflatnum)
1514 			{
1515 				if (gl_backsector->ceilingpic != skyflatnum) // don't cull if back sector is also sky
1516 				{
1517 					wallVerts[2].y = wallVerts[3].y = FIXED_TO_FLOAT(INT32_MAX); // draw to top of map space
1518 					wallVerts[0].y = FIXED_TO_FLOAT(worldtop);
1519 					wallVerts[1].y = FIXED_TO_FLOAT(worldtopslope);
1520 					HWR_DrawSkyWall(wallVerts, &Surf);
1521 				}
1522 			}
1523 
1524 			if (gl_frontsector->floorpic == skyflatnum)
1525 			{
1526 				if (gl_backsector->floorpic != skyflatnum) // don't cull if back sector is also sky
1527 				{
1528 					wallVerts[3].y = FIXED_TO_FLOAT(worldbottom);
1529 					wallVerts[2].y = FIXED_TO_FLOAT(worldbottomslope);
1530 					wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(INT32_MIN); // draw to bottom of map space
1531 					HWR_DrawSkyWall(wallVerts, &Surf);
1532 				}
1533 			}
1534 		}
1535 	}
1536 	else
1537 	{
1538 		// Single sided line... Deal only with the middletexture (if one exists)
1539 		gl_midtexture = R_GetTextureNum(gl_sidedef->midtexture);
1540 		if (gl_midtexture && gl_linedef->special != 41) // (Ignore horizon line for OGL)
1541 		{
1542 			{
1543 				fixed_t     texturevpeg;
1544 				// PEGGING
1545 				if ((gl_linedef->flags & (ML_DONTPEGBOTTOM|ML_EFFECT2)) == (ML_DONTPEGBOTTOM|ML_EFFECT2))
1546 					texturevpeg = gl_frontsector->floorheight + textureheight[gl_sidedef->midtexture] - gl_frontsector->ceilingheight + gl_sidedef->rowoffset;
1547 				else if (gl_linedef->flags & ML_DONTPEGBOTTOM)
1548 					texturevpeg = worldbottom + textureheight[gl_sidedef->midtexture] - worldtop + gl_sidedef->rowoffset;
1549 				else
1550 					// top of texture at top
1551 					texturevpeg = gl_sidedef->rowoffset;
1552 
1553 				grTex = HWR_GetTexture(gl_midtexture);
1554 
1555 				wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY;
1556 				wallVerts[0].t = wallVerts[1].t = (texturevpeg + gl_frontsector->ceilingheight - gl_frontsector->floorheight) * grTex->scaleY;
1557 				wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX;
1558 				wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX;
1559 
1560 				// Texture correction for slopes
1561 				if (gl_linedef->flags & ML_EFFECT2) {
1562 					wallVerts[3].t += (gl_frontsector->ceilingheight - worldtop) * grTex->scaleY;
1563 					wallVerts[2].t += (gl_frontsector->ceilingheight - worldtopslope) * grTex->scaleY;
1564 					wallVerts[0].t += (gl_frontsector->floorheight - worldbottom) * grTex->scaleY;
1565 					wallVerts[1].t += (gl_frontsector->floorheight - worldbottomslope) * grTex->scaleY;
1566 				} else if (gl_linedef->flags & ML_DONTPEGBOTTOM) {
1567 					wallVerts[3].t = wallVerts[0].t + (worldbottom-worldtop) * grTex->scaleY;
1568 					wallVerts[2].t = wallVerts[1].t + (worldbottomslope-worldtopslope) * grTex->scaleY;
1569 				} else {
1570 					wallVerts[0].t = wallVerts[3].t - (worldbottom-worldtop) * grTex->scaleY;
1571 					wallVerts[1].t = wallVerts[2].t - (worldbottomslope-worldtopslope) * grTex->scaleY;
1572 				}
1573 			}
1574 
1575 			//Set textures properly on single sided walls that are sloped
1576 			wallVerts[3].y = FIXED_TO_FLOAT(worldtop);
1577 			wallVerts[0].y = FIXED_TO_FLOAT(worldbottom);
1578 			wallVerts[2].y = FIXED_TO_FLOAT(worldtopslope);
1579 			wallVerts[1].y = FIXED_TO_FLOAT(worldbottomslope);
1580 
1581 			// I don't think that solid walls can use translucent linedef types...
1582 			if (gl_frontsector->numlights)
1583 				HWR_SplitWall(gl_frontsector, wallVerts, gl_midtexture, &Surf, FF_CUTLEVEL, NULL, 0);
1584 			else
1585 			{
1586 				if (grTex->mipmap.flags & TF_TRANSPARENT)
1587 					HWR_AddTransparentWall(wallVerts, &Surf, gl_midtexture, PF_Environment, false, lightnum, colormap);
1588 				else
1589 					HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
1590 			}
1591 		}
1592 
1593 		if (!gl_curline->polyseg)
1594 		{
1595 			if (gl_frontsector->ceilingpic == skyflatnum) // It's a single-sided line with sky for its sector
1596 			{
1597 				wallVerts[2].y = wallVerts[3].y = FIXED_TO_FLOAT(INT32_MAX); // draw to top of map space
1598 				wallVerts[0].y = FIXED_TO_FLOAT(worldtop);
1599 				wallVerts[1].y = FIXED_TO_FLOAT(worldtopslope);
1600 				HWR_DrawSkyWall(wallVerts, &Surf);
1601 			}
1602 			if (gl_frontsector->floorpic == skyflatnum)
1603 			{
1604 				wallVerts[3].y = FIXED_TO_FLOAT(worldbottom);
1605 				wallVerts[2].y = FIXED_TO_FLOAT(worldbottomslope);
1606 				wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(INT32_MIN); // draw to bottom of map space
1607 				HWR_DrawSkyWall(wallVerts, &Surf);
1608 			}
1609 		}
1610 	}
1611 
1612 
1613 	//Hurdler: 3d-floors test
1614 	if (gl_frontsector && gl_backsector && !Tag_Compare(&gl_frontsector->tags, &gl_backsector->tags) && (gl_backsector->ffloors || gl_frontsector->ffloors))
1615 	{
1616 		ffloor_t * rover;
1617 		fixed_t    highcut = 0, lowcut = 0;
1618 
1619 		INT32 texnum;
1620 		line_t * newline = NULL; // Multi-Property FOF
1621 
1622         ///TODO add slope support (fixing cutoffs, proper wall clipping) - maybe just disable highcut/lowcut if either sector or FOF has a slope
1623         ///     to allow fun plane intersecting in OGL? But then people would abuse that and make software look bad. :C
1624 		highcut = gl_frontsector->ceilingheight < gl_backsector->ceilingheight ? gl_frontsector->ceilingheight : gl_backsector->ceilingheight;
1625 		lowcut = gl_frontsector->floorheight > gl_backsector->floorheight ? gl_frontsector->floorheight : gl_backsector->floorheight;
1626 
1627 		if (gl_backsector->ffloors)
1628 		{
1629 			for (rover = gl_backsector->ffloors; rover; rover = rover->next)
1630 			{
1631 				boolean bothsides = false;
1632 				// Skip if it exists on both sectors.
1633 				ffloor_t * r2;
1634 				for (r2 = gl_frontsector->ffloors; r2; r2 = r2->next)
1635 					if (rover->master == r2->master)
1636 					{
1637 						bothsides = true;
1638 						break;
1639 					}
1640 
1641 				if (bothsides) continue;
1642 
1643 				if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERSIDES))
1644 					continue;
1645 				if (!(rover->flags & FF_ALLSIDES) && rover->flags & FF_INVERTSIDES)
1646 					continue;
1647 				if (*rover->topheight < lowcut || *rover->bottomheight > highcut)
1648 					continue;
1649 
1650 				texnum = R_GetTextureNum(sides[rover->master->sidenum[0]].midtexture);
1651 
1652 				if (rover->master->flags & ML_TFERLINE)
1653 				{
1654 					size_t linenum = gl_curline->linedef-gl_backsector->lines[0];
1655 					newline = rover->master->frontsector->lines[0] + linenum;
1656 					texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture);
1657 				}
1658 
1659 				h  = P_GetFFloorTopZAt   (rover, v1x, v1y);
1660 				hS = P_GetFFloorTopZAt   (rover, v2x, v2y);
1661 				l  = P_GetFFloorBottomZAt(rover, v1x, v1y);
1662 				lS = P_GetFFloorBottomZAt(rover, v2x, v2y);
1663 				if (!(*rover->t_slope) && !gl_frontsector->c_slope && !gl_backsector->c_slope && h > highcut)
1664 					h = hS = highcut;
1665 				if (!(*rover->b_slope) && !gl_frontsector->f_slope && !gl_backsector->f_slope && l < lowcut)
1666 					l = lS = lowcut;
1667 				//Hurdler: HW code starts here
1668 				//FIXME: check if peging is correct
1669 				// set top/bottom coords
1670 
1671 				wallVerts[3].y = FIXED_TO_FLOAT(h);
1672 				wallVerts[2].y = FIXED_TO_FLOAT(hS);
1673 				wallVerts[0].y = FIXED_TO_FLOAT(l);
1674 				wallVerts[1].y = FIXED_TO_FLOAT(lS);
1675 				if (rover->flags & FF_FOG)
1676 				{
1677 					wallVerts[3].t = wallVerts[2].t = 0;
1678 					wallVerts[0].t = wallVerts[1].t = 0;
1679 					wallVerts[0].s = wallVerts[3].s = 0;
1680 					wallVerts[2].s = wallVerts[1].s = 0;
1681 				}
1682 				else
1683 				{
1684 					fixed_t texturevpeg;
1685 					boolean attachtobottom = false;
1686 					boolean slopeskew = false; // skew FOF walls with slopes?
1687 
1688 					// Wow, how was this missing from OpenGL for so long?
1689 					// ...Oh well, anyway, Lower Unpegged now changes pegging of FOFs like in software
1690 					// -- Monster Iestyn 26/06/18
1691 					if (newline)
1692 					{
1693 						texturevpeg = sides[newline->sidenum[0]].rowoffset;
1694 						attachtobottom = !!(newline->flags & ML_DONTPEGBOTTOM);
1695 						slopeskew = !!(newline->flags & ML_DONTPEGTOP);
1696 					}
1697 					else
1698 					{
1699 						texturevpeg = sides[rover->master->sidenum[0]].rowoffset;
1700 						attachtobottom = !!(gl_linedef->flags & ML_DONTPEGBOTTOM);
1701 						slopeskew = !!(rover->master->flags & ML_DONTPEGTOP);
1702 					}
1703 
1704 					grTex = HWR_GetTexture(texnum);
1705 
1706 					if (!slopeskew) // no skewing
1707 					{
1708 						if (attachtobottom)
1709 							texturevpeg -= *rover->topheight - *rover->bottomheight;
1710 						wallVerts[3].t = (*rover->topheight - h + texturevpeg) * grTex->scaleY;
1711 						wallVerts[2].t = (*rover->topheight - hS + texturevpeg) * grTex->scaleY;
1712 						wallVerts[0].t = (*rover->topheight - l + texturevpeg) * grTex->scaleY;
1713 						wallVerts[1].t = (*rover->topheight - lS + texturevpeg) * grTex->scaleY;
1714 					}
1715 					else
1716 					{
1717 						if (!attachtobottom) // skew by top
1718 						{
1719 							wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY;
1720 							wallVerts[0].t = (h - l + texturevpeg) * grTex->scaleY;
1721 							wallVerts[1].t = (hS - lS + texturevpeg) * grTex->scaleY;
1722 						}
1723 						else // skew by bottom
1724 						{
1725 							wallVerts[0].t = wallVerts[1].t = texturevpeg * grTex->scaleY;
1726 							wallVerts[3].t = wallVerts[0].t - (h - l) * grTex->scaleY;
1727 							wallVerts[2].t = wallVerts[1].t - (hS - lS) * grTex->scaleY;
1728 						}
1729 					}
1730 
1731 					wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX;
1732 					wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX;
1733 				}
1734 				if (rover->flags & FF_FOG)
1735 				{
1736 					FBITFIELD blendmode;
1737 
1738 					blendmode = PF_Fog|PF_NoTexture;
1739 
1740 					lightnum = HWR_CalcWallLight(rover->master->frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y);
1741 					colormap = rover->master->frontsector->extra_colormap;
1742 
1743 					Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel, rover->master->frontsector->extra_colormap);
1744 
1745 					if (gl_frontsector->numlights)
1746 						HWR_SplitWall(gl_frontsector, wallVerts, 0, &Surf, rover->flags, rover, 0);
1747 					else
1748 						HWR_AddTransparentWall(wallVerts, &Surf, 0, blendmode, true, lightnum, colormap);
1749 				}
1750 				else
1751 				{
1752 					FBITFIELD blendmode = PF_Masked;
1753 
1754 					if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256)
1755 					{
1756 						blendmode = PF_Translucent;
1757 						Surf.PolyColor.s.alpha = (UINT8)rover->alpha-1 > 255 ? 255 : rover->alpha-1;
1758 					}
1759 
1760 					if (gl_frontsector->numlights)
1761 						HWR_SplitWall(gl_frontsector, wallVerts, texnum, &Surf, rover->flags, rover, 0);
1762 					else
1763 					{
1764 						if (blendmode != PF_Masked)
1765 							HWR_AddTransparentWall(wallVerts, &Surf, texnum, blendmode, false, lightnum, colormap);
1766 						else
1767 							HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
1768 					}
1769 				}
1770 			}
1771 		}
1772 
1773 		if (gl_frontsector->ffloors) // Putting this seperate should allow 2 FOF sectors to be connected without too many errors? I think?
1774 		{
1775 			for (rover = gl_frontsector->ffloors; rover; rover = rover->next)
1776 			{
1777 				boolean bothsides = false;
1778 				// Skip if it exists on both sectors.
1779 				ffloor_t * r2;
1780 				for (r2 = gl_backsector->ffloors; r2; r2 = r2->next)
1781 					if (rover->master == r2->master)
1782 					{
1783 						bothsides = true;
1784 						break;
1785 					}
1786 
1787 				if (bothsides) continue;
1788 
1789 				if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERSIDES))
1790 					continue;
1791 				if (!(rover->flags & FF_ALLSIDES || rover->flags & FF_INVERTSIDES))
1792 					continue;
1793 				if (*rover->topheight < lowcut || *rover->bottomheight > highcut)
1794 					continue;
1795 
1796 				texnum = R_GetTextureNum(sides[rover->master->sidenum[0]].midtexture);
1797 
1798 				if (rover->master->flags & ML_TFERLINE)
1799 				{
1800 					size_t linenum = gl_curline->linedef-gl_backsector->lines[0];
1801 					newline = rover->master->frontsector->lines[0] + linenum;
1802 					texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture);
1803 				}
1804 				h  = P_GetFFloorTopZAt   (rover, v1x, v1y);
1805 				hS = P_GetFFloorTopZAt   (rover, v2x, v2y);
1806 				l  = P_GetFFloorBottomZAt(rover, v1x, v1y);
1807 				lS = P_GetFFloorBottomZAt(rover, v2x, v2y);
1808 				if (!(*rover->t_slope) && !gl_frontsector->c_slope && !gl_backsector->c_slope && h > highcut)
1809 					h = hS = highcut;
1810 				if (!(*rover->b_slope) && !gl_frontsector->f_slope && !gl_backsector->f_slope && l < lowcut)
1811 					l = lS = lowcut;
1812 				//Hurdler: HW code starts here
1813 				//FIXME: check if peging is correct
1814 				// set top/bottom coords
1815 
1816 				wallVerts[3].y = FIXED_TO_FLOAT(h);
1817 				wallVerts[2].y = FIXED_TO_FLOAT(hS);
1818 				wallVerts[0].y = FIXED_TO_FLOAT(l);
1819 				wallVerts[1].y = FIXED_TO_FLOAT(lS);
1820 				if (rover->flags & FF_FOG)
1821 				{
1822 					wallVerts[3].t = wallVerts[2].t = 0;
1823 					wallVerts[0].t = wallVerts[1].t = 0;
1824 					wallVerts[0].s = wallVerts[3].s = 0;
1825 					wallVerts[2].s = wallVerts[1].s = 0;
1826 				}
1827 				else
1828 				{
1829 					grTex = HWR_GetTexture(texnum);
1830 
1831 					if (newline)
1832 					{
1833 						wallVerts[3].t = wallVerts[2].t = (*rover->topheight - h + sides[newline->sidenum[0]].rowoffset) * grTex->scaleY;
1834 						wallVerts[0].t = wallVerts[1].t = (h - l + (*rover->topheight - h + sides[newline->sidenum[0]].rowoffset)) * grTex->scaleY;
1835 					}
1836 					else
1837 					{
1838 						wallVerts[3].t = wallVerts[2].t = (*rover->topheight - h + sides[rover->master->sidenum[0]].rowoffset) * grTex->scaleY;
1839 						wallVerts[0].t = wallVerts[1].t = (h - l + (*rover->topheight - h + sides[rover->master->sidenum[0]].rowoffset)) * grTex->scaleY;
1840 					}
1841 
1842 					wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX;
1843 					wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX;
1844 				}
1845 
1846 				if (rover->flags & FF_FOG)
1847 				{
1848 					FBITFIELD blendmode;
1849 
1850 					blendmode = PF_Fog|PF_NoTexture;
1851 
1852 					lightnum = HWR_CalcWallLight(rover->master->frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y);
1853 					colormap = rover->master->frontsector->extra_colormap;
1854 
1855 					Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel, rover->master->frontsector->extra_colormap);
1856 
1857 					if (gl_backsector->numlights)
1858 						HWR_SplitWall(gl_backsector, wallVerts, 0, &Surf, rover->flags, rover, 0);
1859 					else
1860 						HWR_AddTransparentWall(wallVerts, &Surf, 0, blendmode, true, lightnum, colormap);
1861 				}
1862 				else
1863 				{
1864 					FBITFIELD blendmode = PF_Masked;
1865 
1866 					if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256)
1867 					{
1868 						blendmode = PF_Translucent;
1869 						Surf.PolyColor.s.alpha = (UINT8)rover->alpha-1 > 255 ? 255 : rover->alpha-1;
1870 					}
1871 
1872 					if (gl_backsector->numlights)
1873 						HWR_SplitWall(gl_backsector, wallVerts, texnum, &Surf, rover->flags, rover, 0);
1874 					else
1875 					{
1876 						if (blendmode != PF_Masked)
1877 							HWR_AddTransparentWall(wallVerts, &Surf, texnum, blendmode, false, lightnum, colormap);
1878 						else
1879 							HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
1880 					}
1881 				}
1882 			}
1883 		}
1884 	}
1885 //Hurdler: end of 3d-floors test
1886 }
1887 
1888 // From PrBoom:
1889 //
1890 // e6y: Check whether the player can look beyond this line
1891 //
1892 #ifdef NEWCLIP
1893 boolean checkforemptylines = true;
1894 // Don't modify anything here, just check
1895 // Kalaron: Modified for sloped linedefs
CheckClip(seg_t * seg,sector_t * afrontsector,sector_t * abacksector)1896 static boolean CheckClip(seg_t * seg, sector_t * afrontsector, sector_t * abacksector)
1897 {
1898 	fixed_t frontf1,frontf2, frontc1, frontc2; // front floor/ceiling ends
1899 	fixed_t backf1, backf2, backc1, backc2; // back floor ceiling ends
1900 	boolean bothceilingssky = false, bothfloorssky = false;
1901 
1902 	if (abacksector->ceilingpic == skyflatnum && afrontsector->ceilingpic == skyflatnum)
1903 		bothceilingssky = true;
1904 	if (abacksector->floorpic == skyflatnum && afrontsector->floorpic == skyflatnum)
1905 		bothfloorssky = true;
1906 
1907 	// GZDoom method of sloped line clipping
1908 
1909 	if (afrontsector->f_slope || afrontsector->c_slope || abacksector->f_slope || abacksector->c_slope)
1910 	{
1911 		fixed_t v1x, v1y, v2x, v2y; // the seg's vertexes as fixed_t
1912 		v1x = FLOAT_TO_FIXED(((polyvertex_t *)gl_curline->pv1)->x);
1913 		v1y = FLOAT_TO_FIXED(((polyvertex_t *)gl_curline->pv1)->y);
1914 		v2x = FLOAT_TO_FIXED(((polyvertex_t *)gl_curline->pv2)->x);
1915 		v2y = FLOAT_TO_FIXED(((polyvertex_t *)gl_curline->pv2)->y);
1916 #define SLOPEPARAMS(slope, end1, end2, normalheight) \
1917 		end1 = P_GetZAt(slope, v1x, v1y, normalheight); \
1918 		end2 = P_GetZAt(slope, v2x, v2y, normalheight);
1919 
1920 		SLOPEPARAMS(afrontsector->f_slope, frontf1, frontf2, afrontsector->  floorheight)
1921 		SLOPEPARAMS(afrontsector->c_slope, frontc1, frontc2, afrontsector->ceilingheight)
1922 		SLOPEPARAMS( abacksector->f_slope,  backf1,  backf2,  abacksector->  floorheight)
1923 		SLOPEPARAMS( abacksector->c_slope,  backc1,  backc2,  abacksector->ceilingheight)
1924 #undef SLOPEPARAMS
1925 	}
1926 	else
1927 	{
1928 		frontf1 = frontf2 = afrontsector->  floorheight;
1929 		frontc1 = frontc2 = afrontsector->ceilingheight;
1930 		backf1  =  backf2 =  abacksector->  floorheight;
1931 		backc1  =  backc2 =  abacksector->ceilingheight;
1932 	}
1933 	// properly render skies (consider door "open" if both ceilings are sky)
1934 	// same for floors
1935 	if (!bothceilingssky && !bothfloorssky)
1936 	{
1937 		// now check for closed sectors!
1938 		if ((backc1 <= frontf1 && backc2 <= frontf2)
1939 			|| (backf1 >= frontc1 && backf2 >= frontc2))
1940 		{
1941 			checkforemptylines = false;
1942 			return true;
1943 		}
1944 
1945 		if (backc1 <= backf1 && backc2 <= backf2)
1946 		{
1947 			// preserve a kind of transparent door/lift special effect:
1948 			if (((backc1 >= frontc1 && backc2 >= frontc2) || seg->sidedef->toptexture)
1949 			&& ((backf1 <= frontf1 && backf2 <= frontf2) || seg->sidedef->bottomtexture))
1950 			{
1951 				checkforemptylines = false;
1952 				return true;
1953 			}
1954 		}
1955 	}
1956 
1957 	if (!bothceilingssky) {
1958 		if (backc1 != frontc1 || backc2 != frontc2)
1959 		{
1960 			checkforemptylines = false;
1961 			return false;
1962 		}
1963 	}
1964 
1965 	if (!bothfloorssky) {
1966 		if (backf1 != frontf1 || backf2 != frontf2)
1967 		{
1968 			checkforemptylines = false;
1969 			return false;
1970 		}
1971 	}
1972 
1973 	return false;
1974 }
1975 #else
1976 //Hurdler: just like in r_bsp.c
1977 #if 1
1978 #define MAXSEGS         MAXVIDWIDTH/2+1
1979 #else
1980 //Alam_GBC: Or not (may cause overflow)
1981 #define MAXSEGS         128
1982 #endif
1983 
1984 // hw_newend is one past the last valid seg
1985 static cliprange_t *   hw_newend;
1986 static cliprange_t     gl_solidsegs[MAXSEGS];
1987 
1988 // needs fix: walls are incorrectly clipped one column less
1989 static consvar_t cv_glclipwalls = CVAR_INIT ("gr_clipwalls", "Off", 0, CV_OnOff, NULL);
1990 
printsolidsegs(void)1991 static void printsolidsegs(void)
1992 {
1993 	cliprange_t *       start;
1994 	if (!hw_newend)
1995 		return;
1996 	for (start = gl_solidsegs;start != hw_newend;start++)
1997 	{
1998 		CONS_Debug(DBG_RENDER, "%d-%d|",start->first,start->last);
1999 	}
2000 	CONS_Debug(DBG_RENDER, "\n\n");
2001 }
2002 
2003 //
2004 //
2005 //
HWR_ClipSolidWallSegment(INT32 first,INT32 last)2006 static void HWR_ClipSolidWallSegment(INT32 first, INT32 last)
2007 {
2008 	cliprange_t *next, *start;
2009 	float lowfrac, highfrac;
2010 	boolean poorhack = false;
2011 
2012 	// Find the first range that touches the range
2013 	//  (adjacent pixels are touching).
2014 	start = gl_solidsegs;
2015 	while (start->last < first-1)
2016 		start++;
2017 
2018 	if (first < start->first)
2019 	{
2020 		if (last < start->first-1)
2021 		{
2022 			// Post is entirely visible (above start),
2023 			//  so insert a new clippost.
2024 			HWR_StoreWallRange(first, last);
2025 
2026 			next = hw_newend;
2027 			hw_newend++;
2028 
2029 			while (next != start)
2030 			{
2031 				*next = *(next-1);
2032 				next--;
2033 			}
2034 
2035 			next->first = first;
2036 			next->last = last;
2037 			printsolidsegs();
2038 			return;
2039 		}
2040 
2041 		// There is a fragment above *start.
2042 		if (!cv_glclipwalls.value)
2043 		{
2044 			if (!poorhack) HWR_StoreWallRange(first, last);
2045 			poorhack = true;
2046 		}
2047 		else
2048 		{
2049 			highfrac = HWR_ClipViewSegment(start->first+1, (polyvertex_t *)gl_curline->pv1, (polyvertex_t *)gl_curline->pv2);
2050 			HWR_StoreWallRange(0, highfrac);
2051 		}
2052 		// Now adjust the clip size.
2053 		start->first = first;
2054 	}
2055 
2056 	// Bottom contained in start?
2057 	if (last <= start->last)
2058 	{
2059 		printsolidsegs();
2060 		return;
2061 	}
2062 	next = start;
2063 	while (last >= (next+1)->first-1)
2064 	{
2065 		// There is a fragment between two posts.
2066 		if (!cv_glclipwalls.value)
2067 		{
2068 			if (!poorhack) HWR_StoreWallRange(first,last);
2069 			poorhack = true;
2070 		}
2071 		else
2072 		{
2073 			lowfrac  = HWR_ClipViewSegment(next->last-1, (polyvertex_t *)gl_curline->pv1, (polyvertex_t *)gl_curline->pv2);
2074 			highfrac = HWR_ClipViewSegment((next+1)->first+1, (polyvertex_t *)gl_curline->pv1, (polyvertex_t *)gl_curline->pv2);
2075 			HWR_StoreWallRange(lowfrac, highfrac);
2076 		}
2077 		next++;
2078 
2079 		if (last <= next->last)
2080 		{
2081 			// Bottom is contained in next.
2082 			// Adjust the clip size.
2083 			start->last = next->last;
2084 			goto crunch;
2085 		}
2086 	}
2087 
2088 	if (first == next->first+1) // 1 line texture
2089 	{
2090 		if (!cv_glclipwalls.value)
2091 		{
2092 			if (!poorhack) HWR_StoreWallRange(first,last);
2093 			poorhack = true;
2094 		}
2095 		else
2096 			HWR_StoreWallRange(0, 1);
2097 	}
2098 	else
2099 	{
2100 	// There is a fragment after *next.
2101 		if (!cv_glclipwalls.value)
2102 		{
2103 			if (!poorhack) HWR_StoreWallRange(first,last);
2104 			poorhack = true;
2105 		}
2106 		else
2107 		{
2108 			lowfrac  = HWR_ClipViewSegment(next->last-1, (polyvertex_t *)gl_curline->pv1, (polyvertex_t *)gl_curline->pv2);
2109 			HWR_StoreWallRange(lowfrac, 1);
2110 		}
2111 	}
2112 
2113 	// Adjust the clip size.
2114 	start->last = last;
2115 
2116 	// Remove start+1 to next from the clip list,
2117 	// because start now covers their area.
2118 crunch:
2119 	if (next == start)
2120 	{
2121 		printsolidsegs();
2122 		// Post just extended past the bottom of one post.
2123 		return;
2124 	}
2125 
2126 
2127 	while (next++ != hw_newend)
2128 	{
2129 		// Remove a post.
2130 		*++start = *next;
2131 	}
2132 
2133 	hw_newend = start;
2134 	printsolidsegs();
2135 }
2136 
2137 //
2138 //  handle LineDefs with upper and lower texture (windows)
2139 //
HWR_ClipPassWallSegment(INT32 first,INT32 last)2140 static void HWR_ClipPassWallSegment(INT32 first, INT32 last)
2141 {
2142 	cliprange_t *start;
2143 	float lowfrac, highfrac;
2144 	//to allow noclipwalls but still solidseg reject of non-visible walls
2145 	boolean poorhack = false;
2146 
2147 	// Find the first range that touches the range
2148 	//  (adjacent pixels are touching).
2149 	start = gl_solidsegs;
2150 	while (start->last < first - 1)
2151 		start++;
2152 
2153 	if (first < start->first)
2154 	{
2155 		if (last < start->first-1)
2156 		{
2157 			// Post is entirely visible (above start).
2158 			HWR_StoreWallRange(0, 1);
2159 			return;
2160 		}
2161 
2162 		// There is a fragment above *start.
2163 		if (!cv_glclipwalls.value)
2164 		{	//20/08/99: Changed by Hurdler (taken from faB's code)
2165 			if (!poorhack) HWR_StoreWallRange(0, 1);
2166 			poorhack = true;
2167 		}
2168 		else
2169 		{
2170 			highfrac = HWR_ClipViewSegment(min(start->first + 1,
2171 				start->last), (polyvertex_t *)gl_curline->pv1,
2172 				(polyvertex_t *)gl_curline->pv2);
2173 			HWR_StoreWallRange(0, highfrac);
2174 		}
2175 	}
2176 
2177 	// Bottom contained in start?
2178 	if (last <= start->last)
2179 		return;
2180 
2181 	while (last >= (start+1)->first-1)
2182 	{
2183 		// There is a fragment between two posts.
2184 		if (!cv_glclipwalls.value)
2185 		{
2186 			if (!poorhack) HWR_StoreWallRange(0, 1);
2187 			poorhack = true;
2188 		}
2189 		else
2190 		{
2191 			lowfrac  = HWR_ClipViewSegment(max(start->last-1,start->first), (polyvertex_t *)gl_curline->pv1, (polyvertex_t *)gl_curline->pv2);
2192 			highfrac = HWR_ClipViewSegment(min((start+1)->first+1,(start+1)->last), (polyvertex_t *)gl_curline->pv1, (polyvertex_t *)gl_curline->pv2);
2193 			HWR_StoreWallRange(lowfrac, highfrac);
2194 		}
2195 		start++;
2196 
2197 		if (last <= start->last)
2198 			return;
2199 	}
2200 
2201 	if (first == start->first+1) // 1 line texture
2202 	{
2203 		if (!cv_glclipwalls.value)
2204 		{
2205 			if (!poorhack) HWR_StoreWallRange(0, 1);
2206 			poorhack = true;
2207 		}
2208 		else
2209 			HWR_StoreWallRange(0, 1);
2210 	}
2211 	else
2212 	{
2213 		// There is a fragment after *next.
2214 		if (!cv_glclipwalls.value)
2215 		{
2216 			if (!poorhack) HWR_StoreWallRange(0,1);
2217 			poorhack = true;
2218 		}
2219 		else
2220 		{
2221 			lowfrac = HWR_ClipViewSegment(max(start->last - 1,
2222 				start->first), (polyvertex_t *)gl_curline->pv1,
2223 				(polyvertex_t *)gl_curline->pv2);
2224 			HWR_StoreWallRange(lowfrac, 1);
2225 		}
2226 	}
2227 }
2228 
2229 // --------------------------------------------------------------------------
2230 //  HWR_ClipToSolidSegs check if it is hide by wall (solidsegs)
2231 // --------------------------------------------------------------------------
HWR_ClipToSolidSegs(INT32 first,INT32 last)2232 static boolean HWR_ClipToSolidSegs(INT32 first, INT32 last)
2233 {
2234 	cliprange_t * start;
2235 
2236 	// Find the first range that touches the range
2237 	//  (adjacent pixels are touching).
2238 	start = gl_solidsegs;
2239 	while (start->last < first-1)
2240 		start++;
2241 
2242 	if (first < start->first)
2243 		return true;
2244 
2245 	// Bottom contained in start?
2246 	if (last <= start->last)
2247 		return false;
2248 
2249 	return true;
2250 }
2251 
2252 //
2253 // HWR_ClearClipSegs
2254 //
HWR_ClearClipSegs(void)2255 static void HWR_ClearClipSegs(void)
2256 {
2257 	gl_solidsegs[0].first = -0x7fffffff;
2258 	gl_solidsegs[0].last = -1;
2259 	gl_solidsegs[1].first = vid.width; //viewwidth;
2260 	gl_solidsegs[1].last = 0x7fffffff;
2261 	hw_newend = gl_solidsegs+2;
2262 }
2263 #endif // NEWCLIP
2264 
2265 // -----------------+
2266 // HWR_AddLine      : Clips the given segment and adds any visible pieces to the line list.
2267 // Notes            : gl_cursectorlight is set to the current subsector -> sector -> light value
2268 //                  : (it may be mixed with the wall's own flat colour in the future ...)
2269 // -----------------+
HWR_AddLine(seg_t * line)2270 static void HWR_AddLine(seg_t * line)
2271 {
2272 	angle_t angle1, angle2;
2273 #ifndef NEWCLIP
2274 	INT32 x1, x2;
2275 	angle_t span, tspan;
2276 	boolean bothceilingssky = false, bothfloorssky = false;
2277 #endif
2278 
2279 	// SoM: Backsector needs to be run through R_FakeFlat
2280 	static sector_t tempsec;
2281 
2282 	fixed_t v1x, v1y, v2x, v2y; // the seg's vertexes as fixed_t
2283 	if (line->polyseg && !(line->polyseg->flags & POF_RENDERSIDES))
2284 		return;
2285 
2286 	gl_curline = line;
2287 
2288 	v1x = FLOAT_TO_FIXED(((polyvertex_t *)gl_curline->pv1)->x);
2289 	v1y = FLOAT_TO_FIXED(((polyvertex_t *)gl_curline->pv1)->y);
2290 	v2x = FLOAT_TO_FIXED(((polyvertex_t *)gl_curline->pv2)->x);
2291 	v2y = FLOAT_TO_FIXED(((polyvertex_t *)gl_curline->pv2)->y);
2292 
2293 	// OPTIMIZE: quickly reject orthogonal back sides.
2294 	angle1 = R_PointToAngle64(v1x, v1y);
2295 	angle2 = R_PointToAngle64(v2x, v2y);
2296 
2297 #ifdef NEWCLIP
2298 	 // PrBoom: Back side, i.e. backface culling - read: endAngle >= startAngle!
2299 	if (angle2 - angle1 < ANGLE_180)
2300 		return;
2301 
2302 	// PrBoom: use REAL clipping math YAYYYYYYY!!!
2303 
2304 	if (!gld_clipper_SafeCheckRange(angle2, angle1))
2305     {
2306 		return;
2307     }
2308 
2309 	checkforemptylines = true;
2310 #else
2311 	// Clip to view edges.
2312 	span = angle1 - angle2;
2313 
2314 	// backface culling : span is < ANGLE_180 if ang1 > ang2 : the seg is facing
2315 	if (span >= ANGLE_180)
2316 		return;
2317 
2318 	// Global angle needed by segcalc.
2319 	//rw_angle1 = angle1;
2320 	angle1 -= dup_viewangle;
2321 	angle2 -= dup_viewangle;
2322 
2323 	tspan = angle1 + gl_clipangle;
2324 	if (tspan > 2*gl_clipangle)
2325 	{
2326 		tspan -= 2*gl_clipangle;
2327 
2328 		// Totally off the left edge?
2329 		if (tspan >= span)
2330 			return;
2331 
2332 		angle1 = gl_clipangle;
2333 	}
2334 	tspan = gl_clipangle - angle2;
2335 	if (tspan > 2*gl_clipangle)
2336 	{
2337 		tspan -= 2*gl_clipangle;
2338 
2339 		// Totally off the left edge?
2340 		if (tspan >= span)
2341 			return;
2342 
2343 		angle2 = (angle_t)-(signed)gl_clipangle;
2344 	}
2345 
2346 #if 0
2347 	{
2348 		float fx1,fx2,fy1,fy2;
2349 		//BP: test with a better projection than viewangletox[R_PointToAngle(angle)]
2350 		// do not enable this at release 4 mul and 2 div
2351 		fx1 = ((polyvertex_t *)(line->pv1))->x-gl_viewx;
2352 		fy1 = ((polyvertex_t *)(line->pv1))->y-gl_viewy;
2353 		fy2 = (fx1 * gl_viewcos + fy1 * gl_viewsin);
2354 		if (fy2 < 0)
2355 			// the point is back
2356 			fx1 = 0;
2357 		else
2358 			fx1 = gl_windowcenterx + (fx1 * gl_viewsin - fy1 * gl_viewcos) * gl_centerx / fy2;
2359 
2360 		fx2 = ((polyvertex_t *)(line->pv2))->x-gl_viewx;
2361 		fy2 = ((polyvertex_t *)(line->pv2))->y-gl_viewy;
2362 		fy1 = (fx2 * gl_viewcos + fy2 * gl_viewsin);
2363 		if (fy1 < 0)
2364 			// the point is back
2365 			fx2 = vid.width;
2366 		else
2367 			fx2 = gl_windowcenterx + (fx2 * gl_viewsin - fy2 * gl_viewcos) * gl_centerx / fy1;
2368 
2369 		x1 = fx1+0.5f;
2370 		x2 = fx2+0.5f;
2371 	}
2372 #else
2373 	// The seg is in the view range,
2374 	// but not necessarily visible.
2375 	angle1 = (angle1+ANGLE_90)>>ANGLETOFINESHIFT;
2376 	angle2 = (angle2+ANGLE_90)>>ANGLETOFINESHIFT;
2377 
2378 	x1 = gl_viewangletox[angle1];
2379 	x2 = gl_viewangletox[angle2];
2380 #endif
2381 	// Does not cross a pixel?
2382 //	if (x1 == x2)
2383 /*	{
2384 		// BP: HERE IS THE MAIN PROBLEM !
2385 		//CONS_Debug(DBG_RENDER, "tineline\n");
2386 		return;
2387 	}
2388 */
2389 #endif
2390 
2391 	gl_backsector = line->backsector;
2392 
2393 #ifdef NEWCLIP
2394 	if (!line->backsector)
2395     {
2396 		gld_clipper_SafeAddClipRange(angle2, angle1);
2397     }
2398     else
2399     {
2400 		boolean bothceilingssky = false, bothfloorssky = false;
2401 
2402 		gl_backsector = R_FakeFlat(gl_backsector, &tempsec, NULL, NULL, true);
2403 
2404 		if (gl_backsector->ceilingpic == skyflatnum && gl_frontsector->ceilingpic == skyflatnum)
2405 			bothceilingssky = true;
2406 		if (gl_backsector->floorpic == skyflatnum && gl_frontsector->floorpic == skyflatnum)
2407 			bothfloorssky = true;
2408 
2409 		if (bothceilingssky && bothfloorssky) // everything's sky? let's save us a bit of time then
2410 		{
2411 			if (!line->polyseg &&
2412 				!line->sidedef->midtexture
2413 				&& ((!gl_frontsector->ffloors && !gl_backsector->ffloors)
2414 					|| Tag_Compare(&gl_frontsector->tags, &gl_backsector->tags)))
2415 				return; // line is empty, don't even bother
2416 			// treat like wide open window instead
2417 			HWR_ProcessSeg(); // Doesn't need arguments because they're defined globally :D
2418 			return;
2419 		}
2420 
2421 		if (CheckClip(line, gl_frontsector, gl_backsector))
2422 		{
2423 			gld_clipper_SafeAddClipRange(angle2, angle1);
2424 			checkforemptylines = false;
2425 		}
2426 		// Reject empty lines used for triggers and special events.
2427 		// Identical floor and ceiling on both sides,
2428 		//  identical light levels on both sides,
2429 		//  and no middle texture.
2430 		if (checkforemptylines && R_IsEmptyLine(line, gl_frontsector, gl_backsector))
2431 			return;
2432     }
2433 
2434 	HWR_ProcessSeg(); // Doesn't need arguments because they're defined globally :D
2435 	return;
2436 #else
2437 	// Single sided line?
2438 	if (!gl_backsector)
2439 		goto clipsolid;
2440 
2441 	gl_backsector = R_FakeFlat(gl_backsector, &tempsec, NULL, NULL, true);
2442 
2443 	if (gl_backsector->ceilingpic == skyflatnum && gl_frontsector->ceilingpic == skyflatnum)
2444 		bothceilingssky = true;
2445 	if (gl_backsector->floorpic == skyflatnum && gl_frontsector->floorpic == skyflatnum)
2446 		bothfloorssky = true;
2447 
2448 	if (bothceilingssky && bothfloorssky) // everything's sky? let's save us a bit of time then
2449 	{
2450 		if (!line->polyseg &&
2451 			!line->sidedef->midtexture
2452 			&& ((!gl_frontsector->ffloors && !gl_backsector->ffloors)
2453 				|| Tag_Compare(&gl_frontsector->tags, &gl_backsector->tags)))
2454 			return; // line is empty, don't even bother
2455 
2456 		goto clippass; // treat like wide open window instead
2457 	}
2458 
2459 	if (gl_frontsector->f_slope || gl_frontsector->c_slope || gl_backsector->f_slope || gl_backsector->c_slope)
2460 	{
2461 		fixed_t frontf1,frontf2, frontc1, frontc2; // front floor/ceiling ends
2462 		fixed_t backf1, backf2, backc1, backc2; // back floor ceiling ends
2463 
2464 #define SLOPEPARAMS(slope, end1, end2, normalheight) \
2465 		end1 = P_GetZAt(slope, v1x, v1y, normalheight); \
2466 		end2 = P_GetZAt(slope, v2x, v2y, normalheight);
2467 
2468 		SLOPEPARAMS(gl_frontsector->f_slope, frontf1, frontf2, gl_frontsector->  floorheight)
2469 		SLOPEPARAMS(gl_frontsector->c_slope, frontc1, frontc2, gl_frontsector->ceilingheight)
2470 		SLOPEPARAMS( gl_backsector->f_slope,  backf1,  backf2,  gl_backsector->  floorheight)
2471 		SLOPEPARAMS( gl_backsector->c_slope,  backc1,  backc2,  gl_backsector->ceilingheight)
2472 #undef SLOPEPARAMS
2473 		// if both ceilings are skies, consider it always "open"
2474 		// same for floors
2475 		if (!bothceilingssky && !bothfloorssky)
2476 		{
2477 			// Closed door.
2478 			if ((backc1 <= frontf1 && backc2 <= frontf2)
2479 				|| (backf1 >= frontc1 && backf2 >= frontc2))
2480 			{
2481 				goto clipsolid;
2482 			}
2483 
2484 			// Check for automap fix.
2485 			if (backc1 <= backf1 && backc2 <= backf2
2486 			&& ((backc1 >= frontc1 && backc2 >= frontc2) || gl_curline->sidedef->toptexture)
2487 			&& ((backf1 <= frontf1 && backf2 >= frontf2) || gl_curline->sidedef->bottomtexture))
2488 				goto clipsolid;
2489 		}
2490 
2491 		// Window.
2492 		if (!bothceilingssky) // ceilings are always the "same" when sky
2493 			if (backc1 != frontc1 || backc2 != frontc2)
2494 				goto clippass;
2495 		if (!bothfloorssky)	// floors are always the "same" when sky
2496 			if (backf1 != frontf1 || backf2 != frontf2)
2497 				goto clippass;
2498 	}
2499 	else
2500 	{
2501 		// if both ceilings are skies, consider it always "open"
2502 		// same for floors
2503 		if (!bothceilingssky && !bothfloorssky)
2504 		{
2505 			// Closed door.
2506 			if (gl_backsector->ceilingheight <= gl_frontsector->floorheight ||
2507 				gl_backsector->floorheight >= gl_frontsector->ceilingheight)
2508 				goto clipsolid;
2509 
2510 			// Check for automap fix.
2511 			if (gl_backsector->ceilingheight <= gl_backsector->floorheight
2512 			&& ((gl_backsector->ceilingheight >= gl_frontsector->ceilingheight) || gl_curline->sidedef->toptexture)
2513 			&& ((gl_backsector->floorheight <= gl_backsector->floorheight) || gl_curline->sidedef->bottomtexture))
2514 				goto clipsolid;
2515 		}
2516 
2517 		// Window.
2518 		if (!bothceilingssky) // ceilings are always the "same" when sky
2519 			if (gl_backsector->ceilingheight != gl_frontsector->ceilingheight)
2520 				goto clippass;
2521 		if (!bothfloorssky)	// floors are always the "same" when sky
2522 			if (gl_backsector->floorheight != gl_frontsector->floorheight)
2523 				goto clippass;
2524 	}
2525 
2526 	// Reject empty lines used for triggers and special events.
2527 	// Identical floor and ceiling on both sides,
2528 	//  identical light levels on both sides,
2529 	//  and no middle texture.
2530 	if (R_IsEmptyLine(gl_curline, gl_frontsector, gl_backsector))
2531 		return;
2532 
2533 clippass:
2534 	if (x1 == x2)
2535 		{  x2++;x1 -= 2; }
2536 	HWR_ClipPassWallSegment(x1, x2-1);
2537 	return;
2538 
2539 clipsolid:
2540 	if (x1 == x2)
2541 		goto clippass;
2542 	HWR_ClipSolidWallSegment(x1, x2-1);
2543 #endif
2544 }
2545 
2546 // HWR_CheckBBox
2547 // Checks BSP node/subtree bounding box.
2548 // Returns true
2549 //  if some part of the bbox might be visible.
2550 //
2551 // modified to use local variables
2552 
HWR_CheckBBox(fixed_t * bspcoord)2553 static boolean HWR_CheckBBox(fixed_t *bspcoord)
2554 {
2555 	INT32 boxpos;
2556 	fixed_t px1, py1, px2, py2;
2557 	angle_t angle1, angle2;
2558 #ifndef NEWCLIP
2559 	INT32 sx1, sx2;
2560 	angle_t span, tspan;
2561 #endif
2562 
2563 	// Find the corners of the box
2564 	// that define the edges from current viewpoint.
2565 	if (dup_viewx <= bspcoord[BOXLEFT])
2566 		boxpos = 0;
2567 	else if (dup_viewx < bspcoord[BOXRIGHT])
2568 		boxpos = 1;
2569 	else
2570 		boxpos = 2;
2571 
2572 	if (dup_viewy >= bspcoord[BOXTOP])
2573 		boxpos |= 0;
2574 	else if (dup_viewy > bspcoord[BOXBOTTOM])
2575 		boxpos |= 1<<2;
2576 	else
2577 		boxpos |= 2<<2;
2578 
2579 	if (boxpos == 5)
2580 		return true;
2581 
2582 	px1 = bspcoord[checkcoord[boxpos][0]];
2583 	py1 = bspcoord[checkcoord[boxpos][1]];
2584 	px2 = bspcoord[checkcoord[boxpos][2]];
2585 	py2 = bspcoord[checkcoord[boxpos][3]];
2586 
2587 #ifdef NEWCLIP
2588 	angle1 = R_PointToAngle64(px1, py1);
2589 	angle2 = R_PointToAngle64(px2, py2);
2590 	return gld_clipper_SafeCheckRange(angle2, angle1);
2591 #else
2592 	// check clip list for an open space
2593 	angle1 = R_PointToAngle2(dup_viewx>>1, dup_viewy>>1, px1>>1, py1>>1) - dup_viewangle;
2594 	angle2 = R_PointToAngle2(dup_viewx>>1, dup_viewy>>1, px2>>1, py2>>1) - dup_viewangle;
2595 
2596 	span = angle1 - angle2;
2597 
2598 	// Sitting on a line?
2599 	if (span >= ANGLE_180)
2600 		return true;
2601 
2602 	tspan = angle1 + gl_clipangle;
2603 
2604 	if (tspan > 2*gl_clipangle)
2605 	{
2606 		tspan -= 2*gl_clipangle;
2607 
2608 		// Totally off the left edge?
2609 		if (tspan >= span)
2610 			return false;
2611 
2612 		angle1 = gl_clipangle;
2613 	}
2614 	tspan = gl_clipangle - angle2;
2615 	if (tspan > 2*gl_clipangle)
2616 	{
2617 		tspan -= 2*gl_clipangle;
2618 
2619 		// Totally off the left edge?
2620 		if (tspan >= span)
2621 			return false;
2622 
2623 		angle2 = (angle_t)-(signed)gl_clipangle;
2624 	}
2625 
2626 	// Find the first clippost
2627 	//  that touches the source post
2628 	//  (adjacent pixels are touching).
2629 	angle1 = (angle1+ANGLE_90)>>ANGLETOFINESHIFT;
2630 	angle2 = (angle2+ANGLE_90)>>ANGLETOFINESHIFT;
2631 	sx1 = gl_viewangletox[angle1];
2632 	sx2 = gl_viewangletox[angle2];
2633 
2634 	// Does not cross a pixel.
2635 	if (sx1 == sx2)
2636 		return false;
2637 
2638 	return HWR_ClipToSolidSegs(sx1, sx2 - 1);
2639 #endif
2640 }
2641 
2642 //
2643 // HWR_AddPolyObjectSegs
2644 //
2645 // haleyjd 02/19/06
2646 // Adds all segs in all polyobjects in the given subsector.
2647 // Modified for hardware rendering.
2648 //
HWR_AddPolyObjectSegs(void)2649 static inline void HWR_AddPolyObjectSegs(void)
2650 {
2651 	size_t i, j;
2652 	seg_t *gl_fakeline = Z_Calloc(sizeof(seg_t), PU_STATIC, NULL);
2653 	polyvertex_t *pv1 = Z_Calloc(sizeof(polyvertex_t), PU_STATIC, NULL);
2654 	polyvertex_t *pv2 = Z_Calloc(sizeof(polyvertex_t), PU_STATIC, NULL);
2655 
2656 	// Sort through all the polyobjects
2657 	for (i = 0; i < numpolys; ++i)
2658 	{
2659 		// Render the polyobject's lines
2660 		for (j = 0; j < po_ptrs[i]->segCount; ++j)
2661 		{
2662 			// Copy the info of a polyobject's seg, then convert it to OpenGL floating point
2663 			M_Memcpy(gl_fakeline, po_ptrs[i]->segs[j], sizeof(seg_t));
2664 
2665 			// Now convert the line to float and add it to be rendered
2666 			pv1->x = FIXED_TO_FLOAT(gl_fakeline->v1->x);
2667 			pv1->y = FIXED_TO_FLOAT(gl_fakeline->v1->y);
2668 			pv2->x = FIXED_TO_FLOAT(gl_fakeline->v2->x);
2669 			pv2->y = FIXED_TO_FLOAT(gl_fakeline->v2->y);
2670 
2671 			gl_fakeline->pv1 = pv1;
2672 			gl_fakeline->pv2 = pv2;
2673 
2674 			HWR_AddLine(gl_fakeline);
2675 		}
2676 	}
2677 
2678 	// Free temporary data no longer needed
2679 	Z_Free(pv2);
2680 	Z_Free(pv1);
2681 	Z_Free(gl_fakeline);
2682 }
2683 
HWR_RenderPolyObjectPlane(polyobj_t * polysector,boolean isceiling,fixed_t fixedheight,FBITFIELD blendmode,UINT8 lightlevel,levelflat_t * levelflat,sector_t * FOFsector,UINT8 alpha,extracolormap_t * planecolormap)2684 static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, fixed_t fixedheight,
2685 									FBITFIELD blendmode, UINT8 lightlevel, levelflat_t *levelflat, sector_t *FOFsector,
2686 									UINT8 alpha, extracolormap_t *planecolormap)
2687 {
2688 	FSurfaceInfo Surf;
2689 	FOutVector *v3d;
2690 	INT32 shader = SHADER_DEFAULT;
2691 
2692 	size_t nrPlaneVerts = polysector->numVertices;
2693 	INT32 i;
2694 
2695 	float height = FIXED_TO_FLOAT(fixedheight); // constant y for all points on the convex flat polygon
2696 	float flatxref, flatyref;
2697 	float fflatwidth = 64.0f, fflatheight = 64.0f;
2698 	INT32 flatflag = 63;
2699 
2700 	boolean texflat = false;
2701 
2702 	float scrollx = 0.0f, scrolly = 0.0f;
2703 	angle_t angle = 0;
2704 	fixed_t tempxs, tempyt;
2705 
2706 	static FOutVector *planeVerts = NULL;
2707 	static UINT16 numAllocedPlaneVerts = 0;
2708 
2709 	if (nrPlaneVerts < 3)   // Not even a triangle?
2710 		return;
2711 	else if (nrPlaneVerts > (size_t)UINT16_MAX) // FIXME: exceeds plVerts size
2712 	{
2713 		CONS_Debug(DBG_RENDER, "polygon size of %s exceeds max value of %d vertices\n", sizeu1(nrPlaneVerts), UINT16_MAX);
2714 		return;
2715 	}
2716 
2717 	// Allocate plane-vertex buffer if we need to
2718 	if (!planeVerts || nrPlaneVerts > numAllocedPlaneVerts)
2719 	{
2720 		numAllocedPlaneVerts = (UINT16)nrPlaneVerts;
2721 		Z_Free(planeVerts);
2722 		Z_Malloc(numAllocedPlaneVerts * sizeof (FOutVector), PU_LEVEL, &planeVerts);
2723 	}
2724 
2725 	// set texture for polygon
2726 	if (levelflat != NULL)
2727 	{
2728 		if (levelflat->type == LEVELFLAT_FLAT)
2729 		{
2730 			size_t len = W_LumpLength(levelflat->u.flat.lumpnum);
2731 			switch (len)
2732 			{
2733 				case 4194304: // 2048x2048 lump
2734 					fflatwidth = fflatheight = 2048.0f;
2735 					break;
2736 				case 1048576: // 1024x1024 lump
2737 					fflatwidth = fflatheight = 1024.0f;
2738 					break;
2739 				case 262144:// 512x512 lump
2740 					fflatwidth = fflatheight = 512.0f;
2741 					break;
2742 				case 65536: // 256x256 lump
2743 					fflatwidth = fflatheight = 256.0f;
2744 					break;
2745 				case 16384: // 128x128 lump
2746 					fflatwidth = fflatheight = 128.0f;
2747 					break;
2748 				case 1024: // 32x32 lump
2749 					fflatwidth = fflatheight = 32.0f;
2750 					break;
2751 				default: // 64x64 lump
2752 					fflatwidth = fflatheight = 64.0f;
2753 					break;
2754 			}
2755 			flatflag = ((INT32)fflatwidth)-1;
2756 		}
2757 		else
2758 		{
2759 			if (levelflat->type == LEVELFLAT_TEXTURE)
2760 			{
2761 				fflatwidth = textures[levelflat->u.texture.num]->width;
2762 				fflatheight = textures[levelflat->u.texture.num]->height;
2763 			}
2764 			else if (levelflat->type == LEVELFLAT_PATCH || levelflat->type == LEVELFLAT_PNG)
2765 			{
2766 				fflatwidth = levelflat->width;
2767 				fflatheight = levelflat->height;
2768 			}
2769 			texflat = true;
2770 		}
2771 	}
2772 	else // set no texture
2773 		HWR_SetCurrentTexture(NULL);
2774 
2775 	// reference point for flat texture coord for each vertex around the polygon
2776 	flatxref = FIXED_TO_FLOAT(polysector->origVerts[0].x);
2777 	flatyref = FIXED_TO_FLOAT(polysector->origVerts[0].y);
2778 
2779 	flatxref = (float)(((fixed_t)flatxref & (~flatflag)) / fflatwidth);
2780 	flatyref = (float)(((fixed_t)flatyref & (~flatflag)) / fflatheight);
2781 
2782 	// transform
2783 	v3d = planeVerts;
2784 
2785 	if (FOFsector != NULL)
2786 	{
2787 		if (!isceiling) // it's a floor
2788 		{
2789 			scrollx = FIXED_TO_FLOAT(FOFsector->floor_xoffs)/fflatwidth;
2790 			scrolly = FIXED_TO_FLOAT(FOFsector->floor_yoffs)/fflatheight;
2791 			angle = FOFsector->floorpic_angle;
2792 		}
2793 		else // it's a ceiling
2794 		{
2795 			scrollx = FIXED_TO_FLOAT(FOFsector->ceiling_xoffs)/fflatwidth;
2796 			scrolly = FIXED_TO_FLOAT(FOFsector->ceiling_yoffs)/fflatheight;
2797 			angle = FOFsector->ceilingpic_angle;
2798 		}
2799 	}
2800 	else if (gl_frontsector)
2801 	{
2802 		if (!isceiling) // it's a floor
2803 		{
2804 			scrollx = FIXED_TO_FLOAT(gl_frontsector->floor_xoffs)/fflatwidth;
2805 			scrolly = FIXED_TO_FLOAT(gl_frontsector->floor_yoffs)/fflatheight;
2806 			angle = gl_frontsector->floorpic_angle;
2807 		}
2808 		else // it's a ceiling
2809 		{
2810 			scrollx = FIXED_TO_FLOAT(gl_frontsector->ceiling_xoffs)/fflatwidth;
2811 			scrolly = FIXED_TO_FLOAT(gl_frontsector->ceiling_yoffs)/fflatheight;
2812 			angle = gl_frontsector->ceilingpic_angle;
2813 		}
2814 	}
2815 
2816 	if (angle) // Only needs to be done if there's an altered angle
2817 	{
2818 		angle = (InvAngle(angle))>>ANGLETOFINESHIFT;
2819 
2820 		// This needs to be done so that it scrolls in a different direction after rotation like software
2821 		/*tempxs = FLOAT_TO_FIXED(scrollx);
2822 		tempyt = FLOAT_TO_FIXED(scrolly);
2823 		scrollx = (FIXED_TO_FLOAT(FixedMul(tempxs, FINECOSINE(angle)) - FixedMul(tempyt, FINESINE(angle))));
2824 		scrolly = (FIXED_TO_FLOAT(FixedMul(tempxs, FINESINE(angle)) + FixedMul(tempyt, FINECOSINE(angle))));*/
2825 
2826 		// This needs to be done so everything aligns after rotation
2827 		// It would be done so that rotation is done, THEN the translation, but I couldn't get it to rotate AND scroll like software does
2828 		tempxs = FLOAT_TO_FIXED(flatxref);
2829 		tempyt = FLOAT_TO_FIXED(flatyref);
2830 		flatxref = (FIXED_TO_FLOAT(FixedMul(tempxs, FINECOSINE(angle)) - FixedMul(tempyt, FINESINE(angle))));
2831 		flatyref = (FIXED_TO_FLOAT(FixedMul(tempxs, FINESINE(angle)) + FixedMul(tempyt, FINECOSINE(angle))));
2832 	}
2833 
2834 	for (i = 0; i < (INT32)nrPlaneVerts; i++,v3d++)
2835 	{
2836 		// Go from the polysector's original vertex locations
2837 		// Means the flat is offset based on the original vertex locations
2838 		if (texflat)
2839 		{
2840 			v3d->s = (float)(FIXED_TO_FLOAT(polysector->origVerts[i].x) / fflatwidth) + scrollx;
2841 			v3d->t = -(float)(FIXED_TO_FLOAT(polysector->origVerts[i].y) / fflatheight) + scrolly;
2842 		}
2843 		else
2844 		{
2845 			v3d->s = (float)((FIXED_TO_FLOAT(polysector->origVerts[i].x) / fflatwidth) - flatxref + scrollx);
2846 			v3d->t = (float)(flatyref - (FIXED_TO_FLOAT(polysector->origVerts[i].y) / fflatheight) + scrolly);
2847 		}
2848 
2849 		// Need to rotate before translate
2850 		if (angle) // Only needs to be done if there's an altered angle
2851 		{
2852 			tempxs = FLOAT_TO_FIXED(v3d->s);
2853 			tempyt = FLOAT_TO_FIXED(v3d->t);
2854 			v3d->s = (FIXED_TO_FLOAT(FixedMul(tempxs, FINECOSINE(angle)) - FixedMul(tempyt, FINESINE(angle))));
2855 			v3d->t = (FIXED_TO_FLOAT(FixedMul(tempxs, FINESINE(angle)) + FixedMul(tempyt, FINECOSINE(angle))));
2856 		}
2857 
2858 		v3d->x = FIXED_TO_FLOAT(polysector->vertices[i]->x);
2859 		v3d->y = height;
2860 		v3d->z = FIXED_TO_FLOAT(polysector->vertices[i]->y);
2861 	}
2862 
2863 	HWR_Lighting(&Surf, lightlevel, planecolormap);
2864 
2865 	if (blendmode & PF_Translucent)
2866 	{
2867 		Surf.PolyColor.s.alpha = (UINT8)alpha;
2868 		blendmode |= PF_Modulated|PF_Occlude;
2869 	}
2870 	else
2871 		blendmode |= PF_Masked|PF_Modulated;
2872 
2873 	if (HWR_UseShader())
2874 	{
2875 		shader = SHADER_FLOOR;
2876 		blendmode |= PF_ColorMapped;
2877 	}
2878 
2879 	HWR_ProcessPolygon(&Surf, planeVerts, nrPlaneVerts, blendmode, shader, false);
2880 }
2881 
HWR_AddPolyObjectPlanes(void)2882 static void HWR_AddPolyObjectPlanes(void)
2883 {
2884 	size_t i;
2885 	sector_t *polyobjsector;
2886 	INT32 light = 0;
2887 
2888 	// Polyobject Planes need their own function for drawing because they don't have extrasubsectors by themselves
2889 	// It should be okay because polyobjects should always be convex anyway
2890 
2891 	for (i  = 0; i < numpolys; i++)
2892 	{
2893 		polyobjsector = po_ptrs[i]->lines[0]->backsector; // the in-level polyobject sector
2894 
2895 		if (!(po_ptrs[i]->flags & POF_RENDERPLANES)) // Only render planes when you should
2896 			continue;
2897 
2898 		if (po_ptrs[i]->translucency >= NUMTRANSMAPS)
2899 			continue;
2900 
2901 		if (polyobjsector->floorheight <= gl_frontsector->ceilingheight
2902 			&& polyobjsector->floorheight >= gl_frontsector->floorheight
2903 			&& (viewz < polyobjsector->floorheight))
2904 		{
2905 			light = R_GetPlaneLight(gl_frontsector, polyobjsector->floorheight, true);
2906 			if (po_ptrs[i]->translucency > 0)
2907 			{
2908 				FSurfaceInfo Surf;
2909 				FBITFIELD blendmode;
2910 				memset(&Surf, 0x00, sizeof(Surf));
2911 				blendmode = HWR_TranstableToAlpha(po_ptrs[i]->translucency, &Surf);
2912 				HWR_AddTransparentPolyobjectFloor(&levelflats[polyobjsector->floorpic], po_ptrs[i], false, polyobjsector->floorheight,
2913 													(light == -1 ? gl_frontsector->lightlevel : *gl_frontsector->lightlist[light].lightlevel), Surf.PolyColor.s.alpha, polyobjsector, blendmode, (light == -1 ? gl_frontsector->extra_colormap : *gl_frontsector->lightlist[light].extra_colormap));
2914 			}
2915 			else
2916 			{
2917 				HWR_GetLevelFlat(&levelflats[polyobjsector->floorpic]);
2918 				HWR_RenderPolyObjectPlane(po_ptrs[i], false, polyobjsector->floorheight, PF_Occlude,
2919 										(light == -1 ? gl_frontsector->lightlevel : *gl_frontsector->lightlist[light].lightlevel), &levelflats[polyobjsector->floorpic],
2920 										polyobjsector, 255, (light == -1 ? gl_frontsector->extra_colormap : *gl_frontsector->lightlist[light].extra_colormap));
2921 			}
2922 		}
2923 
2924 		if (polyobjsector->ceilingheight >= gl_frontsector->floorheight
2925 			&& polyobjsector->ceilingheight <= gl_frontsector->ceilingheight
2926 			&& (viewz > polyobjsector->ceilingheight))
2927 		{
2928 			light = R_GetPlaneLight(gl_frontsector, polyobjsector->ceilingheight, true);
2929 			if (po_ptrs[i]->translucency > 0)
2930 			{
2931 				FSurfaceInfo Surf;
2932 				FBITFIELD blendmode;
2933 				memset(&Surf, 0x00, sizeof(Surf));
2934 				blendmode = HWR_TranstableToAlpha(po_ptrs[i]->translucency, &Surf);
2935 				HWR_AddTransparentPolyobjectFloor(&levelflats[polyobjsector->ceilingpic], po_ptrs[i], true, polyobjsector->ceilingheight,
2936 				                                  (light == -1 ? gl_frontsector->lightlevel : *gl_frontsector->lightlist[light].lightlevel), Surf.PolyColor.s.alpha, polyobjsector, blendmode, (light == -1 ? gl_frontsector->extra_colormap : *gl_frontsector->lightlist[light].extra_colormap));
2937 			}
2938 			else
2939 			{
2940 				HWR_GetLevelFlat(&levelflats[polyobjsector->ceilingpic]);
2941 				HWR_RenderPolyObjectPlane(po_ptrs[i], true, polyobjsector->ceilingheight, PF_Occlude,
2942 				                          (light == -1 ? gl_frontsector->lightlevel : *gl_frontsector->lightlist[light].lightlevel), &levelflats[polyobjsector->ceilingpic],
2943 				                          polyobjsector, 255, (light == -1 ? gl_frontsector->extra_colormap : *gl_frontsector->lightlist[light].extra_colormap));
2944 			}
2945 		}
2946 	}
2947 }
2948 
2949 // -----------------+
2950 // HWR_Subsector    : Determine floor/ceiling planes.
2951 //                  : Add sprites of things in sector.
2952 //                  : Draw one or more line segments.
2953 // Notes            : Sets gl_cursectorlight to the light of the parent sector, to modulate wall textures
2954 // -----------------+
HWR_Subsector(size_t num)2955 static void HWR_Subsector(size_t num)
2956 {
2957 	INT16 count;
2958 	seg_t *line;
2959 	subsector_t *sub;
2960 	static sector_t tempsec; //SoM: 4/7/2000
2961 	INT32 floorlightlevel;
2962 	INT32 ceilinglightlevel;
2963 	INT32 locFloorHeight, locCeilingHeight;
2964 	INT32 cullFloorHeight, cullCeilingHeight;
2965 	INT32 light = 0;
2966 	extracolormap_t *floorcolormap;
2967 	extracolormap_t *ceilingcolormap;
2968 
2969 #ifdef PARANOIA //no risk while developing, enough debugging nights!
2970 	if (num >= addsubsector)
2971 		I_Error("HWR_Subsector: ss %s with numss = %s, addss = %s\n",
2972 			sizeu1(num), sizeu2(numsubsectors), sizeu3(addsubsector));
2973 
2974 	/*if (num >= numsubsectors)
2975 		I_Error("HWR_Subsector: ss %i with numss = %i",
2976 		        num,
2977 		        numsubsectors);*/
2978 #endif
2979 
2980 	if (num < numsubsectors)
2981 	{
2982 		// subsector
2983 		sub = &subsectors[num];
2984 		// sector
2985 		gl_frontsector = sub->sector;
2986 		// how many linedefs
2987 		count = sub->numlines;
2988 		// first line seg
2989 		line = &segs[sub->firstline];
2990 	}
2991 	else
2992 	{
2993 		// there are no segs but only planes
2994 		sub = &subsectors[0];
2995 		gl_frontsector = sub->sector;
2996 		count = 0;
2997 		line = NULL;
2998 	}
2999 
3000 	//SoM: 4/7/2000: Test to make Boom water work in Hardware mode.
3001 	gl_frontsector = R_FakeFlat(gl_frontsector, &tempsec, &floorlightlevel,
3002 								&ceilinglightlevel, false);
3003 	//FIXME: Use floorlightlevel and ceilinglightlevel insted of lightlevel.
3004 
3005 	floorcolormap = ceilingcolormap = gl_frontsector->extra_colormap;
3006 
3007 	// ------------------------------------------------------------------------
3008 	// sector lighting, DISABLED because it's done in HWR_StoreWallRange
3009 	// ------------------------------------------------------------------------
3010 	/// \todo store a RGBA instead of just intensity, allow coloured sector lighting
3011 	//light = (FUBYTE)(sub->sector->lightlevel & 0xFF) / 255.0f;
3012 	//gl_cursectorlight.red   = light;
3013 	//gl_cursectorlight.green = light;
3014 	//gl_cursectorlight.blue  = light;
3015 	//gl_cursectorlight.alpha = light;
3016 
3017 // ----- end special tricks -----
3018 	cullFloorHeight   = P_GetSectorFloorZAt  (gl_frontsector, viewx, viewy);
3019 	cullCeilingHeight = P_GetSectorCeilingZAt(gl_frontsector, viewx, viewy);
3020 	locFloorHeight    = P_GetSectorFloorZAt  (gl_frontsector, gl_frontsector->soundorg.x, gl_frontsector->soundorg.y);
3021 	locCeilingHeight  = P_GetSectorCeilingZAt(gl_frontsector, gl_frontsector->soundorg.x, gl_frontsector->soundorg.y);
3022 
3023 	if (gl_frontsector->ffloors)
3024 	{
3025 		if (gl_frontsector->moved)
3026 		{
3027 			gl_frontsector->numlights = sub->sector->numlights = 0;
3028 			R_Prep3DFloors(gl_frontsector);
3029 			sub->sector->lightlist = gl_frontsector->lightlist;
3030 			sub->sector->numlights = gl_frontsector->numlights;
3031 			sub->sector->moved = gl_frontsector->moved = false;
3032 		}
3033 
3034 		light = R_GetPlaneLight(gl_frontsector, locFloorHeight, false);
3035 		if (gl_frontsector->floorlightsec == -1)
3036 			floorlightlevel = *gl_frontsector->lightlist[light].lightlevel;
3037 		floorcolormap = *gl_frontsector->lightlist[light].extra_colormap;
3038 
3039 		light = R_GetPlaneLight(gl_frontsector, locCeilingHeight, false);
3040 		if (gl_frontsector->ceilinglightsec == -1)
3041 			ceilinglightlevel = *gl_frontsector->lightlist[light].lightlevel;
3042 		ceilingcolormap = *gl_frontsector->lightlist[light].extra_colormap;
3043 	}
3044 
3045 	sub->sector->extra_colormap = gl_frontsector->extra_colormap;
3046 
3047 	// render floor ?
3048 #ifdef DOPLANES
3049 	// yeah, easy backface cull! :)
3050 	if (cullFloorHeight < dup_viewz)
3051 	{
3052 		if (gl_frontsector->floorpic != skyflatnum)
3053 		{
3054 			if (sub->validcount != validcount)
3055 			{
3056 				HWR_GetLevelFlat(&levelflats[gl_frontsector->floorpic]);
3057 				HWR_RenderPlane(sub, &extrasubsectors[num], false,
3058 					// Hack to make things continue to work around slopes.
3059 					locFloorHeight == cullFloorHeight ? locFloorHeight : gl_frontsector->floorheight,
3060 					// We now return you to your regularly scheduled rendering.
3061 					PF_Occlude, floorlightlevel, &levelflats[gl_frontsector->floorpic], NULL, 255, floorcolormap);
3062 			}
3063 		}
3064 		else
3065 		{
3066 #ifdef POLYSKY
3067 			HWR_RenderSkyPlane(&extrasubsectors[num], locFloorHeight);
3068 #endif
3069 		}
3070 	}
3071 
3072 	if (cullCeilingHeight > dup_viewz)
3073 	{
3074 		if (gl_frontsector->ceilingpic != skyflatnum)
3075 		{
3076 			if (sub->validcount != validcount)
3077 			{
3078 				HWR_GetLevelFlat(&levelflats[gl_frontsector->ceilingpic]);
3079 				HWR_RenderPlane(sub, &extrasubsectors[num], true,
3080 					// Hack to make things continue to work around slopes.
3081 					locCeilingHeight == cullCeilingHeight ? locCeilingHeight : gl_frontsector->ceilingheight,
3082 					// We now return you to your regularly scheduled rendering.
3083 					PF_Occlude, ceilinglightlevel, &levelflats[gl_frontsector->ceilingpic], NULL, 255, ceilingcolormap);
3084 			}
3085 		}
3086 		else
3087 		{
3088 #ifdef POLYSKY
3089 			HWR_RenderSkyPlane(&extrasubsectors[num], locCeilingHeight);
3090 #endif
3091 		}
3092 	}
3093 
3094 #ifndef POLYSKY
3095 	// Moved here because before, when above the ceiling and the floor does not have the sky flat, it doesn't draw the sky
3096 	if (gl_frontsector->ceilingpic == skyflatnum || gl_frontsector->floorpic == skyflatnum)
3097 		drawsky = true;
3098 #endif
3099 
3100 #ifdef R_FAKEFLOORS
3101 	if (gl_frontsector->ffloors)
3102 	{
3103 		/// \todo fix light, xoffs, yoffs, extracolormap ?
3104 		ffloor_t * rover;
3105 		for (rover = gl_frontsector->ffloors;
3106 			rover; rover = rover->next)
3107 		{
3108 			fixed_t cullHeight, centerHeight;
3109 
3110             // bottom plane
3111 			cullHeight   = P_GetFFloorBottomZAt(rover, viewx, viewy);
3112 			centerHeight = P_GetFFloorBottomZAt(rover, gl_frontsector->soundorg.x, gl_frontsector->soundorg.y);
3113 
3114 			if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERPLANES))
3115 				continue;
3116 			if (sub->validcount == validcount)
3117 				continue;
3118 
3119 			if (centerHeight <= locCeilingHeight &&
3120 			    centerHeight >= locFloorHeight &&
3121 			    ((dup_viewz < cullHeight && (rover->flags & FF_BOTHPLANES || !(rover->flags & FF_INVERTPLANES))) ||
3122 			     (dup_viewz > cullHeight && (rover->flags & FF_BOTHPLANES || rover->flags & FF_INVERTPLANES))))
3123 			{
3124 				if (rover->flags & FF_FOG)
3125 				{
3126 					UINT8 alpha;
3127 
3128 					light = R_GetPlaneLight(gl_frontsector, centerHeight, dup_viewz < cullHeight ? true : false);
3129 					alpha = HWR_FogBlockAlpha(*gl_frontsector->lightlist[light].lightlevel, rover->master->frontsector->extra_colormap);
3130 
3131 					HWR_AddTransparentFloor(0,
3132 					                       &extrasubsectors[num],
3133 										   false,
3134 					                       *rover->bottomheight,
3135 					                       *gl_frontsector->lightlist[light].lightlevel,
3136 					                       alpha, rover->master->frontsector, PF_Fog|PF_NoTexture,
3137 										   true, rover->master->frontsector->extra_colormap);
3138 				}
3139 				else if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256) // SoM: Flags are more efficient
3140 				{
3141 					light = R_GetPlaneLight(gl_frontsector, centerHeight, dup_viewz < cullHeight ? true : false);
3142 
3143 					HWR_AddTransparentFloor(&levelflats[*rover->bottompic],
3144 					                       &extrasubsectors[num],
3145 										   false,
3146 					                       *rover->bottomheight,
3147 					                       *gl_frontsector->lightlist[light].lightlevel,
3148 					                       rover->alpha-1 > 255 ? 255 : rover->alpha-1, rover->master->frontsector, (rover->flags & FF_RIPPLE ? PF_Ripple : 0)|PF_Translucent,
3149 					                       false, *gl_frontsector->lightlist[light].extra_colormap);
3150 				}
3151 				else
3152 				{
3153 					HWR_GetLevelFlat(&levelflats[*rover->bottompic]);
3154 					light = R_GetPlaneLight(gl_frontsector, centerHeight, dup_viewz < cullHeight ? true : false);
3155 					HWR_RenderPlane(sub, &extrasubsectors[num], false, *rover->bottomheight, (rover->flags & FF_RIPPLE ? PF_Ripple : 0)|PF_Occlude, *gl_frontsector->lightlist[light].lightlevel, &levelflats[*rover->bottompic],
3156 					                rover->master->frontsector, 255, *gl_frontsector->lightlist[light].extra_colormap);
3157 				}
3158 			}
3159 
3160 			// top plane
3161 			cullHeight   = P_GetFFloorTopZAt(rover, viewx, viewy);
3162 			centerHeight = P_GetFFloorTopZAt(rover, gl_frontsector->soundorg.x, gl_frontsector->soundorg.y);
3163 
3164 			if (centerHeight >= locFloorHeight &&
3165 			    centerHeight <= locCeilingHeight &&
3166 			    ((dup_viewz > cullHeight && (rover->flags & FF_BOTHPLANES || !(rover->flags & FF_INVERTPLANES))) ||
3167 			     (dup_viewz < cullHeight && (rover->flags & FF_BOTHPLANES || rover->flags & FF_INVERTPLANES))))
3168 			{
3169 				if (rover->flags & FF_FOG)
3170 				{
3171 					UINT8 alpha;
3172 
3173 					light = R_GetPlaneLight(gl_frontsector, centerHeight, dup_viewz < cullHeight ? true : false);
3174 					alpha = HWR_FogBlockAlpha(*gl_frontsector->lightlist[light].lightlevel, rover->master->frontsector->extra_colormap);
3175 
3176 					HWR_AddTransparentFloor(0,
3177 					                       &extrasubsectors[num],
3178 										   true,
3179 					                       *rover->topheight,
3180 					                       *gl_frontsector->lightlist[light].lightlevel,
3181 					                       alpha, rover->master->frontsector, PF_Fog|PF_NoTexture,
3182 										   true, rover->master->frontsector->extra_colormap);
3183 				}
3184 				else if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256)
3185 				{
3186 					light = R_GetPlaneLight(gl_frontsector, centerHeight, dup_viewz < cullHeight ? true : false);
3187 
3188 					HWR_AddTransparentFloor(&levelflats[*rover->toppic],
3189 					                        &extrasubsectors[num],
3190 											true,
3191 					                        *rover->topheight,
3192 					                        *gl_frontsector->lightlist[light].lightlevel,
3193 					                        rover->alpha-1 > 255 ? 255 : rover->alpha-1, rover->master->frontsector, (rover->flags & FF_RIPPLE ? PF_Ripple : 0)|PF_Translucent,
3194 					                        false, *gl_frontsector->lightlist[light].extra_colormap);
3195 				}
3196 				else
3197 				{
3198 					HWR_GetLevelFlat(&levelflats[*rover->toppic]);
3199 					light = R_GetPlaneLight(gl_frontsector, centerHeight, dup_viewz < cullHeight ? true : false);
3200 					HWR_RenderPlane(sub, &extrasubsectors[num], true, *rover->topheight, (rover->flags & FF_RIPPLE ? PF_Ripple : 0)|PF_Occlude, *gl_frontsector->lightlist[light].lightlevel, &levelflats[*rover->toppic],
3201 					                  rover->master->frontsector, 255, *gl_frontsector->lightlist[light].extra_colormap);
3202 				}
3203 			}
3204 		}
3205 	}
3206 #endif
3207 #endif //doplanes
3208 
3209 	// Draw all the polyobjects in this subsector
3210 	if (sub->polyList)
3211 	{
3212 		polyobj_t *po = sub->polyList;
3213 
3214 		numpolys = 0;
3215 
3216 		// Count all the polyobjects, reset the list, and recount them
3217 		while (po)
3218 		{
3219 			++numpolys;
3220 			po = (polyobj_t *)(po->link.next);
3221 		}
3222 
3223 		// for render stats
3224 		ps_numpolyobjects += numpolys;
3225 
3226 		// Sort polyobjects
3227 		R_SortPolyObjects(sub);
3228 
3229 		// Draw polyobject lines.
3230 		HWR_AddPolyObjectSegs();
3231 
3232 		if (sub->validcount != validcount) // This validcount situation seems to let us know that the floors have already been drawn.
3233 		{
3234 			// Draw polyobject planes
3235 			HWR_AddPolyObjectPlanes();
3236 		}
3237 	}
3238 
3239 // Hurder ici se passe les choses INT32�essantes!
3240 // on vient de tracer le sol et le plafond
3241 // on trace �pr�ent d'abord les sprites et ensuite les murs
3242 // hurdler: faux: on ajoute seulement les sprites, le murs sont trac� d'abord
3243 	if (line)
3244 	{
3245 		// draw sprites first, coz they are clipped to the solidsegs of
3246 		// subsectors more 'in front'
3247 		HWR_AddSprites(gl_frontsector);
3248 
3249 		//Hurdler: at this point validcount must be the same, but is not because
3250 		//         gl_frontsector doesn't point anymore to sub->sector due to
3251 		//         the call gl_frontsector = R_FakeFlat(...)
3252 		//         if it's not done, the sprite is drawn more than once,
3253 		//         what looks really bad with translucency or dynamic light,
3254 		//         without talking about the overdraw of course.
3255 		sub->sector->validcount = validcount;/// \todo fix that in a better way
3256 
3257 		while (count--)
3258 		{
3259 
3260 			if (!line->glseg && !line->polyseg) // ignore segs that belong to polyobjects
3261 				HWR_AddLine(line);
3262 			line++;
3263 		}
3264 	}
3265 
3266 	sub->validcount = validcount;
3267 }
3268 
3269 //
3270 // Renders all subsectors below a given node,
3271 //  traversing subtree recursively.
3272 // Just call with BSP root.
3273 
3274 #ifdef coolhack
3275 //t;b;l;r
3276 static fixed_t hackbbox[4];
3277 //BOXTOP,
3278 //BOXBOTTOM,
3279 //BOXLEFT,
3280 //BOXRIGHT
HWR_CheckHackBBox(fixed_t * bb)3281 static boolean HWR_CheckHackBBox(fixed_t *bb)
3282 {
3283 	if (bb[BOXTOP] < hackbbox[BOXBOTTOM]) //y up
3284 		return false;
3285 	if (bb[BOXBOTTOM] > hackbbox[BOXTOP])
3286 		return false;
3287 	if (bb[BOXLEFT] > hackbbox[BOXRIGHT])
3288 		return false;
3289 	if (bb[BOXRIGHT] < hackbbox[BOXLEFT])
3290 		return false;
3291 	return true;
3292 }
3293 #endif
3294 
3295 // BP: big hack for a test in lighning ref : 1249753487AB
3296 fixed_t *hwbbox;
3297 
HWR_RenderBSPNode(INT32 bspnum)3298 static void HWR_RenderBSPNode(INT32 bspnum)
3299 {
3300 	/*//GZDoom code
3301 	if(bspnum == -1)
3302 	{
3303 		HWR_Subsector(subsectors);
3304 		return;
3305 	}
3306 	while(!((size_t)bspnum&(~NF_SUBSECTOR))) // Keep going until found a subsector
3307 	{
3308 		node_t *bsp = &nodes[bspnum];
3309 
3310 		// Decide which side the view point is on
3311 		INT32 side = R_PointOnSide(dup_viewx, dup_viewy, bsp);
3312 
3313 		// Recursively divide front space (toward the viewer)
3314 		HWR_RenderBSPNode(bsp->children[side]);
3315 
3316 		// Possibly divide back space (away from viewer)
3317 		side ^= 1;
3318 
3319 		if (!HWR_CheckBBox(bsp->bbox[side]))
3320 			return;
3321 
3322 		bspnum = bsp->children[side];
3323 	}
3324 
3325 	HWR_Subsector(bspnum-1);
3326 */
3327 	node_t *bsp = &nodes[bspnum];
3328 
3329 	// Decide which side the view point is on
3330 	INT32 side;
3331 
3332 	ps_numbspcalls++;
3333 
3334 	// Found a subsector?
3335 	if (bspnum & NF_SUBSECTOR)
3336 	{
3337 		if (bspnum == -1)
3338 		{
3339 			//*(gl_drawsubsector_p++) = 0;
3340 			HWR_Subsector(0);
3341 		}
3342 		else
3343 		{
3344 			//*(gl_drawsubsector_p++) = bspnum&(~NF_SUBSECTOR);
3345 			HWR_Subsector(bspnum&(~NF_SUBSECTOR));
3346 		}
3347 		return;
3348 	}
3349 
3350 	// Decide which side the view point is on.
3351 	side = R_PointOnSide(dup_viewx, dup_viewy, bsp);
3352 
3353 	// BP: big hack for a test in lighning ref : 1249753487AB
3354 	hwbbox = bsp->bbox[side];
3355 
3356 	// Recursively divide front space.
3357 	HWR_RenderBSPNode(bsp->children[side]);
3358 
3359 	// Possibly divide back space.
3360 	if (HWR_CheckBBox(bsp->bbox[side^1]))
3361 	{
3362 		// BP: big hack for a test in lighning ref : 1249753487AB
3363 		hwbbox = bsp->bbox[side^1];
3364 		HWR_RenderBSPNode(bsp->children[side^1]);
3365 	}
3366 }
3367 
3368 /*
3369 //
3370 // Clear 'stack' of subsectors to draw
3371 //
3372 static void HWR_ClearDrawSubsectors(void)
3373 {
3374 	gl_drawsubsector_p = gl_drawsubsectors;
3375 }
3376 
3377 //
3378 // Draw subsectors pushed on the drawsubsectors 'stack', back to front
3379 //
3380 static void HWR_RenderSubsectors(void)
3381 {
3382 	while (gl_drawsubsector_p > gl_drawsubsectors)
3383 	{
3384 		HWR_RenderBSPNode(
3385 		lastsubsec->nextsubsec = bspnum & (~NF_SUBSECTOR);
3386 	}
3387 }
3388 */
3389 
3390 // ==========================================================================
3391 //                                                              FROM R_MAIN.C
3392 // ==========================================================================
3393 
3394 //BP : exactely the same as R_InitTextureMapping
HWR_InitTextureMapping(void)3395 void HWR_InitTextureMapping(void)
3396 {
3397 	angle_t i;
3398 	INT32 x;
3399 	INT32 t;
3400 	fixed_t focallength;
3401 	fixed_t grcenterx;
3402 	fixed_t grcenterxfrac;
3403 	INT32 grviewwidth;
3404 
3405 #define clipanglefov (FIELDOFVIEW>>ANGLETOFINESHIFT)
3406 
3407 	grviewwidth = vid.width;
3408 	grcenterx = grviewwidth/2;
3409 	grcenterxfrac = grcenterx<<FRACBITS;
3410 
3411 	// Use tangent table to generate viewangletox:
3412 	//  viewangletox will give the next greatest x
3413 	//  after the view angle.
3414 	//
3415 	// Calc focallength
3416 	//  so FIELDOFVIEW angles covers SCREENWIDTH.
3417 	focallength = FixedDiv(grcenterxfrac,
3418 		FINETANGENT(FINEANGLES/4+clipanglefov/2));
3419 
3420 	for (i = 0; i < FINEANGLES/2; i++)
3421 	{
3422 		if (FINETANGENT(i) > FRACUNIT*2)
3423 			t = -1;
3424 		else if (FINETANGENT(i) < -FRACUNIT*2)
3425 			t = grviewwidth+1;
3426 		else
3427 		{
3428 			t = FixedMul(FINETANGENT(i), focallength);
3429 			t = (grcenterxfrac - t+FRACUNIT-1)>>FRACBITS;
3430 
3431 			if (t < -1)
3432 				t = -1;
3433 			else if (t > grviewwidth+1)
3434 				t = grviewwidth+1;
3435 		}
3436 		gl_viewangletox[i] = t;
3437 	}
3438 
3439 	// Scan viewangletox[] to generate xtoviewangle[]:
3440 	//  xtoviewangle will give the smallest view angle
3441 	//  that maps to x.
3442 	for (x = 0; x <= grviewwidth; x++)
3443 	{
3444 		i = 0;
3445 		while (gl_viewangletox[i]>x)
3446 			i++;
3447 		gl_xtoviewangle[x] = (i<<ANGLETOFINESHIFT) - ANGLE_90;
3448 	}
3449 
3450 	// Take out the fencepost cases from viewangletox.
3451 	for (i = 0; i < FINEANGLES/2; i++)
3452 	{
3453 		if (gl_viewangletox[i] == -1)
3454 			gl_viewangletox[i] = 0;
3455 		else if (gl_viewangletox[i] == grviewwidth+1)
3456 			gl_viewangletox[i]  = grviewwidth;
3457 	}
3458 
3459 	gl_clipangle = gl_xtoviewangle[0];
3460 }
3461 
3462 // ==========================================================================
3463 // gl_things.c
3464 // ==========================================================================
3465 
3466 // sprites are drawn after all wall and planes are rendered, so that
3467 // sprite translucency effects apply on the rendered view (instead of the background sky!!)
3468 
3469 static UINT32 gl_visspritecount;
3470 static gl_vissprite_t *gl_visspritechunks[MAXVISSPRITES >> VISSPRITECHUNKBITS] = {NULL};
3471 
3472 // --------------------------------------------------------------------------
3473 // HWR_ClearSprites
3474 // Called at frame start.
3475 // --------------------------------------------------------------------------
HWR_ClearSprites(void)3476 static void HWR_ClearSprites(void)
3477 {
3478 	gl_visspritecount = 0;
3479 }
3480 
3481 // --------------------------------------------------------------------------
3482 // HWR_NewVisSprite
3483 // --------------------------------------------------------------------------
3484 static gl_vissprite_t gl_overflowsprite;
3485 
HWR_GetVisSprite(UINT32 num)3486 static gl_vissprite_t *HWR_GetVisSprite(UINT32 num)
3487 {
3488 		UINT32 chunk = num >> VISSPRITECHUNKBITS;
3489 
3490 		// Allocate chunk if necessary
3491 		if (!gl_visspritechunks[chunk])
3492 			Z_Malloc(sizeof(gl_vissprite_t) * VISSPRITESPERCHUNK, PU_LEVEL, &gl_visspritechunks[chunk]);
3493 
3494 		return gl_visspritechunks[chunk] + (num & VISSPRITEINDEXMASK);
3495 }
3496 
HWR_NewVisSprite(void)3497 static gl_vissprite_t *HWR_NewVisSprite(void)
3498 {
3499 	if (gl_visspritecount == MAXVISSPRITES)
3500 		return &gl_overflowsprite;
3501 
3502 	return HWR_GetVisSprite(gl_visspritecount++);
3503 }
3504 
3505 // A hack solution for transparent surfaces appearing on top of linkdraw sprites.
3506 // Keep a list of linkdraw sprites and draw their shapes to the z-buffer after all other
3507 // sprite drawing is done. (effectively the z-buffer drawing of linkdraw sprites is delayed)
3508 // NOTE: This will no longer be necessary once full translucent sorting is implemented, where
3509 // translucent sprites and surfaces are sorted together.
3510 
3511 typedef struct
3512 {
3513 	FOutVector verts[4];
3514 	gl_vissprite_t *spr;
3515 } zbuffersprite_t;
3516 
3517 // this list is used to store data about linkdraw sprites
3518 zbuffersprite_t linkdrawlist[MAXVISSPRITES];
3519 UINT32 linkdrawcount = 0;
3520 
3521 // add the necessary data to the list for delayed z-buffer drawing
HWR_LinkDrawHackAdd(FOutVector * verts,gl_vissprite_t * spr)3522 static void HWR_LinkDrawHackAdd(FOutVector *verts, gl_vissprite_t *spr)
3523 {
3524 	if (linkdrawcount < MAXVISSPRITES)
3525 	{
3526 		memcpy(linkdrawlist[linkdrawcount].verts, verts, sizeof(FOutVector) * 4);
3527 		linkdrawlist[linkdrawcount].spr = spr;
3528 		linkdrawcount++;
3529 	}
3530 }
3531 
3532 // process and clear the list of sprites for delayed z-buffer drawing
HWR_LinkDrawHackFinish(void)3533 static void HWR_LinkDrawHackFinish(void)
3534 {
3535 	UINT32 i;
3536 	FSurfaceInfo surf;
3537 	surf.PolyColor.rgba = 0xFFFFFFFF;
3538 	surf.TintColor.rgba = 0xFFFFFFFF;
3539 	surf.FadeColor.rgba = 0xFFFFFFFF;
3540 	surf.LightInfo.light_level = 0;
3541 	surf.LightInfo.fade_start = 0;
3542 	surf.LightInfo.fade_end = 31;
3543 	for (i = 0; i < linkdrawcount; i++)
3544 	{
3545 		// draw sprite shape, only to z-buffer
3546 		HWR_GetPatch(linkdrawlist[i].spr->gpatch);
3547 		HWR_ProcessPolygon(&surf, linkdrawlist[i].verts, 4, PF_Translucent|PF_Occlude|PF_Invisible, 0, false);
3548 	}
3549 	// reset list
3550 	linkdrawcount = 0;
3551 }
3552 
3553 //
3554 // HWR_DoCulling
3555 // Hardware version of R_DoCulling
3556 // (see r_main.c)
HWR_DoCulling(line_t * cullheight,line_t * viewcullheight,float vz,float bottomh,float toph)3557 static boolean HWR_DoCulling(line_t *cullheight, line_t *viewcullheight, float vz, float bottomh, float toph)
3558 {
3559 	float cullplane;
3560 
3561 	if (!cullheight)
3562 		return false;
3563 
3564 	cullplane = FIXED_TO_FLOAT(cullheight->frontsector->floorheight);
3565 	if (cullheight->flags & ML_NOCLIMB) // Group culling
3566 	{
3567 		if (!viewcullheight)
3568 			return false;
3569 
3570 		// Make sure this is part of the same group
3571 		if (viewcullheight->frontsector == cullheight->frontsector)
3572 		{
3573 			// OK, we can cull
3574 			if (vz > cullplane && toph < cullplane) // Cull if below plane
3575 				return true;
3576 
3577 			if (bottomh > cullplane && vz <= cullplane) // Cull if above plane
3578 				return true;
3579 		}
3580 	}
3581 	else // Quick culling
3582 	{
3583 		if (vz > cullplane && toph < cullplane) // Cull if below plane
3584 			return true;
3585 
3586 		if (bottomh > cullplane && vz <= cullplane) // Cull if above plane
3587 			return true;
3588 	}
3589 
3590 	return false;
3591 }
3592 
HWR_DrawDropShadow(mobj_t * thing,fixed_t scale)3593 static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale)
3594 {
3595 	patch_t *gpatch;
3596 	FOutVector shadowVerts[4];
3597 	FSurfaceInfo sSurf;
3598 	float fscale; float fx; float fy; float offset;
3599 	extracolormap_t *colormap = NULL;
3600 	FBITFIELD blendmode = PF_Translucent|PF_Modulated;
3601 	INT32 shader = SHADER_DEFAULT;
3602 	UINT8 i;
3603 	SINT8 flip = P_MobjFlip(thing);
3604 
3605 	INT32 light;
3606 	fixed_t scalemul;
3607 	UINT16 alpha;
3608 	fixed_t floordiff;
3609 	fixed_t groundz;
3610 	fixed_t slopez;
3611 	pslope_t *groundslope;
3612 
3613 	groundz = R_GetShadowZ(thing, &groundslope);
3614 
3615 	//if (abs(groundz - gl_viewz) / tz > 4) return; // Prevent stretchy shadows and possible crashes
3616 
3617 	floordiff = abs((flip < 0 ? thing->height : 0) + thing->z - groundz);
3618 
3619 	alpha = floordiff / (4*FRACUNIT) + 75;
3620 	if (alpha >= 255) return;
3621 	alpha = 255 - alpha;
3622 
3623 	gpatch = (patch_t *)W_CachePatchName("DSHADOW", PU_SPRITE);
3624 	if (!(gpatch && ((GLPatch_t *)gpatch->hardware)->mipmap->format)) return;
3625 	HWR_GetPatch(gpatch);
3626 
3627 	scalemul = FixedMul(FRACUNIT - floordiff/640, scale);
3628 	scalemul = FixedMul(scalemul, (thing->radius*2) / gpatch->height);
3629 
3630 	fscale = FIXED_TO_FLOAT(scalemul);
3631 	fx = FIXED_TO_FLOAT(thing->x);
3632 	fy = FIXED_TO_FLOAT(thing->y);
3633 
3634 	//  3--2
3635 	//  | /|
3636 	//  |/ |
3637 	//  0--1
3638 
3639 	if (thing && fabsf(fscale - 1.0f) > 1.0E-36f)
3640 		offset = ((gpatch->height)/2) * fscale;
3641 	else
3642 		offset = (float)((gpatch->height)/2);
3643 
3644 	shadowVerts[2].x = shadowVerts[3].x = fx + offset;
3645 	shadowVerts[1].x = shadowVerts[0].x = fx - offset;
3646 	shadowVerts[1].z = shadowVerts[2].z = fy - offset;
3647 	shadowVerts[0].z = shadowVerts[3].z = fy + offset;
3648 
3649 	for (i = 0; i < 4; i++)
3650 	{
3651 		float oldx = shadowVerts[i].x;
3652 		float oldy = shadowVerts[i].z;
3653 		shadowVerts[i].x = fx + ((oldx - fx) * gl_viewcos) - ((oldy - fy) * gl_viewsin);
3654 		shadowVerts[i].z = fy + ((oldx - fx) * gl_viewsin) + ((oldy - fy) * gl_viewcos);
3655 	}
3656 
3657 	if (groundslope)
3658 	{
3659 		for (i = 0; i < 4; i++)
3660 		{
3661 			slopez = P_GetSlopeZAt(groundslope, FLOAT_TO_FIXED(shadowVerts[i].x), FLOAT_TO_FIXED(shadowVerts[i].z));
3662 			shadowVerts[i].y = FIXED_TO_FLOAT(slopez) + flip * 0.05f;
3663 		}
3664 	}
3665 	else
3666 	{
3667 		for (i = 0; i < 4; i++)
3668 			shadowVerts[i].y = FIXED_TO_FLOAT(groundz) + flip * 0.05f;
3669 	}
3670 
3671 	shadowVerts[0].s = shadowVerts[3].s = 0;
3672 	shadowVerts[2].s = shadowVerts[1].s = ((GLPatch_t *)gpatch->hardware)->max_s;
3673 
3674 	shadowVerts[3].t = shadowVerts[2].t = 0;
3675 	shadowVerts[0].t = shadowVerts[1].t = ((GLPatch_t *)gpatch->hardware)->max_t;
3676 
3677 	if (!(thing->renderflags & RF_NOCOLORMAPS))
3678 	{
3679 		if (thing->subsector->sector->numlights)
3680 		{
3681 			// Always use the light at the top instead of whatever I was doing before
3682 			light = R_GetPlaneLight(thing->subsector->sector, groundz, false);
3683 
3684 			if (*thing->subsector->sector->lightlist[light].extra_colormap)
3685 				colormap = *thing->subsector->sector->lightlist[light].extra_colormap;
3686 		}
3687 		else if (thing->subsector->sector->extra_colormap)
3688 			colormap = thing->subsector->sector->extra_colormap;
3689 	}
3690 
3691 	HWR_Lighting(&sSurf, 0, colormap);
3692 	sSurf.PolyColor.s.alpha = alpha;
3693 
3694 	if (HWR_UseShader())
3695 	{
3696 		shader = SHADER_SPRITE;
3697 		blendmode |= PF_ColorMapped;
3698 	}
3699 
3700 	HWR_ProcessPolygon(&sSurf, shadowVerts, 4, blendmode, shader, false);
3701 }
3702 
3703 // This is expecting a pointer to an array containing 4 wallVerts for a sprite
HWR_RotateSpritePolyToAim(gl_vissprite_t * spr,FOutVector * wallVerts,const boolean precip)3704 static void HWR_RotateSpritePolyToAim(gl_vissprite_t *spr, FOutVector *wallVerts, const boolean precip)
3705 {
3706 	if (cv_glspritebillboarding.value
3707 		&& spr && spr->mobj && !R_ThingIsPaperSprite(spr->mobj)
3708 		&& wallVerts)
3709 	{
3710 		float basey = FIXED_TO_FLOAT(spr->mobj->z);
3711 		float lowy = wallVerts[0].y;
3712 		if (!precip && P_MobjFlip(spr->mobj) == -1) // precip doesn't have eflags so they can't flip
3713 		{
3714 			basey = FIXED_TO_FLOAT(spr->mobj->z + spr->mobj->height);
3715 		}
3716 		// Rotate sprites to fully billboard with the camera
3717 		// X, Y, AND Z need to be manipulated for the polys to rotate around the
3718 		// origin, because of how the origin setting works I believe that should
3719 		// be mobj->z or mobj->z + mobj->height
3720 		wallVerts[2].y = wallVerts[3].y = (spr->gzt - basey) * gl_viewludsin + basey;
3721 		wallVerts[0].y = wallVerts[1].y = (lowy - basey) * gl_viewludsin + basey;
3722 		// translate back to be around 0 before translating back
3723 		wallVerts[3].x += ((spr->gzt - basey) * gl_viewludcos) * gl_viewcos;
3724 		wallVerts[2].x += ((spr->gzt - basey) * gl_viewludcos) * gl_viewcos;
3725 
3726 		wallVerts[0].x += ((lowy - basey) * gl_viewludcos) * gl_viewcos;
3727 		wallVerts[1].x += ((lowy - basey) * gl_viewludcos) * gl_viewcos;
3728 
3729 		wallVerts[3].z += ((spr->gzt - basey) * gl_viewludcos) * gl_viewsin;
3730 		wallVerts[2].z += ((spr->gzt - basey) * gl_viewludcos) * gl_viewsin;
3731 
3732 		wallVerts[0].z += ((lowy - basey) * gl_viewludcos) * gl_viewsin;
3733 		wallVerts[1].z += ((lowy - basey) * gl_viewludcos) * gl_viewsin;
3734 	}
3735 }
3736 
HWR_SplitSprite(gl_vissprite_t * spr)3737 static void HWR_SplitSprite(gl_vissprite_t *spr)
3738 {
3739 	FOutVector wallVerts[4];
3740 	FOutVector baseWallVerts[4]; // This is what the verts should end up as
3741 	patch_t *gpatch;
3742 	FSurfaceInfo Surf;
3743 	extracolormap_t *colormap = NULL;
3744 	FUINT lightlevel;
3745 	boolean lightset = true;
3746 	FBITFIELD blend = 0;
3747 	FBITFIELD occlusion;
3748 	INT32 shader = SHADER_DEFAULT;
3749 	boolean use_linkdraw_hack = false;
3750 	UINT8 alpha;
3751 
3752 	INT32 i;
3753 	float realtop, realbot, top, bot;
3754 	float ttop, tbot, tmult;
3755 	float bheight;
3756 	float realheight, heightmult;
3757 	const sector_t *sector = spr->mobj->subsector->sector;
3758 	const lightlist_t *list = sector->lightlist;
3759 	float endrealtop, endrealbot, endtop, endbot;
3760 	float endbheight;
3761 	float endrealheight;
3762 	fixed_t temp;
3763 	fixed_t v1x, v1y, v2x, v2y;
3764 
3765 	gpatch = spr->gpatch;
3766 
3767 	// cache the patch in the graphics card memory
3768 	//12/12/99: Hurdler: same comment as above (for md2)
3769 	//Hurdler: 25/04/2000: now support colormap in hardware mode
3770 	HWR_GetMappedPatch(gpatch, spr->colormap);
3771 
3772 	baseWallVerts[0].x = baseWallVerts[3].x = spr->x1;
3773 	baseWallVerts[2].x = baseWallVerts[1].x = spr->x2;
3774 	baseWallVerts[0].z = baseWallVerts[3].z = spr->z1;
3775 	baseWallVerts[1].z = baseWallVerts[2].z = spr->z2;
3776 
3777 	baseWallVerts[2].y = baseWallVerts[3].y = spr->gzt;
3778 	baseWallVerts[0].y = baseWallVerts[1].y = spr->gz;
3779 
3780 	v1x = FLOAT_TO_FIXED(spr->x1);
3781 	v1y = FLOAT_TO_FIXED(spr->z1);
3782 	v2x = FLOAT_TO_FIXED(spr->x2);
3783 	v2y = FLOAT_TO_FIXED(spr->z2);
3784 
3785 	if (spr->flip)
3786 	{
3787 		baseWallVerts[0].s = baseWallVerts[3].s = ((GLPatch_t *)gpatch->hardware)->max_s;
3788 		baseWallVerts[2].s = baseWallVerts[1].s = 0;
3789 	}
3790 	else
3791 	{
3792 		baseWallVerts[0].s = baseWallVerts[3].s = 0;
3793 		baseWallVerts[2].s = baseWallVerts[1].s = ((GLPatch_t *)gpatch->hardware)->max_s;
3794 	}
3795 
3796 	// flip the texture coords (look familiar?)
3797 	if (spr->vflip)
3798 	{
3799 		baseWallVerts[3].t = baseWallVerts[2].t = ((GLPatch_t *)gpatch->hardware)->max_t;
3800 		baseWallVerts[0].t = baseWallVerts[1].t = 0;
3801 	}
3802 	else
3803 	{
3804 		baseWallVerts[3].t = baseWallVerts[2].t = 0;
3805 		baseWallVerts[0].t = baseWallVerts[1].t = ((GLPatch_t *)gpatch->hardware)->max_t;
3806 	}
3807 
3808 	// if it has a dispoffset, push it a little towards the camera
3809 	if (spr->dispoffset) {
3810 		float co = -gl_viewcos*(0.05f*spr->dispoffset);
3811 		float si = -gl_viewsin*(0.05f*spr->dispoffset);
3812 		baseWallVerts[0].z = baseWallVerts[3].z = baseWallVerts[0].z+si;
3813 		baseWallVerts[1].z = baseWallVerts[2].z = baseWallVerts[1].z+si;
3814 		baseWallVerts[0].x = baseWallVerts[3].x = baseWallVerts[0].x+co;
3815 		baseWallVerts[1].x = baseWallVerts[2].x = baseWallVerts[1].x+co;
3816 	}
3817 
3818 	// Let dispoffset work first since this adjust each vertex
3819 	HWR_RotateSpritePolyToAim(spr, baseWallVerts, false);
3820 
3821 	realtop = top = baseWallVerts[3].y;
3822 	realbot = bot = baseWallVerts[0].y;
3823 	ttop = baseWallVerts[3].t;
3824 	tbot = baseWallVerts[0].t;
3825 	tmult = (tbot - ttop) / (top - bot);
3826 
3827 	endrealtop = endtop = baseWallVerts[2].y;
3828 	endrealbot = endbot = baseWallVerts[1].y;
3829 
3830 	// copy the contents of baseWallVerts into the drawn wallVerts array
3831 	// baseWallVerts is used to know the final shape to easily get the vertex
3832 	// co-ordinates
3833 	memcpy(wallVerts, baseWallVerts, sizeof(baseWallVerts));
3834 
3835 	// if sprite has linkdraw, then dont write to z-buffer (by not using PF_Occlude)
3836 	// this will result in sprites drawn afterwards to be drawn on top like intended when using linkdraw.
3837 	if ((spr->mobj->flags2 & MF2_LINKDRAW) && spr->mobj->tracer)
3838 		occlusion = 0;
3839 	else
3840 		occlusion = PF_Occlude;
3841 
3842 	if (!cv_translucency.value) // translucency disabled
3843 	{
3844 		Surf.PolyColor.s.alpha = 0xFF;
3845 		blend = PF_Translucent|occlusion;
3846 		if (!occlusion) use_linkdraw_hack = true;
3847 	}
3848 	else if (spr->mobj->flags2 & MF2_SHADOW)
3849 	{
3850 		Surf.PolyColor.s.alpha = 0x40;
3851 		blend = HWR_GetBlendModeFlag(spr->mobj->blendmode);
3852 	}
3853 	else if (spr->mobj->frame & FF_TRANSMASK)
3854 	{
3855 		INT32 trans = (spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT;
3856 		blend = HWR_SurfaceBlend(spr->mobj->blendmode, trans, &Surf);
3857 	}
3858 	else
3859 	{
3860 		// BP: i agree that is little better in environement but it don't
3861 		//     work properly under glide nor with fogcolor to ffffff :(
3862 		// Hurdler: PF_Environement would be cool, but we need to fix
3863 		//          the issue with the fog before
3864 		Surf.PolyColor.s.alpha = 0xFF;
3865 		blend = HWR_GetBlendModeFlag(spr->mobj->blendmode)|occlusion;
3866 		if (!occlusion) use_linkdraw_hack = true;
3867 	}
3868 
3869 	if (HWR_UseShader())
3870 	{
3871 		shader = SHADER_SPRITE;
3872 		blend |= PF_ColorMapped;
3873 	}
3874 
3875 	alpha = Surf.PolyColor.s.alpha;
3876 
3877 	// Start with the lightlevel and colormap from the top of the sprite
3878 	lightlevel = *list[sector->numlights - 1].lightlevel;
3879 	if (!(spr->mobj->renderflags & RF_NOCOLORMAPS))
3880 		colormap = *list[sector->numlights - 1].extra_colormap;
3881 
3882 	i = 0;
3883 	temp = FLOAT_TO_FIXED(realtop);
3884 
3885 	if (R_ThingIsFullBright(spr->mobj))
3886 		lightlevel = 255;
3887 	else if (R_ThingIsFullDark(spr->mobj))
3888 		lightlevel = 0;
3889 	else
3890 		lightset = false;
3891 
3892 	for (i = 1; i < sector->numlights; i++)
3893 	{
3894 		fixed_t h = P_GetLightZAt(&sector->lightlist[i], spr->mobj->x, spr->mobj->y);
3895 		if (h <= temp)
3896 		{
3897 			if (!lightset)
3898 				lightlevel = *list[i-1].lightlevel > 255 ? 255 : *list[i-1].lightlevel;
3899 			if (!(spr->mobj->renderflags & RF_NOCOLORMAPS))
3900 				colormap = *list[i-1].extra_colormap;
3901 			break;
3902 		}
3903 	}
3904 
3905 	for (i = 0; i < sector->numlights; i++)
3906 	{
3907 		if (endtop < endrealbot && top < realbot)
3908 			return;
3909 
3910 		// even if we aren't changing colormap or lightlevel, we still need to continue drawing down the sprite
3911 		if (!(list[i].flags & FF_NOSHADE) && (list[i].flags & FF_CUTSPRITES))
3912 		{
3913 			if (!lightset)
3914 				lightlevel = *list[i].lightlevel > 255 ? 255 : *list[i].lightlevel;
3915 			if (!(spr->mobj->renderflags & RF_NOCOLORMAPS))
3916 				colormap = *list[i].extra_colormap;
3917 		}
3918 
3919 		if (i + 1 < sector->numlights)
3920 		{
3921 			temp = P_GetLightZAt(&list[i+1], v1x, v1y);
3922 			bheight = FIXED_TO_FLOAT(temp);
3923 			temp = P_GetLightZAt(&list[i+1], v2x, v2y);
3924 			endbheight = FIXED_TO_FLOAT(temp);
3925 		}
3926 		else
3927 		{
3928 			bheight = realbot;
3929 			endbheight = endrealbot;
3930 		}
3931 
3932 		if (endbheight >= endtop && bheight >= top)
3933 			continue;
3934 
3935 		bot = bheight;
3936 
3937 		if (bot < realbot)
3938 			bot = realbot;
3939 
3940 		endbot = endbheight;
3941 
3942 		if (endbot < endrealbot)
3943 			endbot = endrealbot;
3944 
3945 		wallVerts[3].t = ttop + ((realtop - top) * tmult);
3946 		wallVerts[2].t = ttop + ((endrealtop - endtop) * tmult);
3947 		wallVerts[0].t = ttop + ((realtop - bot) * tmult);
3948 		wallVerts[1].t = ttop + ((endrealtop - endbot) * tmult);
3949 
3950 		wallVerts[3].y = top;
3951 		wallVerts[2].y = endtop;
3952 		wallVerts[0].y = bot;
3953 		wallVerts[1].y = endbot;
3954 
3955 		// The x and y only need to be adjusted in the case that it's not a papersprite
3956 		if (cv_glspritebillboarding.value
3957 			&& spr->mobj && !R_ThingIsPaperSprite(spr->mobj))
3958 		{
3959 			// Get the x and z of the vertices so billboarding draws correctly
3960 			realheight = realbot - realtop;
3961 			endrealheight = endrealbot - endrealtop;
3962 			heightmult = (realtop - top) / realheight;
3963 			wallVerts[3].x = baseWallVerts[3].x + (baseWallVerts[3].x - baseWallVerts[0].x) * heightmult;
3964 			wallVerts[3].z = baseWallVerts[3].z + (baseWallVerts[3].z - baseWallVerts[0].z) * heightmult;
3965 
3966 			heightmult = (endrealtop - endtop) / endrealheight;
3967 			wallVerts[2].x = baseWallVerts[2].x + (baseWallVerts[2].x - baseWallVerts[1].x) * heightmult;
3968 			wallVerts[2].z = baseWallVerts[2].z + (baseWallVerts[2].z - baseWallVerts[1].z) * heightmult;
3969 
3970 			heightmult = (realtop - bot) / realheight;
3971 			wallVerts[0].x = baseWallVerts[3].x + (baseWallVerts[3].x - baseWallVerts[0].x) * heightmult;
3972 			wallVerts[0].z = baseWallVerts[3].z + (baseWallVerts[3].z - baseWallVerts[0].z) * heightmult;
3973 
3974 			heightmult = (endrealtop - endbot) / endrealheight;
3975 			wallVerts[1].x = baseWallVerts[2].x + (baseWallVerts[2].x - baseWallVerts[1].x) * heightmult;
3976 			wallVerts[1].z = baseWallVerts[2].z + (baseWallVerts[2].z - baseWallVerts[1].z) * heightmult;
3977 		}
3978 
3979 		HWR_Lighting(&Surf, lightlevel, colormap);
3980 
3981 		Surf.PolyColor.s.alpha = alpha;
3982 
3983 		HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, shader, false);
3984 
3985 		if (use_linkdraw_hack)
3986 			HWR_LinkDrawHackAdd(wallVerts, spr);
3987 
3988 		top = bot;
3989 		endtop = endbot;
3990 	}
3991 
3992 	bot = realbot;
3993 	endbot = endrealbot;
3994 	if (endtop <= endrealbot && top <= realbot)
3995 		return;
3996 
3997 	// If we're ever down here, somehow the above loop hasn't draw all the light levels of sprite
3998 	wallVerts[3].t = ttop + ((realtop - top) * tmult);
3999 	wallVerts[2].t = ttop + ((endrealtop - endtop) * tmult);
4000 	wallVerts[0].t = ttop + ((realtop - bot) * tmult);
4001 	wallVerts[1].t = ttop + ((endrealtop - endbot) * tmult);
4002 
4003 	wallVerts[3].y = top;
4004 	wallVerts[2].y = endtop;
4005 	wallVerts[0].y = bot;
4006 	wallVerts[1].y = endbot;
4007 
4008 	HWR_Lighting(&Surf, lightlevel, colormap);
4009 
4010 	Surf.PolyColor.s.alpha = alpha;
4011 
4012 	HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, shader, false);
4013 
4014 	if (use_linkdraw_hack)
4015 		HWR_LinkDrawHackAdd(wallVerts, spr);
4016 }
4017 
4018 // -----------------+
4019 // HWR_DrawSprite   : Draw flat sprites
4020 //                  : (monsters, bonuses, weapons, lights, ...)
4021 // Returns          :
4022 // -----------------+
HWR_DrawSprite(gl_vissprite_t * spr)4023 static void HWR_DrawSprite(gl_vissprite_t *spr)
4024 {
4025 	FOutVector wallVerts[4];
4026 	patch_t *gpatch;
4027 	FSurfaceInfo Surf;
4028 	const boolean splat = R_ThingIsFloorSprite(spr->mobj);
4029 
4030 	if (!spr->mobj)
4031 		return;
4032 
4033 	if (!spr->mobj->subsector)
4034 		return;
4035 
4036 	if (spr->mobj->subsector->sector->numlights && !splat)
4037 	{
4038 		HWR_SplitSprite(spr);
4039 		return;
4040 	}
4041 
4042 	// cache sprite graphics
4043 	//12/12/99: Hurdler:
4044 	//          OK, I don't change anything for MD2 support because I want to be
4045 	//          sure to do it the right way. So actually, we keep normal sprite
4046 	//          in memory and we add the md2 model if it exists for that sprite
4047 
4048 	gpatch = spr->gpatch;
4049 
4050 #ifdef ALAM_LIGHTING
4051 	if (!(spr->mobj->flags2 & MF2_DEBRIS) && (spr->mobj->sprite != SPR_PLAY ||
4052 	 (spr->mobj->player && spr->mobj->player->powers[pw_super])))
4053 		HWR_DL_AddLight(spr, gpatch);
4054 #endif
4055 
4056 	// create the sprite billboard
4057 	//
4058 	//  3--2
4059 	//  | /|
4060 	//  |/ |
4061 	//  0--1
4062 
4063 	if (splat)
4064 	{
4065 		F2DCoord verts[4];
4066 		F2DCoord rotated[4];
4067 
4068 		angle_t angle;
4069 		float ca, sa;
4070 		float w, h;
4071 		float xscale, yscale;
4072 		float xoffset, yoffset;
4073 		float leftoffset, topoffset;
4074 		float scale = spr->scale;
4075 		float zoffset = (P_MobjFlip(spr->mobj) * 0.05f);
4076 		pslope_t *splatslope = NULL;
4077 		INT32 i;
4078 
4079 		renderflags_t renderflags = spr->renderflags;
4080 		if (renderflags & RF_SHADOWEFFECTS)
4081 			scale *= spr->shadowscale;
4082 
4083 		if (spr->rotateflags & SRF_3D || renderflags & RF_NOSPLATBILLBOARD)
4084 			angle = spr->mobj->angle;
4085 		else
4086 			angle = viewangle;
4087 
4088 		if (!spr->rotated)
4089 			angle += spr->mobj->rollangle;
4090 
4091 		angle = -angle;
4092 		angle += ANGLE_90;
4093 
4094 		topoffset = spr->spriteyoffset;
4095 		leftoffset = spr->spritexoffset;
4096 		if (spr->flip)
4097 			leftoffset = ((float)gpatch->width - leftoffset);
4098 
4099 		xscale = spr->scale * spr->spritexscale;
4100 		yscale = spr->scale * spr->spriteyscale;
4101 
4102 		xoffset = leftoffset * xscale;
4103 		yoffset = topoffset * yscale;
4104 
4105 		w = (float)gpatch->width * xscale;
4106 		h = (float)gpatch->height * yscale;
4107 
4108 		// Set positions
4109 
4110 		// 3--2
4111 		// |  |
4112 		// 0--1
4113 
4114 		verts[3].x = -xoffset;
4115 		verts[3].y = yoffset;
4116 
4117 		verts[2].x = w - xoffset;
4118 		verts[2].y = yoffset;
4119 
4120 		verts[1].x = w - xoffset;
4121 		verts[1].y = -h + yoffset;
4122 
4123 		verts[0].x = -xoffset;
4124 		verts[0].y = -h + yoffset;
4125 
4126 		ca = FIXED_TO_FLOAT(FINECOSINE((-angle)>>ANGLETOFINESHIFT));
4127 		sa = FIXED_TO_FLOAT(FINESINE((-angle)>>ANGLETOFINESHIFT));
4128 
4129 		// Rotate
4130 		for (i = 0; i < 4; i++)
4131 		{
4132 			rotated[i].x = (verts[i].x * ca) - (verts[i].y * sa);
4133 			rotated[i].y = (verts[i].x * sa) + (verts[i].y * ca);
4134 		}
4135 
4136 		// Translate
4137 		for (i = 0; i < 4; i++)
4138 		{
4139 			wallVerts[i].x = rotated[i].x + FIXED_TO_FLOAT(spr->mobj->x);
4140 			wallVerts[i].z = rotated[i].y + FIXED_TO_FLOAT(spr->mobj->y);
4141 		}
4142 
4143 		if (renderflags & (RF_SLOPESPLAT | RF_OBJECTSLOPESPLAT))
4144 		{
4145 			pslope_t *standingslope = spr->mobj->standingslope; // The slope that the object is standing on.
4146 
4147 			// The slope that was defined for the sprite.
4148 			if (renderflags & RF_SLOPESPLAT)
4149 				splatslope = spr->mobj->floorspriteslope;
4150 
4151 			if (standingslope && (renderflags & RF_OBJECTSLOPESPLAT))
4152 				splatslope = standingslope;
4153 		}
4154 
4155 		// Set vertical position
4156 		if (splatslope)
4157 		{
4158 			for (i = 0; i < 4; i++)
4159 			{
4160 				fixed_t slopez = P_GetSlopeZAt(splatslope, FLOAT_TO_FIXED(wallVerts[i].x), FLOAT_TO_FIXED(wallVerts[i].z));
4161 				wallVerts[i].y = FIXED_TO_FLOAT(slopez) + zoffset;
4162 			}
4163 		}
4164 		else
4165 		{
4166 			for (i = 0; i < 4; i++)
4167 				wallVerts[i].y = FIXED_TO_FLOAT(spr->mobj->z) + zoffset;
4168 		}
4169 	}
4170 	else
4171 	{
4172 		// these were already scaled in HWR_ProjectSprite
4173 		wallVerts[0].x = wallVerts[3].x = spr->x1;
4174 		wallVerts[2].x = wallVerts[1].x = spr->x2;
4175 		wallVerts[2].y = wallVerts[3].y = spr->gzt;
4176 		wallVerts[0].y = wallVerts[1].y = spr->gz;
4177 
4178 		// make a wall polygon (with 2 triangles), using the floor/ceiling heights,
4179 		// and the 2d map coords of start/end vertices
4180 		wallVerts[0].z = wallVerts[3].z = spr->z1;
4181 		wallVerts[1].z = wallVerts[2].z = spr->z2;
4182 	}
4183 
4184 	// cache the patch in the graphics card memory
4185 	//12/12/99: Hurdler: same comment as above (for md2)
4186 	//Hurdler: 25/04/2000: now support colormap in hardware mode
4187 	HWR_GetMappedPatch(gpatch, spr->colormap);
4188 
4189 	if (spr->flip)
4190 	{
4191 		wallVerts[0].s = wallVerts[3].s = ((GLPatch_t *)gpatch->hardware)->max_s;
4192 		wallVerts[2].s = wallVerts[1].s = 0;
4193 	}else{
4194 		wallVerts[0].s = wallVerts[3].s = 0;
4195 		wallVerts[2].s = wallVerts[1].s = ((GLPatch_t *)gpatch->hardware)->max_s;
4196 	}
4197 
4198 	// flip the texture coords (look familiar?)
4199 	if (spr->vflip)
4200 	{
4201 		wallVerts[3].t = wallVerts[2].t = ((GLPatch_t *)gpatch->hardware)->max_t;
4202 		wallVerts[0].t = wallVerts[1].t = 0;
4203 	}else{
4204 		wallVerts[3].t = wallVerts[2].t = 0;
4205 		wallVerts[0].t = wallVerts[1].t = ((GLPatch_t *)gpatch->hardware)->max_t;
4206 	}
4207 
4208 	if (!splat)
4209 	{
4210 		// if it has a dispoffset, push it a little towards the camera
4211 		if (spr->dispoffset) {
4212 			float co = -gl_viewcos*(0.05f*spr->dispoffset);
4213 			float si = -gl_viewsin*(0.05f*spr->dispoffset);
4214 			wallVerts[0].z = wallVerts[3].z = wallVerts[0].z+si;
4215 			wallVerts[1].z = wallVerts[2].z = wallVerts[1].z+si;
4216 			wallVerts[0].x = wallVerts[3].x = wallVerts[0].x+co;
4217 			wallVerts[1].x = wallVerts[2].x = wallVerts[1].x+co;
4218 		}
4219 
4220 		// Let dispoffset work first since this adjust each vertex
4221 		HWR_RotateSpritePolyToAim(spr, wallVerts, false);
4222 	}
4223 
4224 	// This needs to be AFTER the shadows so that the regular sprites aren't drawn completely black.
4225 	// sprite lighting by modulating the RGB components
4226 	/// \todo coloured
4227 
4228 	// colormap test
4229 	{
4230 		sector_t *sector = spr->mobj->subsector->sector;
4231 		UINT8 lightlevel = 0;
4232 		boolean lightset = true;
4233 		extracolormap_t *colormap = NULL;
4234 
4235 		if (R_ThingIsFullBright(spr->mobj))
4236 			lightlevel = 255;
4237 		else if (R_ThingIsFullDark(spr->mobj))
4238 			lightlevel = 0;
4239 		else
4240 			lightset = false;
4241 
4242 		if (!(spr->mobj->renderflags & RF_NOCOLORMAPS))
4243 			colormap = sector->extra_colormap;
4244 
4245 		if (splat && sector->numlights)
4246 		{
4247 			INT32 light = R_GetPlaneLight(sector, spr->mobj->z, false);
4248 
4249 			if (!lightset)
4250 				lightlevel = *sector->lightlist[light].lightlevel > 255 ? 255 : *sector->lightlist[light].lightlevel;
4251 
4252 			if (*sector->lightlist[light].extra_colormap && !(spr->mobj->renderflags & RF_NOCOLORMAPS))
4253 				colormap = *sector->lightlist[light].extra_colormap;
4254 		}
4255 		else if (!lightset)
4256 			lightlevel = sector->lightlevel > 255 ? 255 : sector->lightlevel;
4257 
4258 		HWR_Lighting(&Surf, lightlevel, colormap);
4259 	}
4260 
4261 	{
4262 		INT32 shader = SHADER_DEFAULT;
4263 		FBITFIELD blend = 0;
4264 		FBITFIELD occlusion;
4265 		boolean use_linkdraw_hack = false;
4266 
4267 		// if sprite has linkdraw, then dont write to z-buffer (by not using PF_Occlude)
4268 		// this will result in sprites drawn afterwards to be drawn on top like intended when using linkdraw.
4269 		if ((spr->mobj->flags2 & MF2_LINKDRAW) && spr->mobj->tracer)
4270 			occlusion = 0;
4271 		else
4272 			occlusion = PF_Occlude;
4273 
4274 		if (!cv_translucency.value) // translucency disabled
4275 		{
4276 			Surf.PolyColor.s.alpha = 0xFF;
4277 			blend = PF_Translucent|occlusion;
4278 			if (!occlusion) use_linkdraw_hack = true;
4279 		}
4280 		else if (spr->mobj->flags2 & MF2_SHADOW)
4281 		{
4282 			Surf.PolyColor.s.alpha = 0x40;
4283 			blend = HWR_GetBlendModeFlag(spr->mobj->blendmode);
4284 		}
4285 		else if (spr->mobj->frame & FF_TRANSMASK)
4286 		{
4287 			INT32 trans = (spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT;
4288 			blend = HWR_SurfaceBlend(spr->mobj->blendmode, trans, &Surf);
4289 		}
4290 		else
4291 		{
4292 			// BP: i agree that is little better in environement but it don't
4293 			//     work properly under glide nor with fogcolor to ffffff :(
4294 			// Hurdler: PF_Environement would be cool, but we need to fix
4295 			//          the issue with the fog before
4296 			Surf.PolyColor.s.alpha = 0xFF;
4297 			blend = HWR_GetBlendModeFlag(spr->mobj->blendmode)|occlusion;
4298 			if (!occlusion) use_linkdraw_hack = true;
4299 		}
4300 
4301 		if (spr->renderflags & RF_SHADOWEFFECTS)
4302 		{
4303 			INT32 alpha = Surf.PolyColor.s.alpha;
4304 			alpha -= ((INT32)(spr->shadowheight / 4.0f)) + 75;
4305 			if (alpha < 1)
4306 				return;
4307 
4308 			Surf.PolyColor.s.alpha = (UINT8)(alpha);
4309 			blend = PF_Translucent|occlusion;
4310 			if (!occlusion) use_linkdraw_hack = true;
4311 		}
4312 
4313 		if (HWR_UseShader())
4314 		{
4315 			shader = SHADER_SPRITE;
4316 			blend |= PF_ColorMapped;
4317 		}
4318 
4319 		HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, shader, false);
4320 
4321 		if (use_linkdraw_hack)
4322 			HWR_LinkDrawHackAdd(wallVerts, spr);
4323 	}
4324 }
4325 
4326 #ifdef HWPRECIP
4327 // Sprite drawer for precipitation
HWR_DrawPrecipitationSprite(gl_vissprite_t * spr)4328 static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr)
4329 {
4330 	INT32 shader = SHADER_DEFAULT;
4331 	FBITFIELD blend = 0;
4332 	FOutVector wallVerts[4];
4333 	patch_t *gpatch;
4334 	FSurfaceInfo Surf;
4335 
4336 	if (!spr->mobj)
4337 		return;
4338 
4339 	if (!spr->mobj->subsector)
4340 		return;
4341 
4342 	// cache sprite graphics
4343 	gpatch = spr->gpatch;
4344 
4345 	// create the sprite billboard
4346 	//
4347 	//  3--2
4348 	//  | /|
4349 	//  |/ |
4350 	//  0--1
4351 	wallVerts[0].x = wallVerts[3].x = spr->x1;
4352 	wallVerts[2].x = wallVerts[1].x = spr->x2;
4353 	wallVerts[2].y = wallVerts[3].y = spr->gzt;
4354 	wallVerts[0].y = wallVerts[1].y = spr->gz;
4355 
4356 	// make a wall polygon (with 2 triangles), using the floor/ceiling heights,
4357 	// and the 2d map coords of start/end vertices
4358 	wallVerts[0].z = wallVerts[3].z = spr->z1;
4359 	wallVerts[1].z = wallVerts[2].z = spr->z2;
4360 
4361 	// Let dispoffset work first since this adjust each vertex
4362 	HWR_RotateSpritePolyToAim(spr, wallVerts, true);
4363 
4364 	wallVerts[0].s = wallVerts[3].s = 0;
4365 	wallVerts[2].s = wallVerts[1].s = ((GLPatch_t *)gpatch->hardware)->max_s;
4366 
4367 	wallVerts[3].t = wallVerts[2].t = 0;
4368 	wallVerts[0].t = wallVerts[1].t = ((GLPatch_t *)gpatch->hardware)->max_t;
4369 
4370 	// cache the patch in the graphics card memory
4371 	//12/12/99: Hurdler: same comment as above (for md2)
4372 	//Hurdler: 25/04/2000: now support colormap in hardware mode
4373 	HWR_GetMappedPatch(gpatch, spr->colormap);
4374 
4375 	// colormap test
4376 	{
4377 		sector_t *sector = spr->mobj->subsector->sector;
4378 		UINT8 lightlevel = 255;
4379 		extracolormap_t *colormap = sector->extra_colormap;
4380 
4381 		if (sector->numlights)
4382 		{
4383 			// Always use the light at the top instead of whatever I was doing before
4384 			INT32 light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false);
4385 
4386 			if (!R_ThingIsFullBright(spr->mobj))
4387 				lightlevel = *sector->lightlist[light].lightlevel > 255 ? 255 : *sector->lightlist[light].lightlevel;
4388 
4389 			if (*sector->lightlist[light].extra_colormap)
4390 				colormap = *sector->lightlist[light].extra_colormap;
4391 		}
4392 		else
4393 		{
4394 			if (!R_ThingIsFullBright(spr->mobj))
4395 				lightlevel = sector->lightlevel > 255 ? 255 : sector->lightlevel;
4396 
4397 			if (sector->extra_colormap)
4398 				colormap = sector->extra_colormap;
4399 		}
4400 
4401 		HWR_Lighting(&Surf, lightlevel, colormap);
4402 	}
4403 
4404 	if (spr->mobj->frame & FF_TRANSMASK)
4405 	{
4406 		INT32 trans = (spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT;
4407 		blend = HWR_SurfaceBlend(AST_TRANSLUCENT, trans, &Surf);
4408 	}
4409 	else
4410 	{
4411 		// BP: i agree that is little better in environement but it don't
4412 		//     work properly under glide nor with fogcolor to ffffff :(
4413 		// Hurdler: PF_Environement would be cool, but we need to fix
4414 		//          the issue with the fog before
4415 		Surf.PolyColor.s.alpha = 0xFF;
4416 		blend = HWR_GetBlendModeFlag(spr->mobj->blendmode)|PF_Occlude;
4417 	}
4418 
4419 	if (HWR_UseShader())
4420 	{
4421 		shader = SHADER_SPRITE;
4422 		blend |= PF_ColorMapped;
4423 	}
4424 
4425 	HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, shader, false);
4426 }
4427 #endif
4428 
4429 // --------------------------------------------------------------------------
4430 // Sort vissprites by distance
4431 // --------------------------------------------------------------------------
4432 gl_vissprite_t* gl_vsprorder[MAXVISSPRITES];
4433 
4434 // Note: For more correct transparency the transparent sprites would need to be
4435 // sorted and drawn together with transparent surfaces.
CompareVisSprites(const void * p1,const void * p2)4436 static int CompareVisSprites(const void *p1, const void *p2)
4437 {
4438 	gl_vissprite_t* spr1 = *(gl_vissprite_t*const*)p1;
4439 	gl_vissprite_t* spr2 = *(gl_vissprite_t*const*)p2;
4440 	int idiff;
4441 	float fdiff;
4442 	float tz1, tz2;
4443 
4444 	// Make transparent sprites last. Comment from the previous sort implementation:
4445 	// Sryder:	Oh boy, while it's nice having ALL the sprites sorted properly, it fails when we bring MD2's into the
4446 	//			mix and they want to be translucent. So let's place all the translucent sprites and MD2's AFTER
4447 	//			everything else, but still ordered of course, the depth buffer can handle the opaque ones plenty fine.
4448 	//			We just need to move all translucent ones to the end in order
4449 	// TODO:	Fully sort all sprites and MD2s with walls and floors, this part will be unnecessary after that
4450 	int transparency1;
4451 	int transparency2;
4452 
4453 	// check for precip first, because then sprX->mobj is actually a precipmobj_t and does not have flags2 or tracer
4454 	int linkdraw1 = !spr1->precip && (spr1->mobj->flags2 & MF2_LINKDRAW) && spr1->mobj->tracer;
4455 	int linkdraw2 = !spr2->precip && (spr2->mobj->flags2 & MF2_LINKDRAW) && spr2->mobj->tracer;
4456 
4457 	// ^ is the XOR operation
4458 	// if comparing a linkdraw and non-linkdraw sprite or 2 linkdraw sprites with different tracers, then use
4459 	// the tracer's properties instead of the main sprite's.
4460 	if ((linkdraw1 && linkdraw2 && spr1->mobj->tracer != spr2->mobj->tracer) || (linkdraw1 ^ linkdraw2))
4461 	{
4462 		if (linkdraw1)
4463 		{
4464 			tz1 = spr1->tracertz;
4465 			transparency1 = (spr1->mobj->tracer->flags2 & MF2_SHADOW) || (spr1->mobj->tracer->frame & FF_TRANSMASK);
4466 		}
4467 		else
4468 		{
4469 			tz1 = spr1->tz;
4470 			transparency1 = (!spr1->precip && (spr1->mobj->flags2 & MF2_SHADOW)) || (spr1->mobj->frame & FF_TRANSMASK);
4471 		}
4472 		if (linkdraw2)
4473 		{
4474 			tz2 = spr2->tracertz;
4475 			transparency2 = (spr2->mobj->tracer->flags2 & MF2_SHADOW) || (spr2->mobj->tracer->frame & FF_TRANSMASK);
4476 		}
4477 		else
4478 		{
4479 			tz2 = spr2->tz;
4480 			transparency2 = (!spr2->precip && (spr2->mobj->flags2 & MF2_SHADOW)) || (spr2->mobj->frame & FF_TRANSMASK);
4481 		}
4482 	}
4483 	else
4484 	{
4485 		tz1 = spr1->tz;
4486 		transparency1 = (!spr1->precip && (spr1->mobj->flags2 & MF2_SHADOW)) || (spr1->mobj->frame & FF_TRANSMASK);
4487 		tz2 = spr2->tz;
4488 		transparency2 = (!spr2->precip && (spr2->mobj->flags2 & MF2_SHADOW)) || (spr2->mobj->frame & FF_TRANSMASK);
4489 	}
4490 
4491 	// first compare transparency flags, then compare tz, then compare dispoffset
4492 
4493 	idiff = transparency1 - transparency2;
4494 	if (idiff != 0) return idiff;
4495 
4496 	fdiff = tz2 - tz1; // this order seems correct when checking with apitrace. Back to front.
4497 	if (fabsf(fdiff) < 1.0E-36f)
4498 		return spr1->dispoffset - spr2->dispoffset; // smallest dispoffset first if sprites are at (almost) same location.
4499 	else if (fdiff > 0)
4500 		return 1;
4501 	else
4502 		return -1;
4503 }
4504 
HWR_SortVisSprites(void)4505 static void HWR_SortVisSprites(void)
4506 {
4507 	UINT32 i;
4508 	for (i = 0; i < gl_visspritecount; i++)
4509 	{
4510 		gl_vsprorder[i] = HWR_GetVisSprite(i);
4511 	}
4512 	qsort(gl_vsprorder, gl_visspritecount, sizeof(gl_vissprite_t*), CompareVisSprites);
4513 }
4514 
4515 // A drawnode is something that points to a 3D floor, 3D side, or masked
4516 // middle texture. This is used for sorting with sprites.
4517 typedef struct
4518 {
4519 	FOutVector    wallVerts[4];
4520 	FSurfaceInfo  Surf;
4521 	INT32         texnum;
4522 	FBITFIELD     blend;
4523 	INT32         drawcount;
4524 	boolean fogwall;
4525 	INT32 lightlevel;
4526 	extracolormap_t *wallcolormap; // Doing the lighting in HWR_RenderWall now for correct fog after sorting
4527 } wallinfo_t;
4528 
4529 static wallinfo_t *wallinfo = NULL;
4530 static size_t numwalls = 0; // a list of transparent walls to be drawn
4531 
4532 void HWR_RenderWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend, boolean fogwall, INT32 lightlevel, extracolormap_t *wallcolormap);
4533 
4534 #define MAX_TRANSPARENTWALL 256
4535 
4536 typedef struct
4537 {
4538 	extrasubsector_t *xsub;
4539 	boolean isceiling;
4540 	fixed_t fixedheight;
4541 	INT32 lightlevel;
4542 	levelflat_t *levelflat;
4543 	INT32 alpha;
4544 	sector_t *FOFSector;
4545 	FBITFIELD blend;
4546 	boolean fogplane;
4547 	extracolormap_t *planecolormap;
4548 	INT32 drawcount;
4549 } planeinfo_t;
4550 
4551 static size_t numplanes = 0; // a list of transparent floors to be drawn
4552 static planeinfo_t *planeinfo = NULL;
4553 
4554 typedef struct
4555 {
4556 	polyobj_t *polysector;
4557 	boolean isceiling;
4558 	fixed_t fixedheight;
4559 	INT32 lightlevel;
4560 	levelflat_t *levelflat;
4561 	INT32 alpha;
4562 	sector_t *FOFSector;
4563 	FBITFIELD blend;
4564 	extracolormap_t *planecolormap;
4565 	INT32 drawcount;
4566 } polyplaneinfo_t;
4567 
4568 static size_t numpolyplanes = 0; // a list of transparent poyobject floors to be drawn
4569 static polyplaneinfo_t *polyplaneinfo = NULL;
4570 
4571 //Hurdler: 3D water sutffs
4572 typedef struct gl_drawnode_s
4573 {
4574 	planeinfo_t *plane;
4575 	polyplaneinfo_t *polyplane;
4576 	wallinfo_t *wall;
4577 	gl_vissprite_t *sprite;
4578 
4579 //	struct gl_drawnode_s *next;
4580 //	struct gl_drawnode_s *prev;
4581 } gl_drawnode_t;
4582 
4583 static INT32 drawcount = 0;
4584 
4585 #define MAX_TRANSPARENTFLOOR 512
4586 
4587 // This will likely turn into a copy of HWR_Add3DWater and replace it.
HWR_AddTransparentFloor(levelflat_t * levelflat,extrasubsector_t * xsub,boolean isceiling,fixed_t fixedheight,INT32 lightlevel,INT32 alpha,sector_t * FOFSector,FBITFIELD blend,boolean fogplane,extracolormap_t * planecolormap)4588 void HWR_AddTransparentFloor(levelflat_t *levelflat, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, boolean fogplane, extracolormap_t *planecolormap)
4589 {
4590 	static size_t allocedplanes = 0;
4591 
4592 	// Force realloc if buffer has been freed
4593 	if (!planeinfo)
4594 		allocedplanes = 0;
4595 
4596 	if (allocedplanes < numplanes + 1)
4597 	{
4598 		allocedplanes += MAX_TRANSPARENTFLOOR;
4599 		Z_Realloc(planeinfo, allocedplanes * sizeof (*planeinfo), PU_LEVEL, &planeinfo);
4600 	}
4601 
4602 	planeinfo[numplanes].isceiling = isceiling;
4603 	planeinfo[numplanes].fixedheight = fixedheight;
4604 	planeinfo[numplanes].lightlevel = (planecolormap && (planecolormap->flags & CMF_FOG)) ? lightlevel : 255;
4605 	planeinfo[numplanes].levelflat = levelflat;
4606 	planeinfo[numplanes].xsub = xsub;
4607 	planeinfo[numplanes].alpha = alpha;
4608 	planeinfo[numplanes].FOFSector = FOFSector;
4609 	planeinfo[numplanes].blend = blend;
4610 	planeinfo[numplanes].fogplane = fogplane;
4611 	planeinfo[numplanes].planecolormap = planecolormap;
4612 	planeinfo[numplanes].drawcount = drawcount++;
4613 
4614 	numplanes++;
4615 }
4616 
4617 // Adding this for now until I can create extrasubsector info for polyobjects
4618 // When that happens it'll just be done through HWR_AddTransparentFloor and HWR_RenderPlane
HWR_AddTransparentPolyobjectFloor(levelflat_t * levelflat,polyobj_t * polysector,boolean isceiling,fixed_t fixedheight,INT32 lightlevel,INT32 alpha,sector_t * FOFSector,FBITFIELD blend,extracolormap_t * planecolormap)4619 void HWR_AddTransparentPolyobjectFloor(levelflat_t *levelflat, polyobj_t *polysector, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, extracolormap_t *planecolormap)
4620 {
4621 	static size_t allocedpolyplanes = 0;
4622 
4623 	// Force realloc if buffer has been freed
4624 	if (!polyplaneinfo)
4625 		allocedpolyplanes = 0;
4626 
4627 	if (allocedpolyplanes < numpolyplanes + 1)
4628 	{
4629 		allocedpolyplanes += MAX_TRANSPARENTFLOOR;
4630 		Z_Realloc(polyplaneinfo, allocedpolyplanes * sizeof (*polyplaneinfo), PU_LEVEL, &polyplaneinfo);
4631 	}
4632 
4633 	polyplaneinfo[numpolyplanes].isceiling = isceiling;
4634 	polyplaneinfo[numpolyplanes].fixedheight = fixedheight;
4635 	polyplaneinfo[numpolyplanes].lightlevel = (planecolormap && (planecolormap->flags & CMF_FOG)) ? lightlevel : 255;
4636 	polyplaneinfo[numpolyplanes].levelflat = levelflat;
4637 	polyplaneinfo[numpolyplanes].polysector = polysector;
4638 	polyplaneinfo[numpolyplanes].alpha = alpha;
4639 	polyplaneinfo[numpolyplanes].FOFSector = FOFSector;
4640 	polyplaneinfo[numpolyplanes].blend = blend;
4641 	polyplaneinfo[numpolyplanes].planecolormap = planecolormap;
4642 	polyplaneinfo[numpolyplanes].drawcount = drawcount++;
4643 	numpolyplanes++;
4644 }
4645 
4646 // putting sortindex and sortnode here so the comparator function can see them
4647 gl_drawnode_t *sortnode;
4648 size_t *sortindex;
4649 
CompareDrawNodes(const void * p1,const void * p2)4650 static int CompareDrawNodes(const void *p1, const void *p2)
4651 {
4652 	size_t n1 = *(const size_t*)p1;
4653 	size_t n2 = *(const size_t*)p2;
4654 	INT32 v1 = 0;
4655 	INT32 v2 = 0;
4656 	INT32 diff;
4657 	if (sortnode[n1].plane)
4658 		v1 = sortnode[n1].plane->drawcount;
4659 	else if (sortnode[n1].polyplane)
4660 		v1 = sortnode[n1].polyplane->drawcount;
4661 	else if (sortnode[n1].wall)
4662 		v1 = sortnode[n1].wall->drawcount;
4663 	else I_Error("CompareDrawNodes: n1 unknown");
4664 
4665 	if (sortnode[n2].plane)
4666 		v2 = sortnode[n2].plane->drawcount;
4667 	else if (sortnode[n2].polyplane)
4668 		v2 = sortnode[n2].polyplane->drawcount;
4669 	else if (sortnode[n2].wall)
4670 		v2 = sortnode[n2].wall->drawcount;
4671 	else I_Error("CompareDrawNodes: n2 unknown");
4672 
4673 	diff = v2 - v1;
4674 	if (diff == 0) I_Error("CompareDrawNodes: diff is zero");
4675 	return diff;
4676 }
4677 
CompareDrawNodePlanes(const void * p1,const void * p2)4678 static int CompareDrawNodePlanes(const void *p1, const void *p2)
4679 {
4680 	size_t n1 = *(const size_t*)p1;
4681 	size_t n2 = *(const size_t*)p2;
4682 	if (!sortnode[n1].plane) I_Error("CompareDrawNodePlanes: Uh.. This isn't a plane! (n1)");
4683 	if (!sortnode[n2].plane) I_Error("CompareDrawNodePlanes: Uh.. This isn't a plane! (n2)");
4684 	return ABS(sortnode[n2].plane->fixedheight - viewz) - ABS(sortnode[n1].plane->fixedheight - viewz);
4685 }
4686 
4687 //
4688 // HWR_CreateDrawNodes
4689 // Creates and sorts a list of drawnodes for the scene being rendered.
HWR_CreateDrawNodes(void)4690 static void HWR_CreateDrawNodes(void)
4691 {
4692 	UINT32 i = 0, p = 0;
4693 	size_t run_start = 0;
4694 
4695 	// Dump EVERYTHING into a huge drawnode list. Then we'll sort it!
4696 	// Could this be optimized into _AddTransparentWall/_AddTransparentPlane?
4697 	// Hell yes! But sort algorithm must be modified to use a linked list.
4698 	sortnode = Z_Calloc((sizeof(planeinfo_t)*numplanes)
4699 					+ (sizeof(polyplaneinfo_t)*numpolyplanes)
4700 					+ (sizeof(wallinfo_t)*numwalls)
4701 					,PU_STATIC, NULL);
4702 	// todo:
4703 	// However, in reality we shouldn't be re-copying and shifting all this information
4704 	// that is already lying around. This should all be in some sort of linked list or lists.
4705 	sortindex = Z_Calloc(sizeof(size_t) * (numplanes + numpolyplanes + numwalls), PU_STATIC, NULL);
4706 
4707 	ps_hw_nodesorttime = I_GetPreciseTime();
4708 
4709 	for (i = 0; i < numplanes; i++, p++)
4710 	{
4711 		sortnode[p].plane = &planeinfo[i];
4712 		sortindex[p] = p;
4713 	}
4714 
4715 	for (i = 0; i < numpolyplanes; i++, p++)
4716 	{
4717 		sortnode[p].polyplane = &polyplaneinfo[i];
4718 		sortindex[p] = p;
4719 	}
4720 
4721 	for (i = 0; i < numwalls; i++, p++)
4722 	{
4723 		sortnode[p].wall = &wallinfo[i];
4724 		sortindex[p] = p;
4725 	}
4726 
4727 	ps_numdrawnodes = p;
4728 
4729 	// p is the number of stuff to sort
4730 
4731 	// sort the list based on the value of the 'drawcount' member of the drawnodes.
4732 	qsort(sortindex, p, sizeof(size_t), CompareDrawNodes);
4733 
4734 	// an additional pass is needed to correct the order of consecutive planes in the list.
4735 	// for each consecutive run of planes in the list, sort that run based on plane height and view height.
4736 	while (run_start < p-1)// p-1 because a 1 plane run at the end of the list does not count
4737 	{
4738 		// locate run start
4739 		if (sortnode[sortindex[run_start]].plane)
4740 		{
4741 			// found it, now look for run end
4742 			size_t run_end;// (inclusive)
4743 			for (i = run_start+1; i < p; i++)// size_t and UINT32 being used mixed here... shouldnt break anything though..
4744 			{
4745 				if (!sortnode[sortindex[i]].plane) break;
4746 			}
4747 			run_end = i-1;
4748 			if (run_end > run_start)// if there are multiple consecutive planes, not just one
4749 			{
4750 				// consecutive run of planes found, now sort it
4751 				qsort(sortindex + run_start, run_end - run_start + 1, sizeof(size_t), CompareDrawNodePlanes);
4752 			}
4753 			run_start = run_end + 1;// continue looking for runs coming right after this one
4754 		}
4755 		else
4756 		{
4757 			// this wasnt the run start, try next one
4758 			run_start++;
4759 		}
4760 	}
4761 
4762 	ps_hw_nodesorttime = I_GetPreciseTime() - ps_hw_nodesorttime;
4763 
4764 	ps_hw_nodedrawtime = I_GetPreciseTime();
4765 
4766 	// Okay! Let's draw it all! Woo!
4767 	HWD.pfnSetTransform(&atransform);
4768 	HWD.pfnSetShader(SHADER_DEFAULT);
4769 
4770 	for (i = 0; i < p; i++)
4771 	{
4772 		if (sortnode[sortindex[i]].plane)
4773 		{
4774 			// We aren't traversing the BSP tree, so make gl_frontsector null to avoid crashes.
4775 			gl_frontsector = NULL;
4776 
4777 			if (!(sortnode[sortindex[i]].plane->blend & PF_NoTexture))
4778 				HWR_GetLevelFlat(sortnode[sortindex[i]].plane->levelflat);
4779 			HWR_RenderPlane(NULL, sortnode[sortindex[i]].plane->xsub, sortnode[sortindex[i]].plane->isceiling, sortnode[sortindex[i]].plane->fixedheight, sortnode[sortindex[i]].plane->blend, sortnode[sortindex[i]].plane->lightlevel,
4780 				sortnode[sortindex[i]].plane->levelflat, sortnode[sortindex[i]].plane->FOFSector, sortnode[sortindex[i]].plane->alpha, sortnode[sortindex[i]].plane->planecolormap);
4781 		}
4782 		else if (sortnode[sortindex[i]].polyplane)
4783 		{
4784 			// We aren't traversing the BSP tree, so make gl_frontsector null to avoid crashes.
4785 			gl_frontsector = NULL;
4786 
4787 			if (!(sortnode[sortindex[i]].polyplane->blend & PF_NoTexture))
4788 				HWR_GetLevelFlat(sortnode[sortindex[i]].polyplane->levelflat);
4789 			HWR_RenderPolyObjectPlane(sortnode[sortindex[i]].polyplane->polysector, sortnode[sortindex[i]].polyplane->isceiling, sortnode[sortindex[i]].polyplane->fixedheight, sortnode[sortindex[i]].polyplane->blend, sortnode[sortindex[i]].polyplane->lightlevel,
4790 				sortnode[sortindex[i]].polyplane->levelflat, sortnode[sortindex[i]].polyplane->FOFSector, sortnode[sortindex[i]].polyplane->alpha, sortnode[sortindex[i]].polyplane->planecolormap);
4791 		}
4792 		else if (sortnode[sortindex[i]].wall)
4793 		{
4794 			if (!(sortnode[sortindex[i]].wall->blend & PF_NoTexture))
4795 				HWR_GetTexture(sortnode[sortindex[i]].wall->texnum);
4796 			HWR_RenderWall(sortnode[sortindex[i]].wall->wallVerts, &sortnode[sortindex[i]].wall->Surf, sortnode[sortindex[i]].wall->blend, sortnode[sortindex[i]].wall->fogwall,
4797 				sortnode[sortindex[i]].wall->lightlevel, sortnode[sortindex[i]].wall->wallcolormap);
4798 		}
4799 	}
4800 
4801 	ps_hw_nodedrawtime = I_GetPreciseTime() - ps_hw_nodedrawtime;
4802 
4803 	numwalls = 0;
4804 	numplanes = 0;
4805 	numpolyplanes = 0;
4806 
4807 	// No mem leaks, please.
4808 	Z_Free(sortnode);
4809 	Z_Free(sortindex);
4810 }
4811 
4812 // --------------------------------------------------------------------------
4813 //  Draw all vissprites
4814 // --------------------------------------------------------------------------
4815 
4816 // added the stransform so they can be switched as drawing happenes so MD2s and sprites are sorted correctly with each other
HWR_DrawSprites(void)4817 static void HWR_DrawSprites(void)
4818 {
4819 	UINT32 i;
4820 	boolean skipshadow = false; // skip shadow if it was drawn already for a linkdraw sprite encountered earlier in the list
4821 	HWD.pfnSetSpecialState(HWD_SET_MODEL_LIGHTING, cv_glmodellighting.value);
4822 	for (i = 0; i < gl_visspritecount; i++)
4823 	{
4824 		gl_vissprite_t *spr = gl_vsprorder[i];
4825 #ifdef HWPRECIP
4826 		if (spr->precip)
4827 			HWR_DrawPrecipitationSprite(spr);
4828 		else
4829 #endif
4830 		{
4831 			if (spr->mobj && spr->mobj->shadowscale && cv_shadow.value && !skipshadow)
4832 			{
4833 				HWR_DrawDropShadow(spr->mobj, spr->mobj->shadowscale);
4834 			}
4835 
4836 			if ((spr->mobj->flags2 & MF2_LINKDRAW) && spr->mobj->tracer)
4837 			{
4838 				// If this linkdraw sprite is behind a sprite that has a shadow,
4839 				// then that shadow has to be drawn first, otherwise the shadow ends up on top of
4840 				// the linkdraw sprite because the linkdraw sprite does not modify the z-buffer.
4841 				// The !skipshadow check is there in case there are multiple linkdraw sprites connected
4842 				// to the same tracer, so the tracer's shadow only gets drawn once.
4843 				if (cv_shadow.value && !skipshadow && spr->dispoffset < 0 && spr->mobj->tracer->shadowscale)
4844 				{
4845 					HWR_DrawDropShadow(spr->mobj->tracer, spr->mobj->tracer->shadowscale);
4846 					skipshadow = true;
4847 					// The next sprite in this loop should be either another linkdraw sprite or the tracer.
4848 					// When the tracer is inevitably encountered, skipshadow will cause it's shadow
4849 					// to get skipped and skipshadow will get set to false by the 'else' clause below.
4850 				}
4851 			}
4852 			else
4853 			{
4854 				skipshadow = false;
4855 			}
4856 
4857 			if (spr->mobj && spr->mobj->skin && spr->mobj->sprite == SPR_PLAY)
4858 			{
4859 				if (!cv_glmodels.value || md2_playermodels[(skin_t*)spr->mobj->skin-skins].notfound || md2_playermodels[(skin_t*)spr->mobj->skin-skins].scale < 0.0f)
4860 					HWR_DrawSprite(spr);
4861 				else
4862 				{
4863 					if (!HWR_DrawModel(spr))
4864 						HWR_DrawSprite(spr);
4865 				}
4866 			}
4867 			else
4868 			{
4869 				if (!cv_glmodels.value || md2_models[spr->mobj->sprite].notfound || md2_models[spr->mobj->sprite].scale < 0.0f)
4870 					HWR_DrawSprite(spr);
4871 				else
4872 				{
4873 					if (!HWR_DrawModel(spr))
4874 						HWR_DrawSprite(spr);
4875 				}
4876 			}
4877 		}
4878 	}
4879 	HWD.pfnSetSpecialState(HWD_SET_MODEL_LIGHTING, 0);
4880 
4881 	// At the end of sprite drawing, draw shapes of linkdraw sprites to z-buffer, so they
4882 	// don't get drawn over by transparent surfaces.
4883 	HWR_LinkDrawHackFinish();
4884 	// Work around a r_opengl.c bug with PF_Invisible by making this SetBlend call
4885 	// where PF_Invisible is off and PF_Masked is on.
4886 	// (Other states probably don't matter. Here I left them same as in LinkDrawHackFinish)
4887 	// Without this workaround the rest of the draw calls in this frame (including UI, screen texture)
4888 	// can get drawn using an incorrect glBlendFunc, resulting in a occasional black screen.
4889 	HWD.pfnSetBlend(PF_Translucent|PF_Occlude|PF_Masked);
4890 }
4891 
4892 // --------------------------------------------------------------------------
4893 // HWR_AddSprites
4894 // During BSP traversal, this adds sprites by sector.
4895 // --------------------------------------------------------------------------
4896 static UINT8 sectorlight;
HWR_AddSprites(sector_t * sec)4897 static void HWR_AddSprites(sector_t *sec)
4898 {
4899 	mobj_t *thing;
4900 #ifdef HWPRECIP
4901 	precipmobj_t *precipthing;
4902 #endif
4903 	fixed_t limit_dist, hoop_limit_dist;
4904 
4905 	// BSP is traversed by subsector.
4906 	// A sector might have been split into several
4907 	//  subsectors during BSP building.
4908 	// Thus we check whether its already added.
4909 	if (sec->validcount == validcount)
4910 		return;
4911 
4912 	// Well, now it will be done.
4913 	sec->validcount = validcount;
4914 
4915 	// sprite lighting
4916 	sectorlight = sec->lightlevel & 0xff;
4917 
4918 	// Handle all things in sector.
4919 	// If a limit exists, handle things a tiny bit different.
4920 	limit_dist = (fixed_t)(cv_drawdist.value) << FRACBITS;
4921 	hoop_limit_dist = (fixed_t)(cv_drawdist_nights.value) << FRACBITS;
4922 	for (thing = sec->thinglist; thing; thing = thing->snext)
4923 	{
4924 		if (R_ThingVisibleWithinDist(thing, limit_dist, hoop_limit_dist))
4925 			HWR_ProjectSprite(thing);
4926 	}
4927 
4928 #ifdef HWPRECIP
4929 	// no, no infinite draw distance for precipitation. this option at zero is supposed to turn it off
4930 	if ((limit_dist = (fixed_t)cv_drawdist_precip.value << FRACBITS))
4931 	{
4932 		for (precipthing = sec->preciplist; precipthing; precipthing = precipthing->snext)
4933 		{
4934 			if (R_PrecipThingVisible(precipthing, limit_dist))
4935 				HWR_ProjectPrecipitationSprite(precipthing);
4936 		}
4937 	}
4938 #endif
4939 }
4940 
4941 // --------------------------------------------------------------------------
4942 // HWR_ProjectSprite
4943 //  Generates a vissprite for a thing if it might be visible.
4944 // --------------------------------------------------------------------------
4945 // BP why not use xtoviexangle/viewangletox like in bsp ?....
HWR_ProjectSprite(mobj_t * thing)4946 static void HWR_ProjectSprite(mobj_t *thing)
4947 {
4948 	gl_vissprite_t *vis;
4949 	float tr_x, tr_y;
4950 	float tz;
4951 	float tracertz = 0.0f;
4952 	float x1, x2;
4953 	float rightsin, rightcos;
4954 	float this_scale, this_xscale, this_yscale;
4955 	float spritexscale, spriteyscale;
4956 	float shadowheight = 1.0f, shadowscale = 1.0f;
4957 	float gz, gzt;
4958 	spritedef_t *sprdef;
4959 	spriteframe_t *sprframe;
4960 #ifdef ROTSPRITE
4961 	spriteinfo_t *sprinfo;
4962 #endif
4963 	md2_t *md2;
4964 	size_t lumpoff;
4965 	unsigned rot;
4966 	UINT16 flip;
4967 	boolean vflip = (!(thing->eflags & MFE_VERTICALFLIP) != !R_ThingVerticallyFlipped(thing));
4968 	boolean mirrored = thing->mirrored;
4969 	boolean hflip = (!R_ThingHorizontallyFlipped(thing) != !mirrored);
4970 	INT32 dispoffset;
4971 
4972 	angle_t ang;
4973 	INT32 heightsec, phs;
4974 	const boolean splat = R_ThingIsFloorSprite(thing);
4975 	const boolean papersprite = (R_ThingIsPaperSprite(thing) && !splat);
4976 	angle_t mobjangle = (thing->player ? thing->player->drawangle : thing->angle);
4977 	float z1, z2;
4978 
4979 	fixed_t spr_width, spr_height;
4980 	fixed_t spr_offset, spr_topoffset;
4981 #ifdef ROTSPRITE
4982 	patch_t *rotsprite = NULL;
4983 	INT32 rollangle = 0;
4984 #endif
4985 
4986 	if (!thing)
4987 		return;
4988 
4989 	if (thing->spritexscale < 1 || thing->spriteyscale < 1)
4990 		return;
4991 
4992 	// Visibility check by the blend mode.
4993 	if (thing->frame & FF_TRANSMASK)
4994 	{
4995 		if (!R_BlendLevelVisible(thing->blendmode, (thing->frame & FF_TRANSMASK)>>FF_TRANSSHIFT))
4996 			return;
4997 	}
4998 
4999 	dispoffset = thing->info->dispoffset;
5000 
5001 	this_scale = FIXED_TO_FLOAT(thing->scale);
5002 	spritexscale = FIXED_TO_FLOAT(thing->spritexscale);
5003 	spriteyscale = FIXED_TO_FLOAT(thing->spriteyscale);
5004 
5005 	// transform the origin point
5006 	tr_x = FIXED_TO_FLOAT(thing->x) - gl_viewx;
5007 	tr_y = FIXED_TO_FLOAT(thing->y) - gl_viewy;
5008 
5009 	// rotation around vertical axis
5010 	tz = (tr_x * gl_viewcos) + (tr_y * gl_viewsin);
5011 
5012 	// thing is behind view plane?
5013 	if (tz < ZCLIP_PLANE && !(papersprite || splat))
5014 	{
5015 		if (cv_glmodels.value) //Yellow: Only MD2's dont disappear
5016 		{
5017 			if (thing->skin && thing->sprite == SPR_PLAY)
5018 				md2 = &md2_playermodels[( (skin_t *)thing->skin - skins )];
5019 			else
5020 				md2 = &md2_models[thing->sprite];
5021 
5022 			if (md2->notfound || md2->scale < 0.0f)
5023 				return;
5024 		}
5025 		else
5026 			return;
5027 	}
5028 
5029 	// The above can stay as it works for cutting sprites that are too close
5030 	tr_x = FIXED_TO_FLOAT(thing->x);
5031 	tr_y = FIXED_TO_FLOAT(thing->y);
5032 
5033 	// decide which patch to use for sprite relative to player
5034 #ifdef RANGECHECK
5035 	if ((unsigned)thing->sprite >= numsprites)
5036 		I_Error("HWR_ProjectSprite: invalid sprite number %i ", thing->sprite);
5037 #endif
5038 
5039 	rot = thing->frame&FF_FRAMEMASK;
5040 
5041 	//Fab : 02-08-98: 'skin' override spritedef currently used for skin
5042 	if (thing->skin && thing->sprite == SPR_PLAY)
5043 	{
5044 		sprdef = &((skin_t *)thing->skin)->sprites[thing->sprite2];
5045 #ifdef ROTSPRITE
5046 		sprinfo = &((skin_t *)thing->skin)->sprinfo[thing->sprite2];
5047 #endif
5048 	}
5049 	else
5050 	{
5051 		sprdef = &sprites[thing->sprite];
5052 #ifdef ROTSPRITE
5053 		sprinfo = &spriteinfo[thing->sprite];
5054 #endif
5055 	}
5056 
5057 	if (rot >= sprdef->numframes)
5058 	{
5059 		CONS_Alert(CONS_ERROR, M_GetText("HWR_ProjectSprite: invalid sprite frame %s/%s for %s\n"),
5060 			sizeu1(rot), sizeu2(sprdef->numframes), sprnames[thing->sprite]);
5061 		thing->sprite = states[S_UNKNOWN].sprite;
5062 		thing->frame = states[S_UNKNOWN].frame;
5063 		sprdef = &sprites[thing->sprite];
5064 #ifdef ROTSPRITE
5065 		sprinfo = &spriteinfo[thing->sprite];
5066 #endif
5067 		rot = thing->frame&FF_FRAMEMASK;
5068 		thing->state->sprite = thing->sprite;
5069 		thing->state->frame = thing->frame;
5070 	}
5071 
5072 	sprframe = &sprdef->spriteframes[rot];
5073 
5074 #ifdef PARANOIA
5075 	if (!sprframe)
5076 		I_Error("sprframes NULL for sprite %d\n", thing->sprite);
5077 #endif
5078 
5079 	ang = R_PointToAngle (thing->x, thing->y) - mobjangle;
5080 	if (mirrored)
5081 		ang = InvAngle(ang);
5082 
5083 	if (sprframe->rotate == SRF_SINGLE)
5084 	{
5085 		// use single rotation for all views
5086 		rot = 0;                        //Fab: for vis->patch below
5087 		lumpoff = sprframe->lumpid[0];     //Fab: see note above
5088 		flip = sprframe->flip; // Will only be 0x00 or 0xFF
5089 
5090 		if (papersprite && ang < ANGLE_180)
5091 			flip ^= 0xFFFF;
5092 	}
5093 	else
5094 	{
5095 		// choose a different rotation based on player view
5096 		if ((sprframe->rotate & SRF_RIGHT) && (ang < ANGLE_180)) // See from right
5097 			rot = 6; // F7 slot
5098 		else if ((sprframe->rotate & SRF_LEFT) && (ang >= ANGLE_180)) // See from left
5099 			rot = 2; // F3 slot
5100 		else if (sprframe->rotate & SRF_3DGE) // 16-angle mode
5101 		{
5102 			rot = (ang+ANGLE_180+ANGLE_11hh)>>28;
5103 			rot = ((rot & 1)<<3)|(rot>>1);
5104 		}
5105 		else // Normal behaviour
5106 			rot = (ang+ANGLE_202h)>>29;
5107 
5108 		//Fab: lumpid is the index for spritewidth,spriteoffset... tables
5109 		lumpoff = sprframe->lumpid[rot];
5110 		flip = sprframe->flip & (1<<rot);
5111 
5112 		if (papersprite && ang < ANGLE_180)
5113 			flip ^= (1<<rot);
5114 	}
5115 
5116 	if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES)
5117 		this_scale *= FIXED_TO_FLOAT(((skin_t *)thing->skin)->highresscale);
5118 
5119 	spr_width = spritecachedinfo[lumpoff].width;
5120 	spr_height = spritecachedinfo[lumpoff].height;
5121 	spr_offset = spritecachedinfo[lumpoff].offset;
5122 	spr_topoffset = spritecachedinfo[lumpoff].topoffset;
5123 
5124 #ifdef ROTSPRITE
5125 	if (thing->rollangle
5126 	&& !(splat && !(thing->renderflags & RF_NOSPLATROLLANGLE)))
5127 	{
5128 		rollangle = R_GetRollAngle(thing->rollangle);
5129 		rotsprite = Patch_GetRotatedSprite(sprframe, (thing->frame & FF_FRAMEMASK), rot, flip, false, sprinfo, rollangle);
5130 
5131 		if (rotsprite != NULL)
5132 		{
5133 			spr_width = rotsprite->width << FRACBITS;
5134 			spr_height = rotsprite->height << FRACBITS;
5135 			spr_offset = rotsprite->leftoffset << FRACBITS;
5136 			spr_topoffset = rotsprite->topoffset << FRACBITS;
5137 			spr_topoffset += FEETADJUST;
5138 
5139 			// flip -> rotate, not rotate -> flip
5140 			flip = 0;
5141 		}
5142 	}
5143 #endif
5144 
5145 	if (thing->renderflags & RF_ABSOLUTEOFFSETS)
5146 	{
5147 		spr_offset = thing->spritexoffset;
5148 		spr_topoffset = thing->spriteyoffset;
5149 	}
5150 	else
5151 	{
5152 		SINT8 flipoffset = 1;
5153 
5154 		if ((thing->renderflags & RF_FLIPOFFSETS) && flip)
5155 			flipoffset = -1;
5156 
5157 		spr_offset += thing->spritexoffset * flipoffset;
5158 		spr_topoffset += thing->spriteyoffset * flipoffset;
5159 	}
5160 
5161 	if (papersprite)
5162 	{
5163 		rightsin = FIXED_TO_FLOAT(FINESINE((mobjangle)>>ANGLETOFINESHIFT));
5164 		rightcos = FIXED_TO_FLOAT(FINECOSINE((mobjangle)>>ANGLETOFINESHIFT));
5165 	}
5166 	else
5167 	{
5168 		rightsin = FIXED_TO_FLOAT(FINESINE((viewangle + ANGLE_90)>>ANGLETOFINESHIFT));
5169 		rightcos = FIXED_TO_FLOAT(FINECOSINE((viewangle + ANGLE_90)>>ANGLETOFINESHIFT));
5170 	}
5171 
5172 	flip = !flip != !hflip;
5173 
5174 	if (thing->renderflags & RF_SHADOWEFFECTS)
5175 	{
5176 		mobj_t *caster = thing->target;
5177 
5178 		if (caster && !P_MobjWasRemoved(caster))
5179 		{
5180 			fixed_t groundz = R_GetShadowZ(thing, NULL);
5181 			fixed_t floordiff = abs(((thing->eflags & MFE_VERTICALFLIP) ? caster->height : 0) + caster->z - groundz);
5182 
5183 			shadowheight = FIXED_TO_FLOAT(floordiff);
5184 			shadowscale = FIXED_TO_FLOAT(FixedMul(FRACUNIT - floordiff/640, caster->scale));
5185 
5186 			if (splat)
5187 				spritexscale *= shadowscale;
5188 			spriteyscale *= shadowscale;
5189 		}
5190 	}
5191 
5192 	this_xscale = spritexscale * this_scale;
5193 	this_yscale = spriteyscale * this_scale;
5194 
5195 	if (flip)
5196 	{
5197 		x1 = (FIXED_TO_FLOAT(spr_width - spr_offset) * this_xscale);
5198 		x2 = (FIXED_TO_FLOAT(spr_offset) * this_xscale);
5199 	}
5200 	else
5201 	{
5202 		x1 = (FIXED_TO_FLOAT(spr_offset) * this_xscale);
5203 		x2 = (FIXED_TO_FLOAT(spr_width - spr_offset) * this_xscale);
5204 	}
5205 
5206 	// test if too close
5207 /*
5208 	if (papersprite)
5209 	{
5210 		z1 = tz - x1 * angle_scalez;
5211 		z2 = tz + x2 * angle_scalez;
5212 
5213 		if (max(z1, z2) < ZCLIP_PLANE)
5214 			return;
5215 	}
5216 */
5217 
5218 	z1 = tr_y + x1 * rightsin;
5219 	z2 = tr_y - x2 * rightsin;
5220 	x1 = tr_x + x1 * rightcos;
5221 	x2 = tr_x - x2 * rightcos;
5222 
5223 	if (vflip)
5224 	{
5225 		gz = FIXED_TO_FLOAT(thing->z + thing->height) - (FIXED_TO_FLOAT(spr_topoffset) * this_yscale);
5226 		gzt = gz + (FIXED_TO_FLOAT(spr_height) * this_yscale);
5227 	}
5228 	else
5229 	{
5230 		gzt = FIXED_TO_FLOAT(thing->z) + (FIXED_TO_FLOAT(spr_topoffset) * this_yscale);
5231 		gz = gzt - (FIXED_TO_FLOAT(spr_height) * this_yscale);
5232 	}
5233 
5234 	if (thing->subsector->sector->cullheight)
5235 	{
5236 		if (HWR_DoCulling(thing->subsector->sector->cullheight, viewsector->cullheight, gl_viewz, gz, gzt))
5237 			return;
5238 	}
5239 
5240 	heightsec = thing->subsector->sector->heightsec;
5241 	if (viewplayer->mo && viewplayer->mo->subsector)
5242 		phs = viewplayer->mo->subsector->sector->heightsec;
5243 	else
5244 		phs = -1;
5245 
5246 	if (heightsec != -1 && phs != -1) // only clip things which are in special sectors
5247 	{
5248 		if (gl_viewz < FIXED_TO_FLOAT(sectors[phs].floorheight) ?
5249 		FIXED_TO_FLOAT(thing->z) >= FIXED_TO_FLOAT(sectors[heightsec].floorheight) :
5250 		gzt < FIXED_TO_FLOAT(sectors[heightsec].floorheight))
5251 			return;
5252 		if (gl_viewz > FIXED_TO_FLOAT(sectors[phs].ceilingheight) ?
5253 		gzt < FIXED_TO_FLOAT(sectors[heightsec].ceilingheight) && gl_viewz >= FIXED_TO_FLOAT(sectors[heightsec].ceilingheight) :
5254 		FIXED_TO_FLOAT(thing->z) >= FIXED_TO_FLOAT(sectors[heightsec].ceilingheight))
5255 			return;
5256 	}
5257 
5258 	if ((thing->flags2 & MF2_LINKDRAW) && thing->tracer)
5259 	{
5260 		if (! R_ThingVisible(thing->tracer))
5261 			return;
5262 
5263 		// calculate tz for tracer, same way it is calculated for this sprite
5264 		// transform the origin point
5265 		tr_x = FIXED_TO_FLOAT(thing->tracer->x) - gl_viewx;
5266 		tr_y = FIXED_TO_FLOAT(thing->tracer->y) - gl_viewy;
5267 
5268 		// rotation around vertical axis
5269 		tracertz = (tr_x * gl_viewcos) + (tr_y * gl_viewsin);
5270 
5271 		// Software does not render the linkdraw sprite if the tracer is behind the view plane,
5272 		// so do the same check here.
5273 		// NOTE: This check has the same flaw as the view plane check at the beginning of HWR_ProjectSprite:
5274 		// the view aiming angle is not taken into account, leading to sprites disappearing too early when they
5275 		// can still be seen when looking down/up at steep angles.
5276 		if (tracertz < ZCLIP_PLANE)
5277 			return;
5278 
5279 		// if the sprite is behind the tracer, invert dispoffset, putting the sprite behind the tracer
5280 		if (tz > tracertz)
5281 			dispoffset *= -1;
5282 	}
5283 
5284 	// store information in a vissprite
5285 	vis = HWR_NewVisSprite();
5286 	vis->x1 = x1;
5287 	vis->x2 = x2;
5288 	vis->z1 = z1;
5289 	vis->z2 = z2;
5290 
5291 	vis->tz = tz; // Keep tz for the simple sprite sorting that happens
5292 	vis->tracertz = tracertz;
5293 
5294 	vis->renderflags = thing->renderflags;
5295 	vis->rotateflags = sprframe->rotate;
5296 
5297 	vis->shadowheight = shadowheight;
5298 	vis->shadowscale = shadowscale;
5299 	vis->dispoffset = dispoffset; // Monster Iestyn: 23/11/15: HARDWARE SUPPORT AT LAST
5300 	vis->flip = flip;
5301 
5302 	vis->scale = this_scale;
5303 	vis->spritexscale = spritexscale;
5304 	vis->spriteyscale = spriteyscale;
5305 	vis->spritexoffset = FIXED_TO_FLOAT(spr_offset);
5306 	vis->spriteyoffset = FIXED_TO_FLOAT(spr_topoffset);
5307 
5308 	vis->rotated = false;
5309 
5310 #ifdef ROTSPRITE
5311 	if (rotsprite)
5312 	{
5313 		vis->gpatch = (patch_t *)rotsprite;
5314 		vis->rotated = true;
5315 	}
5316 	else
5317 #endif
5318 		vis->gpatch = (patch_t *)W_CachePatchNum(sprframe->lumppat[rot], PU_SPRITE);
5319 
5320 	vis->mobj = thing;
5321 
5322 	//Hurdler: 25/04/2000: now support colormap in hardware mode
5323 	if ((vis->mobj->flags & (MF_ENEMY|MF_BOSS)) && (vis->mobj->flags2 & MF2_FRET) && !(vis->mobj->flags & MF_GRENADEBOUNCE) && (leveltime & 1)) // Bosses "flash"
5324 	{
5325 		if (vis->mobj->type == MT_CYBRAKDEMON || vis->mobj->colorized)
5326 			vis->colormap = R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE);
5327 		else if (vis->mobj->type == MT_METALSONIC_BATTLE)
5328 			vis->colormap = R_GetTranslationColormap(TC_METALSONIC, 0, GTC_CACHE);
5329 		else
5330 			vis->colormap = R_GetTranslationColormap(TC_BOSS, 0, GTC_CACHE);
5331 	}
5332 	else if (thing->color)
5333 	{
5334 		// New colormap stuff for skins Tails 06-07-2002
5335 		if (thing->colorized)
5336 			vis->colormap = R_GetTranslationColormap(TC_RAINBOW, thing->color, GTC_CACHE);
5337 		else if (thing->player && thing->player->dashmode >= DASHMODE_THRESHOLD
5338 			&& (thing->player->charflags & SF_DASHMODE)
5339 			&& ((leveltime/2) & 1))
5340 		{
5341 			if (thing->player->charflags & SF_MACHINE)
5342 				vis->colormap = R_GetTranslationColormap(TC_DASHMODE, 0, GTC_CACHE);
5343 			else
5344 				vis->colormap = R_GetTranslationColormap(TC_RAINBOW, thing->color, GTC_CACHE);
5345 		}
5346 		else if (thing->skin && thing->sprite == SPR_PLAY) // This thing is a player!
5347 		{
5348 			size_t skinnum = (skin_t*)thing->skin-skins;
5349 			vis->colormap = R_GetTranslationColormap((INT32)skinnum, thing->color, GTC_CACHE);
5350 		}
5351 		else
5352 			vis->colormap = R_GetTranslationColormap(TC_DEFAULT, vis->mobj->color ? vis->mobj->color : SKINCOLOR_CYAN, GTC_CACHE);
5353 	}
5354 	else
5355 		vis->colormap = NULL;
5356 
5357 	// set top/bottom coords
5358 	vis->gzt = gzt;
5359 	vis->gz = gz;
5360 
5361 	//CONS_Debug(DBG_RENDER, "------------------\nH: sprite  : %d\nH: frame   : %x\nH: type    : %d\nH: sname   : %s\n\n",
5362 	//            thing->sprite, thing->frame, thing->type, sprnames[thing->sprite]);
5363 
5364 	vis->vflip = vflip;
5365 
5366 	vis->precip = false;
5367 }
5368 
5369 #ifdef HWPRECIP
5370 // Precipitation projector for hardware mode
HWR_ProjectPrecipitationSprite(precipmobj_t * thing)5371 static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
5372 {
5373 	gl_vissprite_t *vis;
5374 	float tr_x, tr_y;
5375 	float tz;
5376 	float x1, x2;
5377 	float z1, z2;
5378 	float rightsin, rightcos;
5379 	spritedef_t *sprdef;
5380 	spriteframe_t *sprframe;
5381 	size_t lumpoff;
5382 	unsigned rot = 0;
5383 	UINT8 flip;
5384 
5385 	// Visibility check by the blend mode.
5386 	if (thing->frame & FF_TRANSMASK)
5387 	{
5388 		if (!R_BlendLevelVisible(thing->blendmode, (thing->frame & FF_TRANSMASK)>>FF_TRANSSHIFT))
5389 			return;
5390 	}
5391 
5392 	// transform the origin point
5393 	tr_x = FIXED_TO_FLOAT(thing->x) - gl_viewx;
5394 	tr_y = FIXED_TO_FLOAT(thing->y) - gl_viewy;
5395 
5396 	// rotation around vertical axis
5397 	tz = (tr_x * gl_viewcos) + (tr_y * gl_viewsin);
5398 
5399 	// thing is behind view plane?
5400 	if (tz < ZCLIP_PLANE)
5401 		return;
5402 
5403 	tr_x = FIXED_TO_FLOAT(thing->x);
5404 	tr_y = FIXED_TO_FLOAT(thing->y);
5405 
5406 	// decide which patch to use for sprite relative to player
5407 	if ((unsigned)thing->sprite >= numsprites)
5408 #ifdef RANGECHECK
5409 		I_Error("HWR_ProjectPrecipitationSprite: invalid sprite number %i ",
5410 		        thing->sprite);
5411 #else
5412 		return;
5413 #endif
5414 
5415 	sprdef = &sprites[thing->sprite];
5416 
5417 	if ((size_t)(thing->frame&FF_FRAMEMASK) >= sprdef->numframes)
5418 #ifdef RANGECHECK
5419 		I_Error("HWR_ProjectPrecipitationSprite: invalid sprite frame %i : %i for %s",
5420 		        thing->sprite, thing->frame, sprnames[thing->sprite]);
5421 #else
5422 		return;
5423 #endif
5424 
5425 	sprframe = &sprdef->spriteframes[thing->frame & FF_FRAMEMASK];
5426 
5427 	// use single rotation for all views
5428 	lumpoff = sprframe->lumpid[0];
5429 	flip = sprframe->flip; // Will only be 0x00 or 0xFF
5430 
5431 	rightsin = FIXED_TO_FLOAT(FINESINE((viewangle + ANGLE_90)>>ANGLETOFINESHIFT));
5432 	rightcos = FIXED_TO_FLOAT(FINECOSINE((viewangle + ANGLE_90)>>ANGLETOFINESHIFT));
5433 	if (flip)
5434 	{
5435 		x1 = FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width - spritecachedinfo[lumpoff].offset);
5436 		x2 = FIXED_TO_FLOAT(spritecachedinfo[lumpoff].offset);
5437 	}
5438 	else
5439 	{
5440 		x1 = FIXED_TO_FLOAT(spritecachedinfo[lumpoff].offset);
5441 		x2 = FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width - spritecachedinfo[lumpoff].offset);
5442 	}
5443 
5444 	z1 = tr_y + x1 * rightsin;
5445 	z2 = tr_y - x2 * rightsin;
5446 	x1 = tr_x + x1 * rightcos;
5447 	x2 = tr_x - x2 * rightcos;
5448 
5449 	//
5450 	// store information in a vissprite
5451 	//
5452 	vis = HWR_NewVisSprite();
5453 	vis->x1 = x1;
5454 	vis->x2 = x2;
5455 	vis->z1 = z1;
5456 	vis->z2 = z2;
5457 	vis->tz = tz;
5458 	vis->dispoffset = 0; // Monster Iestyn: 23/11/15: HARDWARE SUPPORT AT LAST
5459 	vis->gpatch = (patch_t *)W_CachePatchNum(sprframe->lumppat[rot], PU_SPRITE);
5460 	vis->flip = flip;
5461 	vis->mobj = (mobj_t *)thing;
5462 
5463 	vis->colormap = NULL;
5464 
5465 	// set top/bottom coords
5466 	vis->gzt = FIXED_TO_FLOAT(thing->z + spritecachedinfo[lumpoff].topoffset);
5467 	vis->gz = vis->gzt - FIXED_TO_FLOAT(spritecachedinfo[lumpoff].height);
5468 
5469 	vis->precip = true;
5470 
5471 	// okay... this is a hack, but weather isn't networked, so it should be ok
5472 	if (!(thing->precipflags & PCF_THUNK))
5473 	{
5474 		if (thing->precipflags & PCF_RAIN)
5475 			P_RainThinker(thing);
5476 		else
5477 			P_SnowThinker(thing);
5478 		thing->precipflags |= PCF_THUNK;
5479 	}
5480 }
5481 #endif
5482 
5483 // ==========================================================================
5484 // Sky dome rendering, ported from PrBoom+
5485 // ==========================================================================
5486 
5487 static gl_sky_t gl_sky;
5488 
HWR_SkyDomeVertex(gl_sky_t * sky,gl_skyvertex_t * vbo,int r,int c,signed char yflip,float delta,boolean foglayer)5489 static void HWR_SkyDomeVertex(gl_sky_t *sky, gl_skyvertex_t *vbo, int r, int c, signed char yflip, float delta, boolean foglayer)
5490 {
5491 	const float radians = (float)(M_PIl / 180.0f);
5492 	const float scale = 10000.0f;
5493 	const float maxSideAngle = 60.0f;
5494 
5495 	float topAngle = (c / (float)sky->columns * 360.0f);
5496 	float sideAngle = (maxSideAngle * (sky->rows - r) / sky->rows);
5497 	float height = (float)(sin(sideAngle * radians));
5498 	float realRadius = (float)(scale * cos(sideAngle * radians));
5499 	float x = (float)(realRadius * cos(topAngle * radians));
5500 	float y = (!yflip) ? scale * height : -scale * height;
5501 	float z = (float)(realRadius * sin(topAngle * radians));
5502 	float timesRepeat = (4 * (256.0f / sky->width));
5503 	if (fpclassify(timesRepeat) == FP_ZERO)
5504 		timesRepeat = 1.0f;
5505 
5506 	if (!foglayer)
5507 	{
5508 		vbo->r = 255;
5509 		vbo->g = 255;
5510 		vbo->b = 255;
5511 		vbo->a = (r == 0 ? 0 : 255);
5512 
5513 		// And the texture coordinates.
5514 		vbo->u = (-timesRepeat * c / (float)sky->columns);
5515 		if (!yflip)	// Flipped Y is for the lower hemisphere.
5516 			vbo->v = (r / (float)sky->rows) + 0.5f;
5517 		else
5518 			vbo->v = 1.0f + ((sky->rows - r) / (float)sky->rows) + 0.5f;
5519 	}
5520 
5521 	if (r != 4)
5522 		y += 300.0f;
5523 
5524 	// And finally the vertex.
5525 	vbo->x = x;
5526 	vbo->y = y + delta;
5527 	vbo->z = z;
5528 }
5529 
5530 // Clears the sky dome.
HWR_ClearSkyDome(void)5531 void HWR_ClearSkyDome(void)
5532 {
5533 	gl_sky_t *sky = &gl_sky;
5534 
5535 	if (sky->loops)
5536 		free(sky->loops);
5537 	if (sky->data)
5538 		free(sky->data);
5539 
5540 	sky->loops = NULL;
5541 	sky->data = NULL;
5542 
5543 	sky->vbo = 0;
5544 	sky->rows = sky->columns = 0;
5545 	sky->loopcount = 0;
5546 
5547 	sky->detail = 0;
5548 	sky->texture = -1;
5549 	sky->width = sky->height = 0;
5550 
5551 	sky->rebuild = true;
5552 }
5553 
HWR_BuildSkyDome(void)5554 void HWR_BuildSkyDome(void)
5555 {
5556 	int c, r;
5557 	signed char yflip;
5558 	int row_count = 4;
5559 	int col_count = 4;
5560 	float delta;
5561 
5562 	gl_sky_t *sky = &gl_sky;
5563 	gl_skyvertex_t *vertex_p;
5564 	texture_t *texture = textures[texturetranslation[skytexture]];
5565 
5566 	sky->detail = 16;
5567 	col_count *= sky->detail;
5568 
5569 	if ((sky->columns != col_count) || (sky->rows != row_count))
5570 		HWR_ClearSkyDome();
5571 
5572 	sky->columns = col_count;
5573 	sky->rows = row_count;
5574 	sky->vertex_count = 2 * sky->rows * (sky->columns * 2 + 2) + sky->columns * 2;
5575 
5576 	if (!sky->loops)
5577 		sky->loops = malloc((sky->rows * 2 + 2) * sizeof(sky->loops[0]));
5578 
5579 	// create vertex array
5580 	if (!sky->data)
5581 		sky->data = malloc(sky->vertex_count * sizeof(sky->data[0]));
5582 
5583 	sky->texture = texturetranslation[skytexture];
5584 	sky->width = texture->width;
5585 	sky->height = texture->height;
5586 
5587 	vertex_p = &sky->data[0];
5588 	sky->loopcount = 0;
5589 
5590 	for (yflip = 0; yflip < 2; yflip++)
5591 	{
5592 		sky->loops[sky->loopcount].mode = HWD_SKYLOOP_FAN;
5593 		sky->loops[sky->loopcount].vertexindex = vertex_p - &sky->data[0];
5594 		sky->loops[sky->loopcount].vertexcount = col_count;
5595 		sky->loops[sky->loopcount].use_texture = false;
5596 		sky->loopcount++;
5597 
5598 		delta = 0.0f;
5599 
5600 		for (c = 0; c < col_count; c++)
5601 		{
5602 			HWR_SkyDomeVertex(sky, vertex_p, 1, c, yflip, 0.0f, true);
5603 			vertex_p->r = 255;
5604 			vertex_p->g = 255;
5605 			vertex_p->b = 255;
5606 			vertex_p->a = 255;
5607 			vertex_p++;
5608 		}
5609 
5610 		delta = (yflip ? 5.0f : -5.0f) / 128.0f;
5611 
5612 		for (r = 0; r < row_count; r++)
5613 		{
5614 			sky->loops[sky->loopcount].mode = HWD_SKYLOOP_STRIP;
5615 			sky->loops[sky->loopcount].vertexindex = vertex_p - &sky->data[0];
5616 			sky->loops[sky->loopcount].vertexcount = 2 * col_count + 2;
5617 			sky->loops[sky->loopcount].use_texture = true;
5618 			sky->loopcount++;
5619 
5620 			for (c = 0; c <= col_count; c++)
5621 			{
5622 				HWR_SkyDomeVertex(sky, vertex_p++, r + (yflip ? 1 : 0), (c ? c : 0), yflip, delta, false);
5623 				HWR_SkyDomeVertex(sky, vertex_p++, r + (yflip ? 0 : 1), (c ? c : 0), yflip, delta, false);
5624 			}
5625 		}
5626 	}
5627 }
5628 
HWR_DrawSkyBackground(player_t * player)5629 static void HWR_DrawSkyBackground(player_t *player)
5630 {
5631 	HWD.pfnSetBlend(PF_Translucent|PF_NoDepthTest|PF_Modulated);
5632 
5633 	if (cv_glskydome.value)
5634 	{
5635 		FTransform dometransform;
5636 		const float fpov = FIXED_TO_FLOAT(cv_fov.value+player->fovadd);
5637 		postimg_t *type;
5638 
5639 		if (splitscreen && player == &players[secondarydisplayplayer])
5640 			type = &postimgtype2;
5641 		else
5642 			type = &postimgtype;
5643 
5644 		memset(&dometransform, 0x00, sizeof(FTransform));
5645 
5646 		//04/01/2000: Hurdler: added for T&L
5647 		//                     It should replace all other gl_viewxxx when finished
5648 		HWR_SetTransformAiming(&dometransform, player, false);
5649 		dometransform.angley = (float)((viewangle-ANGLE_270)>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
5650 
5651 		if (*type == postimg_flip)
5652 			dometransform.flip = true;
5653 		else
5654 			dometransform.flip = false;
5655 
5656 		dometransform.scalex = 1;
5657 		dometransform.scaley = (float)vid.width/vid.height;
5658 		dometransform.scalez = 1;
5659 		dometransform.fovxangle = fpov; // Tails
5660 		dometransform.fovyangle = fpov; // Tails
5661 		if (player->viewrollangle != 0)
5662 		{
5663 			fixed_t rol = AngleFixed(player->viewrollangle);
5664 			dometransform.rollangle = FIXED_TO_FLOAT(rol);
5665 			dometransform.roll = true;
5666 		}
5667 		dometransform.splitscreen = splitscreen;
5668 
5669 		HWR_GetTexture(texturetranslation[skytexture]);
5670 
5671 		if (gl_sky.texture != texturetranslation[skytexture])
5672 		{
5673 			HWR_ClearSkyDome();
5674 			HWR_BuildSkyDome();
5675 		}
5676 
5677 		HWD.pfnSetShader(SHADER_SKY); // sky shader
5678 		HWD.pfnSetTransform(&dometransform);
5679 		HWD.pfnRenderSkyDome(&gl_sky);
5680 	}
5681 	else
5682 	{
5683 		FOutVector v[4];
5684 		angle_t angle;
5685 		float dimensionmultiply;
5686 		float aspectratio;
5687 		float angleturn;
5688 
5689 		HWR_GetTexture(texturetranslation[skytexture]);
5690 		aspectratio = (float)vid.width/(float)vid.height;
5691 
5692 		//Hurdler: the sky is the only texture who need 4.0f instead of 1.0
5693 		//         because it's called just after clearing the screen
5694 		//         and thus, the near clipping plane is set to 3.99
5695 		// Sryder: Just use the near clipping plane value then
5696 
5697 		//  3--2
5698 		//  | /|
5699 		//  |/ |
5700 		//  0--1
5701 		v[0].x = v[3].x = -ZCLIP_PLANE-1;
5702 		v[1].x = v[2].x =  ZCLIP_PLANE+1;
5703 		v[0].y = v[1].y = -ZCLIP_PLANE-1;
5704 		v[2].y = v[3].y =  ZCLIP_PLANE+1;
5705 
5706 		v[0].z = v[1].z = v[2].z = v[3].z = ZCLIP_PLANE+1;
5707 
5708 		// X
5709 
5710 		// NOTE: This doesn't work right with texture widths greater than 1024
5711 		// software doesn't draw any further than 1024 for skies anyway, but this doesn't overlap properly
5712 		// The only time this will probably be an issue is when a sky wider than 1024 is used as a sky AND a regular wall texture
5713 
5714 		angle = (dup_viewangle + gl_xtoviewangle[0]);
5715 
5716 		dimensionmultiply = ((float)textures[texturetranslation[skytexture]]->width/256.0f);
5717 
5718 		v[0].s = v[3].s = (-1.0f * angle) / ((ANGLE_90-1)*dimensionmultiply); // left
5719 		v[2].s = v[1].s = v[0].s + (1.0f/dimensionmultiply); // right (or left + 1.0f)
5720 		// use +angle and -1.0f above instead if you wanted old backwards behavior
5721 
5722 		// Y
5723 		angle = aimingangle;
5724 		dimensionmultiply = ((float)textures[texturetranslation[skytexture]]->height/(128.0f*aspectratio));
5725 
5726 		if (splitscreen)
5727 		{
5728 			dimensionmultiply *= 2;
5729 			angle *= 2;
5730 		}
5731 
5732 		// Middle of the sky should always be at angle 0
5733 		// need to keep correct aspect ratio with X
5734 		if (atransform.flip)
5735 		{
5736 			// During vertical flip the sky should be flipped and it's y movement should also be flipped obviously
5737 			v[3].t = v[2].t = -(0.5f-(0.5f/dimensionmultiply)); // top
5738 			v[0].t = v[1].t = v[3].t - (1.0f/dimensionmultiply); // bottom (or top - 1.0f)
5739 		}
5740 		else
5741 		{
5742 			v[0].t = v[1].t = -(0.5f-(0.5f/dimensionmultiply)); // bottom
5743 			v[3].t = v[2].t = v[0].t - (1.0f/dimensionmultiply); // top (or bottom - 1.0f)
5744 		}
5745 
5746 		angleturn = (((float)ANGLE_45-1.0f)*aspectratio)*dimensionmultiply;
5747 
5748 		if (angle > ANGLE_180) // Do this because we don't want the sky to suddenly teleport when crossing over 0 to 360 and vice versa
5749 		{
5750 			angle = InvAngle(angle);
5751 			v[3].t = v[2].t += ((float) angle / angleturn);
5752 			v[0].t = v[1].t += ((float) angle / angleturn);
5753 		}
5754 		else
5755 		{
5756 			v[3].t = v[2].t -= ((float) angle / angleturn);
5757 			v[0].t = v[1].t -= ((float) angle / angleturn);
5758 		}
5759 
5760 		HWD.pfnUnSetShader();
5761 		HWD.pfnDrawPolygon(NULL, v, 4, 0);
5762 	}
5763 
5764 	HWD.pfnSetShader(SHADER_DEFAULT);
5765 }
5766 
5767 
5768 // -----------------+
5769 // HWR_ClearView : clear the viewwindow, with maximum z value
5770 // -----------------+
HWR_ClearView(void)5771 static inline void HWR_ClearView(void)
5772 {
5773 	//  3--2
5774 	//  | /|
5775 	//  |/ |
5776 	//  0--1
5777 
5778 	/// \bug faB - enable depth mask, disable color mask
5779 
5780 	HWD.pfnGClipRect((INT32)gl_viewwindowx,
5781 	                 (INT32)gl_viewwindowy,
5782 	                 (INT32)(gl_viewwindowx + gl_viewwidth),
5783 	                 (INT32)(gl_viewwindowy + gl_viewheight),
5784 	                 ZCLIP_PLANE);
5785 	HWD.pfnClearBuffer(false, true, 0);
5786 
5787 	//disable clip window - set to full size
5788 	// rem by Hurdler
5789 	// HWD.pfnGClipRect(0, 0, vid.width, vid.height);
5790 }
5791 
5792 
5793 // -----------------+
5794 // HWR_SetViewSize  : set projection and scaling values
5795 // -----------------+
HWR_SetViewSize(void)5796 void HWR_SetViewSize(void)
5797 {
5798 	// setup view size
5799 	gl_viewwidth = (float)vid.width;
5800 	gl_viewheight = (float)vid.height;
5801 
5802 	if (splitscreen)
5803 		gl_viewheight /= 2;
5804 
5805 	gl_centerx = gl_viewwidth / 2;
5806 	gl_basecentery = gl_viewheight / 2; //note: this is (gl_centerx * gl_viewheight / gl_viewwidth)
5807 
5808 	gl_viewwindowx = (vid.width - gl_viewwidth) / 2;
5809 	gl_windowcenterx = (float)(vid.width / 2);
5810 	if (fabsf(gl_viewwidth - vid.width) < 1.0E-36f)
5811 	{
5812 		gl_baseviewwindowy = 0;
5813 		gl_basewindowcentery = gl_viewheight / 2;               // window top left corner at 0,0
5814 	}
5815 	else
5816 	{
5817 		gl_baseviewwindowy = (vid.height-gl_viewheight) / 2;
5818 		gl_basewindowcentery = (float)(vid.height / 2);
5819 	}
5820 
5821 	gl_pspritexscale = gl_viewwidth / BASEVIDWIDTH;
5822 	gl_pspriteyscale = ((vid.height*gl_pspritexscale*BASEVIDWIDTH)/BASEVIDHEIGHT)/vid.width;
5823 
5824 	HWD.pfnFlushScreenTextures();
5825 }
5826 
5827 // Set view aiming, for the sky dome, the skybox,
5828 // and the normal view, all with a single function.
HWR_SetTransformAiming(FTransform * trans,player_t * player,boolean skybox)5829 static void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean skybox)
5830 {
5831 	// 1 = always on
5832 	// 2 = chasecam only
5833 	if (cv_glshearing.value == 1 || (cv_glshearing.value == 2 && R_IsViewpointThirdPerson(player, skybox)))
5834 	{
5835 		fixed_t fixedaiming = AIMINGTODY(aimingangle);
5836 		trans->viewaiming = FIXED_TO_FLOAT(fixedaiming);
5837 		trans->shearing = true;
5838 		gl_aimingangle = 0;
5839 	}
5840 	else
5841 	{
5842 		trans->shearing = false;
5843 		gl_aimingangle = aimingangle;
5844 	}
5845 
5846 	trans->anglex = (float)(gl_aimingangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
5847 }
5848 
5849 //
5850 // Sets the shader state.
5851 //
HWR_SetShaderState(void)5852 static void HWR_SetShaderState(void)
5853 {
5854 	hwdshaderoption_t state = cv_glshaders.value;
5855 
5856 	if (!cv_glallowshaders.value)
5857 		state = (cv_glshaders.value == HWD_SHADEROPTION_ON ? HWD_SHADEROPTION_NOCUSTOM : cv_glshaders.value);
5858 
5859 	HWD.pfnSetSpecialState(HWD_SET_SHADERS, (INT32)state);
5860 	HWD.pfnSetShader(SHADER_DEFAULT);
5861 }
5862 
5863 // ==========================================================================
5864 // Same as rendering the player view, but from the skybox object
5865 // ==========================================================================
HWR_RenderSkyboxView(INT32 viewnumber,player_t * player)5866 void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player)
5867 {
5868 	const float fpov = FIXED_TO_FLOAT(cv_fov.value+player->fovadd);
5869 	postimg_t *type;
5870 
5871 	if (splitscreen && player == &players[secondarydisplayplayer])
5872 		type = &postimgtype2;
5873 	else
5874 		type = &postimgtype;
5875 
5876 	{
5877 		// do we really need to save player (is it not the same)?
5878 		player_t *saved_player = stplyr;
5879 		stplyr = player;
5880 		ST_doPaletteStuff();
5881 		stplyr = saved_player;
5882 #ifdef ALAM_LIGHTING
5883 		HWR_SetLights(viewnumber);
5884 #endif
5885 	}
5886 
5887 	// note: sets viewangle, viewx, viewy, viewz
5888 	R_SkyboxFrame(player);
5889 
5890 	// copy view cam position for local use
5891 	dup_viewx = viewx;
5892 	dup_viewy = viewy;
5893 	dup_viewz = viewz;
5894 	dup_viewangle = viewangle;
5895 
5896 	// set window position
5897 	gl_centery = gl_basecentery;
5898 	gl_viewwindowy = gl_baseviewwindowy;
5899 	gl_windowcentery = gl_basewindowcentery;
5900 	if (splitscreen && viewnumber == 1)
5901 	{
5902 		gl_viewwindowy += (vid.height/2);
5903 		gl_windowcentery += (vid.height/2);
5904 	}
5905 
5906 	// check for new console commands.
5907 	NetUpdate();
5908 
5909 	gl_viewx = FIXED_TO_FLOAT(dup_viewx);
5910 	gl_viewy = FIXED_TO_FLOAT(dup_viewy);
5911 	gl_viewz = FIXED_TO_FLOAT(dup_viewz);
5912 	gl_viewsin = FIXED_TO_FLOAT(viewsin);
5913 	gl_viewcos = FIXED_TO_FLOAT(viewcos);
5914 
5915 	//04/01/2000: Hurdler: added for T&L
5916 	//                     It should replace all other gl_viewxxx when finished
5917 	memset(&atransform, 0x00, sizeof(FTransform));
5918 
5919 	HWR_SetTransformAiming(&atransform, player, true);
5920 	atransform.angley = (float)(viewangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
5921 
5922 	gl_viewludsin = FIXED_TO_FLOAT(FINECOSINE(gl_aimingangle>>ANGLETOFINESHIFT));
5923 	gl_viewludcos = FIXED_TO_FLOAT(-FINESINE(gl_aimingangle>>ANGLETOFINESHIFT));
5924 
5925 	if (*type == postimg_flip)
5926 		atransform.flip = true;
5927 	else
5928 		atransform.flip = false;
5929 
5930 	atransform.x      = gl_viewx;  // FIXED_TO_FLOAT(viewx)
5931 	atransform.y      = gl_viewy;  // FIXED_TO_FLOAT(viewy)
5932 	atransform.z      = gl_viewz;  // FIXED_TO_FLOAT(viewz)
5933 	atransform.scalex = 1;
5934 	atransform.scaley = (float)vid.width/vid.height;
5935 	atransform.scalez = 1;
5936 
5937 	atransform.fovxangle = fpov; // Tails
5938 	atransform.fovyangle = fpov; // Tails
5939 	if (player->viewrollangle != 0)
5940 	{
5941 		fixed_t rol = AngleFixed(player->viewrollangle);
5942 		atransform.rollangle = FIXED_TO_FLOAT(rol);
5943 		atransform.roll = true;
5944 	}
5945 	atransform.splitscreen = splitscreen;
5946 
5947 	gl_fovlud = (float)(1.0l/tan((double)(fpov*M_PIl/360l)));
5948 
5949 	//------------------------------------------------------------------------
5950 	HWR_ClearView();
5951 
5952 	if (drawsky)
5953 		HWR_DrawSkyBackground(player);
5954 
5955 	//Hurdler: it doesn't work in splitscreen mode
5956 	drawsky = splitscreen;
5957 
5958 	HWR_ClearSprites();
5959 
5960 	drawcount = 0;
5961 
5962 #ifdef NEWCLIP
5963 	if (rendermode == render_opengl)
5964 	{
5965 		angle_t a1 = gld_FrustumAngle(gl_aimingangle);
5966 		gld_clipper_Clear();
5967 		gld_clipper_SafeAddClipRange(viewangle + a1, viewangle - a1);
5968 #ifdef HAVE_SPHEREFRUSTRUM
5969 		gld_FrustrumSetup();
5970 #endif
5971 	}
5972 #else
5973 	HWR_ClearClipSegs();
5974 #endif
5975 
5976 	//04/01/2000: Hurdler: added for T&L
5977 	//                     Actually it only works on Walls and Planes
5978 	HWD.pfnSetTransform(&atransform);
5979 
5980 	// Reset the shader state.
5981 	HWR_SetShaderState();
5982 
5983 	validcount++;
5984 
5985 	if (cv_glbatching.value)
5986 		HWR_StartBatching();
5987 
5988 	HWR_RenderBSPNode((INT32)numnodes-1);
5989 
5990 #ifndef NEWCLIP
5991 	// Make a viewangle int so we can render things based on mouselook
5992 	if (player == &players[consoleplayer])
5993 		viewangle = localaiming;
5994 	else if (splitscreen && player == &players[secondarydisplayplayer])
5995 		viewangle = localaiming2;
5996 
5997 	// Handle stuff when you are looking farther up or down.
5998 	if ((gl_aimingangle || cv_fov.value+player->fovadd > 90*FRACUNIT))
5999 	{
6000 		dup_viewangle += ANGLE_90;
6001 		HWR_ClearClipSegs();
6002 		HWR_RenderBSPNode((INT32)numnodes-1); //left
6003 
6004 		dup_viewangle += ANGLE_90;
6005 		if (((INT32)gl_aimingangle > ANGLE_45 || (INT32)gl_aimingangle<-ANGLE_45))
6006 		{
6007 			HWR_ClearClipSegs();
6008 			HWR_RenderBSPNode((INT32)numnodes-1); //back
6009 		}
6010 
6011 		dup_viewangle += ANGLE_90;
6012 		HWR_ClearClipSegs();
6013 		HWR_RenderBSPNode((INT32)numnodes-1); //right
6014 
6015 		dup_viewangle += ANGLE_90;
6016 	}
6017 #endif
6018 
6019 	if (cv_glbatching.value)
6020 		HWR_RenderBatches();
6021 
6022 	// Check for new console commands.
6023 	NetUpdate();
6024 
6025 #ifdef ALAM_LIGHTING
6026 	//14/11/99: Hurdler: moved here because it doesn't work with
6027 	// subsector, see other comments;
6028 	HWR_ResetLights();
6029 #endif
6030 
6031 	// Draw MD2 and sprites
6032 	HWR_SortVisSprites();
6033 	HWR_DrawSprites();
6034 
6035 #ifdef NEWCORONAS
6036 	//Hurdler: they must be drawn before translucent planes, what about gl fog?
6037 	HWR_DrawCoronas();
6038 #endif
6039 
6040 	if (numplanes || numpolyplanes || numwalls) //Hurdler: render 3D water and transparent walls after everything
6041 	{
6042 		HWR_CreateDrawNodes();
6043 	}
6044 
6045 	HWD.pfnSetTransform(NULL);
6046 	HWD.pfnUnSetShader();
6047 
6048 	// Check for new console commands.
6049 	NetUpdate();
6050 
6051 	// added by Hurdler for correct splitscreen
6052 	// moved here by hurdler so it works with the new near clipping plane
6053 	HWD.pfnGClipRect(0, 0, vid.width, vid.height, NZCLIP_PLANE);
6054 }
6055 
6056 // ==========================================================================
6057 //
6058 // ==========================================================================
HWR_RenderPlayerView(INT32 viewnumber,player_t * player)6059 void HWR_RenderPlayerView(INT32 viewnumber, player_t *player)
6060 {
6061 	const float fpov = FIXED_TO_FLOAT(cv_fov.value+player->fovadd);
6062 	postimg_t *type;
6063 
6064 	const boolean skybox = (skyboxmo[0] && cv_skybox.value); // True if there's a skybox object and skyboxes are on
6065 
6066 	FRGBAFloat ClearColor;
6067 
6068 	if (splitscreen && player == &players[secondarydisplayplayer])
6069 		type = &postimgtype2;
6070 	else
6071 		type = &postimgtype;
6072 
6073 	ClearColor.red = 0.0f;
6074 	ClearColor.green = 0.0f;
6075 	ClearColor.blue = 0.0f;
6076 	ClearColor.alpha = 1.0f;
6077 
6078 	if (cv_glshaders.value)
6079 		HWD.pfnSetShaderInfo(HWD_SHADERINFO_LEVELTIME, (INT32)leveltime); // The water surface shader needs the leveltime.
6080 
6081 	if (viewnumber == 0) // Only do it if it's the first screen being rendered
6082 		HWD.pfnClearBuffer(true, false, &ClearColor); // Clear the Color Buffer, stops HOMs. Also seems to fix the skybox issue on Intel GPUs.
6083 
6084 	ps_hw_skyboxtime = I_GetPreciseTime();
6085 	if (skybox && drawsky) // If there's a skybox and we should be drawing the sky, draw the skybox
6086 		HWR_RenderSkyboxView(viewnumber, player); // This is drawn before everything else so it is placed behind
6087 	ps_hw_skyboxtime = I_GetPreciseTime() - ps_hw_skyboxtime;
6088 
6089 	{
6090 		// do we really need to save player (is it not the same)?
6091 		player_t *saved_player = stplyr;
6092 		stplyr = player;
6093 		ST_doPaletteStuff();
6094 		stplyr = saved_player;
6095 #ifdef ALAM_LIGHTING
6096 		HWR_SetLights(viewnumber);
6097 #endif
6098 	}
6099 
6100 	// note: sets viewangle, viewx, viewy, viewz
6101 	R_SetupFrame(player);
6102 	framecount++; // timedemo
6103 
6104 	// copy view cam position for local use
6105 	dup_viewx = viewx;
6106 	dup_viewy = viewy;
6107 	dup_viewz = viewz;
6108 	dup_viewangle = viewangle;
6109 
6110 	// set window position
6111 	gl_centery = gl_basecentery;
6112 	gl_viewwindowy = gl_baseviewwindowy;
6113 	gl_windowcentery = gl_basewindowcentery;
6114 	if (splitscreen && viewnumber == 1)
6115 	{
6116 		gl_viewwindowy += (vid.height/2);
6117 		gl_windowcentery += (vid.height/2);
6118 	}
6119 
6120 	// check for new console commands.
6121 	NetUpdate();
6122 
6123 	gl_viewx = FIXED_TO_FLOAT(dup_viewx);
6124 	gl_viewy = FIXED_TO_FLOAT(dup_viewy);
6125 	gl_viewz = FIXED_TO_FLOAT(dup_viewz);
6126 	gl_viewsin = FIXED_TO_FLOAT(viewsin);
6127 	gl_viewcos = FIXED_TO_FLOAT(viewcos);
6128 
6129 	//04/01/2000: Hurdler: added for T&L
6130 	//                     It should replace all other gl_viewxxx when finished
6131 	memset(&atransform, 0x00, sizeof(FTransform));
6132 
6133 	HWR_SetTransformAiming(&atransform, player, false);
6134 	atransform.angley = (float)(viewangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
6135 
6136 	gl_viewludsin = FIXED_TO_FLOAT(FINECOSINE(gl_aimingangle>>ANGLETOFINESHIFT));
6137 	gl_viewludcos = FIXED_TO_FLOAT(-FINESINE(gl_aimingangle>>ANGLETOFINESHIFT));
6138 
6139 	if (*type == postimg_flip)
6140 		atransform.flip = true;
6141 	else
6142 		atransform.flip = false;
6143 
6144 	atransform.x      = gl_viewx;  // FIXED_TO_FLOAT(viewx)
6145 	atransform.y      = gl_viewy;  // FIXED_TO_FLOAT(viewy)
6146 	atransform.z      = gl_viewz;  // FIXED_TO_FLOAT(viewz)
6147 	atransform.scalex = 1;
6148 	atransform.scaley = (float)vid.width/vid.height;
6149 	atransform.scalez = 1;
6150 
6151 	atransform.fovxangle = fpov; // Tails
6152 	atransform.fovyangle = fpov; // Tails
6153 	if (player->viewrollangle != 0)
6154 	{
6155 		fixed_t rol = AngleFixed(player->viewrollangle);
6156 		atransform.rollangle = FIXED_TO_FLOAT(rol);
6157 		atransform.roll = true;
6158 	}
6159 	atransform.splitscreen = splitscreen;
6160 
6161 	gl_fovlud = (float)(1.0l/tan((double)(fpov*M_PIl/360l)));
6162 
6163 	//------------------------------------------------------------------------
6164 	HWR_ClearView(); // Clears the depth buffer and resets the view I believe
6165 
6166 	if (!skybox && drawsky) // Don't draw the regular sky if there's a skybox
6167 		HWR_DrawSkyBackground(player);
6168 
6169 	//Hurdler: it doesn't work in splitscreen mode
6170 	drawsky = splitscreen;
6171 
6172 	HWR_ClearSprites();
6173 
6174 	drawcount = 0;
6175 
6176 #ifdef NEWCLIP
6177 	if (rendermode == render_opengl)
6178 	{
6179 		angle_t a1 = gld_FrustumAngle(gl_aimingangle);
6180 		gld_clipper_Clear();
6181 		gld_clipper_SafeAddClipRange(viewangle + a1, viewangle - a1);
6182 #ifdef HAVE_SPHEREFRUSTRUM
6183 		gld_FrustrumSetup();
6184 #endif
6185 	}
6186 #else
6187 	HWR_ClearClipSegs();
6188 #endif
6189 
6190 	//04/01/2000: Hurdler: added for T&L
6191 	//                     Actually it only works on Walls and Planes
6192 	HWD.pfnSetTransform(&atransform);
6193 
6194 	// Reset the shader state.
6195 	HWR_SetShaderState();
6196 
6197 	ps_numbspcalls = 0;
6198 	ps_numpolyobjects = 0;
6199 	ps_bsptime = I_GetPreciseTime();
6200 
6201 	validcount++;
6202 
6203 	if (cv_glbatching.value)
6204 		HWR_StartBatching();
6205 
6206 	HWR_RenderBSPNode((INT32)numnodes-1);
6207 
6208 #ifndef NEWCLIP
6209 	// Make a viewangle int so we can render things based on mouselook
6210 	if (player == &players[consoleplayer])
6211 		viewangle = localaiming;
6212 	else if (splitscreen && player == &players[secondarydisplayplayer])
6213 		viewangle = localaiming2;
6214 
6215 	// Handle stuff when you are looking farther up or down.
6216 	if ((gl_aimingangle || cv_fov.value+player->fovadd > 90*FRACUNIT))
6217 	{
6218 		dup_viewangle += ANGLE_90;
6219 		HWR_ClearClipSegs();
6220 		HWR_RenderBSPNode((INT32)numnodes-1); //left
6221 
6222 		dup_viewangle += ANGLE_90;
6223 		if (((INT32)gl_aimingangle > ANGLE_45 || (INT32)gl_aimingangle<-ANGLE_45))
6224 		{
6225 			HWR_ClearClipSegs();
6226 			HWR_RenderBSPNode((INT32)numnodes-1); //back
6227 		}
6228 
6229 		dup_viewangle += ANGLE_90;
6230 		HWR_ClearClipSegs();
6231 		HWR_RenderBSPNode((INT32)numnodes-1); //right
6232 
6233 		dup_viewangle += ANGLE_90;
6234 	}
6235 #endif
6236 
6237 	ps_bsptime = I_GetPreciseTime() - ps_bsptime;
6238 
6239 	if (cv_glbatching.value)
6240 		HWR_RenderBatches();
6241 
6242 	// Check for new console commands.
6243 	NetUpdate();
6244 
6245 #ifdef ALAM_LIGHTING
6246 	//14/11/99: Hurdler: moved here because it doesn't work with
6247 	// subsector, see other comments;
6248 	HWR_ResetLights();
6249 #endif
6250 
6251 	// Draw MD2 and sprites
6252 	ps_numsprites = gl_visspritecount;
6253 	ps_hw_spritesorttime = I_GetPreciseTime();
6254 	HWR_SortVisSprites();
6255 	ps_hw_spritesorttime = I_GetPreciseTime() - ps_hw_spritesorttime;
6256 	ps_hw_spritedrawtime = I_GetPreciseTime();
6257 	HWR_DrawSprites();
6258 	ps_hw_spritedrawtime = I_GetPreciseTime() - ps_hw_spritedrawtime;
6259 
6260 #ifdef NEWCORONAS
6261 	//Hurdler: they must be drawn before translucent planes, what about gl fog?
6262 	HWR_DrawCoronas();
6263 #endif
6264 
6265 	ps_numdrawnodes = 0;
6266 	ps_hw_nodesorttime = 0;
6267 	ps_hw_nodedrawtime = 0;
6268 	if (numplanes || numpolyplanes || numwalls) //Hurdler: render 3D water and transparent walls after everything
6269 	{
6270 		HWR_CreateDrawNodes();
6271 	}
6272 
6273 	HWD.pfnSetTransform(NULL);
6274 	HWD.pfnUnSetShader();
6275 
6276 	HWR_DoPostProcessor(player);
6277 
6278 	// Check for new console commands.
6279 	NetUpdate();
6280 
6281 	// added by Hurdler for correct splitscreen
6282 	// moved here by hurdler so it works with the new near clipping plane
6283 	HWD.pfnGClipRect(0, 0, vid.width, vid.height, NZCLIP_PLANE);
6284 }
6285 
HWR_LoadLevel(void)6286 void HWR_LoadLevel(void)
6287 {
6288 #ifdef ALAM_LIGHTING
6289 	// BP: reset light between levels (we draw preview frame lights on current frame)
6290 	HWR_ResetLights();
6291 #endif
6292 
6293 	HWR_CreatePlanePolygons((INT32)numnodes - 1);
6294 
6295 	// Build the sky dome
6296 	HWR_ClearSkyDome();
6297 	HWR_BuildSkyDome();
6298 
6299 	gl_maploaded = true;
6300 }
6301 
6302 // ==========================================================================
6303 //                                                         3D ENGINE COMMANDS
6304 // ==========================================================================
6305 
6306 static CV_PossibleValue_t glshaders_cons_t[] = {{HWD_SHADEROPTION_OFF, "Off"}, {HWD_SHADEROPTION_ON, "On"}, {HWD_SHADEROPTION_NOCUSTOM, "Ignore custom shaders"}, {0, NULL}};
6307 static CV_PossibleValue_t glmodelinterpolation_cons_t[] = {{0, "Off"}, {1, "Sometimes"}, {2, "Always"}, {0, NULL}};
6308 static CV_PossibleValue_t glfakecontrast_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Smooth"}, {0, NULL}};
6309 static CV_PossibleValue_t glshearing_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Third-person"}, {0, NULL}};
6310 
6311 static void CV_glfiltermode_OnChange(void);
6312 static void CV_glanisotropic_OnChange(void);
6313 
6314 static CV_PossibleValue_t glfiltermode_cons_t[]= {{HWD_SET_TEXTUREFILTER_POINTSAMPLED, "Nearest"},
6315 	{HWD_SET_TEXTUREFILTER_BILINEAR, "Bilinear"}, {HWD_SET_TEXTUREFILTER_TRILINEAR, "Trilinear"},
6316 	{HWD_SET_TEXTUREFILTER_MIXED1, "Linear_Nearest"},
6317 	{HWD_SET_TEXTUREFILTER_MIXED2, "Nearest_Linear"},
6318 	{HWD_SET_TEXTUREFILTER_MIXED3, "Nearest_Mipmap"},
6319 	{0, NULL}};
6320 CV_PossibleValue_t glanisotropicmode_cons_t[] = {{1, "MIN"}, {16, "MAX"}, {0, NULL}};
6321 
6322 consvar_t cv_glshaders = CVAR_INIT ("gr_shaders", "On", CV_SAVE, glshaders_cons_t, NULL);
6323 consvar_t cv_glallowshaders = CVAR_INIT ("gr_allowclientshaders", "On", CV_NETVAR, CV_OnOff, NULL);
6324 consvar_t cv_fovchange = CVAR_INIT ("gr_fovchange", "Off", CV_SAVE, CV_OnOff, NULL);
6325 
6326 #ifdef ALAM_LIGHTING
6327 consvar_t cv_gldynamiclighting = CVAR_INIT ("gr_dynamiclighting", "On", CV_SAVE, CV_OnOff, NULL);
6328 consvar_t cv_glstaticlighting  = CVAR_INIT ("gr_staticlighting", "On", CV_SAVE, CV_OnOff, NULL);
6329 consvar_t cv_glcoronas = CVAR_INIT ("gr_coronas", "On", CV_SAVE, CV_OnOff, NULL);
6330 consvar_t cv_glcoronasize = CVAR_INIT ("gr_coronasize", "1", CV_SAVE|CV_FLOAT, 0, NULL);
6331 #endif
6332 
6333 consvar_t cv_glmodels = CVAR_INIT ("gr_models", "Off", CV_SAVE, CV_OnOff, NULL);
6334 consvar_t cv_glmodelinterpolation = CVAR_INIT ("gr_modelinterpolation", "Sometimes", CV_SAVE, glmodelinterpolation_cons_t, NULL);
6335 consvar_t cv_glmodellighting = CVAR_INIT ("gr_modellighting", "Off", CV_SAVE, CV_OnOff, NULL);
6336 
6337 consvar_t cv_glshearing = CVAR_INIT ("gr_shearing", "Off", CV_SAVE, glshearing_cons_t, NULL);
6338 consvar_t cv_glspritebillboarding = CVAR_INIT ("gr_spritebillboarding", "Off", CV_SAVE, CV_OnOff, NULL);
6339 consvar_t cv_glskydome = CVAR_INIT ("gr_skydome", "On", CV_SAVE, CV_OnOff, NULL);
6340 consvar_t cv_glfakecontrast = CVAR_INIT ("gr_fakecontrast", "Smooth", CV_SAVE, glfakecontrast_cons_t, NULL);
6341 consvar_t cv_glslopecontrast = CVAR_INIT ("gr_slopecontrast", "Off", CV_SAVE, CV_OnOff, NULL);
6342 
6343 consvar_t cv_glfiltermode = CVAR_INIT ("gr_filtermode", "Nearest", CV_SAVE|CV_CALL, glfiltermode_cons_t, CV_glfiltermode_OnChange);
6344 consvar_t cv_glanisotropicmode = CVAR_INIT ("gr_anisotropicmode", "1", CV_CALL, glanisotropicmode_cons_t, CV_glanisotropic_OnChange);
6345 
6346 consvar_t cv_glsolvetjoin = CVAR_INIT ("gr_solvetjoin", "On", 0, CV_OnOff, NULL);
6347 
6348 consvar_t cv_glbatching = CVAR_INIT ("gr_batching", "On", 0, CV_OnOff, NULL);
6349 
CV_glfiltermode_OnChange(void)6350 static void CV_glfiltermode_OnChange(void)
6351 {
6352 	if (rendermode == render_opengl)
6353 		HWD.pfnSetSpecialState(HWD_SET_TEXTUREFILTERMODE, cv_glfiltermode.value);
6354 }
6355 
CV_glanisotropic_OnChange(void)6356 static void CV_glanisotropic_OnChange(void)
6357 {
6358 	if (rendermode == render_opengl)
6359 		HWD.pfnSetSpecialState(HWD_SET_TEXTUREANISOTROPICMODE, cv_glanisotropicmode.value);
6360 }
6361 
6362 //added by Hurdler: console varibale that are saved
HWR_AddCommands(void)6363 void HWR_AddCommands(void)
6364 {
6365 	CV_RegisterVar(&cv_fovchange);
6366 
6367 #ifdef ALAM_LIGHTING
6368 	CV_RegisterVar(&cv_glstaticlighting);
6369 	CV_RegisterVar(&cv_gldynamiclighting);
6370 	CV_RegisterVar(&cv_glcoronasize);
6371 	CV_RegisterVar(&cv_glcoronas);
6372 #endif
6373 
6374 	CV_RegisterVar(&cv_glmodellighting);
6375 	CV_RegisterVar(&cv_glmodelinterpolation);
6376 	CV_RegisterVar(&cv_glmodels);
6377 
6378 	CV_RegisterVar(&cv_glskydome);
6379 	CV_RegisterVar(&cv_glspritebillboarding);
6380 	CV_RegisterVar(&cv_glfakecontrast);
6381 	CV_RegisterVar(&cv_glshearing);
6382 	CV_RegisterVar(&cv_glshaders);
6383 	CV_RegisterVar(&cv_glallowshaders);
6384 
6385 	CV_RegisterVar(&cv_glfiltermode);
6386 	CV_RegisterVar(&cv_glsolvetjoin);
6387 
6388 	CV_RegisterVar(&cv_glbatching);
6389 
6390 #ifndef NEWCLIP
6391 	CV_RegisterVar(&cv_glclipwalls);
6392 #endif
6393 }
6394 
HWR_AddSessionCommands(void)6395 void HWR_AddSessionCommands(void)
6396 {
6397 	if (gl_sessioncommandsadded)
6398 		return;
6399 	CV_RegisterVar(&cv_glanisotropicmode);
6400 	gl_sessioncommandsadded = true;
6401 }
6402 
6403 // --------------------------------------------------------------------------
6404 // Setup the hardware renderer
6405 // --------------------------------------------------------------------------
HWR_Startup(void)6406 void HWR_Startup(void)
6407 {
6408 	if (!gl_init)
6409 	{
6410 		CONS_Printf("HWR_Startup()...\n");
6411 
6412 		HWR_InitPolyPool();
6413 		HWR_AddSessionCommands();
6414 		HWR_InitMapTextures();
6415 		HWR_InitModels();
6416 #ifdef ALAM_LIGHTING
6417 		HWR_InitLight();
6418 #endif
6419 
6420 		HWR_LoadAllCustomShaders();
6421 		if (!HWR_CompileShaders())
6422 			gl_shadersavailable = false;
6423 	}
6424 
6425 	if (rendermode == render_opengl)
6426 		textureformat = patchformat = GL_TEXFMT_RGBA;
6427 
6428 	gl_init = true;
6429 }
6430 
6431 // --------------------------------------------------------------------------
6432 // Called after switching to the hardware renderer
6433 // --------------------------------------------------------------------------
HWR_Switch(void)6434 void HWR_Switch(void)
6435 {
6436 	// Add session commands
6437 	if (!gl_sessioncommandsadded)
6438 		HWR_AddSessionCommands();
6439 
6440 	// Set special states from CVARs
6441 	HWD.pfnSetSpecialState(HWD_SET_TEXTUREFILTERMODE, cv_glfiltermode.value);
6442 	HWD.pfnSetSpecialState(HWD_SET_TEXTUREANISOTROPICMODE, cv_glanisotropicmode.value);
6443 
6444 	// Load textures
6445 	if (!gl_maptexturesloaded)
6446 		HWR_LoadMapTextures(numtextures);
6447 
6448 	// Create plane polygons
6449 	if (!gl_maploaded && (gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction)))
6450 	{
6451 		HWR_ClearAllTextures();
6452 		HWR_LoadLevel();
6453 	}
6454 }
6455 
6456 // --------------------------------------------------------------------------
6457 // Free resources allocated by the hardware renderer
6458 // --------------------------------------------------------------------------
HWR_Shutdown(void)6459 void HWR_Shutdown(void)
6460 {
6461 	CONS_Printf("HWR_Shutdown()\n");
6462 	HWR_FreeExtraSubsectors();
6463 	HWR_FreePolyPool();
6464 	HWR_FreeMapTextures();
6465 	HWD.pfnFlushScreenTextures();
6466 }
6467 
transform(float * cx,float * cy,float * cz)6468 void transform(float *cx, float *cy, float *cz)
6469 {
6470 	float tr_x,tr_y;
6471 	// translation
6472 	tr_x = *cx - gl_viewx;
6473 	tr_y = *cz - gl_viewy;
6474 //	*cy = *cy;
6475 
6476 	// rotation around vertical y axis
6477 	*cx = (tr_x * gl_viewsin) - (tr_y * gl_viewcos);
6478 	tr_x = (tr_x * gl_viewcos) + (tr_y * gl_viewsin);
6479 
6480 	//look up/down ----TOTAL SUCKS!!!--- do the 2 in one!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
6481 	tr_y = *cy - gl_viewz;
6482 
6483 	*cy = (tr_x * gl_viewludcos) + (tr_y * gl_viewludsin);
6484 	*cz = (tr_x * gl_viewludsin) - (tr_y * gl_viewludcos);
6485 
6486 	//scale y before frustum so that frustum can be scaled to screen height
6487 	*cy *= ORIGINAL_ASPECT * gl_fovlud;
6488 	*cx *= gl_fovlud;
6489 }
6490 
HWR_AddTransparentWall(FOutVector * wallVerts,FSurfaceInfo * pSurf,INT32 texnum,FBITFIELD blend,boolean fogwall,INT32 lightlevel,extracolormap_t * wallcolormap)6491 void HWR_AddTransparentWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, INT32 texnum, FBITFIELD blend, boolean fogwall, INT32 lightlevel, extracolormap_t *wallcolormap)
6492 {
6493 	static size_t allocedwalls = 0;
6494 
6495 	// Force realloc if buffer has been freed
6496 	if (!wallinfo)
6497 		allocedwalls = 0;
6498 
6499 	if (allocedwalls < numwalls + 1)
6500 	{
6501 		allocedwalls += MAX_TRANSPARENTWALL;
6502 		Z_Realloc(wallinfo, allocedwalls * sizeof (*wallinfo), PU_LEVEL, &wallinfo);
6503 	}
6504 
6505 	M_Memcpy(wallinfo[numwalls].wallVerts, wallVerts, sizeof (wallinfo[numwalls].wallVerts));
6506 	M_Memcpy(&wallinfo[numwalls].Surf, pSurf, sizeof (FSurfaceInfo));
6507 	wallinfo[numwalls].texnum = texnum;
6508 	wallinfo[numwalls].blend = blend;
6509 	wallinfo[numwalls].drawcount = drawcount++;
6510 	wallinfo[numwalls].fogwall = fogwall;
6511 	wallinfo[numwalls].lightlevel = lightlevel;
6512 	wallinfo[numwalls].wallcolormap = wallcolormap;
6513 	numwalls++;
6514 }
6515 
HWR_RenderWall(FOutVector * wallVerts,FSurfaceInfo * pSurf,FBITFIELD blend,boolean fogwall,INT32 lightlevel,extracolormap_t * wallcolormap)6516 void HWR_RenderWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend, boolean fogwall, INT32 lightlevel, extracolormap_t *wallcolormap)
6517 {
6518 	FBITFIELD blendmode = blend;
6519 	UINT8 alpha = pSurf->PolyColor.s.alpha; // retain the alpha
6520 
6521 	INT32 shader = SHADER_DEFAULT;
6522 
6523 	// Lighting is done here instead so that fog isn't drawn incorrectly on transparent walls after sorting
6524 	HWR_Lighting(pSurf, lightlevel, wallcolormap);
6525 
6526 	pSurf->PolyColor.s.alpha = alpha; // put the alpha back after lighting
6527 
6528 	if (blend & PF_Environment)
6529 		blendmode |= PF_Occlude;	// PF_Occlude must be used for solid objects
6530 
6531 	if (HWR_UseShader())
6532 	{
6533 		if (fogwall)
6534 			shader = SHADER_FOG;
6535 		else
6536 			shader = SHADER_WALL;
6537 
6538 		blendmode |= PF_ColorMapped;
6539 	}
6540 
6541 	if (fogwall)
6542 		blendmode |= PF_Fog;
6543 
6544 	blendmode |= PF_Modulated;	// No PF_Occlude means overlapping (incorrect) transparency
6545 	HWR_ProcessPolygon(pSurf, wallVerts, 4, blendmode, shader, false);
6546 }
6547 
HWR_GetTextureUsed(void)6548 INT32 HWR_GetTextureUsed(void)
6549 {
6550 	return HWD.pfnGetTextureUsed();
6551 }
6552 
HWR_DoPostProcessor(player_t * player)6553 void HWR_DoPostProcessor(player_t *player)
6554 {
6555 	postimg_t *type;
6556 
6557 	HWD.pfnUnSetShader();
6558 
6559 	if (splitscreen && player == &players[secondarydisplayplayer])
6560 		type = &postimgtype2;
6561 	else
6562 		type = &postimgtype;
6563 
6564 	// Armageddon Blast Flash!
6565 	// Could this even be considered postprocessor?
6566 	if (player->flashcount)
6567 	{
6568 		FOutVector      v[4];
6569 		FSurfaceInfo Surf;
6570 
6571 		v[0].x = v[2].y = v[3].x = v[3].y = -4.0f;
6572 		v[0].y = v[1].x = v[1].y = v[2].x = 4.0f;
6573 		v[0].z = v[1].z = v[2].z = v[3].z = 4.0f; // 4.0 because of the same reason as with the sky, just after the screen is cleared so near clipping plane is 3.99
6574 
6575 		// This won't change if the flash palettes are changed unfortunately, but it works for its purpose
6576 		if (player->flashpal == PAL_NUKE)
6577 		{
6578 			Surf.PolyColor.s.red = 0xff;
6579 			Surf.PolyColor.s.green = Surf.PolyColor.s.blue = 0x7F; // The nuke palette is kind of pink-ish
6580 		}
6581 		else
6582 			Surf.PolyColor.s.red = Surf.PolyColor.s.green = Surf.PolyColor.s.blue = 0xff;
6583 
6584 		Surf.PolyColor.s.alpha = 0xc0; // match software mode
6585 
6586 		HWD.pfnDrawPolygon(&Surf, v, 4, PF_Modulated|PF_Additive|PF_NoTexture|PF_NoDepthTest);
6587 	}
6588 
6589 	// Capture the screen for intermission and screen waving
6590 	if(gamestate != GS_INTERMISSION)
6591 		HWD.pfnMakeScreenTexture();
6592 
6593 	if (splitscreen) // Not supported in splitscreen - someone want to add support?
6594 		return;
6595 
6596 	// Drunken vision! WooOOooo~
6597 	if (*type == postimg_water || *type == postimg_heat)
6598 	{
6599 		// 10 by 10 grid. 2 coordinates (xy)
6600 		float v[SCREENVERTS][SCREENVERTS][2];
6601 		static double disStart = 0;
6602 		UINT8 x, y;
6603 		INT32 WAVELENGTH;
6604 		INT32 AMPLITUDE;
6605 		INT32 FREQUENCY;
6606 
6607 		// Modifies the wave.
6608 		if (*type == postimg_water)
6609 		{
6610 			WAVELENGTH = 20; // Lower is longer
6611 			AMPLITUDE = 20; // Lower is bigger
6612 			FREQUENCY = 16; // Lower is faster
6613 		}
6614 		else
6615 		{
6616 			WAVELENGTH = 10; // Lower is longer
6617 			AMPLITUDE = 30; // Lower is bigger
6618 			FREQUENCY = 4; // Lower is faster
6619 		}
6620 
6621 		for (x = 0; x < SCREENVERTS; x++)
6622 		{
6623 			for (y = 0; y < SCREENVERTS; y++)
6624 			{
6625 				// Change X position based on its Y position.
6626 				v[x][y][0] = (x/((float)(SCREENVERTS-1.0f)/9.0f))-4.5f + (float)sin((disStart+(y*WAVELENGTH))/FREQUENCY)/AMPLITUDE;
6627 				v[x][y][1] = (y/((float)(SCREENVERTS-1.0f)/9.0f))-4.5f;
6628 			}
6629 		}
6630 		HWD.pfnPostImgRedraw(v);
6631 		if (!(paused || P_AutoPause()))
6632 			disStart += 1;
6633 
6634 		// Capture the screen again for screen waving on the intermission
6635 		if(gamestate != GS_INTERMISSION)
6636 			HWD.pfnMakeScreenTexture();
6637 	}
6638 	// Flipping of the screen isn't done here anymore
6639 }
6640 
HWR_StartScreenWipe(void)6641 void HWR_StartScreenWipe(void)
6642 {
6643 	//CONS_Debug(DBG_RENDER, "In HWR_StartScreenWipe()\n");
6644 	HWD.pfnStartScreenWipe();
6645 }
6646 
HWR_EndScreenWipe(void)6647 void HWR_EndScreenWipe(void)
6648 {
6649 	//CONS_Debug(DBG_RENDER, "In HWR_EndScreenWipe()\n");
6650 	HWD.pfnEndScreenWipe();
6651 }
6652 
HWR_DrawIntermissionBG(void)6653 void HWR_DrawIntermissionBG(void)
6654 {
6655 	HWD.pfnDrawIntermissionBG();
6656 }
6657 
6658 //
6659 // hwr mode wipes
6660 //
6661 static lumpnum_t wipelumpnum;
6662 
6663 // puts wipe lumpname in wipename[9]
HWR_WipeCheck(UINT8 wipenum,UINT8 scrnnum)6664 static boolean HWR_WipeCheck(UINT8 wipenum, UINT8 scrnnum)
6665 {
6666 	static char lumpname[9] = "FADEmmss";
6667 	size_t lsize;
6668 
6669 	// not a valid wipe number
6670 	if (wipenum > 99 || scrnnum > 99)
6671 		return false; // shouldn't end up here really, the loop should've stopped running beforehand
6672 
6673 	// puts the numbers into the wipename
6674 	lumpname[4] = '0'+(wipenum/10);
6675 	lumpname[5] = '0'+(wipenum%10);
6676 	lumpname[6] = '0'+(scrnnum/10);
6677 	lumpname[7] = '0'+(scrnnum%10);
6678 	wipelumpnum = W_CheckNumForName(lumpname);
6679 
6680 	// again, shouldn't be here really
6681 	if (wipelumpnum == LUMPERROR)
6682 		return false;
6683 
6684 	lsize = W_LumpLength(wipelumpnum);
6685 	if (!(lsize == 256000 || lsize == 64000 || lsize == 16000 || lsize == 4000))
6686 	{
6687 		CONS_Alert(CONS_WARNING, "Fade mask lump %s of incorrect size, ignored\n", lumpname);
6688 		return false; // again, shouldn't get here if it is a bad size
6689 	}
6690 
6691 	return true;
6692 }
6693 
HWR_DoWipe(UINT8 wipenum,UINT8 scrnnum)6694 void HWR_DoWipe(UINT8 wipenum, UINT8 scrnnum)
6695 {
6696 	if (!HWR_WipeCheck(wipenum, scrnnum))
6697 		return;
6698 
6699 	HWR_GetFadeMask(wipelumpnum);
6700 	HWD.pfnDoScreenWipe();
6701 }
6702 
HWR_DoTintedWipe(UINT8 wipenum,UINT8 scrnnum)6703 void HWR_DoTintedWipe(UINT8 wipenum, UINT8 scrnnum)
6704 {
6705 	// It does the same thing
6706 	HWR_DoWipe(wipenum, scrnnum);
6707 }
6708 
HWR_MakeScreenFinalTexture(void)6709 void HWR_MakeScreenFinalTexture(void)
6710 {
6711     HWD.pfnMakeScreenFinalTexture();
6712 }
6713 
HWR_DrawScreenFinalTexture(int width,int height)6714 void HWR_DrawScreenFinalTexture(int width, int height)
6715 {
6716     HWD.pfnDrawScreenFinalTexture(width, height);
6717 }
6718 
HWR_FindShaderDefs(UINT16 wadnum)6719 static inline UINT16 HWR_FindShaderDefs(UINT16 wadnum)
6720 {
6721 	UINT16 i;
6722 	lumpinfo_t *lump_p;
6723 
6724 	lump_p = wadfiles[wadnum]->lumpinfo;
6725 	for (i = 0; i < wadfiles[wadnum]->numlumps; i++, lump_p++)
6726 		if (memcmp(lump_p->name, "SHADERS", 7) == 0)
6727 			return i;
6728 
6729 	return INT16_MAX;
6730 }
6731 
HWR_CompileShaders(void)6732 boolean HWR_CompileShaders(void)
6733 {
6734 	return HWD.pfnCompileShaders();
6735 }
6736 
6737 customshaderxlat_t shaderxlat[] =
6738 {
6739 	{"Flat", SHADER_FLOOR},
6740 	{"WallTexture", SHADER_WALL},
6741 	{"Sprite", SHADER_SPRITE},
6742 	{"Model", SHADER_MODEL},
6743 	{"ModelLighting", SHADER_MODEL_LIGHTING},
6744 	{"WaterRipple", SHADER_WATER},
6745 	{"Fog", SHADER_FOG},
6746 	{"Sky", SHADER_SKY},
6747 	{NULL, 0},
6748 };
6749 
HWR_LoadAllCustomShaders(void)6750 void HWR_LoadAllCustomShaders(void)
6751 {
6752 	INT32 i;
6753 
6754 	// read every custom shader
6755 	for (i = 0; i < numwadfiles; i++)
6756 		HWR_LoadCustomShadersFromFile(i, (wadfiles[i]->type == RET_PK3));
6757 }
6758 
HWR_LoadCustomShadersFromFile(UINT16 wadnum,boolean PK3)6759 void HWR_LoadCustomShadersFromFile(UINT16 wadnum, boolean PK3)
6760 {
6761 	UINT16 lump;
6762 	char *shaderdef, *line;
6763 	char *stoken;
6764 	char *value;
6765 	size_t size;
6766 	int linenum = 1;
6767 	int shadertype = 0;
6768 	int i;
6769 
6770 	lump = HWR_FindShaderDefs(wadnum);
6771 	if (lump == INT16_MAX)
6772 		return;
6773 
6774 	shaderdef = W_CacheLumpNumPwad(wadnum, lump, PU_CACHE);
6775 	size = W_LumpLengthPwad(wadnum, lump);
6776 
6777 	line = Z_Malloc(size+1, PU_STATIC, NULL);
6778 	M_Memcpy(line, shaderdef, size);
6779 	line[size] = '\0';
6780 
6781 	stoken = strtok(line, "\r\n ");
6782 	while (stoken)
6783 	{
6784 		if ((stoken[0] == '/' && stoken[1] == '/')
6785 			|| (stoken[0] == '#'))// skip comments
6786 		{
6787 			stoken = strtok(NULL, "\r\n");
6788 			goto skip_field;
6789 		}
6790 
6791 		if (!stricmp(stoken, "GLSL"))
6792 		{
6793 			value = strtok(NULL, "\r\n ");
6794 			if (!value)
6795 			{
6796 				CONS_Alert(CONS_WARNING, "HWR_LoadCustomShadersFromFile: Missing shader type (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum);
6797 				stoken = strtok(NULL, "\r\n"); // skip end of line
6798 				goto skip_lump;
6799 			}
6800 
6801 			if (!stricmp(value, "VERTEX"))
6802 				shadertype = 1;
6803 			else if (!stricmp(value, "FRAGMENT"))
6804 				shadertype = 2;
6805 
6806 skip_lump:
6807 			stoken = strtok(NULL, "\r\n ");
6808 			linenum++;
6809 		}
6810 		else
6811 		{
6812 			value = strtok(NULL, "\r\n= ");
6813 			if (!value)
6814 			{
6815 				CONS_Alert(CONS_WARNING, "HWR_LoadCustomShadersFromFile: Missing shader target (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum);
6816 				stoken = strtok(NULL, "\r\n"); // skip end of line
6817 				goto skip_field;
6818 			}
6819 
6820 			if (!shadertype)
6821 			{
6822 				CONS_Alert(CONS_ERROR, "HWR_LoadCustomShadersFromFile: Missing shader type (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum);
6823 				Z_Free(line);
6824 				return;
6825 			}
6826 
6827 			for (i = 0; shaderxlat[i].type; i++)
6828 			{
6829 				if (!stricmp(shaderxlat[i].type, stoken))
6830 				{
6831 					size_t shader_size;
6832 					char *shader_source;
6833 					char *shader_lumpname;
6834 					UINT16 shader_lumpnum;
6835 
6836 					if (PK3)
6837 					{
6838 						shader_lumpname = Z_Malloc(strlen(value) + 12, PU_STATIC, NULL);
6839 						strcpy(shader_lumpname, "Shaders/sh_");
6840 						strcat(shader_lumpname, value);
6841 						shader_lumpnum = W_CheckNumForFullNamePK3(shader_lumpname, wadnum, 0);
6842 					}
6843 					else
6844 					{
6845 						shader_lumpname = Z_Malloc(strlen(value) + 4, PU_STATIC, NULL);
6846 						strcpy(shader_lumpname, "SH_");
6847 						strcat(shader_lumpname, value);
6848 						shader_lumpnum = W_CheckNumForNamePwad(shader_lumpname, wadnum, 0);
6849 					}
6850 
6851 					if (shader_lumpnum == INT16_MAX)
6852 					{
6853 						CONS_Alert(CONS_ERROR, "HWR_LoadCustomShadersFromFile: Missing shader source %s (file %s, line %d)\n", shader_lumpname, wadfiles[wadnum]->filename, linenum);
6854 						Z_Free(shader_lumpname);
6855 						continue;
6856 					}
6857 
6858 					shader_size = W_LumpLengthPwad(wadnum, shader_lumpnum);
6859 					shader_source = Z_Malloc(shader_size, PU_STATIC, NULL);
6860 					W_ReadLumpPwad(wadnum, shader_lumpnum, shader_source);
6861 
6862 					HWD.pfnLoadCustomShader(shaderxlat[i].id, shader_source, shader_size, (shadertype == 2));
6863 
6864 					Z_Free(shader_source);
6865 					Z_Free(shader_lumpname);
6866 				}
6867 			}
6868 
6869 skip_field:
6870 			stoken = strtok(NULL, "\r\n= ");
6871 			linenum++;
6872 		}
6873 	}
6874 
6875 	Z_Free(line);
6876 	return;
6877 }
6878 
HWR_GetShaderName(INT32 shader)6879 const char *HWR_GetShaderName(INT32 shader)
6880 {
6881 	INT32 i;
6882 
6883 	if (shader)
6884 	{
6885 		for (i = 0; shaderxlat[i].type; i++)
6886 		{
6887 			if (shaderxlat[i].id == shader)
6888 				return shaderxlat[i].type;
6889 		}
6890 
6891 		return "Unknown";
6892 	}
6893 
6894 	return "Default";
6895 }
6896 
6897 #endif // HWRENDER
6898