2020-01-23 23:12:15 +00:00
|
|
|
|
// SONIC ROBO BLAST 2
|
2014-03-15 16:59:03 +00:00
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Copyright (C) 1998-2000 by DooM Legacy Team.
|
2020-01-23 23:12:15 +00:00
|
|
|
|
// Copyright (C) 1999-2020 by Sonic Team Junior.
|
2014-03-15 16:59:03 +00:00
|
|
|
|
//
|
2020-01-23 23:12:15 +00:00
|
|
|
|
// This program is free software distributed under the
|
|
|
|
|
// terms of the GNU General Public License, version 2.
|
|
|
|
|
// See the 'LICENSE' file for more details.
|
2014-03-15 16:59:03 +00:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2020-01-23 23:12:15 +00:00
|
|
|
|
/// \file hw_main.c
|
2014-03-15 16:59:03 +00:00
|
|
|
|
/// \brief hardware renderer, using the standard HardWareRender driver DLL for SRB2
|
|
|
|
|
|
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
|
|
#include "../doomstat.h"
|
|
|
|
|
|
|
|
|
|
#ifdef HWRENDER
|
|
|
|
|
#include "hw_glob.h"
|
|
|
|
|
#include "hw_light.h"
|
|
|
|
|
#include "hw_drv.h"
|
2020-06-07 18:20:52 +00:00
|
|
|
|
#include "hw_batching.h"
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
#include "../i_video.h" // for rendermode == render_glide
|
|
|
|
|
#include "../v_video.h"
|
|
|
|
|
#include "../p_local.h"
|
|
|
|
|
#include "../p_setup.h"
|
|
|
|
|
#include "../r_local.h"
|
2019-10-28 18:28:42 +00:00
|
|
|
|
#include "../r_patch.h"
|
2014-03-15 16:59:03 +00:00
|
|
|
|
#include "../r_bsp.h"
|
|
|
|
|
#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"
|
2019-11-05 15:10:42 +00:00
|
|
|
|
#include "../f_finale.h"
|
2020-01-16 17:37:32 +00:00
|
|
|
|
#include "../r_things.h" // R_GetShadowZ
|
2016-01-17 04:10:38 +00:00
|
|
|
|
#include "../p_slopes.h"
|
2014-03-15 16:59:03 +00:00
|
|
|
|
#include "hw_md2.h"
|
|
|
|
|
|
2017-01-10 18:01:03 +00:00
|
|
|
|
#ifdef NEWCLIP
|
|
|
|
|
#include "hw_clip.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
#define R_FAKEFLOORS
|
2016-10-27 22:41:24 +00:00
|
|
|
|
#define HWPRECIP
|
2014-03-15 16:59:03 +00:00
|
|
|
|
//#define POLYSKY
|
|
|
|
|
|
|
|
|
|
// ==========================================================================
|
|
|
|
|
// the hardware driver object
|
|
|
|
|
// ==========================================================================
|
|
|
|
|
struct hwdriver_s hwdriver;
|
|
|
|
|
|
|
|
|
|
// ==========================================================================
|
|
|
|
|
// PROTOS
|
|
|
|
|
// ==========================================================================
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void HWR_AddSprites(sector_t *sec);
|
|
|
|
|
static void HWR_ProjectSprite(mobj_t *thing);
|
|
|
|
|
#ifdef HWPRECIP
|
|
|
|
|
static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing);
|
|
|
|
|
#endif
|
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
void HWR_AddTransparentFloor(levelflat_t *levelflat, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, boolean fogplane, extracolormap_t *planecolormap);
|
2019-11-09 01:58:41 +00:00
|
|
|
|
void HWR_AddTransparentPolyobjectFloor(levelflat_t *levelflat, polyobj_t *polysector, boolean isceiling, fixed_t fixedheight,
|
2014-10-27 20:57:45 +00:00
|
|
|
|
INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, extracolormap_t *planecolormap);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
boolean drawsky = true;
|
|
|
|
|
|
|
|
|
|
// ==========================================================================
|
|
|
|
|
// VIEW GLOBALS
|
|
|
|
|
// ==========================================================================
|
|
|
|
|
// Fineangles in the SCREENWIDTH wide window.
|
|
|
|
|
#define FIELDOFVIEW ANGLE_90
|
|
|
|
|
#define ABS(x) ((x) < 0 ? -(x) : (x))
|
|
|
|
|
|
|
|
|
|
static angle_t gr_clipangle;
|
|
|
|
|
|
|
|
|
|
// The viewangletox[viewangle + FINEANGLES/4] lookup
|
|
|
|
|
// maps the visible view angles to screen X coordinates,
|
|
|
|
|
// flattening the arc to a flat projection plane.
|
|
|
|
|
// There will be many angles mapped to the same X.
|
|
|
|
|
static INT32 gr_viewangletox[FINEANGLES/2];
|
|
|
|
|
|
|
|
|
|
// The xtoviewangleangle[] table maps a screen pixel
|
|
|
|
|
// to the lowest viewangle that maps back to x ranges
|
|
|
|
|
// from clipangle to -clipangle.
|
|
|
|
|
static angle_t gr_xtoviewangle[MAXVIDWIDTH+1];
|
|
|
|
|
|
|
|
|
|
// ==========================================================================
|
|
|
|
|
// GLOBALS
|
|
|
|
|
// ==========================================================================
|
|
|
|
|
|
|
|
|
|
// uncomment to remove the plane rendering
|
|
|
|
|
#define DOPLANES
|
|
|
|
|
//#define DOWALLS
|
|
|
|
|
|
|
|
|
|
// test of drawing sky by polygons like in software with visplane, unfortunately
|
|
|
|
|
// this doesn't work since we must have z for pixel and z for texture (not like now with z = oow)
|
|
|
|
|
//#define POLYSKY
|
|
|
|
|
|
|
|
|
|
// test change fov when looking up/down but bsp projection messup :(
|
|
|
|
|
//#define NOCRAPPYMLOOK
|
|
|
|
|
|
|
|
|
|
// base values set at SetViewSize
|
|
|
|
|
static float gr_basecentery;
|
|
|
|
|
|
|
|
|
|
float gr_baseviewwindowy, gr_basewindowcentery;
|
|
|
|
|
float gr_viewwidth, gr_viewheight; // viewport clipping boundaries (screen coords)
|
|
|
|
|
float gr_viewwindowx;
|
|
|
|
|
|
|
|
|
|
static float gr_centerx, gr_centery;
|
|
|
|
|
static float gr_viewwindowy; // top left corner of view window
|
|
|
|
|
static float gr_windowcenterx; // center of view window, for projection
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
// STUFF FOR THE PROJECTION CODE
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
FTransform atransform;
|
|
|
|
|
// duplicates of the main code, set after R_SetupFrame() passed them into sharedstruct,
|
|
|
|
|
// copied here for local use
|
|
|
|
|
static fixed_t dup_viewx, dup_viewy, dup_viewz;
|
|
|
|
|
static angle_t dup_viewangle;
|
|
|
|
|
|
|
|
|
|
static float gr_viewx, gr_viewy, gr_viewz;
|
|
|
|
|
static float gr_viewsin, gr_viewcos;
|
|
|
|
|
|
|
|
|
|
// Maybe not necessary with the new T&L code (needs to be checked!)
|
|
|
|
|
static float gr_viewludsin, gr_viewludcos; // look up down kik test
|
|
|
|
|
static float gr_fovlud;
|
|
|
|
|
|
2020-01-23 22:44:46 +00:00
|
|
|
|
static angle_t gr_aimingangle;
|
2020-02-08 20:42:26 +00:00
|
|
|
|
static void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean skybox);
|
2020-01-23 22:44:46 +00:00
|
|
|
|
|
2020-05-01 17:57:48 +00:00
|
|
|
|
// Render stats
|
2020-05-02 17:43:53 +00:00
|
|
|
|
int rs_hw_nodesorttime = 0;
|
|
|
|
|
int rs_hw_nodedrawtime = 0;
|
|
|
|
|
int rs_hw_spritesorttime = 0;
|
|
|
|
|
int rs_hw_spritedrawtime = 0;
|
2020-04-18 22:25:28 +00:00
|
|
|
|
|
2020-06-07 18:20:52 +00:00
|
|
|
|
// Render stats for batching
|
|
|
|
|
int rs_hw_numpolys = 0;
|
|
|
|
|
int rs_hw_numverts = 0;
|
|
|
|
|
int rs_hw_numcalls = 0;
|
|
|
|
|
int rs_hw_numshaders = 0;
|
|
|
|
|
int rs_hw_numtextures = 0;
|
|
|
|
|
int rs_hw_numpolyflags = 0;
|
|
|
|
|
int rs_hw_numcolors = 0;
|
|
|
|
|
int rs_hw_batchsorttime = 0;
|
|
|
|
|
int rs_hw_batchdrawtime = 0;
|
|
|
|
|
|
2020-06-18 14:39:34 +00:00
|
|
|
|
boolean gr_shadersavailable = true;
|
|
|
|
|
|
2020-04-18 22:25:28 +00:00
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
// ==========================================================================
|
2019-12-25 19:22:01 +00:00
|
|
|
|
// Lighting
|
2014-03-15 16:59:03 +00:00
|
|
|
|
// ==========================================================================
|
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
void HWR_Lighting(FSurfaceInfo *Surface, INT32 light_level, extracolormap_t *colormap)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2019-12-25 19:22:01 +00:00
|
|
|
|
RGBA_t poly_color, tint_color, fade_color;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
poly_color.rgba = 0xFFFFFFFF;
|
|
|
|
|
tint_color.rgba = (colormap != NULL) ? (UINT32)colormap->rgba : GL_DEFAULTMIX;
|
|
|
|
|
fade_color.rgba = (colormap != NULL) ? (UINT32)colormap->fadergba : GL_DEFAULTFOG;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
// Crappy backup coloring if you can't do shaders
|
2020-06-18 14:39:34 +00:00
|
|
|
|
if (!cv_grshaders.value || !gr_shadersavailable)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2019-12-25 19:22:01 +00:00
|
|
|
|
// be careful, this may get negative for high lightlevel values.
|
|
|
|
|
float tint_alpha, fade_alpha;
|
|
|
|
|
float red, green, blue;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
red = (float)poly_color.s.red;
|
|
|
|
|
green = (float)poly_color.s.green;
|
|
|
|
|
blue = (float)poly_color.s.blue;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
// 48 is just an arbritrary value that looked relatively okay.
|
|
|
|
|
tint_alpha = (float)(sqrt(tint_color.s.alpha) * 48) / 255.0f;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
// 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;
|
2014-03-24 17:11:45 +00:00
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
// Clamp the alpha values
|
|
|
|
|
tint_alpha = min(max(tint_alpha, 0.0f), 1.0f);
|
|
|
|
|
fade_alpha = min(max(fade_alpha, 0.0f), 1.0f);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
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));
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
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));
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
poly_color.s.red = (UINT8)red;
|
|
|
|
|
poly_color.s.green = (UINT8)green;
|
|
|
|
|
poly_color.s.blue = (UINT8)blue;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
UINT8 HWR_FogBlockAlpha(INT32 light, extracolormap_t *colormap) // Let's see if this can work
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2018-03-15 23:58:37 +00:00
|
|
|
|
RGBA_t realcolor, surfcolor;
|
|
|
|
|
INT32 alpha;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2020-01-08 01:55:36 +00:00
|
|
|
|
realcolor.rgba = (colormap != NULL) ? colormap->rgba : GL_DEFAULTMIX;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2020-06-18 14:39:34 +00:00
|
|
|
|
if (cv_grshaders.value && gr_shadersavailable)
|
2020-01-08 01:55:36 +00:00
|
|
|
|
{
|
|
|
|
|
surfcolor.s.alpha = (255 - light);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-01-08 01:55:36 +00:00
|
|
|
|
light = light - (255 - light);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2020-01-08 01:55:36 +00:00
|
|
|
|
// Don't go out of bounds
|
|
|
|
|
if (light < 0)
|
|
|
|
|
light = 0;
|
|
|
|
|
else if (light > 255)
|
|
|
|
|
light = 255;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2020-01-08 01:55:36 +00:00
|
|
|
|
alpha = (realcolor.s.alpha*255)/25;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2020-01-08 01:55:36 +00:00
|
|
|
|
// 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;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return surfcolor.s.alpha;
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-16 21:45:49 +00:00
|
|
|
|
static FUINT HWR_CalcWallLight(FUINT lightnum, fixed_t v1x, fixed_t v1y, fixed_t v2x, fixed_t v2y)
|
|
|
|
|
{
|
|
|
|
|
INT16 finallight = lightnum;
|
|
|
|
|
|
|
|
|
|
if (cv_grfakecontrast.value != 0)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2020-01-16 21:45:49 +00:00
|
|
|
|
const UINT8 contrast = 8;
|
|
|
|
|
fixed_t extralight = 0;
|
|
|
|
|
|
|
|
|
|
if (cv_grfakecontrast.value == 2) // Smooth setting
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2020-01-16 21:45:49 +00:00
|
|
|
|
extralight = (-(contrast<<FRACBITS) +
|
|
|
|
|
FixedDiv(AngleFixed(R_PointToAngle2(0, 0,
|
|
|
|
|
abs(v1x - v2x),
|
|
|
|
|
abs(v1y - v2y))), 90<<FRACBITS)
|
|
|
|
|
* (contrast * 2)) >> FRACBITS;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-01-16 21:45:49 +00:00
|
|
|
|
if (v1y == v2y)
|
|
|
|
|
extralight = -contrast;
|
|
|
|
|
else if (v1x == v2x)
|
|
|
|
|
extralight = contrast;
|
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2020-01-16 21:45:49 +00:00
|
|
|
|
if (extralight != 0)
|
|
|
|
|
{
|
|
|
|
|
finallight += extralight;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2020-01-16 21:45:49 +00:00
|
|
|
|
if (finallight < 0)
|
|
|
|
|
finallight = 0;
|
|
|
|
|
if (finallight > 255)
|
|
|
|
|
finallight = 255;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-16 21:45:49 +00:00
|
|
|
|
return (FUINT)finallight;
|
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2020-01-16 21:45:49 +00:00
|
|
|
|
static FUINT HWR_CalcSlopeLight(FUINT lightnum, angle_t dir, fixed_t delta)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2020-01-16 21:45:49 +00:00
|
|
|
|
INT16 finallight = lightnum;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2020-01-16 21:45:49 +00:00
|
|
|
|
if (cv_grfakecontrast.value != 0 && cv_grslopecontrast.value != 0)
|
|
|
|
|
{
|
|
|
|
|
const UINT8 contrast = 8;
|
|
|
|
|
fixed_t extralight = 0;
|
2014-03-24 17:11:45 +00:00
|
|
|
|
|
2020-01-16 21:45:49 +00:00
|
|
|
|
if (cv_grfakecontrast.value == 2) // Smooth setting
|
|
|
|
|
{
|
|
|
|
|
fixed_t dirmul = abs(FixedDiv(AngleFixed(dir) - (180<<FRACBITS), 180<<FRACBITS));
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2020-01-16 21:45:49 +00:00
|
|
|
|
extralight = -(contrast<<FRACBITS) + (dirmul * (contrast * 2));
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2020-01-16 21:45:49 +00:00
|
|
|
|
extralight = FixedMul(extralight, delta*4) >> FRACBITS;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
dir = ((dir + ANGLE_45) / ANGLE_90) * ANGLE_90;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2020-01-16 21:45:49 +00:00
|
|
|
|
if (dir == ANGLE_180)
|
|
|
|
|
extralight = -contrast;
|
|
|
|
|
else if (dir == 0)
|
|
|
|
|
extralight = contrast;
|
|
|
|
|
|
|
|
|
|
if (delta >= FRACUNIT/2)
|
|
|
|
|
extralight *= 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (extralight != 0)
|
|
|
|
|
{
|
|
|
|
|
finallight += extralight;
|
|
|
|
|
|
|
|
|
|
if (finallight < 0)
|
|
|
|
|
finallight = 0;
|
|
|
|
|
if (finallight > 255)
|
|
|
|
|
finallight = 255;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (FUINT)finallight;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ==========================================================================
|
|
|
|
|
// FLOOR/CEILING GENERATION FROM SUBSECTORS
|
|
|
|
|
// ==========================================================================
|
|
|
|
|
|
|
|
|
|
#ifdef DOPLANES
|
|
|
|
|
|
|
|
|
|
// -----------------+
|
|
|
|
|
// HWR_RenderPlane : Render a floor or ceiling convex polygon
|
|
|
|
|
// -----------------+
|
2020-04-25 05:10:30 +00:00
|
|
|
|
static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, FBITFIELD PolyFlags, INT32 lightlevel, levelflat_t *levelflat, sector_t *FOFsector, UINT8 alpha, extracolormap_t *planecolormap)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
|
|
|
|
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;
|
2019-11-09 02:42:15 +00:00
|
|
|
|
float fflatwidth = 64.0f, fflatheight = 64.0f;
|
|
|
|
|
INT32 flatflag = 63;
|
2019-11-09 01:58:41 +00:00
|
|
|
|
boolean texflat = false;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
size_t len;
|
|
|
|
|
float scrollx = 0.0f, scrolly = 0.0f;
|
|
|
|
|
angle_t angle = 0;
|
|
|
|
|
FSurfaceInfo Surf;
|
|
|
|
|
fixed_t tempxsow, tempytow;
|
2016-01-28 13:56:23 +00:00
|
|
|
|
pslope_t *slope = NULL;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
static FOutVector *planeVerts = NULL;
|
|
|
|
|
static UINT16 numAllocedPlaneVerts = 0;
|
|
|
|
|
|
2020-06-07 18:20:52 +00:00
|
|
|
|
int shader;
|
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
// no convex poly were generated for this subsector
|
|
|
|
|
if (!xsub->planepoly)
|
|
|
|
|
return;
|
|
|
|
|
|
2016-01-28 13:56:23 +00:00
|
|
|
|
// Get the slope pointer to simplify future code
|
|
|
|
|
if (FOFsector)
|
|
|
|
|
{
|
2016-07-27 18:56:21 +00:00
|
|
|
|
if (FOFsector->f_slope && !isceiling)
|
2016-01-28 13:56:23 +00:00
|
|
|
|
slope = FOFsector->f_slope;
|
2016-07-27 18:56:21 +00:00
|
|
|
|
else if (FOFsector->c_slope && isceiling)
|
2016-01-28 13:56:23 +00:00
|
|
|
|
slope = FOFsector->c_slope;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-07-27 18:56:21 +00:00
|
|
|
|
if (gr_frontsector->f_slope && !isceiling)
|
2016-01-28 13:56:23 +00:00
|
|
|
|
slope = gr_frontsector->f_slope;
|
2016-07-27 18:56:21 +00:00
|
|
|
|
else if (gr_frontsector->c_slope && isceiling)
|
2016-01-28 13:56:23 +00:00
|
|
|
|
slope = gr_frontsector->c_slope;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set fixedheight to the slope's height from our viewpoint, if we have a slope
|
|
|
|
|
if (slope)
|
2020-05-18 13:23:56 +00:00
|
|
|
|
fixedheight = P_GetSlopeZAt(slope, viewx, viewy);
|
2016-01-17 04:10:38 +00:00
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
height = FIXED_TO_FLOAT(fixedheight);
|
|
|
|
|
|
|
|
|
|
pv = xsub->planepoly->pts;
|
|
|
|
|
nrPlaneVerts = xsub->planepoly->numpts;
|
|
|
|
|
|
|
|
|
|
if (nrPlaneVerts < 3) //not even a triangle ?
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-09 02:42:15 +00:00
|
|
|
|
// set texture for polygon
|
|
|
|
|
if (levelflat != NULL)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2019-11-09 02:42:15 +00:00
|
|
|
|
if (levelflat->type == LEVELFLAT_TEXTURE)
|
2019-11-09 01:58:41 +00:00
|
|
|
|
{
|
2019-11-09 02:42:15 +00:00
|
|
|
|
fflatwidth = textures[levelflat->u.texture.num]->width;
|
|
|
|
|
fflatheight = textures[levelflat->u.texture.num]->height;
|
|
|
|
|
texflat = true;
|
2019-11-09 01:58:41 +00:00
|
|
|
|
}
|
2019-11-09 02:42:15 +00:00
|
|
|
|
else if (levelflat->type == LEVELFLAT_FLAT)
|
|
|
|
|
{
|
|
|
|
|
len = W_LumpLength(levelflat->u.flat.lumpnum);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-11-09 02:42:15 +00:00
|
|
|
|
switch (len)
|
|
|
|
|
{
|
|
|
|
|
case 4194304: // 2048x2048 lump
|
|
|
|
|
fflatwidth = fflatheight = 2048.0f;
|
|
|
|
|
break;
|
|
|
|
|
case 1048576: // 1024x1024 lump
|
|
|
|
|
fflatwidth = fflatheight = 1024.0f;
|
|
|
|
|
break;
|
|
|
|
|
case 262144:// 512x512 lump
|
|
|
|
|
fflatwidth = fflatheight = 512.0f;
|
|
|
|
|
break;
|
|
|
|
|
case 65536: // 256x256 lump
|
|
|
|
|
fflatwidth = fflatheight = 256.0f;
|
|
|
|
|
break;
|
|
|
|
|
case 16384: // 128x128 lump
|
|
|
|
|
fflatwidth = fflatheight = 128.0f;
|
|
|
|
|
break;
|
|
|
|
|
case 1024: // 32x32 lump
|
|
|
|
|
fflatwidth = fflatheight = 32.0f;
|
|
|
|
|
break;
|
|
|
|
|
default: // 64x64 lump
|
|
|
|
|
fflatwidth = fflatheight = 64.0f;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-05-21 03:28:52 +00:00
|
|
|
|
|
2019-11-09 02:42:15 +00:00
|
|
|
|
flatflag = ((INT32)fflatwidth)-1;
|
|
|
|
|
}
|
2019-05-26 19:22:33 +00:00
|
|
|
|
}
|
2019-11-09 02:42:15 +00:00
|
|
|
|
else // set no texture
|
2020-06-07 18:20:52 +00:00
|
|
|
|
HWR_SetCurrentTexture(NULL);
|
2019-05-21 03:28:52 +00:00
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
// reference point for flat texture coord for each vertex around the polygon
|
2019-05-26 19:22:33 +00:00
|
|
|
|
flatxref = (float)(((fixed_t)pv->x & (~flatflag)) / fflatwidth);
|
|
|
|
|
flatyref = (float)(((fixed_t)pv->y & (~flatflag)) / fflatheight);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
// transform
|
|
|
|
|
if (FOFsector != NULL)
|
|
|
|
|
{
|
2016-07-27 18:56:21 +00:00
|
|
|
|
if (!isceiling) // it's a floor
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2019-05-21 03:28:52 +00:00
|
|
|
|
scrollx = FIXED_TO_FLOAT(FOFsector->floor_xoffs)/fflatwidth;
|
|
|
|
|
scrolly = FIXED_TO_FLOAT(FOFsector->floor_yoffs)/fflatheight;
|
2017-03-30 20:57:36 +00:00
|
|
|
|
angle = FOFsector->floorpic_angle;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
else // it's a ceiling
|
|
|
|
|
{
|
2019-05-21 03:28:52 +00:00
|
|
|
|
scrollx = FIXED_TO_FLOAT(FOFsector->ceiling_xoffs)/fflatwidth;
|
|
|
|
|
scrolly = FIXED_TO_FLOAT(FOFsector->ceiling_yoffs)/fflatheight;
|
2017-03-30 20:57:36 +00:00
|
|
|
|
angle = FOFsector->ceilingpic_angle;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (gr_frontsector)
|
|
|
|
|
{
|
2016-07-27 18:56:21 +00:00
|
|
|
|
if (!isceiling) // it's a floor
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2019-05-21 03:28:52 +00:00
|
|
|
|
scrollx = FIXED_TO_FLOAT(gr_frontsector->floor_xoffs)/fflatwidth;
|
|
|
|
|
scrolly = FIXED_TO_FLOAT(gr_frontsector->floor_yoffs)/fflatheight;
|
2017-03-30 20:57:36 +00:00
|
|
|
|
angle = gr_frontsector->floorpic_angle;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
else // it's a ceiling
|
|
|
|
|
{
|
2019-05-21 03:28:52 +00:00
|
|
|
|
scrollx = FIXED_TO_FLOAT(gr_frontsector->ceiling_xoffs)/fflatwidth;
|
|
|
|
|
scrolly = FIXED_TO_FLOAT(gr_frontsector->ceiling_yoffs)/fflatheight;
|
2017-03-30 20:57:36 +00:00
|
|
|
|
angle = gr_frontsector->ceilingpic_angle;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
if (angle) // Only needs to be done if there's an altered angle
|
|
|
|
|
{
|
2019-12-25 19:22:01 +00:00
|
|
|
|
|
|
|
|
|
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))));*/
|
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
// 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))));
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-22 17:13:59 +00:00
|
|
|
|
#define SETUP3DVERT(vert, vx, vy) {\
|
|
|
|
|
/* Hurdler: add scrolling texture on floor/ceiling */\
|
|
|
|
|
if (texflat)\
|
|
|
|
|
{\
|
2020-04-25 05:10:30 +00:00
|
|
|
|
vert->s = (float)((vx) / fflatwidth) + scrollx;\
|
|
|
|
|
vert->t = -(float)((vy) / fflatheight) + scrolly;\
|
2020-03-22 17:13:59 +00:00
|
|
|
|
}\
|
|
|
|
|
else\
|
|
|
|
|
{\
|
2020-04-25 05:10:30 +00:00
|
|
|
|
vert->s = (float)(((vx) / fflatwidth) - flatxref + scrollx);\
|
|
|
|
|
vert->t = (float)(flatyref - ((vy) / fflatheight) + scrolly);\
|
2020-03-22 17:13:59 +00:00
|
|
|
|
}\
|
|
|
|
|
\
|
|
|
|
|
/* Need to rotate before translate */\
|
|
|
|
|
if (angle) /* Only needs to be done if there's an altered angle */\
|
|
|
|
|
{\
|
2020-04-25 05:10:30 +00:00
|
|
|
|
tempxsow = FLOAT_TO_FIXED(vert->s);\
|
|
|
|
|
tempytow = FLOAT_TO_FIXED(vert->t);\
|
2020-03-22 17:13:59 +00:00
|
|
|
|
if (texflat)\
|
|
|
|
|
tempytow = -tempytow;\
|
2020-04-25 05:10:30 +00:00
|
|
|
|
vert->s = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINECOSINE(angle)) - FixedMul(tempytow, FINESINE(angle))));\
|
|
|
|
|
vert->t = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINESINE(angle)) + FixedMul(tempytow, FINECOSINE(angle))));\
|
2020-03-22 17:13:59 +00:00
|
|
|
|
}\
|
|
|
|
|
\
|
|
|
|
|
vert->x = (vx);\
|
|
|
|
|
vert->y = height;\
|
|
|
|
|
vert->z = (vy);\
|
|
|
|
|
\
|
|
|
|
|
if (slope)\
|
|
|
|
|
{\
|
2020-05-18 18:35:30 +00:00
|
|
|
|
fixedheight = P_GetSlopeZAt(slope, FLOAT_TO_FIXED((vx)), FLOAT_TO_FIXED((vy)));\
|
2020-03-22 17:13:59 +00:00
|
|
|
|
vert->y = FIXED_TO_FLOAT(fixedheight);\
|
|
|
|
|
}\
|
|
|
|
|
}
|
2016-01-17 04:10:38 +00:00
|
|
|
|
|
2020-03-22 17:13:59 +00:00
|
|
|
|
for (i = 0, v3d = planeVerts; i < nrPlaneVerts; i++,v3d++,pv++)
|
|
|
|
|
SETUP3DVERT(v3d, pv->x, pv->y);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2020-01-16 21:45:49 +00:00
|
|
|
|
if (slope)
|
|
|
|
|
lightlevel = HWR_CalcSlopeLight(lightlevel, R_PointToAngle2(0, 0, slope->normal.x, slope->normal.y), abs(slope->zdelta));
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
HWR_Lighting(&Surf, lightlevel, planecolormap);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
if (PolyFlags & (PF_Translucent|PF_Fog))
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2019-12-25 19:22:01 +00:00
|
|
|
|
Surf.PolyColor.s.alpha = (UINT8)alpha;
|
|
|
|
|
PolyFlags |= PF_Modulated;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
2019-12-25 19:22:01 +00:00
|
|
|
|
PolyFlags |= PF_Masked|PF_Modulated;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
if (PolyFlags & PF_Fog)
|
2020-06-07 18:20:52 +00:00
|
|
|
|
shader = 6; // fog shader
|
2019-12-25 19:22:01 +00:00
|
|
|
|
else if (PolyFlags & PF_Ripple)
|
2020-06-07 18:20:52 +00:00
|
|
|
|
shader = 5; // water shader
|
2014-03-15 16:59:03 +00:00
|
|
|
|
else
|
2020-06-07 18:20:52 +00:00
|
|
|
|
shader = 1; // floor shader
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2020-06-07 18:20:52 +00:00
|
|
|
|
HWR_ProcessPolygon(&Surf, planeVerts, nrPlaneVerts, PolyFlags, shader, false);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2020-03-22 17:13:59 +00:00
|
|
|
|
if (subsector)
|
|
|
|
|
{
|
|
|
|
|
// Horizon lines
|
2020-03-22 17:20:26 +00:00
|
|
|
|
FOutVector horizonpts[6];
|
2020-03-22 17:13:59 +00:00
|
|
|
|
float dist, vx, vy;
|
2020-03-22 17:52:17 +00:00
|
|
|
|
float x1, y1, xd, yd;
|
|
|
|
|
UINT8 numplanes, j;
|
|
|
|
|
vertex_t v; // For determining the closest distance from the line to the camera, to split render planes for minimum distortion;
|
|
|
|
|
|
2020-03-23 13:23:36 +00:00
|
|
|
|
const float renderdist = 27000.0f; // How far out to properly render the plane
|
2020-03-22 17:20:26 +00:00
|
|
|
|
const float farrenderdist = 32768.0f; // From here, raise plane to horizon level to fill in the line with some texture distortion
|
2020-03-22 17:13:59 +00:00
|
|
|
|
|
|
|
|
|
seg_t *line = &segs[subsector->firstline];
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < subsector->numlines; i++, line++)
|
|
|
|
|
{
|
|
|
|
|
if (!line->glseg && line->linedef->special == HORIZONSPECIAL && R_PointOnSegSide(dup_viewx, dup_viewy, line) == 0)
|
|
|
|
|
{
|
2020-03-22 17:52:17 +00:00
|
|
|
|
P_ClosestPointOnLine(viewx, viewy, line->linedef, &v);
|
|
|
|
|
dist = FIXED_TO_FLOAT(R_PointToDist(v.x, v.y));
|
|
|
|
|
|
|
|
|
|
x1 = ((polyvertex_t *)line->pv1)->x;
|
|
|
|
|
y1 = ((polyvertex_t *)line->pv1)->y;
|
|
|
|
|
xd = ((polyvertex_t *)line->pv2)->x - x1;
|
|
|
|
|
yd = ((polyvertex_t *)line->pv2)->y - y1;
|
|
|
|
|
|
|
|
|
|
// Based on the seg length and the distance from the line, split horizon into multiple poly sets to reduce distortion
|
|
|
|
|
dist = sqrtf((xd*xd) + (yd*yd)) / dist / 16.0f;
|
|
|
|
|
if (dist > 100.0f)
|
|
|
|
|
numplanes = 100;
|
|
|
|
|
else
|
|
|
|
|
numplanes = (UINT8)dist + 1;
|
|
|
|
|
|
|
|
|
|
for (j = 0; j < numplanes; j++)
|
|
|
|
|
{
|
|
|
|
|
// Left side
|
|
|
|
|
vx = x1 + xd * j / numplanes;
|
|
|
|
|
vy = y1 + yd * j / numplanes;
|
|
|
|
|
SETUP3DVERT((&horizonpts[1]), vx, vy);
|
|
|
|
|
|
|
|
|
|
dist = sqrtf(powf(vx - gr_viewx, 2) + powf(vy - gr_viewy, 2));
|
|
|
|
|
vx = (vx - gr_viewx) * renderdist / dist + gr_viewx;
|
|
|
|
|
vy = (vy - gr_viewy) * renderdist / dist + gr_viewy;
|
|
|
|
|
SETUP3DVERT((&horizonpts[0]), vx, vy);
|
|
|
|
|
|
|
|
|
|
// Right side
|
|
|
|
|
vx = x1 + xd * (j+1) / numplanes;
|
|
|
|
|
vy = y1 + yd * (j+1) / numplanes;
|
|
|
|
|
SETUP3DVERT((&horizonpts[2]), vx, vy);
|
|
|
|
|
|
|
|
|
|
dist = sqrtf(powf(vx - gr_viewx, 2) + powf(vy - gr_viewy, 2));
|
|
|
|
|
vx = (vx - gr_viewx) * renderdist / dist + gr_viewx;
|
|
|
|
|
vy = (vy - gr_viewy) * renderdist / dist + gr_viewy;
|
|
|
|
|
SETUP3DVERT((&horizonpts[3]), vx, vy);
|
|
|
|
|
|
|
|
|
|
// Horizon fills
|
|
|
|
|
vx = (horizonpts[0].x - gr_viewx) * farrenderdist / renderdist + gr_viewx;
|
|
|
|
|
vy = (horizonpts[0].z - gr_viewy) * farrenderdist / renderdist + gr_viewy;
|
|
|
|
|
SETUP3DVERT((&horizonpts[5]), vx, vy);
|
|
|
|
|
horizonpts[5].y = gr_viewz;
|
|
|
|
|
|
|
|
|
|
vx = (horizonpts[3].x - gr_viewx) * farrenderdist / renderdist + gr_viewx;
|
|
|
|
|
vy = (horizonpts[3].z - gr_viewy) * farrenderdist / renderdist + gr_viewy;
|
|
|
|
|
SETUP3DVERT((&horizonpts[4]), vx, vy);
|
|
|
|
|
horizonpts[4].y = gr_viewz;
|
|
|
|
|
|
|
|
|
|
// Draw
|
2020-06-07 18:20:52 +00:00
|
|
|
|
HWR_ProcessPolygon(&Surf, horizonpts, 6, PolyFlags, shader, true);
|
2020-03-22 17:52:17 +00:00
|
|
|
|
}
|
2020-03-22 17:13:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
#ifdef ALAM_LIGHTING
|
|
|
|
|
// add here code for dynamic lighting on planes
|
|
|
|
|
HWR_PlaneLighting(planeVerts, nrPlaneVerts);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef POLYSKY
|
|
|
|
|
// this don't draw anything it only update the z-buffer so there isn't problem with
|
|
|
|
|
// wall/things upper that sky (map12)
|
|
|
|
|
static void HWR_RenderSkyPlane(extrasubsector_t *xsub, fixed_t fixedheight)
|
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
// no convex poly were generated for this subsector
|
|
|
|
|
if (!xsub->planepoly)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
height = FIXED_TO_FLOAT(fixedheight);
|
|
|
|
|
|
|
|
|
|
pv = xsub->planepoly->pts;
|
|
|
|
|
nrPlaneVerts = xsub->planepoly->numpts;
|
|
|
|
|
|
|
|
|
|
if (nrPlaneVerts < 3) // not even a triangle?
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (nrPlaneVerts > MAXPLANEVERTICES) // FIXME: exceeds plVerts size
|
|
|
|
|
{
|
|
|
|
|
CONS_Debug(DBG_RENDER, "polygon size of %d exceeds max value of %d vertices\n", nrPlaneVerts, MAXPLANEVERTICES);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// transform
|
|
|
|
|
v3d = planeVerts;
|
|
|
|
|
for (i = 0; i < nrPlaneVerts; i++,v3d++,pv++)
|
|
|
|
|
{
|
2019-12-25 19:22:01 +00:00
|
|
|
|
v3d->s = 0.0f;
|
|
|
|
|
v3d->t = 0.0f;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
v3d->x = pv->x;
|
|
|
|
|
v3d->y = height;
|
|
|
|
|
v3d->z = pv->y;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HWD.pfnDrawPolygon(NULL, planeVerts, nrPlaneVerts,
|
|
|
|
|
PF_Clip|PF_Invisible|PF_NoTexture|PF_Occlude);
|
|
|
|
|
}
|
|
|
|
|
#endif //polysky
|
|
|
|
|
|
|
|
|
|
#endif //doplanes
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
wallVerts order is :
|
|
|
|
|
3--2
|
|
|
|
|
| /|
|
|
|
|
|
|/ |
|
|
|
|
|
0--1
|
|
|
|
|
*/
|
|
|
|
|
#ifdef WALLSPLATS
|
|
|
|
|
static void HWR_DrawSegsSplats(FSurfaceInfo * pSurf)
|
|
|
|
|
{
|
2019-12-25 19:22:01 +00:00
|
|
|
|
FOutVector wallVerts[4];
|
2014-03-15 16:59:03 +00:00
|
|
|
|
wallsplat_t *splat;
|
|
|
|
|
GLPatch_t *gpatch;
|
|
|
|
|
fixed_t i;
|
|
|
|
|
// seg bbox
|
|
|
|
|
fixed_t segbbox[4];
|
|
|
|
|
|
|
|
|
|
M_ClearBox(segbbox);
|
|
|
|
|
M_AddToBox(segbbox,
|
2016-11-07 21:55:56 +00:00
|
|
|
|
FLOAT_TO_FIXED(((polyvertex_t *)gr_curline->pv1)->x),
|
|
|
|
|
FLOAT_TO_FIXED(((polyvertex_t *)gr_curline->pv1)->y));
|
2014-03-15 16:59:03 +00:00
|
|
|
|
M_AddToBox(segbbox,
|
2016-11-07 21:55:56 +00:00
|
|
|
|
FLOAT_TO_FIXED(((polyvertex_t *)gr_curline->pv2)->x),
|
|
|
|
|
FLOAT_TO_FIXED(((polyvertex_t *)gr_curline->pv2)->y));
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
2019-09-08 21:27:35 +00:00
|
|
|
|
gpatch = W_CachePatchNum(splat->patch, PU_PATCH);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
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 :
|
2019-12-25 19:22:01 +00:00
|
|
|
|
pSurf.PolyColor.s.alpha = 0xff;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
i = PF_Translucent;
|
|
|
|
|
break;
|
|
|
|
|
case SPLATDRAWMODE_TRANS :
|
2019-12-25 19:22:01 +00:00
|
|
|
|
pSurf.PolyColor.s.alpha = 128;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
i = PF_Translucent;
|
|
|
|
|
break;
|
|
|
|
|
case SPLATDRAWMODE_SHADE :
|
2019-12-25 19:22:01 +00:00
|
|
|
|
pSurf.PolyColor.s.alpha = 0xff;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
i = PF_Substractive;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
HWD.pfnSetShader(2); // wall shader
|
|
|
|
|
HWD.pfnDrawPolygon(&pSurf, wallVerts, 4, i|PF_Modulated|PF_Decal);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
FBITFIELD HWR_TranstableToAlpha(INT32 transtablenum, FSurfaceInfo *pSurf)
|
|
|
|
|
{
|
|
|
|
|
switch (transtablenum)
|
|
|
|
|
{
|
2020-02-10 19:26:29 +00:00
|
|
|
|
case 0 : pSurf->FlatColor.s.alpha = 0x00;return PF_Masked;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
case tr_trans10 : pSurf->FlatColor.s.alpha = 0xe6;return PF_Translucent;
|
|
|
|
|
case tr_trans20 : pSurf->FlatColor.s.alpha = 0xcc;return PF_Translucent;
|
|
|
|
|
case tr_trans30 : pSurf->FlatColor.s.alpha = 0xb3;return PF_Translucent;
|
|
|
|
|
case tr_trans40 : pSurf->FlatColor.s.alpha = 0x99;return PF_Translucent;
|
|
|
|
|
case tr_trans50 : pSurf->FlatColor.s.alpha = 0x80;return PF_Translucent;
|
|
|
|
|
case tr_trans60 : pSurf->FlatColor.s.alpha = 0x66;return PF_Translucent;
|
|
|
|
|
case tr_trans70 : pSurf->FlatColor.s.alpha = 0x4c;return PF_Translucent;
|
|
|
|
|
case tr_trans80 : pSurf->FlatColor.s.alpha = 0x33;return PF_Translucent;
|
|
|
|
|
case tr_trans90 : pSurf->FlatColor.s.alpha = 0x19;return PF_Translucent;
|
|
|
|
|
}
|
|
|
|
|
return PF_Translucent;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
static void HWR_AddTransparentWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, INT32 texnum, FBITFIELD blend, boolean fogwall, INT32 lightlevel, extracolormap_t *wallcolormap);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
// ==========================================================================
|
|
|
|
|
// Wall generation from subsector segs
|
|
|
|
|
// ==========================================================================
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
//
|
|
|
|
|
// HWR_ProjectWall
|
|
|
|
|
//
|
|
|
|
|
static void HWR_ProjectWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blendmode, INT32 lightlevel, extracolormap_t *wallcolormap)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2019-12-25 19:22:01 +00:00
|
|
|
|
HWR_Lighting(pSurf, lightlevel, wallcolormap);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2020-06-07 18:20:52 +00:00
|
|
|
|
HWR_ProcessPolygon(pSurf, wallVerts, 4, blendmode|PF_Modulated|PF_Occlude, 2, false); // wall shader
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
#ifdef WALLSPLATS
|
|
|
|
|
if (gr_curline->linedef->splats && cv_splats.value)
|
|
|
|
|
HWR_DrawSegsSplats(pSurf);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ==========================================================================
|
|
|
|
|
// BSP, CULL, ETC..
|
|
|
|
|
// ==========================================================================
|
|
|
|
|
|
|
|
|
|
// return the frac from the interception of the clipping line
|
|
|
|
|
// (in fact a clipping plane that has a constant, so can clip with simple 2d)
|
|
|
|
|
// with the wall segment
|
|
|
|
|
//
|
2017-01-10 18:01:03 +00:00
|
|
|
|
#ifndef NEWCLIP
|
2014-03-15 16:59:03 +00:00
|
|
|
|
static float HWR_ClipViewSegment(INT32 x, polyvertex_t *v1, polyvertex_t *v2)
|
|
|
|
|
{
|
|
|
|
|
float num, den;
|
|
|
|
|
float v1x, v1y, v1dx, v1dy, v2dx, v2dy;
|
|
|
|
|
angle_t pclipangle = gr_xtoviewangle[x];
|
|
|
|
|
|
|
|
|
|
// a segment of a polygon
|
|
|
|
|
v1x = v1->x;
|
|
|
|
|
v1y = v1->y;
|
|
|
|
|
v1dx = (v2->x - v1->x);
|
|
|
|
|
v1dy = (v2->y - v1->y);
|
|
|
|
|
|
|
|
|
|
// the clipping line
|
|
|
|
|
pclipangle = pclipangle + dup_viewangle; //back to normal angle (non-relative)
|
|
|
|
|
v2dx = FIXED_TO_FLOAT(FINECOSINE(pclipangle>>ANGLETOFINESHIFT));
|
|
|
|
|
v2dy = FIXED_TO_FLOAT(FINESINE(pclipangle>>ANGLETOFINESHIFT));
|
|
|
|
|
|
|
|
|
|
den = v2dy*v1dx - v2dx*v1dy;
|
|
|
|
|
if (den == 0)
|
|
|
|
|
return -1; // parallel
|
|
|
|
|
|
|
|
|
|
// calc the frac along the polygon segment,
|
|
|
|
|
//num = (v2x - v1x)*v2dy + (v1y - v2y)*v2dx;
|
|
|
|
|
//num = -v1x * v2dy + v1y * v2dx;
|
|
|
|
|
num = (gr_viewx - v1x)*v2dy + (v1y - gr_viewy)*v2dx;
|
|
|
|
|
|
|
|
|
|
return num / den;
|
|
|
|
|
}
|
2017-01-10 18:01:03 +00:00
|
|
|
|
#endif
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// HWR_SplitWall
|
|
|
|
|
//
|
2019-12-25 19:22:01 +00:00
|
|
|
|
static void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum, FSurfaceInfo* Surf, INT32 cutflag, ffloor_t *pfloor)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
|
|
|
|
/* 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 */
|
2016-01-27 06:00:15 +00:00
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
float realtop, realbot, top, bot;
|
|
|
|
|
float pegt, pegb, pegmul;
|
|
|
|
|
float height = 0.0f, bheight = 0.0f;
|
2016-01-27 06:00:15 +00:00
|
|
|
|
|
|
|
|
|
float endrealtop, endrealbot, endtop, endbot;
|
|
|
|
|
float endpegt, endpegb, endpegmul;
|
|
|
|
|
float endheight = 0.0f, endbheight = 0.0f;
|
|
|
|
|
|
2020-05-18 13:23:56 +00:00
|
|
|
|
// compiler complains when P_GetSlopeZAt is used in FLOAT_TO_FIXED directly
|
|
|
|
|
// use this as a temp var to store P_GetSlopeZAt's return value each time
|
2016-01-28 13:56:23 +00:00
|
|
|
|
fixed_t temp;
|
2016-01-27 06:00:15 +00:00
|
|
|
|
|
2019-12-26 01:09:31 +00:00
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
INT32 solid, i;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
lightlist_t * list = sector->lightlist;
|
2019-12-25 19:22:01 +00:00
|
|
|
|
const UINT8 alpha = Surf->PolyColor.s.alpha;
|
2019-12-26 01:09:31 +00:00
|
|
|
|
FUINT lightnum = HWR_CalcWallLight(sector->lightlevel, v1x, v1y, v2x, v2y);
|
2018-03-20 14:20:02 +00:00
|
|
|
|
extracolormap_t *colormap = NULL;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2016-01-27 06:00:15 +00:00
|
|
|
|
realtop = top = wallVerts[3].y;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
realbot = bot = wallVerts[0].y;
|
2016-01-27 06:00:15 +00:00
|
|
|
|
pegt = wallVerts[3].t;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
pegb = wallVerts[0].t;
|
|
|
|
|
pegmul = (pegb - pegt) / (top - bot);
|
|
|
|
|
|
2016-01-27 06:00:15 +00:00
|
|
|
|
endrealtop = endtop = wallVerts[2].y;
|
|
|
|
|
endrealbot = endbot = wallVerts[1].y;
|
|
|
|
|
endpegt = wallVerts[2].t;
|
|
|
|
|
endpegb = wallVerts[1].t;
|
|
|
|
|
endpegmul = (endpegb - endpegt) / (endtop - endbot);
|
|
|
|
|
|
2018-03-20 14:20:02 +00:00
|
|
|
|
for (i = 0; i < sector->numlights; i++)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2020-06-07 17:01:05 +00:00
|
|
|
|
if (endtop < endrealbot && top < realbot)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
return;
|
|
|
|
|
|
2018-03-20 14:20:02 +00:00
|
|
|
|
if (!(list[i].flags & FF_NOSHADE))
|
|
|
|
|
{
|
|
|
|
|
if (pfloor && (pfloor->flags & FF_FOG))
|
|
|
|
|
{
|
2019-12-26 01:09:31 +00:00
|
|
|
|
lightnum = HWR_CalcWallLight(pfloor->master->frontsector->lightlevel, v1x, v1y, v2x, v2y);
|
2018-03-20 14:20:02 +00:00
|
|
|
|
colormap = pfloor->master->frontsector->extra_colormap;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2019-12-26 01:09:31 +00:00
|
|
|
|
lightnum = HWR_CalcWallLight(*list[i].lightlevel, v1x, v1y, v2x, v2y);
|
2018-09-12 20:28:55 +00:00
|
|
|
|
colormap = *list[i].extra_colormap;
|
2018-03-20 14:20:02 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
solid = false;
|
|
|
|
|
|
2018-03-20 14:20:02 +00:00
|
|
|
|
if ((sector->lightlist[i].flags & FF_CUTSOLIDS) && !(cutflag & FF_EXTRA))
|
|
|
|
|
solid = true;
|
|
|
|
|
else if ((sector->lightlist[i].flags & FF_CUTEXTRA) && (cutflag & FF_EXTRA))
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2018-03-20 14:20:02 +00:00
|
|
|
|
if (sector->lightlist[i].flags & FF_EXTRA)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2018-03-20 14:20:02 +00:00
|
|
|
|
if ((sector->lightlist[i].flags & (FF_FOG|FF_SWIMMABLE)) == (cutflag & (FF_FOG|FF_SWIMMABLE))) // Only merge with your own types
|
2014-03-15 16:59:03 +00:00
|
|
|
|
solid = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
2018-03-20 14:20:02 +00:00
|
|
|
|
solid = true;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
solid = false;
|
|
|
|
|
|
2020-03-22 14:17:16 +00:00
|
|
|
|
temp = P_GetLightZAt(&list[i], v1x, v1y);
|
|
|
|
|
height = FIXED_TO_FLOAT(temp);
|
|
|
|
|
temp = P_GetLightZAt(&list[i], v2x, v2y);
|
|
|
|
|
endheight = FIXED_TO_FLOAT(temp);
|
2016-01-27 06:00:15 +00:00
|
|
|
|
if (solid)
|
2016-01-28 13:56:23 +00:00
|
|
|
|
{
|
2020-03-22 14:17:16 +00:00
|
|
|
|
temp = P_GetFFloorBottomZAt(list[i].caster, v1x, v1y);
|
|
|
|
|
bheight = FIXED_TO_FLOAT(temp);
|
|
|
|
|
temp = P_GetFFloorBottomZAt(list[i].caster, v2x, v2y);
|
|
|
|
|
endbheight = FIXED_TO_FLOAT(temp);
|
2016-01-28 13:56:23 +00:00
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2020-03-20 17:55:29 +00:00
|
|
|
|
if (endheight >= endtop && height >= top)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
|
|
|
|
if (solid && top > bheight)
|
|
|
|
|
top = bheight;
|
2016-01-28 13:56:23 +00:00
|
|
|
|
if (solid && endtop > endbheight)
|
|
|
|
|
endtop = endbheight;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-03-20 14:20:02 +00:00
|
|
|
|
if (i + 1 < sector->numlights)
|
|
|
|
|
{
|
2020-03-22 14:17:16 +00:00
|
|
|
|
temp = P_GetLightZAt(&list[i+1], v1x, v1y);
|
|
|
|
|
bheight = FIXED_TO_FLOAT(temp);
|
|
|
|
|
temp = P_GetLightZAt(&list[i+1], v2x, v2y);
|
|
|
|
|
endbheight = FIXED_TO_FLOAT(temp);
|
2018-03-20 14:20:02 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
bheight = realbot;
|
|
|
|
|
endbheight = endrealbot;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-20 17:55:29 +00:00
|
|
|
|
if (endbheight >= endtop && bheight >= top)
|
2018-03-20 14:20:02 +00:00
|
|
|
|
continue;
|
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
//Found a break;
|
2018-03-20 14:20:02 +00:00
|
|
|
|
bot = bheight;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
if (bot < realbot)
|
|
|
|
|
bot = realbot;
|
|
|
|
|
|
2018-03-20 14:20:02 +00:00
|
|
|
|
endbot = endbheight;
|
2016-01-27 06:00:15 +00:00
|
|
|
|
|
2016-01-28 13:56:23 +00:00
|
|
|
|
if (endbot < endrealbot)
|
|
|
|
|
endbot = endrealbot;
|
2020-06-07 17:01:05 +00:00
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
Surf->PolyColor.s.alpha = alpha;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2016-01-27 06:00:15 +00:00
|
|
|
|
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);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2016-01-27 06:00:15 +00:00
|
|
|
|
// set top/bottom coords
|
|
|
|
|
wallVerts[3].y = top;
|
|
|
|
|
wallVerts[2].y = endtop;
|
|
|
|
|
wallVerts[0].y = bot;
|
2016-01-28 13:56:23 +00:00
|
|
|
|
wallVerts[1].y = endbot;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2018-03-20 14:20:02 +00:00
|
|
|
|
if (cutflag & FF_FOG)
|
|
|
|
|
HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Fog|PF_NoTexture, true, lightnum, colormap);
|
|
|
|
|
else if (cutflag & FF_TRANSLUCENT)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Translucent, false, lightnum, colormap);
|
|
|
|
|
else
|
|
|
|
|
HWR_ProjectWall(wallVerts, Surf, PF_Masked, lightnum, colormap);
|
|
|
|
|
|
2018-03-20 14:20:02 +00:00
|
|
|
|
top = bot;
|
|
|
|
|
endtop = endbot;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bot = realbot;
|
2016-01-28 13:56:23 +00:00
|
|
|
|
endbot = endrealbot;
|
2020-03-20 17:55:29 +00:00
|
|
|
|
if (endtop <= endrealbot && top <= realbot)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
return;
|
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
Surf->PolyColor.s.alpha = alpha;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2016-01-28 13:56:23 +00:00
|
|
|
|
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);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
// set top/bottom coords
|
2016-01-28 13:56:23 +00:00
|
|
|
|
wallVerts[3].y = top;
|
|
|
|
|
wallVerts[2].y = endtop;
|
|
|
|
|
wallVerts[0].y = bot;
|
|
|
|
|
wallVerts[1].y = endbot;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2018-03-20 14:20:02 +00:00
|
|
|
|
if (cutflag & FF_FOG)
|
|
|
|
|
HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Fog|PF_NoTexture, true, lightnum, colormap);
|
|
|
|
|
else if (cutflag & FF_TRANSLUCENT)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Translucent, false, lightnum, colormap);
|
|
|
|
|
else
|
|
|
|
|
HWR_ProjectWall(wallVerts, Surf, PF_Masked, lightnum, colormap);
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-01 22:04:04 +00:00
|
|
|
|
// HWR_DrawSkyWall
|
2014-09-08 22:29:05 +00:00
|
|
|
|
// Draw walls into the depth buffer so that anything behind is culled properly
|
2020-04-25 17:34:32 +00:00
|
|
|
|
static void HWR_DrawSkyWall(FOutVector *wallVerts, FSurfaceInfo *Surf)
|
2014-09-08 22:29:05 +00:00
|
|
|
|
{
|
2020-06-07 18:20:52 +00:00
|
|
|
|
HWR_SetCurrentTexture(NULL);
|
2014-09-08 22:29:05 +00:00
|
|
|
|
// 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;
|
2018-02-01 22:04:04 +00:00
|
|
|
|
// this no longer sets top/bottom coords, this should be done before caling the function
|
2019-12-25 19:22:01 +00:00
|
|
|
|
HWR_ProjectWall(wallVerts, Surf, PF_Invisible|PF_NoTexture, 255, NULL);
|
2014-09-08 22:29:05 +00:00
|
|
|
|
// 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
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
//
|
2019-12-25 19:22:01 +00:00
|
|
|
|
// HWR_ProcessSeg
|
2014-03-15 16:59:03 +00:00
|
|
|
|
// 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
|
|
|
|
|
//
|
2017-01-10 18:01:03 +00:00
|
|
|
|
static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2019-12-25 19:22:01 +00:00
|
|
|
|
FOutVector wallVerts[4];
|
2014-03-15 16:59:03 +00:00
|
|
|
|
v2d_t vs, ve; // start, end vertices of 2d line (view from above)
|
|
|
|
|
|
|
|
|
|
fixed_t worldtop, worldbottom;
|
|
|
|
|
fixed_t worldhigh = 0, worldlow = 0;
|
2016-01-17 04:10:38 +00:00
|
|
|
|
fixed_t worldtopslope, worldbottomslope;
|
|
|
|
|
fixed_t worldhighslope = 0, worldlowslope = 0;
|
|
|
|
|
fixed_t v1x, v1y, v2x, v2y;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
GLTexture_t *grTex = NULL;
|
|
|
|
|
float cliplow = 0.0f, cliphigh = 0.0f;
|
|
|
|
|
INT32 gr_midtexture;
|
|
|
|
|
fixed_t h, l; // 3D sides and 2s middle textures
|
2016-01-28 13:56:23 +00:00
|
|
|
|
fixed_t hS, lS;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
FUINT lightnum = 0; // shut up compiler
|
|
|
|
|
extracolormap_t *colormap;
|
|
|
|
|
FSurfaceInfo Surf;
|
|
|
|
|
|
|
|
|
|
gr_sidedef = gr_curline->sidedef;
|
|
|
|
|
gr_linedef = gr_curline->linedef;
|
|
|
|
|
|
2016-11-07 21:55:56 +00:00
|
|
|
|
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;
|
2016-01-17 04:10:38 +00:00
|
|
|
|
|
2016-01-28 13:56:23 +00:00
|
|
|
|
v1x = FLOAT_TO_FIXED(vs.x);
|
|
|
|
|
v1y = FLOAT_TO_FIXED(vs.y);
|
|
|
|
|
v2x = FLOAT_TO_FIXED(ve.x);
|
|
|
|
|
v2y = FLOAT_TO_FIXED(ve.y);
|
|
|
|
|
|
2017-01-12 21:43:37 +00:00
|
|
|
|
#define SLOPEPARAMS(slope, end1, end2, normalheight) \
|
2020-05-18 13:23:56 +00:00
|
|
|
|
end1 = P_GetZAt(slope, v1x, v1y, normalheight); \
|
|
|
|
|
end2 = P_GetZAt(slope, v2x, v2y, normalheight);
|
2017-01-12 21:43:37 +00:00
|
|
|
|
|
|
|
|
|
SLOPEPARAMS(gr_frontsector->c_slope, worldtop, worldtopslope, gr_frontsector->ceilingheight)
|
|
|
|
|
SLOPEPARAMS(gr_frontsector->f_slope, worldbottom, worldbottomslope, gr_frontsector->floorheight)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
// x offset the texture
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
|
|
|
|
fixed_t texturehpeg = gr_sidedef->textureoffset + gr_curline->offset;
|
2019-12-25 19:22:01 +00:00
|
|
|
|
cliplow = (float)texturehpeg;
|
|
|
|
|
cliphigh = (float)(texturehpeg + (gr_curline->flength*FRACUNIT));
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-26 01:09:31 +00:00
|
|
|
|
lightnum = HWR_CalcWallLight(gr_frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
colormap = gr_frontsector->extra_colormap;
|
|
|
|
|
|
|
|
|
|
if (gr_frontsector)
|
2019-12-25 19:22:01 +00:00
|
|
|
|
Surf.PolyColor.s.alpha = 255;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
if (gr_backsector)
|
|
|
|
|
{
|
2018-02-01 22:04:04 +00:00
|
|
|
|
INT32 gr_toptexture = 0, gr_bottomtexture = 0;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
// two sided line
|
2018-02-01 22:04:04 +00:00
|
|
|
|
boolean bothceilingssky = false; // turned on if both back and front ceilings are sky
|
2018-02-03 19:48:18 +00:00
|
|
|
|
boolean bothfloorssky = false; // likewise, but for floors
|
2016-01-17 04:10:38 +00:00
|
|
|
|
|
2017-01-12 21:43:37 +00:00
|
|
|
|
SLOPEPARAMS(gr_backsector->c_slope, worldhigh, worldhighslope, gr_backsector->ceilingheight)
|
|
|
|
|
SLOPEPARAMS(gr_backsector->f_slope, worldlow, worldlowslope, gr_backsector->floorheight)
|
|
|
|
|
#undef SLOPEPARAMS
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
// hack to allow height changes in outdoor areas
|
|
|
|
|
// This is what gets rid of the upper textures if there should be sky
|
2018-02-03 18:30:49 +00:00
|
|
|
|
if (gr_frontsector->ceilingpic == skyflatnum
|
|
|
|
|
&& gr_backsector->ceilingpic == skyflatnum)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2018-02-01 22:04:04 +00:00
|
|
|
|
bothceilingssky = true;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-02-03 19:48:18 +00:00
|
|
|
|
// likewise, but for floors and upper textures
|
|
|
|
|
if (gr_frontsector->floorpic == skyflatnum
|
|
|
|
|
&& gr_backsector->floorpic == skyflatnum)
|
|
|
|
|
{
|
|
|
|
|
bothfloorssky = true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-01 22:04:04 +00:00
|
|
|
|
if (!bothceilingssky)
|
|
|
|
|
gr_toptexture = R_GetTextureNum(gr_sidedef->toptexture);
|
2018-02-03 19:48:18 +00:00
|
|
|
|
if (!bothfloorssky)
|
|
|
|
|
gr_bottomtexture = R_GetTextureNum(gr_sidedef->bottomtexture);
|
2016-12-16 21:38:53 +00:00
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
// check TOP TEXTURE
|
2020-03-20 17:55:29 +00:00
|
|
|
|
if ((worldhighslope < worldtopslope || worldhigh < worldtop) && gr_toptexture)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
|
|
|
|
{
|
|
|
|
|
fixed_t texturevpegtop; // top
|
|
|
|
|
|
2016-12-16 21:38:53 +00:00
|
|
|
|
grTex = HWR_GetTexture(gr_toptexture);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
// PEGGING
|
|
|
|
|
if (gr_linedef->flags & ML_DONTPEGTOP)
|
|
|
|
|
texturevpegtop = 0;
|
2016-01-17 04:10:38 +00:00
|
|
|
|
else if (gr_linedef->flags & ML_EFFECT1)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
texturevpegtop = worldhigh + textureheight[gr_sidedef->toptexture] - worldtop;
|
2016-01-17 04:10:38 +00:00
|
|
|
|
else
|
|
|
|
|
texturevpegtop = gr_backsector->ceilingheight + textureheight[gr_sidedef->toptexture] - gr_frontsector->ceilingheight;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
texturevpegtop += gr_sidedef->rowoffset;
|
|
|
|
|
|
2014-03-28 23:28:00 +00:00
|
|
|
|
// 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
|
2016-12-16 21:38:53 +00:00
|
|
|
|
texturevpegtop %= SHORT(textures[gr_toptexture]->height)<<FRACBITS;
|
2014-03-28 23:28:00 +00:00
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
wallVerts[3].t = wallVerts[2].t = texturevpegtop * grTex->scaleY;
|
2016-01-17 04:10:38 +00:00
|
|
|
|
wallVerts[0].t = wallVerts[1].t = (texturevpegtop + gr_frontsector->ceilingheight - gr_backsector->ceilingheight) * grTex->scaleY;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX;
|
|
|
|
|
wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX;
|
2016-01-17 04:10:38 +00:00
|
|
|
|
|
2016-01-28 13:56:23 +00:00
|
|
|
|
// 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
|
2016-06-01 18:22:54 +00:00
|
|
|
|
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;
|
2016-01-28 13:56:23 +00:00
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// set top/bottom coords
|
2016-01-17 04:10:38 +00:00
|
|
|
|
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);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
if (gr_frontsector->numlights)
|
2018-03-20 14:20:02 +00:00
|
|
|
|
HWR_SplitWall(gr_frontsector, wallVerts, gr_toptexture, &Surf, FF_CUTLEVEL, NULL);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
else if (grTex->mipmap.flags & TF_TRANSPARENT)
|
2016-12-16 21:38:53 +00:00
|
|
|
|
HWR_AddTransparentWall(wallVerts, &Surf, gr_toptexture, PF_Environment, false, lightnum, colormap);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
else
|
|
|
|
|
HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// check BOTTOM TEXTURE
|
2016-01-17 04:10:38 +00:00
|
|
|
|
if ((
|
2016-01-28 13:56:23 +00:00
|
|
|
|
worldlowslope > worldbottomslope ||
|
2016-12-16 21:38:53 +00:00
|
|
|
|
worldlow > worldbottom) && gr_bottomtexture) //only if VISIBLE!!!
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
|
|
|
|
{
|
|
|
|
|
fixed_t texturevpegbottom = 0; // bottom
|
|
|
|
|
|
2016-12-16 21:38:53 +00:00
|
|
|
|
grTex = HWR_GetTexture(gr_bottomtexture);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
// PEGGING
|
2016-01-24 08:41:30 +00:00
|
|
|
|
if (!(gr_linedef->flags & ML_DONTPEGBOTTOM))
|
|
|
|
|
texturevpegbottom = 0;
|
|
|
|
|
else if (gr_linedef->flags & ML_EFFECT1)
|
2016-06-01 17:51:38 +00:00
|
|
|
|
texturevpegbottom = worldbottom - worldlow;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
else
|
2016-06-01 17:51:38 +00:00
|
|
|
|
texturevpegbottom = gr_frontsector->floorheight - gr_backsector->floorheight;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
texturevpegbottom += gr_sidedef->rowoffset;
|
|
|
|
|
|
2014-03-28 23:28:00 +00:00
|
|
|
|
// 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
|
2016-12-16 21:38:53 +00:00
|
|
|
|
texturevpegbottom %= SHORT(textures[gr_bottomtexture]->height)<<FRACBITS;
|
2014-03-28 23:28:00 +00:00
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
wallVerts[3].t = wallVerts[2].t = texturevpegbottom * grTex->scaleY;
|
2016-01-24 08:41:30 +00:00
|
|
|
|
wallVerts[0].t = wallVerts[1].t = (texturevpegbottom + gr_backsector->floorheight - gr_frontsector->floorheight) * grTex->scaleY;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX;
|
|
|
|
|
wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX;
|
2016-01-24 08:41:30 +00:00
|
|
|
|
|
2016-01-28 13:56:23 +00:00
|
|
|
|
// 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
|
2016-06-01 17:51:38 +00:00
|
|
|
|
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;
|
2016-01-28 13:56:23 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Skewed by top
|
|
|
|
|
wallVerts[0].t = (texturevpegbottom + worldlow - worldbottom) * grTex->scaleY;
|
|
|
|
|
wallVerts[1].t = (texturevpegbottom + worldlowslope - worldbottomslope) * grTex->scaleY;
|
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// set top/bottom coords
|
2016-01-17 04:10:38 +00:00
|
|
|
|
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);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
if (gr_frontsector->numlights)
|
2018-03-20 14:20:02 +00:00
|
|
|
|
HWR_SplitWall(gr_frontsector, wallVerts, gr_bottomtexture, &Surf, FF_CUTLEVEL, NULL);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
else if (grTex->mipmap.flags & TF_TRANSPARENT)
|
2016-12-16 21:38:53 +00:00
|
|
|
|
HWR_AddTransparentWall(wallVerts, &Surf, gr_bottomtexture, PF_Environment, false, lightnum, colormap);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
else
|
|
|
|
|
HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
|
|
|
|
|
}
|
2016-12-16 21:38:53 +00:00
|
|
|
|
gr_midtexture = R_GetTextureNum(gr_sidedef->midtexture);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
// 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
|
2016-01-27 06:00:15 +00:00
|
|
|
|
{
|
|
|
|
|
popentop = min(worldtop, worldhigh);
|
|
|
|
|
popenbottom = max(worldbottom, worldlow);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-01-28 13:56:23 +00:00
|
|
|
|
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))
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
|
|
|
|
polybottom = popenbottom + gr_sidedef->rowoffset;
|
|
|
|
|
polytop = polybottom + textureheight[gr_midtexture]*repeats;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
polytop = popentop + gr_sidedef->rowoffset;
|
|
|
|
|
polybottom = polytop - textureheight[gr_midtexture]*repeats;
|
|
|
|
|
}
|
|
|
|
|
// CB
|
|
|
|
|
// 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;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// The cut-off values of a linedef can always be constant, since every line has an absoulute front and or back sector
|
2016-01-27 06:00:15 +00:00
|
|
|
|
lowcut = popenbottom;
|
|
|
|
|
highcut = popentop;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-01-27 06:00:15 +00:00
|
|
|
|
h = min(highcut, polytop);
|
|
|
|
|
l = max(polybottom, lowcut);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
// PEGGING
|
2016-01-28 13:56:23 +00:00
|
|
|
|
if (!!(gr_linedef->flags & ML_DONTPEGBOTTOM) ^ !!(gr_linedef->flags & ML_EFFECT3))
|
2014-03-15 16:59:03 +00:00
|
|
|
|
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);
|
|
|
|
|
|
2016-01-28 13:56:23 +00:00
|
|
|
|
// 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);
|
|
|
|
|
}
|
2016-01-27 06:00:15 +00:00
|
|
|
|
|
2020-01-26 11:24:52 +00:00
|
|
|
|
// set alpha for transparent walls
|
2014-03-15 16:59:03 +00:00
|
|
|
|
// ooops ! this do not work at all because render order we should render it in backtofront order
|
|
|
|
|
switch (gr_linedef->special)
|
|
|
|
|
{
|
|
|
|
|
// 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:
|
2020-02-10 19:26:29 +00:00
|
|
|
|
if (gr_linedef->alpha >= 0 && gr_linedef->alpha < FRACUNIT)
|
2020-01-26 11:24:52 +00:00
|
|
|
|
blendmode = HWR_TranstableToAlpha(R_GetLinedefTransTable(gr_linedef->alpha), &Surf);
|
|
|
|
|
else
|
|
|
|
|
blendmode = PF_Masked;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
2014-08-30 13:10:55 +00:00
|
|
|
|
|
|
|
|
|
if (gr_curline->polyseg && gr_curline->polyseg->translucency > 0)
|
|
|
|
|
{
|
|
|
|
|
if (gr_curline->polyseg->translucency >= NUMTRANSMAPS) // wall not drawn
|
2014-08-30 13:20:07 +00:00
|
|
|
|
{
|
2019-12-25 19:22:01 +00:00
|
|
|
|
Surf.PolyColor.s.alpha = 0x00; // This shouldn't draw anything regardless of blendmode
|
2014-08-30 13:20:07 +00:00
|
|
|
|
blendmode = PF_Masked;
|
|
|
|
|
}
|
2014-08-30 13:36:18 +00:00
|
|
|
|
else
|
|
|
|
|
blendmode = HWR_TranstableToAlpha(gr_curline->polyseg->translucency, &Surf);
|
2014-08-30 13:10:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
if (gr_frontsector->numlights)
|
2014-03-20 20:34:56 +00:00
|
|
|
|
{
|
|
|
|
|
if (!(blendmode & PF_Masked))
|
2018-03-20 14:20:02 +00:00
|
|
|
|
HWR_SplitWall(gr_frontsector, wallVerts, gr_midtexture, &Surf, FF_TRANSLUCENT, NULL);
|
2014-03-20 20:34:56 +00:00
|
|
|
|
else
|
2017-09-08 23:41:11 +00:00
|
|
|
|
{
|
2018-03-20 14:20:02 +00:00
|
|
|
|
HWR_SplitWall(gr_frontsector, wallVerts, gr_midtexture, &Surf, FF_CUTLEVEL, NULL);
|
2017-09-08 23:41:11 +00:00
|
|
|
|
}
|
2014-03-20 20:34:56 +00:00
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
else if (!(blendmode & PF_Masked))
|
|
|
|
|
HWR_AddTransparentWall(wallVerts, &Surf, gr_midtexture, blendmode, false, lightnum, colormap);
|
|
|
|
|
else
|
|
|
|
|
HWR_ProjectWall(wallVerts, &Surf, blendmode, lightnum, colormap);
|
|
|
|
|
}
|
2014-09-08 22:29:05 +00:00
|
|
|
|
|
2018-02-01 22:04:04 +00:00
|
|
|
|
// Sky culling
|
|
|
|
|
// No longer so much a mess as before!
|
2014-10-27 20:57:45 +00:00
|
|
|
|
if (!gr_curline->polyseg) // Don't do it for polyobjects
|
2014-09-08 22:29:05 +00:00
|
|
|
|
{
|
2018-02-01 22:04:04 +00:00
|
|
|
|
if (gr_frontsector->ceilingpic == skyflatnum)
|
2014-10-27 20:57:45 +00:00
|
|
|
|
{
|
2018-02-01 22:04:04 +00:00
|
|
|
|
if (gr_backsector->ceilingpic != skyflatnum) // don't cull if back sector is also sky
|
2014-10-27 20:57:45 +00:00
|
|
|
|
{
|
2018-02-01 22:04:04 +00:00
|
|
|
|
wallVerts[2].y = wallVerts[3].y = FIXED_TO_FLOAT(INT32_MAX); // draw to top of map space
|
|
|
|
|
wallVerts[0].y = FIXED_TO_FLOAT(worldtop);
|
|
|
|
|
wallVerts[1].y = FIXED_TO_FLOAT(worldtopslope);
|
|
|
|
|
HWR_DrawSkyWall(wallVerts, &Surf);
|
2014-09-09 00:59:19 +00:00
|
|
|
|
}
|
2014-09-08 22:29:05 +00:00
|
|
|
|
}
|
2014-09-09 00:59:19 +00:00
|
|
|
|
|
2018-02-01 22:04:04 +00:00
|
|
|
|
if (gr_frontsector->floorpic == skyflatnum)
|
|
|
|
|
{
|
|
|
|
|
if (gr_backsector->floorpic != skyflatnum) // don't cull if back sector is also sky
|
2014-10-27 20:57:45 +00:00
|
|
|
|
{
|
2018-02-01 22:04:04 +00:00
|
|
|
|
wallVerts[3].y = FIXED_TO_FLOAT(worldbottom);
|
|
|
|
|
wallVerts[2].y = FIXED_TO_FLOAT(worldbottomslope);
|
|
|
|
|
wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(INT32_MIN); // draw to bottom of map space
|
|
|
|
|
HWR_DrawSkyWall(wallVerts, &Surf);
|
2014-09-09 00:59:19 +00:00
|
|
|
|
}
|
2014-09-08 22:29:05 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Single sided line... Deal only with the middletexture (if one exists)
|
2016-12-16 21:38:53 +00:00
|
|
|
|
gr_midtexture = R_GetTextureNum(gr_sidedef->midtexture);
|
2019-12-25 19:22:01 +00:00
|
|
|
|
if (gr_midtexture && gr_linedef->special != 41) // (Ignore horizon line for OGL)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
|
|
|
|
{
|
|
|
|
|
fixed_t texturevpeg;
|
|
|
|
|
// PEGGING
|
2016-01-28 13:56:23 +00:00
|
|
|
|
if ((gr_linedef->flags & (ML_DONTPEGBOTTOM|ML_EFFECT2)) == (ML_DONTPEGBOTTOM|ML_EFFECT2))
|
2016-01-24 08:41:30 +00:00
|
|
|
|
texturevpeg = gr_frontsector->floorheight + textureheight[gr_sidedef->midtexture] - gr_frontsector->ceilingheight + gr_sidedef->rowoffset;
|
2020-03-20 17:55:29 +00:00
|
|
|
|
else if (gr_linedef->flags & ML_DONTPEGBOTTOM)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
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;
|
2016-01-24 08:41:30 +00:00
|
|
|
|
wallVerts[0].t = wallVerts[1].t = (texturevpeg + gr_frontsector->ceilingheight - gr_frontsector->floorheight) * grTex->scaleY;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX;
|
|
|
|
|
wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX;
|
2016-01-24 08:41:30 +00:00
|
|
|
|
|
2016-01-28 13:56:23 +00:00
|
|
|
|
// 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;
|
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
2020-03-20 17:55:29 +00:00
|
|
|
|
|
2016-01-28 13:56:23 +00:00
|
|
|
|
//Set textures properly on single sided walls that are sloped
|
2016-01-24 08:41:30 +00:00
|
|
|
|
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);
|
2020-03-20 17:55:29 +00:00
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
// I don't think that solid walls can use translucent linedef types...
|
|
|
|
|
if (gr_frontsector->numlights)
|
2018-03-20 14:20:02 +00:00
|
|
|
|
HWR_SplitWall(gr_frontsector, wallVerts, gr_midtexture, &Surf, FF_CUTLEVEL, NULL);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-09-08 22:29:05 +00:00
|
|
|
|
|
2014-10-27 20:57:45 +00:00
|
|
|
|
if (!gr_curline->polyseg)
|
|
|
|
|
{
|
|
|
|
|
if (gr_frontsector->ceilingpic == skyflatnum) // It's a single-sided line with sky for its sector
|
2018-02-01 22:04:04 +00:00
|
|
|
|
{
|
|
|
|
|
wallVerts[2].y = wallVerts[3].y = FIXED_TO_FLOAT(INT32_MAX); // draw to top of map space
|
|
|
|
|
wallVerts[0].y = FIXED_TO_FLOAT(worldtop);
|
|
|
|
|
wallVerts[1].y = FIXED_TO_FLOAT(worldtopslope);
|
|
|
|
|
HWR_DrawSkyWall(wallVerts, &Surf);
|
|
|
|
|
}
|
2014-10-27 20:57:45 +00:00
|
|
|
|
if (gr_frontsector->floorpic == skyflatnum)
|
2018-02-01 22:04:04 +00:00
|
|
|
|
{
|
|
|
|
|
wallVerts[3].y = FIXED_TO_FLOAT(worldbottom);
|
|
|
|
|
wallVerts[2].y = FIXED_TO_FLOAT(worldbottomslope);
|
|
|
|
|
wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(INT32_MIN); // draw to bottom of map space
|
|
|
|
|
HWR_DrawSkyWall(wallVerts, &Surf);
|
|
|
|
|
}
|
2014-10-27 20:57:45 +00:00
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//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;
|
|
|
|
|
|
2014-04-17 12:02:34 +00:00
|
|
|
|
INT32 texnum;
|
|
|
|
|
line_t * newline = NULL; // Multi-Property FOF
|
|
|
|
|
|
2016-01-24 08:41:30 +00:00
|
|
|
|
///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
|
2014-03-15 16:59:03 +00:00
|
|
|
|
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)
|
|
|
|
|
{
|
2020-03-25 07:34:52 +00:00
|
|
|
|
if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERSIDES))
|
|
|
|
|
continue;
|
|
|
|
|
if (!(rover->flags & FF_ALLSIDES) && rover->flags & FF_INVERTSIDES)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
continue;
|
|
|
|
|
if (*rover->topheight < lowcut || *rover->bottomheight > highcut)
|
|
|
|
|
continue;
|
|
|
|
|
|
2016-12-16 21:38:53 +00:00
|
|
|
|
texnum = R_GetTextureNum(sides[rover->master->sidenum[0]].midtexture);
|
2014-04-17 12:02:34 +00:00
|
|
|
|
|
|
|
|
|
if (rover->master->flags & ML_TFERLINE)
|
|
|
|
|
{
|
|
|
|
|
size_t linenum = gr_curline->linedef-gr_backsector->lines[0];
|
|
|
|
|
newline = rover->master->frontsector->lines[0] + linenum;
|
2016-12-16 21:38:53 +00:00
|
|
|
|
texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture);
|
2014-04-17 12:02:34 +00:00
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2020-03-22 14:17:16 +00:00
|
|
|
|
h = P_GetFFloorTopZAt (rover, v1x, v1y);
|
|
|
|
|
hS = P_GetFFloorTopZAt (rover, v2x, v2y);
|
|
|
|
|
l = P_GetFFloorBottomZAt(rover, v1x, v1y);
|
|
|
|
|
lS = P_GetFFloorBottomZAt(rover, v2x, v2y);
|
2016-01-25 05:57:53 +00:00
|
|
|
|
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
|
|
|
|
|
|
2016-01-28 13:56:23 +00:00
|
|
|
|
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);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
2017-01-12 21:43:37 +00:00
|
|
|
|
else
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2018-06-26 20:41:05 +00:00
|
|
|
|
fixed_t texturevpeg;
|
2018-09-28 16:02:02 +00:00
|
|
|
|
boolean attachtobottom = false;
|
|
|
|
|
boolean slopeskew = false; // skew FOF walls with slopes?
|
2014-04-17 12:02:34 +00:00
|
|
|
|
|
2018-06-26 20:41:05 +00:00
|
|
|
|
// 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
|
2014-04-17 12:02:34 +00:00
|
|
|
|
if (newline)
|
|
|
|
|
{
|
2018-06-26 20:41:05 +00:00
|
|
|
|
texturevpeg = sides[newline->sidenum[0]].rowoffset;
|
2018-09-28 16:02:02 +00:00
|
|
|
|
attachtobottom = !!(newline->flags & ML_DONTPEGBOTTOM);
|
|
|
|
|
slopeskew = !!(newline->flags & ML_DONTPEGTOP);
|
2014-04-17 12:02:34 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2018-06-26 20:41:05 +00:00
|
|
|
|
texturevpeg = sides[rover->master->sidenum[0]].rowoffset;
|
2018-09-28 16:02:02 +00:00
|
|
|
|
attachtobottom = !!(gr_linedef->flags & ML_DONTPEGBOTTOM);
|
|
|
|
|
slopeskew = !!(rover->master->flags & ML_DONTPEGTOP);
|
2014-04-17 12:02:34 +00:00
|
|
|
|
}
|
2018-06-26 20:41:05 +00:00
|
|
|
|
|
|
|
|
|
grTex = HWR_GetTexture(texnum);
|
|
|
|
|
|
2018-09-28 16:02:02 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
2018-03-15 23:58:37 +00:00
|
|
|
|
blendmode = PF_Fog|PF_NoTexture;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-12-26 01:09:31 +00:00
|
|
|
|
lightnum = HWR_CalcWallLight(rover->master->frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
colormap = rover->master->frontsector->extra_colormap;
|
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel, rover->master->frontsector->extra_colormap);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
if (gr_frontsector->numlights)
|
2018-03-20 14:20:02 +00:00
|
|
|
|
HWR_SplitWall(gr_frontsector, wallVerts, 0, &Surf, rover->flags, rover);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
else
|
|
|
|
|
HWR_AddTransparentWall(wallVerts, &Surf, 0, blendmode, true, lightnum, colormap);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
FBITFIELD blendmode = PF_Masked;
|
|
|
|
|
|
2017-09-08 23:41:11 +00:00
|
|
|
|
if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
|
|
|
|
blendmode = PF_Translucent;
|
2019-12-25 19:22:01 +00:00
|
|
|
|
Surf.PolyColor.s.alpha = (UINT8)rover->alpha-1 > 255 ? 255 : rover->alpha-1;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (gr_frontsector->numlights)
|
2018-03-20 14:20:02 +00:00
|
|
|
|
HWR_SplitWall(gr_frontsector, wallVerts, texnum, &Surf, rover->flags, rover);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (blendmode != PF_Masked)
|
2014-04-17 12:02:34 +00:00
|
|
|
|
HWR_AddTransparentWall(wallVerts, &Surf, texnum, blendmode, false, lightnum, colormap);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
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)
|
|
|
|
|
{
|
2020-03-25 07:34:52 +00:00
|
|
|
|
if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERSIDES))
|
|
|
|
|
continue;
|
|
|
|
|
if (!(rover->flags & FF_ALLSIDES || rover->flags & FF_INVERTSIDES))
|
2014-03-15 16:59:03 +00:00
|
|
|
|
continue;
|
|
|
|
|
if (*rover->topheight < lowcut || *rover->bottomheight > highcut)
|
|
|
|
|
continue;
|
|
|
|
|
|
2016-12-16 21:38:53 +00:00
|
|
|
|
texnum = R_GetTextureNum(sides[rover->master->sidenum[0]].midtexture);
|
2014-04-17 12:02:34 +00:00
|
|
|
|
|
|
|
|
|
if (rover->master->flags & ML_TFERLINE)
|
|
|
|
|
{
|
|
|
|
|
size_t linenum = gr_curline->linedef-gr_backsector->lines[0];
|
|
|
|
|
newline = rover->master->frontsector->lines[0] + linenum;
|
2016-12-16 21:38:53 +00:00
|
|
|
|
texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture);
|
2014-04-17 12:02:34 +00:00
|
|
|
|
}
|
2020-03-22 14:17:16 +00:00
|
|
|
|
h = P_GetFFloorTopZAt (rover, v1x, v1y);
|
|
|
|
|
hS = P_GetFFloorTopZAt (rover, v2x, v2y);
|
|
|
|
|
l = P_GetFFloorBottomZAt(rover, v1x, v1y);
|
|
|
|
|
lS = P_GetFFloorBottomZAt(rover, v2x, v2y);
|
2016-01-25 05:57:53 +00:00
|
|
|
|
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
|
2014-04-17 12:02:34 +00:00
|
|
|
|
|
2016-01-28 13:56:23 +00:00
|
|
|
|
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);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
2017-01-12 21:43:37 +00:00
|
|
|
|
else
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2014-04-17 12:02:34 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
2018-03-15 23:58:37 +00:00
|
|
|
|
blendmode = PF_Fog|PF_NoTexture;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-12-26 01:09:31 +00:00
|
|
|
|
lightnum = HWR_CalcWallLight(rover->master->frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
colormap = rover->master->frontsector->extra_colormap;
|
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel, rover->master->frontsector->extra_colormap);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
if (gr_backsector->numlights)
|
2018-03-20 14:20:02 +00:00
|
|
|
|
HWR_SplitWall(gr_backsector, wallVerts, 0, &Surf, rover->flags, rover);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
else
|
|
|
|
|
HWR_AddTransparentWall(wallVerts, &Surf, 0, blendmode, true, lightnum, colormap);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
FBITFIELD blendmode = PF_Masked;
|
|
|
|
|
|
2017-09-08 23:41:11 +00:00
|
|
|
|
if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
|
|
|
|
blendmode = PF_Translucent;
|
2019-12-25 19:22:01 +00:00
|
|
|
|
Surf.PolyColor.s.alpha = (UINT8)rover->alpha-1 > 255 ? 255 : rover->alpha-1;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (gr_backsector->numlights)
|
2018-03-20 14:20:02 +00:00
|
|
|
|
HWR_SplitWall(gr_backsector, wallVerts, texnum, &Surf, rover->flags, rover);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (blendmode != PF_Masked)
|
2014-04-17 12:02:34 +00:00
|
|
|
|
HWR_AddTransparentWall(wallVerts, &Surf, texnum, blendmode, false, lightnum, colormap);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
else
|
|
|
|
|
HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//Hurdler: end of 3d-floors test
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-10 18:01:03 +00:00
|
|
|
|
// From PrBoom:
|
|
|
|
|
//
|
|
|
|
|
// e6y: Check whether the player can look beyond this line
|
|
|
|
|
//
|
|
|
|
|
#ifdef NEWCLIP
|
2017-01-10 20:07:02 +00:00
|
|
|
|
boolean checkforemptylines = true;
|
2017-01-10 18:01:03 +00:00
|
|
|
|
// Don't modify anything here, just check
|
|
|
|
|
// Kalaron: Modified for sloped linedefs
|
|
|
|
|
static boolean CheckClip(seg_t * seg, 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
|
2018-02-07 17:46:01 +00:00
|
|
|
|
boolean bothceilingssky = false, bothfloorssky = false;
|
|
|
|
|
|
|
|
|
|
if (abacksector->ceilingpic == skyflatnum && afrontsector->ceilingpic == skyflatnum)
|
|
|
|
|
bothceilingssky = true;
|
|
|
|
|
if (abacksector->floorpic == skyflatnum && afrontsector->floorpic == skyflatnum)
|
|
|
|
|
bothfloorssky = true;
|
2017-01-10 18:01:03 +00:00
|
|
|
|
|
|
|
|
|
// GZDoom method of sloped line clipping
|
|
|
|
|
|
|
|
|
|
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) \
|
2020-05-18 13:23:56 +00:00
|
|
|
|
end1 = P_GetZAt(slope, v1x, v1y, normalheight); \
|
|
|
|
|
end2 = P_GetZAt(slope, v2x, v2y, normalheight);
|
2017-01-10 18:01:03 +00:00
|
|
|
|
|
2020-03-22 14:17:16 +00:00
|
|
|
|
SLOPEPARAMS(afrontsector->f_slope, frontf1, frontf2, afrontsector-> floorheight)
|
2017-01-10 18:01:03 +00:00
|
|
|
|
SLOPEPARAMS(afrontsector->c_slope, frontc1, frontc2, afrontsector->ceilingheight)
|
2020-03-22 14:17:16 +00:00
|
|
|
|
SLOPEPARAMS( abacksector->f_slope, backf1, backf2, abacksector-> floorheight)
|
|
|
|
|
SLOPEPARAMS( abacksector->c_slope, backc1, backc2, abacksector->ceilingheight)
|
2017-01-10 18:01:03 +00:00
|
|
|
|
#undef SLOPEPARAMS
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-03-22 14:17:16 +00:00
|
|
|
|
frontf1 = frontf2 = afrontsector-> floorheight;
|
2017-01-10 18:01:03 +00:00
|
|
|
|
frontc1 = frontc2 = afrontsector->ceilingheight;
|
2020-03-22 14:17:16 +00:00
|
|
|
|
backf1 = backf2 = abacksector-> floorheight;
|
|
|
|
|
backc1 = backc2 = abacksector->ceilingheight;
|
2017-01-10 18:01:03 +00:00
|
|
|
|
}
|
2018-02-01 22:04:04 +00:00
|
|
|
|
// properly render skies (consider door "open" if both ceilings are sky)
|
2018-02-03 19:48:18 +00:00
|
|
|
|
// same for floors
|
2018-02-07 17:46:01 +00:00
|
|
|
|
if (!bothceilingssky && !bothfloorssky)
|
2017-01-10 18:01:03 +00:00
|
|
|
|
{
|
2018-02-01 22:04:04 +00:00
|
|
|
|
// now check for closed sectors!
|
2018-02-03 18:30:49 +00:00
|
|
|
|
if ((backc1 <= frontf1 && backc2 <= frontf2)
|
|
|
|
|
|| (backf1 >= frontc1 && backf2 >= frontc2))
|
2018-02-01 22:04:04 +00:00
|
|
|
|
{
|
|
|
|
|
checkforemptylines = false;
|
|
|
|
|
return true;
|
2017-01-10 18:01:03 +00:00
|
|
|
|
}
|
2018-02-01 22:04:04 +00:00
|
|
|
|
|
|
|
|
|
if (backc1 <= backf1 && backc2 <= backf2)
|
2017-01-10 18:01:03 +00:00
|
|
|
|
{
|
2018-02-01 22:04:04 +00:00
|
|
|
|
// preserve a kind of transparent door/lift special effect:
|
|
|
|
|
if (((backc1 >= frontc1 && backc2 >= frontc2) || seg->sidedef->toptexture)
|
|
|
|
|
&& ((backf1 <= frontf1 && backf2 <= frontf2) || seg->sidedef->bottomtexture))
|
|
|
|
|
{
|
|
|
|
|
checkforemptylines = false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2017-01-10 18:01:03 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-07 17:46:01 +00:00
|
|
|
|
if (!bothceilingssky) {
|
|
|
|
|
if (backc1 != frontc1 || backc2 != frontc2)
|
|
|
|
|
{
|
|
|
|
|
checkforemptylines = false;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!bothfloorssky) {
|
|
|
|
|
if (backf1 != frontf1 || backf2 != frontf2)
|
2017-01-10 20:07:02 +00:00
|
|
|
|
{
|
|
|
|
|
checkforemptylines = false;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2018-02-07 17:46:01 +00:00
|
|
|
|
}
|
2017-01-10 18:01:03 +00:00
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
#else
|
2014-03-15 16:59:03 +00:00
|
|
|
|
//Hurdler: just like in r_bsp.c
|
|
|
|
|
#if 1
|
|
|
|
|
#define MAXSEGS MAXVIDWIDTH/2+1
|
|
|
|
|
#else
|
|
|
|
|
//Alam_GBC: Or not (may cause overflow)
|
|
|
|
|
#define MAXSEGS 128
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// hw_newend is one past the last valid seg
|
|
|
|
|
static cliprange_t * hw_newend;
|
|
|
|
|
static cliprange_t gr_solidsegs[MAXSEGS];
|
|
|
|
|
|
2019-12-12 20:30:19 +00:00
|
|
|
|
// needs fix: walls are incorrectly clipped one column less
|
|
|
|
|
static consvar_t cv_grclipwalls = {"gr_clipwalls", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
static void printsolidsegs(void)
|
|
|
|
|
{
|
|
|
|
|
cliprange_t * start;
|
2019-12-12 19:53:31 +00:00
|
|
|
|
if (!hw_newend)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
return;
|
|
|
|
|
for (start = gr_solidsegs;start != hw_newend;start++)
|
|
|
|
|
{
|
|
|
|
|
CONS_Debug(DBG_RENDER, "%d-%d|",start->first,start->last);
|
|
|
|
|
}
|
|
|
|
|
CONS_Debug(DBG_RENDER, "\n\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
static void HWR_ClipSolidWallSegment(INT32 first, INT32 last)
|
|
|
|
|
{
|
|
|
|
|
cliprange_t *next, *start;
|
|
|
|
|
float lowfrac, highfrac;
|
|
|
|
|
boolean poorhack = false;
|
|
|
|
|
|
|
|
|
|
// Find the first range that touches the range
|
|
|
|
|
// (adjacent pixels are touching).
|
|
|
|
|
start = gr_solidsegs;
|
|
|
|
|
while (start->last < first-1)
|
|
|
|
|
start++;
|
|
|
|
|
|
|
|
|
|
if (first < start->first)
|
|
|
|
|
{
|
|
|
|
|
if (last < start->first-1)
|
|
|
|
|
{
|
|
|
|
|
// Post is entirely visible (above start),
|
|
|
|
|
// so insert a new clippost.
|
|
|
|
|
HWR_StoreWallRange(first, last);
|
|
|
|
|
|
|
|
|
|
next = hw_newend;
|
|
|
|
|
hw_newend++;
|
|
|
|
|
|
|
|
|
|
while (next != start)
|
|
|
|
|
{
|
|
|
|
|
*next = *(next-1);
|
|
|
|
|
next--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
next->first = first;
|
|
|
|
|
next->last = last;
|
|
|
|
|
printsolidsegs();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// There is a fragment above *start.
|
|
|
|
|
if (!cv_grclipwalls.value)
|
|
|
|
|
{
|
|
|
|
|
if (!poorhack) HWR_StoreWallRange(first, last);
|
|
|
|
|
poorhack = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-11-07 21:55:56 +00:00
|
|
|
|
highfrac = HWR_ClipViewSegment(start->first+1, (polyvertex_t *)gr_curline->pv1, (polyvertex_t *)gr_curline->pv2);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
HWR_StoreWallRange(0, highfrac);
|
|
|
|
|
}
|
|
|
|
|
// Now adjust the clip size.
|
|
|
|
|
start->first = first;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Bottom contained in start?
|
|
|
|
|
if (last <= start->last)
|
|
|
|
|
{
|
|
|
|
|
printsolidsegs();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
next = start;
|
|
|
|
|
while (last >= (next+1)->first-1)
|
|
|
|
|
{
|
|
|
|
|
// There is a fragment between two posts.
|
|
|
|
|
if (!cv_grclipwalls.value)
|
|
|
|
|
{
|
|
|
|
|
if (!poorhack) HWR_StoreWallRange(first,last);
|
|
|
|
|
poorhack = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-11-07 21:55:56 +00:00
|
|
|
|
lowfrac = HWR_ClipViewSegment(next->last-1, (polyvertex_t *)gr_curline->pv1, (polyvertex_t *)gr_curline->pv2);
|
|
|
|
|
highfrac = HWR_ClipViewSegment((next+1)->first+1, (polyvertex_t *)gr_curline->pv1, (polyvertex_t *)gr_curline->pv2);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
HWR_StoreWallRange(lowfrac, highfrac);
|
|
|
|
|
}
|
|
|
|
|
next++;
|
|
|
|
|
|
|
|
|
|
if (last <= next->last)
|
|
|
|
|
{
|
|
|
|
|
// Bottom is contained in next.
|
|
|
|
|
// Adjust the clip size.
|
|
|
|
|
start->last = next->last;
|
|
|
|
|
goto crunch;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (first == next->first+1) // 1 line texture
|
|
|
|
|
{
|
|
|
|
|
if (!cv_grclipwalls.value)
|
|
|
|
|
{
|
|
|
|
|
if (!poorhack) HWR_StoreWallRange(first,last);
|
|
|
|
|
poorhack = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
HWR_StoreWallRange(0, 1);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// There is a fragment after *next.
|
|
|
|
|
if (!cv_grclipwalls.value)
|
|
|
|
|
{
|
|
|
|
|
if (!poorhack) HWR_StoreWallRange(first,last);
|
|
|
|
|
poorhack = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-11-07 21:55:56 +00:00
|
|
|
|
lowfrac = HWR_ClipViewSegment(next->last-1, (polyvertex_t *)gr_curline->pv1, (polyvertex_t *)gr_curline->pv2);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
HWR_StoreWallRange(lowfrac, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Adjust the clip size.
|
|
|
|
|
start->last = last;
|
|
|
|
|
|
|
|
|
|
// Remove start+1 to next from the clip list,
|
|
|
|
|
// because start now covers their area.
|
|
|
|
|
crunch:
|
|
|
|
|
if (next == start)
|
|
|
|
|
{
|
|
|
|
|
printsolidsegs();
|
|
|
|
|
// Post just extended past the bottom of one post.
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while (next++ != hw_newend)
|
|
|
|
|
{
|
|
|
|
|
// Remove a post.
|
|
|
|
|
*++start = *next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hw_newend = start;
|
|
|
|
|
printsolidsegs();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// handle LineDefs with upper and lower texture (windows)
|
|
|
|
|
//
|
|
|
|
|
static void HWR_ClipPassWallSegment(INT32 first, INT32 last)
|
|
|
|
|
{
|
|
|
|
|
cliprange_t *start;
|
|
|
|
|
float lowfrac, highfrac;
|
|
|
|
|
//to allow noclipwalls but still solidseg reject of non-visible walls
|
|
|
|
|
boolean poorhack = false;
|
|
|
|
|
|
|
|
|
|
// Find the first range that touches the range
|
|
|
|
|
// (adjacent pixels are touching).
|
|
|
|
|
start = gr_solidsegs;
|
|
|
|
|
while (start->last < first - 1)
|
|
|
|
|
start++;
|
|
|
|
|
|
|
|
|
|
if (first < start->first)
|
|
|
|
|
{
|
|
|
|
|
if (last < start->first-1)
|
|
|
|
|
{
|
|
|
|
|
// Post is entirely visible (above start).
|
|
|
|
|
HWR_StoreWallRange(0, 1);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// There is a fragment above *start.
|
|
|
|
|
if (!cv_grclipwalls.value)
|
|
|
|
|
{ //20/08/99: Changed by Hurdler (taken from faB's code)
|
|
|
|
|
if (!poorhack) HWR_StoreWallRange(0, 1);
|
|
|
|
|
poorhack = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
highfrac = HWR_ClipViewSegment(min(start->first + 1,
|
2016-11-07 21:55:56 +00:00
|
|
|
|
start->last), (polyvertex_t *)gr_curline->pv1,
|
|
|
|
|
(polyvertex_t *)gr_curline->pv2);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
HWR_StoreWallRange(0, highfrac);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Bottom contained in start?
|
|
|
|
|
if (last <= start->last)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
while (last >= (start+1)->first-1)
|
|
|
|
|
{
|
|
|
|
|
// There is a fragment between two posts.
|
|
|
|
|
if (!cv_grclipwalls.value)
|
|
|
|
|
{
|
|
|
|
|
if (!poorhack) HWR_StoreWallRange(0, 1);
|
|
|
|
|
poorhack = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-11-07 21:55:56 +00:00
|
|
|
|
lowfrac = HWR_ClipViewSegment(max(start->last-1,start->first), (polyvertex_t *)gr_curline->pv1, (polyvertex_t *)gr_curline->pv2);
|
|
|
|
|
highfrac = HWR_ClipViewSegment(min((start+1)->first+1,(start+1)->last), (polyvertex_t *)gr_curline->pv1, (polyvertex_t *)gr_curline->pv2);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
HWR_StoreWallRange(lowfrac, highfrac);
|
|
|
|
|
}
|
|
|
|
|
start++;
|
|
|
|
|
|
|
|
|
|
if (last <= start->last)
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (first == start->first+1) // 1 line texture
|
|
|
|
|
{
|
|
|
|
|
if (!cv_grclipwalls.value)
|
|
|
|
|
{
|
|
|
|
|
if (!poorhack) HWR_StoreWallRange(0, 1);
|
|
|
|
|
poorhack = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
HWR_StoreWallRange(0, 1);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// There is a fragment after *next.
|
|
|
|
|
if (!cv_grclipwalls.value)
|
|
|
|
|
{
|
|
|
|
|
if (!poorhack) HWR_StoreWallRange(0,1);
|
|
|
|
|
poorhack = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
lowfrac = HWR_ClipViewSegment(max(start->last - 1,
|
2016-11-07 21:55:56 +00:00
|
|
|
|
start->first), (polyvertex_t *)gr_curline->pv1,
|
|
|
|
|
(polyvertex_t *)gr_curline->pv2);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
HWR_StoreWallRange(lowfrac, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
// HWR_ClipToSolidSegs check if it is hide by wall (solidsegs)
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
static boolean HWR_ClipToSolidSegs(INT32 first, INT32 last)
|
|
|
|
|
{
|
|
|
|
|
cliprange_t * start;
|
|
|
|
|
|
|
|
|
|
// Find the first range that touches the range
|
|
|
|
|
// (adjacent pixels are touching).
|
|
|
|
|
start = gr_solidsegs;
|
|
|
|
|
while (start->last < first-1)
|
|
|
|
|
start++;
|
|
|
|
|
|
|
|
|
|
if (first < start->first)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
// Bottom contained in start?
|
|
|
|
|
if (last <= start->last)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// HWR_ClearClipSegs
|
|
|
|
|
//
|
|
|
|
|
static void HWR_ClearClipSegs(void)
|
|
|
|
|
{
|
|
|
|
|
gr_solidsegs[0].first = -0x7fffffff;
|
|
|
|
|
gr_solidsegs[0].last = -1;
|
|
|
|
|
gr_solidsegs[1].first = vid.width; //viewwidth;
|
|
|
|
|
gr_solidsegs[1].last = 0x7fffffff;
|
|
|
|
|
hw_newend = gr_solidsegs+2;
|
|
|
|
|
}
|
2017-01-10 18:01:03 +00:00
|
|
|
|
#endif // NEWCLIP
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
// -----------------+
|
|
|
|
|
// HWR_AddLine : Clips the given segment and adds any visible pieces to the line list.
|
|
|
|
|
// Notes : gr_cursectorlight is set to the current subsector -> sector -> light value
|
|
|
|
|
// : (it may be mixed with the wall's own flat colour in the future ...)
|
|
|
|
|
// -----------------+
|
|
|
|
|
static void HWR_AddLine(seg_t * line)
|
|
|
|
|
{
|
|
|
|
|
angle_t angle1, angle2;
|
2017-01-10 18:01:03 +00:00
|
|
|
|
#ifndef NEWCLIP
|
|
|
|
|
INT32 x1, x2;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
angle_t span, tspan;
|
2018-02-07 17:46:01 +00:00
|
|
|
|
boolean bothceilingssky = false, bothfloorssky = false;
|
2017-01-10 18:01:03 +00:00
|
|
|
|
#endif
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
// SoM: Backsector needs to be run through R_FakeFlat
|
2018-03-29 22:28:54 +00:00
|
|
|
|
static sector_t tempsec;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2016-12-21 22:31:09 +00:00
|
|
|
|
fixed_t v1x, v1y, v2x, v2y; // the seg's vertexes as fixed_t
|
2014-03-15 16:59:03 +00:00
|
|
|
|
if (line->polyseg && !(line->polyseg->flags & POF_RENDERSIDES))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
gr_curline = line;
|
|
|
|
|
|
2016-12-21 22:31:09 +00:00
|
|
|
|
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);
|
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
// OPTIMIZE: quickly reject orthogonal back sides.
|
2016-12-21 22:31:09 +00:00
|
|
|
|
angle1 = R_PointToAngle(v1x, v1y);
|
|
|
|
|
angle2 = R_PointToAngle(v2x, v2y);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2017-01-10 18:01:03 +00:00
|
|
|
|
#ifdef NEWCLIP
|
|
|
|
|
// 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;
|
|
|
|
|
}
|
2017-01-10 20:07:02 +00:00
|
|
|
|
|
|
|
|
|
checkforemptylines = true;
|
2017-01-10 18:01:03 +00:00
|
|
|
|
#else
|
2014-03-15 16:59:03 +00:00
|
|
|
|
// Clip to view edges.
|
|
|
|
|
span = angle1 - angle2;
|
|
|
|
|
|
|
|
|
|
// backface culling : span is < ANGLE_180 if ang1 > ang2 : the seg is facing
|
|
|
|
|
if (span >= ANGLE_180)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// Global angle needed by segcalc.
|
|
|
|
|
//rw_angle1 = angle1;
|
|
|
|
|
angle1 -= dup_viewangle;
|
|
|
|
|
angle2 -= dup_viewangle;
|
|
|
|
|
|
|
|
|
|
tspan = angle1 + gr_clipangle;
|
|
|
|
|
if (tspan > 2*gr_clipangle)
|
|
|
|
|
{
|
|
|
|
|
tspan -= 2*gr_clipangle;
|
|
|
|
|
|
|
|
|
|
// Totally off the left edge?
|
|
|
|
|
if (tspan >= span)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
angle1 = gr_clipangle;
|
|
|
|
|
}
|
|
|
|
|
tspan = gr_clipangle - angle2;
|
|
|
|
|
if (tspan > 2*gr_clipangle)
|
|
|
|
|
{
|
|
|
|
|
tspan -= 2*gr_clipangle;
|
|
|
|
|
|
|
|
|
|
// Totally off the left edge?
|
|
|
|
|
if (tspan >= span)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
angle2 = (angle_t)-(signed)gr_clipangle;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
{
|
|
|
|
|
float fx1,fx2,fy1,fy2;
|
|
|
|
|
//BP: test with a better projection than viewangletox[R_PointToAngle(angle)]
|
|
|
|
|
// do not enable this at release 4 mul and 2 div
|
2016-11-07 21:55:56 +00:00
|
|
|
|
fx1 = ((polyvertex_t *)(line->pv1))->x-gr_viewx;
|
|
|
|
|
fy1 = ((polyvertex_t *)(line->pv1))->y-gr_viewy;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
fy2 = (fx1 * gr_viewcos + fy1 * gr_viewsin);
|
|
|
|
|
if (fy2 < 0)
|
|
|
|
|
// the point is back
|
|
|
|
|
fx1 = 0;
|
|
|
|
|
else
|
|
|
|
|
fx1 = gr_windowcenterx + (fx1 * gr_viewsin - fy1 * gr_viewcos) * gr_centerx / fy2;
|
|
|
|
|
|
2016-11-07 21:55:56 +00:00
|
|
|
|
fx2 = ((polyvertex_t *)(line->pv2))->x-gr_viewx;
|
|
|
|
|
fy2 = ((polyvertex_t *)(line->pv2))->y-gr_viewy;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
fy1 = (fx2 * gr_viewcos + fy2 * gr_viewsin);
|
|
|
|
|
if (fy1 < 0)
|
|
|
|
|
// the point is back
|
|
|
|
|
fx2 = vid.width;
|
|
|
|
|
else
|
|
|
|
|
fx2 = gr_windowcenterx + (fx2 * gr_viewsin - fy2 * gr_viewcos) * gr_centerx / fy1;
|
|
|
|
|
|
|
|
|
|
x1 = fx1+0.5f;
|
|
|
|
|
x2 = fx2+0.5f;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
// The seg is in the view range,
|
|
|
|
|
// but not necessarily visible.
|
|
|
|
|
angle1 = (angle1+ANGLE_90)>>ANGLETOFINESHIFT;
|
|
|
|
|
angle2 = (angle2+ANGLE_90)>>ANGLETOFINESHIFT;
|
|
|
|
|
|
|
|
|
|
x1 = gr_viewangletox[angle1];
|
|
|
|
|
x2 = gr_viewangletox[angle2];
|
|
|
|
|
#endif
|
|
|
|
|
// Does not cross a pixel?
|
|
|
|
|
// if (x1 == x2)
|
|
|
|
|
/* {
|
|
|
|
|
// BP: HERE IS THE MAIN PROBLEM !
|
|
|
|
|
//CONS_Debug(DBG_RENDER, "tineline\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
*/
|
2017-01-10 18:01:03 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
gr_backsector = line->backsector;
|
|
|
|
|
|
2017-01-10 18:01:03 +00:00
|
|
|
|
#ifdef NEWCLIP
|
|
|
|
|
if (!line->backsector)
|
|
|
|
|
{
|
|
|
|
|
gld_clipper_SafeAddClipRange(angle2, angle1);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2018-02-07 17:46:01 +00:00
|
|
|
|
boolean bothceilingssky = false, bothfloorssky = false;
|
|
|
|
|
|
2017-01-10 18:01:03 +00:00
|
|
|
|
gr_backsector = R_FakeFlat(gr_backsector, &tempsec, NULL, NULL, true);
|
2018-02-07 17:46:01 +00:00
|
|
|
|
|
|
|
|
|
if (gr_backsector->ceilingpic == skyflatnum && gr_frontsector->ceilingpic == skyflatnum)
|
|
|
|
|
bothceilingssky = true;
|
|
|
|
|
if (gr_backsector->floorpic == skyflatnum && gr_frontsector->floorpic == skyflatnum)
|
|
|
|
|
bothfloorssky = true;
|
|
|
|
|
|
|
|
|
|
if (bothceilingssky && bothfloorssky) // everything's sky? let's save us a bit of time then
|
|
|
|
|
{
|
2020-05-02 10:08:31 +00:00
|
|
|
|
if (!line->polyseg &&
|
|
|
|
|
!line->sidedef->midtexture
|
|
|
|
|
&& ((!gr_frontsector->ffloors && !gr_backsector->ffloors)
|
|
|
|
|
|| (gr_frontsector->tag == gr_backsector->tag)))
|
2018-02-07 17:46:01 +00:00
|
|
|
|
return; // line is empty, don't even bother
|
|
|
|
|
// treat like wide open window instead
|
|
|
|
|
HWR_ProcessSeg(); // Doesn't need arguments because they're defined globally :D
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-10 18:01:03 +00:00
|
|
|
|
if (CheckClip(line, gr_frontsector, gr_backsector))
|
|
|
|
|
{
|
|
|
|
|
gld_clipper_SafeAddClipRange(angle2, angle1);
|
2017-01-10 20:07:02 +00:00
|
|
|
|
checkforemptylines = false;
|
2017-01-10 18:01:03 +00:00
|
|
|
|
}
|
2017-01-10 20:07:02 +00:00
|
|
|
|
// 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;
|
2017-01-10 18:01:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HWR_ProcessSeg(); // Doesn't need arguments because they're defined globally :D
|
|
|
|
|
return;
|
|
|
|
|
#else
|
2014-03-15 16:59:03 +00:00
|
|
|
|
// Single sided line?
|
|
|
|
|
if (!gr_backsector)
|
|
|
|
|
goto clipsolid;
|
|
|
|
|
|
|
|
|
|
gr_backsector = R_FakeFlat(gr_backsector, &tempsec, NULL, NULL, true);
|
|
|
|
|
|
2018-02-07 17:46:01 +00:00
|
|
|
|
if (gr_backsector->ceilingpic == skyflatnum && gr_frontsector->ceilingpic == skyflatnum)
|
|
|
|
|
bothceilingssky = true;
|
|
|
|
|
if (gr_backsector->floorpic == skyflatnum && gr_frontsector->floorpic == skyflatnum)
|
|
|
|
|
bothfloorssky = true;
|
|
|
|
|
|
|
|
|
|
if (bothceilingssky && bothfloorssky) // everything's sky? let's save us a bit of time then
|
|
|
|
|
{
|
2020-05-02 10:08:31 +00:00
|
|
|
|
if (!line->polyseg &&
|
|
|
|
|
!line->sidedef->midtexture
|
|
|
|
|
&& ((!gr_frontsector->ffloors && !gr_backsector->ffloors)
|
|
|
|
|
|| (gr_frontsector->tag == gr_backsector->tag)))
|
2018-02-07 17:46:01 +00:00
|
|
|
|
return; // line is empty, don't even bother
|
|
|
|
|
|
|
|
|
|
goto clippass; // treat like wide open window instead
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-04 17:31:21 +00:00
|
|
|
|
if (gr_frontsector->f_slope || gr_frontsector->c_slope || gr_backsector->f_slope || gr_backsector->c_slope)
|
|
|
|
|
{
|
|
|
|
|
fixed_t frontf1,frontf2, frontc1, frontc2; // front floor/ceiling ends
|
|
|
|
|
fixed_t backf1, backf2, backc1, backc2; // back floor ceiling ends
|
|
|
|
|
|
|
|
|
|
#define SLOPEPARAMS(slope, end1, end2, normalheight) \
|
2020-05-18 13:23:56 +00:00
|
|
|
|
end1 = P_GetZAt(slope, v1x, v1y, normalheight); \
|
|
|
|
|
end2 = P_GetZAt(slope, v2x, v2y, normalheight);
|
2016-06-04 17:31:21 +00:00
|
|
|
|
|
2020-03-22 14:17:16 +00:00
|
|
|
|
SLOPEPARAMS(gr_frontsector->f_slope, frontf1, frontf2, gr_frontsector-> floorheight)
|
2016-06-04 17:31:21 +00:00
|
|
|
|
SLOPEPARAMS(gr_frontsector->c_slope, frontc1, frontc2, gr_frontsector->ceilingheight)
|
2020-03-22 14:17:16 +00:00
|
|
|
|
SLOPEPARAMS( gr_backsector->f_slope, backf1, backf2, gr_backsector-> floorheight)
|
|
|
|
|
SLOPEPARAMS( gr_backsector->c_slope, backc1, backc2, gr_backsector->ceilingheight)
|
2016-06-04 17:31:21 +00:00
|
|
|
|
#undef SLOPEPARAMS
|
2018-02-03 19:48:18 +00:00
|
|
|
|
// if both ceilings are skies, consider it always "open"
|
|
|
|
|
// same for floors
|
2018-02-07 17:46:01 +00:00
|
|
|
|
if (!bothceilingssky && !bothfloorssky)
|
2016-06-04 17:31:21 +00:00
|
|
|
|
{
|
2018-02-01 22:04:04 +00:00
|
|
|
|
// Closed door.
|
|
|
|
|
if ((backc1 <= frontf1 && backc2 <= frontf2)
|
|
|
|
|
|| (backf1 >= frontc1 && backf2 >= frontc2))
|
|
|
|
|
{
|
|
|
|
|
goto clipsolid;
|
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2018-02-01 22:04:04 +00:00
|
|
|
|
// Check for automap fix.
|
|
|
|
|
if (backc1 <= backf1 && backc2 <= backf2
|
|
|
|
|
&& ((backc1 >= frontc1 && backc2 >= frontc2) || gr_curline->sidedef->toptexture)
|
2018-02-03 18:30:49 +00:00
|
|
|
|
&& ((backf1 <= frontf1 && backf2 >= frontf2) || gr_curline->sidedef->bottomtexture))
|
2018-02-01 22:04:04 +00:00
|
|
|
|
goto clipsolid;
|
|
|
|
|
}
|
2016-12-21 22:31:09 +00:00
|
|
|
|
|
2016-06-04 17:31:21 +00:00
|
|
|
|
// Window.
|
2018-02-07 17:46:01 +00:00
|
|
|
|
if (!bothceilingssky) // ceilings are always the "same" when sky
|
|
|
|
|
if (backc1 != frontc1 || backc2 != frontc2)
|
|
|
|
|
goto clippass;
|
|
|
|
|
if (!bothfloorssky) // floors are always the "same" when sky
|
|
|
|
|
if (backf1 != frontf1 || backf2 != frontf2)
|
|
|
|
|
goto clippass;
|
2016-06-04 17:31:21 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2018-02-03 19:48:18 +00:00
|
|
|
|
// if both ceilings are skies, consider it always "open"
|
|
|
|
|
// same for floors
|
2018-02-07 17:46:01 +00:00
|
|
|
|
if (!bothceilingssky && !bothfloorssky)
|
2018-02-01 22:04:04 +00:00
|
|
|
|
{
|
|
|
|
|
// Closed door.
|
|
|
|
|
if (gr_backsector->ceilingheight <= gr_frontsector->floorheight ||
|
|
|
|
|
gr_backsector->floorheight >= gr_frontsector->ceilingheight)
|
|
|
|
|
goto clipsolid;
|
|
|
|
|
|
|
|
|
|
// Check for automap fix.
|
|
|
|
|
if (gr_backsector->ceilingheight <= gr_backsector->floorheight
|
|
|
|
|
&& ((gr_backsector->ceilingheight >= gr_frontsector->ceilingheight) || gr_curline->sidedef->toptexture)
|
2018-02-03 18:30:49 +00:00
|
|
|
|
&& ((gr_backsector->floorheight <= gr_backsector->floorheight) || gr_curline->sidedef->bottomtexture))
|
2018-02-01 22:04:04 +00:00
|
|
|
|
goto clipsolid;
|
|
|
|
|
}
|
2016-12-21 22:31:09 +00:00
|
|
|
|
|
2016-06-04 17:31:21 +00:00
|
|
|
|
// Window.
|
2018-02-07 17:46:01 +00:00
|
|
|
|
if (!bothceilingssky) // ceilings are always the "same" when sky
|
|
|
|
|
if (gr_backsector->ceilingheight != gr_frontsector->ceilingheight)
|
|
|
|
|
goto clippass;
|
|
|
|
|
if (!bothfloorssky) // floors are always the "same" when sky
|
|
|
|
|
if (gr_backsector->floorheight != gr_frontsector->floorheight)
|
|
|
|
|
goto clippass;
|
2016-06-04 17:31:21 +00:00
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
// 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.
|
2017-05-31 16:17:08 +00:00
|
|
|
|
if (R_IsEmptyLine(gr_curline, gr_frontsector, gr_backsector))
|
2014-03-15 16:59:03 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
clippass:
|
|
|
|
|
if (x1 == x2)
|
|
|
|
|
{ x2++;x1 -= 2; }
|
|
|
|
|
HWR_ClipPassWallSegment(x1, x2-1);
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
clipsolid:
|
|
|
|
|
if (x1 == x2)
|
|
|
|
|
goto clippass;
|
|
|
|
|
HWR_ClipSolidWallSegment(x1, x2-1);
|
2017-01-10 18:01:03 +00:00
|
|
|
|
#endif
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// HWR_CheckBBox
|
|
|
|
|
// Checks BSP node/subtree bounding box.
|
|
|
|
|
// Returns true
|
|
|
|
|
// if some part of the bbox might be visible.
|
|
|
|
|
//
|
|
|
|
|
// modified to use local variables
|
|
|
|
|
|
|
|
|
|
static boolean HWR_CheckBBox(fixed_t *bspcoord)
|
|
|
|
|
{
|
2017-01-10 18:01:03 +00:00
|
|
|
|
INT32 boxpos;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
fixed_t px1, py1, px2, py2;
|
2017-01-10 18:01:03 +00:00
|
|
|
|
angle_t angle1, angle2;
|
|
|
|
|
#ifndef NEWCLIP
|
|
|
|
|
INT32 sx1, sx2;
|
|
|
|
|
angle_t span, tspan;
|
|
|
|
|
#endif
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
// Find the corners of the box
|
|
|
|
|
// that define the edges from current viewpoint.
|
|
|
|
|
if (dup_viewx <= bspcoord[BOXLEFT])
|
|
|
|
|
boxpos = 0;
|
|
|
|
|
else if (dup_viewx < bspcoord[BOXRIGHT])
|
|
|
|
|
boxpos = 1;
|
|
|
|
|
else
|
|
|
|
|
boxpos = 2;
|
|
|
|
|
|
|
|
|
|
if (dup_viewy >= bspcoord[BOXTOP])
|
|
|
|
|
boxpos |= 0;
|
|
|
|
|
else if (dup_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]];
|
|
|
|
|
|
2017-01-10 18:01:03 +00:00
|
|
|
|
#ifdef NEWCLIP
|
|
|
|
|
angle1 = R_PointToAngle(px1, py1);
|
|
|
|
|
angle2 = R_PointToAngle(px2, py2);
|
|
|
|
|
return gld_clipper_SafeCheckRange(angle2, angle1);
|
|
|
|
|
#else
|
2014-03-15 16:59:03 +00:00
|
|
|
|
// check clip list for an open space
|
2018-05-26 12:13:37 +00:00
|
|
|
|
angle1 = R_PointToAngle2(dup_viewx>>1, dup_viewy>>1, px1>>1, py1>>1) - dup_viewangle;
|
|
|
|
|
angle2 = R_PointToAngle2(dup_viewx>>1, dup_viewy>>1, px2>>1, py2>>1) - dup_viewangle;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
span = angle1 - angle2;
|
|
|
|
|
|
|
|
|
|
// Sitting on a line?
|
|
|
|
|
if (span >= ANGLE_180)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
tspan = angle1 + gr_clipangle;
|
|
|
|
|
|
|
|
|
|
if (tspan > 2*gr_clipangle)
|
|
|
|
|
{
|
|
|
|
|
tspan -= 2*gr_clipangle;
|
|
|
|
|
|
|
|
|
|
// Totally off the left edge?
|
|
|
|
|
if (tspan >= span)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
angle1 = gr_clipangle;
|
|
|
|
|
}
|
|
|
|
|
tspan = gr_clipangle - angle2;
|
|
|
|
|
if (tspan > 2*gr_clipangle)
|
|
|
|
|
{
|
|
|
|
|
tspan -= 2*gr_clipangle;
|
|
|
|
|
|
|
|
|
|
// Totally off the left edge?
|
|
|
|
|
if (tspan >= span)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
angle2 = (angle_t)-(signed)gr_clipangle;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Find the first clippost
|
|
|
|
|
// that touches the source post
|
|
|
|
|
// (adjacent pixels are touching).
|
|
|
|
|
angle1 = (angle1+ANGLE_90)>>ANGLETOFINESHIFT;
|
|
|
|
|
angle2 = (angle2+ANGLE_90)>>ANGLETOFINESHIFT;
|
|
|
|
|
sx1 = gr_viewangletox[angle1];
|
|
|
|
|
sx2 = gr_viewangletox[angle2];
|
|
|
|
|
|
|
|
|
|
// Does not cross a pixel.
|
|
|
|
|
if (sx1 == sx2)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return HWR_ClipToSolidSegs(sx1, sx2 - 1);
|
2017-01-10 18:01:03 +00:00
|
|
|
|
#endif
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// HWR_AddPolyObjectSegs
|
|
|
|
|
//
|
|
|
|
|
// haleyjd 02/19/06
|
|
|
|
|
// Adds all segs in all polyobjects in the given subsector.
|
|
|
|
|
// Modified for hardware rendering.
|
|
|
|
|
//
|
|
|
|
|
static inline 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);
|
|
|
|
|
|
2016-11-07 21:55:56 +00:00
|
|
|
|
gr_fakeline->pv1 = pv1;
|
|
|
|
|
gr_fakeline->pv2 = pv2;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
HWR_AddLine(gr_fakeline);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Free temporary data no longer needed
|
|
|
|
|
Z_Free(pv2);
|
|
|
|
|
Z_Free(pv1);
|
|
|
|
|
Z_Free(gr_fakeline);
|
|
|
|
|
}
|
2014-10-27 20:57:45 +00:00
|
|
|
|
|
2016-07-27 18:56:21 +00:00
|
|
|
|
static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, fixed_t fixedheight,
|
2019-11-09 01:58:41 +00:00
|
|
|
|
FBITFIELD blendmode, UINT8 lightlevel, levelflat_t *levelflat, sector_t *FOFsector,
|
2014-10-27 20:57:45 +00:00
|
|
|
|
UINT8 alpha, extracolormap_t *planecolormap)
|
|
|
|
|
{
|
|
|
|
|
float height; //constant y for all points on the convex flat polygon
|
|
|
|
|
FOutVector *v3d;
|
|
|
|
|
INT32 i;
|
|
|
|
|
float flatxref,flatyref;
|
2019-11-09 02:42:15 +00:00
|
|
|
|
float fflatwidth = 64.0f, fflatheight = 64.0f;
|
|
|
|
|
INT32 flatflag = 63;
|
2019-11-09 01:58:41 +00:00
|
|
|
|
boolean texflat = false;
|
2014-10-27 20:57:45 +00:00
|
|
|
|
size_t len;
|
|
|
|
|
float scrollx = 0.0f, scrolly = 0.0f;
|
|
|
|
|
angle_t angle = 0;
|
|
|
|
|
FSurfaceInfo Surf;
|
2019-12-25 19:22:01 +00:00
|
|
|
|
fixed_t tempxs, tempyt;
|
2014-10-27 20:57:45 +00:00
|
|
|
|
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;
|
|
|
|
|
|
2019-07-09 20:43:38 +00:00
|
|
|
|
if (nrPlaneVerts > (size_t)UINT16_MAX) // FIXME: exceeds plVerts size
|
2014-10-27 20:57:45 +00:00
|
|
|
|
{
|
2015-01-10 22:27:24 +00:00
|
|
|
|
CONS_Debug(DBG_RENDER, "polygon size of %s exceeds max value of %d vertices\n", sizeu1(nrPlaneVerts), UINT16_MAX);
|
2014-10-27 20:57:45 +00:00
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-09 02:42:15 +00:00
|
|
|
|
// set texture for polygon
|
|
|
|
|
if (levelflat != NULL)
|
2014-10-27 20:57:45 +00:00
|
|
|
|
{
|
2019-11-09 02:42:15 +00:00
|
|
|
|
if (levelflat->type == LEVELFLAT_TEXTURE)
|
2019-11-09 01:58:41 +00:00
|
|
|
|
{
|
2019-11-09 02:42:15 +00:00
|
|
|
|
fflatwidth = textures[levelflat->u.texture.num]->width;
|
|
|
|
|
fflatheight = textures[levelflat->u.texture.num]->height;
|
|
|
|
|
texflat = true;
|
2019-11-09 01:58:41 +00:00
|
|
|
|
}
|
2019-11-09 02:42:15 +00:00
|
|
|
|
else if (levelflat->type == LEVELFLAT_FLAT)
|
|
|
|
|
{
|
|
|
|
|
len = W_LumpLength(levelflat->u.flat.lumpnum);
|
2014-10-27 20:57:45 +00:00
|
|
|
|
|
2019-11-09 02:42:15 +00:00
|
|
|
|
switch (len)
|
|
|
|
|
{
|
|
|
|
|
case 4194304: // 2048x2048 lump
|
|
|
|
|
fflatwidth = fflatheight = 2048.0f;
|
|
|
|
|
break;
|
|
|
|
|
case 1048576: // 1024x1024 lump
|
|
|
|
|
fflatwidth = fflatheight = 1024.0f;
|
|
|
|
|
break;
|
|
|
|
|
case 262144:// 512x512 lump
|
|
|
|
|
fflatwidth = fflatheight = 512.0f;
|
|
|
|
|
break;
|
|
|
|
|
case 65536: // 256x256 lump
|
|
|
|
|
fflatwidth = fflatheight = 256.0f;
|
|
|
|
|
break;
|
|
|
|
|
case 16384: // 128x128 lump
|
|
|
|
|
fflatwidth = fflatheight = 128.0f;
|
|
|
|
|
break;
|
|
|
|
|
case 1024: // 32x32 lump
|
|
|
|
|
fflatwidth = fflatheight = 32.0f;
|
|
|
|
|
break;
|
|
|
|
|
default: // 64x64 lump
|
|
|
|
|
fflatwidth = fflatheight = 64.0f;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-05-21 03:28:52 +00:00
|
|
|
|
|
2019-11-09 02:42:15 +00:00
|
|
|
|
flatflag = ((INT32)fflatwidth)-1;
|
|
|
|
|
}
|
2019-05-26 21:16:13 +00:00
|
|
|
|
}
|
2019-11-09 02:42:15 +00:00
|
|
|
|
else // set no texture
|
2020-06-07 18:20:52 +00:00
|
|
|
|
HWR_SetCurrentTexture(NULL);
|
2019-05-21 03:28:52 +00:00
|
|
|
|
|
2014-10-27 20:57:45 +00:00
|
|
|
|
// reference point for flat texture coord for each vertex around the polygon
|
2019-05-26 21:16:13 +00:00
|
|
|
|
flatxref = (float)((polysector->origVerts[0].x & (~flatflag)) / fflatwidth);
|
|
|
|
|
flatyref = (float)((polysector->origVerts[0].y & (~flatflag)) / fflatheight);
|
2014-10-27 20:57:45 +00:00
|
|
|
|
|
|
|
|
|
// transform
|
|
|
|
|
v3d = planeVerts;
|
|
|
|
|
|
|
|
|
|
if (FOFsector != NULL)
|
|
|
|
|
{
|
2016-07-27 18:56:21 +00:00
|
|
|
|
if (!isceiling) // it's a floor
|
2014-10-27 20:57:45 +00:00
|
|
|
|
{
|
2019-05-21 03:28:52 +00:00
|
|
|
|
scrollx = FIXED_TO_FLOAT(FOFsector->floor_xoffs)/fflatwidth;
|
|
|
|
|
scrolly = FIXED_TO_FLOAT(FOFsector->floor_yoffs)/fflatheight;
|
2014-10-27 20:57:45 +00:00
|
|
|
|
angle = FOFsector->floorpic_angle>>ANGLETOFINESHIFT;
|
|
|
|
|
}
|
|
|
|
|
else // it's a ceiling
|
|
|
|
|
{
|
2019-05-21 03:28:52 +00:00
|
|
|
|
scrollx = FIXED_TO_FLOAT(FOFsector->ceiling_xoffs)/fflatwidth;
|
|
|
|
|
scrolly = FIXED_TO_FLOAT(FOFsector->ceiling_yoffs)/fflatheight;
|
2014-10-27 20:57:45 +00:00
|
|
|
|
angle = FOFsector->ceilingpic_angle>>ANGLETOFINESHIFT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (gr_frontsector)
|
|
|
|
|
{
|
2016-07-27 18:56:21 +00:00
|
|
|
|
if (!isceiling) // it's a floor
|
2014-10-27 20:57:45 +00:00
|
|
|
|
{
|
2019-05-21 03:28:52 +00:00
|
|
|
|
scrollx = FIXED_TO_FLOAT(gr_frontsector->floor_xoffs)/fflatwidth;
|
|
|
|
|
scrolly = FIXED_TO_FLOAT(gr_frontsector->floor_yoffs)/fflatheight;
|
2014-10-27 20:57:45 +00:00
|
|
|
|
angle = gr_frontsector->floorpic_angle>>ANGLETOFINESHIFT;
|
|
|
|
|
}
|
|
|
|
|
else // it's a ceiling
|
|
|
|
|
{
|
2019-05-21 03:28:52 +00:00
|
|
|
|
scrollx = FIXED_TO_FLOAT(gr_frontsector->ceiling_xoffs)/fflatwidth;
|
|
|
|
|
scrolly = FIXED_TO_FLOAT(gr_frontsector->ceiling_yoffs)/fflatheight;
|
2014-10-27 20:57:45 +00:00
|
|
|
|
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
|
2019-12-25 19:22:01 +00:00
|
|
|
|
tempxs = FLOAT_TO_FIXED(scrollx);
|
|
|
|
|
tempyt = FLOAT_TO_FIXED(scrolly);
|
|
|
|
|
scrollx = (FIXED_TO_FLOAT(FixedMul(tempxs, FINECOSINE(angle)) - FixedMul(tempyt, FINESINE(angle))));
|
|
|
|
|
scrolly = (FIXED_TO_FLOAT(FixedMul(tempxs, FINESINE(angle)) + FixedMul(tempyt, FINECOSINE(angle))));
|
2014-10-27 20:57:45 +00:00
|
|
|
|
|
|
|
|
|
// 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
|
2019-12-25 19:22:01 +00:00
|
|
|
|
tempxs = FLOAT_TO_FIXED(flatxref);
|
|
|
|
|
tempyt = FLOAT_TO_FIXED(flatyref);
|
|
|
|
|
flatxref = (FIXED_TO_FLOAT(FixedMul(tempxs, FINECOSINE(angle)) - FixedMul(tempyt, FINESINE(angle))));
|
|
|
|
|
flatyref = (FIXED_TO_FLOAT(FixedMul(tempxs, FINESINE(angle)) + FixedMul(tempyt, FINECOSINE(angle))));
|
2014-10-27 20:57:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-11-02 04:15:05 +00:00
|
|
|
|
for (i = 0; i < (INT32)nrPlaneVerts; i++,v3d++)
|
2014-10-27 20:57:45 +00:00
|
|
|
|
{
|
2019-05-26 21:16:13 +00:00
|
|
|
|
// Go from the polysector's original vertex locations
|
|
|
|
|
// Means the flat is offset based on the original vertex locations
|
|
|
|
|
if (texflat)
|
|
|
|
|
{
|
2019-12-25 19:22:01 +00:00
|
|
|
|
v3d->s = (float)(FIXED_TO_FLOAT(polysector->origVerts[i].x) / fflatwidth) + scrollx;
|
|
|
|
|
v3d->t = -(float)(FIXED_TO_FLOAT(polysector->origVerts[i].y) / fflatheight) + scrolly;
|
2019-05-26 21:16:13 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2019-12-25 19:22:01 +00:00
|
|
|
|
v3d->s = (float)((FIXED_TO_FLOAT(polysector->origVerts[i].x) / fflatwidth) - flatxref + scrollx);
|
|
|
|
|
v3d->t = (float)(flatyref - (FIXED_TO_FLOAT(polysector->origVerts[i].y) / fflatheight) + scrolly);
|
2019-05-26 21:16:13 +00:00
|
|
|
|
}
|
2014-10-27 20:57:45 +00:00
|
|
|
|
|
|
|
|
|
// Need to rotate before translate
|
|
|
|
|
if (angle) // Only needs to be done if there's an altered angle
|
|
|
|
|
{
|
2019-12-25 19:22:01 +00:00
|
|
|
|
tempxs = FLOAT_TO_FIXED(v3d->s);
|
|
|
|
|
tempyt = FLOAT_TO_FIXED(v3d->t);
|
2019-05-26 21:16:13 +00:00
|
|
|
|
if (texflat)
|
2019-12-25 19:22:01 +00:00
|
|
|
|
tempyt = -tempyt;
|
|
|
|
|
v3d->s = (FIXED_TO_FLOAT(FixedMul(tempxs, FINECOSINE(angle)) - FixedMul(tempyt, FINESINE(angle))));
|
|
|
|
|
v3d->t = (FIXED_TO_FLOAT(-FixedMul(tempxs, FINESINE(angle)) - FixedMul(tempyt, FINECOSINE(angle))));
|
2014-10-27 20:57:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-11-14 22:19:44 +00:00
|
|
|
|
v3d->x = FIXED_TO_FLOAT(polysector->vertices[i]->x);
|
2014-10-27 20:57:45 +00:00
|
|
|
|
v3d->y = height;
|
2014-11-14 22:19:44 +00:00
|
|
|
|
v3d->z = FIXED_TO_FLOAT(polysector->vertices[i]->y);
|
2014-10-27 20:57:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
HWR_Lighting(&Surf, lightlevel, planecolormap);
|
2014-10-27 20:57:45 +00:00
|
|
|
|
|
|
|
|
|
if (blendmode & PF_Translucent)
|
|
|
|
|
{
|
2019-12-25 19:22:01 +00:00
|
|
|
|
Surf.PolyColor.s.alpha = (UINT8)alpha;
|
2014-10-27 20:57:45 +00:00
|
|
|
|
blendmode |= PF_Modulated|PF_Occlude|PF_Clip;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
blendmode |= PF_Masked|PF_Modulated|PF_Clip;
|
|
|
|
|
|
2020-06-07 18:20:52 +00:00
|
|
|
|
HWR_ProcessPolygon(&Surf, planeVerts, nrPlaneVerts, blendmode, 1, false); // floor shader
|
2014-10-27 20:57:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void HWR_AddPolyObjectPlanes(void)
|
|
|
|
|
{
|
|
|
|
|
size_t i;
|
2014-11-02 03:52:17 +00:00
|
|
|
|
sector_t *polyobjsector;
|
2019-08-22 21:30:36 +00:00
|
|
|
|
INT32 light = 0;
|
2014-10-27 20:57:45 +00:00
|
|
|
|
|
|
|
|
|
// 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))
|
|
|
|
|
{
|
2019-08-22 21:30:36 +00:00
|
|
|
|
light = R_GetPlaneLight(gr_frontsector, polyobjsector->floorheight, true);
|
2014-10-27 20:57:45 +00:00
|
|
|
|
if (po_ptrs[i]->translucency > 0)
|
|
|
|
|
{
|
|
|
|
|
FSurfaceInfo Surf;
|
2019-08-22 21:30:36 +00:00
|
|
|
|
FBITFIELD blendmode;
|
|
|
|
|
memset(&Surf, 0x00, sizeof(Surf));
|
|
|
|
|
blendmode = HWR_TranstableToAlpha(po_ptrs[i]->translucency, &Surf);
|
2019-11-09 01:58:41 +00:00
|
|
|
|
HWR_AddTransparentPolyobjectFloor(&levelflats[polyobjsector->floorpic], po_ptrs[i], false, polyobjsector->floorheight,
|
2019-12-25 19:22:01 +00:00
|
|
|
|
(light == -1 ? gr_frontsector->lightlevel : *gr_frontsector->lightlist[light].lightlevel), Surf.PolyColor.s.alpha, polyobjsector, blendmode, (light == -1 ? gr_frontsector->extra_colormap : *gr_frontsector->lightlist[light].extra_colormap));
|
2014-10-27 20:57:45 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2019-11-09 02:42:15 +00:00
|
|
|
|
HWR_GetLevelFlat(&levelflats[polyobjsector->floorpic]);
|
2016-07-27 18:56:21 +00:00
|
|
|
|
HWR_RenderPolyObjectPlane(po_ptrs[i], false, polyobjsector->floorheight, PF_Occlude,
|
2019-11-09 01:58:41 +00:00
|
|
|
|
(light == -1 ? gr_frontsector->lightlevel : *gr_frontsector->lightlist[light].lightlevel), &levelflats[polyobjsector->floorpic],
|
2019-08-22 21:30:36 +00:00
|
|
|
|
polyobjsector, 255, (light == -1 ? gr_frontsector->extra_colormap : *gr_frontsector->lightlist[light].extra_colormap));
|
2014-10-27 20:57:45 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (polyobjsector->ceilingheight >= gr_frontsector->floorheight
|
|
|
|
|
&& polyobjsector->ceilingheight <= gr_frontsector->ceilingheight
|
|
|
|
|
&& (viewz > polyobjsector->ceilingheight))
|
|
|
|
|
{
|
2019-08-22 21:30:36 +00:00
|
|
|
|
light = R_GetPlaneLight(gr_frontsector, polyobjsector->ceilingheight, true);
|
2014-10-27 20:57:45 +00:00
|
|
|
|
if (po_ptrs[i]->translucency > 0)
|
|
|
|
|
{
|
|
|
|
|
FSurfaceInfo Surf;
|
2016-05-27 05:28:21 +00:00
|
|
|
|
FBITFIELD blendmode;
|
2016-05-27 05:19:16 +00:00
|
|
|
|
memset(&Surf, 0x00, sizeof(Surf));
|
2016-05-27 05:28:21 +00:00
|
|
|
|
blendmode = HWR_TranstableToAlpha(po_ptrs[i]->translucency, &Surf);
|
2019-11-09 01:58:41 +00:00
|
|
|
|
HWR_AddTransparentPolyobjectFloor(&levelflats[polyobjsector->ceilingpic], po_ptrs[i], true, polyobjsector->ceilingheight,
|
2019-12-25 19:22:01 +00:00
|
|
|
|
(light == -1 ? gr_frontsector->lightlevel : *gr_frontsector->lightlist[light].lightlevel), Surf.PolyColor.s.alpha, polyobjsector, blendmode, (light == -1 ? gr_frontsector->extra_colormap : *gr_frontsector->lightlist[light].extra_colormap));
|
2014-10-27 20:57:45 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2019-11-09 02:42:15 +00:00
|
|
|
|
HWR_GetLevelFlat(&levelflats[polyobjsector->ceilingpic]);
|
2016-07-27 18:56:21 +00:00
|
|
|
|
HWR_RenderPolyObjectPlane(po_ptrs[i], true, polyobjsector->ceilingheight, PF_Occlude,
|
2019-12-08 07:15:25 +00:00
|
|
|
|
(light == -1 ? gr_frontsector->lightlevel : *gr_frontsector->lightlist[light].lightlevel), &levelflats[polyobjsector->ceilingpic],
|
2019-08-22 21:30:36 +00:00
|
|
|
|
polyobjsector, 255, (light == -1 ? gr_frontsector->extra_colormap : *gr_frontsector->lightlist[light].extra_colormap));
|
2014-10-27 20:57:45 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
// -----------------+
|
|
|
|
|
// HWR_Subsector : Determine floor/ceiling planes.
|
|
|
|
|
// : Add sprites of things in sector.
|
|
|
|
|
// : Draw one or more line segments.
|
|
|
|
|
// Notes : Sets gr_cursectorlight to the light of the parent sector, to modulate wall textures
|
|
|
|
|
// -----------------+
|
|
|
|
|
static void HWR_Subsector(size_t num)
|
|
|
|
|
{
|
|
|
|
|
INT16 count;
|
|
|
|
|
seg_t *line;
|
|
|
|
|
subsector_t *sub;
|
2018-03-29 22:28:54 +00:00
|
|
|
|
static sector_t tempsec; //SoM: 4/7/2000
|
2014-03-15 16:59:03 +00:00
|
|
|
|
INT32 floorlightlevel;
|
|
|
|
|
INT32 ceilinglightlevel;
|
|
|
|
|
INT32 locFloorHeight, locCeilingHeight;
|
2016-01-28 13:56:23 +00:00
|
|
|
|
INT32 cullFloorHeight, cullCeilingHeight;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
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));
|
|
|
|
|
|
|
|
|
|
/*if (num >= numsubsectors)
|
|
|
|
|
I_Error("HWR_Subsector: ss %i with numss = %i",
|
|
|
|
|
num,
|
|
|
|
|
numsubsectors);*/
|
|
|
|
|
#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;
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------
|
|
|
|
|
// sector lighting, DISABLED because it's done in HWR_StoreWallRange
|
|
|
|
|
// ------------------------------------------------------------------------
|
|
|
|
|
/// \todo store a RGBA instead of just intensity, allow coloured sector lighting
|
|
|
|
|
//light = (FUBYTE)(sub->sector->lightlevel & 0xFF) / 255.0f;
|
|
|
|
|
//gr_cursectorlight.red = light;
|
|
|
|
|
//gr_cursectorlight.green = light;
|
|
|
|
|
//gr_cursectorlight.blue = light;
|
|
|
|
|
//gr_cursectorlight.alpha = light;
|
|
|
|
|
|
|
|
|
|
// ----- for special tricks with HW renderer -----
|
|
|
|
|
if (gr_frontsector->pseudoSector)
|
|
|
|
|
{
|
2016-01-24 08:41:30 +00:00
|
|
|
|
cullFloorHeight = locFloorHeight = gr_frontsector->virtualFloorheight;
|
|
|
|
|
cullCeilingHeight = locCeilingHeight = gr_frontsector->virtualCeilingheight;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
else if (gr_frontsector->virtualFloor)
|
|
|
|
|
{
|
2016-01-28 13:56:23 +00:00
|
|
|
|
///@TODO Is this whole virtualFloor mess even useful? I don't think it even triggers ever.
|
2016-01-24 08:41:30 +00:00
|
|
|
|
cullFloorHeight = locFloorHeight = gr_frontsector->virtualFloorheight;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
if (gr_frontsector->virtualCeiling)
|
2016-01-24 08:41:30 +00:00
|
|
|
|
cullCeilingHeight = locCeilingHeight = gr_frontsector->virtualCeilingheight;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
else
|
2016-01-24 08:41:30 +00:00
|
|
|
|
cullCeilingHeight = locCeilingHeight = gr_frontsector->ceilingheight;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
else if (gr_frontsector->virtualCeiling)
|
|
|
|
|
{
|
2016-01-24 08:41:30 +00:00
|
|
|
|
cullCeilingHeight = locCeilingHeight = gr_frontsector->virtualCeilingheight;
|
|
|
|
|
cullFloorHeight = locFloorHeight = gr_frontsector->floorheight;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-03-22 14:17:16 +00:00
|
|
|
|
cullFloorHeight = P_GetSectorFloorZAt (gr_frontsector, viewx, viewy);
|
|
|
|
|
cullCeilingHeight = P_GetSectorCeilingZAt(gr_frontsector, viewx, viewy);
|
|
|
|
|
locFloorHeight = P_GetSectorFloorZAt (gr_frontsector, gr_frontsector->soundorg.x, gr_frontsector->soundorg.y);
|
|
|
|
|
locCeilingHeight = P_GetSectorCeilingZAt(gr_frontsector, gr_frontsector->soundorg.x, gr_frontsector->soundorg.y);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
// ----- 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;
|
2018-09-12 20:28:55 +00:00
|
|
|
|
floorcolormap = *gr_frontsector->lightlist[light].extra_colormap;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
light = R_GetPlaneLight(gr_frontsector, locCeilingHeight, false);
|
|
|
|
|
if (gr_frontsector->ceilinglightsec == -1)
|
|
|
|
|
ceilinglightlevel = *gr_frontsector->lightlist[light].lightlevel;
|
2018-09-12 20:28:55 +00:00
|
|
|
|
ceilingcolormap = *gr_frontsector->lightlist[light].extra_colormap;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub->sector->extra_colormap = gr_frontsector->extra_colormap;
|
|
|
|
|
|
|
|
|
|
// render floor ?
|
|
|
|
|
#ifdef DOPLANES
|
|
|
|
|
// yeah, easy backface cull! :)
|
2016-01-24 08:41:30 +00:00
|
|
|
|
if (cullFloorHeight < dup_viewz)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
|
|
|
|
if (gr_frontsector->floorpic != skyflatnum)
|
|
|
|
|
{
|
|
|
|
|
if (sub->validcount != validcount)
|
|
|
|
|
{
|
2019-11-09 02:42:15 +00:00
|
|
|
|
HWR_GetLevelFlat(&levelflats[gr_frontsector->floorpic]);
|
2020-03-22 17:13:59 +00:00
|
|
|
|
HWR_RenderPlane(sub, &extrasubsectors[num], false,
|
2016-01-28 13:56:23 +00:00
|
|
|
|
// Hack to make things continue to work around slopes.
|
|
|
|
|
locFloorHeight == cullFloorHeight ? locFloorHeight : gr_frontsector->floorheight,
|
|
|
|
|
// We now return you to your regularly scheduled rendering.
|
2019-12-25 19:22:01 +00:00
|
|
|
|
PF_Occlude, floorlightlevel, &levelflats[gr_frontsector->floorpic], NULL, 255, floorcolormap);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
#ifdef POLYSKY
|
|
|
|
|
HWR_RenderSkyPlane(&extrasubsectors[num], locFloorHeight);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-24 08:41:30 +00:00
|
|
|
|
if (cullCeilingHeight > dup_viewz)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
|
|
|
|
if (gr_frontsector->ceilingpic != skyflatnum)
|
|
|
|
|
{
|
|
|
|
|
if (sub->validcount != validcount)
|
|
|
|
|
{
|
2019-11-09 02:42:15 +00:00
|
|
|
|
HWR_GetLevelFlat(&levelflats[gr_frontsector->ceilingpic]);
|
2020-03-22 17:13:59 +00:00
|
|
|
|
HWR_RenderPlane(sub, &extrasubsectors[num], true,
|
2016-01-28 13:56:23 +00:00
|
|
|
|
// Hack to make things continue to work around slopes.
|
|
|
|
|
locCeilingHeight == cullCeilingHeight ? locCeilingHeight : gr_frontsector->ceilingheight,
|
|
|
|
|
// We now return you to your regularly scheduled rendering.
|
2019-12-25 19:22:01 +00:00
|
|
|
|
PF_Occlude, ceilinglightlevel, &levelflats[gr_frontsector->ceilingpic], NULL, 255, ceilingcolormap);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
#ifdef POLYSKY
|
|
|
|
|
HWR_RenderSkyPlane(&extrasubsectors[num], locCeilingHeight);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifndef POLYSKY
|
|
|
|
|
// Moved here because before, when above the ceiling and the floor does not have the sky flat, it doesn't draw the sky
|
|
|
|
|
if (gr_frontsector->ceilingpic == skyflatnum || gr_frontsector->floorpic == skyflatnum)
|
|
|
|
|
drawsky = true;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef R_FAKEFLOORS
|
|
|
|
|
if (gr_frontsector->ffloors)
|
|
|
|
|
{
|
|
|
|
|
/// \todo fix light, xoffs, yoffs, extracolormap ?
|
|
|
|
|
ffloor_t * rover;
|
|
|
|
|
for (rover = gr_frontsector->ffloors;
|
|
|
|
|
rover; rover = rover->next)
|
|
|
|
|
{
|
2016-01-28 13:56:23 +00:00
|
|
|
|
fixed_t cullHeight, centerHeight;
|
2016-01-25 05:57:53 +00:00
|
|
|
|
|
|
|
|
|
// bottom plane
|
2020-03-22 14:17:16 +00:00
|
|
|
|
cullHeight = P_GetFFloorBottomZAt(rover, viewx, viewy);
|
|
|
|
|
centerHeight = P_GetFFloorBottomZAt(rover, gr_frontsector->soundorg.x, gr_frontsector->soundorg.y);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERPLANES))
|
|
|
|
|
continue;
|
|
|
|
|
if (sub->validcount == validcount)
|
|
|
|
|
continue;
|
|
|
|
|
|
2016-01-25 05:57:53 +00:00
|
|
|
|
if (centerHeight <= locCeilingHeight &&
|
|
|
|
|
centerHeight >= locFloorHeight &&
|
2020-03-25 07:34:52 +00:00
|
|
|
|
((dup_viewz < cullHeight && (rover->flags & FF_BOTHPLANES || !(rover->flags & FF_INVERTPLANES))) ||
|
2016-01-25 05:57:53 +00:00
|
|
|
|
(dup_viewz > cullHeight && (rover->flags & FF_BOTHPLANES || rover->flags & FF_INVERTPLANES))))
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
|
|
|
|
if (rover->flags & FF_FOG)
|
|
|
|
|
{
|
|
|
|
|
UINT8 alpha;
|
|
|
|
|
|
2016-01-25 05:57:53 +00:00
|
|
|
|
light = R_GetPlaneLight(gr_frontsector, centerHeight, dup_viewz < cullHeight ? true : false);
|
2019-12-25 19:22:01 +00:00
|
|
|
|
alpha = HWR_FogBlockAlpha(*gr_frontsector->lightlist[light].lightlevel, rover->master->frontsector->extra_colormap);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
HWR_AddTransparentFloor(0,
|
2014-03-15 16:59:03 +00:00
|
|
|
|
&extrasubsectors[num],
|
2016-07-27 18:56:21 +00:00
|
|
|
|
false,
|
2014-03-15 16:59:03 +00:00
|
|
|
|
*rover->bottomheight,
|
|
|
|
|
*gr_frontsector->lightlist[light].lightlevel,
|
2018-03-15 23:58:37 +00:00
|
|
|
|
alpha, rover->master->frontsector, PF_Fog|PF_NoTexture,
|
2014-03-15 16:59:03 +00:00
|
|
|
|
true, rover->master->frontsector->extra_colormap);
|
|
|
|
|
}
|
2017-09-08 23:41:11 +00:00
|
|
|
|
else if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256) // SoM: Flags are more efficient
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2016-01-25 05:57:53 +00:00
|
|
|
|
light = R_GetPlaneLight(gr_frontsector, centerHeight, dup_viewz < cullHeight ? true : false);
|
2019-12-25 19:22:01 +00:00
|
|
|
|
|
2019-11-09 01:58:41 +00:00
|
|
|
|
HWR_AddTransparentFloor(&levelflats[*rover->bottompic],
|
2014-03-15 16:59:03 +00:00
|
|
|
|
&extrasubsectors[num],
|
2016-07-27 18:56:21 +00:00
|
|
|
|
false,
|
2014-03-15 16:59:03 +00:00
|
|
|
|
*rover->bottomheight,
|
|
|
|
|
*gr_frontsector->lightlist[light].lightlevel,
|
2019-12-25 19:22:01 +00:00
|
|
|
|
rover->alpha-1 > 255 ? 255 : rover->alpha-1, rover->master->frontsector, (rover->flags & FF_RIPPLE ? PF_Ripple : 0)|PF_Translucent,
|
2018-09-12 20:28:55 +00:00
|
|
|
|
false, *gr_frontsector->lightlist[light].extra_colormap);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2019-11-09 02:42:15 +00:00
|
|
|
|
HWR_GetLevelFlat(&levelflats[*rover->bottompic]);
|
2016-01-25 05:57:53 +00:00
|
|
|
|
light = R_GetPlaneLight(gr_frontsector, centerHeight, dup_viewz < cullHeight ? true : false);
|
2020-04-25 05:10:30 +00:00
|
|
|
|
HWR_RenderPlane(sub, &extrasubsectors[num], false, *rover->bottomheight, (rover->flags & FF_RIPPLE ? PF_Ripple : 0)|PF_Occlude, *gr_frontsector->lightlist[light].lightlevel, &levelflats[*rover->bottompic],
|
2019-12-25 19:22:01 +00:00
|
|
|
|
rover->master->frontsector, 255, *gr_frontsector->lightlist[light].extra_colormap);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2016-01-25 05:57:53 +00:00
|
|
|
|
|
|
|
|
|
// top plane
|
2020-03-22 14:17:16 +00:00
|
|
|
|
cullHeight = P_GetFFloorTopZAt(rover, viewx, viewy);
|
|
|
|
|
centerHeight = P_GetFFloorTopZAt(rover, gr_frontsector->soundorg.x, gr_frontsector->soundorg.y);
|
2016-01-25 05:57:53 +00:00
|
|
|
|
|
|
|
|
|
if (centerHeight >= locFloorHeight &&
|
|
|
|
|
centerHeight <= locCeilingHeight &&
|
2020-03-25 07:34:52 +00:00
|
|
|
|
((dup_viewz > cullHeight && (rover->flags & FF_BOTHPLANES || !(rover->flags & FF_INVERTPLANES))) ||
|
2016-01-25 05:57:53 +00:00
|
|
|
|
(dup_viewz < cullHeight && (rover->flags & FF_BOTHPLANES || rover->flags & FF_INVERTPLANES))))
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
|
|
|
|
if (rover->flags & FF_FOG)
|
|
|
|
|
{
|
|
|
|
|
UINT8 alpha;
|
|
|
|
|
|
2016-01-25 05:57:53 +00:00
|
|
|
|
light = R_GetPlaneLight(gr_frontsector, centerHeight, dup_viewz < cullHeight ? true : false);
|
2019-12-25 19:22:01 +00:00
|
|
|
|
alpha = HWR_FogBlockAlpha(*gr_frontsector->lightlist[light].lightlevel, rover->master->frontsector->extra_colormap);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
HWR_AddTransparentFloor(0,
|
2014-03-15 16:59:03 +00:00
|
|
|
|
&extrasubsectors[num],
|
2016-07-27 18:56:21 +00:00
|
|
|
|
true,
|
2014-03-15 16:59:03 +00:00
|
|
|
|
*rover->topheight,
|
|
|
|
|
*gr_frontsector->lightlist[light].lightlevel,
|
2018-03-15 23:58:37 +00:00
|
|
|
|
alpha, rover->master->frontsector, PF_Fog|PF_NoTexture,
|
2014-03-15 16:59:03 +00:00
|
|
|
|
true, rover->master->frontsector->extra_colormap);
|
|
|
|
|
}
|
2017-09-08 23:41:11 +00:00
|
|
|
|
else if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2016-01-25 05:57:53 +00:00
|
|
|
|
light = R_GetPlaneLight(gr_frontsector, centerHeight, dup_viewz < cullHeight ? true : false);
|
2019-12-25 19:22:01 +00:00
|
|
|
|
|
2019-11-09 01:58:41 +00:00
|
|
|
|
HWR_AddTransparentFloor(&levelflats[*rover->toppic],
|
2014-03-15 16:59:03 +00:00
|
|
|
|
&extrasubsectors[num],
|
2016-07-27 18:56:21 +00:00
|
|
|
|
true,
|
2014-03-15 16:59:03 +00:00
|
|
|
|
*rover->topheight,
|
|
|
|
|
*gr_frontsector->lightlist[light].lightlevel,
|
2019-12-25 19:22:01 +00:00
|
|
|
|
rover->alpha-1 > 255 ? 255 : rover->alpha-1, rover->master->frontsector, (rover->flags & FF_RIPPLE ? PF_Ripple : 0)|PF_Translucent,
|
2018-09-12 20:28:55 +00:00
|
|
|
|
false, *gr_frontsector->lightlist[light].extra_colormap);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2019-11-09 02:42:15 +00:00
|
|
|
|
HWR_GetLevelFlat(&levelflats[*rover->toppic]);
|
2016-01-25 05:57:53 +00:00
|
|
|
|
light = R_GetPlaneLight(gr_frontsector, centerHeight, dup_viewz < cullHeight ? true : false);
|
2020-04-25 05:10:30 +00:00
|
|
|
|
HWR_RenderPlane(sub, &extrasubsectors[num], true, *rover->topheight, (rover->flags & FF_RIPPLE ? PF_Ripple : 0)|PF_Occlude, *gr_frontsector->lightlist[light].lightlevel, &levelflats[*rover->toppic],
|
2019-12-25 19:22:01 +00:00
|
|
|
|
rover->master->frontsector, 255, *gr_frontsector->lightlist[light].extra_colormap);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
#endif //doplanes
|
|
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-18 22:25:28 +00:00
|
|
|
|
// for render stats
|
|
|
|
|
rs_numpolyobjects += numpolys;
|
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
// Sort polyobjects
|
|
|
|
|
R_SortPolyObjects(sub);
|
|
|
|
|
|
|
|
|
|
// Draw polyobject lines.
|
|
|
|
|
HWR_AddPolyObjectSegs();
|
|
|
|
|
|
2014-10-27 20:57:45 +00:00
|
|
|
|
if (sub->validcount != validcount) // This validcount situation seems to let us know that the floors have already been drawn.
|
|
|
|
|
{
|
|
|
|
|
// Draw polyobject planes
|
|
|
|
|
HWR_AddPolyObjectPlanes();
|
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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--)
|
|
|
|
|
{
|
2020-01-06 13:40:59 +00:00
|
|
|
|
|
2020-05-02 10:08:31 +00:00
|
|
|
|
if (!line->glseg && !line->polyseg) // ignore segs that belong to polyobjects
|
2014-03-15 16:59:03 +00:00
|
|
|
|
HWR_AddLine(line);
|
2020-01-06 14:58:05 +00:00
|
|
|
|
line++;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub->validcount = validcount;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Renders all subsectors below a given node,
|
|
|
|
|
// traversing subtree recursively.
|
|
|
|
|
// Just call with BSP root.
|
|
|
|
|
|
|
|
|
|
#ifdef coolhack
|
|
|
|
|
//t;b;l;r
|
|
|
|
|
static fixed_t hackbbox[4];
|
|
|
|
|
//BOXTOP,
|
|
|
|
|
//BOXBOTTOM,
|
|
|
|
|
//BOXLEFT,
|
|
|
|
|
//BOXRIGHT
|
|
|
|
|
static boolean HWR_CheckHackBBox(fixed_t *bb)
|
|
|
|
|
{
|
|
|
|
|
if (bb[BOXTOP] < hackbbox[BOXBOTTOM]) //y up
|
|
|
|
|
return false;
|
|
|
|
|
if (bb[BOXBOTTOM] > hackbbox[BOXTOP])
|
|
|
|
|
return false;
|
|
|
|
|
if (bb[BOXLEFT] > hackbbox[BOXRIGHT])
|
|
|
|
|
return false;
|
|
|
|
|
if (bb[BOXRIGHT] < hackbbox[BOXLEFT])
|
|
|
|
|
return false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// BP: big hack for a test in lighning ref : 1249753487AB
|
|
|
|
|
fixed_t *hwbbox;
|
|
|
|
|
|
|
|
|
|
static void HWR_RenderBSPNode(INT32 bspnum)
|
|
|
|
|
{
|
|
|
|
|
/*//GZDoom code
|
|
|
|
|
if(bspnum == -1)
|
|
|
|
|
{
|
|
|
|
|
HWR_Subsector(subsectors);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
while(!((size_t)bspnum&(~NF_SUBSECTOR))) // Keep going until found a subsector
|
|
|
|
|
{
|
|
|
|
|
node_t *bsp = &nodes[bspnum];
|
|
|
|
|
|
|
|
|
|
// Decide which side the view point is on
|
|
|
|
|
INT32 side = R_PointOnSide(dup_viewx, dup_viewy, bsp);
|
|
|
|
|
|
|
|
|
|
// Recursively divide front space (toward the viewer)
|
|
|
|
|
HWR_RenderBSPNode(bsp->children[side]);
|
|
|
|
|
|
|
|
|
|
// Possibly divide back space (away from viewer)
|
|
|
|
|
side ^= 1;
|
|
|
|
|
|
|
|
|
|
if (!HWR_CheckBBox(bsp->bbox[side]))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
bspnum = bsp->children[side];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HWR_Subsector(bspnum-1);
|
|
|
|
|
*/
|
|
|
|
|
node_t *bsp = &nodes[bspnum];
|
|
|
|
|
|
|
|
|
|
// Decide which side the view point is on
|
|
|
|
|
INT32 side;
|
|
|
|
|
|
2020-04-18 22:25:28 +00:00
|
|
|
|
rs_numbspcalls++;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
// Found a subsector?
|
|
|
|
|
if (bspnum & NF_SUBSECTOR)
|
|
|
|
|
{
|
|
|
|
|
if (bspnum == -1)
|
|
|
|
|
{
|
|
|
|
|
//*(gr_drawsubsector_p++) = 0;
|
|
|
|
|
HWR_Subsector(0);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
//*(gr_drawsubsector_p++) = bspnum&(~NF_SUBSECTOR);
|
|
|
|
|
HWR_Subsector(bspnum&(~NF_SUBSECTOR));
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Decide which side the view point is on.
|
|
|
|
|
side = R_PointOnSide(dup_viewx, dup_viewy, bsp);
|
|
|
|
|
|
|
|
|
|
// BP: big hack for a test in lighning ref : 1249753487AB
|
|
|
|
|
hwbbox = bsp->bbox[side];
|
|
|
|
|
|
|
|
|
|
// Recursively divide front space.
|
|
|
|
|
HWR_RenderBSPNode(bsp->children[side]);
|
|
|
|
|
|
|
|
|
|
// Possibly divide back space.
|
|
|
|
|
if (HWR_CheckBBox(bsp->bbox[side^1]))
|
|
|
|
|
{
|
|
|
|
|
// BP: big hack for a test in lighning ref : 1249753487AB
|
|
|
|
|
hwbbox = bsp->bbox[side^1];
|
|
|
|
|
HWR_RenderBSPNode(bsp->children[side^1]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
//
|
|
|
|
|
// Clear 'stack' of subsectors to draw
|
|
|
|
|
//
|
|
|
|
|
static void HWR_ClearDrawSubsectors(void)
|
|
|
|
|
{
|
|
|
|
|
gr_drawsubsector_p = gr_drawsubsectors;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Draw subsectors pushed on the drawsubsectors 'stack', back to front
|
|
|
|
|
//
|
|
|
|
|
static void HWR_RenderSubsectors(void)
|
|
|
|
|
{
|
|
|
|
|
while (gr_drawsubsector_p > gr_drawsubsectors)
|
|
|
|
|
{
|
|
|
|
|
HWR_RenderBSPNode(
|
|
|
|
|
lastsubsec->nextsubsec = bspnum & (~NF_SUBSECTOR);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// ==========================================================================
|
|
|
|
|
// FROM R_MAIN.C
|
|
|
|
|
// ==========================================================================
|
|
|
|
|
|
|
|
|
|
//BP : exactely the same as R_InitTextureMapping
|
|
|
|
|
void HWR_InitTextureMapping(void)
|
|
|
|
|
{
|
|
|
|
|
angle_t i;
|
|
|
|
|
INT32 x;
|
|
|
|
|
INT32 t;
|
|
|
|
|
fixed_t focallength;
|
|
|
|
|
fixed_t grcenterx;
|
|
|
|
|
fixed_t grcenterxfrac;
|
|
|
|
|
INT32 grviewwidth;
|
|
|
|
|
|
|
|
|
|
#define clipanglefov (FIELDOFVIEW>>ANGLETOFINESHIFT)
|
|
|
|
|
|
|
|
|
|
grviewwidth = vid.width;
|
|
|
|
|
grcenterx = grviewwidth/2;
|
|
|
|
|
grcenterxfrac = grcenterx<<FRACBITS;
|
|
|
|
|
|
|
|
|
|
// Use tangent table to generate viewangletox:
|
|
|
|
|
// viewangletox will give the next greatest x
|
|
|
|
|
// after the view angle.
|
|
|
|
|
//
|
|
|
|
|
// Calc focallength
|
|
|
|
|
// so FIELDOFVIEW angles covers SCREENWIDTH.
|
|
|
|
|
focallength = FixedDiv(grcenterxfrac,
|
|
|
|
|
FINETANGENT(FINEANGLES/4+clipanglefov/2));
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < FINEANGLES/2; i++)
|
|
|
|
|
{
|
|
|
|
|
if (FINETANGENT(i) > FRACUNIT*2)
|
|
|
|
|
t = -1;
|
|
|
|
|
else if (FINETANGENT(i) < -FRACUNIT*2)
|
|
|
|
|
t = grviewwidth+1;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
t = FixedMul(FINETANGENT(i), focallength);
|
|
|
|
|
t = (grcenterxfrac - t+FRACUNIT-1)>>FRACBITS;
|
|
|
|
|
|
|
|
|
|
if (t < -1)
|
|
|
|
|
t = -1;
|
|
|
|
|
else if (t > grviewwidth+1)
|
|
|
|
|
t = grviewwidth+1;
|
|
|
|
|
}
|
|
|
|
|
gr_viewangletox[i] = t;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Scan viewangletox[] to generate xtoviewangle[]:
|
|
|
|
|
// xtoviewangle will give the smallest view angle
|
|
|
|
|
// that maps to x.
|
|
|
|
|
for (x = 0; x <= grviewwidth; x++)
|
|
|
|
|
{
|
|
|
|
|
i = 0;
|
|
|
|
|
while (gr_viewangletox[i]>x)
|
|
|
|
|
i++;
|
|
|
|
|
gr_xtoviewangle[x] = (i<<ANGLETOFINESHIFT) - ANGLE_90;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Take out the fencepost cases from viewangletox.
|
|
|
|
|
for (i = 0; i < FINEANGLES/2; i++)
|
|
|
|
|
{
|
|
|
|
|
if (gr_viewangletox[i] == -1)
|
|
|
|
|
gr_viewangletox[i] = 0;
|
|
|
|
|
else if (gr_viewangletox[i] == grviewwidth+1)
|
|
|
|
|
gr_viewangletox[i] = grviewwidth;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gr_clipangle = gr_xtoviewangle[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ==========================================================================
|
|
|
|
|
// 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++);
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-12 00:55:07 +00:00
|
|
|
|
//
|
|
|
|
|
// 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;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-02 03:58:11 +00:00
|
|
|
|
static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale)
|
2015-01-02 15:14:22 +00:00
|
|
|
|
{
|
2020-01-16 17:37:32 +00:00
|
|
|
|
GLPatch_t *gpatch;
|
|
|
|
|
FOutVector shadowVerts[4];
|
2015-01-02 15:14:22 +00:00
|
|
|
|
FSurfaceInfo sSurf;
|
2020-01-16 17:37:32 +00:00
|
|
|
|
float fscale; float fx; float fy; float offset;
|
|
|
|
|
extracolormap_t *colormap = NULL;
|
|
|
|
|
UINT8 i;
|
2020-05-30 17:21:26 +00:00
|
|
|
|
SINT8 flip = P_MobjFlip(thing);
|
2015-01-02 15:14:22 +00:00
|
|
|
|
|
2020-01-16 17:37:32 +00:00
|
|
|
|
INT32 light;
|
|
|
|
|
fixed_t scalemul;
|
|
|
|
|
UINT16 alpha;
|
|
|
|
|
fixed_t floordiff;
|
2020-05-30 17:21:26 +00:00
|
|
|
|
fixed_t groundz;
|
2020-01-16 17:37:32 +00:00
|
|
|
|
fixed_t slopez;
|
2020-05-30 17:21:26 +00:00
|
|
|
|
pslope_t *groundslope;
|
2015-01-02 15:14:22 +00:00
|
|
|
|
|
2020-05-30 17:21:26 +00:00
|
|
|
|
groundz = R_GetShadowZ(thing, &groundslope);
|
2015-01-02 15:14:22 +00:00
|
|
|
|
|
2020-05-30 17:21:26 +00:00
|
|
|
|
//if (abs(groundz - gr_viewz) / tz > 4) return; // Prevent stretchy shadows and possible crashes
|
2015-01-02 15:14:22 +00:00
|
|
|
|
|
2020-05-30 17:21:26 +00:00
|
|
|
|
floordiff = abs((flip < 0 ? thing->height : 0) + thing->z - groundz);
|
2015-01-02 15:14:22 +00:00
|
|
|
|
|
2020-01-16 17:37:32 +00:00
|
|
|
|
alpha = floordiff / (4*FRACUNIT) + 75;
|
|
|
|
|
if (alpha >= 255) return;
|
|
|
|
|
alpha = 255 - alpha;
|
2018-03-21 19:45:37 +00:00
|
|
|
|
|
2020-01-16 17:37:32 +00:00
|
|
|
|
gpatch = (GLPatch_t *)W_CachePatchName("DSHADOW", PU_CACHE);
|
|
|
|
|
if (!(gpatch && gpatch->mipmap->grInfo.format)) return;
|
|
|
|
|
HWR_GetPatch(gpatch);
|
|
|
|
|
|
|
|
|
|
scalemul = FixedMul(FRACUNIT - floordiff/640, scale);
|
2020-05-02 16:13:16 +00:00
|
|
|
|
scalemul = FixedMul(scalemul, (thing->radius*2) / SHORT(gpatch->height));
|
2020-01-16 17:37:32 +00:00
|
|
|
|
|
|
|
|
|
fscale = FIXED_TO_FLOAT(scalemul);
|
|
|
|
|
fx = FIXED_TO_FLOAT(thing->x);
|
|
|
|
|
fy = FIXED_TO_FLOAT(thing->y);
|
2015-01-02 15:14:22 +00:00
|
|
|
|
|
|
|
|
|
// 3--2
|
|
|
|
|
// | /|
|
|
|
|
|
// |/ |
|
|
|
|
|
// 0--1
|
|
|
|
|
|
2020-01-16 17:37:32 +00:00
|
|
|
|
if (thing && fabsf(fscale - 1.0f) > 1.0E-36f)
|
2020-05-02 16:13:16 +00:00
|
|
|
|
offset = (SHORT(gpatch->height)/2) * fscale;
|
2020-01-16 17:37:32 +00:00
|
|
|
|
else
|
2020-05-02 16:13:16 +00:00
|
|
|
|
offset = (float)(SHORT(gpatch->height)/2);
|
2015-01-02 15:14:22 +00:00
|
|
|
|
|
2020-02-02 03:58:11 +00:00
|
|
|
|
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);
|
|
|
|
|
}
|
2020-01-16 17:37:32 +00:00
|
|
|
|
|
2020-05-30 17:21:26 +00:00
|
|
|
|
if (groundslope)
|
2015-01-02 15:14:22 +00:00
|
|
|
|
{
|
2020-01-16 17:37:32 +00:00
|
|
|
|
for (i = 0; i < 4; i++)
|
|
|
|
|
{
|
2020-05-30 17:21:26 +00:00
|
|
|
|
slopez = P_GetSlopeZAt(groundslope, FLOAT_TO_FIXED(shadowVerts[i].x), FLOAT_TO_FIXED(shadowVerts[i].z));
|
|
|
|
|
shadowVerts[i].y = FIXED_TO_FLOAT(slopez) + flip * 0.05f;
|
2020-01-16 17:37:32 +00:00
|
|
|
|
}
|
2015-01-02 15:14:22 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-01-16 17:37:32 +00:00
|
|
|
|
for (i = 0; i < 4; i++)
|
2020-05-30 17:21:26 +00:00
|
|
|
|
shadowVerts[i].y = FIXED_TO_FLOAT(groundz) + flip * 0.05f;
|
2015-01-02 15:14:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-02-02 03:58:11 +00:00
|
|
|
|
shadowVerts[0].s = shadowVerts[3].s = 0;
|
|
|
|
|
shadowVerts[2].s = shadowVerts[1].s = gpatch->max_s;
|
2015-01-02 15:14:22 +00:00
|
|
|
|
|
2020-02-02 03:58:11 +00:00
|
|
|
|
shadowVerts[3].t = shadowVerts[2].t = 0;
|
|
|
|
|
shadowVerts[0].t = shadowVerts[1].t = gpatch->max_t;
|
2015-01-02 15:14:22 +00:00
|
|
|
|
|
2020-01-16 17:37:32 +00:00
|
|
|
|
if (thing->subsector->sector->numlights)
|
2015-01-02 15:14:22 +00:00
|
|
|
|
{
|
2020-05-30 17:21:26 +00:00
|
|
|
|
light = R_GetPlaneLight(thing->subsector->sector, groundz, false); // Always use the light at the top instead of whatever I was doing before
|
2015-01-02 15:14:22 +00:00
|
|
|
|
|
2020-01-16 17:37:32 +00:00
|
|
|
|
if (*thing->subsector->sector->lightlist[light].extra_colormap)
|
|
|
|
|
colormap = *thing->subsector->sector->lightlist[light].extra_colormap;
|
2015-01-02 15:14:22 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-01-16 17:37:32 +00:00
|
|
|
|
if (thing->subsector->sector->extra_colormap)
|
|
|
|
|
colormap = thing->subsector->sector->extra_colormap;
|
2015-01-02 15:14:22 +00:00
|
|
|
|
}
|
2020-01-16 17:37:32 +00:00
|
|
|
|
|
2020-02-02 03:58:11 +00:00
|
|
|
|
HWR_Lighting(&sSurf, 0, colormap);
|
2020-01-16 19:55:55 +00:00
|
|
|
|
sSurf.PolyColor.s.alpha = alpha;
|
2020-01-16 17:37:32 +00:00
|
|
|
|
|
2020-06-07 18:20:52 +00:00
|
|
|
|
HWR_ProcessPolygon(&sSurf, shadowVerts, 4, PF_Translucent|PF_Modulated|PF_Clip, 3, false); // sprite shader
|
2015-01-02 15:14:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-04-30 22:08:01 +00:00
|
|
|
|
// This is expecting a pointer to an array containing 4 wallVerts for a sprite
|
2020-05-10 19:09:08 +00:00
|
|
|
|
static void HWR_RotateSpritePolyToAim(gr_vissprite_t *spr, FOutVector *wallVerts, const boolean precip)
|
2019-04-30 22:08:01 +00:00
|
|
|
|
{
|
2019-05-06 19:24:26 +00:00
|
|
|
|
if (cv_grspritebillboarding.value
|
|
|
|
|
&& spr && spr->mobj && !(spr->mobj->frame & FF_PAPERSPRITE)
|
|
|
|
|
&& wallVerts)
|
2019-04-30 22:08:01 +00:00
|
|
|
|
{
|
|
|
|
|
float basey = FIXED_TO_FLOAT(spr->mobj->z);
|
|
|
|
|
float lowy = wallVerts[0].y;
|
2020-05-10 19:09:08 +00:00
|
|
|
|
if (!precip && P_MobjFlip(spr->mobj) == -1) // precip doesn't have eflags so they can't flip
|
2019-04-30 22:08:01 +00:00
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-22 00:52:14 +00:00
|
|
|
|
static void HWR_SplitSprite(gr_vissprite_t *spr)
|
|
|
|
|
{
|
|
|
|
|
float this_scale = 1.0f;
|
|
|
|
|
FOutVector wallVerts[4];
|
2019-04-30 22:08:01 +00:00
|
|
|
|
FOutVector baseWallVerts[4]; // This is what the verts should end up as
|
2018-03-22 00:52:14 +00:00
|
|
|
|
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;
|
2019-12-25 19:22:01 +00:00
|
|
|
|
float ttop, tbot, tmult;
|
2018-03-22 00:52:14 +00:00
|
|
|
|
float bheight;
|
2019-04-30 22:08:01 +00:00
|
|
|
|
float realheight, heightmult;
|
2018-03-22 00:52:14 +00:00
|
|
|
|
const sector_t *sector = spr->mobj->subsector->sector;
|
|
|
|
|
const lightlist_t *list = sector->lightlist;
|
|
|
|
|
float endrealtop, endrealbot, endtop, endbot;
|
|
|
|
|
float endbheight;
|
2019-04-30 22:08:01 +00:00
|
|
|
|
float endrealheight;
|
2018-03-22 00:52:14 +00:00
|
|
|
|
fixed_t temp;
|
|
|
|
|
fixed_t v1x, v1y, v2x, v2y;
|
|
|
|
|
|
|
|
|
|
this_scale = FIXED_TO_FLOAT(spr->mobj->scale);
|
|
|
|
|
|
|
|
|
|
if (hires)
|
|
|
|
|
this_scale = this_scale * FIXED_TO_FLOAT(((skin_t *)spr->mobj->skin)->highresscale);
|
|
|
|
|
|
2019-08-18 17:16:48 +00:00
|
|
|
|
gpatch = spr->gpatch; //W_CachePatchNum(spr->patchlumpnum, PU_CACHE);
|
2018-03-22 00:52:14 +00:00
|
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
|
2019-04-30 22:08:01 +00:00
|
|
|
|
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;
|
2018-03-22 00:52:14 +00:00
|
|
|
|
|
2019-04-30 22:08:01 +00:00
|
|
|
|
baseWallVerts[2].y = baseWallVerts[3].y = spr->ty;
|
2018-12-15 00:33:40 +00:00
|
|
|
|
if (spr->mobj && fabsf(this_scale - 1.0f) > 1.0E-36f)
|
2019-04-30 22:08:01 +00:00
|
|
|
|
baseWallVerts[0].y = baseWallVerts[1].y = spr->ty - gpatch->height * this_scale;
|
2018-03-22 00:52:14 +00:00
|
|
|
|
else
|
2019-04-30 22:08:01 +00:00
|
|
|
|
baseWallVerts[0].y = baseWallVerts[1].y = spr->ty - gpatch->height;
|
2018-03-22 00:52:14 +00:00
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
2019-12-25 19:22:01 +00:00
|
|
|
|
baseWallVerts[0].s = baseWallVerts[3].s = gpatch->max_s;
|
|
|
|
|
baseWallVerts[2].s = baseWallVerts[1].s = 0;
|
2019-04-30 22:08:01 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2019-12-25 19:22:01 +00:00
|
|
|
|
baseWallVerts[0].s = baseWallVerts[3].s = 0;
|
|
|
|
|
baseWallVerts[2].s = baseWallVerts[1].s = gpatch->max_s;
|
2018-03-22 00:52:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// flip the texture coords (look familiar?)
|
|
|
|
|
if (spr->vflip)
|
|
|
|
|
{
|
2019-12-25 19:22:01 +00:00
|
|
|
|
baseWallVerts[3].t = baseWallVerts[2].t = gpatch->max_t;
|
|
|
|
|
baseWallVerts[0].t = baseWallVerts[1].t = 0;
|
2019-04-30 22:08:01 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2019-12-25 19:22:01 +00:00
|
|
|
|
baseWallVerts[3].t = baseWallVerts[2].t = 0;
|
|
|
|
|
baseWallVerts[0].t = baseWallVerts[1].t = gpatch->max_t;
|
2018-03-22 00:52:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-12-18 21:37:01 +00:00
|
|
|
|
// if it has a dispoffset, push it a little towards the camera
|
|
|
|
|
if (spr->dispoffset) {
|
2018-12-18 21:59:59 +00:00
|
|
|
|
float co = -gr_viewcos*(0.05f*spr->dispoffset);
|
|
|
|
|
float si = -gr_viewsin*(0.05f*spr->dispoffset);
|
2019-04-30 22:08:01 +00:00
|
|
|
|
baseWallVerts[0].z = baseWallVerts[3].z = baseWallVerts[0].z+si;
|
|
|
|
|
baseWallVerts[1].z = baseWallVerts[2].z = baseWallVerts[1].z+si;
|
|
|
|
|
baseWallVerts[0].x = baseWallVerts[3].x = baseWallVerts[0].x+co;
|
|
|
|
|
baseWallVerts[1].x = baseWallVerts[2].x = baseWallVerts[1].x+co;
|
2018-12-18 21:37:01 +00:00
|
|
|
|
}
|
2018-12-18 21:59:59 +00:00
|
|
|
|
|
2019-04-30 22:08:01 +00:00
|
|
|
|
// Let dispoffset work first since this adjust each vertex
|
2020-05-10 19:09:08 +00:00
|
|
|
|
HWR_RotateSpritePolyToAim(spr, baseWallVerts, false);
|
2019-04-30 22:08:01 +00:00
|
|
|
|
|
|
|
|
|
realtop = top = baseWallVerts[3].y;
|
|
|
|
|
realbot = bot = baseWallVerts[0].y;
|
2019-12-25 19:22:01 +00:00
|
|
|
|
ttop = baseWallVerts[3].t;
|
|
|
|
|
tbot = baseWallVerts[0].t;
|
|
|
|
|
tmult = (tbot - ttop) / (top - bot);
|
2018-03-22 00:52:14 +00:00
|
|
|
|
|
2019-04-30 22:08:01 +00:00
|
|
|
|
endrealtop = endtop = baseWallVerts[2].y;
|
|
|
|
|
endrealbot = endbot = baseWallVerts[1].y;
|
2018-03-22 00:52:14 +00:00
|
|
|
|
|
2019-04-30 22:08:01 +00:00
|
|
|
|
// 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));
|
|
|
|
|
|
2018-03-22 00:52:14 +00:00
|
|
|
|
if (!cv_translucency.value) // translucency disabled
|
|
|
|
|
{
|
2019-12-25 19:22:01 +00:00
|
|
|
|
Surf.PolyColor.s.alpha = 0xFF;
|
2018-03-22 00:52:14 +00:00
|
|
|
|
blend = PF_Translucent|PF_Occlude;
|
|
|
|
|
}
|
|
|
|
|
else if (spr->mobj->flags2 & MF2_SHADOW)
|
|
|
|
|
{
|
2019-12-25 19:22:01 +00:00
|
|
|
|
Surf.PolyColor.s.alpha = 0x40;
|
2018-03-22 00:52:14 +00:00
|
|
|
|
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
|
2019-12-25 19:22:01 +00:00
|
|
|
|
Surf.PolyColor.s.alpha = 0xFF;
|
2018-03-22 00:52:14 +00:00
|
|
|
|
blend = PF_Translucent|PF_Occlude;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
alpha = Surf.PolyColor.s.alpha;
|
2018-03-22 00:52:14 +00:00
|
|
|
|
|
|
|
|
|
// Start with the lightlevel and colormap from the top of the sprite
|
|
|
|
|
lightlevel = *list[sector->numlights - 1].lightlevel;
|
2018-09-12 20:28:55 +00:00
|
|
|
|
colormap = *list[sector->numlights - 1].extra_colormap;
|
2018-03-22 00:52:14 +00:00
|
|
|
|
i = 0;
|
|
|
|
|
temp = FLOAT_TO_FIXED(realtop);
|
|
|
|
|
|
2018-05-16 20:04:57 +00:00
|
|
|
|
if (spr->mobj->frame & FF_FULLBRIGHT)
|
|
|
|
|
lightlevel = 255;
|
|
|
|
|
|
2018-03-22 00:52:14 +00:00
|
|
|
|
for (i = 1; i < sector->numlights; i++)
|
|
|
|
|
{
|
2020-03-22 14:17:16 +00:00
|
|
|
|
fixed_t h = P_GetLightZAt(§or->lightlist[i], spr->mobj->x, spr->mobj->y);
|
2018-03-22 00:52:14 +00:00
|
|
|
|
if (h <= temp)
|
|
|
|
|
{
|
2018-05-16 20:04:57 +00:00
|
|
|
|
if (!(spr->mobj->frame & FF_FULLBRIGHT))
|
2020-03-08 03:41:52 +00:00
|
|
|
|
lightlevel = *list[i-1].lightlevel > 255 ? 255 : *list[i-1].lightlevel;
|
2018-09-12 20:28:55 +00:00
|
|
|
|
colormap = *list[i-1].extra_colormap;
|
2018-03-22 00:52:14 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < sector->numlights; i++)
|
|
|
|
|
{
|
2020-03-20 17:55:29 +00:00
|
|
|
|
if (endtop < endrealbot && top < realbot)
|
2018-03-22 00:52:14 +00:00
|
|
|
|
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))
|
|
|
|
|
{
|
2018-05-16 20:04:57 +00:00
|
|
|
|
if (!(spr->mobj->frame & FF_FULLBRIGHT))
|
2020-03-08 03:41:52 +00:00
|
|
|
|
lightlevel = *list[i].lightlevel > 255 ? 255 : *list[i].lightlevel;
|
2018-09-12 20:28:55 +00:00
|
|
|
|
colormap = *list[i].extra_colormap;
|
2018-03-22 00:52:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (i + 1 < sector->numlights)
|
|
|
|
|
{
|
2020-03-22 14:17:16 +00:00
|
|
|
|
temp = P_GetLightZAt(&list[i+1], v1x, v1y);
|
|
|
|
|
bheight = FIXED_TO_FLOAT(temp);
|
|
|
|
|
temp = P_GetLightZAt(&list[i+1], v2x, v2y);
|
|
|
|
|
endbheight = FIXED_TO_FLOAT(temp);
|
2018-03-22 00:52:14 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
bheight = realbot;
|
|
|
|
|
endbheight = endrealbot;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-20 17:55:29 +00:00
|
|
|
|
if (endbheight >= endtop && bheight >= top)
|
2018-03-22 00:52:14 +00:00
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
bot = bheight;
|
|
|
|
|
|
|
|
|
|
if (bot < realbot)
|
|
|
|
|
bot = realbot;
|
|
|
|
|
|
|
|
|
|
endbot = endbheight;
|
|
|
|
|
|
|
|
|
|
if (endbot < endrealbot)
|
|
|
|
|
endbot = endrealbot;
|
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
wallVerts[3].t = ttop + ((realtop - top) * tmult);
|
|
|
|
|
wallVerts[2].t = ttop + ((endrealtop - endtop) * tmult);
|
|
|
|
|
wallVerts[0].t = ttop + ((realtop - bot) * tmult);
|
|
|
|
|
wallVerts[1].t = ttop + ((endrealtop - endbot) * tmult);
|
2018-03-22 00:52:14 +00:00
|
|
|
|
|
|
|
|
|
wallVerts[3].y = top;
|
|
|
|
|
wallVerts[2].y = endtop;
|
|
|
|
|
wallVerts[0].y = bot;
|
|
|
|
|
wallVerts[1].y = endbot;
|
2019-04-30 22:08:01 +00:00
|
|
|
|
|
|
|
|
|
// The x and y only need to be adjusted in the case that it's not a papersprite
|
2019-05-06 19:24:26 +00:00
|
|
|
|
if (cv_grspritebillboarding.value
|
|
|
|
|
&& spr->mobj && !(spr->mobj->frame & FF_PAPERSPRITE))
|
2019-04-30 22:08:01 +00:00
|
|
|
|
{
|
|
|
|
|
// 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;
|
|
|
|
|
}
|
2018-03-22 00:52:14 +00:00
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
HWR_Lighting(&Surf, lightlevel, colormap);
|
2018-03-22 00:52:14 +00:00
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
Surf.PolyColor.s.alpha = alpha;
|
2018-03-22 00:52:14 +00:00
|
|
|
|
|
2020-06-07 18:20:52 +00:00
|
|
|
|
HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip, 3, false); // sprite shader
|
2018-03-22 00:52:14 +00:00
|
|
|
|
|
|
|
|
|
top = bot;
|
|
|
|
|
endtop = endbot;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bot = realbot;
|
|
|
|
|
endbot = endrealbot;
|
2020-03-20 17:55:29 +00:00
|
|
|
|
if (endtop <= endrealbot && top <= realbot)
|
2018-03-22 00:52:14 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// If we're ever down here, somehow the above loop hasn't draw all the light levels of sprite
|
2019-12-25 19:22:01 +00:00
|
|
|
|
wallVerts[3].t = ttop + ((realtop - top) * tmult);
|
|
|
|
|
wallVerts[2].t = ttop + ((endrealtop - endtop) * tmult);
|
|
|
|
|
wallVerts[0].t = ttop + ((realtop - bot) * tmult);
|
|
|
|
|
wallVerts[1].t = ttop + ((endrealtop - endbot) * tmult);
|
2018-03-22 00:52:14 +00:00
|
|
|
|
|
|
|
|
|
wallVerts[3].y = top;
|
|
|
|
|
wallVerts[2].y = endtop;
|
|
|
|
|
wallVerts[0].y = bot;
|
|
|
|
|
wallVerts[1].y = endbot;
|
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
HWR_Lighting(&Surf, lightlevel, colormap);
|
2018-03-22 00:52:14 +00:00
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
Surf.PolyColor.s.alpha = alpha;
|
2018-03-22 00:52:14 +00:00
|
|
|
|
|
2020-06-07 18:20:52 +00:00
|
|
|
|
HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip, 3, false); // sprite shader
|
2018-03-22 00:52:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
// -----------------+
|
|
|
|
|
// HWR_DrawSprite : Draw flat sprites
|
|
|
|
|
// : (monsters, bonuses, weapons, lights, ...)
|
|
|
|
|
// Returns :
|
|
|
|
|
// -----------------+
|
|
|
|
|
static void HWR_DrawSprite(gr_vissprite_t *spr)
|
|
|
|
|
{
|
2018-03-21 19:45:37 +00:00
|
|
|
|
float this_scale = 1.0f;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
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);
|
2016-12-13 21:02:23 +00:00
|
|
|
|
//const boolean papersprite = (spr->mobj && (spr->mobj->frame & FF_PAPERSPRITE));
|
2014-03-15 16:59:03 +00:00
|
|
|
|
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;
|
|
|
|
|
|
2018-03-22 00:52:14 +00:00
|
|
|
|
if (spr->mobj->subsector->sector->numlights)
|
|
|
|
|
{
|
|
|
|
|
HWR_SplitSprite(spr);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
// 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
|
|
|
|
|
|
2019-08-18 17:16:48 +00:00
|
|
|
|
gpatch = spr->gpatch; //W_CachePatchNum(spr->patchlumpnum, PU_CACHE);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
#ifdef ALAM_LIGHTING
|
|
|
|
|
if (!(spr->mobj->flags2 & MF2_DEBRIS) && (spr->mobj->sprite != SPR_PLAY ||
|
|
|
|
|
(spr->mobj->player && spr->mobj->player->powers[pw_super])))
|
|
|
|
|
HWR_DL_AddLight(spr, gpatch);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// 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;
|
2018-12-15 00:33:40 +00:00
|
|
|
|
if (spr->mobj && fabsf(this_scale - 1.0f) > 1.0E-36f)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
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
|
2016-12-13 21:02:23 +00:00
|
|
|
|
wallVerts[0].z = wallVerts[3].z = spr->z1;
|
2018-03-21 19:45:37 +00:00
|
|
|
|
wallVerts[1].z = wallVerts[2].z = spr->z2;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
if (spr->flip)
|
|
|
|
|
{
|
2019-12-25 19:22:01 +00:00
|
|
|
|
wallVerts[0].s = wallVerts[3].s = gpatch->max_s;
|
|
|
|
|
wallVerts[2].s = wallVerts[1].s = 0;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}else{
|
2019-12-25 19:22:01 +00:00
|
|
|
|
wallVerts[0].s = wallVerts[3].s = 0;
|
|
|
|
|
wallVerts[2].s = wallVerts[1].s = gpatch->max_s;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// flip the texture coords (look familiar?)
|
|
|
|
|
if (spr->vflip)
|
|
|
|
|
{
|
2019-12-25 19:22:01 +00:00
|
|
|
|
wallVerts[3].t = wallVerts[2].t = gpatch->max_t;
|
|
|
|
|
wallVerts[0].t = wallVerts[1].t = 0;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}else{
|
2019-12-25 19:22:01 +00:00
|
|
|
|
wallVerts[3].t = wallVerts[2].t = 0;
|
|
|
|
|
wallVerts[0].t = wallVerts[1].t = gpatch->max_t;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
|
2018-12-18 21:37:01 +00:00
|
|
|
|
// if it has a dispoffset, push it a little towards the camera
|
|
|
|
|
if (spr->dispoffset) {
|
2018-12-18 21:59:59 +00:00
|
|
|
|
float co = -gr_viewcos*(0.05f*spr->dispoffset);
|
|
|
|
|
float si = -gr_viewsin*(0.05f*spr->dispoffset);
|
2018-12-18 21:37:01 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
2018-12-18 21:59:59 +00:00
|
|
|
|
|
2019-04-30 22:08:01 +00:00
|
|
|
|
// Let dispoffset work first since this adjust each vertex
|
2020-05-10 19:09:08 +00:00
|
|
|
|
HWR_RotateSpritePolyToAim(spr, wallVerts, false);
|
2019-04-30 22:08:01 +00:00
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
// 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;
|
2015-01-28 15:16:50 +00:00
|
|
|
|
UINT8 lightlevel = 255;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
extracolormap_t *colormap = sector->extra_colormap;
|
|
|
|
|
|
2018-03-22 00:52:14 +00:00
|
|
|
|
if (!(spr->mobj->frame & FF_FULLBRIGHT))
|
2020-03-08 03:41:52 +00:00
|
|
|
|
lightlevel = sector->lightlevel > 255 ? 255 : sector->lightlevel;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
HWR_Lighting(&Surf, lightlevel, colormap);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
FBITFIELD blend = 0;
|
2015-01-02 15:14:22 +00:00
|
|
|
|
if (!cv_translucency.value) // translucency disabled
|
|
|
|
|
{
|
2019-12-25 19:22:01 +00:00
|
|
|
|
Surf.PolyColor.s.alpha = 0xFF;
|
2015-01-02 15:14:22 +00:00
|
|
|
|
blend = PF_Translucent|PF_Occlude;
|
|
|
|
|
}
|
|
|
|
|
else if (spr->mobj->flags2 & MF2_SHADOW)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2019-12-25 19:22:01 +00:00
|
|
|
|
Surf.PolyColor.s.alpha = 0x40;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
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
|
2019-12-25 19:22:01 +00:00
|
|
|
|
Surf.PolyColor.s.alpha = 0xFF;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
blend = PF_Translucent|PF_Occlude;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-07 18:20:52 +00:00
|
|
|
|
HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip, 3, false); // sprite shader
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef HWPRECIP
|
|
|
|
|
// 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
|
2019-08-18 17:16:48 +00:00
|
|
|
|
gpatch = spr->gpatch; //W_CachePatchNum(spr->patchlumpnum, PU_CACHE);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
// 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
|
2018-03-21 19:45:37 +00:00
|
|
|
|
wallVerts[0].z = wallVerts[3].z = spr->z1;
|
|
|
|
|
wallVerts[1].z = wallVerts[2].z = spr->z2;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-04-30 22:08:01 +00:00
|
|
|
|
// Let dispoffset work first since this adjust each vertex
|
2020-05-10 19:09:08 +00:00
|
|
|
|
HWR_RotateSpritePolyToAim(spr, wallVerts, true);
|
2019-04-30 22:08:01 +00:00
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
wallVerts[0].s = wallVerts[3].s = 0;
|
|
|
|
|
wallVerts[2].s = wallVerts[1].s = gpatch->max_s;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
wallVerts[3].t = wallVerts[2].t = 0;
|
|
|
|
|
wallVerts[0].t = wallVerts[1].t = gpatch->max_t;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
|
2016-10-27 22:41:24 +00:00
|
|
|
|
// colormap test
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2016-10-27 22:41:24 +00:00
|
|
|
|
sector_t *sector = spr->mobj->subsector->sector;
|
|
|
|
|
UINT8 lightlevel = 255;
|
|
|
|
|
extracolormap_t *colormap = sector->extra_colormap;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2016-10-27 22:41:24 +00:00
|
|
|
|
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))
|
2020-03-08 03:41:52 +00:00
|
|
|
|
lightlevel = *sector->lightlist[light].lightlevel > 255 ? 255 : *sector->lightlist[light].lightlevel;
|
2016-10-27 22:41:24 +00:00
|
|
|
|
|
2018-09-12 20:28:55 +00:00
|
|
|
|
if (*sector->lightlist[light].extra_colormap)
|
|
|
|
|
colormap = *sector->lightlist[light].extra_colormap;
|
2016-10-27 22:41:24 +00:00
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
else
|
2016-10-27 22:41:24 +00:00
|
|
|
|
{
|
|
|
|
|
if (!(spr->mobj->frame & FF_FULLBRIGHT))
|
2020-03-08 03:41:52 +00:00
|
|
|
|
lightlevel = sector->lightlevel > 255 ? 255 : sector->lightlevel;
|
2016-10-27 22:41:24 +00:00
|
|
|
|
|
|
|
|
|
if (sector->extra_colormap)
|
|
|
|
|
colormap = sector->extra_colormap;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
HWR_Lighting(&Surf, lightlevel, colormap);
|
2016-10-27 22:41:24 +00:00
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
if (spr->mobj->flags2 & MF2_SHADOW)
|
|
|
|
|
{
|
2019-12-25 19:22:01 +00:00
|
|
|
|
Surf.PolyColor.s.alpha = 0x40;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
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
|
2019-12-25 19:22:01 +00:00
|
|
|
|
Surf.PolyColor.s.alpha = 0xFF;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
blend = PF_Translucent|PF_Occlude;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-07 18:20:52 +00:00
|
|
|
|
HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip, 3, false); // sprite shader
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
// Sort vissprites by distance
|
|
|
|
|
// --------------------------------------------------------------------------
|
2020-06-19 11:32:34 +00:00
|
|
|
|
gr_vissprite_t* gr_vsprorder[MAXVISSPRITES];
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2020-06-19 11:32:34 +00:00
|
|
|
|
// Note: 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)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2020-06-19 11:32:34 +00:00
|
|
|
|
gr_vissprite_t* spr1 = *(gr_vissprite_t*const*)p1;
|
|
|
|
|
gr_vissprite_t* spr2 = *(gr_vissprite_t*const*)p2;
|
|
|
|
|
int idiff;
|
|
|
|
|
float fdiff;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2020-06-19 11:32:34 +00:00
|
|
|
|
// Make transparent sprites last. Comment from the previous sort implementation:
|
2018-03-09 09:58:10 +00:00
|
|
|
|
// Sryder: Oh boy, while it's nice having ALL the sprites sorted properly, it fails when we bring MD2's into the
|
|
|
|
|
// mix and they want to be translucent. So let's place all the translucent sprites and MD2's AFTER
|
|
|
|
|
// everything else, but still ordered of course, the depth buffer can handle the opaque ones plenty fine.
|
|
|
|
|
// We just need to move all translucent ones to the end in order
|
|
|
|
|
// TODO: Fully sort all sprites and MD2s with walls and floors, this part will be unnecessary after that
|
2020-06-19 11:32:34 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2020-06-19 11:32:34 +00:00
|
|
|
|
static void HWR_SortVisSprites(void)
|
|
|
|
|
{
|
|
|
|
|
UINT32 i;
|
2018-03-09 09:58:10 +00:00
|
|
|
|
for (i = 0; i < gr_visspritecount; i++)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2020-06-19 11:32:34 +00:00
|
|
|
|
gr_vsprorder[i] = HWR_GetVisSprite(i);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
2020-06-19 11:32:34 +00:00
|
|
|
|
qsort(gr_vsprorder, gr_visspritecount, sizeof(gr_vissprite_t*), CompareVisSprites);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
{
|
2019-12-25 19:22:01 +00:00
|
|
|
|
FOutVector wallVerts[4];
|
2014-03-15 16:59:03 +00:00
|
|
|
|
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
|
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
void HWR_RenderWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend, boolean fogwall, INT32 lightlevel, extracolormap_t *wallcolormap);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
#define MAX_TRANSPARENTWALL 256
|
|
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
|
{
|
|
|
|
|
extrasubsector_t *xsub;
|
2016-07-27 18:56:21 +00:00
|
|
|
|
boolean isceiling;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
fixed_t fixedheight;
|
|
|
|
|
INT32 lightlevel;
|
2019-11-09 01:58:41 +00:00
|
|
|
|
levelflat_t *levelflat;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
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;
|
|
|
|
|
|
2014-10-27 20:57:45 +00:00
|
|
|
|
typedef struct
|
|
|
|
|
{
|
|
|
|
|
polyobj_t *polysector;
|
2016-07-27 18:56:21 +00:00
|
|
|
|
boolean isceiling;
|
2014-10-27 20:57:45 +00:00
|
|
|
|
fixed_t fixedheight;
|
|
|
|
|
INT32 lightlevel;
|
2019-11-09 01:58:41 +00:00
|
|
|
|
levelflat_t *levelflat;
|
2014-10-27 20:57:45 +00:00
|
|
|
|
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;
|
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
//Hurdler: 3D water sutffs
|
|
|
|
|
typedef struct gr_drawnode_s
|
|
|
|
|
{
|
|
|
|
|
planeinfo_t *plane;
|
2014-10-27 20:57:45 +00:00
|
|
|
|
polyplaneinfo_t *polyplane;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
wallinfo_t *wall;
|
|
|
|
|
gr_vissprite_t *sprite;
|
|
|
|
|
|
|
|
|
|
// struct gr_drawnode_s *next;
|
|
|
|
|
// struct gr_drawnode_s *prev;
|
|
|
|
|
} gr_drawnode_t;
|
|
|
|
|
|
|
|
|
|
static INT32 drawcount = 0;
|
|
|
|
|
|
|
|
|
|
#define MAX_TRANSPARENTFLOOR 512
|
|
|
|
|
|
|
|
|
|
// This will likely turn into a copy of HWR_Add3DWater and replace it.
|
2019-12-25 19:22:01 +00:00
|
|
|
|
void HWR_AddTransparentFloor(levelflat_t *levelflat, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, boolean fogplane, extracolormap_t *planecolormap)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-27 18:56:21 +00:00
|
|
|
|
planeinfo[numplanes].isceiling = isceiling;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
planeinfo[numplanes].fixedheight = fixedheight;
|
2020-02-16 19:19:24 +00:00
|
|
|
|
planeinfo[numplanes].lightlevel = (planecolormap && (planecolormap->flags & CMF_FOG)) ? lightlevel : 255;
|
2019-11-09 01:58:41 +00:00
|
|
|
|
planeinfo[numplanes].levelflat = levelflat;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
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++;
|
2016-07-27 18:56:21 +00:00
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
numplanes++;
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-27 20:57:45 +00:00
|
|
|
|
// 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
|
2019-12-25 19:22:01 +00:00
|
|
|
|
void HWR_AddTransparentPolyobjectFloor(levelflat_t *levelflat, polyobj_t *polysector, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, extracolormap_t *planecolormap)
|
2014-10-27 20:57:45 +00:00
|
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-27 18:56:21 +00:00
|
|
|
|
polyplaneinfo[numpolyplanes].isceiling = isceiling;
|
2014-10-27 20:57:45 +00:00
|
|
|
|
polyplaneinfo[numpolyplanes].fixedheight = fixedheight;
|
2020-02-16 19:19:24 +00:00
|
|
|
|
polyplaneinfo[numpolyplanes].lightlevel = (planecolormap && (planecolormap->flags & CMF_FOG)) ? lightlevel : 255;
|
2019-11-09 01:58:41 +00:00
|
|
|
|
polyplaneinfo[numpolyplanes].levelflat = levelflat;
|
2014-10-27 20:57:45 +00:00
|
|
|
|
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++;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-18 16:40:14 +00:00
|
|
|
|
// 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("CompareDrawNodes: 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("CompareDrawNodes: n2 unknown");
|
|
|
|
|
|
|
|
|
|
diff = v2 - v1;
|
|
|
|
|
if (diff == 0) I_Error("CompareDrawNodes: 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("CompareDrawNodePlanes: Uh.. This isn't a plane! (n1)");
|
|
|
|
|
if (!sortnode[n2].plane) I_Error("CompareDrawNodePlanes: Uh.. This isn't a plane! (n2)");
|
|
|
|
|
return ABS(sortnode[n2].plane->fixedheight - viewz) - ABS(sortnode[n1].plane->fixedheight - viewz);
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
//
|
|
|
|
|
// HWR_CreateDrawNodes
|
|
|
|
|
// Creates and sorts a list of drawnodes for the scene being rendered.
|
|
|
|
|
static void HWR_CreateDrawNodes(void)
|
|
|
|
|
{
|
2020-06-18 16:40:14 +00:00
|
|
|
|
UINT32 i = 0, p = 0;
|
|
|
|
|
size_t run_start = 0;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
// 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.
|
2020-06-18 16:40:14 +00:00
|
|
|
|
sortnode = Z_Calloc((sizeof(planeinfo_t)*numplanes)
|
|
|
|
|
+ (sizeof(polyplaneinfo_t)*numpolyplanes)
|
|
|
|
|
+ (sizeof(wallinfo_t)*numwalls)
|
|
|
|
|
,PU_STATIC, NULL);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
// 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.
|
2020-06-18 16:40:14 +00:00
|
|
|
|
sortindex = Z_Calloc(sizeof(size_t) * (numplanes + numpolyplanes + numwalls), PU_STATIC, NULL);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2020-05-02 17:43:53 +00:00
|
|
|
|
rs_hw_nodesorttime = I_GetTimeMicros();
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
for (i = 0; i < numplanes; i++, p++)
|
|
|
|
|
{
|
|
|
|
|
sortnode[p].plane = &planeinfo[i];
|
|
|
|
|
sortindex[p] = p;
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-27 20:57:45 +00:00
|
|
|
|
for (i = 0; i < numpolyplanes; i++, p++)
|
|
|
|
|
{
|
|
|
|
|
sortnode[p].polyplane = &polyplaneinfo[i];
|
|
|
|
|
sortindex[p] = p;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
for (i = 0; i < numwalls; i++, p++)
|
|
|
|
|
{
|
|
|
|
|
sortnode[p].wall = &wallinfo[i];
|
|
|
|
|
sortindex[p] = p;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-18 22:25:28 +00:00
|
|
|
|
rs_numdrawnodes = p;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
// p is the number of stuff to sort
|
|
|
|
|
|
2020-06-18 16:40:14 +00:00
|
|
|
|
// sort the list based on the value of the 'drawcount' member of the drawnodes.
|
|
|
|
|
qsort(sortindex, p, sizeof(size_t), CompareDrawNodes);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2020-06-18 16:40:14 +00:00
|
|
|
|
// an additional pass is needed to correct the order of consecutive planes in the list.
|
|
|
|
|
// for each consecutive run of planes in the list, sort that run based on plane height and view height.
|
|
|
|
|
while (run_start < p-1)// p-1 because a 1 plane run at the end of the list does not count
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2020-06-18 16:40:14 +00:00
|
|
|
|
// locate run start
|
|
|
|
|
if (sortnode[sortindex[run_start]].plane)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2020-06-18 16:40:14 +00:00
|
|
|
|
// 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..
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2020-06-18 16:40:14 +00:00
|
|
|
|
if (!sortnode[sortindex[i]].plane) break;
|
2014-10-27 20:57:45 +00:00
|
|
|
|
}
|
2020-06-18 16:40:14 +00:00
|
|
|
|
run_end = i-1;
|
|
|
|
|
if (run_end > run_start)// if there are multiple consecutive planes, not just one
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2020-06-18 16:40:14 +00:00
|
|
|
|
// consecutive run of planes found, now sort it
|
|
|
|
|
qsort(sortindex + run_start, run_end - run_start + 1, sizeof(size_t), CompareDrawNodePlanes);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
2020-06-18 16:40:14 +00:00
|
|
|
|
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++;
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2020-05-02 17:43:53 +00:00
|
|
|
|
rs_hw_nodesorttime = I_GetTimeMicros() - rs_hw_nodesorttime;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2020-05-02 17:43:53 +00:00
|
|
|
|
rs_hw_nodedrawtime = I_GetTimeMicros();
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
// Okay! Let's draw it all! Woo!
|
2019-12-25 19:22:01 +00:00
|
|
|
|
HWD.pfnSetTransform(&atransform);
|
|
|
|
|
HWD.pfnSetShader(0);
|
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
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))
|
2019-11-09 02:42:15 +00:00
|
|
|
|
HWR_GetLevelFlat(sortnode[sortindex[i]].plane->levelflat);
|
2016-07-27 18:56:21 +00:00
|
|
|
|
HWR_RenderPlane(NULL, sortnode[sortindex[i]].plane->xsub, sortnode[sortindex[i]].plane->isceiling, sortnode[sortindex[i]].plane->fixedheight, sortnode[sortindex[i]].plane->blend, sortnode[sortindex[i]].plane->lightlevel,
|
2019-12-25 19:22:01 +00:00
|
|
|
|
sortnode[sortindex[i]].plane->levelflat, sortnode[sortindex[i]].plane->FOFSector, sortnode[sortindex[i]].plane->alpha, sortnode[sortindex[i]].plane->planecolormap);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
2014-10-27 20:57:45 +00:00
|
|
|
|
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))
|
2019-11-09 02:42:15 +00:00
|
|
|
|
HWR_GetLevelFlat(sortnode[sortindex[i]].polyplane->levelflat);
|
2016-07-27 18:56:21 +00:00
|
|
|
|
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,
|
2019-11-09 01:58:41 +00:00
|
|
|
|
sortnode[sortindex[i]].polyplane->levelflat, sortnode[sortindex[i]].polyplane->FOFSector, sortnode[sortindex[i]].polyplane->alpha, sortnode[sortindex[i]].polyplane->planecolormap);
|
2014-10-27 20:57:45 +00:00
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-02 17:43:53 +00:00
|
|
|
|
rs_hw_nodedrawtime = I_GetTimeMicros() - rs_hw_nodedrawtime;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
numwalls = 0;
|
|
|
|
|
numplanes = 0;
|
2014-10-27 20:57:45 +00:00
|
|
|
|
numpolyplanes = 0;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
// No mem leaks, please.
|
|
|
|
|
Z_Free(sortnode);
|
|
|
|
|
Z_Free(sortindex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
// Draw all vissprites
|
|
|
|
|
// --------------------------------------------------------------------------
|
2019-12-25 19:22:01 +00:00
|
|
|
|
|
2017-09-07 23:56:58 +00:00
|
|
|
|
// added the stransform so they can be switched as drawing happenes so MD2s and sprites are sorted correctly with each other
|
2014-03-15 16:59:03 +00:00
|
|
|
|
static void HWR_DrawSprites(void)
|
|
|
|
|
{
|
2020-06-19 11:32:34 +00:00
|
|
|
|
UINT32 i;
|
|
|
|
|
HWD.pfnSetSpecialState(HWD_SET_MODEL_LIGHTING, cv_grmodellighting.value);
|
|
|
|
|
for (i = 0; i < gr_visspritecount; i++)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2020-06-19 11:32:34 +00:00
|
|
|
|
gr_vissprite_t *spr = gr_vsprorder[i];
|
2014-03-15 16:59:03 +00:00
|
|
|
|
#ifdef HWPRECIP
|
2020-06-19 11:32:34 +00:00
|
|
|
|
if (spr->precip)
|
|
|
|
|
HWR_DrawPrecipitationSprite(spr);
|
|
|
|
|
else
|
2014-03-15 16:59:03 +00:00
|
|
|
|
#endif
|
2020-06-19 11:32:34 +00:00
|
|
|
|
{
|
|
|
|
|
if (spr->mobj && spr->mobj->shadowscale && cv_shadow.value)
|
2020-01-16 17:37:32 +00:00
|
|
|
|
{
|
2020-06-19 11:32:34 +00:00
|
|
|
|
HWR_DrawDropShadow(spr->mobj, spr->mobj->shadowscale);
|
|
|
|
|
}
|
2020-01-16 17:37:32 +00:00
|
|
|
|
|
2020-06-19 11:32:34 +00:00
|
|
|
|
if (spr->mobj && spr->mobj->skin && spr->mobj->sprite == SPR_PLAY)
|
|
|
|
|
{
|
|
|
|
|
if (!cv_grmodels.value || md2_playermodels[(skin_t*)spr->mobj->skin-skins].notfound || md2_playermodels[(skin_t*)spr->mobj->skin-skins].scale < 0.0f)
|
|
|
|
|
HWR_DrawSprite(spr);
|
|
|
|
|
else
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2020-06-19 11:32:34 +00:00
|
|
|
|
if (!HWR_DrawModel(spr))
|
2014-03-15 16:59:03 +00:00
|
|
|
|
HWR_DrawSprite(spr);
|
|
|
|
|
}
|
2020-06-19 11:32:34 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (!cv_grmodels.value || md2_models[spr->mobj->sprite].notfound || md2_models[spr->mobj->sprite].scale < 0.0f)
|
|
|
|
|
HWR_DrawSprite(spr);
|
2017-09-07 23:56:58 +00:00
|
|
|
|
else
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2020-06-19 11:32:34 +00:00
|
|
|
|
if (!HWR_DrawModel(spr))
|
2017-09-07 23:56:58 +00:00
|
|
|
|
HWR_DrawSprite(spr);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
2020-01-16 17:37:32 +00:00
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2020-06-19 11:32:34 +00:00
|
|
|
|
HWD.pfnSetSpecialState(HWD_SET_MODEL_LIGHTING, 0);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
// HWR_AddSprites
|
|
|
|
|
// During BSP traversal, this adds sprites by sector.
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
static UINT8 sectorlight;
|
|
|
|
|
static void HWR_AddSprites(sector_t *sec)
|
|
|
|
|
{
|
|
|
|
|
mobj_t *thing;
|
|
|
|
|
#ifdef HWPRECIP
|
|
|
|
|
precipmobj_t *precipthing;
|
|
|
|
|
#endif
|
2020-01-18 04:45:55 +00:00
|
|
|
|
fixed_t limit_dist, hoop_limit_dist;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
|
|
|
|
|
// sprite lighting
|
2014-03-24 16:11:25 +00:00
|
|
|
|
sectorlight = sec->lightlevel & 0xff;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
// Handle all things in sector.
|
|
|
|
|
// If a limit exists, handle things a tiny bit different.
|
2019-10-11 19:02:11 +00:00
|
|
|
|
limit_dist = (fixed_t)(cv_drawdist.value) << FRACBITS;
|
|
|
|
|
hoop_limit_dist = (fixed_t)(cv_drawdist_nights.value) << FRACBITS;
|
2020-01-18 04:45:55 +00:00
|
|
|
|
for (thing = sec->thinglist; thing; thing = thing->snext)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2020-01-18 04:45:55 +00:00
|
|
|
|
if (R_ThingVisibleWithinDist(thing, limit_dist, hoop_limit_dist))
|
2018-10-07 14:00:58 +00:00
|
|
|
|
HWR_ProjectSprite(thing);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef HWPRECIP
|
2019-06-18 12:33:35 +00:00
|
|
|
|
// no, no infinite draw distance for precipitation. this option at zero is supposed to turn it off
|
2014-03-15 16:59:03 +00:00
|
|
|
|
if ((limit_dist = (fixed_t)cv_drawdist_precip.value << FRACBITS))
|
|
|
|
|
{
|
|
|
|
|
for (precipthing = sec->preciplist; precipthing; precipthing = precipthing->snext)
|
|
|
|
|
{
|
2020-01-18 04:45:55 +00:00
|
|
|
|
if (R_PrecipThingVisible(precipthing, limit_dist))
|
|
|
|
|
HWR_ProjectPrecipitationSprite(precipthing);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
// HWR_ProjectSprite
|
|
|
|
|
// Generates a vissprite for a thing if it might be visible.
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
// BP why not use xtoviexangle/viewangletox like in bsp ?....
|
|
|
|
|
static void HWR_ProjectSprite(mobj_t *thing)
|
|
|
|
|
{
|
|
|
|
|
gr_vissprite_t *vis;
|
|
|
|
|
float tr_x, tr_y;
|
2018-03-21 19:45:37 +00:00
|
|
|
|
float tz;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
float x1, x2;
|
2018-03-21 19:45:37 +00:00
|
|
|
|
float rightsin, rightcos;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
float this_scale;
|
|
|
|
|
float gz, gzt;
|
|
|
|
|
spritedef_t *sprdef;
|
|
|
|
|
spriteframe_t *sprframe;
|
2019-09-29 15:13:51 +00:00
|
|
|
|
spriteinfo_t *sprinfo;
|
2020-01-09 04:52:34 +00:00
|
|
|
|
md2_t *md2;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
size_t lumpoff;
|
|
|
|
|
unsigned rot;
|
2020-01-08 20:49:14 +00:00
|
|
|
|
UINT16 flip;
|
2016-09-24 13:23:00 +00:00
|
|
|
|
boolean vflip = (!(thing->eflags & MFE_VERTICALFLIP) != !(thing->frame & FF_VERTICALFLIP));
|
2020-06-07 20:11:36 +00:00
|
|
|
|
boolean mirrored = thing->mirrored;
|
|
|
|
|
boolean hflip = (!(thing->frame & FF_HORIZONTALFLIP) != !mirrored);
|
2016-09-24 13:23:00 +00:00
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
angle_t ang;
|
|
|
|
|
INT32 heightsec, phs;
|
2016-12-13 21:02:23 +00:00
|
|
|
|
const boolean papersprite = (thing->frame & FF_PAPERSPRITE);
|
2018-04-06 17:42:07 +00:00
|
|
|
|
angle_t mobjangle = (thing->player ? thing->player->drawangle : thing->angle);
|
2016-12-13 21:02:23 +00:00
|
|
|
|
float z1, z2;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-08-18 17:16:48 +00:00
|
|
|
|
fixed_t spr_width, spr_height;
|
|
|
|
|
fixed_t spr_offset, spr_topoffset;
|
|
|
|
|
#ifdef ROTSPRITE
|
|
|
|
|
patch_t *rotsprite = NULL;
|
2019-12-27 00:27:30 +00:00
|
|
|
|
INT32 rollangle = 0;
|
2019-08-18 17:16:48 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
if (!thing)
|
|
|
|
|
return;
|
2019-08-18 17:16:48 +00:00
|
|
|
|
|
|
|
|
|
this_scale = FIXED_TO_FLOAT(thing->scale);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
// 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?
|
2020-01-09 04:52:34 +00:00
|
|
|
|
if (tz < ZCLIP_PLANE && !papersprite)
|
|
|
|
|
{
|
|
|
|
|
if (cv_grmodels.value) //Yellow: Only MD2's dont disappear
|
|
|
|
|
{
|
|
|
|
|
if (thing->skin && thing->sprite == SPR_PLAY)
|
|
|
|
|
md2 = &md2_playermodels[( (skin_t *)thing->skin - skins )];
|
|
|
|
|
else
|
|
|
|
|
md2 = &md2_models[thing->sprite];
|
|
|
|
|
|
|
|
|
|
if (md2->notfound || md2->scale < 0.0f)
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return;
|
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2018-03-21 19:45:37 +00:00
|
|
|
|
// The above can stay as it works for cutting sprites that are too close
|
|
|
|
|
tr_x = FIXED_TO_FLOAT(thing->x);
|
|
|
|
|
tr_y = FIXED_TO_FLOAT(thing->y);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
// 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)
|
2019-09-29 15:13:51 +00:00
|
|
|
|
{
|
2015-01-22 15:23:45 +00:00
|
|
|
|
sprdef = &((skin_t *)thing->skin)->sprites[thing->sprite2];
|
2019-09-29 15:13:51 +00:00
|
|
|
|
sprinfo = &((skin_t *)thing->skin)->sprinfo[thing->sprite2];
|
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
else
|
2019-09-29 15:13:51 +00:00
|
|
|
|
{
|
2014-03-15 16:59:03 +00:00
|
|
|
|
sprdef = &sprites[thing->sprite];
|
2019-09-29 15:13:51 +00:00
|
|
|
|
sprinfo = NULL;
|
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
if (rot >= sprdef->numframes)
|
|
|
|
|
{
|
2015-02-15 17:15:55 +00:00
|
|
|
|
CONS_Alert(CONS_ERROR, M_GetText("HWR_ProjectSprite: invalid sprite frame %s/%s for %s\n"),
|
2014-03-15 16:59:03 +00:00
|
|
|
|
sizeu1(rot), sizeu2(sprdef->numframes), sprnames[thing->sprite]);
|
|
|
|
|
thing->sprite = states[S_UNKNOWN].sprite;
|
|
|
|
|
thing->frame = states[S_UNKNOWN].frame;
|
2015-02-18 23:42:01 +00:00
|
|
|
|
sprdef = &sprites[thing->sprite];
|
2019-09-29 15:13:51 +00:00
|
|
|
|
sprinfo = NULL;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
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
|
|
|
|
|
|
2018-06-11 18:53:16 +00:00
|
|
|
|
ang = R_PointToAngle (thing->x, thing->y) - mobjangle;
|
2020-06-07 20:11:36 +00:00
|
|
|
|
if (mirrored)
|
|
|
|
|
ang = InvAngle(ang);
|
2016-12-13 21:02:23 +00:00
|
|
|
|
|
2016-07-18 23:04:00 +00:00
|
|
|
|
if (sprframe->rotate == SRF_SINGLE)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
|
|
|
|
// 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
|
2018-06-09 17:47:42 +00:00
|
|
|
|
|
2018-06-09 21:58:03 +00:00
|
|
|
|
if (papersprite && ang < ANGLE_180)
|
2020-01-08 20:49:14 +00:00
|
|
|
|
flip ^= 0xFFFF;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
2016-07-18 23:04:00 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// choose a different rotation based on player view
|
2016-08-06 23:21:16 +00:00
|
|
|
|
if ((sprframe->rotate & SRF_RIGHT) && (ang < ANGLE_180)) // See from right
|
2016-07-18 23:04:00 +00:00
|
|
|
|
rot = 6; // F7 slot
|
2016-08-06 23:21:16 +00:00
|
|
|
|
else if ((sprframe->rotate & SRF_LEFT) && (ang >= ANGLE_180)) // See from left
|
2016-07-18 23:04:00 +00:00
|
|
|
|
rot = 2; // F3 slot
|
2020-01-08 20:49:14 +00:00
|
|
|
|
else if (sprframe->rotate & SRF_3DGE) // 16-angle mode
|
|
|
|
|
{
|
|
|
|
|
rot = (ang+ANGLE_180+ANGLE_11hh)>>28;
|
|
|
|
|
rot = ((rot & 1)<<3)|(rot>>1);
|
|
|
|
|
}
|
2016-07-18 23:04:00 +00:00
|
|
|
|
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);
|
2018-06-09 21:58:03 +00:00
|
|
|
|
|
|
|
|
|
if (papersprite && ang < ANGLE_180)
|
2020-01-08 20:49:14 +00:00
|
|
|
|
flip ^= (1<<rot);
|
2016-07-18 23:04:00 +00:00
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES)
|
|
|
|
|
this_scale = this_scale * FIXED_TO_FLOAT(((skin_t *)thing->skin)->highresscale);
|
|
|
|
|
|
2019-08-18 17:16:48 +00:00
|
|
|
|
spr_width = spritecachedinfo[lumpoff].width;
|
|
|
|
|
spr_height = spritecachedinfo[lumpoff].height;
|
|
|
|
|
spr_offset = spritecachedinfo[lumpoff].offset;
|
|
|
|
|
spr_topoffset = spritecachedinfo[lumpoff].topoffset;
|
|
|
|
|
|
|
|
|
|
#ifdef ROTSPRITE
|
2019-12-27 00:27:30 +00:00
|
|
|
|
if (thing->rollangle)
|
2019-08-18 17:16:48 +00:00
|
|
|
|
{
|
2019-12-27 00:27:30 +00:00
|
|
|
|
rollangle = R_GetRollAngle(thing->rollangle);
|
2020-01-08 20:49:14 +00:00
|
|
|
|
if (!(sprframe->rotsprite.cached & (1<<rot)))
|
2019-09-29 17:12:53 +00:00
|
|
|
|
R_CacheRotSprite(thing->sprite, (thing->frame & FF_FRAMEMASK), sprinfo, sprframe, rot, flip);
|
2019-08-18 17:16:48 +00:00
|
|
|
|
rotsprite = sprframe->rotsprite.patch[rot][rollangle];
|
|
|
|
|
if (rotsprite != NULL)
|
|
|
|
|
{
|
2020-05-02 16:13:16 +00:00
|
|
|
|
spr_width = SHORT(rotsprite->width) << FRACBITS;
|
|
|
|
|
spr_height = SHORT(rotsprite->height) << FRACBITS;
|
|
|
|
|
spr_offset = SHORT(rotsprite->leftoffset) << FRACBITS;
|
|
|
|
|
spr_topoffset = SHORT(rotsprite->topoffset) << FRACBITS;
|
2019-08-18 17:16:48 +00:00
|
|
|
|
// flip -> rotate, not rotate -> flip
|
|
|
|
|
flip = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2018-06-09 17:47:42 +00:00
|
|
|
|
if (papersprite)
|
2018-04-06 17:42:07 +00:00
|
|
|
|
{
|
2018-06-11 18:53:16 +00:00
|
|
|
|
rightsin = FIXED_TO_FLOAT(FINESINE((mobjangle)>>ANGLETOFINESHIFT));
|
|
|
|
|
rightcos = FIXED_TO_FLOAT(FINECOSINE((mobjangle)>>ANGLETOFINESHIFT));
|
2018-04-06 17:42:07 +00:00
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
else
|
2018-04-06 17:42:07 +00:00
|
|
|
|
{
|
|
|
|
|
rightsin = FIXED_TO_FLOAT(FINESINE((viewangle + ANGLE_90)>>ANGLETOFINESHIFT));
|
|
|
|
|
rightcos = FIXED_TO_FLOAT(FINECOSINE((viewangle + ANGLE_90)>>ANGLETOFINESHIFT));
|
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2020-06-07 20:11:36 +00:00
|
|
|
|
flip = !flip != !hflip;
|
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
if (flip)
|
2018-03-21 19:45:37 +00:00
|
|
|
|
{
|
2019-08-18 17:16:48 +00:00
|
|
|
|
x1 = (FIXED_TO_FLOAT(spr_width - spr_offset) * this_scale);
|
|
|
|
|
x2 = (FIXED_TO_FLOAT(spr_offset) * this_scale);
|
2018-03-21 19:45:37 +00:00
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
else
|
2018-03-21 19:45:37 +00:00
|
|
|
|
{
|
2019-08-18 17:16:48 +00:00
|
|
|
|
x1 = (FIXED_TO_FLOAT(spr_offset) * this_scale);
|
|
|
|
|
x2 = (FIXED_TO_FLOAT(spr_width - spr_offset) * this_scale);
|
2018-03-21 19:45:37 +00:00
|
|
|
|
}
|
2017-05-13 11:49:30 +00:00
|
|
|
|
|
2018-04-06 17:42:07 +00:00
|
|
|
|
// test if too close
|
|
|
|
|
/*
|
|
|
|
|
if (papersprite)
|
|
|
|
|
{
|
|
|
|
|
z1 = tz - x1 * angle_scalez;
|
|
|
|
|
z2 = tz + x2 * angle_scalez;
|
2017-05-13 11:49:30 +00:00
|
|
|
|
|
2018-04-06 17:42:07 +00:00
|
|
|
|
if (max(z1, z2) < ZCLIP_PLANE)
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
*/
|
2016-12-13 21:02:23 +00:00
|
|
|
|
|
2018-03-21 19:45:37 +00:00
|
|
|
|
z1 = tr_y + x1 * rightsin;
|
|
|
|
|
z2 = tr_y - x2 * rightsin;
|
|
|
|
|
x1 = tr_x + x1 * rightcos;
|
|
|
|
|
x2 = tr_x - x2 * rightcos;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2016-09-24 13:23:00 +00:00
|
|
|
|
if (vflip)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2019-08-18 17:16:48 +00:00
|
|
|
|
gz = FIXED_TO_FLOAT(thing->z+thing->height) - FIXED_TO_FLOAT(spr_topoffset) * this_scale;
|
|
|
|
|
gzt = gz + FIXED_TO_FLOAT(spr_height) * this_scale;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2019-08-18 17:16:48 +00:00
|
|
|
|
gzt = FIXED_TO_FLOAT(thing->z) + FIXED_TO_FLOAT(spr_topoffset) * this_scale;
|
|
|
|
|
gz = gzt - FIXED_TO_FLOAT(spr_height) * this_scale;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (thing->subsector->sector->cullheight)
|
|
|
|
|
{
|
2014-11-12 00:55:07 +00:00
|
|
|
|
if (HWR_DoCulling(thing->subsector->sector->cullheight, viewsector->cullheight, gr_viewz, gz, gzt))
|
|
|
|
|
return;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
heightsec = thing->subsector->sector->heightsec;
|
2018-06-23 17:47:32 +00:00
|
|
|
|
if (viewplayer->mo && viewplayer->mo->subsector)
|
|
|
|
|
phs = viewplayer->mo->subsector->sector->heightsec;
|
|
|
|
|
else
|
|
|
|
|
phs = -1;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
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(thing->z) >= 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(thing->z) >= FIXED_TO_FLOAT(sectors[heightsec].ceilingheight))
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-06 15:31:13 +00:00
|
|
|
|
if ((thing->flags2 & MF2_LINKDRAW) && thing->tracer)
|
|
|
|
|
{
|
|
|
|
|
// bodge support - not nearly as comprehensive as r_things.c, but better than nothing
|
2020-01-18 04:56:32 +00:00
|
|
|
|
if (! R_ThingVisible(thing->tracer))
|
2019-10-06 15:31:13 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
// store information in a vissprite
|
|
|
|
|
vis = HWR_NewVisSprite();
|
|
|
|
|
vis->x1 = x1;
|
|
|
|
|
vis->x2 = x2;
|
2018-03-21 19:45:37 +00:00
|
|
|
|
vis->tz = tz; // Keep tz for the simple sprite sorting that happens
|
2015-11-23 17:01:10 +00:00
|
|
|
|
vis->dispoffset = thing->info->dispoffset; // Monster Iestyn: 23/11/15: HARDWARE SUPPORT AT LAST
|
2019-08-18 17:16:48 +00:00
|
|
|
|
//vis->patchlumpnum = sprframe->lumppat[rot];
|
|
|
|
|
#ifdef ROTSPRITE
|
|
|
|
|
if (rotsprite)
|
|
|
|
|
vis->gpatch = (GLPatch_t *)rotsprite;
|
|
|
|
|
else
|
|
|
|
|
#endif
|
|
|
|
|
vis->gpatch = (GLPatch_t *)W_CachePatchNum(sprframe->lumppat[rot], PU_CACHE);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
vis->flip = flip;
|
|
|
|
|
vis->mobj = thing;
|
2016-12-13 21:02:23 +00:00
|
|
|
|
vis->z1 = z1;
|
|
|
|
|
vis->z2 = z2;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
//Hurdler: 25/04/2000: now support colormap in hardware mode
|
2019-10-06 15:31:13 +00:00
|
|
|
|
if ((vis->mobj->flags & (MF_ENEMY|MF_BOSS)) && (vis->mobj->flags2 & MF2_FRET) && !(vis->mobj->flags & MF_GRENADEBOUNCE) && (leveltime & 1)) // Bosses "flash"
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2019-07-02 23:58:02 +00:00
|
|
|
|
if (vis->mobj->type == MT_CYBRAKDEMON || vis->mobj->colorized)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
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
|
2019-06-18 16:55:57 +00:00
|
|
|
|
if (thing->colorized)
|
|
|
|
|
vis->colormap = R_GetTranslationColormap(TC_RAINBOW, thing->color, GTC_CACHE);
|
2019-11-04 13:11:04 +00:00
|
|
|
|
else if (thing->player && thing->player->dashmode >= DASHMODE_THRESHOLD
|
|
|
|
|
&& (thing->player->charflags & SF_DASHMODE)
|
|
|
|
|
&& ((leveltime/2) & 1))
|
|
|
|
|
{
|
|
|
|
|
if (thing->player->charflags & SF_MACHINE)
|
|
|
|
|
vis->colormap = R_GetTranslationColormap(TC_DASHMODE, 0, GTC_CACHE);
|
|
|
|
|
else
|
|
|
|
|
vis->colormap = R_GetTranslationColormap(TC_RAINBOW, thing->color, GTC_CACHE);
|
|
|
|
|
}
|
2019-06-18 16:55:57 +00:00
|
|
|
|
else if (thing->skin && thing->sprite == SPR_PLAY) // This thing is a player!
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
|
|
|
|
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, vis->mobj->color ? vis->mobj->color : SKINCOLOR_CYAN, GTC_CACHE);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
vis->colormap = colormaps;
|
|
|
|
|
|
|
|
|
|
// set top/bottom coords
|
2018-03-21 19:45:37 +00:00
|
|
|
|
vis->ty = gzt;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
//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]);
|
|
|
|
|
|
2016-09-24 13:23:00 +00:00
|
|
|
|
vis->vflip = vflip;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
vis->precip = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef HWPRECIP
|
|
|
|
|
// Precipitation projector for hardware mode
|
|
|
|
|
static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
|
|
|
|
|
{
|
|
|
|
|
gr_vissprite_t *vis;
|
|
|
|
|
float tr_x, tr_y;
|
2018-03-21 19:45:37 +00:00
|
|
|
|
float tz;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
float x1, x2;
|
2018-03-21 19:45:37 +00:00
|
|
|
|
float z1, z2;
|
|
|
|
|
float rightsin, rightcos;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
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;
|
|
|
|
|
|
2018-03-21 19:45:37 +00:00
|
|
|
|
tr_x = FIXED_TO_FLOAT(thing->x);
|
|
|
|
|
tr_y = FIXED_TO_FLOAT(thing->y);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
|
2018-03-21 19:45:37 +00:00
|
|
|
|
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);
|
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2018-03-21 19:45:37 +00:00
|
|
|
|
z1 = tr_y + x1 * rightsin;
|
|
|
|
|
z2 = tr_y - x2 * rightsin;
|
|
|
|
|
x1 = tr_x + x1 * rightcos;
|
|
|
|
|
x2 = tr_x - x2 * rightcos;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// store information in a vissprite
|
|
|
|
|
//
|
|
|
|
|
vis = HWR_NewVisSprite();
|
|
|
|
|
vis->x1 = x1;
|
2016-10-27 22:41:24 +00:00
|
|
|
|
vis->x2 = x2;
|
2018-03-21 19:45:37 +00:00
|
|
|
|
vis->z1 = z1;
|
|
|
|
|
vis->z2 = z2;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
vis->tz = tz;
|
2015-11-23 17:01:10 +00:00
|
|
|
|
vis->dispoffset = 0; // Monster Iestyn: 23/11/15: HARDWARE SUPPORT AT LAST
|
2019-08-18 17:16:48 +00:00
|
|
|
|
//vis->patchlumpnum = sprframe->lumppat[rot];
|
|
|
|
|
vis->gpatch = (GLPatch_t *)W_CachePatchNum(sprframe->lumppat[rot], PU_CACHE);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
vis->flip = flip;
|
|
|
|
|
vis->mobj = (mobj_t *)thing;
|
|
|
|
|
|
|
|
|
|
vis->colormap = colormaps;
|
|
|
|
|
|
|
|
|
|
// set top/bottom coords
|
2018-03-21 19:45:37 +00:00
|
|
|
|
vis->ty = FIXED_TO_FLOAT(thing->z + spritecachedinfo[lumpoff].topoffset);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
vis->precip = true;
|
2019-06-18 12:33:35 +00:00
|
|
|
|
|
|
|
|
|
// okay... this is a hack, but weather isn't networked, so it should be ok
|
|
|
|
|
if (!(thing->precipflags & PCF_THUNK))
|
|
|
|
|
{
|
|
|
|
|
if (thing->precipflags & PCF_RAIN)
|
|
|
|
|
P_RainThinker(thing);
|
|
|
|
|
else
|
|
|
|
|
P_SnowThinker(thing);
|
|
|
|
|
thing->precipflags |= PCF_THUNK;
|
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// ==========================================================================
|
|
|
|
|
//
|
|
|
|
|
// ==========================================================================
|
2019-09-18 02:38:04 +00:00
|
|
|
|
static void HWR_DrawSkyBackground(player_t *player)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2019-09-18 02:38:04 +00:00
|
|
|
|
if (cv_grskydome.value)
|
|
|
|
|
{
|
2019-12-08 05:27:51 +00:00
|
|
|
|
FTransform dometransform;
|
2019-12-31 17:21:46 +00:00
|
|
|
|
const float fpov = FIXED_TO_FLOAT(cv_fov.value+player->fovadd);
|
2019-09-18 02:38:04 +00:00
|
|
|
|
postimg_t *type;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-09-18 02:38:04 +00:00
|
|
|
|
if (splitscreen && player == &players[secondarydisplayplayer])
|
|
|
|
|
type = &postimgtype2;
|
|
|
|
|
else
|
|
|
|
|
type = &postimgtype;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-12-08 05:27:51 +00:00
|
|
|
|
memset(&dometransform, 0x00, sizeof(FTransform));
|
2018-11-10 19:19:41 +00:00
|
|
|
|
|
2019-09-18 02:38:04 +00:00
|
|
|
|
//04/01/2000: Hurdler: added for T&L
|
|
|
|
|
// It should replace all other gr_viewxxx when finished
|
2020-02-08 20:42:26 +00:00
|
|
|
|
HWR_SetTransformAiming(&dometransform, player, false);
|
2019-12-08 05:27:51 +00:00
|
|
|
|
dometransform.angley = (float)((viewangle-ANGLE_270)>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-09-18 02:38:04 +00:00
|
|
|
|
if (*type == postimg_flip)
|
2019-12-08 05:27:51 +00:00
|
|
|
|
dometransform.flip = true;
|
2019-09-18 02:38:04 +00:00
|
|
|
|
else
|
2019-12-08 05:27:51 +00:00
|
|
|
|
dometransform.flip = false;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-12-08 05:27:51 +00:00
|
|
|
|
dometransform.scalex = 1;
|
|
|
|
|
dometransform.scaley = (float)vid.width/vid.height;
|
|
|
|
|
dometransform.scalez = 1;
|
|
|
|
|
dometransform.fovxangle = fpov; // Tails
|
|
|
|
|
dometransform.fovyangle = fpov; // Tails
|
2020-01-18 03:55:16 +00:00
|
|
|
|
if (player->viewrollangle != 0)
|
|
|
|
|
{
|
|
|
|
|
fixed_t rol = AngleFixed(player->viewrollangle);
|
|
|
|
|
dometransform.rollangle = FIXED_TO_FLOAT(rol);
|
|
|
|
|
dometransform.roll = true;
|
|
|
|
|
}
|
2019-12-08 05:27:51 +00:00
|
|
|
|
dometransform.splitscreen = splitscreen;
|
2014-03-20 20:13:15 +00:00
|
|
|
|
|
2019-09-18 02:38:04 +00:00
|
|
|
|
HWR_GetTexture(texturetranslation[skytexture]);
|
2019-12-08 05:27:51 +00:00
|
|
|
|
HWD.pfnRenderSkyDome(skytexture, textures[skytexture]->width, textures[skytexture]->height, dometransform);
|
2019-09-18 02:38:04 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
FOutVector v[4];
|
|
|
|
|
angle_t angle;
|
|
|
|
|
float dimensionmultiply;
|
|
|
|
|
float aspectratio;
|
|
|
|
|
float angleturn;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-09-18 02:38:04 +00:00
|
|
|
|
HWR_GetTexture(texturetranslation[skytexture]);
|
|
|
|
|
aspectratio = (float)vid.width/(float)vid.height;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-09-18 02:38:04 +00:00
|
|
|
|
//Hurdler: the sky is the only texture who need 4.0f instead of 1.0
|
|
|
|
|
// because it's called just after clearing the screen
|
|
|
|
|
// and thus, the near clipping plane is set to 3.99
|
|
|
|
|
// Sryder: Just use the near clipping plane value then
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-09-18 02:38:04 +00:00
|
|
|
|
// 3--2
|
|
|
|
|
// | /|
|
|
|
|
|
// |/ |
|
|
|
|
|
// 0--1
|
|
|
|
|
v[0].x = v[3].x = -ZCLIP_PLANE-1;
|
|
|
|
|
v[1].x = v[2].x = ZCLIP_PLANE+1;
|
|
|
|
|
v[0].y = v[1].y = -ZCLIP_PLANE-1;
|
|
|
|
|
v[2].y = v[3].y = ZCLIP_PLANE+1;
|
2014-03-20 20:13:15 +00:00
|
|
|
|
|
2019-09-18 02:38:04 +00:00
|
|
|
|
v[0].z = v[1].z = v[2].z = v[3].z = ZCLIP_PLANE+1;
|
2018-11-10 19:19:41 +00:00
|
|
|
|
|
2019-09-18 02:38:04 +00:00
|
|
|
|
// X
|
2014-09-07 23:55:32 +00:00
|
|
|
|
|
2019-09-18 02:38:04 +00:00
|
|
|
|
// NOTE: This doesn't work right with texture widths greater than 1024
|
|
|
|
|
// software doesn't draw any further than 1024 for skies anyway, but this doesn't overlap properly
|
|
|
|
|
// The only time this will probably be an issue is when a sky wider than 1024 is used as a sky AND a regular wall texture
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-09-18 02:38:04 +00:00
|
|
|
|
angle = (dup_viewangle + gr_xtoviewangle[0]);
|
2018-11-10 19:19:41 +00:00
|
|
|
|
|
2019-09-18 02:38:04 +00:00
|
|
|
|
dimensionmultiply = ((float)textures[texturetranslation[skytexture]]->width/256.0f);
|
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
v[0].s = v[3].s = (-1.0f * angle) / ((ANGLE_90-1)*dimensionmultiply); // left
|
|
|
|
|
v[2].s = v[1].s = v[0].s + (1.0f/dimensionmultiply); // right (or left + 1.0f)
|
2019-09-18 02:38:04 +00:00
|
|
|
|
// use +angle and -1.0f above instead if you wanted old backwards behavior
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-09-18 02:38:04 +00:00
|
|
|
|
// Y
|
|
|
|
|
angle = aimingangle;
|
|
|
|
|
dimensionmultiply = ((float)textures[texturetranslation[skytexture]]->height/(128.0f*aspectratio));
|
|
|
|
|
|
|
|
|
|
if (splitscreen)
|
|
|
|
|
{
|
|
|
|
|
dimensionmultiply *= 2;
|
|
|
|
|
angle *= 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Middle of the sky should always be at angle 0
|
|
|
|
|
// need to keep correct aspect ratio with X
|
|
|
|
|
if (atransform.flip)
|
|
|
|
|
{
|
|
|
|
|
// During vertical flip the sky should be flipped and it's y movement should also be flipped obviously
|
2019-12-25 19:22:01 +00:00
|
|
|
|
v[3].t = v[2].t = -(0.5f-(0.5f/dimensionmultiply)); // top
|
|
|
|
|
v[0].t = v[1].t = v[3].t - (1.0f/dimensionmultiply); // bottom (or top - 1.0f)
|
2019-09-18 02:38:04 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2019-12-25 19:22:01 +00:00
|
|
|
|
v[0].t = v[1].t = -(0.5f-(0.5f/dimensionmultiply)); // bottom
|
|
|
|
|
v[3].t = v[2].t = v[0].t - (1.0f/dimensionmultiply); // top (or bottom - 1.0f)
|
2019-09-18 02:38:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
angleturn = (((float)ANGLE_45-1.0f)*aspectratio)*dimensionmultiply;
|
|
|
|
|
|
|
|
|
|
if (angle > ANGLE_180) // Do this because we don't want the sky to suddenly teleport when crossing over 0 to 360 and vice versa
|
|
|
|
|
{
|
|
|
|
|
angle = InvAngle(angle);
|
2019-12-25 19:22:01 +00:00
|
|
|
|
v[3].t = v[2].t += ((float) angle / angleturn);
|
|
|
|
|
v[0].t = v[1].t += ((float) angle / angleturn);
|
2019-09-18 02:38:04 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2019-12-25 19:22:01 +00:00
|
|
|
|
v[3].t = v[2].t -= ((float) angle / angleturn);
|
|
|
|
|
v[0].t = v[1].t -= ((float) angle / angleturn);
|
2019-09-18 02:38:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
HWD.pfnSetShader(7); // sky shader
|
2019-09-18 02:38:04 +00:00
|
|
|
|
HWD.pfnDrawPolygon(NULL, v, 4, 0);
|
2019-12-25 19:22:01 +00:00
|
|
|
|
HWD.pfnSetShader(0);
|
2019-09-18 02:38:04 +00:00
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// -----------------+
|
|
|
|
|
// HWR_ClearView : clear the viewwindow, with maximum z value
|
|
|
|
|
// -----------------+
|
|
|
|
|
static inline void HWR_ClearView(void)
|
|
|
|
|
{
|
|
|
|
|
// 3--2
|
|
|
|
|
// | /|
|
|
|
|
|
// |/ |
|
|
|
|
|
// 0--1
|
|
|
|
|
|
|
|
|
|
/// \bug faB - enable depth mask, disable color mask
|
|
|
|
|
|
|
|
|
|
HWD.pfnGClipRect((INT32)gr_viewwindowx,
|
|
|
|
|
(INT32)gr_viewwindowy,
|
|
|
|
|
(INT32)(gr_viewwindowx + gr_viewwidth),
|
|
|
|
|
(INT32)(gr_viewwindowy + gr_viewheight),
|
2018-03-06 03:48:15 +00:00
|
|
|
|
ZCLIP_PLANE);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
HWD.pfnClearBuffer(false, true, 0);
|
|
|
|
|
|
|
|
|
|
//disable clip window - set to full size
|
|
|
|
|
// rem by Hurdler
|
|
|
|
|
// HWD.pfnGClipRect(0, 0, vid.width, vid.height);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// -----------------+
|
|
|
|
|
// 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 (splitscreen)
|
|
|
|
|
gr_viewheight /= 2;
|
|
|
|
|
|
|
|
|
|
gr_centerx = gr_viewwidth / 2;
|
|
|
|
|
gr_basecentery = gr_viewheight / 2; //note: this is (gr_centerx * gr_viewheight / gr_viewwidth)
|
|
|
|
|
|
|
|
|
|
gr_viewwindowx = (vid.width - gr_viewwidth) / 2;
|
|
|
|
|
gr_windowcenterx = (float)(vid.width / 2);
|
2018-12-15 00:33:40 +00:00
|
|
|
|
if (fabsf(gr_viewwidth - vid.width) < 1.0E-36f)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
|
|
|
|
gr_baseviewwindowy = 0;
|
|
|
|
|
gr_basewindowcentery = gr_viewheight / 2; // window top left corner at 0,0
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
gr_baseviewwindowy = (vid.height-gr_viewheight) / 2;
|
|
|
|
|
gr_basewindowcentery = (float)(vid.height / 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gr_pspritexscale = gr_viewwidth / BASEVIDWIDTH;
|
|
|
|
|
gr_pspriteyscale = ((vid.height*gr_pspritexscale*BASEVIDWIDTH)/BASEVIDHEIGHT)/vid.width;
|
2018-03-07 05:19:06 +00:00
|
|
|
|
|
|
|
|
|
HWD.pfnFlushScreenTextures();
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-01-23 22:44:46 +00:00
|
|
|
|
// Set view aiming, for the sky dome, the skybox,
|
|
|
|
|
// and the normal view, all with a single function.
|
2020-02-08 20:42:26 +00:00
|
|
|
|
static void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean skybox)
|
2020-01-23 22:44:46 +00:00
|
|
|
|
{
|
2020-02-08 20:42:26 +00:00
|
|
|
|
// 1 = always on
|
|
|
|
|
// 2 = chasecam only
|
2020-02-08 21:08:56 +00:00
|
|
|
|
if (cv_grshearing.value == 1 || (cv_grshearing.value == 2 && R_IsViewpointThirdPerson(player, skybox)))
|
2020-01-23 22:44:46 +00:00
|
|
|
|
{
|
|
|
|
|
fixed_t fixedaiming = AIMINGTODY(aimingangle);
|
|
|
|
|
trans->viewaiming = FIXED_TO_FLOAT(fixedaiming);
|
|
|
|
|
trans->shearing = true;
|
|
|
|
|
gr_aimingangle = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
trans->shearing = false;
|
|
|
|
|
gr_aimingangle = aimingangle;
|
|
|
|
|
}
|
2020-02-08 20:42:26 +00:00
|
|
|
|
|
2020-01-23 22:44:46 +00:00
|
|
|
|
trans->anglex = (float)(gr_aimingangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-20 20:13:15 +00:00
|
|
|
|
// ==========================================================================
|
|
|
|
|
// Same as rendering the player view, but from the skybox object
|
|
|
|
|
// ==========================================================================
|
|
|
|
|
void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player)
|
|
|
|
|
{
|
2019-12-31 17:21:46 +00:00
|
|
|
|
const float fpov = FIXED_TO_FLOAT(cv_fov.value+player->fovadd);
|
2014-08-27 03:56:30 +00:00
|
|
|
|
postimg_t *type;
|
|
|
|
|
|
|
|
|
|
if (splitscreen && player == &players[secondarydisplayplayer])
|
|
|
|
|
type = &postimgtype2;
|
|
|
|
|
else
|
|
|
|
|
type = &postimgtype;
|
2014-03-20 20:13:15 +00:00
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
// do we really need to save player (is it not the same)?
|
|
|
|
|
player_t *saved_player = stplyr;
|
|
|
|
|
stplyr = player;
|
|
|
|
|
ST_doPaletteStuff();
|
|
|
|
|
stplyr = saved_player;
|
|
|
|
|
#ifdef ALAM_LIGHTING
|
|
|
|
|
HWR_SetLights(viewnumber);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// note: sets viewangle, viewx, viewy, viewz
|
|
|
|
|
R_SkyboxFrame(player);
|
|
|
|
|
|
|
|
|
|
// copy view cam position for local use
|
|
|
|
|
dup_viewx = viewx;
|
|
|
|
|
dup_viewy = viewy;
|
|
|
|
|
dup_viewz = viewz;
|
|
|
|
|
dup_viewangle = viewangle;
|
|
|
|
|
|
|
|
|
|
// set window position
|
|
|
|
|
gr_centery = gr_basecentery;
|
|
|
|
|
gr_viewwindowy = gr_baseviewwindowy;
|
|
|
|
|
gr_windowcentery = gr_basewindowcentery;
|
|
|
|
|
if (splitscreen && viewnumber == 1)
|
|
|
|
|
{
|
|
|
|
|
gr_viewwindowy += (vid.height/2);
|
|
|
|
|
gr_windowcentery += (vid.height/2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// check for new console commands.
|
|
|
|
|
NetUpdate();
|
|
|
|
|
|
|
|
|
|
gr_viewx = FIXED_TO_FLOAT(dup_viewx);
|
|
|
|
|
gr_viewy = FIXED_TO_FLOAT(dup_viewy);
|
|
|
|
|
gr_viewz = FIXED_TO_FLOAT(dup_viewz);
|
|
|
|
|
gr_viewsin = FIXED_TO_FLOAT(viewsin);
|
|
|
|
|
gr_viewcos = FIXED_TO_FLOAT(viewcos);
|
|
|
|
|
|
|
|
|
|
//04/01/2000: Hurdler: added for T&L
|
|
|
|
|
// It should replace all other gr_viewxxx when finished
|
2019-12-08 02:55:28 +00:00
|
|
|
|
memset(&atransform, 0x00, sizeof(FTransform));
|
|
|
|
|
|
2020-02-08 20:42:26 +00:00
|
|
|
|
HWR_SetTransformAiming(&atransform, player, true);
|
2014-03-20 20:13:15 +00:00
|
|
|
|
atransform.angley = (float)(viewangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
|
2014-04-07 16:08:04 +00:00
|
|
|
|
|
2020-01-23 22:44:46 +00:00
|
|
|
|
gr_viewludsin = FIXED_TO_FLOAT(FINECOSINE(gr_aimingangle>>ANGLETOFINESHIFT));
|
|
|
|
|
gr_viewludcos = FIXED_TO_FLOAT(-FINESINE(gr_aimingangle>>ANGLETOFINESHIFT));
|
|
|
|
|
|
2014-08-27 03:56:30 +00:00
|
|
|
|
if (*type == postimg_flip)
|
2014-04-07 16:08:04 +00:00
|
|
|
|
atransform.flip = true;
|
|
|
|
|
else
|
|
|
|
|
atransform.flip = false;
|
|
|
|
|
|
2014-03-20 20:13:15 +00:00
|
|
|
|
atransform.x = gr_viewx; // FIXED_TO_FLOAT(viewx)
|
|
|
|
|
atransform.y = gr_viewy; // FIXED_TO_FLOAT(viewy)
|
|
|
|
|
atransform.z = gr_viewz; // FIXED_TO_FLOAT(viewz)
|
|
|
|
|
atransform.scalex = 1;
|
2018-03-22 01:10:53 +00:00
|
|
|
|
atransform.scaley = (float)vid.width/vid.height;
|
2014-03-20 20:13:15 +00:00
|
|
|
|
atransform.scalez = 1;
|
2019-12-25 19:22:01 +00:00
|
|
|
|
|
2014-03-20 20:13:15 +00:00
|
|
|
|
atransform.fovxangle = fpov; // Tails
|
|
|
|
|
atransform.fovyangle = fpov; // Tails
|
2020-01-18 03:55:16 +00:00
|
|
|
|
if (player->viewrollangle != 0)
|
|
|
|
|
{
|
|
|
|
|
fixed_t rol = AngleFixed(player->viewrollangle);
|
|
|
|
|
atransform.rollangle = FIXED_TO_FLOAT(rol);
|
|
|
|
|
atransform.roll = true;
|
|
|
|
|
}
|
2014-03-20 20:13:15 +00:00
|
|
|
|
atransform.splitscreen = splitscreen;
|
|
|
|
|
|
|
|
|
|
gr_fovlud = (float)(1.0l/tan((double)(fpov*M_PIl/360l)));
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
|
|
|
HWR_ClearView();
|
|
|
|
|
|
|
|
|
|
if (drawsky)
|
2019-09-18 02:38:04 +00:00
|
|
|
|
HWR_DrawSkyBackground(player);
|
2014-03-20 20:13:15 +00:00
|
|
|
|
|
|
|
|
|
//Hurdler: it doesn't work in splitscreen mode
|
|
|
|
|
drawsky = splitscreen;
|
|
|
|
|
|
|
|
|
|
HWR_ClearSprites();
|
|
|
|
|
|
|
|
|
|
drawcount = 0;
|
2019-12-25 19:22:01 +00:00
|
|
|
|
|
2017-01-10 18:01:03 +00:00
|
|
|
|
#ifdef NEWCLIP
|
|
|
|
|
if (rendermode == render_opengl)
|
|
|
|
|
{
|
2019-12-25 19:22:01 +00:00
|
|
|
|
angle_t a1 = gld_FrustumAngle(gr_aimingangle);
|
2017-01-10 18:01:03 +00:00
|
|
|
|
gld_clipper_Clear();
|
|
|
|
|
gld_clipper_SafeAddClipRange(viewangle + a1, viewangle - a1);
|
|
|
|
|
#ifdef HAVE_SPHEREFRUSTRUM
|
|
|
|
|
gld_FrustrumSetup();
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
#else
|
2014-03-20 20:13:15 +00:00
|
|
|
|
HWR_ClearClipSegs();
|
2017-01-10 18:01:03 +00:00
|
|
|
|
#endif
|
2014-03-20 20:13:15 +00:00
|
|
|
|
|
|
|
|
|
//04/01/2000: Hurdler: added for T&L
|
|
|
|
|
// Actually it only works on Walls and Planes
|
|
|
|
|
HWD.pfnSetTransform(&atransform);
|
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
// Reset the shader state.
|
|
|
|
|
HWD.pfnSetSpecialState(HWD_SET_SHADERS, cv_grshaders.value);
|
|
|
|
|
HWD.pfnSetShader(0);
|
|
|
|
|
|
2014-03-20 20:13:15 +00:00
|
|
|
|
validcount++;
|
|
|
|
|
|
2020-06-07 18:20:52 +00:00
|
|
|
|
if (cv_grbatching.value)
|
|
|
|
|
HWR_StartBatching();
|
|
|
|
|
|
2014-03-20 20:13:15 +00:00
|
|
|
|
HWR_RenderBSPNode((INT32)numnodes-1);
|
|
|
|
|
|
2017-01-10 18:01:03 +00:00
|
|
|
|
#ifndef NEWCLIP
|
2014-03-20 20:13:15 +00:00
|
|
|
|
// Make a viewangle int so we can render things based on mouselook
|
|
|
|
|
if (player == &players[consoleplayer])
|
|
|
|
|
viewangle = localaiming;
|
|
|
|
|
else if (splitscreen && player == &players[secondarydisplayplayer])
|
|
|
|
|
viewangle = localaiming2;
|
|
|
|
|
|
|
|
|
|
// Handle stuff when you are looking farther up or down.
|
2020-01-23 22:44:46 +00:00
|
|
|
|
if ((gr_aimingangle || cv_fov.value+player->fovadd > 90*FRACUNIT))
|
2014-03-20 20:13:15 +00:00
|
|
|
|
{
|
|
|
|
|
dup_viewangle += ANGLE_90;
|
|
|
|
|
HWR_ClearClipSegs();
|
|
|
|
|
HWR_RenderBSPNode((INT32)numnodes-1); //left
|
|
|
|
|
|
|
|
|
|
dup_viewangle += ANGLE_90;
|
2020-01-23 22:44:46 +00:00
|
|
|
|
if (((INT32)gr_aimingangle > ANGLE_45 || (INT32)gr_aimingangle<-ANGLE_45))
|
2014-03-20 20:13:15 +00:00
|
|
|
|
{
|
|
|
|
|
HWR_ClearClipSegs();
|
|
|
|
|
HWR_RenderBSPNode((INT32)numnodes-1); //back
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dup_viewangle += ANGLE_90;
|
|
|
|
|
HWR_ClearClipSegs();
|
|
|
|
|
HWR_RenderBSPNode((INT32)numnodes-1); //right
|
|
|
|
|
|
|
|
|
|
dup_viewangle += ANGLE_90;
|
|
|
|
|
}
|
2017-01-10 18:01:03 +00:00
|
|
|
|
#endif
|
2014-03-20 20:13:15 +00:00
|
|
|
|
|
2020-06-07 18:20:52 +00:00
|
|
|
|
if (cv_grbatching.value)
|
|
|
|
|
HWR_RenderBatches();
|
|
|
|
|
|
2014-03-20 20:13:15 +00:00
|
|
|
|
// Check for new console commands.
|
|
|
|
|
NetUpdate();
|
|
|
|
|
|
|
|
|
|
#ifdef ALAM_LIGHTING
|
|
|
|
|
//14/11/99: Hurdler: moved here because it doesn't work with
|
|
|
|
|
// subsector, see other comments;
|
|
|
|
|
HWR_ResetLights();
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Draw MD2 and sprites
|
|
|
|
|
HWR_SortVisSprites();
|
|
|
|
|
HWR_DrawSprites();
|
2019-12-25 19:22:01 +00:00
|
|
|
|
|
2014-03-20 20:13:15 +00:00
|
|
|
|
#ifdef NEWCORONAS
|
|
|
|
|
//Hurdler: they must be drawn before translucent planes, what about gl fog?
|
|
|
|
|
HWR_DrawCoronas();
|
|
|
|
|
#endif
|
|
|
|
|
|
2014-10-27 20:57:45 +00:00
|
|
|
|
if (numplanes || numpolyplanes || numwalls) //Hurdler: render 3D water and transparent walls after everything
|
2014-03-20 20:13:15 +00:00
|
|
|
|
{
|
|
|
|
|
HWR_CreateDrawNodes();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HWD.pfnSetTransform(NULL);
|
2019-12-25 19:22:01 +00:00
|
|
|
|
HWD.pfnUnSetShader();
|
2014-03-20 20:13:15 +00:00
|
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
// ==========================================================================
|
|
|
|
|
//
|
|
|
|
|
// ==========================================================================
|
|
|
|
|
void HWR_RenderPlayerView(INT32 viewnumber, player_t *player)
|
|
|
|
|
{
|
2019-12-31 17:21:46 +00:00
|
|
|
|
const float fpov = FIXED_TO_FLOAT(cv_fov.value+player->fovadd);
|
2014-08-27 03:56:30 +00:00
|
|
|
|
postimg_t *type;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2014-03-20 20:13:15 +00:00
|
|
|
|
const boolean skybox = (skyboxmo[0] && cv_skybox.value); // True if there's a skybox object and skyboxes are on
|
|
|
|
|
|
2014-03-22 17:17:40 +00:00
|
|
|
|
FRGBAFloat ClearColor;
|
|
|
|
|
|
2014-08-27 03:56:30 +00:00
|
|
|
|
if (splitscreen && player == &players[secondarydisplayplayer])
|
|
|
|
|
type = &postimgtype2;
|
|
|
|
|
else
|
|
|
|
|
type = &postimgtype;
|
|
|
|
|
|
2014-03-22 17:17:40 +00:00
|
|
|
|
ClearColor.red = 0.0f;
|
|
|
|
|
ClearColor.green = 0.0f;
|
|
|
|
|
ClearColor.blue = 0.0f;
|
|
|
|
|
ClearColor.alpha = 1.0f;
|
|
|
|
|
|
2020-01-24 00:25:54 +00:00
|
|
|
|
if (cv_grshaders.value)
|
|
|
|
|
HWD.pfnSetShaderInfo(HWD_SHADERINFO_LEVELTIME, (INT32)leveltime); // The water surface shader needs the leveltime.
|
|
|
|
|
|
2014-03-30 23:07:55 +00:00
|
|
|
|
if (viewnumber == 0) // Only do it if it's the first screen being rendered
|
|
|
|
|
HWD.pfnClearBuffer(true, false, &ClearColor); // Clear the Color Buffer, stops HOMs. Also seems to fix the skybox issue on Intel GPUs.
|
2014-03-22 17:17:40 +00:00
|
|
|
|
|
2014-03-20 20:13:15 +00:00
|
|
|
|
if (skybox && drawsky) // If there's a skybox and we should be drawing the sky, draw the skybox
|
|
|
|
|
HWR_RenderSkyboxView(viewnumber, player); // This is drawn before everything else so it is placed behind
|
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
|
|
|
|
// do we really need to save player (is it not the same)?
|
|
|
|
|
player_t *saved_player = stplyr;
|
|
|
|
|
stplyr = player;
|
|
|
|
|
ST_doPaletteStuff();
|
|
|
|
|
stplyr = saved_player;
|
|
|
|
|
#ifdef ALAM_LIGHTING
|
|
|
|
|
HWR_SetLights(viewnumber);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// note: sets viewangle, viewx, viewy, viewz
|
2019-06-01 19:26:25 +00:00
|
|
|
|
R_SetupFrame(player);
|
2018-12-28 04:05:06 +00:00
|
|
|
|
framecount++; // timedemo
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
// copy view cam position for local use
|
|
|
|
|
dup_viewx = viewx;
|
|
|
|
|
dup_viewy = viewy;
|
|
|
|
|
dup_viewz = viewz;
|
|
|
|
|
dup_viewangle = viewangle;
|
|
|
|
|
|
|
|
|
|
// set window position
|
|
|
|
|
gr_centery = gr_basecentery;
|
|
|
|
|
gr_viewwindowy = gr_baseviewwindowy;
|
|
|
|
|
gr_windowcentery = gr_basewindowcentery;
|
|
|
|
|
if (splitscreen && viewnumber == 1)
|
|
|
|
|
{
|
|
|
|
|
gr_viewwindowy += (vid.height/2);
|
|
|
|
|
gr_windowcentery += (vid.height/2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// check for new console commands.
|
|
|
|
|
NetUpdate();
|
|
|
|
|
|
|
|
|
|
gr_viewx = FIXED_TO_FLOAT(dup_viewx);
|
|
|
|
|
gr_viewy = FIXED_TO_FLOAT(dup_viewy);
|
|
|
|
|
gr_viewz = FIXED_TO_FLOAT(dup_viewz);
|
|
|
|
|
gr_viewsin = FIXED_TO_FLOAT(viewsin);
|
|
|
|
|
gr_viewcos = FIXED_TO_FLOAT(viewcos);
|
|
|
|
|
|
|
|
|
|
//04/01/2000: Hurdler: added for T&L
|
|
|
|
|
// It should replace all other gr_viewxxx when finished
|
2019-12-08 02:55:28 +00:00
|
|
|
|
memset(&atransform, 0x00, sizeof(FTransform));
|
|
|
|
|
|
2020-02-08 20:42:26 +00:00
|
|
|
|
HWR_SetTransformAiming(&atransform, player, false);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
atransform.angley = (float)(viewangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
|
2014-04-07 16:08:04 +00:00
|
|
|
|
|
2020-01-23 22:44:46 +00:00
|
|
|
|
gr_viewludsin = FIXED_TO_FLOAT(FINECOSINE(gr_aimingangle>>ANGLETOFINESHIFT));
|
|
|
|
|
gr_viewludcos = FIXED_TO_FLOAT(-FINESINE(gr_aimingangle>>ANGLETOFINESHIFT));
|
|
|
|
|
|
2014-08-27 03:56:30 +00:00
|
|
|
|
if (*type == postimg_flip)
|
2014-04-07 16:08:04 +00:00
|
|
|
|
atransform.flip = true;
|
|
|
|
|
else
|
|
|
|
|
atransform.flip = false;
|
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
atransform.x = gr_viewx; // FIXED_TO_FLOAT(viewx)
|
|
|
|
|
atransform.y = gr_viewy; // FIXED_TO_FLOAT(viewy)
|
|
|
|
|
atransform.z = gr_viewz; // FIXED_TO_FLOAT(viewz)
|
|
|
|
|
atransform.scalex = 1;
|
2018-03-22 01:10:53 +00:00
|
|
|
|
atransform.scaley = (float)vid.width/vid.height;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
atransform.scalez = 1;
|
2019-12-25 19:22:01 +00:00
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
atransform.fovxangle = fpov; // Tails
|
|
|
|
|
atransform.fovyangle = fpov; // Tails
|
2020-01-18 03:55:16 +00:00
|
|
|
|
if (player->viewrollangle != 0)
|
|
|
|
|
{
|
|
|
|
|
fixed_t rol = AngleFixed(player->viewrollangle);
|
|
|
|
|
atransform.rollangle = FIXED_TO_FLOAT(rol);
|
|
|
|
|
atransform.roll = true;
|
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
atransform.splitscreen = splitscreen;
|
|
|
|
|
|
|
|
|
|
gr_fovlud = (float)(1.0l/tan((double)(fpov*M_PIl/360l)));
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------
|
2014-03-22 17:17:40 +00:00
|
|
|
|
HWR_ClearView(); // Clears the depth buffer and resets the view I believe
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2014-03-20 20:13:15 +00:00
|
|
|
|
if (!skybox && drawsky) // Don't draw the regular sky if there's a skybox
|
2019-09-18 02:38:04 +00:00
|
|
|
|
HWR_DrawSkyBackground(player);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
//Hurdler: it doesn't work in splitscreen mode
|
|
|
|
|
drawsky = splitscreen;
|
|
|
|
|
|
|
|
|
|
HWR_ClearSprites();
|
|
|
|
|
|
|
|
|
|
drawcount = 0;
|
2019-12-25 19:22:01 +00:00
|
|
|
|
|
2017-01-10 18:01:03 +00:00
|
|
|
|
#ifdef NEWCLIP
|
|
|
|
|
if (rendermode == render_opengl)
|
|
|
|
|
{
|
2019-12-25 19:22:01 +00:00
|
|
|
|
angle_t a1 = gld_FrustumAngle(gr_aimingangle);
|
2017-01-10 18:01:03 +00:00
|
|
|
|
gld_clipper_Clear();
|
|
|
|
|
gld_clipper_SafeAddClipRange(viewangle + a1, viewangle - a1);
|
|
|
|
|
#ifdef HAVE_SPHEREFRUSTRUM
|
|
|
|
|
gld_FrustrumSetup();
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
#else
|
2014-03-15 16:59:03 +00:00
|
|
|
|
HWR_ClearClipSegs();
|
2017-01-10 18:01:03 +00:00
|
|
|
|
#endif
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
//04/01/2000: Hurdler: added for T&L
|
|
|
|
|
// Actually it only works on Walls and Planes
|
|
|
|
|
HWD.pfnSetTransform(&atransform);
|
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
// Reset the shader state.
|
|
|
|
|
HWD.pfnSetSpecialState(HWD_SET_SHADERS, cv_grshaders.value);
|
|
|
|
|
HWD.pfnSetShader(0);
|
|
|
|
|
|
2020-04-18 22:25:28 +00:00
|
|
|
|
rs_numbspcalls = 0;
|
|
|
|
|
rs_numpolyobjects = 0;
|
|
|
|
|
rs_bsptime = I_GetTimeMicros();
|
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
validcount++;
|
|
|
|
|
|
2020-06-07 18:20:52 +00:00
|
|
|
|
if (cv_grbatching.value)
|
|
|
|
|
HWR_StartBatching();
|
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
HWR_RenderBSPNode((INT32)numnodes-1);
|
|
|
|
|
|
2017-01-10 18:01:03 +00:00
|
|
|
|
#ifndef NEWCLIP
|
2014-03-15 16:59:03 +00:00
|
|
|
|
// Make a viewangle int so we can render things based on mouselook
|
|
|
|
|
if (player == &players[consoleplayer])
|
|
|
|
|
viewangle = localaiming;
|
|
|
|
|
else if (splitscreen && player == &players[secondarydisplayplayer])
|
|
|
|
|
viewangle = localaiming2;
|
|
|
|
|
|
|
|
|
|
// Handle stuff when you are looking farther up or down.
|
2020-01-23 22:44:46 +00:00
|
|
|
|
if ((gr_aimingangle || cv_fov.value+player->fovadd > 90*FRACUNIT))
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
|
|
|
|
dup_viewangle += ANGLE_90;
|
|
|
|
|
HWR_ClearClipSegs();
|
|
|
|
|
HWR_RenderBSPNode((INT32)numnodes-1); //left
|
|
|
|
|
|
|
|
|
|
dup_viewangle += ANGLE_90;
|
2020-01-23 22:44:46 +00:00
|
|
|
|
if (((INT32)gr_aimingangle > ANGLE_45 || (INT32)gr_aimingangle<-ANGLE_45))
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
|
|
|
|
HWR_ClearClipSegs();
|
|
|
|
|
HWR_RenderBSPNode((INT32)numnodes-1); //back
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dup_viewangle += ANGLE_90;
|
|
|
|
|
HWR_ClearClipSegs();
|
|
|
|
|
HWR_RenderBSPNode((INT32)numnodes-1); //right
|
|
|
|
|
|
|
|
|
|
dup_viewangle += ANGLE_90;
|
|
|
|
|
}
|
2017-01-10 18:01:03 +00:00
|
|
|
|
#endif
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2020-04-18 22:25:28 +00:00
|
|
|
|
rs_bsptime = I_GetTimeMicros() - rs_bsptime;
|
|
|
|
|
|
2020-06-07 18:20:52 +00:00
|
|
|
|
if (cv_grbatching.value)
|
|
|
|
|
HWR_RenderBatches();
|
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
// Check for new console commands.
|
|
|
|
|
NetUpdate();
|
|
|
|
|
|
|
|
|
|
#ifdef ALAM_LIGHTING
|
|
|
|
|
//14/11/99: Hurdler: moved here because it doesn't work with
|
|
|
|
|
// subsector, see other comments;
|
|
|
|
|
HWR_ResetLights();
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Draw MD2 and sprites
|
2020-04-18 22:25:28 +00:00
|
|
|
|
rs_numsprites = gr_visspritecount;
|
2020-05-02 17:43:53 +00:00
|
|
|
|
rs_hw_spritesorttime = I_GetTimeMicros();
|
2014-03-15 16:59:03 +00:00
|
|
|
|
HWR_SortVisSprites();
|
2020-05-02 17:43:53 +00:00
|
|
|
|
rs_hw_spritesorttime = I_GetTimeMicros() - rs_hw_spritesorttime;
|
|
|
|
|
rs_hw_spritedrawtime = I_GetTimeMicros();
|
2014-03-15 16:59:03 +00:00
|
|
|
|
HWR_DrawSprites();
|
2020-05-02 17:43:53 +00:00
|
|
|
|
rs_hw_spritedrawtime = I_GetTimeMicros() - rs_hw_spritedrawtime;
|
2019-12-25 19:22:01 +00:00
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
#ifdef NEWCORONAS
|
|
|
|
|
//Hurdler: they must be drawn before translucent planes, what about gl fog?
|
|
|
|
|
HWR_DrawCoronas();
|
|
|
|
|
#endif
|
|
|
|
|
|
2020-04-18 22:25:28 +00:00
|
|
|
|
rs_numdrawnodes = 0;
|
2020-05-02 17:43:53 +00:00
|
|
|
|
rs_hw_nodesorttime = 0;
|
|
|
|
|
rs_hw_nodedrawtime = 0;
|
2014-10-27 20:57:45 +00:00
|
|
|
|
if (numplanes || numpolyplanes || numwalls) //Hurdler: render 3D water and transparent walls after everything
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
|
|
|
|
HWR_CreateDrawNodes();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HWD.pfnSetTransform(NULL);
|
2019-12-25 19:22:01 +00:00
|
|
|
|
HWD.pfnUnSetShader();
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ==========================================================================
|
|
|
|
|
// 3D ENGINE COMMANDS
|
|
|
|
|
// ==========================================================================
|
|
|
|
|
|
2019-12-12 20:30:19 +00:00
|
|
|
|
static CV_PossibleValue_t grmodelinterpolation_cons_t[] = {{0, "Off"}, {1, "Sometimes"}, {2, "Always"}, {0, NULL}};
|
2019-12-26 01:09:31 +00:00
|
|
|
|
static CV_PossibleValue_t grfakecontrast_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Smooth"}, {0, NULL}};
|
2020-02-08 20:42:26 +00:00
|
|
|
|
static CV_PossibleValue_t grshearing_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Third-person"}, {0, NULL}};
|
2019-12-12 20:30:19 +00:00
|
|
|
|
|
|
|
|
|
static void CV_grfiltermode_OnChange(void);
|
|
|
|
|
static void CV_granisotropic_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}};
|
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
consvar_t cv_grshaders = {"gr_shaders", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
2019-12-31 17:21:46 +00:00
|
|
|
|
consvar_t cv_fovchange = {"gr_fovchange", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
2019-12-12 20:30:19 +00:00
|
|
|
|
|
|
|
|
|
#ifdef ALAM_LIGHTING
|
|
|
|
|
consvar_t cv_grdynamiclighting = {"gr_dynamiclighting", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
|
|
|
|
consvar_t cv_grstaticlighting = {"gr_staticlighting", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
|
|
|
|
consvar_t cv_grcoronas = {"gr_coronas", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
2019-12-12 20:37:55 +00:00
|
|
|
|
consvar_t cv_grcoronasize = {"gr_coronasize", "1", CV_SAVE|CV_FLOAT, 0, NULL, 0, NULL, NULL, 0, 0, NULL};
|
2019-12-12 20:30:19 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
consvar_t cv_grmodels = {"gr_models", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
|
|
|
|
consvar_t cv_grmodelinterpolation = {"gr_modelinterpolation", "Sometimes", CV_SAVE, grmodelinterpolation_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
|
2020-01-24 01:02:18 +00:00
|
|
|
|
consvar_t cv_grmodellighting = {"gr_modellighting", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
2019-12-12 20:30:19 +00:00
|
|
|
|
|
2020-02-17 15:30:02 +00:00
|
|
|
|
consvar_t cv_grshearing = {"gr_shearing", "Off", CV_SAVE, grshearing_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
|
2019-12-13 00:52:59 +00:00
|
|
|
|
consvar_t cv_grspritebillboarding = {"gr_spritebillboarding", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
2019-12-12 20:30:19 +00:00
|
|
|
|
consvar_t cv_grskydome = {"gr_skydome", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
2019-12-26 01:09:31 +00:00
|
|
|
|
consvar_t cv_grfakecontrast = {"gr_fakecontrast", "Smooth", CV_SAVE, grfakecontrast_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
|
2020-01-16 21:45:49 +00:00
|
|
|
|
consvar_t cv_grslopecontrast = {"gr_slopecontrast", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
2019-12-12 20:30:19 +00:00
|
|
|
|
|
2019-12-12 20:37:55 +00:00
|
|
|
|
consvar_t cv_grfiltermode = {"gr_filtermode", "Nearest", CV_SAVE|CV_CALL, grfiltermode_cons_t,
|
2019-12-12 20:30:19 +00:00
|
|
|
|
CV_grfiltermode_OnChange, 0, NULL, NULL, 0, 0, NULL};
|
2019-12-12 21:28:05 +00:00
|
|
|
|
consvar_t cv_granisotropicmode = {"gr_anisotropicmode", "1", CV_CALL, granisotropicmode_cons_t,
|
2019-12-12 20:30:19 +00:00
|
|
|
|
CV_granisotropic_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};
|
|
|
|
|
|
2020-06-07 18:20:52 +00:00
|
|
|
|
consvar_t cv_grbatching = {"gr_batching", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
2019-12-12 20:30:19 +00:00
|
|
|
|
|
|
|
|
|
static void CV_grfiltermode_OnChange(void)
|
|
|
|
|
{
|
|
|
|
|
if (rendermode == render_opengl)
|
|
|
|
|
HWD.pfnSetSpecialState(HWD_SET_TEXTUREFILTERMODE, cv_grfiltermode.value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void CV_granisotropic_OnChange(void)
|
|
|
|
|
{
|
|
|
|
|
if (rendermode == render_opengl)
|
|
|
|
|
HWD.pfnSetSpecialState(HWD_SET_TEXTUREANISOTROPICMODE, cv_granisotropicmode.value);
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
//added by Hurdler: console varibale that are saved
|
|
|
|
|
void HWR_AddCommands(void)
|
|
|
|
|
{
|
2019-12-31 17:21:46 +00:00
|
|
|
|
CV_RegisterVar(&cv_fovchange);
|
2019-12-12 20:30:19 +00:00
|
|
|
|
|
|
|
|
|
#ifdef ALAM_LIGHTING
|
|
|
|
|
CV_RegisterVar(&cv_grstaticlighting);
|
|
|
|
|
CV_RegisterVar(&cv_grdynamiclighting);
|
|
|
|
|
CV_RegisterVar(&cv_grcoronasize);
|
|
|
|
|
CV_RegisterVar(&cv_grcoronas);
|
|
|
|
|
#endif
|
|
|
|
|
|
2019-12-12 20:48:29 +00:00
|
|
|
|
CV_RegisterVar(&cv_grmodellighting);
|
2019-12-12 20:30:19 +00:00
|
|
|
|
CV_RegisterVar(&cv_grmodelinterpolation);
|
|
|
|
|
CV_RegisterVar(&cv_grmodels);
|
2019-12-12 20:48:29 +00:00
|
|
|
|
|
2019-12-12 20:30:19 +00:00
|
|
|
|
CV_RegisterVar(&cv_grskydome);
|
|
|
|
|
CV_RegisterVar(&cv_grspritebillboarding);
|
2019-12-26 01:09:31 +00:00
|
|
|
|
CV_RegisterVar(&cv_grfakecontrast);
|
2019-12-25 19:22:01 +00:00
|
|
|
|
CV_RegisterVar(&cv_grshearing);
|
|
|
|
|
CV_RegisterVar(&cv_grshaders);
|
2019-12-12 20:30:19 +00:00
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
CV_RegisterVar(&cv_grfiltermode);
|
|
|
|
|
CV_RegisterVar(&cv_grcorrecttricks);
|
|
|
|
|
CV_RegisterVar(&cv_grsolvetjoin);
|
|
|
|
|
|
2020-04-18 22:25:28 +00:00
|
|
|
|
CV_RegisterVar(&cv_renderstats);
|
2020-06-07 18:20:52 +00:00
|
|
|
|
CV_RegisterVar(&cv_grbatching);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2017-01-10 18:01:03 +00:00
|
|
|
|
#ifndef NEWCLIP
|
2014-03-15 16:59:03 +00:00
|
|
|
|
CV_RegisterVar(&cv_grclipwalls);
|
2017-01-10 18:01:03 +00:00
|
|
|
|
#endif
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-12 21:28:05 +00:00
|
|
|
|
void HWR_AddSessionCommands(void)
|
|
|
|
|
{
|
2019-12-17 19:12:44 +00:00
|
|
|
|
static boolean alreadycalled = false;
|
|
|
|
|
if (alreadycalled)
|
|
|
|
|
return;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-12-12 21:28:05 +00:00
|
|
|
|
CV_RegisterVar(&cv_granisotropicmode);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-12-17 19:12:44 +00:00
|
|
|
|
alreadycalled = true;
|
2019-12-12 21:28:05 +00:00
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
// Setup the hardware renderer
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
void HWR_Startup(void)
|
|
|
|
|
{
|
|
|
|
|
static boolean startupdone = false;
|
|
|
|
|
|
|
|
|
|
// do this once
|
|
|
|
|
if (!startupdone)
|
|
|
|
|
{
|
2020-01-27 05:15:34 +00:00
|
|
|
|
INT32 i;
|
2019-11-05 13:28:19 +00:00
|
|
|
|
CONS_Printf("HWR_Startup()...\n");
|
2020-01-27 05:15:34 +00:00
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
HWR_InitPolyPool();
|
2019-12-12 21:28:05 +00:00
|
|
|
|
HWR_AddSessionCommands();
|
2014-03-15 16:59:03 +00:00
|
|
|
|
HWR_InitTextureCache();
|
2019-11-05 13:28:19 +00:00
|
|
|
|
HWR_InitModels();
|
2014-03-15 16:59:03 +00:00
|
|
|
|
#ifdef ALAM_LIGHTING
|
|
|
|
|
HWR_InitLight();
|
|
|
|
|
#endif
|
2020-01-27 05:15:34 +00:00
|
|
|
|
|
|
|
|
|
// read every custom shader
|
|
|
|
|
for (i = 0; i < numwadfiles; i++)
|
|
|
|
|
HWR_ReadShaders(i, (wadfiles[i]->type == RET_PK3));
|
2020-06-18 14:39:34 +00:00
|
|
|
|
if (!HWR_LoadShaders())
|
|
|
|
|
gr_shadersavailable = false;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rendermode == render_opengl)
|
2017-09-29 21:48:14 +00:00
|
|
|
|
textureformat = patchformat = GR_RGBA;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
startupdone = true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-17 19:12:44 +00:00
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
// Called after switching to the hardware renderer
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
void HWR_Switch(void)
|
|
|
|
|
{
|
|
|
|
|
// Set special states from CVARs
|
|
|
|
|
HWD.pfnSetSpecialState(HWD_SET_TEXTUREFILTERMODE, cv_grfiltermode.value);
|
|
|
|
|
HWD.pfnSetSpecialState(HWD_SET_TEXTUREANISOTROPICMODE, cv_granisotropicmode.value);
|
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
// Free resources allocated by the hardware renderer
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
void HWR_Shutdown(void)
|
|
|
|
|
{
|
|
|
|
|
CONS_Printf("HWR_Shutdown()\n");
|
|
|
|
|
HWR_FreeExtraSubsectors();
|
|
|
|
|
HWR_FreePolyPool();
|
|
|
|
|
HWR_FreeTextureCache();
|
2018-03-07 05:19:06 +00:00
|
|
|
|
HWD.pfnFlushScreenTextures();
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void transform(float *cx, float *cy, float *cz)
|
|
|
|
|
{
|
|
|
|
|
float tr_x,tr_y;
|
|
|
|
|
// translation
|
|
|
|
|
tr_x = *cx - gr_viewx;
|
|
|
|
|
tr_y = *cz - gr_viewy;
|
|
|
|
|
// *cy = *cy;
|
|
|
|
|
|
|
|
|
|
// rotation around vertical y axis
|
|
|
|
|
*cx = (tr_x * gr_viewsin) - (tr_y * gr_viewcos);
|
|
|
|
|
tr_x = (tr_x * gr_viewcos) + (tr_y * gr_viewsin);
|
|
|
|
|
|
|
|
|
|
//look up/down ----TOTAL SUCKS!!!--- do the 2 in one!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
|
|
|
tr_y = *cy - gr_viewz;
|
|
|
|
|
|
|
|
|
|
*cy = (tr_x * gr_viewludcos) + (tr_y * gr_viewludsin);
|
|
|
|
|
*cz = (tr_x * gr_viewludsin) - (tr_y * gr_viewludcos);
|
|
|
|
|
|
|
|
|
|
//scale y before frustum so that frustum can be scaled to screen height
|
|
|
|
|
*cy *= ORIGINAL_ASPECT * gr_fovlud;
|
|
|
|
|
*cx *= gr_fovlud;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
void HWR_AddTransparentWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, INT32 texnum, FBITFIELD blend, boolean fogwall, INT32 lightlevel, extracolormap_t *wallcolormap)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
|
|
|
|
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++;
|
|
|
|
|
}
|
2019-11-09 02:42:15 +00:00
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
void HWR_RenderWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend, boolean fogwall, INT32 lightlevel, extracolormap_t *wallcolormap)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2019-12-25 19:22:01 +00:00
|
|
|
|
FBITFIELD blendmode = blend;
|
|
|
|
|
UINT8 alpha = pSurf->PolyColor.s.alpha; // retain the alpha
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2020-06-07 18:20:52 +00:00
|
|
|
|
int shader;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
// Lighting is done here instead so that fog isn't drawn incorrectly on transparent walls after sorting
|
|
|
|
|
HWR_Lighting(pSurf, lightlevel, wallcolormap);
|
2019-11-09 02:42:15 +00:00
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
pSurf->PolyColor.s.alpha = alpha; // put the alpha back after lighting
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2020-06-07 18:20:52 +00:00
|
|
|
|
shader = 2; // wall shader
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
if (blend & PF_Environment)
|
|
|
|
|
blendmode |= PF_Occlude; // PF_Occlude must be used for solid objects
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
if (fogwall)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2019-12-25 19:22:01 +00:00
|
|
|
|
blendmode |= PF_Fog;
|
2020-06-07 18:20:52 +00:00
|
|
|
|
shader = 6; // fog shader
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
blendmode |= PF_Modulated; // No PF_Occlude means overlapping (incorrect) transparency
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2020-06-07 18:20:52 +00:00
|
|
|
|
HWR_ProcessPolygon(pSurf, wallVerts, 4, blendmode, shader, false);
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
#ifdef WALLSPLATS
|
|
|
|
|
if (gr_curline->linedef->splats && cv_splats.value)
|
|
|
|
|
HWR_DrawSegsSplats(pSurf);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
INT32 HWR_GetTextureUsed(void)
|
|
|
|
|
{
|
|
|
|
|
return HWD.pfnGetTextureUsed();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void HWR_DoPostProcessor(player_t *player)
|
|
|
|
|
{
|
2014-08-27 03:56:30 +00:00
|
|
|
|
postimg_t *type;
|
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
HWD.pfnUnSetShader();
|
|
|
|
|
|
2014-08-27 03:56:30 +00:00
|
|
|
|
if (splitscreen && player == &players[secondarydisplayplayer])
|
|
|
|
|
type = &postimgtype2;
|
|
|
|
|
else
|
|
|
|
|
type = &postimgtype;
|
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
// Armageddon Blast Flash!
|
|
|
|
|
// Could this even be considered postprocessor?
|
|
|
|
|
if (player->flashcount)
|
|
|
|
|
{
|
|
|
|
|
FOutVector v[4];
|
|
|
|
|
FSurfaceInfo Surf;
|
|
|
|
|
|
2014-03-23 00:04:35 +00:00
|
|
|
|
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)
|
|
|
|
|
{
|
2019-12-25 19:22:01 +00:00
|
|
|
|
Surf.PolyColor.s.red = 0xff;
|
|
|
|
|
Surf.PolyColor.s.green = Surf.PolyColor.s.blue = 0x7F; // The nuke palette is kind of pink-ish
|
2014-03-23 00:04:35 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
2019-12-25 19:22:01 +00:00
|
|
|
|
Surf.PolyColor.s.red = Surf.PolyColor.s.green = Surf.PolyColor.s.blue = 0xff;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
Surf.PolyColor.s.alpha = 0xc0; // match software mode
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
|
|
|
|
HWD.pfnDrawPolygon(&Surf, v, 4, PF_Modulated|PF_Additive|PF_NoTexture|PF_NoDepthTest|PF_Clip|PF_NoZClip);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Capture the screen for intermission and screen waving
|
|
|
|
|
if(gamestate != GS_INTERMISSION)
|
|
|
|
|
HWD.pfnMakeScreenTexture();
|
|
|
|
|
|
|
|
|
|
if (splitscreen) // Not supported in splitscreen - someone want to add support?
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// Drunken vision! WooOOooo~
|
2014-08-27 03:56:30 +00:00
|
|
|
|
if (*type == postimg_water || *type == postimg_heat)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
|
|
|
|
// 10 by 10 grid. 2 coordinates (xy)
|
|
|
|
|
float v[SCREENVERTS][SCREENVERTS][2];
|
|
|
|
|
static double disStart = 0;
|
|
|
|
|
UINT8 x, y;
|
|
|
|
|
INT32 WAVELENGTH;
|
|
|
|
|
INT32 AMPLITUDE;
|
|
|
|
|
INT32 FREQUENCY;
|
|
|
|
|
|
|
|
|
|
// Modifies the wave.
|
2014-08-27 03:56:30 +00:00
|
|
|
|
if (*type == postimg_water)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
|
|
|
|
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);
|
2020-01-24 00:25:54 +00:00
|
|
|
|
if (!(paused || P_AutoPause()))
|
|
|
|
|
disStart += 1;
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2014-04-07 16:08:04 +00:00
|
|
|
|
// Capture the screen again for screen waving on the intermission
|
|
|
|
|
if(gamestate != GS_INTERMISSION)
|
|
|
|
|
HWD.pfnMakeScreenTexture();
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
2014-04-07 16:08:04 +00:00
|
|
|
|
// Flipping of the screen isn't done here anymore
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void HWR_StartScreenWipe(void)
|
|
|
|
|
{
|
|
|
|
|
//CONS_Debug(DBG_RENDER, "In HWR_StartScreenWipe()\n");
|
|
|
|
|
HWD.pfnStartScreenWipe();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void HWR_EndScreenWipe(void)
|
|
|
|
|
{
|
|
|
|
|
//CONS_Debug(DBG_RENDER, "In HWR_EndScreenWipe()\n");
|
|
|
|
|
HWD.pfnEndScreenWipe();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void HWR_DrawIntermissionBG(void)
|
|
|
|
|
{
|
|
|
|
|
HWD.pfnDrawIntermissionBG();
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-05 15:10:42 +00:00
|
|
|
|
//
|
|
|
|
|
// hwr mode wipes
|
|
|
|
|
//
|
|
|
|
|
static lumpnum_t wipelumpnum;
|
|
|
|
|
|
2019-11-15 22:40:58 +00:00
|
|
|
|
// puts wipe lumpname in wipename[9]
|
2019-11-05 15:31:50 +00:00
|
|
|
|
static boolean HWR_WipeCheck(UINT8 wipenum, UINT8 scrnnum)
|
2014-03-15 16:59:03 +00:00
|
|
|
|
{
|
2019-11-15 22:40:58 +00:00
|
|
|
|
static char lumpname[9] = "FADEmmss";
|
2014-09-04 00:35:29 +00:00
|
|
|
|
size_t lsize;
|
|
|
|
|
|
2019-11-05 15:10:42 +00:00
|
|
|
|
// not a valid wipe number
|
|
|
|
|
if (wipenum > 99 || scrnnum > 99)
|
|
|
|
|
return false; // shouldn't end up here really, the loop should've stopped running beforehand
|
2014-09-04 00:35:29 +00:00
|
|
|
|
|
2019-11-05 15:10:42 +00:00
|
|
|
|
// puts the numbers into the wipename
|
2019-11-15 22:40:58 +00:00
|
|
|
|
lumpname[4] = '0'+(wipenum/10);
|
|
|
|
|
lumpname[5] = '0'+(wipenum%10);
|
|
|
|
|
lumpname[6] = '0'+(scrnnum/10);
|
|
|
|
|
lumpname[7] = '0'+(scrnnum%10);
|
2019-11-15 22:09:02 +00:00
|
|
|
|
wipelumpnum = W_CheckNumForName(lumpname);
|
2014-09-04 00:35:29 +00:00
|
|
|
|
|
2019-11-05 15:10:42 +00:00
|
|
|
|
// again, shouldn't be here really
|
|
|
|
|
if (wipelumpnum == LUMPERROR)
|
|
|
|
|
return false;
|
2014-09-04 00:35:29 +00:00
|
|
|
|
|
2019-11-05 15:10:42 +00:00
|
|
|
|
lsize = W_LumpLength(wipelumpnum);
|
2014-09-04 00:35:29 +00:00
|
|
|
|
if (!(lsize == 256000 || lsize == 64000 || lsize == 16000 || lsize == 4000))
|
|
|
|
|
{
|
2019-11-15 22:09:02 +00:00
|
|
|
|
CONS_Alert(CONS_WARNING, "Fade mask lump %s of incorrect size, ignored\n", lumpname);
|
2019-11-05 15:10:42 +00:00
|
|
|
|
return false; // again, shouldn't get here if it is a bad size
|
2014-09-04 00:35:29 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-11-05 15:10:42 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
2014-03-15 16:59:03 +00:00
|
|
|
|
|
2019-11-05 15:10:42 +00:00
|
|
|
|
void HWR_DoWipe(UINT8 wipenum, UINT8 scrnnum)
|
|
|
|
|
{
|
2019-11-05 15:31:50 +00:00
|
|
|
|
if (!HWR_WipeCheck(wipenum, scrnnum))
|
2019-11-05 15:10:42 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
HWR_GetFadeMask(wipelumpnum);
|
2018-12-27 20:23:33 +00:00
|
|
|
|
HWD.pfnDoScreenWipe();
|
2014-03-15 16:59:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-11-05 15:10:42 +00:00
|
|
|
|
void HWR_DoTintedWipe(UINT8 wipenum, UINT8 scrnnum)
|
2019-09-10 02:31:48 +00:00
|
|
|
|
{
|
2019-11-05 15:31:50 +00:00
|
|
|
|
// It does the same thing
|
|
|
|
|
HWR_DoWipe(wipenum, scrnnum);
|
2019-11-05 15:10:42 +00:00
|
|
|
|
}
|
2019-10-29 02:14:00 +00:00
|
|
|
|
|
2014-11-14 00:06:38 +00:00
|
|
|
|
void HWR_MakeScreenFinalTexture(void)
|
|
|
|
|
{
|
|
|
|
|
HWD.pfnMakeScreenFinalTexture();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void HWR_DrawScreenFinalTexture(int width, int height)
|
|
|
|
|
{
|
|
|
|
|
HWD.pfnDrawScreenFinalTexture(width, height);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-25 19:22:01 +00:00
|
|
|
|
// 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;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-18 14:39:34 +00:00
|
|
|
|
boolean HWR_LoadShaders(void)
|
2020-01-27 05:15:34 +00:00
|
|
|
|
{
|
2020-06-18 14:39:34 +00:00
|
|
|
|
return HWD.pfnInitCustomShaders();
|
2020-01-27 05:15:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void HWR_ReadShaders(UINT16 wadnum, boolean PK3)
|
2019-12-25 19:22:01 +00:00
|
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
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)
|
|
|
|
|
{
|
2020-01-27 05:15:34 +00:00
|
|
|
|
CONS_Alert(CONS_WARNING, "HWR_ReadShaders: Missing shader type (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum);
|
2019-12-25 19:22:01 +00:00
|
|
|
|
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)
|
|
|
|
|
{
|
2020-01-27 05:15:34 +00:00
|
|
|
|
CONS_Alert(CONS_WARNING, "HWR_ReadShaders: Missing shader target (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum);
|
2019-12-25 19:22:01 +00:00
|
|
|
|
stoken = strtok(NULL, "\r\n"); // skip end of line
|
|
|
|
|
goto skip_field;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!shadertype)
|
|
|
|
|
{
|
2020-01-27 05:15:34 +00:00
|
|
|
|
CONS_Alert(CONS_ERROR, "HWR_ReadShaders: Missing shader type (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum);
|
2019-12-25 19:22:01 +00:00
|
|
|
|
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)
|
|
|
|
|
{
|
2020-01-27 05:15:34 +00:00
|
|
|
|
CONS_Alert(CONS_ERROR, "HWR_ReadShaders: Missing shader source %s (file %s, line %d)\n", shader_lumpname, wadfiles[wadnum]->filename, linenum);
|
2019-12-25 19:22:01 +00:00
|
|
|
|
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++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Z_Free(line);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-15 16:59:03 +00:00
|
|
|
|
#endif // HWRENDER
|