Isometric Mode and Robin (#2618)
* Feature-complete isometric mode fork. * Dithered transparency condition tweaks. * Dithered transparency for non-corpse monsters only (and missiles). * SpectatorCamera vertical shift. * Including math.h in hw_sprites.cpp to keep visual studio happy (it couldn't find M_SQRT2 definition). * Defining MY_SQRT2 in hw_sprites.cpp to keep visual studio happy (it couldn't find M_SQRT2 definition). * Defining MY_SQRT2 in r_utility.cpp also to keep visual studio happy. * retrigger checks * Have correct sprite angle-frame face the camera with orthographic projection enabled. * Dithered Transparency now works properly on 3D floors. Moved that dither-trans flag setting code within hw_bsp.cpp to handle double-processing of linedefs. Added helper functions to FRenderViewpoint class 'bool IsOrtho()' and 'bool IsAllowedOoB()' to clean up checks everywhere in the code. * Fixed indents. Added bbox property to subsector struct and use it instead of BSP nodes and Clippers (creating a bbox around viewpoint and checking for overlap) in orthographic mode when no fog of war is active. Turns out to be much faster. Though you need really big maps (Winter's Fury MAP01) to see a difference in fps. * Non-linux checks don't like uint. Changed to unsigned int. * Small change of a float to camera.zs. Ignore for testing. Should make no difference. * Update actor.h to remain mergeable RF2_NOMIPMAP was introduced, so I had to displace RF_ISOMETRICSPRITES to next bit.
This commit is contained in:
parent
b044baf850
commit
95b264bdb6
33 changed files with 819 additions and 84 deletions
|
|
@ -2816,7 +2816,7 @@ void DAutomap::drawPlayers ()
|
||||||
int numarrowlines;
|
int numarrowlines;
|
||||||
|
|
||||||
double vh = players[consoleplayer].viewheight;
|
double vh = players[consoleplayer].viewheight;
|
||||||
DVector2 pos = players[consoleplayer].camera->InterpolatedPosition(r_viewpoint.TicFrac).XY();
|
DVector2 pos = players[consoleplayer].mo->InterpolatedPosition(r_viewpoint.TicFrac).XY();
|
||||||
pt.x = pos.X;
|
pt.x = pos.X;
|
||||||
pt.y = pos.Y;
|
pt.y = pos.Y;
|
||||||
if (am_rotate == 1 || (am_rotate == 2 && viewactive))
|
if (am_rotate == 1 || (am_rotate == 2 && viewactive))
|
||||||
|
|
@ -2826,7 +2826,7 @@ void DAutomap::drawPlayers ()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
angle = players[consoleplayer].camera->InterpolatedAngles(r_viewpoint.TicFrac).Yaw;
|
angle = players[consoleplayer].mo->InterpolatedAngles(r_viewpoint.TicFrac).Yaw;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (am_cheat != 0 && CheatMapArrow.Size() > 0)
|
if (am_cheat != 0 && CheatMapArrow.Size() > 0)
|
||||||
|
|
|
||||||
|
|
@ -54,3 +54,6 @@ EXTERN_CVAR(Int, gl_shadowmap_filter)
|
||||||
EXTERN_CVAR(Bool, gl_brightfog)
|
EXTERN_CVAR(Bool, gl_brightfog)
|
||||||
EXTERN_CVAR(Bool, gl_lightadditivesurfaces)
|
EXTERN_CVAR(Bool, gl_lightadditivesurfaces)
|
||||||
EXTERN_CVAR(Bool, gl_notexturefill)
|
EXTERN_CVAR(Bool, gl_notexturefill)
|
||||||
|
|
||||||
|
EXTERN_CVAR(Bool, r_radarclipper)
|
||||||
|
EXTERN_CVAR(Bool, r_dithertransparency)
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ enum ERenderEffect
|
||||||
EFF_SPHEREMAP,
|
EFF_SPHEREMAP,
|
||||||
EFF_BURN,
|
EFF_BURN,
|
||||||
EFF_STENCIL,
|
EFF_STENCIL,
|
||||||
|
EFF_DITHERTRANS,
|
||||||
MAX_EFFECTS
|
MAX_EFFECTS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -299,6 +299,7 @@ const FEffectShader effectshaders[] =
|
||||||
{ "spheremap", "shaders/glsl/main.vp", "shaders/glsl/main.fp", "shaders/glsl/func_normal.fp", "shaders/glsl/material_normal.fp", "#define SPHEREMAP\n#define NO_ALPHATEST\n" },
|
{ "spheremap", "shaders/glsl/main.vp", "shaders/glsl/main.fp", "shaders/glsl/func_normal.fp", "shaders/glsl/material_normal.fp", "#define SPHEREMAP\n#define NO_ALPHATEST\n" },
|
||||||
{ "burn", "shaders/glsl/main.vp", "shaders/glsl/burn.fp", nullptr, nullptr, "#define SIMPLE\n#define NO_ALPHATEST\n" },
|
{ "burn", "shaders/glsl/main.vp", "shaders/glsl/burn.fp", nullptr, nullptr, "#define SIMPLE\n#define NO_ALPHATEST\n" },
|
||||||
{ "stencil", "shaders/glsl/main.vp", "shaders/glsl/stencil.fp", nullptr, nullptr, "#define SIMPLE\n#define NO_ALPHATEST\n" },
|
{ "stencil", "shaders/glsl/main.vp", "shaders/glsl/stencil.fp", nullptr, nullptr, "#define SIMPLE\n#define NO_ALPHATEST\n" },
|
||||||
|
{ "dithertrans", "shaders/glsl/main.vp", "shaders/glsl/main.fp", "shaders/glsl/func_normal.fp", "shaders/glsl/material_normal.fp", "#define NO_ALPHATEST\n#define DITHERTRANS\n" },
|
||||||
};
|
};
|
||||||
|
|
||||||
int DFrameBuffer::GetShaderCount()
|
int DFrameBuffer::GetShaderCount()
|
||||||
|
|
|
||||||
|
|
@ -146,11 +146,27 @@ float VREyeInfo::getShift() const
|
||||||
return vr_swap_eyes ? -res : res;
|
return vr_swap_eyes ? -res : res;
|
||||||
}
|
}
|
||||||
|
|
||||||
VSMatrix VREyeInfo::GetProjection(float fov, float aspectRatio, float fovRatio) const
|
VSMatrix VREyeInfo::GetProjection(float fov, float aspectRatio, float fovRatio, bool iso_ortho) const
|
||||||
{
|
{
|
||||||
VSMatrix result;
|
VSMatrix result;
|
||||||
|
|
||||||
if (mShiftFactor == 0)
|
if (iso_ortho) // Orthographic projection for isometric viewpoint
|
||||||
|
{
|
||||||
|
double zNear = -3.0/fovRatio; // screen->GetZNear();
|
||||||
|
double zFar = screen->GetZFar();
|
||||||
|
|
||||||
|
double fH = tan(DEG2RAD(fov) / 2) / fovRatio;
|
||||||
|
double fW = fH * aspectRatio * mScaleFactor;
|
||||||
|
double left = -fW;
|
||||||
|
double right = fW;
|
||||||
|
double bottom = -fH;
|
||||||
|
double top = fH;
|
||||||
|
|
||||||
|
VSMatrix fmat(1);
|
||||||
|
fmat.ortho((float)left, (float)right, (float)bottom, (float)top, (float)zNear, (float)zFar);
|
||||||
|
return fmat;
|
||||||
|
}
|
||||||
|
else if (mShiftFactor == 0)
|
||||||
{
|
{
|
||||||
float fovy = (float)(2 * RAD2DEG(atan(tan(DEG2RAD(fov) / 2) / fovRatio)));
|
float fovy = (float)(2 * RAD2DEG(atan(tan(DEG2RAD(fov) / 2) / fovRatio)));
|
||||||
result.perspective(fovy, aspectRatio, screen->GetZNear(), screen->GetZFar());
|
result.perspective(fovy, aspectRatio, screen->GetZNear(), screen->GetZFar());
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ struct VREyeInfo
|
||||||
float mShiftFactor;
|
float mShiftFactor;
|
||||||
float mScaleFactor;
|
float mScaleFactor;
|
||||||
|
|
||||||
VSMatrix GetProjection(float fov, float aspectRatio, float fovRatio) const;
|
VSMatrix GetProjection(float fov, float aspectRatio, float fovRatio, bool iso_ortho) const;
|
||||||
DVector3 GetViewShift(float yaw) const;
|
DVector3 GetViewShift(float yaw) const;
|
||||||
private:
|
private:
|
||||||
float getShift() const;
|
float getShift() const;
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,13 @@ public:
|
||||||
m_Box[BOXTOP] = pos.Y;
|
m_Box[BOXTOP] = pos.Y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CheckOverlap(const FBoundingBox &box2)
|
||||||
|
{
|
||||||
|
bool hori = (Left() > box2.Right()) || (Right() < box2.Left());
|
||||||
|
bool vert = (Bottom() > box2.Top()) || (Top() < box2.Bottom());
|
||||||
|
return !(hori || vert); // [DVR] For alternative space partition
|
||||||
|
}
|
||||||
|
|
||||||
inline double Top () const { return m_Box[BOXTOP]; }
|
inline double Top () const { return m_Box[BOXTOP]; }
|
||||||
inline double Bottom () const { return m_Box[BOXBOTTOM]; }
|
inline double Bottom () const { return m_Box[BOXBOTTOM]; }
|
||||||
inline double Left () const { return m_Box[BOXLEFT]; }
|
inline double Left () const { return m_Box[BOXLEFT]; }
|
||||||
|
|
|
||||||
|
|
@ -1819,6 +1819,7 @@ MapFlagHandlers[] =
|
||||||
{ "disableskyboxao", MITYPE_CLRFLAG3, LEVEL3_SKYBOXAO, 0 },
|
{ "disableskyboxao", MITYPE_CLRFLAG3, LEVEL3_SKYBOXAO, 0 },
|
||||||
{ "avoidmelee", MITYPE_SETFLAG3, LEVEL3_AVOIDMELEE, 0 },
|
{ "avoidmelee", MITYPE_SETFLAG3, LEVEL3_AVOIDMELEE, 0 },
|
||||||
{ "attenuatelights", MITYPE_SETFLAG3, LEVEL3_ATTENUATE, 0 },
|
{ "attenuatelights", MITYPE_SETFLAG3, LEVEL3_ATTENUATE, 0 },
|
||||||
|
{ "nofogofwar", MITYPE_SETFLAG3, LEVEL3_NOFOGOFWAR, 0 },
|
||||||
{ "nobotnodes", MITYPE_IGNORE, 0, 0 }, // Skulltag option: nobotnodes
|
{ "nobotnodes", MITYPE_IGNORE, 0, 0 }, // Skulltag option: nobotnodes
|
||||||
{ "nopassover", MITYPE_COMPATFLAG, COMPATF_NO_PASSMOBJ, 0 },
|
{ "nopassover", MITYPE_COMPATFLAG, COMPATF_NO_PASSMOBJ, 0 },
|
||||||
{ "passover", MITYPE_CLRCOMPATFLAG, COMPATF_NO_PASSMOBJ, 0 },
|
{ "passover", MITYPE_CLRCOMPATFLAG, COMPATF_NO_PASSMOBJ, 0 },
|
||||||
|
|
|
||||||
|
|
@ -269,7 +269,8 @@ enum ELevelFlags : unsigned int
|
||||||
LEVEL3_NOSHADOWMAP = 0x00010000, // disables shadowmaps for a given level.
|
LEVEL3_NOSHADOWMAP = 0x00010000, // disables shadowmaps for a given level.
|
||||||
LEVEL3_AVOIDMELEE = 0x00020000, // global flag needed for proper MBF support.
|
LEVEL3_AVOIDMELEE = 0x00020000, // global flag needed for proper MBF support.
|
||||||
LEVEL3_NOJUMPDOWN = 0x00040000, // only for MBF21. Inverse of MBF's dog_jumping flag.
|
LEVEL3_NOJUMPDOWN = 0x00040000, // only for MBF21. Inverse of MBF's dog_jumping flag.
|
||||||
LEVEL3_LIGHTCREATED = 0x00080000, // a light had been created in the last frame
|
LEVEL3_LIGHTCREATED = 0x00080000, // a light had been created in the last frame
|
||||||
|
LEVEL3_NOFOGOFWAR = 0x00100000, // disables effect of r_radarclipper CVAR on this map
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -303,6 +303,7 @@ struct secplane_t
|
||||||
DVector3 normal;
|
DVector3 normal;
|
||||||
double D, negiC; // negative iC because that also saves a negation in all methods using this.
|
double D, negiC; // negative iC because that also saves a negation in all methods using this.
|
||||||
public:
|
public:
|
||||||
|
bool dithertransflag; // Render plane with dithering transparency shader (gets reset every frame)
|
||||||
friend FSerializer &Serialize(FSerializer &arc, const char *key, secplane_t &p, secplane_t *def);
|
friend FSerializer &Serialize(FSerializer &arc, const char *key, secplane_t &p, secplane_t *def);
|
||||||
|
|
||||||
void set(double aa, double bb, double cc, double dd)
|
void set(double aa, double bb, double cc, double dd)
|
||||||
|
|
@ -1179,6 +1180,8 @@ enum
|
||||||
WALLF_ABSLIGHTING_TOP = WALLF_ABSLIGHTING_TIER << 0, // Top tier light is absolute instead of relative
|
WALLF_ABSLIGHTING_TOP = WALLF_ABSLIGHTING_TIER << 0, // Top tier light is absolute instead of relative
|
||||||
WALLF_ABSLIGHTING_MID = WALLF_ABSLIGHTING_TIER << 1, // Mid tier light is absolute instead of relative
|
WALLF_ABSLIGHTING_MID = WALLF_ABSLIGHTING_TIER << 1, // Mid tier light is absolute instead of relative
|
||||||
WALLF_ABSLIGHTING_BOTTOM = WALLF_ABSLIGHTING_TIER << 2, // Bottom tier light is absolute instead of relative
|
WALLF_ABSLIGHTING_BOTTOM = WALLF_ABSLIGHTING_TIER << 2, // Bottom tier light is absolute instead of relative
|
||||||
|
|
||||||
|
WALLF_DITHERTRANS = 8192, // Render with dithering transparency shader (gets reset every frame)
|
||||||
};
|
};
|
||||||
|
|
||||||
struct side_t
|
struct side_t
|
||||||
|
|
@ -1654,6 +1657,7 @@ struct subsector_t
|
||||||
uint32_t numlines;
|
uint32_t numlines;
|
||||||
uint16_t flags;
|
uint16_t flags;
|
||||||
short mapsection;
|
short mapsection;
|
||||||
|
FBoundingBox bbox; // [DVR] For alternative space culling in orthographic projection with no fog of war
|
||||||
|
|
||||||
// subsector related GL data
|
// subsector related GL data
|
||||||
int validcount;
|
int validcount;
|
||||||
|
|
|
||||||
|
|
@ -3262,6 +3262,25 @@ void MapLoader::LoadLevel(MapData *map, const char *lumpname, int position)
|
||||||
|
|
||||||
Level->aabbTree = new DoomLevelAABBTree(Level);
|
Level->aabbTree = new DoomLevelAABBTree(Level);
|
||||||
Level->levelMesh = new DoomLevelMesh(*Level);
|
Level->levelMesh = new DoomLevelMesh(*Level);
|
||||||
|
|
||||||
|
// [DVR] Populate subsector->bbox for alternative space culling in orthographic projection with no fog of war
|
||||||
|
subsector_t* sub = &Level->subsectors[0];
|
||||||
|
seg_t* seg;
|
||||||
|
for (unsigned int kk = 0; kk < Level->subsectors.Size(); kk++)
|
||||||
|
{
|
||||||
|
sub[kk].bbox.ClearBox();
|
||||||
|
unsigned int count = sub[kk].numlines;
|
||||||
|
seg = sub[kk].firstline;
|
||||||
|
while(count--)
|
||||||
|
{
|
||||||
|
if((seg->v1 != nullptr) && (seg->v2 != nullptr))
|
||||||
|
{
|
||||||
|
sub[kk].bbox.AddToBox(seg->v1->fPos());
|
||||||
|
sub[kk].bbox.AddToBox(seg->v2->fPos());
|
||||||
|
}
|
||||||
|
seg++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
|
||||||
|
|
@ -502,6 +502,7 @@ enum ActorRenderFlag2
|
||||||
RF2_FLIPSPRITEOFFSETY = 0x0020,
|
RF2_FLIPSPRITEOFFSETY = 0x0020,
|
||||||
RF2_CAMFOLLOWSPLAYER = 0x0040, // Matches the cam's base position and angles to the main viewpoint.
|
RF2_CAMFOLLOWSPLAYER = 0x0040, // Matches the cam's base position and angles to the main viewpoint.
|
||||||
RF2_NOMIPMAP = 0x0080, // [Nash] forces no mipmapping on sprites. Useful for tiny sprites that need to remain visually crisp
|
RF2_NOMIPMAP = 0x0080, // [Nash] forces no mipmapping on sprites. Useful for tiny sprites that need to remain visually crisp
|
||||||
|
RF2_ISOMETRICSPRITES = 0x0100,
|
||||||
};
|
};
|
||||||
|
|
||||||
// This translucency value produces the closest match to Heretic's TINTTAB.
|
// This translucency value produces the closest match to Heretic's TINTTAB.
|
||||||
|
|
@ -692,8 +693,10 @@ struct FDropItem
|
||||||
|
|
||||||
enum EViewPosFlags // [MC] Flags for SetViewPos.
|
enum EViewPosFlags // [MC] Flags for SetViewPos.
|
||||||
{
|
{
|
||||||
VPSF_ABSOLUTEOFFSET = 1 << 1, // Don't include angles.
|
VPSF_ABSOLUTEOFFSET = 1 << 1, // Don't include angles.
|
||||||
VPSF_ABSOLUTEPOS = 1 << 2, // Use absolute position.
|
VPSF_ABSOLUTEPOS = 1 << 2, // Use absolute position.
|
||||||
|
VPSF_ALLOWOUTOFBOUNDS = 1 << 3, // Allow viewpoint to go out of bounds (hardware renderer only).
|
||||||
|
VPSF_ORTHOGRAPHIC = 1 << 4, // Use orthographic projection (hardware renderer only).
|
||||||
};
|
};
|
||||||
|
|
||||||
enum EAnimOverrideFlags
|
enum EAnimOverrideFlags
|
||||||
|
|
@ -1123,6 +1126,8 @@ public:
|
||||||
DAngle SpriteAngle;
|
DAngle SpriteAngle;
|
||||||
DAngle SpriteRotation;
|
DAngle SpriteRotation;
|
||||||
DVector2 AutomapOffsets; // Offset the actors' sprite view on the automap by these coordinates.
|
DVector2 AutomapOffsets; // Offset the actors' sprite view on the automap by these coordinates.
|
||||||
|
float isoscaleY; // Y-scale to compensate for Y-billboarding for isometric sprites
|
||||||
|
float isotheta; // Rotation angle to compensate for Y-billboarding for isometric sprites
|
||||||
DRotator Angles;
|
DRotator Angles;
|
||||||
DRotator ViewAngles; // Angle offsets for cameras
|
DRotator ViewAngles; // Angle offsets for cameras
|
||||||
TObjPtr<DViewPosition*> ViewPos; // Position offsets for cameras
|
TObjPtr<DViewPosition*> ViewPos; // Position offsets for cameras
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,7 @@
|
||||||
#include "p_blockmap.h"
|
#include "p_blockmap.h"
|
||||||
#include "p_3dmidtex.h"
|
#include "p_3dmidtex.h"
|
||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
|
#include "d_main.h"
|
||||||
|
|
||||||
#include "decallib.h"
|
#include "decallib.h"
|
||||||
|
|
||||||
|
|
@ -5577,33 +5578,42 @@ void R_OffsetView(FRenderViewpoint& viewPoint, const DVector3& dir, const double
|
||||||
{
|
{
|
||||||
const DAngle baseYaw = dir.Angle();
|
const DAngle baseYaw = dir.Angle();
|
||||||
FTraceResults trace = {};
|
FTraceResults trace = {};
|
||||||
if (Trace(viewPoint.Pos, viewPoint.sector, dir, distance, 0u, 0u, nullptr, trace))
|
if (viewPoint.IsAllowedOoB() && V_IsHardwareRenderer())
|
||||||
|
{
|
||||||
|
viewPoint.Pos += dir * distance;
|
||||||
|
viewPoint.sector = viewPoint.ViewLevel->PointInRenderSubsector(viewPoint.Pos)->sector;
|
||||||
|
}
|
||||||
|
else if (Trace(viewPoint.Pos, viewPoint.sector, dir, distance, 0u, 0u, nullptr, trace))
|
||||||
{
|
{
|
||||||
viewPoint.Pos = trace.HitPos - trace.HitVector * min<double>(5.0, trace.Distance);
|
viewPoint.Pos = trace.HitPos - trace.HitVector * min<double>(5.0, trace.Distance);
|
||||||
viewPoint.sector = viewPoint.ViewLevel->PointInRenderSubsector(viewPoint.Pos)->sector;
|
viewPoint.sector = viewPoint.ViewLevel->PointInRenderSubsector(viewPoint.Pos)->sector;
|
||||||
|
viewPoint.Angles.Yaw += deltaangle(baseYaw, trace.SrcAngleFromTarget);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
viewPoint.Pos = trace.HitPos;
|
viewPoint.Pos = trace.HitPos;
|
||||||
viewPoint.sector = trace.Sector;
|
viewPoint.sector = trace.Sector;
|
||||||
|
viewPoint.Angles.Yaw += deltaangle(baseYaw, trace.SrcAngleFromTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
viewPoint.Angles.Yaw += deltaangle(baseYaw, trace.SrcAngleFromTarget);
|
|
||||||
// TODO: Why does this even need to be done? Please fix tracers already.
|
// TODO: Why does this even need to be done? Please fix tracers already.
|
||||||
if (dir.Z < 0.0)
|
if (!viewPoint.IsAllowedOoB() || !V_IsHardwareRenderer())
|
||||||
{
|
{
|
||||||
while (!viewPoint.sector->PortalBlocksMovement(sector_t::floor) && viewPoint.Pos.Z < viewPoint.sector->GetPortalPlaneZ(sector_t::floor))
|
if (dir.Z < 0.0)
|
||||||
{
|
{
|
||||||
viewPoint.Pos += viewPoint.sector->GetPortalDisplacement(sector_t::floor);
|
while (!viewPoint.sector->PortalBlocksMovement(sector_t::floor) && viewPoint.Pos.Z < viewPoint.sector->GetPortalPlaneZ(sector_t::floor))
|
||||||
viewPoint.sector = viewPoint.sector->GetPortal(sector_t::floor)->mDestination;
|
{
|
||||||
|
viewPoint.Pos += viewPoint.sector->GetPortalDisplacement(sector_t::floor);
|
||||||
|
viewPoint.sector = viewPoint.sector->GetPortal(sector_t::floor)->mDestination;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
else if (dir.Z > 0.0)
|
||||||
else if (dir.Z > 0.0)
|
|
||||||
{
|
|
||||||
while (!viewPoint.sector->PortalBlocksMovement(sector_t::ceiling) && viewPoint.Pos.Z > viewPoint.sector->GetPortalPlaneZ(sector_t::ceiling))
|
|
||||||
{
|
{
|
||||||
viewPoint.Pos += viewPoint.sector->GetPortalDisplacement(sector_t::ceiling);
|
while (!viewPoint.sector->PortalBlocksMovement(sector_t::ceiling) && viewPoint.Pos.Z > viewPoint.sector->GetPortalPlaneZ(sector_t::ceiling))
|
||||||
viewPoint.sector = viewPoint.sector->GetPortal(sector_t::ceiling)->mDestination;
|
{
|
||||||
|
viewPoint.Pos += viewPoint.sector->GetPortalDisplacement(sector_t::ceiling);
|
||||||
|
viewPoint.sector = viewPoint.sector->GetPortal(sector_t::ceiling)->mDestination;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -633,6 +633,9 @@ cont:
|
||||||
case TRACE_Stop:
|
case TRACE_Stop:
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
case TRACE_ContinueOutOfBounds:
|
||||||
|
return true;
|
||||||
|
|
||||||
case TRACE_Abort:
|
case TRACE_Abort:
|
||||||
Results->HitType = TRACE_HitNone;
|
Results->HitType = TRACE_HitNone;
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -732,6 +735,7 @@ bool FTraceInfo::ThingCheck(intercept_t *in, double dist, DVector3 hit)
|
||||||
switch (TraceCallback(*Results, TraceCallbackData))
|
switch (TraceCallback(*Results, TraceCallbackData))
|
||||||
{
|
{
|
||||||
case TRACE_Continue: return true;
|
case TRACE_Continue: return true;
|
||||||
|
case TRACE_ContinueOutOfBounds: return true;
|
||||||
case TRACE_Stop: return false;
|
case TRACE_Stop: return false;
|
||||||
case TRACE_Abort: Results->HitType = TRACE_HitNone; return false;
|
case TRACE_Abort: Results->HitType = TRACE_HitNone; return false;
|
||||||
case TRACE_Skip: Results->HitType = TRACE_HitNone; return true;
|
case TRACE_Skip: Results->HitType = TRACE_HitNone; return true;
|
||||||
|
|
|
||||||
|
|
@ -109,6 +109,7 @@ enum ETraceStatus
|
||||||
TRACE_Continue, // continue the trace, returning this hit if there are none further along
|
TRACE_Continue, // continue the trace, returning this hit if there are none further along
|
||||||
TRACE_Skip, // continue the trace; do not return this hit
|
TRACE_Skip, // continue the trace; do not return this hit
|
||||||
TRACE_Abort, // stop the trace, returning no hits
|
TRACE_Abort, // stop the trace, returning no hits
|
||||||
|
TRACE_ContinueOutOfBounds, // continue the trace through walls; don't use this for railguns
|
||||||
};
|
};
|
||||||
|
|
||||||
bool Trace(const DVector3 &start, sector_t *sector, const DVector3 &direction, double maxDist,
|
bool Trace(const DVector3 &start, sector_t *sector, const DVector3 &direction, double maxDist,
|
||||||
|
|
|
||||||
|
|
@ -163,7 +163,11 @@ sector_t* RenderViewpoint(FRenderViewpoint& mainvp, AActor* camera, IntRect* bou
|
||||||
di->Viewpoint.FieldOfView = DAngle::fromDeg(fov); // Set the real FOV for the current scene (it's not necessarily the same as the global setting in r_viewpoint)
|
di->Viewpoint.FieldOfView = DAngle::fromDeg(fov); // Set the real FOV for the current scene (it's not necessarily the same as the global setting in r_viewpoint)
|
||||||
|
|
||||||
// Stereo mode specific perspective projection
|
// Stereo mode specific perspective projection
|
||||||
di->VPUniforms.mProjectionMatrix = eye.GetProjection(fov, ratio, fovratio);
|
float inv_iso_dist = 1.0f;
|
||||||
|
bool iso_ortho = (camera->ViewPos != NULL) && (camera->ViewPos->Flags & VPSF_ORTHOGRAPHIC);
|
||||||
|
if (iso_ortho && (camera->ViewPos->Offset.Length() > 0)) inv_iso_dist = 1.0/camera->ViewPos->Offset.Length();
|
||||||
|
di->VPUniforms.mProjectionMatrix = eye.GetProjection(fov, ratio, fovratio * inv_iso_dist, iso_ortho);
|
||||||
|
|
||||||
// Stereo mode specific viewpoint adjustment
|
// Stereo mode specific viewpoint adjustment
|
||||||
vp.Pos += eye.GetViewShift(vp.HWAngles.Yaw.Degrees());
|
vp.Pos += eye.GetViewShift(vp.HWAngles.Yaw.Degrees());
|
||||||
di->SetupView(RenderState, vp.Pos.X, vp.Pos.Y, vp.Pos.Z, false, false);
|
di->SetupView(RenderState, vp.Pos.X, vp.Pos.Y, vp.Pos.Z, false, false);
|
||||||
|
|
|
||||||
|
|
@ -51,11 +51,24 @@
|
||||||
CVAR(Bool, gl_multithread, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
CVAR(Bool, gl_multithread, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||||
|
|
||||||
EXTERN_CVAR(Float, r_actorspriteshadowdist)
|
EXTERN_CVAR(Float, r_actorspriteshadowdist)
|
||||||
|
EXTERN_CVAR(Bool, r_radarclipper)
|
||||||
|
EXTERN_CVAR(Bool, r_dithertransparency)
|
||||||
|
|
||||||
thread_local bool isWorkerThread;
|
thread_local bool isWorkerThread;
|
||||||
ctpl::thread_pool renderPool(1);
|
ctpl::thread_pool renderPool(1);
|
||||||
bool inited = false;
|
bool inited = false;
|
||||||
|
|
||||||
|
const int MAXDITHERACTORS = 20; // Maximum number of enemies that can set dither-transparency flags
|
||||||
|
AActor* RenderedTargets[MAXDITHERACTORS];
|
||||||
|
int RTnum;
|
||||||
|
|
||||||
|
void ClearDitherTargets()
|
||||||
|
{
|
||||||
|
RTnum = 0; // Number of rendered enemies/targets
|
||||||
|
for (int ii = 0; ii < MAXDITHERACTORS; ii++)
|
||||||
|
RenderedTargets[ii] = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
struct RenderJob
|
struct RenderJob
|
||||||
{
|
{
|
||||||
enum
|
enum
|
||||||
|
|
@ -269,6 +282,20 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip)
|
||||||
auto &clipper = *mClipper;
|
auto &clipper = *mClipper;
|
||||||
angle_t startAngle = clipper.GetClipAngle(seg->v2);
|
angle_t startAngle = clipper.GetClipAngle(seg->v2);
|
||||||
angle_t endAngle = clipper.GetClipAngle(seg->v1);
|
angle_t endAngle = clipper.GetClipAngle(seg->v1);
|
||||||
|
auto &clipperr = *rClipper;
|
||||||
|
angle_t startAngleR = clipperr.PointToPseudoAngle(seg->v2->fX(), seg->v2->fY());
|
||||||
|
angle_t endAngleR = clipperr.PointToPseudoAngle(seg->v1->fX(), seg->v1->fY());
|
||||||
|
|
||||||
|
if(r_radarclipper && !(Level->flags3 & LEVEL3_NOFOGOFWAR) && (startAngleR - endAngleR >= ANGLE_180))
|
||||||
|
{
|
||||||
|
if (!seg->backsector) clipperr.SafeAddClipRange(startAngleR, endAngleR);
|
||||||
|
else if((seg->sidedef != nullptr) && !uint8_t(seg->sidedef->Flags & WALLF_POLYOBJ) && (currentsector->sectornum != seg->backsector->sectornum))
|
||||||
|
{
|
||||||
|
if (in_area == area_default) in_area = hw_CheckViewArea(seg->v2, seg->v1, seg->frontsector, seg->backsector);
|
||||||
|
backsector = hw_FakeFlat(seg->backsector, in_area, true);
|
||||||
|
if (hw_CheckClip(seg->sidedef, currentsector, backsector)) clipperr.SafeAddClipRange(startAngleR, endAngleR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Back side, i.e. backface culling - read: endAngle >= startAngle!
|
// Back side, i.e. backface culling - read: endAngle >= startAngle!
|
||||||
if (startAngle-endAngle<ANGLE_180)
|
if (startAngle-endAngle<ANGLE_180)
|
||||||
|
|
@ -280,9 +307,13 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip)
|
||||||
{
|
{
|
||||||
if (!(currentsubsector->flags & SSECMF_DRAWN))
|
if (!(currentsubsector->flags & SSECMF_DRAWN))
|
||||||
{
|
{
|
||||||
if (clipper.SafeCheckRange(startAngle, endAngle))
|
if (clipper.SafeCheckRange(startAngle, endAngle) && (!r_radarclipper || (Level->flags3 & LEVEL3_NOFOGOFWAR)))
|
||||||
{
|
{
|
||||||
currentsubsector->flags |= SSECMF_DRAWN;
|
currentsubsector->flags |= SSECMF_DRAWN;
|
||||||
|
}
|
||||||
|
if ((r_radarclipper || !(Level->flags3 & LEVEL3_NOFOGOFWAR)) && clipperr.SafeCheckRange(startAngleR, endAngleR))
|
||||||
|
{
|
||||||
|
currentsubsector->flags |= SSECMF_DRAWN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
@ -292,13 +323,37 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
currentsubsector->flags |= SSECMF_DRAWN;
|
|
||||||
|
auto &clipperv = *vClipper;
|
||||||
|
angle_t startPitch = clipperv.PointToPseudoPitch(seg->v1->fX(), seg->v1->fY(), currentsector->floorplane.ZatPoint(seg->v1));
|
||||||
|
angle_t endPitch = clipperv.PointToPseudoPitch(seg->v1->fX(), seg->v1->fY(), currentsector->ceilingplane.ZatPoint(seg->v1));
|
||||||
|
angle_t startPitch2 = clipperv.PointToPseudoPitch(seg->v2->fX(), seg->v2->fY(), currentsector->floorplane.ZatPoint(seg->v2));
|
||||||
|
angle_t endPitch2 = clipperv.PointToPseudoPitch(seg->v2->fX(), seg->v2->fY(), currentsector->ceilingplane.ZatPoint(seg->v2));
|
||||||
|
angle_t temp;
|
||||||
|
// Wall can be tilted from viewpoint perspective. Find vertical extent on screen in psuedopitch units (0 to 2, bottom to top)
|
||||||
|
if(int(startPitch) > int(startPitch2)) // Handle zero crossing
|
||||||
|
{
|
||||||
|
temp = startPitch; startPitch = startPitch2; startPitch2 = temp; // exchange
|
||||||
|
}
|
||||||
|
if(int(endPitch) > int(endPitch2)) // Handle zero crossing
|
||||||
|
{
|
||||||
|
temp = endPitch; endPitch = endPitch2; endPitch2 = temp; // exchange
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!clipperv.SafeCheckRange(startPitch, endPitch2))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!r_radarclipper || (Level->flags3 & LEVEL3_NOFOGOFWAR) || clipperr.SafeCheckRange(startAngleR, endAngleR))
|
||||||
|
currentsubsector->flags |= SSECMF_DRAWN;
|
||||||
|
|
||||||
uint8_t ispoly = uint8_t(seg->sidedef->Flags & WALLF_POLYOBJ);
|
uint8_t ispoly = uint8_t(seg->sidedef->Flags & WALLF_POLYOBJ);
|
||||||
|
|
||||||
if (!seg->backsector)
|
if (!seg->backsector)
|
||||||
{
|
{
|
||||||
clipper.SafeAddClipRange(startAngle, endAngle);
|
if(!Viewpoint.IsAllowedOoB())
|
||||||
|
if (!(seg->sidedef->Flags & WALLF_DITHERTRANS)) clipper.SafeAddClipRange(startAngle, endAngle);
|
||||||
}
|
}
|
||||||
else if (!ispoly) // Two-sided polyobjects never obstruct the view
|
else if (!ispoly) // Two-sided polyobjects never obstruct the view
|
||||||
{
|
{
|
||||||
|
|
@ -325,7 +380,8 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip)
|
||||||
|
|
||||||
if (hw_CheckClip(seg->sidedef, currentsector, backsector))
|
if (hw_CheckClip(seg->sidedef, currentsector, backsector))
|
||||||
{
|
{
|
||||||
clipper.SafeAddClipRange(startAngle, endAngle);
|
if(!Viewpoint.IsAllowedOoB() && !(seg->sidedef->Flags & WALLF_DITHERTRANS))
|
||||||
|
clipper.SafeAddClipRange(startAngle, endAngle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -526,13 +582,14 @@ void HWDrawInfo::RenderThings(subsector_t * sub, sector_t * sector)
|
||||||
{
|
{
|
||||||
sector_t * sec=sub->sector;
|
sector_t * sec=sub->sector;
|
||||||
// Handle all things in sector.
|
// Handle all things in sector.
|
||||||
const auto &vp = Viewpoint;
|
const auto &vp = Viewpoint;
|
||||||
for (auto p = sec->touching_renderthings; p != nullptr; p = p->m_snext)
|
for (auto p = sec->touching_renderthings; p != nullptr; p = p->m_snext)
|
||||||
{
|
{
|
||||||
auto thing = p->m_thing;
|
auto thing = p->m_thing;
|
||||||
if (thing->validcount == validcount) continue;
|
if (thing->validcount == validcount) continue;
|
||||||
thing->validcount = validcount;
|
thing->validcount = validcount;
|
||||||
|
|
||||||
|
if(Viewpoint.IsAllowedOoB() && thing->Sector->isSecret() && thing->Sector->wasSecret() && !r_radarclipper) continue; // This covers things that are touching non-secret sectors
|
||||||
FIntCVar *cvar = thing->GetInfo()->distancecheck;
|
FIntCVar *cvar = thing->GetInfo()->distancecheck;
|
||||||
if (cvar != nullptr && *cvar >= 0)
|
if (cvar != nullptr && *cvar >= 0)
|
||||||
{
|
{
|
||||||
|
|
@ -666,6 +723,51 @@ void HWDrawInfo::DoSubsector(subsector_t * sub)
|
||||||
|
|
||||||
fakesector=hw_FakeFlat(sector, in_area, false);
|
fakesector=hw_FakeFlat(sector, in_area, false);
|
||||||
|
|
||||||
|
if(Viewpoint.IsAllowedOoB() && sector->isSecret() && sector->wasSecret() && !r_radarclipper) return;
|
||||||
|
|
||||||
|
// cull everything if subsector outside vertical clipper
|
||||||
|
if ((sub->polys == nullptr) && (!Viewpoint.IsOrtho() || !((Level->flags3 & LEVEL3_NOFOGOFWAR) || !r_radarclipper)))
|
||||||
|
{
|
||||||
|
auto &clipper = *mClipper;
|
||||||
|
auto &clipperv = *vClipper;
|
||||||
|
auto &clipperr = *rClipper;
|
||||||
|
int count = sub->numlines;
|
||||||
|
seg_t * seg = sub->firstline;
|
||||||
|
bool anglevisible = false;
|
||||||
|
bool pitchvisible = false;
|
||||||
|
bool radarvisible = false;
|
||||||
|
angle_t pitchtemp;
|
||||||
|
angle_t pitchmin = ANGLE_90;
|
||||||
|
angle_t pitchmax = 0;
|
||||||
|
|
||||||
|
while (count--)
|
||||||
|
{
|
||||||
|
if((seg->v1 != nullptr) && (seg->v2 != nullptr))
|
||||||
|
{
|
||||||
|
angle_t startAngle = clipper.GetClipAngle(seg->v2);
|
||||||
|
angle_t endAngle = clipper.GetClipAngle(seg->v1);
|
||||||
|
if (startAngle-endAngle >= ANGLE_180) anglevisible |= clipper.SafeCheckRange(startAngle, endAngle);
|
||||||
|
angle_t startAngleR = clipperr.PointToPseudoAngle(seg->v2->fX(), seg->v2->fY());
|
||||||
|
angle_t endAngleR = clipperr.PointToPseudoAngle(seg->v1->fX(), seg->v1->fY());
|
||||||
|
if (startAngleR-endAngleR >= ANGLE_180)
|
||||||
|
radarvisible |= (clipperr.SafeCheckRange(startAngleR, endAngleR) || (Level->flags3 & LEVEL3_NOFOGOFWAR) || ((sub->flags & SSECMF_DRAWN) && !deathmatch));
|
||||||
|
pitchmin = clipperv.PointToPseudoPitch(seg->v1->fX(), seg->v1->fY(), sector->floorplane.ZatPoint(seg->v1));
|
||||||
|
pitchmax = clipperv.PointToPseudoPitch(seg->v1->fX(), seg->v1->fY(), sector->ceilingplane.ZatPoint(seg->v1));
|
||||||
|
pitchvisible |= clipperv.SafeCheckRange(pitchmin, pitchmax);
|
||||||
|
if (pitchvisible && anglevisible && radarvisible) break;
|
||||||
|
pitchtemp = clipperv.PointToPseudoPitch(seg->v2->fX(), seg->v2->fY(), sector->floorplane.ZatPoint(seg->v2));
|
||||||
|
if (int(pitchmin) > int(pitchtemp)) pitchmin = pitchtemp;
|
||||||
|
pitchtemp = clipperv.PointToPseudoPitch(seg->v2->fX(), seg->v2->fY(), sector->ceilingplane.ZatPoint(seg->v2));
|
||||||
|
if (int(pitchmax) < int(pitchtemp)) pitchmax = pitchtemp;
|
||||||
|
pitchvisible |= clipperv.SafeCheckRange(pitchmin, pitchmax);
|
||||||
|
if (pitchvisible && anglevisible && radarvisible) break;
|
||||||
|
}
|
||||||
|
seg++;
|
||||||
|
}
|
||||||
|
// Skip subsector if outside vertical or horizontal clippers or is in unexplored territory (fog of war)
|
||||||
|
if(!pitchvisible || !anglevisible || (!radarvisible && r_radarclipper)) return;
|
||||||
|
}
|
||||||
|
|
||||||
if (mClipPortal)
|
if (mClipPortal)
|
||||||
{
|
{
|
||||||
int clipres = mClipPortal->ClipSubsector(sub);
|
int clipres = mClipPortal->ClipSubsector(sub);
|
||||||
|
|
@ -723,6 +825,20 @@ void HWDrawInfo::DoSubsector(subsector_t * sub)
|
||||||
SetupSprite.Unclock();
|
SetupSprite.Unclock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (r_dithertransparency && Viewpoint.IsAllowedOoB() && (RTnum < MAXDITHERACTORS))
|
||||||
|
{
|
||||||
|
// [DVR] Not parallelizable due to variables RTnum and RenderedTargets[]
|
||||||
|
for (auto p = sector->touching_renderthings; p != nullptr; p = p->m_snext)
|
||||||
|
{
|
||||||
|
auto thing = p->m_thing;
|
||||||
|
if (thing->validcount == validcount) continue; // Don't double count
|
||||||
|
if (((thing->flags3 & MF3_ISMONSTER) && !(thing->flags & MF_CORPSE)) || (thing->flags & MF_MISSILE))
|
||||||
|
{
|
||||||
|
if (RTnum < MAXDITHERACTORS) RenderedTargets[RTnum++] = thing;
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gl_render_flats)
|
if (gl_render_flats)
|
||||||
|
|
@ -843,19 +959,62 @@ void HWDrawInfo::RenderBSPNode (void *node)
|
||||||
if (!(no_renderflags[bsp->Index()] & SSRF_SEEN))
|
if (!(no_renderflags[bsp->Index()] & SSRF_SEEN))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (Viewpoint.IsOrtho())
|
||||||
|
{
|
||||||
|
if (!vClipper->CheckBoxOrthoPitch(bsp->bbox[side]))
|
||||||
|
{
|
||||||
|
if (!(no_renderflags[bsp->Index()] & SSRF_SEEN))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
node = bsp->children[side];
|
node = bsp->children[side];
|
||||||
}
|
}
|
||||||
DoSubsector ((subsector_t *)((uint8_t *)node - 1));
|
DoSubsector ((subsector_t *)((uint8_t *)node - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// No need for clipping inside frustum if no fog of war (How is this faster!)
|
||||||
|
void HWDrawInfo::RenderOrthoNoFog()
|
||||||
|
{
|
||||||
|
if (Viewpoint.IsOrtho() && ((Level->flags3 & LEVEL3_NOFOGOFWAR) || !r_radarclipper))
|
||||||
|
{
|
||||||
|
double vxdbl = Viewpoint.camera->X();
|
||||||
|
double vydbl = Viewpoint.camera->Y();
|
||||||
|
double ext = Viewpoint.camera->ViewPos->Offset.Length() ?
|
||||||
|
3.0 * Viewpoint.camera->ViewPos->Offset.Length() : 100.0;
|
||||||
|
FBoundingBox viewbox(vxdbl, vydbl, ext);
|
||||||
|
|
||||||
|
for (unsigned int kk = 0; kk < Level->subsectors.Size(); kk++)
|
||||||
|
{
|
||||||
|
if (Level->subsectors[kk].bbox.CheckOverlap(viewbox))
|
||||||
|
{
|
||||||
|
DoSubsector (&Level->subsectors[kk]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void HWDrawInfo::RenderBSP(void *node, bool drawpsprites)
|
void HWDrawInfo::RenderBSP(void *node, bool drawpsprites)
|
||||||
{
|
{
|
||||||
|
ClearDitherTargets();
|
||||||
Bsp.Clock();
|
Bsp.Clock();
|
||||||
|
|
||||||
// Give the DrawInfo the viewpoint in fixed point because that's what the nodes are.
|
// Give the DrawInfo the viewpoint in fixed point because that's what the nodes are.
|
||||||
viewx = FLOAT2FIXED(Viewpoint.Pos.X);
|
viewx = FLOAT2FIXED(Viewpoint.Pos.X);
|
||||||
viewy = FLOAT2FIXED(Viewpoint.Pos.Y);
|
viewy = FLOAT2FIXED(Viewpoint.Pos.Y);
|
||||||
|
if (r_radarclipper && !(Level->flags3 & LEVEL3_NOFOGOFWAR) && Viewpoint.IsAllowedOoB() && (Viewpoint.camera->ViewPos->Flags & VPSF_ABSOLUTEOFFSET))
|
||||||
|
{
|
||||||
|
if (Viewpoint.camera->tracer != NULL)
|
||||||
|
{
|
||||||
|
viewx = FLOAT2FIXED(Viewpoint.camera->tracer->X());
|
||||||
|
viewy = FLOAT2FIXED(Viewpoint.camera->tracer->Y());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
viewx = FLOAT2FIXED(Viewpoint.camera->X());
|
||||||
|
viewy = FLOAT2FIXED(Viewpoint.camera->Y());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
validcount++; // used for processing sidedefs only once by the renderer.
|
validcount++; // used for processing sidedefs only once by the renderer.
|
||||||
|
|
||||||
|
|
@ -866,7 +1025,8 @@ void HWDrawInfo::RenderBSP(void *node, bool drawpsprites)
|
||||||
auto future = renderPool.push([&](int id) {
|
auto future = renderPool.push([&](int id) {
|
||||||
WorkerThread();
|
WorkerThread();
|
||||||
});
|
});
|
||||||
RenderBSPNode(node);
|
if (Viewpoint.IsOrtho() && ((Level->flags3 & LEVEL3_NOFOGOFWAR) || !r_radarclipper)) RenderOrthoNoFog();
|
||||||
|
else RenderBSPNode(node);
|
||||||
|
|
||||||
jobQueue.AddJob(RenderJob::TerminateJob, nullptr, nullptr);
|
jobQueue.AddJob(RenderJob::TerminateJob, nullptr, nullptr);
|
||||||
Bsp.Unclock();
|
Bsp.Unclock();
|
||||||
|
|
@ -876,9 +1036,21 @@ void HWDrawInfo::RenderBSP(void *node, bool drawpsprites)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
RenderBSPNode(node);
|
if (Viewpoint.IsOrtho() && ((Level->flags3 & LEVEL3_NOFOGOFWAR) || !r_radarclipper)) RenderOrthoNoFog();
|
||||||
|
else RenderBSPNode(node);
|
||||||
Bsp.Unclock();
|
Bsp.Unclock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make rendered targets set dither transparency flags on level geometry for next pass
|
||||||
|
// Can't do this inside DoSubsector() because both Trace() and P_CheckSight() affect 'validcount' global variable
|
||||||
|
for (int ii = 0; ii < MAXDITHERACTORS; ii++)
|
||||||
|
{
|
||||||
|
if ( RenderedTargets[ii] && P_CheckSight(players[consoleplayer].mo, RenderedTargets[ii], 0) )
|
||||||
|
{
|
||||||
|
SetDitherTransFlags(RenderedTargets[ii]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Process all the sprites on the current portal's back side which touch the portal.
|
// Process all the sprites on the current portal's back side which touch the portal.
|
||||||
if (mCurrentPortal != nullptr) mCurrentPortal->RenderAttached(this);
|
if (mCurrentPortal != nullptr) mCurrentPortal->RenderAttached(this);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -193,7 +193,7 @@ void Clipper::AddClipRange(angle_t start, angle_t end)
|
||||||
|
|
||||||
if (node->end < end)
|
if (node->end < end)
|
||||||
{
|
{
|
||||||
node->end = end;
|
node->end = end; // [DVR] This never triggers because of previous while loop. Remove?
|
||||||
}
|
}
|
||||||
|
|
||||||
ClipNode *node2 = node->next;
|
ClipNode *node2 = node->next;
|
||||||
|
|
@ -361,6 +361,17 @@ angle_t Clipper::AngleToPseudo(angle_t ang)
|
||||||
return xs_Fix<30>::ToFix(result);
|
return xs_Fix<30>::ToFix(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
angle_t Clipper::PitchToPseudo(double ang)
|
||||||
|
{
|
||||||
|
return AngleToPseudo(DAngle::fromDeg(90.0-ang).BAMs()); // Pitch is positive when looking down
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// ! Returns the pseudoangle between the line p1 to (infinity, p1.y) and the
|
// ! Returns the pseudoangle between the line p1 to (infinity, p1.y) and the
|
||||||
|
|
@ -378,11 +389,28 @@ angle_t Clipper::PointToPseudoAngle(double x, double y)
|
||||||
{
|
{
|
||||||
double vecx = x - viewpoint->Pos.X;
|
double vecx = x - viewpoint->Pos.X;
|
||||||
double vecy = y - viewpoint->Pos.Y;
|
double vecy = y - viewpoint->Pos.Y;
|
||||||
|
if ((viewpoint->camera != NULL) && amRadar)
|
||||||
|
{
|
||||||
|
if (viewpoint->camera->tracer != NULL)
|
||||||
|
{
|
||||||
|
vecx = x - viewpoint->camera->tracer->X();
|
||||||
|
vecy = y - viewpoint->camera->tracer->Y();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vecx = x - viewpoint->camera->X();
|
||||||
|
vecy = y - viewpoint->camera->Y();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (vecx == 0 && vecy == 0)
|
if (vecx == 0 && vecy == 0)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
else if (!amRadar && viewpoint->IsOrtho())
|
||||||
|
{
|
||||||
|
return PointToPseudoOrthoAngle(x, y);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
double result = vecy / (fabs(vecx) + fabs(vecy));
|
double result = vecy / (fabs(vecx) + fabs(vecy));
|
||||||
|
|
@ -395,6 +423,78 @@ angle_t Clipper::PointToPseudoAngle(double x, double y)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
angle_t Clipper::PointToPseudoPitch(double x, double y, double z)
|
||||||
|
{
|
||||||
|
double vecx = x - viewpoint->Pos.X;
|
||||||
|
double vecy = y - viewpoint->Pos.Y;
|
||||||
|
double vecz = z - viewpoint->Pos.Z;
|
||||||
|
double result = 0;
|
||||||
|
|
||||||
|
if (vecx == 0 && vecy == 0 && vecz == 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (viewpoint->IsOrtho())
|
||||||
|
{
|
||||||
|
return PointToPseudoOrthoPitch(x, y, z);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
double result = vecz / (g_sqrt(vecx*vecx + vecy*vecy) + fabs(vecz)); // -ffast-math compile flag applies to this file, yes?
|
||||||
|
if ((vecx * viewpoint->TanCos + vecy * viewpoint->TanSin) <= 0.0) // Point is behind viewpoint
|
||||||
|
{
|
||||||
|
result = 2.0 - result;
|
||||||
|
}
|
||||||
|
return xs_Fix<30>::ToFix(result + 1.0); // range to 0 to 2 to 4 (bottom to top to suplex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
angle_t Clipper::PointToPseudoOrthoAngle(double x, double y)
|
||||||
|
{
|
||||||
|
DVector3 disp = DVector3( x, y, 0 ) - viewpoint->camera->Pos();
|
||||||
|
if (viewpoint->camera->ViewPos->Offset.XY().Length() == 0)
|
||||||
|
{
|
||||||
|
return AngleToPseudo( viewpoint->Angles.Yaw.BAMs() );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
angle_t af = viewpoint->FrustAngle;
|
||||||
|
double xproj = disp.XY().Length() * deltaangle(disp.Angle(), viewpoint->Angles.Yaw).Sin();
|
||||||
|
xproj *= viewpoint->ScreenProj;
|
||||||
|
if (fabs(xproj) < 2.0)
|
||||||
|
{
|
||||||
|
return AngleToPseudo( viewpoint->Angles.Yaw.BAMs() - xproj * 0.5 * af );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return (xproj > 0.0 ? AngleToPseudo( viewpoint->Angles.Yaw.BAMs() - af ) : AngleToPseudo( viewpoint->Angles.Yaw.BAMs() + af ));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
angle_t Clipper::PointToPseudoOrthoPitch(double x, double y, double z)
|
||||||
|
{
|
||||||
|
DVector3 disp = DVector3( x, y, z ) - viewpoint->camera->Pos();
|
||||||
|
if (viewpoint->camera->ViewPos->Offset.XY().Length() > 0)
|
||||||
|
{
|
||||||
|
double yproj = viewpoint->PitchSin * disp.XY().Length() * deltaangle(disp.Angle(), viewpoint->Angles.Yaw).Cos();
|
||||||
|
yproj += viewpoint->PitchCos * disp.Z;
|
||||||
|
yproj *= viewpoint->ScreenProj;
|
||||||
|
if (fabs(yproj) <= 1.5)
|
||||||
|
{
|
||||||
|
return PitchToPseudo(viewpoint->Angles.Pitch.Degrees() - yproj * 0.5 * viewpoint->FieldOfView.Degrees() );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
double a2 = 0.75*viewpoint->FieldOfView.Degrees();
|
||||||
|
a2 *= ( yproj > 0.0 ? -1.0 : 1.0 );
|
||||||
|
return PitchToPseudo(viewpoint->Angles.Pitch.Degrees() + a2 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else return PitchToPseudo(viewpoint->Angles.Pitch.Degrees());
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
|
|
@ -428,7 +528,7 @@ bool Clipper::CheckBox(const float *bspcoord)
|
||||||
|
|
||||||
// Find the corners of the box
|
// Find the corners of the box
|
||||||
// that define the edges from current viewpoint.
|
// that define the edges from current viewpoint.
|
||||||
auto &vp = viewpoint;
|
auto &vp = viewpoint;
|
||||||
boxpos = (vp->Pos.X <= bspcoord[BOXLEFT] ? 0 : vp->Pos.X < bspcoord[BOXRIGHT ] ? 1 : 2) +
|
boxpos = (vp->Pos.X <= bspcoord[BOXLEFT] ? 0 : vp->Pos.X < bspcoord[BOXRIGHT ] ? 1 : 2) +
|
||||||
(vp->Pos.Y >= bspcoord[BOXTOP ] ? 0 : vp->Pos.Y > bspcoord[BOXBOTTOM] ? 4 : 8);
|
(vp->Pos.Y >= bspcoord[BOXTOP ] ? 0 : vp->Pos.Y > bspcoord[BOXBOTTOM] ? 4 : 8);
|
||||||
|
|
||||||
|
|
@ -438,6 +538,46 @@ bool Clipper::CheckBox(const float *bspcoord)
|
||||||
angle1 = PointToPseudoAngle (bspcoord[check[0]], bspcoord[check[1]]);
|
angle1 = PointToPseudoAngle (bspcoord[check[0]], bspcoord[check[1]]);
|
||||||
angle2 = PointToPseudoAngle (bspcoord[check[2]], bspcoord[check[3]]);
|
angle2 = PointToPseudoAngle (bspcoord[check[2]], bspcoord[check[3]]);
|
||||||
|
|
||||||
|
if (vp->IsOrtho())
|
||||||
|
{
|
||||||
|
if (angle2 != angle1) return true;
|
||||||
|
switch (boxpos) // Check if the closer corner is poking into the view area
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
case 10:
|
||||||
|
if ( angle1 != PointToPseudoAngle (bspcoord[check[2]], bspcoord[check[1]]) ) return true;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
case 8:
|
||||||
|
if ( angle1 != PointToPseudoAngle (bspcoord[check[0]], bspcoord[check[3]]) ) return true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return SafeCheckRange(angle2, angle1);
|
return SafeCheckRange(angle2, angle1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Clipper::CheckBoxOrthoPitch(const float *bspcoord)
|
||||||
|
{
|
||||||
|
angle_t pitchmin, pitchmax;
|
||||||
|
auto &vp = viewpoint;
|
||||||
|
if (!vp->IsOrtho()) return true;
|
||||||
|
|
||||||
|
angle_t pitchtemp;
|
||||||
|
double padding = 1.0/viewpoint->ScreenProj/viewpoint->PitchCos;
|
||||||
|
double camz = vp->camera->Pos().Z - padding;
|
||||||
|
pitchmin = PointToPseudoPitch (bspcoord[BOXLEFT], bspcoord[BOXTOP], camz);
|
||||||
|
pitchmax = PointToPseudoPitch (bspcoord[BOXLEFT], bspcoord[BOXTOP], camz + 2.0*padding);
|
||||||
|
for (int yi = BOXTOP; yi <= BOXBOTTOM; yi++)
|
||||||
|
for (int xi = BOXLEFT; xi <= BOXRIGHT; xi++)
|
||||||
|
{
|
||||||
|
pitchtemp = PointToPseudoPitch (bspcoord[xi], bspcoord[yi], camz);
|
||||||
|
if (pitchmin - pitchtemp < ANGLE_180) pitchmin = pitchtemp;
|
||||||
|
pitchtemp = PointToPseudoPitch (bspcoord[xi], bspcoord[yi], camz + 2.0*padding);
|
||||||
|
if (pitchtemp - pitchmax < ANGLE_180) pitchmax = pitchtemp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (pitchmax != pitchmin); // SafeCheckRange(pitchmin, pitchmax);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,10 +29,11 @@ class Clipper
|
||||||
ClipNode * clipnodes = nullptr;
|
ClipNode * clipnodes = nullptr;
|
||||||
ClipNode * cliphead = nullptr;
|
ClipNode * cliphead = nullptr;
|
||||||
ClipNode * silhouette = nullptr; // will be preserved even when RemoveClipRange is called
|
ClipNode * silhouette = nullptr; // will be preserved even when RemoveClipRange is called
|
||||||
const FRenderViewpoint *viewpoint = nullptr;
|
FRenderViewpoint *viewpoint = nullptr;
|
||||||
bool blocked = false;
|
bool blocked = false;
|
||||||
|
|
||||||
static angle_t AngleToPseudo(angle_t ang);
|
static angle_t AngleToPseudo(angle_t ang);
|
||||||
|
static angle_t PitchToPseudo(double ang);
|
||||||
bool IsRangeVisible(angle_t startangle, angle_t endangle);
|
bool IsRangeVisible(angle_t startangle, angle_t endangle);
|
||||||
void RemoveRange(ClipNode * cn);
|
void RemoveRange(ClipNode * cn);
|
||||||
void AddClipRange(angle_t startangle, angle_t endangle);
|
void AddClipRange(angle_t startangle, angle_t endangle);
|
||||||
|
|
@ -41,6 +42,7 @@ class Clipper
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
bool amRadar = false;
|
||||||
Clipper();
|
Clipper();
|
||||||
|
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
@ -72,7 +74,7 @@ public:
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetViewpoint(const FRenderViewpoint &vp)
|
void SetViewpoint(FRenderViewpoint &vp)
|
||||||
{
|
{
|
||||||
viewpoint = &vp;
|
viewpoint = &vp;
|
||||||
}
|
}
|
||||||
|
|
@ -116,6 +118,10 @@ public:
|
||||||
SafeAddClipRange(AngleToPseudo(startangle), AngleToPseudo(endangle));
|
SafeAddClipRange(AngleToPseudo(startangle), AngleToPseudo(endangle));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SafeAddClipRangeDegPitches(double startpitch, double endpitch)
|
||||||
|
{
|
||||||
|
SafeAddClipRange(PitchToPseudo(startpitch), PitchToPseudo(endpitch));
|
||||||
|
}
|
||||||
|
|
||||||
void SafeRemoveClipRange(angle_t startangle, angle_t endangle)
|
void SafeRemoveClipRange(angle_t startangle, angle_t endangle)
|
||||||
{
|
{
|
||||||
|
|
@ -147,9 +153,13 @@ public:
|
||||||
return blocked;
|
return blocked;
|
||||||
}
|
}
|
||||||
|
|
||||||
angle_t PointToPseudoAngle(double x, double y);
|
angle_t PointToPseudoAngle(double x, double y);
|
||||||
|
angle_t PointToPseudoPitch(double x, double y, double z);
|
||||||
|
angle_t PointToPseudoOrthoAngle(double x, double y);
|
||||||
|
angle_t PointToPseudoOrthoPitch(double x, double y, double z);
|
||||||
|
|
||||||
bool CheckBox(const float *bspcoord);
|
bool CheckBox(const float *bspcoord);
|
||||||
|
bool CheckBoxOrthoPitch(const float *bspcoord);
|
||||||
|
|
||||||
// Used to speed up angle calculations during clipping
|
// Used to speed up angle calculations during clipping
|
||||||
inline angle_t GetClipAngle(vertex_t *v)
|
inline angle_t GetClipAngle(vertex_t *v)
|
||||||
|
|
|
||||||
|
|
@ -131,12 +131,19 @@ HWDrawInfo *HWDrawInfo::StartDrawInfo(FLevelLocals *lev, HWDrawInfo *parent, FRe
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
static Clipper staticClipper; // Since all scenes are processed sequentially we only need one clipper.
|
static Clipper staticClipper; // Since all scenes are processed sequentially we only need one clipper.
|
||||||
|
static Clipper staticVClipper; // Another clipper to clip vertically (used if (VPSF_ALLOWOUTOFBOUNDS & camera->viewpos->Flags)).
|
||||||
|
static Clipper staticRClipper; // Another clipper for radar (doesn't actually clip. Changes SSECMF_DRAWN setting).
|
||||||
static HWDrawInfo * gl_drawinfo; // This is a linked list of all active DrawInfos and needed to free the memory arena after the last one goes out of scope.
|
static HWDrawInfo * gl_drawinfo; // This is a linked list of all active DrawInfos and needed to free the memory arena after the last one goes out of scope.
|
||||||
|
|
||||||
void HWDrawInfo::StartScene(FRenderViewpoint &parentvp, HWViewpointUniforms *uniforms)
|
void HWDrawInfo::StartScene(FRenderViewpoint &parentvp, HWViewpointUniforms *uniforms)
|
||||||
{
|
{
|
||||||
staticClipper.Clear();
|
staticClipper.Clear();
|
||||||
|
staticVClipper.Clear();
|
||||||
|
staticRClipper.Clear();
|
||||||
mClipper = &staticClipper;
|
mClipper = &staticClipper;
|
||||||
|
vClipper = &staticVClipper;
|
||||||
|
rClipper = &staticRClipper;
|
||||||
|
rClipper->amRadar = true;
|
||||||
|
|
||||||
Viewpoint = parentvp;
|
Viewpoint = parentvp;
|
||||||
lightmode = getRealLightmode(Level, true);
|
lightmode = getRealLightmode(Level, true);
|
||||||
|
|
@ -169,6 +176,8 @@ void HWDrawInfo::StartScene(FRenderViewpoint &parentvp, HWViewpointUniforms *uni
|
||||||
VPUniforms.mLightBlendMode = (level.info ? (int)level.info->lightblendmode : 0);
|
VPUniforms.mLightBlendMode = (level.info ? (int)level.info->lightblendmode : 0);
|
||||||
}
|
}
|
||||||
mClipper->SetViewpoint(Viewpoint);
|
mClipper->SetViewpoint(Viewpoint);
|
||||||
|
vClipper->SetViewpoint(Viewpoint);
|
||||||
|
rClipper->SetViewpoint(Viewpoint);
|
||||||
|
|
||||||
ClearBuffers();
|
ClearBuffers();
|
||||||
|
|
||||||
|
|
@ -257,7 +266,9 @@ void HWDrawInfo::ClearBuffers()
|
||||||
|
|
||||||
void HWDrawInfo::UpdateCurrentMapSection()
|
void HWDrawInfo::UpdateCurrentMapSection()
|
||||||
{
|
{
|
||||||
const int mapsection = Level->PointInRenderSubsector(Viewpoint.Pos)->mapsection;
|
int mapsection = Level->PointInRenderSubsector(Viewpoint.Pos)->mapsection;
|
||||||
|
if (Viewpoint.IsAllowedOoB())
|
||||||
|
mapsection = Level->PointInRenderSubsector(Viewpoint.camera->Pos())->mapsection;
|
||||||
CurrentMapSections.Set(mapsection);
|
CurrentMapSections.Set(mapsection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -270,9 +281,11 @@ void HWDrawInfo::UpdateCurrentMapSection()
|
||||||
|
|
||||||
void HWDrawInfo::SetViewArea()
|
void HWDrawInfo::SetViewArea()
|
||||||
{
|
{
|
||||||
auto &vp = Viewpoint;
|
auto &vp = Viewpoint;
|
||||||
// The render_sector is better suited to represent the current position in GL
|
// The render_sector is better suited to represent the current position in GL
|
||||||
vp.sector = Level->PointInRenderSubsector(vp.Pos)->render_sector;
|
vp.sector = Level->PointInRenderSubsector(vp.Pos)->render_sector;
|
||||||
|
if (Viewpoint.IsAllowedOoB())
|
||||||
|
vp.sector = Level->PointInRenderSubsector(vp.camera->Pos())->render_sector;
|
||||||
|
|
||||||
// Get the heightsec state from the render sector, not the current one!
|
// Get the heightsec state from the render sector, not the current one!
|
||||||
if (vp.sector->GetHeightSec())
|
if (vp.sector->GetHeightSec())
|
||||||
|
|
@ -351,16 +364,14 @@ int HWDrawInfo::SetFullbrightFlags(player_t *player)
|
||||||
|
|
||||||
angle_t HWDrawInfo::FrustumAngle()
|
angle_t HWDrawInfo::FrustumAngle()
|
||||||
{
|
{
|
||||||
float tilt = fabs(Viewpoint.HWAngles.Pitch.Degrees());
|
// If pitch is larger than this you can look all around at an FOV of 90 degrees
|
||||||
|
if (fabs(Viewpoint.HWAngles.Pitch.Degrees()) > 89.0) return 0xffffffff;
|
||||||
|
|
||||||
// If the pitch is larger than this you can look all around at a FOV of 90°
|
double xratio = r_viewwindow.FocalTangent / Viewpoint.PitchCos;
|
||||||
if (tilt > 46.0f) return 0xffffffff;
|
double floatangle = 0.035 + atan ( xratio ) * 48.0 / AspectMultiplier(r_viewwindow.WidescreenRatio); // this is radians
|
||||||
|
angle_t a1 = DAngle::fromRad(floatangle).BAMs();
|
||||||
|
|
||||||
// ok, this is a gross hack that barely works...
|
if (a1 >= ANGLE_90) return 0xffffffff;
|
||||||
// but at least it doesn't overestimate too much...
|
|
||||||
double floatangle = 2.0 + (45.0 + ((tilt / 1.9)))*Viewpoint.FieldOfView.Degrees() * 48.0 / AspectMultiplier(r_viewwindow.WidescreenRatio) / 90.0;
|
|
||||||
angle_t a1 = DAngle::fromDeg(floatangle).BAMs();
|
|
||||||
if (a1 >= ANGLE_180) return 0xffffffff;
|
|
||||||
return a1;
|
return a1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -438,8 +449,12 @@ HWDecal *HWDrawInfo::AddDecal(bool onmirror)
|
||||||
void HWDrawInfo::CreateScene(bool drawpsprites)
|
void HWDrawInfo::CreateScene(bool drawpsprites)
|
||||||
{
|
{
|
||||||
const auto &vp = Viewpoint;
|
const auto &vp = Viewpoint;
|
||||||
angle_t a1 = FrustumAngle();
|
angle_t a1 = FrustumAngle(); // horizontally clip the back of the viewport
|
||||||
mClipper->SafeAddClipRangeRealAngles(vp.Angles.Yaw.BAMs() + a1, vp.Angles.Yaw.BAMs() - a1);
|
mClipper->SafeAddClipRangeRealAngles(vp.Angles.Yaw.BAMs() + a1, vp.Angles.Yaw.BAMs() - a1);
|
||||||
|
Viewpoint.FrustAngle = a1;
|
||||||
|
double a2 = 20.0 + 0.5*Viewpoint.FieldOfView.Degrees(); // FrustumPitch for vertical clipping
|
||||||
|
if (a2 > 179.0) a2 = 179.0;
|
||||||
|
vClipper->SafeAddClipRangeDegPitches(vp.HWAngles.Pitch.Degrees() - a2, vp.HWAngles.Pitch.Degrees() + a2); // clip the suplex range
|
||||||
|
|
||||||
// reset the portal manager
|
// reset the portal manager
|
||||||
portalState.StartFrame();
|
portalState.StartFrame();
|
||||||
|
|
@ -648,6 +663,79 @@ void HWDrawInfo::DrawCorona(FRenderState& state, ACorona* corona, double dist)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// TraceCallbackForDitherTransparency
|
||||||
|
// Toggles dither flag on anything that occludes the actor's
|
||||||
|
// position from viewpoint.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
static ETraceStatus TraceCallbackForDitherTransparency(FTraceResults& res, void* userdata)
|
||||||
|
{
|
||||||
|
int* count = (int*)userdata;
|
||||||
|
double bf, bc;
|
||||||
|
(*count)++;
|
||||||
|
switch(res.HitType)
|
||||||
|
{
|
||||||
|
case TRACE_HitWall:
|
||||||
|
if (!(res.Line->sidedef[res.Side]->Flags & WALLF_DITHERTRANS))
|
||||||
|
{
|
||||||
|
bf = res.Line->sidedef[res.Side]->sector->floorplane.ZatPoint(res.HitPos.XY());
|
||||||
|
bc = res.Line->sidedef[res.Side]->sector->ceilingplane.ZatPoint(res.HitPos.XY());
|
||||||
|
if ((res.HitPos.Z <= bc) && (res.HitPos.Z >= bf)) res.Line->sidedef[res.Side]->Flags |= WALLF_DITHERTRANS;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TRACE_HitFloor:
|
||||||
|
res.Sector->floorplane.dithertransflag = true;
|
||||||
|
break;
|
||||||
|
case TRACE_HitCeiling:
|
||||||
|
res.Sector->ceilingplane.dithertransflag = true;
|
||||||
|
break;
|
||||||
|
case TRACE_HitActor:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRACE_ContinueOutOfBounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void HWDrawInfo::SetDitherTransFlags(AActor* actor)
|
||||||
|
{
|
||||||
|
if (actor && actor->Sector)
|
||||||
|
{
|
||||||
|
FTraceResults results;
|
||||||
|
double horix = Viewpoint.Sin * actor->radius;
|
||||||
|
double horiy = Viewpoint.Cos * actor->radius;
|
||||||
|
DVector3 actorpos = actor->Pos();
|
||||||
|
DVector3 vvec = actorpos - Viewpoint.Pos;
|
||||||
|
if (Viewpoint.IsOrtho())
|
||||||
|
{
|
||||||
|
vvec += Viewpoint.camera->Pos() - actorpos;
|
||||||
|
vvec *= 5.0; // Should be 4.0? (since zNear is behind screen by 3*dist in VREyeInfo::GetProjection())
|
||||||
|
}
|
||||||
|
double distance = vvec.Length() - actor->radius;
|
||||||
|
DVector3 campos = actorpos - vvec;
|
||||||
|
sector_t* startsec;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
vvec = vvec.Unit();
|
||||||
|
campos.X -= horix; campos.Y += horiy; campos.Z += actor->Height * 0.25;
|
||||||
|
for (int iter = 0; iter < 3; iter++)
|
||||||
|
{
|
||||||
|
startsec = Level->PointInRenderSubsector(campos)->sector;
|
||||||
|
Trace(campos, startsec, vvec, distance,
|
||||||
|
0, 0, actor, results, 0, TraceCallbackForDitherTransparency, &count);
|
||||||
|
campos.Z += actor->Height * 0.5;
|
||||||
|
Trace(campos, startsec, vvec, distance,
|
||||||
|
0, 0, actor, results, 0, TraceCallbackForDitherTransparency, &count);
|
||||||
|
campos.Z -= actor->Height * 0.5;
|
||||||
|
campos.X += horix; campos.Y -= horiy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static ETraceStatus CheckForViewpointActor(FTraceResults& res, void* userdata)
|
static ETraceStatus CheckForViewpointActor(FTraceResults& res, void* userdata)
|
||||||
{
|
{
|
||||||
FRenderViewpoint* data = (FRenderViewpoint*)userdata;
|
FRenderViewpoint* data = (FRenderViewpoint*)userdata;
|
||||||
|
|
@ -803,13 +891,17 @@ void HWDrawInfo::DrawScene(int drawmode)
|
||||||
{
|
{
|
||||||
static int recursion = 0;
|
static int recursion = 0;
|
||||||
static int ssao_portals_available = 0;
|
static int ssao_portals_available = 0;
|
||||||
const auto& vp = Viewpoint;
|
auto& vp = Viewpoint;
|
||||||
|
|
||||||
bool applySSAO = false;
|
bool applySSAO = false;
|
||||||
if (drawmode == DM_MAINVIEW)
|
if (drawmode == DM_MAINVIEW)
|
||||||
{
|
{
|
||||||
ssao_portals_available = gl_ssao_portals;
|
ssao_portals_available = gl_ssao_portals;
|
||||||
applySSAO = true;
|
applySSAO = true;
|
||||||
|
if (r_dithertransparency && vp.IsAllowedOoB())
|
||||||
|
{
|
||||||
|
vp.camera->tracer ? SetDitherTransFlags(vp.camera->tracer) : SetDitherTransFlags(players[consoleplayer].mo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (drawmode == DM_OFFSCREEN)
|
else if (drawmode == DM_OFFSCREEN)
|
||||||
{
|
{
|
||||||
|
|
@ -864,6 +956,8 @@ void HWDrawInfo::ProcessScene(bool toscreen)
|
||||||
portalState.BeginScene();
|
portalState.BeginScene();
|
||||||
|
|
||||||
int mapsection = Level->PointInRenderSubsector(Viewpoint.Pos)->mapsection;
|
int mapsection = Level->PointInRenderSubsector(Viewpoint.Pos)->mapsection;
|
||||||
|
if (Viewpoint.IsAllowedOoB())
|
||||||
|
mapsection = Level->PointInRenderSubsector(Viewpoint.camera->Pos())->mapsection;
|
||||||
CurrentMapSections.Set(mapsection);
|
CurrentMapSections.Set(mapsection);
|
||||||
DrawScene(toscreen ? DM_MAINVIEW : DM_OFFSCREEN);
|
DrawScene(toscreen ? DM_MAINVIEW : DM_OFFSCREEN);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -146,6 +146,8 @@ struct HWDrawInfo
|
||||||
HWPortal *mCurrentPortal;
|
HWPortal *mCurrentPortal;
|
||||||
//FRotator mAngles;
|
//FRotator mAngles;
|
||||||
Clipper *mClipper;
|
Clipper *mClipper;
|
||||||
|
Clipper *vClipper; // Vertical clipper
|
||||||
|
Clipper *rClipper; // Radar clipper
|
||||||
FRenderViewpoint Viewpoint;
|
FRenderViewpoint Viewpoint;
|
||||||
HWViewpointUniforms VPUniforms; // per-viewpoint uniform state
|
HWViewpointUniforms VPUniforms; // per-viewpoint uniform state
|
||||||
TArray<HWPortal *> Portals;
|
TArray<HWPortal *> Portals;
|
||||||
|
|
@ -234,6 +236,7 @@ public:
|
||||||
|
|
||||||
HWPortal * FindPortal(const void * src);
|
HWPortal * FindPortal(const void * src);
|
||||||
void RenderBSPNode(void *node);
|
void RenderBSPNode(void *node);
|
||||||
|
void RenderOrthoNoFog();
|
||||||
void RenderBSP(void *node, bool drawpsprites);
|
void RenderBSP(void *node, bool drawpsprites);
|
||||||
|
|
||||||
static HWDrawInfo *StartDrawInfo(FLevelLocals *lev, HWDrawInfo *parent, FRenderViewpoint &parentvp, HWViewpointUniforms *uniforms);
|
static HWDrawInfo *StartDrawInfo(FLevelLocals *lev, HWDrawInfo *parent, FRenderViewpoint &parentvp, HWViewpointUniforms *uniforms);
|
||||||
|
|
@ -302,6 +305,8 @@ public:
|
||||||
void DrawCoronas(FRenderState& state);
|
void DrawCoronas(FRenderState& state);
|
||||||
void DrawCorona(FRenderState& state, ACorona* corona, double dist);
|
void DrawCorona(FRenderState& state, ACorona* corona, double dist);
|
||||||
|
|
||||||
|
void SetDitherTransFlags(AActor* actor);
|
||||||
|
|
||||||
void ProcessLowerMinisegs(TArray<seg_t *> &lowersegs);
|
void ProcessLowerMinisegs(TArray<seg_t *> &lowersegs);
|
||||||
void AddSubsectorToPortal(FSectorPortalGroup *portal, subsector_t *sub);
|
void AddSubsectorToPortal(FSectorPortalGroup *portal, subsector_t *sub);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -320,7 +320,7 @@ void HWFlat::DrawFlat(HWDrawInfo *di, FRenderState &state, bool translucent)
|
||||||
state.SetObjectColor(FlatColor | 0xff000000);
|
state.SetObjectColor(FlatColor | 0xff000000);
|
||||||
state.SetAddColor(AddColor | 0xff000000);
|
state.SetAddColor(AddColor | 0xff000000);
|
||||||
state.ApplyTextureManipulation(TextureFx);
|
state.ApplyTextureManipulation(TextureFx);
|
||||||
|
if (plane.plane.dithertransflag) state.SetEffect(EFF_DITHERTRANS);
|
||||||
|
|
||||||
if (hacktype & SSRF_PLANEHACK)
|
if (hacktype & SSRF_PLANEHACK)
|
||||||
{
|
{
|
||||||
|
|
@ -372,6 +372,7 @@ void HWFlat::DrawFlat(HWDrawInfo *di, FRenderState &state, bool translucent)
|
||||||
state.SetObjectColor(0xffffffff);
|
state.SetObjectColor(0xffffffff);
|
||||||
state.SetAddColor(0);
|
state.SetAddColor(0);
|
||||||
state.ApplyTextureManipulation(nullptr);
|
state.ApplyTextureManipulation(nullptr);
|
||||||
|
if (plane.plane.dithertransflag) state.SetEffect(EFF_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
@ -408,6 +409,8 @@ inline void HWFlat::PutFlat(HWDrawInfo *di, bool fog)
|
||||||
void HWFlat::Process(HWDrawInfo *di, sector_t * model, int whichplane, bool fog)
|
void HWFlat::Process(HWDrawInfo *di, sector_t * model, int whichplane, bool fog)
|
||||||
{
|
{
|
||||||
plane.GetFromSector(model, whichplane);
|
plane.GetFromSector(model, whichplane);
|
||||||
|
model->ceilingplane.dithertransflag = false; // Resetting this every frame
|
||||||
|
model->floorplane.dithertransflag = false; // Resetting this every frame
|
||||||
if (whichplane != int(ceiling))
|
if (whichplane != int(ceiling))
|
||||||
{
|
{
|
||||||
// Flip the normal if the source plane has a different orientation than what we are about to render.
|
// Flip the normal if the source plane has a different orientation than what we are about to render.
|
||||||
|
|
@ -506,7 +509,7 @@ void HWFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector, int which)
|
||||||
|
|
||||||
uint8_t sink;
|
uint8_t sink;
|
||||||
uint8_t &srf = hacktype? sink : di->section_renderflags[di->Level->sections.SectionIndex(section)];
|
uint8_t &srf = hacktype? sink : di->section_renderflags[di->Level->sections.SectionIndex(section)];
|
||||||
const auto &vp = di->Viewpoint;
|
auto &vp = di->Viewpoint;
|
||||||
|
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
|
@ -515,7 +518,7 @@ void HWFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector, int which)
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
if ((which & SSRF_RENDERFLOOR) && frontsector->floorplane.ZatPoint(vp.Pos) <= vp.Pos.Z && (!section || !(section->flags & FSection::DONTRENDERFLOOR)))
|
if (((which & SSRF_RENDERFLOOR) && frontsector->floorplane.ZatPoint(vp.Pos) <= vp.Pos.Z && (!section || !(section->flags & FSection::DONTRENDERFLOOR)))&& !(vp.IsOrtho() && (vp.PitchSin < 0.0)))
|
||||||
{
|
{
|
||||||
// process the original floor first.
|
// process the original floor first.
|
||||||
|
|
||||||
|
|
@ -573,7 +576,7 @@ void HWFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector, int which)
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
if ((which & SSRF_RENDERCEILING) && frontsector->ceilingplane.ZatPoint(vp.Pos) >= vp.Pos.Z && (!section || !(section->flags & FSection::DONTRENDERCEILING)))
|
if (((which & SSRF_RENDERCEILING) && frontsector->ceilingplane.ZatPoint(vp.Pos) >= vp.Pos.Z && (!section || !(section->flags & FSection::DONTRENDERCEILING))) && !(vp.IsOrtho() && (vp.PitchSin > 0.0)))
|
||||||
{
|
{
|
||||||
// process the original ceiling first.
|
// process the original ceiling first.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -563,7 +563,8 @@ bool HWMirrorPortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *clippe
|
||||||
angle_t af = di->FrustumAngle();
|
angle_t af = di->FrustumAngle();
|
||||||
if (af < ANGLE_180) clipper->SafeAddClipRangeRealAngles(vp.Angles.Yaw.BAMs() + af, vp.Angles.Yaw.BAMs() - af);
|
if (af < ANGLE_180) clipper->SafeAddClipRangeRealAngles(vp.Angles.Yaw.BAMs() + af, vp.Angles.Yaw.BAMs() - af);
|
||||||
|
|
||||||
clipper->SafeAddClipRange(linedef->v1, linedef->v2);
|
if(!di->Viewpoint.IsAllowedOoB())
|
||||||
|
clipper->SafeAddClipRange(linedef->v1, linedef->v2);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,7 @@ void HWSkyInfo::init(HWDrawInfo *di, sector_t* sec, int skypos, int sky1, PalEnt
|
||||||
void HWWall::SkyPlane(HWWallDispatcher *di, sector_t *sector, int plane, bool allowreflect)
|
void HWWall::SkyPlane(HWWallDispatcher *di, sector_t *sector, int plane, bool allowreflect)
|
||||||
{
|
{
|
||||||
int ptype = -1;
|
int ptype = -1;
|
||||||
|
if (di->di && di->di->Viewpoint.IsAllowedOoB()) return; // Couldn't prevent sky portal occlusion. Skybox is bad in ortho too.
|
||||||
|
|
||||||
FSectorPortal *sportal = sector->ValidatePortal(plane);
|
FSectorPortal *sportal = sector->ValidatePortal(plane);
|
||||||
if (sportal != nullptr && sportal->mFlags & PORTSF_INSKYBOX) sportal = nullptr; // no recursions, delete it here to simplify the following code
|
if (sportal != nullptr && sportal->mFlags & PORTSF_INSKYBOX) sportal = nullptr; // no recursions, delete it here to simplify the following code
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,7 @@ extern TArray<spriteframe_t> SpriteFrames;
|
||||||
extern uint32_t r_renderercaps;
|
extern uint32_t r_renderercaps;
|
||||||
|
|
||||||
const float LARGE_VALUE = 1e19f;
|
const float LARGE_VALUE = 1e19f;
|
||||||
|
const float MY_SQRT2 = 1.41421356237309504880; // sqrt(2)
|
||||||
|
|
||||||
EXTERN_CVAR(Bool, r_debug_disable_vis_filter)
|
EXTERN_CVAR(Bool, r_debug_disable_vis_filter)
|
||||||
EXTERN_CVAR(Float, transsouls)
|
EXTERN_CVAR(Float, transsouls)
|
||||||
|
|
@ -494,7 +495,7 @@ bool HWSprite::CalculateVertices(HWDrawInfo* di, FVector3* v, DVector3* vp)
|
||||||
}
|
}
|
||||||
else // traditional "Y" billboard mode
|
else // traditional "Y" billboard mode
|
||||||
{
|
{
|
||||||
if (doRoll || !offset.isZero())
|
if (doRoll || !offset.isZero() || (actor && (actor->renderflags2 & RF2_ISOMETRICSPRITES)))
|
||||||
{
|
{
|
||||||
mat.MakeIdentity();
|
mat.MakeIdentity();
|
||||||
|
|
||||||
|
|
@ -516,6 +517,16 @@ bool HWSprite::CalculateVertices(HWDrawInfo* di, FVector3* v, DVector3* vp)
|
||||||
mat.Translate(-center.X, -center.Z, -center.Y);
|
mat.Translate(-center.X, -center.Z, -center.Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (actor && (actor->renderflags2 & RF2_ISOMETRICSPRITES) && di->Viewpoint.IsOrtho())
|
||||||
|
{
|
||||||
|
float angleRad = (FAngle::fromDeg(270.) - HWAngles.Yaw).Radians();
|
||||||
|
mat.Translate(center.X, center.Z, center.Y);
|
||||||
|
mat.Translate(0.0, z2 - center.Z, 0.0);
|
||||||
|
mat.Rotate(-sin(angleRad), 0, cos(angleRad), -actor->isotheta);
|
||||||
|
mat.Translate(0.0, center.Z - z2, 0.0);
|
||||||
|
mat.Translate(-center.X, -center.Z, -center.Y);
|
||||||
|
}
|
||||||
|
|
||||||
v[0] = mat * FVector3(x1, z1, y1);
|
v[0] = mat * FVector3(x1, z1, y1);
|
||||||
v[1] = mat * FVector3(x2, z1, y2);
|
v[1] = mat * FVector3(x2, z1, y2);
|
||||||
v[2] = mat * FVector3(x1, z2, y1);
|
v[2] = mat * FVector3(x1, z2, y1);
|
||||||
|
|
@ -911,6 +922,7 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
|
||||||
{
|
{
|
||||||
bool mirror = false;
|
bool mirror = false;
|
||||||
DAngle ang = (thingpos - vp.Pos).Angle();
|
DAngle ang = (thingpos - vp.Pos).Angle();
|
||||||
|
if (di->Viewpoint.IsOrtho()) ang = vp.Angles.Yaw;
|
||||||
FTextureID patch;
|
FTextureID patch;
|
||||||
// [ZZ] add direct picnum override
|
// [ZZ] add direct picnum override
|
||||||
if (isPicnumOverride)
|
if (isPicnumOverride)
|
||||||
|
|
@ -1004,7 +1016,25 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
|
||||||
if (thing->renderflags & RF_SPRITEFLIP) // [SP] Flip back
|
if (thing->renderflags & RF_SPRITEFLIP) // [SP] Flip back
|
||||||
thing->renderflags ^= RF_XFLIP;
|
thing->renderflags ^= RF_XFLIP;
|
||||||
|
|
||||||
r.Scale(sprscale.X, isSpriteShadow ? sprscale.Y * 0.15 : sprscale.Y);
|
// If sprite is isometric, do both vertical scaling and partial rotation to face the camera to compensate for Y-billboarding.
|
||||||
|
// Using just rotation (about z=0) might cause tall+slender (high aspect ratio) sprites to clip out of collision box
|
||||||
|
// at the top and clip into whatever is behind them from the viewpoint's perspective. - [DVR]
|
||||||
|
thing->isoscaleY = 1.0;
|
||||||
|
thing->isotheta = vp.HWAngles.Pitch.Degrees();
|
||||||
|
if (thing->renderflags2 & RF2_ISOMETRICSPRITES)
|
||||||
|
{
|
||||||
|
float floordist = thing->radius * vp.floordistfact;
|
||||||
|
floordist -= 0.5 * r.width * vp.cotfloor;
|
||||||
|
float sineisotheta = floordist / r.height;
|
||||||
|
double scl = g_sqrt( 1.0 + sineisotheta * sineisotheta - 2.0 * vp.PitchSin * sineisotheta );
|
||||||
|
if ((thing->radius > 0.0) && (scl > fabs(vp.PitchCos)))
|
||||||
|
{
|
||||||
|
thing->isoscaleY = scl / ( fabs(vp.PitchCos) > 0.01 ? fabs(vp.PitchCos) : 0.01 );
|
||||||
|
thing->isotheta = 180.0 * asin( sineisotheta / thing->isoscaleY ) / M_PI;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Scale(sprscale.X, isSpriteShadow ? sprscale.Y * 0.15 * thing->isoscaleY : sprscale.Y * thing->isoscaleY);
|
||||||
|
|
||||||
if (thing->renderflags & (RF_ROLLSPRITE|RF_FLATSPRITE))
|
if (thing->renderflags & (RF_ROLLSPRITE|RF_FLATSPRITE))
|
||||||
{
|
{
|
||||||
|
|
@ -1018,7 +1048,7 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
|
||||||
z1 = z - r.top;
|
z1 = z - r.top;
|
||||||
z2 = z1 - r.height;
|
z2 = z1 - r.height;
|
||||||
|
|
||||||
float spriteheight = sprscale.Y * r.height;
|
float spriteheight = sprscale.Y * r.height * thing->isoscaleY;
|
||||||
|
|
||||||
// Tests show that this doesn't look good for many decorations and corpses
|
// Tests show that this doesn't look good for many decorations and corpses
|
||||||
if (spriteheight > 0 && gl_spriteclip > 0 && (thing->renderflags & RF_SPRITETYPEMASK) == RF_FACESPRITE)
|
if (spriteheight > 0 && gl_spriteclip > 0 && (thing->renderflags & RF_SPRITETYPEMASK) == RF_FACESPRITE)
|
||||||
|
|
@ -1037,6 +1067,13 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
|
||||||
x2 = x - viewvecY*rightfac;
|
x2 = x - viewvecY*rightfac;
|
||||||
y1 = y + viewvecX*leftfac;
|
y1 = y + viewvecX*leftfac;
|
||||||
y2 = y + viewvecX*rightfac;
|
y2 = y + viewvecX*rightfac;
|
||||||
|
if (thing->renderflags2 & RF2_ISOMETRICSPRITES) // If sprites are drawn from an isometric perspective
|
||||||
|
{
|
||||||
|
x1 -= viewvecX * thing->radius * MY_SQRT2;
|
||||||
|
x2 -= viewvecX * thing->radius * MY_SQRT2;
|
||||||
|
y1 -= viewvecY * thing->radius * MY_SQRT2;
|
||||||
|
y2 -= viewvecY * thing->radius * MY_SQRT2;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case RF_FLATSPRITE:
|
case RF_FLATSPRITE:
|
||||||
|
|
@ -1077,6 +1114,7 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
|
||||||
}
|
}
|
||||||
|
|
||||||
depth = (float)((x - vp.Pos.X) * vp.TanCos + (y - vp.Pos.Y) * vp.TanSin);
|
depth = (float)((x - vp.Pos.X) * vp.TanCos + (y - vp.Pos.Y) * vp.TanSin);
|
||||||
|
if(thing->renderflags2 & RF2_ISOMETRICSPRITES) depth = depth * vp.PitchCos - vp.PitchSin * z2; // Helps with stacking actors with small xy offsets
|
||||||
if (isSpriteShadow) depth += 1.f/65536.f; // always sort shadows behind the sprite.
|
if (isSpriteShadow) depth += 1.f/65536.f; // always sort shadows behind the sprite.
|
||||||
|
|
||||||
// light calculation
|
// light calculation
|
||||||
|
|
|
||||||
|
|
@ -83,10 +83,16 @@ void SetSplitPlanes(FRenderState& state, const secplane_t& top, const secplane_t
|
||||||
|
|
||||||
void HWWall::RenderWall(FRenderState &state, int textured)
|
void HWWall::RenderWall(FRenderState &state, int textured)
|
||||||
{
|
{
|
||||||
|
if (seg->sidedef->Flags & WALLF_DITHERTRANS) state.SetEffect(EFF_DITHERTRANS);
|
||||||
assert(vertcount > 0);
|
assert(vertcount > 0);
|
||||||
state.SetLightIndex(dynlightindex);
|
state.SetLightIndex(dynlightindex);
|
||||||
state.Draw(DT_TriangleFan, vertindex, vertcount);
|
state.Draw(DT_TriangleFan, vertindex, vertcount);
|
||||||
vertexcount += vertcount;
|
vertexcount += vertcount;
|
||||||
|
if (seg->sidedef->Flags & WALLF_DITHERTRANS)
|
||||||
|
{
|
||||||
|
state.SetEffect(EFF_NONE);
|
||||||
|
seg->sidedef->Flags &= ~WALLF_DITHERTRANS; // reset this every frame
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
@ -2175,6 +2181,8 @@ void HWWall::Process(HWWallDispatcher *di, seg_t *seg, sector_t * frontsector, s
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isportal = seg->linedef->isVisualPortal() && seg->sidedef == seg->linedef->sidedef[0];
|
bool isportal = seg->linedef->isVisualPortal() && seg->sidedef == seg->linedef->sidedef[0];
|
||||||
|
// Don't render portal insides if in orthographic mode
|
||||||
|
if (di->di) isportal &= !(di->di->Viewpoint.IsOrtho());
|
||||||
|
|
||||||
//return;
|
//return;
|
||||||
// [GZ] 3D middle textures are necessarily two-sided, even if they lack the explicit two-sided flag
|
// [GZ] 3D middle textures are necessarily two-sided, even if they lack the explicit two-sided flag
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,9 @@
|
||||||
#include "i_system.h"
|
#include "i_system.h"
|
||||||
#include "v_draw.h"
|
#include "v_draw.h"
|
||||||
#include "i_interface.h"
|
#include "i_interface.h"
|
||||||
|
#include "d_main.h"
|
||||||
|
|
||||||
|
const float MY_SQRT2 = 1.41421356237309504880; // sqrt(2)
|
||||||
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
|
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
|
||||||
|
|
||||||
extern bool DrawFSHUD; // [RH] Defined in d_main.cpp
|
extern bool DrawFSHUD; // [RH] Defined in d_main.cpp
|
||||||
|
|
@ -103,6 +105,8 @@ CVAR (Bool, r_deathcamera, false, CVAR_ARCHIVE)
|
||||||
CVAR (Int, r_clearbuffer, 0, 0)
|
CVAR (Int, r_clearbuffer, 0, 0)
|
||||||
CVAR (Bool, r_drawvoxels, true, 0)
|
CVAR (Bool, r_drawvoxels, true, 0)
|
||||||
CVAR (Bool, r_drawplayersprites, true, 0) // [RH] Draw player sprites?
|
CVAR (Bool, r_drawplayersprites, true, 0) // [RH] Draw player sprites?
|
||||||
|
CVARD (Bool, r_radarclipper, false, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_CHEAT, "Use the horizontal clipper from camera->tracer's perspective")
|
||||||
|
CVARD (Bool, r_dithertransparency, false, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_CHEAT, "Use dithered-transparency shading for actor-occluding level geometry")
|
||||||
CUSTOM_CVAR(Float, r_quakeintensity, 1.0f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
CUSTOM_CVAR(Float, r_quakeintensity, 1.0f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||||
{
|
{
|
||||||
if (self < 0.f) self = 0.f;
|
if (self < 0.f) self = 0.f;
|
||||||
|
|
@ -155,9 +159,14 @@ FRenderViewpoint::FRenderViewpoint()
|
||||||
Sin = 0.0;
|
Sin = 0.0;
|
||||||
TanCos = 0.0;
|
TanCos = 0.0;
|
||||||
TanSin = 0.0;
|
TanSin = 0.0;
|
||||||
|
PitchCos = 0.0;
|
||||||
|
PitchSin = 0.0;
|
||||||
|
floordistfact = 0.0;
|
||||||
|
cotfloor = 0.0;
|
||||||
camera = nullptr;
|
camera = nullptr;
|
||||||
sector = nullptr;
|
sector = nullptr;
|
||||||
FieldOfView = DAngle::fromDeg(90.); // Angles in the SCREENWIDTH wide window
|
FieldOfView = DAngle::fromDeg(90.); // Angles in the SCREENWIDTH wide window
|
||||||
|
ScreenProj = 0.0;
|
||||||
TicFrac = 0.0;
|
TicFrac = 0.0;
|
||||||
FrameTime = 0;
|
FrameTime = 0;
|
||||||
extralight = 0;
|
extralight = 0;
|
||||||
|
|
@ -552,39 +561,42 @@ void R_InterpolateView(FRenderViewpoint& viewPoint, const player_t* const player
|
||||||
|
|
||||||
// Due to interpolation this is not necessarily the same as the sector the camera is in.
|
// Due to interpolation this is not necessarily the same as the sector the camera is in.
|
||||||
viewPoint.sector = viewLvl->PointInRenderSubsector(viewPoint.Pos)->sector;
|
viewPoint.sector = viewLvl->PointInRenderSubsector(viewPoint.Pos)->sector;
|
||||||
bool moved = false;
|
if (!viewPoint.IsAllowedOoB() || !V_IsHardwareRenderer())
|
||||||
while (!viewPoint.sector->PortalBlocksMovement(sector_t::ceiling))
|
|
||||||
{
|
{
|
||||||
if (viewPoint.Pos.Z > viewPoint.sector->GetPortalPlaneZ(sector_t::ceiling))
|
bool moved = false;
|
||||||
|
while (!viewPoint.sector->PortalBlocksMovement(sector_t::ceiling))
|
||||||
{
|
{
|
||||||
const DVector2 offset = viewPoint.sector->GetPortalDisplacement(sector_t::ceiling);
|
if (viewPoint.Pos.Z > viewPoint.sector->GetPortalPlaneZ(sector_t::ceiling))
|
||||||
viewPoint.Pos += offset;
|
|
||||||
viewPoint.ActorPos += offset;
|
|
||||||
viewPoint.sector = viewPoint.sector->GetPortal(sector_t::ceiling)->mDestination;
|
|
||||||
moved = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!moved)
|
|
||||||
{
|
|
||||||
while (!viewPoint.sector->PortalBlocksMovement(sector_t::floor))
|
|
||||||
{
|
|
||||||
if (viewPoint.Pos.Z < viewPoint.sector->GetPortalPlaneZ(sector_t::floor))
|
|
||||||
{
|
{
|
||||||
const DVector2 offset = viewPoint.sector->GetPortalDisplacement(sector_t::floor);
|
const DVector2 offset = viewPoint.sector->GetPortalDisplacement(sector_t::ceiling);
|
||||||
viewPoint.Pos += offset;
|
viewPoint.Pos += offset;
|
||||||
viewPoint.ActorPos += offset;
|
viewPoint.ActorPos += offset;
|
||||||
viewPoint.sector = viewPoint.sector->GetPortal(sector_t::floor)->mDestination;
|
viewPoint.sector = viewPoint.sector->GetPortal(sector_t::ceiling)->mDestination;
|
||||||
|
moved = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!moved)
|
||||||
|
{
|
||||||
|
while (!viewPoint.sector->PortalBlocksMovement(sector_t::floor))
|
||||||
|
{
|
||||||
|
if (viewPoint.Pos.Z < viewPoint.sector->GetPortalPlaneZ(sector_t::floor))
|
||||||
|
{
|
||||||
|
const DVector2 offset = viewPoint.sector->GetPortalDisplacement(sector_t::floor);
|
||||||
|
viewPoint.Pos += offset;
|
||||||
|
viewPoint.ActorPos += offset;
|
||||||
|
viewPoint.sector = viewPoint.sector->GetPortal(sector_t::floor)->mDestination;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (P_NoInterpolation(player, viewPoint.camera))
|
if (P_NoInterpolation(player, viewPoint.camera))
|
||||||
|
|
@ -680,10 +692,46 @@ void FRenderViewpoint::SetViewAngle(const FViewWindow& viewWindow)
|
||||||
TanSin = viewWindow.FocalTangent * Sin;
|
TanSin = viewWindow.FocalTangent * Sin;
|
||||||
TanCos = viewWindow.FocalTangent * Cos;
|
TanCos = viewWindow.FocalTangent * Cos;
|
||||||
|
|
||||||
|
PitchSin = Angles.Pitch.Sin();
|
||||||
|
PitchCos = Angles.Pitch.Cos();
|
||||||
|
|
||||||
|
floordistfact = MY_SQRT2 + ( fabs(Cos) > fabs(Sin) ? 1.0/fabs(Cos) : 1.0/fabs(Sin) );
|
||||||
|
cotfloor = ( fabs(Cos) > fabs(Sin) ? fabs(Sin/Cos) : fabs(Cos/Sin) );
|
||||||
|
|
||||||
const DVector2 v = Angles.Yaw.ToVector();
|
const DVector2 v = Angles.Yaw.ToVector();
|
||||||
ViewVector.X = v.X;
|
ViewVector.X = v.X;
|
||||||
ViewVector.Y = v.Y;
|
ViewVector.Y = v.Y;
|
||||||
HWAngles.Yaw = FAngle::fromDeg(270.0 - Angles.Yaw.Degrees());
|
HWAngles.Yaw = FAngle::fromDeg(270.0 - Angles.Yaw.Degrees());
|
||||||
|
|
||||||
|
if (IsOrtho() && (camera->ViewPos->Offset.XY().Length() > 0.0))
|
||||||
|
ScreenProj = 1.34396 / camera->ViewPos->Offset.Length(); // [DVR] Estimated. +/-1 should be top/bottom of screen.
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// R_IsAllowedOoB()
|
||||||
|
// Checks if camera actor exists, has viewpos,
|
||||||
|
// and viewpos has VPSF_ALLOWOUTOFBOUNDS flag set.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
bool FRenderViewpoint::IsAllowedOoB()
|
||||||
|
{
|
||||||
|
return (camera && camera->ViewPos && (camera->ViewPos->Flags & VPSF_ALLOWOUTOFBOUNDS));
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// R_IsOrtho()
|
||||||
|
// Checks if camera actor exists, has viewpos,
|
||||||
|
// and viewpos has VPSF_ORTHOGRAPHIC flag set.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
bool FRenderViewpoint::IsOrtho()
|
||||||
|
{
|
||||||
|
return (camera && camera->ViewPos && (camera->ViewPos->Flags & VPSF_ORTHOGRAPHIC));
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
@ -1017,14 +1065,15 @@ void R_SetupFrame(FRenderViewpoint& viewPoint, const FViewWindow& viewWindow, AA
|
||||||
viewPoint.SetViewAngle(viewWindow);
|
viewPoint.SetViewAngle(viewWindow);
|
||||||
|
|
||||||
// Keep the view within the sector's floor and ceiling
|
// Keep the view within the sector's floor and ceiling
|
||||||
if (viewPoint.sector->PortalBlocksMovement(sector_t::ceiling))
|
// But allow VPSF_ALLOWOUTOFBOUNDS camera viewpoints to go out of bounds when using hardware renderer
|
||||||
|
if (viewPoint.sector->PortalBlocksMovement(sector_t::ceiling) && (!viewPoint.IsAllowedOoB() || !V_IsHardwareRenderer()))
|
||||||
{
|
{
|
||||||
const double z = viewPoint.sector->ceilingplane.ZatPoint(viewPoint.Pos) - 4.0;
|
const double z = viewPoint.sector->ceilingplane.ZatPoint(viewPoint.Pos) - 4.0;
|
||||||
if (viewPoint.Pos.Z > z)
|
if (viewPoint.Pos.Z > z)
|
||||||
viewPoint.Pos.Z = z;
|
viewPoint.Pos.Z = z;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (viewPoint.sector->PortalBlocksMovement(sector_t::floor))
|
if (viewPoint.sector->PortalBlocksMovement(sector_t::floor) && (!viewPoint.IsAllowedOoB() || !V_IsHardwareRenderer()))
|
||||||
{
|
{
|
||||||
const double z = viewPoint.sector->floorplane.ZatPoint(viewPoint.Pos) + 4.0;
|
const double z = viewPoint.sector->floorplane.ZatPoint(viewPoint.Pos) + 4.0;
|
||||||
if (viewPoint.Pos.Z < z)
|
if (viewPoint.Pos.Z < z)
|
||||||
|
|
|
||||||
|
|
@ -33,10 +33,16 @@ struct FRenderViewpoint
|
||||||
double Sin; // sin(Angles.Yaw)
|
double Sin; // sin(Angles.Yaw)
|
||||||
double TanCos; // FocalTangent * cos(Angles.Yaw)
|
double TanCos; // FocalTangent * cos(Angles.Yaw)
|
||||||
double TanSin; // FocalTangent * sin(Angles.Yaw)
|
double TanSin; // FocalTangent * sin(Angles.Yaw)
|
||||||
|
double PitchCos; // cos(Angles.Pitch)
|
||||||
|
double PitchSin; // sin(Angles.Pitch)
|
||||||
|
double floordistfact; // used for isometric sprites Y-billboarding compensation in hw_sprites.cpp
|
||||||
|
double cotfloor; // used for isometric sprites Y-billboarding compensation in hw_sprites.cpp
|
||||||
|
angle_t FrustAngle; // FrustumAngle() result
|
||||||
|
|
||||||
AActor *camera; // camera actor
|
AActor *camera; // camera actor
|
||||||
sector_t *sector; // [RH] keep track of sector viewing from
|
sector_t *sector; // [RH] keep track of sector viewing from
|
||||||
DAngle FieldOfView; // current field of view
|
DAngle FieldOfView; // current field of view
|
||||||
|
double ScreenProj; // Screen projection factor for orthographic projection
|
||||||
|
|
||||||
double TicFrac; // fraction of tic for interpolation
|
double TicFrac; // fraction of tic for interpolation
|
||||||
uint32_t FrameTime; // current frame's time in tics.
|
uint32_t FrameTime; // current frame's time in tics.
|
||||||
|
|
@ -45,6 +51,8 @@ struct FRenderViewpoint
|
||||||
bool showviewer; // show the camera actor?
|
bool showviewer; // show the camera actor?
|
||||||
bool bForceNoViewer; // Never show the camera Actor.
|
bool bForceNoViewer; // Never show the camera Actor.
|
||||||
void SetViewAngle(const FViewWindow& viewWindow);
|
void SetViewAngle(const FViewWindow& viewWindow);
|
||||||
|
bool IsAllowedOoB(); // Checks if camera actor exists, has viewpos, and viewpos has VPSF_ALLOWOUTOFBOUNDS flag set
|
||||||
|
bool IsOrtho(); // Checks if camera actor exists, has viewpos, and viewpos has VPSF_ORTHOGRAPHIC flag set
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -385,6 +385,7 @@ static FFlagDef ActorFlagDefs[]=
|
||||||
DEFINE_FLAG(RF2, FLIPSPRITEOFFSETY, AActor, renderflags2),
|
DEFINE_FLAG(RF2, FLIPSPRITEOFFSETY, AActor, renderflags2),
|
||||||
DEFINE_FLAG(RF2, CAMFOLLOWSPLAYER, AActor, renderflags2),
|
DEFINE_FLAG(RF2, CAMFOLLOWSPLAYER, AActor, renderflags2),
|
||||||
DEFINE_FLAG(RF2, NOMIPMAP, AActor, renderflags2),
|
DEFINE_FLAG(RF2, NOMIPMAP, AActor, renderflags2),
|
||||||
|
DEFINE_FLAG(RF2, ISOMETRICSPRITES, AActor, renderflags2),
|
||||||
|
|
||||||
// Bounce flags
|
// Bounce flags
|
||||||
DEFINE_FLAG2(BOUNCE_Walls, BOUNCEONWALLS, AActor, BounceFlags),
|
DEFINE_FLAG2(BOUNCE_Walls, BOUNCEONWALLS, AActor, BounceFlags),
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,23 @@ const int TEXF_Detailmap = 0x20000;
|
||||||
const int TEXF_Glowmap = 0x40000;
|
const int TEXF_Glowmap = 0x40000;
|
||||||
const int TEXF_ClampY = 0x80000;
|
const int TEXF_ClampY = 0x80000;
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
//
|
||||||
|
// RGB to HSV
|
||||||
|
//
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
vec3 rgb2hsv(vec3 c)
|
||||||
|
{
|
||||||
|
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
|
||||||
|
vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
|
||||||
|
vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
|
||||||
|
|
||||||
|
float d = q.x - min(q.w, q.y);
|
||||||
|
float e = 1.0e-10;
|
||||||
|
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
|
||||||
|
}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
//
|
//
|
||||||
// Color to grayscale
|
// Color to grayscale
|
||||||
|
|
@ -870,6 +887,27 @@ void main()
|
||||||
frag.rgb = frag.rgb + uFogColor.rgb;
|
frag.rgb = frag.rgb + uFogColor.rgb;
|
||||||
}
|
}
|
||||||
FragColor = frag;
|
FragColor = frag;
|
||||||
|
|
||||||
|
#ifdef DITHERTRANS
|
||||||
|
int index = (int(pixelpos.x) % 8) * 8 + int(pixelpos.y) % 8;
|
||||||
|
const float DITHER_THRESHOLDS[64] =
|
||||||
|
{
|
||||||
|
1.0 / 65.0, 33.0 / 65.0, 9.0 / 65.0, 41.0 / 65.0, 3.0 / 65.0, 35.0 / 65.0, 11.0 / 65.0, 43.0 / 65.0,
|
||||||
|
49.0 / 65.0, 17.0 / 65.0, 57.0 / 65.0, 25.0 / 65.0, 51.0 / 65.0, 19.0 / 65.0, 59.0 / 65.0, 27.0 / 65.0,
|
||||||
|
13.0 / 65.0, 45.0 / 65.0, 5.0 / 65.0, 37.0 / 65.0, 15.0 / 65.0, 47.0 / 65.0, 7.0 / 65.0, 39.0 / 65.0,
|
||||||
|
61.0 / 65.0, 29.0 / 65.0, 53.0 / 65.0, 21.0 / 65.0, 63.0 / 65.0, 31.0 / 65.0, 55.0 / 65.0, 23.0 / 65.0,
|
||||||
|
4.0 / 65.0, 36.0 / 65.0, 12.0 / 65.0, 44.0 / 65.0, 2.0 / 65.0, 34.0 / 65.0, 10.0 / 65.0, 42.0 / 65.0,
|
||||||
|
52.0 / 65.0, 20.0 / 65.0, 60.0 / 65.0, 28.0 / 65.0, 50.0 / 65.0, 18.0 / 65.0, 58.0 / 65.0, 26.0 / 65.0,
|
||||||
|
16.0 / 65.0, 48.0 / 65.0, 8.0 / 65.0, 40.0 / 65.0, 14.0 / 65.0, 46.0 / 65.0, 6.0 / 65.0, 38.0 / 65.0,
|
||||||
|
64.0 / 65.0, 32.0 / 65.0, 56.0 / 65.0, 24.0 / 65.0, 62.0 / 65.0, 30.0 / 65.0, 54.0 / 65.0, 22.0 /65.0
|
||||||
|
};
|
||||||
|
|
||||||
|
vec3 fragHSV = rgb2hsv(FragColor.rgb);
|
||||||
|
float brightness = clamp(1.5*fragHSV.z, 0.1, 1.0);
|
||||||
|
if (DITHER_THRESHOLDS[index] < brightness) discard;
|
||||||
|
else FragColor *= 0.5;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef GBUFFER_PASS
|
#ifdef GBUFFER_PASS
|
||||||
FragFog = vec4(AmbientOcclusionColor(), 1.0);
|
FragFog = vec4(AmbientOcclusionColor(), 1.0);
|
||||||
FragNormal = vec4(vEyeNormal.xyz * 0.5 + 0.5, 1.0);
|
FragNormal = vec4(vEyeNormal.xyz * 0.5 + 0.5, 1.0);
|
||||||
|
|
|
||||||
|
|
@ -493,6 +493,11 @@ void main()
|
||||||
if (frag.a <= uAlphaThreshold) discard;
|
if (frag.a <= uAlphaThreshold) discard;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef DITHERTRANS
|
||||||
|
int index = (int(pixelpos.x) % 2) * 2 + int(pixelpos.y) % 2;
|
||||||
|
if (index != 2) discard;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if (DEF_FOG_2D == 0) // check for special 2D 'fog' mode.
|
#if (DEF_FOG_2D == 0) // check for special 2D 'fog' mode.
|
||||||
{
|
{
|
||||||
float fogdist = 0.0;
|
float fogdist = 0.0;
|
||||||
|
|
|
||||||
|
|
@ -128,3 +128,87 @@ class AimingCamera : SecurityCamera
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SpectatorCamera : Actor
|
||||||
|
{
|
||||||
|
|
||||||
|
bool chasingtracer;
|
||||||
|
double lagdistance; // camera gives chase (lazy follow) if tracer gets > lagdistance away from camera.pos
|
||||||
|
int chasemode; // 0: chase until tracer centered, 1: same but only when tracer is moving, 2: stop chase if tracer within lagdistance
|
||||||
|
property lagdistance : lagdistance;
|
||||||
|
property chasingtracer : chasingtracer;
|
||||||
|
property chasemode : chasemode;
|
||||||
|
|
||||||
|
default
|
||||||
|
{
|
||||||
|
+NOBLOCKMAP
|
||||||
|
+NOGRAVITY
|
||||||
|
+NOINTERACTION
|
||||||
|
RenderStyle "None";
|
||||||
|
CameraHeight 0;
|
||||||
|
SpectatorCamera.chasingtracer false;
|
||||||
|
SpectatorCamera.lagdistance 0.0;
|
||||||
|
SpectatorCamera.chasemode 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Init(double dist, double yaw, double inpitch, int inflags)
|
||||||
|
{
|
||||||
|
|
||||||
|
double zshift = 0.0;
|
||||||
|
if(tracer != NULL)
|
||||||
|
{
|
||||||
|
if(player != NULL) zshift = -0.25*tracer.height;
|
||||||
|
else zshift = 0.5*tracer.height;
|
||||||
|
}
|
||||||
|
else if (player != NULL && player.mo != NULL) zshift = -0.5*player.mo.height;
|
||||||
|
|
||||||
|
SetViewPos((-dist*Cos(yaw)*Cos(inpitch), -dist*Sin(yaw)*Cos(inpitch), dist*Sin(inpitch)+zshift), inflags);
|
||||||
|
LookAtSelf(inpitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LookAtSelf(double inpitch)
|
||||||
|
{
|
||||||
|
if(ViewPos.Offset.length() > 0.)
|
||||||
|
{
|
||||||
|
Vector3 negviewpos = (-1.0) * ViewPos.Offset;
|
||||||
|
angle = negviewpos.Angle();
|
||||||
|
pitch = inpitch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override void Tick()
|
||||||
|
{
|
||||||
|
if(tracer != NULL)
|
||||||
|
{
|
||||||
|
Vector3 distvec = tracer.pos - pos;
|
||||||
|
double dist = distvec.length();
|
||||||
|
if((dist <= 4 && chasingtracer) || lagdistance <= 0.0) // Keep tracer centered on screen
|
||||||
|
{
|
||||||
|
SetOrigin(tracer.pos, true);
|
||||||
|
chasingtracer = false;
|
||||||
|
}
|
||||||
|
else // Lazy follow tracer
|
||||||
|
{
|
||||||
|
if(dist >= 2*lagdistance)
|
||||||
|
{
|
||||||
|
SetOrigin(tracer.pos, true);
|
||||||
|
chasingtracer = false;
|
||||||
|
}
|
||||||
|
else if(dist > lagdistance && !chasingtracer) chasingtracer = true;
|
||||||
|
|
||||||
|
if(chasingtracer)
|
||||||
|
{
|
||||||
|
speed = tracer.vel.xy.length()/dist;
|
||||||
|
if((speed == 0.0) && (chasemode == 0)) speed = tracer.speed/dist;
|
||||||
|
SetOrigin(pos + 2*distvec*speed, true);
|
||||||
|
if(chasemode > 1) chasingtracer = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(player != NULL && player.mo != NULL)
|
||||||
|
{
|
||||||
|
cameraFOV = player.FOV;
|
||||||
|
SetOrigin(player.mo.pos, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -421,8 +421,10 @@ enum EActivationFlags
|
||||||
// [MC] Flags for SetViewPos.
|
// [MC] Flags for SetViewPos.
|
||||||
enum EViewPosFlags
|
enum EViewPosFlags
|
||||||
{
|
{
|
||||||
VPSF_ABSOLUTEOFFSET = 1 << 1, // Don't include angles.
|
VPSF_ABSOLUTEOFFSET = 1 << 1, // Don't include angles.
|
||||||
VPSF_ABSOLUTEPOS = 1 << 2, // Use absolute position.
|
VPSF_ABSOLUTEPOS = 1 << 2, // Use absolute position.
|
||||||
|
VPSF_ALLOWOUTOFBOUNDS = 1 << 3, // Allow viewpoint to go out of bounds (hardware renderer only).
|
||||||
|
VPSF_ORTHOGRAPHIC = 1 << 4, // Use orthographic projection (hardware renderer only).
|
||||||
};
|
};
|
||||||
|
|
||||||
// Flags for A_TakeInventory and A_TakeFromTarget
|
// Flags for A_TakeInventory and A_TakeFromTarget
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue