Team Fortress 2 Source Code as on 22/4/2020
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

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "Portal_DynamicMeshRenderingUtils.h"
  9. #include "iviewrender.h"
  10. extern ConVar mat_wireframe;
  11. int ClipPolyToPlane_LerpTexCoords( PortalMeshPoint_t *inVerts, int vertCount, PortalMeshPoint_t *outVerts, const Vector& normal, float dist, float fOnPlaneEpsilon )
  12. {
  13. vec_t *dists = (vec_t *)stackalloc( sizeof(vec_t) * vertCount * 4 ); //4x vertcount should cover all cases
  14. int *sides = (int *)stackalloc( sizeof(int) * vertCount * 4 );
  15. int counts[3];
  16. vec_t dot;
  17. int i, j;
  18. Vector mid = vec3_origin;
  19. int outCount;
  20. counts[0] = counts[1] = counts[2] = 0;
  21. // determine sides for each point
  22. for ( i = 0; i < vertCount; i++ )
  23. {
  24. dot = DotProduct( inVerts[i].vWorldSpacePosition, normal) - dist;
  25. dists[i] = dot;
  26. if ( dot > fOnPlaneEpsilon )
  27. sides[i] = SIDE_FRONT;
  28. else if ( dot < -fOnPlaneEpsilon )
  29. sides[i] = SIDE_BACK;
  30. else
  31. sides[i] = SIDE_ON;
  32. counts[sides[i]]++;
  33. }
  34. sides[i] = sides[0];
  35. dists[i] = dists[0];
  36. if (!counts[0])
  37. return 0;
  38. if (!counts[1])
  39. {
  40. // Copy to output verts
  41. //for ( i = 0; i < vertCount; i++ )
  42. memcpy( outVerts, inVerts, sizeof( PortalMeshPoint_t ) * vertCount );
  43. return vertCount;
  44. }
  45. outCount = 0;
  46. for ( i = 0; i < vertCount; i++ )
  47. {
  48. if (sides[i] == SIDE_ON)
  49. {
  50. memcpy( &outVerts[outCount], &inVerts[i], sizeof( PortalMeshPoint_t ) );
  51. ++outCount;
  52. continue;
  53. }
  54. if (sides[i] == SIDE_FRONT)
  55. {
  56. memcpy( &outVerts[outCount], &inVerts[i], sizeof( PortalMeshPoint_t ) );
  57. ++outCount;
  58. }
  59. if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
  60. continue;
  61. Vector& p1 = inVerts[i].vWorldSpacePosition;
  62. // generate a split point
  63. int i2 = (i+1)%vertCount;
  64. Vector& p2 = inVerts[i2].vWorldSpacePosition;
  65. dot = dists[i] / (dists[i]-dists[i+1]);
  66. for (j=0 ; j<3 ; j++)
  67. {
  68. mid[j] = p1[j] + dot*(p2[j]-p1[j]);
  69. }
  70. VectorCopy (mid, outVerts[outCount].vWorldSpacePosition);
  71. outVerts[outCount].texCoord.x = inVerts[i].texCoord.x + dot*(inVerts[i2].texCoord.x - inVerts[i].texCoord.x);
  72. outVerts[outCount].texCoord.y = inVerts[i].texCoord.y + dot*(inVerts[i2].texCoord.y - inVerts[i].texCoord.y);
  73. ++outCount;
  74. }
  75. return outCount;
  76. }
  77. void RenderPortalMeshConvexPolygon( PortalMeshPoint_t *pVerts, int iVertCount, const IMaterial *pMaterial, void *pBind )
  78. {
  79. CMatRenderContextPtr pRenderContext( materials );
  80. pRenderContext->Bind( (IMaterial *)pMaterial, pBind );
  81. //PortalMeshPoint_t *pMidVerts = (PortalMeshPoint_t *)stackalloc( sizeof( PortalMeshPoint_t ) * iVertCount );
  82. CMeshBuilder meshBuilder;
  83. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  84. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, iVertCount - 2 );
  85. //any convex polygon can be rendered with a triangle strip by starting at a vertex and alternating vertices from each side
  86. int iForwardCounter = 0;
  87. int iReverseCounter = iVertCount - 1; //guaranteed to be >= 2 to start
  88. do
  89. {
  90. PortalMeshPoint_t *pVertex = &pVerts[iForwardCounter];
  91. meshBuilder.Position3fv( &pVertex->vWorldSpacePosition.x );
  92. meshBuilder.TexCoord2fv( 0, &pVertex->texCoord.x );
  93. meshBuilder.AdvanceVertex();
  94. ++iForwardCounter;
  95. if( iForwardCounter > iReverseCounter )
  96. break;
  97. pVertex = &pVerts[iReverseCounter];
  98. meshBuilder.Position3fv( &pVertex->vWorldSpacePosition.x );
  99. meshBuilder.TexCoord2fv( 0, &pVertex->texCoord.x );
  100. meshBuilder.AdvanceVertex();
  101. --iReverseCounter;
  102. } while( iForwardCounter <= iReverseCounter );
  103. meshBuilder.End();
  104. pMesh->Draw();
  105. }
  106. void Clip_And_Render_Convex_Polygon( PortalMeshPoint_t *pVerts, int iVertCount, const IMaterial *pMaterial, void *pBind )
  107. {
  108. PortalMeshPoint_t *pInVerts = (PortalMeshPoint_t *)stackalloc( iVertCount * 4 * sizeof( PortalMeshPoint_t ) ); //really only should need 2x points, but I'm paranoid
  109. PortalMeshPoint_t *pOutVerts = (PortalMeshPoint_t *)stackalloc( iVertCount * 4 * sizeof( PortalMeshPoint_t ) );
  110. PortalMeshPoint_t *pTempVerts;
  111. //clip by the viewing frustum
  112. {
  113. VPlane *pFrustum = view->GetFrustum();
  114. //clip by first plane and put output into pInVerts
  115. iVertCount = ClipPolyToPlane_LerpTexCoords( pVerts, iVertCount, pInVerts, pFrustum[0].m_Normal, pFrustum[0].m_Dist, 0.01f );
  116. //clip by other planes and flipflop in and out pointers
  117. for( int i = 1; i != FRUSTUM_NUMPLANES; ++i )
  118. {
  119. if( iVertCount < 3 )
  120. return; //nothing to draw
  121. iVertCount = ClipPolyToPlane_LerpTexCoords( pInVerts, iVertCount, pOutVerts, pFrustum[i].m_Normal, pFrustum[i].m_Dist, 0.01f );
  122. pTempVerts = pInVerts; pInVerts = pOutVerts; pOutVerts = pTempVerts; //swap vertex pointers
  123. }
  124. if( iVertCount < 3 )
  125. return; //nothing to draw
  126. }
  127. CMatRenderContextPtr pRenderContext( materials );
  128. RenderPortalMeshConvexPolygon( pOutVerts, iVertCount, pMaterial, pBind );
  129. if( mat_wireframe.GetBool() )
  130. RenderPortalMeshConvexPolygon( pOutVerts, iVertCount, materials->FindMaterial( "shadertest/wireframe", TEXTURE_GROUP_CLIENT_EFFECTS, false ), pBind );
  131. stackfree( pOutVerts );
  132. stackfree( pInVerts );
  133. }