diff --git a/src/gamedata/r_defs.h b/src/gamedata/r_defs.h index a6f4c2c4f3b..663f3aa388d 100644 --- a/src/gamedata/r_defs.h +++ b/src/gamedata/r_defs.h @@ -1196,6 +1196,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 @@ -1271,6 +1274,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) diff --git a/src/rendering/hwrenderer/hw_entrypoint.cpp b/src/rendering/hwrenderer/hw_entrypoint.cpp index e55c041a643..0252fbc40d3 100644 --- a/src/rendering/hwrenderer/hw_entrypoint.cpp +++ b/src/rendering/hwrenderer/hw_entrypoint.cpp @@ -167,6 +167,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()); diff --git a/src/rendering/hwrenderer/scene/hw_bsp.cpp b/src/rendering/hwrenderer/scene/hw_bsp.cpp index 2c1abdf7c13..3f834fcf6d2 100644 --- a/src/rendering/hwrenderer/scene/hw_bsp.cpp +++ b/src/rendering/hwrenderer/scene/hw_bsp.cpp @@ -287,15 +287,17 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip) 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(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; } } @@ -313,7 +315,7 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip) { 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; } @@ -326,31 +328,7 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip) 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); @@ -358,7 +336,7 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip) 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 { @@ -385,7 +363,7 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip) 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); } } @@ -729,8 +707,8 @@ void HWDrawInfo::DoSubsector(subsector_t * sub) 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))) + // cull everything if subsector outside all relevant clippers + if ((sub->polys == nullptr)) { auto &clipper = *mClipper; auto &clipperv = *vClipper; @@ -739,7 +717,10 @@ void HWDrawInfo::DoSubsector(subsector_t * sub) 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; @@ -748,25 +729,43 @@ void HWDrawInfo::DoSubsector(subsector_t * sub) { 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); } @@ -835,7 +834,7 @@ void HWDrawInfo::DoSubsector(subsector_t * sub) 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) @@ -988,8 +987,8 @@ void HWDrawInfo::RenderOrthoNoFog() { 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); @@ -1014,16 +1013,8 @@ void HWDrawInfo::RenderBSP(void *node, bool drawpsprites) viewy = FLOAT2FIXED(Viewpoint.Pos.Y); if (r_radarclipper && !(Level->flags3 & LEVEL3_NOFOGOFWAR) && Viewpoint.IsAllowedOoB()) { - 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()); - } + viewx = FLOAT2FIXED(Viewpoint.OffPos.X); + viewy = FLOAT2FIXED(Viewpoint.OffPos.Y); } validcount++; // used for processing sidedefs only once by the renderer. diff --git a/src/rendering/hwrenderer/scene/hw_clipper.cpp b/src/rendering/hwrenderer/scene/hw_clipper.cpp index 059a3998187..7444af30993 100644 --- a/src/rendering/hwrenderer/scene/hw_clipper.cpp +++ b/src/rendering/hwrenderer/scene/hw_clipper.cpp @@ -394,18 +394,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) @@ -467,7 +459,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() ); @@ -491,7 +483,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(); diff --git a/src/rendering/hwrenderer/scene/hw_drawinfo.cpp b/src/rendering/hwrenderer/scene/hw_drawinfo.cpp index 3453b6e500e..4042039336c 100644 --- a/src/rendering/hwrenderer/scene/hw_drawinfo.cpp +++ b/src/rendering/hwrenderer/scene/hw_drawinfo.cpp @@ -160,6 +160,7 @@ void HWDrawInfo::StartScene(FRenderViewpoint &parentvp, HWViewpointUniforms *uni VPUniforms.mProjectionMatrix.loadIdentity(); VPUniforms.mViewMatrix.loadIdentity(); VPUniforms.mNormalViewMatrix.loadIdentity(); + ProjectionMatrix2.loadIdentity(); VPUniforms.mViewHeight = viewheight; if (lightmode == ELightMode::Build) { @@ -684,24 +685,88 @@ void HWDrawInfo::DrawCorona(FRenderState& state, ACorona* corona, double dist) 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)) res.Line->sidedef[res.Side]->Flags |= WALLF_DITHERTRANS; + sector_t* linesec = res.Line->sidedef[res.Side]->sector; + if (linesec->subsectorcount > 0 && (*CurMapSections)[linesec->subsectors[0]->mapsection]) + { + 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(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: - res.Sector->floorplane.dithertransflag = true; + if (res.Sector->subsectorcount > 0 && (*CurMapSections)[res.Sector->subsectors[0]->mapsection] && res.HitVector.dot(res.Sector->floorplane.Normal()) < 0.0) + { + if (res.HitPos.Z == res.Sector->floorplane.ZatPoint(res.HitPos)) + { + 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++) + { + rover = res.Sector->e->XFloor.ffloors[kk]; + if ((rover->flags&(FF_EXISTS | FF_RENDERPLANES | FF_THISINSIDE)) == (FF_EXISTS | FF_RENDERPLANES)) + { + if (res.HitPos.Z == rover->top.plane->ZatPoint(res.HitPos)) + { + rover->top.plane->dithertransflag = true; + break; // Out of for loop + } + } + } + } + } break; case TRACE_HitCeiling: - res.Sector->ceilingplane.dithertransflag = true; + if (res.Sector->subsectorcount > 0 && (*CurMapSections)[res.Sector->subsectors[0]->mapsection] && res.HitVector.dot(res.Sector->ceilingplane.Normal()) < 0.0) + { + if (res.HitPos.Z == res.Sector->ceilingplane.ZatPoint(res.HitPos)) + { + 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++) + { + rover = res.Sector->e->XFloor.ffloors[kk]; + if ((rover->flags&(FF_EXISTS | FF_RENDERPLANES | FF_THISINSIDE)) == (FF_EXISTS | FF_RENDERPLANES)) + { + if (res.HitPos.Z == rover->bottom.plane->ZatPoint(res.HitPos)) + { + rover->bottom.plane->dithertransflag = true; + break; // Out of for loop + } + } + } + } + } break; case TRACE_HitActor: default: @@ -714,6 +779,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; @@ -723,13 +789,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; @@ -737,13 +801,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; + } + } } } diff --git a/src/rendering/hwrenderer/scene/hw_drawinfo.h b/src/rendering/hwrenderer/scene/hw_drawinfo.h index ce848e29710..e4cbeb98eb9 100644 --- a/src/rendering/hwrenderer/scene/hw_drawinfo.h +++ b/src/rendering/hwrenderer/scene/hw_drawinfo.h @@ -150,6 +150,7 @@ struct HWDrawInfo Clipper *rClipper; // Radar clipper FRenderViewpoint Viewpoint; HWViewpointUniforms VPUniforms; // per-viewpoint uniform state + VSMatrix ProjectionMatrix2; TArray Portals; TArray Decals[2]; // the second slot is for mirrors which get rendered in a separate pass. TArray hudsprites; // These may just be stored by value. diff --git a/src/rendering/hwrenderer/scene/hw_flats.cpp b/src/rendering/hwrenderer/scene/hw_flats.cpp index f423c73fce5..317ba939969 100644 --- a/src/rendering/hwrenderer/scene/hw_flats.cpp +++ b/src/rendering/hwrenderer/scene/hw_flats.cpp @@ -47,6 +47,7 @@ #include "hw_drawstructs.h" #include "hw_renderstate.h" #include "texturemanager.h" +#include "hw_viewpointbuffer.h" #ifdef _DEBUG CVAR(Int, gl_breaksec, -1, 0) @@ -314,6 +315,7 @@ void HWFlat::DrawFlat(HWDrawInfo *di, FRenderState &state, bool translucent) 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 SetColor(state, di->Level, di->lightmode, lightlevel, rel, di->isFullbrightScene(), Colormap, alpha); SetFog(state, di->Level, di->lightmode, lightlevel, rel, di->isFullbrightScene(), &Colormap, false); @@ -364,7 +366,11 @@ void HWFlat::DrawFlat(HWDrawInfo *di, FRenderState &state, bool translucent) else state.AlphaFunc(Alpha_GEqual, 0.f); state.SetMaterial(texture, UF_Texture, 0, CLAMP_NONE, NO_TRANSLATION, -1); SetPlaneTextureRotation(state, &plane, texture); + di->VPUniforms.mViewMatrix.translate(0.0, zshift, 0.0); + screen->mViewpoints->SetViewpoint(state, &di->VPUniforms); DrawSubsectors(di, state); + di->VPUniforms.mViewMatrix.translate(0.0, -zshift, 0.0); + screen->mViewpoints->SetViewpoint(state, &di->VPUniforms); state.EnableTextureMatrix(false); } state.SetRenderStyle(DefaultRenderStyle()); @@ -518,7 +524,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)))&& !(vp.IsOrtho() && (vp.PitchSin < 0.0))) + if ((which & SSRF_RENDERFLOOR) && (vp.IsOrtho() ? vp.ViewVector3D.dot(frontsector->floorplane.Normal()) < 0.0 : frontsector->floorplane.ZatPoint(vp.Pos) <= vp.Pos.Z) && (!section || !(section->flags & FSection::DONTRENDERFLOOR))) { // process the original floor first. @@ -576,7 +582,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))) && !(vp.IsOrtho() && (vp.PitchSin > 0.0))) + if ((which & SSRF_RENDERCEILING) && (vp.IsOrtho() ? vp.ViewVector3D.dot(frontsector->ceilingplane.Normal()) < 0.0 : frontsector->ceilingplane.ZatPoint(vp.Pos) >= vp.Pos.Z) && (!section || !(section->flags & FSection::DONTRENDERCEILING))) { // process the original ceiling first. @@ -661,7 +667,7 @@ void HWFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector, int which) double ff_top = rover->top.plane->ZatPoint(sector->centerspot); if (ff_top < lastceilingheight) { - if (vp.Pos.Z <= rover->top.plane->ZatPoint(vp.Pos)) + if ((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; @@ -675,7 +681,7 @@ void HWFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector, int which) double ff_bottom = rover->bottom.plane->ZatPoint(sector->centerspot); if (ff_bottom < lastceilingheight) { - if (vp.Pos.Z <= rover->bottom.plane->ZatPoint(vp.Pos)) + if ((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; @@ -701,7 +707,7 @@ void HWFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector, int which) double ff_bottom = rover->bottom.plane->ZatPoint(sector->centerspot); if (ff_bottom > lastfloorheight || (rover->flags&FF_FIX)) { - if (vp.Pos.Z >= rover->bottom.plane->ZatPoint(vp.Pos)) + if ((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; @@ -722,7 +728,7 @@ void HWFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector, int which) double ff_top = rover->top.plane->ZatPoint(sector->centerspot); if (ff_top > lastfloorheight) { - if (vp.Pos.Z >= rover->top.plane->ZatPoint(vp.Pos)) + if ((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; diff --git a/src/rendering/hwrenderer/scene/hw_portal.cpp b/src/rendering/hwrenderer/scene/hw_portal.cpp index b0ea3a8c9bc..7746aa33850 100644 --- a/src/rendering/hwrenderer/scene/hw_portal.cpp +++ b/src/rendering/hwrenderer/scene/hw_portal.cpp @@ -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; } @@ -325,6 +333,7 @@ void HWPortal::RemoveStencil(HWDrawInfo *di, FRenderState &state, bool usestenci bool needdepth = NeedDepthBuffer(); // Restore the old view + auto &vp = di->Viewpoint; if (vp.camera != nullptr) vp.camera->renderflags = (vp.camera->renderflags & ~RF_MAYBEINVISIBLE) | savedvisibility; @@ -410,20 +419,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(); @@ -608,6 +620,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(); @@ -791,10 +805,18 @@ bool HWSectorStackPortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *c 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 (lines.Size() > 0) + { + flat.plane.GetFromSector(lines[0].sub->sector, + lines[0].sub->sector->GetPortal(sector_t::ceiling)->mType & (PORTS_STACKEDSECTORTHING | PORTS_PORTAL | PORTS_LINKEDPORTAL) ? + sector_t::ceiling : sector_t::floor); + 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); @@ -802,6 +824,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); @@ -811,6 +834,22 @@ bool HWSectorStackPortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *c } +void HWSectorStackPortal::DrawPortalStencil(FRenderState &state, int pass) +{ + 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); + } +} + + void HWSectorStackPortal::Shutdown(HWDrawInfo *di, FRenderState &rstate) { if (origin->plane != -1) screen->instack[origin->plane]--; @@ -858,12 +897,31 @@ 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) +{ + 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); + } +} + + void HWPlaneMirrorPortal::Shutdown(HWDrawInfo *di, FRenderState &rstate) { auto state = mState; diff --git a/src/rendering/hwrenderer/scene/hw_portal.h b/src/rendering/hwrenderer/scene/hw_portal.h index 29481f9e32d..50034df6a95 100644 --- a/src/rendering/hwrenderer/scene/hw_portal.h +++ b/src/rendering/hwrenderer/scene/hw_portal.h @@ -59,13 +59,14 @@ class HWPortal TArray mPrimIndices; unsigned int mTopCap = ~0u, mBottomCap = ~0u; - void DrawPortalStencil(FRenderState &state, int pass); + virtual void DrawPortalStencil(FRenderState &state, int pass); public: FPortalSceneState * mState; TArray lines; BoundingRect boundingBox; int planesused = 0; + HWFlat flat; HWPortal(FPortalSceneState *s, bool local = false) : mState(s), boundingBox(false) { @@ -112,6 +113,8 @@ struct FPortalSceneState int skyboxrecursion = 0; + VSMatrix tempmatrix; + void BeginScene() { UniqueSkies.Clear(); @@ -145,7 +148,7 @@ class HWScenePortalBase : public HWPortal 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); Shutdown(di, state); @@ -267,6 +270,7 @@ struct HWSectorStackPortal : public HWScenePortalBase TArray 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. @@ -293,6 +297,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; diff --git a/src/rendering/hwrenderer/scene/hw_sky.cpp b/src/rendering/hwrenderer/scene/hw_sky.cpp index 6d77a275d5d..2aef16c8f03 100644 --- a/src/rendering/hwrenderer/scene/hw_sky.cpp +++ b/src/rendering/hwrenderer/scene/hw_sky.cpp @@ -130,7 +130,6 @@ 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 @@ -155,11 +154,17 @@ void HWWall::SkyPlane(HWWallDispatcher *di, sector_t *sector, int plane, bool al 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) { if (sector->PortalBlocksView(plane)) return; - if (di->di && screen->instack[1 - plane]) return; ptype = PORTALTYPE_SECTORSTACK; portal = glport; diff --git a/src/rendering/hwrenderer/scene/hw_walls.cpp b/src/rendering/hwrenderer/scene/hw_walls.cpp index 5c5e357d559..d5271d05f1b 100644 --- a/src/rendering/hwrenderer/scene/hw_walls.cpp +++ b/src/rendering/hwrenderer/scene/hw_walls.cpp @@ -83,15 +83,31 @@ 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 |= seg->sidedef->Flags & WALLF_DITHERTRANS_MID; + if (ditherT) + { + state.SetEffect(EFF_DITHERTRANS); + } assert(vertcount > 0); state.SetLightIndex(dynlightindex); 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; + } } } @@ -628,7 +644,8 @@ void HWWall::PutPortal(HWWallDispatcher *di, int ptype, int plane) break; case PORTALTYPE_PLANEMIRROR: - if (portalState.PlaneMirrorMode * planemirror->fC() <= 0) + if (ddi->Viewpoint.IsOrtho() ? (ddi->Viewpoint.ViewVector3D.dot(planemirror->Normal()) < 0) + : (portalState.PlaneMirrorMode * planemirror->fC() <= 0)) { planemirror = portalState.UniquePlaneMirrors.Get(planemirror); portal = ddi->FindPortal(planemirror); @@ -2181,8 +2198,6 @@ 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 diff --git a/src/rendering/r_utility.cpp b/src/rendering/r_utility.cpp index 3a3fdd70e7f..035ac6de7cf 100644 --- a/src/rendering/r_utility.cpp +++ b/src/rendering/r_utility.cpp @@ -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)) { diff --git a/src/rendering/r_utility.h b/src/rendering/r_utility.h index f7e4a1e1d34..0c2f47833ca 100644 --- a/src/rendering/r_utility.h +++ b/src/rendering/r_utility.h @@ -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.