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.
279 lines
8.1 KiB
279 lines
8.1 KiB
//========= Copyright © 1996-2005, 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;
|
|
}
|
|
|
|
// Returns true if clipping took place.
|
|
// Outputs two polygons: One for each side of the plane
|
|
void ProjectPortalPolyToPlane( PortalMeshPoint_t *pInVerts, int nVertCount,
|
|
const Vector& normal, float flDist, const Vector &vCameraPos )
|
|
{
|
|
for ( int i = 0; i < nVertCount; i++ )
|
|
{
|
|
// project point onto plane
|
|
Vector vDir( pInVerts[i].vWorldSpacePosition - vCameraPos );
|
|
float flT = ( flDist - DotProduct( vCameraPos, normal ) ) / DotProduct( vDir, normal );
|
|
pInVerts[i].vWorldSpacePosition = vCameraPos + flT * vDir;
|
|
|
|
/*
|
|
double dirx, diry, dirz;
|
|
dirx = pInVerts[i].vWorldSpacePosition.x - vCameraPos.x;
|
|
diry = pInVerts[i].vWorldSpacePosition.y - vCameraPos.y;
|
|
dirz = pInVerts[i].vWorldSpacePosition.z - vCameraPos.z;
|
|
double dot1 = vCameraPos.x * normal.x + vCameraPos.y * normal.y + vCameraPos.z * normal.z;
|
|
double dot2 = dirx * normal.x + diry * normal.y + dirz * normal.z;
|
|
double flT2 = ( double( flDist ) - dot1 ) / dot2;
|
|
pInVerts[i].vWorldSpacePosition.x = double( vCameraPos.x ) + flT2 * dirx;
|
|
pInVerts[i].vWorldSpacePosition.y = double( vCameraPos.y ) + flT2 * diry;
|
|
pInVerts[i].vWorldSpacePosition.z = double( vCameraPos.z ) + flT2 * dirz;
|
|
*/
|
|
}
|
|
}
|
|
|
|
// Clips a convex poly to a single plane
|
|
bool ClipPortalPolyToPlane( PortalMeshPoint_t *pInVerts, int nVertCount,
|
|
PortalMeshPoint_t *pFrontVerts, int *pFrontVertCount,
|
|
const Vector& normal, float flDist )
|
|
{
|
|
if ( nVertCount < 3 )
|
|
{
|
|
*pFrontVertCount = 0;
|
|
return false;
|
|
}
|
|
|
|
float *dists = (float *)stackalloc( sizeof(float) * nVertCount );
|
|
int *sides = (int *)stackalloc( sizeof(int) * nVertCount );
|
|
int count[2] = { 0, 0 };
|
|
|
|
// determine sides for each point
|
|
for ( int i = 0; i < nVertCount; i++ )
|
|
{
|
|
float dot = DotProduct( pInVerts[i].vWorldSpacePosition, normal) - flDist;
|
|
dists[i] = dot;
|
|
sides[i] = ( dot >= 0.0f ) ? SIDE_FRONT : SIDE_BACK;
|
|
count[ sides[i] ]++;
|
|
}
|
|
|
|
// no need to clip anything
|
|
if ( count[0] == 0 )
|
|
{
|
|
*pFrontVertCount = 0;
|
|
return false;
|
|
}
|
|
|
|
int outCount1 = 0;
|
|
for ( int i = 0; i < nVertCount; i++ )
|
|
{
|
|
int i2 = ( i + 1 ) % nVertCount;
|
|
|
|
if ( sides[i] == SIDE_FRONT )
|
|
{
|
|
memcpy( &pFrontVerts[outCount1], &pInVerts[i], sizeof( PortalMeshPoint_t ) );
|
|
++outCount1;
|
|
|
|
}
|
|
if ( sides[i2] == sides[i] )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// generate a split point
|
|
float dot = dists[i] / ( dists[i] - dists[i2] );
|
|
|
|
Vector& p1 = pInVerts[i].vWorldSpacePosition;
|
|
Vector& p2 = pInVerts[i2].vWorldSpacePosition;
|
|
Vector midPt = p1 + dot * ( p2 - p1 );
|
|
|
|
Vector2D& uv1 = pInVerts[i].texCoord;
|
|
Vector2D& uv2 = pInVerts[i2].texCoord;
|
|
Vector2D midUv = uv1 + dot * ( uv2 - uv1 );
|
|
|
|
VectorCopy( midPt, pFrontVerts[outCount1].vWorldSpacePosition );
|
|
pFrontVerts[outCount1].texCoord = midUv;
|
|
|
|
++outCount1;
|
|
}
|
|
|
|
*pFrontVertCount = outCount1;
|
|
return true;
|
|
}
|
|
|
|
|
|
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 );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|