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.

332 lines
8.8 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "disp_vrad.h"
  8. #include "utllinkedlist.h"
  9. #include "utlvector.h"
  10. #include "iscratchpad3d.h"
  11. #include "scratchpadutils.h"
  12. //#define USE_SCRATCHPAD
  13. #if defined( USE_SCRATCHPAD )
  14. static IScratchPad3D *g_pPad = 0;
  15. #endif
  16. int FindNeighborCornerVert( CCoreDispInfo *pDisp, const Vector &vTest )
  17. {
  18. CDispUtilsHelper *pDispHelper = pDisp;
  19. int iClosest = 0;
  20. float flClosest = 1e24;
  21. for ( int iCorner=0; iCorner < 4; iCorner++ )
  22. {
  23. // Has it been touched?
  24. CVertIndex cornerVert = pDispHelper->GetPowerInfo()->GetCornerPointIndex( iCorner );
  25. int iCornerVert = pDispHelper->VertIndexToInt( cornerVert );
  26. const Vector &vCornerVert = pDisp->GetVert( iCornerVert );
  27. float flDist = vCornerVert.DistTo( vTest );
  28. if ( flDist < flClosest )
  29. {
  30. iClosest = iCorner;
  31. flClosest = flDist;
  32. }
  33. }
  34. if ( flClosest <= 0.1f )
  35. return iClosest;
  36. else
  37. return -1;
  38. }
  39. int GetAllNeighbors( const CCoreDispInfo *pDisp, int (&iNeighbors)[512] )
  40. {
  41. int nNeighbors = 0;
  42. // Check corner neighbors.
  43. for ( int iCorner=0; iCorner < 4; iCorner++ )
  44. {
  45. const CDispCornerNeighbors *pCorner = pDisp->GetCornerNeighbors( iCorner );
  46. for ( int i=0; i < pCorner->m_nNeighbors; i++ )
  47. {
  48. if ( nNeighbors < ARRAYSIZE( iNeighbors ) )
  49. iNeighbors[nNeighbors++] = pCorner->m_Neighbors[i];
  50. }
  51. }
  52. for ( int iEdge=0; iEdge < 4; iEdge++ )
  53. {
  54. const CDispNeighbor *pEdge = pDisp->GetEdgeNeighbor( iEdge );
  55. for ( int i=0; i < 2; i++ )
  56. {
  57. if ( pEdge->m_SubNeighbors[i].IsValid() )
  58. if ( nNeighbors < 512 )
  59. iNeighbors[nNeighbors++] = pEdge->m_SubNeighbors[i].GetNeighborIndex();
  60. }
  61. }
  62. return nNeighbors;
  63. }
  64. void BlendCorners( CCoreDispInfo **ppListBase, int listSize )
  65. {
  66. CUtlVector<int> nbCornerVerts;
  67. for ( int iDisp=0; iDisp < listSize; iDisp++ )
  68. {
  69. CCoreDispInfo *pDisp = ppListBase[iDisp];
  70. int iNeighbors[512];
  71. int nNeighbors = GetAllNeighbors( pDisp, iNeighbors );
  72. // Make sure we have room for all the neighbors.
  73. nbCornerVerts.RemoveAll();
  74. nbCornerVerts.EnsureCapacity( nNeighbors );
  75. nbCornerVerts.AddMultipleToTail( nNeighbors );
  76. // For each corner.
  77. for ( int iCorner=0; iCorner < 4; iCorner++ )
  78. {
  79. // Has it been touched?
  80. CVertIndex cornerVert = pDisp->GetCornerPointIndex( iCorner );
  81. int iCornerVert = pDisp->VertIndexToInt( cornerVert );
  82. const Vector &vCornerVert = pDisp->GetVert( iCornerVert );
  83. // For each displacement sharing this corner..
  84. Vector vAverage = pDisp->GetNormal( iCornerVert );
  85. for ( int iNeighbor=0; iNeighbor < nNeighbors; iNeighbor++ )
  86. {
  87. int iNBListIndex = iNeighbors[iNeighbor];
  88. CCoreDispInfo *pNeighbor = ppListBase[iNBListIndex];
  89. // Find out which vert it is on the neighbor.
  90. int iNBCorner = FindNeighborCornerVert( pNeighbor, vCornerVert );
  91. if ( iNBCorner == -1 )
  92. {
  93. nbCornerVerts[iNeighbor] = -1; // remove this neighbor from the list.
  94. }
  95. else
  96. {
  97. CVertIndex viNBCornerVert = pNeighbor->GetCornerPointIndex( iNBCorner );
  98. int iNBVert = pNeighbor->VertIndexToInt( viNBCornerVert );
  99. nbCornerVerts[iNeighbor] = iNBVert;
  100. vAverage += pNeighbor->GetNormal( iNBVert );
  101. }
  102. }
  103. // Blend all the neighbor normals with this one.
  104. VectorNormalize( vAverage );
  105. pDisp->SetNormal( iCornerVert, vAverage );
  106. #if defined( USE_SCRATCHPAD )
  107. ScratchPad_DrawArrowSimple(
  108. g_pPad,
  109. pDisp->GetVert( iCornerVert ),
  110. pDisp->GetNormal( iCornerVert ),
  111. Vector( 0, 0, 1 ),
  112. 25 );
  113. #endif
  114. for ( int iNeighbor=0; iNeighbor < nNeighbors; iNeighbor++ )
  115. {
  116. int iNBListIndex = iNeighbors[iNeighbor];
  117. if ( nbCornerVerts[iNeighbor] == -1 )
  118. continue;
  119. CCoreDispInfo *pNeighbor = ppListBase[iNBListIndex];
  120. pNeighbor->SetNormal( nbCornerVerts[iNeighbor], vAverage );
  121. }
  122. }
  123. }
  124. }
  125. void BlendTJuncs( CCoreDispInfo **ppListBase, int listSize )
  126. {
  127. for ( int iDisp=0; iDisp < listSize; iDisp++ )
  128. {
  129. CCoreDispInfo *pDisp = ppListBase[iDisp];
  130. for ( int iEdge=0; iEdge < 4; iEdge++ )
  131. {
  132. CDispNeighbor *pEdge = pDisp->GetEdgeNeighbor( iEdge );
  133. CVertIndex viMidPoint = pDisp->GetEdgeMidPoint( iEdge );
  134. int iMidPoint = pDisp->VertIndexToInt( viMidPoint );
  135. if ( pEdge->m_SubNeighbors[0].IsValid() && pEdge->m_SubNeighbors[1].IsValid() )
  136. {
  137. const Vector &vMidPoint = pDisp->GetVert( iMidPoint );
  138. CCoreDispInfo *pNeighbor1 = ppListBase[pEdge->m_SubNeighbors[0].GetNeighborIndex()];
  139. CCoreDispInfo *pNeighbor2 = ppListBase[pEdge->m_SubNeighbors[1].GetNeighborIndex()];
  140. int iNBCorners[2];
  141. iNBCorners[0] = FindNeighborCornerVert( pNeighbor1, vMidPoint );
  142. iNBCorners[1] = FindNeighborCornerVert( pNeighbor2, vMidPoint );
  143. if ( iNBCorners[0] != -1 && iNBCorners[1] != -1 )
  144. {
  145. CVertIndex viNBCorners[2] =
  146. {
  147. pNeighbor1->GetCornerPointIndex( iNBCorners[0] ),
  148. pNeighbor2->GetCornerPointIndex( iNBCorners[1] )
  149. };
  150. Vector vAverage = pDisp->GetNormal( iMidPoint );
  151. vAverage += pNeighbor1->GetNormal( viNBCorners[0] );
  152. vAverage += pNeighbor2->GetNormal( viNBCorners[1] );
  153. VectorNormalize( vAverage );
  154. pDisp->SetNormal( iMidPoint, vAverage );
  155. pNeighbor1->SetNormal( viNBCorners[0], vAverage );
  156. pNeighbor2->SetNormal( viNBCorners[1], vAverage );
  157. #if defined( USE_SCRATCHPAD )
  158. ScratchPad_DrawArrowSimple( g_pPad, pDisp->GetVert( iMidPoint ), pDisp->GetNormal( iMidPoint ), Vector( 0, 1, 1 ), 25 );
  159. #endif
  160. }
  161. }
  162. }
  163. }
  164. }
  165. void BlendEdges( CCoreDispInfo **ppListBase, int listSize )
  166. {
  167. for ( int iDisp=0; iDisp < listSize; iDisp++ )
  168. {
  169. CCoreDispInfo *pDisp = ppListBase[iDisp];
  170. for ( int iEdge=0; iEdge < 4; iEdge++ )
  171. {
  172. CDispNeighbor *pEdge = pDisp->GetEdgeNeighbor( iEdge );
  173. for ( int iSub=0; iSub < 2; iSub++ )
  174. {
  175. CDispSubNeighbor *pSub = &pEdge->m_SubNeighbors[iSub];
  176. if ( !pSub->IsValid() )
  177. continue;
  178. CCoreDispInfo *pNeighbor = ppListBase[ pSub->GetNeighborIndex() ];
  179. int iEdgeDim = g_EdgeDims[iEdge];
  180. CDispSubEdgeIterator it;
  181. it.Start( pDisp, iEdge, iSub, true );
  182. // Get setup on the first corner vert.
  183. it.Next();
  184. CVertIndex viPrevPos = it.GetVertIndex();
  185. while ( it.Next() )
  186. {
  187. // Blend the two.
  188. if ( !it.IsLastVert() )
  189. {
  190. Vector vAverage = pDisp->GetNormal( it.GetVertIndex() ) + pNeighbor->GetNormal( it.GetNBVertIndex() );
  191. VectorNormalize( vAverage );
  192. pDisp->SetNormal( it.GetVertIndex(), vAverage );
  193. pNeighbor->SetNormal( it.GetNBVertIndex(), vAverage );
  194. #if defined( USE_SCRATCHPAD )
  195. ScratchPad_DrawArrowSimple( g_pPad, pDisp->GetVert( it.GetVertIndex() ), pDisp->GetNormal( it.GetVertIndex() ), Vector( 1, 0, 0 ), 25 );
  196. #endif
  197. }
  198. // Now blend the in-between verts (if this edge is high-res).
  199. int iPrevPos = viPrevPos[ !iEdgeDim ];
  200. int iCurPos = it.GetVertIndex()[ !iEdgeDim ];
  201. for ( int iTween = iPrevPos+1; iTween < iCurPos; iTween++ )
  202. {
  203. float flPercent = RemapVal( iTween, iPrevPos, iCurPos, 0, 1 );
  204. Vector vNormal;
  205. VectorLerp( pDisp->GetNormal( viPrevPos ), pDisp->GetNormal( it.GetVertIndex() ), flPercent, vNormal );
  206. VectorNormalize( vNormal );
  207. CVertIndex viTween;
  208. viTween[iEdgeDim] = it.GetVertIndex()[ iEdgeDim ];
  209. viTween[!iEdgeDim] = iTween;
  210. pDisp->SetNormal( viTween, vNormal );
  211. #if defined( USE_SCRATCHPAD )
  212. ScratchPad_DrawArrowSimple( g_pPad, pDisp->GetVert( viTween ), pDisp->GetNormal( viTween ), Vector( 1, 0.5, 0 ), 25 );
  213. #endif
  214. }
  215. viPrevPos = it.GetVertIndex();
  216. }
  217. }
  218. }
  219. }
  220. }
  221. #if defined( USE_SCRATCHPAD )
  222. void ScratchPad_DrawOriginalNormals( const CCoreDispInfo *pListBase, int listSize )
  223. {
  224. for ( int i=0; i < listSize; i++ )
  225. {
  226. const CCoreDispInfo *pDisp = &pListBase[i];
  227. const CPowerInfo *pPowerInfo = pDisp->GetPowerInfo();
  228. // Draw the triangles.
  229. for ( int iTri=0; iTri < pPowerInfo->GetNumTriInfos(); iTri++ )
  230. {
  231. const CTriInfo *pTriInfo = pPowerInfo->GetTriInfo( iTri );
  232. for ( int iLine=0; iLine < 3; iLine++ )
  233. {
  234. const Vector &v1 = pDisp->GetVert( pTriInfo->m_Indices[iLine] );
  235. const Vector &v2 = pDisp->GetVert( pTriInfo->m_Indices[(iLine+1)%3] );
  236. g_pPad->DrawLine( CSPVert( v1 ), CSPVert( v2 ) );
  237. }
  238. }
  239. // Draw the normals.
  240. CDispCircumferenceIterator it( pPowerInfo->GetSideLength() );
  241. while ( it.Next() )
  242. {
  243. ScratchPad_DrawArrowSimple(
  244. g_pPad,
  245. pDisp->GetVert( it.GetVertIndex() ),
  246. pDisp->GetNormal( it.GetVertIndex() ),
  247. Vector( 0, 1, 0 ),
  248. 15 );
  249. }
  250. }
  251. }
  252. #endif
  253. void SmoothNeighboringDispSurfNormals( CCoreDispInfo **ppListBase, int listSize )
  254. {
  255. //#if defined( USE_SCRATCHPAD )
  256. // g_pPad = ScratchPad3D_Create();
  257. // ScratchPad_DrawOriginalNormals( pListBase, listSize );
  258. //#endif
  259. BlendTJuncs( ppListBase, listSize );
  260. BlendCorners( ppListBase, listSize );
  261. BlendEdges( ppListBase, listSize );
  262. }