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 = §ors[gl_linedef->frontsector->heightsec];
1291 else
1292 front = gl_linedef->frontsector;
1293
1294 if (gl_linedef->backsector->heightsec != -1)
1295 back = §ors[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(§or->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