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.

580 lines
16 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "disp_powerinfo.h"
  8. #include "disp_common.h"
  9. #include "commonmacros.h"
  10. // memdbgon must be the last include file in a .cpp file!!!
  11. #include "tier0/memdbgon.h"
  12. // ------------------------------------------------------------------------ //
  13. // Internal classes.
  14. // ------------------------------------------------------------------------ //
  15. // These point at the vertices connecting to each of the [north,south,east,west] vertices.
  16. class CVertCorners
  17. {
  18. public:
  19. short m_Corner1[2];
  20. short m_Corner2[2];
  21. };
  22. // ------------------------------------------------------------------------ //
  23. // Globals.
  24. // ------------------------------------------------------------------------ //
  25. // This points at vertices to the side of a node (north, south, east, west).
  26. static short g_SideVertMul[4][2] = { {1,0}, {0,1}, {-1,0}, {0,-1} };
  27. static CVertCorners g_SideVertCorners[4] =
  28. {
  29. { {1,-1}, {1,1} },
  30. { {1,1}, {-1,1} },
  31. { {-1,1}, {-1,-1} },
  32. { {-1,-1}, {1,-1} }
  33. };
  34. // This is used in loops on child nodes. The indices point at the nodes:
  35. // 0 = upper-right
  36. // 1 = upper-left
  37. // 2 = lower-left
  38. // 3 = lower-right
  39. static CVertIndex g_ChildNodeIndexMul[4] =
  40. {
  41. CVertIndex(1,1),
  42. CVertIndex(-1,1),
  43. CVertIndex(-1,-1),
  44. CVertIndex(1,-1)
  45. };
  46. // These are multipliers on vertMul (not nodeMul).
  47. static CVertIndex g_ChildNodeDependencies[4][2] =
  48. {
  49. { CVertIndex(1,0), CVertIndex(0,1) },
  50. { CVertIndex(0,1), CVertIndex(-1,0) },
  51. { CVertIndex(-1,0), CVertIndex(0,-1) },
  52. { CVertIndex(0,-1), CVertIndex(1,0) }
  53. };
  54. // 2x2 rotation matrices for each orientation.
  55. static int g_OrientationRotations[4][2][2] =
  56. {
  57. {{1, 0}, // CCW_0
  58. {0, 1}},
  59. {{0, 1}, // CCW_90
  60. {-1,0}},
  61. {{-1,0}, // CCW_180
  62. {0,-1}},
  63. {{0, -1}, // CCW_270
  64. {1, 0}}
  65. };
  66. // ------------------------------------------------------------------------ //
  67. // Helper functions.
  68. // ------------------------------------------------------------------------ //
  69. // Apply a 2D rotation to the specified CVertIndex around the specified centerpoint.
  70. static CVertIndex Transform2D(
  71. int const mat[2][2],
  72. CVertIndex const &vert,
  73. CVertIndex const &centerPoint )
  74. {
  75. CVertIndex translated = vert - centerPoint;
  76. CVertIndex transformed(
  77. translated.x*mat[0][0] + translated.y*mat[0][1],
  78. translated.x*mat[1][0] + translated.y*mat[1][1] );
  79. return transformed + centerPoint;
  80. }
  81. // Rotate a given CVertIndex with a specified orientation.
  82. // Do this with a lookup table eventually!
  83. static void GetEdgeVertIndex( int sideLength, int iEdge, int iVert, CVertIndex &out )
  84. {
  85. if( iEdge == NEIGHBOREDGE_RIGHT )
  86. {
  87. out.x = sideLength - 1;
  88. out.y = iVert;
  89. }
  90. else if( iEdge == NEIGHBOREDGE_TOP )
  91. {
  92. out.x = iVert;
  93. out.y = sideLength - 1;
  94. }
  95. else if( iEdge == NEIGHBOREDGE_LEFT )
  96. {
  97. out.x = 0;
  98. out.y = iVert;
  99. }
  100. else
  101. {
  102. out.x = iVert;
  103. out.y = 0;
  104. }
  105. }
  106. // Generate an index given a CVertIndex and the size of the displacement it resides in.
  107. static int VertIndex( CVertIndex const &vert, int iMaxPower )
  108. {
  109. return vert.y * ((1 << iMaxPower) + 1) + vert.x;
  110. }
  111. static CVertIndex WrapVertIndex( CVertIndex const &in, int sideLength )
  112. {
  113. int out[2];
  114. for( int i=0; i < 2; i++ )
  115. {
  116. if( in[i] < 0 )
  117. out[i] = sideLength - 1 - (-in[i] % sideLength);
  118. else if( in[i] >= sideLength )
  119. out[i] = in[i] % sideLength;
  120. else
  121. out[i] = in[i];
  122. }
  123. return CVertIndex( out[0], out[1] );
  124. }
  125. static int GetFreeDependency( CVertDependency *pDep, int nElements )
  126. {
  127. for( int i=0; i < nElements; i++ )
  128. {
  129. if( !pDep[i].IsValid() )
  130. return i;
  131. }
  132. Assert( false );
  133. return 0;
  134. }
  135. static void AddDependency(
  136. CVertInfo *dependencies,
  137. int sideLength,
  138. CVertIndex const &nodeIndex,
  139. CVertIndex const &dependency,
  140. int iMaxPower,
  141. bool bCheckNeighborDependency,
  142. bool bAddReverseDependency )
  143. {
  144. int iNodeIndex = VertIndex( nodeIndex, iMaxPower );
  145. CVertInfo *pNode = &dependencies[iNodeIndex];
  146. int iDep = GetFreeDependency( pNode->m_Dependencies, sizeof(pNode->m_Dependencies)/sizeof(pNode->m_Dependencies[0]) );
  147. pNode->m_Dependencies[iDep].m_iVert = dependency;
  148. pNode->m_Dependencies[iDep].m_iNeighbor = -1;
  149. if( bAddReverseDependency )
  150. {
  151. CVertInfo *pDep = &dependencies[VertIndex( dependency, iMaxPower )];
  152. iDep = GetFreeDependency( pDep->m_ReverseDependencies, CVertInfo::NUM_REVERSE_DEPENDENCIES );
  153. pDep->m_ReverseDependencies[iDep].m_iVert = nodeIndex;
  154. pDep->m_ReverseDependencies[iDep].m_iNeighbor = -1;
  155. }
  156. // Edge verts automatically add a dependency for the neighbor.
  157. // Internal verts wind up in here twice anyway so it doesn't need to
  158. if( bCheckNeighborDependency )
  159. {
  160. int iConnection = GetEdgeIndexFromPoint( nodeIndex, iMaxPower );
  161. if( iConnection != -1 )
  162. {
  163. Assert( !pNode->m_Dependencies[1].IsValid() );
  164. CVertIndex delta( nodeIndex.x - dependency.x, nodeIndex.y - dependency.y );
  165. CVertIndex newIndex( nodeIndex.x + delta.x, nodeIndex.y + delta.y );
  166. int fullSideLength = (1 << iMaxPower) + 1;
  167. pNode->m_Dependencies[1].m_iVert = WrapVertIndex( CVertIndex( newIndex.x, newIndex.y ), fullSideLength );
  168. pNode->m_Dependencies[1].m_iNeighbor = iConnection;
  169. }
  170. }
  171. }
  172. // --------------------------------------------------------------------------------- //
  173. // CTesselateWinding stuff.
  174. // --------------------------------------------------------------------------------- //
  175. CTesselateVert::CTesselateVert( CVertIndex const &index, int iNode )
  176. : m_Index( index )
  177. {
  178. m_iNode = iNode;
  179. }
  180. CVertInfo::CVertInfo()
  181. {
  182. int i;
  183. for( i=0; i < sizeof(m_Dependencies)/sizeof(m_Dependencies[0]); i++ )
  184. {
  185. m_Dependencies[i].m_iVert = CVertIndex( -1, -1 );
  186. m_Dependencies[i].m_iNeighbor = -1;
  187. }
  188. for( i=0; i < sizeof(m_ReverseDependencies)/sizeof(m_ReverseDependencies[0]); i++ )
  189. {
  190. m_ReverseDependencies[i].m_iVert = CVertIndex( -1, -1 );
  191. m_ReverseDependencies[i].m_iNeighbor = -1;
  192. }
  193. m_iParent.x = m_iParent.y = -1;
  194. m_iNodeLevel = -1;
  195. }
  196. CTesselateVert g_TesselateVerts[] =
  197. {
  198. CTesselateVert( CVertIndex(1,-1), CHILDNODE_LOWER_RIGHT),
  199. CTesselateVert( CVertIndex(0,-1), -1),
  200. CTesselateVert( CVertIndex(-1,-1), CHILDNODE_LOWER_LEFT),
  201. CTesselateVert( CVertIndex(-1, 0), -1),
  202. CTesselateVert( CVertIndex(-1, 1), CHILDNODE_UPPER_LEFT),
  203. CTesselateVert( CVertIndex(0, 1), -1),
  204. CTesselateVert( CVertIndex(1, 1), CHILDNODE_UPPER_RIGHT),
  205. CTesselateVert( CVertIndex(1, 0), -1),
  206. CTesselateVert( CVertIndex(1,-1), CHILDNODE_LOWER_RIGHT)
  207. };
  208. CTesselateWinding g_TWinding =
  209. {
  210. g_TesselateVerts,
  211. sizeof( g_TesselateVerts ) / sizeof( g_TesselateVerts[0] )
  212. };
  213. // --------------------------------------------------------------------------------- //
  214. // CPowerInfo stuff.
  215. // --------------------------------------------------------------------------------- //
  216. // Precalculated info about each particular displacement size.
  217. #define DECLARE_TABLES( size ) \
  218. static CVertInfo g_VertInfo_##size##x##size[ size*size ]; \
  219. static CFourVerts g_SideVerts_##size##x##size[ size*size ]; \
  220. static CFourVerts g_ChildVerts_##size##x##size[ size*size ]; \
  221. static CFourVerts g_SideVertCorners_##size##x##size[ size*size ]; \
  222. static CTwoUShorts g_ErrorEdges_##size##x##size[ size*size ]; \
  223. static CTriInfo g_TriInfos_##size##x##size[ (size-1)*(size-1)*2 ]; \
  224. static CPowerInfo g_PowerInfo_##size##x##size( \
  225. g_VertInfo_##size##x##size, \
  226. g_SideVerts_##size##x##size, \
  227. g_ChildVerts_##size##x##size, \
  228. g_SideVertCorners_##size##x##size,\
  229. g_ErrorEdges_##size##x##size, \
  230. g_TriInfos_##size##x##size \
  231. )
  232. #define POWERINFO_ENTRY( size ) \
  233. (&g_PowerInfo_##size##x##size)
  234. DECLARE_TABLES( 5 );
  235. DECLARE_TABLES( 9 );
  236. DECLARE_TABLES( 17 );
  237. // Index by m_Power.
  238. CPowerInfo *g_PowerInfos[NUM_POWERINFOS] =
  239. {
  240. NULL,
  241. NULL,
  242. POWERINFO_ENTRY(5),
  243. POWERINFO_ENTRY(9),
  244. POWERINFO_ENTRY(17)
  245. };
  246. CPowerInfo::CPowerInfo(
  247. CVertInfo *pVertInfo,
  248. CFourVerts *pSideVerts,
  249. CFourVerts *pChildVerts,
  250. CFourVerts *pSideVertCorners,
  251. CTwoUShorts *pErrorEdges,
  252. CTriInfo *pTriInfos )
  253. {
  254. m_pVertInfo = pVertInfo;
  255. m_pSideVerts = pSideVerts;
  256. m_pChildVerts = pChildVerts;
  257. m_pSideVertCorners = pSideVertCorners;
  258. m_pErrorEdges = pErrorEdges;
  259. m_pTriInfos = pTriInfos;
  260. }
  261. static void InitPowerInfoTriInfos_R(
  262. CPowerInfo *pInfo,
  263. CVertIndex const &nodeIndex,
  264. CTriInfo* &pTriInfo,
  265. int iMaxPower,
  266. int iLevel )
  267. {
  268. int iNodeIndex = VertIndex( nodeIndex, iMaxPower );
  269. if( iLevel+1 < iMaxPower )
  270. {
  271. // Recurse into children.
  272. for( int iChild=0; iChild < 4; iChild++ )
  273. {
  274. InitPowerInfoTriInfos_R(
  275. pInfo,
  276. pInfo->m_pChildVerts[iNodeIndex].m_Verts[iChild],
  277. pTriInfo,
  278. iMaxPower,
  279. iLevel+1 );
  280. }
  281. }
  282. else
  283. {
  284. unsigned short indices[3];
  285. int vertInc = 1 << ((iMaxPower - iLevel) - 1);
  286. // We're at a leaf, generate the tris.
  287. CTesselateWinding *pWinding = &g_TWinding;
  288. // Starting at the bottom-left, wind clockwise picking up vertices and
  289. // generating triangles.
  290. int iCurTriVert = 0;
  291. for( int iVert=0; iVert < pWinding->m_nVerts; iVert++ )
  292. {
  293. CVertIndex sideVert = BuildOffsetVertIndex( nodeIndex, pWinding->m_Verts[iVert].m_Index, vertInc );
  294. if( iCurTriVert == 1 )
  295. {
  296. // Add this vert and finish the tri.
  297. pTriInfo->m_Indices[0] = indices[0];
  298. pTriInfo->m_Indices[1] = VertIndex( sideVert, iMaxPower );
  299. pTriInfo->m_Indices[2] = iNodeIndex;
  300. ++pTriInfo;
  301. }
  302. indices[0] = VertIndex( sideVert, iMaxPower );
  303. iCurTriVert = 1;
  304. }
  305. }
  306. }
  307. static void InitPowerInfo_R(
  308. CPowerInfo *pPowerInfo,
  309. int iMaxPower,
  310. CVertIndex const &nodeIndex,
  311. CVertIndex const &dependency1,
  312. CVertIndex const &dependency2,
  313. CVertIndex const &nodeEdge1,
  314. CVertIndex const &nodeEdge2,
  315. CVertIndex const &iParent,
  316. int iLevel )
  317. {
  318. int sideLength = ((1 << iMaxPower) + 1);
  319. int iNodeIndex = VertIndex( nodeIndex, iMaxPower );
  320. pPowerInfo->m_pVertInfo[iNodeIndex].m_iParent = iParent;
  321. pPowerInfo->m_pVertInfo[iNodeIndex].m_iNodeLevel = iLevel + 1;
  322. pPowerInfo->m_pErrorEdges[iNodeIndex].m_Values[0] = (unsigned short)(VertIndex( nodeEdge1, iMaxPower ));
  323. pPowerInfo->m_pErrorEdges[iNodeIndex].m_Values[1] = (unsigned short)(VertIndex( nodeEdge2, iMaxPower ));
  324. // Add this node's dependencies.
  325. AddDependency( pPowerInfo->m_pVertInfo, sideLength, nodeIndex, dependency1, iMaxPower, false, true );
  326. AddDependency( pPowerInfo->m_pVertInfo, sideLength, nodeIndex, dependency2, iMaxPower, false, true );
  327. // The 4 side vertices depend on this node.
  328. int iPower = iMaxPower - iLevel;
  329. int vertInc = 1 << (iPower - 1);
  330. for( int iSide=0; iSide < 4; iSide++ )
  331. {
  332. // Store the side vert index.
  333. CVertIndex sideVert( nodeIndex.x + g_SideVertMul[iSide][0]*vertInc, nodeIndex.y + g_SideVertMul[iSide][1]*vertInc );
  334. int iSideVert = VertIndex( sideVert, iMaxPower );
  335. pPowerInfo->m_pSideVerts[iNodeIndex].m_Verts[iSide] = sideVert;
  336. // Store the side vert corners.
  337. CVertIndex sideVertCorner0 = CVertIndex( nodeIndex.x + g_SideVertCorners[iSide].m_Corner1[0]*vertInc, nodeIndex.y + g_SideVertCorners[iSide].m_Corner1[1]*vertInc );
  338. CVertIndex sideVertCorner1 = CVertIndex( nodeIndex.x + g_SideVertCorners[iSide].m_Corner2[0]*vertInc, nodeIndex.y + g_SideVertCorners[iSide].m_Corner2[1]*vertInc );
  339. pPowerInfo->m_pSideVertCorners[iNodeIndex].m_Verts[iSide] = sideVertCorner0;
  340. // Write the side vert corners into the error-edges list.
  341. pPowerInfo->m_pErrorEdges[iSideVert].m_Values[0] = (unsigned short)VertIndex( sideVertCorner0, iMaxPower );
  342. pPowerInfo->m_pErrorEdges[iSideVert].m_Values[1] = (unsigned short)VertIndex( sideVertCorner1, iMaxPower );
  343. AddDependency(
  344. pPowerInfo->m_pVertInfo,
  345. sideLength,
  346. sideVert,
  347. nodeIndex,
  348. iMaxPower,
  349. true,
  350. true );
  351. }
  352. // Recurse into the children.
  353. int nodeInc = vertInc >> 1;
  354. if( nodeInc )
  355. {
  356. for( int iChild=0; iChild < 4; iChild++ )
  357. {
  358. CVertIndex childVert( nodeIndex.x + g_ChildNodeIndexMul[iChild].x * nodeInc, nodeIndex.y + g_ChildNodeIndexMul[iChild].y * nodeInc );
  359. pPowerInfo->m_pChildVerts[iNodeIndex].m_Verts[iChild] = childVert;
  360. InitPowerInfo_R( pPowerInfo,
  361. iMaxPower,
  362. childVert,
  363. CVertIndex(nodeIndex.x + g_ChildNodeDependencies[iChild][0].x*vertInc, nodeIndex.y + g_ChildNodeDependencies[iChild][0].y*vertInc),
  364. CVertIndex(nodeIndex.x + g_ChildNodeDependencies[iChild][1].x*vertInc, nodeIndex.y + g_ChildNodeDependencies[iChild][1].y*vertInc),
  365. nodeIndex,
  366. CVertIndex( nodeIndex.x + g_ChildNodeIndexMul[iChild].x * vertInc, nodeIndex.y + g_ChildNodeIndexMul[iChild].y * vertInc ),
  367. nodeIndex,
  368. iLevel + 1 );
  369. }
  370. }
  371. }
  372. void InitPowerInfo( CPowerInfo *pInfo, int iMaxPower )
  373. {
  374. int sideLength = (1 << iMaxPower) + 1;
  375. // Precalculate the dependency graph.
  376. CVertIndex nodeDependency1( sideLength-1, sideLength-1 );
  377. CVertIndex nodeDependency2( 0, 0 );
  378. pInfo->m_RootNode = CVertIndex( sideLength/2, sideLength/2 );
  379. pInfo->m_SideLength = sideLength;
  380. pInfo->m_SideLengthM1 = sideLength - 1;
  381. pInfo->m_MidPoint = sideLength / 2;
  382. pInfo->m_MaxVerts = sideLength * sideLength;
  383. // Setup the corner indices.
  384. pInfo->m_CornerPointIndices[CORNER_LOWER_LEFT].Init( 0, 0 );
  385. pInfo->m_CornerPointIndices[CORNER_UPPER_LEFT].Init( 0, sideLength-1 );
  386. pInfo->m_CornerPointIndices[CORNER_UPPER_RIGHT].Init( sideLength-1, sideLength-1 );
  387. pInfo->m_CornerPointIndices[CORNER_LOWER_RIGHT].Init( sideLength-1, 0 );
  388. InitPowerInfo_R(
  389. pInfo,
  390. iMaxPower,
  391. pInfo->m_RootNode,
  392. nodeDependency1, // dependencies
  393. nodeDependency2,
  394. CVertIndex(0,0), // error edge
  395. CVertIndex(sideLength-1, sideLength-1),
  396. CVertIndex(-1,-1), // parent
  397. 0 );
  398. pInfo->m_Power = iMaxPower;
  399. CTriInfo *pTriInfo = pInfo->m_pTriInfos;
  400. InitPowerInfoTriInfos_R( pInfo, pInfo->m_RootNode, pTriInfo, iMaxPower, 0 );
  401. for( int iEdge=0; iEdge < 4; iEdge++ )
  402. {
  403. // Figure out the start vert and increment.
  404. CVertIndex nextVert;
  405. GetEdgeVertIndex( sideLength, iEdge, 0, pInfo->m_EdgeStartVerts[iEdge] );
  406. GetEdgeVertIndex( sideLength, iEdge, 1, nextVert );
  407. pInfo->m_EdgeIncrements[iEdge] = nextVert - pInfo->m_EdgeStartVerts[iEdge];
  408. // Now get the neighbor's start vert and increment.
  409. CVertIndex nbStartVert, nbNextVert, nbDelta;
  410. GetEdgeVertIndex( sideLength, (iEdge+2)&3, 0, nbStartVert );
  411. GetEdgeVertIndex( sideLength, (iEdge+2)&3, 1, nbNextVert );
  412. nbDelta = nbNextVert - nbStartVert;
  413. // Rotate it for each orientation.
  414. for( int orient=0; orient < 4; orient++ )
  415. {
  416. pInfo->m_NeighborStartVerts[iEdge][orient] = Transform2D(
  417. g_OrientationRotations[orient],
  418. nbStartVert,
  419. CVertIndex( sideLength/2, sideLength/2 ) );
  420. pInfo->m_NeighborIncrements[iEdge][orient] = Transform2D(
  421. g_OrientationRotations[orient],
  422. nbDelta,
  423. CVertIndex(0,0) );
  424. }
  425. }
  426. // Init the node index increments.
  427. int curPowerOf4 = 1;
  428. int curTotal = 0;
  429. for( int i=0; i < iMaxPower-1; i++ )
  430. {
  431. curTotal += curPowerOf4;
  432. pInfo->m_NodeIndexIncrements[iMaxPower-i-2] = curTotal;
  433. curPowerOf4 *= 4;
  434. }
  435. // Store off the total node count
  436. pInfo->m_NodeCount = curTotal + curPowerOf4;
  437. pInfo->m_nTriInfos = Square( 1 << iMaxPower ) * 2;
  438. }
  439. class CPowerInfoInitializer
  440. {
  441. public:
  442. CPowerInfoInitializer()
  443. {
  444. Assert( MAX_MAP_DISP_POWER+1 == NUM_POWERINFOS );
  445. for( int i=0; i <= MAX_MAP_DISP_POWER; i++ )
  446. {
  447. if( g_PowerInfos[i] )
  448. {
  449. InitPowerInfo( g_PowerInfos[i], i );
  450. }
  451. }
  452. }
  453. };
  454. static CPowerInfoInitializer g_PowerInfoInitializer;
  455. const CPowerInfo* GetPowerInfo( int iPower )
  456. {
  457. Assert( iPower >= 0 && iPower < ARRAYSIZE( g_PowerInfos ) );
  458. Assert( g_PowerInfos[iPower] );
  459. return g_PowerInfos[iPower];
  460. }
  461. // ------------------------------------------------------------------------------------------------ //
  462. // CPowerInfo member function initialization.
  463. // ------------------------------------------------------------------------------------------------ //
  464. const CVertIndex& CPowerInfo::GetCornerPointIndex( int iCorner ) const
  465. {
  466. Assert( iCorner >= 0 && iCorner < 4 );
  467. return m_CornerPointIndices[iCorner];
  468. }