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.

341 lines
12 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //===========================================================================//
  7. #include "tier2/beamsegdraw.h"
  8. #include "materialsystem/imaterialvar.h"
  9. #include "convar.h"
  10. // memdbgon must be the last include file in a .cpp file!!!
  11. #include "tier0/memdbgon.h"
  12. //-----------------------------------------------------------------------------
  13. //
  14. // CBeamSegDraw implementation.
  15. //
  16. //-----------------------------------------------------------------------------
  17. void CBeamSegDraw::Start( IMatRenderContext *pRenderContext, int nSegs, IMaterial *pMaterial, CMeshBuilder *pMeshBuilder, int nMeshVertCount )
  18. {
  19. m_pRenderContext = pRenderContext;
  20. Assert( nSegs >= 2 );
  21. m_nSegsDrawn = 0;
  22. m_nTotalSegs = nSegs;
  23. m_pRenderContext->GetWorldSpaceCameraPosition( &m_vecCameraPos );
  24. if ( pMeshBuilder )
  25. {
  26. m_pMeshBuilder = pMeshBuilder;
  27. m_nMeshVertCount = nMeshVertCount;
  28. }
  29. else
  30. {
  31. m_pMeshBuilder = NULL;
  32. m_nMeshVertCount = 0;
  33. IMesh *pMesh = m_pRenderContext->GetDynamicMesh( true, NULL, NULL, pMaterial );
  34. m_Mesh.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, (nSegs-1) * 2 );
  35. }
  36. }
  37. inline void CBeamSegDraw::ComputeNormal( const Vector &vecCameraPos, const Vector &vStartPos, const Vector &vNextPos, Vector *pNormal )
  38. {
  39. // vTangentY = line vector for beam
  40. Vector vTangentY;
  41. VectorSubtract( vStartPos, vNextPos, vTangentY );
  42. // vDirToBeam = vector from viewer origin to beam
  43. Vector vDirToBeam;
  44. VectorSubtract( vStartPos, vecCameraPos, vDirToBeam );
  45. // Get a vector that is perpendicular to us and perpendicular to the beam.
  46. // This is used to fatten the beam.
  47. CrossProduct( vTangentY, vDirToBeam, *pNormal );
  48. VectorNormalizeFast( *pNormal );
  49. }
  50. inline void CBeamSegDraw::SpecifySeg( const Vector &vecCameraPos, const Vector &vNormal )
  51. {
  52. // SUCKY: Need to do a fair amount more work to get the tangent owing to the averaged normal
  53. Vector vDirToBeam, vTangentY;
  54. VectorSubtract( m_Seg.m_vPos, vecCameraPos, vDirToBeam );
  55. CrossProduct( vDirToBeam, vNormal, vTangentY );
  56. VectorNormalizeFast( vTangentY );
  57. // Build the endpoints.
  58. Vector vPoint1, vPoint2;
  59. VectorMA( m_Seg.m_vPos, m_Seg.m_flWidth*0.5f, vNormal, vPoint1 );
  60. VectorMA( m_Seg.m_vPos, -m_Seg.m_flWidth*0.5f, vNormal, vPoint2 );
  61. if ( m_pMeshBuilder )
  62. {
  63. // Specify the points.
  64. m_pMeshBuilder->Position3fv( vPoint1.Base() );
  65. m_pMeshBuilder->Color4ubv( (const unsigned char *) &m_Seg.m_color );
  66. m_pMeshBuilder->TexCoord2f( 0, 0, m_Seg.m_flTexCoord );
  67. m_pMeshBuilder->TexCoord2f( 1, 0, m_Seg.m_flTexCoord );
  68. m_pMeshBuilder->TangentS3fv( vNormal.Base() );
  69. m_pMeshBuilder->TangentT3fv( vTangentY.Base() );
  70. m_pMeshBuilder->AdvanceVertex();
  71. m_pMeshBuilder->Position3fv( vPoint2.Base() );
  72. m_pMeshBuilder->Color4ubv( (const unsigned char *) &m_Seg.m_color );
  73. m_pMeshBuilder->TexCoord2f( 0, 1, m_Seg.m_flTexCoord );
  74. m_pMeshBuilder->TexCoord2f( 1, 1, m_Seg.m_flTexCoord );
  75. m_pMeshBuilder->TangentS3fv( vNormal.Base() );
  76. m_pMeshBuilder->TangentT3fv( vTangentY.Base() );
  77. m_pMeshBuilder->AdvanceVertex();
  78. if ( m_nSegsDrawn > 1 )
  79. {
  80. int nBase = ( ( m_nSegsDrawn - 2 ) * 2 ) + m_nMeshVertCount;
  81. m_pMeshBuilder->FastIndex( nBase );
  82. m_pMeshBuilder->FastIndex( nBase + 1 );
  83. m_pMeshBuilder->FastIndex( nBase + 2 );
  84. m_pMeshBuilder->FastIndex( nBase + 1 );
  85. m_pMeshBuilder->FastIndex( nBase + 3 );
  86. m_pMeshBuilder->FastIndex( nBase + 2 );
  87. }
  88. }
  89. else
  90. {
  91. // Specify the points.
  92. m_Mesh.Position3fv( vPoint1.Base() );
  93. m_Mesh.Color4ubv( (const unsigned char *) &m_Seg.m_color );
  94. m_Mesh.TexCoord2f( 0, 0, m_Seg.m_flTexCoord );
  95. m_Mesh.TexCoord2f( 1, 0, m_Seg.m_flTexCoord );
  96. m_Mesh.TangentS3fv( vNormal.Base() );
  97. m_Mesh.TangentT3fv( vTangentY.Base() );
  98. m_Mesh.AdvanceVertex();
  99. m_Mesh.Position3fv( vPoint2.Base() );
  100. m_Mesh.Color4ubv( (const unsigned char *) &m_Seg.m_color );
  101. m_Mesh.TexCoord2f( 0, 1, m_Seg.m_flTexCoord );
  102. m_Mesh.TexCoord2f( 1, 1, m_Seg.m_flTexCoord );
  103. m_Mesh.TangentS3fv( vNormal.Base() );
  104. m_Mesh.TangentT3fv( vTangentY.Base() );
  105. m_Mesh.AdvanceVertex();
  106. }
  107. }
  108. void CBeamSegDraw::NextSeg( BeamSeg_t *pSeg )
  109. {
  110. if ( m_nSegsDrawn > 0 )
  111. {
  112. // Get a vector that is perpendicular to us and perpendicular to the beam.
  113. // This is used to fatten the beam.
  114. Vector vNormal, vAveNormal;
  115. ComputeNormal( m_vecCameraPos, m_Seg.m_vPos, pSeg->m_vPos, &vNormal );
  116. if ( m_nSegsDrawn > 1 )
  117. {
  118. // Average this with the previous normal
  119. VectorAdd( vNormal, m_vNormalLast, vAveNormal );
  120. vAveNormal *= 0.5f;
  121. VectorNormalizeFast( vAveNormal );
  122. }
  123. else
  124. {
  125. vAveNormal = vNormal;
  126. }
  127. m_vNormalLast = vNormal;
  128. SpecifySeg( m_vecCameraPos, vAveNormal );
  129. }
  130. m_Seg = *pSeg;
  131. ++m_nSegsDrawn;
  132. if( m_nSegsDrawn == m_nTotalSegs )
  133. {
  134. SpecifySeg( m_vecCameraPos, m_vNormalLast );
  135. }
  136. }
  137. void CBeamSegDraw::LoadSIMDData( FourVectors * RESTRICT pV4StartPos, FourVectors * RESTRICT pV4EndPos, FourVectors * RESTRICT pV4HalfWidth, int nV4SegCount, const BeamSeg_t * pSegs )
  138. {
  139. const BeamSeg_t *RESTRICT pCurSeg = pSegs;
  140. for ( int i = 0; i < nV4SegCount; ++i, pCurSeg+= 4 )
  141. {
  142. pV4StartPos[i].LoadAndSwizzleAligned( pCurSeg[0].m_vPos, pCurSeg[1].m_vPos, pCurSeg[2].m_vPos, pCurSeg[3].m_vPos );
  143. pV4EndPos[i].LoadAndSwizzleAligned( pCurSeg[1].m_vPos, pCurSeg[2].m_vPos, pCurSeg[3].m_vPos, pCurSeg[4].m_vPos );
  144. // load and broadcast the halfwidths
  145. // if you load from values in memory (rather than computed values in registers),
  146. // .Load is faster.
  147. pV4HalfWidth[i].Load( pCurSeg[0].m_flWidth , pCurSeg[1].m_flWidth , pCurSeg[2].m_flWidth , pCurSeg[3].m_flWidth );
  148. pV4HalfWidth[i] *= Four_PointFives;
  149. }
  150. }
  151. void CBeamSegDraw::ComputeRenderInfo( BeamSegRenderInfo_t * pRenderInfo, const Vector &vecCameraPos, int nSegCount, const BeamSeg_t *pSrcSegs ) RESTRICT
  152. {
  153. int nPaddedSegCount = ( ( nSegCount + 3 ) >> 2 ) << 2;
  154. // FIXME: Can we figure out a way of avoiding this extra copy?
  155. // NOTE: We need an extra one since LoadSIMDData will load off the end
  156. BeamSeg_t *pSegs = (BeamSeg_t*)stackalloc( ( nPaddedSegCount + 1 ) * sizeof(BeamSeg_t) );
  157. memcpy( pSegs, pSrcSegs, nSegCount * sizeof(BeamSeg_t) );
  158. int nEndSegCount = ( nPaddedSegCount - nSegCount + 1 );
  159. BeamSeg_t endCap = pSrcSegs[nSegCount-1];
  160. endCap.m_vPos += pSrcSegs[nSegCount-1].m_vPos - pSrcSegs[nSegCount-2].m_vPos;
  161. for ( int i = 0; i < nEndSegCount; ++i )
  162. {
  163. memcpy( &pSegs[nSegCount+i], &endCap, sizeof(BeamSeg_t) );
  164. }
  165. FourVectors v4CameraPos;
  166. v4CameraPos.LoadAndSwizzle( vecCameraPos );
  167. int nV4SegCount = nPaddedSegCount >> 2;
  168. FourVectors *pV4StartPos = (FourVectors*)stackalloc( nV4SegCount * sizeof(FourVectors) );
  169. FourVectors *pV4EndPos = (FourVectors*)stackalloc( nV4SegCount * sizeof(FourVectors) );
  170. FourVectors *pV4HalfWidth = (FourVectors*)stackalloc( nV4SegCount * sizeof(FourVectors) );
  171. FourVectors *pV4AveNormals = (FourVectors*)stackalloc( ( nV4SegCount + 2 ) * sizeof(FourVectors) );
  172. CBeamSegDraw::LoadSIMDData( pV4StartPos, pV4EndPos, pV4HalfWidth, nV4SegCount, pSegs );
  173. fltx4 v4LMask = { 0.25f, 0.25f, 0.25f, 0.0f };
  174. fltx4 v4LPrevMask = { 0.0f, 0.0f, 0.0f, 0.25f };
  175. fltx4 v4RMask = { 0.0f, 0.25f, 0.25f, 0.25f };
  176. fltx4 v4RNextMask = { 0.25f, 0.0f, 0.0f, 0.0f };
  177. fltx4 v4AveFactor = { 0.5f, 0.5f, 0.5f, 0.5f };
  178. // This is the only ones that need initial data are the first two
  179. memset( pV4AveNormals, 0, 2 * sizeof(FourVectors) );
  180. // Yes, that 1 is correct. We're going to write bogus crap on either end
  181. FourVectors eps( FLT_EPSILON );
  182. FourVectors *pV4CurAveNormal = &pV4AveNormals[1];
  183. for ( int i = 0; i < nV4SegCount; ++i, ++pV4CurAveNormal )
  184. {
  185. // prefetch
  186. PREFETCH360( pRenderInfo + (i << 2), 0 );
  187. PREFETCH360( pRenderInfo + (i << 2) + 1, 0 );
  188. FourVectors v4TangentY = pV4StartPos[i] - pV4EndPos[i];
  189. FourVectors v4CameraToStart = pV4StartPos[i] - v4CameraPos;
  190. FourVectors v4Normal = v4TangentY ^ v4CameraToStart;
  191. v4Normal += eps;
  192. v4Normal = VectorNormalizeFast( v4Normal );
  193. FourVectors v4LNormal = RotateLeft( v4Normal );
  194. FourVectors v4RNormal = RotateRight( v4Normal );
  195. pV4CurAveNormal[0] = Madd( v4Normal, v4AveFactor, pV4CurAveNormal[0] );
  196. pV4CurAveNormal[0] = Madd( v4LNormal, v4LMask, pV4CurAveNormal[0] );
  197. pV4CurAveNormal[0] = Madd( v4RNormal, v4RMask, pV4CurAveNormal[0] );
  198. pV4CurAveNormal[-1] = Madd( v4LNormal, v4LPrevMask, pV4CurAveNormal[-1] );
  199. pV4CurAveNormal[1] = Mul( v4RNormal, v4RNextMask );
  200. }
  201. // FIXME: Do I need to fixup the endpoints, to clamp their normals to the unsmoothed value?
  202. // Maybe I can get away with not doing that.
  203. FourVectors *pV4Normals = &pV4AveNormals[1];
  204. FourVectors *pV4TangentY = (FourVectors*)stackalloc( nV4SegCount * sizeof(FourVectors) );
  205. FourVectors *pV4Point1 = (FourVectors*)stackalloc( nV4SegCount * sizeof(FourVectors) );
  206. FourVectors *pV4Point2 = (FourVectors*)stackalloc( nV4SegCount * sizeof(FourVectors) );
  207. for ( int i = 0; i < nV4SegCount; ++i )
  208. {
  209. // prefetch
  210. // (write top half rows)
  211. PREFETCH360( pRenderInfo + (i << 2) + 2, 0 );
  212. PREFETCH360( pRenderInfo + (i << 2) + 3, 0 );
  213. FourVectors v4Normal = VectorNormalizeFast( pV4Normals[i] );
  214. FourVectors v4CameraToStart = pV4StartPos[i] - v4CameraPos;
  215. FourVectors v4TangentY = v4CameraToStart ^ v4Normal;
  216. pV4Normals[i] = v4Normal;
  217. v4TangentY += eps;
  218. pV4TangentY[i] = VectorNormalizeFast( v4TangentY );
  219. FourVectors v4Offset = Mul( v4Normal, pV4HalfWidth[i] );
  220. pV4Point1[i] = pV4StartPos[i] + v4Offset;
  221. pV4Point2[i] = pV4StartPos[i] - v4Offset;
  222. }
  223. const BeamSeg_t * RESTRICT pSeg = pSrcSegs;
  224. // The code below has a few load-hit-stores (due to the
  225. // transform to vector for store). For an alternate
  226. // pathway that does the same thing without the LHS,
  227. // see changelist 588032. It was more complicated, but
  228. // didn't profile to actually be any faster, so it
  229. // was taken back out.
  230. for ( int i = 0 ; i < nSegCount; ++i, ++pRenderInfo, ++pSeg )
  231. {
  232. int nIndex = ( i >> 2 );
  233. int j = ( i & 0x3 );
  234. pRenderInfo->m_vecCenter = pV4StartPos[nIndex].Vec( j );
  235. pRenderInfo->m_vecPoint1 = pV4Point1[nIndex].Vec( j );
  236. pRenderInfo->m_vecPoint2 = pV4Point2[nIndex].Vec( j );
  237. pRenderInfo->m_vecTangentS = pV4Normals[nIndex].Vec( j );
  238. pRenderInfo->m_vecTangentT = pV4TangentY[nIndex].Vec( j );
  239. pRenderInfo->m_flTexCoord = pSeg->m_flTexCoord;
  240. pRenderInfo->m_color = pSeg->m_color;
  241. }
  242. }
  243. void CBeamSegDraw::End()
  244. {
  245. if ( m_pMeshBuilder )
  246. {
  247. m_pMeshBuilder = NULL;
  248. return;
  249. }
  250. m_Mesh.End( false, true );
  251. }
  252. //-----------------------------------------------------------------------------
  253. // Purpose:
  254. //-----------------------------------------------------------------------------
  255. void CBeamSegDrawArbitrary::SetNormal( const Vector &normal )
  256. {
  257. m_vNormalLast = normal;
  258. }
  259. //-----------------------------------------------------------------------------
  260. // Purpose:
  261. //-----------------------------------------------------------------------------
  262. void CBeamSegDrawArbitrary::NextSeg( BeamSeg_t *pSeg )
  263. {
  264. if ( m_nSegsDrawn > 0 )
  265. {
  266. Vector segDir = ( m_PrevSeg.m_vPos - pSeg->m_vPos );
  267. VectorNormalize( segDir );
  268. Vector normal = CrossProduct( segDir, m_vNormalLast );
  269. SpecifySeg( normal );
  270. }
  271. m_PrevSeg = m_Seg;
  272. m_Seg = *pSeg;
  273. ++m_nSegsDrawn;
  274. }
  275. void CBeamSegDrawArbitrary::SpecifySeg( const Vector &vNormal )
  276. {
  277. // Build the endpoints.
  278. Vector vPoint1, vPoint2;
  279. Vector vDelta;
  280. VectorMultiply( vNormal, m_Seg.m_flWidth*0.5f, vDelta );
  281. VectorAdd( m_Seg.m_vPos, vDelta, vPoint1 );
  282. VectorSubtract( m_Seg.m_vPos, vDelta, vPoint2 );
  283. m_Mesh.Position3fv( vPoint1.Base() );
  284. m_Mesh.Color4ub( m_Seg.m_color.r, m_Seg.m_color.g, m_Seg.m_color.b, m_Seg.m_color.a );
  285. m_Mesh.TexCoord2f( 0, 0, m_Seg.m_flTexCoord );
  286. m_Mesh.TexCoord2f( 1, 0, m_Seg.m_flTexCoord );
  287. m_Mesh.AdvanceVertex();
  288. m_Mesh.Position3fv( vPoint2.Base() );
  289. m_Mesh.Color4ub( m_Seg.m_color.r, m_Seg.m_color.g, m_Seg.m_color.b, m_Seg.m_color.a );
  290. m_Mesh.TexCoord2f( 0, 1, m_Seg.m_flTexCoord );
  291. m_Mesh.TexCoord2f( 1, 1, m_Seg.m_flTexCoord );
  292. m_Mesh.AdvanceVertex();
  293. }