diff --git a/src/engine/renderer/tr_backend.cpp b/src/engine/renderer/tr_backend.cpp index ce00605dc5..05ca2a961d 100644 --- a/src/engine/renderer/tr_backend.cpp +++ b/src/engine/renderer/tr_backend.cpp @@ -386,7 +386,7 @@ void GL_PolygonOffset( float factor, float units ) void GL_Cull( cullType_t cullType ) { - if ( backEnd.viewParms.isMirror ) + if ( backEnd.viewParms.mirrorLevel % 2 == 1 ) { GL_FrontFace( GL_CW ); } @@ -5543,7 +5543,7 @@ const RenderCommand *PreparePortalCommand::ExecuteSelf( ) const GL_State( GLS_COLORMASK_BITS ); glState.glStateBitsMask = GLS_COLORMASK_BITS; - Tess_Begin( Tess_StageIteratorGeneric, nullptr, shader, + Tess_Begin( Tess_StageIteratorPortal, nullptr, shader, nullptr, false, false, -1, -1 ); rb_surfaceTable[Util::ordinal(*(surface->surface))](surface->surface ); Tess_End(); @@ -5556,10 +5556,10 @@ const RenderCommand *PreparePortalCommand::ExecuteSelf( ) const glStencilFunc( GL_EQUAL, backEnd.viewParms.portalLevel + 1, 0xff ); glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ); - GL_State( GLS_DEPTHMASK_TRUE | GLS_DEPTHTEST_DISABLE | GLS_COLORMASK_BITS ); - glState.glStateBitsMask = GLS_DEPTHMASK_TRUE | GLS_DEPTHTEST_DISABLE | GLS_COLORMASK_BITS; + GL_State( GLS_DEPTHMASK_TRUE | GLS_COLORMASK_BITS | GLS_DEPTHFUNC_ALWAYS); + glState.glStateBitsMask = GLS_DEPTHMASK_TRUE | GLS_COLORMASK_BITS | GLS_DEPTHFUNC_ALWAYS; - Tess_Begin( Tess_StageIteratorGeneric, nullptr, shader, + Tess_Begin( Tess_StageIteratorPortal, nullptr, shader, nullptr, false, false, -1, -1 ); rb_surfaceTable[Util::ordinal(*(surface->surface))](surface->surface ); Tess_End(); @@ -5604,17 +5604,30 @@ const RenderCommand *FinalisePortalCommand::ExecuteSelf( ) const GL_LoadModelViewMatrix( backEnd.orientation.modelViewMatrix ); + GL_State( GLS_DEPTHMASK_TRUE | GLS_DEPTHFUNC_ALWAYS ); + glState.glStateBitsMask = GLS_DEPTHMASK_TRUE | GLS_DEPTHFUNC_ALWAYS; + glStencilFunc( GL_EQUAL, backEnd.viewParms.portalLevel + 1, 0xff ); + glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ); + + Tess_Begin( Tess_StageIteratorGeneric, nullptr, shader, + nullptr, false, false, -1, -1 ); + rb_surfaceTable[Util::ordinal( *( surface->surface ) )]( surface->surface ); + Tess_End(); + glStencilOp( GL_KEEP, GL_KEEP, GL_DECR ); - GL_State( GLS_DEPTHMASK_TRUE | GLS_DEPTHFUNC_ALWAYS | GLS_COLORMASK_BITS ); - glState.glStateBitsMask = GLS_DEPTHMASK_TRUE | GLS_DEPTHFUNC_ALWAYS | GLS_COLORMASK_BITS; + GL_State( GLS_COLORMASK_BITS | GLS_DEPTHFUNC_ALWAYS); + glState.glStateBitsMask = GLS_COLORMASK_BITS | GLS_DEPTHFUNC_ALWAYS; - Tess_Begin( Tess_StageIteratorGeneric, nullptr, shader, + Tess_Begin( Tess_StageIteratorPortal, nullptr, shader, nullptr, false, false, -1, -1 ); rb_surfaceTable[Util::ordinal(*(surface->surface))](surface->surface ); Tess_End(); + glStencilFunc( GL_EQUAL, backEnd.viewParms.portalLevel, 0xff ); + glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ); + glState.glStateBitsMask = 0; if( backEnd.viewParms.portalLevel == 0 ) { diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index fdf87faf4e..97719b56bb 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -1619,6 +1619,7 @@ enum class deluxeMode_t { NONE, GRID, MAP }; vec3_t pvsOrigin; // may be different than or.origin for portals int portalLevel; // number of portals this view is through + int mirrorLevel; bool isMirror; // the portal is a mirror, invert the face culling int frameSceneNum; // copied from tr.frameSceneNum @@ -3521,6 +3522,7 @@ inline bool checkGLErrors() void Tess_StageIteratorDebug(); void Tess_StageIteratorGeneric(); + void Tess_StageIteratorPortal(); void Tess_StageIteratorDepthFill(); void Tess_StageIteratorShadowFill(); void Tess_StageIteratorLighting(); diff --git a/src/engine/renderer/tr_main.cpp b/src/engine/renderer/tr_main.cpp index 3cd22c9793..e3321bf44b 100644 --- a/src/engine/renderer/tr_main.cpp +++ b/src/engine/renderer/tr_main.cpp @@ -1301,28 +1301,39 @@ static bool R_GetPortalOrientations( drawSurf_t *drawSurf, orientation_t *surfac // locate the portal entity closest to this plane. // origin will be the origin of the portal, origin2 will be // the origin of the camera - for ( i = 0; i < tr.refdef.numEntities; i++ ) - { - e = &tr.refdef.entities[ i ]; - - if ( e->e.reType != refEntityType_t::RT_PORTALSURFACE ) - { + int numVertsOld = tess.numVertexes; + rb_surfaceTable[Util::ordinal( *( drawSurf->surface ) )]( drawSurf->surface ); + int numVerts = tess.numVertexes - numVertsOld; + vec3_t portalCenter{ 0.0, 0.0, 0.0 }; + for ( int vertIndex = 0; vertIndex < numVerts; vertIndex++ ) { + VectorAdd( portalCenter, tess.verts[vertIndex].xyz, portalCenter ); + } + VectorScale( portalCenter, 1.0 / numVerts, portalCenter ); + float minDistance = FLT_MAX; + trRefEntity_t* currentPortal = nullptr; + for ( i = 0; i < tr.refdef.numEntities; i++ ) { + e = &tr.refdef.entities[i]; + + if ( e->e.reType != refEntityType_t::RT_PORTALSURFACE ) { continue; } - d = DotProduct( e->e.origin, originalPlane.normal ) - originalPlane.dist; - - if ( d > 64 || d < -64 ) - { - continue; + float distance = Distance( e->e.origin, portalCenter ); + if ( distance < minDistance ) { + minDistance = distance; + currentPortal = e; } - - // get the pvsOrigin from the entity + } + if( currentPortal) { + // project the origin onto the surface plane to get + // an origin point we can rotate around + e = currentPortal; VectorCopy( e->e.oldorigin, pvsOrigin ); + d = DotProduct( e->e.origin, plane.normal ) - plane.dist; + VectorMA( e->e.origin, -d, surface->axis[ 0 ], surface->origin ); // if the entity is just a mirror, don't use as a camera point - if ( e->e.oldorigin[ 0 ] == e->e.origin[ 0 ] && e->e.oldorigin[ 1 ] == e->e.origin[ 1 ] && e->e.oldorigin[ 2 ] == e->e.origin[ 2 ] ) - { + if ( e->e.oldorigin[ 0 ] == e->e.origin[ 0 ] && e->e.oldorigin[ 1 ] == e->e.origin[ 1 ] && e->e.oldorigin[ 2 ] == e->e.origin[ 2 ] ) { VectorScale( plane.normal, plane.dist, surface->origin ); VectorCopy( surface->origin, camera->origin ); VectorSubtract( vec3_origin, surface->axis[ 0 ], camera->axis[ 0 ] ); @@ -1333,11 +1344,6 @@ static bool R_GetPortalOrientations( drawSurf_t *drawSurf, orientation_t *surfac return true; } - // project the origin onto the surface plane to get - // an origin point we can rotate around - d = DotProduct( e->e.origin, plane.normal ) - plane.dist; - VectorMA( e->e.origin, -d, surface->axis[ 0 ], surface->origin ); - // now get the camera origin and orientation VectorCopy( e->e.oldorigin, camera->origin ); AxisCopy( e->e.axis, camera->axis ); @@ -1865,6 +1871,9 @@ static bool R_MirrorViewBySurface(drawSurf_t *drawSurf) { return false; // bad portal, no portalentity } + if ( newParms.isMirror ) { + newParms.mirrorLevel++; + } // draw stencil mask R_AddPreparePortalCmd( drawSurf ); diff --git a/src/engine/renderer/tr_shade.cpp b/src/engine/renderer/tr_shade.cpp index c5d19ac8b5..a6db45aeae 100644 --- a/src/engine/renderer/tr_shade.cpp +++ b/src/engine/renderer/tr_shade.cpp @@ -2876,6 +2876,67 @@ void Tess_StageIteratorGeneric() } } + +void Tess_StageIteratorPortal() { + int stage; + + // log this call + if ( r_logFile->integer ) { + // don't just call LogComment, or we will get + // a call to va() every frame! + GLimp_LogComment( va + ( "--- Tess_StageIteratorPortal( %s, %i vertices, %i triangles ) ---\n", tess.surfaceShader->name, + tess.numVertexes, tess.numIndexes / 3 ) ); + } + + GL_CheckErrors(); + + if ( !glState.currentVBO || !glState.currentIBO || glState.currentVBO == tess.vbo || glState.currentIBO == tess.ibo ) { + Tess_UpdateVBOs(); + } + + // set face culling appropriately + if ( backEnd.currentEntity->e.renderfx & RF_SWAPCULL ) + GL_Cull( ReverseCull( tess.surfaceShader->cullType ) ); + else + GL_Cull( tess.surfaceShader->cullType ); + + // call shader function + for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ ) { + shaderStage_t* pStage = tess.surfaceStages[stage]; + + if ( !pStage ) { + break; + } + + if ( !RB_EvalExpression( &pStage->ifExp, 1.0 ) ) { + continue; + } + + switch ( pStage->type ) { + case stageType_t::ST_COLORMAP: + case stageType_t::ST_LIGHTMAP: + case stageType_t::ST_DIFFUSEMAP: + case stageType_t::ST_COLLAPSE_lighting_PHONG: + case stageType_t::ST_COLLAPSE_lighting_PBR: + case stageType_t::ST_COLLAPSE_reflection_CB: + case stageType_t::ST_REFLECTIONMAP: + case stageType_t::ST_REFRACTIONMAP: + case stageType_t::ST_DISPERSIONMAP: + case stageType_t::ST_SKYBOXMAP: + case stageType_t::ST_SCREENMAP: + case stageType_t::ST_PORTALMAP: + case stageType_t::ST_HEATHAZEMAP: + case stageType_t::ST_LIQUIDMAP: + Render_generic( pStage ); + return; + + default: + break; + } + } +} + void Tess_StageIteratorDepthFill() { int stage;