mirror of
https://github.com/ZDoom/qzdoom.git
synced 2025-02-21 11:21:04 +00:00
- moved all portal code that sets up a scene to be rendered into API independent code and let it be handled by a common wrapper class.
This commit is contained in:
parent
3936e3018d
commit
6ebec37baf
13 changed files with 728 additions and 689 deletions
|
@ -175,23 +175,6 @@ void FDrawInfoList::Release(FDrawInfo * di)
|
||||||
mList.Push(di);
|
mList.Push(di);
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
FDrawInfo::FDrawInfo()
|
|
||||||
{
|
|
||||||
next = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
FDrawInfo::~FDrawInfo()
|
|
||||||
{
|
|
||||||
ClearBuffers();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// Sets up a new drawinfo struct
|
// Sets up a new drawinfo struct
|
||||||
|
@ -225,7 +208,7 @@ void FDrawInfo::StartScene()
|
||||||
{
|
{
|
||||||
ClearBuffers();
|
ClearBuffers();
|
||||||
|
|
||||||
next = gl_drawinfo;
|
outer = gl_drawinfo;
|
||||||
gl_drawinfo = this;
|
gl_drawinfo = this;
|
||||||
for (int i = 0; i < GLDL_TYPES; i++) drawlists[i].Reset();
|
for (int i = 0; i < GLDL_TYPES; i++) drawlists[i].Reset();
|
||||||
decals[0].Clear();
|
decals[0].Clear();
|
||||||
|
@ -233,7 +216,7 @@ void FDrawInfo::StartScene()
|
||||||
hudsprites.Clear();
|
hudsprites.Clear();
|
||||||
|
|
||||||
// Fullbright information needs to be propagated from the main view.
|
// Fullbright information needs to be propagated from the main view.
|
||||||
if (next != nullptr) FullbrightFlags = next->FullbrightFlags;
|
if (outer != nullptr) FullbrightFlags = outer->FullbrightFlags;
|
||||||
else FullbrightFlags = 0;
|
else FullbrightFlags = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -247,7 +230,7 @@ FDrawInfo *FDrawInfo::EndDrawInfo()
|
||||||
{
|
{
|
||||||
assert(this == gl_drawinfo);
|
assert(this == gl_drawinfo);
|
||||||
for(int i=0;i<GLDL_TYPES;i++) drawlists[i].Reset();
|
for(int i=0;i<GLDL_TYPES;i++) drawlists[i].Reset();
|
||||||
gl_drawinfo=next;
|
gl_drawinfo=static_cast<FDrawInfo*>(outer);
|
||||||
di_list.Release(this);
|
di_list.Release(this);
|
||||||
if (gl_drawinfo == nullptr)
|
if (gl_drawinfo == nullptr)
|
||||||
ResetRenderDataAllocator();
|
ResetRenderDataAllocator();
|
||||||
|
@ -499,9 +482,15 @@ void FDrawInfo::FloodLowerGap(seg_t * seg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Same here for the dependency on the portal.
|
// Same here for the dependency on the portal.
|
||||||
void FDrawInfo::AddSubsectorToPortal(FSectorPortalGroup *portal, subsector_t *sub)
|
void FDrawInfo::AddSubsectorToPortal(FSectorPortalGroup *ptg, subsector_t *sub)
|
||||||
{
|
{
|
||||||
portal->GetRenderState()->AddSubsector(sub);
|
auto portal = GLRenderer->mPortalState.FindPortal(ptg);
|
||||||
|
if (!portal)
|
||||||
|
{
|
||||||
|
portal = new GLScenePortal(&GLRenderer->mPortalState, new HWSectorStackPortal(ptg));
|
||||||
|
}
|
||||||
|
auto ptl = static_cast<HWSectorStackPortal*>(static_cast<GLScenePortal*>(portal)->mScene);
|
||||||
|
ptl->AddSubsector(sub);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<FFlatVertex *, unsigned int> FDrawInfo::AllocVertices(unsigned int count)
|
std::pair<FFlatVertex *, unsigned int> FDrawInfo::AllocVertices(unsigned int count)
|
||||||
|
@ -523,5 +512,10 @@ int FDrawInfo::UploadLights(FDynLightData &data)
|
||||||
return GLRenderer->mLights->UploadLights(data);
|
return GLRenderer->mLights->UploadLights(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FDrawInfo::SetDepthClamp(bool on)
|
||||||
|
{
|
||||||
|
return gl_RenderState.SetDepthClamp(on);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -35,14 +35,10 @@ enum Drawpasses
|
||||||
|
|
||||||
struct FDrawInfo : public HWDrawInfo
|
struct FDrawInfo : public HWDrawInfo
|
||||||
{
|
{
|
||||||
FDrawInfo * next;
|
|
||||||
HWDrawList drawlists[GLDL_TYPES];
|
HWDrawList drawlists[GLDL_TYPES];
|
||||||
TArray<HUDSprite> hudsprites; // These may just be stored by value.
|
TArray<HUDSprite> hudsprites; // These may just be stored by value.
|
||||||
TArray<GLDecal *> decals[2]; // the second slot is for mirrors which get rendered in a separate pass.
|
TArray<GLDecal *> decals[2]; // the second slot is for mirrors which get rendered in a separate pass.
|
||||||
|
|
||||||
FDrawInfo();
|
|
||||||
~FDrawInfo();
|
|
||||||
|
|
||||||
void ApplyVPUniforms() override;
|
void ApplyVPUniforms() override;
|
||||||
|
|
||||||
void AddWall(GLWall *wall) override;
|
void AddWall(GLWall *wall) override;
|
||||||
|
@ -56,15 +52,6 @@ struct FDrawInfo : public HWDrawInfo
|
||||||
std::pair<FFlatVertex *, unsigned int> AllocVertices(unsigned int count) override;
|
std::pair<FFlatVertex *, unsigned int> AllocVertices(unsigned int count) override;
|
||||||
int UploadLights(FDynLightData &data) override;
|
int UploadLights(FDynLightData &data) override;
|
||||||
|
|
||||||
// Legacy GL only.
|
|
||||||
bool PutWallCompat(GLWall *wall, int passflag);
|
|
||||||
bool PutFlatCompat(GLFlat *flat, bool fog);
|
|
||||||
void RenderFogBoundaryCompat(GLWall *wall);
|
|
||||||
void RenderLightsCompat(GLWall *wall, int pass);
|
|
||||||
void DrawSubsectorLights(GLFlat *flat, subsector_t * sub, int pass);
|
|
||||||
void DrawLightsCompat(GLFlat *flat, int pass);
|
|
||||||
|
|
||||||
|
|
||||||
void DrawDecal(GLDecal *gldecal);
|
void DrawDecal(GLDecal *gldecal);
|
||||||
void DrawDecals();
|
void DrawDecals();
|
||||||
void DrawDecalsForMirror(GLWall *wall);
|
void DrawDecalsForMirror(GLWall *wall);
|
||||||
|
@ -111,7 +98,8 @@ struct FDrawInfo : public HWDrawInfo
|
||||||
void ProcessScene(bool toscreen = false);
|
void ProcessScene(bool toscreen = false);
|
||||||
void EndDrawScene(sector_t * viewsector);
|
void EndDrawScene(sector_t * viewsector);
|
||||||
void DrawEndScene2D(sector_t * viewsector);
|
void DrawEndScene2D(sector_t * viewsector);
|
||||||
|
bool SetDepthClamp(bool on) override;
|
||||||
|
|
||||||
static FDrawInfo *StartDrawInfo(FRenderViewpoint &parentvp, HWViewpointUniforms *uniforms);
|
static FDrawInfo *StartDrawInfo(FRenderViewpoint &parentvp, HWViewpointUniforms *uniforms);
|
||||||
FDrawInfo *EndDrawInfo();
|
FDrawInfo *EndDrawInfo();
|
||||||
|
|
||||||
|
|
|
@ -222,34 +222,6 @@ bool GLPortal::Start(bool usestencil, bool doquery, HWDrawInfo *outer_di, HWDraw
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void GLPortal::ClearClipper(HWDrawInfo *di)
|
|
||||||
{
|
|
||||||
auto outer_di = static_cast<FDrawInfo*>(di)->next;
|
|
||||||
DAngle angleOffset = deltaangle(outer_di->Viewpoint.Angles.Yaw, di->Viewpoint.Angles.Yaw);
|
|
||||||
|
|
||||||
di->mClipper->Clear();
|
|
||||||
|
|
||||||
// Set the clipper to the minimal visible area
|
|
||||||
di->mClipper->SafeAddClipRange(0,0xffffffff);
|
|
||||||
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;
|
|
||||||
|
|
||||||
if (deltaangle(endAngle, startAngle) < 0)
|
|
||||||
{
|
|
||||||
di->mClipper->SafeRemoveClipRangeRealAngles(startAngle.BAMs(), endAngle.BAMs());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// and finally clip it to the visible area
|
|
||||||
angle_t a1 = di->FrustumAngle();
|
|
||||||
if (a1 < ANGLE_180) di->mClipper->SafeAddClipRangeRealAngles(di->Viewpoint.Angles.Yaw.BAMs() + a1, di->Viewpoint.Angles.Yaw.BAMs() - a1);
|
|
||||||
|
|
||||||
// lock the parts that have just been clipped out.
|
|
||||||
di->mClipper->SetSilhouette();
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// End
|
// End
|
||||||
|
@ -346,454 +318,12 @@ void GLPortal::End(HWDrawInfo *di, bool usestencil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// Skybox Portal
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// GLSkyboxPortal::DrawContents
|
|
||||||
//
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void GLSkyboxPortal::DrawContents(HWDrawInfo *di)
|
|
||||||
{
|
|
||||||
int old_pm = mState->PlaneMirrorMode;
|
|
||||||
|
|
||||||
if (mState->skyboxrecursion >= 3)
|
|
||||||
{
|
|
||||||
ClearScreen(di);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto &vp = di->Viewpoint;
|
|
||||||
|
|
||||||
mState->skyboxrecursion++;
|
|
||||||
AActor *origin = portal->mSkybox;
|
|
||||||
portal->mFlags |= PORTSF_INSKYBOX;
|
|
||||||
vp.extralight = 0;
|
|
||||||
|
|
||||||
mState->PlaneMirrorMode = 0;
|
|
||||||
|
|
||||||
bool oldclamp = gl_RenderState.SetDepthClamp(false);
|
|
||||||
vp.Pos = origin->InterpolatedPosition(vp.TicFrac);
|
|
||||||
vp.ActorPos = origin->Pos();
|
|
||||||
vp.Angles.Yaw += (origin->PrevAngles.Yaw + deltaangle(origin->PrevAngles.Yaw, origin->Angles.Yaw) * vp.TicFrac);
|
|
||||||
|
|
||||||
// Don't let the viewpoint be too close to a floor or ceiling
|
|
||||||
double floorh = origin->Sector->floorplane.ZatPoint(origin->Pos());
|
|
||||||
double ceilh = origin->Sector->ceilingplane.ZatPoint(origin->Pos());
|
|
||||||
if (vp.Pos.Z < floorh + 4) vp.Pos.Z = floorh + 4;
|
|
||||||
if (vp.Pos.Z > ceilh - 4) vp.Pos.Z = ceilh - 4;
|
|
||||||
|
|
||||||
vp.ViewActor = origin;
|
|
||||||
|
|
||||||
mState->inskybox = true;
|
|
||||||
di->SetupView(vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(mState->MirrorFlag & 1), !!(mState->PlaneMirrorFlag & 1));
|
|
||||||
di->SetViewArea();
|
|
||||||
ClearClipper(di);
|
|
||||||
|
|
||||||
di->UpdateCurrentMapSection();
|
|
||||||
|
|
||||||
static_cast<FDrawInfo*>(di)->DrawScene(DM_PORTAL);
|
|
||||||
portal->mFlags &= ~PORTSF_INSKYBOX;
|
|
||||||
mState->inskybox = false;
|
|
||||||
gl_RenderState.SetDepthClamp(oldclamp);
|
|
||||||
mState->skyboxrecursion--;
|
|
||||||
|
|
||||||
mState->PlaneMirrorMode = old_pm;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// Sector stack Portal
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// Fixme: This needs abstraction.
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
GLSectorStackPortal *FSectorPortalGroup::GetRenderState()
|
|
||||||
{
|
|
||||||
if (glportal == nullptr) glportal = new GLSectorStackPortal(&GLRenderer->mPortalState, this);
|
|
||||||
return glportal;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GLSectorStackPortal::~GLSectorStackPortal()
|
|
||||||
{
|
|
||||||
if (origin != nullptr && origin->glportal == this)
|
|
||||||
{
|
|
||||||
origin->glportal = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// GLSectorStackPortal::SetupCoverage
|
|
||||||
//
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
static uint8_t SetCoverage(HWDrawInfo *di, void *node)
|
|
||||||
{
|
|
||||||
if (level.nodes.Size() == 0)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (!((size_t)node & 1)) // Keep going until found a subsector
|
|
||||||
{
|
|
||||||
node_t *bsp = (node_t *)node;
|
|
||||||
uint8_t coverage = SetCoverage(di, bsp->children[0]) | SetCoverage(di, bsp->children[1]);
|
|
||||||
di->no_renderflags[bsp->Index()] = coverage;
|
|
||||||
return coverage;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
subsector_t *sub = (subsector_t *)((uint8_t *)node - 1);
|
|
||||||
return di->ss_renderflags[sub->Index()] & SSRF_SEEN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLSectorStackPortal::SetupCoverage(HWDrawInfo *di)
|
|
||||||
{
|
|
||||||
for(unsigned i=0; i<subsectors.Size(); i++)
|
|
||||||
{
|
|
||||||
subsector_t *sub = subsectors[i];
|
|
||||||
int plane = origin->plane;
|
|
||||||
for(int j=0;j<sub->portalcoverage[plane].sscount; j++)
|
|
||||||
{
|
|
||||||
subsector_t *dsub = &::level.subsectors[sub->portalcoverage[plane].subsectors[j]];
|
|
||||||
di->CurrentMapSections.Set(dsub->mapsection);
|
|
||||||
di->ss_renderflags[dsub->Index()] |= SSRF_SEEN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SetCoverage(di, ::level.HeadNode());
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// GLSectorStackPortal::DrawContents
|
|
||||||
//
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
void GLSectorStackPortal::DrawContents(HWDrawInfo *di)
|
|
||||||
{
|
|
||||||
FSectorPortalGroup *portal = origin;
|
|
||||||
auto &vp = di->Viewpoint;
|
|
||||||
|
|
||||||
vp.Pos += origin->mDisplacement;
|
|
||||||
vp.ActorPos += origin->mDisplacement;
|
|
||||||
vp.ViewActor = nullptr;
|
|
||||||
|
|
||||||
// avoid recursions!
|
|
||||||
if (origin->plane != -1) screen->instack[origin->plane]++;
|
|
||||||
|
|
||||||
di->SetupView(vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(mState->MirrorFlag&1), !!(mState->PlaneMirrorFlag&1));
|
|
||||||
SetupCoverage(di);
|
|
||||||
ClearClipper(di);
|
|
||||||
|
|
||||||
// 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 = R_PointInSubsector(vp.Pos);
|
|
||||||
if (!(di->ss_renderflags[sub->Index()] & SSRF_SEEN))
|
|
||||||
{
|
|
||||||
di->mClipper->SafeAddClipRange(0, ANGLE_MAX);
|
|
||||||
di->mClipper->SetBlocked(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
static_cast<FDrawInfo*>(di)->DrawScene(DM_PORTAL);
|
|
||||||
|
|
||||||
if (origin->plane != -1) screen->instack[origin->plane]--;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// Plane Mirror Portal
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// GLPlaneMirrorPortal::DrawContents
|
|
||||||
//
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void GLPlaneMirrorPortal::DrawContents(HWDrawInfo *di)
|
|
||||||
{
|
|
||||||
if (mState->renderdepth > r_mirror_recursions)
|
|
||||||
{
|
|
||||||
ClearScreen(di);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// A plane mirror needs to flip the portal exclusion logic because inside the mirror, up is down and down is up.
|
|
||||||
std::swap(screen->instack[sector_t::floor], screen->instack[sector_t::ceiling]);
|
|
||||||
|
|
||||||
auto &vp = di->Viewpoint;
|
|
||||||
int old_pm = mState->PlaneMirrorMode;
|
|
||||||
|
|
||||||
// the player is always visible in a mirror.
|
|
||||||
vp.showviewer = true;
|
|
||||||
|
|
||||||
double planez = origin->ZatPoint(vp.Pos);
|
|
||||||
vp.Pos.Z = 2 * planez - vp.Pos.Z;
|
|
||||||
vp.ViewActor = nullptr;
|
|
||||||
mState->PlaneMirrorMode = origin->fC() < 0 ? -1 : 1;
|
|
||||||
|
|
||||||
mState->PlaneMirrorFlag++;
|
|
||||||
di->SetClipHeight(planez, mState->PlaneMirrorMode < 0 ? -1.f : 1.f);
|
|
||||||
di->SetupView(vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(mState->MirrorFlag & 1), !!(mState->PlaneMirrorFlag & 1));
|
|
||||||
ClearClipper(di);
|
|
||||||
|
|
||||||
di->UpdateCurrentMapSection();
|
|
||||||
|
|
||||||
static_cast<FDrawInfo*>(di)->DrawScene(DM_PORTAL);
|
|
||||||
mState->PlaneMirrorFlag--;
|
|
||||||
mState->PlaneMirrorMode = old_pm;
|
|
||||||
std::swap(screen->instack[sector_t::floor], screen->instack[sector_t::ceiling]);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Common code for line to line and mirror portals
|
|
||||||
//
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
int GLLinePortal::ClipSeg(seg_t *seg, const DVector3 &viewpos)
|
|
||||||
{
|
|
||||||
line_t *linedef = seg->linedef;
|
|
||||||
if (!linedef)
|
|
||||||
{
|
|
||||||
return PClip_Inside; // should be handled properly.
|
|
||||||
}
|
|
||||||
return P_ClipLineToPortal(linedef, line(), viewpos) ? PClip_InFront : PClip_Inside;
|
|
||||||
}
|
|
||||||
|
|
||||||
int GLLinePortal::ClipSubsector(subsector_t *sub)
|
|
||||||
{
|
|
||||||
// this seg is completely behind the mirror
|
|
||||||
for(unsigned int i=0;i<sub->numlines;i++)
|
|
||||||
{
|
|
||||||
if (P_PointOnLineSidePrecise(sub->firstline[i].v1->fPos(), line()) == 0) return PClip_Inside;
|
|
||||||
}
|
|
||||||
return PClip_InFront;
|
|
||||||
}
|
|
||||||
|
|
||||||
int GLLinePortal::ClipPoint(const DVector2 &pos)
|
|
||||||
{
|
|
||||||
if (P_PointOnLineSidePrecise(pos, line()))
|
|
||||||
{
|
|
||||||
return PClip_InFront;
|
|
||||||
}
|
|
||||||
return PClip_Inside;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// Mirror Portal
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// R_EnterMirror
|
|
||||||
//
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
void GLMirrorPortal::DrawContents(HWDrawInfo *di)
|
|
||||||
{
|
|
||||||
if (mState->renderdepth>r_mirror_recursions)
|
|
||||||
{
|
|
||||||
ClearScreen(di);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto &vp = di->Viewpoint;
|
|
||||||
di->UpdateCurrentMapSection();
|
|
||||||
|
|
||||||
di->mClipPortal = this;
|
|
||||||
DAngle StartAngle = vp.Angles.Yaw;
|
|
||||||
DVector3 StartPos = vp.Pos;
|
|
||||||
|
|
||||||
vertex_t *v1 = linedef->v1;
|
|
||||||
vertex_t *v2 = linedef->v2;
|
|
||||||
|
|
||||||
// the player is always visible in a mirror.
|
|
||||||
vp.showviewer = true;
|
|
||||||
// Reflect the current view behind the mirror.
|
|
||||||
if (linedef->Delta().X == 0)
|
|
||||||
{
|
|
||||||
// vertical mirror
|
|
||||||
vp.Pos.X = 2 * v1->fX() - StartPos.X;
|
|
||||||
|
|
||||||
// Compensation for reendering inaccuracies
|
|
||||||
if (StartPos.X < v1->fX()) vp.Pos.X -= 0.1;
|
|
||||||
else vp.Pos.X += 0.1;
|
|
||||||
}
|
|
||||||
else if (linedef->Delta().Y == 0)
|
|
||||||
{
|
|
||||||
// horizontal mirror
|
|
||||||
vp.Pos.Y = 2*v1->fY() - StartPos.Y;
|
|
||||||
|
|
||||||
// Compensation for reendering inaccuracies
|
|
||||||
if (StartPos.Y<v1->fY()) vp.Pos.Y -= 0.1;
|
|
||||||
else vp.Pos.Y += 0.1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// any mirror--use floats to avoid integer overflow.
|
|
||||||
// Use doubles to avoid losing precision which is very important here.
|
|
||||||
|
|
||||||
double dx = v2->fX() - v1->fX();
|
|
||||||
double dy = v2->fY() - v1->fY();
|
|
||||||
double x1 = v1->fX();
|
|
||||||
double y1 = v1->fY();
|
|
||||||
double x = StartPos.X;
|
|
||||||
double y = StartPos.Y;
|
|
||||||
|
|
||||||
// the above two cases catch len == 0
|
|
||||||
double r = ((x - x1)*dx + (y - y1)*dy) / (dx*dx + dy*dy);
|
|
||||||
|
|
||||||
vp.Pos.X = (x1 + r * dx)*2 - x;
|
|
||||||
vp.Pos.Y = (y1 + r * dy)*2 - y;
|
|
||||||
|
|
||||||
// Compensation for reendering inaccuracies
|
|
||||||
FVector2 v(-dx, dy);
|
|
||||||
v.MakeUnit();
|
|
||||||
|
|
||||||
vp.Pos.X+= v[1] * mState->renderdepth / 2;
|
|
||||||
vp.Pos.Y+= v[0] * mState->renderdepth / 2;
|
|
||||||
}
|
|
||||||
vp.Angles.Yaw = linedef->Delta().Angle() * 2. - StartAngle;
|
|
||||||
|
|
||||||
vp.ViewActor = nullptr;
|
|
||||||
|
|
||||||
mState->MirrorFlag++;
|
|
||||||
di->SetClipLine(linedef);
|
|
||||||
di->SetupView(vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(mState->MirrorFlag&1), !!(mState->PlaneMirrorFlag&1));
|
|
||||||
|
|
||||||
di->mClipper->Clear();
|
|
||||||
|
|
||||||
angle_t af = di->FrustumAngle();
|
|
||||||
if (af<ANGLE_180) di->mClipper->SafeAddClipRangeRealAngles(vp.Angles.Yaw.BAMs()+af, vp.Angles.Yaw.BAMs()-af);
|
|
||||||
|
|
||||||
di->mClipper->SafeAddClipRange(linedef->v1, linedef->v2);
|
|
||||||
|
|
||||||
static_cast<FDrawInfo*>(di)->DrawScene(DM_PORTAL);
|
|
||||||
|
|
||||||
mState->MirrorFlag--;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// Line to line Portal
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
void GLLineToLinePortal::DrawContents(HWDrawInfo *di)
|
|
||||||
{
|
|
||||||
// TODO: Handle recursion more intelligently
|
|
||||||
if (mState->renderdepth>r_mirror_recursions)
|
|
||||||
{
|
|
||||||
ClearScreen(di);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto &vp = di->Viewpoint;
|
|
||||||
di->mClipPortal = this;
|
|
||||||
|
|
||||||
line_t *origin = glport->lines[0]->mOrigin;
|
|
||||||
P_TranslatePortalXY(origin, vp.Pos.X, vp.Pos.Y);
|
|
||||||
P_TranslatePortalXY(origin, vp.ActorPos.X, vp.ActorPos.Y);
|
|
||||||
P_TranslatePortalAngle(origin, vp.Angles.Yaw);
|
|
||||||
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);
|
|
||||||
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();
|
|
||||||
if (distp > EQUAL_EPSILON)
|
|
||||||
{
|
|
||||||
double dist1 = (vp.Pos - vp.Path[0]).Length();
|
|
||||||
double dist2 = (vp.Pos - vp.Path[1]).Length();
|
|
||||||
|
|
||||||
if (dist1 + dist2 < distp + 1)
|
|
||||||
{
|
|
||||||
vp.camera->renderflags |= RF_MAYBEINVISIBLE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < lines.Size(); i++)
|
|
||||||
{
|
|
||||||
line_t *line = lines[i].seg->linedef->getPortalDestination();
|
|
||||||
subsector_t *sub;
|
|
||||||
if (line->sidedef[0]->Flags & WALLF_POLYOBJ)
|
|
||||||
sub = R_PointInSubsector(line->v1->fixX(), line->v1->fixY());
|
|
||||||
else sub = line->frontsector->subsectors[0];
|
|
||||||
di->CurrentMapSections.Set(sub->mapsection);
|
|
||||||
}
|
|
||||||
|
|
||||||
vp.ViewActor = nullptr;
|
|
||||||
di->SetClipLine(glport->lines[0]->mDestination);
|
|
||||||
di->SetupView(vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(mState->MirrorFlag&1), !!(mState->PlaneMirrorFlag&1));
|
|
||||||
|
|
||||||
ClearClipper(di);
|
|
||||||
static_cast<FDrawInfo*>(di)->DrawScene(DM_PORTAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLLineToLinePortal::RenderAttached(HWDrawInfo *di)
|
|
||||||
{
|
|
||||||
di->ProcessActorsInPortal(glport, di->in_area);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// Horizon Portal
|
// Horizon Portal
|
||||||
//
|
//
|
||||||
// This simply draws the area in medium sized squares. Drawing it as a whole
|
|
||||||
// polygon creates visible inaccuracies.
|
|
||||||
//
|
|
||||||
// Originally I tried to minimize the amount of data to be drawn but there
|
|
||||||
// are 2 problems with it:
|
|
||||||
//
|
|
||||||
// 1. Setting this up completely negates any performance gains.
|
|
||||||
// 2. It doesn't work with a 360° field of view (as when you are looking up.)
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// So the brute force mechanism is just as good.
|
|
||||||
//
|
|
||||||
//
|
//
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -978,17 +508,6 @@ void GLEEHorizonPortal::DrawContents(HWDrawInfo *di)
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *GLSkyPortal::GetName() { return "Sky"; }
|
const char *GLSkyPortal::GetName() { return "Sky"; }
|
||||||
const char *GLSkyboxPortal::GetName() { return "Skybox"; }
|
|
||||||
const char *GLSectorStackPortal::GetName() { return "Sectorstack"; }
|
|
||||||
const char *GLPlaneMirrorPortal::GetName() { return "Planemirror"; }
|
|
||||||
const char *GLMirrorPortal::GetName() { return "Mirror"; }
|
|
||||||
const char *GLLineToLinePortal::GetName() { return "LineToLine"; }
|
|
||||||
const char *GLHorizonPortal::GetName() { return "Horizon"; }
|
const char *GLHorizonPortal::GetName() { return "Horizon"; }
|
||||||
const char *GLEEHorizonPortal::GetName() { return "EEHorizon"; }
|
const char *GLEEHorizonPortal::GetName() { return "EEHorizon"; }
|
||||||
|
|
||||||
// This needs to remain on the renderer side until the portal interface can be abstracted.
|
|
||||||
void FSectorPortalGroup::AddSubsector(subsector_t *sub)
|
|
||||||
{
|
|
||||||
GLSectorStackPortal *glportal = GetRenderState();
|
|
||||||
glportal->AddSubsector(sub);
|
|
||||||
}
|
|
||||||
|
|
|
@ -66,115 +66,30 @@ protected:
|
||||||
void ClearScreen(HWDrawInfo *di);
|
void ClearScreen(HWDrawInfo *di);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GLLinePortal : public GLPortal
|
class GLScenePortal : public GLPortal
|
||||||
{
|
{
|
||||||
// this must be the same as at the start of line_t, so that we can pass in this structure directly to P_ClipLineToPortal.
|
public:
|
||||||
vertex_t *v1, *v2; // vertices, from v1 to v2
|
HWScenePortalBase *mScene;
|
||||||
DVector2 delta; // precalculated v2 - v1 for side checking
|
GLScenePortal(FPortalSceneState *state, HWScenePortalBase *handler) : GLPortal(state)
|
||||||
|
|
||||||
angle_t angv1, angv2; // for quick comparisons with a line or subsector
|
|
||||||
|
|
||||||
GLLinePortal(FPortalSceneState *state, line_t *line) : GLPortal(state)
|
|
||||||
{
|
{
|
||||||
v1 = line->v1;
|
mScene = handler;
|
||||||
v2 = line->v2;
|
handler->SetOwner(this);
|
||||||
CalcDelta();
|
|
||||||
}
|
}
|
||||||
|
~GLScenePortal() { delete mScene; }
|
||||||
GLLinePortal(FPortalSceneState *state, FLinePortalSpan *line) : GLPortal(state)
|
virtual void * GetSource() const { return mScene->GetSource(); }
|
||||||
{
|
virtual const char *GetName() { return mScene->GetName(); }
|
||||||
if (line->lines[0]->mType != PORTT_LINKED || line->v1 == nullptr)
|
virtual bool IsSky() { return false; }
|
||||||
|
virtual bool NeedCap() { return true; }
|
||||||
|
virtual bool NeedDepthBuffer() { return true; }
|
||||||
|
virtual void DrawContents(HWDrawInfo *di)
|
||||||
|
{
|
||||||
|
if (mScene->Setup(di, di->mClipper))
|
||||||
{
|
{
|
||||||
// For non-linked portals we must check the actual linedef.
|
static_cast<FDrawInfo*>(di)->DrawScene(DM_PORTAL);
|
||||||
line_t *lline = line->lines[0]->mDestination;
|
mScene->Shutdown(di);
|
||||||
v1 = lline->v1;
|
|
||||||
v2 = lline->v2;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// For linked portals we can check the merged span.
|
|
||||||
v1 = line->v1;
|
|
||||||
v2 = line->v2;
|
|
||||||
}
|
|
||||||
CalcDelta();
|
|
||||||
}
|
}
|
||||||
|
virtual void RenderAttached(HWDrawInfo *di) { return mScene->RenderAttached(di); }
|
||||||
void CalcDelta()
|
|
||||||
{
|
|
||||||
delta = v2->fPos() - v1->fPos();
|
|
||||||
}
|
|
||||||
|
|
||||||
line_t *line()
|
|
||||||
{
|
|
||||||
vertex_t **pv = &v1;
|
|
||||||
return reinterpret_cast<line_t*>(pv);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual int ClipSeg(seg_t *seg, const DVector3 &viewpos);
|
|
||||||
virtual int ClipSubsector(subsector_t *sub);
|
|
||||||
virtual int ClipPoint(const DVector2 &pos);
|
|
||||||
virtual bool NeedCap() { return false; }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct GLMirrorPortal : public GLLinePortal
|
|
||||||
{
|
|
||||||
// mirror portals always consist of single linedefs!
|
|
||||||
line_t * linedef;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void DrawContents(HWDrawInfo *di);
|
|
||||||
virtual void * GetSource() const { return linedef; }
|
|
||||||
virtual const char *GetName();
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
GLMirrorPortal(FPortalSceneState *state, line_t * line)
|
|
||||||
: GLLinePortal(state, line)
|
|
||||||
{
|
|
||||||
linedef=line;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct GLLineToLinePortal : public GLLinePortal
|
|
||||||
{
|
|
||||||
FLinePortalSpan *glport;
|
|
||||||
protected:
|
|
||||||
virtual void DrawContents(HWDrawInfo *di);
|
|
||||||
virtual void * GetSource() const { return glport; }
|
|
||||||
virtual const char *GetName();
|
|
||||||
virtual line_t *ClipLine() { return line(); }
|
|
||||||
virtual void RenderAttached(HWDrawInfo *di);
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
GLLineToLinePortal(FPortalSceneState *state, FLinePortalSpan *ll)
|
|
||||||
: GLLinePortal(state, ll)
|
|
||||||
{
|
|
||||||
glport = ll;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct GLSkyboxPortal : public GLPortal
|
|
||||||
{
|
|
||||||
FSectorPortal * portal;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void DrawContents(HWDrawInfo *di);
|
|
||||||
virtual void * GetSource() const { return portal; }
|
|
||||||
virtual bool IsSky() { return true; }
|
|
||||||
virtual const char *GetName();
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
|
|
||||||
GLSkyboxPortal(FPortalSceneState *state, FSectorPortal * pt) : GLPortal(state)
|
|
||||||
{
|
|
||||||
portal=pt;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -201,51 +116,6 @@ public:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct GLSectorStackPortal : public GLPortal
|
|
||||||
{
|
|
||||||
TArray<subsector_t *> subsectors;
|
|
||||||
protected:
|
|
||||||
virtual ~GLSectorStackPortal();
|
|
||||||
virtual void DrawContents(HWDrawInfo *di);
|
|
||||||
virtual void * GetSource() const { return origin; }
|
|
||||||
virtual bool IsSky() { return true; } // although this isn't a real sky it can be handled as one.
|
|
||||||
virtual const char *GetName();
|
|
||||||
FSectorPortalGroup *origin;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
GLSectorStackPortal(FPortalSceneState *state, FSectorPortalGroup *pt) : GLPortal(state)
|
|
||||||
{
|
|
||||||
origin=pt;
|
|
||||||
}
|
|
||||||
void SetupCoverage(HWDrawInfo *di);
|
|
||||||
void AddSubsector(subsector_t *sub)
|
|
||||||
{
|
|
||||||
subsectors.Push(sub);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
struct GLPlaneMirrorPortal : public GLPortal
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
virtual void DrawContents(HWDrawInfo *di);
|
|
||||||
virtual void * GetSource() const { return origin; }
|
|
||||||
virtual const char *GetName();
|
|
||||||
secplane_t * origin;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
GLPlaneMirrorPortal(FPortalSceneState *state, secplane_t * pt) : GLPortal(state)
|
|
||||||
{
|
|
||||||
origin=pt;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct GLHorizonPortal : public GLPortal
|
struct GLHorizonPortal : public GLPortal
|
||||||
{
|
{
|
||||||
GLHorizonInfo * origin;
|
GLHorizonInfo * origin;
|
||||||
|
|
|
@ -113,7 +113,6 @@ void FDrawInfo::CreateScene()
|
||||||
ProcessAll.Clock();
|
ProcessAll.Clock();
|
||||||
|
|
||||||
// clip the scene and fill the drawlists
|
// clip the scene and fill the drawlists
|
||||||
for(auto p : level.portalGroups) p->glportal = nullptr;
|
|
||||||
Bsp.Clock();
|
Bsp.Clock();
|
||||||
GLRenderer->mVBO->Map();
|
GLRenderer->mVBO->Map();
|
||||||
GLRenderer->mLights->Begin();
|
GLRenderer->mLights->Begin();
|
||||||
|
|
|
@ -358,13 +358,17 @@ void FDrawInfo::AddPortal(GLWall *wall, int ptype)
|
||||||
{
|
{
|
||||||
// either a regular skybox or an Eternity-style horizon
|
// either a regular skybox or an Eternity-style horizon
|
||||||
if (wall->secportal->mType != PORTS_SKYVIEWPOINT) portal = new GLEEHorizonPortal(&pstate, wall->secportal);
|
if (wall->secportal->mType != PORTS_SKYVIEWPOINT) portal = new GLEEHorizonPortal(&pstate, wall->secportal);
|
||||||
else portal = new GLSkyboxPortal(&pstate, wall->secportal);
|
else portal = new GLScenePortal(&pstate, new HWSkyboxPortal(wall->secportal));
|
||||||
}
|
}
|
||||||
portal->AddLine(wall);
|
portal->AddLine(wall);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PORTALTYPE_SECTORSTACK:
|
case PORTALTYPE_SECTORSTACK:
|
||||||
portal = wall->portal->GetRenderState();
|
portal = pstate.FindPortal(wall->portal);
|
||||||
|
if (!portal)
|
||||||
|
{
|
||||||
|
portal = new GLScenePortal(&pstate, new HWSectorStackPortal(wall->portal));
|
||||||
|
}
|
||||||
portal->AddLine(wall);
|
portal->AddLine(wall);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -374,14 +378,14 @@ void FDrawInfo::AddPortal(GLWall *wall, int ptype)
|
||||||
//@sync-portal
|
//@sync-portal
|
||||||
wall->planemirror = pstate.UniquePlaneMirrors.Get(wall->planemirror);
|
wall->planemirror = pstate.UniquePlaneMirrors.Get(wall->planemirror);
|
||||||
portal = pstate.FindPortal(wall->planemirror);
|
portal = pstate.FindPortal(wall->planemirror);
|
||||||
if (!portal) portal = new GLPlaneMirrorPortal(&pstate, wall->planemirror);
|
if (!portal) portal = new GLScenePortal(&pstate, new HWPlaneMirrorPortal(wall->planemirror));
|
||||||
portal->AddLine(wall);
|
portal->AddLine(wall);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PORTALTYPE_MIRROR:
|
case PORTALTYPE_MIRROR:
|
||||||
portal = pstate.FindPortal(wall->seg->linedef);
|
portal = pstate.FindPortal(wall->seg->linedef);
|
||||||
if (!portal) portal = new GLMirrorPortal(&pstate, wall->seg->linedef);
|
if (!portal) portal = new GLScenePortal(&pstate, new HWMirrorPortal(wall->seg->linedef));
|
||||||
portal->AddLine(wall);
|
portal->AddLine(wall);
|
||||||
if (gl_mirror_envmap)
|
if (gl_mirror_envmap)
|
||||||
{
|
{
|
||||||
|
@ -399,7 +403,7 @@ void FDrawInfo::AddPortal(GLWall *wall, int ptype)
|
||||||
{
|
{
|
||||||
ProcessActorsInPortal(otherside->getPortal()->mGroup, in_area);
|
ProcessActorsInPortal(otherside->getPortal()->mGroup, in_area);
|
||||||
}
|
}
|
||||||
portal = new GLLineToLinePortal(&pstate, wall->lineportal);
|
portal = new GLScenePortal(&pstate, new HWLineToLinePortal(wall->lineportal));
|
||||||
}
|
}
|
||||||
portal->AddLine(wall);
|
portal->AddLine(wall);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -538,13 +538,13 @@ void HWDrawInfo::DoSubsector(subsector_t * sub)
|
||||||
portal = fakesector->GetPortalGroup(sector_t::ceiling);
|
portal = fakesector->GetPortalGroup(sector_t::ceiling);
|
||||||
if (portal != nullptr)
|
if (portal != nullptr)
|
||||||
{
|
{
|
||||||
portal->AddSubsector(sub);
|
AddSubsectorToPortal(portal, sub);
|
||||||
}
|
}
|
||||||
|
|
||||||
portal = fakesector->GetPortalGroup(sector_t::floor);
|
portal = fakesector->GetPortalGroup(sector_t::floor);
|
||||||
if (portal != nullptr)
|
if (portal != nullptr)
|
||||||
{
|
{
|
||||||
portal->AddSubsector(sub);
|
AddSubsectorToPortal(portal, sub);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -223,7 +223,7 @@ angle_t HWDrawInfo::FrustumAngle()
|
||||||
|
|
||||||
void HWDrawInfo::SetViewMatrix(const FRotator &angles, float vx, float vy, float vz, bool mirror, bool planemirror)
|
void HWDrawInfo::SetViewMatrix(const FRotator &angles, float vx, float vy, float vz, bool mirror, bool planemirror)
|
||||||
{
|
{
|
||||||
float mult = mirror ? -1 : 1;
|
float mult = mirror ? -1.f : 1.f;
|
||||||
float planemult = planemirror ? -level.info->pixelstretch : level.info->pixelstretch;
|
float planemult = planemirror ? -level.info->pixelstretch : level.info->pixelstretch;
|
||||||
|
|
||||||
VPUniforms.mViewMatrix.loadIdentity();
|
VPUniforms.mViewMatrix.loadIdentity();
|
||||||
|
@ -250,7 +250,6 @@ void HWDrawInfo::SetupView(float vx, float vy, float vz, bool mirror, bool plane
|
||||||
ApplyVPUniforms();
|
ApplyVPUniforms();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
@ -268,3 +267,4 @@ void HWViewpointUniforms::SetDefaults()
|
||||||
mClipLine.X = -10000000.0f;
|
mClipLine.X = -10000000.0f;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ class Clipper;
|
||||||
class IPortal;
|
class IPortal;
|
||||||
class FFlatVertexGenerator;
|
class FFlatVertexGenerator;
|
||||||
class IRenderQueue;
|
class IRenderQueue;
|
||||||
|
class HWScenePortalBase;
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
|
@ -58,7 +59,10 @@ enum EPortalClip
|
||||||
|
|
||||||
struct HWDrawInfo
|
struct HWDrawInfo
|
||||||
{
|
{
|
||||||
virtual ~HWDrawInfo() {}
|
virtual ~HWDrawInfo()
|
||||||
|
{
|
||||||
|
ClearBuffers();
|
||||||
|
}
|
||||||
|
|
||||||
struct wallseg
|
struct wallseg
|
||||||
{
|
{
|
||||||
|
@ -96,9 +100,10 @@ struct HWDrawInfo
|
||||||
bool isNightvision() const { return !!(FullbrightFlags & Nightvision); }
|
bool isNightvision() const { return !!(FullbrightFlags & Nightvision); }
|
||||||
bool isStealthVision() const { return !!(FullbrightFlags & StealthVision); }
|
bool isStealthVision() const { return !!(FullbrightFlags & StealthVision); }
|
||||||
|
|
||||||
|
HWDrawInfo * outer = nullptr;
|
||||||
int FullbrightFlags;
|
int FullbrightFlags;
|
||||||
std::atomic<int> spriteindex;
|
std::atomic<int> spriteindex;
|
||||||
IPortal *mClipPortal;
|
HWScenePortalBase *mClipPortal;
|
||||||
IPortal *mCurrentPortal;
|
IPortal *mCurrentPortal;
|
||||||
//FRotator mAngles;
|
//FRotator mAngles;
|
||||||
IShadowMap *mShadowMap;
|
IShadowMap *mShadowMap;
|
||||||
|
@ -240,6 +245,7 @@ public:
|
||||||
|
|
||||||
virtual int UploadLights(FDynLightData &data) = 0;
|
virtual int UploadLights(FDynLightData &data) = 0;
|
||||||
virtual void ApplyVPUniforms() = 0;
|
virtual void ApplyVPUniforms() = 0;
|
||||||
|
virtual bool SetDepthClamp(bool on) = 0;
|
||||||
|
|
||||||
virtual GLDecal *AddDecal(bool onmirror) = 0;
|
virtual GLDecal *AddDecal(bool onmirror) = 0;
|
||||||
virtual std::pair<FFlatVertex *, unsigned int> AllocVertices(unsigned int count) = 0;
|
virtual std::pair<FFlatVertex *, unsigned int> AllocVertices(unsigned int count) = 0;
|
||||||
|
|
|
@ -26,7 +26,14 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "c_dispatch.h"
|
#include "c_dispatch.h"
|
||||||
|
#include "portal.h"
|
||||||
|
#include "p_maputl.h"
|
||||||
#include "hw_portal.h"
|
#include "hw_portal.h"
|
||||||
|
#include "hw_clipper.h"
|
||||||
|
#include "actor.h"
|
||||||
|
#include "g_levellocals.h"
|
||||||
|
|
||||||
|
EXTERN_CVAR(Int, r_mirror_recursions)
|
||||||
|
|
||||||
IPortal * FPortalSceneState::FindPortal(const void * src)
|
IPortal * FPortalSceneState::FindPortal(const void * src)
|
||||||
{
|
{
|
||||||
|
@ -155,3 +162,476 @@ bool FPortalSceneState::RenderFirstSkyPortal(int recursion, HWDrawInfo *outer_di
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void HWScenePortalBase::ClearClipper(HWDrawInfo *di)
|
||||||
|
{
|
||||||
|
auto outer_di = di->outer;
|
||||||
|
DAngle angleOffset = deltaangle(outer_di->Viewpoint.Angles.Yaw, di->Viewpoint.Angles.Yaw);
|
||||||
|
|
||||||
|
di->mClipper->Clear();
|
||||||
|
|
||||||
|
auto &lines = mOwner->lines;
|
||||||
|
// Set the clipper to the minimal visible area
|
||||||
|
di->mClipper->SafeAddClipRange(0, 0xffffffff);
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (deltaangle(endAngle, startAngle) < 0)
|
||||||
|
{
|
||||||
|
di->mClipper->SafeRemoveClipRangeRealAngles(startAngle.BAMs(), endAngle.BAMs());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// and finally clip it to the visible area
|
||||||
|
angle_t a1 = di->FrustumAngle();
|
||||||
|
if (a1 < ANGLE_180) di->mClipper->SafeAddClipRangeRealAngles(di->Viewpoint.Angles.Yaw.BAMs() + a1, di->Viewpoint.Angles.Yaw.BAMs() - a1);
|
||||||
|
|
||||||
|
// lock the parts that have just been clipped out.
|
||||||
|
di->mClipper->SetSilhouette();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Common code for line to line and mirror portals
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
int HWLinePortal::ClipSeg(seg_t *seg, const DVector3 &viewpos)
|
||||||
|
{
|
||||||
|
line_t *linedef = seg->linedef;
|
||||||
|
if (!linedef)
|
||||||
|
{
|
||||||
|
return PClip_Inside; // should be handled properly.
|
||||||
|
}
|
||||||
|
return P_ClipLineToPortal(linedef, line(), viewpos) ? PClip_InFront : PClip_Inside;
|
||||||
|
}
|
||||||
|
|
||||||
|
int HWLinePortal::ClipSubsector(subsector_t *sub)
|
||||||
|
{
|
||||||
|
// this seg is completely behind the mirror
|
||||||
|
for (unsigned int i = 0; i<sub->numlines; i++)
|
||||||
|
{
|
||||||
|
if (P_PointOnLineSidePrecise(sub->firstline[i].v1->fPos(), line()) == 0) return PClip_Inside;
|
||||||
|
}
|
||||||
|
return PClip_InFront;
|
||||||
|
}
|
||||||
|
|
||||||
|
int HWLinePortal::ClipPoint(const DVector2 &pos)
|
||||||
|
{
|
||||||
|
if (P_PointOnLineSidePrecise(pos, line()))
|
||||||
|
{
|
||||||
|
return PClip_InFront;
|
||||||
|
}
|
||||||
|
return PClip_Inside;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Mirror Portal
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool HWMirrorPortal::Setup(HWDrawInfo *di, Clipper *clipper)
|
||||||
|
{
|
||||||
|
auto state = mOwner->mState;
|
||||||
|
if (state->renderdepth > r_mirror_recursions)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &vp = di->Viewpoint;
|
||||||
|
di->UpdateCurrentMapSection();
|
||||||
|
|
||||||
|
di->mClipPortal = this;
|
||||||
|
DAngle StartAngle = vp.Angles.Yaw;
|
||||||
|
DVector3 StartPos = vp.Pos;
|
||||||
|
|
||||||
|
vertex_t *v1 = linedef->v1;
|
||||||
|
vertex_t *v2 = linedef->v2;
|
||||||
|
|
||||||
|
// the player is always visible in a mirror.
|
||||||
|
vp.showviewer = true;
|
||||||
|
// Reflect the current view behind the mirror.
|
||||||
|
if (linedef->Delta().X == 0)
|
||||||
|
{
|
||||||
|
// vertical mirror
|
||||||
|
vp.Pos.X = 2 * v1->fX() - StartPos.X;
|
||||||
|
|
||||||
|
// Compensation for reendering inaccuracies
|
||||||
|
if (StartPos.X < v1->fX()) vp.Pos.X -= 0.1;
|
||||||
|
else vp.Pos.X += 0.1;
|
||||||
|
}
|
||||||
|
else if (linedef->Delta().Y == 0)
|
||||||
|
{
|
||||||
|
// horizontal mirror
|
||||||
|
vp.Pos.Y = 2 * v1->fY() - StartPos.Y;
|
||||||
|
|
||||||
|
// Compensation for reendering inaccuracies
|
||||||
|
if (StartPos.Y < v1->fY()) vp.Pos.Y -= 0.1;
|
||||||
|
else vp.Pos.Y += 0.1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// any mirror--use floats to avoid integer overflow.
|
||||||
|
// Use doubles to avoid losing precision which is very important here.
|
||||||
|
|
||||||
|
double dx = v2->fX() - v1->fX();
|
||||||
|
double dy = v2->fY() - v1->fY();
|
||||||
|
double x1 = v1->fX();
|
||||||
|
double y1 = v1->fY();
|
||||||
|
double x = StartPos.X;
|
||||||
|
double y = StartPos.Y;
|
||||||
|
|
||||||
|
// the above two cases catch len == 0
|
||||||
|
double r = ((x - x1)*dx + (y - y1)*dy) / (dx*dx + dy * dy);
|
||||||
|
|
||||||
|
vp.Pos.X = (x1 + r * dx) * 2 - x;
|
||||||
|
vp.Pos.Y = (y1 + r * dy) * 2 - y;
|
||||||
|
|
||||||
|
// Compensation for reendering inaccuracies
|
||||||
|
FVector2 v(-dx, dy);
|
||||||
|
v.MakeUnit();
|
||||||
|
|
||||||
|
vp.Pos.X += v[1] * state->renderdepth / 2;
|
||||||
|
vp.Pos.Y += v[0] * state->renderdepth / 2;
|
||||||
|
}
|
||||||
|
vp.Angles.Yaw = linedef->Delta().Angle() * 2. - StartAngle;
|
||||||
|
|
||||||
|
vp.ViewActor = nullptr;
|
||||||
|
|
||||||
|
state->MirrorFlag++;
|
||||||
|
di->SetClipLine(linedef);
|
||||||
|
di->SetupView(vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(state->MirrorFlag & 1), !!(state->PlaneMirrorFlag & 1));
|
||||||
|
|
||||||
|
clipper->Clear();
|
||||||
|
|
||||||
|
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);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HWMirrorPortal::Shutdown(HWDrawInfo *di)
|
||||||
|
{
|
||||||
|
mOwner->mState->MirrorFlag--;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *HWMirrorPortal::GetName() { return "Mirror"; }
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Line to line Portal
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
bool HWLineToLinePortal::Setup(HWDrawInfo *di, Clipper *clipper)
|
||||||
|
{
|
||||||
|
// TODO: Handle recursion more intelligently
|
||||||
|
auto &state = mOwner->mState;
|
||||||
|
if (state->renderdepth>r_mirror_recursions)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto &vp = di->Viewpoint;
|
||||||
|
di->mClipPortal = this;
|
||||||
|
|
||||||
|
line_t *origin = glport->lines[0]->mOrigin;
|
||||||
|
P_TranslatePortalXY(origin, vp.Pos.X, vp.Pos.Y);
|
||||||
|
P_TranslatePortalXY(origin, vp.ActorPos.X, vp.ActorPos.Y);
|
||||||
|
P_TranslatePortalAngle(origin, vp.Angles.Yaw);
|
||||||
|
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);
|
||||||
|
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();
|
||||||
|
if (distp > EQUAL_EPSILON)
|
||||||
|
{
|
||||||
|
double dist1 = (vp.Pos - vp.Path[0]).Length();
|
||||||
|
double dist2 = (vp.Pos - vp.Path[1]).Length();
|
||||||
|
|
||||||
|
if (dist1 + dist2 < distp + 1)
|
||||||
|
{
|
||||||
|
vp.camera->renderflags |= RF_MAYBEINVISIBLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &lines = mOwner->lines;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < lines.Size(); i++)
|
||||||
|
{
|
||||||
|
line_t *line = lines[i].seg->linedef->getPortalDestination();
|
||||||
|
subsector_t *sub;
|
||||||
|
if (line->sidedef[0]->Flags & WALLF_POLYOBJ)
|
||||||
|
sub = R_PointInSubsector(line->v1->fixX(), line->v1->fixY());
|
||||||
|
else sub = line->frontsector->subsectors[0];
|
||||||
|
di->CurrentMapSections.Set(sub->mapsection);
|
||||||
|
}
|
||||||
|
|
||||||
|
vp.ViewActor = nullptr;
|
||||||
|
di->SetClipLine(glport->lines[0]->mDestination);
|
||||||
|
di->SetupView(vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(state->MirrorFlag & 1), !!(state->PlaneMirrorFlag & 1));
|
||||||
|
|
||||||
|
ClearClipper(di);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HWLineToLinePortal::RenderAttached(HWDrawInfo *di)
|
||||||
|
{
|
||||||
|
di->ProcessActorsInPortal(glport, di->in_area);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *HWLineToLinePortal::GetName() { return "LineToLine"; }
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Skybox Portal
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// GLSkyboxPortal::DrawContents
|
||||||
|
//
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool HWSkyboxPortal::Setup(HWDrawInfo *di, Clipper *clipper)
|
||||||
|
{
|
||||||
|
auto state = mOwner->mState;
|
||||||
|
old_pm = state->PlaneMirrorMode;
|
||||||
|
|
||||||
|
if (mOwner->mState->skyboxrecursion >= 3)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto &vp = di->Viewpoint;
|
||||||
|
|
||||||
|
state->skyboxrecursion++;
|
||||||
|
state->PlaneMirrorMode = 0;
|
||||||
|
state->inskybox = true;
|
||||||
|
|
||||||
|
AActor *origin = portal->mSkybox;
|
||||||
|
portal->mFlags |= PORTSF_INSKYBOX;
|
||||||
|
vp.extralight = 0;
|
||||||
|
|
||||||
|
|
||||||
|
oldclamp = di->SetDepthClamp(false);
|
||||||
|
vp.Pos = origin->InterpolatedPosition(vp.TicFrac);
|
||||||
|
vp.ActorPos = origin->Pos();
|
||||||
|
vp.Angles.Yaw += (origin->PrevAngles.Yaw + deltaangle(origin->PrevAngles.Yaw, origin->Angles.Yaw) * vp.TicFrac);
|
||||||
|
|
||||||
|
// Don't let the viewpoint be too close to a floor or ceiling
|
||||||
|
double floorh = origin->Sector->floorplane.ZatPoint(origin->Pos());
|
||||||
|
double ceilh = origin->Sector->ceilingplane.ZatPoint(origin->Pos());
|
||||||
|
if (vp.Pos.Z < floorh + 4) vp.Pos.Z = floorh + 4;
|
||||||
|
if (vp.Pos.Z > ceilh - 4) vp.Pos.Z = ceilh - 4;
|
||||||
|
|
||||||
|
vp.ViewActor = origin;
|
||||||
|
|
||||||
|
di->SetupView(vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(state->MirrorFlag & 1), !!(state->PlaneMirrorFlag & 1));
|
||||||
|
di->SetViewArea();
|
||||||
|
ClearClipper(di);
|
||||||
|
di->UpdateCurrentMapSection();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void HWSkyboxPortal::Shutdown(HWDrawInfo *di)
|
||||||
|
{
|
||||||
|
auto state = mOwner->mState;
|
||||||
|
portal->mFlags &= ~PORTSF_INSKYBOX;
|
||||||
|
di->SetDepthClamp(oldclamp);
|
||||||
|
state->inskybox = false;
|
||||||
|
state->skyboxrecursion--;
|
||||||
|
state->PlaneMirrorMode = old_pm;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *HWSkyboxPortal::GetName() { return "Skybox"; }
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Sector stack Portal
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// GLSectorStackPortal::SetupCoverage
|
||||||
|
//
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static uint8_t SetCoverage(HWDrawInfo *di, void *node)
|
||||||
|
{
|
||||||
|
if (level.nodes.Size() == 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!((size_t)node & 1)) // Keep going until found a subsector
|
||||||
|
{
|
||||||
|
node_t *bsp = (node_t *)node;
|
||||||
|
uint8_t coverage = SetCoverage(di, bsp->children[0]) | SetCoverage(di, bsp->children[1]);
|
||||||
|
di->no_renderflags[bsp->Index()] = coverage;
|
||||||
|
return coverage;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
subsector_t *sub = (subsector_t *)((uint8_t *)node - 1);
|
||||||
|
return di->ss_renderflags[sub->Index()] & SSRF_SEEN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HWSectorStackPortal::SetupCoverage(HWDrawInfo *di)
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i<subsectors.Size(); i++)
|
||||||
|
{
|
||||||
|
subsector_t *sub = subsectors[i];
|
||||||
|
int plane = origin->plane;
|
||||||
|
for (int j = 0; j<sub->portalcoverage[plane].sscount; j++)
|
||||||
|
{
|
||||||
|
subsector_t *dsub = &::level.subsectors[sub->portalcoverage[plane].subsectors[j]];
|
||||||
|
di->CurrentMapSections.Set(dsub->mapsection);
|
||||||
|
di->ss_renderflags[dsub->Index()] |= SSRF_SEEN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SetCoverage(di, ::level.HeadNode());
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// GLSectorStackPortal::DrawContents
|
||||||
|
//
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
bool HWSectorStackPortal::Setup(HWDrawInfo *di, Clipper *clipper)
|
||||||
|
{
|
||||||
|
auto state = mOwner->mState;
|
||||||
|
FSectorPortalGroup *portal = origin;
|
||||||
|
auto &vp = di->Viewpoint;
|
||||||
|
|
||||||
|
vp.Pos += origin->mDisplacement;
|
||||||
|
vp.ActorPos += origin->mDisplacement;
|
||||||
|
vp.ViewActor = nullptr;
|
||||||
|
|
||||||
|
// avoid recursions!
|
||||||
|
if (origin->plane != -1) screen->instack[origin->plane]++;
|
||||||
|
|
||||||
|
di->SetupView(vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(state->MirrorFlag & 1), !!(state->PlaneMirrorFlag & 1));
|
||||||
|
SetupCoverage(di);
|
||||||
|
ClearClipper(di);
|
||||||
|
|
||||||
|
// 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 = R_PointInSubsector(vp.Pos);
|
||||||
|
if (!(di->ss_renderflags[sub->Index()] & SSRF_SEEN))
|
||||||
|
{
|
||||||
|
di->mClipper->SafeAddClipRange(0, ANGLE_MAX);
|
||||||
|
di->mClipper->SetBlocked(true);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void HWSectorStackPortal::Shutdown(HWDrawInfo *di)
|
||||||
|
{
|
||||||
|
if (origin->plane != -1) screen->instack[origin->plane]--;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *HWSectorStackPortal::GetName() { return "Sectorstack"; }
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Plane Mirror Portal
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// GLPlaneMirrorPortal::DrawContents
|
||||||
|
//
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool HWPlaneMirrorPortal::Setup(HWDrawInfo *di, Clipper *clipper)
|
||||||
|
{
|
||||||
|
auto state = mOwner->mState;
|
||||||
|
if (state->renderdepth > r_mirror_recursions)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// A plane mirror needs to flip the portal exclusion logic because inside the mirror, up is down and down is up.
|
||||||
|
std::swap(screen->instack[sector_t::floor], screen->instack[sector_t::ceiling]);
|
||||||
|
|
||||||
|
auto &vp = di->Viewpoint;
|
||||||
|
int old_pm = state->PlaneMirrorMode;
|
||||||
|
|
||||||
|
// the player is always visible in a mirror.
|
||||||
|
vp.showviewer = true;
|
||||||
|
|
||||||
|
double planez = origin->ZatPoint(vp.Pos);
|
||||||
|
vp.Pos.Z = 2 * planez - vp.Pos.Z;
|
||||||
|
vp.ViewActor = nullptr;
|
||||||
|
state->PlaneMirrorMode = origin->fC() < 0 ? -1 : 1;
|
||||||
|
|
||||||
|
state->PlaneMirrorFlag++;
|
||||||
|
di->SetClipHeight(planez, state->PlaneMirrorMode < 0 ? -1.f : 1.f);
|
||||||
|
di->SetupView(vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(state->MirrorFlag & 1), !!(state->PlaneMirrorFlag & 1));
|
||||||
|
ClearClipper(di);
|
||||||
|
|
||||||
|
di->UpdateCurrentMapSection();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HWPlaneMirrorPortal::Shutdown(HWDrawInfo *di)
|
||||||
|
{
|
||||||
|
auto state = mOwner->mState;
|
||||||
|
state->PlaneMirrorFlag--;
|
||||||
|
state->PlaneMirrorMode = old_pm;
|
||||||
|
std::swap(screen->instack[sector_t::floor], screen->instack[sector_t::ceiling]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *HWPlaneMirrorPortal::GetName() { return "Planemirror"; }
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "portal.h"
|
||||||
#include "hw_drawinfo.h"
|
#include "hw_drawinfo.h"
|
||||||
#include "hw_drawstructs.h"
|
#include "hw_drawstructs.h"
|
||||||
#include "hwrenderer/textures/hw_material.h"
|
#include "hwrenderer/textures/hw_material.h"
|
||||||
|
@ -39,16 +40,12 @@ struct FPortalSceneState;
|
||||||
class IPortal
|
class IPortal
|
||||||
{
|
{
|
||||||
friend struct FPortalSceneState;
|
friend struct FPortalSceneState;
|
||||||
protected:
|
public:
|
||||||
FPortalSceneState * mState;
|
FPortalSceneState * mState;
|
||||||
TArray<GLWall> lines;
|
TArray<GLWall> lines;
|
||||||
public:
|
|
||||||
IPortal(FPortalSceneState *s, bool local);
|
IPortal(FPortalSceneState *s, bool local);
|
||||||
virtual ~IPortal() {}
|
virtual ~IPortal() {}
|
||||||
virtual int ClipSeg(seg_t *seg, const DVector3 &viewpos) { return PClip_Inside; }
|
|
||||||
virtual int ClipSubsector(subsector_t *sub) { return PClip_Inside; }
|
|
||||||
virtual int ClipPoint(const DVector2 &pos) { return PClip_Inside; }
|
|
||||||
virtual line_t *ClipLine() { return nullptr; }
|
|
||||||
virtual void * GetSource() const = 0; // GetSource MUST be implemented!
|
virtual void * GetSource() const = 0; // GetSource MUST be implemented!
|
||||||
virtual const char *GetName() = 0;
|
virtual const char *GetName() = 0;
|
||||||
virtual bool IsSky() { return false; }
|
virtual bool IsSky() { return false; }
|
||||||
|
@ -127,3 +124,191 @@ inline IPortal::IPortal(FPortalSceneState *s, bool local) : mState(s)
|
||||||
{
|
{
|
||||||
if (!local) s->portals.Push(this);
|
if (!local) s->portals.Push(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class HWScenePortalBase
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
IPortal *mOwner;
|
||||||
|
public:
|
||||||
|
HWScenePortalBase() {}
|
||||||
|
virtual ~HWScenePortalBase() {}
|
||||||
|
void SetOwner(IPortal *p) { mOwner = p; }
|
||||||
|
void ClearClipper(HWDrawInfo *di);
|
||||||
|
|
||||||
|
virtual int ClipSeg(seg_t *seg, const DVector3 &viewpos) { return PClip_Inside; }
|
||||||
|
virtual int ClipSubsector(subsector_t *sub) { return PClip_Inside; }
|
||||||
|
virtual int ClipPoint(const DVector2 &pos) { return PClip_Inside; }
|
||||||
|
virtual line_t *ClipLine() { return nullptr; }
|
||||||
|
|
||||||
|
virtual bool IsSky() { return false; }
|
||||||
|
virtual bool NeedCap() { return false; }
|
||||||
|
virtual bool NeedDepthBuffer() { return true; }
|
||||||
|
virtual void * GetSource() const = 0; // GetSource MUST be implemented!
|
||||||
|
virtual const char *GetName() = 0;
|
||||||
|
|
||||||
|
virtual bool Setup(HWDrawInfo *di, Clipper *clipper) = 0;
|
||||||
|
virtual void Shutdown(HWDrawInfo *di) {}
|
||||||
|
virtual void RenderAttached(HWDrawInfo *di) {}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HWLinePortal : public HWScenePortalBase
|
||||||
|
{
|
||||||
|
// this must be the same as at the start of line_t, so that we can pass in this structure directly to P_ClipLineToPortal.
|
||||||
|
vertex_t *v1, *v2; // vertices, from v1 to v2
|
||||||
|
DVector2 delta; // precalculated v2 - v1 for side checking
|
||||||
|
|
||||||
|
angle_t angv1, angv2; // for quick comparisons with a line or subsector
|
||||||
|
|
||||||
|
HWLinePortal(line_t *line)
|
||||||
|
{
|
||||||
|
v1 = line->v1;
|
||||||
|
v2 = line->v2;
|
||||||
|
CalcDelta();
|
||||||
|
}
|
||||||
|
|
||||||
|
HWLinePortal(FLinePortalSpan *line)
|
||||||
|
{
|
||||||
|
if (line->lines[0]->mType != PORTT_LINKED || line->v1 == nullptr)
|
||||||
|
{
|
||||||
|
// For non-linked portals we must check the actual linedef.
|
||||||
|
line_t *lline = line->lines[0]->mDestination;
|
||||||
|
v1 = lline->v1;
|
||||||
|
v2 = lline->v2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// For linked portals we can check the merged span.
|
||||||
|
v1 = line->v1;
|
||||||
|
v2 = line->v2;
|
||||||
|
}
|
||||||
|
CalcDelta();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CalcDelta()
|
||||||
|
{
|
||||||
|
delta = v2->fPos() - v1->fPos();
|
||||||
|
}
|
||||||
|
|
||||||
|
line_t *line()
|
||||||
|
{
|
||||||
|
vertex_t **pv = &v1;
|
||||||
|
return reinterpret_cast<line_t*>(pv);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ClipSeg(seg_t *seg, const DVector3 &viewpos) override;
|
||||||
|
int ClipSubsector(subsector_t *sub) override;
|
||||||
|
int ClipPoint(const DVector2 &pos);
|
||||||
|
bool NeedCap() override { return false; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HWMirrorPortal : public HWLinePortal
|
||||||
|
{
|
||||||
|
// mirror portals always consist of single linedefs!
|
||||||
|
line_t * linedef;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool Setup(HWDrawInfo *di, Clipper *clipper) override;
|
||||||
|
void Shutdown(HWDrawInfo *di) override;
|
||||||
|
void * GetSource() const override { return linedef; }
|
||||||
|
const char *GetName() override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
HWMirrorPortal(line_t * line)
|
||||||
|
: HWLinePortal(line)
|
||||||
|
{
|
||||||
|
linedef = line;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct HWLineToLinePortal : public HWLinePortal
|
||||||
|
{
|
||||||
|
FLinePortalSpan *glport;
|
||||||
|
protected:
|
||||||
|
bool Setup(HWDrawInfo *di, Clipper *clipper) override;
|
||||||
|
virtual void * GetSource() const override { return glport; }
|
||||||
|
virtual const char *GetName() override;
|
||||||
|
virtual line_t *ClipLine() override { return line(); }
|
||||||
|
virtual void RenderAttached(HWDrawInfo *di) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
HWLineToLinePortal(FLinePortalSpan *ll)
|
||||||
|
: HWLinePortal(ll)
|
||||||
|
{
|
||||||
|
glport = ll;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct HWSkyboxPortal : public HWScenePortalBase
|
||||||
|
{
|
||||||
|
bool oldclamp;
|
||||||
|
int old_pm;
|
||||||
|
FSectorPortal * portal;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool Setup(HWDrawInfo *di, Clipper *clipper) override;
|
||||||
|
void Shutdown(HWDrawInfo *di) override;
|
||||||
|
virtual void * GetSource() const { return portal; }
|
||||||
|
virtual bool IsSky() { return true; }
|
||||||
|
virtual const char *GetName();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
|
||||||
|
HWSkyboxPortal(FSectorPortal * pt)
|
||||||
|
{
|
||||||
|
portal = pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct HWSectorStackPortal : public HWScenePortalBase
|
||||||
|
{
|
||||||
|
TArray<subsector_t *> subsectors;
|
||||||
|
protected:
|
||||||
|
bool Setup(HWDrawInfo *di, Clipper *clipper) override;
|
||||||
|
void Shutdown(HWDrawInfo *di) 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.
|
||||||
|
virtual const char *GetName();
|
||||||
|
FSectorPortalGroup *origin;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
HWSectorStackPortal(FSectorPortalGroup *pt)
|
||||||
|
{
|
||||||
|
origin = pt;
|
||||||
|
}
|
||||||
|
void SetupCoverage(HWDrawInfo *di);
|
||||||
|
void AddSubsector(subsector_t *sub)
|
||||||
|
{
|
||||||
|
subsectors.Push(sub);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HWPlaneMirrorPortal : public HWScenePortalBase
|
||||||
|
{
|
||||||
|
int old_pm;
|
||||||
|
protected:
|
||||||
|
bool Setup(HWDrawInfo *di, Clipper *clipper) override;
|
||||||
|
void Shutdown(HWDrawInfo *di) override;
|
||||||
|
virtual void * GetSource() const { return origin; }
|
||||||
|
virtual const char *GetName();
|
||||||
|
secplane_t * origin;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
HWPlaneMirrorPortal(secplane_t * pt)
|
||||||
|
{
|
||||||
|
origin = pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
|
@ -254,11 +254,6 @@ struct FSectorPortalGroup
|
||||||
{
|
{
|
||||||
DVector2 mDisplacement;
|
DVector2 mDisplacement;
|
||||||
int plane;
|
int plane;
|
||||||
GLSectorStackPortal *glportal; // for quick access to the render data. This is only valid during BSP traversal!
|
|
||||||
|
|
||||||
GLSectorStackPortal *GetRenderState();
|
|
||||||
|
|
||||||
void AddSubsector(subsector_t *sub);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -363,7 +363,6 @@ static void GroupSectorPortals()
|
||||||
FSectorPortalGroup *portal = new FSectorPortalGroup;
|
FSectorPortalGroup *portal = new FSectorPortalGroup;
|
||||||
portal->mDisplacement = pair->Key.mDisplacement;
|
portal->mDisplacement = pair->Key.mDisplacement;
|
||||||
portal->plane = (i == 1 ? sector_t::floor : sector_t::ceiling); /**/
|
portal->plane = (i == 1 ? sector_t::floor : sector_t::ceiling); /**/
|
||||||
portal->glportal = NULL;
|
|
||||||
level.portalGroups.Push(portal);
|
level.portalGroups.Push(portal);
|
||||||
for (unsigned j = 0; j < pair->Value.Size(); j++)
|
for (unsigned j = 0; j < pair->Value.Size(); j++)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue