- 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:
Christoph Oelckers 2018-06-23 20:57:02 +02:00
parent 3936e3018d
commit 6ebec37baf
13 changed files with 728 additions and 689 deletions

View file

@ -175,23 +175,6 @@ void FDrawInfoList::Release(FDrawInfo * di)
mList.Push(di);
}
//==========================================================================
//
//
//
//==========================================================================
FDrawInfo::FDrawInfo()
{
next = NULL;
}
FDrawInfo::~FDrawInfo()
{
ClearBuffers();
}
//==========================================================================
//
// Sets up a new drawinfo struct
@ -225,7 +208,7 @@ void FDrawInfo::StartScene()
{
ClearBuffers();
next = gl_drawinfo;
outer = gl_drawinfo;
gl_drawinfo = this;
for (int i = 0; i < GLDL_TYPES; i++) drawlists[i].Reset();
decals[0].Clear();
@ -233,7 +216,7 @@ void FDrawInfo::StartScene()
hudsprites.Clear();
// 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;
}
@ -247,7 +230,7 @@ FDrawInfo *FDrawInfo::EndDrawInfo()
{
assert(this == gl_drawinfo);
for(int i=0;i<GLDL_TYPES;i++) drawlists[i].Reset();
gl_drawinfo=next;
gl_drawinfo=static_cast<FDrawInfo*>(outer);
di_list.Release(this);
if (gl_drawinfo == nullptr)
ResetRenderDataAllocator();
@ -499,9 +482,15 @@ void FDrawInfo::FloodLowerGap(seg_t * seg)
}
// 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)
@ -523,5 +512,10 @@ int FDrawInfo::UploadLights(FDynLightData &data)
return GLRenderer->mLights->UploadLights(data);
}
bool FDrawInfo::SetDepthClamp(bool on)
{
return gl_RenderState.SetDepthClamp(on);
}

View file

@ -35,14 +35,10 @@ enum Drawpasses
struct FDrawInfo : public HWDrawInfo
{
FDrawInfo * next;
HWDrawList drawlists[GLDL_TYPES];
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.
FDrawInfo();
~FDrawInfo();
void ApplyVPUniforms() override;
void AddWall(GLWall *wall) override;
@ -56,15 +52,6 @@ struct FDrawInfo : public HWDrawInfo
std::pair<FFlatVertex *, unsigned int> AllocVertices(unsigned int count) 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 DrawDecals();
void DrawDecalsForMirror(GLWall *wall);
@ -111,7 +98,8 @@ struct FDrawInfo : public HWDrawInfo
void ProcessScene(bool toscreen = false);
void EndDrawScene(sector_t * viewsector);
void DrawEndScene2D(sector_t * viewsector);
bool SetDepthClamp(bool on) override;
static FDrawInfo *StartDrawInfo(FRenderViewpoint &parentvp, HWViewpointUniforms *uniforms);
FDrawInfo *EndDrawInfo();

View file

@ -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
@ -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
//
// 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 *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 *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);
}

View file

@ -66,115 +66,30 @@ protected:
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.
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
GLLinePortal(FPortalSceneState *state, line_t *line) : GLPortal(state)
public:
HWScenePortalBase *mScene;
GLScenePortal(FPortalSceneState *state, HWScenePortalBase *handler) : GLPortal(state)
{
v1 = line->v1;
v2 = line->v2;
CalcDelta();
mScene = handler;
handler->SetOwner(this);
}
GLLinePortal(FPortalSceneState *state, FLinePortalSpan *line) : GLPortal(state)
{
if (line->lines[0]->mType != PORTT_LINKED || line->v1 == nullptr)
~GLScenePortal() { delete mScene; }
virtual void * GetSource() const { return mScene->GetSource(); }
virtual const char *GetName() { return mScene->GetName(); }
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.
line_t *lline = line->lines[0]->mDestination;
v1 = lline->v1;
v2 = lline->v2;
static_cast<FDrawInfo*>(di)->DrawScene(DM_PORTAL);
mScene->Shutdown(di);
}
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);
}
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;
}
virtual void RenderAttached(HWDrawInfo *di) { return mScene->RenderAttached(di); }
};
@ -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
{
GLHorizonInfo * origin;

View file

@ -113,7 +113,6 @@ void FDrawInfo::CreateScene()
ProcessAll.Clock();
// clip the scene and fill the drawlists
for(auto p : level.portalGroups) p->glportal = nullptr;
Bsp.Clock();
GLRenderer->mVBO->Map();
GLRenderer->mLights->Begin();

View file

@ -358,13 +358,17 @@ void FDrawInfo::AddPortal(GLWall *wall, int ptype)
{
// either a regular skybox or an Eternity-style horizon
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);
break;
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);
break;
@ -374,14 +378,14 @@ void FDrawInfo::AddPortal(GLWall *wall, int ptype)
//@sync-portal
wall->planemirror = pstate.UniquePlaneMirrors.Get(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);
}
break;
case PORTALTYPE_MIRROR:
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);
if (gl_mirror_envmap)
{
@ -399,7 +403,7 @@ void FDrawInfo::AddPortal(GLWall *wall, int ptype)
{
ProcessActorsInPortal(otherside->getPortal()->mGroup, in_area);
}
portal = new GLLineToLinePortal(&pstate, wall->lineportal);
portal = new GLScenePortal(&pstate, new HWLineToLinePortal(wall->lineportal));
}
portal->AddLine(wall);
break;

View file

@ -538,13 +538,13 @@ void HWDrawInfo::DoSubsector(subsector_t * sub)
portal = fakesector->GetPortalGroup(sector_t::ceiling);
if (portal != nullptr)
{
portal->AddSubsector(sub);
AddSubsectorToPortal(portal, sub);
}
portal = fakesector->GetPortalGroup(sector_t::floor);
if (portal != nullptr)
{
portal->AddSubsector(sub);
AddSubsectorToPortal(portal, sub);
}
}
}

View file

@ -223,7 +223,7 @@ angle_t HWDrawInfo::FrustumAngle()
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;
VPUniforms.mViewMatrix.loadIdentity();
@ -250,7 +250,6 @@ void HWDrawInfo::SetupView(float vx, float vy, float vz, bool mirror, bool plane
ApplyVPUniforms();
}
//-----------------------------------------------------------------------------
//
//
@ -268,3 +267,4 @@ void HWViewpointUniforms::SetDefaults()
mClipLine.X = -10000000.0f;
}

View file

@ -23,6 +23,7 @@ class Clipper;
class IPortal;
class FFlatVertexGenerator;
class IRenderQueue;
class HWScenePortalBase;
//==========================================================================
//
@ -58,7 +59,10 @@ enum EPortalClip
struct HWDrawInfo
{
virtual ~HWDrawInfo() {}
virtual ~HWDrawInfo()
{
ClearBuffers();
}
struct wallseg
{
@ -96,9 +100,10 @@ struct HWDrawInfo
bool isNightvision() const { return !!(FullbrightFlags & Nightvision); }
bool isStealthVision() const { return !!(FullbrightFlags & StealthVision); }
HWDrawInfo * outer = nullptr;
int FullbrightFlags;
std::atomic<int> spriteindex;
IPortal *mClipPortal;
HWScenePortalBase *mClipPortal;
IPortal *mCurrentPortal;
//FRotator mAngles;
IShadowMap *mShadowMap;
@ -240,6 +245,7 @@ public:
virtual int UploadLights(FDynLightData &data) = 0;
virtual void ApplyVPUniforms() = 0;
virtual bool SetDepthClamp(bool on) = 0;
virtual GLDecal *AddDecal(bool onmirror) = 0;
virtual std::pair<FFlatVertex *, unsigned int> AllocVertices(unsigned int count) = 0;

View file

@ -26,7 +26,14 @@
*/
#include "c_dispatch.h"
#include "portal.h"
#include "p_maputl.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)
{
@ -155,3 +162,476 @@ bool FPortalSceneState::RenderFirstSkyPortal(int recursion, HWDrawInfo *outer_di
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"; }

View file

@ -1,5 +1,6 @@
#pragma once
#include "portal.h"
#include "hw_drawinfo.h"
#include "hw_drawstructs.h"
#include "hwrenderer/textures/hw_material.h"
@ -39,16 +40,12 @@ struct FPortalSceneState;
class IPortal
{
friend struct FPortalSceneState;
protected:
public:
FPortalSceneState * mState;
TArray<GLWall> lines;
public:
IPortal(FPortalSceneState *s, bool local);
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 const char *GetName() = 0;
virtual bool IsSky() { return false; }
@ -127,3 +124,191 @@ inline IPortal::IPortal(FPortalSceneState *s, bool local) : mState(s)
{
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;
}
};

View file

@ -254,11 +254,6 @@ struct FSectorPortalGroup
{
DVector2 mDisplacement;
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);
};

View file

@ -363,7 +363,6 @@ static void GroupSectorPortals()
FSectorPortalGroup *portal = new FSectorPortalGroup;
portal->mDisplacement = pair->Key.mDisplacement;
portal->plane = (i == 1 ? sector_t::floor : sector_t::ceiling); /**/
portal->glportal = NULL;
level.portalGroups.Push(portal);
for (unsigned j = 0; j < pair->Value.Size(); j++)
{