//----------------------------------------------------------------------------- // // End // //----------------------------------------------------------------------------- void GLPortal::End(bool usestencil) { bool needdepth = NeedDepthBuffer(); PortalAll.Clock(); GLRenderer->mCurrentPortal = NextPortal; if (clipsave) glEnable (GL_CLIP_PLANE0+renderdepth-1); if (usestencil) { if (needdepth) FDrawInfo::EndDrawInfo(); // Restore the old view viewx=savedviewx; viewy=savedviewy; viewz=savedviewz; viewangle=savedviewangle; GLRenderer->mViewActor=savedviewactor; in_area=savedviewarea; GLRenderer->SetupView(viewx, viewy, viewz, viewangle, !!(MirrorFlag&1), !!(PlaneMirrorFlag&1)); glColor4f(1,1,1,1); glColorMask(0,0,0,0); // no graphics glColor3f(1,1,1); gl_RenderState.EnableTexture(false); gl_RenderState.Apply(); if (needdepth) { // first step: reset the depth buffer to max. depth glDepthRange(1,1); // always glDepthFunc(GL_ALWAYS); // write the farthest depth value DrawPortalStencil(); } else { glEnable(GL_DEPTH_TEST); } // second step: restore the depth buffer to the previous values and reset the stencil glDepthFunc(GL_LEQUAL); glDepthRange(0,1); glStencilOp(GL_KEEP,GL_KEEP,GL_DECR); glStencilFunc(GL_EQUAL,recursion,~0); // draw sky into stencil DrawPortalStencil(); glDepthFunc(GL_LESS); gl_RenderState.EnableTexture(true); glColorMask(1,1,1,1); recursion--; // restore old stencil op. glStencilOp(GL_KEEP,GL_KEEP,GL_KEEP); glStencilFunc(GL_EQUAL,recursion,~0); // draw sky into stencil } else { if (needdepth) { FDrawInfo::EndDrawInfo(); glClear(GL_DEPTH_BUFFER_BIT); } else { glEnable(GL_DEPTH_TEST); glDepthMask(true); } // Restore the old view viewx=savedviewx; viewy=savedviewy; viewz=savedviewz; viewangle=savedviewangle; GLRenderer->mViewActor=savedviewactor; in_area=savedviewarea; GLRenderer->SetupView(viewx, viewy, viewz, viewangle, !!(MirrorFlag&1), !!(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. glColor4f(1,1,1,1); glDepthFunc(GL_LEQUAL); glDepthRange(0,1); glColorMask(0,0,0,0); // no graphics gl_RenderState.EnableTexture(false); DrawPortalStencil(); gl_RenderState.EnableTexture(true); glColorMask(1,1,1,1); glDepthFunc(GL_LESS); } PortalAll.Unclock(); }
bool GLPortal::Start(bool usestencil, bool doquery) { rendered_portals++; PortalAll.Clock(); if (usestencil) { if (!gl_portals) { PortalAll.Unclock(); return false; } // Create stencil glStencilFunc(GL_EQUAL,recursion,~0); // create stencil glStencilOp(GL_KEEP,GL_KEEP,GL_INCR); // increment stencil of valid pixels glColorMask(0,0,0,0); // don't write to the graphics buffer gl_RenderState.EnableTexture(false); glColor3f(1,1,1); glDepthFunc(GL_LESS); gl_RenderState.Apply(); if (NeedDepthBuffer()) { glDepthMask(false); // don't write to Z-buffer! 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) glGenQueries(1, &QueryObject); if (QueryObject) { glBeginQuery(GL_SAMPLES_PASSED_ARB, QueryObject); } else doquery = false; // some kind of error happened DrawPortalStencil(); glEndQuery(GL_SAMPLES_PASSED_ARB); // Clear Z-buffer glStencilFunc(GL_EQUAL,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); glDepthFunc(GL_ALWAYS); DrawPortalStencil(); // set normal drawing mode gl_RenderState.EnableTexture(true); glDepthFunc(GL_LESS); glColorMask(1,1,1,1); glDepthRange(0,1); GLuint sampleCount; glGetQueryObjectuiv(QueryObject, GL_QUERY_RESULT_ARB, &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 PortalAll.Unclock(); return false; } FDrawInfo::StartDrawInfo(); } else { // No z-buffer is needed therefore we can skip all the complicated stuff that is involved // No occlusion queries will be done here. For these portals the overhead is far greater // than the benefit. // Note: We must draw the stencil with z-write enabled here because there is no second pass! glDepthMask(true); DrawPortalStencil(); glStencilFunc(GL_EQUAL,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); glDisable(GL_DEPTH_TEST); glDepthMask(false); // don't write to Z-buffer! } recursion++; } else { if (NeedDepthBuffer()) { FDrawInfo::StartDrawInfo(); } else { glDepthMask(false); glDisable(GL_DEPTH_TEST); } } // The clip plane from the previous portal must be deactivated for this one. clipsave = glIsEnabled(GL_CLIP_PLANE0+renderdepth-1); if (clipsave) glDisable(GL_CLIP_PLANE0+renderdepth-1); // save viewpoint savedviewx=viewx; savedviewy=viewy; savedviewz=viewz; savedviewactor=GLRenderer->mViewActor; savedviewangle=viewangle; savedviewarea=in_area; NextPortal = GLRenderer->mCurrentPortal; GLRenderer->mCurrentPortal = NULL; // Portals which need this have to set it themselves PortalAll.Unclock(); return true; }
//----------------------------------------------------------------------------- // // End // //----------------------------------------------------------------------------- void HWPortal::RemoveStencil(HWDrawInfo *di, FRenderState &state, bool usestencil) { Clocker c(PortalAll); bool needdepth = NeedDepthBuffer(); // Restore the old view auto &vp = di->Viewpoint; if (vp.camera != nullptr) vp.camera->renderflags = (vp.camera->renderflags & ~RF_MAYBEINVISIBLE) | savedvisibility; if (usestencil) { state.SetColorMask(false); // no graphics state.SetEffect(EFF_NONE); state.ResetColor(); state.EnableTexture(false); if (needdepth) { // first step: reset the depth buffer to max. depth state.SetDepthRange(1, 1); // always state.SetDepthFunc(DF_Always); // write the farthest depth value DrawPortalStencil(state, STP_DepthClear); } else { state.EnableDepthTest(true); } // second step: restore the depth buffer to the previous values and reset the stencil state.SetDepthFunc(DF_LEqual); state.SetDepthRange(0, 1); state.SetStencil(0, SOP_Decrement); DrawPortalStencil(state, STP_DepthRestore); state.SetDepthFunc(DF_Less); state.EnableTexture(true); state.SetEffect(EFF_NONE); state.SetColorMask(true); screen->stencilValue--; // restore old stencil op. state.SetStencil(0, SOP_Keep); } else { if (needdepth) { state.Clear(CT_Depth); } else { state.EnableDepthTest(true); state.SetDepthMask(true); } // This draws a valid z-buffer into the stencil's contents to ensure it // doesn't get overwritten by the level's geometry. state.ResetColor(); state.SetDepthFunc(DF_LEqual); state.SetDepthRange(0, 1); state.SetColorMask(0, 0, 0, 1); // mark portal in alpha channel but don't touch color state.SetEffect(EFF_STENCIL); state.EnableTexture(false); state.SetRenderStyle(STYLE_Source); DrawPortalStencil(state, STP_DepthRestore); state.SetEffect(EFF_NONE); state.EnableTexture(true); state.SetColorMask(true); state.SetDepthFunc(DF_Less); } }
void HWPortal::SetupStencil(HWDrawInfo *di, FRenderState &state, bool usestencil) { Clocker c(PortalAll); rendered_portals++; if (usestencil) { // Create stencil state.SetStencil(0, SOP_Increment); // create stencil, increment stencil of valid pixels state.SetColorMask(false); state.SetEffect(EFF_STENCIL); state.EnableTexture(false); state.ResetColor(); state.SetDepthFunc(DF_Less); if (NeedDepthBuffer()) { state.SetDepthMask(false); // don't write to Z-buffer! DrawPortalStencil(state, STP_Stencil); // Clear Z-buffer state.SetStencil(1, SOP_Keep); // draw sky into stencil. This stage doesn't modify the stencil. state.SetDepthMask(true); // enable z-buffer again state.SetDepthRange(1, 1); state.SetDepthFunc(DF_Always); DrawPortalStencil(state, STP_DepthClear); // set normal drawing mode state.EnableTexture(true); state.SetDepthRange(0, 1); state.SetDepthFunc(DF_Less); state.SetColorMask(true); state.SetEffect(EFF_NONE); } else { // No z-buffer is needed therefore we can skip all the complicated stuff that is involved // Note: We must draw the stencil with z-write enabled here because there is no second pass! state.SetDepthMask(true); DrawPortalStencil(state, STP_AllInOne); state.SetStencil(1, SOP_Keep); // draw sky into stencil. This stage doesn't modify the stencil. state.EnableTexture(true); state.SetColorMask(true); state.SetEffect(EFF_NONE); state.EnableDepthTest(false); state.SetDepthMask(false); // don't write to Z-buffer! } screen->stencilValue++; } else { if (!NeedDepthBuffer()) { state.SetDepthMask(false); state.EnableDepthTest(false); } } // save viewpoint savedvisibility = di->Viewpoint.camera ? di->Viewpoint.camera->renderflags & RF_MAYBEINVISIBLE : ActorRenderFlags::FromInt(0); }
//----------------------------------------------------------------------------- // // End // //----------------------------------------------------------------------------- void GLPortal::End(bool usestencil) { bool needdepth = NeedDepthBuffer(); PortalAll.Clock(); if (PrevPortal != NULL) PrevPortal->PopState(); GLRenderer->mCurrentPortal = PrevPortal; GLRenderer->mClipPortal = PrevClipPortal; if (usestencil) { if (needdepth) FDrawInfo::EndDrawInfo(); // Restore the old view ViewPath[0] = savedviewpath[0]; ViewPath[1] = savedviewpath[1]; ViewPos = savedViewPos; ViewAngle = savedAngle; GLRenderer->mViewActor=savedviewactor; in_area=savedviewarea; if (camera != nullptr) camera->renderflags = (camera->renderflags & ~RF_INVISIBLE) | savedvisibility; GLRenderer->SetupView(ViewPos.X, ViewPos.Y, ViewPos.Z, ViewAngle, !!(MirrorFlag & 1), !!(PlaneMirrorFlag & 1)); { ScopedColorMask colorMask(0, 0, 0, 0); // glColorMask(0, 0, 0, 0); // no graphics gl_RenderState.SetEffect(EFF_NONE); gl_RenderState.ResetColor(); gl_RenderState.EnableTexture(false); gl_RenderState.Apply(); if (needdepth) { // first step: reset the depth buffer to max. depth glDepthRange(1, 1); // always glDepthFunc(GL_ALWAYS); // write the farthest depth value DrawPortalStencil(); } else { glEnable(GL_DEPTH_TEST); } // second step: restore the depth buffer to the previous values and reset the stencil glDepthFunc(GL_LEQUAL); glDepthRange(0, 1); glStencilOp(GL_KEEP, GL_KEEP, GL_DECR); glStencilFunc(GL_EQUAL, recursion, ~0); // draw sky into stencil DrawPortalStencil(); glDepthFunc(GL_LESS); gl_RenderState.EnableTexture(true); gl_RenderState.SetEffect(EFF_NONE); } // glColorMask(1, 1, 1, 1); recursion--; // restore old stencil op. glStencilOp(GL_KEEP,GL_KEEP,GL_KEEP); glStencilFunc(GL_EQUAL,recursion,~0); // draw sky into stencil } else { if (needdepth) { FDrawInfo::EndDrawInfo(); glClear(GL_DEPTH_BUFFER_BIT); } else { glEnable(GL_DEPTH_TEST); glDepthMask(true); } // Restore the old view ViewPos = savedViewPos; ViewAngle = savedAngle; GLRenderer->mViewActor=savedviewactor; in_area=savedviewarea; if (camera != nullptr) camera->renderflags |= savedvisibility; GLRenderer->SetupView(ViewPos.X, ViewPos.Y, ViewPos.Z, ViewAngle, !!(MirrorFlag&1), !!(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. gl_RenderState.ResetColor(); glDepthFunc(GL_LEQUAL); glDepthRange(0, 1); { ScopedColorMask colorMask(0, 0, 0, 0); // glColorMask(0,0,0,0); // no graphics gl_RenderState.SetEffect(EFF_STENCIL); gl_RenderState.EnableTexture(false); DrawPortalStencil(); gl_RenderState.SetEffect(EFF_NONE); gl_RenderState.EnableTexture(true); } // glColorMask(1, 1, 1, 1); glDepthFunc(GL_LESS); } PortalAll.Unclock(); }
bool GLPortal::Start(bool usestencil, bool doquery) { rendered_portals++; PortalAll.Clock(); if (usestencil) { if (!gl_portals) { PortalAll.Unclock(); return false; } // Create stencil glStencilFunc(GL_EQUAL,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 gl_RenderState.SetEffect(EFF_STENCIL); gl_RenderState.EnableTexture(false); gl_RenderState.ResetColor(); glDepthFunc(GL_LESS); gl_RenderState.Apply(); if (NeedDepthBuffer()) { glDepthMask(false); // don't write to Z-buffer! 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 && doquery) glGenQueries(1, &QueryObject); if (QueryObject) { glBeginQuery(GL_SAMPLES_PASSED, QueryObject); } else doquery = false; // some kind of error happened DrawPortalStencil(); glEndQuery(GL_SAMPLES_PASSED); // Clear Z-buffer glStencilFunc(GL_EQUAL, 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); glDepthFunc(GL_ALWAYS); DrawPortalStencil(); // set normal drawing mode gl_RenderState.EnableTexture(true); glDepthFunc(GL_LESS); // glColorMask(1, 1, 1, 1); gl_RenderState.SetEffect(EFF_NONE); glDepthRange(0, 1); GLuint sampleCount; if (QueryObject) { glGetQueryObjectuiv(QueryObject, 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 PortalAll.Unclock(); return false; } } FDrawInfo::StartDrawInfo(); } else { // No z-buffer is needed therefore we can skip all the complicated stuff that is involved // No occlusion queries will be done here. For these portals the overhead is far greater // than the benefit. // Note: We must draw the stencil with z-write enabled here because there is no second pass! glDepthMask(true); DrawPortalStencil(); glStencilFunc(GL_EQUAL, 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); gl_RenderState.SetEffect(EFF_NONE); glDisable(GL_DEPTH_TEST); glDepthMask(false); // don't write to Z-buffer! } } recursion++; } else { if (NeedDepthBuffer()) { FDrawInfo::StartDrawInfo(); } else { glDepthMask(false); glDisable(GL_DEPTH_TEST); } } // save viewpoint savedViewPos = ViewPos; savedAngle = ViewAngle; savedviewactor=GLRenderer->mViewActor; savedviewarea=in_area; savedviewpath[0] = ViewPath[0]; savedviewpath[1] = ViewPath[1]; savedvisibility = camera ? camera->renderflags & RF_INVISIBLE : ActorRenderFlags::FromInt(0); PrevPortal = GLRenderer->mCurrentPortal; PrevClipPortal = GLRenderer->mClipPortal; GLRenderer->mClipPortal = NULL; // Portals which need this have to set it themselves GLRenderer->mCurrentPortal = this; if (PrevPortal != NULL) PrevPortal->PushState(); PortalAll.Unclock(); return true; }