mirror of
https://github.com/ZDoom/gzdoom.git
synced 2025-03-21 02:11:25 +00:00
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;
|
||||
|
||||
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.y = pos.Y;
|
||||
if (am_rotate == 1 || (am_rotate == 2 && viewactive))
|
||||
|
@ -2826,7 +2826,7 @@ void DAutomap::drawPlayers ()
|
|||
}
|
||||
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)
|
||||
|
|
|
@ -54,3 +54,6 @@ EXTERN_CVAR(Int, gl_shadowmap_filter)
|
|||
EXTERN_CVAR(Bool, gl_brightfog)
|
||||
EXTERN_CVAR(Bool, gl_lightadditivesurfaces)
|
||||
EXTERN_CVAR(Bool, gl_notexturefill)
|
||||
|
||||
EXTERN_CVAR(Bool, r_radarclipper)
|
||||
EXTERN_CVAR(Bool, r_dithertransparency)
|
||||
|
|
|
@ -25,7 +25,7 @@ enum ERenderEffect
|
|||
EFF_SPHEREMAP,
|
||||
EFF_BURN,
|
||||
EFF_STENCIL,
|
||||
|
||||
EFF_DITHERTRANS,
|
||||
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" },
|
||||
{ "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" },
|
||||
{ "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()
|
||||
|
|
|
@ -146,11 +146,27 @@ float VREyeInfo::getShift() const
|
|||
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;
|
||||
|
||||
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)));
|
||||
result.perspective(fovy, aspectRatio, screen->GetZNear(), screen->GetZFar());
|
||||
|
|
|
@ -27,7 +27,7 @@ struct VREyeInfo
|
|||
float mShiftFactor;
|
||||
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;
|
||||
private:
|
||||
float getShift() const;
|
||||
|
|
|
@ -72,6 +72,13 @@ public:
|
|||
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 Bottom () const { return m_Box[BOXBOTTOM]; }
|
||||
inline double Left () const { return m_Box[BOXLEFT]; }
|
||||
|
|
|
@ -1819,6 +1819,7 @@ MapFlagHandlers[] =
|
|||
{ "disableskyboxao", MITYPE_CLRFLAG3, LEVEL3_SKYBOXAO, 0 },
|
||||
{ "avoidmelee", MITYPE_SETFLAG3, LEVEL3_AVOIDMELEE, 0 },
|
||||
{ "attenuatelights", MITYPE_SETFLAG3, LEVEL3_ATTENUATE, 0 },
|
||||
{ "nofogofwar", MITYPE_SETFLAG3, LEVEL3_NOFOGOFWAR, 0 },
|
||||
{ "nobotnodes", MITYPE_IGNORE, 0, 0 }, // Skulltag option: nobotnodes
|
||||
{ "nopassover", MITYPE_COMPATFLAG, 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_AVOIDMELEE = 0x00020000, // global flag needed for proper MBF support.
|
||||
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;
|
||||
double D, negiC; // negative iC because that also saves a negation in all methods using this.
|
||||
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);
|
||||
|
||||
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_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_DITHERTRANS = 8192, // Render with dithering transparency shader (gets reset every frame)
|
||||
};
|
||||
|
||||
struct side_t
|
||||
|
@ -1654,6 +1657,7 @@ struct subsector_t
|
|||
uint32_t numlines;
|
||||
uint16_t flags;
|
||||
short mapsection;
|
||||
FBoundingBox bbox; // [DVR] For alternative space culling in orthographic projection with no fog of war
|
||||
|
||||
// subsector related GL data
|
||||
int validcount;
|
||||
|
|
|
@ -3262,6 +3262,25 @@ void MapLoader::LoadLevel(MapData *map, const char *lumpname, int position)
|
|||
|
||||
Level->aabbTree = new DoomLevelAABBTree(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_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_ISOMETRICSPRITES = 0x0100,
|
||||
};
|
||||
|
||||
// This translucency value produces the closest match to Heretic's TINTTAB.
|
||||
|
@ -692,8 +693,10 @@ struct FDropItem
|
|||
|
||||
enum EViewPosFlags // [MC] Flags for SetViewPos.
|
||||
{
|
||||
VPSF_ABSOLUTEOFFSET = 1 << 1, // Don't include angles.
|
||||
VPSF_ABSOLUTEPOS = 1 << 2, // Use absolute position.
|
||||
VPSF_ABSOLUTEOFFSET = 1 << 1, // Don't include angles.
|
||||
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
|
||||
|
@ -1123,6 +1126,8 @@ public:
|
|||
DAngle SpriteAngle;
|
||||
DAngle SpriteRotation;
|
||||
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 ViewAngles; // Angle offsets for cameras
|
||||
TObjPtr<DViewPosition*> ViewPos; // Position offsets for cameras
|
||||
|
|
|
@ -82,6 +82,7 @@
|
|||
#include "p_blockmap.h"
|
||||
#include "p_3dmidtex.h"
|
||||
#include "vm.h"
|
||||
#include "d_main.h"
|
||||
|
||||
#include "decallib.h"
|
||||
|
||||
|
@ -5577,33 +5578,42 @@ void R_OffsetView(FRenderViewpoint& viewPoint, const DVector3& dir, const double
|
|||
{
|
||||
const DAngle baseYaw = dir.Angle();
|
||||
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.sector = viewPoint.ViewLevel->PointInRenderSubsector(viewPoint.Pos)->sector;
|
||||
viewPoint.Angles.Yaw += deltaangle(baseYaw, trace.SrcAngleFromTarget);
|
||||
}
|
||||
else
|
||||
{
|
||||
viewPoint.Pos = trace.HitPos;
|
||||
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.
|
||||
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);
|
||||
viewPoint.sector = viewPoint.sector->GetPortal(sector_t::floor)->mDestination;
|
||||
while (!viewPoint.sector->PortalBlocksMovement(sector_t::floor) && viewPoint.Pos.Z < viewPoint.sector->GetPortalPlaneZ(sector_t::floor))
|
||||
{
|
||||
viewPoint.Pos += viewPoint.sector->GetPortalDisplacement(sector_t::floor);
|
||||
viewPoint.sector = viewPoint.sector->GetPortal(sector_t::floor)->mDestination;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (dir.Z > 0.0)
|
||||
{
|
||||
while (!viewPoint.sector->PortalBlocksMovement(sector_t::ceiling) && viewPoint.Pos.Z > viewPoint.sector->GetPortalPlaneZ(sector_t::ceiling))
|
||||
else if (dir.Z > 0.0)
|
||||
{
|
||||
viewPoint.Pos += viewPoint.sector->GetPortalDisplacement(sector_t::ceiling);
|
||||
viewPoint.sector = viewPoint.sector->GetPortal(sector_t::ceiling)->mDestination;
|
||||
while (!viewPoint.sector->PortalBlocksMovement(sector_t::ceiling) && viewPoint.Pos.Z > viewPoint.sector->GetPortalPlaneZ(sector_t::ceiling))
|
||||
{
|
||||
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:
|
||||
return false;
|
||||
|
||||
case TRACE_ContinueOutOfBounds:
|
||||
return true;
|
||||
|
||||
case TRACE_Abort:
|
||||
Results->HitType = TRACE_HitNone;
|
||||
return false;
|
||||
|
@ -732,6 +735,7 @@ bool FTraceInfo::ThingCheck(intercept_t *in, double dist, DVector3 hit)
|
|||
switch (TraceCallback(*Results, TraceCallbackData))
|
||||
{
|
||||
case TRACE_Continue: return true;
|
||||
case TRACE_ContinueOutOfBounds: return true;
|
||||
case TRACE_Stop: return false;
|
||||
case TRACE_Abort: Results->HitType = TRACE_HitNone; return false;
|
||||
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_Skip, // continue the trace; do not return this hit
|
||||
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,
|
||||
|
|
|
@ -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)
|
||||
|
||||
// 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
|
||||
vp.Pos += eye.GetViewShift(vp.HWAngles.Yaw.Degrees());
|
||||
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)
|
||||
|
||||
EXTERN_CVAR(Float, r_actorspriteshadowdist)
|
||||
EXTERN_CVAR(Bool, r_radarclipper)
|
||||
EXTERN_CVAR(Bool, r_dithertransparency)
|
||||
|
||||
thread_local bool isWorkerThread;
|
||||
ctpl::thread_pool renderPool(1);
|
||||
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
|
||||
{
|
||||
enum
|
||||
|
@ -269,6 +282,20 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip)
|
|||
auto &clipper = *mClipper;
|
||||
angle_t startAngle = clipper.GetClipAngle(seg->v2);
|
||||
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!
|
||||
if (startAngle-endAngle<ANGLE_180)
|
||||
|
@ -280,25 +307,53 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip)
|
|||
{
|
||||
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;
|
||||
}
|
||||
|
||||
if (!clipper.SafeCheckRange(startAngle, endAngle))
|
||||
if (!clipper.SafeCheckRange(startAngle, endAngle))
|
||||
{
|
||||
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);
|
||||
|
||||
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
|
||||
{
|
||||
|
@ -325,7 +380,8 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip)
|
|||
|
||||
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;
|
||||
// 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)
|
||||
{
|
||||
auto thing = p->m_thing;
|
||||
if (thing->validcount == validcount) continue;
|
||||
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;
|
||||
if (cvar != nullptr && *cvar >= 0)
|
||||
{
|
||||
|
@ -666,6 +723,51 @@ void HWDrawInfo::DoSubsector(subsector_t * sub)
|
|||
|
||||
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)
|
||||
{
|
||||
int clipres = mClipPortal->ClipSubsector(sub);
|
||||
|
@ -723,6 +825,20 @@ void HWDrawInfo::DoSubsector(subsector_t * sub)
|
|||
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)
|
||||
|
@ -843,19 +959,62 @@ void HWDrawInfo::RenderBSPNode (void *node)
|
|||
if (!(no_renderflags[bsp->Index()] & SSRF_SEEN))
|
||||
return;
|
||||
}
|
||||
if (Viewpoint.IsOrtho())
|
||||
{
|
||||
if (!vClipper->CheckBoxOrthoPitch(bsp->bbox[side]))
|
||||
{
|
||||
if (!(no_renderflags[bsp->Index()] & SSRF_SEEN))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
node = bsp->children[side];
|
||||
}
|
||||
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)
|
||||
{
|
||||
ClearDitherTargets();
|
||||
Bsp.Clock();
|
||||
|
||||
// Give the DrawInfo the viewpoint in fixed point because that's what the nodes are.
|
||||
viewx = FLOAT2FIXED(Viewpoint.Pos.X);
|
||||
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.
|
||||
|
||||
|
@ -866,7 +1025,8 @@ void HWDrawInfo::RenderBSP(void *node, bool drawpsprites)
|
|||
auto future = renderPool.push([&](int id) {
|
||||
WorkerThread();
|
||||
});
|
||||
RenderBSPNode(node);
|
||||
if (Viewpoint.IsOrtho() && ((Level->flags3 & LEVEL3_NOFOGOFWAR) || !r_radarclipper)) RenderOrthoNoFog();
|
||||
else RenderBSPNode(node);
|
||||
|
||||
jobQueue.AddJob(RenderJob::TerminateJob, nullptr, nullptr);
|
||||
Bsp.Unclock();
|
||||
|
@ -876,9 +1036,21 @@ void HWDrawInfo::RenderBSP(void *node, bool drawpsprites)
|
|||
}
|
||||
else
|
||||
{
|
||||
RenderBSPNode(node);
|
||||
if (Viewpoint.IsOrtho() && ((Level->flags3 & LEVEL3_NOFOGOFWAR) || !r_radarclipper)) RenderOrthoNoFog();
|
||||
else RenderBSPNode(node);
|
||||
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.
|
||||
if (mCurrentPortal != nullptr) mCurrentPortal->RenderAttached(this);
|
||||
|
||||
|
|
|
@ -193,7 +193,7 @@ void Clipper::AddClipRange(angle_t start, angle_t 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;
|
||||
|
@ -361,6 +361,17 @@ angle_t Clipper::AngleToPseudo(angle_t ang)
|
|||
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
|
||||
|
@ -378,11 +389,28 @@ angle_t Clipper::PointToPseudoAngle(double x, double y)
|
|||
{
|
||||
double vecx = x - viewpoint->Pos.X;
|
||||
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)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (!amRadar && viewpoint->IsOrtho())
|
||||
{
|
||||
return PointToPseudoOrthoAngle(x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
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
|
||||
// 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) +
|
||||
(vp->Pos.Y >= bspcoord[BOXTOP ] ? 0 : vp->Pos.Y > bspcoord[BOXBOTTOM] ? 4 : 8);
|
||||
|
||||
|
@ -437,7 +537,47 @@ bool Clipper::CheckBox(const float *bspcoord)
|
|||
check = checkcoord[boxpos];
|
||||
angle1 = PointToPseudoAngle (bspcoord[check[0]], bspcoord[check[1]]);
|
||||
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);
|
||||
}
|
||||
|
||||
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 * cliphead = nullptr;
|
||||
ClipNode * silhouette = nullptr; // will be preserved even when RemoveClipRange is called
|
||||
const FRenderViewpoint *viewpoint = nullptr;
|
||||
FRenderViewpoint *viewpoint = nullptr;
|
||||
bool blocked = false;
|
||||
|
||||
static angle_t AngleToPseudo(angle_t ang);
|
||||
static angle_t PitchToPseudo(double ang);
|
||||
bool IsRangeVisible(angle_t startangle, angle_t endangle);
|
||||
void RemoveRange(ClipNode * cn);
|
||||
void AddClipRange(angle_t startangle, angle_t endangle);
|
||||
|
@ -41,6 +42,7 @@ class Clipper
|
|||
|
||||
public:
|
||||
|
||||
bool amRadar = false;
|
||||
Clipper();
|
||||
|
||||
void Clear();
|
||||
|
@ -72,7 +74,7 @@ public:
|
|||
return c;
|
||||
}
|
||||
|
||||
void SetViewpoint(const FRenderViewpoint &vp)
|
||||
void SetViewpoint(FRenderViewpoint &vp)
|
||||
{
|
||||
viewpoint = &vp;
|
||||
}
|
||||
|
@ -116,6 +118,10 @@ public:
|
|||
SafeAddClipRange(AngleToPseudo(startangle), AngleToPseudo(endangle));
|
||||
}
|
||||
|
||||
void SafeAddClipRangeDegPitches(double startpitch, double endpitch)
|
||||
{
|
||||
SafeAddClipRange(PitchToPseudo(startpitch), PitchToPseudo(endpitch));
|
||||
}
|
||||
|
||||
void SafeRemoveClipRange(angle_t startangle, angle_t endangle)
|
||||
{
|
||||
|
@ -146,10 +152,14 @@ public:
|
|||
{
|
||||
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 CheckBoxOrthoPitch(const float *bspcoord);
|
||||
|
||||
// Used to speed up angle calculations during clipping
|
||||
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 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.
|
||||
|
||||
void HWDrawInfo::StartScene(FRenderViewpoint &parentvp, HWViewpointUniforms *uniforms)
|
||||
{
|
||||
staticClipper.Clear();
|
||||
staticVClipper.Clear();
|
||||
staticRClipper.Clear();
|
||||
mClipper = &staticClipper;
|
||||
vClipper = &staticVClipper;
|
||||
rClipper = &staticRClipper;
|
||||
rClipper->amRadar = true;
|
||||
|
||||
Viewpoint = parentvp;
|
||||
lightmode = getRealLightmode(Level, true);
|
||||
|
@ -169,6 +176,8 @@ void HWDrawInfo::StartScene(FRenderViewpoint &parentvp, HWViewpointUniforms *uni
|
|||
VPUniforms.mLightBlendMode = (level.info ? (int)level.info->lightblendmode : 0);
|
||||
}
|
||||
mClipper->SetViewpoint(Viewpoint);
|
||||
vClipper->SetViewpoint(Viewpoint);
|
||||
rClipper->SetViewpoint(Viewpoint);
|
||||
|
||||
ClearBuffers();
|
||||
|
||||
|
@ -257,7 +266,9 @@ void HWDrawInfo::ClearBuffers()
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -270,9 +281,11 @@ void HWDrawInfo::UpdateCurrentMapSection()
|
|||
|
||||
void HWDrawInfo::SetViewArea()
|
||||
{
|
||||
auto &vp = Viewpoint;
|
||||
auto &vp = Viewpoint;
|
||||
// The render_sector is better suited to represent the current position in GL
|
||||
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!
|
||||
if (vp.sector->GetHeightSec())
|
||||
|
@ -351,16 +364,14 @@ int HWDrawInfo::SetFullbrightFlags(player_t *player)
|
|||
|
||||
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°
|
||||
if (tilt > 46.0f) return 0xffffffff;
|
||||
double xratio = r_viewwindow.FocalTangent / Viewpoint.PitchCos;
|
||||
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...
|
||||
// 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;
|
||||
if (a1 >= ANGLE_90) return 0xffffffff;
|
||||
return a1;
|
||||
}
|
||||
|
||||
|
@ -438,8 +449,12 @@ HWDecal *HWDrawInfo::AddDecal(bool onmirror)
|
|||
void HWDrawInfo::CreateScene(bool drawpsprites)
|
||||
{
|
||||
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);
|
||||
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
|
||||
portalState.StartFrame();
|
||||
|
@ -648,6 +663,79 @@ void HWDrawInfo::DrawCorona(FRenderState& state, ACorona* corona, double dist)
|
|||
#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)
|
||||
{
|
||||
FRenderViewpoint* data = (FRenderViewpoint*)userdata;
|
||||
|
@ -803,13 +891,17 @@ void HWDrawInfo::DrawScene(int drawmode)
|
|||
{
|
||||
static int recursion = 0;
|
||||
static int ssao_portals_available = 0;
|
||||
const auto& vp = Viewpoint;
|
||||
auto& vp = Viewpoint;
|
||||
|
||||
bool applySSAO = false;
|
||||
if (drawmode == DM_MAINVIEW)
|
||||
{
|
||||
ssao_portals_available = gl_ssao_portals;
|
||||
applySSAO = true;
|
||||
if (r_dithertransparency && vp.IsAllowedOoB())
|
||||
{
|
||||
vp.camera->tracer ? SetDitherTransFlags(vp.camera->tracer) : SetDitherTransFlags(players[consoleplayer].mo);
|
||||
}
|
||||
}
|
||||
else if (drawmode == DM_OFFSCREEN)
|
||||
{
|
||||
|
@ -864,6 +956,8 @@ void HWDrawInfo::ProcessScene(bool toscreen)
|
|||
portalState.BeginScene();
|
||||
|
||||
int mapsection = Level->PointInRenderSubsector(Viewpoint.Pos)->mapsection;
|
||||
if (Viewpoint.IsAllowedOoB())
|
||||
mapsection = Level->PointInRenderSubsector(Viewpoint.camera->Pos())->mapsection;
|
||||
CurrentMapSections.Set(mapsection);
|
||||
DrawScene(toscreen ? DM_MAINVIEW : DM_OFFSCREEN);
|
||||
|
||||
|
|
|
@ -146,6 +146,8 @@ struct HWDrawInfo
|
|||
HWPortal *mCurrentPortal;
|
||||
//FRotator mAngles;
|
||||
Clipper *mClipper;
|
||||
Clipper *vClipper; // Vertical clipper
|
||||
Clipper *rClipper; // Radar clipper
|
||||
FRenderViewpoint Viewpoint;
|
||||
HWViewpointUniforms VPUniforms; // per-viewpoint uniform state
|
||||
TArray<HWPortal *> Portals;
|
||||
|
@ -234,6 +236,7 @@ public:
|
|||
|
||||
HWPortal * FindPortal(const void * src);
|
||||
void RenderBSPNode(void *node);
|
||||
void RenderOrthoNoFog();
|
||||
void RenderBSP(void *node, bool drawpsprites);
|
||||
|
||||
static HWDrawInfo *StartDrawInfo(FLevelLocals *lev, HWDrawInfo *parent, FRenderViewpoint &parentvp, HWViewpointUniforms *uniforms);
|
||||
|
@ -302,6 +305,8 @@ public:
|
|||
void DrawCoronas(FRenderState& state);
|
||||
void DrawCorona(FRenderState& state, ACorona* corona, double dist);
|
||||
|
||||
void SetDitherTransFlags(AActor* actor);
|
||||
|
||||
void ProcessLowerMinisegs(TArray<seg_t *> &lowersegs);
|
||||
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.SetAddColor(AddColor | 0xff000000);
|
||||
state.ApplyTextureManipulation(TextureFx);
|
||||
|
||||
if (plane.plane.dithertransflag) state.SetEffect(EFF_DITHERTRANS);
|
||||
|
||||
if (hacktype & SSRF_PLANEHACK)
|
||||
{
|
||||
|
@ -372,6 +372,7 @@ void HWFlat::DrawFlat(HWDrawInfo *di, FRenderState &state, bool translucent)
|
|||
state.SetObjectColor(0xffffffff);
|
||||
state.SetAddColor(0);
|
||||
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)
|
||||
{
|
||||
plane.GetFromSector(model, whichplane);
|
||||
model->ceilingplane.dithertransflag = false; // Resetting this every frame
|
||||
model->floorplane.dithertransflag = false; // Resetting this every frame
|
||||
if (whichplane != int(ceiling))
|
||||
{
|
||||
// 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 &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.
|
||||
|
||||
|
@ -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.
|
||||
|
||||
|
|
|
@ -563,7 +563,8 @@ bool HWMirrorPortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *clippe
|
|||
angle_t af = di->FrustumAngle();
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
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);
|
||||
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;
|
||||
|
||||
const float LARGE_VALUE = 1e19f;
|
||||
const float MY_SQRT2 = 1.41421356237309504880; // sqrt(2)
|
||||
|
||||
EXTERN_CVAR(Bool, r_debug_disable_vis_filter)
|
||||
EXTERN_CVAR(Float, transsouls)
|
||||
|
@ -494,7 +495,7 @@ bool HWSprite::CalculateVertices(HWDrawInfo* di, FVector3* v, DVector3* vp)
|
|||
}
|
||||
else // traditional "Y" billboard mode
|
||||
{
|
||||
if (doRoll || !offset.isZero())
|
||||
if (doRoll || !offset.isZero() || (actor && (actor->renderflags2 & RF2_ISOMETRICSPRITES)))
|
||||
{
|
||||
mat.MakeIdentity();
|
||||
|
||||
|
@ -516,6 +517,16 @@ bool HWSprite::CalculateVertices(HWDrawInfo* di, FVector3* v, DVector3* vp)
|
|||
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[1] = mat * FVector3(x2, z1, y2);
|
||||
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;
|
||||
DAngle ang = (thingpos - vp.Pos).Angle();
|
||||
if (di->Viewpoint.IsOrtho()) ang = vp.Angles.Yaw;
|
||||
FTextureID patch;
|
||||
// [ZZ] add direct picnum override
|
||||
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
|
||||
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))
|
||||
{
|
||||
|
@ -1018,7 +1048,7 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
|
|||
z1 = z - r.top;
|
||||
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
|
||||
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;
|
||||
y1 = y + viewvecX*leftfac;
|
||||
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;
|
||||
}
|
||||
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);
|
||||
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.
|
||||
|
||||
// light calculation
|
||||
|
|
|
@ -83,10 +83,16 @@ void SetSplitPlanes(FRenderState& state, const secplane_t& top, const secplane_t
|
|||
|
||||
void HWWall::RenderWall(FRenderState &state, int textured)
|
||||
{
|
||||
if (seg->sidedef->Flags & WALLF_DITHERTRANS) state.SetEffect(EFF_DITHERTRANS);
|
||||
assert(vertcount > 0);
|
||||
state.SetLightIndex(dynlightindex);
|
||||
state.Draw(DT_TriangleFan, vertindex, 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];
|
||||
// Don't render portal insides if in orthographic mode
|
||||
if (di->di) isportal &= !(di->di->Viewpoint.IsOrtho());
|
||||
|
||||
//return;
|
||||
// [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 "v_draw.h"
|
||||
#include "i_interface.h"
|
||||
#include "d_main.h"
|
||||
|
||||
const float MY_SQRT2 = 1.41421356237309504880; // sqrt(2)
|
||||
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
|
||||
|
||||
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 (Bool, r_drawvoxels, true, 0)
|
||||
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)
|
||||
{
|
||||
if (self < 0.f) self = 0.f;
|
||||
|
@ -155,9 +159,14 @@ FRenderViewpoint::FRenderViewpoint()
|
|||
Sin = 0.0;
|
||||
TanCos = 0.0;
|
||||
TanSin = 0.0;
|
||||
PitchCos = 0.0;
|
||||
PitchSin = 0.0;
|
||||
floordistfact = 0.0;
|
||||
cotfloor = 0.0;
|
||||
camera = nullptr;
|
||||
sector = nullptr;
|
||||
FieldOfView = DAngle::fromDeg(90.); // Angles in the SCREENWIDTH wide window
|
||||
ScreenProj = 0.0;
|
||||
TicFrac = 0.0;
|
||||
FrameTime = 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.
|
||||
viewPoint.sector = viewLvl->PointInRenderSubsector(viewPoint.Pos)->sector;
|
||||
bool moved = false;
|
||||
while (!viewPoint.sector->PortalBlocksMovement(sector_t::ceiling))
|
||||
if (!viewPoint.IsAllowedOoB() || !V_IsHardwareRenderer())
|
||||
{
|
||||
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);
|
||||
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))
|
||||
if (viewPoint.Pos.Z > viewPoint.sector->GetPortalPlaneZ(sector_t::ceiling))
|
||||
{
|
||||
const DVector2 offset = viewPoint.sector->GetPortalDisplacement(sector_t::floor);
|
||||
const DVector2 offset = viewPoint.sector->GetPortalDisplacement(sector_t::ceiling);
|
||||
viewPoint.Pos += 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
|
||||
{
|
||||
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))
|
||||
|
@ -680,10 +692,46 @@ void FRenderViewpoint::SetViewAngle(const FViewWindow& viewWindow)
|
|||
TanSin = viewWindow.FocalTangent * Sin;
|
||||
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();
|
||||
ViewVector.X = v.X;
|
||||
ViewVector.Y = v.Y;
|
||||
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);
|
||||
|
||||
// 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;
|
||||
if (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;
|
||||
if (viewPoint.Pos.Z < z)
|
||||
|
|
|
@ -33,10 +33,16 @@ struct FRenderViewpoint
|
|||
double Sin; // sin(Angles.Yaw)
|
||||
double TanCos; // FocalTangent * cos(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
|
||||
sector_t *sector; // [RH] keep track of sector viewing from
|
||||
DAngle FieldOfView; // current field of view
|
||||
double ScreenProj; // Screen projection factor for orthographic projection
|
||||
|
||||
double TicFrac; // fraction of tic for interpolation
|
||||
uint32_t FrameTime; // current frame's time in tics.
|
||||
|
@ -45,6 +51,8 @@ struct FRenderViewpoint
|
|||
bool showviewer; // show the camera actor?
|
||||
bool bForceNoViewer; // Never show the camera Actor.
|
||||
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, CAMFOLLOWSPLAYER, AActor, renderflags2),
|
||||
DEFINE_FLAG(RF2, NOMIPMAP, AActor, renderflags2),
|
||||
DEFINE_FLAG(RF2, ISOMETRICSPRITES, AActor, renderflags2),
|
||||
|
||||
// Bounce flags
|
||||
DEFINE_FLAG2(BOUNCE_Walls, BOUNCEONWALLS, AActor, BounceFlags),
|
||||
|
|
|
@ -48,6 +48,23 @@ const int TEXF_Detailmap = 0x20000;
|
|||
const int TEXF_Glowmap = 0x40000;
|
||||
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
|
||||
|
@ -870,6 +887,27 @@ void main()
|
|||
frag.rgb = frag.rgb + uFogColor.rgb;
|
||||
}
|
||||
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
|
||||
FragFog = vec4(AmbientOcclusionColor(), 1.0);
|
||||
FragNormal = vec4(vEyeNormal.xyz * 0.5 + 0.5, 1.0);
|
||||
|
|
|
@ -493,6 +493,11 @@ void main()
|
|||
if (frag.a <= uAlphaThreshold) discard;
|
||||
#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.
|
||||
{
|
||||
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.
|
||||
enum EViewPosFlags
|
||||
{
|
||||
VPSF_ABSOLUTEOFFSET = 1 << 1, // Don't include angles.
|
||||
VPSF_ABSOLUTEPOS = 1 << 2, // Use absolute position.
|
||||
VPSF_ABSOLUTEOFFSET = 1 << 1, // Don't include angles.
|
||||
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
|
||||
|
@ -1501,4 +1503,4 @@ enum EModelFlags
|
|||
MDL_MODELSAREATTACHMENTS = 1<<12, // any model index after 0 is treated as an attachment, and therefore will use the bone results of index 0
|
||||
MDL_CORRECTPIXELSTRETCH = 1<<13, // ensure model does not distort with pixel stretch when pitch/roll is applied
|
||||
MDL_FORCECULLBACKFACES = 1<<14,
|
||||
};
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue