Allow portal rendering and sky rendering (with stencils) and reflective flats with OoB and Ortho viewpoints. Works with r_radarclipper too.

This commit is contained in:
Dileep V. Reddy 2025-03-09 21:14:54 -06:00 committed by Nash Muhandes
commit 6c93c3d564
13 changed files with 300 additions and 137 deletions

View file

@ -1226,6 +1226,9 @@ enum
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)
WALLF_DITHERTRANS_TOP = WALLF_DITHERTRANS << 0, // Top tier (gets reset every frame)
WALLF_DITHERTRANS_MID = WALLF_DITHERTRANS << 1, // Mid tier (gets reset every frame)
WALLF_DITHERTRANS_BOTTOM = WALLF_DITHERTRANS << 2, // Bottom tier (gets reset every frame)
};
struct side_t
@ -1303,6 +1306,8 @@ struct side_t
int numsegs;
int sidenum;
int dithertranscount;
int GetLightLevel (bool foggy, int baselight, int which, bool is3dlight=false, int *pfakecontrast_usedbygzdoom=NULL) const;
void SetLight(int16_t l)

View file

@ -174,6 +174,7 @@ sector_t* RenderViewpoint(FRenderViewpoint& mainvp, AActor* camera, IntRect* bou
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);
di->ProjectionMatrix2 = eye.GetProjection(fov, ratio, fovratio, false); // Regular ol' perspective projection matrix
// Stereo mode specific viewpoint adjustment
vp.Pos += eye.GetViewShift(vp.HWAngles.Yaw.Degrees());
@ -470,4 +471,4 @@ ADD_STAT(lightprobes)
FString out;
out.Format("Rendering probe: %d / %d", lightProbeBuilder.GetStep(), level.lightProbes.Size());
return out;
}
}

View file

