Skip to content

Commit

Permalink
Fix portal surface blending, entity selection and recursive chains wi…
Browse files Browse the repository at this point in the history
…th mirrors

Fixes portal blending with portal surfaces, misc_portal_surface entity selection and GL_FrontFace for mirrors in chains of recursive portals/mirrors. Fixes #1011. Disables the 64qu distance limit for portal entities which wasn't working properly anyway.

We only need to render one stage for portal surfaces in depth and stencil passes, so render the first one available in Tess_StageIteratorPortal(). Don't compute color and texMatrices since we don't use those at this stage.
  • Loading branch information
VReaperV committed Jan 19, 2024
1 parent 83a165d commit bf333c6
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 28 deletions.
29 changes: 21 additions & 8 deletions src/engine/renderer/tr_backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
}
Expand Down Expand Up @@ -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();
Expand All @@ -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();
Expand Down Expand Up @@ -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 ) {
Expand Down
2 changes: 2 additions & 0 deletions src/engine/renderer/tr_local.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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();
Expand Down
49 changes: 29 additions & 20 deletions src/engine/renderer/tr_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 ] );
Expand All @@ -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 );
Expand Down Expand Up @@ -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 );
Expand Down
61 changes: 61 additions & 0 deletions src/engine/renderer/tr_shade.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit bf333c6

Please sign in to comment.