|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "Portal_DynamicMeshRenderingUtils.h"
#include "iviewrender.h"
extern ConVar mat_wireframe;
int ClipPolyToPlane_LerpTexCoords( PortalMeshPoint_t *inVerts, int vertCount, PortalMeshPoint_t *outVerts, const Vector& normal, float dist, float fOnPlaneEpsilon ) { vec_t *dists = (vec_t *)stackalloc( sizeof(vec_t) * vertCount * 4 ); //4x vertcount should cover all cases
int *sides = (int *)stackalloc( sizeof(int) * vertCount * 4 ); int counts[3]; vec_t dot; int i, j; Vector mid = vec3_origin; int outCount;
counts[0] = counts[1] = counts[2] = 0;
// determine sides for each point
for ( i = 0; i < vertCount; i++ ) { dot = DotProduct( inVerts[i].vWorldSpacePosition, normal) - dist; dists[i] = dot; if ( dot > fOnPlaneEpsilon ) sides[i] = SIDE_FRONT; else if ( dot < -fOnPlaneEpsilon ) sides[i] = SIDE_BACK; else sides[i] = SIDE_ON; counts[sides[i]]++; } sides[i] = sides[0]; dists[i] = dists[0];
if (!counts[0]) return 0;
if (!counts[1]) { // Copy to output verts
//for ( i = 0; i < vertCount; i++ )
memcpy( outVerts, inVerts, sizeof( PortalMeshPoint_t ) * vertCount ); return vertCount; }
outCount = 0; for ( i = 0; i < vertCount; i++ ) { if (sides[i] == SIDE_ON) { memcpy( &outVerts[outCount], &inVerts[i], sizeof( PortalMeshPoint_t ) ); ++outCount; continue; } if (sides[i] == SIDE_FRONT) { memcpy( &outVerts[outCount], &inVerts[i], sizeof( PortalMeshPoint_t ) ); ++outCount; } if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) continue;
Vector& p1 = inVerts[i].vWorldSpacePosition;
// generate a split point
int i2 = (i+1)%vertCount; Vector& p2 = inVerts[i2].vWorldSpacePosition; dot = dists[i] / (dists[i]-dists[i+1]); for (j=0 ; j<3 ; j++) { mid[j] = p1[j] + dot*(p2[j]-p1[j]); }
VectorCopy (mid, outVerts[outCount].vWorldSpacePosition); outVerts[outCount].texCoord.x = inVerts[i].texCoord.x + dot*(inVerts[i2].texCoord.x - inVerts[i].texCoord.x); outVerts[outCount].texCoord.y = inVerts[i].texCoord.y + dot*(inVerts[i2].texCoord.y - inVerts[i].texCoord.y); ++outCount; }
return outCount; }
void RenderPortalMeshConvexPolygon( PortalMeshPoint_t *pVerts, int iVertCount, const IMaterial *pMaterial, void *pBind ) { CMatRenderContextPtr pRenderContext( materials ); pRenderContext->Bind( (IMaterial *)pMaterial, pBind );
//PortalMeshPoint_t *pMidVerts = (PortalMeshPoint_t *)stackalloc( sizeof( PortalMeshPoint_t ) * iVertCount );
CMeshBuilder meshBuilder; IMesh* pMesh = pRenderContext->GetDynamicMesh( true ); meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, iVertCount - 2 );
//any convex polygon can be rendered with a triangle strip by starting at a vertex and alternating vertices from each side
int iForwardCounter = 0; int iReverseCounter = iVertCount - 1; //guaranteed to be >= 2 to start
do { PortalMeshPoint_t *pVertex = &pVerts[iForwardCounter]; meshBuilder.Position3fv( &pVertex->vWorldSpacePosition.x ); meshBuilder.TexCoord2fv( 0, &pVertex->texCoord.x ); meshBuilder.AdvanceVertex(); ++iForwardCounter;
if( iForwardCounter > iReverseCounter ) break;
pVertex = &pVerts[iReverseCounter]; meshBuilder.Position3fv( &pVertex->vWorldSpacePosition.x ); meshBuilder.TexCoord2fv( 0, &pVertex->texCoord.x ); meshBuilder.AdvanceVertex(); --iReverseCounter; } while( iForwardCounter <= iReverseCounter );
meshBuilder.End(); pMesh->Draw(); }
void Clip_And_Render_Convex_Polygon( PortalMeshPoint_t *pVerts, int iVertCount, const IMaterial *pMaterial, void *pBind ) { PortalMeshPoint_t *pInVerts = (PortalMeshPoint_t *)stackalloc( iVertCount * 4 * sizeof( PortalMeshPoint_t ) ); //really only should need 2x points, but I'm paranoid
PortalMeshPoint_t *pOutVerts = (PortalMeshPoint_t *)stackalloc( iVertCount * 4 * sizeof( PortalMeshPoint_t ) ); PortalMeshPoint_t *pTempVerts;
//clip by the viewing frustum
{ VPlane *pFrustum = view->GetFrustum(); //clip by first plane and put output into pInVerts
iVertCount = ClipPolyToPlane_LerpTexCoords( pVerts, iVertCount, pInVerts, pFrustum[0].m_Normal, pFrustum[0].m_Dist, 0.01f );
//clip by other planes and flipflop in and out pointers
for( int i = 1; i != FRUSTUM_NUMPLANES; ++i ) { if( iVertCount < 3 ) return; //nothing to draw
iVertCount = ClipPolyToPlane_LerpTexCoords( pInVerts, iVertCount, pOutVerts, pFrustum[i].m_Normal, pFrustum[i].m_Dist, 0.01f ); pTempVerts = pInVerts; pInVerts = pOutVerts; pOutVerts = pTempVerts; //swap vertex pointers
}
if( iVertCount < 3 ) return; //nothing to draw
}
CMatRenderContextPtr pRenderContext( materials ); RenderPortalMeshConvexPolygon( pOutVerts, iVertCount, pMaterial, pBind ); if( mat_wireframe.GetBool() ) RenderPortalMeshConvexPolygon( pOutVerts, iVertCount, materials->FindMaterial( "shadertest/wireframe", TEXTURE_GROUP_CLIENT_EFFECTS, false ), pBind );
stackfree( pOutVerts ); stackfree( pInVerts ); }
|