Counter Strike : Global Offensive Source Code
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

  1. //========= Copyright � 1996-2005, 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. // Returns true if clipping took place.
  78. // Outputs two polygons: One for each side of the plane
  79. void ProjectPortalPolyToPlane( PortalMeshPoint_t *pInVerts, int nVertCount,
  80. const Vector& normal, float flDist, const Vector &vCameraPos )
  81. {
  82. for ( int i = 0; i < nVertCount; i++ )
  83. {
  84. // project point onto plane
  85. Vector vDir( pInVerts[i].vWorldSpacePosition - vCameraPos );
  86. float flT = ( flDist - DotProduct( vCameraPos, normal ) ) / DotProduct( vDir, normal );
  87. pInVerts[i].vWorldSpacePosition = vCameraPos + flT * vDir;
  88. /*
  89. double dirx, diry, dirz;
  90. dirx = pInVerts[i].vWorldSpacePosition.x - vCameraPos.x;
  91. diry = pInVerts[i].vWorldSpacePosition.y - vCameraPos.y;
  92. dirz = pInVerts[i].vWorldSpacePosition.z - vCameraPos.z;
  93. double dot1 = vCameraPos.x * normal.x + vCameraPos.y * normal.y + vCameraPos.z * normal.z;
  94. double dot2 = dirx * normal.x + diry * normal.y + dirz * normal.z;
  95. double flT2 = ( double( flDist ) - dot1 ) / dot2;
  96. pInVerts[i].vWorldSpacePosition.x = double( vCameraPos.x ) + flT2 * dirx;
  97. pInVerts[i].vWorldSpacePosition.y = double( vCameraPos.y ) + flT2 * diry;
  98. pInVerts[i].vWorldSpacePosition.z = double( vCameraPos.z ) + flT2 * dirz;
  99. */
  100. }
  101. }
  102. // Clips a convex poly to a single plane
  103. bool ClipPortalPolyToPlane( PortalMeshPoint_t *pInVerts, int nVertCount,
  104. PortalMeshPoint_t *pFrontVerts, int *pFrontVertCount,
  105. const Vector& normal, float flDist )
  106. {
  107. if ( nVertCount < 3 )
  108. {
  109. *pFrontVertCount = 0;
  110. return false;
  111. }
  112. float *dists = (float *)stackalloc( sizeof(float) * nVertCount );
  113. int *sides = (int *)stackalloc( sizeof(int) * nVertCount );
  114. int count[2] = { 0, 0 };
  115. // determine sides for each point
  116. for ( int i = 0; i < nVertCount; i++ )
  117. {
  118. float dot = DotProduct( pInVerts[i].vWorldSpacePosition, normal) - flDist;
  119. dists[i] = dot;
  120. sides[i] = ( dot >= 0.0f ) ? SIDE_FRONT : SIDE_BACK;
  121. count[ sides[i] ]++;
  122. }
  123. // no need to clip anything
  124. if ( count[0] == 0 )
  125. {
  126. *pFrontVertCount = 0;
  127. return false;
  128. }
  129. int outCount1 = 0;
  130. for ( int i = 0; i < nVertCount; i++ )
  131. {
  132. int i2 = ( i + 1 ) % nVertCount;
  133. if ( sides[i] == SIDE_FRONT )
  134. {
  135. memcpy( &pFrontVerts[outCount1], &pInVerts[i], sizeof( PortalMeshPoint_t ) );
  136. ++outCount1;
  137. }
  138. if ( sides[i2] == sides[i] )
  139. {
  140. continue;
  141. }
  142. // generate a split point
  143. float dot = dists[i] / ( dists[i] - dists[i2] );
  144. Vector& p1 = pInVerts[i].vWorldSpacePosition;
  145. Vector& p2 = pInVerts[i2].vWorldSpacePosition;
  146. Vector midPt = p1 + dot * ( p2 - p1 );
  147. Vector2D& uv1 = pInVerts[i].texCoord;
  148. Vector2D& uv2 = pInVerts[i2].texCoord;
  149. Vector2D midUv = uv1 + dot * ( uv2 - uv1 );
  150. VectorCopy( midPt, pFrontVerts[outCount1].vWorldSpacePosition );
  151. pFrontVerts[outCount1].texCoord = midUv;
  152. ++outCount1;
  153. }
  154. *pFrontVertCount = outCount1;
  155. return true;
  156. }
  157. void RenderPortalMeshConvexPolygon( PortalMeshPoint_t *pVerts, int iVertCount, const IMaterial *pMaterial, void *pBind )
  158. {
  159. CMatRenderContextPtr pRenderContext( materials );
  160. pRenderContext->Bind( (IMaterial *)pMaterial, pBind );
  161. //PortalMeshPoint_t *pMidVerts = (PortalMeshPoint_t *)stackalloc( sizeof( PortalMeshPoint_t ) * iVertCount );
  162. CMeshBuilder meshBuilder;
  163. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  164. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, iVertCount - 2 );
  165. //any convex polygon can be rendered with a triangle strip by starting at a vertex and alternating vertices from each side
  166. int iForwardCounter = 0;
  167. int iReverseCounter = iVertCount - 1; //guaranteed to be >= 2 to start
  168. do
  169. {
  170. PortalMeshPoint_t *pVertex = &pVerts[iForwardCounter];
  171. meshBuilder.Position3fv( &pVertex->vWorldSpacePosition.x );
  172. meshBuilder.TexCoord2fv( 0, &pVertex->texCoord.x );
  173. meshBuilder.AdvanceVertex();
  174. ++iForwardCounter;
  175. if( iForwardCounter > iReverseCounter )
  176. break;
  177. pVertex = &pVerts[iReverseCounter];
  178. meshBuilder.Position3fv( &pVertex->vWorldSpacePosition.x );
  179. meshBuilder.TexCoord2fv( 0, &pVertex->texCoord.x );
  180. meshBuilder.AdvanceVertex();
  181. --iReverseCounter;
  182. } while( iForwardCounter <= iReverseCounter );
  183. meshBuilder.End();
  184. pMesh->Draw();
  185. }
  186. void Clip_And_Render_Convex_Polygon( PortalMeshPoint_t *pVerts, int iVertCount, const IMaterial *pMaterial, void *pBind )
  187. {
  188. PortalMeshPoint_t *pInVerts = (PortalMeshPoint_t *)stackalloc( iVertCount * 4 * sizeof( PortalMeshPoint_t ) ); //really only should need 2x points, but I'm paranoid
  189. PortalMeshPoint_t *pOutVerts = (PortalMeshPoint_t *)stackalloc( iVertCount * 4 * sizeof( PortalMeshPoint_t ) );
  190. PortalMeshPoint_t *pTempVerts;
  191. //clip by the viewing frustum
  192. {
  193. VPlane *pFrustum = view->GetFrustum();
  194. //clip by first plane and put output into pInVerts
  195. iVertCount = ClipPolyToPlane_LerpTexCoords( pVerts, iVertCount, pInVerts, pFrustum[0].m_Normal, pFrustum[0].m_Dist, 0.01f );
  196. //clip by other planes and flipflop in and out pointers
  197. for( int i = 1; i != FRUSTUM_NUMPLANES; ++i )
  198. {
  199. if( iVertCount < 3 )
  200. return; //nothing to draw
  201. iVertCount = ClipPolyToPlane_LerpTexCoords( pInVerts, iVertCount, pOutVerts, pFrustum[i].m_Normal, pFrustum[i].m_Dist, 0.01f );
  202. pTempVerts = pInVerts; pInVerts = pOutVerts; pOutVerts = pTempVerts; //swap vertex pointers
  203. }
  204. if( iVertCount < 3 )
  205. return; //nothing to draw
  206. }
  207. CMatRenderContextPtr pRenderContext( materials );
  208. RenderPortalMeshConvexPolygon( pOutVerts, iVertCount, pMaterial, pBind );
  209. if( mat_wireframe.GetBool() )
  210. RenderPortalMeshConvexPolygon( pOutVerts, iVertCount, materials->FindMaterial( "shadertest/wireframe", TEXTURE_GROUP_CLIENT_EFFECTS, false ), pBind );
  211. stackfree( pOutVerts );
  212. stackfree( pInVerts );
  213. }