mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-25 13:31:37 +00:00
Feature-complete isometric mode fork.
This commit is contained in:
parent
29a2ca0b13
commit
6e7ae739e2
31 changed files with 711 additions and 72 deletions
|
@ -2808,7 +2808,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))
|
||||
|
@ -2818,7 +2818,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;
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -270,6 +270,7 @@ enum ELevelFlags : unsigned int
|
|||
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_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
|
||||
|
|
|
@ -501,6 +501,7 @@ enum ActorRenderFlag2
|
|||
RF2_FLIPSPRITEOFFSETX = 0x0010,
|
||||
RF2_FLIPSPRITEOFFSETY = 0x0020,
|
||||
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.
|
||||
|
@ -693,6 +694,8 @@ enum EViewPosFlags // [MC] Flags for SetViewPos.
|
|||
{
|
||||
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
|
||||
|
@ -1119,6 +1122,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.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.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.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);
|
||||
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,6 +51,8 @@
|
|||
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);
|
||||
|
@ -269,6 +271,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 +296,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.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
|
||||
{
|
||||
|
@ -325,7 +369,8 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip)
|
|||
|
||||
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;
|
||||
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;
|
||||
if (cvar != nullptr && *cvar >= 0)
|
||||
{
|
||||
|
@ -666,6 +712,51 @@ void HWDrawInfo::DoSubsector(subsector_t * sub)
|
|||
|
||||
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)
|
||||
{
|
||||
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 (multithread)
|
||||
if (multithread)
|
||||
{
|
||||
jobQueue.AddJob(RenderJob::SpriteJob, sub, nullptr);
|
||||
}
|
||||
|
@ -723,6 +814,23 @@ void HWDrawInfo::DoSubsector(subsector_t * sub)
|
|||
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)
|
||||
|
@ -843,6 +951,14 @@ void HWDrawInfo::RenderBSPNode (void *node)
|
|||
if (!(no_renderflags[bsp->Index()] & SSRF_SEEN))
|
||||
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];
|
||||
}
|
||||
|
@ -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.
|
||||
viewx = FLOAT2FIXED(Viewpoint.Pos.X);
|
||||
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.
|
||||
|
||||
|
|
|
@ -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->camera->ViewPos != NULL) && (viewpoint->camera->ViewPos->Flags & VPSF_ORTHOGRAPHIC))
|
||||
{
|
||||
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->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)
|
||||
{
|
||||
angle_t angle1, angle2;
|
||||
angle_t angle1, angle2;
|
||||
|
||||
int boxpos;
|
||||
const uint8_t* check;
|
||||
|
@ -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->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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ class Clipper
|
|||
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();
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -148,8 +154,12 @@ public:
|
|||
}
|
||||
|
||||
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.camera->ViewPos != NULL) && (Viewpoint.camera->ViewPos->Flags & VPSF_ALLOWOUTOFBOUNDS))
|
||||
mapsection = Level->PointInRenderSubsector(Viewpoint.camera->Pos())->mapsection;
|
||||
CurrentMapSections.Set(mapsection);
|
||||
}
|
||||
|
||||
|
@ -273,6 +284,8 @@ void HWDrawInfo::SetViewArea()
|
|||
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 ((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!
|
||||
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.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)
|
||||
{
|
||||
FRenderViewpoint* data = (FRenderViewpoint*)userdata;
|
||||
|
@ -810,6 +898,10 @@ void HWDrawInfo::DrawScene(int drawmode)
|
|||
{
|
||||
ssao_portals_available = gl_ssao_portals;
|
||||
applySSAO = true;
|
||||
if (r_dithertransparency)
|
||||
{
|
||||
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.camera->ViewPos != NULL) && (Viewpoint.camera->ViewPos->Flags & VPSF_ALLOWOUTOFBOUNDS))
|
||||
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;
|
||||
|
@ -302,6 +304,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.
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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.
|
||||
|
||||
|
|
|
@ -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.camera->ViewPos != NULL) && (di->Viewpoint.camera->ViewPos->Flags & VPSF_ALLOWOUTOFBOUNDS)))
|
||||
clipper->SafeAddClipRange(linedef->v1, linedef->v2);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
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);
|
||||
if (sportal != nullptr && sportal->mFlags & PORTSF_INSKYBOX) sportal = nullptr; // no recursions, delete it here to simplify the following code
|
||||
|
|
|
@ -489,7 +489,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();
|
||||
|
||||
|
@ -509,6 +509,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.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[1] = mat * FVector3(x2, z1, y2);
|
||||
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;
|
||||
DAngle ang = (thingpos - vp.Pos).Angle();
|
||||
if (thing->renderflags2 & RF2_ISOMETRICSPRITES) ang = vp.Angles.Yaw;
|
||||
FTextureID patch;
|
||||
// [ZZ] add direct picnum override
|
||||
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
|
||||
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 leftfac = rightfac - r.width;
|
||||
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)
|
||||
|
@ -1021,6 +1050,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 * M_SQRT2;
|
||||
x2 -= viewvecX * thing->radius * M_SQRT2;
|
||||
y1 -= viewvecY * thing->radius * M_SQRT2;
|
||||
y2 -= viewvecY * thing->radius * M_SQRT2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
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);
|
||||
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
|
||||
isportal &= !(di->di->Viewpoint.camera->ViewPos && (di->di->Viewpoint.camera->ViewPos->Flags & VPSF_ORTHOGRAPHIC));
|
||||
|
||||
//return;
|
||||
// [GZ] 3D middle textures are necessarily two-sided, even if they lack the explicit two-sided flag
|
||||
|
|
|
@ -66,6 +66,7 @@
|
|||
#include "i_system.h"
|
||||
#include "v_draw.h"
|
||||
#include "i_interface.h"
|
||||
#include "d_main.h"
|
||||
|
||||
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
|
||||
|
||||
|
@ -103,6 +104,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 +158,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;
|
||||
|
@ -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.
|
||||
viewPoint.sector = viewLvl->PointInRenderSubsector(viewPoint.Pos)->sector;
|
||||
bool moved = false;
|
||||
while (!viewPoint.sector->PortalBlocksMovement(sector_t::ceiling))
|
||||
if (!viewPoint.camera->ViewPos || !(viewPoint.camera->ViewPos->Flags & VPSF_ALLOWOUTOFBOUNDS) || !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;
|
||||
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).
|
||||
if (!posOfs.isZero())
|
||||
{
|
||||
const double distance = posOfs.Length();
|
||||
const double distance = posOfs.Length();
|
||||
posOfs /= distance;
|
||||
R_OffsetView(viewPoint, posOfs, distance);
|
||||
}
|
||||
|
@ -682,10 +693,20 @@ void FRenderViewpoint::SetViewAngle(const FViewWindow& viewWindow)
|
|||
TanSin = viewWindow.FocalTangent * Sin;
|
||||
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();
|
||||
ViewVector.X = v.X;
|
||||
ViewVector.Y = v.Y;
|
||||
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);
|
||||
|
||||
// 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;
|
||||
if (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;
|
||||
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.
|
||||
|
|
|
@ -384,6 +384,7 @@ static FFlagDef ActorFlagDefs[]=
|
|||
DEFINE_FLAG(RF2, FLIPSPRITEOFFSETX, AActor, renderflags2),
|
||||
DEFINE_FLAG(RF2, FLIPSPRITEOFFSETY, AActor, renderflags2),
|
||||
DEFINE_FLAG(RF2, CAMFOLLOWSPLAYER, 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.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -422,6 +422,8 @@ enum EViewPosFlags
|
|||
{
|
||||
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
|
||||
|
@ -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_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