You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
183 lines
5.1 KiB
183 lines
5.1 KiB
//========= 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 ); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|