//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //===========================================================================// #include "tier2/beamsegdraw.h" #include "materialsystem/imaterialvar.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" //----------------------------------------------------------------------------- // // CBeamSegDraw implementation. // //----------------------------------------------------------------------------- void CBeamSegDraw::Start( IMatRenderContext *pRenderContext, int nSegs, IMaterial *pMaterial, CMeshBuilder *pMeshBuilder, int nMeshVertCount ) { m_pRenderContext = pRenderContext; Assert( nSegs >= 2 ); m_nSegsDrawn = 0; m_nTotalSegs = nSegs; if ( pMeshBuilder ) { m_pMeshBuilder = pMeshBuilder; m_nMeshVertCount = nMeshVertCount; } else { m_pMeshBuilder = NULL; m_nMeshVertCount = 0; IMesh *pMesh = m_pRenderContext->GetDynamicMesh( true, NULL, NULL, pMaterial ); m_Mesh.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, (nSegs-1) * 2 ); } } inline void CBeamSegDraw::ComputeNormal( const Vector &vecCameraPos, const Vector &vStartPos, const Vector &vNextPos, Vector *pNormal ) { // vTangentY = line vector for beam Vector vTangentY; VectorSubtract( vStartPos, vNextPos, vTangentY ); // vDirToBeam = vector from viewer origin to beam Vector vDirToBeam; VectorSubtract( vStartPos, vecCameraPos, vDirToBeam ); // Get a vector that is perpendicular to us and perpendicular to the beam. // This is used to fatten the beam. CrossProduct( vTangentY, vDirToBeam, *pNormal ); VectorNormalizeFast( *pNormal ); } inline void CBeamSegDraw::SpecifySeg( const Vector &vecCameraPos, const Vector &vNormal ) { // SUCKY: Need to do a fair amount more work to get the tangent owing to the averaged normal Vector vDirToBeam, vTangentY; VectorSubtract( m_Seg.m_vPos, vecCameraPos, vDirToBeam ); CrossProduct( vDirToBeam, vNormal, vTangentY ); VectorNormalizeFast( vTangentY ); // Build the endpoints. Vector vPoint1, vPoint2; VectorMA( m_Seg.m_vPos, m_Seg.m_flWidth*0.5f, vNormal, vPoint1 ); VectorMA( m_Seg.m_vPos, -m_Seg.m_flWidth*0.5f, vNormal, vPoint2 ); if ( m_pMeshBuilder ) { // Specify the points. m_pMeshBuilder->Position3fv( vPoint1.Base() ); m_pMeshBuilder->Color4f( VectorExpand( m_Seg.m_vColor ), m_Seg.m_flAlpha ); m_pMeshBuilder->TexCoord2f( 0, 0, m_Seg.m_flTexCoord ); m_pMeshBuilder->TexCoord2f( 1, 0, m_Seg.m_flTexCoord ); m_pMeshBuilder->TangentS3fv( vNormal.Base() ); m_pMeshBuilder->TangentT3fv( vTangentY.Base() ); m_pMeshBuilder->AdvanceVertex(); m_pMeshBuilder->Position3fv( vPoint2.Base() ); m_pMeshBuilder->Color4f( VectorExpand( m_Seg.m_vColor ), m_Seg.m_flAlpha ); m_pMeshBuilder->TexCoord2f( 0, 1, m_Seg.m_flTexCoord ); m_pMeshBuilder->TexCoord2f( 1, 1, m_Seg.m_flTexCoord ); m_pMeshBuilder->TangentS3fv( vNormal.Base() ); m_pMeshBuilder->TangentT3fv( vTangentY.Base() ); m_pMeshBuilder->AdvanceVertex(); if ( m_nSegsDrawn > 1 ) { int nBase = ( ( m_nSegsDrawn - 2 ) * 2 ) + m_nMeshVertCount; m_pMeshBuilder->FastIndex( nBase ); m_pMeshBuilder->FastIndex( nBase + 1 ); m_pMeshBuilder->FastIndex( nBase + 2 ); m_pMeshBuilder->FastIndex( nBase + 1 ); m_pMeshBuilder->FastIndex( nBase + 3 ); m_pMeshBuilder->FastIndex( nBase + 2 ); } } else { // Specify the points. m_Mesh.Position3fv( vPoint1.Base() ); m_Mesh.Color4f( VectorExpand( m_Seg.m_vColor ), m_Seg.m_flAlpha ); m_Mesh.TexCoord2f( 0, 0, m_Seg.m_flTexCoord ); m_Mesh.TexCoord2f( 1, 0, m_Seg.m_flTexCoord ); m_Mesh.TangentS3fv( vNormal.Base() ); m_Mesh.TangentT3fv( vTangentY.Base() ); m_Mesh.AdvanceVertex(); m_Mesh.Position3fv( vPoint2.Base() ); m_Mesh.Color4f( VectorExpand( m_Seg.m_vColor ), m_Seg.m_flAlpha ); m_Mesh.TexCoord2f( 0, 1, m_Seg.m_flTexCoord ); m_Mesh.TexCoord2f( 1, 1, m_Seg.m_flTexCoord ); m_Mesh.TangentS3fv( vNormal.Base() ); m_Mesh.TangentT3fv( vTangentY.Base() ); m_Mesh.AdvanceVertex(); } } void CBeamSegDraw::NextSeg( BeamSeg_t *pSeg ) { Vector vecCameraPos; m_pRenderContext->GetWorldSpaceCameraPosition( &vecCameraPos ); if ( m_nSegsDrawn > 0 ) { // Get a vector that is perpendicular to us and perpendicular to the beam. // This is used to fatten the beam. Vector vNormal, vAveNormal; ComputeNormal( vecCameraPos, m_Seg.m_vPos, pSeg->m_vPos, &vNormal ); if ( m_nSegsDrawn > 1 ) { // Average this with the previous normal VectorAdd( vNormal, m_vNormalLast, vAveNormal ); vAveNormal *= 0.5f; VectorNormalizeFast( vAveNormal ); } else { vAveNormal = vNormal; } m_vNormalLast = vNormal; SpecifySeg( vecCameraPos, vAveNormal ); } m_Seg = *pSeg; ++m_nSegsDrawn; if( m_nSegsDrawn == m_nTotalSegs ) { SpecifySeg( vecCameraPos, m_vNormalLast ); } } void CBeamSegDraw::End() { if ( m_pMeshBuilder ) { m_pMeshBuilder = NULL; return; } m_Mesh.End( false, true ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CBeamSegDrawArbitrary::SetNormal( const Vector &normal ) { m_vNormalLast = normal; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CBeamSegDrawArbitrary::NextSeg( BeamSeg_t *pSeg ) { if ( m_nSegsDrawn > 0 ) { Vector segDir = ( m_PrevSeg.m_vPos - pSeg->m_vPos ); VectorNormalize( segDir ); Vector normal = CrossProduct( segDir, m_vNormalLast ); SpecifySeg( normal ); } m_PrevSeg = m_Seg; m_Seg = *pSeg; ++m_nSegsDrawn; } //----------------------------------------------------------------------------- // Purpose: // Input : &vNextPos - //----------------------------------------------------------------------------- void CBeamSegDrawArbitrary::SpecifySeg( const Vector &vNormal ) { // Build the endpoints. Vector vPoint1, vPoint2; Vector vDelta; VectorMultiply( vNormal, m_Seg.m_flWidth*0.5f, vDelta ); VectorAdd( m_Seg.m_vPos, vDelta, vPoint1 ); VectorSubtract( m_Seg.m_vPos, vDelta, vPoint2 ); // Specify the points. Assert( IsFinite(m_Seg.m_vColor.x) && IsFinite(m_Seg.m_vColor.y) && IsFinite(m_Seg.m_vColor.z) && IsFinite(m_Seg.m_flAlpha) ); Assert( (m_Seg.m_vColor.x >= 0.0) && (m_Seg.m_vColor.y >= 0.0) && (m_Seg.m_vColor.z >= 0.0) && (m_Seg.m_flAlpha >= 0.0) ); Assert( (m_Seg.m_vColor.x <= 1.0) && (m_Seg.m_vColor.y <= 1.0) && (m_Seg.m_vColor.z <= 1.0) && (m_Seg.m_flAlpha <= 1.0) ); unsigned char r = FastFToC( m_Seg.m_vColor.x ); unsigned char g = FastFToC( m_Seg.m_vColor.y ); unsigned char b = FastFToC( m_Seg.m_vColor.z ); unsigned char a = FastFToC( m_Seg.m_flAlpha ); m_Mesh.Position3fv( vPoint1.Base() ); m_Mesh.Color4ub( r, g, b, a ); m_Mesh.TexCoord2f( 0, 0, m_Seg.m_flTexCoord ); m_Mesh.TexCoord2f( 1, 0, m_Seg.m_flTexCoord ); m_Mesh.AdvanceVertex(); m_Mesh.Position3fv( vPoint2.Base() ); m_Mesh.Color4ub( r, g, b, a ); m_Mesh.TexCoord2f( 0, 1, m_Seg.m_flTexCoord ); m_Mesh.TexCoord2f( 1, 1, m_Seg.m_flTexCoord ); m_Mesh.AdvanceVertex(); }