Feature-complete isometric mode fork.

This commit is contained in:
Dileep V. Reddy 2024-06-24 14:18:30 -06:00
parent 29a2ca0b13
commit 6e7ae739e2
No known key found for this signature in database
GPG key ID: 7E1FE104B057EBF3
31 changed files with 711 additions and 72 deletions

View file

@ -2808,7 +2808,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))
@ -2818,7 +2818,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)

View file

@ -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)

View file

@ -25,7 +25,7 @@ enum ERenderEffect
EFF_SPHEREMAP, EFF_SPHEREMAP,
EFF_BURN, EFF_BURN,
EFF_STENCIL, EFF_STENCIL,
EFF_DITHERTRANS,
MAX_EFFECTS MAX_EFFECTS
}; };

View file

@ -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()

View file

@ -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());

View file

@ -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;

View file

@ -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 },

View file

@ -270,6 +270,7 @@ enum ELevelFlags : unsigned int
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
}; };

View file

@ -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

View file

@ -501,6 +501,7 @@ enum ActorRenderFlag2
RF2_FLIPSPRITEOFFSETX = 0x0010, RF2_FLIPSPRITEOFFSETX = 0x0010,
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_ISOMETRICSPRITES = 0x0080,
}; };
// This translucency value produces the closest match to Heretic's TINTTAB. // This translucency value produces the closest match to Heretic's TINTTAB.
@ -693,6 +694,8 @@ 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
@ -1119,6 +1122,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

View file

@ -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.camera->ViewPos && (viewPoint.camera->ViewPos->Flags & VPSF_ALLOWOUTOFBOUNDS) && 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.camera->ViewPos || !(viewPoint.camera->ViewPos->Flags & VPSF_ALLOWOUTOFBOUNDS) || !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;
}
} }
} }
} }

View file

@ -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;

View file

@ -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,

View file

@ -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);

View file

@ -51,6 +51,8 @@
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);
@ -269,6 +271,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,25 +296,53 @@ 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;
} }
if (!clipper.SafeCheckRange(startAngle, endAngle)) if (!clipper.SafeCheckRange(startAngle, endAngle))
{ {
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.camera->ViewPos != NULL) && (Viewpoint.camera->ViewPos->Flags & VPSF_ALLOWOUTOFBOUNDS)))
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 +369,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.camera->ViewPos != NULL) && (Viewpoint.camera->ViewPos->Flags & VPSF_ALLOWOUTOFBOUNDS)))
if (!(seg->sidedef->Flags & WALLF_DITHERTRANS)) clipper.SafeAddClipRange(startAngle, endAngle);
} }
} }
} }
@ -533,6 +578,7 @@ void HWDrawInfo::RenderThings(subsector_t * sub, sector_t * sector)
if (thing->validcount == validcount) continue; if (thing->validcount == validcount) continue;
thing->validcount = validcount; thing->validcount = validcount;
if((Viewpoint.camera->ViewPos != NULL) && (Viewpoint.camera->ViewPos->Flags & VPSF_ALLOWOUTOFBOUNDS) && 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 +712,51 @@ void HWDrawInfo::DoSubsector(subsector_t * sub)
fakesector=hw_FakeFlat(sector, in_area, false); fakesector=hw_FakeFlat(sector, in_area, false);
if((Viewpoint.camera->ViewPos != NULL) && (Viewpoint.camera->ViewPos->Flags & VPSF_ALLOWOUTOFBOUNDS) && sector->isSecret() && sector->wasSecret() && !r_radarclipper) return;
// cull everything if subsector outside vertical clipper
if (sub->polys == nullptr)
{
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);
@ -712,7 +803,7 @@ void HWDrawInfo::DoSubsector(subsector_t * sub)
if (gl_render_things && (sector->touching_renderthings || sector->sectorportal_thinglist)) if (gl_render_things && (sector->touching_renderthings || sector->sectorportal_thinglist))
{ {
if (multithread) if (multithread)
{ {
jobQueue.AddJob(RenderJob::SpriteJob, sub, nullptr); jobQueue.AddJob(RenderJob::SpriteJob, sub, nullptr);
} }
@ -723,6 +814,23 @@ void HWDrawInfo::DoSubsector(subsector_t * sub)
SetupSprite.Unclock(); SetupSprite.Unclock();
} }
} }
if (r_dithertransparency)
{
// [DVR] Not parallelizable due to line->validcount race coundition
for (auto p = sector->touching_renderthings; p != nullptr; p = p->m_snext)
{
auto thing = p->m_thing;
if (((thing->flags & MF_SHOOTABLE) && (thing->health > 0)) || (thing->flags & MF_MISSILE))
{
if ( P_CheckSight(players[consoleplayer].mo, thing, 0) )
{
SetDitherTransFlags(thing);
}
}
}
validcount++; // [DVR] Need this since Trace() and P_CheckSight() get called
// and they set line->validcount = validcount, preventing lines from being processed.
}
} }
if (gl_render_flats) if (gl_render_flats)
@ -843,6 +951,14 @@ void HWDrawInfo::RenderBSPNode (void *node)
if (!(no_renderflags[bsp->Index()] & SSRF_SEEN)) if (!(no_renderflags[bsp->Index()] & SSRF_SEEN))
return; return;
} }
if ((Viewpoint.camera->ViewPos != NULL) && (Viewpoint.camera->ViewPos->Flags & VPSF_ORTHOGRAPHIC))
{
if (!vClipper->CheckBoxOrthoPitch(bsp->bbox[side]))
{
if (!(no_renderflags[bsp->Index()] & SSRF_SEEN))
return;
}
}
node = bsp->children[side]; node = bsp->children[side];
} }
@ -856,6 +972,19 @@ void HWDrawInfo::RenderBSP(void *node, bool drawpsprites)
// 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.camera->ViewPos != NULL) && (Viewpoint.camera->ViewPos->Flags & (VPSF_ABSOLUTEOFFSET | VPSF_ALLOWOUTOFBOUNDS)))
{
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.

View file

@ -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->camera->ViewPos != NULL) && (viewpoint->camera->ViewPos->Flags & VPSF_ORTHOGRAPHIC))
{
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->camera->ViewPos != NULL) && (viewpoint->camera->ViewPos->Flags & VPSF_ORTHOGRAPHIC))
{
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());
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// //
@ -421,7 +521,7 @@ angle_t Clipper::PointToPseudoAngle(double x, double y)
bool Clipper::CheckBox(const float *bspcoord) bool Clipper::CheckBox(const float *bspcoord)
{ {
angle_t angle1, angle2; angle_t angle1, angle2;
int boxpos; int boxpos;
const uint8_t* check; const uint8_t* check;
@ -437,7 +537,47 @@ bool Clipper::CheckBox(const float *bspcoord)
check = checkcoord[boxpos]; check = checkcoord[boxpos];
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->camera->ViewPos != NULL) && (vp->camera->ViewPos->Flags & VPSF_ORTHOGRAPHIC))
{
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->camera->ViewPos != NULL) && (vp->camera->ViewPos->Flags & VPSF_ORTHOGRAPHIC))) 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);
}

