@@ -1255,24 +1255,22 @@ entityNum is the entity that the portal surface is a part of, which may
12551255be moving and rotating.
12561256
12571257Returns true if it should be mirrored
1258-
1259- PRECONDITION: tess.verts/indexes are populated with the surface data
12601258=================
12611259*/
12621260static bool R_GetPortalOrientations ( drawSurf_t *drawSurf, orientation_t *surface, orientation_t *camera, vec3_t pvsOrigin,
12631261 bool *mirror, vec3_t *outOrigin, vec3_t *outAxis )
12641262{
12651263 cplane_t originalPlane, plane;
12661264
1267- ASSERT ( tess.numVertexes && tess.numIndexes );
1268-
12691265 // create plane axis for the portal we are seeing
12701266 R_PlaneForSurface ( drawSurf->surface , &originalPlane );
12711267
12721268 // rotate the plane if necessary
1269+ vec3_t portalCenter;
12731270 if ( drawSurf->entity != &tr.worldEntity )
12741271 {
12751272 tr.currentEntity = drawSurf->entity ;
1273+ VectorCopy ( drawSurf->entity ->e .origin , portalCenter );
12761274
12771275 // get the orientation of the entity
12781276 R_RotateEntityForViewParms ( tr.currentEntity , &tr.viewParms , &tr.orientation );
@@ -1284,6 +1282,7 @@ static bool R_GetPortalOrientations( drawSurf_t *drawSurf, orientation_t *surfac
12841282 }
12851283 else
12861284 {
1285+ VectorCopy ( tr.world ->portals [drawSurf->portalNum ].origin , portalCenter );
12871286 plane = originalPlane;
12881287 }
12891288
@@ -1294,12 +1293,6 @@ static bool R_GetPortalOrientations( drawSurf_t *drawSurf, orientation_t *surfac
12941293 // locate the portal entity closest to this plane.
12951294 // origin will be the origin of the portal, origin2 will be
12961295 // the origin of the camera
1297- vec3_t portalCenter{ 0.0 , 0.0 , 0.0 };
1298- for ( uint32_t vertIndex = 0 ; vertIndex < tess.numVertexes ; vertIndex++ ) {
1299- VectorAdd ( portalCenter, tess.verts [vertIndex].xyz , portalCenter );
1300- }
1301- VectorScale ( portalCenter, 1.0 / tess.numVertexes , portalCenter );
1302-
13031296 trRefEntity_t* currentPortal = nullptr ;
13041297 trRefEntity_t* e;
13051298 float minDistance = FLT_MAX;
@@ -1316,9 +1309,6 @@ static bool R_GetPortalOrientations( drawSurf_t *drawSurf, orientation_t *surfac
13161309 currentPortal = e;
13171310 }
13181311 }
1319- if ( drawSurf->entity != &tr.worldEntity ) {
1320- VectorAdd ( portalCenter, drawSurf->entity ->e .origin , portalCenter );
1321- }
13221312
13231313 if ( currentPortal ) {
13241314 // project the origin onto the surface plane to get
@@ -1523,8 +1513,6 @@ static bool IsMirror( const drawSurf_t *drawSurf )
15231513** 0 = on screen, in range
15241514** 1 = on screen, out of range
15251515** 2 = off screen
1526- **
1527- ** Note: caller must clear tess data afterward
15281516*/
15291517int PortalOffScreenOrOutOfRange ( const drawSurf_t *drawSurf, screenRect_t& surfRect )
15301518{
@@ -1538,64 +1526,58 @@ int PortalOffScreenOrOutOfRange( const drawSurf_t *drawSurf, screenRect_t& surfR
15381526 tr.currentEntity = drawSurf->entity ;
15391527
15401528 // rotate if necessary
1541- if ( tr. currentEntity != &tr. worldEntity )
1542- {
1543- R_RotateEntityForViewParms ( tr.currentEntity , &tr. viewParms , &tr. orientation );
1544- }
1545- else
1546- {
1529+ AABB aabb;
1530+ if ( tr. currentEntity != &tr. worldEntity ) {
1531+ VectorCopy ( tr.currentEntity -> e . origin , aabb. origin );
1532+ VectorCopy ( tr. currentEntity -> localBounds [ 0 ], aabb. mins );
1533+ VectorCopy ( tr. currentEntity -> localBounds [ 1 ], aabb. maxs );
1534+ } else {
15471535 tr.orientation = tr.viewParms .world ;
1536+ VectorCopy ( tr.world ->portals [drawSurf->portalNum ].origin , aabb.origin );
1537+ VectorCopy ( tr.world ->portals [drawSurf->portalNum ].mins , aabb.mins );
1538+ VectorCopy ( tr.world ->portals [drawSurf->portalNum ].maxs , aabb.maxs );
15481539 }
15491540
1550- if ( glConfig.smpActive )
1551- {
1552- // https://github.com/DaemonEngine/Daemon/issues/1216
1553- Log::Warn ( " portals are not compatible with r_smp" );
1554- return 1 ;
1555- }
1556-
1557- // Try to do tessellation CPU-side... won't work for static VBO surfaces
1558- // (https://github.com/DaemonEngine/Daemon/issues/1199)
1559- R_BindNullVBO ();
1560- Tess_MapVBOs ( /* forceCPU=*/ true );
1561- Tess_Begin ( Tess_StageIteratorDummy, drawSurf->shader , nullptr , true , -1 , 0 );
1562- rb_surfaceTable[Util::ordinal ( *( drawSurf->surface ) )]( drawSurf->surface );
1563-
1564- if ( tess.numVertexes <= 0 || tess.numIndexes <= 0 || glState.currentVBO != nullptr )
1565- {
1566- Log::Warn ( " failed to generate portal vertices" );
1567- return 1 ;
1541+ if ( drawSurf->portalNum == -1 ) {
1542+ return 0 ;
15681543 }
15691544
15701545 screenRect_t newRect;
1571- Vector4Set (newRect.coords , 999999 , 999999 , -999999 , -999999 );
1546+ Vector4Set ( newRect.coords , 999999 , 999999 , -999999 , -999999 );
15721547
15731548 uint32_t pointOr = 0 ;
15741549 uint32_t pointAnd = ( uint32_t ) ~0 ;
1575- for ( uint32_t i = 0 ; i < tess.numVertexes ; i++ )
1576- {
1550+
1551+ // TODO: Can we just drop the scissor test here? Then we could simply do R_CullBox()
1552+ vec3_t verts[8 ];
1553+ VectorCopy ( aabb.mins , verts[0 ] );
1554+ VectorSet ( verts[1 ], aabb.maxs [0 ], aabb.mins [1 ], aabb.mins [2 ] );
1555+ VectorSet ( verts[2 ], aabb.mins [0 ], aabb.maxs [1 ], aabb.mins [2 ] );
1556+ VectorSet ( verts[3 ], aabb.maxs [0 ], aabb.maxs [1 ], aabb.mins [2 ] );
1557+ VectorCopy ( aabb.maxs , verts[4 ] );
1558+ VectorSet ( verts[5 ], aabb.maxs [0 ], aabb.mins [1 ], aabb.maxs [2 ] );
1559+ VectorSet ( verts[6 ], aabb.mins [0 ], aabb.maxs [1 ], aabb.maxs [2 ] );
1560+ VectorSet ( verts[7 ], aabb.maxs [0 ], aabb.maxs [1 ], aabb.maxs [2 ] );
1561+
1562+ for ( uint32_t i = 0 ; i < 8 ; i++ ) {
15771563 uint32_t pointFlags = 0 ;
15781564 vec4_t normalized;
15791565 vec4_t window;
15801566
15811567 vec4_t clip, eye;
1582- R_TransformModelToClip ( tess. verts [ i ]. xyz , tr.orientation .modelViewMatrix , tr.viewParms .projectionMatrix , eye, clip );
1568+ R_TransformModelToClip ( verts[i] , tr.orientation .modelViewMatrix , tr.viewParms .projectionMatrix , eye, clip );
15831569
1584- R_TransformClipToWindow (clip, &tr.viewParms , normalized, window);
1570+ R_TransformClipToWindow ( clip, &tr.viewParms , normalized, window );
15851571
1586- newRect.coords [0 ] = std::min (newRect.coords [0 ], (int ) window[0 ]);
1587- newRect.coords [1 ] = std::min (newRect.coords [1 ], (int ) window[1 ]);
1588- newRect.coords [2 ] = std::max (newRect.coords [2 ], (int ) window[0 ]);
1589- newRect.coords [3 ] = std::max (newRect.coords [3 ], (int ) window[1 ]);
1572+ newRect.coords [0 ] = std::min ( newRect.coords [0 ], ( int ) window[0 ] );
1573+ newRect.coords [1 ] = std::min ( newRect.coords [1 ], ( int ) window[1 ] );
1574+ newRect.coords [2 ] = std::max ( newRect.coords [2 ], ( int ) window[0 ] );
1575+ newRect.coords [3 ] = std::max ( newRect.coords [3 ], ( int ) window[1 ] );
15901576
1591- for ( int j = 0 ; j < 3 ; j++ )
1592- {
1593- if ( clip[ j ] >= clip[ 3 ] )
1594- {
1577+ for ( int j = 0 ; j < 3 ; j++ ) {
1578+ if ( clip[j] >= clip[3 ] ) {
15951579 pointFlags |= ( 1 << ( j * 2 ) );
1596- }
1597- else if ( clip[ j ] <= -clip[ 3 ] )
1598- {
1580+ } else if ( clip[j] <= -clip[3 ] ) {
15991581 pointFlags |= ( 1 << ( j * 2 + 1 ) );
16001582 }
16011583 }
@@ -1606,69 +1588,27 @@ int PortalOffScreenOrOutOfRange( const drawSurf_t *drawSurf, screenRect_t& surfR
16061588
16071589 // if the surface intersects the near plane, then expand the scissor rect to cover the screen because of back projection
16081590 // OPTIMIZE: can be avoided by clipping triangle edges with the near plane
1609- if (pointOr & 0x20 )
1610- {
1591+ if ( pointOr & 0x20 ) {
16111592 newRect = parentRect;
16121593 }
16131594
1614- surfRect.coords [0 ] = std::max (newRect.coords [0 ], surfRect.coords [0 ]);
1615- surfRect.coords [1 ] = std::max (newRect.coords [1 ], surfRect.coords [1 ]);
1616- surfRect.coords [2 ] = std::min (newRect.coords [2 ], surfRect.coords [2 ]);
1617- surfRect.coords [3 ] = std::min (newRect.coords [3 ], surfRect.coords [3 ]);
1595+ surfRect.coords [0 ] = std::max ( newRect.coords [0 ], surfRect.coords [0 ] );
1596+ surfRect.coords [1 ] = std::max ( newRect.coords [1 ], surfRect.coords [1 ] );
1597+ surfRect.coords [2 ] = std::min ( newRect.coords [2 ], surfRect.coords [2 ] );
1598+ surfRect.coords [3 ] = std::min ( newRect.coords [3 ], surfRect.coords [3 ] );
16181599
16191600 // trivially reject
1620- if ( pointAnd )
1621- {
1622- return 2 ;
1623- }
1624-
1625- // determine if this surface is backfaced and also determine the distance
1626- // to the nearest vertex so we can cull based on portal range. Culling
1627- // based on vertex distance isn't 100% correct (we should be checking for
1628- // range to the surface), but it's good enough for the types of portals
1629- // we have in the game right now.
1630- uint32_t numTriangles = tess.numIndexes / 3 ;
1631-
1632- float shortest = FLT_MAX;
1633- for ( uint32_t i = 0 ; i < tess.numIndexes ; i += 3 )
1634- {
1635- vec3_t normal;
1636- vec3_t qnormal;
1637-
1638- VectorSubtract ( tess.verts [ tess.indexes [ i ] ].xyz , tr.viewParms .pvsOrigin , normal );
1639- if ( tr.currentEntity != &tr.worldEntity ) {
1640- VectorAdd ( normal, tr.currentEntity ->e .origin , normal );
1641- }
1642-
1643- float len = VectorLengthSquared ( normal );
1644-
1645- if ( len < shortest )
1646- {
1647- shortest = len;
1648- }
1649-
1650- R_QtangentsToNormal ( tess.verts [ tess.indexes [ i ] ].qtangents , qnormal );
1651-
1652- if ( ( DotProduct ( normal, qnormal ) ) >= 0 )
1653- {
1654- numTriangles--;
1655- }
1656- }
1657-
1658- if ( !numTriangles )
1659- {
1601+ if ( pointAnd ) {
16601602 return 2 ;
16611603 }
16621604
16631605 // mirrors can early out at this point, since we don't do a fade over distance
16641606 // with them (although we could)
1665- if ( IsMirror ( drawSurf ) )
1666- {
1607+ if ( IsMirror ( drawSurf ) ) {
16671608 return 0 ;
16681609 }
16691610
1670- if ( shortest > ( tess.surfaceShader ->portalRange * tess.surfaceShader ->portalRange ) )
1671- {
1611+ if ( Distance ( tr.viewParms .pvsOrigin , aabb.origin ) > ( drawSurf->shader ->portalRange * drawSurf->shader ->portalRange ) ) {
16721612 return 1 ;
16731613 }
16741614
@@ -1803,7 +1743,6 @@ bool R_MirrorViewBySurface(drawSurf_t *drawSurf)
18031743 DAEMON_FALLTHROUGH;
18041744
18051745 case 2 :
1806- Tess_Clear ();
18071746 return false ;
18081747 }
18091748
@@ -1812,7 +1751,6 @@ bool R_MirrorViewBySurface(drawSurf_t *drawSurf)
18121751 bool foundPortal = R_GetPortalOrientations (
18131752 drawSurf, &surface, &camera, newParms.pvsOrigin , &newParms.isMirror ,
18141753 &newParms.orientation .origin , newParms.orientation .axis );
1815- Tess_Clear ();
18161754
18171755 if ( !foundPortal )
18181756 {
@@ -1912,7 +1850,7 @@ int R_SpriteFogNum( trRefEntity_t *ent )
19121850R_AddDrawSurf
19131851=================
19141852*/
1915- int R_AddDrawSurf ( surfaceType_t *surface, shader_t *shader, int lightmapNum, int fogNum, bool bspSurface )
1853+ int R_AddDrawSurf ( surfaceType_t *surface, shader_t *shader, int lightmapNum, int fogNum, bool bspSurface, int portalNum )
19161854{
19171855 // instead of checking for overflow, we just mask the index
19181856 // so it wraps around
@@ -1926,6 +1864,7 @@ int R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, int lightmapNum, in
19261864 drawSurf->shader = shader;
19271865 drawSurf->bspSurface = bspSurface;
19281866 drawSurf->fog = fogNum;
1867+ drawSurf->portalNum = portalNum;
19291868
19301869 int entityNum;
19311870
0 commit comments