diff options
Diffstat (limited to 'game/client/portal/Portal_DynamicMeshRenderingUtils.cpp')
| -rw-r--r-- | game/client/portal/Portal_DynamicMeshRenderingUtils.cpp | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/game/client/portal/Portal_DynamicMeshRenderingUtils.cpp b/game/client/portal/Portal_DynamicMeshRenderingUtils.cpp new file mode 100644 index 0000000..f5b32fa --- /dev/null +++ b/game/client/portal/Portal_DynamicMeshRenderingUtils.cpp @@ -0,0 +1,183 @@ +//========= 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 ); +} + + + + + + + + + + + + + + |