@ -290,15 +290,17 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip, FRenderState& state)
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());
angle_t paddingR = 0x00200000; // Make radar clipping more aggressive (reveal less)
if(Viewpoint.IsAllowedOoB() && r_radarclipper && !(Level->flags3 & LEVEL3_NOFOGOFWAR) && (startAngleR - endAngleR >= ANGLE_180))
{
if (!seg->backsector) clipperr.SafeAddClipRange(startAngleR, endAngleR);
if (!seg->backsector) clipperr.SafeAddClipRange(startAngleR - paddingR, endAngleR + paddingR);
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->v1, seg->v2, seg->frontsector, seg->backsector);
backsector = hw_FakeFlat(drawctx, seg->backsector, in_area, true);
if (hw_CheckClip(seg->sidedef, currentsector, backsector)) clipperr.SafeAddClipRange(startAngleR, endAngleR);
if (hw_CheckClip(seg->sidedef, currentsector, backsector)) clipperr.SafeAddClipRange(startAngleR - paddingR, endAngleR + paddingR);
backsector = nullptr;
}
}
@ -316,7 +318,7 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip, FRenderState& state)
{
currentsubsector->flags |= SSECMF_DRAWN;
}
if ((r_radarclipper || !(Level->flags3 & LEVEL3_NOFOGOFWAR)) && clipperr.SafeCheckRange(startAngleR, endAngleR))
if (Viewpoint.IsAllowedOoB() && (r_radarclipper && !(Level->flags3 & LEVEL3_NOFOGOFWAR)) && clipperr.SafeCheckRange(startAngleR, endAngleR))
{
currentsubsector->flags |= SSECMF_DRAWN;
}
@ -329,31 +331,7 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip, FRenderState& state)
return;
}
if (Viewpoint.IsAllowedOoB()) // No need for vertical clipping if viewpoint not allowed out of bounds
{
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))
if (Viewpoint.IsAllowedOoB() && (!r_radarclipper || (Level->flags3 & LEVEL3_NOFOGOFWAR) || clipperr.SafeCheckRange(startAngleR, endAngleR)))
currentsubsector->flags |= SSECMF_DRAWN;
uint8_t ispoly = uint8_t(seg->sidedef->Flags & WALLF_POLYOBJ);
@ -361,7 +339,7 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip, FRenderState& state)
if (!seg->backsector)
{
if(!Viewpoint.IsAllowedOoB())
if (!(seg->sidedef->Flags & WALLF_DITHERTRANS)) clipper.SafeAddClipRange(startAngle, endAngle);
if (!(seg->sidedef->Flags & WALLF_DITHERTRANS_MID)) clipper.SafeAddClipRange(startAngle, endAngle);
}
else if (!ispoly) // Two-sided polyobjects never obstruct the view
{
@ -388,7 +366,7 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip, FRenderState& state)
if (hw_CheckClip(seg->sidedef, currentsector, backsector))
{
if(!Viewpoint.IsAllowedOoB() && !(seg->sidedef->Flags & WALLF_DITHERTRANS))
if(!Viewpoint.IsAllowedOoB() && !(seg->sidedef->Flags & WALLF_DITHERTRANS_MID))
clipper.SafeAddClipRange(startAngle, endAngle);
}
}
@ -732,8 +710,8 @@ void HWDrawInfo::DoSubsector(subsector_t * sub, FRenderState& state)
if(Viewpoint.IsAllowedOoB() && sector->isSecret() && sector->wasSecret() && !r_radarclipper) return;
// cull everything if subsector outside all clippers
if ((sub->polys == nullptr) && (!Viewpoint.IsOrtho() || !((Level->flags3 & LEVEL3_NOFOGOFWAR) || !r_radarclipper)))
// cull everything if subsector outside all relevant clippers
if ((sub->polys == nullptr))
{
auto &clipper = *mClipper;
auto &clipperv = *vClipper;
@ -742,7 +720,10 @@ void HWDrawInfo::DoSubsector(subsector_t * sub, FRenderState& state)
seg_t * seg = sub->firstline;
bool anglevisible = false;
bool pitchvisible = !(Viewpoint.IsAllowedOoB()); // No vertical clipping if viewpoint is not allowed out of bounds
bool radarvisible = false;
bool radarvisible = !(Viewpoint.IsAllowedOoB()) || !r_radarclipper || (Level->flags3 & LEVEL3_NOFOGOFWAR) || ((sub->flags & SSECMF_DRAWN) && !deathmatch);
bool ceilreflect = (mCurrentPortal && strcmp(mCurrentPortal->GetName(), "Planemirror ceiling"));
bool floorreflect = (mCurrentPortal && strcmp(mCurrentPortal->GetName(), "Planemirror floor"));
double planez = (ceilreflect ? sector->ceilingplane.ZatPoint(Viewpoint.Pos) : sector->floorplane.ZatPoint(Viewpoint.Pos));
angle_t pitchtemp;
angle_t pitchmin = ANGLE_90;
angle_t pitchmax = 0;
@ -751,25 +732,43 @@ void HWDrawInfo::DoSubsector(subsector_t * sub, FRenderState& state)
{
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));
if (!anglevisible)
{
angle_t startAngle = clipper.GetClipAngle(seg->v2);
angle_t endAngle = clipper.GetClipAngle(seg->v1);
if (startAngle-endAngle >= ANGLE_180) anglevisible |= clipper.SafeCheckRange(startAngle, endAngle);
}
if (!radarvisible)
{
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);
}
if (!pitchvisible)
{
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));
pitchmin = clipperv.PointToPseudoPitch(seg->v1->fX(), seg->v1->fY(),
(ceilreflect || floorreflect) ?
2 * planez - sector->floorplane.ZatPoint(seg->v1) :
sector->floorplane.ZatPoint(seg->v1));
pitchmax = clipperv.PointToPseudoPitch(seg->v1->fX(), seg->v1->fY(),
(ceilreflect || floorreflect) ?
2 * planez - sector->ceilingplane.ZatPoint(seg->v1) :
sector->ceilingplane.ZatPoint(seg->v1));
pitchvisible |= clipperv.SafeCheckRange(pitchmin, pitchmax);
}
if (pitchvisible && anglevisible && radarvisible) break;
if (!pitchvisible)
{
pitchtemp = clipperv.PointToPseudoPitch(seg->v2->fX(), seg->v2->fY(), sector->floorplane.ZatPoint(seg->v2));
pitchtemp = clipperv.PointToPseudoPitch(seg->v2->fX(), seg->v2->fY(),
(ceilreflect || floorreflect) ?
2 * planez - sector->floorplane.ZatPoint(seg->v2) :
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));
pitchtemp = clipperv.PointToPseudoPitch(seg->v2->fX(), seg->v2->fY(),
(ceilreflect || floorreflect) ?
2 * planez - sector->ceilingplane.ZatPoint(seg->v2) :
sector->ceilingplane.ZatPoint(seg->v2));
if (int(pitchmax) < int(pitchtemp)) pitchmax = pitchtemp;
pitchvisible |= clipperv.SafeCheckRange(pitchmin, pitchmax);
}
@ -838,7 +837,7 @@ void HWDrawInfo::DoSubsector(subsector_t * sub, FRenderState& state)
SetupSprite.Unclock();
}
}
if (r_dithertransparency && Viewpoint.IsAllowedOoB() && (RTnum < MAXDITHERACTORS))
if (r_dithertransparency && Viewpoint.IsAllowedOoB() && (RTnum < MAXDITHERACTORS) && mCurrentPortal == nullptr)
{
// [DVR] Not parallelizable due to variables RTnum and RenderedTargets[]
for (auto p = sector->touching_renderthings; p != nullptr; p = p->m_snext)
@ -992,8 +991,8 @@ void HWDrawInfo::RenderOrthoNoFog(FRenderState& state)
{
if (Viewpoint.IsOrtho() && ((Level->flags3 & LEVEL3_NOFOGOFWAR) || !r_radarclipper))
{
double vxdbl = Viewpoint.camera->X();
double vydbl = Viewpoint.camera->Y();
double vxdbl = Viewpoint.OffPos.X;
double vydbl = Viewpoint.OffPos.Y;
double ext = Viewpoint.camera->ViewPos->Offset.Length() ?
3.0 * Viewpoint.camera->ViewPos->Offset.Length() * tan (Viewpoint.FieldOfView.Radians()*0.5) : 100.0;
FBoundingBox viewbox(vxdbl, vydbl, ext);
@ -1018,16 +1017,8 @@ void HWDrawInfo::RenderBSP(void *node, bool drawpsprites, FRenderState& state)
viewy = FLOAT2FIXED(Viewpoint.Pos.Y);
if (r_radarclipper && !(Level->flags3 & LEVEL3_NOFOGOFWAR) && Viewpoint.IsAllowedOoB())
{
if (Viewpoint.camera->tracer != nullptr)
{
viewx = FLOAT2FIXED(Viewpoint.camera->tracer->X());
viewy = FLOAT2FIXED(Viewpoint.camera->tracer->Y());
}
else
{
viewx = FLOAT2FIXED(Viewpoint.camera->X());
viewy = FLOAT2FIXED(Viewpoint.camera->Y());
}
viewx = FLOAT2FIXED(Viewpoint.OffPos.X);
viewy = FLOAT2FIXED(Viewpoint.OffPos.Y);
}
validcount++; // used for processing sidedefs only once by the renderer.

View file

@ -387,18 +387,10 @@ 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 (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();
}
vecx = x - viewpoint->OffPos.X;
vecy = y - viewpoint->OffPos.Y;
}
if (vecx == 0 && vecy == 0)
@ -460,7 +452,7 @@ angle_t Clipper::PointToPseudoPitch(double x, double y, double z)
angle_t Clipper::PointToPseudoOrthoAngle(double x, double y)
{
DVector3 disp = DVector3( x, y, 0 ) - viewpoint->camera->Pos();
DVector3 disp = DVector3(x, y, 0) - viewpoint->OffPos;
if (viewpoint->camera->ViewPos->Offset.XY().Length() == 0)
{
return AngleToPseudo( viewpoint->Angles.Yaw.BAMs() );
@ -484,7 +476,7 @@ angle_t Clipper::PointToPseudoOrthoAngle(double x, double y)
angle_t Clipper::PointToPseudoOrthoPitch(double x, double y, double z)
{
DVector3 disp = DVector3( x, y, z ) - viewpoint->camera->Pos();
DVector3 disp = DVector3(x, y, z) - viewpoint->OffPos;
if (viewpoint->camera->ViewPos->Offset.XY().Length() > 0)
{
double yproj = viewpoint->PitchSin * disp.XY().Length() * deltaangle(disp.Angle(), viewpoint->Angles.Yaw).Cos();

View file

@ -113,6 +113,7 @@ void HWDrawInfo::StartScene(FRenderViewpoint &parentvp, HWViewpointUniforms *uni
VPUniforms.mProjectionMatrix.loadIdentity();
VPUniforms.mViewMatrix.loadIdentity();
VPUniforms.mNormalViewMatrix.loadIdentity();
ProjectionMatrix2.loadIdentity();
VPUniforms.mViewOffsetX = -screen->mSceneViewport.left;
VPUniforms.mViewOffsetY = -screen->mSceneViewport.top;
VPUniforms.mViewHeight = viewheight;
@ -926,63 +927,84 @@ static ETraceStatus CheckForViewpointActor(FTraceResults& res, void* userdata)
static ETraceStatus TraceCallbackForDitherTransparency(FTraceResults& res, void* userdata)
{
int* count = (int*)userdata;
BitArray* CurMapSections = (BitArray*)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))
sector_t* linesec = res.Line->sidedef[res.Side]->sector;
if (linesec->subsectorcount > 0 && (*CurMapSections)[linesec->subsectors[0]->mapsection])
{
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.Line->sidedef[!res.Side])
{
// Two sided line! So let's find out if mid, top, or bottom texture needs dithered transparency
bf = max(bf, res.Line->sidedef[!res.Side]->sector->floorplane.ZatPoint(res.HitPos.XY()));
bc = min(bc, res.Line->sidedef[!res.Side]->sector->ceilingplane.ZatPoint(res.HitPos.XY()));
if (res.HitPos.Z <= bf) res.Line->sidedef[res.Side]->Flags |= WALLF_DITHERTRANS_BOTTOM;
else if (res.HitPos.Z < bc) res.Line->sidedef[res.Side]->Flags |= WALLF_DITHERTRANS_MID;
else res.Line->sidedef[res.Side]->Flags |= WALLF_DITHERTRANS_TOP;
res.Line->sidedef[res.Side]->dithertranscount = max<int>(1, res.Line->sidedef[!res.Side]->sector->e->XFloor.ffloors.Size());
}
else if ((res.HitPos.Z <= bc) && (res.HitPos.Z >= bf))
{
res.Line->sidedef[res.Side]->Flags |= WALLF_DITHERTRANS_MID;
res.Line->sidedef[res.Side]->dithertranscount = 1;
}
}
}
}
break;
case TRACE_HitFloor:
if (res.HitPos.Z == res.Sector->floorplane.ZatPoint(res.HitPos))
if (res.Sector->subsectorcount > 0 && (*CurMapSections)[res.Sector->subsectors[0]->mapsection] && res.HitVector.dot(res.Sector->floorplane.Normal()) < 0.0)
{
res.Sector->floorplane.dithertransflag = true;
}
else if (res.Sector->e->XFloor.ffloors.Size()) // Maybe it was 3D floors
{
F3DFloor *rover;
int kk;
for (kk = 0; kk < (int)res.Sector->e->XFloor.ffloors.Size(); kk++)
if (res.HitPos.Z == res.Sector->floorplane.ZatPoint(res.HitPos))
{
rover = res.Sector->e->XFloor.ffloors[kk];
if ((rover->flags&(FF_EXISTS | FF_RENDERPLANES | FF_THISINSIDE)) == (FF_EXISTS | FF_RENDERPLANES))
res.Sector->floorplane.dithertransflag = true;
}
else if (res.Sector->e->XFloor.ffloors.Size()) // Maybe it was 3D floors
{
F3DFloor *rover;
int kk;
for (kk = 0; kk < (int)res.Sector->e->XFloor.ffloors.Size(); kk++)
{
if (res.HitPos.Z == rover->top.plane->ZatPoint(res.HitPos))
rover = res.Sector->e->XFloor.ffloors[kk];
if ((rover->flags&(FF_EXISTS | FF_RENDERPLANES | FF_THISINSIDE)) == (FF_EXISTS | FF_RENDERPLANES))
{
rover->top.plane->dithertransflag = true;
break; // Out of for loop
if (res.HitPos.Z == rover->top.plane->ZatPoint(res.HitPos))
{
rover->top.plane->dithertransflag = true;
break; // Out of for loop
}
}
}
}
}
break;
case TRACE_HitCeiling:
if (res.HitPos.Z == res.Sector->ceilingplane.ZatPoint(res.HitPos))
if (res.Sector->subsectorcount > 0 && (*CurMapSections)[res.Sector->subsectors[0]->mapsection] && res.HitVector.dot(res.Sector->ceilingplane.Normal()) < 0.0)
{
res.Sector->ceilingplane.dithertransflag = true;
}
else if (res.Sector->e->XFloor.ffloors.Size()) // Maybe it was 3D floors
{
F3DFloor *rover;
int kk;
for (kk = 0; kk < (int)res.Sector->e->XFloor.ffloors.Size(); kk++)
if (res.HitPos.Z == res.Sector->ceilingplane.ZatPoint(res.HitPos))
{
rover = res.Sector->e->XFloor.ffloors[kk];
if ((rover->flags&(FF_EXISTS | FF_RENDERPLANES | FF_THISINSIDE)) == (FF_EXISTS | FF_RENDERPLANES))
res.Sector->ceilingplane.dithertransflag = true;
}
else if (res.Sector->e->XFloor.ffloors.Size()) // Maybe it was 3D floors
{
F3DFloor *rover;
int kk;
for (kk = 0; kk < (int)res.Sector->e->XFloor.ffloors.Size(); kk++)
{
if (res.HitPos.Z == rover->bottom.plane->ZatPoint(res.HitPos))
rover = res.Sector->e->XFloor.ffloors[kk];
if ((rover->flags&(FF_EXISTS | FF_RENDERPLANES | FF_THISINSIDE)) == (FF_EXISTS | FF_RENDERPLANES))
{
rover->bottom.plane->dithertransflag = true;
break; // Out of for loop
if (res.HitPos.Z == rover->bottom.plane->ZatPoint(res.HitPos))
{
rover->bottom.plane->dithertransflag = true;
break; // Out of for loop
}
}
}
}
@ -999,6 +1021,7 @@ static ETraceStatus TraceCallbackForDitherTransparency(FTraceResults& res, void*
void HWDrawInfo::SetDitherTransFlags(AActor* actor)
{
// This should really be moved to a shader and have the GPU do some shape-tracing.
if (actor && actor->Sector)
{
FTraceResults results;
@ -1008,13 +1031,11 @@ void HWDrawInfo::SetDitherTransFlags(AActor* actor)
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())
vvec = 5.0 * Viewpoint.camera->ViewPos->Offset.Length() * Viewpoint.ViewVector3D; // 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;
@ -1022,13 +1043,25 @@ void HWDrawInfo::SetDitherTransFlags(AActor* actor)
{
startsec = Level->PointInRenderSubsector(campos)->sector;
Trace(campos, startsec, vvec, distance,
0, 0, actor, results, 0, TraceCallbackForDitherTransparency, &count);
0, 0, actor, results, TRACE_PortalRestrict, TraceCallbackForDitherTransparency, &CurrentMapSections);
campos.Z += actor->Height * 0.5;
Trace(campos, startsec, vvec, distance,
0, 0, actor, results, 0, TraceCallbackForDitherTransparency, &count);
0, 0, actor, results, TRACE_PortalRestrict, TraceCallbackForDitherTransparency, &CurrentMapSections);
campos.Z -= actor->Height * 0.5;
campos.X += horix; campos.Y -= horiy;
}
// Tracers don't work on 3D floors when you are starting in the same sector (standing under them, for example)
if (actor->Sector->e->XFloor.ffloors.Size()) // 3D floor
{
F3DFloor *rover;
for (int kk = 0; kk < (int)actor->Sector->e->XFloor.ffloors.Size(); kk++)
{
rover = actor->Sector->e->XFloor.ffloors[kk];
rover->top.plane->dithertransflag = true;
rover->bottom.plane->dithertransflag = true;
}
}
}
}

View file

@ -152,6 +152,7 @@ struct HWDrawInfo
Clipper *rClipper; // Radar clipper
FRenderViewpoint Viewpoint;
HWViewpointUniforms VPUniforms; // per-viewpoint uniform state
VSMatrix ProjectionMatrix2;
TArray<HWPortal *> Portals;
TArray<HWDecal *> Decals[2]; // the second slot is for mirrors which get rendered in a separate pass.
TArray<HUDSprite> hudsprites; // These may just be stored by value.

View file

@ -330,6 +330,7 @@ void HWFlat::DrawFlat(HWFlatDispatcher *di, FRenderState &state, bool translucen
int rel = getExtraLight();
state.SetNormal(plane.plane.Normal().X, plane.plane.Normal().Z, plane.plane.Normal().Y);
double zshift = (plane.plane.Normal().Z > 0.0 ? 0.01f : -0.01f); // The HWPlaneMirrorPortal::DrawPortalStencil() z-fights with flats
state.SetLightProbeIndex(sector->lightProbe.index);
SetColor(state, di->Level, di->lightmode, lightlevel, rel, di->isFullbrightScene(), Colormap, alpha);
@ -384,7 +385,18 @@ void HWFlat::DrawFlat(HWFlatDispatcher *di, FRenderState &state, bool translucen
else state.AlphaFunc(Alpha_GEqual, 0.f);
state.SetMaterial(texture, UF_Texture, 0, CLAMP_NONE, NO_TRANSLATION, -1);
bool texmatrix = SetPlaneTextureRotation(state, &plane, texture);
if (di->di && di->di->Viewpoint.IsAllowedOoB())
{
di->di->VPUniforms.mViewMatrix.translate(0.0, zshift, 0.0);
di->di->vpIndex = state.SetViewpoint(di->di->VPUniforms);
// screen->mViewpoints->SetViewpoint(state, &di->di->VPUniforms);
}
DrawSubsectors(di, state);
if (di->di && di->di->Viewpoint.IsAllowedOoB())
{
di->di->VPUniforms.mViewMatrix.translate(0.0, -zshift, 0.0);
di->di->vpIndex = state.SetViewpoint(di->di->VPUniforms);
}
if (texmatrix)
state.SetTextureMatrix(VSMatrix::identity());
}
@ -557,7 +569,7 @@ void HWFlat::ProcessSector(HWFlatDispatcher *di, FRenderState& state, sector_t *
//
//
//
if (((which & SSRF_RENDERFLOOR) && (!di->di || (((frontsector->floorplane.ZatPoint(vp->Pos) <= vp->Pos.Z) && (!section || !(section->flags & FSection::DONTRENDERFLOOR)))))) && !(di->di && vp->IsOrtho() && (vp->PitchSin < 0.0)))
if ((which & SSRF_RENDERFLOOR) && ((di->di && vp->IsOrtho()) ? vp->ViewVector3D.dot(frontsector->floorplane.Normal()) < 0.0 : (!di->di || (frontsector->floorplane.ZatPoint(vp->Pos) <= vp->Pos.Z))) && (!section || !(section->flags & FSection::DONTRENDERFLOOR)))
{
// process the original floor first.
@ -615,7 +627,7 @@ void HWFlat::ProcessSector(HWFlatDispatcher *di, FRenderState& state, sector_t *
//
//
//
if (((which & SSRF_RENDERCEILING) && ((!di->di || ((frontsector->ceilingplane.ZatPoint(vp->Pos) >= vp->Pos.Z) && (!section || !(section->flags & FSection::DONTRENDERCEILING)))))) && !(di->di && vp->IsOrtho() && (vp->PitchSin > 0.0)))
if ((which & SSRF_RENDERCEILING) && ((di->di && vp->IsOrtho()) ? vp->ViewVector3D.dot(frontsector->ceilingplane.Normal()) < 0.0 : (!di->di || (frontsector->ceilingplane.ZatPoint(vp->Pos) >= vp->Pos.Z))) && (!section || !(section->flags & FSection::DONTRENDERCEILING)))
{
// process the original ceiling first.
@ -700,7 +712,7 @@ void HWFlat::ProcessSector(HWFlatDispatcher *di, FRenderState& state, sector_t *
double ff_top = rover->top.plane->ZatPoint(sector->centerspot);
if (ff_top < lastceilingheight)
{
if (!di->di || vp->Pos.Z <= rover->top.plane->ZatPoint(vp->Pos))
if (!di->di || (vp->IsOrtho() ? vp->ViewVector3D.dot(rover->top.plane->Normal()) > 0.0 : vp->Pos.Z <= rover->top.plane->ZatPoint(vp->Pos)))
{
SetFrom3DFloor(rover, true, !!(rover->flags&FF_FOG));
Colormap.FadeColor = frontsector->Colormap.FadeColor;
@ -714,7 +726,7 @@ void HWFlat::ProcessSector(HWFlatDispatcher *di, FRenderState& state, sector_t *
double ff_bottom = rover->bottom.plane->ZatPoint(sector->centerspot);
if (ff_bottom < lastceilingheight)
{
if (!di->di || vp->Pos.Z <= rover->bottom.plane->ZatPoint(vp->Pos))
if (!di->di || (vp->IsOrtho() ? vp->ViewVector3D.dot(rover->bottom.plane->Normal()) > 0.0 : vp->Pos.Z <= rover->bottom.plane->ZatPoint(vp->Pos)))
{
SetFrom3DFloor(rover, false, !(rover->flags&FF_FOG));
Colormap.FadeColor = frontsector->Colormap.FadeColor;
@ -740,7 +752,7 @@ void HWFlat::ProcessSector(HWFlatDispatcher *di, FRenderState& state, sector_t *
double ff_bottom = rover->bottom.plane->ZatPoint(sector->centerspot);
if (ff_bottom > lastfloorheight || (rover->flags&FF_FIX))
{
if (!di->di || vp->Pos.Z >= rover->bottom.plane->ZatPoint(vp->Pos))
if (!di->di || (vp->IsOrtho() ? vp->ViewVector3D.dot(rover->bottom.plane->Normal()) > 0.0 : vp->Pos.Z >= rover->bottom.plane->ZatPoint(vp->Pos)))
{
SetFrom3DFloor(rover, false, !(rover->flags&FF_FOG));
Colormap.FadeColor = frontsector->Colormap.FadeColor;
@ -761,7 +773,7 @@ void HWFlat::ProcessSector(HWFlatDispatcher *di, FRenderState& state, sector_t *
double ff_top = rover->top.plane->ZatPoint(sector->centerspot);
if (ff_top > lastfloorheight)
{
if (!di->di || vp->Pos.Z >= rover->top.plane->ZatPoint(vp->Pos))
if (!di->di || (vp->IsOrtho() ? vp->ViewVector3D.dot(rover->top.plane->Normal()) > 0.0 : vp->Pos.Z >= rover->top.plane->ZatPoint(vp->Pos)))
{
SetFrom3DFloor(rover, true, !!(rover->flags&FF_FOG));
Colormap.FadeColor = frontsector->Colormap.FadeColor;

View file

@ -125,6 +125,7 @@ bool FPortalSceneState::RenderFirstSkyPortal(int recursion, HWDrawInfo *outer_di
{
HWPortal * best = nullptr;
unsigned bestindex = 0;
bool usestencil = outer_di->Viewpoint.IsAllowedOoB();
// Find the one with the highest amount of lines.
// Normally this is also the one that saves the largest amount
@ -145,7 +146,7 @@ bool FPortalSceneState::RenderFirstSkyPortal(int recursion, HWDrawInfo *outer_di
}
// If the portal area contains the current camera viewpoint, let's always use it because it's likely to give the largest area.
if (p->boundingBox.contains(outer_di->Viewpoint.Pos))
if (p->boundingBox.contains(usestencil ? outer_di->Viewpoint.OffPos : outer_di->Viewpoint.Pos))
{
best = p;
bestindex = i;
@ -157,7 +158,14 @@ bool FPortalSceneState::RenderFirstSkyPortal(int recursion, HWDrawInfo *outer_di
if (best)
{
portals.Delete(bestindex);
RenderPortal(best, state, false, outer_di);
if (usestencil && ((strcmp(best->GetName(), "Sky") == 0) || (strcmp(best->GetName(), "Skybox") == 0)))
{
tempmatrix = outer_di->VPUniforms.mProjectionMatrix; // ensure perspective projection matrix for skies
outer_di->VPUniforms.mProjectionMatrix = outer_di->ProjectionMatrix2;
}
RenderPortal(best, state, usestencil, outer_di);
if (usestencil && ((strcmp(best->GetName(), "Sky") == 0) || (strcmp(best->GetName(), "Skybox") == 0)))
outer_di->VPUniforms.mProjectionMatrix = tempmatrix;
delete best;
return true;
}
@ -408,20 +416,23 @@ void HWScenePortalBase::ClearClipper(HWDrawInfo *di, Clipper *clipper)
// Set the clipper to the minimal visible area
clipper->SafeAddClipRange(0, 0xffffffff);
auto outvp = outer_di->Viewpoint;
DVector3 outPos = clipper->amRadar ? outvp.OffPos : outvp.Pos;
angle_t padding = clipper->amRadar ? 0x00200000 : 0x00000000; // Make radar clipping more aggressive (reveal less)
for (unsigned int i = 0; i < lines.Size(); i++)
{
DAngle startAngle = (DVector2(lines[i].glseg.x2, lines[i].glseg.y2) - outer_di->Viewpoint.Pos).Angle() + angleOffset;
DAngle endAngle = (DVector2(lines[i].glseg.x1, lines[i].glseg.y1) - outer_di->Viewpoint.Pos).Angle() + angleOffset;
DAngle startAngle = (DVector2(lines[i].glseg.x2, lines[i].glseg.y2) - outPos).Angle() + angleOffset;
DAngle endAngle = (DVector2(lines[i].glseg.x1, lines[i].glseg.y1) - outPos).Angle() + angleOffset;
if (deltaangle(endAngle, startAngle) < nullAngle)
{
clipper->SafeRemoveClipRangeRealAngles(startAngle.BAMs(), endAngle.BAMs());
clipper->SafeRemoveClipRangeRealAngles(startAngle.BAMs() + padding, endAngle.BAMs() - padding);
}
}
// and finally clip it to the visible area
angle_t a1 = di->FrustumAngle();
if (a1 < ANGLE_180) clipper->SafeAddClipRangeRealAngles(di->Viewpoint.Angles.Yaw.BAMs() + a1, di->Viewpoint.Angles.Yaw.BAMs() - a1);
if (!clipper->amRadar && a1 < ANGLE_180) clipper->SafeAddClipRangeRealAngles(di->Viewpoint.Angles.Yaw.BAMs() + a1, di->Viewpoint.Angles.Yaw.BAMs() - a1);
// lock the parts that have just been clipped out.
clipper->SetSilhouette();
@ -493,6 +504,7 @@ bool HWMirrorPortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *clippe
}
auto &vp = di->Viewpoint;
state->vpIsAllowedOoB = vp.IsAllowedOoB();
di->UpdateCurrentMapSection();
di->mClipPortal = this;
@ -597,6 +609,7 @@ bool HWLineToLinePortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *cl
return false;
}
auto &vp = di->Viewpoint;
state->vpIsAllowedOoB = vp.IsAllowedOoB();
di->mClipPortal = this;
line_t *origin = glport->lines[0]->mOrigin;
@ -606,6 +619,8 @@ bool HWLineToLinePortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *cl
P_TranslatePortalZ(origin, vp.Pos.Z);
P_TranslatePortalXY(origin, vp.Path[0].X, vp.Path[0].Y);
P_TranslatePortalXY(origin, vp.Path[1].X, vp.Path[1].Y);
P_TranslatePortalXY(origin, vp.OffPos.X, vp.OffPos.Y);
P_TranslatePortalZ(origin, vp.OffPos.Z);
if (!vp.showviewer && vp.camera != nullptr && P_PointOnLineSidePrecise(vp.Path[0], glport->lines[0]->mDestination) != P_PointOnLineSidePrecise(vp.Path[1], glport->lines[0]->mDestination))
{
double distp = (vp.Path[0] - vp.Path[1]).Length();
@ -674,6 +689,7 @@ bool HWSkyboxPortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *clippe
return false;
}
auto &vp = di->Viewpoint;
state->vpIsAllowedOoB = vp.IsAllowedOoB();
state->skyboxrecursion++;
state->PlaneMirrorMode = 0;
@ -785,14 +801,21 @@ bool HWSectorStackPortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *c
FSectorPortalGroup *portal = origin;
auto &vp = di->Viewpoint;
state->vpIsAllowedOoB = vp.IsAllowedOoB();
vp.Pos += origin->mDisplacement;
vp.ActorPos += origin->mDisplacement;
vp.ViewActor = nullptr;
vp.OffPos += origin->mDisplacement;
// avoid recursions!
if (origin->plane != -1) screen->instack[origin->plane]++;
if (vp.IsAllowedOoB() && lines.Size() > 0)
{
flat.plane.GetFromSector(lines[0].sub->sector, origin->plane);
di->SetClipHeight(flat.plane.plane.ZatPoint(vp.Pos),
flat.plane.plane.Normal().Z > 0 ? -1.f : 1.f);
}
di->SetupView(rstate, vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(state->MirrorFlag & 1), !!(state->PlaneMirrorFlag & 1));
SetupCoverage(di);
ClearClipper(di, clipper);
@ -800,6 +823,7 @@ bool HWSectorStackPortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *c
// If the viewpoint is not within the portal, we need to invalidate the entire clip area.
// The portal will re-validate the necessary parts when its subsectors get traversed.
subsector_t *sub = di->Level->PointInRenderSubsector(vp.Pos);
if (vp.IsAllowedOoB()) sub = di->Level->PointInRenderSubsector(vp.OffPos);
if (!(di->ss_renderflags[sub->Index()] & SSRF_SEEN))
{
clipper->SafeAddClipRange(0, ANGLE_MAX);
@ -809,6 +833,30 @@ bool HWSectorStackPortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *c
}
void HWSectorStackPortal::DrawPortalStencil(FRenderState &state, int pass)
{
if (mState->vpIsAllowedOoB)
{
bool isceiling = planesused & (1 << sector_t::ceiling);
for (unsigned i = 0; i<subsectors.Size(); i++)
{
subsector_t *sub = subsectors[i];
flat.section = sub->section;
flat.iboindex = sub->sector->iboindex[isceiling ? sector_t::ceiling : sector_t::floor];
flat.plane.GetFromSector(sub->sector, isceiling ? sector_t::ceiling : sector_t::floor);
// if (isceiling) flat.plane.plane.FlipVert(); // Doesn't do anything. Stencil is a screen-space projection
state.SetNormal(flat.plane.plane.Normal().X, flat.plane.plane.Normal().Z, flat.plane.plane.Normal().Y);
state.DrawIndexed(DT_Triangles, flat.iboindex + flat.section->vertexindex, flat.section->vertexcount, i == 0);
}
}
else
{
HWPortal::DrawPortalStencil(state, pass);
}
}
void HWSectorStackPortal::Shutdown(HWDrawInfo *di, FRenderState &rstate)
{
if (origin->plane != -1) screen->instack[origin->plane]--;
@ -843,6 +891,7 @@ bool HWPlaneMirrorPortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *c
std::swap(screen->instack[sector_t::floor], screen->instack[sector_t::ceiling]);
auto &vp = di->Viewpoint;
state->vpIsAllowedOoB = vp.IsAllowedOoB();
old_pm = state->PlaneMirrorMode;
// the player is always visible in a mirror.
@ -856,12 +905,38 @@ bool HWPlaneMirrorPortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *c
state->PlaneMirrorFlag++;
di->SetClipHeight(planez, state->PlaneMirrorMode < 0 ? -1.f : 1.f);
di->SetupView(rstate, vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(state->MirrorFlag & 1), !!(state->PlaneMirrorFlag & 1));
vp.ViewVector3D.Z = - vp.ViewVector3D.Z;
vp.OffPos.Z = 2 * planez - vp.OffPos.Z;
ClearClipper(di, clipper);
di->UpdateCurrentMapSection();
return true;
}
void HWPlaneMirrorPortal::DrawPortalStencil(FRenderState &state, int pass)
{
if (mState->vpIsAllowedOoB)
{
bool isceiling = planesused & (1 << sector_t::ceiling);
for (unsigned int i = 0; i < lines.Size(); i++)
{
flat.section = lines[i].sub->section;
flat.iboindex = lines[i].sub->sector->iboindex[isceiling ? sector_t::ceiling : sector_t::floor];
flat.plane.GetFromSector(lines[i].sub->sector, isceiling ? sector_t::ceiling : sector_t::floor);
// if (isceiling) flat.plane.plane.FlipVert(); // Doesn't do anything. Stencil is a screen-space projection
state.SetNormal(flat.plane.plane.Normal().X, flat.plane.plane.Normal().Z, flat.plane.plane.Normal().Y);
state.DrawIndexed(DT_Triangles, flat.iboindex + flat.section->vertexindex, flat.section->vertexcount, i == 0);
}
}
else
{
HWPortal::DrawPortalStencil(state, pass);
}
}
void HWPlaneMirrorPortal::Shutdown(HWDrawInfo *di, FRenderState &rstate)
{
auto state = mState;

View file

@ -59,13 +59,12 @@ class HWPortal
TArray<unsigned int> mPrimIndices;
unsigned int mTopCap = ~0u, mBottomCap = ~0u;
void DrawPortalStencil(FRenderState &state, int pass);
public:
FPortalSceneState * mState;
TArray<HWWall> lines;
BoundingRect boundingBox;
int planesused = 0;
HWFlat flat;
HWPortal(FPortalSceneState *s, bool local = false) : mState(s), boundingBox(false)
{
@ -83,6 +82,7 @@ public:
virtual bool NeedDepthBuffer() { return true; }
virtual void DrawContents(HWDrawInfo *di, FRenderState &state) = 0;
virtual void RenderAttached(HWDrawInfo *di, FRenderState& state) {}
virtual void DrawPortalStencil(FRenderState &state, int pass);
void SetupStencil(HWDrawInfo *di, FRenderState &state, bool usestencil);
void RemoveStencil(HWDrawInfo *di, FRenderState &state, bool usestencil);
@ -105,6 +105,7 @@ struct FPortalSceneState
int PlaneMirrorMode = 0;
bool inskybox = 0;
bool vpIsAllowedOoB = 0;
UniqueList<HWSkyInfo> UniqueSkies;
UniqueList<HWHorizonInfo> UniqueHorizons;
@ -112,6 +113,8 @@ struct FPortalSceneState
int skyboxrecursion = 0;
VSMatrix tempmatrix;
void BeginScene()
{
UniqueSkies.Clear();
@ -144,7 +147,7 @@ public:
virtual bool NeedDepthBuffer() { return true; }
virtual void DrawContents(HWDrawInfo *di, FRenderState &state)
{
if (Setup(di, state, di->mClipper))
if (Setup(di, state, (di->Viewpoint.IsAllowedOoB() ? di->rClipper : di->mClipper)))
{
di->DrawScene(DM_PORTAL, state);
Shutdown(di, state);
@ -266,6 +269,7 @@ struct HWSectorStackPortal : public HWScenePortalBase
TArray<subsector_t *> subsectors;
protected:
bool Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *clipper) override;
void DrawPortalStencil(FRenderState &state, int pass) override;
void Shutdown(HWDrawInfo *di, FRenderState &rstate) override;
virtual void * GetSource() const { return origin; }
virtual bool IsSky() { return true; } // although this isn't a real sky it can be handled as one.
@ -292,6 +296,7 @@ struct HWPlaneMirrorPortal : public HWScenePortalBase
protected:
bool Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *clipper) override;
void Shutdown(HWDrawInfo *di, FRenderState &rstate) override;
void DrawPortalStencil(FRenderState &state, int pass) override;
virtual void * GetSource() const { return origin; }
virtual const char *GetName();
secplane_t * origin;

View file

@ -130,7 +130,6 @@ void HWSkyInfo::init(HWDrawInfo *di, sector_t* sec, int skypos, int sky1, PalEnt
void HWWall::SkyPlane(HWWallDispatcher *di, FRenderState& state, 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
@ -155,6 +154,13 @@ void HWWall::SkyPlane(HWWallDispatcher *di, FRenderState& state, sector_t *secto
case PORTS_PORTAL:
case PORTS_LINKEDPORTAL:
{
if (di->di && di->di->Viewpoint.IsAllowedOoB())
{
secplane_t myplane = plane ? sector->ceilingplane : sector->floorplane;
if (di->di->Viewpoint.IsOrtho() && di->di->Viewpoint.ViewVector3D.dot(myplane.Normal()) > 0.0) return;
else if (plane==1 && di->di->Viewpoint.Pos.Z >= myplane.ZatPoint(di->di->Viewpoint.Pos)) return;
else if (plane==0 && di->di->Viewpoint.Pos.Z <= myplane.ZatPoint(di->di->Viewpoint.Pos)) return;
}
auto glport = sector->GetPortalGroup(plane);
if (glport != NULL)
{
@ -314,7 +320,10 @@ void HWWall::SkyTop(HWWallDispatcher *di, FRenderState& state, seg_t * seg,secto
if (backreflect > 0 && bs->ceilingplane.fD() == fs->ceilingplane.fD() && !bs->isClosed())
{
// Don't add intra-portal line to the portal.
return;
if (!(di->di && di->di->Viewpoint.IsAllowedOoB()))
{
return;
}
}
}
else
@ -393,7 +402,10 @@ void HWWall::SkyBottom(HWWallDispatcher *di, FRenderState& state, seg_t * seg,se
if (backreflect > 0 && bs->floorplane.fD() == fs->floorplane.fD() && !bs->isClosed())
{
// Don't add intra-portal line to the portal.
return;
if (!(di->di && di->di->Viewpoint.IsAllowedOoB()))
{
return;
}
}
}
else

View file

@ -84,16 +84,32 @@ 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);
bool ditherT = (type == RENDERWALL_BOTTOM) && (seg->sidedef->Flags & WALLF_DITHERTRANS_BOTTOM);
ditherT |= (type == RENDERWALL_TOP) && (seg->sidedef->Flags & WALLF_DITHERTRANS_TOP);
ditherT = ditherT || (seg->sidedef->Flags & WALLF_DITHERTRANS_MID);
if (ditherT)
{
state.SetEffect(EFF_DITHERTRANS);
}
assert(vertcount > 0);
state.SetLightIndex(dynlightindex);
state.SetLightProbeIndex(seg->sidedef->lightProbe.index);
state.Draw(DT_TriangleFan, vertindex, vertcount);
vertexcount += vertcount;
if (seg->sidedef->Flags & WALLF_DITHERTRANS)
if (ditherT)
{
state.SetEffect(EFF_NONE);
seg->sidedef->Flags &= ~WALLF_DITHERTRANS; // reset this every frame
switch(type) // reset this every frame
{
case RENDERWALL_TOP:
seg->sidedef->Flags &= ~WALLF_DITHERTRANS_TOP;
break;
case RENDERWALL_BOTTOM:
seg->sidedef->Flags &= ~WALLF_DITHERTRANS_BOTTOM;
break;
default:
if (seg->sidedef->dithertranscount-- <= 0) seg->sidedef->Flags &= ~WALLF_DITHERTRANS_MID;
}
}
}
@ -609,7 +625,8 @@ void HWWall::PutPortal(HWWallDispatcher *di, FRenderState& state, int ptype, int
break;
case PORTALTYPE_PLANEMIRROR:
if (ddi->drawctx->portalState.PlaneMirrorMode * planemirror->fC() <= 0)
if (ddi->Viewpoint.IsOrtho() ? (ddi->Viewpoint.ViewVector3D.dot(planemirror->Normal()) < 0)
: (ddi->drawctx->portalState.PlaneMirrorMode * planemirror->fC() <= 0))
{
planemirror = ddi->drawctx->portalState.UniquePlaneMirrors.Get(planemirror);
portal = ddi->FindPortal(planemirror);
@ -2049,8 +2066,6 @@ void HWWall::Process(HWWallDispatcher *di, FRenderState& state, seg_t *seg, sect
}
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

View file

@ -550,8 +550,12 @@ void R_InterpolateView(FRenderViewpoint& viewPoint, const player_t* const player
const int prevPortalGroup = viewLvl->PointInRenderSubsector(iView->Old.Pos)->sector->PortalGroup;
const int curPortalGroup = viewLvl->PointInRenderSubsector(iView->New.Pos)->sector->PortalGroup;
const DVector2 portalOffset = viewLvl->Displacements.getOffset(prevPortalGroup, curPortalGroup);
viewPoint.Pos = iView->Old.Pos * inverseTicFrac + (iView->New.Pos - portalOffset) * ticFrac;
if (viewPoint.IsAllowedOoB() && prevPortalGroup != curPortalGroup) viewPoint.Pos = iView->New.Pos;
else
{
const DVector2 portalOffset = viewLvl->Displacements.getOffset(prevPortalGroup, curPortalGroup);
viewPoint.Pos = iView->Old.Pos * inverseTicFrac + (iView->New.Pos - portalOffset) * ticFrac;
}
viewPoint.Path[0] = viewPoint.Path[1] = iView->New.Pos;
}
}
@ -704,6 +708,21 @@ void FRenderViewpoint::SetViewAngle(const FViewWindow& viewWindow)
ViewVector.X = v.X;
ViewVector.Y = v.Y;
HWAngles.Yaw = FAngle::fromDeg(270.0 - Angles.Yaw.Degrees());
ViewVector3D.X = v.X * PitchCos;
ViewVector3D.Y = v.Y * PitchCos;
ViewVector3D.Z = -PitchSin;
if (IsOrtho() || IsAllowedOoB()) // These auto-ensure that camera and camera->ViewPos exist
{
if (camera->tracer != NULL)
{
OffPos = camera->tracer->Pos();
}
else
{
OffPos = Pos + ViewVector3D * camera->ViewPos->Offset.Length();
}
}
if (IsOrtho() && (camera->ViewPos->Offset.XY().Length() > 0.0))
{

View file

@ -25,6 +25,8 @@ struct FRenderViewpoint
DRotator Angles; // Camera angles
FRotator HWAngles; // Actual rotation angles for the hardware renderer
DVector2 ViewVector; // HWR only: direction the camera is facing.
DVector3 ViewVector3D; // 3D direction the camera is facing.
DVector3 OffPos; // Viewpoint position to use for Ortho and OoB calculations
AActor *ViewActor; // either the same as camera or nullptr
FLevelLocals *ViewLevel; // The level this viewpoint is on.