View file

@ -33,6 +33,7 @@ class Clipper
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();
@ -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)
{ {
@ -148,8 +154,12 @@ public:
} }
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)

View file

@ -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.camera->ViewPos != NULL) && (Viewpoint.camera->ViewPos->Flags & VPSF_ALLOWOUTOFBOUNDS))
mapsection = Level->PointInRenderSubsector(Viewpoint.camera->Pos())->mapsection;
CurrentMapSections.Set(mapsection); CurrentMapSections.Set(mapsection);
} }
@ -273,6 +284,8 @@ 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 ((vp.camera->ViewPos != NULL) && (vp.camera->ViewPos->Flags & VPSF_ALLOWOUTOFBOUNDS))
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.camera->ViewPos && (Viewpoint.camera->ViewPos->Flags & VPSF_ORTHOGRAPHIC))
{
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,
MF_SOLID, ML_BLOCKEVERYTHING, actor, results, 0, TraceCallbackForDitherTransparency, &count);
campos.Z += actor->Height * 0.5;
Trace(campos, startsec, vvec, distance,
MF_SOLID, ML_BLOCKEVERYTHING, 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;
@ -810,6 +898,10 @@ void HWDrawInfo::DrawScene(int drawmode)
{ {
ssao_portals_available = gl_ssao_portals; ssao_portals_available = gl_ssao_portals;
applySSAO = true; applySSAO = true;
if (r_dithertransparency)
{
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.camera->ViewPos != NULL) && (Viewpoint.camera->ViewPos->Flags & VPSF_ALLOWOUTOFBOUNDS))
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);

View file

@ -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;
@ -302,6 +304,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);

View file

@ -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.
@ -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.camera->ViewPos != NULL) && (vp.camera->ViewPos->Flags & VPSF_ORTHOGRAPHIC) && (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.camera->ViewPos != NULL) && (vp.camera->ViewPos->Flags & VPSF_ORTHOGRAPHIC) && (vp.PitchSin > 0.0)))
{ {
// process the original ceiling first. // process the original ceiling first.

View file

@ -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.camera->ViewPos != NULL) && (di->Viewpoint.camera->ViewPos->Flags & VPSF_ALLOWOUTOFBOUNDS)))
clipper->SafeAddClipRange(linedef->v1, linedef->v2);
return true; return true;
} }

