Isometric Mode and Robin (#2618)
* Feature-complete isometric mode fork. * Dithered transparency condition tweaks. * Dithered transparency for non-corpse monsters only (and missiles). * SpectatorCamera vertical shift. * Including math.h in hw_sprites.cpp to keep visual studio happy (it couldn't find M_SQRT2 definition). * Defining MY_SQRT2 in hw_sprites.cpp to keep visual studio happy (it couldn't find M_SQRT2 definition). * Defining MY_SQRT2 in r_utility.cpp also to keep visual studio happy. * retrigger checks * Have correct sprite angle-frame face the camera with orthographic projection enabled. * Dithered Transparency now works properly on 3D floors. Moved that dither-trans flag setting code within hw_bsp.cpp to handle double-processing of linedefs. Added helper functions to FRenderViewpoint class 'bool IsOrtho()' and 'bool IsAllowedOoB()' to clean up checks everywhere in the code. * Fixed indents. Added bbox property to subsector struct and use it instead of BSP nodes and Clippers (creating a bbox around viewpoint and checking for overlap) in orthographic mode when no fog of war is active. Turns out to be much faster. Though you need really big maps (Winter's Fury MAP01) to see a difference in fps. * Non-linux checks don't like uint. Changed to unsigned int. * Small change of a float to camera.zs. Ignore for testing. Should make no difference. * Update actor.h to remain mergeable RF2_NOMIPMAP was introduced, so I had to displace RF_ISOMETRICSPRITES to next bit.
This commit is contained in:
parent
b044baf850
commit
95b264bdb6
33 changed files with 819 additions and 84 deletions
|
|
@ -163,7 +163,11 @@ sector_t* RenderViewpoint(FRenderViewpoint& mainvp, AActor* camera, IntRect* bou
|
|||
di->Viewpoint.FieldOfView = DAngle::fromDeg(fov); // Set the real FOV for the current scene (it's not necessarily the same as the global setting in r_viewpoint)
|
||||
|
||||
// Stereo mode specific perspective projection
|
||||
di->VPUniforms.mProjectionMatrix = eye.GetProjection(fov, ratio, fovratio);
|
||||
float inv_iso_dist = 1.0f;
|
||||
bool iso_ortho = (camera->ViewPos != NULL) && (camera->ViewPos->Flags & VPSF_ORTHOGRAPHIC);
|
||||
if (iso_ortho && (camera->ViewPos->Offset.Length() > 0)) inv_iso_dist = 1.0/camera->ViewPos->Offset.Length();
|
||||
di->VPUniforms.mProjectionMatrix = eye.GetProjection(fov, ratio, fovratio * inv_iso_dist, iso_ortho);
|
||||
|
||||
// Stereo mode specific viewpoint adjustment
|
||||
vp.Pos += eye.GetViewShift(vp.HWAngles.Yaw.Degrees());
|
||||
di->SetupView(RenderState, vp.Pos.X, vp.Pos.Y, vp.Pos.Z, false, false);
|
||||
|
|
|
|||
|
|
@ -51,11 +51,24 @@
|
|||
CVAR(Bool, gl_multithread, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
|
||||
EXTERN_CVAR(Float, r_actorspriteshadowdist)
|
||||
EXTERN_CVAR(Bool, r_radarclipper)
|
||||
EXTERN_CVAR(Bool, r_dithertransparency)
|
||||
|
||||
thread_local bool isWorkerThread;
|
||||
ctpl::thread_pool renderPool(1);
|
||||
bool inited = false;
|
||||
|
||||
const int MAXDITHERACTORS = 20; // Maximum number of enemies that can set dither-transparency flags
|
||||
AActor* RenderedTargets[MAXDITHERACTORS];
|
||||
int RTnum;
|
||||
|
||||
void ClearDitherTargets()
|
||||
{
|
||||
RTnum = 0; // Number of rendered enemies/targets
|
||||
for (int ii = 0; ii < MAXDITHERACTORS; ii++)
|
||||
RenderedTargets[ii] = nullptr;
|
||||
}
|
||||
|
||||
struct RenderJob
|
||||
{
|
||||
enum
|
||||
|
|
@ -269,6 +282,20 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip)
|
|||
auto &clipper = *mClipper;
|
||||
angle_t startAngle = clipper.GetClipAngle(seg->v2);
|
||||
angle_t endAngle = clipper.GetClipAngle(seg->v1);
|
||||
auto &clipperr = *rClipper;
|
||||
angle_t startAngleR = clipperr.PointToPseudoAngle(seg->v2->fX(), seg->v2->fY());
|
||||
angle_t endAngleR = clipperr.PointToPseudoAngle(seg->v1->fX(), seg->v1->fY());
|
||||
|
||||
if(r_radarclipper && !(Level->flags3 & LEVEL3_NOFOGOFWAR) && (startAngleR - endAngleR >= ANGLE_180))
|
||||
{
|
||||
if (!seg->backsector) clipperr.SafeAddClipRange(startAngleR, endAngleR);
|
||||
else if((seg->sidedef != nullptr) && !uint8_t(seg->sidedef->Flags & WALLF_POLYOBJ) && (currentsector->sectornum != seg->backsector->sectornum))
|
||||
{
|
||||
if (in_area == area_default) in_area = hw_CheckViewArea(seg->v2, seg->v1, seg->frontsector, seg->backsector);
|
||||
backsector = hw_FakeFlat(seg->backsector, in_area, true);
|
||||
if (hw_CheckClip(seg->sidedef, currentsector, backsector)) clipperr.SafeAddClipRange(startAngleR, endAngleR);
|
||||
}
|
||||
}
|
||||
|
||||
// Back side, i.e. backface culling - read: endAngle >= startAngle!
|
||||
if (startAngle-endAngle<ANGLE_180)
|
||||
|
|
@ -280,25 +307,53 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip)
|
|||
{
|
||||
if (!(currentsubsector->flags & SSECMF_DRAWN))
|
||||
{
|
||||
if (clipper.SafeCheckRange(startAngle, endAngle))
|
||||
if (clipper.SafeCheckRange(startAngle, endAngle) && (!r_radarclipper || (Level->flags3 & LEVEL3_NOFOGOFWAR)))
|
||||
{
|
||||
currentsubsector->flags |= SSECMF_DRAWN;
|
||||
currentsubsector->flags |= SSECMF_DRAWN;
|
||||
}
|
||||
if ((r_radarclipper || !(Level->flags3 & LEVEL3_NOFOGOFWAR)) && clipperr.SafeCheckRange(startAngleR, endAngleR))
|
||||
{
|
||||
currentsubsector->flags |= SSECMF_DRAWN;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!clipper.SafeCheckRange(startAngle, endAngle))
|
||||
if (!clipper.SafeCheckRange(startAngle, endAngle))
|
||||
{
|
||||
return;
|
||||
}
|
||||
currentsubsector->flags |= SSECMF_DRAWN;
|
||||
|
||||
auto &clipperv = *vClipper;
|
||||
angle_t startPitch = clipperv.PointToPseudoPitch(seg->v1->fX(), seg->v1->fY(), currentsector->floorplane.ZatPoint(seg->v1));
|
||||
angle_t endPitch = clipperv.PointToPseudoPitch(seg->v1->fX(), seg->v1->fY(), currentsector->ceilingplane.ZatPoint(seg->v1));
|
||||
angle_t startPitch2 = clipperv.PointToPseudoPitch(seg->v2->fX(), seg->v2->fY(), currentsector->floorplane.ZatPoint(seg->v2));
|
||||
angle_t endPitch2 = clipperv.PointToPseudoPitch(seg->v2->fX(), seg->v2->fY(), currentsector->ceilingplane.ZatPoint(seg->v2));
|
||||
angle_t temp;
|
||||
// Wall can be tilted from viewpoint perspective. Find vertical extent on screen in psuedopitch units (0 to 2, bottom to top)
|
||||
if(int(startPitch) > int(startPitch2)) // Handle zero crossing
|
||||
{
|
||||
temp = startPitch; startPitch = startPitch2; startPitch2 = temp; // exchange
|
||||
}
|
||||
if(int(endPitch) > int(endPitch2)) // Handle zero crossing
|
||||
{
|
||||
temp = endPitch; endPitch = endPitch2; endPitch2 = temp; // exchange
|
||||
}
|
||||
|
||||
if (!clipperv.SafeCheckRange(startPitch, endPitch2))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!r_radarclipper || (Level->flags3 & LEVEL3_NOFOGOFWAR) || clipperr.SafeCheckRange(startAngleR, endAngleR))
|
||||
currentsubsector->flags |= SSECMF_DRAWN;
|
||||
|
||||
uint8_t ispoly = uint8_t(seg->sidedef->Flags & WALLF_POLYOBJ);
|
||||
|
||||
if (!seg->backsector)
|
||||
{
|
||||
clipper.SafeAddClipRange(startAngle, endAngle);
|
||||
if(!Viewpoint.IsAllowedOoB())
|
||||
if (!(seg->sidedef->Flags & WALLF_DITHERTRANS)) clipper.SafeAddClipRange(startAngle, endAngle);
|
||||
}
|
||||
else if (!ispoly) // Two-sided polyobjects never obstruct the view
|
||||
{
|
||||
|
|
@ -325,7 +380,8 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip)
|
|||
|
||||
if (hw_CheckClip(seg->sidedef, currentsector, backsector))
|
||||
{
|
||||
clipper.SafeAddClipRange(startAngle, endAngle);
|
||||
if(!Viewpoint.IsAllowedOoB() && !(seg->sidedef->Flags & WALLF_DITHERTRANS))
|
||||
clipper.SafeAddClipRange(startAngle, endAngle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -526,13 +582,14 @@ void HWDrawInfo::RenderThings(subsector_t * sub, sector_t * sector)
|
|||
{
|
||||
sector_t * sec=sub->sector;
|
||||
// Handle all things in sector.
|
||||
const auto &vp = Viewpoint;
|
||||
const auto &vp = Viewpoint;
|
||||
for (auto p = sec->touching_renderthings; p != nullptr; p = p->m_snext)
|
||||
{
|
||||
auto thing = p->m_thing;
|
||||
if (thing->validcount == validcount) continue;
|
||||
thing->validcount = validcount;
|
||||
|
||||
if(Viewpoint.IsAllowedOoB() && thing->Sector->isSecret() && thing->Sector->wasSecret() && !r_radarclipper) continue; // This covers things that are touching non-secret sectors
|
||||
FIntCVar *cvar = thing->GetInfo()->distancecheck;
|
||||
if (cvar != nullptr && *cvar >= 0)
|
||||
{
|
||||
|
|
@ -666,6 +723,51 @@ void HWDrawInfo::DoSubsector(subsector_t * sub)
|
|||
|
||||
fakesector=hw_FakeFlat(sector, in_area, false);
|
||||
|
||||
if(Viewpoint.IsAllowedOoB() && sector->isSecret() && sector->wasSecret() && !r_radarclipper) return;
|
||||
|
||||
// cull everything if subsector outside vertical clipper
|
||||
if ((sub->polys == nullptr) && (!Viewpoint.IsOrtho() || !((Level->flags3 & LEVEL3_NOFOGOFWAR) || !r_radarclipper)))
|
||||
{
|
||||
auto &clipper = *mClipper;
|
||||
auto &clipperv = *vClipper;
|
||||
auto &clipperr = *rClipper;
|
||||
int count = sub->numlines;
|
||||
seg_t * seg = sub->firstline;
|
||||
bool anglevisible = false;
|
||||
bool pitchvisible = false;
|
||||
bool radarvisible = false;
|
||||
angle_t pitchtemp;
|
||||
angle_t pitchmin = ANGLE_90;
|
||||
angle_t pitchmax = 0;
|
||||
|
||||
while (count--)
|
||||
{
|
||||
if((seg->v1 != nullptr) && (seg->v2 != nullptr))
|
||||
{
|
||||
angle_t startAngle = clipper.GetClipAngle(seg->v2);
|
||||
angle_t endAngle = clipper.GetClipAngle(seg->v1);
|
||||
if (startAngle-endAngle >= ANGLE_180) anglevisible |= clipper.SafeCheckRange(startAngle, endAngle);
|
||||
angle_t startAngleR = clipperr.PointToPseudoAngle(seg->v2->fX(), seg->v2->fY());
|
||||
angle_t endAngleR = clipperr.PointToPseudoAngle(seg->v1->fX(), seg->v1->fY());
|
||||
if (startAngleR-endAngleR >= ANGLE_180)
|
||||
radarvisible |= (clipperr.SafeCheckRange(startAngleR, endAngleR) || (Level->flags3 & LEVEL3_NOFOGOFWAR) || ((sub->flags & SSECMF_DRAWN) && !deathmatch));
|
||||
pitchmin = clipperv.PointToPseudoPitch(seg->v1->fX(), seg->v1->fY(), sector->floorplane.ZatPoint(seg->v1));
|
||||
pitchmax = clipperv.PointToPseudoPitch(seg->v1->fX(), seg->v1->fY(), sector->ceilingplane.ZatPoint(seg->v1));
|
||||
pitchvisible |= clipperv.SafeCheckRange(pitchmin, pitchmax);
|
||||
if (pitchvisible && anglevisible && radarvisible) break;
|
||||
pitchtemp = clipperv.PointToPseudoPitch(seg->v2->fX(), seg->v2->fY(), sector->floorplane.ZatPoint(seg->v2));
|
||||
if (int(pitchmin) > int(pitchtemp)) pitchmin = pitchtemp;
|
||||
pitchtemp = clipperv.PointToPseudoPitch(seg->v2->fX(), seg->v2->fY(), sector->ceilingplane.ZatPoint(seg->v2));
|
||||
if (int(pitchmax) < int(pitchtemp)) pitchmax = pitchtemp;
|
||||
pitchvisible |= clipperv.SafeCheckRange(pitchmin, pitchmax);
|
||||
if (pitchvisible && anglevisible && radarvisible) break;
|
||||
}
|
||||
seg++;
|
||||
}
|
||||
// Skip subsector if outside vertical or horizontal clippers or is in unexplored territory (fog of war)
|
||||
if(!pitchvisible || !anglevisible || (!radarvisible && r_radarclipper)) return;
|
||||
}
|
||||
|
||||
if (mClipPortal)
|
||||
{
|
||||
int clipres = mClipPortal->ClipSubsector(sub);
|
||||
|
|
@ -723,6 +825,20 @@ void HWDrawInfo::DoSubsector(subsector_t * sub)
|
|||
SetupSprite.Unclock();
|
||||
}
|
||||
}
|
||||
if (r_dithertransparency && Viewpoint.IsAllowedOoB() && (RTnum < MAXDITHERACTORS))
|
||||
{
|
||||
// [DVR] Not parallelizable due to variables RTnum and RenderedTargets[]
|
||||
for (auto p = sector->touching_renderthings; p != nullptr; p = p->m_snext)
|
||||
{
|
||||
auto thing = p->m_thing;
|
||||
if (thing->validcount == validcount) continue; // Don't double count
|
||||
if (((thing->flags3 & MF3_ISMONSTER) && !(thing->flags & MF_CORPSE)) || (thing->flags & MF_MISSILE))
|
||||
{
|
||||
if (RTnum < MAXDITHERACTORS) RenderedTargets[RTnum++] = thing;
|
||||
else break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gl_render_flats)
|
||||
|
|
@ -843,19 +959,62 @@ void HWDrawInfo::RenderBSPNode (void *node)
|
|||
if (!(no_renderflags[bsp->Index()] & SSRF_SEEN))
|
||||
return;
|
||||
}
|
||||
if (Viewpoint.IsOrtho())
|
||||
{
|
||||
if (!vClipper->CheckBoxOrthoPitch(bsp->bbox[side]))
|
||||
{
|
||||
if (!(no_renderflags[bsp->Index()] & SSRF_SEEN))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
node = bsp->children[side];
|
||||
}
|
||||
DoSubsector ((subsector_t *)((uint8_t *)node - 1));
|
||||
}
|
||||
|
||||
// No need for clipping inside frustum if no fog of war (How is this faster!)
|
||||
void HWDrawInfo::RenderOrthoNoFog()
|
||||
{
|
||||
if (Viewpoint.IsOrtho() && ((Level->flags3 & LEVEL3_NOFOGOFWAR) || !r_radarclipper))
|
||||
{
|
||||
double vxdbl = Viewpoint.camera->X();
|
||||
double vydbl = Viewpoint.camera->Y();
|
||||
double ext = Viewpoint.camera->ViewPos->Offset.Length() ?
|
||||
3.0 * Viewpoint.camera->ViewPos->Offset.Length() : 100.0;
|
||||
FBoundingBox viewbox(vxdbl, vydbl, ext);
|
||||
|
||||
for (unsigned int kk = 0; kk < Level->subsectors.Size(); kk++)
|
||||
{
|
||||
if (Level->subsectors[kk].bbox.CheckOverlap(viewbox))
|
||||
{
|
||||
DoSubsector (&Level->subsectors[kk]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HWDrawInfo::RenderBSP(void *node, bool drawpsprites)
|
||||
{
|
||||
ClearDitherTargets();
|
||||
Bsp.Clock();
|
||||
|
||||
// Give the DrawInfo the viewpoint in fixed point because that's what the nodes are.
|
||||
viewx = FLOAT2FIXED(Viewpoint.Pos.X);
|
||||
viewy = FLOAT2FIXED(Viewpoint.Pos.Y);
|
||||
if (r_radarclipper && !(Level->flags3 & LEVEL3_NOFOGOFWAR) && Viewpoint.IsAllowedOoB() && (Viewpoint.camera->ViewPos->Flags & VPSF_ABSOLUTEOFFSET))
|
||||
{
|
||||
if (Viewpoint.camera->tracer != NULL)
|
||||
{
|
||||
viewx = FLOAT2FIXED(Viewpoint.camera->tracer->X());
|
||||
viewy = FLOAT2FIXED(Viewpoint.camera->tracer->Y());
|
||||
}
|
||||
else
|
||||
{
|
||||
viewx = FLOAT2FIXED(Viewpoint.camera->X());
|
||||
viewy = FLOAT2FIXED(Viewpoint.camera->Y());
|
||||
}
|
||||
}
|
||||
|
||||
validcount++; // used for processing sidedefs only once by the renderer.
|
||||
|
||||
|
|
@ -866,7 +1025,8 @@ void HWDrawInfo::RenderBSP(void *node, bool drawpsprites)
|
|||
auto future = renderPool.push([&](int id) {
|
||||
WorkerThread();
|
||||
});
|
||||
RenderBSPNode(node);
|
||||
if (Viewpoint.IsOrtho() && ((Level->flags3 & LEVEL3_NOFOGOFWAR) || !r_radarclipper)) RenderOrthoNoFog();
|
||||
else RenderBSPNode(node);
|
||||
|
||||
jobQueue.AddJob(RenderJob::TerminateJob, nullptr, nullptr);
|
||||
Bsp.Unclock();
|
||||
|
|
@ -876,9 +1036,21 @@ void HWDrawInfo::RenderBSP(void *node, bool drawpsprites)
|
|||
}
|
||||
else
|
||||
{
|
||||
RenderBSPNode(node);
|
||||
if (Viewpoint.IsOrtho() && ((Level->flags3 & LEVEL3_NOFOGOFWAR) || !r_radarclipper)) RenderOrthoNoFog();
|
||||
else RenderBSPNode(node);
|
||||
Bsp.Unclock();
|
||||
}
|
||||
|
||||
// Make rendered targets set dither transparency flags on level geometry for next pass
|
||||
// Can't do this inside DoSubsector() because both Trace() and P_CheckSight() affect 'validcount' global variable
|
||||
for (int ii = 0; ii < MAXDITHERACTORS; ii++)
|
||||
{
|
||||
if ( RenderedTargets[ii] && P_CheckSight(players[consoleplayer].mo, RenderedTargets[ii], 0) )
|
||||
{
|
||||
SetDitherTransFlags(RenderedTargets[ii]);
|
||||
}
|
||||
}
|
||||
|
||||
// Process all the sprites on the current portal's back side which touch the portal.
|
||||
if (mCurrentPortal != nullptr) mCurrentPortal->RenderAttached(this);
|
||||
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ void Clipper::AddClipRange(angle_t start, angle_t end)
|
|||
|
||||
if (node->end < end)
|
||||
{
|
||||
node->end = end;
|
||||
node->end = end; // [DVR] This never triggers because of previous while loop. Remove?
|
||||
}
|
||||
|
||||
ClipNode *node2 = node->next;
|
||||
|
|
@ -361,6 +361,17 @@ angle_t Clipper::AngleToPseudo(angle_t ang)
|
|||
return xs_Fix<30>::ToFix(result);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
angle_t Clipper::PitchToPseudo(double ang)
|
||||
{
|
||||
return AngleToPseudo(DAngle::fromDeg(90.0-ang).BAMs()); // Pitch is positive when looking down
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ! Returns the pseudoangle between the line p1 to (infinity, p1.y) and the
|
||||
|
|
@ -378,11 +389,28 @@ angle_t Clipper::PointToPseudoAngle(double x, double y)
|
|||
{
|
||||
double vecx = x - viewpoint->Pos.X;
|
||||
double vecy = y - viewpoint->Pos.Y;
|
||||
if ((viewpoint->camera != NULL) && amRadar)
|
||||
{
|
||||
if (viewpoint->camera->tracer != NULL)
|
||||
{
|
||||
vecx = x - viewpoint->camera->tracer->X();
|
||||
vecy = y - viewpoint->camera->tracer->Y();
|
||||
}
|
||||
else
|
||||
{
|
||||
vecx = x - viewpoint->camera->X();
|
||||
vecy = y - viewpoint->camera->Y();
|
||||
}
|
||||
}
|
||||
|
||||
if (vecx == 0 && vecy == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (!amRadar && viewpoint->IsOrtho())
|
||||
{
|
||||
return PointToPseudoOrthoAngle(x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
double result = vecy / (fabs(vecx) + fabs(vecy));
|
||||
|
|
@ -395,6 +423,78 @@ angle_t Clipper::PointToPseudoAngle(double x, double y)
|
|||
}
|
||||
|
||||
|
||||
angle_t Clipper::PointToPseudoPitch(double x, double y, double z)
|
||||
{
|
||||
double vecx = x - viewpoint->Pos.X;
|
||||
double vecy = y - viewpoint->Pos.Y;
|
||||
double vecz = z - viewpoint->Pos.Z;
|
||||
double result = 0;
|
||||
|
||||
if (vecx == 0 && vecy == 0 && vecz == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (viewpoint->IsOrtho())
|
||||
{
|
||||
return PointToPseudoOrthoPitch(x, y, z);
|
||||
}
|
||||
else
|
||||
{
|
||||
double result = vecz / (g_sqrt(vecx*vecx + vecy*vecy) + fabs(vecz)); // -ffast-math compile flag applies to this file, yes?
|
||||
if ((vecx * viewpoint->TanCos + vecy * viewpoint->TanSin) <= 0.0) // Point is behind viewpoint
|
||||
{
|
||||
result = 2.0 - result;
|
||||
}
|
||||
return xs_Fix<30>::ToFix(result + 1.0); // range to 0 to 2 to 4 (bottom to top to suplex)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
angle_t Clipper::PointToPseudoOrthoAngle(double x, double y)
|
||||
{
|
||||
DVector3 disp = DVector3( x, y, 0 ) - viewpoint->camera->Pos();
|
||||
if (viewpoint->camera->ViewPos->Offset.XY().Length() == 0)
|
||||
{
|
||||
return AngleToPseudo( viewpoint->Angles.Yaw.BAMs() );
|
||||
}
|
||||
else
|
||||
{
|
||||
angle_t af = viewpoint->FrustAngle;
|
||||
double xproj = disp.XY().Length() * deltaangle(disp.Angle(), viewpoint->Angles.Yaw).Sin();
|
||||
xproj *= viewpoint->ScreenProj;
|
||||
if (fabs(xproj) < 2.0)
|
||||
{
|
||||
return AngleToPseudo( viewpoint->Angles.Yaw.BAMs() - xproj * 0.5 * af );
|
||||
}
|
||||
else
|
||||
{
|
||||
return (xproj > 0.0 ? AngleToPseudo( viewpoint->Angles.Yaw.BAMs() - af ) : AngleToPseudo( viewpoint->Angles.Yaw.BAMs() + af ));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
angle_t Clipper::PointToPseudoOrthoPitch(double x, double y, double z)
|
||||
{
|
||||
DVector3 disp = DVector3( x, y, z ) - viewpoint->camera->Pos();
|
||||
if (viewpoint->camera->ViewPos->Offset.XY().Length() > 0)
|
||||
{
|
||||
double yproj = viewpoint->PitchSin * disp.XY().Length() * deltaangle(disp.Angle(), viewpoint->Angles.Yaw).Cos();
|
||||
yproj += viewpoint->PitchCos * disp.Z;
|
||||
yproj *= viewpoint->ScreenProj;
|
||||
if (fabs(yproj) <= 1.5)
|
||||
{
|
||||
return PitchToPseudo(viewpoint->Angles.Pitch.Degrees() - yproj * 0.5 * viewpoint->FieldOfView.Degrees() );
|
||||
}
|
||||
else
|
||||
{
|
||||
double a2 = 0.75*viewpoint->FieldOfView.Degrees();
|
||||
a2 *= ( yproj > 0.0 ? -1.0 : 1.0 );
|
||||
return PitchToPseudo(viewpoint->Angles.Pitch.Degrees() + a2 );
|
||||
}
|
||||
}
|
||||
else return PitchToPseudo(viewpoint->Angles.Pitch.Degrees());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
|
|
@ -428,7 +528,7 @@ bool Clipper::CheckBox(const float *bspcoord)
|
|||
|
||||
// Find the corners of the box
|
||||
// that define the edges from current viewpoint.
|
||||
auto &vp = viewpoint;
|
||||
auto &vp = viewpoint;
|
||||
boxpos = (vp->Pos.X <= bspcoord[BOXLEFT] ? 0 : vp->Pos.X < bspcoord[BOXRIGHT ] ? 1 : 2) +
|
||||
(vp->Pos.Y >= bspcoord[BOXTOP ] ? 0 : vp->Pos.Y > bspcoord[BOXBOTTOM] ? 4 : 8);
|
||||
|
||||
|
|
@ -437,7 +537,47 @@ bool Clipper::CheckBox(const float *bspcoord)
|
|||
check = checkcoord[boxpos];
|
||||
angle1 = PointToPseudoAngle (bspcoord[check[0]], bspcoord[check[1]]);
|
||||
angle2 = PointToPseudoAngle (bspcoord[check[2]], bspcoord[check[3]]);
|
||||
|
||||
if (vp->IsOrtho())
|
||||
{
|
||||
if (angle2 != angle1) return true;
|
||||
switch (boxpos) // Check if the closer corner is poking into the view area
|
||||
{
|
||||
case 0:
|
||||
case 10:
|
||||
if ( angle1 != PointToPseudoAngle (bspcoord[check[2]], bspcoord[check[1]]) ) return true;
|
||||
break;
|
||||
case 2:
|
||||
case 8:
|
||||
if ( angle1 != PointToPseudoAngle (bspcoord[check[0]], bspcoord[check[3]]) ) return true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return SafeCheckRange(angle2, angle1);
|
||||
}
|
||||
|
||||
bool Clipper::CheckBoxOrthoPitch(const float *bspcoord)
|
||||
{
|
||||
angle_t pitchmin, pitchmax;
|
||||
auto &vp = viewpoint;
|
||||
if (!vp->IsOrtho()) return true;
|
||||
|
||||
angle_t pitchtemp;
|
||||
double padding = 1.0/viewpoint->ScreenProj/viewpoint->PitchCos;
|
||||
double camz = vp->camera->Pos().Z - padding;
|
||||
pitchmin = PointToPseudoPitch (bspcoord[BOXLEFT], bspcoord[BOXTOP], camz);
|
||||
pitchmax = PointToPseudoPitch (bspcoord[BOXLEFT], bspcoord[BOXTOP], camz + 2.0*padding);
|
||||
for (int yi = BOXTOP; yi <= BOXBOTTOM; yi++)
|
||||
for (int xi = BOXLEFT; xi <= BOXRIGHT; xi++)
|
||||
{
|
||||
pitchtemp = PointToPseudoPitch (bspcoord[xi], bspcoord[yi], camz);
|
||||
if (pitchmin - pitchtemp < ANGLE_180) pitchmin = pitchtemp;
|
||||
pitchtemp = PointToPseudoPitch (bspcoord[xi], bspcoord[yi], camz + 2.0*padding);
|
||||
if (pitchtemp - pitchmax < ANGLE_180) pitchmax = pitchtemp;
|
||||
}
|
||||
|
||||
return (pitchmax != pitchmin); // SafeCheckRange(pitchmin, pitchmax);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,10 +29,11 @@ class Clipper
|
|||
ClipNode * clipnodes = nullptr;
|
||||
ClipNode * cliphead = nullptr;
|
||||
ClipNode * silhouette = nullptr; // will be preserved even when RemoveClipRange is called
|
||||
const FRenderViewpoint *viewpoint = nullptr;
|
||||
FRenderViewpoint *viewpoint = nullptr;
|
||||
bool blocked = false;
|
||||
|
||||
static angle_t AngleToPseudo(angle_t ang);
|
||||
static angle_t PitchToPseudo(double ang);
|
||||
bool IsRangeVisible(angle_t startangle, angle_t endangle);
|
||||
void RemoveRange(ClipNode * cn);
|
||||
void AddClipRange(angle_t startangle, angle_t endangle);
|
||||
|
|
@ -41,6 +42,7 @@ class Clipper
|
|||
|
||||
public:
|
||||
|
||||
bool amRadar = false;
|
||||
Clipper();
|
||||
|
||||
void Clear();
|
||||
|
|
@ -72,7 +74,7 @@ public:
|
|||
return c;
|
||||
}
|
||||
|
||||
void SetViewpoint(const FRenderViewpoint &vp)
|
||||
void SetViewpoint(FRenderViewpoint &vp)
|
||||
{
|
||||
viewpoint = &vp;
|
||||
}
|
||||
|
|
@ -116,6 +118,10 @@ public:
|
|||
SafeAddClipRange(AngleToPseudo(startangle), AngleToPseudo(endangle));
|
||||
}
|
||||
|
||||
void SafeAddClipRangeDegPitches(double startpitch, double endpitch)
|
||||
{
|
||||
SafeAddClipRange(PitchToPseudo(startpitch), PitchToPseudo(endpitch));
|
||||
}
|
||||
|
||||
void SafeRemoveClipRange(angle_t startangle, angle_t endangle)
|
||||
{
|
||||
|
|
@ -146,10 +152,14 @@ public:
|
|||
{
|
||||
return blocked;
|
||||
}
|
||||
|
||||
angle_t PointToPseudoAngle(double x, double y);
|
||||
|
||||
angle_t PointToPseudoAngle(double x, double y);
|
||||
angle_t PointToPseudoPitch(double x, double y, double z);
|
||||
angle_t PointToPseudoOrthoAngle(double x, double y);
|
||||
angle_t PointToPseudoOrthoPitch(double x, double y, double z);
|
||||
|
||||
bool CheckBox(const float *bspcoord);
|
||||
bool CheckBoxOrthoPitch(const float *bspcoord);
|
||||
|
||||
// Used to speed up angle calculations during clipping
|
||||
inline angle_t GetClipAngle(vertex_t *v)
|
||||
|
|
|
|||
|
|
@ -131,12 +131,19 @@ HWDrawInfo *HWDrawInfo::StartDrawInfo(FLevelLocals *lev, HWDrawInfo *parent, FRe
|
|||
//==========================================================================
|
||||
|
||||
static Clipper staticClipper; // Since all scenes are processed sequentially we only need one clipper.
|
||||
static Clipper staticVClipper; // Another clipper to clip vertically (used if (VPSF_ALLOWOUTOFBOUNDS & camera->viewpos->Flags)).
|
||||
static Clipper staticRClipper; // Another clipper for radar (doesn't actually clip. Changes SSECMF_DRAWN setting).
|
||||
static HWDrawInfo * gl_drawinfo; // This is a linked list of all active DrawInfos and needed to free the memory arena after the last one goes out of scope.
|
||||
|
||||
void HWDrawInfo::StartScene(FRenderViewpoint &parentvp, HWViewpointUniforms *uniforms)
|
||||
{
|
||||
staticClipper.Clear();
|
||||
staticVClipper.Clear();
|
||||
staticRClipper.Clear();
|
||||
mClipper = &staticClipper;
|
||||
vClipper = &staticVClipper;
|
||||
rClipper = &staticRClipper;
|
||||
rClipper->amRadar = true;
|
||||
|
||||
Viewpoint = parentvp;
|
||||
lightmode = getRealLightmode(Level, true);
|
||||
|
|
@ -169,6 +176,8 @@ void HWDrawInfo::StartScene(FRenderViewpoint &parentvp, HWViewpointUniforms *uni
|
|||
VPUniforms.mLightBlendMode = (level.info ? (int)level.info->lightblendmode : 0);
|
||||
}
|
||||
mClipper->SetViewpoint(Viewpoint);
|
||||
vClipper->SetViewpoint(Viewpoint);
|
||||
rClipper->SetViewpoint(Viewpoint);
|
||||
|
||||
ClearBuffers();
|
||||
|
||||
|
|
@ -257,7 +266,9 @@ void HWDrawInfo::ClearBuffers()
|
|||
|
||||
void HWDrawInfo::UpdateCurrentMapSection()
|
||||
{
|
||||
const int mapsection = Level->PointInRenderSubsector(Viewpoint.Pos)->mapsection;
|
||||
int mapsection = Level->PointInRenderSubsector(Viewpoint.Pos)->mapsection;
|
||||
if (Viewpoint.IsAllowedOoB())
|
||||
mapsection = Level->PointInRenderSubsector(Viewpoint.camera->Pos())->mapsection;
|
||||
CurrentMapSections.Set(mapsection);
|
||||
}
|
||||
|
||||
|
|
@ -270,9 +281,11 @@ void HWDrawInfo::UpdateCurrentMapSection()
|
|||
|
||||
void HWDrawInfo::SetViewArea()
|
||||
{
|
||||
auto &vp = Viewpoint;
|
||||
auto &vp = Viewpoint;
|
||||
// The render_sector is better suited to represent the current position in GL
|
||||
vp.sector = Level->PointInRenderSubsector(vp.Pos)->render_sector;
|
||||
if (Viewpoint.IsAllowedOoB())
|
||||
vp.sector = Level->PointInRenderSubsector(vp.camera->Pos())->render_sector;
|
||||
|
||||
// Get the heightsec state from the render sector, not the current one!
|
||||
if (vp.sector->GetHeightSec())
|
||||
|
|
@ -351,16 +364,14 @@ int HWDrawInfo::SetFullbrightFlags(player_t *player)
|
|||
|
||||
angle_t HWDrawInfo::FrustumAngle()
|
||||
{
|
||||
float tilt = fabs(Viewpoint.HWAngles.Pitch.Degrees());
|
||||
// If pitch is larger than this you can look all around at an FOV of 90 degrees
|
||||
if (fabs(Viewpoint.HWAngles.Pitch.Degrees()) > 89.0) return 0xffffffff;
|
||||
|
||||
// If the pitch is larger than this you can look all around at a FOV of 90°
|
||||
if (tilt > 46.0f) return 0xffffffff;
|
||||
double xratio = r_viewwindow.FocalTangent / Viewpoint.PitchCos;
|
||||
double floatangle = 0.035 + atan ( xratio ) * 48.0 / AspectMultiplier(r_viewwindow.WidescreenRatio); // this is radians
|
||||
angle_t a1 = DAngle::fromRad(floatangle).BAMs();
|
||||
|
||||
// ok, this is a gross hack that barely works...
|
||||
// but at least it doesn't overestimate too much...
|
||||
double floatangle = 2.0 + (45.0 + ((tilt / 1.9)))*Viewpoint.FieldOfView.Degrees() * 48.0 / AspectMultiplier(r_viewwindow.WidescreenRatio) / 90.0;
|
||||
angle_t a1 = DAngle::fromDeg(floatangle).BAMs();
|
||||
if (a1 >= ANGLE_180) return 0xffffffff;
|
||||
if (a1 >= ANGLE_90) return 0xffffffff;
|
||||
return a1;
|
||||
}
|
||||
|
||||
|
|
@ -438,8 +449,12 @@ HWDecal *HWDrawInfo::AddDecal(bool onmirror)
|
|||
void HWDrawInfo::CreateScene(bool drawpsprites)
|
||||
{
|
||||
const auto &vp = Viewpoint;
|
||||
angle_t a1 = FrustumAngle();
|
||||
angle_t a1 = FrustumAngle(); // horizontally clip the back of the viewport
|
||||
mClipper->SafeAddClipRangeRealAngles(vp.Angles.Yaw.BAMs() + a1, vp.Angles.Yaw.BAMs() - a1);
|
||||
Viewpoint.FrustAngle = a1;
|
||||
double a2 = 20.0 + 0.5*Viewpoint.FieldOfView.Degrees(); // FrustumPitch for vertical clipping
|
||||
if (a2 > 179.0) a2 = 179.0;
|
||||
vClipper->SafeAddClipRangeDegPitches(vp.HWAngles.Pitch.Degrees() - a2, vp.HWAngles.Pitch.Degrees() + a2); // clip the suplex range
|
||||
|
||||
// reset the portal manager
|
||||
portalState.StartFrame();
|
||||
|
|
@ -648,6 +663,79 @@ void HWDrawInfo::DrawCorona(FRenderState& state, ACorona* corona, double dist)
|
|||
#endif
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// TraceCallbackForDitherTransparency
|
||||
// Toggles dither flag on anything that occludes the actor's
|
||||
// position from viewpoint.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static ETraceStatus TraceCallbackForDitherTransparency(FTraceResults& res, void* userdata)
|
||||
{
|
||||
int* count = (int*)userdata;
|
||||
double bf, bc;
|
||||
(*count)++;
|
||||
switch(res.HitType)
|
||||
{
|
||||
case TRACE_HitWall:
|
||||
if (!(res.Line->sidedef[res.Side]->Flags & WALLF_DITHERTRANS))
|
||||
{
|
||||
bf = res.Line->sidedef[res.Side]->sector->floorplane.ZatPoint(res.HitPos.XY());
|
||||
bc = res.Line->sidedef[res.Side]->sector->ceilingplane.ZatPoint(res.HitPos.XY());
|
||||
if ((res.HitPos.Z <= bc) && (res.HitPos.Z >= bf)) res.Line->sidedef[res.Side]->Flags |= WALLF_DITHERTRANS;
|
||||
}
|
||||
break;
|
||||
case TRACE_HitFloor:
|
||||
res.Sector->floorplane.dithertransflag = true;
|
||||
break;
|
||||
case TRACE_HitCeiling:
|
||||
res.Sector->ceilingplane.dithertransflag = true;
|
||||
break;
|
||||
case TRACE_HitActor:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return TRACE_ContinueOutOfBounds;
|
||||
}
|
||||
|
||||
|
||||
void HWDrawInfo::SetDitherTransFlags(AActor* actor)
|
||||
{
|
||||
if (actor && actor->Sector)
|
||||
{
|
||||
FTraceResults results;
|
||||
double horix = Viewpoint.Sin * actor->radius;
|
||||
double horiy = Viewpoint.Cos * actor->radius;
|
||||
DVector3 actorpos = actor->Pos();
|
||||
DVector3 vvec = actorpos - Viewpoint.Pos;
|
||||
if (Viewpoint.IsOrtho())
|
||||
{
|
||||
vvec += Viewpoint.camera->Pos() - actorpos;
|
||||
vvec *= 5.0; // Should be 4.0? (since zNear is behind screen by 3*dist in VREyeInfo::GetProjection())
|
||||
}
|
||||
double distance = vvec.Length() - actor->radius;
|
||||
DVector3 campos = actorpos - vvec;
|
||||
sector_t* startsec;
|
||||
int count = 0;
|
||||
|
||||
vvec = vvec.Unit();
|
||||
campos.X -= horix; campos.Y += horiy; campos.Z += actor->Height * 0.25;
|
||||
for (int iter = 0; iter < 3; iter++)
|
||||
{
|
||||
startsec = Level->PointInRenderSubsector(campos)->sector;
|
||||
Trace(campos, startsec, vvec, distance,
|
||||
0, 0, actor, results, 0, TraceCallbackForDitherTransparency, &count);
|
||||
campos.Z += actor->Height * 0.5;
|
||||
Trace(campos, startsec, vvec, distance,
|
||||
0, 0, actor, results, 0, TraceCallbackForDitherTransparency, &count);
|
||||
campos.Z -= actor->Height * 0.5;
|
||||
campos.X += horix; campos.Y -= horiy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static ETraceStatus CheckForViewpointActor(FTraceResults& res, void* userdata)
|
||||
{
|
||||
FRenderViewpoint* data = (FRenderViewpoint*)userdata;
|
||||
|
|
@ -803,13 +891,17 @@ void HWDrawInfo::DrawScene(int drawmode)
|
|||
{
|
||||
static int recursion = 0;
|
||||
static int ssao_portals_available = 0;
|
||||
const auto& vp = Viewpoint;
|
||||
auto& vp = Viewpoint;
|
||||
|
||||
bool applySSAO = false;
|
||||
if (drawmode == DM_MAINVIEW)
|
||||
{
|
||||
ssao_portals_available = gl_ssao_portals;
|
||||
applySSAO = true;
|
||||
if (r_dithertransparency && vp.IsAllowedOoB())
|
||||
{
|
||||
vp.camera->tracer ? SetDitherTransFlags(vp.camera->tracer) : SetDitherTransFlags(players[consoleplayer].mo);
|
||||
}
|
||||
}
|
||||
else if (drawmode == DM_OFFSCREEN)
|
||||
{
|
||||
|
|
@ -864,6 +956,8 @@ void HWDrawInfo::ProcessScene(bool toscreen)
|
|||
portalState.BeginScene();
|
||||
|
||||
int mapsection = Level->PointInRenderSubsector(Viewpoint.Pos)->mapsection;
|
||||
if (Viewpoint.IsAllowedOoB())
|
||||
mapsection = Level->PointInRenderSubsector(Viewpoint.camera->Pos())->mapsection;
|
||||
CurrentMapSections.Set(mapsection);
|
||||
DrawScene(toscreen ? DM_MAINVIEW : DM_OFFSCREEN);
|
||||
|
||||
|
|
|
|||
|
|
@ -146,6 +146,8 @@ struct HWDrawInfo
|
|||
HWPortal *mCurrentPortal;
|
||||
//FRotator mAngles;
|
||||
Clipper *mClipper;
|
||||
Clipper *vClipper; // Vertical clipper
|
||||
Clipper *rClipper; // Radar clipper
|
||||
FRenderViewpoint Viewpoint;
|
||||
HWViewpointUniforms VPUniforms; // per-viewpoint uniform state
|
||||
TArray<HWPortal *> Portals;
|
||||
|
|
@ -234,6 +236,7 @@ public:
|
|||
|
||||
HWPortal * FindPortal(const void * src);
|
||||
void RenderBSPNode(void *node);
|
||||
void RenderOrthoNoFog();
|
||||
void RenderBSP(void *node, bool drawpsprites);
|
||||
|
||||
static HWDrawInfo *StartDrawInfo(FLevelLocals *lev, HWDrawInfo *parent, FRenderViewpoint &parentvp, HWViewpointUniforms *uniforms);
|
||||
|
|
@ -302,6 +305,8 @@ public:
|
|||
void DrawCoronas(FRenderState& state);
|
||||
void DrawCorona(FRenderState& state, ACorona* corona, double dist);
|
||||
|
||||
void SetDitherTransFlags(AActor* actor);
|
||||
|
||||
void ProcessLowerMinisegs(TArray<seg_t *> &lowersegs);
|
||||
void AddSubsectorToPortal(FSectorPortalGroup *portal, subsector_t *sub);
|
||||
|
||||
|
|
|
|||
|
|
@ -320,7 +320,7 @@ void HWFlat::DrawFlat(HWDrawInfo *di, FRenderState &state, bool translucent)
|
|||
state.SetObjectColor(FlatColor | 0xff000000);
|
||||
state.SetAddColor(AddColor | 0xff000000);
|
||||
state.ApplyTextureManipulation(TextureFx);
|
||||
|
||||
if (plane.plane.dithertransflag) state.SetEffect(EFF_DITHERTRANS);
|
||||
|
||||
if (hacktype & SSRF_PLANEHACK)
|
||||
{
|
||||
|
|
@ -372,6 +372,7 @@ void HWFlat::DrawFlat(HWDrawInfo *di, FRenderState &state, bool translucent)
|
|||
state.SetObjectColor(0xffffffff);
|
||||
state.SetAddColor(0);
|
||||
state.ApplyTextureManipulation(nullptr);
|
||||
if (plane.plane.dithertransflag) state.SetEffect(EFF_NONE);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
@ -408,6 +409,8 @@ inline void HWFlat::PutFlat(HWDrawInfo *di, bool fog)
|
|||
void HWFlat::Process(HWDrawInfo *di, sector_t * model, int whichplane, bool fog)
|
||||
{
|
||||
plane.GetFromSector(model, whichplane);
|
||||
model->ceilingplane.dithertransflag = false; // Resetting this every frame
|
||||
model->floorplane.dithertransflag = false; // Resetting this every frame
|
||||
if (whichplane != int(ceiling))
|
||||
{
|
||||
// Flip the normal if the source plane has a different orientation than what we are about to render.
|
||||
|
|
@ -506,7 +509,7 @@ void HWFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector, int which)
|
|||
|
||||
uint8_t sink;
|
||||
uint8_t &srf = hacktype? sink : di->section_renderflags[di->Level->sections.SectionIndex(section)];
|
||||
const auto &vp = di->Viewpoint;
|
||||
auto &vp = di->Viewpoint;
|
||||
|
||||
//
|
||||
//
|
||||
|
|
@ -515,7 +518,7 @@ void HWFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector, int which)
|
|||
//
|
||||
//
|
||||
//
|
||||
if ((which & SSRF_RENDERFLOOR) && frontsector->floorplane.ZatPoint(vp.Pos) <= vp.Pos.Z && (!section || !(section->flags & FSection::DONTRENDERFLOOR)))
|
||||
if (((which & SSRF_RENDERFLOOR) && frontsector->floorplane.ZatPoint(vp.Pos) <= vp.Pos.Z && (!section || !(section->flags & FSection::DONTRENDERFLOOR)))&& !(vp.IsOrtho() && (vp.PitchSin < 0.0)))
|
||||
{
|
||||
// process the original floor first.
|
||||
|
||||
|
|
@ -573,7 +576,7 @@ void HWFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector, int which)
|
|||
//
|
||||
//
|
||||
//
|
||||
if ((which & SSRF_RENDERCEILING) && frontsector->ceilingplane.ZatPoint(vp.Pos) >= vp.Pos.Z && (!section || !(section->flags & FSection::DONTRENDERCEILING)))
|
||||
if (((which & SSRF_RENDERCEILING) && frontsector->ceilingplane.ZatPoint(vp.Pos) >= vp.Pos.Z && (!section || !(section->flags & FSection::DONTRENDERCEILING))) && !(vp.IsOrtho() && (vp.PitchSin > 0.0)))
|
||||
{
|
||||
// process the original ceiling first.
|
||||
|
||||
|
|
|
|||
|
|
@ -563,7 +563,8 @@ bool HWMirrorPortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *clippe
|
|||
angle_t af = di->FrustumAngle();
|
||||
if (af < ANGLE_180) clipper->SafeAddClipRangeRealAngles(vp.Angles.Yaw.BAMs() + af, vp.Angles.Yaw.BAMs() - af);
|
||||
|
||||
clipper->SafeAddClipRange(linedef->v1, linedef->v2);
|
||||
if(!di->Viewpoint.IsAllowedOoB())
|
||||
clipper->SafeAddClipRange(linedef->v1, linedef->v2);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -130,6 +130,7 @@ void HWSkyInfo::init(HWDrawInfo *di, sector_t* sec, int skypos, int sky1, PalEnt
|
|||
void HWWall::SkyPlane(HWWallDispatcher *di, sector_t *sector, int plane, bool allowreflect)
|
||||
{
|
||||
int ptype = -1;
|
||||
if (di->di && di->di->Viewpoint.IsAllowedOoB()) return; // Couldn't prevent sky portal occlusion. Skybox is bad in ortho too.
|
||||
|
||||
FSectorPortal *sportal = sector->ValidatePortal(plane);
|
||||
if (sportal != nullptr && sportal->mFlags & PORTSF_INSKYBOX) sportal = nullptr; // no recursions, delete it here to simplify the following code
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ extern TArray<spriteframe_t> SpriteFrames;
|
|||
extern uint32_t r_renderercaps;
|
||||
|
||||
const float LARGE_VALUE = 1e19f;
|
||||
const float MY_SQRT2 = 1.41421356237309504880; // sqrt(2)
|
||||
|
||||
EXTERN_CVAR(Bool, r_debug_disable_vis_filter)
|
||||
EXTERN_CVAR(Float, transsouls)
|
||||
|
|
@ -494,7 +495,7 @@ bool HWSprite::CalculateVertices(HWDrawInfo* di, FVector3* v, DVector3* vp)
|
|||
}
|
||||
else // traditional "Y" billboard mode
|
||||
{
|
||||
if (doRoll || !offset.isZero())
|
||||
if (doRoll || !offset.isZero() || (actor && (actor->renderflags2 & RF2_ISOMETRICSPRITES)))
|
||||
{
|
||||
mat.MakeIdentity();
|
||||
|
||||
|
|
@ -516,6 +517,16 @@ bool HWSprite::CalculateVertices(HWDrawInfo* di, FVector3* v, DVector3* vp)
|
|||
mat.Translate(-center.X, -center.Z, -center.Y);
|
||||
}
|
||||
|
||||
if (actor && (actor->renderflags2 & RF2_ISOMETRICSPRITES) && di->Viewpoint.IsOrtho())
|
||||
{
|
||||
float angleRad = (FAngle::fromDeg(270.) - HWAngles.Yaw).Radians();
|
||||
mat.Translate(center.X, center.Z, center.Y);
|
||||
mat.Translate(0.0, z2 - center.Z, 0.0);
|
||||
mat.Rotate(-sin(angleRad), 0, cos(angleRad), -actor->isotheta);
|
||||
mat.Translate(0.0, center.Z - z2, 0.0);
|
||||
mat.Translate(-center.X, -center.Z, -center.Y);
|
||||
}
|
||||
|
||||
v[0] = mat * FVector3(x1, z1, y1);
|
||||
v[1] = mat * FVector3(x2, z1, y2);
|
||||
v[2] = mat * FVector3(x1, z2, y1);
|
||||
|
|
@ -911,6 +922,7 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
|
|||
{
|
||||
bool mirror = false;
|
||||
DAngle ang = (thingpos - vp.Pos).Angle();
|
||||
if (di->Viewpoint.IsOrtho()) ang = vp.Angles.Yaw;
|
||||
FTextureID patch;
|
||||
// [ZZ] add direct picnum override
|
||||
if (isPicnumOverride)
|
||||
|
|
@ -1004,7 +1016,25 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
|
|||
if (thing->renderflags & RF_SPRITEFLIP) // [SP] Flip back
|
||||
thing->renderflags ^= RF_XFLIP;
|
||||
|
||||
r.Scale(sprscale.X, isSpriteShadow ? sprscale.Y * 0.15 : sprscale.Y);
|
||||
// If sprite is isometric, do both vertical scaling and partial rotation to face the camera to compensate for Y-billboarding.
|
||||
// Using just rotation (about z=0) might cause tall+slender (high aspect ratio) sprites to clip out of collision box
|
||||
// at the top and clip into whatever is behind them from the viewpoint's perspective. - [DVR]
|
||||
thing->isoscaleY = 1.0;
|
||||
thing->isotheta = vp.HWAngles.Pitch.Degrees();
|
||||
if (thing->renderflags2 & RF2_ISOMETRICSPRITES)
|
||||
{
|
||||
float floordist = thing->radius * vp.floordistfact;
|
||||
floordist -= 0.5 * r.width * vp.cotfloor;
|
||||
float sineisotheta = floordist / r.height;
|
||||
double scl = g_sqrt( 1.0 + sineisotheta * sineisotheta - 2.0 * vp.PitchSin * sineisotheta );
|
||||
if ((thing->radius > 0.0) && (scl > fabs(vp.PitchCos)))
|
||||
{
|
||||
thing->isoscaleY = scl / ( fabs(vp.PitchCos) > 0.01 ? fabs(vp.PitchCos) : 0.01 );
|
||||
thing->isotheta = 180.0 * asin( sineisotheta / thing->isoscaleY ) / M_PI;
|
||||
}
|
||||
}
|
||||
|
||||
r.Scale(sprscale.X, isSpriteShadow ? sprscale.Y * 0.15 * thing->isoscaleY : sprscale.Y * thing->isoscaleY);
|
||||
|
||||
if (thing->renderflags & (RF_ROLLSPRITE|RF_FLATSPRITE))
|
||||
{
|
||||
|
|
@ -1018,7 +1048,7 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
|
|||
z1 = z - r.top;
|
||||
z2 = z1 - r.height;
|
||||
|
||||
float spriteheight = sprscale.Y * r.height;
|
||||
float spriteheight = sprscale.Y * r.height * thing->isoscaleY;
|
||||
|
||||
// Tests show that this doesn't look good for many decorations and corpses
|
||||
if (spriteheight > 0 && gl_spriteclip > 0 && (thing->renderflags & RF_SPRITETYPEMASK) == RF_FACESPRITE)
|
||||
|
|
@ -1037,6 +1067,13 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
|
|||
x2 = x - viewvecY*rightfac;
|
||||
y1 = y + viewvecX*leftfac;
|
||||
y2 = y + viewvecX*rightfac;
|
||||
if (thing->renderflags2 & RF2_ISOMETRICSPRITES) // If sprites are drawn from an isometric perspective
|
||||
{
|
||||
x1 -= viewvecX * thing->radius * MY_SQRT2;
|
||||
x2 -= viewvecX * thing->radius * MY_SQRT2;
|
||||
y1 -= viewvecY * thing->radius * MY_SQRT2;
|
||||
y2 -= viewvecY * thing->radius * MY_SQRT2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RF_FLATSPRITE:
|
||||
|
|
@ -1077,6 +1114,7 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
|
|||
}
|
||||
|
||||
depth = (float)((x - vp.Pos.X) * vp.TanCos + (y - vp.Pos.Y) * vp.TanSin);
|
||||
if(thing->renderflags2 & RF2_ISOMETRICSPRITES) depth = depth * vp.PitchCos - vp.PitchSin * z2; // Helps with stacking actors with small xy offsets
|
||||
if (isSpriteShadow) depth += 1.f/65536.f; // always sort shadows behind the sprite.
|
||||
|
||||
// light calculation
|
||||
|
|
|
|||
|
|
@ -83,10 +83,16 @@ void SetSplitPlanes(FRenderState& state, const secplane_t& top, const secplane_t
|
|||
|
||||
void HWWall::RenderWall(FRenderState &state, int textured)
|
||||
{
|
||||
if (seg->sidedef->Flags & WALLF_DITHERTRANS) state.SetEffect(EFF_DITHERTRANS);
|
||||
assert(vertcount > 0);
|
||||
state.SetLightIndex(dynlightindex);
|
||||
state.Draw(DT_TriangleFan, vertindex, vertcount);
|
||||
vertexcount += vertcount;
|
||||
if (seg->sidedef->Flags & WALLF_DITHERTRANS)
|
||||
{
|
||||
state.SetEffect(EFF_NONE);
|
||||
seg->sidedef->Flags &= ~WALLF_DITHERTRANS; // reset this every frame
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
@ -2175,6 +2181,8 @@ void HWWall::Process(HWWallDispatcher *di, seg_t *seg, sector_t * frontsector, s
|
|||
}
|
||||
|
||||
bool isportal = seg->linedef->isVisualPortal() && seg->sidedef == seg->linedef->sidedef[0];
|
||||
// Don't render portal insides if in orthographic mode
|
||||
if (di->di) isportal &= !(di->di->Viewpoint.IsOrtho());
|
||||
|
||||
//return;
|
||||
// [GZ] 3D middle textures are necessarily two-sided, even if they lack the explicit two-sided flag
|
||||
|
|
|
|||
|
|
@ -66,7 +66,9 @@
|
|||
#include "i_system.h"
|
||||
#include "v_draw.h"
|
||||
#include "i_interface.h"
|
||||
#include "d_main.h"
|
||||
|
||||
const float MY_SQRT2 = 1.41421356237309504880; // sqrt(2)
|
||||
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
|
||||
|
||||
extern bool DrawFSHUD; // [RH] Defined in d_main.cpp
|
||||
|
|
@ -103,6 +105,8 @@ CVAR (Bool, r_deathcamera, false, CVAR_ARCHIVE)
|
|||
CVAR (Int, r_clearbuffer, 0, 0)
|
||||
CVAR (Bool, r_drawvoxels, true, 0)
|
||||
CVAR (Bool, r_drawplayersprites, true, 0) // [RH] Draw player sprites?
|
||||
CVARD (Bool, r_radarclipper, false, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_CHEAT, "Use the horizontal clipper from camera->tracer's perspective")
|
||||
CVARD (Bool, r_dithertransparency, false, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_CHEAT, "Use dithered-transparency shading for actor-occluding level geometry")
|
||||
CUSTOM_CVAR(Float, r_quakeintensity, 1.0f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 0.f) self = 0.f;
|
||||
|
|
@ -155,9 +159,14 @@ FRenderViewpoint::FRenderViewpoint()
|
|||
Sin = 0.0;
|
||||
TanCos = 0.0;
|
||||
TanSin = 0.0;
|
||||
PitchCos = 0.0;
|
||||
PitchSin = 0.0;
|
||||
floordistfact = 0.0;
|
||||
cotfloor = 0.0;
|
||||
camera = nullptr;
|
||||
sector = nullptr;
|
||||
FieldOfView = DAngle::fromDeg(90.); // Angles in the SCREENWIDTH wide window
|
||||
ScreenProj = 0.0;
|
||||
TicFrac = 0.0;
|
||||
FrameTime = 0;
|
||||
extralight = 0;
|
||||
|
|
@ -552,39 +561,42 @@ void R_InterpolateView(FRenderViewpoint& viewPoint, const player_t* const player
|
|||
|
||||
// Due to interpolation this is not necessarily the same as the sector the camera is in.
|
||||
viewPoint.sector = viewLvl->PointInRenderSubsector(viewPoint.Pos)->sector;
|
||||
bool moved = false;
|
||||
while (!viewPoint.sector->PortalBlocksMovement(sector_t::ceiling))
|
||||
if (!viewPoint.IsAllowedOoB() || !V_IsHardwareRenderer())
|
||||
{
|
||||
if (viewPoint.Pos.Z > viewPoint.sector->GetPortalPlaneZ(sector_t::ceiling))
|
||||
bool moved = false;
|
||||
while (!viewPoint.sector->PortalBlocksMovement(sector_t::ceiling))
|
||||
{
|
||||
const DVector2 offset = viewPoint.sector->GetPortalDisplacement(sector_t::ceiling);
|
||||
viewPoint.Pos += offset;
|
||||
viewPoint.ActorPos += offset;
|
||||
viewPoint.sector = viewPoint.sector->GetPortal(sector_t::ceiling)->mDestination;
|
||||
moved = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!moved)
|
||||
{
|
||||
while (!viewPoint.sector->PortalBlocksMovement(sector_t::floor))
|
||||
{
|
||||
if (viewPoint.Pos.Z < viewPoint.sector->GetPortalPlaneZ(sector_t::floor))
|
||||
if (viewPoint.Pos.Z > viewPoint.sector->GetPortalPlaneZ(sector_t::ceiling))
|
||||
{
|
||||
const DVector2 offset = viewPoint.sector->GetPortalDisplacement(sector_t::floor);
|
||||
const DVector2 offset = viewPoint.sector->GetPortalDisplacement(sector_t::ceiling);
|
||||
viewPoint.Pos += offset;
|
||||
viewPoint.ActorPos += offset;
|
||||
viewPoint.sector = viewPoint.sector->GetPortal(sector_t::floor)->mDestination;
|
||||
viewPoint.sector = viewPoint.sector->GetPortal(sector_t::ceiling)->mDestination;
|
||||
moved = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!moved)
|
||||
{
|
||||
while (!viewPoint.sector->PortalBlocksMovement(sector_t::floor))
|
||||
{
|
||||
if (viewPoint.Pos.Z < viewPoint.sector->GetPortalPlaneZ(sector_t::floor))
|
||||
{
|
||||
const DVector2 offset = viewPoint.sector->GetPortalDisplacement(sector_t::floor);
|
||||
viewPoint.Pos += offset;
|
||||
viewPoint.ActorPos += offset;
|
||||
viewPoint.sector = viewPoint.sector->GetPortal(sector_t::floor)->mDestination;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (P_NoInterpolation(player, viewPoint.camera))
|
||||
|
|
@ -680,10 +692,46 @@ void FRenderViewpoint::SetViewAngle(const FViewWindow& viewWindow)
|
|||
TanSin = viewWindow.FocalTangent * Sin;
|
||||
TanCos = viewWindow.FocalTangent * Cos;
|
||||
|
||||
PitchSin = Angles.Pitch.Sin();
|
||||
PitchCos = Angles.Pitch.Cos();
|
||||
|
||||
floordistfact = MY_SQRT2 + ( fabs(Cos) > fabs(Sin) ? 1.0/fabs(Cos) : 1.0/fabs(Sin) );
|
||||
cotfloor = ( fabs(Cos) > fabs(Sin) ? fabs(Sin/Cos) : fabs(Cos/Sin) );
|
||||
|
||||
const DVector2 v = Angles.Yaw.ToVector();
|
||||
ViewVector.X = v.X;
|
||||
ViewVector.Y = v.Y;
|
||||
HWAngles.Yaw = FAngle::fromDeg(270.0 - Angles.Yaw.Degrees());
|
||||
|
||||
if (IsOrtho() && (camera->ViewPos->Offset.XY().Length() > 0.0))
|
||||
ScreenProj = 1.34396 / camera->ViewPos->Offset.Length(); // [DVR] Estimated. +/-1 should be top/bottom of screen.
|
||||
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// R_IsAllowedOoB()
|
||||
// Checks if camera actor exists, has viewpos,
|
||||
// and viewpos has VPSF_ALLOWOUTOFBOUNDS flag set.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FRenderViewpoint::IsAllowedOoB()
|
||||
{
|
||||
return (camera && camera->ViewPos && (camera->ViewPos->Flags & VPSF_ALLOWOUTOFBOUNDS));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// R_IsOrtho()
|
||||
// Checks if camera actor exists, has viewpos,
|
||||
// and viewpos has VPSF_ORTHOGRAPHIC flag set.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FRenderViewpoint::IsOrtho()
|
||||
{
|
||||
return (camera && camera->ViewPos && (camera->ViewPos->Flags & VPSF_ORTHOGRAPHIC));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
@ -1017,14 +1065,15 @@ void R_SetupFrame(FRenderViewpoint& viewPoint, const FViewWindow& viewWindow, AA
|
|||
viewPoint.SetViewAngle(viewWindow);
|
||||
|
||||
// Keep the view within the sector's floor and ceiling
|
||||
if (viewPoint.sector->PortalBlocksMovement(sector_t::ceiling))
|
||||
// But allow VPSF_ALLOWOUTOFBOUNDS camera viewpoints to go out of bounds when using hardware renderer
|
||||
if (viewPoint.sector->PortalBlocksMovement(sector_t::ceiling) && (!viewPoint.IsAllowedOoB() || !V_IsHardwareRenderer()))
|
||||
{
|
||||
const double z = viewPoint.sector->ceilingplane.ZatPoint(viewPoint.Pos) - 4.0;
|
||||
if (viewPoint.Pos.Z > z)
|
||||
viewPoint.Pos.Z = z;
|
||||
}
|
||||
|
||||
if (viewPoint.sector->PortalBlocksMovement(sector_t::floor))
|
||||
if (viewPoint.sector->PortalBlocksMovement(sector_t::floor) && (!viewPoint.IsAllowedOoB() || !V_IsHardwareRenderer()))
|
||||
{
|
||||
const double z = viewPoint.sector->floorplane.ZatPoint(viewPoint.Pos) + 4.0;
|
||||
if (viewPoint.Pos.Z < z)
|
||||
|
|
|
|||
|
|
@ -33,10 +33,16 @@ struct FRenderViewpoint
|
|||
double Sin; // sin(Angles.Yaw)
|
||||
double TanCos; // FocalTangent * cos(Angles.Yaw)
|
||||
double TanSin; // FocalTangent * sin(Angles.Yaw)
|
||||
double PitchCos; // cos(Angles.Pitch)
|
||||
double PitchSin; // sin(Angles.Pitch)
|
||||
double floordistfact; // used for isometric sprites Y-billboarding compensation in hw_sprites.cpp
|
||||
double cotfloor; // used for isometric sprites Y-billboarding compensation in hw_sprites.cpp
|
||||
angle_t FrustAngle; // FrustumAngle() result
|
||||
|
||||
AActor *camera; // camera actor
|
||||
sector_t *sector; // [RH] keep track of sector viewing from
|
||||
DAngle FieldOfView; // current field of view
|
||||
double ScreenProj; // Screen projection factor for orthographic projection
|
||||
|
||||
double TicFrac; // fraction of tic for interpolation
|
||||
uint32_t FrameTime; // current frame's time in tics.
|
||||
|
|
@ -45,6 +51,8 @@ struct FRenderViewpoint
|
|||
bool showviewer; // show the camera actor?
|
||||
bool bForceNoViewer; // Never show the camera Actor.
|
||||
void SetViewAngle(const FViewWindow& viewWindow);
|
||||
bool IsAllowedOoB(); // Checks if camera actor exists, has viewpos, and viewpos has VPSF_ALLOWOUTOFBOUNDS flag set
|
||||
bool IsOrtho(); // Checks if camera actor exists, has viewpos, and viewpos has VPSF_ORTHOGRAPHIC flag set
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue