diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1a298824a3..75e2d36faa 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -841,6 +841,7 @@ set( FASTMATH_SOURCES hwrenderer/scene/hw_drawlist.cpp hwrenderer/scene/hw_clipper.cpp hwrenderer/scene/hw_flats.cpp + hwrenderer/scene/hw_portal.cpp hwrenderer/scene/hw_renderhacks.cpp hwrenderer/scene/hw_sky.cpp hwrenderer/scene/hw_sprites.cpp diff --git a/src/gl/models/gl_models.cpp b/src/gl/models/gl_models.cpp index b92b832a8f..97c5c09fd5 100644 --- a/src/gl/models/gl_models.cpp +++ b/src/gl/models/gl_models.cpp @@ -65,7 +65,7 @@ void FGLModelRenderer::BeginDrawModel(AActor *actor, FSpriteModelFrame *smf, con if (!(actor->RenderStyle == LegacyRenderStyles[STYLE_Normal]) && !(smf->flags & MDL_DONTCULLBACKFACES)) { glEnable(GL_CULL_FACE); - glFrontFace((mirrored ^ GLPortal::isMirrored()) ? GL_CCW : GL_CW); + glFrontFace((mirrored ^ GLRenderer->mPortalState.isMirrored()) ? GL_CCW : GL_CW); } gl_RenderState.mModelMatrix = objectToWorldMatrix; @@ -91,7 +91,7 @@ void FGLModelRenderer::BeginDrawHUDModel(AActor *actor, const VSMatrix &objectTo if (!(actor->RenderStyle == LegacyRenderStyles[STYLE_Normal])) { glEnable(GL_CULL_FACE); - glFrontFace((mirrored ^ GLPortal::isMirrored()) ? GL_CW : GL_CCW); + glFrontFace((mirrored ^ GLRenderer->mPortalState.isMirrored()) ? GL_CW : GL_CCW); } gl_RenderState.mModelMatrix = objectToWorldMatrix; diff --git a/src/gl/renderer/gl_lightdata.cpp b/src/gl/renderer/gl_lightdata.cpp index 1810f4bfcf..7566c0f12d 100644 --- a/src/gl/renderer/gl_lightdata.cpp +++ b/src/gl/renderer/gl_lightdata.cpp @@ -173,7 +173,7 @@ void gl_SetFog(int lightlevel, int rellight, bool fullbright, const FColormap *c } // Make fog a little denser when inside a skybox - if (GLPortal::inskybox) fogdensity+=fogdensity/2; + if (GLRenderer->mPortalState.inskybox) fogdensity+=fogdensity/2; // no fog in enhanced vision modes! diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index 3a3f6b3282..a605025d25 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -150,6 +150,8 @@ void FGLRenderer::Initialize(int width, int height) mCustomPostProcessShaders = new FCustomPostProcessShaders(); // needed for the core profile, because someone decided it was a good idea to remove the default VAO. + glGenQueries(1, &PortalQueryObject); + glGenVertexArrays(1, &mVAOID); glBindVertexArray(mVAOID); FGLDebug::LabelObject(GL_VERTEX_ARRAY, mVAOID, "FGLRenderer.mVAOID"); @@ -164,14 +166,10 @@ void FGLRenderer::Initialize(int width, int height) SetupLevel(); mShaderManager = new FShaderManager; mSamplerManager = new FSamplerManager; - - GLPortal::Initialize(); } FGLRenderer::~FGLRenderer() { - GLPortal::Shutdown(); - FlushModels(); AActor::DeleteAllAttachedLights(); FMaterial::FlushAll(); @@ -186,6 +184,8 @@ FGLRenderer::~FGLRenderer() glBindVertexArray(0); glDeleteVertexArrays(1, &mVAOID); } + if (PortalQueryObject != 0) glDeleteQueries(1, &PortalQueryObject); + if (swdrawer) delete swdrawer; if (mBuffers) delete mBuffers; if (mPresentShader) delete mPresentShader; diff --git a/src/gl/renderer/gl_renderer.h b/src/gl/renderer/gl_renderer.h index 46c097ba1b..2aebd01698 100644 --- a/src/gl/renderer/gl_renderer.h +++ b/src/gl/renderer/gl_renderer.h @@ -6,6 +6,7 @@ #include "vectors.h" #include "r_renderer.h" #include "r_data/matrix.h" +#include "hwrenderer/scene/hw_portal.h" #include "gl/dynlights/gl_shadowmap.h" #include @@ -73,6 +74,8 @@ public: FSamplerManager *mSamplerManager; unsigned int mFBID; unsigned int mVAOID; + unsigned int PortalQueryObject; + int mOldFBID; FGLRenderBuffers *mBuffers; @@ -110,6 +113,8 @@ public: FLightBuffer *mLights; SWSceneDrawer *swdrawer = nullptr; + FPortalSceneState mPortalState; + bool buffersActive = false; float mSceneClearColor[3]; diff --git a/src/gl/scene/gl_drawinfo.cpp b/src/gl/scene/gl_drawinfo.cpp index b8a3d7c706..de3cd91ee0 100644 --- a/src/gl/scene/gl_drawinfo.cpp +++ b/src/gl/scene/gl_drawinfo.cpp @@ -265,7 +265,7 @@ FDrawInfo *FDrawInfo::EndDrawInfo() void FDrawInfo::SetupFloodStencil(wallseg * ws) { - int recursion = GLPortal::GetRecursion(); + int recursion = GLRenderer->mPortalState.GetRecursion(); // Create stencil glStencilFunc(GL_EQUAL, recursion, ~0); // create stencil @@ -297,7 +297,7 @@ void FDrawInfo::SetupFloodStencil(wallseg * ws) void FDrawInfo::ClearFloodStencil(wallseg * ws) { - int recursion = GLPortal::GetRecursion(); + int recursion = GLRenderer->mPortalState.GetRecursion(); glStencilOp(GL_KEEP,GL_KEEP,GL_DECR); gl_RenderState.EnableTexture(false); diff --git a/src/gl/scene/gl_drawinfo.h b/src/gl/scene/gl_drawinfo.h index 2859be9993..ec0a6ed85e 100644 --- a/src/gl/scene/gl_drawinfo.h +++ b/src/gl/scene/gl_drawinfo.h @@ -112,11 +112,6 @@ struct FDrawInfo : public HWDrawInfo void EndDrawScene(sector_t * viewsector); void DrawEndScene2D(sector_t * viewsector); - // These should go into hwrenderer later. - void SetViewMatrix(const FRotator &angles, float vx, float vy, float vz, bool mirror, bool planemirror); - void SetupView(float vx, float vy, float vz, bool mirror, bool planemirror); - - static FDrawInfo *StartDrawInfo(FRenderViewpoint &parentvp, HWViewpointUniforms *uniforms); FDrawInfo *EndDrawInfo(); diff --git a/src/gl/scene/gl_portal.cpp b/src/gl/scene/gl_portal.cpp index 2b49309760..f8d560f271 100644 --- a/src/gl/scene/gl_portal.cpp +++ b/src/gl/scene/gl_portal.cpp @@ -58,42 +58,12 @@ EXTERN_CVAR(Bool, gl_portals) EXTERN_CVAR(Bool, gl_noquery) EXTERN_CVAR(Int, r_mirror_recursions) -TArray GLPortal::portals; -TArray GLPortal::planestack; -int GLPortal::recursion; -int GLPortal::MirrorFlag; -int GLPortal::PlaneMirrorFlag; -int GLPortal::renderdepth; -int GLPortal::PlaneMirrorMode; -GLuint GLPortal::QueryObject; - -bool GLPortal::inskybox; - -UniqueList UniqueSkies; -UniqueList UniqueHorizons; -UniqueList UniquePlaneMirrors; - -int skyboxrecursion = 0; - //========================================================================== // // // //========================================================================== - -void GLPortal::BeginScene() -{ - UniqueSkies.Clear(); - UniqueHorizons.Clear(); - UniquePlaneMirrors.Clear(); -} - -//========================================================================== -// -// -// -//========================================================================== -void GLPortal::ClearScreen(FDrawInfo *di) +void GLPortal::ClearScreen(HWDrawInfo *di) { bool multi = !!glIsEnabled(GL_MULTISAMPLE); @@ -142,17 +112,13 @@ void GLPortal::DrawPortalStencil() } - - - - //----------------------------------------------------------------------------- // // Start // //----------------------------------------------------------------------------- -bool GLPortal::Start(bool usestencil, bool doquery, FDrawInfo *outer_di, FDrawInfo **pDi) +bool GLPortal::Start(bool usestencil, bool doquery, HWDrawInfo *outer_di, HWDrawInfo **pDi) { *pDi = nullptr; rendered_portals++; @@ -166,7 +132,7 @@ bool GLPortal::Start(bool usestencil, bool doquery, FDrawInfo *outer_di, FDrawIn } // Create stencil - glStencilFunc(GL_EQUAL,recursion,~0); // create stencil + glStencilFunc(GL_EQUAL, mState->recursion, ~0); // create stencil glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); // increment stencil of valid pixels { ScopedColorMask colorMask(0, 0, 0, 0); // glColorMask(0,0,0,0); // don't write to the graphics buffer @@ -182,19 +148,15 @@ bool GLPortal::Start(bool usestencil, bool doquery, FDrawInfo *outer_di, FDrawIn if (!NeedDepthBuffer()) doquery = false; // too much overhead and nothing to gain. else if (gl_noquery) doquery = false; - // If occlusion query is supported let's use it to avoid rendering portals that aren't visible - if (QueryObject) - { - glBeginQuery(GL_SAMPLES_PASSED, QueryObject); - } - else doquery = false; // some kind of error happened + // Use occlusion query to avoid rendering portals that aren't visible + glBeginQuery(GL_SAMPLES_PASSED, GLRenderer->PortalQueryObject); DrawPortalStencil(); glEndQuery(GL_SAMPLES_PASSED); // Clear Z-buffer - glStencilFunc(GL_EQUAL, recursion + 1, ~0); // draw sky into stencil + glStencilFunc(GL_EQUAL, mState->recursion + 1, ~0); // draw sky into stencil glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // this stage doesn't modify the stencil glDepthMask(true); // enable z-buffer again glDepthRange(1, 1); @@ -210,17 +172,14 @@ bool GLPortal::Start(bool usestencil, bool doquery, FDrawInfo *outer_di, FDrawIn GLuint sampleCount; - if (QueryObject) - { - glGetQueryObjectuiv(QueryObject, GL_QUERY_RESULT, &sampleCount); + glGetQueryObjectuiv(GLRenderer->PortalQueryObject, GL_QUERY_RESULT, &sampleCount); - if (sampleCount == 0) // not visible - { - // restore default stencil op. - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - glStencilFunc(GL_EQUAL, recursion, ~0); // draw sky into stencil - return false; - } + if (sampleCount == 0) // not visible + { + // restore default stencil op. + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + glStencilFunc(GL_EQUAL, mState->recursion, ~0); // draw sky into stencil + return false; } } else @@ -232,7 +191,7 @@ bool GLPortal::Start(bool usestencil, bool doquery, FDrawInfo *outer_di, FDrawIn glDepthMask(true); DrawPortalStencil(); - glStencilFunc(GL_EQUAL, recursion + 1, ~0); // draw sky into stencil + glStencilFunc(GL_EQUAL, mState->recursion + 1, ~0); // draw sky into stencil glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // this stage doesn't modify the stencil gl_RenderState.EnableTexture(true); // glColorMask(1,1,1,1); @@ -241,7 +200,7 @@ bool GLPortal::Start(bool usestencil, bool doquery, FDrawInfo *outer_di, FDrawIn glDepthMask(false); // don't write to Z-buffer! } } - recursion++; + mState->recursion++; } @@ -262,14 +221,13 @@ bool GLPortal::Start(bool usestencil, bool doquery, FDrawInfo *outer_di, FDrawIn PrevPortal = GLRenderer->mCurrentPortal; GLRenderer->mCurrentPortal = this; - if (PrevPortal != nullptr) PrevPortal->PushState(); return true; } -inline void GLPortal::ClearClipper(FDrawInfo *di) +inline void GLPortal::ClearClipper(HWDrawInfo *di) { - auto outer_di = di->next; + auto outer_di = static_cast(di)->next; DAngle angleOffset = deltaangle(outer_di->Viewpoint.Angles.Yaw, di->Viewpoint.Angles.Yaw); di->mClipper->Clear(); @@ -300,15 +258,14 @@ inline void GLPortal::ClearClipper(FDrawInfo *di) // End // //----------------------------------------------------------------------------- -void GLPortal::End(FDrawInfo *di, bool usestencil) +void GLPortal::End(HWDrawInfo *di, bool usestencil) { bool needdepth = NeedDepthBuffer(); Clocker c(PortalAll); - if (PrevPortal != nullptr) PrevPortal->PopState(); GLRenderer->mCurrentPortal = PrevPortal; - di = di->EndDrawInfo(); + di = static_cast(di)->EndDrawInfo(); di->ApplyVPUniforms(); if (usestencil) { @@ -316,7 +273,6 @@ void GLPortal::End(FDrawInfo *di, bool usestencil) // Restore the old view if (vp.camera != nullptr) vp.camera->renderflags = (vp.camera->renderflags & ~RF_MAYBEINVISIBLE) | savedvisibility; - di->SetupView(vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(MirrorFlag & 1), !!(PlaneMirrorFlag & 1)); { ScopedColorMask colorMask(0, 0, 0, 0); // glColorMask(0, 0, 0, 0); // no graphics @@ -341,7 +297,7 @@ void GLPortal::End(FDrawInfo *di, bool usestencil) glDepthFunc(GL_LEQUAL); glDepthRange(0, 1); glStencilOp(GL_KEEP, GL_KEEP, GL_DECR); - glStencilFunc(GL_EQUAL, recursion, ~0); // draw sky into stencil + glStencilFunc(GL_EQUAL, mState->recursion, ~0); // draw sky into stencil DrawPortalStencil(); glDepthFunc(GL_LESS); @@ -349,11 +305,11 @@ void GLPortal::End(FDrawInfo *di, bool usestencil) gl_RenderState.EnableTexture(true); gl_RenderState.SetEffect(EFF_NONE); } // glColorMask(1, 1, 1, 1); - recursion--; + mState->recursion--; // restore old stencil op. glStencilOp(GL_KEEP,GL_KEEP,GL_KEEP); - glStencilFunc(GL_EQUAL,recursion,~0); // draw sky into stencil + glStencilFunc(GL_EQUAL, mState->recursion,~0); // draw sky into stencil } else { @@ -370,7 +326,7 @@ void GLPortal::End(FDrawInfo *di, bool usestencil) // Restore the old view if (vp.camera != nullptr) vp.camera->renderflags = (vp.camera->renderflags & ~RF_MAYBEINVISIBLE) | savedvisibility; - di->SetupView(vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(MirrorFlag & 1), !!(PlaneMirrorFlag & 1)); + di->SetupView(vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(mState->MirrorFlag & 1), !!(mState->PlaneMirrorFlag & 1)); // This draws a valid z-buffer into the stencil's contents to ensure it // doesn't get overwritten by the level's geometry. @@ -394,141 +350,6 @@ void GLPortal::End(FDrawInfo *di, bool usestencil) } -//----------------------------------------------------------------------------- -// -// StartFrame -// -//----------------------------------------------------------------------------- -void GLPortal::StartFrame() -{ - GLPortal * p = nullptr; - portals.Push(p); - if (renderdepth == 0) - { - inskybox = false; - screen->instack[sector_t::floor] = screen->instack[sector_t::ceiling] = 0; - } - renderdepth++; -} - - -//----------------------------------------------------------------------------- -// -// printing portal info -// -//----------------------------------------------------------------------------- - -static bool gl_portalinfo; - -CCMD(gl_portalinfo) -{ - gl_portalinfo = true; -} - -static FString indent; - -//----------------------------------------------------------------------------- -// -// EndFrame -// -//----------------------------------------------------------------------------- - -void GLPortal::EndFrame(FDrawInfo *outer_di) -{ - GLPortal * p; - - if (gl_portalinfo) - { - Printf("%s%d portals, depth = %d\n%s{\n", indent.GetChars(), portals.Size(), renderdepth, indent.GetChars()); - indent += " "; - } - - // Only use occlusion query if there are more than 2 portals. - // Otherwise there's too much overhead. - // (And don't forget to consider the separating nullptr pointers!) - bool usequery = portals.Size() > 2 + (unsigned)renderdepth; - - while (portals.Pop(p) && p) - { - if (gl_portalinfo) - { - Printf("%sProcessing %s, depth = %d, query = %d\n", indent.GetChars(), p->GetName(), renderdepth, usequery); - } - if (p->lines.Size() > 0) - { - p->RenderPortal(true, usequery, outer_di); - } - delete p; - } - renderdepth--; - - if (gl_portalinfo) - { - indent.Truncate(long(indent.Len()-2)); - Printf("%s}\n", indent.GetChars()); - if (portals.Size() == 0) gl_portalinfo = false; - } -} - - -//----------------------------------------------------------------------------- -// -// Renders one sky portal without a stencil. -// In more complex scenes using a stencil for skies can severely stall -// the GPU and there's rarely more than one sky visible at a time. -// -//----------------------------------------------------------------------------- -bool GLPortal::RenderFirstSkyPortal(int recursion, FDrawInfo *outer_di) -{ - GLPortal * p; - GLPortal * best = nullptr; - unsigned bestindex=0; - - // Find the one with the highest amount of lines. - // Normally this is also the one that saves the largest amount - // of time by drawing it before the scene itself. - for(int i = portals.Size()-1; i >= 0 && portals[i] != nullptr; --i) - { - p=portals[i]; - if (p->lines.Size() > 0 && p->IsSky()) - { - // Cannot clear the depth buffer inside a portal recursion - if (recursion && p->NeedDepthBuffer()) continue; - - if (!best || p->lines.Size()>best->lines.Size()) - { - best=p; - bestindex=i; - } - } - } - - if (best) - { - portals.Delete(bestindex); - best->RenderPortal(false, false, outer_di); - delete best; - return true; - } - return false; -} - - -//----------------------------------------------------------------------------- -// -// FindPortal -// -//----------------------------------------------------------------------------- - -GLPortal * GLPortal::FindPortal(const void * src) -{ - int i=portals.Size()-1; - - while (i>=0 && portals[i] && portals[i]->GetSource()!=src) i--; - return i>=0? portals[i]:nullptr; -} - - //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // @@ -545,23 +366,23 @@ GLPortal * GLPortal::FindPortal(const void * src) // //----------------------------------------------------------------------------- -void GLSkyboxPortal::DrawContents(FDrawInfo *di) +void GLSkyboxPortal::DrawContents(HWDrawInfo *di) { - int old_pm = PlaneMirrorMode; + int old_pm = mState->PlaneMirrorMode; - if (skyboxrecursion >= 3) + if (mState->skyboxrecursion >= 3) { ClearScreen(di); return; } auto &vp = di->Viewpoint; - skyboxrecursion++; + mState->skyboxrecursion++; AActor *origin = portal->mSkybox; portal->mFlags |= PORTSF_INSKYBOX; vp.extralight = 0; - PlaneMirrorMode = 0; + mState->PlaneMirrorMode = 0; bool oldclamp = gl_RenderState.SetDepthClamp(false); vp.Pos = origin->InterpolatedPosition(vp.TicFrac); @@ -576,20 +397,20 @@ void GLSkyboxPortal::DrawContents(FDrawInfo *di) vp.ViewActor = origin; - inskybox = true; - di->SetupView(vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(MirrorFlag & 1), !!(PlaneMirrorFlag & 1)); + 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(); - di->DrawScene(DM_SKYPORTAL); + static_cast(di)->DrawScene(DM_PORTAL); portal->mFlags &= ~PORTSF_INSKYBOX; - inskybox = false; + mState->inskybox = false; gl_RenderState.SetDepthClamp(oldclamp); - skyboxrecursion--; + mState->skyboxrecursion--; - PlaneMirrorMode = old_pm; + mState->PlaneMirrorMode = old_pm; } //----------------------------------------------------------------------------- @@ -611,7 +432,7 @@ void GLSkyboxPortal::DrawContents(FDrawInfo *di) GLSectorStackPortal *FSectorPortalGroup::GetRenderState() { - if (glportal == nullptr) glportal = new GLSectorStackPortal(this); + if (glportal == nullptr) glportal = new GLSectorStackPortal(&GLRenderer->mPortalState, this); return glportal; } @@ -631,7 +452,7 @@ GLSectorStackPortal::~GLSectorStackPortal() // //----------------------------------------------------------------------------- -static uint8_t SetCoverage(FDrawInfo *di, void *node) +static uint8_t SetCoverage(HWDrawInfo *di, void *node) { if (level.nodes.Size() == 0) { @@ -651,7 +472,7 @@ static uint8_t SetCoverage(FDrawInfo *di, void *node) } } -void GLSectorStackPortal::SetupCoverage(FDrawInfo *di) +void GLSectorStackPortal::SetupCoverage(HWDrawInfo *di) { for(unsigned i=0; iViewpoint; @@ -684,7 +505,7 @@ void GLSectorStackPortal::DrawContents(FDrawInfo *di) // avoid recursions! if (origin->plane != -1) screen->instack[origin->plane]++; - di->SetupView(vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(MirrorFlag&1), !!(PlaneMirrorFlag&1)); + di->SetupView(vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(mState->MirrorFlag&1), !!(mState->PlaneMirrorFlag&1)); SetupCoverage(di); ClearClipper(di); @@ -697,7 +518,7 @@ void GLSectorStackPortal::DrawContents(FDrawInfo *di) di->mClipper->SetBlocked(true); } - di->DrawScene(DM_PORTAL); + static_cast(di)->DrawScene(DM_PORTAL); if (origin->plane != -1) screen->instack[origin->plane]--; } @@ -718,9 +539,9 @@ void GLSectorStackPortal::DrawContents(FDrawInfo *di) // //----------------------------------------------------------------------------- -void GLPlaneMirrorPortal::DrawContents(FDrawInfo *di) +void GLPlaneMirrorPortal::DrawContents(HWDrawInfo *di) { - if (renderdepth > r_mirror_recursions) + if (mState->renderdepth > r_mirror_recursions) { ClearScreen(di); return; @@ -729,7 +550,7 @@ void GLPlaneMirrorPortal::DrawContents(FDrawInfo *di) std::swap(screen->instack[sector_t::floor], screen->instack[sector_t::ceiling]); auto &vp = di->Viewpoint; - int old_pm = PlaneMirrorMode; + int old_pm = mState->PlaneMirrorMode; // the player is always visible in a mirror. vp.showviewer = true; @@ -737,18 +558,18 @@ void GLPlaneMirrorPortal::DrawContents(FDrawInfo *di) double planez = origin->ZatPoint(vp.Pos); vp.Pos.Z = 2 * planez - vp.Pos.Z; vp.ViewActor = nullptr; - PlaneMirrorMode = origin->fC() < 0 ? -1 : 1; + mState->PlaneMirrorMode = origin->fC() < 0 ? -1 : 1; - PlaneMirrorFlag++; - di->SetClipHeight(planez, PlaneMirrorMode < 0 ? -1.f : 1.f); - di->SetupView(vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(MirrorFlag & 1), !!(PlaneMirrorFlag & 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(); - di->DrawScene(DM_PORTAL); - PlaneMirrorFlag--; - PlaneMirrorMode = old_pm; + static_cast(di)->DrawScene(DM_PORTAL); + mState->PlaneMirrorFlag--; + mState->PlaneMirrorMode = old_pm; std::swap(screen->instack[sector_t::floor], screen->instack[sector_t::ceiling]); } @@ -803,9 +624,9 @@ int GLLinePortal::ClipPoint(const DVector2 &pos) // R_EnterMirror // //----------------------------------------------------------------------------- -void GLMirrorPortal::DrawContents(FDrawInfo *di) +void GLMirrorPortal::DrawContents(HWDrawInfo *di) { - if (renderdepth>r_mirror_recursions) + if (mState->renderdepth>r_mirror_recursions) { ClearScreen(di); return; @@ -864,16 +685,16 @@ void GLMirrorPortal::DrawContents(FDrawInfo *di) FVector2 v(-dx, dy); v.MakeUnit(); - vp.Pos.X+= v[1] * renderdepth / 2; - vp.Pos.Y+= v[0] * renderdepth / 2; + 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; - MirrorFlag++; + mState->MirrorFlag++; di->SetClipLine(linedef); - di->SetupView(vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(MirrorFlag&1), !!(PlaneMirrorFlag&1)); + di->SetupView(vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(mState->MirrorFlag&1), !!(mState->PlaneMirrorFlag&1)); di->mClipper->Clear(); @@ -882,9 +703,9 @@ void GLMirrorPortal::DrawContents(FDrawInfo *di) di->mClipper->SafeAddClipRange(linedef->v1, linedef->v2); - di->DrawScene(DM_PORTAL); + static_cast(di)->DrawScene(DM_PORTAL); - MirrorFlag--; + mState->MirrorFlag--; } //----------------------------------------------------------------------------- @@ -902,10 +723,10 @@ void GLMirrorPortal::DrawContents(FDrawInfo *di) // // //----------------------------------------------------------------------------- -void GLLineToLinePortal::DrawContents(FDrawInfo *di) +void GLLineToLinePortal::DrawContents(HWDrawInfo *di) { // TODO: Handle recursion more intelligently - if (renderdepth>r_mirror_recursions) + if (mState->renderdepth>r_mirror_recursions) { ClearScreen(di); return; @@ -948,13 +769,13 @@ void GLLineToLinePortal::DrawContents(FDrawInfo *di) vp.ViewActor = nullptr; di->SetClipLine(glport->lines[0]->mDestination); - di->SetupView(vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(MirrorFlag&1), !!(PlaneMirrorFlag&1)); + di->SetupView(vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(mState->MirrorFlag&1), !!(mState->PlaneMirrorFlag&1)); ClearClipper(di); - di->DrawScene(DM_PORTAL); + static_cast(di)->DrawScene(DM_PORTAL); } -void GLLineToLinePortal::RenderAttached(FDrawInfo *di) +void GLLineToLinePortal::RenderAttached(HWDrawInfo *di) { di->ProcessActorsInPortal(glport, di->in_area); } @@ -981,8 +802,8 @@ void GLLineToLinePortal::RenderAttached(FDrawInfo *di) //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -GLHorizonPortal::GLHorizonPortal(GLHorizonInfo * pt, FRenderViewpoint &vp, bool local) - : GLPortal(local) +GLHorizonPortal::GLHorizonPortal(FPortalSceneState *s, GLHorizonInfo * pt, FRenderViewpoint &vp, bool local) + : GLPortal(s, local) { origin = pt; @@ -1045,8 +866,9 @@ GLHorizonPortal::GLHorizonPortal(GLHorizonInfo * pt, FRenderViewpoint &vp, bool // GLHorizonPortal::DrawContents // //----------------------------------------------------------------------------- -void GLHorizonPortal::DrawContents(FDrawInfo *di) +void GLHorizonPortal::DrawContents(HWDrawInfo *hwdi) { + auto di = static_cast(hwdi); Clocker c(PortalAll); FMaterial * gltexture; @@ -1117,7 +939,7 @@ void GLHorizonPortal::DrawContents(FDrawInfo *di) // //----------------------------------------------------------------------------- -void GLEEHorizonPortal::DrawContents(FDrawInfo *di) +void GLEEHorizonPortal::DrawContents(HWDrawInfo *di) { auto &vp = di->Viewpoint; sector_t *sector = portal->mOrigin; @@ -1126,7 +948,7 @@ void GLEEHorizonPortal::DrawContents(FDrawInfo *di) { GLSkyInfo skyinfo; skyinfo.init(sector->sky, 0); - GLSkyPortal sky(&skyinfo, true); + GLSkyPortal sky(mState, &skyinfo, true); sky.DrawContents(di); } if (sector->GetTexture(sector_t::ceiling) != skyflatnum) @@ -1140,7 +962,7 @@ void GLEEHorizonPortal::DrawContents(FDrawInfo *di) { horz.plane.Texheight = vp.Pos.Z + fabs(horz.plane.Texheight); } - GLHorizonPortal ceil(&horz, di->Viewpoint, true); + GLHorizonPortal ceil(mState, &horz, di->Viewpoint, true); ceil.DrawContents(di); } if (sector->GetTexture(sector_t::floor) != skyflatnum) @@ -1154,26 +976,11 @@ void GLEEHorizonPortal::DrawContents(FDrawInfo *di) { horz.plane.Texheight = vp.Pos.Z - fabs(horz.plane.Texheight); } - GLHorizonPortal floor(&horz, di->Viewpoint, true); + GLHorizonPortal floor(mState, &horz, di->Viewpoint, true); floor.DrawContents(di); } } -void GLPortal::Initialize() -{ - assert(0 == QueryObject); - glGenQueries(1, &QueryObject); -} - -void GLPortal::Shutdown() -{ - if (0 != QueryObject) - { - glDeleteQueries(1, &QueryObject); - QueryObject = 0; - } -} - const char *GLSkyPortal::GetName() { return "Sky"; } const char *GLSkyboxPortal::GetName() { return "Skybox"; } const char *GLSectorStackPortal::GetName() { return "Sectorstack"; } diff --git a/src/gl/scene/gl_portal.h b/src/gl/scene/gl_portal.h index b7d04b971f..d944617659 100644 --- a/src/gl/scene/gl_portal.h +++ b/src/gl/scene/gl_portal.h @@ -44,92 +44,27 @@ #include "hwrenderer/scene/hw_drawstructs.h" #include "hwrenderer/scene/hw_portal.h" -extern UniqueList UniqueSkies; -extern UniqueList UniqueHorizons; -extern UniqueList UniquePlaneMirrors; struct GLEEHorizonPortal; class GLPortal : public IPortal { - static TArray portals; - static int recursion; - static unsigned int QueryObject; -protected: - static TArray planestack; - static int MirrorFlag; - static int PlaneMirrorFlag; - static int renderdepth; - -public: - static int PlaneMirrorMode; - static int inupperstack; - static bool inskybox; private: void DrawPortalStencil(); - AActor * savedviewactor; ActorRenderFlags savedvisibility; GLPortal *PrevPortal; TArray mPrimIndices; protected: - TArray lines; int level; - GLPortal(bool local = false) { if (!local) portals.Push(this); } - virtual ~GLPortal() { } + GLPortal(FPortalSceneState *state, bool local = false) : IPortal(state, local) { } - bool Start(bool usestencil, bool doquery, FDrawInfo *outer_di, FDrawInfo **pDi); - void End(FDrawInfo *di, bool usestencil); - virtual void DrawContents(FDrawInfo *di)=0; - virtual void * GetSource() const =0; // GetSource MUST be implemented! - void ClearClipper(FDrawInfo *di); - virtual bool IsSky() { return false; } - virtual bool NeedCap() { return true; } - virtual bool NeedDepthBuffer() { return true; } - void ClearScreen(FDrawInfo *di); - virtual const char *GetName() = 0; - virtual void PushState() {} - virtual void PopState() {} - -public: - - void RenderPortal(bool usestencil, bool doquery, FDrawInfo *outer_di) - { - // Start may perform an occlusion query. If that returns 0 there - // is no need to draw the stencil's contents and there's also no - // need to restore the affected area becasue there is none! - FDrawInfo *di; - if (Start(usestencil, doquery, outer_di, &di)) - { - DrawContents(di); - End(di, usestencil); - } - } - - void AddLine(GLWall * l) - { - lines.Push(*l); - } - - static int GetRecursion() - { - return recursion; - } - - static bool isMirrored() { return !!((MirrorFlag ^ PlaneMirrorFlag) & 1); } - - virtual void RenderAttached(FDrawInfo *di) {} - - static void BeginScene(); - static void StartFrame(); - static bool RenderFirstSkyPortal(int recursion, FDrawInfo *outer_di); - static void EndFrame(FDrawInfo *outer_di); - static GLPortal * FindPortal(const void * src); - - static void Initialize(); - static void Shutdown(); + bool Start(bool usestencil, bool doquery, HWDrawInfo *outer_di, HWDrawInfo **pDi) override; + void End(HWDrawInfo *di, bool usestencil) override; + void ClearClipper(HWDrawInfo *di); + void ClearScreen(HWDrawInfo *di); }; struct GLLinePortal : public GLPortal @@ -140,14 +75,14 @@ struct GLLinePortal : public GLPortal angle_t angv1, angv2; // for quick comparisons with a line or subsector - GLLinePortal(line_t *line) + GLLinePortal(FPortalSceneState *state, line_t *line) : GLPortal(state) { v1 = line->v1; v2 = line->v2; CalcDelta(); } - GLLinePortal(FLinePortalSpan *line) + GLLinePortal(FPortalSceneState *state, FLinePortalSpan *line) : GLPortal(state) { if (line->lines[0]->mType != PORTT_LINKED || line->v1 == nullptr) { @@ -189,14 +124,14 @@ struct GLMirrorPortal : public GLLinePortal line_t * linedef; protected: - virtual void DrawContents(FDrawInfo *di); + virtual void DrawContents(HWDrawInfo *di); virtual void * GetSource() const { return linedef; } virtual const char *GetName(); public: - GLMirrorPortal(line_t * line) - : GLLinePortal(line) + GLMirrorPortal(FPortalSceneState *state, line_t * line) + : GLLinePortal(state, line) { linedef=line; } @@ -207,16 +142,16 @@ struct GLLineToLinePortal : public GLLinePortal { FLinePortalSpan *glport; protected: - virtual void DrawContents(FDrawInfo *di); + virtual void DrawContents(HWDrawInfo *di); virtual void * GetSource() const { return glport; } virtual const char *GetName(); virtual line_t *ClipLine() { return line(); } - virtual void RenderAttached(FDrawInfo *di); + virtual void RenderAttached(HWDrawInfo *di); public: - GLLineToLinePortal(FLinePortalSpan *ll) - : GLLinePortal(ll) + GLLineToLinePortal(FPortalSceneState *state, FLinePortalSpan *ll) + : GLLinePortal(state, ll) { glport = ll; } @@ -228,7 +163,7 @@ struct GLSkyboxPortal : public GLPortal FSectorPortal * portal; protected: - virtual void DrawContents(FDrawInfo *di); + virtual void DrawContents(HWDrawInfo *di); virtual void * GetSource() const { return portal; } virtual bool IsSky() { return true; } virtual const char *GetName(); @@ -236,7 +171,7 @@ protected: public: - GLSkyboxPortal(FSectorPortal * pt) + GLSkyboxPortal(FPortalSceneState *state, FSectorPortal * pt) : GLPortal(state) { portal=pt; } @@ -250,7 +185,7 @@ struct GLSkyPortal : public GLPortal friend struct GLEEHorizonPortal; protected: - virtual void DrawContents(FDrawInfo *di); + virtual void DrawContents(HWDrawInfo *di); virtual void * GetSource() const { return origin; } virtual bool IsSky() { return true; } virtual bool NeedDepthBuffer() { return false; } @@ -259,8 +194,8 @@ protected: public: - GLSkyPortal(GLSkyInfo * pt, bool local = false) - : GLPortal(local) + GLSkyPortal(FPortalSceneState *state, GLSkyInfo * pt, bool local = false) + : GLPortal(state, local) { origin=pt; } @@ -274,7 +209,7 @@ struct GLSectorStackPortal : public GLPortal TArray subsectors; protected: virtual ~GLSectorStackPortal(); - virtual void DrawContents(FDrawInfo *di); + 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(); @@ -282,11 +217,11 @@ protected: public: - GLSectorStackPortal(FSectorPortalGroup *pt) + GLSectorStackPortal(FPortalSceneState *state, FSectorPortalGroup *pt) : GLPortal(state) { origin=pt; } - void SetupCoverage(FDrawInfo *di); + void SetupCoverage(HWDrawInfo *di); void AddSubsector(subsector_t *sub) { subsectors.Push(sub); @@ -297,14 +232,14 @@ public: struct GLPlaneMirrorPortal : public GLPortal { protected: - virtual void DrawContents(FDrawInfo *di); + virtual void DrawContents(HWDrawInfo *di); virtual void * GetSource() const { return origin; } virtual const char *GetName(); secplane_t * origin; public: - GLPlaneMirrorPortal(secplane_t * pt) + GLPlaneMirrorPortal(FPortalSceneState *state, secplane_t * pt) : GLPortal(state) { origin=pt; } @@ -320,7 +255,7 @@ struct GLHorizonPortal : public GLPortal friend struct GLEEHorizonPortal; protected: - virtual void DrawContents(FDrawInfo *di); + virtual void DrawContents(HWDrawInfo *di); virtual void * GetSource() const { return origin; } virtual bool NeedDepthBuffer() { return false; } virtual bool NeedCap() { return false; } @@ -328,7 +263,7 @@ protected: public: - GLHorizonPortal(GLHorizonInfo * pt, FRenderViewpoint &vp, bool local = false); + GLHorizonPortal(FPortalSceneState *state, GLHorizonInfo * pt, FRenderViewpoint &vp, bool local = false); }; struct GLEEHorizonPortal : public GLPortal @@ -336,7 +271,7 @@ struct GLEEHorizonPortal : public GLPortal FSectorPortal * portal; protected: - virtual void DrawContents(FDrawInfo *di); + virtual void DrawContents(HWDrawInfo *di); virtual void * GetSource() const { return portal; } virtual bool NeedDepthBuffer() { return false; } virtual bool NeedCap() { return false; } @@ -344,7 +279,7 @@ protected: public: - GLEEHorizonPortal(FSectorPortal *pt) + GLEEHorizonPortal(FPortalSceneState *state, FSectorPortal *pt) : GLPortal(state) { portal=pt; } diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index 057683caf3..123fd47beb 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -50,6 +50,7 @@ #include "gl/renderer/gl_renderbuffers.h" #include "gl/data/gl_vertexbuffer.h" #include "hwrenderer/scene/hw_clipper.h" +#include "hwrenderer/scene/hw_portal.h" #include "gl/scene/gl_drawinfo.h" #include "gl/scene/gl_portal.h" #include "gl/stereo3d/gl_stereo3d.h" @@ -91,41 +92,6 @@ void FDrawInfo::ApplyVPUniforms() } -//----------------------------------------------------------------------------- -// -// Setup the modelview matrix -// -//----------------------------------------------------------------------------- - -void FDrawInfo::SetViewMatrix(const FRotator &angles, float vx, float vy, float vz, bool mirror, bool planemirror) -{ - float mult = mirror? -1:1; - float planemult = planemirror? -level.info->pixelstretch : level.info->pixelstretch; - - VPUniforms.mViewMatrix.loadIdentity(); - VPUniforms.mViewMatrix.rotate(angles.Roll.Degrees, 0.0f, 0.0f, 1.0f); - VPUniforms.mViewMatrix.rotate(angles.Pitch.Degrees, 1.0f, 0.0f, 0.0f); - VPUniforms.mViewMatrix.rotate(angles.Yaw.Degrees, 0.0f, mult, 0.0f); - VPUniforms.mViewMatrix.translate(vx * mult, -vz * planemult , -vy); - VPUniforms.mViewMatrix.scale(-mult, planemult, 1); -} - - -//----------------------------------------------------------------------------- -// -// SetupView -// Setup the view rotation matrix for the given viewpoint -// -//----------------------------------------------------------------------------- -void FDrawInfo::SetupView(float vx, float vy, float vz, bool mirror, bool planemirror) -{ - auto &vp = Viewpoint; - vp.SetViewAngle(r_viewwindow); - SetViewMatrix(vp.HWAngles, vx, vy, vz, mirror, planemirror); - SetCameraPos(vp.Pos); - ApplyVPUniforms(); -} - //----------------------------------------------------------------------------- // // CreateScene @@ -141,7 +107,7 @@ void FDrawInfo::CreateScene() mClipper->SafeAddClipRangeRealAngles(vp.Angles.Yaw.BAMs() + a1, vp.Angles.Yaw.BAMs() - a1); // reset the portal manager - GLPortal::StartFrame(); + GLRenderer->mPortalState.StartFrame(); PO_LinkToSubsectors(); ProcessAll.Clock(); @@ -195,7 +161,7 @@ void FDrawInfo::RenderScene(int recursion) RenderAll.Clock(); glDepthMask(true); - if (!gl_no_skyclear) GLPortal::RenderFirstSkyPortal(recursion, this); + if (!gl_no_skyclear) GLRenderer->mPortalState.RenderFirstSkyPortal(recursion, this); gl_RenderState.EnableFog(true); gl_RenderState.BlendFunc(GL_ONE,GL_ZERO); @@ -377,7 +343,7 @@ void FDrawInfo::DrawScene(int drawmode) // Handle all portals after rendering the opaque objects but before // doing all translucent stuff recursion++; - GLPortal::EndFrame(this); + GLRenderer->mPortalState.EndFrame(this); recursion--; RenderTranslucent(); } @@ -444,7 +410,7 @@ void FDrawInfo::DrawEndScene2D(sector_t * viewsector) void FDrawInfo::ProcessScene(bool toscreen) { iter_dlightf = iter_dlight = draw_dlight = draw_dlightf = 0; - GLPortal::BeginScene(); + GLRenderer->mPortalState.BeginScene(); int mapsection = R_PointInSubsector(Viewpoint.Pos)->mapsection; CurrentMapSections.Set(mapsection); diff --git a/src/gl/scene/gl_skydome.cpp b/src/gl/scene/gl_skydome.cpp index 9f3ef2bd7a..9feaad5b01 100644 --- a/src/gl/scene/gl_skydome.cpp +++ b/src/gl/scene/gl_skydome.cpp @@ -210,7 +210,7 @@ static void RenderBox(FTextureID texno, FMaterial * gltex, float x_offset, bool // // //----------------------------------------------------------------------------- -void GLSkyPortal::DrawContents(FDrawInfo *di) +void GLSkyPortal::DrawContents(HWDrawInfo *di) { bool drawBoth = false; auto &vp = di->Viewpoint; @@ -230,7 +230,7 @@ void GLSkyPortal::DrawContents(FDrawInfo *di) gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); bool oldClamp = gl_RenderState.SetDepthClamp(true); - di->SetupView(0, 0, 0, !!(MirrorFlag & 1), !!(PlaneMirrorFlag & 1)); + di->SetupView(0, 0, 0, !!(mState->MirrorFlag & 1), !!(mState->PlaneMirrorFlag & 1)); gl_RenderState.SetVertexBuffer(GLRenderer->mSkyVBO); if (origin->texture[0] && origin->texture[0]->tex->bSkybox) diff --git a/src/gl/scene/gl_walls_draw.cpp b/src/gl/scene/gl_walls_draw.cpp index 8c989313bb..5a2a841555 100644 --- a/src/gl/scene/gl_walls_draw.cpp +++ b/src/gl/scene/gl_walls_draw.cpp @@ -337,7 +337,8 @@ void FDrawInfo::AddMirrorSurface(GLWall *w) void FDrawInfo::AddPortal(GLWall *wall, int ptype) { - GLPortal * portal; + auto &pstate = GLRenderer->mPortalState; + IPortal * portal; wall->MakeVertices(this, false); switch (ptype) @@ -345,19 +346,19 @@ void FDrawInfo::AddPortal(GLWall *wall, int ptype) // portals don't go into the draw list. // Instead they are added to the portal manager case PORTALTYPE_HORIZON: - wall->horizon = UniqueHorizons.Get(wall->horizon); - portal = GLPortal::FindPortal(wall->horizon); - if (!portal) portal = new GLHorizonPortal(wall->horizon, Viewpoint); + wall->horizon = pstate.UniqueHorizons.Get(wall->horizon); + portal = pstate.FindPortal(wall->horizon); + if (!portal) portal = new GLHorizonPortal(&pstate, wall->horizon, Viewpoint); portal->AddLine(wall); break; case PORTALTYPE_SKYBOX: - portal = GLPortal::FindPortal(wall->secportal); + portal = pstate.FindPortal(wall->secportal); if (!portal) { // either a regular skybox or an Eternity-style horizon - if (wall->secportal->mType != PORTS_SKYVIEWPOINT) portal = new GLEEHorizonPortal(wall->secportal); - else portal = new GLSkyboxPortal(wall->secportal); + if (wall->secportal->mType != PORTS_SKYVIEWPOINT) portal = new GLEEHorizonPortal(&pstate, wall->secportal); + else portal = new GLSkyboxPortal(&pstate, wall->secportal); } portal->AddLine(wall); break; @@ -368,19 +369,19 @@ void FDrawInfo::AddPortal(GLWall *wall, int ptype) break; case PORTALTYPE_PLANEMIRROR: - if (GLPortal::PlaneMirrorMode * wall->planemirror->fC() <= 0) + if (pstate.PlaneMirrorMode * wall->planemirror->fC() <= 0) { //@sync-portal - wall->planemirror = UniquePlaneMirrors.Get(wall->planemirror); - portal = GLPortal::FindPortal(wall->planemirror); - if (!portal) portal = new GLPlaneMirrorPortal(wall->planemirror); + wall->planemirror = pstate.UniquePlaneMirrors.Get(wall->planemirror); + portal = pstate.FindPortal(wall->planemirror); + if (!portal) portal = new GLPlaneMirrorPortal(&pstate, wall->planemirror); portal->AddLine(wall); } break; case PORTALTYPE_MIRROR: - portal = GLPortal::FindPortal(wall->seg->linedef); - if (!portal) portal = new GLMirrorPortal(wall->seg->linedef); + portal = pstate.FindPortal(wall->seg->linedef); + if (!portal) portal = new GLMirrorPortal(&pstate, wall->seg->linedef); portal->AddLine(wall); if (gl_mirror_envmap) { @@ -390,7 +391,7 @@ void FDrawInfo::AddPortal(GLWall *wall, int ptype) break; case PORTALTYPE_LINETOLINE: - portal = GLPortal::FindPortal(wall->lineportal); + portal = pstate.FindPortal(wall->lineportal); if (!portal) { line_t *otherside = wall->lineportal->lines[0]->mDestination; @@ -398,15 +399,15 @@ void FDrawInfo::AddPortal(GLWall *wall, int ptype) { ProcessActorsInPortal(otherside->getPortal()->mGroup, in_area); } - portal = new GLLineToLinePortal(wall->lineportal); + portal = new GLLineToLinePortal(&pstate, wall->lineportal); } portal->AddLine(wall); break; case PORTALTYPE_SKY: - wall->sky = UniqueSkies.Get(wall->sky); - portal = GLPortal::FindPortal(wall->sky); - if (!portal) portal = new GLSkyPortal(wall->sky); + wall->sky = pstate.UniqueSkies.Get(wall->sky); + portal = pstate.FindPortal(wall->sky); + if (!portal) portal = new GLSkyPortal(&pstate, wall->sky); portal->AddLine(wall); break; } diff --git a/src/hwrenderer/scene/hw_drawinfo.cpp b/src/hwrenderer/scene/hw_drawinfo.cpp index 3b73d72c6c..994bfc7c2a 100644 --- a/src/hwrenderer/scene/hw_drawinfo.cpp +++ b/src/hwrenderer/scene/hw_drawinfo.cpp @@ -214,6 +214,42 @@ angle_t HWDrawInfo::FrustumAngle() return a1; } +//----------------------------------------------------------------------------- +// +// Setup the modelview matrix +// +//----------------------------------------------------------------------------- + +void HWDrawInfo::SetViewMatrix(const FRotator &angles, float vx, float vy, float vz, bool mirror, bool planemirror) +{ + float mult = mirror ? -1 : 1; + float planemult = planemirror ? -level.info->pixelstretch : level.info->pixelstretch; + + VPUniforms.mViewMatrix.loadIdentity(); + VPUniforms.mViewMatrix.rotate(angles.Roll.Degrees, 0.0f, 0.0f, 1.0f); + VPUniforms.mViewMatrix.rotate(angles.Pitch.Degrees, 1.0f, 0.0f, 0.0f); + VPUniforms.mViewMatrix.rotate(angles.Yaw.Degrees, 0.0f, mult, 0.0f); + VPUniforms.mViewMatrix.translate(vx * mult, -vz * planemult, -vy); + VPUniforms.mViewMatrix.scale(-mult, planemult, 1); +} + + +//----------------------------------------------------------------------------- +// +// SetupView +// Setup the view rotation matrix for the given viewpoint +// +//----------------------------------------------------------------------------- +void HWDrawInfo::SetupView(float vx, float vy, float vz, bool mirror, bool planemirror) +{ + auto &vp = Viewpoint; + vp.SetViewAngle(r_viewwindow); + SetViewMatrix(vp.HWAngles, vx, vy, vz, mirror, planemirror); + SetCameraPos(vp.Pos); + ApplyVPUniforms(); +} + + //----------------------------------------------------------------------------- // // diff --git a/src/hwrenderer/scene/hw_drawinfo.h b/src/hwrenderer/scene/hw_drawinfo.h index 2c55145c9d..f52ae45808 100644 --- a/src/hwrenderer/scene/hw_drawinfo.h +++ b/src/hwrenderer/scene/hw_drawinfo.h @@ -217,6 +217,8 @@ public: void PrepareTargeterSprites(); void UpdateCurrentMapSection(); + void SetViewMatrix(const FRotator &angles, float vx, float vy, float vz, bool mirror, bool planemirror); + void SetupView(float vx, float vy, float vz, bool mirror, bool planemirror); angle_t FrustumAngle(); virtual void DrawWall(GLWall *wall, int pass) = 0; diff --git a/src/hwrenderer/scene/hw_portal.cpp b/src/hwrenderer/scene/hw_portal.cpp new file mode 100644 index 0000000000..9c6ca5caa7 --- /dev/null +++ b/src/hwrenderer/scene/hw_portal.cpp @@ -0,0 +1,157 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2004-2018 Christoph Oelckers +// All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// +/* +** hw_portal.cpp +** portal maintenance classes for skyboxes, horizons etc. (API independent parts) +** +*/ + +#include "c_dispatch.h" +#include "hw_portal.h" + +IPortal * FPortalSceneState::FindPortal(const void * src) +{ + int i = portals.Size() - 1; + + while (i >= 0 && portals[i] && portals[i]->GetSource() != src) i--; + return i >= 0 ? portals[i] : nullptr; +} + +//----------------------------------------------------------------------------- +// +// StartFrame +// +//----------------------------------------------------------------------------- + +void FPortalSceneState::StartFrame() +{ + IPortal * p = nullptr; + portals.Push(p); + if (renderdepth == 0) + { + inskybox = false; + screen->instack[sector_t::floor] = screen->instack[sector_t::ceiling] = 0; + } + renderdepth++; +} + +//----------------------------------------------------------------------------- +// +// printing portal info +// +//----------------------------------------------------------------------------- + +static bool gl_portalinfo; + +CCMD(gl_portalinfo) +{ + gl_portalinfo = true; +} + +static FString indent; + +//----------------------------------------------------------------------------- +// +// EndFrame +// +//----------------------------------------------------------------------------- + +void FPortalSceneState::EndFrame(HWDrawInfo *outer_di) +{ + IPortal * p; + + if (gl_portalinfo) + { + Printf("%s%d portals, depth = %d\n%s{\n", indent.GetChars(), portals.Size(), renderdepth, indent.GetChars()); + indent += " "; + } + + // Only use occlusion query if there are more than 2 portals. + // Otherwise there's too much overhead. + // (And don't forget to consider the separating null pointers!) + bool usequery = portals.Size() > 2 + (unsigned)renderdepth; + + while (portals.Pop(p) && p) + { + if (gl_portalinfo) + { + Printf("%sProcessing %s, depth = %d, query = %d\n", indent.GetChars(), p->GetName(), renderdepth, usequery); + } + if (p->lines.Size() > 0) + { + p->RenderPortal(true, usequery, outer_di); + } + delete p; + } + renderdepth--; + + if (gl_portalinfo) + { + indent.Truncate(long(indent.Len()-2)); + Printf("%s}\n", indent.GetChars()); + if (portals.Size() == 0) gl_portalinfo = false; + } +} + + +//----------------------------------------------------------------------------- +// +// Renders one sky portal without a stencil. +// In more complex scenes using a stencil for skies can severely stall +// the GPU and there's rarely more than one sky visible at a time. +// +//----------------------------------------------------------------------------- +bool FPortalSceneState::RenderFirstSkyPortal(int recursion, HWDrawInfo *outer_di) +{ + IPortal * p; + IPortal * best = nullptr; + unsigned bestindex=0; + + // Find the one with the highest amount of lines. + // Normally this is also the one that saves the largest amount + // of time by drawing it before the scene itself. + for(int i = portals.Size()-1; i >= 0 && portals[i] != nullptr; --i) + { + p=portals[i]; + if (p->lines.Size() > 0 && p->IsSky()) + { + // Cannot clear the depth buffer inside a portal recursion + if (recursion && p->NeedDepthBuffer()) continue; + + if (!best || p->lines.Size()>best->lines.Size()) + { + best=p; + bestindex=i; + } + } + } + + if (best) + { + portals.Delete(bestindex); + best->RenderPortal(false, false, outer_di); + delete best; + return true; + } + return false; +} + diff --git a/src/hwrenderer/scene/hw_portal.h b/src/hwrenderer/scene/hw_portal.h index b4a313c94d..da23db5526 100644 --- a/src/hwrenderer/scene/hw_portal.h +++ b/src/hwrenderer/scene/hw_portal.h @@ -1,6 +1,7 @@ #pragma once #include "hw_drawinfo.h" +#include "hw_drawstructs.h" #include "hwrenderer/textures/hw_material.h" struct GLSkyInfo @@ -33,12 +34,96 @@ struct GLHorizonInfo PalEntry specialcolor; }; +struct FPortalSceneState; + class IPortal { + friend struct FPortalSceneState; +protected: + FPortalSceneState * mState; + TArray 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; } + virtual bool NeedCap() { return true; } + virtual bool NeedDepthBuffer() { return true; } + virtual void DrawContents(HWDrawInfo *di) = 0; + virtual void RenderAttached(HWDrawInfo *di) {} + virtual bool Start(bool usestencil, bool doquery, HWDrawInfo *outer_di, HWDrawInfo **pDi) = 0; + virtual void End(HWDrawInfo *di, bool usestencil) = 0; + + void AddLine(GLWall * l) + { + lines.Push(*l); + } + + void RenderPortal(bool usestencil, bool doquery, HWDrawInfo *outer_di) + { + // Start may perform an occlusion query. If that returns 0 there + // is no need to draw the stencil's contents and there's also no + // need to restore the affected area becasue there is none! + HWDrawInfo *di; + if (Start(usestencil, doquery, outer_di, &di)) + { + DrawContents(di); + End(di, usestencil); + } + } + + }; + +struct FPortalSceneState +{ + TArray portals; + int recursion = 0; + + int MirrorFlag = 0; + int PlaneMirrorFlag = 0; + int renderdepth = 0; + + int PlaneMirrorMode = 0; + bool inskybox = 0; + + UniqueList UniqueSkies; + UniqueList UniqueHorizons; + UniqueList UniquePlaneMirrors; + + int skyboxrecursion = 0; + + void BeginScene() + { + UniqueSkies.Clear(); + UniqueHorizons.Clear(); + UniquePlaneMirrors.Clear(); + } + + int GetRecursion() const + { + return recursion; + } + + bool isMirrored() const + { + return !!((MirrorFlag ^ PlaneMirrorFlag) & 1); + } + + IPortal * FindPortal(const void * src); + void StartFrame(); + bool RenderFirstSkyPortal(int recursion, HWDrawInfo *outer_di); + void EndFrame(HWDrawInfo *outer_di); + + +}; + +inline IPortal::IPortal(FPortalSceneState *s, bool local) : mState(s) +{ + if (!local) s->portals.Push(this); +}