View file

@ -130,6 +130,10 @@ 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->Viewpoint.camera != NULL && di->di->Viewpoint.camera->ViewPos != NULL)
{
if(di->di->Viewpoint.camera->ViewPos->Flags & VPSF_ALLOWOUTOFBOUNDS) return;
}
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

View file

@ -489,7 +489,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();
@ -509,6 +509,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.camera->ViewPos != NULL) && (di->Viewpoint.camera->ViewPos->Flags & VPSF_ORTHOGRAPHIC))
{
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);
@ -902,6 +912,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 (thing->renderflags2 & RF2_ISOMETRICSPRITES) ang = vp.Angles.Yaw;
FTextureID patch; FTextureID patch;
// [ZZ] add direct picnum override // [ZZ] add direct picnum override
if (isPicnumOverride) if (isPicnumOverride)
@ -995,14 +1006,32 @@ 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);
float rightfac = -r.left; float rightfac = -r.left;
float leftfac = rightfac - r.width; float leftfac = rightfac - r.width;
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)
@ -1021,6 +1050,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 * M_SQRT2;
x2 -= viewvecX * thing->radius * M_SQRT2;
y1 -= viewvecY * thing->radius * M_SQRT2;
y2 -= viewvecY * thing->radius * M_SQRT2;
}
break; break;
} }
case RF_FLATSPRITE: case RF_FLATSPRITE:
@ -1061,6 +1097,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

View file

@ -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
isportal &= !(di->di->Viewpoint.camera->ViewPos && (di->di->Viewpoint.camera->ViewPos->Flags & VPSF_ORTHOGRAPHIC));
//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

View file

@ -66,6 +66,7 @@
#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"
// EXTERNAL DATA DECLARATIONS ---------------------------------------------- // EXTERNAL DATA DECLARATIONS ----------------------------------------------
@ -103,6 +104,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 +158,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;
@ -554,37 +562,40 @@ 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.camera->ViewPos || !(viewPoint.camera->ViewPos->Flags & VPSF_ALLOWOUTOFBOUNDS) || !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;
}
} }
} }
} }
@ -628,7 +639,7 @@ void R_InterpolateView(FRenderViewpoint& viewPoint, const player_t* const player
// Now that we have the current interpolated position, offset from that directly (for view offset + chase cam). // Now that we have the current interpolated position, offset from that directly (for view offset + chase cam).
if (!posOfs.isZero()) if (!posOfs.isZero())
{ {
const double distance = posOfs.Length(); const double distance = posOfs.Length();
posOfs /= distance; posOfs /= distance;
R_OffsetView(viewPoint, posOfs, distance); R_OffsetView(viewPoint, posOfs, distance);
} }
@ -682,10 +693,20 @@ 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 = M_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 ((camera->ViewPos != NULL) && (camera->ViewPos->Flags & VPSF_ORTHOGRAPHIC) && (camera->ViewPos->Offset.XY().Length() > 0.0))
ScreenProj = 1.34396 / camera->ViewPos->Offset.Length(); // [DVR] Estimated. +/-1 should be top/bottom of screen.
} }
//========================================================================== //==========================================================================
@ -1019,14 +1040,17 @@ 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
bool disembodied = false;
if (viewPoint.camera->ViewPos != NULL) disembodied = viewPoint.camera->ViewPos->Flags & VPSF_ALLOWOUTOFBOUNDS;
if (viewPoint.sector->PortalBlocksMovement(sector_t::ceiling) && (!disembodied || !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) && (!disembodied || !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)

View file

@ -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.

View file

@ -384,6 +384,7 @@ static FFlagDef ActorFlagDefs[]=
DEFINE_FLAG(RF2, FLIPSPRITEOFFSETX, AActor, renderflags2), DEFINE_FLAG(RF2, FLIPSPRITEOFFSETX, AActor, renderflags2),
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, ISOMETRICSPRITES, AActor, renderflags2),
// Bounce flags // Bounce flags
DEFINE_FLAG2(BOUNCE_Walls, BOUNCEONWALLS, AActor, BounceFlags), DEFINE_FLAG2(BOUNCE_Walls, BOUNCEONWALLS, AActor, BounceFlags),

View file

@ -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);

View file

@ -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;

View file

@ -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.5*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 != (0., 0., 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);
}
}
}

View file

@ -422,6 +422,8 @@ 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
@ -1495,4 +1497,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_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_CORRECTPIXELSTRETCH = 1<<13, // ensure model does not distort with pixel stretch when pitch/roll is applied
MDL_FORCECULLBACKFACES = 1<<14, MDL_FORCECULLBACKFACES = 1<<14,
}; };