mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Fake contrast for the segs are calculated at map load. OpenGL only has the options "Standard" and "Smooth" now. Standard is default and replicates software. Smooth changes the contrast more smoothly depending on angle.
5125 lines
156 KiB
C
5125 lines
156 KiB
C
// SONIC ROBO BLAST 2
|
||
//-----------------------------------------------------------------------------
|
||
// Copyright (C) 1993-1996 by id Software, Inc.
|
||
// Copyright (C) 1998-2000 by DooM Legacy Team.
|
||
// Copyright (C) 1999-2019 by Sonic Team Junior.
|
||
//
|
||
// This program is free software distributed under the
|
||
// terms of the GNU General Public License, version 2.
|
||
// See the 'LICENSE' file for more details.
|
||
//-----------------------------------------------------------------------------
|
||
/// \file
|
||
/// \brief hardware renderer, using the standard HardWareRender driver DLL for SRB2
|
||
|
||
#include <math.h>
|
||
|
||
#include "../doomstat.h"
|
||
|
||
#ifdef HWRENDER
|
||
#include "hw_main.h"
|
||
#include "hw_glob.h"
|
||
#include "hw_drv.h"
|
||
#include "hw_md2.h"
|
||
#include "hw_clip.h"
|
||
#include "hw_light.h"
|
||
|
||
#include "../i_video.h" // for rendermode == render_glide
|
||
#include "../v_video.h"
|
||
#include "../p_local.h"
|
||
#include "../p_setup.h"
|
||
#include "../r_local.h"
|
||
#include "../r_bsp.h" // R_NoEncore
|
||
#include "../r_main.h" // cv_fov
|
||
#include "../d_clisrv.h"
|
||
#include "../w_wad.h"
|
||
#include "../z_zone.h"
|
||
#include "../r_splats.h"
|
||
#include "../g_game.h"
|
||
#include "../st_stuff.h"
|
||
#include "../i_system.h"
|
||
#include "../m_cheat.h"
|
||
#include "../r_things.h" // R_GetShadowZ
|
||
|
||
#ifdef ESLOPE
|
||
#include "../p_slopes.h"
|
||
#endif
|
||
|
||
#include <stdlib.h> // qsort
|
||
|
||
#define ABS(x) ((x) < 0 ? -(x) : (x))
|
||
|
||
// ==========================================================================
|
||
// the hardware driver object
|
||
// ==========================================================================
|
||
struct hwdriver_s hwdriver;
|
||
|
||
// ==========================================================================
|
||
// Commands and console variables
|
||
// ==========================================================================
|
||
|
||
static void CV_filtermode_ONChange(void);
|
||
static void CV_anisotropic_ONChange(void);
|
||
|
||
static CV_PossibleValue_t grfiltermode_cons_t[]= {{HWD_SET_TEXTUREFILTER_POINTSAMPLED, "Nearest"},
|
||
{HWD_SET_TEXTUREFILTER_BILINEAR, "Bilinear"}, {HWD_SET_TEXTUREFILTER_TRILINEAR, "Trilinear"},
|
||
{HWD_SET_TEXTUREFILTER_MIXED1, "Linear_Nearest"},
|
||
{HWD_SET_TEXTUREFILTER_MIXED2, "Nearest_Linear"},
|
||
{HWD_SET_TEXTUREFILTER_MIXED3, "Nearest_Mipmap"},
|
||
{0, NULL}};
|
||
CV_PossibleValue_t granisotropicmode_cons_t[] = {{1, "MIN"}, {16, "MAX"}, {0, NULL}};
|
||
|
||
consvar_t cv_grrounddown = {"gr_rounddown", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||
|
||
|
||
consvar_t cv_grfiltermode = {"gr_filtermode", "Nearest", CV_CALL|CV_SAVE, grfiltermode_cons_t,
|
||
CV_filtermode_ONChange, 0, NULL, NULL, 0, 0, NULL};
|
||
consvar_t cv_granisotropicmode = {"gr_anisotropicmode", "1", CV_CALL|CV_SAVE, granisotropicmode_cons_t,
|
||
CV_anisotropic_ONChange, 0, NULL, NULL, 0, 0, NULL};
|
||
consvar_t cv_grcorrecttricks = {"gr_correcttricks", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||
consvar_t cv_grsolvetjoin = {"gr_solvetjoin", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||
|
||
consvar_t cv_grbatching = {"gr_batching", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||
|
||
static void CV_filtermode_ONChange(void)
|
||
{
|
||
HWD.pfnSetSpecialState(HWD_SET_TEXTUREFILTERMODE, cv_grfiltermode.value);
|
||
}
|
||
|
||
static void CV_anisotropic_ONChange(void)
|
||
{
|
||
HWD.pfnSetSpecialState(HWD_SET_TEXTUREANISOTROPICMODE, cv_granisotropicmode.value);
|
||
}
|
||
|
||
// ==========================================================================
|
||
// Globals
|
||
// ==========================================================================
|
||
|
||
// base values set at SetViewSize
|
||
static float gr_basecentery;
|
||
static float gr_basecenterx;
|
||
|
||
float gr_baseviewwindowy, gr_basewindowcentery;
|
||
float gr_baseviewwindowx, gr_basewindowcenterx;
|
||
float gr_viewwidth, gr_viewheight; // viewport clipping boundaries (screen coords)
|
||
|
||
static float gr_centerx;
|
||
static float gr_viewwindowx;
|
||
static float gr_windowcenterx; // center of view window, for projection
|
||
|
||
static float gr_centery;
|
||
static float gr_viewwindowy; // top left corner of view window
|
||
static float gr_windowcentery;
|
||
|
||
static float gr_pspritexscale, gr_pspriteyscale;
|
||
|
||
|
||
static seg_t *gr_curline;
|
||
static side_t *gr_sidedef;
|
||
static line_t *gr_linedef;
|
||
static sector_t *gr_frontsector;
|
||
static sector_t *gr_backsector;
|
||
|
||
boolean gr_shadersavailable = true;
|
||
|
||
// ==========================================================================
|
||
// View position
|
||
// ==========================================================================
|
||
|
||
FTransform atransform;
|
||
|
||
// Float variants of viewx, viewy, viewz, etc.
|
||
static float gr_viewx, gr_viewy, gr_viewz;
|
||
static float gr_viewsin, gr_viewcos;
|
||
|
||
static angle_t gr_aimingangle;
|
||
static float gr_viewludsin, gr_viewludcos;
|
||
|
||
static INT32 drawcount = 0;
|
||
|
||
// ==========================================================================
|
||
// Lighting
|
||
// ==========================================================================
|
||
|
||
void HWR_Lighting(FSurfaceInfo *Surface, INT32 light_level, extracolormap_t *colormap)
|
||
{
|
||
RGBA_t poly_color, tint_color, fade_color;
|
||
|
||
poly_color.rgba = 0xFFFFFFFF;
|
||
tint_color.rgba = (colormap != NULL) ? (UINT32)colormap->rgba : GL_DEFAULTMIX;
|
||
fade_color.rgba = (colormap != NULL) ? (UINT32)colormap->fadergba : GL_DEFAULTFOG;
|
||
|
||
// Crappy backup coloring if you can't do shaders
|
||
if (!(cv_grshaders.value && gr_shadersavailable))
|
||
{
|
||
// be careful, this may get negative for high lightlevel values.
|
||
float tint_alpha, fade_alpha;
|
||
float red, green, blue;
|
||
|
||
red = (float)poly_color.s.red;
|
||
green = (float)poly_color.s.green;
|
||
blue = (float)poly_color.s.blue;
|
||
|
||
// 48 is just an arbritrary value that looked relatively okay.
|
||
tint_alpha = (float)(sqrt(tint_color.s.alpha) * 48) / 255.0f;
|
||
|
||
// 8 is roughly the brightness of the "close" color in Software, and 16 the brightness of the "far" color.
|
||
// 8 is too bright for dark levels, and 16 is too dark for bright levels.
|
||
// 12 is the compromise value. It doesn't look especially good anywhere, but it's the most balanced.
|
||
// (Also, as far as I can tell, fade_color's alpha is actually not used in Software, so we only use light level.)
|
||
fade_alpha = (float)(sqrt(255-light_level) * 12) / 255.0f;
|
||
|
||
// Clamp the alpha values
|
||
tint_alpha = min(max(tint_alpha, 0.0f), 1.0f);
|
||
fade_alpha = min(max(fade_alpha, 0.0f), 1.0f);
|
||
|
||
red = (tint_color.s.red * tint_alpha) + (red * (1.0f - tint_alpha));
|
||
green = (tint_color.s.green * tint_alpha) + (green * (1.0f - tint_alpha));
|
||
blue = (tint_color.s.blue * tint_alpha) + (blue * (1.0f - tint_alpha));
|
||
|
||
red = (fade_color.s.red * fade_alpha) + (red * (1.0f - fade_alpha));
|
||
green = (fade_color.s.green * fade_alpha) + (green * (1.0f - fade_alpha));
|
||
blue = (fade_color.s.blue * fade_alpha) + (blue * (1.0f - fade_alpha));
|
||
|
||
poly_color.s.red = (UINT8)red;
|
||
poly_color.s.green = (UINT8)green;
|
||
poly_color.s.blue = (UINT8)blue;
|
||
}
|
||
|
||
Surface->PolyColor.rgba = poly_color.rgba;
|
||
Surface->TintColor.rgba = tint_color.rgba;
|
||
Surface->FadeColor.rgba = fade_color.rgba;
|
||
Surface->LightInfo.light_level = light_level;
|
||
Surface->LightInfo.fade_start = (colormap != NULL) ? colormap->fadestart : 0;
|
||
Surface->LightInfo.fade_end = (colormap != NULL) ? colormap->fadeend : 31;
|
||
}
|
||
|
||
UINT8 HWR_FogBlockAlpha(INT32 light, extracolormap_t *colormap) // Let's see if this can work
|
||
{
|
||
RGBA_t realcolor, surfcolor;
|
||
INT32 alpha;
|
||
|
||
realcolor.rgba = (colormap != NULL) ? colormap->rgba : GL_DEFAULTMIX;
|
||
|
||
if (!(cv_grshaders.value && gr_shadersavailable))
|
||
{
|
||
light = light - (255 - light);
|
||
|
||
// Don't go out of bounds
|
||
if (light < 0)
|
||
light = 0;
|
||
else if (light > 255)
|
||
light = 255;
|
||
|
||
alpha = (realcolor.s.alpha*255)/25;
|
||
|
||
// at 255 brightness, alpha is between 0 and 127, at 0 brightness alpha will always be 255
|
||
surfcolor.s.alpha = (alpha*light) / (2*256) + 255-light;
|
||
}
|
||
else
|
||
{
|
||
surfcolor.s.alpha = (255 - light);
|
||
}
|
||
|
||
return surfcolor.s.alpha;
|
||
}
|
||
|
||
// Lightnum = current light
|
||
// line = the seg to get the light offset from
|
||
static FUINT HWR_CalcWallLight(seg_t *line, FUINT lightnum)
|
||
{
|
||
INT16 finallight = lightnum;
|
||
|
||
fixed_t extralight = 0;
|
||
|
||
if (cv_grfakecontrast.value == 1) // Smooth setting
|
||
extralight += line->hwLightOffset;
|
||
else
|
||
extralight += line->lightOffset * 8;
|
||
|
||
if (extralight != 0)
|
||
{
|
||
finallight += extralight;
|
||
|
||
if (finallight < 0)
|
||
finallight = 0;
|
||
if (finallight > 255)
|
||
finallight = 255;
|
||
}
|
||
|
||
return (FUINT)finallight;
|
||
}
|
||
|
||
// ==========================================================================
|
||
// Floor and ceiling generation from subsectors
|
||
// ==========================================================================
|
||
|
||
// HWR_RenderPlane
|
||
// Render a floor or ceiling convex polygon
|
||
void HWR_RenderPlane(extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, FBITFIELD PolyFlags, INT32 lightlevel, lumpnum_t lumpnum, sector_t *FOFsector, UINT8 alpha, extracolormap_t *planecolormap)
|
||
{
|
||
polyvertex_t * pv;
|
||
float height; //constant y for all points on the convex flat polygon
|
||
FOutVector *v3d;
|
||
INT32 nrPlaneVerts; //verts original define of convex flat polygon
|
||
INT32 i;
|
||
float flatxref,flatyref;
|
||
float fflatsize;
|
||
INT32 flatflag;
|
||
size_t len;
|
||
float scrollx = 0.0f, scrolly = 0.0f;
|
||
angle_t angle = 0;
|
||
FSurfaceInfo Surf;
|
||
fixed_t tempxsow, tempytow;
|
||
#ifdef ESLOPE
|
||
pslope_t *slope = NULL;
|
||
#endif
|
||
|
||
static FOutVector *planeVerts = NULL;
|
||
static UINT16 numAllocedPlaneVerts = 0;
|
||
|
||
// no convex poly were generated for this subsector
|
||
if (!xsub->planepoly)
|
||
return;
|
||
|
||
#ifdef ESLOPE
|
||
// Get the slope pointer to simplify future code
|
||
if (FOFsector)
|
||
{
|
||
if (FOFsector->f_slope && !isceiling)
|
||
slope = FOFsector->f_slope;
|
||
else if (FOFsector->c_slope && isceiling)
|
||
slope = FOFsector->c_slope;
|
||
}
|
||
else
|
||
{
|
||
if (gr_frontsector->f_slope && !isceiling)
|
||
slope = gr_frontsector->f_slope;
|
||
else if (gr_frontsector->c_slope && isceiling)
|
||
slope = gr_frontsector->c_slope;
|
||
}
|
||
|
||
// Set fixedheight to the slope's height from our viewpoint, if we have a slope
|
||
if (slope)
|
||
fixedheight = P_GetZAt(slope, viewx, viewy);
|
||
#endif
|
||
|
||
height = FIXED_TO_FLOAT(fixedheight);
|
||
|
||
pv = xsub->planepoly->pts;
|
||
nrPlaneVerts = xsub->planepoly->numpts;
|
||
|
||
if (nrPlaneVerts < 3) //not even a triangle ?
|
||
return;
|
||
|
||
if (nrPlaneVerts > INT16_MAX) // FIXME: exceeds plVerts size
|
||
{
|
||
CONS_Debug(DBG_RENDER, "polygon size of %d exceeds max value of %d vertices\n", nrPlaneVerts, UINT16_MAX);
|
||
return;
|
||
}
|
||
|
||
// Allocate plane-vertex buffer if we need to
|
||
if (!planeVerts || nrPlaneVerts > numAllocedPlaneVerts)
|
||
{
|
||
numAllocedPlaneVerts = (UINT16)nrPlaneVerts;
|
||
Z_Free(planeVerts);
|
||
Z_Malloc(numAllocedPlaneVerts * sizeof (FOutVector), PU_LEVEL, &planeVerts);
|
||
}
|
||
|
||
len = W_LumpLength(lumpnum);
|
||
|
||
switch (len)
|
||
{
|
||
case 4194304: // 2048x2048 lump
|
||
fflatsize = 2048.0f;
|
||
flatflag = 2047;
|
||
break;
|
||
case 1048576: // 1024x1024 lump
|
||
fflatsize = 1024.0f;
|
||
flatflag = 1023;
|
||
break;
|
||
case 262144:// 512x512 lump
|
||
fflatsize = 512.0f;
|
||
flatflag = 511;
|
||
break;
|
||
case 65536: // 256x256 lump
|
||
fflatsize = 256.0f;
|
||
flatflag = 255;
|
||
break;
|
||
case 16384: // 128x128 lump
|
||
fflatsize = 128.0f;
|
||
flatflag = 127;
|
||
break;
|
||
case 1024: // 32x32 lump
|
||
fflatsize = 32.0f;
|
||
flatflag = 31;
|
||
break;
|
||
default: // 64x64 lump
|
||
fflatsize = 64.0f;
|
||
flatflag = 63;
|
||
break;
|
||
}
|
||
|
||
// reference point for flat texture coord for each vertex around the polygon
|
||
flatxref = (float)(((fixed_t)pv->x & (~flatflag)) / fflatsize);
|
||
flatyref = (float)(((fixed_t)pv->y & (~flatflag)) / fflatsize);
|
||
|
||
// transform
|
||
v3d = planeVerts;
|
||
|
||
if (FOFsector != NULL)
|
||
{
|
||
if (!isceiling) // it's a floor
|
||
{
|
||
scrollx = FIXED_TO_FLOAT(FOFsector->floor_xoffs)/fflatsize;
|
||
scrolly = FIXED_TO_FLOAT(FOFsector->floor_yoffs)/fflatsize;
|
||
angle = FOFsector->floorpic_angle;
|
||
}
|
||
else // it's a ceiling
|
||
{
|
||
scrollx = FIXED_TO_FLOAT(FOFsector->ceiling_xoffs)/fflatsize;
|
||
scrolly = FIXED_TO_FLOAT(FOFsector->ceiling_yoffs)/fflatsize;
|
||
angle = FOFsector->ceilingpic_angle;
|
||
}
|
||
}
|
||
else if (gr_frontsector)
|
||
{
|
||
if (!isceiling) // it's a floor
|
||
{
|
||
scrollx = FIXED_TO_FLOAT(gr_frontsector->floor_xoffs)/fflatsize;
|
||
scrolly = FIXED_TO_FLOAT(gr_frontsector->floor_yoffs)/fflatsize;
|
||
angle = gr_frontsector->floorpic_angle;
|
||
}
|
||
else // it's a ceiling
|
||
{
|
||
scrollx = FIXED_TO_FLOAT(gr_frontsector->ceiling_xoffs)/fflatsize;
|
||
scrolly = FIXED_TO_FLOAT(gr_frontsector->ceiling_yoffs)/fflatsize;
|
||
angle = gr_frontsector->ceilingpic_angle;
|
||
}
|
||
}
|
||
|
||
|
||
if (angle) // Only needs to be done if there's an altered angle
|
||
{
|
||
|
||
angle = (InvAngle(angle)+ANGLE_180)>>ANGLETOFINESHIFT;
|
||
|
||
// This needs to be done so that it scrolls in a different direction after rotation like software
|
||
/*tempxsow = FLOAT_TO_FIXED(scrollx);
|
||
tempytow = FLOAT_TO_FIXED(scrolly);
|
||
scrollx = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINECOSINE(angle)) - FixedMul(tempytow, FINESINE(angle))));
|
||
scrolly = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINESINE(angle)) + FixedMul(tempytow, FINECOSINE(angle))));*/
|
||
|
||
// This needs to be done so everything aligns after rotation
|
||
// 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
|
||
tempxsow = FLOAT_TO_FIXED(flatxref);
|
||
tempytow = FLOAT_TO_FIXED(flatyref);
|
||
flatxref = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINECOSINE(angle)) - FixedMul(tempytow, FINESINE(angle))));
|
||
flatyref = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINESINE(angle)) + FixedMul(tempytow, FINECOSINE(angle))));
|
||
}
|
||
|
||
|
||
for (i = 0; i < nrPlaneVerts; i++,v3d++,pv++)
|
||
{
|
||
// Hurdler: add scrolling texture on floor/ceiling
|
||
v3d->s = (float)((pv->x / fflatsize) - flatxref + scrollx);
|
||
v3d->t = (float)(flatyref - (pv->y / fflatsize) + scrolly);
|
||
|
||
//v3d->s = (float)(pv->x / fflatsize);
|
||
//v3d->t = (float)(pv->y / fflatsize);
|
||
|
||
// Need to rotate before translate
|
||
if (angle) // Only needs to be done if there's an altered angle
|
||
{
|
||
tempxsow = FLOAT_TO_FIXED(v3d->s);
|
||
tempytow = FLOAT_TO_FIXED(v3d->t);
|
||
v3d->s = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINECOSINE(angle)) - FixedMul(tempytow, FINESINE(angle))));
|
||
v3d->t = (FIXED_TO_FLOAT(-FixedMul(tempxsow, FINESINE(angle)) - FixedMul(tempytow, FINECOSINE(angle))));
|
||
}
|
||
|
||
//v3d->s = (float)(v3d->s - flatxref + scrollx);
|
||
//v3d->t = (float)(flatyref - v3d->t + scrolly);
|
||
|
||
v3d->x = pv->x;
|
||
v3d->y = height;
|
||
v3d->z = pv->y;
|
||
|
||
#ifdef ESLOPE
|
||
if (slope)
|
||
{
|
||
fixedheight = P_GetZAt(slope, FLOAT_TO_FIXED(pv->x), FLOAT_TO_FIXED(pv->y));
|
||
v3d->y = FIXED_TO_FLOAT(fixedheight);
|
||
}
|
||
#endif
|
||
}
|
||
|
||
HWR_Lighting(&Surf, lightlevel, planecolormap);
|
||
|
||
if (PolyFlags & (PF_Translucent|PF_Fog))
|
||
{
|
||
Surf.PolyColor.s.alpha = (UINT8)alpha;
|
||
PolyFlags |= PF_Modulated;
|
||
}
|
||
else
|
||
PolyFlags |= PF_Masked|PF_Modulated;
|
||
|
||
if (PolyFlags & PF_Fog)
|
||
HWD.pfnSetShader(6); // fog shader
|
||
else if (PolyFlags & PF_Ripple)
|
||
HWD.pfnSetShader(5); // water shader
|
||
else
|
||
HWD.pfnSetShader(1); // floor shader
|
||
|
||
HWD.pfnDrawPolygon(&Surf, planeVerts, nrPlaneVerts, PolyFlags);
|
||
}
|
||
|
||
#ifdef WALLSPLATS
|
||
static void HWR_DrawSegsSplats(FSurfaceInfo * pSurf)
|
||
{
|
||
FOutVector wallVerts[4];
|
||
wallsplat_t *splat;
|
||
GLPatch_t *gpatch;
|
||
fixed_t i;
|
||
// seg bbox
|
||
fixed_t segbbox[4];
|
||
|
||
M_ClearBox(segbbox);
|
||
M_AddToBox(segbbox,
|
||
FLOAT_TO_FIXED(((polyvertex_t *)gr_curline->pv1)->x),
|
||
FLOAT_TO_FIXED(((polyvertex_t *)gr_curline->pv1)->y));
|
||
M_AddToBox(segbbox,
|
||
FLOAT_TO_FIXED(((polyvertex_t *)gr_curline->pv2)->x),
|
||
FLOAT_TO_FIXED(((polyvertex_t *)gr_curline->pv2)->y));
|
||
|
||
splat = (wallsplat_t *)gr_curline->linedef->splats;
|
||
for (; splat; splat = splat->next)
|
||
{
|
||
//BP: don't draw splat extern to this seg
|
||
// this is quick fix best is explain in logboris.txt at 12-4-2000
|
||
if (!M_PointInBox(segbbox,splat->v1.x,splat->v1.y) && !M_PointInBox(segbbox,splat->v2.x,splat->v2.y))
|
||
continue;
|
||
|
||
gpatch = W_CachePatchNum(splat->patch, PU_CACHE);
|
||
HWR_GetPatch(gpatch);
|
||
|
||
wallVerts[0].x = wallVerts[3].x = FIXED_TO_FLOAT(splat->v1.x);
|
||
wallVerts[0].z = wallVerts[3].z = FIXED_TO_FLOAT(splat->v1.y);
|
||
wallVerts[2].x = wallVerts[1].x = FIXED_TO_FLOAT(splat->v2.x);
|
||
wallVerts[2].z = wallVerts[1].z = FIXED_TO_FLOAT(splat->v2.y);
|
||
|
||
i = splat->top;
|
||
if (splat->yoffset)
|
||
i += *splat->yoffset;
|
||
|
||
wallVerts[2].y = wallVerts[3].y = FIXED_TO_FLOAT(i)+(gpatch->height>>1);
|
||
wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(i)-(gpatch->height>>1);
|
||
|
||
wallVerts[3].s = wallVerts[3].t = wallVerts[2].s = wallVerts[0].t = 0.0f;
|
||
wallVerts[1].s = wallVerts[1].t = wallVerts[2].t = wallVerts[0].s = 1.0f;
|
||
|
||
switch (splat->flags & SPLATDRAWMODE_MASK)
|
||
{
|
||
case SPLATDRAWMODE_OPAQUE :
|
||
pSurf.PolyColor.s.alpha = 0xff;
|
||
i = PF_Translucent;
|
||
break;
|
||
case SPLATDRAWMODE_TRANS :
|
||
pSurf.PolyColor.s.alpha = 128;
|
||
i = PF_Translucent;
|
||
break;
|
||
case SPLATDRAWMODE_SHADE :
|
||
pSurf.PolyColor.s.alpha = 0xff;
|
||
i = PF_Substractive;
|
||
break;
|
||
}
|
||
|
||
HWD.pfnSetShader(2); // wall shader
|
||
HWD.pfnDrawPolygon(&pSurf, wallVerts, 4, i|PF_Modulated|PF_Decal);
|
||
}
|
||
}
|
||
#endif
|
||
|
||
FBITFIELD HWR_TranstableToAlpha(INT32 transtablenum, FSurfaceInfo *pSurf)
|
||
{
|
||
switch (transtablenum)
|
||
{
|
||
case tr_trans10 : pSurf->PolyColor.s.alpha = 0xe6;return PF_Translucent;
|
||
case tr_trans20 : pSurf->PolyColor.s.alpha = 0xcc;return PF_Translucent;
|
||
case tr_trans30 : pSurf->PolyColor.s.alpha = 0xb3;return PF_Translucent;
|
||
case tr_trans40 : pSurf->PolyColor.s.alpha = 0x99;return PF_Translucent;
|
||
case tr_trans50 : pSurf->PolyColor.s.alpha = 0x80;return PF_Translucent;
|
||
case tr_trans60 : pSurf->PolyColor.s.alpha = 0x66;return PF_Translucent;
|
||
case tr_trans70 : pSurf->PolyColor.s.alpha = 0x4c;return PF_Translucent;
|
||
case tr_trans80 : pSurf->PolyColor.s.alpha = 0x33;return PF_Translucent;
|
||
case tr_trans90 : pSurf->PolyColor.s.alpha = 0x19;return PF_Translucent;
|
||
}
|
||
return PF_Translucent;
|
||
}
|
||
|
||
// ==========================================================================
|
||
// Wall generation from subsector segs
|
||
// ==========================================================================
|
||
|
||
//
|
||
// HWR_ProjectWall
|
||
//
|
||
void HWR_ProjectWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blendmode, INT32 lightlevel, extracolormap_t *wallcolormap)
|
||
{
|
||
HWR_Lighting(pSurf, lightlevel, wallcolormap);
|
||
|
||
HWD.pfnSetShader(2); // wall shader
|
||
HWD.pfnDrawPolygon(pSurf, wallVerts, 4, blendmode|PF_Modulated|PF_Occlude);
|
||
|
||
#ifdef WALLSPLATS
|
||
if (gr_curline->linedef->splats && cv_splats.value)
|
||
HWR_DrawSegsSplats(pSurf);
|
||
#endif
|
||
}
|
||
|
||
//
|
||
// HWR_SplitWall
|
||
//
|
||
void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum, FSurfaceInfo* Surf, INT32 cutflag, ffloor_t *pfloor)
|
||
{
|
||
/* SoM: split up and light walls according to the
|
||
lightlist. This may also include leaving out parts
|
||
of the wall that can't be seen */
|
||
|
||
float realtop, realbot, top, bot;
|
||
float pegt, pegb, pegmul;
|
||
float height = 0.0f, bheight = 0.0f;
|
||
|
||
#ifdef ESLOPE
|
||
float endrealtop, endrealbot, endtop, endbot;
|
||
float endpegt, endpegb, endpegmul;
|
||
float endheight = 0.0f, endbheight = 0.0f;
|
||
|
||
fixed_t v1x = FLOAT_TO_FIXED(wallVerts[0].x);
|
||
fixed_t v1y = FLOAT_TO_FIXED(wallVerts[0].z); // not a typo
|
||
fixed_t v2x = FLOAT_TO_FIXED(wallVerts[1].x);
|
||
fixed_t v2y = FLOAT_TO_FIXED(wallVerts[1].z); // not a typo
|
||
// compiler complains when P_GetZAt is used in FLOAT_TO_FIXED directly
|
||
// use this as a temp var to store P_GetZAt's return value each time
|
||
fixed_t temp;
|
||
#endif
|
||
|
||
INT32 solid, i;
|
||
lightlist_t * list = sector->lightlist;
|
||
const UINT8 alpha = Surf->PolyColor.s.alpha;
|
||
FUINT lightnum = HWR_CalcWallLight(gr_curline, sector->lightlevel);
|
||
extracolormap_t *colormap = NULL;
|
||
|
||
realtop = top = wallVerts[3].y;
|
||
realbot = bot = wallVerts[0].y;
|
||
pegt = wallVerts[3].t;
|
||
pegb = wallVerts[0].t;
|
||
pegmul = (pegb - pegt) / (top - bot);
|
||
|
||
#ifdef ESLOPE
|
||
endrealtop = endtop = wallVerts[2].y;
|
||
endrealbot = endbot = wallVerts[1].y;
|
||
endpegt = wallVerts[2].t;
|
||
endpegb = wallVerts[1].t;
|
||
endpegmul = (endpegb - endpegt) / (endtop - endbot);
|
||
#endif
|
||
|
||
for (i = 0; i < sector->numlights; i++)
|
||
{
|
||
#ifdef ESLOPE
|
||
if (endtop < endrealbot)
|
||
#endif
|
||
if (top < realbot)
|
||
return;
|
||
|
||
if (!(list[i].flags & FF_NOSHADE))
|
||
{
|
||
if (pfloor && (pfloor->flags & FF_FOG))
|
||
{
|
||
lightnum = HWR_CalcWallLight(gr_curline, pfloor->master->frontsector->lightlevel);
|
||
colormap = pfloor->master->frontsector->extra_colormap;
|
||
}
|
||
else
|
||
{
|
||
lightnum = HWR_CalcWallLight(gr_curline, *list[i].lightlevel);
|
||
colormap = list[i].extra_colormap;
|
||
}
|
||
}
|
||
|
||
solid = false;
|
||
|
||
if ((sector->lightlist[i].flags & FF_CUTSOLIDS) && !(cutflag & FF_EXTRA))
|
||
solid = true;
|
||
else if ((sector->lightlist[i].flags & FF_CUTEXTRA) && (cutflag & FF_EXTRA))
|
||
{
|
||
if (sector->lightlist[i].flags & FF_EXTRA)
|
||
{
|
||
if ((sector->lightlist[i].flags & (FF_FOG|FF_SWIMMABLE)) == (cutflag & (FF_FOG|FF_SWIMMABLE))) // Only merge with your own types
|
||
solid = true;
|
||
}
|
||
else
|
||
solid = true;
|
||
}
|
||
else
|
||
solid = false;
|
||
|
||
#ifdef ESLOPE
|
||
if (list[i].slope)
|
||
{
|
||
temp = P_GetZAt(list[i].slope, v1x, v1y);
|
||
height = FIXED_TO_FLOAT(temp);
|
||
temp = P_GetZAt(list[i].slope, v2x, v2y);
|
||
endheight = FIXED_TO_FLOAT(temp);
|
||
}
|
||
else
|
||
height = endheight = FIXED_TO_FLOAT(list[i].height);
|
||
if (solid)
|
||
{
|
||
if (*list[i].caster->b_slope)
|
||
{
|
||
temp = P_GetZAt(*list[i].caster->b_slope, v1x, v1y);
|
||
bheight = FIXED_TO_FLOAT(temp);
|
||
temp = P_GetZAt(*list[i].caster->b_slope, v2x, v2y);
|
||
endbheight = FIXED_TO_FLOAT(temp);
|
||
}
|
||
else
|
||
bheight = endbheight = FIXED_TO_FLOAT(*list[i].caster->bottomheight);
|
||
}
|
||
#else
|
||
height = FIXED_TO_FLOAT(list[i].height);
|
||
if (solid)
|
||
bheight = FIXED_TO_FLOAT(*list[i].caster->bottomheight);
|
||
#endif
|
||
|
||
#ifdef ESLOPE
|
||
if (endheight >= endtop)
|
||
#endif
|
||
if (height >= top)
|
||
{
|
||
if (solid && top > bheight)
|
||
top = bheight;
|
||
#ifdef ESLOPE
|
||
if (solid && endtop > endbheight)
|
||
endtop = endbheight;
|
||
#endif
|
||
}
|
||
|
||
#ifdef ESLOPE
|
||
if (i + 1 < sector->numlights)
|
||
{
|
||
if (list[i+1].slope)
|
||
{
|
||
temp = P_GetZAt(list[i+1].slope, v1x, v1y);
|
||
bheight = FIXED_TO_FLOAT(temp);
|
||
temp = P_GetZAt(list[i+1].slope, v2x, v2y);
|
||
endbheight = FIXED_TO_FLOAT(temp);
|
||
}
|
||
else
|
||
bheight = endbheight = FIXED_TO_FLOAT(list[i+1].height);
|
||
}
|
||
else
|
||
{
|
||
bheight = realbot;
|
||
endbheight = endrealbot;
|
||
}
|
||
#else
|
||
if (i + 1 < sector->numlights)
|
||
{
|
||
bheight = FIXED_TO_FLOAT(list[i+1].height);
|
||
}
|
||
else
|
||
{
|
||
bheight = realbot;
|
||
}
|
||
#endif
|
||
|
||
#ifdef ESLOPE
|
||
if (endbheight >= endtop)
|
||
#endif
|
||
if (bheight >= top)
|
||
continue;
|
||
|
||
//Found a break;
|
||
bot = bheight;
|
||
|
||
if (bot < realbot)
|
||
bot = realbot;
|
||
|
||
#ifdef ESLOPE
|
||
endbot = endbheight;
|
||
|
||
if (endbot < endrealbot)
|
||
endbot = endrealbot;
|
||
#endif
|
||
Surf->PolyColor.s.alpha = alpha;
|
||
|
||
#ifdef ESLOPE
|
||
wallVerts[3].t = pegt + ((realtop - top) * pegmul);
|
||
wallVerts[2].t = endpegt + ((endrealtop - endtop) * endpegmul);
|
||
wallVerts[0].t = pegt + ((realtop - bot) * pegmul);
|
||
wallVerts[1].t = endpegt + ((endrealtop - endbot) * endpegmul);
|
||
|
||
// set top/bottom coords
|
||
wallVerts[3].y = top;
|
||
wallVerts[2].y = endtop;
|
||
wallVerts[0].y = bot;
|
||
wallVerts[1].y = endbot;
|
||
#else
|
||
wallVerts[3].t = wallVerts[2].t = pegt + ((realtop - top) * pegmul);
|
||
wallVerts[0].t = wallVerts[1].t = pegt + ((realtop - bot) * pegmul);
|
||
|
||
// set top/bottom coords
|
||
wallVerts[2].y = wallVerts[3].y = top;
|
||
wallVerts[0].y = wallVerts[1].y = bot;
|
||
#endif
|
||
|
||
if (cutflag & FF_FOG)
|
||
HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Fog|PF_NoTexture, true, lightnum, colormap);
|
||
else if (cutflag & FF_TRANSLUCENT)
|
||
HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Translucent, false, lightnum, colormap);
|
||
else
|
||
HWR_ProjectWall(wallVerts, Surf, PF_Masked, lightnum, colormap);
|
||
|
||
top = bot;
|
||
#ifdef ESLOPE
|
||
endtop = endbot;
|
||
#endif
|
||
}
|
||
|
||
bot = realbot;
|
||
#ifdef ESLOPE
|
||
endbot = endrealbot;
|
||
if (endtop <= endrealbot)
|
||
#endif
|
||
if (top <= realbot)
|
||
return;
|
||
|
||
Surf->PolyColor.s.alpha = alpha;
|
||
|
||
#ifdef ESLOPE
|
||
wallVerts[3].t = pegt + ((realtop - top) * pegmul);
|
||
wallVerts[2].t = endpegt + ((endrealtop - endtop) * endpegmul);
|
||
wallVerts[0].t = pegt + ((realtop - bot) * pegmul);
|
||
wallVerts[1].t = endpegt + ((endrealtop - endbot) * endpegmul);
|
||
|
||
// set top/bottom coords
|
||
wallVerts[3].y = top;
|
||
wallVerts[2].y = endtop;
|
||
wallVerts[0].y = bot;
|
||
wallVerts[1].y = endbot;
|
||
#else
|
||
wallVerts[3].t = wallVerts[2].t = pegt + ((realtop - top) * pegmul);
|
||
wallVerts[0].t = wallVerts[1].t = pegt + ((realtop - bot) * pegmul);
|
||
|
||
// set top/bottom coords
|
||
wallVerts[2].y = wallVerts[3].y = top;
|
||
wallVerts[0].y = wallVerts[1].y = bot;
|
||
#endif
|
||
|
||
if (cutflag & FF_FOG)
|
||
HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Fog|PF_NoTexture, true, lightnum, colormap);
|
||
else if (cutflag & FF_TRANSLUCENT)
|
||
HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Translucent, false, lightnum, colormap);
|
||
else
|
||
HWR_ProjectWall(wallVerts, Surf, PF_Masked, lightnum, colormap);
|
||
}
|
||
|
||
// HWR_DrawSkyWalls
|
||
// Draw walls into the depth buffer so that anything behind is culled properly
|
||
void HWR_DrawSkyWall(FOutVector *wallVerts, FSurfaceInfo *Surf)
|
||
{
|
||
HWD.pfnSetTexture(NULL);
|
||
// no texture
|
||
wallVerts[3].t = wallVerts[2].t = 0;
|
||
wallVerts[0].t = wallVerts[1].t = 0;
|
||
wallVerts[0].s = wallVerts[3].s = 0;
|
||
wallVerts[2].s = wallVerts[1].s = 0;
|
||
|
||
HWR_ProjectWall(wallVerts, Surf, PF_Invisible|PF_NoTexture, 255, NULL);
|
||
// PF_Invisible so it's not drawn into the colour buffer
|
||
// PF_NoTexture for no texture
|
||
// PF_Occlude is set in HWR_ProjectWall to draw into the depth buffer
|
||
}
|
||
|
||
//
|
||
// HWR_ProcessSeg
|
||
// A portion or all of a wall segment will be drawn, from startfrac to endfrac,
|
||
// where 0 is the start of the segment, 1 the end of the segment
|
||
// Anything between means the wall segment has been clipped with solidsegs,
|
||
// reducing wall overdraw to a minimum
|
||
//
|
||
void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
|
||
{
|
||
FOutVector wallVerts[4];
|
||
v2d_t vs, ve; // start, end vertices of 2d line (view from above)
|
||
|
||
fixed_t worldtop, worldbottom;
|
||
fixed_t worldhigh = 0, worldlow = 0;
|
||
#ifdef ESLOPE
|
||
fixed_t worldtopslope, worldbottomslope;
|
||
fixed_t worldhighslope = 0, worldlowslope = 0;
|
||
fixed_t v1x, v1y, v2x, v2y;
|
||
#endif
|
||
|
||
GLTexture_t *grTex = NULL;
|
||
float cliplow = 0.0f, cliphigh = 0.0f;
|
||
INT32 gr_midtexture;
|
||
fixed_t h, l; // 3D sides and 2s middle textures
|
||
#ifdef ESLOPE
|
||
fixed_t hS, lS;
|
||
#endif
|
||
|
||
FUINT lightnum = 0; // shut up compiler
|
||
extracolormap_t *colormap;
|
||
FSurfaceInfo Surf;
|
||
|
||
gr_sidedef = gr_curline->sidedef;
|
||
gr_linedef = gr_curline->linedef;
|
||
|
||
vs.x = ((polyvertex_t *)gr_curline->pv1)->x;
|
||
vs.y = ((polyvertex_t *)gr_curline->pv1)->y;
|
||
ve.x = ((polyvertex_t *)gr_curline->pv2)->x;
|
||
ve.y = ((polyvertex_t *)gr_curline->pv2)->y;
|
||
|
||
#ifdef ESLOPE
|
||
v1x = FLOAT_TO_FIXED(vs.x);
|
||
v1y = FLOAT_TO_FIXED(vs.y);
|
||
v2x = FLOAT_TO_FIXED(ve.x);
|
||
v2y = FLOAT_TO_FIXED(ve.y);
|
||
#endif
|
||
#ifdef ESLOPE
|
||
|
||
#define SLOPEPARAMS(slope, end1, end2, normalheight) \
|
||
if (slope) { \
|
||
end1 = P_GetZAt(slope, v1x, v1y); \
|
||
end2 = P_GetZAt(slope, v2x, v2y); \
|
||
} else \
|
||
end1 = end2 = normalheight;
|
||
|
||
SLOPEPARAMS(gr_frontsector->c_slope, worldtop, worldtopslope, gr_frontsector->ceilingheight)
|
||
SLOPEPARAMS(gr_frontsector->f_slope, worldbottom, worldbottomslope, gr_frontsector->floorheight)
|
||
#else
|
||
worldtop = gr_frontsector->ceilingheight;
|
||
worldbottom = gr_frontsector->floorheight;
|
||
#endif
|
||
|
||
// remember vertices ordering
|
||
// 3--2
|
||
// | /|
|
||
// |/ |
|
||
// 0--1
|
||
// make a wall polygon (with 2 triangles), using the floor/ceiling heights,
|
||
// and the 2d map coords of start/end vertices
|
||
wallVerts[0].x = wallVerts[3].x = vs.x;
|
||
wallVerts[0].z = wallVerts[3].z = vs.y;
|
||
wallVerts[2].x = wallVerts[1].x = ve.x;
|
||
wallVerts[2].z = wallVerts[1].z = ve.y;
|
||
|
||
// x offset the texture
|
||
{
|
||
fixed_t texturehpeg = gr_sidedef->textureoffset + gr_curline->offset;
|
||
cliplow = (float)texturehpeg;
|
||
cliphigh = (float)(texturehpeg + (gr_curline->flength*FRACUNIT));
|
||
}
|
||
|
||
lightnum = HWR_CalcWallLight(gr_curline, gr_frontsector->lightlevel);
|
||
colormap = gr_frontsector->extra_colormap;
|
||
|
||
if (gr_frontsector)
|
||
Surf.PolyColor.s.alpha = 255;
|
||
|
||
if (gr_backsector)
|
||
{
|
||
INT32 gr_toptexture, gr_bottomtexture;
|
||
// two sided line
|
||
|
||
#ifdef ESLOPE
|
||
SLOPEPARAMS(gr_backsector->c_slope, worldhigh, worldhighslope, gr_backsector->ceilingheight)
|
||
SLOPEPARAMS(gr_backsector->f_slope, worldlow, worldlowslope, gr_backsector->floorheight)
|
||
#undef SLOPEPARAMS
|
||
#else
|
||
worldhigh = gr_backsector->ceilingheight;
|
||
worldlow = gr_backsector->floorheight;
|
||
#endif
|
||
|
||
// Sky culling
|
||
if (!gr_curline->polyseg) // Don't do it for polyobjects
|
||
{
|
||
// Sky Ceilings
|
||
wallVerts[3].y = wallVerts[2].y = FIXED_TO_FLOAT(INT32_MAX);
|
||
|
||
if (gr_frontsector->ceilingpic == skyflatnum)
|
||
{
|
||
if (gr_backsector->ceilingpic == skyflatnum)
|
||
{
|
||
// Both front and back sectors are sky, needs skywall from the frontsector's ceiling, but only if the
|
||
// backsector is lower
|
||
if ((worldhigh <= worldtop && worldhighslope <= worldtopslope)// Assuming ESLOPE is always on with my changes
|
||
&& (worldhigh != worldtop || worldhighslope != worldtopslope))
|
||
// Removing the second line above will render more rarely visible skywalls. Example: Cave garden ceiling in Dark race
|
||
{
|
||
#ifdef ESLOPE
|
||
wallVerts[0].y = FIXED_TO_FLOAT(worldhigh);
|
||
wallVerts[1].y = FIXED_TO_FLOAT(worldhighslope);
|
||
#else
|
||
wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(worldhigh);
|
||
#endif
|
||
HWR_DrawSkyWall(wallVerts, &Surf);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// Only the frontsector is sky, just draw a skywall from the front ceiling
|
||
#ifdef ESLOPE
|
||
wallVerts[0].y = FIXED_TO_FLOAT(worldtop);
|
||
wallVerts[1].y = FIXED_TO_FLOAT(worldtopslope);
|
||
#else
|
||
wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(worldtop);
|
||
#endif
|
||
HWR_DrawSkyWall(wallVerts, &Surf);
|
||
}
|
||
}
|
||
else if (gr_backsector->ceilingpic == skyflatnum)
|
||
{
|
||
// Only the backsector is sky, just draw a skywall from the front ceiling
|
||
#ifdef ESLOPE
|
||
wallVerts[0].y = FIXED_TO_FLOAT(worldtop);
|
||
wallVerts[1].y = FIXED_TO_FLOAT(worldtopslope);
|
||
#else
|
||
wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(worldtop);
|
||
#endif
|
||
HWR_DrawSkyWall(wallVerts, &Surf);
|
||
}
|
||
|
||
|
||
// Sky Floors
|
||
wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(INT32_MIN);
|
||
|
||
if (gr_frontsector->floorpic == skyflatnum)
|
||
{
|
||
if (gr_backsector->floorpic == skyflatnum)
|
||
{
|
||
// Both front and back sectors are sky, needs skywall from the backsector's floor, but only if the
|
||
// it's higher, also needs to check for bottomtexture as the floors don't usually move down
|
||
// when both sides are sky floors
|
||
if ((worldlow >= worldbottom && worldlowslope >= worldbottomslope)
|
||
&& (worldlow != worldbottom || worldlowslope != worldbottomslope)
|
||
// Removing the second line above will render more rarely visible skywalls. Example: Cave garden ceiling in Dark race
|
||
&& !(gr_sidedef->bottomtexture))
|
||
{
|
||
#ifdef ESLOPE
|
||
wallVerts[3].y = FIXED_TO_FLOAT(worldlow);
|
||
wallVerts[2].y = FIXED_TO_FLOAT(worldlowslope);
|
||
#else
|
||
wallVerts[3].y = wallVerts[2].y = FIXED_TO_FLOAT(worldlow);
|
||
#endif
|
||
|
||
HWR_DrawSkyWall(wallVerts, &Surf);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// Only the backsector has sky, just draw a skywall from the back floor
|
||
#ifdef ESLOPE
|
||
wallVerts[3].y = FIXED_TO_FLOAT(worldbottom);
|
||
wallVerts[2].y = FIXED_TO_FLOAT(worldbottomslope);
|
||
#else
|
||
wallVerts[3].y = wallVerts[2].y = FIXED_TO_FLOAT(worldbottom);
|
||
#endif
|
||
|
||
HWR_DrawSkyWall(wallVerts, &Surf);
|
||
}
|
||
}
|
||
else if ((gr_backsector->floorpic == skyflatnum) && !(gr_sidedef->bottomtexture))
|
||
{
|
||
// Only the backsector has sky, just draw a skywall from the back floor if there's no bottomtexture
|
||
#ifdef ESLOPE
|
||
wallVerts[3].y = FIXED_TO_FLOAT(worldlow);
|
||
wallVerts[2].y = FIXED_TO_FLOAT(worldlowslope);
|
||
#else
|
||
wallVerts[3].y = wallVerts[2].y = FIXED_TO_FLOAT(worldlow);
|
||
#endif
|
||
|
||
HWR_DrawSkyWall(wallVerts, &Surf);
|
||
}
|
||
|
||
}
|
||
|
||
// hack to allow height changes in outdoor areas
|
||
// This is what gets rid of the upper textures if there should be sky
|
||
if (gr_frontsector->ceilingpic == skyflatnum &&
|
||
gr_backsector->ceilingpic == skyflatnum)
|
||
{
|
||
worldtop = worldhigh;
|
||
#ifdef ESLOPE
|
||
worldtopslope = worldhighslope;
|
||
#endif
|
||
}
|
||
|
||
gr_toptexture = R_GetTextureNum(gr_sidedef->toptexture);
|
||
gr_bottomtexture = R_GetTextureNum(gr_sidedef->bottomtexture);
|
||
|
||
// check TOP TEXTURE
|
||
if ((
|
||
#ifdef ESLOPE
|
||
worldhighslope < worldtopslope ||
|
||
#endif
|
||
worldhigh < worldtop
|
||
) && gr_toptexture)
|
||
{
|
||
{
|
||
fixed_t texturevpegtop; // top
|
||
|
||
grTex = HWR_GetTexture(gr_toptexture);
|
||
|
||
// PEGGING
|
||
if (gr_linedef->flags & ML_DONTPEGTOP)
|
||
texturevpegtop = 0;
|
||
#ifdef ESLOPE
|
||
else if (gr_linedef->flags & ML_EFFECT1)
|
||
texturevpegtop = worldhigh + textureheight[gr_sidedef->toptexture] - worldtop;
|
||
else
|
||
texturevpegtop = gr_backsector->ceilingheight + textureheight[gr_sidedef->toptexture] - gr_frontsector->ceilingheight;
|
||
#else
|
||
else
|
||
texturevpegtop = worldhigh + textureheight[gr_sidedef->toptexture] - worldtop;
|
||
#endif
|
||
|
||
texturevpegtop += gr_sidedef->rowoffset;
|
||
|
||
// 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
|
||
texturevpegtop %= SHORT(textures[gr_toptexture]->height)<<FRACBITS;
|
||
|
||
wallVerts[3].t = wallVerts[2].t = texturevpegtop * grTex->scaleY;
|
||
wallVerts[0].t = wallVerts[1].t = (texturevpegtop + gr_frontsector->ceilingheight - gr_backsector->ceilingheight) * grTex->scaleY;
|
||
wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX;
|
||
wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX;
|
||
|
||
#ifdef ESLOPE
|
||
// Adjust t value for sloped walls
|
||
if (!(gr_linedef->flags & ML_EFFECT1))
|
||
{
|
||
// Unskewed
|
||
wallVerts[3].t -= (worldtop - gr_frontsector->ceilingheight) * grTex->scaleY;
|
||
wallVerts[2].t -= (worldtopslope - gr_frontsector->ceilingheight) * grTex->scaleY;
|
||
wallVerts[0].t -= (worldhigh - gr_backsector->ceilingheight) * grTex->scaleY;
|
||
wallVerts[1].t -= (worldhighslope - gr_backsector->ceilingheight) * grTex->scaleY;
|
||
}
|
||
else if (gr_linedef->flags & ML_DONTPEGTOP)
|
||
{
|
||
// Skewed by top
|
||
wallVerts[0].t = (texturevpegtop + worldtop - worldhigh) * grTex->scaleY;
|
||
wallVerts[1].t = (texturevpegtop + worldtopslope - worldhighslope) * grTex->scaleY;
|
||
}
|
||
else
|
||
{
|
||
// Skewed by bottom
|
||
wallVerts[0].t = wallVerts[1].t = (texturevpegtop + worldtop - worldhigh) * grTex->scaleY;
|
||
wallVerts[3].t = wallVerts[0].t - (worldtop - worldhigh) * grTex->scaleY;
|
||
wallVerts[2].t = wallVerts[1].t - (worldtopslope - worldhighslope) * grTex->scaleY;
|
||
}
|
||
#endif
|
||
}
|
||
|
||
// set top/bottom coords
|
||
#ifdef ESLOPE
|
||
wallVerts[3].y = FIXED_TO_FLOAT(worldtop);
|
||
wallVerts[0].y = FIXED_TO_FLOAT(worldhigh);
|
||
wallVerts[2].y = FIXED_TO_FLOAT(worldtopslope);
|
||
wallVerts[1].y = FIXED_TO_FLOAT(worldhighslope);
|
||
#else
|
||
wallVerts[2].y = wallVerts[3].y = FIXED_TO_FLOAT(worldtop);
|
||
wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(worldhigh);
|
||
#endif
|
||
|
||
if (gr_frontsector->numlights)
|
||
HWR_SplitWall(gr_frontsector, wallVerts, gr_toptexture, &Surf, FF_CUTLEVEL, NULL);
|
||
else if (grTex->mipmap.flags & TF_TRANSPARENT)
|
||
HWR_AddTransparentWall(wallVerts, &Surf, gr_toptexture, PF_Environment, false, lightnum, colormap);
|
||
else
|
||
HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
|
||
}
|
||
|
||
// check BOTTOM TEXTURE
|
||
if ((
|
||
#ifdef ESLOPE
|
||
worldlowslope > worldbottomslope ||
|
||
#endif
|
||
worldlow > worldbottom) && gr_bottomtexture) //only if VISIBLE!!!
|
||
{
|
||
{
|
||
fixed_t texturevpegbottom = 0; // bottom
|
||
|
||
grTex = HWR_GetTexture(gr_bottomtexture);
|
||
|
||
// PEGGING
|
||
#ifdef ESLOPE
|
||
if (!(gr_linedef->flags & ML_DONTPEGBOTTOM))
|
||
texturevpegbottom = 0;
|
||
else if (gr_linedef->flags & ML_EFFECT1)
|
||
texturevpegbottom = worldbottom - worldlow;
|
||
else
|
||
texturevpegbottom = gr_frontsector->floorheight - gr_backsector->floorheight;
|
||
#else
|
||
if (gr_linedef->flags & ML_DONTPEGBOTTOM)
|
||
texturevpegbottom = worldbottom - worldlow;
|
||
else
|
||
texturevpegbottom = 0;
|
||
#endif
|
||
|
||
texturevpegbottom += gr_sidedef->rowoffset;
|
||
|
||
// 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
|
||
texturevpegbottom %= SHORT(textures[gr_bottomtexture]->height)<<FRACBITS;
|
||
|
||
wallVerts[3].t = wallVerts[2].t = texturevpegbottom * grTex->scaleY;
|
||
wallVerts[0].t = wallVerts[1].t = (texturevpegbottom + gr_backsector->floorheight - gr_frontsector->floorheight) * grTex->scaleY;
|
||
wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX;
|
||
wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX;
|
||
|
||
#ifdef ESLOPE
|
||
// Adjust t value for sloped walls
|
||
if (!(gr_linedef->flags & ML_EFFECT1))
|
||
{
|
||
// Unskewed
|
||
wallVerts[0].t -= (worldbottom - gr_frontsector->floorheight) * grTex->scaleY;
|
||
wallVerts[1].t -= (worldbottomslope - gr_frontsector->floorheight) * grTex->scaleY;
|
||
wallVerts[3].t -= (worldlow - gr_backsector->floorheight) * grTex->scaleY;
|
||
wallVerts[2].t -= (worldlowslope - gr_backsector->floorheight) * grTex->scaleY;
|
||
}
|
||
else if (gr_linedef->flags & ML_DONTPEGBOTTOM)
|
||
{
|
||
// Skewed by bottom
|
||
wallVerts[0].t = wallVerts[1].t = (texturevpegbottom + worldlow - worldbottom) * grTex->scaleY;
|
||
//wallVerts[3].t = wallVerts[0].t - (worldlow - worldbottom) * grTex->scaleY; // no need, [3] is already this
|
||
wallVerts[2].t = wallVerts[1].t - (worldlowslope - worldbottomslope) * grTex->scaleY;
|
||
}
|
||
else
|
||
{
|
||
// Skewed by top
|
||
wallVerts[0].t = (texturevpegbottom + worldlow - worldbottom) * grTex->scaleY;
|
||
wallVerts[1].t = (texturevpegbottom + worldlowslope - worldbottomslope) * grTex->scaleY;
|
||
}
|
||
#endif
|
||
}
|
||
|
||
// set top/bottom coords
|
||
#ifdef ESLOPE
|
||
wallVerts[3].y = FIXED_TO_FLOAT(worldlow);
|
||
wallVerts[0].y = FIXED_TO_FLOAT(worldbottom);
|
||
wallVerts[2].y = FIXED_TO_FLOAT(worldlowslope);
|
||
wallVerts[1].y = FIXED_TO_FLOAT(worldbottomslope);
|
||
#else
|
||
wallVerts[2].y = wallVerts[3].y = FIXED_TO_FLOAT(worldlow);
|
||
wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(worldbottom);
|
||
#endif
|
||
|
||
if (gr_frontsector->numlights)
|
||
HWR_SplitWall(gr_frontsector, wallVerts, gr_bottomtexture, &Surf, FF_CUTLEVEL, NULL);
|
||
else if (grTex->mipmap.flags & TF_TRANSPARENT)
|
||
HWR_AddTransparentWall(wallVerts, &Surf, gr_bottomtexture, PF_Environment, false, lightnum, colormap);
|
||
else
|
||
HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
|
||
}
|
||
gr_midtexture = R_GetTextureNum(gr_sidedef->midtexture);
|
||
if (gr_midtexture)
|
||
{
|
||
FBITFIELD blendmode;
|
||
sector_t *front, *back;
|
||
fixed_t popentop, popenbottom, polytop, polybottom, lowcut, highcut;
|
||
fixed_t texturevpeg = 0;
|
||
INT32 repeats;
|
||
|
||
if (gr_linedef->frontsector->heightsec != -1)
|
||
front = §ors[gr_linedef->frontsector->heightsec];
|
||
else
|
||
front = gr_linedef->frontsector;
|
||
|
||
if (gr_linedef->backsector->heightsec != -1)
|
||
back = §ors[gr_linedef->backsector->heightsec];
|
||
else
|
||
back = gr_linedef->backsector;
|
||
|
||
if (gr_sidedef->repeatcnt)
|
||
repeats = 1 + gr_sidedef->repeatcnt;
|
||
else if (gr_linedef->flags & ML_EFFECT5)
|
||
{
|
||
fixed_t high, low;
|
||
|
||
if (front->ceilingheight > back->ceilingheight)
|
||
high = back->ceilingheight;
|
||
else
|
||
high = front->ceilingheight;
|
||
|
||
if (front->floorheight > back->floorheight)
|
||
low = front->floorheight;
|
||
else
|
||
low = back->floorheight;
|
||
|
||
repeats = (high - low)/textureheight[gr_sidedef->midtexture];
|
||
if ((high-low)%textureheight[gr_sidedef->midtexture])
|
||
repeats++; // tile an extra time to fill the gap -- Monster Iestyn
|
||
}
|
||
else
|
||
repeats = 1;
|
||
|
||
// SoM: a little note: This code re-arranging will
|
||
// fix the bug in Nimrod map02. popentop and popenbottom
|
||
// record the limits the texture can be displayed in.
|
||
// polytop and polybottom, are the ideal (i.e. unclipped)
|
||
// heights of the polygon, and h & l, are the final (clipped)
|
||
// poly coords.
|
||
|
||
#ifdef POLYOBJECTS
|
||
// NOTE: With polyobjects, whenever you need to check the properties of the polyobject sector it belongs to,
|
||
// you must use the linedef's backsector to be correct
|
||
// From CB
|
||
if (gr_curline->polyseg)
|
||
{
|
||
popentop = back->ceilingheight;
|
||
popenbottom = back->floorheight;
|
||
}
|
||
else
|
||
#endif
|
||
{
|
||
#ifdef ESLOPE
|
||
popentop = min(worldtop, worldhigh);
|
||
popenbottom = max(worldbottom, worldlow);
|
||
#else
|
||
popentop = min(front->ceilingheight, back->ceilingheight);
|
||
popenbottom = max(front->floorheight, back->floorheight);
|
||
#endif
|
||
}
|
||
|
||
#ifdef ESLOPE
|
||
if (gr_linedef->flags & ML_EFFECT2)
|
||
{
|
||
if (!!(gr_linedef->flags & ML_DONTPEGBOTTOM) ^ !!(gr_linedef->flags & ML_EFFECT3))
|
||
{
|
||
polybottom = max(front->floorheight, back->floorheight) + gr_sidedef->rowoffset;
|
||
polytop = polybottom + textureheight[gr_midtexture]*repeats;
|
||
}
|
||
else
|
||
{
|
||
polytop = min(front->ceilingheight, back->ceilingheight) + gr_sidedef->rowoffset;
|
||
polybottom = polytop - textureheight[gr_midtexture]*repeats;
|
||
}
|
||
}
|
||
else if (!!(gr_linedef->flags & ML_DONTPEGBOTTOM) ^ !!(gr_linedef->flags & ML_EFFECT3))
|
||
#else
|
||
if (gr_linedef->flags & ML_DONTPEGBOTTOM)
|
||
#endif
|
||
{
|
||
polybottom = popenbottom + gr_sidedef->rowoffset;
|
||
polytop = polybottom + textureheight[gr_midtexture]*repeats;
|
||
}
|
||
else
|
||
{
|
||
polytop = popentop + gr_sidedef->rowoffset;
|
||
polybottom = polytop - textureheight[gr_midtexture]*repeats;
|
||
}
|
||
// CB
|
||
#ifdef POLYOBJECTS
|
||
// NOTE: With polyobjects, whenever you need to check the properties of the polyobject sector it belongs to,
|
||
// you must use the linedef's backsector to be correct
|
||
if (gr_curline->polyseg)
|
||
{
|
||
lowcut = polybottom;
|
||
highcut = polytop;
|
||
}
|
||
#endif
|
||
else
|
||
{
|
||
// The cut-off values of a linedef can always be constant, since every line has an absoulute front and or back sector
|
||
lowcut = popenbottom;
|
||
highcut = popentop;
|
||
}
|
||
|
||
h = min(highcut, polytop);
|
||
l = max(polybottom, lowcut);
|
||
|
||
{
|
||
// PEGGING
|
||
#ifdef ESLOPE
|
||
if (!!(gr_linedef->flags & ML_DONTPEGBOTTOM) ^ !!(gr_linedef->flags & ML_EFFECT3))
|
||
#else
|
||
if (gr_linedef->flags & ML_DONTPEGBOTTOM)
|
||
#endif
|
||
texturevpeg = textureheight[gr_sidedef->midtexture]*repeats - h + polybottom;
|
||
else
|
||
texturevpeg = polytop - h;
|
||
|
||
grTex = HWR_GetTexture(gr_midtexture);
|
||
|
||
wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY;
|
||
wallVerts[0].t = wallVerts[1].t = (h - l + texturevpeg) * grTex->scaleY;
|
||
wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX;
|
||
wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX;
|
||
}
|
||
|
||
// set top/bottom coords
|
||
// Take the texture peg into account, rather than changing the offsets past
|
||
// where the polygon might not be.
|
||
wallVerts[2].y = wallVerts[3].y = FIXED_TO_FLOAT(h);
|
||
wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(l);
|
||
|
||
#ifdef ESLOPE
|
||
// Correct to account for slopes
|
||
{
|
||
fixed_t midtextureslant;
|
||
|
||
if (gr_linedef->flags & ML_EFFECT2)
|
||
midtextureslant = 0;
|
||
else if (!!(gr_linedef->flags & ML_DONTPEGBOTTOM) ^ !!(gr_linedef->flags & ML_EFFECT3))
|
||
midtextureslant = worldlow < worldbottom
|
||
? worldbottomslope-worldbottom
|
||
: worldlowslope-worldlow;
|
||
else
|
||
midtextureslant = worldtop < worldhigh
|
||
? worldtopslope-worldtop
|
||
: worldhighslope-worldhigh;
|
||
|
||
polytop += midtextureslant;
|
||
polybottom += midtextureslant;
|
||
|
||
highcut += worldtop < worldhigh
|
||
? worldtopslope-worldtop
|
||
: worldhighslope-worldhigh;
|
||
lowcut += worldlow < worldbottom
|
||
? worldbottomslope-worldbottom
|
||
: worldlowslope-worldlow;
|
||
|
||
// Texture stuff
|
||
h = min(highcut, polytop);
|
||
l = max(polybottom, lowcut);
|
||
|
||
{
|
||
// PEGGING
|
||
if (!!(gr_linedef->flags & ML_DONTPEGBOTTOM) ^ !!(gr_linedef->flags & ML_EFFECT3))
|
||
texturevpeg = textureheight[gr_sidedef->midtexture]*repeats - h + polybottom;
|
||
else
|
||
texturevpeg = polytop - h;
|
||
wallVerts[2].t = texturevpeg * grTex->scaleY;
|
||
wallVerts[1].t = (h - l + texturevpeg) * grTex->scaleY;
|
||
}
|
||
|
||
wallVerts[2].y = FIXED_TO_FLOAT(h);
|
||
wallVerts[1].y = FIXED_TO_FLOAT(l);
|
||
}
|
||
#endif
|
||
|
||
// set alpha for transparent walls (new boom and legacy linedef types)
|
||
// ooops ! this do not work at all because render order we should render it in backtofront order
|
||
switch (gr_linedef->special)
|
||
{
|
||
case 900:
|
||
blendmode = HWR_TranstableToAlpha(tr_trans10, &Surf);
|
||
break;
|
||
case 901:
|
||
blendmode = HWR_TranstableToAlpha(tr_trans20, &Surf);
|
||
break;
|
||
case 902:
|
||
blendmode = HWR_TranstableToAlpha(tr_trans30, &Surf);
|
||
break;
|
||
case 903:
|
||
blendmode = HWR_TranstableToAlpha(tr_trans40, &Surf);
|
||
break;
|
||
case 904:
|
||
blendmode = HWR_TranstableToAlpha(tr_trans50, &Surf);
|
||
break;
|
||
case 905:
|
||
blendmode = HWR_TranstableToAlpha(tr_trans60, &Surf);
|
||
break;
|
||
case 906:
|
||
blendmode = HWR_TranstableToAlpha(tr_trans70, &Surf);
|
||
break;
|
||
case 907:
|
||
blendmode = HWR_TranstableToAlpha(tr_trans80, &Surf);
|
||
break;
|
||
case 908:
|
||
blendmode = HWR_TranstableToAlpha(tr_trans90, &Surf);
|
||
break;
|
||
// Translucent
|
||
case 102:
|
||
case 121:
|
||
case 123:
|
||
case 124:
|
||
case 125:
|
||
case 141:
|
||
case 142:
|
||
case 144:
|
||
case 145:
|
||
case 174:
|
||
case 175:
|
||
case 192:
|
||
case 195:
|
||
case 221:
|
||
case 253:
|
||
case 256:
|
||
blendmode = PF_Translucent;
|
||
break;
|
||
default:
|
||
blendmode = PF_Masked;
|
||
break;
|
||
}
|
||
|
||
#ifdef POLYOBJECTS
|
||
if (gr_curline->polyseg && gr_curline->polyseg->translucency > 0)
|
||
{
|
||
if (gr_curline->polyseg->translucency >= NUMTRANSMAPS) // wall not drawn
|
||
{
|
||
Surf.PolyColor.s.alpha = 0x00; // This shouldn't draw anything regardless of blendmode
|
||
blendmode = PF_Masked;
|
||
}
|
||
else
|
||
blendmode = HWR_TranstableToAlpha(gr_curline->polyseg->translucency, &Surf);
|
||
}
|
||
#endif
|
||
|
||
if (gr_frontsector->numlights)
|
||
{
|
||
if (!(blendmode & PF_Masked))
|
||
HWR_SplitWall(gr_frontsector, wallVerts, gr_midtexture, &Surf, FF_TRANSLUCENT, NULL);
|
||
else
|
||
{
|
||
HWR_SplitWall(gr_frontsector, wallVerts, gr_midtexture, &Surf, FF_CUTLEVEL, NULL);
|
||
}
|
||
}
|
||
else if (!(blendmode & PF_Masked))
|
||
HWR_AddTransparentWall(wallVerts, &Surf, gr_midtexture, blendmode, false, lightnum, colormap);
|
||
else
|
||
HWR_ProjectWall(wallVerts, &Surf, blendmode, lightnum, colormap);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// Single sided line... Deal only with the middletexture (if one exists)
|
||
gr_midtexture = R_GetTextureNum(gr_sidedef->midtexture);
|
||
if (gr_midtexture
|
||
&& gr_linedef->special != HORIZONSPECIAL) // Ignore horizon line for OGL
|
||
{
|
||
{
|
||
fixed_t texturevpeg;
|
||
// PEGGING
|
||
#ifdef ESLOPE
|
||
if ((gr_linedef->flags & (ML_DONTPEGBOTTOM|ML_EFFECT2)) == (ML_DONTPEGBOTTOM|ML_EFFECT2))
|
||
texturevpeg = gr_frontsector->floorheight + textureheight[gr_sidedef->midtexture] - gr_frontsector->ceilingheight + gr_sidedef->rowoffset;
|
||
else
|
||
#endif
|
||
if (gr_linedef->flags & ML_DONTPEGBOTTOM)
|
||
texturevpeg = worldbottom + textureheight[gr_sidedef->midtexture] - worldtop + gr_sidedef->rowoffset;
|
||
else
|
||
// top of texture at top
|
||
texturevpeg = gr_sidedef->rowoffset;
|
||
|
||
grTex = HWR_GetTexture(gr_midtexture);
|
||
|
||
wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY;
|
||
wallVerts[0].t = wallVerts[1].t = (texturevpeg + gr_frontsector->ceilingheight - gr_frontsector->floorheight) * grTex->scaleY;
|
||
wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX;
|
||
wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX;
|
||
|
||
#ifdef ESLOPE
|
||
// Texture correction for slopes
|
||
if (gr_linedef->flags & ML_EFFECT2) {
|
||
wallVerts[3].t += (gr_frontsector->ceilingheight - worldtop) * grTex->scaleY;
|
||
wallVerts[2].t += (gr_frontsector->ceilingheight - worldtopslope) * grTex->scaleY;
|
||
wallVerts[0].t += (gr_frontsector->floorheight - worldbottom) * grTex->scaleY;
|
||
wallVerts[1].t += (gr_frontsector->floorheight - worldbottomslope) * grTex->scaleY;
|
||
} else if (gr_linedef->flags & ML_DONTPEGBOTTOM) {
|
||
wallVerts[3].t = wallVerts[0].t + (worldbottom-worldtop) * grTex->scaleY;
|
||
wallVerts[2].t = wallVerts[1].t + (worldbottomslope-worldtopslope) * grTex->scaleY;
|
||
} else {
|
||
wallVerts[0].t = wallVerts[3].t - (worldbottom-worldtop) * grTex->scaleY;
|
||
wallVerts[1].t = wallVerts[2].t - (worldbottomslope-worldtopslope) * grTex->scaleY;
|
||
}
|
||
#endif
|
||
}
|
||
#ifdef ESLOPE
|
||
//Set textures properly on single sided walls that are sloped
|
||
wallVerts[3].y = FIXED_TO_FLOAT(worldtop);
|
||
wallVerts[0].y = FIXED_TO_FLOAT(worldbottom);
|
||
wallVerts[2].y = FIXED_TO_FLOAT(worldtopslope);
|
||
wallVerts[1].y = FIXED_TO_FLOAT(worldbottomslope);
|
||
#else
|
||
// set top/bottom coords
|
||
wallVerts[2].y = wallVerts[3].y = FIXED_TO_FLOAT(worldtop);
|
||
wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(worldbottom);
|
||
#endif
|
||
|
||
if (gr_frontsector->numlights)
|
||
HWR_SplitWall(gr_frontsector, wallVerts, gr_midtexture, &Surf, FF_CUTLEVEL, NULL);
|
||
// I don't think that solid walls can use translucent linedef types...
|
||
else
|
||
{
|
||
if (grTex->mipmap.flags & TF_TRANSPARENT)
|
||
HWR_AddTransparentWall(wallVerts, &Surf, gr_midtexture, PF_Environment, false, lightnum, colormap);
|
||
else
|
||
HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
#ifdef ESLOPE
|
||
//Set textures properly on single sided walls that are sloped
|
||
wallVerts[3].y = FIXED_TO_FLOAT(worldtop);
|
||
wallVerts[0].y = FIXED_TO_FLOAT(worldbottom);
|
||
wallVerts[2].y = FIXED_TO_FLOAT(worldtopslope);
|
||
wallVerts[1].y = FIXED_TO_FLOAT(worldbottomslope);
|
||
#else
|
||
// set top/bottom coords
|
||
wallVerts[2].y = wallVerts[3].y = FIXED_TO_FLOAT(worldtop);
|
||
wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(worldbottom);
|
||
#endif
|
||
|
||
// When there's no midtexture, draw a skywall to prevent rendering behind it
|
||
HWR_DrawSkyWall(wallVerts, &Surf);
|
||
}
|
||
|
||
|
||
// Single sided lines are simple for skywalls, just need to draw from the top or bottom of the sector if there's
|
||
// a sky flat
|
||
if (!gr_curline->polyseg)
|
||
{
|
||
if (gr_frontsector->ceilingpic == skyflatnum) // It's a single-sided line with sky for its sector
|
||
{
|
||
wallVerts[3].y = wallVerts[2].y = FIXED_TO_FLOAT(INT32_MAX);
|
||
#ifdef ESLOPE
|
||
wallVerts[0].y = FIXED_TO_FLOAT(worldtop);
|
||
wallVerts[1].y = FIXED_TO_FLOAT(worldtopslope);
|
||
#else
|
||
wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(worldtop);
|
||
#endif
|
||
HWR_DrawSkyWall(wallVerts, &Surf);
|
||
}
|
||
if (gr_frontsector->floorpic == skyflatnum)
|
||
{
|
||
#ifdef ESLOPE
|
||
wallVerts[3].y = FIXED_TO_FLOAT(worldbottom);
|
||
wallVerts[2].y = FIXED_TO_FLOAT(worldbottomslope);
|
||
#else
|
||
wallVerts[3].y = wallVerts[2].y = FIXED_TO_FLOAT(worldbottom);
|
||
#endif
|
||
wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(INT32_MIN);
|
||
|
||
HWR_DrawSkyWall(wallVerts, &Surf);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
//Hurdler: 3d-floors test
|
||
if (gr_frontsector && gr_backsector && gr_frontsector->tag != gr_backsector->tag && (gr_backsector->ffloors || gr_frontsector->ffloors))
|
||
{
|
||
ffloor_t * rover;
|
||
fixed_t highcut = 0, lowcut = 0;
|
||
|
||
INT32 texnum;
|
||
line_t * newline = NULL; // Multi-Property FOF
|
||
|
||
///TODO add slope support (fixing cutoffs, proper wall clipping) - maybe just disable highcut/lowcut if either sector or FOF has a slope
|
||
/// to allow fun plane intersecting in OGL? But then people would abuse that and make software look bad. :C
|
||
highcut = gr_frontsector->ceilingheight < gr_backsector->ceilingheight ? gr_frontsector->ceilingheight : gr_backsector->ceilingheight;
|
||
lowcut = gr_frontsector->floorheight > gr_backsector->floorheight ? gr_frontsector->floorheight : gr_backsector->floorheight;
|
||
|
||
if (gr_backsector->ffloors)
|
||
{
|
||
for (rover = gr_backsector->ffloors; rover; rover = rover->next)
|
||
{
|
||
if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERSIDES) || (rover->flags & FF_INVERTSIDES))
|
||
continue;
|
||
if (*rover->topheight < lowcut || *rover->bottomheight > highcut)
|
||
continue;
|
||
|
||
texnum = R_GetTextureNum(sides[rover->master->sidenum[0]].midtexture);
|
||
|
||
if (rover->master->flags & ML_TFERLINE)
|
||
{
|
||
size_t linenum = gr_curline->linedef-gr_backsector->lines[0];
|
||
newline = rover->master->frontsector->lines[0] + linenum;
|
||
texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture);
|
||
}
|
||
|
||
#ifdef ESLOPE
|
||
h = *rover->t_slope ? P_GetZAt(*rover->t_slope, v1x, v1y) : *rover->topheight;
|
||
hS = *rover->t_slope ? P_GetZAt(*rover->t_slope, v2x, v2y) : *rover->topheight;
|
||
l = *rover->b_slope ? P_GetZAt(*rover->b_slope, v1x, v1y) : *rover->bottomheight;
|
||
lS = *rover->b_slope ? P_GetZAt(*rover->b_slope, v2x, v2y) : *rover->bottomheight;
|
||
if (!(*rover->t_slope) && !gr_frontsector->c_slope && !gr_backsector->c_slope && h > highcut)
|
||
h = hS = highcut;
|
||
if (!(*rover->b_slope) && !gr_frontsector->f_slope && !gr_backsector->f_slope && l < lowcut)
|
||
l = lS = lowcut;
|
||
//Hurdler: HW code starts here
|
||
//FIXME: check if peging is correct
|
||
// set top/bottom coords
|
||
|
||
wallVerts[3].y = FIXED_TO_FLOAT(h);
|
||
wallVerts[2].y = FIXED_TO_FLOAT(hS);
|
||
wallVerts[0].y = FIXED_TO_FLOAT(l);
|
||
wallVerts[1].y = FIXED_TO_FLOAT(lS);
|
||
#else
|
||
h = *rover->topheight;
|
||
l = *rover->bottomheight;
|
||
if (h > highcut)
|
||
h = highcut;
|
||
if (l < lowcut)
|
||
l = lowcut;
|
||
//Hurdler: HW code starts here
|
||
//FIXME: check if peging is correct
|
||
// set top/bottom coords
|
||
wallVerts[2].y = wallVerts[3].y = FIXED_TO_FLOAT(h);
|
||
wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(l);
|
||
#endif
|
||
if (rover->flags & FF_FOG)
|
||
{
|
||
wallVerts[3].t = wallVerts[2].t = 0;
|
||
wallVerts[0].t = wallVerts[1].t = 0;
|
||
wallVerts[0].s = wallVerts[3].s = 0;
|
||
wallVerts[2].s = wallVerts[1].s = 0;
|
||
}
|
||
else
|
||
{
|
||
fixed_t texturevpeg;
|
||
boolean attachtobottom = false;
|
||
#ifdef ESLOPE
|
||
boolean slopeskew = false; // skew FOF walls with slopes?
|
||
#endif
|
||
|
||
// Wow, how was this missing from OpenGL for so long?
|
||
// ...Oh well, anyway, Lower Unpegged now changes pegging of FOFs like in software
|
||
// -- Monster Iestyn 26/06/18
|
||
if (newline)
|
||
{
|
||
texturevpeg = sides[newline->sidenum[0]].rowoffset;
|
||
attachtobottom = !!(newline->flags & ML_DONTPEGBOTTOM);
|
||
#ifdef ESLOPE
|
||
slopeskew = !!(newline->flags & ML_DONTPEGTOP);
|
||
#endif
|
||
}
|
||
else
|
||
{
|
||
texturevpeg = sides[rover->master->sidenum[0]].rowoffset;
|
||
attachtobottom = !!(gr_linedef->flags & ML_DONTPEGBOTTOM);
|
||
#ifdef ESLOPE
|
||
slopeskew = !!(rover->master->flags & ML_DONTPEGTOP);
|
||
#endif
|
||
}
|
||
|
||
grTex = HWR_GetTexture(texnum);
|
||
|
||
#ifdef ESLOPE
|
||
if (!slopeskew) // no skewing
|
||
{
|
||
if (attachtobottom)
|
||
texturevpeg -= *rover->topheight - *rover->bottomheight;
|
||
wallVerts[3].t = (*rover->topheight - h + texturevpeg) * grTex->scaleY;
|
||
wallVerts[2].t = (*rover->topheight - hS + texturevpeg) * grTex->scaleY;
|
||
wallVerts[0].t = (*rover->topheight - l + texturevpeg) * grTex->scaleY;
|
||
wallVerts[1].t = (*rover->topheight - lS + texturevpeg) * grTex->scaleY;
|
||
}
|
||
else
|
||
{
|
||
if (!attachtobottom) // skew by top
|
||
{
|
||
wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY;
|
||
wallVerts[0].t = (h - l + texturevpeg) * grTex->scaleY;
|
||
wallVerts[1].t = (hS - lS + texturevpeg) * grTex->scaleY;
|
||
}
|
||
else // skew by bottom
|
||
{
|
||
wallVerts[0].t = wallVerts[1].t = texturevpeg * grTex->scaleY;
|
||
wallVerts[3].t = wallVerts[0].t - (h - l) * grTex->scaleY;
|
||
wallVerts[2].t = wallVerts[1].t - (hS - lS) * grTex->scaleY;
|
||
}
|
||
}
|
||
#else
|
||
if (attachtobottom)
|
||
texturevpeg -= *rover->topheight - *rover->bottomheight;
|
||
wallVerts[3].t = wallVerts[2].t = (*rover->topheight - h + texturevpeg) * grTex->scaleY;
|
||
wallVerts[0].t = wallVerts[1].t = (*rover->topheight - l + texturevpeg) * grTex->scaleY;
|
||
#endif
|
||
|
||
wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX;
|
||
wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX;
|
||
}
|
||
if (rover->flags & FF_FOG)
|
||
{
|
||
FBITFIELD blendmode;
|
||
|
||
blendmode = PF_Fog|PF_NoTexture;
|
||
|
||
lightnum = HWR_CalcWallLight(gr_curline, rover->master->frontsector->lightlevel);
|
||
colormap = rover->master->frontsector->extra_colormap;
|
||
|
||
Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel, rover->master->frontsector->extra_colormap);
|
||
|
||
if (gr_frontsector->numlights)
|
||
HWR_SplitWall(gr_frontsector, wallVerts, 0, &Surf, rover->flags, rover);
|
||
else
|
||
HWR_AddTransparentWall(wallVerts, &Surf, 0, blendmode, true, lightnum, colormap);
|
||
}
|
||
else
|
||
{
|
||
FBITFIELD blendmode = PF_Masked;
|
||
|
||
if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256)
|
||
{
|
||
blendmode = PF_Translucent;
|
||
Surf.PolyColor.s.alpha = (UINT8)rover->alpha-1 > 255 ? 255 : rover->alpha-1;
|
||
}
|
||
|
||
if (gr_frontsector->numlights)
|
||
HWR_SplitWall(gr_frontsector, wallVerts, texnum, &Surf, rover->flags, rover);
|
||
else
|
||
{
|
||
if (blendmode != PF_Masked)
|
||
HWR_AddTransparentWall(wallVerts, &Surf, texnum, blendmode, false, lightnum, colormap);
|
||
else
|
||
HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (gr_frontsector->ffloors) // Putting this seperate should allow 2 FOF sectors to be connected without too many errors? I think?
|
||
{
|
||
for (rover = gr_frontsector->ffloors; rover; rover = rover->next)
|
||
{
|
||
if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERSIDES) || !(rover->flags & FF_ALLSIDES))
|
||
continue;
|
||
if (*rover->topheight < lowcut || *rover->bottomheight > highcut)
|
||
continue;
|
||
|
||
texnum = R_GetTextureNum(sides[rover->master->sidenum[0]].midtexture);
|
||
|
||
if (rover->master->flags & ML_TFERLINE)
|
||
{
|
||
size_t linenum = gr_curline->linedef-gr_backsector->lines[0];
|
||
newline = rover->master->frontsector->lines[0] + linenum;
|
||
texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture);
|
||
}
|
||
#ifdef ESLOPE //backsides
|
||
h = *rover->t_slope ? P_GetZAt(*rover->t_slope, v1x, v1y) : *rover->topheight;
|
||
hS = *rover->t_slope ? P_GetZAt(*rover->t_slope, v2x, v2y) : *rover->topheight;
|
||
l = *rover->b_slope ? P_GetZAt(*rover->b_slope, v1x, v1y) : *rover->bottomheight;
|
||
lS = *rover->b_slope ? P_GetZAt(*rover->b_slope, v2x, v2y) : *rover->bottomheight;
|
||
if (!(*rover->t_slope) && !gr_frontsector->c_slope && !gr_backsector->c_slope && h > highcut)
|
||
h = hS = highcut;
|
||
if (!(*rover->b_slope) && !gr_frontsector->f_slope && !gr_backsector->f_slope && l < lowcut)
|
||
l = lS = lowcut;
|
||
//Hurdler: HW code starts here
|
||
//FIXME: check if peging is correct
|
||
// set top/bottom coords
|
||
|
||
wallVerts[3].y = FIXED_TO_FLOAT(h);
|
||
wallVerts[2].y = FIXED_TO_FLOAT(hS);
|
||
wallVerts[0].y = FIXED_TO_FLOAT(l);
|
||
wallVerts[1].y = FIXED_TO_FLOAT(lS);
|
||
#else
|
||
h = *rover->topheight;
|
||
l = *rover->bottomheight;
|
||
if (h > highcut)
|
||
h = highcut;
|
||
if (l < lowcut)
|
||
l = lowcut;
|
||
//Hurdler: HW code starts here
|
||
//FIXME: check if peging is correct
|
||
// set top/bottom coords
|
||
wallVerts[2].y = wallVerts[3].y = FIXED_TO_FLOAT(h);
|
||
wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(l);
|
||
#endif
|
||
if (rover->flags & FF_FOG)
|
||
{
|
||
wallVerts[3].t = wallVerts[2].t = 0;
|
||
wallVerts[0].t = wallVerts[1].t = 0;
|
||
wallVerts[0].s = wallVerts[3].s = 0;
|
||
wallVerts[2].s = wallVerts[1].s = 0;
|
||
}
|
||
else
|
||
{
|
||
grTex = HWR_GetTexture(texnum);
|
||
|
||
if (newline)
|
||
{
|
||
wallVerts[3].t = wallVerts[2].t = (*rover->topheight - h + sides[newline->sidenum[0]].rowoffset) * grTex->scaleY;
|
||
wallVerts[0].t = wallVerts[1].t = (h - l + (*rover->topheight - h + sides[newline->sidenum[0]].rowoffset)) * grTex->scaleY;
|
||
}
|
||
else
|
||
{
|
||
wallVerts[3].t = wallVerts[2].t = (*rover->topheight - h + sides[rover->master->sidenum[0]].rowoffset) * grTex->scaleY;
|
||
wallVerts[0].t = wallVerts[1].t = (h - l + (*rover->topheight - h + sides[rover->master->sidenum[0]].rowoffset)) * grTex->scaleY;
|
||
}
|
||
|
||
wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX;
|
||
wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX;
|
||
}
|
||
|
||
if (rover->flags & FF_FOG)
|
||
{
|
||
FBITFIELD blendmode;
|
||
|
||
blendmode = PF_Fog|PF_NoTexture;
|
||
|
||
lightnum = HWR_CalcWallLight(gr_curline, rover->master->frontsector->lightlevel);
|
||
colormap = rover->master->frontsector->extra_colormap;
|
||
|
||
Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel, rover->master->frontsector->extra_colormap);
|
||
|
||
if (gr_backsector->numlights)
|
||
HWR_SplitWall(gr_backsector, wallVerts, 0, &Surf, rover->flags, rover);
|
||
else
|
||
HWR_AddTransparentWall(wallVerts, &Surf, 0, blendmode, true, lightnum, colormap);
|
||
}
|
||
else
|
||
{
|
||
FBITFIELD blendmode = PF_Masked;
|
||
|
||
if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256)
|
||
{
|
||
blendmode = PF_Translucent;
|
||
Surf.PolyColor.s.alpha = (UINT8)rover->alpha-1 > 255 ? 255 : rover->alpha-1;
|
||
}
|
||
|
||
if (gr_backsector->numlights)
|
||
HWR_SplitWall(gr_backsector, wallVerts, texnum, &Surf, rover->flags, rover);
|
||
else
|
||
{
|
||
if (blendmode != PF_Masked)
|
||
HWR_AddTransparentWall(wallVerts, &Surf, texnum, blendmode, false, lightnum, colormap);
|
||
else
|
||
HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
//Hurdler: end of 3d-floors test
|
||
}
|
||
|
||
// From PrBoom:
|
||
//
|
||
// e6y: Check whether the player can look beyond this line, rturns true if we can't
|
||
//
|
||
|
||
boolean checkforemptylines = true;
|
||
// Don't modify anything here, just check
|
||
// Kalaron: Modified for sloped linedefs
|
||
static boolean CheckClip(sector_t * afrontsector, sector_t * abacksector)
|
||
{
|
||
fixed_t frontf1,frontf2, frontc1, frontc2; // front floor/ceiling ends
|
||
fixed_t backf1, backf2, backc1, backc2; // back floor ceiling ends
|
||
|
||
// GZDoom method of sloped line clipping
|
||
|
||
#ifdef ESLOPE
|
||
if (afrontsector->f_slope || afrontsector->c_slope || abacksector->f_slope || abacksector->c_slope)
|
||
{
|
||
fixed_t v1x, v1y, v2x, v2y; // the seg's vertexes as fixed_t
|
||
v1x = FLOAT_TO_FIXED(((polyvertex_t *)gr_curline->pv1)->x);
|
||
v1y = FLOAT_TO_FIXED(((polyvertex_t *)gr_curline->pv1)->y);
|
||
v2x = FLOAT_TO_FIXED(((polyvertex_t *)gr_curline->pv2)->x);
|
||
v2y = FLOAT_TO_FIXED(((polyvertex_t *)gr_curline->pv2)->y);
|
||
#define SLOPEPARAMS(slope, end1, end2, normalheight) \
|
||
if (slope) { \
|
||
end1 = P_GetZAt(slope, v1x, v1y); \
|
||
end2 = P_GetZAt(slope, v2x, v2y); \
|
||
} else \
|
||
end1 = end2 = normalheight;
|
||
|
||
SLOPEPARAMS(afrontsector->f_slope, frontf1, frontf2, afrontsector->floorheight)
|
||
SLOPEPARAMS(afrontsector->c_slope, frontc1, frontc2, afrontsector->ceilingheight)
|
||
SLOPEPARAMS( abacksector->f_slope, backf1, backf2, abacksector->floorheight)
|
||
SLOPEPARAMS( abacksector->c_slope, backc1, backc2, abacksector->ceilingheight)
|
||
#undef SLOPEPARAMS
|
||
}
|
||
else
|
||
#endif
|
||
{
|
||
frontf1 = frontf2 = afrontsector->floorheight;
|
||
frontc1 = frontc2 = afrontsector->ceilingheight;
|
||
backf1 = backf2 = abacksector->floorheight;
|
||
backc1 = backc2 = abacksector->ceilingheight;
|
||
}
|
||
|
||
|
||
// now check for closed sectors!
|
||
|
||
// here we're talking about a CEILING lower than a floor. ...yeah we don't even need to bother.
|
||
if (backc1 <= frontf1 && backc2 <= frontf2)
|
||
{
|
||
checkforemptylines = false;
|
||
return true;
|
||
}
|
||
|
||
// here we're talking about floors higher than ceilings, don't even bother either.
|
||
if (backf1 >= frontc1 && backf2 >= frontc2)
|
||
{
|
||
checkforemptylines = false;
|
||
return true;
|
||
}
|
||
|
||
// Lat: Ok, here's what we need to do, we want to draw thok barriers. Let's define what a thok barrier is;
|
||
// -Must have ceilheight <= floorheight
|
||
// -ceilpic must be skyflatnum
|
||
// -an adjacant sector needs to have a ceilingheight or a floor height different than the one we have, otherwise, it's just a huge ass wall, we shouldn't render past it.
|
||
// -said adjacant sector cannot also be a thok barrier, because that's also dumb and we could render far more than we need to as a result :V
|
||
|
||
if (backc1 <= backf1 && backc2 <= backf2)
|
||
{
|
||
checkforemptylines = false;
|
||
|
||
// before we do anything, if both sectors are thok barriers, GET ME OUT OF HERE!
|
||
if (frontc1 <= backc1 && frontc2 <= backc2)
|
||
return true; // STOP RENDERING.
|
||
|
||
// draw floors at the top of thok barriers:
|
||
if (backc1 < frontc1 || backc2 < frontc2)
|
||
return false;
|
||
|
||
if (backf1 > frontf1 || backf2 > frontf2)
|
||
return false;
|
||
|
||
return true;
|
||
}
|
||
|
||
// Window.
|
||
// We know it's a window when the above isn't true and the back and front sectors don't match
|
||
if (backc1 != frontc1 || backc2 != frontc2
|
||
|| backf1 != frontf1 || backf2 != frontf2)
|
||
{
|
||
checkforemptylines = false;
|
||
return false;
|
||
}
|
||
|
||
// In this case we just need to check whether there is actually a need to render any lines, so checkforempty lines
|
||
// stays true
|
||
return false;
|
||
}
|
||
|
||
// HWR_AddLine
|
||
// Clips the given segment and adds any visible pieces to the line list.
|
||
void HWR_AddLine(seg_t *line)
|
||
{
|
||
angle_t angle1, angle2;
|
||
|
||
// SoM: Backsector needs to be run through R_FakeFlat
|
||
static sector_t tempsec;
|
||
|
||
fixed_t v1x, v1y, v2x, v2y; // the seg's vertexes as fixed_t
|
||
#ifdef POLYOBJECTS
|
||
if (line->polyseg && !(line->polyseg->flags & POF_RENDERSIDES))
|
||
return;
|
||
#endif
|
||
|
||
gr_curline = line;
|
||
|
||
v1x = FLOAT_TO_FIXED(((polyvertex_t *)gr_curline->pv1)->x);
|
||
v1y = FLOAT_TO_FIXED(((polyvertex_t *)gr_curline->pv1)->y);
|
||
v2x = FLOAT_TO_FIXED(((polyvertex_t *)gr_curline->pv2)->x);
|
||
v2y = FLOAT_TO_FIXED(((polyvertex_t *)gr_curline->pv2)->y);
|
||
|
||
// OPTIMIZE: quickly reject orthogonal back sides.
|
||
angle1 = R_PointToAngleEx(viewx, viewy, v1x, v1y);
|
||
angle2 = R_PointToAngleEx(viewx, viewy, v2x, v2y);
|
||
|
||
// PrBoom: Back side, i.e. backface culling - read: endAngle >= startAngle!
|
||
if (angle2 - angle1 < ANGLE_180)
|
||
return;
|
||
|
||
// PrBoom: use REAL clipping math YAYYYYYYY!!!
|
||
if (!gld_clipper_SafeCheckRange(angle2, angle1))
|
||
return;
|
||
|
||
checkforemptylines = true;
|
||
|
||
gr_backsector = line->backsector;
|
||
|
||
if (!line->backsector)
|
||
gld_clipper_SafeAddClipRange(angle2, angle1);
|
||
else
|
||
{
|
||
gr_backsector = R_FakeFlat(gr_backsector, &tempsec, NULL, NULL, true);
|
||
if (CheckClip(gr_frontsector, gr_backsector))
|
||
{
|
||
gld_clipper_SafeAddClipRange(angle2, angle1);
|
||
checkforemptylines = false;
|
||
}
|
||
// Reject empty lines used for triggers and special events.
|
||
// Identical floor and ceiling on both sides,
|
||
// identical light levels on both sides,
|
||
// and no middle texture.
|
||
if (checkforemptylines && R_IsEmptyLine(line, gr_frontsector, gr_backsector))
|
||
return;
|
||
}
|
||
|
||
HWR_ProcessSeg(); // Doesn't need arguments because they're defined globally :D
|
||
return;
|
||
}
|
||
|
||
// HWR_CheckBBox
|
||
// Checks BSP node/subtree bounding box.
|
||
// Returns true
|
||
// if some part of the bbox might be visible.
|
||
//
|
||
// modified to use local variables
|
||
|
||
boolean HWR_CheckBBox(fixed_t *bspcoord)
|
||
{
|
||
INT32 boxpos;
|
||
fixed_t px1, py1, px2, py2;
|
||
angle_t angle1, angle2;
|
||
|
||
// Find the corners of the box
|
||
// that define the edges from current viewpoint.
|
||
if (viewx <= bspcoord[BOXLEFT])
|
||
boxpos = 0;
|
||
else if (viewx < bspcoord[BOXRIGHT])
|
||
boxpos = 1;
|
||
else
|
||
boxpos = 2;
|
||
|
||
if (viewy >= bspcoord[BOXTOP])
|
||
boxpos |= 0;
|
||
else if (viewy > bspcoord[BOXBOTTOM])
|
||
boxpos |= 1<<2;
|
||
else
|
||
boxpos |= 2<<2;
|
||
|
||
if (boxpos == 5)
|
||
return true;
|
||
|
||
px1 = bspcoord[checkcoord[boxpos][0]];
|
||
py1 = bspcoord[checkcoord[boxpos][1]];
|
||
px2 = bspcoord[checkcoord[boxpos][2]];
|
||
py2 = bspcoord[checkcoord[boxpos][3]];
|
||
|
||
angle1 = R_PointToAngleEx(viewx, viewy, px1, py1);
|
||
angle2 = R_PointToAngleEx(viewx, viewy, px2, py2);
|
||
return gld_clipper_SafeCheckRange(angle2, angle1);
|
||
}
|
||
|
||
#ifdef POLYOBJECTS
|
||
|
||
//
|
||
// HWR_AddPolyObjectSegs
|
||
//
|
||
// haleyjd 02/19/06
|
||
// Adds all segs in all polyobjects in the given subsector.
|
||
// Modified for hardware rendering.
|
||
//
|
||
void HWR_AddPolyObjectSegs(void)
|
||
{
|
||
size_t i, j;
|
||
seg_t *gr_fakeline = Z_Calloc(sizeof(seg_t), PU_STATIC, NULL);
|
||
polyvertex_t *pv1 = Z_Calloc(sizeof(polyvertex_t), PU_STATIC, NULL);
|
||
polyvertex_t *pv2 = Z_Calloc(sizeof(polyvertex_t), PU_STATIC, NULL);
|
||
|
||
// Sort through all the polyobjects
|
||
for (i = 0; i < numpolys; ++i)
|
||
{
|
||
// Render the polyobject's lines
|
||
for (j = 0; j < po_ptrs[i]->segCount; ++j)
|
||
{
|
||
// Copy the info of a polyobject's seg, then convert it to OpenGL floating point
|
||
M_Memcpy(gr_fakeline, po_ptrs[i]->segs[j], sizeof(seg_t));
|
||
|
||
// Now convert the line to float and add it to be rendered
|
||
pv1->x = FIXED_TO_FLOAT(gr_fakeline->v1->x);
|
||
pv1->y = FIXED_TO_FLOAT(gr_fakeline->v1->y);
|
||
pv2->x = FIXED_TO_FLOAT(gr_fakeline->v2->x);
|
||
pv2->y = FIXED_TO_FLOAT(gr_fakeline->v2->y);
|
||
|
||
gr_fakeline->pv1 = pv1;
|
||
gr_fakeline->pv2 = pv2;
|
||
|
||
HWR_AddLine(gr_fakeline);
|
||
}
|
||
}
|
||
|
||
// Free temporary data no longer needed
|
||
Z_Free(pv2);
|
||
Z_Free(pv1);
|
||
Z_Free(gr_fakeline);
|
||
}
|
||
|
||
#ifdef POLYOBJECTS_PLANES
|
||
void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, fixed_t fixedheight, FBITFIELD blendmode, UINT8 lightlevel, lumpnum_t lumpnum, sector_t *FOFsector, UINT8 alpha, extracolormap_t *planecolormap)
|
||
{
|
||
float height; //constant y for all points on the convex flat polygon
|
||
FOutVector *v3d;
|
||
INT32 i;
|
||
float flatxref,flatyref;
|
||
float fflatsize;
|
||
INT32 flatflag;
|
||
size_t len;
|
||
float scrollx = 0.0f, scrolly = 0.0f;
|
||
angle_t angle = 0;
|
||
FSurfaceInfo Surf;
|
||
fixed_t tempxsow, tempytow;
|
||
size_t nrPlaneVerts;
|
||
|
||
static FOutVector *planeVerts = NULL;
|
||
static UINT16 numAllocedPlaneVerts = 0;
|
||
|
||
nrPlaneVerts = polysector->numVertices;
|
||
|
||
height = FIXED_TO_FLOAT(fixedheight);
|
||
|
||
if (nrPlaneVerts < 3) //not even a triangle ?
|
||
return;
|
||
|
||
if (nrPlaneVerts > INT16_MAX) // FIXME: exceeds plVerts size
|
||
{
|
||
CONS_Debug(DBG_RENDER, "polygon size of %s exceeds max value of %d vertices\n", sizeu1(nrPlaneVerts), UINT16_MAX);
|
||
return;
|
||
}
|
||
|
||
// Allocate plane-vertex buffer if we need to
|
||
if (!planeVerts || nrPlaneVerts > numAllocedPlaneVerts)
|
||
{
|
||
numAllocedPlaneVerts = (UINT16)nrPlaneVerts;
|
||
Z_Free(planeVerts);
|
||
Z_Malloc(numAllocedPlaneVerts * sizeof (FOutVector), PU_LEVEL, &planeVerts);
|
||
}
|
||
|
||
len = W_LumpLength(lumpnum);
|
||
|
||
switch (len)
|
||
{
|
||
case 4194304: // 2048x2048 lump
|
||
fflatsize = 2048.0f;
|
||
flatflag = 2047;
|
||
break;
|
||
case 1048576: // 1024x1024 lump
|
||
fflatsize = 1024.0f;
|
||
flatflag = 1023;
|
||
break;
|
||
case 262144:// 512x512 lump
|
||
fflatsize = 512.0f;
|
||
flatflag = 511;
|
||
break;
|
||
case 65536: // 256x256 lump
|
||
fflatsize = 256.0f;
|
||
flatflag = 255;
|
||
break;
|
||
case 16384: // 128x128 lump
|
||
fflatsize = 128.0f;
|
||
flatflag = 127;
|
||
break;
|
||
case 1024: // 32x32 lump
|
||
fflatsize = 32.0f;
|
||
flatflag = 31;
|
||
break;
|
||
default: // 64x64 lump
|
||
fflatsize = 64.0f;
|
||
flatflag = 63;
|
||
break;
|
||
}
|
||
|
||
// reference point for flat texture coord for each vertex around the polygon
|
||
flatxref = (float)(((fixed_t)FIXED_TO_FLOAT(polysector->origVerts[0].x) & (~flatflag)) / fflatsize);
|
||
flatyref = (float)(((fixed_t)FIXED_TO_FLOAT(polysector->origVerts[0].y) & (~flatflag)) / fflatsize);
|
||
|
||
// transform
|
||
v3d = planeVerts;
|
||
|
||
if (FOFsector != NULL)
|
||
{
|
||
if (!isceiling) // it's a floor
|
||
{
|
||
scrollx = FIXED_TO_FLOAT(FOFsector->floor_xoffs)/fflatsize;
|
||
scrolly = FIXED_TO_FLOAT(FOFsector->floor_yoffs)/fflatsize;
|
||
angle = FOFsector->floorpic_angle>>ANGLETOFINESHIFT;
|
||
}
|
||
else // it's a ceiling
|
||
{
|
||
scrollx = FIXED_TO_FLOAT(FOFsector->ceiling_xoffs)/fflatsize;
|
||
scrolly = FIXED_TO_FLOAT(FOFsector->ceiling_yoffs)/fflatsize;
|
||
angle = FOFsector->ceilingpic_angle>>ANGLETOFINESHIFT;
|
||
}
|
||
}
|
||
else if (gr_frontsector)
|
||
{
|
||
if (!isceiling) // it's a floor
|
||
{
|
||
scrollx = FIXED_TO_FLOAT(gr_frontsector->floor_xoffs)/fflatsize;
|
||
scrolly = FIXED_TO_FLOAT(gr_frontsector->floor_yoffs)/fflatsize;
|
||
angle = gr_frontsector->floorpic_angle>>ANGLETOFINESHIFT;
|
||
}
|
||
else // it's a ceiling
|
||
{
|
||
scrollx = FIXED_TO_FLOAT(gr_frontsector->ceiling_xoffs)/fflatsize;
|
||
scrolly = FIXED_TO_FLOAT(gr_frontsector->ceiling_yoffs)/fflatsize;
|
||
angle = gr_frontsector->ceilingpic_angle>>ANGLETOFINESHIFT;
|
||
}
|
||
}
|
||
|
||
if (angle) // Only needs to be done if there's an altered angle
|
||
{
|
||
// This needs to be done so that it scrolls in a different direction after rotation like software
|
||
tempxsow = FLOAT_TO_FIXED(scrollx);
|
||
tempytow = FLOAT_TO_FIXED(scrolly);
|
||
scrollx = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINECOSINE(angle)) - FixedMul(tempytow, FINESINE(angle))));
|
||
scrolly = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINESINE(angle)) + FixedMul(tempytow, FINECOSINE(angle))));
|
||
|
||
// This needs to be done so everything aligns after rotation
|
||
// 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
|
||
tempxsow = FLOAT_TO_FIXED(flatxref);
|
||
tempytow = FLOAT_TO_FIXED(flatyref);
|
||
flatxref = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINECOSINE(angle)) - FixedMul(tempytow, FINESINE(angle))));
|
||
flatyref = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINESINE(angle)) + FixedMul(tempytow, FINECOSINE(angle))));
|
||
}
|
||
|
||
for (i = 0; i < (INT32)nrPlaneVerts; i++,v3d++)
|
||
{
|
||
// Hurdler: add scrolling texture on floor/ceiling
|
||
v3d->s = (float)((FIXED_TO_FLOAT(polysector->origVerts[i].x) / fflatsize) - flatxref + scrollx); // Go from the polysector's original vertex locations
|
||
v3d->t = (float)(flatyref - (FIXED_TO_FLOAT(polysector->origVerts[i].y) / fflatsize) + scrolly); // Means the flat is offset based on the original vertex locations
|
||
|
||
// Need to rotate before translate
|
||
if (angle) // Only needs to be done if there's an altered angle
|
||
{
|
||
tempxsow = FLOAT_TO_FIXED(v3d->s);
|
||
tempytow = FLOAT_TO_FIXED(v3d->t);
|
||
v3d->s = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINECOSINE(angle)) - FixedMul(tempytow, FINESINE(angle))));
|
||
v3d->t = (FIXED_TO_FLOAT(-FixedMul(tempxsow, FINESINE(angle)) - FixedMul(tempytow, FINECOSINE(angle))));
|
||
}
|
||
|
||
v3d->x = FIXED_TO_FLOAT(polysector->vertices[i]->x);
|
||
v3d->y = height;
|
||
v3d->z = FIXED_TO_FLOAT(polysector->vertices[i]->y);
|
||
}
|
||
|
||
HWR_Lighting(&Surf, lightlevel, planecolormap);
|
||
|
||
if (blendmode & PF_Translucent)
|
||
{
|
||
Surf.PolyColor.s.alpha = (UINT8)alpha;
|
||
blendmode |= PF_Modulated|PF_Occlude;
|
||
}
|
||
else
|
||
blendmode |= PF_Masked|PF_Modulated;
|
||
|
||
HWD.pfnSetShader(1); // floor shader
|
||
HWD.pfnDrawPolygon(&Surf, planeVerts, nrPlaneVerts, blendmode);
|
||
}
|
||
|
||
void HWR_AddPolyObjectPlanes(void)
|
||
{
|
||
size_t i;
|
||
sector_t *polyobjsector;
|
||
|
||
// Polyobject Planes need their own function for drawing because they don't have extrasubsectors by themselves
|
||
// It should be okay because polyobjects should always be convex anyway
|
||
|
||
for (i = 0; i < numpolys; i++)
|
||
{
|
||
polyobjsector = po_ptrs[i]->lines[0]->backsector; // the in-level polyobject sector
|
||
|
||
if (!(po_ptrs[i]->flags & POF_RENDERPLANES)) // Only render planes when you should
|
||
continue;
|
||
|
||
if (po_ptrs[i]->translucency >= NUMTRANSMAPS)
|
||
continue;
|
||
|
||
if (polyobjsector->floorheight <= gr_frontsector->ceilingheight
|
||
&& polyobjsector->floorheight >= gr_frontsector->floorheight
|
||
&& (viewz < polyobjsector->floorheight))
|
||
{
|
||
if (po_ptrs[i]->translucency > 0)
|
||
{
|
||
FSurfaceInfo Surf;
|
||
FBITFIELD blendmode = HWR_TranstableToAlpha(po_ptrs[i]->translucency, &Surf);
|
||
HWR_AddTransparentPolyobjectFloor(levelflats[polyobjsector->floorpic].lumpnum, po_ptrs[i], false, polyobjsector->floorheight,
|
||
polyobjsector->lightlevel, Surf.PolyColor.s.alpha, polyobjsector, blendmode, NULL);
|
||
}
|
||
else
|
||
{
|
||
HWR_GetFlat(levelflats[polyobjsector->floorpic].lumpnum, R_NoEncore(polyobjsector, false));
|
||
HWR_RenderPolyObjectPlane(po_ptrs[i], false, polyobjsector->floorheight, PF_Occlude,
|
||
polyobjsector->lightlevel, levelflats[polyobjsector->floorpic].lumpnum,
|
||
polyobjsector, 255, NULL);
|
||
}
|
||
}
|
||
|
||
if (polyobjsector->ceilingheight >= gr_frontsector->floorheight
|
||
&& polyobjsector->ceilingheight <= gr_frontsector->ceilingheight
|
||
&& (viewz > polyobjsector->ceilingheight))
|
||
{
|
||
if (po_ptrs[i]->translucency > 0)
|
||
{
|
||
FSurfaceInfo Surf;
|
||
FBITFIELD blendmode;
|
||
memset(&Surf, 0x00, sizeof(Surf));
|
||
blendmode = HWR_TranstableToAlpha(po_ptrs[i]->translucency, &Surf);
|
||
HWR_AddTransparentPolyobjectFloor(levelflats[polyobjsector->ceilingpic].lumpnum, po_ptrs[i], true, polyobjsector->ceilingheight,
|
||
polyobjsector->lightlevel, Surf.PolyColor.s.alpha, polyobjsector, blendmode, NULL);
|
||
}
|
||
else
|
||
{
|
||
HWR_GetFlat(levelflats[polyobjsector->ceilingpic].lumpnum, R_NoEncore(polyobjsector, true));
|
||
HWR_RenderPolyObjectPlane(po_ptrs[i], true, polyobjsector->ceilingheight, PF_Occlude,
|
||
polyobjsector->lightlevel, levelflats[polyobjsector->floorpic].lumpnum,
|
||
polyobjsector, 255, NULL);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
#endif
|
||
#endif
|
||
|
||
// -----------------+
|
||
// HWR_Subsector : Determine floor/ceiling planes.
|
||
// : Add sprites of things in sector.
|
||
// : Draw one or more line segments.
|
||
// -----------------+
|
||
void HWR_Subsector(size_t num)
|
||
{
|
||
INT16 count;
|
||
seg_t *line;
|
||
subsector_t *sub;
|
||
static sector_t tempsec; //SoM: 4/7/2000
|
||
INT32 floorlightlevel;
|
||
INT32 ceilinglightlevel;
|
||
INT32 locFloorHeight, locCeilingHeight;
|
||
INT32 cullFloorHeight, cullCeilingHeight;
|
||
INT32 light = 0;
|
||
extracolormap_t *floorcolormap;
|
||
extracolormap_t *ceilingcolormap;
|
||
|
||
#ifdef PARANOIA //no risk while developing, enough debugging nights!
|
||
if (num >= addsubsector)
|
||
I_Error("HWR_Subsector: ss %s with numss = %s, addss = %s\n",
|
||
sizeu1(num), sizeu2(numsubsectors), sizeu3(addsubsector));
|
||
#endif
|
||
|
||
if (num < numsubsectors)
|
||
{
|
||
// subsector
|
||
sub = &subsectors[num];
|
||
// sector
|
||
gr_frontsector = sub->sector;
|
||
// how many linedefs
|
||
count = sub->numlines;
|
||
// first line seg
|
||
line = &segs[sub->firstline];
|
||
}
|
||
else
|
||
{
|
||
// there are no segs but only planes
|
||
sub = &subsectors[0];
|
||
gr_frontsector = sub->sector;
|
||
count = 0;
|
||
line = NULL;
|
||
}
|
||
|
||
//SoM: 4/7/2000: Test to make Boom water work in Hardware mode.
|
||
gr_frontsector = R_FakeFlat(gr_frontsector, &tempsec, &floorlightlevel,
|
||
&ceilinglightlevel, false);
|
||
//FIXME: Use floorlightlevel and ceilinglightlevel insted of lightlevel.
|
||
|
||
floorcolormap = ceilingcolormap = gr_frontsector->extra_colormap;
|
||
|
||
// ----- for special tricks with HW renderer -----
|
||
if (gr_frontsector->pseudoSector)
|
||
{
|
||
cullFloorHeight = locFloorHeight = gr_frontsector->virtualFloorheight;
|
||
cullCeilingHeight = locCeilingHeight = gr_frontsector->virtualCeilingheight;
|
||
}
|
||
else if (gr_frontsector->virtualFloor)
|
||
{
|
||
///@TODO Is this whole virtualFloor mess even useful? I don't think it even triggers ever.
|
||
cullFloorHeight = locFloorHeight = gr_frontsector->virtualFloorheight;
|
||
if (gr_frontsector->virtualCeiling)
|
||
cullCeilingHeight = locCeilingHeight = gr_frontsector->virtualCeilingheight;
|
||
else
|
||
cullCeilingHeight = locCeilingHeight = gr_frontsector->ceilingheight;
|
||
}
|
||
else if (gr_frontsector->virtualCeiling)
|
||
{
|
||
cullCeilingHeight = locCeilingHeight = gr_frontsector->virtualCeilingheight;
|
||
cullFloorHeight = locFloorHeight = gr_frontsector->floorheight;
|
||
}
|
||
else
|
||
{
|
||
cullFloorHeight = locFloorHeight = gr_frontsector->floorheight;
|
||
cullCeilingHeight = locCeilingHeight = gr_frontsector->ceilingheight;
|
||
|
||
#ifdef ESLOPE
|
||
if (gr_frontsector->f_slope)
|
||
{
|
||
cullFloorHeight = P_GetZAt(gr_frontsector->f_slope, viewx, viewy);
|
||
locFloorHeight = P_GetZAt(gr_frontsector->f_slope, gr_frontsector->soundorg.x, gr_frontsector->soundorg.y);
|
||
}
|
||
|
||
if (gr_frontsector->c_slope)
|
||
{
|
||
cullCeilingHeight = P_GetZAt(gr_frontsector->c_slope, viewx, viewy);
|
||
locCeilingHeight = P_GetZAt(gr_frontsector->c_slope, gr_frontsector->soundorg.x, gr_frontsector->soundorg.y);
|
||
}
|
||
#endif
|
||
}
|
||
// ----- end special tricks -----
|
||
|
||
if (gr_frontsector->ffloors)
|
||
{
|
||
if (gr_frontsector->moved)
|
||
{
|
||
gr_frontsector->numlights = sub->sector->numlights = 0;
|
||
R_Prep3DFloors(gr_frontsector);
|
||
sub->sector->lightlist = gr_frontsector->lightlist;
|
||
sub->sector->numlights = gr_frontsector->numlights;
|
||
sub->sector->moved = gr_frontsector->moved = false;
|
||
}
|
||
|
||
light = R_GetPlaneLight(gr_frontsector, locFloorHeight, false);
|
||
if (gr_frontsector->floorlightsec == -1)
|
||
floorlightlevel = *gr_frontsector->lightlist[light].lightlevel;
|
||
floorcolormap = gr_frontsector->lightlist[light].extra_colormap;
|
||
|
||
light = R_GetPlaneLight(gr_frontsector, locCeilingHeight, false);
|
||
if (gr_frontsector->ceilinglightsec == -1)
|
||
ceilinglightlevel = *gr_frontsector->lightlist[light].lightlevel;
|
||
ceilingcolormap = gr_frontsector->lightlist[light].extra_colormap;
|
||
}
|
||
|
||
sub->sector->extra_colormap = gr_frontsector->extra_colormap;
|
||
|
||
//R_PlaneLightOverride(gr_frontsector, false, &floorlightlevel);
|
||
//R_PlaneLightOverride(gr_frontsector, true, &ceilinglightlevel);
|
||
|
||
// render floor ?
|
||
// yeah, easy backface cull! :)
|
||
if (cullFloorHeight < viewz)
|
||
{
|
||
if (gr_frontsector->floorpic != skyflatnum)
|
||
{
|
||
if (sub->validcount != validcount)
|
||
{
|
||
HWR_GetFlat(levelflats[gr_frontsector->floorpic].lumpnum, R_NoEncore(gr_frontsector, false));
|
||
HWR_RenderPlane(&extrasubsectors[num], false,
|
||
// Hack to make things continue to work around slopes.
|
||
locFloorHeight == cullFloorHeight ? locFloorHeight : gr_frontsector->floorheight,
|
||
// We now return you to your regularly scheduled rendering.
|
||
PF_Occlude, floorlightlevel, levelflats[gr_frontsector->floorpic].lumpnum, NULL, 255, floorcolormap);
|
||
}
|
||
}
|
||
}
|
||
|
||
if (cullCeilingHeight > viewz)
|
||
{
|
||
if (gr_frontsector->ceilingpic != skyflatnum)
|
||
{
|
||
if (sub->validcount != validcount)
|
||
{
|
||
HWR_GetFlat(levelflats[gr_frontsector->ceilingpic].lumpnum, R_NoEncore(gr_frontsector, true));
|
||
HWR_RenderPlane(&extrasubsectors[num], true,
|
||
// Hack to make things continue to work around slopes.
|
||
locCeilingHeight == cullCeilingHeight ? locCeilingHeight : gr_frontsector->ceilingheight,
|
||
// We now return you to your regularly scheduled rendering.
|
||
PF_Occlude, ceilinglightlevel, levelflats[gr_frontsector->ceilingpic].lumpnum,NULL, 255, ceilingcolormap);
|
||
}
|
||
}
|
||
}
|
||
|
||
if (gr_frontsector->ffloors)
|
||
{
|
||
/// \todo fix light, xoffs, yoffs, extracolormap ?
|
||
ffloor_t * rover;
|
||
for (rover = gr_frontsector->ffloors;
|
||
rover; rover = rover->next)
|
||
{
|
||
fixed_t cullHeight, centerHeight;
|
||
|
||
// bottom plane
|
||
#ifdef ESLOPE
|
||
if (*rover->b_slope)
|
||
{
|
||
cullHeight = P_GetZAt(*rover->b_slope, viewx, viewy);
|
||
centerHeight = P_GetZAt(*rover->b_slope, gr_frontsector->soundorg.x, gr_frontsector->soundorg.y);
|
||
}
|
||
else
|
||
#endif
|
||
cullHeight = centerHeight = *rover->bottomheight;
|
||
|
||
if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERPLANES))
|
||
continue;
|
||
if (sub->validcount == validcount)
|
||
continue;
|
||
|
||
if (centerHeight <= locCeilingHeight &&
|
||
centerHeight >= locFloorHeight &&
|
||
((viewz < cullHeight && !(rover->flags & FF_INVERTPLANES)) ||
|
||
(viewz > cullHeight && (rover->flags & FF_BOTHPLANES || rover->flags & FF_INVERTPLANES))))
|
||
{
|
||
if (rover->flags & FF_FOG)
|
||
{
|
||
UINT8 alpha;
|
||
|
||
light = R_GetPlaneLight(gr_frontsector, centerHeight, viewz < cullHeight ? true : false);
|
||
|
||
alpha = HWR_FogBlockAlpha(*gr_frontsector->lightlist[light].lightlevel, rover->master->frontsector->extra_colormap);
|
||
|
||
HWR_AddTransparentFloor(0,
|
||
&extrasubsectors[num],
|
||
false,
|
||
*rover->bottomheight,
|
||
*gr_frontsector->lightlist[light].lightlevel,
|
||
alpha, rover->master->frontsector, PF_Fog|PF_NoTexture,
|
||
true, rover->master->frontsector->extra_colormap);
|
||
}
|
||
else if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256) // SoM: Flags are more efficient
|
||
{
|
||
light = R_GetPlaneLight(gr_frontsector, centerHeight, viewz < cullHeight ? true : false);
|
||
HWR_AddTransparentFloor(levelflats[*rover->bottompic].lumpnum,
|
||
&extrasubsectors[num],
|
||
false,
|
||
*rover->bottomheight,
|
||
*gr_frontsector->lightlist[light].lightlevel,
|
||
rover->alpha-1 > 255 ? 255 : rover->alpha-1, rover->master->frontsector, (rover->flags & FF_RIPPLE ? PF_Ripple : 0)|PF_Translucent,
|
||
false, gr_frontsector->lightlist[light].extra_colormap);
|
||
}
|
||
else
|
||
{
|
||
HWR_GetFlat(levelflats[*rover->bottompic].lumpnum, R_NoEncore(gr_frontsector, false));
|
||
light = R_GetPlaneLight(gr_frontsector, centerHeight, viewz < cullHeight ? true : false);
|
||
HWR_RenderPlane(&extrasubsectors[num], false, *rover->bottomheight, (rover->flags & FF_RIPPLE ? PF_Ripple : 0)|PF_Occlude, *gr_frontsector->lightlist[light].lightlevel, levelflats[*rover->bottompic].lumpnum,
|
||
rover->master->frontsector, 255, gr_frontsector->lightlist[light].extra_colormap);
|
||
}
|
||
}
|
||
|
||
// top plane
|
||
#ifdef ESLOPE
|
||
if (*rover->t_slope)
|
||
{
|
||
cullHeight = P_GetZAt(*rover->t_slope, viewx, viewy);
|
||
centerHeight = P_GetZAt(*rover->t_slope, gr_frontsector->soundorg.x, gr_frontsector->soundorg.y);
|
||
}
|
||
else
|
||
#endif
|
||
cullHeight = centerHeight = *rover->topheight;
|
||
|
||
if (centerHeight >= locFloorHeight &&
|
||
centerHeight <= locCeilingHeight &&
|
||
((viewz > cullHeight && !(rover->flags & FF_INVERTPLANES)) ||
|
||
(viewz < cullHeight && (rover->flags & FF_BOTHPLANES || rover->flags & FF_INVERTPLANES))))
|
||
{
|
||
if (rover->flags & FF_FOG)
|
||
{
|
||
UINT8 alpha;
|
||
|
||
light = R_GetPlaneLight(gr_frontsector, centerHeight, viewz < cullHeight ? true : false);
|
||
|
||
alpha = HWR_FogBlockAlpha(*gr_frontsector->lightlist[light].lightlevel, rover->master->frontsector->extra_colormap);
|
||
|
||
HWR_AddTransparentFloor(0,
|
||
&extrasubsectors[num],
|
||
true,
|
||
*rover->topheight,
|
||
*gr_frontsector->lightlist[light].lightlevel,
|
||
alpha, rover->master->frontsector, PF_Fog|PF_NoTexture,
|
||
true, rover->master->frontsector->extra_colormap);
|
||
}
|
||
else if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256)
|
||
{
|
||
light = R_GetPlaneLight(gr_frontsector, centerHeight, viewz < cullHeight ? true : false);
|
||
HWR_AddTransparentFloor(levelflats[*rover->toppic].lumpnum,
|
||
&extrasubsectors[num],
|
||
true,
|
||
*rover->topheight,
|
||
*gr_frontsector->lightlist[light].lightlevel,
|
||
rover->alpha-1 > 255 ? 255 : rover->alpha-1, rover->master->frontsector, (rover->flags & FF_RIPPLE ? PF_Ripple : 0)|PF_Translucent,
|
||
false, gr_frontsector->lightlist[light].extra_colormap);
|
||
}
|
||
else
|
||
{
|
||
HWR_GetFlat(levelflats[*rover->toppic].lumpnum, R_NoEncore(gr_frontsector, true));
|
||
light = R_GetPlaneLight(gr_frontsector, centerHeight, viewz < cullHeight ? true : false);
|
||
HWR_RenderPlane(&extrasubsectors[num], true, *rover->topheight, (rover->flags & FF_RIPPLE ? PF_Ripple : 0)|PF_Occlude, *gr_frontsector->lightlist[light].lightlevel, levelflats[*rover->toppic].lumpnum,
|
||
rover->master->frontsector, 255, gr_frontsector->lightlist[light].extra_colormap);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
#ifdef POLYOBJECTS
|
||
// Draw all the polyobjects in this subsector
|
||
if (sub->polyList)
|
||
{
|
||
polyobj_t *po = sub->polyList;
|
||
|
||
numpolys = 0;
|
||
|
||
// Count all the polyobjects, reset the list, and recount them
|
||
while (po)
|
||
{
|
||
++numpolys;
|
||
po = (polyobj_t *)(po->link.next);
|
||
}
|
||
|
||
// Sort polyobjects
|
||
R_SortPolyObjects(sub);
|
||
|
||
// Draw polyobject lines.
|
||
HWR_AddPolyObjectSegs();
|
||
|
||
#ifdef POLYOBJECTS_PLANES
|
||
if (sub->validcount != validcount) // This validcount situation seems to let us know that the floors have already been drawn.
|
||
{
|
||
// Draw polyobject planes
|
||
HWR_AddPolyObjectPlanes();
|
||
}
|
||
#endif
|
||
}
|
||
#endif
|
||
|
||
// Hurder ici se passe les choses INT32<33>essantes!
|
||
// on vient de tracer le sol et le plafond
|
||
// on trace <20>pr<70>ent d'abord les sprites et ensuite les murs
|
||
// hurdler: faux: on ajoute seulement les sprites, le murs sont trac<61> d'abord
|
||
if (line)
|
||
{
|
||
// draw sprites first, coz they are clipped to the solidsegs of
|
||
// subsectors more 'in front'
|
||
HWR_AddSprites(gr_frontsector);
|
||
|
||
//Hurdler: at this point validcount must be the same, but is not because
|
||
// gr_frontsector doesn't point anymore to sub->sector due to
|
||
// the call gr_frontsector = R_FakeFlat(...)
|
||
// if it's not done, the sprite is drawn more than once,
|
||
// what looks really bad with translucency or dynamic light,
|
||
// without talking about the overdraw of course.
|
||
sub->sector->validcount = validcount;/// \todo fix that in a better way
|
||
|
||
while (count--)
|
||
{
|
||
#ifdef POLYOBJECTS
|
||
if (!line->polyseg) // ignore segs that belong to polyobjects
|
||
#endif
|
||
HWR_AddLine(line);
|
||
line++;
|
||
}
|
||
}
|
||
|
||
sub->validcount = validcount;
|
||
}
|
||
|
||
//
|
||
// Renders all subsectors below a given node,
|
||
// traversing subtree recursively.
|
||
// Just call with BSP root.
|
||
|
||
void HWR_RenderBSPNode(INT32 bspnum)
|
||
{
|
||
node_t *bsp = &nodes[bspnum];
|
||
|
||
// Decide which side the view point is on
|
||
INT32 side;
|
||
|
||
// Found a subsector?
|
||
if (bspnum & NF_SUBSECTOR)
|
||
{
|
||
if (bspnum != -1)
|
||
HWR_Subsector(bspnum&(~NF_SUBSECTOR));
|
||
return;
|
||
}
|
||
|
||
// Decide which side the view point is on.
|
||
side = R_PointOnSide(viewx, viewy, bsp);
|
||
|
||
// Recursively divide front space.
|
||
HWR_RenderBSPNode(bsp->children[side]);
|
||
|
||
// Possibly divide back space.
|
||
if (HWR_CheckBBox(bsp->bbox[side^1]))
|
||
HWR_RenderBSPNode(bsp->children[side^1]);
|
||
}
|
||
|
||
// ==========================================================================
|
||
// gr_things.c
|
||
// ==========================================================================
|
||
|
||
// sprites are drawn after all wall and planes are rendered, so that
|
||
// sprite translucency effects apply on the rendered view (instead of the background sky!!)
|
||
|
||
static UINT32 gr_visspritecount;
|
||
static gr_vissprite_t *gr_visspritechunks[MAXVISSPRITES >> VISSPRITECHUNKBITS] = {NULL};
|
||
|
||
// --------------------------------------------------------------------------
|
||
// HWR_ClearSprites
|
||
// Called at frame start.
|
||
// --------------------------------------------------------------------------
|
||
static void HWR_ClearSprites(void)
|
||
{
|
||
gr_visspritecount = 0;
|
||
}
|
||
|
||
// --------------------------------------------------------------------------
|
||
// HWR_NewVisSprite
|
||
// --------------------------------------------------------------------------
|
||
static gr_vissprite_t gr_overflowsprite;
|
||
|
||
static gr_vissprite_t *HWR_GetVisSprite(UINT32 num)
|
||
{
|
||
UINT32 chunk = num >> VISSPRITECHUNKBITS;
|
||
|
||
// Allocate chunk if necessary
|
||
if (!gr_visspritechunks[chunk])
|
||
Z_Malloc(sizeof(gr_vissprite_t) * VISSPRITESPERCHUNK, PU_LEVEL, &gr_visspritechunks[chunk]);
|
||
|
||
return gr_visspritechunks[chunk] + (num & VISSPRITEINDEXMASK);
|
||
}
|
||
|
||
static gr_vissprite_t *HWR_NewVisSprite(void)
|
||
{
|
||
if (gr_visspritecount == MAXVISSPRITES)
|
||
return &gr_overflowsprite;
|
||
|
||
return HWR_GetVisSprite(gr_visspritecount++);
|
||
}
|
||
|
||
//
|
||
// HWR_DoCulling
|
||
// Hardware version of R_DoCulling
|
||
// (see r_main.c)
|
||
static boolean HWR_DoCulling(line_t *cullheight, line_t *viewcullheight, float vz, float bottomh, float toph)
|
||
{
|
||
float cullplane;
|
||
|
||
if (!cullheight)
|
||
return false;
|
||
|
||
cullplane = FIXED_TO_FLOAT(cullheight->frontsector->floorheight);
|
||
if (cullheight->flags & ML_NOCLIMB) // Group culling
|
||
{
|
||
if (!viewcullheight)
|
||
return false;
|
||
|
||
// Make sure this is part of the same group
|
||
if (viewcullheight->frontsector == cullheight->frontsector)
|
||
{
|
||
// OK, we can cull
|
||
if (vz > cullplane && toph < cullplane) // Cull if below plane
|
||
return true;
|
||
|
||
if (bottomh > cullplane && vz <= cullplane) // Cull if above plane
|
||
return true;
|
||
}
|
||
}
|
||
else // Quick culling
|
||
{
|
||
if (vz > cullplane && toph < cullplane) // Cull if below plane
|
||
return true;
|
||
|
||
if (bottomh > cullplane && vz <= cullplane) // Cull if above plane
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale)
|
||
{
|
||
const fixed_t thingxpos = thing->x + thing->sprxoff;
|
||
const fixed_t thingypos = thing->y + thing->spryoff;
|
||
const fixed_t thingzpos = thing->z + thing->sprzoff;
|
||
|
||
GLPatch_t *gpatch;
|
||
FOutVector shadowVerts[4];
|
||
FSurfaceInfo sSurf;
|
||
float fscale; float fx; float fy; float offset;
|
||
UINT8 lightlevel = 0;
|
||
extracolormap_t *colormap = NULL;
|
||
UINT8 i;
|
||
|
||
INT32 light;
|
||
fixed_t scalemul;
|
||
UINT16 alpha;
|
||
fixed_t floordiff;
|
||
fixed_t floorz;
|
||
fixed_t slopez;
|
||
pslope_t *floorslope;
|
||
|
||
floorz = R_GetShadowZ(thing, &floorslope);
|
||
floordiff = abs(thingzpos - floorz);
|
||
|
||
alpha = floordiff / (4*FRACUNIT) + 75;
|
||
if (alpha >= 255) return;
|
||
alpha = 255 - alpha;
|
||
|
||
if (thing->whiteshadow)
|
||
{
|
||
gpatch = (GLPatch_t *)W_CachePatchName("LSHADOW", PU_CACHE);
|
||
lightlevel = 255;
|
||
}
|
||
else
|
||
{
|
||
gpatch = (GLPatch_t *)W_CachePatchName("DSHADOW", PU_CACHE);
|
||
lightlevel = 0;
|
||
}
|
||
|
||
if (!(gpatch && gpatch->mipmap->grInfo.format)) return;
|
||
HWR_GetPatch(gpatch);
|
||
|
||
scalemul = FixedMul(FRACUNIT - floordiff/640, scale);
|
||
scalemul = FixedMul(scalemul, (thing->radius*2) / gpatch->height);
|
||
|
||
fscale = FIXED_TO_FLOAT(scalemul);
|
||
fx = FIXED_TO_FLOAT(thingxpos);
|
||
fy = FIXED_TO_FLOAT(thingypos);
|
||
|
||
// 3--2
|
||
// | /|
|
||
// |/ |
|
||
// 0--1
|
||
|
||
if (thing && fabsf(fscale - 1.0f) > 1.0E-36f)
|
||
offset = (gpatch->height/2) * fscale;
|
||
else
|
||
offset = (float)(gpatch->height/2);
|
||
|
||
shadowVerts[2].x = shadowVerts[3].x = fx + offset;
|
||
shadowVerts[1].x = shadowVerts[0].x = fx - offset;
|
||
shadowVerts[1].z = shadowVerts[2].z = fy - offset;
|
||
shadowVerts[0].z = shadowVerts[3].z = fy + offset;
|
||
|
||
for (i = 0; i < 4; i++)
|
||
{
|
||
float oldx = shadowVerts[i].x;
|
||
float oldy = shadowVerts[i].z;
|
||
shadowVerts[i].x = fx + ((oldx - fx) * gr_viewcos) - ((oldy - fy) * gr_viewsin);
|
||
shadowVerts[i].z = fy + ((oldx - fx) * gr_viewsin) + ((oldy - fy) * gr_viewcos);
|
||
}
|
||
|
||
if (floorslope)
|
||
{
|
||
for (i = 0; i < 4; i++)
|
||
{
|
||
slopez = P_GetZAt(floorslope, FLOAT_TO_FIXED(shadowVerts[i].x), FLOAT_TO_FIXED(shadowVerts[i].z));
|
||
shadowVerts[i].y = FIXED_TO_FLOAT(slopez) + 0.05f;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
for (i = 0; i < 4; i++)
|
||
shadowVerts[i].y = FIXED_TO_FLOAT(floorz) + 0.05f;
|
||
}
|
||
|
||
shadowVerts[0].s = shadowVerts[3].s = 0;
|
||
shadowVerts[2].s = shadowVerts[1].s = gpatch->max_s;
|
||
|
||
shadowVerts[3].t = shadowVerts[2].t = 0;
|
||
shadowVerts[0].t = shadowVerts[1].t = gpatch->max_t;
|
||
|
||
if (thing->subsector->sector->numlights)
|
||
{
|
||
light = R_GetPlaneLight(thing->subsector->sector, floorz, false); // Always use the light at the top instead of whatever I was doing before
|
||
|
||
if (thing->subsector->sector->lightlist[light].extra_colormap)
|
||
colormap = thing->subsector->sector->lightlist[light].extra_colormap;
|
||
}
|
||
else
|
||
{
|
||
if (thing->subsector->sector->extra_colormap)
|
||
colormap = thing->subsector->sector->extra_colormap;
|
||
}
|
||
|
||
HWR_Lighting(&sSurf, lightlevel, colormap);
|
||
sSurf.PolyColor.s.alpha = alpha;
|
||
|
||
HWD.pfnSetShader(3); // sprite shader
|
||
HWD.pfnDrawPolygon(&sSurf, shadowVerts, 4, PF_Translucent|PF_Modulated);
|
||
}
|
||
|
||
// This is expecting a pointer to an array containing 4 wallVerts for a sprite
|
||
static void HWR_RotateSpritePolyToAim(gr_vissprite_t *spr, FOutVector *wallVerts)
|
||
{
|
||
if (cv_grspritebillboarding.value && spr && spr->mobj && !(spr->mobj->frame & FF_PAPERSPRITE) && wallVerts)
|
||
{
|
||
float basey = FIXED_TO_FLOAT(spr->mobj->z);
|
||
float lowy = wallVerts[0].y;
|
||
if (P_MobjFlip(spr->mobj) == -1)
|
||
{
|
||
basey = FIXED_TO_FLOAT(spr->mobj->z + spr->mobj->height);
|
||
}
|
||
// Rotate sprites to fully billboard with the camera
|
||
// X, Y, AND Z need to be manipulated for the polys to rotate around the
|
||
// origin, because of how the origin setting works I believe that should
|
||
// be mobj->z or mobj->z + mobj->height
|
||
wallVerts[2].y = wallVerts[3].y = (spr->ty - basey) * gr_viewludsin + basey;
|
||
wallVerts[0].y = wallVerts[1].y = (lowy - basey) * gr_viewludsin + basey;
|
||
// translate back to be around 0 before translating back
|
||
wallVerts[3].x += ((spr->ty - basey) * gr_viewludcos) * gr_viewcos;
|
||
wallVerts[2].x += ((spr->ty - basey) * gr_viewludcos) * gr_viewcos;
|
||
|
||
wallVerts[0].x += ((lowy - basey) * gr_viewludcos) * gr_viewcos;
|
||
wallVerts[1].x += ((lowy - basey) * gr_viewludcos) * gr_viewcos;
|
||
|
||
wallVerts[3].z += ((spr->ty - basey) * gr_viewludcos) * gr_viewsin;
|
||
wallVerts[2].z += ((spr->ty - basey) * gr_viewludcos) * gr_viewsin;
|
||
|
||
wallVerts[0].z += ((lowy - basey) * gr_viewludcos) * gr_viewsin;
|
||
wallVerts[1].z += ((lowy - basey) * gr_viewludcos) * gr_viewsin;
|
||
}
|
||
}
|
||
|
||
static void HWR_SplitSprite(gr_vissprite_t *spr)
|
||
{
|
||
float this_scale = 1.0f;
|
||
FOutVector wallVerts[4];
|
||
FOutVector baseWallVerts[4]; // This is what the verts should end up as
|
||
GLPatch_t *gpatch;
|
||
FSurfaceInfo Surf;
|
||
const boolean hires = (spr->mobj && spr->mobj->skin && ((skin_t *)spr->mobj->skin)->flags & SF_HIRES);
|
||
extracolormap_t *colormap;
|
||
FUINT lightlevel;
|
||
FBITFIELD blend = 0;
|
||
UINT8 alpha;
|
||
|
||
INT32 i;
|
||
float realtop, realbot, top, bot;
|
||
float towtop, towbot, towmult;
|
||
float bheight;
|
||
float realheight, heightmult;
|
||
const sector_t *sector = spr->mobj->subsector->sector;
|
||
const lightlist_t *list = sector->lightlist;
|
||
#ifdef ESLOPE
|
||
float endrealtop, endrealbot, endtop, endbot;
|
||
float endbheight;
|
||
float endrealheight;
|
||
fixed_t temp;
|
||
fixed_t v1x, v1y, v2x, v2y;
|
||
#endif
|
||
|
||
this_scale = FIXED_TO_FLOAT(spr->mobj->scale);
|
||
|
||
if (hires)
|
||
this_scale = this_scale * FIXED_TO_FLOAT(((skin_t *)spr->mobj->skin)->highresscale);
|
||
|
||
gpatch = W_CachePatchNum(spr->patchlumpnum, PU_CACHE);
|
||
|
||
// cache the patch in the graphics card memory
|
||
//12/12/99: Hurdler: same comment as above (for md2)
|
||
//Hurdler: 25/04/2000: now support colormap in hardware mode
|
||
HWR_GetMappedPatch(gpatch, spr->colormap);
|
||
|
||
baseWallVerts[0].x = baseWallVerts[3].x = spr->x1;
|
||
baseWallVerts[2].x = baseWallVerts[1].x = spr->x2;
|
||
baseWallVerts[0].z = baseWallVerts[3].z = spr->z1;
|
||
baseWallVerts[1].z = baseWallVerts[2].z = spr->z2;
|
||
|
||
baseWallVerts[2].y = baseWallVerts[3].y = spr->ty;
|
||
if (spr->mobj && fabsf(this_scale - 1.0f) > 1.0E-36f)
|
||
baseWallVerts[0].y = baseWallVerts[1].y = spr->ty - gpatch->height * this_scale;
|
||
else
|
||
baseWallVerts[0].y = baseWallVerts[1].y = spr->ty - gpatch->height;
|
||
|
||
v1x = FLOAT_TO_FIXED(spr->x1);
|
||
v1y = FLOAT_TO_FIXED(spr->z1);
|
||
v2x = FLOAT_TO_FIXED(spr->x2);
|
||
v2y = FLOAT_TO_FIXED(spr->z2);
|
||
|
||
if (spr->flip)
|
||
{
|
||
baseWallVerts[0].s = baseWallVerts[3].s = gpatch->max_s;
|
||
baseWallVerts[2].s = baseWallVerts[1].s = 0;
|
||
}
|
||
else
|
||
{
|
||
baseWallVerts[0].s = baseWallVerts[3].s = 0;
|
||
baseWallVerts[2].s = baseWallVerts[1].s = gpatch->max_s;
|
||
}
|
||
|
||
// flip the texture coords (look familiar?)
|
||
if (spr->vflip)
|
||
{
|
||
baseWallVerts[3].t = baseWallVerts[2].t = gpatch->max_t;
|
||
baseWallVerts[0].t = baseWallVerts[1].t = 0;
|
||
}
|
||
else
|
||
{
|
||
baseWallVerts[3].t = baseWallVerts[2].t = 0;
|
||
baseWallVerts[0].t = baseWallVerts[1].t = gpatch->max_t;
|
||
}
|
||
|
||
// Let dispoffset work first since this adjust each vertex
|
||
HWR_RotateSpritePolyToAim(spr, baseWallVerts);
|
||
|
||
// push it toward the camera to mitigate floor-clipping sprites
|
||
{
|
||
float sprdist = sqrtf((spr->x1 - gr_viewx)*(spr->x1 - gr_viewx) + (spr->z1 - gr_viewy)*(spr->z1 - gr_viewy) + (spr->ty - gr_viewz)*(spr->ty - gr_viewz));
|
||
float distfact = ((2.0f*spr->dispoffset) + 20.0f) / sprdist;
|
||
for (i = 0; i < 4; i++)
|
||
{
|
||
baseWallVerts[i].x += (gr_viewx - baseWallVerts[i].x)*distfact;
|
||
baseWallVerts[i].z += (gr_viewy - baseWallVerts[i].z)*distfact;
|
||
baseWallVerts[i].y += (gr_viewz - baseWallVerts[i].y)*distfact;
|
||
}
|
||
}
|
||
|
||
realtop = top = baseWallVerts[3].y;
|
||
realbot = bot = baseWallVerts[0].y;
|
||
towtop = baseWallVerts[3].t;
|
||
towbot = baseWallVerts[0].t;
|
||
towmult = (towbot - towtop) / (top - bot);
|
||
|
||
#ifdef ESLOPE
|
||
endrealtop = endtop = baseWallVerts[2].y;
|
||
endrealbot = endbot = baseWallVerts[1].y;
|
||
#endif
|
||
|
||
// copy the contents of baseWallVerts into the drawn wallVerts array
|
||
// baseWallVerts is used to know the final shape to easily get the vertex
|
||
// co-ordinates
|
||
memcpy(wallVerts, baseWallVerts, sizeof(baseWallVerts));
|
||
|
||
if (!cv_translucency.value) // translucency disabled
|
||
{
|
||
Surf.PolyColor.s.alpha = 0xFF;
|
||
blend = PF_Translucent|PF_Occlude;
|
||
}
|
||
else if (spr->mobj->flags2 & MF2_SHADOW)
|
||
{
|
||
Surf.PolyColor.s.alpha = 0x40;
|
||
blend = PF_Translucent;
|
||
}
|
||
else if (spr->mobj->frame & FF_TRANSMASK)
|
||
blend = HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf);
|
||
else
|
||
{
|
||
// BP: i agree that is little better in environement but it don't
|
||
// work properly under glide nor with fogcolor to ffffff :(
|
||
// Hurdler: PF_Environement would be cool, but we need to fix
|
||
// the issue with the fog before
|
||
Surf.PolyColor.s.alpha = 0xFF;
|
||
blend = PF_Translucent|PF_Occlude;
|
||
}
|
||
|
||
alpha = Surf.PolyColor.s.alpha;
|
||
|
||
temp = FLOAT_TO_FIXED(realtop);
|
||
|
||
#ifdef ESLOPE
|
||
// Start with the lightlevel and colormap from the top of the sprite
|
||
lightlevel = 255;
|
||
colormap = list[sector->numlights - 1].extra_colormap;
|
||
|
||
if (!(spr->mobj->frame & FF_FULLBRIGHT))
|
||
{
|
||
lightlevel = *list[sector->numlights - 1].lightlevel;
|
||
if (spr->mobj->frame & FF_SEMIBRIGHT)
|
||
lightlevel = 128 + (lightlevel>>1);
|
||
}
|
||
|
||
for (i = 1; i < sector->numlights; i++)
|
||
{
|
||
fixed_t h = sector->lightlist[i].slope ? P_GetZAt(sector->lightlist[i].slope, spr->mobj->x, spr->mobj->y)
|
||
: sector->lightlist[i].height;
|
||
if (h <= temp)
|
||
{
|
||
if (!(spr->mobj->frame & FF_FULLBRIGHT))
|
||
{
|
||
lightlevel = *list[i-1].lightlevel;
|
||
if (spr->mobj->frame & FF_SEMIBRIGHT)
|
||
lightlevel = 128 + (lightlevel>>1);
|
||
}
|
||
colormap = list[i-1].extra_colormap;
|
||
break;
|
||
}
|
||
}
|
||
#else
|
||
i = R_GetPlaneLight(sector, temp, false);
|
||
if (!(spr->mobj->frame & FF_FULLBRIGHT))
|
||
{
|
||
lightlevel = *list[i].lightlevel;
|
||
if (spr->mobj->frame & FF_SEMIBRIGHT)
|
||
lightlevel = 128 + (lightlevel>>1);
|
||
}
|
||
colormap = list[i].extra_colormap;
|
||
#endif
|
||
|
||
for (i = 0; i < sector->numlights; i++)
|
||
{
|
||
#ifdef ESLOPE
|
||
if (endtop < endrealbot)
|
||
#endif
|
||
if (top < realbot)
|
||
return;
|
||
|
||
// even if we aren't changing colormap or lightlevel, we still need to continue drawing down the sprite
|
||
if (!(list[i].flags & FF_NOSHADE) && (list[i].flags & FF_CUTSPRITES))
|
||
{
|
||
if (!(spr->mobj->frame & FF_FULLBRIGHT))
|
||
{
|
||
lightlevel = *list[i].lightlevel;
|
||
if (spr->mobj->frame & FF_SEMIBRIGHT)
|
||
lightlevel = 128 + (lightlevel>>1);
|
||
}
|
||
colormap = list[i].extra_colormap;
|
||
}
|
||
|
||
#ifdef ESLOPE
|
||
if (i + 1 < sector->numlights)
|
||
{
|
||
if (list[i+1].slope)
|
||
{
|
||
temp = P_GetZAt(list[i+1].slope, v1x, v1y);
|
||
bheight = FIXED_TO_FLOAT(temp);
|
||
temp = P_GetZAt(list[i+1].slope, v2x, v2y);
|
||
endbheight = FIXED_TO_FLOAT(temp);
|
||
}
|
||
else
|
||
bheight = endbheight = FIXED_TO_FLOAT(list[i+1].height);
|
||
}
|
||
else
|
||
{
|
||
bheight = realbot;
|
||
endbheight = endrealbot;
|
||
}
|
||
#else
|
||
if (i + 1 < sector->numlights)
|
||
{
|
||
bheight = FIXED_TO_FLOAT(list[i+1].height);
|
||
}
|
||
else
|
||
{
|
||
bheight = realbot;
|
||
}
|
||
#endif
|
||
|
||
#ifdef ESLOPE
|
||
if (endbheight >= endtop)
|
||
#endif
|
||
if (bheight >= top)
|
||
continue;
|
||
|
||
bot = bheight;
|
||
|
||
if (bot < realbot)
|
||
bot = realbot;
|
||
|
||
#ifdef ESLOPE
|
||
endbot = endbheight;
|
||
|
||
if (endbot < endrealbot)
|
||
endbot = endrealbot;
|
||
#endif
|
||
|
||
#ifdef ESLOPE
|
||
wallVerts[3].t = towtop + ((realtop - top) * towmult);
|
||
wallVerts[2].t = towtop + ((endrealtop - endtop) * towmult);
|
||
wallVerts[0].t = towtop + ((realtop - bot) * towmult);
|
||
wallVerts[1].t = towtop + ((endrealtop - endbot) * towmult);
|
||
|
||
wallVerts[3].y = top;
|
||
wallVerts[2].y = endtop;
|
||
wallVerts[0].y = bot;
|
||
wallVerts[1].y = endbot;
|
||
|
||
// The x and y only need to be adjusted in the case that it's not a papersprite
|
||
if (cv_grspritebillboarding.value && spr->mobj && !(spr->mobj->frame & FF_PAPERSPRITE))
|
||
{
|
||
// Get the x and z of the vertices so billboarding draws correctly
|
||
realheight = realbot - realtop;
|
||
endrealheight = endrealbot - endrealtop;
|
||
heightmult = (realtop - top) / realheight;
|
||
wallVerts[3].x = baseWallVerts[3].x + (baseWallVerts[3].x - baseWallVerts[0].x) * heightmult;
|
||
wallVerts[3].z = baseWallVerts[3].z + (baseWallVerts[3].z - baseWallVerts[0].z) * heightmult;
|
||
|
||
heightmult = (endrealtop - endtop) / endrealheight;
|
||
wallVerts[2].x = baseWallVerts[2].x + (baseWallVerts[2].x - baseWallVerts[1].x) * heightmult;
|
||
wallVerts[2].z = baseWallVerts[2].z + (baseWallVerts[2].z - baseWallVerts[1].z) * heightmult;
|
||
|
||
heightmult = (realtop - bot) / realheight;
|
||
wallVerts[0].x = baseWallVerts[3].x + (baseWallVerts[3].x - baseWallVerts[0].x) * heightmult;
|
||
wallVerts[0].z = baseWallVerts[3].z + (baseWallVerts[3].z - baseWallVerts[0].z) * heightmult;
|
||
|
||
heightmult = (endrealtop - endbot) / endrealheight;
|
||
wallVerts[1].x = baseWallVerts[2].x + (baseWallVerts[2].x - baseWallVerts[1].x) * heightmult;
|
||
wallVerts[1].z = baseWallVerts[2].z + (baseWallVerts[2].z - baseWallVerts[1].z) * heightmult;
|
||
}
|
||
#else
|
||
wallVerts[3].t = wallVerts[2].t = towtop + ((realtop - top) * towmult);
|
||
wallVerts[0].t = wallVerts[1].t = towtop + ((realtop - bot) * towmult);
|
||
|
||
wallVerts[2].y = wallVerts[3].y = top;
|
||
wallVerts[0].y = wallVerts[1].y = bot;
|
||
|
||
// The x and y only need to be adjusted in the case that it's not a papersprite
|
||
if (cv_grspritebillboarding.value && spr->mobj && !(spr->mobj->frame & FF_PAPERSPRITE))
|
||
{
|
||
// Get the x and z of the vertices so billboarding draws correctly
|
||
realheight = realbot - realtop;
|
||
heightmult = (realtop - top) / realheight;
|
||
wallVerts[3].x = baseWallVerts[3].x + (baseWallVerts[3].x - baseWallVerts[0].x) * heightmult;
|
||
wallVerts[3].z = baseWallVerts[3].z + (baseWallVerts[3].z - baseWallVerts[0].z) * heightmult;
|
||
wallVerts[2].x = baseWallVerts[2].x + (baseWallVerts[2].x - baseWallVerts[1].x) * heightmult;
|
||
wallVerts[2].z = baseWallVerts[2].z + (baseWallVerts[2].z - baseWallVerts[1].z) * heightmult;
|
||
|
||
heightmult = (realtop - bot) / realheight;
|
||
wallVerts[0].x = baseWallVerts[3].x + (baseWallVerts[3].x - baseWallVerts[0].x) * heightmult;
|
||
wallVerts[0].z = baseWallVerts[3].z + (baseWallVerts[3].z - baseWallVerts[0].z) * heightmult;
|
||
wallVerts[1].x = baseWallVerts[2].x + (baseWallVerts[2].x - baseWallVerts[1].x) * heightmult;
|
||
wallVerts[1].z = baseWallVerts[2].z + (baseWallVerts[2].z - baseWallVerts[1].z) * heightmult;
|
||
}
|
||
#endif
|
||
|
||
HWR_Lighting(&Surf, lightlevel, colormap);
|
||
|
||
Surf.PolyColor.s.alpha = alpha;
|
||
|
||
HWD.pfnSetShader(3); // sprite shader
|
||
HWD.pfnDrawPolygon(&Surf, wallVerts, 4, blend|PF_Modulated);
|
||
|
||
top = bot;
|
||
#ifdef ESLOPE
|
||
endtop = endbot;
|
||
#endif
|
||
}
|
||
|
||
bot = realbot;
|
||
#ifdef ESLOPE
|
||
endbot = endrealbot;
|
||
if (endtop <= endrealbot)
|
||
#endif
|
||
if (top <= realbot)
|
||
return;
|
||
|
||
// If we're ever down here, somehow the above loop hasn't draw all the light levels of sprite
|
||
#ifdef ESLOPE
|
||
wallVerts[3].t = towtop + ((realtop - top) * towmult);
|
||
wallVerts[2].t = towtop + ((endrealtop - endtop) * towmult);
|
||
wallVerts[0].t = towtop + ((realtop - bot) * towmult);
|
||
wallVerts[1].t = towtop + ((endrealtop - endbot) * towmult);
|
||
|
||
wallVerts[3].y = top;
|
||
wallVerts[2].y = endtop;
|
||
wallVerts[0].y = bot;
|
||
wallVerts[1].y = endbot;
|
||
#else
|
||
wallVerts[3].t = wallVerts[2].t = towtop + ((realtop - top) * towmult);
|
||
wallVerts[0].t = wallVerts[1].t = towtop + ((realtop - bot) * towmult);
|
||
|
||
wallVerts[2].y = wallVerts[3].y = top;
|
||
wallVerts[0].y = wallVerts[1].y = bot;
|
||
#endif
|
||
|
||
HWR_Lighting(&Surf, lightlevel, colormap);
|
||
|
||
Surf.PolyColor.s.alpha = alpha;
|
||
|
||
HWD.pfnSetShader(3); // sprite shader
|
||
HWD.pfnDrawPolygon(&Surf, wallVerts, 4, blend|PF_Modulated);
|
||
}
|
||
|
||
// -----------------+
|
||
// HWR_DrawSprite : Draw flat sprites
|
||
// : (monsters, bonuses, weapons, lights, ...)
|
||
// Returns :
|
||
// -----------------+
|
||
static void HWR_DrawSprite(gr_vissprite_t *spr)
|
||
{
|
||
float this_scale = 1.0f;
|
||
FOutVector wallVerts[4];
|
||
GLPatch_t *gpatch; // sprite patch converted to hardware
|
||
FSurfaceInfo Surf;
|
||
const boolean hires = (spr->mobj && spr->mobj->skin && ((skin_t *)spr->mobj->skin)->flags & SF_HIRES);
|
||
if (spr->mobj)
|
||
this_scale = FIXED_TO_FLOAT(spr->mobj->scale);
|
||
if (hires)
|
||
this_scale = this_scale * FIXED_TO_FLOAT(((skin_t *)spr->mobj->skin)->highresscale);
|
||
|
||
if (!spr->mobj)
|
||
return;
|
||
|
||
if (!spr->mobj->subsector)
|
||
return;
|
||
|
||
if (spr->mobj->subsector->sector->numlights)
|
||
{
|
||
HWR_SplitSprite(spr);
|
||
return;
|
||
}
|
||
|
||
// cache sprite graphics
|
||
//12/12/99: Hurdler:
|
||
// OK, I don't change anything for MD2 support because I want to be
|
||
// sure to do it the right way. So actually, we keep normal sprite
|
||
// in memory and we add the md2 model if it exists for that sprite
|
||
|
||
gpatch = W_CachePatchNum(spr->patchlumpnum, PU_CACHE);
|
||
|
||
// create the sprite billboard
|
||
//
|
||
// 3--2
|
||
// | /|
|
||
// |/ |
|
||
// 0--1
|
||
|
||
// these were already scaled in HWR_ProjectSprite
|
||
wallVerts[0].x = wallVerts[3].x = spr->x1;
|
||
wallVerts[2].x = wallVerts[1].x = spr->x2;
|
||
wallVerts[2].y = wallVerts[3].y = spr->ty;
|
||
if (spr->mobj && fabsf(this_scale - 1.0f) > 1.0E-36f)
|
||
wallVerts[0].y = wallVerts[1].y = spr->ty - gpatch->height * this_scale;
|
||
else
|
||
wallVerts[0].y = wallVerts[1].y = spr->ty - gpatch->height;
|
||
|
||
// make a wall polygon (with 2 triangles), using the floor/ceiling heights,
|
||
// and the 2d map coords of start/end vertices
|
||
wallVerts[0].z = wallVerts[3].z = spr->z1;
|
||
wallVerts[1].z = wallVerts[2].z = spr->z2;
|
||
|
||
if (spr->flip)
|
||
{
|
||
wallVerts[0].s = wallVerts[3].s = gpatch->max_s;
|
||
wallVerts[2].s = wallVerts[1].s = 0;
|
||
}else{
|
||
wallVerts[0].s = wallVerts[3].s = 0;
|
||
wallVerts[2].s = wallVerts[1].s = gpatch->max_s;
|
||
}
|
||
|
||
// flip the texture coords (look familiar?)
|
||
if (spr->vflip)
|
||
{
|
||
wallVerts[3].t = wallVerts[2].t = gpatch->max_t;
|
||
wallVerts[0].t = wallVerts[1].t = 0;
|
||
}else{
|
||
wallVerts[3].t = wallVerts[2].t = 0;
|
||
wallVerts[0].t = wallVerts[1].t = gpatch->max_t;
|
||
}
|
||
|
||
// cache the patch in the graphics card memory
|
||
//12/12/99: Hurdler: same comment as above (for md2)
|
||
//Hurdler: 25/04/2000: now support colormap in hardware mode
|
||
HWR_GetMappedPatch(gpatch, spr->colormap);
|
||
|
||
// if it has a dispoffset, push it a little towards the camera
|
||
if (spr->dispoffset) {
|
||
float co = -gr_viewcos*(0.05f*spr->dispoffset);
|
||
float si = -gr_viewsin*(0.05f*spr->dispoffset);
|
||
wallVerts[0].z = wallVerts[3].z = wallVerts[0].z+si;
|
||
wallVerts[1].z = wallVerts[2].z = wallVerts[1].z+si;
|
||
wallVerts[0].x = wallVerts[3].x = wallVerts[0].x+co;
|
||
wallVerts[1].x = wallVerts[2].x = wallVerts[1].x+co;
|
||
}
|
||
|
||
// Let dispoffset work first since this adjust each vertex
|
||
// ...nah
|
||
HWR_RotateSpritePolyToAim(spr, wallVerts);
|
||
|
||
// push it toward the camera to mitigate floor-clipping sprites
|
||
{
|
||
float sprdist = sqrtf((spr->x1 - gr_viewx)*(spr->x1 - gr_viewx) + (spr->z1 - gr_viewy)*(spr->z1 - gr_viewy) + (spr->ty - gr_viewz)*(spr->ty - gr_viewz));
|
||
float distfact = ((2.0f*spr->dispoffset) + 20.0f) / sprdist;
|
||
size_t i;
|
||
for (i = 0; i < 4; i++)
|
||
{
|
||
wallVerts[i].x += (gr_viewx - wallVerts[i].x)*distfact;
|
||
wallVerts[i].z += (gr_viewy - wallVerts[i].z)*distfact;
|
||
wallVerts[i].y += (gr_viewz - wallVerts[i].y)*distfact;
|
||
}
|
||
}
|
||
|
||
// This needs to be AFTER the shadows so that the regular sprites aren't drawn completely black.
|
||
// sprite lighting by modulating the RGB components
|
||
/// \todo coloured
|
||
|
||
// colormap test
|
||
{
|
||
sector_t *sector = spr->mobj->subsector->sector;
|
||
UINT8 lightlevel = 255;
|
||
extracolormap_t *colormap = sector->extra_colormap;
|
||
|
||
if (!(spr->mobj->frame & FF_FULLBRIGHT))
|
||
{
|
||
lightlevel = sector->lightlevel;
|
||
if (spr->mobj->frame & FF_SEMIBRIGHT)
|
||
lightlevel = 128 + (lightlevel>>1);
|
||
}
|
||
|
||
HWR_Lighting(&Surf, lightlevel, colormap);
|
||
}
|
||
|
||
{
|
||
FBITFIELD blend = 0;
|
||
if (!cv_translucency.value) // translucency disabled
|
||
{
|
||
Surf.PolyColor.s.alpha = 0xFF;
|
||
blend = PF_Translucent|PF_Occlude;
|
||
}
|
||
else if (spr->mobj->flags2 & MF2_SHADOW)
|
||
{
|
||
Surf.PolyColor.s.alpha = 0x40;
|
||
blend = PF_Translucent;
|
||
}
|
||
else if (spr->mobj->frame & FF_TRANSMASK)
|
||
blend = HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf);
|
||
else
|
||
{
|
||
// BP: i agree that is little better in environement but it don't
|
||
// work properly under glide nor with fogcolor to ffffff :(
|
||
// Hurdler: PF_Environement would be cool, but we need to fix
|
||
// the issue with the fog before
|
||
Surf.PolyColor.s.alpha = 0xFF;
|
||
blend = PF_Translucent|PF_Occlude;
|
||
}
|
||
|
||
HWD.pfnSetShader(3); // sprite shader
|
||
HWD.pfnDrawPolygon(&Surf, wallVerts, 4, blend|PF_Modulated);
|
||
}
|
||
}
|
||
|
||
// Sprite drawer for precipitation
|
||
static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr)
|
||
{
|
||
FBITFIELD blend = 0;
|
||
FOutVector wallVerts[4];
|
||
GLPatch_t *gpatch; // sprite patch converted to hardware
|
||
FSurfaceInfo Surf;
|
||
|
||
if (!spr->mobj)
|
||
return;
|
||
|
||
if (!spr->mobj->subsector)
|
||
return;
|
||
|
||
// cache sprite graphics
|
||
gpatch = W_CachePatchNum(spr->patchlumpnum, PU_CACHE);
|
||
|
||
// create the sprite billboard
|
||
//
|
||
// 3--2
|
||
// | /|
|
||
// |/ |
|
||
// 0--1
|
||
wallVerts[0].x = wallVerts[3].x = spr->x1;
|
||
wallVerts[2].x = wallVerts[1].x = spr->x2;
|
||
wallVerts[2].y = wallVerts[3].y = spr->ty;
|
||
wallVerts[0].y = wallVerts[1].y = spr->ty - gpatch->height;
|
||
|
||
// make a wall polygon (with 2 triangles), using the floor/ceiling heights,
|
||
// and the 2d map coords of start/end vertices
|
||
wallVerts[0].z = wallVerts[3].z = spr->z1;
|
||
wallVerts[1].z = wallVerts[2].z = spr->z2;
|
||
|
||
// Let dispoffset work first since this adjust each vertex
|
||
HWR_RotateSpritePolyToAim(spr, wallVerts);
|
||
|
||
wallVerts[0].s = wallVerts[3].s = 0;
|
||
wallVerts[2].s = wallVerts[1].s = gpatch->max_s;
|
||
|
||
wallVerts[3].t = wallVerts[2].t = 0;
|
||
wallVerts[0].t = wallVerts[1].t = gpatch->max_t;
|
||
|
||
// cache the patch in the graphics card memory
|
||
//12/12/99: Hurdler: same comment as above (for md2)
|
||
//Hurdler: 25/04/2000: now support colormap in hardware mode
|
||
HWR_GetMappedPatch(gpatch, spr->colormap);
|
||
|
||
// colormap test
|
||
{
|
||
sector_t *sector = spr->mobj->subsector->sector;
|
||
UINT8 lightlevel = 255;
|
||
extracolormap_t *colormap = sector->extra_colormap;
|
||
|
||
if (sector->numlights)
|
||
{
|
||
INT32 light;
|
||
|
||
light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false); // Always use the light at the top instead of whatever I was doing before
|
||
|
||
if (!(spr->mobj->frame & FF_FULLBRIGHT))
|
||
lightlevel = *sector->lightlist[light].lightlevel;
|
||
|
||
if (sector->lightlist[light].extra_colormap)
|
||
colormap = sector->lightlist[light].extra_colormap;
|
||
}
|
||
else
|
||
{
|
||
if (!(spr->mobj->frame & FF_FULLBRIGHT))
|
||
lightlevel = sector->lightlevel;
|
||
|
||
if (sector->extra_colormap)
|
||
colormap = sector->extra_colormap;
|
||
}
|
||
|
||
if (spr->mobj->frame & FF_SEMIBRIGHT)
|
||
lightlevel = 128 + (lightlevel>>1);
|
||
|
||
HWR_Lighting(&Surf, lightlevel, colormap);
|
||
}
|
||
|
||
if (spr->mobj->flags2 & MF2_SHADOW)
|
||
{
|
||
Surf.PolyColor.s.alpha = 0x40;
|
||
blend = PF_Translucent;
|
||
}
|
||
else if (spr->mobj->frame & FF_TRANSMASK)
|
||
blend = HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf);
|
||
else
|
||
{
|
||
// BP: i agree that is little better in environement but it don't
|
||
// work properly under glide nor with fogcolor to ffffff :(
|
||
// Hurdler: PF_Environement would be cool, but we need to fix
|
||
// the issue with the fog before
|
||
Surf.PolyColor.s.alpha = 0xFF;
|
||
blend = PF_Translucent|PF_Occlude;
|
||
}
|
||
|
||
HWD.pfnSetShader(3); // sprite shader
|
||
HWD.pfnDrawPolygon(&Surf, wallVerts, 4, blend|PF_Modulated);
|
||
}
|
||
|
||
// --------------------------------------------------------------------------
|
||
// Sort vissprites by distance
|
||
// --------------------------------------------------------------------------
|
||
|
||
gr_vissprite_t* gr_vsprorder[MAXVISSPRITES];
|
||
|
||
// For more correct transparency the transparent sprites would need to be
|
||
// sorted and drawn together with transparent surfaces.
|
||
static int CompareVisSprites(const void *p1, const void *p2)
|
||
{
|
||
gr_vissprite_t* spr1 = *(gr_vissprite_t*const*)p1;
|
||
gr_vissprite_t* spr2 = *(gr_vissprite_t*const*)p2;
|
||
int idiff;
|
||
float fdiff;
|
||
|
||
// make transparent sprites last
|
||
// "boolean to int"
|
||
|
||
int transparency1 = (spr1->mobj->flags2 & MF2_SHADOW) || (spr1->mobj->frame & FF_TRANSMASK);
|
||
int transparency2 = (spr2->mobj->flags2 & MF2_SHADOW) || (spr2->mobj->frame & FF_TRANSMASK);
|
||
idiff = transparency1 - transparency2;
|
||
if (idiff != 0) return idiff;
|
||
|
||
fdiff = spr2->tz - spr1->tz;// this order seems correct when checking with apitrace. Back to front.
|
||
if (fabsf(fdiff) < 1.0E-36f)
|
||
return spr1->dispoffset - spr2->dispoffset;// smallest dispoffset first if sprites are at (almost) same location.
|
||
else if (fdiff > 0)
|
||
return 1;
|
||
else
|
||
return -1;
|
||
}
|
||
|
||
|
||
static void HWR_SortVisSprites(void)
|
||
{
|
||
UINT32 i;
|
||
for (i = 0; i < gr_visspritecount; i++)
|
||
{
|
||
gr_vsprorder[i] = HWR_GetVisSprite(i);
|
||
}
|
||
qsort(gr_vsprorder, gr_visspritecount, sizeof(gr_vissprite_t*), CompareVisSprites);
|
||
}
|
||
|
||
// A drawnode is something that points to a 3D floor, 3D side, or masked
|
||
// middle texture. This is used for sorting with sprites.
|
||
typedef struct
|
||
{
|
||
FOutVector wallVerts[4];
|
||
FSurfaceInfo Surf;
|
||
INT32 texnum;
|
||
FBITFIELD blend;
|
||
INT32 drawcount;
|
||
boolean fogwall;
|
||
INT32 lightlevel;
|
||
extracolormap_t *wallcolormap; // Doing the lighting in HWR_RenderWall now for correct fog after sorting
|
||
} wallinfo_t;
|
||
|
||
static wallinfo_t *wallinfo = NULL;
|
||
static size_t numwalls = 0; // a list of transparent walls to be drawn
|
||
|
||
typedef struct
|
||
{
|
||
extrasubsector_t *xsub;
|
||
boolean isceiling;
|
||
fixed_t fixedheight;
|
||
INT32 lightlevel;
|
||
lumpnum_t lumpnum;
|
||
INT32 alpha;
|
||
sector_t *FOFSector;
|
||
FBITFIELD blend;
|
||
boolean fogplane;
|
||
extracolormap_t *planecolormap;
|
||
INT32 drawcount;
|
||
} planeinfo_t;
|
||
|
||
static size_t numplanes = 0; // a list of transparent floors to be drawn
|
||
static planeinfo_t *planeinfo = NULL;
|
||
|
||
typedef struct
|
||
{
|
||
polyobj_t *polysector;
|
||
boolean isceiling;
|
||
fixed_t fixedheight;
|
||
INT32 lightlevel;
|
||
lumpnum_t lumpnum;
|
||
INT32 alpha;
|
||
sector_t *FOFSector;
|
||
FBITFIELD blend;
|
||
extracolormap_t *planecolormap;
|
||
INT32 drawcount;
|
||
} polyplaneinfo_t;
|
||
|
||
static size_t numpolyplanes = 0; // a list of transparent poyobject floors to be drawn
|
||
static polyplaneinfo_t *polyplaneinfo = NULL;
|
||
|
||
typedef struct gr_drawnode_s
|
||
{
|
||
planeinfo_t *plane;
|
||
polyplaneinfo_t *polyplane;
|
||
wallinfo_t *wall;
|
||
gr_vissprite_t *sprite;
|
||
} gr_drawnode_t;
|
||
|
||
#define MAX_TRANSPARENTWALL 256
|
||
#define MAX_TRANSPARENTFLOOR 512
|
||
|
||
// This will likely turn into a copy of HWR_Add3DWater and replace it.
|
||
void HWR_AddTransparentFloor(lumpnum_t lumpnum, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, boolean fogplane, extracolormap_t *planecolormap)
|
||
{
|
||
static size_t allocedplanes = 0;
|
||
|
||
// Force realloc if buffer has been freed
|
||
if (!planeinfo)
|
||
allocedplanes = 0;
|
||
|
||
if (allocedplanes < numplanes + 1)
|
||
{
|
||
allocedplanes += MAX_TRANSPARENTFLOOR;
|
||
Z_Realloc(planeinfo, allocedplanes * sizeof (*planeinfo), PU_LEVEL, &planeinfo);
|
||
}
|
||
|
||
planeinfo[numplanes].isceiling = isceiling;
|
||
planeinfo[numplanes].fixedheight = fixedheight;
|
||
planeinfo[numplanes].lightlevel = lightlevel;
|
||
planeinfo[numplanes].lumpnum = lumpnum;
|
||
planeinfo[numplanes].xsub = xsub;
|
||
planeinfo[numplanes].alpha = alpha;
|
||
planeinfo[numplanes].FOFSector = FOFSector;
|
||
planeinfo[numplanes].blend = blend;
|
||
planeinfo[numplanes].fogplane = fogplane;
|
||
planeinfo[numplanes].planecolormap = planecolormap;
|
||
planeinfo[numplanes].drawcount = drawcount++;
|
||
|
||
numplanes++;
|
||
}
|
||
|
||
// Adding this for now until I can create extrasubsector info for polyobjects
|
||
// When that happens it'll just be done through HWR_AddTransparentFloor and HWR_RenderPlane
|
||
void HWR_AddTransparentPolyobjectFloor(lumpnum_t lumpnum, polyobj_t *polysector, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, extracolormap_t *planecolormap)
|
||
{
|
||
static size_t allocedpolyplanes = 0;
|
||
|
||
// Force realloc if buffer has been freed
|
||
if (!polyplaneinfo)
|
||
allocedpolyplanes = 0;
|
||
|
||
if (allocedpolyplanes < numpolyplanes + 1)
|
||
{
|
||
allocedpolyplanes += MAX_TRANSPARENTFLOOR;
|
||
Z_Realloc(polyplaneinfo, allocedpolyplanes * sizeof (*polyplaneinfo), PU_LEVEL, &polyplaneinfo);
|
||
}
|
||
|
||
polyplaneinfo[numpolyplanes].isceiling = isceiling;
|
||
polyplaneinfo[numpolyplanes].fixedheight = fixedheight;
|
||
polyplaneinfo[numpolyplanes].lightlevel = lightlevel;
|
||
polyplaneinfo[numpolyplanes].lumpnum = lumpnum;
|
||
polyplaneinfo[numpolyplanes].polysector = polysector;
|
||
polyplaneinfo[numpolyplanes].alpha = alpha;
|
||
polyplaneinfo[numpolyplanes].FOFSector = FOFSector;
|
||
polyplaneinfo[numpolyplanes].blend = blend;
|
||
polyplaneinfo[numpolyplanes].planecolormap = planecolormap;
|
||
polyplaneinfo[numpolyplanes].drawcount = drawcount++;
|
||
numpolyplanes++;
|
||
}
|
||
|
||
// putting sortindex and sortnode here so the comparator function can see them
|
||
gr_drawnode_t *sortnode;
|
||
size_t *sortindex;
|
||
|
||
static int CompareDrawNodes(const void *p1, const void *p2)
|
||
{
|
||
size_t n1 = *(const size_t*)p1;
|
||
size_t n2 = *(const size_t*)p2;
|
||
INT32 v1 = 0;
|
||
INT32 v2 = 0;
|
||
INT32 diff;
|
||
if (sortnode[n1].plane)
|
||
v1 = sortnode[n1].plane->drawcount;
|
||
else if (sortnode[n1].polyplane)
|
||
v1 = sortnode[n1].polyplane->drawcount;
|
||
else if (sortnode[n1].wall)
|
||
v1 = sortnode[n1].wall->drawcount;
|
||
else I_Error("n1 unknown");
|
||
|
||
if (sortnode[n2].plane)
|
||
v2 = sortnode[n2].plane->drawcount;
|
||
else if (sortnode[n2].polyplane)
|
||
v2 = sortnode[n2].polyplane->drawcount;
|
||
else if (sortnode[n2].wall)
|
||
v2 = sortnode[n2].wall->drawcount;
|
||
else I_Error("n2 unknown");
|
||
|
||
diff = v2 - v1;
|
||
if (diff == 0) I_Error("diff is zero");
|
||
return diff;
|
||
}
|
||
|
||
static int CompareDrawNodePlanes(const void *p1, const void *p2)
|
||
{
|
||
size_t n1 = *(const size_t*)p1;
|
||
size_t n2 = *(const size_t*)p2;
|
||
if (!sortnode[n1].plane) I_Error("Uh.. This isn't a plane! (n1)");
|
||
if (!sortnode[n2].plane) I_Error("Uh.. This isn't a plane! (n2)");
|
||
return ABS(sortnode[n2].plane->fixedheight - viewz) - ABS(sortnode[n1].plane->fixedheight - viewz);
|
||
}
|
||
|
||
// HWR_RenderDrawNodes
|
||
// Creates, sorts and renders a list of drawnodes for the current frame.
|
||
void HWR_RenderDrawNodes(void)
|
||
{
|
||
UINT32 i = 0, p = 0;
|
||
size_t run_start = 0;
|
||
|
||
// Dump EVERYTHING into a huge drawnode list. Then we'll sort it!
|
||
// Could this be optimized into _AddTransparentWall/_AddTransparentPlane?
|
||
// Hell yes! But sort algorithm must be modified to use a linked list.
|
||
sortnode = Z_Calloc((sizeof(planeinfo_t)*numplanes)
|
||
+ (sizeof(polyplaneinfo_t)*numpolyplanes)
|
||
+ (sizeof(wallinfo_t)*numwalls)
|
||
,PU_STATIC, NULL);
|
||
// todo:
|
||
// However, in reality we shouldn't be re-copying and shifting all this information
|
||
// that is already lying around. This should all be in some sort of linked list or lists.
|
||
sortindex = Z_Calloc(sizeof(size_t) * (numplanes + numpolyplanes + numwalls), PU_STATIC, NULL);
|
||
|
||
for (i = 0; i < numplanes; i++, p++)
|
||
{
|
||
sortnode[p].plane = &planeinfo[i];
|
||
sortindex[p] = p;
|
||
}
|
||
|
||
for (i = 0; i < numpolyplanes; i++, p++)
|
||
{
|
||
sortnode[p].polyplane = &polyplaneinfo[i];
|
||
sortindex[p] = p;
|
||
}
|
||
|
||
for (i = 0; i < numwalls; i++, p++)
|
||
{
|
||
sortnode[p].wall = &wallinfo[i];
|
||
sortindex[p] = p;
|
||
}
|
||
|
||
// p is the number of stuff to sort
|
||
|
||
// Add the 3D floors, thicksides, and masked textures...
|
||
// Instead of going through drawsegs, we need to iterate
|
||
// through the lists of masked textures and
|
||
// translucent ffloors being drawn.
|
||
|
||
// im not sure if this sort on the next line is needed.
|
||
// it sorts the list based on the value of the 'drawcount' member of the drawnodes.
|
||
// im thinking the list might already be in that order, but i havent bothered to check yet.
|
||
// anyway doing this sort does not hurt and does not take much time.
|
||
// the while loop after this sort is important however!
|
||
qsort(sortindex, p, sizeof(size_t), CompareDrawNodes);
|
||
|
||
// try solving floor order here. for each consecutive run of floors in the list, sort that run.
|
||
while (run_start < p-1)// p-1 because a 1 plane run at the end of the list does not count
|
||
{
|
||
// locate run start
|
||
if (sortnode[sortindex[run_start]].plane)
|
||
{
|
||
// found it, now look for run end
|
||
size_t run_end;// (inclusive)
|
||
for (i = run_start+1; i < p; i++)// size_t and UINT32 being used mixed here... shouldnt break anything though..
|
||
{
|
||
if (!sortnode[sortindex[i]].plane) break;
|
||
}
|
||
run_end = i-1;
|
||
if (run_end > run_start)// if there are multiple consecutive planes, not just one
|
||
{
|
||
// consecutive run of planes found, now sort it
|
||
// not sure how long these runs can be in reality...
|
||
qsort(sortindex + run_start, run_end - run_start + 1, sizeof(size_t), CompareDrawNodePlanes);
|
||
}
|
||
run_start = run_end + 1;// continue looking for runs coming right after this one
|
||
}
|
||
else
|
||
{
|
||
// this wasnt the run start, try next one
|
||
run_start++;
|
||
}
|
||
}
|
||
|
||
// Okay! Let's draw it all! Woo!
|
||
HWD.pfnSetTransform(&atransform);
|
||
HWD.pfnSetShader(0);
|
||
|
||
for (i = 0; i < p; i++)
|
||
{
|
||
if (sortnode[sortindex[i]].plane)
|
||
{
|
||
// We aren't traversing the BSP tree, so make gr_frontsector null to avoid crashes.
|
||
gr_frontsector = NULL;
|
||
|
||
if (!(sortnode[sortindex[i]].plane->blend & PF_NoTexture))
|
||
HWR_GetFlat(sortnode[sortindex[i]].plane->lumpnum, R_NoEncore(sortnode[sortindex[i]].plane->FOFSector, sortnode[sortindex[i]].plane->isceiling));
|
||
HWR_RenderPlane(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,
|
||
sortnode[sortindex[i]].plane->lumpnum, sortnode[sortindex[i]].plane->FOFSector, sortnode[sortindex[i]].plane->alpha, /*sortnode[sortindex[i]].plane->fogplane,*/ sortnode[sortindex[i]].plane->planecolormap);
|
||
}
|
||
else if (sortnode[sortindex[i]].polyplane)
|
||
{
|
||
// We aren't traversing the BSP tree, so make gr_frontsector null to avoid crashes.
|
||
gr_frontsector = NULL;
|
||
|
||
if (!(sortnode[sortindex[i]].polyplane->blend & PF_NoTexture))
|
||
HWR_GetFlat(sortnode[sortindex[i]].polyplane->lumpnum, R_NoEncore(sortnode[sortindex[i]].polyplane->FOFSector, sortnode[sortindex[i]].polyplane->isceiling));
|
||
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,
|
||
sortnode[sortindex[i]].polyplane->lumpnum, sortnode[sortindex[i]].polyplane->FOFSector, sortnode[sortindex[i]].polyplane->alpha, sortnode[sortindex[i]].polyplane->planecolormap);
|
||
}
|
||
else if (sortnode[sortindex[i]].wall)
|
||
{
|
||
if (!(sortnode[sortindex[i]].wall->blend & PF_NoTexture))
|
||
HWR_GetTexture(sortnode[sortindex[i]].wall->texnum);
|
||
HWR_RenderWall(sortnode[sortindex[i]].wall->wallVerts, &sortnode[sortindex[i]].wall->Surf, sortnode[sortindex[i]].wall->blend, sortnode[sortindex[i]].wall->fogwall,
|
||
sortnode[sortindex[i]].wall->lightlevel, sortnode[sortindex[i]].wall->wallcolormap);
|
||
}
|
||
}
|
||
|
||
numwalls = 0;
|
||
numplanes = 0;
|
||
numpolyplanes = 0;
|
||
|
||
// No mem leaks, please.
|
||
Z_Free(sortnode);
|
||
Z_Free(sortindex);
|
||
}
|
||
|
||
// --------------------------------------------------------------------------
|
||
// Draw all vissprites
|
||
// --------------------------------------------------------------------------
|
||
void HWR_DrawSprites(void)
|
||
{
|
||
UINT32 i;
|
||
for (i = 0; i < gr_visspritecount; i++)
|
||
{
|
||
gr_vissprite_t *spr = gr_vsprorder[i];
|
||
|
||
if (spr->precip)
|
||
{
|
||
HWR_DrawPrecipitationSprite(spr);
|
||
}
|
||
else
|
||
{
|
||
if (spr->mobj && spr->mobj->shadowscale && cv_shadow.value)
|
||
{
|
||
HWR_DrawDropShadow(spr->mobj, spr->mobj->shadowscale);
|
||
}
|
||
|
||
if (spr->mobj && spr->mobj->skin && spr->mobj->sprite == SPR_PLAY)
|
||
{
|
||
// 8/1/19: Only don't display player models if no default SPR_PLAY is found.
|
||
if (!cv_grmdls.value
|
||
|| ((md2_playermodels[(skin_t*)spr->mobj->skin-skins].notfound
|
||
|| md2_playermodels[(skin_t*)spr->mobj->skin-skins].scale < 0.0f)
|
||
&& ((!cv_grfallbackplayermodel.value)
|
||
|| md2_models[SPR_PLAY].notfound
|
||
|| md2_models[SPR_PLAY].scale < 0.0f))
|
||
|| spr->mobj->state == &states[S_PLAY_SIGN])
|
||
{
|
||
HWR_DrawSprite(spr);
|
||
}
|
||
else
|
||
{
|
||
HWR_DrawMD2(spr);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (!cv_grmdls.value || md2_models[spr->mobj->sprite].notfound || md2_models[spr->mobj->sprite].scale < 0.0f)
|
||
{
|
||
HWR_DrawSprite(spr);
|
||
}
|
||
else
|
||
{
|
||
HWR_DrawMD2(spr);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// --------------------------------------------------------------------------
|
||
// HWR_AddSprites
|
||
// During BSP traversal, this adds sprites by sector.
|
||
// --------------------------------------------------------------------------
|
||
void HWR_AddSprites(sector_t *sec)
|
||
{
|
||
mobj_t *thing;
|
||
precipmobj_t *precipthing;
|
||
fixed_t approx_dist, limit_dist;
|
||
|
||
INT32 splitflags;
|
||
boolean split_drawsprite; // drawing with splitscreen flags
|
||
|
||
// BSP is traversed by subsector.
|
||
// A sector might have been split into several
|
||
// subsectors during BSP building.
|
||
// Thus we check whether its already added.
|
||
if (sec->validcount == validcount)
|
||
return;
|
||
|
||
// Well, now it will be done.
|
||
sec->validcount = validcount;
|
||
|
||
// Handle all things in sector.
|
||
// If a limit exists, handle things a tiny bit different.
|
||
if ((limit_dist = (fixed_t)(cv_drawdist.value) * mapobjectscale))
|
||
{
|
||
for (thing = sec->thinglist; thing; thing = thing->snext)
|
||
{
|
||
|
||
split_drawsprite = false;
|
||
|
||
if (thing->sprite == SPR_NULL || thing->flags2 & MF2_DONTDRAW)
|
||
continue;
|
||
|
||
splitflags = thing->eflags & (MFE_DRAWONLYFORP1|MFE_DRAWONLYFORP2|MFE_DRAWONLYFORP3|MFE_DRAWONLYFORP4);
|
||
|
||
if (r_splitscreen && splitflags)
|
||
{
|
||
if (thing->eflags & MFE_DRAWONLYFORP1)
|
||
if (viewssnum == 0)
|
||
split_drawsprite = true;
|
||
|
||
if (thing->eflags & MFE_DRAWONLYFORP2)
|
||
if (viewssnum == 1)
|
||
split_drawsprite = true;
|
||
|
||
if (thing->eflags & MFE_DRAWONLYFORP3 && splitscreen > 1)
|
||
if (viewssnum == 2)
|
||
split_drawsprite = true;
|
||
|
||
if (thing->eflags & MFE_DRAWONLYFORP4 && splitscreen > 2)
|
||
if (viewssnum == 3)
|
||
split_drawsprite = true;
|
||
}
|
||
else
|
||
split_drawsprite = true;
|
||
|
||
if (!split_drawsprite)
|
||
continue;
|
||
|
||
approx_dist = P_AproxDistance(viewx-thing->x, viewy-thing->y);
|
||
|
||
if (approx_dist > limit_dist)
|
||
continue;
|
||
|
||
HWR_ProjectSprite(thing);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// Draw everything in sector, no checks
|
||
for (thing = sec->thinglist; thing; thing = thing->snext)
|
||
{
|
||
|
||
split_drawsprite = false;
|
||
|
||
if (thing->sprite == SPR_NULL || thing->flags2 & MF2_DONTDRAW)
|
||
continue;
|
||
|
||
splitflags = thing->eflags & (MFE_DRAWONLYFORP1|MFE_DRAWONLYFORP2|MFE_DRAWONLYFORP3|MFE_DRAWONLYFORP4);
|
||
|
||
if (r_splitscreen && splitflags)
|
||
{
|
||
if (thing->eflags & MFE_DRAWONLYFORP1)
|
||
if (viewssnum == 0)
|
||
split_drawsprite = true;
|
||
|
||
if (thing->eflags & MFE_DRAWONLYFORP2)
|
||
if (viewssnum == 1)
|
||
split_drawsprite = true;
|
||
|
||
if (thing->eflags & MFE_DRAWONLYFORP3 && splitscreen > 1)
|
||
if (viewssnum == 2)
|
||
split_drawsprite = true;
|
||
|
||
if (thing->eflags & MFE_DRAWONLYFORP4 && splitscreen > 2)
|
||
if (viewssnum == 3)
|
||
split_drawsprite = true;
|
||
}
|
||
else
|
||
split_drawsprite = true;
|
||
|
||
if (!split_drawsprite)
|
||
continue;
|
||
|
||
HWR_ProjectSprite(thing);
|
||
}
|
||
}
|
||
|
||
// No to infinite precipitation draw distance.
|
||
if ((limit_dist = (fixed_t)(cv_drawdist_precip.value) * mapobjectscale))
|
||
{
|
||
for (precipthing = sec->preciplist; precipthing; precipthing = precipthing->snext)
|
||
{
|
||
if (precipthing->precipflags & PCF_INVISIBLE)
|
||
continue;
|
||
|
||
approx_dist = P_AproxDistance(viewx-precipthing->x, viewy-precipthing->y);
|
||
|
||
if (approx_dist > limit_dist)
|
||
continue;
|
||
|
||
HWR_ProjectPrecipitationSprite(precipthing);
|
||
}
|
||
}
|
||
}
|
||
|
||
// --------------------------------------------------------------------------
|
||
// HWR_ProjectSprite
|
||
// Generates a vissprite for a thing if it might be visible.
|
||
// --------------------------------------------------------------------------
|
||
// BP why not use xtoviexangle/viewangletox like in bsp ?....
|
||
void HWR_ProjectSprite(mobj_t *thing)
|
||
{
|
||
const fixed_t thingxpos = thing->x + thing->sprxoff;
|
||
const fixed_t thingypos = thing->y + thing->spryoff;
|
||
const fixed_t thingzpos = thing->z + thing->sprzoff;
|
||
|
||
gr_vissprite_t *vis;
|
||
float tr_x, tr_y;
|
||
float tz;
|
||
float x1, x2;
|
||
float z1, z2;
|
||
float rightsin, rightcos;
|
||
float this_scale;
|
||
float gz, gzt;
|
||
spritedef_t *sprdef;
|
||
spriteframe_t *sprframe;
|
||
size_t lumpoff;
|
||
unsigned rot;
|
||
UINT8 flip;
|
||
boolean vflip = (!(thing->eflags & MFE_VERTICALFLIP) != !(thing->frame & FF_VERTICALFLIP));
|
||
angle_t ang;
|
||
const boolean papersprite = (thing->frame & FF_PAPERSPRITE);
|
||
INT32 heightsec, phs;
|
||
|
||
if (!thing)
|
||
return;
|
||
else
|
||
this_scale = FIXED_TO_FLOAT(thing->scale);
|
||
|
||
// transform the origin point
|
||
tr_x = FIXED_TO_FLOAT(thingxpos) - gr_viewx;
|
||
tr_y = FIXED_TO_FLOAT(thingypos) - gr_viewy;
|
||
|
||
// rotation around vertical axis
|
||
tz = (tr_x * gr_viewcos) + (tr_y * gr_viewsin);
|
||
|
||
// thing is behind view plane?
|
||
if (tz < ZCLIP_PLANE && !papersprite && (!cv_grmdls.value || md2_models[thing->sprite].notfound == true)) //Yellow: Only MD2's dont disappear
|
||
return;
|
||
|
||
// The above can stay as it works for cutting sprites that are too close
|
||
tr_x = FIXED_TO_FLOAT(thingxpos);
|
||
tr_y = FIXED_TO_FLOAT(thingypos);
|
||
|
||
// decide which patch to use for sprite relative to player
|
||
#ifdef RANGECHECK
|
||
if ((unsigned)thing->sprite >= numsprites)
|
||
I_Error("HWR_ProjectSprite: invalid sprite number %i ", thing->sprite);
|
||
#endif
|
||
|
||
rot = thing->frame&FF_FRAMEMASK;
|
||
|
||
//Fab : 02-08-98: 'skin' override spritedef currently used for skin
|
||
if (thing->skin && thing->sprite == SPR_PLAY)
|
||
sprdef = &((skin_t *)thing->skin)->spritedef;
|
||
else
|
||
sprdef = &sprites[thing->sprite];
|
||
|
||
if (rot >= sprdef->numframes)
|
||
{
|
||
CONS_Alert(CONS_ERROR, M_GetText("HWR_ProjectSprite: invalid sprite frame %s/%s for %s\n"),
|
||
sizeu1(rot), sizeu2(sprdef->numframes), sprnames[thing->sprite]);
|
||
thing->sprite = states[S_UNKNOWN].sprite;
|
||
thing->frame = states[S_UNKNOWN].frame;
|
||
sprdef = &sprites[thing->sprite];
|
||
rot = thing->frame&FF_FRAMEMASK;
|
||
thing->state->sprite = thing->sprite;
|
||
thing->state->frame = thing->frame;
|
||
}
|
||
|
||
sprframe = &sprdef->spriteframes[rot];
|
||
|
||
#ifdef PARANOIA
|
||
if (!sprframe)
|
||
I_Error("sprframes NULL for sprite %d\n", thing->sprite);
|
||
#endif
|
||
|
||
if (thing->player)
|
||
ang = R_PointToAngle (thingxpos, thingypos) - thing->player->frameangle;
|
||
else
|
||
ang = R_PointToAngle (thingxpos, thingypos) - thing->angle;
|
||
|
||
if (sprframe->rotate == SRF_SINGLE)
|
||
{
|
||
// use single rotation for all views
|
||
rot = 0; //Fab: for vis->patch below
|
||
lumpoff = sprframe->lumpid[0]; //Fab: see note above
|
||
flip = sprframe->flip; // Will only be 0x00 or 0xFF
|
||
|
||
if (papersprite && ang < ANGLE_180)
|
||
{
|
||
if (flip)
|
||
flip = 0;
|
||
else
|
||
flip = 255;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// choose a different rotation based on player view
|
||
if ((ang < ANGLE_180) && (sprframe->rotate & SRF_RIGHT)) // See from right
|
||
rot = 6; // F7 slot
|
||
else if ((ang >= ANGLE_180) && (sprframe->rotate & SRF_LEFT)) // See from left
|
||
rot = 2; // F3 slot
|
||
else // Normal behaviour
|
||
rot = (ang+ANGLE_202h)>>29;
|
||
|
||
//Fab: lumpid is the index for spritewidth,spriteoffset... tables
|
||
lumpoff = sprframe->lumpid[rot];
|
||
flip = sprframe->flip & (1<<rot);
|
||
|
||
if (papersprite && ang < ANGLE_180)
|
||
{
|
||
if (flip)
|
||
flip = 0;
|
||
else
|
||
flip = 1<<rot;
|
||
}
|
||
}
|
||
|
||
if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES)
|
||
this_scale = this_scale * FIXED_TO_FLOAT(((skin_t *)thing->skin)->highresscale);
|
||
|
||
if (papersprite)
|
||
{
|
||
rightsin = FIXED_TO_FLOAT(FINESINE((thing->angle)>>ANGLETOFINESHIFT));
|
||
rightcos = FIXED_TO_FLOAT(FINECOSINE((thing->angle)>>ANGLETOFINESHIFT));
|
||
}
|
||
else
|
||
{
|
||
rightsin = FIXED_TO_FLOAT(FINESINE((viewangle + ANGLE_90)>>ANGLETOFINESHIFT));
|
||
rightcos = FIXED_TO_FLOAT(FINECOSINE((viewangle + ANGLE_90)>>ANGLETOFINESHIFT));
|
||
}
|
||
|
||
if (flip)
|
||
{
|
||
x1 = (FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width - spritecachedinfo[lumpoff].offset) * this_scale);
|
||
x2 = (FIXED_TO_FLOAT(spritecachedinfo[lumpoff].offset) * this_scale);
|
||
}
|
||
else
|
||
{
|
||
x1 = (FIXED_TO_FLOAT(spritecachedinfo[lumpoff].offset) * this_scale);
|
||
x2 = (FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width - spritecachedinfo[lumpoff].offset) * this_scale);
|
||
}
|
||
|
||
z1 = tr_y + x1 * rightsin;
|
||
z2 = tr_y - x2 * rightsin;
|
||
x1 = tr_x + x1 * rightcos;
|
||
x2 = tr_x - x2 * rightcos;
|
||
|
||
if (vflip)
|
||
{
|
||
gz = FIXED_TO_FLOAT(thingzpos + thing->height) - FIXED_TO_FLOAT(spritecachedinfo[lumpoff].topoffset) * this_scale;
|
||
gzt = gz + FIXED_TO_FLOAT(spritecachedinfo[lumpoff].height) * this_scale;
|
||
}
|
||
else
|
||
{
|
||
gzt = FIXED_TO_FLOAT(thingzpos) + FIXED_TO_FLOAT(spritecachedinfo[lumpoff].topoffset) * this_scale;
|
||
gz = gzt - FIXED_TO_FLOAT(spritecachedinfo[lumpoff].height) * this_scale;
|
||
}
|
||
|
||
if (thing->subsector->sector->cullheight)
|
||
{
|
||
if (HWR_DoCulling(thing->subsector->sector->cullheight, viewsector->cullheight, gr_viewz, gz, gzt))
|
||
return;
|
||
}
|
||
|
||
heightsec = thing->subsector->sector->heightsec;
|
||
if (viewplayer->mo && viewplayer->mo->subsector)
|
||
phs = viewplayer->mo->subsector->sector->heightsec;
|
||
else
|
||
phs = -1;
|
||
|
||
if (heightsec != -1 && phs != -1) // only clip things which are in special sectors
|
||
{
|
||
if (gr_viewz < FIXED_TO_FLOAT(sectors[phs].floorheight) ?
|
||
FIXED_TO_FLOAT(thingzpos) >= FIXED_TO_FLOAT(sectors[heightsec].floorheight) :
|
||
gzt < FIXED_TO_FLOAT(sectors[heightsec].floorheight))
|
||
return;
|
||
if (gr_viewz > FIXED_TO_FLOAT(sectors[phs].ceilingheight) ?
|
||
gzt < FIXED_TO_FLOAT(sectors[heightsec].ceilingheight) && gr_viewz >= FIXED_TO_FLOAT(sectors[heightsec].ceilingheight) :
|
||
FIXED_TO_FLOAT(thingzpos) >= FIXED_TO_FLOAT(sectors[heightsec].ceilingheight))
|
||
return;
|
||
}
|
||
|
||
// store information in a vissprite
|
||
vis = HWR_NewVisSprite();
|
||
vis->x1 = x1;
|
||
vis->x2 = x2;
|
||
vis->z1 = z1;
|
||
vis->z2 = z2;
|
||
vis->tz = tz; // Keep tz for the simple sprite sorting that happens
|
||
vis->dispoffset = thing->info->dispoffset; // Monster Iestyn: 23/11/15: HARDWARE SUPPORT AT LAST
|
||
vis->patchlumpnum = sprframe->lumppat[rot];
|
||
vis->flip = flip;
|
||
vis->mobj = thing;
|
||
|
||
|
||
//Hurdler: 25/04/2000: now support colormap in hardware mode
|
||
if ((vis->mobj->flags & MF_BOSS) && (vis->mobj->flags2 & MF2_FRET) && (leveltime & 1)) // Bosses "flash"
|
||
{
|
||
if (vis->mobj->type == MT_CYBRAKDEMON)
|
||
vis->colormap = R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE);
|
||
else if (vis->mobj->type == MT_METALSONIC_BATTLE)
|
||
vis->colormap = R_GetTranslationColormap(TC_METALSONIC, 0, GTC_CACHE);
|
||
else
|
||
vis->colormap = R_GetTranslationColormap(TC_BOSS, 0, GTC_CACHE);
|
||
}
|
||
else if (thing->color)
|
||
{
|
||
// New colormap stuff for skins Tails 06-07-2002
|
||
if (thing->colorized)
|
||
vis->colormap = R_GetTranslationColormap(TC_RAINBOW, thing->color, GTC_CACHE);
|
||
else if (thing->skin && thing->sprite == SPR_PLAY) // This thing is a player!
|
||
{
|
||
size_t skinnum = (skin_t*)thing->skin-skins;
|
||
vis->colormap = R_GetTranslationColormap((INT32)skinnum, thing->color, GTC_CACHE);
|
||
}
|
||
else
|
||
vis->colormap = R_GetTranslationColormap(TC_DEFAULT, thing->color, GTC_CACHE);
|
||
}
|
||
else
|
||
{
|
||
vis->colormap = colormaps;
|
||
#ifdef GLENCORE
|
||
if (encoremap && (thing->flags & (MF_SCENERY|MF_NOTHINK)) && !(thing->flags & MF_DONTENCOREMAP))
|
||
vis->colormap += (256*32);
|
||
#endif
|
||
}
|
||
|
||
// set top/bottom coords
|
||
vis->ty = gzt;
|
||
|
||
//CONS_Debug(DBG_RENDER, "------------------\nH: sprite : %d\nH: frame : %x\nH: type : %d\nH: sname : %s\n\n",
|
||
// thing->sprite, thing->frame, thing->type, sprnames[thing->sprite]);
|
||
|
||
vis->vflip = vflip;
|
||
|
||
vis->precip = false;
|
||
}
|
||
|
||
// Precipitation projector for hardware mode
|
||
void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
|
||
{
|
||
gr_vissprite_t *vis;
|
||
float tr_x, tr_y;
|
||
float tz;
|
||
float x1, x2;
|
||
float z1, z2;
|
||
float rightsin, rightcos;
|
||
spritedef_t *sprdef;
|
||
spriteframe_t *sprframe;
|
||
size_t lumpoff;
|
||
unsigned rot = 0;
|
||
UINT8 flip;
|
||
|
||
// transform the origin point
|
||
tr_x = FIXED_TO_FLOAT(thing->x) - gr_viewx;
|
||
tr_y = FIXED_TO_FLOAT(thing->y) - gr_viewy;
|
||
|
||
// rotation around vertical axis
|
||
tz = (tr_x * gr_viewcos) + (tr_y * gr_viewsin);
|
||
|
||
// thing is behind view plane?
|
||
if (tz < ZCLIP_PLANE)
|
||
return;
|
||
|
||
tr_x = FIXED_TO_FLOAT(thing->x);
|
||
tr_y = FIXED_TO_FLOAT(thing->y);
|
||
|
||
// decide which patch to use for sprite relative to player
|
||
if ((unsigned)thing->sprite >= numsprites)
|
||
#ifdef RANGECHECK
|
||
I_Error("HWR_ProjectPrecipitationSprite: invalid sprite number %i ",
|
||
thing->sprite);
|
||
#else
|
||
return;
|
||
#endif
|
||
|
||
sprdef = &sprites[thing->sprite];
|
||
|
||
if ((size_t)(thing->frame&FF_FRAMEMASK) >= sprdef->numframes)
|
||
#ifdef RANGECHECK
|
||
I_Error("HWR_ProjectPrecipitationSprite: invalid sprite frame %i : %i for %s",
|
||
thing->sprite, thing->frame, sprnames[thing->sprite]);
|
||
#else
|
||
return;
|
||
#endif
|
||
|
||
sprframe = &sprdef->spriteframes[ thing->frame & FF_FRAMEMASK];
|
||
|
||
// use single rotation for all views
|
||
lumpoff = sprframe->lumpid[0];
|
||
flip = sprframe->flip; // Will only be 0x00 or 0xFF
|
||
|
||
rightsin = FIXED_TO_FLOAT(FINESINE((viewangle + ANGLE_90)>>ANGLETOFINESHIFT));
|
||
rightcos = FIXED_TO_FLOAT(FINECOSINE((viewangle + ANGLE_90)>>ANGLETOFINESHIFT));
|
||
if (flip)
|
||
{
|
||
x1 = FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width - spritecachedinfo[lumpoff].offset);
|
||
x2 = FIXED_TO_FLOAT(spritecachedinfo[lumpoff].offset);
|
||
}
|
||
else
|
||
{
|
||
x1 = FIXED_TO_FLOAT(spritecachedinfo[lumpoff].offset);
|
||
x2 = FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width - spritecachedinfo[lumpoff].offset);
|
||
}
|
||
|
||
z1 = tr_y + x1 * rightsin;
|
||
z2 = tr_y - x2 * rightsin;
|
||
x1 = tr_x + x1 * rightcos;
|
||
x2 = tr_x - x2 * rightcos;
|
||
|
||
// okay, we can't return now... this is a hack, but weather isn't networked, so it should be ok
|
||
if (!(thing->precipflags & PCF_THUNK))
|
||
{
|
||
P_PrecipThinker(thing);
|
||
thing->precipflags |= PCF_THUNK;
|
||
}
|
||
|
||
//
|
||
// store information in a vissprite
|
||
//
|
||
vis = HWR_NewVisSprite();
|
||
vis->x1 = x1;
|
||
vis->x2 = x2;
|
||
vis->z1 = z1;
|
||
vis->z2 = z2;
|
||
vis->tz = tz;
|
||
vis->dispoffset = 0; // Monster Iestyn: 23/11/15: HARDWARE SUPPORT AT LAST
|
||
vis->patchlumpnum = sprframe->lumppat[rot];
|
||
vis->flip = flip;
|
||
vis->mobj = (mobj_t *)thing;
|
||
|
||
vis->colormap = colormaps;
|
||
|
||
#ifdef GLENCORE
|
||
if (encoremap && !(thing->flags & MF_DONTENCOREMAP))
|
||
vis->colormap += (256*32);
|
||
#endif
|
||
|
||
// set top/bottom coords
|
||
vis->ty = FIXED_TO_FLOAT(thing->z + spritecachedinfo[lumpoff].topoffset);
|
||
|
||
vis->precip = true;
|
||
}
|
||
|
||
static boolean drewsky = false;
|
||
|
||
void HWR_DrawSkyBackground(float fpov)
|
||
{
|
||
FTransform dometransform;
|
||
|
||
if (drewsky)
|
||
return;
|
||
|
||
memset(&dometransform, 0x00, sizeof(FTransform));
|
||
|
||
//04/01/2000: Hurdler: added for T&L
|
||
// It should replace all other gr_viewxxx when finished
|
||
if (!atransform.shearing)
|
||
dometransform.anglex = (float)(aimingangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
|
||
dometransform.angley = (float)((viewangle-ANGLE_270)>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
|
||
|
||
dometransform.flip = atransform.flip;
|
||
dometransform.mirror = atransform.mirror;
|
||
dometransform.shearing = atransform.shearing;
|
||
dometransform.viewaiming = atransform.viewaiming;
|
||
|
||
dometransform.scalex = 1;
|
||
dometransform.scaley = (float)vid.width/vid.height;
|
||
dometransform.scalez = 1;
|
||
dometransform.fovxangle = fpov; // Tails
|
||
dometransform.fovyangle = fpov; // Tails
|
||
dometransform.splitscreen = splitscreen;
|
||
|
||
HWR_GetTexture(texturetranslation[skytexture]);
|
||
HWD.pfnSetShader(7); // sky shader
|
||
HWD.pfnRenderSkyDome(skytexture, textures[skytexture]->width, textures[skytexture]->height, dometransform);
|
||
HWD.pfnSetShader(0);
|
||
}
|
||
|
||
|
||
// -----------------+
|
||
// HWR_ClearView : clear the viewwindow, with maximum z value
|
||
// -----------------+
|
||
static inline void HWR_ClearView(void)
|
||
{
|
||
HWD.pfnGClipRect((INT32)gr_viewwindowx,
|
||
(INT32)gr_viewwindowy,
|
||
(INT32)(gr_viewwindowx + gr_viewwidth),
|
||
(INT32)(gr_viewwindowy + gr_viewheight),
|
||
ZCLIP_PLANE);
|
||
HWD.pfnClearBuffer(false, true, 0);
|
||
}
|
||
|
||
|
||
// -----------------+
|
||
// HWR_SetViewSize : set projection and scaling values
|
||
// -----------------+
|
||
void HWR_SetViewSize(void)
|
||
{
|
||
// setup view size
|
||
gr_viewwidth = (float)vid.width;
|
||
gr_viewheight = (float)vid.height;
|
||
|
||
if (r_splitscreen)
|
||
gr_viewheight /= 2;
|
||
|
||
if (r_splitscreen > 1)
|
||
gr_viewwidth /= 2;
|
||
|
||
gr_basecenterx = gr_viewwidth / 2;
|
||
gr_basecentery = gr_viewheight / 2;
|
||
|
||
gr_baseviewwindowy = 0;
|
||
gr_basewindowcentery = (float)(gr_viewheight / 2);
|
||
|
||
gr_baseviewwindowx = 0;
|
||
gr_basewindowcenterx = (float)(gr_viewwidth / 2);
|
||
|
||
gr_pspritexscale = ((vid.width*gr_pspriteyscale*BASEVIDHEIGHT)/BASEVIDWIDTH)/vid.height;
|
||
gr_pspriteyscale = ((vid.height*gr_pspritexscale*BASEVIDWIDTH)/BASEVIDHEIGHT)/vid.width;
|
||
|
||
HWD.pfnFlushScreenTextures();
|
||
}
|
||
|
||
|
||
// ==========================================================================
|
||
// Render the current frame.
|
||
// ==========================================================================
|
||
void HWR_RenderFrame(INT32 viewnumber, player_t *player, boolean skybox)
|
||
{
|
||
angle_t a1;
|
||
const float fpov = FIXED_TO_FLOAT(cv_fov.value+player->fovadd);
|
||
postimg_t *postprocessor = &postimgtype[0];
|
||
INT32 i;
|
||
|
||
// set window position
|
||
gr_centerx = gr_basecenterx;
|
||
gr_viewwindowx = gr_baseviewwindowx;
|
||
gr_windowcenterx = gr_basewindowcenterx;
|
||
gr_centery = gr_basecentery;
|
||
gr_viewwindowy = gr_baseviewwindowy;
|
||
gr_windowcentery = gr_basewindowcentery;
|
||
|
||
if ((r_splitscreen == 1 && viewnumber == 1) || (r_splitscreen > 1 && viewnumber > 1))
|
||
{
|
||
gr_viewwindowy += gr_viewheight;
|
||
gr_windowcentery += gr_viewheight;
|
||
}
|
||
|
||
if (r_splitscreen > 1 && viewnumber & 1)
|
||
{
|
||
gr_viewwindowx += gr_viewwidth;
|
||
gr_windowcenterx += gr_viewwidth;
|
||
}
|
||
|
||
// check for new console commands.
|
||
NetUpdate();
|
||
|
||
gr_viewx = FIXED_TO_FLOAT(viewx);
|
||
gr_viewy = FIXED_TO_FLOAT(viewy);
|
||
gr_viewz = FIXED_TO_FLOAT(viewz);
|
||
gr_viewsin = FIXED_TO_FLOAT(viewsin);
|
||
gr_viewcos = FIXED_TO_FLOAT(viewcos);
|
||
|
||
// Set T&L transform
|
||
atransform.x = gr_viewx;
|
||
atransform.y = gr_viewy;
|
||
atransform.z = gr_viewz;
|
||
|
||
atransform.scalex = 1;
|
||
atransform.scaley = (float)vid.width/vid.height;
|
||
atransform.scalez = 1;
|
||
|
||
// 14042019
|
||
gr_aimingangle = aimingangle;
|
||
atransform.shearing = false;
|
||
atransform.viewaiming = aimingangle;
|
||
|
||
if (cv_grshearing.value)
|
||
{
|
||
gr_aimingangle = 0;
|
||
atransform.shearing = true;
|
||
}
|
||
|
||
gr_viewludsin = FIXED_TO_FLOAT(FINECOSINE(gr_aimingangle>>ANGLETOFINESHIFT));
|
||
gr_viewludcos = FIXED_TO_FLOAT(-FINESINE(gr_aimingangle>>ANGLETOFINESHIFT));
|
||
|
||
atransform.anglex = (float)(gr_aimingangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
|
||
atransform.angley = (float)(viewangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
|
||
|
||
atransform.fovxangle = fpov; // Tails
|
||
atransform.fovyangle = fpov; // Tails
|
||
atransform.splitscreen = r_splitscreen;
|
||
|
||
for (i = 0; i <= splitscreen; i++)
|
||
{
|
||
if (player == &players[displayplayers[i]])
|
||
postprocessor = &postimgtype[i];
|
||
}
|
||
|
||
atransform.flip = false;
|
||
if (*postprocessor == postimg_flip)
|
||
atransform.flip = true;
|
||
|
||
atransform.mirror = false;
|
||
if (*postprocessor == postimg_mirror)
|
||
atransform.mirror = true;
|
||
|
||
// Clear view, set viewport (glViewport), set perspective...
|
||
HWR_ClearView();
|
||
HWR_ClearSprites();
|
||
|
||
ST_doPaletteStuff();
|
||
|
||
// Draw the sky background.
|
||
HWR_DrawSkyBackground(fpov);
|
||
if (skybox)
|
||
drewsky = true;
|
||
|
||
a1 = gld_FrustumAngle(gr_aimingangle);
|
||
gld_clipper_Clear();
|
||
gld_clipper_SafeAddClipRange(viewangle + a1, viewangle - a1);
|
||
#ifdef HAVE_SPHEREFRUSTRUM
|
||
gld_FrustrumSetup();
|
||
#endif
|
||
|
||
// Set transform.
|
||
HWD.pfnSetTransform(&atransform);
|
||
|
||
// Reset the shader state.
|
||
HWD.pfnSetSpecialState(HWD_SET_SHADERS, cv_grshaders.value);
|
||
HWD.pfnSetShader(0);
|
||
|
||
if (cv_grbatching.value)
|
||
HWD.pfnStartBatching();
|
||
|
||
drawcount = 0;
|
||
validcount++;
|
||
|
||
// Recursively "render" the BSP tree.
|
||
HWR_RenderBSPNode((INT32)numnodes-1);
|
||
|
||
if (cv_grbatching.value)
|
||
{
|
||
int dummy = 0;// the vars in RenderBatches are meant for render stats. But we don't have that stuff in this branch
|
||
// so that stuff could be removed...
|
||
HWD.pfnRenderBatches(&dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy);
|
||
}
|
||
|
||
// Check for new console commands.
|
||
// this was removed since it caused crashes on leaving record attack with models on since it was removing mobjs that were about to be rendered
|
||
//NetUpdate();
|
||
|
||
// Draw MD2 and sprites
|
||
HWR_SortVisSprites();
|
||
HWR_DrawSprites();
|
||
|
||
if (numplanes || numpolyplanes || numwalls) // Render FOFs and translucent walls after everything
|
||
HWR_RenderDrawNodes();
|
||
|
||
// Unset transform and shader
|
||
HWD.pfnSetTransform(NULL);
|
||
HWD.pfnUnSetShader();
|
||
|
||
// Run post processor effects
|
||
if (!skybox)
|
||
HWR_DoPostProcessor(player);
|
||
|
||
// Check for new console commands.
|
||
NetUpdate();
|
||
|
||
// added by Hurdler for correct splitscreen
|
||
// moved here by hurdler so it works with the new near clipping plane
|
||
HWD.pfnGClipRect(0, 0, vid.width, vid.height, NZCLIP_PLANE);
|
||
}
|
||
|
||
// ==========================================================================
|
||
// Render the player view.
|
||
// ==========================================================================
|
||
void HWR_RenderPlayerView(INT32 viewnumber, player_t *player)
|
||
{
|
||
const boolean skybox = (skyboxmo[0] && cv_skybox.value); // True if there's a skybox object and skyboxes are on
|
||
|
||
// Clear the color buffer, stops HOMs. Also seems to fix the skybox issue on Intel GPUs.
|
||
if (viewnumber == 0) // Only do it if it's the first screen being rendered
|
||
{
|
||
FRGBAFloat ClearColor;
|
||
|
||
ClearColor.red = 0.0f;
|
||
ClearColor.green = 0.0f;
|
||
ClearColor.blue = 0.0f;
|
||
ClearColor.alpha = 1.0f;
|
||
|
||
HWD.pfnClearBuffer(true, false, &ClearColor);
|
||
}
|
||
|
||
if (viewnumber > 3)
|
||
return;
|
||
|
||
// Render the skybox if there is one.
|
||
drewsky = false;
|
||
if (skybox)
|
||
{
|
||
R_SkyboxFrame(player);
|
||
HWR_RenderFrame(viewnumber, player, true);
|
||
}
|
||
|
||
R_SetupFrame(player, false); // This can stay false because it is only used to set viewsky in r_main.c, which isn't used here
|
||
HWR_RenderFrame(viewnumber, player, false);
|
||
}
|
||
|
||
// ==========================================================================
|
||
// 3D ENGINE COMMANDS
|
||
// ==========================================================================
|
||
|
||
// **************************************************************************
|
||
// 3D ENGINE SETUP
|
||
// **************************************************************************
|
||
|
||
// --------------------------------------------------------------------------
|
||
// Add hardware engine commands & consvars
|
||
// --------------------------------------------------------------------------
|
||
//added by Hurdler: console varibale that are saved
|
||
void HWR_AddCommands(void)
|
||
{
|
||
CV_RegisterVar(&cv_grrounddown);
|
||
CV_RegisterVar(&cv_grfiltermode);
|
||
CV_RegisterVar(&cv_granisotropicmode);
|
||
CV_RegisterVar(&cv_grcorrecttricks);
|
||
CV_RegisterVar(&cv_grsolvetjoin);
|
||
|
||
CV_RegisterVar(&cv_grbatching);
|
||
}
|
||
|
||
// --------------------------------------------------------------------------
|
||
// Setup the hardware renderer
|
||
// --------------------------------------------------------------------------
|
||
void HWR_Startup(void)
|
||
{
|
||
static boolean startupdone = false;
|
||
|
||
// do this once
|
||
if (!startupdone)
|
||
{
|
||
CONS_Printf("HWR_Startup()...\n");
|
||
HWR_InitTextureCache();
|
||
HWR_InitMD2();
|
||
}
|
||
|
||
if (rendermode == render_opengl)
|
||
textureformat = patchformat =
|
||
#ifdef _NDS
|
||
GR_TEXFMT_P_8;
|
||
#else
|
||
GR_RGBA;
|
||
#endif
|
||
|
||
startupdone = true;
|
||
|
||
// jimita
|
||
HWD.pfnKillShaders();
|
||
if (!HWD.pfnLoadShaders())
|
||
gr_shadersavailable = false;
|
||
}
|
||
|
||
|
||
// --------------------------------------------------------------------------
|
||
// Free resources allocated by the hardware renderer
|
||
// --------------------------------------------------------------------------
|
||
void HWR_Shutdown(void)
|
||
{
|
||
CONS_Printf("HWR_Shutdown()\n");
|
||
HWR_FreeExtraSubsectors();
|
||
HWR_FreeTextureCache();
|
||
HWD.pfnFlushScreenTextures();
|
||
}
|
||
|
||
void HWR_AddTransparentWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, INT32 texnum, FBITFIELD blend, boolean fogwall, INT32 lightlevel, extracolormap_t *wallcolormap)
|
||
{
|
||
static size_t allocedwalls = 0;
|
||
|
||
// Force realloc if buffer has been freed
|
||
if (!wallinfo)
|
||
allocedwalls = 0;
|
||
|
||
if (allocedwalls < numwalls + 1)
|
||
{
|
||
allocedwalls += MAX_TRANSPARENTWALL;
|
||
Z_Realloc(wallinfo, allocedwalls * sizeof (*wallinfo), PU_LEVEL, &wallinfo);
|
||
}
|
||
|
||
M_Memcpy(wallinfo[numwalls].wallVerts, wallVerts, sizeof (wallinfo[numwalls].wallVerts));
|
||
M_Memcpy(&wallinfo[numwalls].Surf, pSurf, sizeof (FSurfaceInfo));
|
||
wallinfo[numwalls].texnum = texnum;
|
||
wallinfo[numwalls].blend = blend;
|
||
wallinfo[numwalls].drawcount = drawcount++;
|
||
wallinfo[numwalls].fogwall = fogwall;
|
||
wallinfo[numwalls].lightlevel = lightlevel;
|
||
wallinfo[numwalls].wallcolormap = wallcolormap;
|
||
numwalls++;
|
||
}
|
||
|
||
void HWR_RenderWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend, boolean fogwall, INT32 lightlevel, extracolormap_t *wallcolormap)
|
||
{
|
||
FBITFIELD blendmode = blend;
|
||
UINT8 alpha = pSurf->PolyColor.s.alpha; // retain the alpha
|
||
|
||
// Lighting is done here instead so that fog isn't drawn incorrectly on transparent walls after sorting
|
||
HWR_Lighting(pSurf, lightlevel, wallcolormap);
|
||
|
||
pSurf->PolyColor.s.alpha = alpha; // put the alpha back after lighting
|
||
|
||
HWD.pfnSetShader(2); // wall shader
|
||
|
||
if (blend & PF_Environment)
|
||
blendmode |= PF_Occlude; // PF_Occlude must be used for solid objects
|
||
|
||
if (fogwall)
|
||
{
|
||
blendmode |= PF_Fog;
|
||
HWD.pfnSetShader(6); // fog shader
|
||
}
|
||
|
||
blendmode |= PF_Modulated; // No PF_Occlude means overlapping (incorrect) transparency
|
||
|
||
HWD.pfnDrawPolygon(pSurf, wallVerts, 4, blendmode);
|
||
|
||
#ifdef WALLSPLATS
|
||
if (gr_curline->linedef->splats && cv_splats.value)
|
||
HWR_DrawSegsSplats(pSurf);
|
||
#endif
|
||
}
|
||
|
||
void HWR_DoPostProcessor(player_t *player)
|
||
{
|
||
postimg_t *type = &postimgtype[0];
|
||
UINT8 i;
|
||
|
||
HWD.pfnUnSetShader();
|
||
|
||
for (i = r_splitscreen; i > 0; i--)
|
||
{
|
||
if (player == &players[displayplayers[i]])
|
||
{
|
||
type = &postimgtype[i];
|
||
break;
|
||
}
|
||
}
|
||
|
||
// Armageddon Blast Flash!
|
||
// Could this even be considered postprocessor?
|
||
if (player->flashcount)
|
||
{
|
||
FOutVector v[4];
|
||
FSurfaceInfo Surf;
|
||
|
||
v[0].x = v[2].y = v[3].x = v[3].y = -4.0f;
|
||
v[0].y = v[1].x = v[1].y = v[2].x = 4.0f;
|
||
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
|
||
|
||
// This won't change if the flash palettes are changed unfortunately, but it works for its purpose
|
||
if (player->flashpal == PAL_NUKE)
|
||
{
|
||
Surf.PolyColor.s.red = 0xff;
|
||
Surf.PolyColor.s.green = Surf.PolyColor.s.blue = 0x7F; // The nuke palette is kind of pink-ish
|
||
}
|
||
else
|
||
Surf.PolyColor.s.red = Surf.PolyColor.s.green = Surf.PolyColor.s.blue = 0xff;
|
||
|
||
Surf.PolyColor.s.alpha = 0xc0; // match software mode
|
||
|
||
HWD.pfnDrawPolygon(&Surf, v, 4, PF_Modulated|PF_Translucent|PF_NoTexture|PF_NoDepthTest);
|
||
}
|
||
|
||
// Capture the screen for intermission and screen waving
|
||
if(gamestate != GS_INTERMISSION)
|
||
HWD.pfnMakeScreenTexture();
|
||
|
||
if (r_splitscreen) // Not supported in splitscreen - someone want to add support?
|
||
return;
|
||
|
||
// Drunken vision! WooOOooo~
|
||
if (*type == postimg_water || *type == postimg_heat)
|
||
{
|
||
// 10 by 10 grid. 2 coordinates (xy)
|
||
float v[SCREENVERTS][SCREENVERTS][2];
|
||
double disStart = leveltime;
|
||
UINT8 x, y;
|
||
INT32 WAVELENGTH;
|
||
INT32 AMPLITUDE;
|
||
INT32 FREQUENCY;
|
||
|
||
// Modifies the wave.
|
||
if (*type == postimg_water)
|
||
{
|
||
WAVELENGTH = 20; // Lower is longer
|
||
AMPLITUDE = 20; // Lower is bigger
|
||
FREQUENCY = 16; // Lower is faster
|
||
}
|
||
else
|
||
{
|
||
WAVELENGTH = 10; // Lower is longer
|
||
AMPLITUDE = 30; // Lower is bigger
|
||
FREQUENCY = 4; // Lower is faster
|
||
}
|
||
|
||
for (x = 0; x < SCREENVERTS; x++)
|
||
{
|
||
for (y = 0; y < SCREENVERTS; y++)
|
||
{
|
||
// Change X position based on its Y position.
|
||
v[x][y][0] = (x/((float)(SCREENVERTS-1.0f)/9.0f))-4.5f + (float)sin((disStart+(y*WAVELENGTH))/FREQUENCY)/AMPLITUDE;
|
||
v[x][y][1] = (y/((float)(SCREENVERTS-1.0f)/9.0f))-4.5f;
|
||
}
|
||
}
|
||
HWD.pfnPostImgRedraw(v);
|
||
|
||
// Capture the screen again for screen waving on the intermission
|
||
if(gamestate != GS_INTERMISSION)
|
||
HWD.pfnMakeScreenTexture();
|
||
}
|
||
// Flipping of the screen isn't done here anymore
|
||
}
|
||
|
||
void HWR_StartScreenWipe(void)
|
||
{
|
||
HWD.pfnStartScreenWipe();
|
||
}
|
||
|
||
void HWR_EndScreenWipe(void)
|
||
{
|
||
HWD.pfnEndScreenWipe();
|
||
}
|
||
|
||
void HWR_DrawIntermissionBG(void)
|
||
{
|
||
HWD.pfnDrawIntermissionBG();
|
||
}
|
||
|
||
void HWR_DoWipe(UINT8 wipenum, UINT8 scrnnum)
|
||
{
|
||
static char lumpname[9] = "FADEmmss";
|
||
lumpnum_t lumpnum;
|
||
size_t lsize;
|
||
|
||
if (wipenum > 99 || scrnnum > 99) // not a valid wipe number
|
||
return; // shouldn't end up here really, the loop should've stopped running beforehand
|
||
|
||
// puts the numbers into the lumpname
|
||
sprintf(&lumpname[4], "%.2hu%.2hu", (UINT16)wipenum, (UINT16)scrnnum);
|
||
lumpnum = W_CheckNumForName(lumpname);
|
||
|
||
if (lumpnum == LUMPERROR) // again, shouldn't be here really
|
||
return;
|
||
|
||
lsize = W_LumpLength(lumpnum);
|
||
|
||
if (!(lsize == 256000 || lsize == 64000 || lsize == 16000 || lsize == 4000))
|
||
{
|
||
CONS_Alert(CONS_WARNING, "Fade mask lump %s of incorrect size, ignored\n", lumpname);
|
||
return; // again, shouldn't get here if it is a bad size
|
||
}
|
||
|
||
HWR_GetFadeMask(lumpnum);
|
||
HWD.pfnDoScreenWipe();
|
||
}
|
||
|
||
void HWR_MakeScreenFinalTexture(void)
|
||
{
|
||
HWD.pfnMakeScreenFinalTexture();
|
||
}
|
||
|
||
void HWR_DrawScreenFinalTexture(int width, int height)
|
||
{
|
||
HWD.pfnDrawScreenFinalTexture(width, height);
|
||
}
|
||
|
||
// jimita 18032019
|
||
typedef struct
|
||
{
|
||
char type[16];
|
||
INT32 id;
|
||
} shaderxlat_t;
|
||
|
||
static inline UINT16 HWR_CheckShader(UINT16 wadnum)
|
||
{
|
||
UINT16 i;
|
||
lumpinfo_t *lump_p;
|
||
|
||
lump_p = wadfiles[wadnum]->lumpinfo;
|
||
for (i = 0; i < wadfiles[wadnum]->numlumps; i++, lump_p++)
|
||
if (memcmp(lump_p->name, "SHADERS", 7) == 0)
|
||
return i;
|
||
|
||
return INT16_MAX;
|
||
}
|
||
|
||
void HWR_LoadShaders(UINT16 wadnum, boolean PK3)
|
||
{
|
||
UINT16 lump;
|
||
char *shaderdef, *line;
|
||
char *stoken;
|
||
char *value;
|
||
size_t size;
|
||
int linenum = 1;
|
||
int shadertype = 0;
|
||
int i;
|
||
|
||
#define SHADER_TYPES 7
|
||
shaderxlat_t shaderxlat[SHADER_TYPES] =
|
||
{
|
||
{"Flat", 1},
|
||
{"WallTexture", 2},
|
||
{"Sprite", 3},
|
||
{"Model", 4},
|
||
{"WaterRipple", 5},
|
||
{"Fog", 6},
|
||
{"Sky", 7},
|
||
};
|
||
|
||
lump = HWR_CheckShader(wadnum);
|
||
if (lump == INT16_MAX)
|
||
return;
|
||
|
||
shaderdef = W_CacheLumpNumPwad(wadnum, lump, PU_CACHE);
|
||
size = W_LumpLengthPwad(wadnum, lump);
|
||
|
||
line = Z_Malloc(size+1, PU_STATIC, NULL);
|
||
if (!line)
|
||
I_Error("HWR_LoadShaders: No more free memory\n");
|
||
|
||
M_Memcpy(line, shaderdef, size);
|
||
line[size] = '\0';
|
||
|
||
stoken = strtok(line, "\r\n ");
|
||
while (stoken)
|
||
{
|
||
if ((stoken[0] == '/' && stoken[1] == '/')
|
||
|| (stoken[0] == '#'))// skip comments
|
||
{
|
||
stoken = strtok(NULL, "\r\n");
|
||
goto skip_field;
|
||
}
|
||
|
||
if (!stricmp(stoken, "GLSL"))
|
||
{
|
||
value = strtok(NULL, "\r\n ");
|
||
if (!value)
|
||
{
|
||
CONS_Alert(CONS_WARNING, "HWR_LoadShaders: Missing shader type (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum);
|
||
stoken = strtok(NULL, "\r\n"); // skip end of line
|
||
goto skip_lump;
|
||
}
|
||
|
||
if (!stricmp(value, "VERTEX"))
|
||
shadertype = 1;
|
||
else if (!stricmp(value, "FRAGMENT"))
|
||
shadertype = 2;
|
||
|
||
skip_lump:
|
||
stoken = strtok(NULL, "\r\n ");
|
||
linenum++;
|
||
}
|
||
else
|
||
{
|
||
value = strtok(NULL, "\r\n= ");
|
||
if (!value)
|
||
{
|
||
CONS_Alert(CONS_WARNING, "HWR_LoadShaders: Missing shader target (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum);
|
||
stoken = strtok(NULL, "\r\n"); // skip end of line
|
||
goto skip_field;
|
||
}
|
||
|
||
if (!shadertype)
|
||
{
|
||
CONS_Alert(CONS_ERROR, "HWR_LoadShaders: Missing shader type (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum);
|
||
Z_Free(line);
|
||
return;
|
||
}
|
||
|
||
for (i = 0; i < SHADER_TYPES; i++)
|
||
{
|
||
if (!stricmp(shaderxlat[i].type, stoken))
|
||
{
|
||
size_t shader_size;
|
||
char *shader_source;
|
||
char *shader_lumpname;
|
||
UINT16 shader_lumpnum;
|
||
|
||
if (PK3)
|
||
{
|
||
shader_lumpname = Z_Malloc(strlen(value) + 12, PU_STATIC, NULL);
|
||
strcpy(shader_lumpname, "Shaders/sh_");
|
||
strcat(shader_lumpname, value);
|
||
shader_lumpnum = W_CheckNumForFullNamePK3(shader_lumpname, wadnum, 0);
|
||
}
|
||
else
|
||
{
|
||
shader_lumpname = Z_Malloc(strlen(value) + 4, PU_STATIC, NULL);
|
||
strcpy(shader_lumpname, "SH_");
|
||
strcat(shader_lumpname, value);
|
||
shader_lumpnum = W_CheckNumForNamePwad(shader_lumpname, wadnum, 0);
|
||
}
|
||
|
||
if (shader_lumpnum == INT16_MAX)
|
||
{
|
||
CONS_Alert(CONS_ERROR, "HWR_LoadShaders: Missing shader source %s (file %s, line %d)\n", shader_lumpname, wadfiles[wadnum]->filename, linenum);
|
||
Z_Free(shader_lumpname);
|
||
continue;
|
||
}
|
||
|
||
shader_size = W_LumpLengthPwad(wadnum, shader_lumpnum);
|
||
shader_source = Z_Malloc(shader_size, PU_STATIC, NULL);
|
||
W_ReadLumpPwad(wadnum, shader_lumpnum, shader_source);
|
||
|
||
HWD.pfnLoadCustomShader(shaderxlat[i].id, shader_source, shader_size, (shadertype == 2));
|
||
|
||
Z_Free(shader_source);
|
||
Z_Free(shader_lumpname);
|
||
}
|
||
}
|
||
|
||
skip_field:
|
||
stoken = strtok(NULL, "\r\n= ");
|
||
linenum++;
|
||
}
|
||
}
|
||
|
||
HWD.pfnInitCustomShaders();
|
||
|
||
Z_Free(line);
|
||
return;
|
||
}
|
||
|
||
#endif // HWRENDER
|