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.

2770 lines
88 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include <stdafx.h>
  7. #include "MapOverlay.h"
  8. #include "MapFace.h"
  9. #include "MapSolid.h"
  10. #include "MapWorld.h"
  11. #include "MainFrm.h"
  12. #include "GlobalFunctions.h"
  13. #include "MapDoc.h"
  14. #include "TextureSystem.h"
  15. #include "Material.h"
  16. #include "materialsystem/IMesh.h"
  17. #include "Box3D.h"
  18. #include "MapDefs.h"
  19. #include "CollisionUtils.h"
  20. #include "MapSideList.h"
  21. #include "MapDisp.h"
  22. #include "ToolManager.h"
  23. #include "objectproperties.h"
  24. #include "ChunkFile.h"
  25. #include "mapview.h"
  26. #include "options.h"
  27. // memdbgon must be the last include file in a .cpp file!!!
  28. #include <tier0/memdbgon.h>
  29. IMPLEMENT_MAPCLASS( CMapOverlay )
  30. #define OVERLAY_INITSIZE 25.0f // x2
  31. #define OVERLAY_BASIS_U 0
  32. #define OVERLAY_BASIS_V 1
  33. #define OVERLAY_BASIS_NORMAL 2
  34. #define OVERLAY_HANDLES_COUNT 4
  35. #define OVERLAY_WORLDSPACE_EPSILON 0.03125f
  36. #define OVERLAY_DISPSPACE_EPSILON 0.000001f
  37. #define OVERLAY_BARYCENTRIC_EPSILON 0.001f
  38. #define OVERLAY_BLENDTYPE_VERT 0
  39. #define OVERLAY_BLENDTYPE_EDGE 1
  40. #define OVERLAY_BLENDTYPE_BARY 2
  41. #define OVERLAY_ANGLE0 1
  42. #define OVERLAY_ANGLE45 2
  43. #define OVERLAY_ANGLE90 3
  44. #define OVERLAY_ANGLE135 4
  45. #define OVERLAY_INVALID_VALUE -99999.9f
  46. //=============================================================================
  47. //
  48. // Basis Functions
  49. //
  50. //-----------------------------------------------------------------------------
  51. // Purpose: Initialize the basis data.
  52. //-----------------------------------------------------------------------------
  53. void CMapOverlay::Basis_Clear( void )
  54. {
  55. m_Basis.m_pFace = NULL;
  56. m_Basis.m_vecOrigin.Init();
  57. for( int iAxis = 0; iAxis < 3; iAxis++ )
  58. {
  59. m_Basis.m_vecAxes[iAxis].Init( OVERLAY_INVALID_VALUE, OVERLAY_INVALID_VALUE, OVERLAY_INVALID_VALUE );
  60. m_Basis.m_nAxesFlip[iAxis] = 0;
  61. }
  62. }
  63. //-----------------------------------------------------------------------------
  64. // Purpose: Build the overlay basis given an entity and base face (CMapFace).
  65. //-----------------------------------------------------------------------------
  66. void CMapOverlay::Basis_Init( CMapFace *pFace )
  67. {
  68. // Valid face?
  69. Assert( pFace != NULL );
  70. if( !pFace )
  71. return;
  72. // Set the face the basis are derived from.
  73. Basis_SetFace( pFace );
  74. // Set the basis origin.
  75. Basis_UpdateOrigin();
  76. // Setup the basis axes.
  77. Basis_BuildAxes();
  78. // Initialize the texture coordinates - based on basis.
  79. Material_TexCoordInit();
  80. }
  81. //-----------------------------------------------------------------------------
  82. // Purpose:
  83. //-----------------------------------------------------------------------------
  84. void CMapOverlay::Basis_UpdateOrigin( void )
  85. {
  86. CMapEntity *pEntity = static_cast<CMapEntity*>( GetParent() );
  87. if ( pEntity )
  88. {
  89. Vector vecEntityOrigin;
  90. pEntity->GetOrigin( vecEntityOrigin );
  91. Vector vecPoint( 0.0f, 0.0f, 0.0f );
  92. if ( !EntityOnSurfFromListToBaseFacePlane( vecEntityOrigin, vecPoint ) )
  93. {
  94. vecPoint = vecEntityOrigin;
  95. }
  96. m_Basis.m_vecOrigin = vecPoint;
  97. }
  98. // Update the property box.
  99. Basis_UpdateParentKey();
  100. }
  101. //-----------------------------------------------------------------------------
  102. // Purpose:
  103. //-----------------------------------------------------------------------------
  104. void CMapOverlay::Basis_BuildAxes( void )
  105. {
  106. // Valid face?
  107. if( !m_Basis.m_pFace )
  108. return;
  109. // Build the basis axes.
  110. Vector vecFaceNormal;
  111. m_Basis.m_pFace->GetFaceNormal( vecFaceNormal );
  112. VectorNormalize( vecFaceNormal );
  113. VectorCopy( vecFaceNormal, m_Basis.m_vecAxes[OVERLAY_BASIS_NORMAL] );
  114. Basis_SetInitialUAxis( vecFaceNormal );
  115. m_Basis.m_vecAxes[OVERLAY_BASIS_V] = m_Basis.m_vecAxes[OVERLAY_BASIS_NORMAL].Cross( m_Basis.m_vecAxes[OVERLAY_BASIS_U] );
  116. VectorNormalize( m_Basis.m_vecAxes[OVERLAY_BASIS_V] );
  117. m_Basis.m_vecAxes[OVERLAY_BASIS_U] = m_Basis.m_vecAxes[OVERLAY_BASIS_V].Cross( m_Basis.m_vecAxes[OVERLAY_BASIS_NORMAL] );
  118. VectorNormalize( m_Basis.m_vecAxes[OVERLAY_BASIS_U] );
  119. // Flip uvn axes?
  120. for ( int iAxis = 0; iAxis < 3; ++iAxis )
  121. {
  122. for ( int iComp = 0; iComp < 3; ++iComp )
  123. {
  124. if ( Basis_IsFlipped( iAxis, iComp ) )
  125. {
  126. m_Basis.m_vecAxes[iAxis][iComp] = -m_Basis.m_vecAxes[iAxis][iComp];
  127. }
  128. }
  129. }
  130. Basis_UpdateParentKey();
  131. }
  132. //-----------------------------------------------------------------------------
  133. // Purpose: A basis building helper function that finds the best guess u-axis
  134. // given a base face (CMapFace) normal.
  135. // Input: vecNormal - the base face normal
  136. //-----------------------------------------------------------------------------
  137. void CMapOverlay::Basis_SetInitialUAxis( Vector const &vecNormal )
  138. {
  139. // Find the major vector component.
  140. int nMajorAxis = 0;
  141. float flAxisValue = vecNormal[0];
  142. if ( FloatMakePositive( vecNormal[1] ) > FloatMakePositive( flAxisValue ) )
  143. {
  144. nMajorAxis = 1;
  145. flAxisValue = vecNormal[1];
  146. }
  147. if ( FloatMakePositive( vecNormal[2] ) > FloatMakePositive( flAxisValue ) )
  148. {
  149. nMajorAxis = 2;
  150. }
  151. if ( ( nMajorAxis == 1 ) || ( nMajorAxis == 2 ) )
  152. {
  153. m_Basis.m_vecAxes[OVERLAY_BASIS_U].Init( 1.0f, 0.0f, 0.0f );
  154. }
  155. else
  156. {
  157. m_Basis.m_vecAxes[OVERLAY_BASIS_U].Init( 0.0f, 1.0f, 0.0f );
  158. }
  159. }
  160. //-----------------------------------------------------------------------------
  161. // Purpose:
  162. //-----------------------------------------------------------------------------
  163. bool CMapOverlay::Basis_IsValid( void )
  164. {
  165. for ( int iBasis = 0; iBasis < 3; ++iBasis )
  166. {
  167. for ( int iAxis = 0; iAxis < 3; ++iAxis )
  168. {
  169. if ( m_Basis.m_vecAxes[iBasis][iAxis] == OVERLAY_INVALID_VALUE )
  170. return false;
  171. }
  172. }
  173. return true;
  174. }
  175. //-----------------------------------------------------------------------------
  176. // Purpose:
  177. //-----------------------------------------------------------------------------
  178. void CMapOverlay::Basis_SetFace( CMapFace *pFace )
  179. {
  180. // Verify face.
  181. if ( !pFace )
  182. return;
  183. m_Basis.m_pFace = pFace;
  184. }
  185. //-----------------------------------------------------------------------------
  186. // Purpose: Copy the basis data from the source into the destination.
  187. // Input: pSrc - the basis source data
  188. // pDst (Output) - destination for the basis data
  189. //-----------------------------------------------------------------------------
  190. void CMapOverlay::Basis_Copy( Basis_t *pSrc, Basis_t *pDst )
  191. {
  192. pDst->m_pFace = pSrc->m_pFace;
  193. pDst->m_vecOrigin = pSrc->m_vecOrigin;
  194. for ( int iAxis = 0; iAxis < 3; iAxis++ )
  195. {
  196. pDst->m_vecAxes[iAxis] = pSrc->m_vecAxes[iAxis];
  197. pDst->m_nAxesFlip[iAxis] = pSrc->m_nAxesFlip[iAxis];
  198. }
  199. }
  200. //-----------------------------------------------------------------------------
  201. // Purpose:
  202. //-----------------------------------------------------------------------------
  203. void CMapOverlay::Basis_UpdateParentKey( void )
  204. {
  205. char szValue[80];
  206. CMapEntity *pEntity = ( CMapEntity* )GetParent();
  207. if ( pEntity )
  208. {
  209. sprintf( szValue, "%g %g %g", m_Basis.m_vecOrigin.x, m_Basis.m_vecOrigin.y, m_Basis.m_vecOrigin.z );
  210. pEntity->NotifyChildKeyChanged( this, "BasisOrigin", szValue );
  211. sprintf( szValue, "%g %g %g", m_Basis.m_vecAxes[OVERLAY_BASIS_U].x, m_Basis.m_vecAxes[OVERLAY_BASIS_U].y, m_Basis.m_vecAxes[OVERLAY_BASIS_U].z );
  212. pEntity->NotifyChildKeyChanged( this, "BasisU", szValue );
  213. sprintf( szValue, "%g %g %g", m_Basis.m_vecAxes[OVERLAY_BASIS_V].x, m_Basis.m_vecAxes[OVERLAY_BASIS_V].y, m_Basis.m_vecAxes[OVERLAY_BASIS_V].z );
  214. pEntity->NotifyChildKeyChanged( this, "BasisV", szValue );
  215. sprintf( szValue, "%g %g %g", m_Basis.m_vecAxes[OVERLAY_BASIS_NORMAL].x, m_Basis.m_vecAxes[OVERLAY_BASIS_NORMAL].y, m_Basis.m_vecAxes[OVERLAY_BASIS_NORMAL].z );
  216. pEntity->NotifyChildKeyChanged( this, "BasisNormal", szValue );
  217. }
  218. }
  219. //=============================================================================
  220. //
  221. // Basis - Legacy support!
  222. //
  223. //-----------------------------------------------------------------------------
  224. // Purpose:
  225. //-----------------------------------------------------------------------------
  226. void CMapOverlay::Basis_BuildFromSideList( void )
  227. {
  228. // Initialization (don't have or couldn't find the basis face)
  229. if ( m_Faces.Count() > 0 )
  230. {
  231. Basis_Init( m_Faces.Element( 0 ) );
  232. }
  233. else
  234. {
  235. m_Basis.m_pFace = NULL;
  236. }
  237. }
  238. //-----------------------------------------------------------------------------
  239. // Purpose:
  240. // Input: iAxis - 0, 1, 2 (u, v, n)
  241. // iComponet - 0, 1, 2 (x, y, z)
  242. //-----------------------------------------------------------------------------
  243. void CMapOverlay::Basis_ToggleAxesFlip( int iAxis, int iComponent )
  244. {
  245. if ( iAxis < 0 || iAxis > 2 || iComponent < 0 || iComponent > 2 )
  246. return;
  247. int nValue = ( 1 << iComponent );
  248. m_Basis.m_nAxesFlip[iAxis] ^= nValue;
  249. }
  250. //-----------------------------------------------------------------------------
  251. // Purpose:
  252. //-----------------------------------------------------------------------------
  253. bool CMapOverlay::Basis_IsFlipped( int iAxis, int iComponent )
  254. {
  255. if ( iAxis < 0 || iAxis > 2 || iComponent < 0 || iComponent > 2 )
  256. return false;
  257. int nValue = ( 1 << iComponent );
  258. return ( ( m_Basis.m_nAxesFlip[iAxis] & nValue ) != 0 );
  259. }
  260. //=============================================================================
  261. //
  262. // Handles Functions
  263. //
  264. //-----------------------------------------------------------------------------
  265. // Purpose:
  266. //-----------------------------------------------------------------------------
  267. void CMapOverlay::Handles_Clear( void )
  268. {
  269. m_Handles.m_iHit = -1;
  270. for ( int iHandle = 0; iHandle < OVERLAY_HANDLES_COUNT; iHandle++ )
  271. {
  272. m_Handles.m_vec3D[iHandle].Init();
  273. }
  274. m_Handles.m_vecBasisCoords[0].Init( -OVERLAY_INITSIZE, -OVERLAY_INITSIZE );
  275. m_Handles.m_vecBasisCoords[1].Init( -OVERLAY_INITSIZE, OVERLAY_INITSIZE );
  276. m_Handles.m_vecBasisCoords[2].Init( OVERLAY_INITSIZE, OVERLAY_INITSIZE );
  277. m_Handles.m_vecBasisCoords[3].Init( OVERLAY_INITSIZE, -OVERLAY_INITSIZE );
  278. }
  279. //-----------------------------------------------------------------------------
  280. // Purpose:
  281. //-----------------------------------------------------------------------------
  282. void CMapOverlay::Handles_Init( CMapFace *pFace )
  283. {
  284. IEditorTexture *pTexture = g_Textures.FindActiveTexture( GetDefaultTextureName() );
  285. int nWidth = pTexture->GetMappingWidth();
  286. int nHeight = pTexture->GetMappingHeight();
  287. // Half-height (width) and 1/4 scale
  288. int nWidthHalf = nWidth / 8;
  289. int nHeightHalf = nHeight / 8;
  290. m_Handles.m_vecBasisCoords[0].Init( -nWidthHalf, -nHeightHalf );
  291. m_Handles.m_vecBasisCoords[1].Init( -nWidthHalf, nHeightHalf );
  292. m_Handles.m_vecBasisCoords[2].Init( nWidthHalf, nHeightHalf );
  293. m_Handles.m_vecBasisCoords[3].Init( nWidthHalf, -nHeightHalf );
  294. Handles_Build3D();
  295. Handles_UpdateParentKey();
  296. }
  297. //-----------------------------------------------------------------------------
  298. // Purpose:
  299. //-----------------------------------------------------------------------------
  300. void CMapOverlay::Handles_Build3D( void )
  301. {
  302. // Verify that we have a valid basis to build the handles from.
  303. if ( !Basis_IsValid() )
  304. return;
  305. for ( int iHandle = 0; iHandle < OVERLAY_HANDLES_COUNT; iHandle++ )
  306. {
  307. Vector vecHandle;
  308. OverlayUVToOverlayPlane( m_Handles.m_vecBasisCoords[iHandle], vecHandle );
  309. OverlayPlaneToSurfFromList( vecHandle, m_Handles.m_vec3D[iHandle] );
  310. }
  311. Handles_FixOrder();
  312. }
  313. //-----------------------------------------------------------------------------
  314. // Purpose:
  315. //-----------------------------------------------------------------------------
  316. void CMapOverlay::Handles_Render3D( CRender3D *pRender )
  317. {
  318. // Set the render mode to "flat."
  319. pRender->PushRenderMode( RENDER_MODE_FLAT );
  320. // Set the color, should be based on selection.
  321. unsigned char ucColor[4];
  322. ucColor[0] = ucColor[1] = ucColor[2] = ucColor[3] = 255;
  323. unsigned char ucSelectColor[4];
  324. ucSelectColor[0] = ucSelectColor[3] = 255;
  325. ucSelectColor[1] = ucSelectColor[2] = 0;
  326. pRender->SetHandleStyle( HANDLE_RADIUS, CRender::HANDLE_SQUARE );
  327. for ( int iHandle = 0; iHandle < OVERLAY_HANDLES_COUNT; iHandle++ )
  328. {
  329. pRender->BeginRenderHitTarget( this, iHandle );
  330. if ( m_Handles.m_iHit == iHandle )
  331. {
  332. pRender->SetHandleColor( ucSelectColor[0], ucSelectColor[1], ucSelectColor[2] );
  333. }
  334. else
  335. {
  336. pRender->SetHandleColor( ucColor[0], ucColor[1], ucColor[2] );
  337. }
  338. pRender->DrawHandle( m_Handles.m_vec3D[iHandle] );
  339. pRender->EndRenderHitTarget();
  340. }
  341. pRender->PopRenderMode();
  342. }
  343. //-----------------------------------------------------------------------------
  344. // Purpose:
  345. //-----------------------------------------------------------------------------
  346. void CMapOverlay::Handles_SurfToOverlayPlane( CMapFace *pFace, Vector const &vecSurf, Vector &vecPoint )
  347. {
  348. Vector vecWorld;
  349. if ( pFace->HasDisp() )
  350. {
  351. EditDispHandle_t handle = pFace->GetDisp();
  352. CMapDisp *pDisp = EditDispMgr()->GetDisp( handle );
  353. pDisp->SurfToBaseFacePlane( vecSurf, vecWorld );
  354. }
  355. else
  356. {
  357. vecWorld = vecSurf;
  358. }
  359. WorldToOverlayPlane( vecWorld, vecPoint );
  360. }
  361. //-----------------------------------------------------------------------------
  362. // Purpose:
  363. //-----------------------------------------------------------------------------
  364. void CMapOverlay::Handles_Copy( Handles_t *pSrc, Handles_t *pDst )
  365. {
  366. pDst->m_iHit = pSrc->m_iHit;
  367. for ( int iHandle = 0; iHandle < OVERLAY_HANDLES_COUNT; ++iHandle )
  368. {
  369. pDst->m_vecBasisCoords[iHandle] = pSrc->m_vecBasisCoords[iHandle];
  370. pDst->m_vec3D[iHandle] = pSrc->m_vec3D[iHandle];
  371. }
  372. }
  373. //-----------------------------------------------------------------------------
  374. // Purpose:
  375. //-----------------------------------------------------------------------------
  376. void CMapOverlay::Handles_UpdateParentKey( void )
  377. {
  378. char szValue[80];
  379. CMapEntity *pEntity = ( CMapEntity* )GetParent();
  380. if ( pEntity )
  381. {
  382. sprintf( szValue, "%g %g %g", m_Handles.m_vecBasisCoords[0].x, m_Handles.m_vecBasisCoords[0].y, ( float )m_Basis.m_nAxesFlip[0] );
  383. pEntity->NotifyChildKeyChanged( this, "uv0", szValue );
  384. sprintf( szValue, "%g %g %g", m_Handles.m_vecBasisCoords[1].x, m_Handles.m_vecBasisCoords[1].y, ( float )m_Basis.m_nAxesFlip[1] );
  385. pEntity->NotifyChildKeyChanged( this, "uv1", szValue );
  386. sprintf( szValue, "%g %g %g", m_Handles.m_vecBasisCoords[2].x, m_Handles.m_vecBasisCoords[2].y, ( float )m_Basis.m_nAxesFlip[2] );
  387. pEntity->NotifyChildKeyChanged( this, "uv2", szValue );
  388. sprintf( szValue, "%g %g %g", m_Handles.m_vecBasisCoords[3].x, m_Handles.m_vecBasisCoords[3].y, 0.0f );
  389. pEntity->NotifyChildKeyChanged( this, "uv3", szValue );
  390. }
  391. }
  392. //=============================================================================
  393. //
  394. // ClipFace Functions
  395. //
  396. //-----------------------------------------------------------------------------
  397. // Purpose:
  398. //-----------------------------------------------------------------------------
  399. CMapOverlay::ClipFace_t *CMapOverlay::ClipFace_Create( int nSize )
  400. {
  401. ClipFace_t *pClipFace = new ClipFace_t;
  402. if ( pClipFace )
  403. {
  404. pClipFace->m_nPointCount = nSize;
  405. if ( nSize > 0 )
  406. {
  407. pClipFace->m_aPoints.SetSize( nSize );
  408. pClipFace->m_aNormals.SetSize( nSize );
  409. pClipFace->m_aDispPointUVs.SetSize( nSize );
  410. for ( int iCoord = 0; iCoord < NUM_CLIPFACE_TEXCOORDS; iCoord++ )
  411. {
  412. pClipFace->m_aTexCoords[iCoord].SetSize( nSize );
  413. }
  414. pClipFace->m_aBlends.SetSize( nSize );
  415. for ( int iPoint = 0; iPoint < nSize; iPoint++ )
  416. {
  417. pClipFace->m_aPoints[iPoint].Init();
  418. pClipFace->m_aNormals[iPoint].Init( 0, 0, 1 );
  419. pClipFace->m_aDispPointUVs[iPoint].Init();
  420. pClipFace->m_aBlends[iPoint].Init();
  421. for ( int iCoord = 0; iCoord < NUM_CLIPFACE_TEXCOORDS; iCoord++ )
  422. {
  423. pClipFace->m_aTexCoords[iCoord][iPoint].Init();
  424. }
  425. }
  426. }
  427. }
  428. return pClipFace;
  429. }
  430. //-----------------------------------------------------------------------------
  431. // Purpose:
  432. //-----------------------------------------------------------------------------
  433. void CMapOverlay::ClipFace_Destroy( ClipFace_t **ppClipFace )
  434. {
  435. if( *ppClipFace )
  436. {
  437. delete *ppClipFace;
  438. *ppClipFace = NULL;
  439. }
  440. }
  441. //-----------------------------------------------------------------------------
  442. //-----------------------------------------------------------------------------
  443. CMapOverlay::ClipFace_t *CMapOverlay::ClipFace_Copy( ClipFace_t *pSrc )
  444. {
  445. ClipFace_t *pDst = ClipFace_Create( pSrc->m_nPointCount );
  446. if ( pDst )
  447. {
  448. for ( int iPoint = 0; iPoint < pSrc->m_nPointCount; iPoint++ )
  449. {
  450. pDst->m_aPoints[iPoint] = pSrc->m_aPoints[iPoint];
  451. pDst->m_aNormals[iPoint] = pSrc->m_aNormals[iPoint];
  452. pDst->m_aDispPointUVs[iPoint] = pSrc->m_aDispPointUVs[iPoint];
  453. for ( int iTexCoord=0; iTexCoord < NUM_CLIPFACE_TEXCOORDS; iTexCoord++ )
  454. {
  455. pDst->m_aTexCoords[iTexCoord][iPoint] = pSrc->m_aTexCoords[iTexCoord][iPoint];
  456. }
  457. pDst->m_aBlends[iPoint].m_nType = pSrc->m_aBlends[iPoint].m_nType;
  458. for ( int iBlend = 0; iBlend < 3; iBlend++ )
  459. {
  460. pDst->m_aBlends[iPoint].m_iPoints[iBlend] = pSrc->m_aBlends[iPoint].m_iPoints[iBlend];
  461. pDst->m_aBlends[iPoint].m_flBlends[iBlend] = pSrc->m_aBlends[iPoint].m_flBlends[iBlend];
  462. }
  463. }
  464. }
  465. return pDst;
  466. }
  467. //-----------------------------------------------------------------------------
  468. //-----------------------------------------------------------------------------
  469. void CMapOverlay::ClipFace_GetBounds( ClipFace_t *pClipFace, Vector &vecMin, Vector &vecMax )
  470. {
  471. if ( pClipFace )
  472. {
  473. vecMin = vecMax = pClipFace->m_aPoints.Element( 0 );
  474. for ( int iPoints = 1; iPoints < pClipFace->m_nPointCount; iPoints++ )
  475. {
  476. Vector vecPoint = pClipFace->m_aPoints.Element( iPoints );
  477. // Min
  478. if ( vecMin.x > vecPoint.x ) { vecMin.x = vecPoint.x; }
  479. if ( vecMin.y > vecPoint.y ) { vecMin.y = vecPoint.y; }
  480. if ( vecMin.z > vecPoint.z ) { vecMin.z = vecPoint.z; }
  481. // Max
  482. if ( vecMax.x < vecPoint.x ) { vecMax.x = vecPoint.x; }
  483. if ( vecMax.y < vecPoint.y ) { vecMax.y = vecPoint.y; }
  484. if ( vecMax.z < vecPoint.z ) { vecMax.z = vecPoint.z; }
  485. }
  486. }
  487. }
  488. //-----------------------------------------------------------------------------
  489. //-----------------------------------------------------------------------------
  490. void CMapOverlay::ClipFace_Clip( ClipFace_t *pClipFace, cplane_t *pClipPlane, float flEpsilon,
  491. ClipFace_t **ppFront, ClipFace_t **ppBack )
  492. {
  493. if ( !pClipFace )
  494. return;
  495. float flDists[128];
  496. int nSides[128];
  497. int nSideCounts[3];
  498. // Initialize
  499. *ppFront = *ppBack = NULL;
  500. // Determine "sidedness" of all the polygon points.
  501. nSideCounts[0] = nSideCounts[1] = nSideCounts[2] = 0;
  502. int iPoint;
  503. for ( iPoint = 0; iPoint < pClipFace->m_nPointCount; iPoint++ )
  504. {
  505. flDists[iPoint] = pClipPlane->normal.Dot( pClipFace->m_aPoints.Element( iPoint ) ) - pClipPlane->dist;
  506. if ( flDists[iPoint] > flEpsilon )
  507. {
  508. nSides[iPoint] = SIDE_FRONT;
  509. }
  510. else if ( flDists[iPoint] < -flEpsilon )
  511. {
  512. nSides[iPoint] = SIDE_BACK;
  513. }
  514. else
  515. {
  516. nSides[iPoint] = SIDE_ON;
  517. }
  518. nSideCounts[nSides[iPoint]]++;
  519. }
  520. // Wrap around (close the polygon).
  521. nSides[iPoint] = nSides[0];
  522. flDists[iPoint] = flDists[0];
  523. // All points in back - no split (copy face to back).
  524. if( !nSideCounts[SIDE_FRONT] )
  525. {
  526. *ppBack = ClipFace_Copy( pClipFace );
  527. return;
  528. }
  529. // All points in front - no split (copy face to front).
  530. if( !nSideCounts[SIDE_BACK] )
  531. {
  532. *ppFront = ClipFace_Copy( pClipFace );
  533. return;
  534. }
  535. // Build new front and back faces. Leave room for two extra points on each side because any
  536. // point might be on the plane, which would put it into both the front and back sides, and then
  537. // we need to allow for an additional vertex created by clipping.
  538. ClipFace_t *pFront = ClipFace_Create( pClipFace->m_nPointCount + 2 );
  539. ClipFace_t *pBack = ClipFace_Create( pClipFace->m_nPointCount + 2 );
  540. if ( !pFront || !pBack )
  541. {
  542. ClipFace_Destroy( &pFront );
  543. ClipFace_Destroy( &pBack );
  544. return;
  545. }
  546. // Reset the counts as they are used to build the surface.
  547. pFront->m_nPointCount = 0;
  548. pBack->m_nPointCount = 0;
  549. // For every point on the face being clipped, determine which side of the clipping plane it is on
  550. // and add it to a either a front list or a back list. Points that are on the plane are added to
  551. // both lists.
  552. for ( iPoint = 0; iPoint < pClipFace->m_nPointCount; iPoint++ )
  553. {
  554. // "On" clip plane.
  555. if ( nSides[iPoint] == SIDE_ON )
  556. {
  557. pFront->m_aPoints[pFront->m_nPointCount] = pClipFace->m_aPoints[iPoint];
  558. pFront->m_aNormals[pFront->m_nPointCount] = pClipFace->m_aNormals[iPoint];
  559. for ( int iTexCoord=0; iTexCoord < NUM_CLIPFACE_TEXCOORDS; iTexCoord++ )
  560. pFront->m_aTexCoords[iTexCoord][pFront->m_nPointCount] = pClipFace->m_aTexCoords[iTexCoord][iPoint];
  561. pFront->m_nPointCount++;
  562. pBack->m_aPoints[pBack->m_nPointCount] = pClipFace->m_aPoints[iPoint];
  563. pBack->m_aNormals[pBack->m_nPointCount] = pClipFace->m_aNormals[iPoint];
  564. for ( int iTexCoord=0; iTexCoord < NUM_CLIPFACE_TEXCOORDS; iTexCoord++ )
  565. pBack->m_aTexCoords[iTexCoord][pBack->m_nPointCount] = pClipFace->m_aTexCoords[iTexCoord][iPoint];
  566. pBack->m_nPointCount++;
  567. continue;
  568. }
  569. // "In back" of clip plane.
  570. if ( nSides[iPoint] == SIDE_BACK )
  571. {
  572. pBack->m_aPoints[pBack->m_nPointCount] = pClipFace->m_aPoints[iPoint];
  573. pBack->m_aNormals[pBack->m_nPointCount] = pClipFace->m_aNormals[iPoint];
  574. for ( int iTexCoord=0; iTexCoord < NUM_CLIPFACE_TEXCOORDS; iTexCoord++ )
  575. pBack->m_aTexCoords[iTexCoord][pBack->m_nPointCount] = pClipFace->m_aTexCoords[iTexCoord][iPoint];
  576. pBack->m_nPointCount++;
  577. }
  578. // "In front" of clip plane.
  579. if ( nSides[iPoint] == SIDE_FRONT )
  580. {
  581. pFront->m_aPoints[pFront->m_nPointCount] = pClipFace->m_aPoints[iPoint];
  582. pFront->m_aNormals[pFront->m_nPointCount] = pClipFace->m_aNormals[iPoint];
  583. for ( int iTexCoord=0; iTexCoord < NUM_CLIPFACE_TEXCOORDS; iTexCoord++ )
  584. pFront->m_aTexCoords[iTexCoord][pFront->m_nPointCount] = pClipFace->m_aTexCoords[iTexCoord][iPoint];
  585. pFront->m_nPointCount++;
  586. }
  587. if ( nSides[iPoint+1] == SIDE_ON || nSides[iPoint+1] == nSides[iPoint] )
  588. continue;
  589. // Split!
  590. float fraction = flDists[iPoint] / ( flDists[iPoint] - flDists[iPoint+1] );
  591. Vector vecPoint = pClipFace->m_aPoints[iPoint] + ( pClipFace->m_aPoints[(iPoint+1)%pClipFace->m_nPointCount] - pClipFace->m_aPoints[iPoint] ) * fraction;
  592. Vector vecNormal = pClipFace->m_aNormals[iPoint] + ( pClipFace->m_aNormals[(iPoint+1)%pClipFace->m_nPointCount] - pClipFace->m_aNormals[iPoint] ) * fraction;
  593. vecNormal.NormalizeInPlace();
  594. for ( int iTexCoord=0; iTexCoord < NUM_CLIPFACE_TEXCOORDS; iTexCoord++ )
  595. {
  596. Vector2D vecTexCoord = pClipFace->m_aTexCoords[iTexCoord][iPoint] + ( pClipFace->m_aTexCoords[iTexCoord][(iPoint+1)%pClipFace->m_nPointCount] - pClipFace->m_aTexCoords[iTexCoord][iPoint] ) * fraction;
  597. pFront->m_aTexCoords[iTexCoord][pFront->m_nPointCount] = vecTexCoord;
  598. pBack->m_aTexCoords[iTexCoord][pBack->m_nPointCount] = vecTexCoord;
  599. }
  600. pFront->m_aPoints[pFront->m_nPointCount] = vecPoint;
  601. pFront->m_aNormals[pFront->m_nPointCount] = vecNormal;
  602. pFront->m_nPointCount++;
  603. pBack->m_aPoints[pBack->m_nPointCount] = vecPoint;
  604. pBack->m_aNormals[pBack->m_nPointCount] = vecNormal;
  605. pBack->m_nPointCount++;
  606. }
  607. *ppFront = pFront;
  608. *ppBack = pBack;
  609. }
  610. //-----------------------------------------------------------------------------
  611. //-----------------------------------------------------------------------------
  612. void CMapOverlay::ClipFace_ClipBarycentric( ClipFace_t *pClipFace, cplane_t *pClipPlane, float flEpsilon,
  613. int iClip, CMapDisp *pDisp,
  614. ClipFace_t **ppFront, ClipFace_t **ppBack )
  615. {
  616. if ( !pClipFace )
  617. return;
  618. float flDists[128];
  619. int nSides[128];
  620. int nSideCounts[3];
  621. // Determine "sidedness" of all the polygon points.
  622. nSideCounts[0] = nSideCounts[1] = nSideCounts[2] = 0;
  623. int iPoint;
  624. for ( iPoint = 0; iPoint < pClipFace->m_nPointCount; iPoint++ )
  625. {
  626. flDists[iPoint] = pClipPlane->normal.Dot( pClipFace->m_aDispPointUVs.Element( iPoint ) ) - pClipPlane->dist;
  627. if ( flDists[iPoint] > flEpsilon )
  628. {
  629. nSides[iPoint] = SIDE_FRONT;
  630. }
  631. else if ( flDists[iPoint] < -flEpsilon )
  632. {
  633. nSides[iPoint] = SIDE_BACK;
  634. }
  635. else
  636. {
  637. nSides[iPoint] = SIDE_ON;
  638. }
  639. nSideCounts[nSides[iPoint]]++;
  640. }
  641. // Wrap around (close the polygon).
  642. nSides[iPoint] = nSides[0];
  643. flDists[iPoint] = flDists[0];
  644. // All points in back - no split (copy face to back).
  645. if( !nSideCounts[SIDE_FRONT] )
  646. {
  647. *ppBack = ClipFace_Copy( pClipFace );
  648. return;
  649. }
  650. // All points in front - no split (copy face to front).
  651. if( !nSideCounts[SIDE_BACK] )
  652. {
  653. *ppFront = ClipFace_Copy( pClipFace );
  654. return;
  655. }
  656. // Build new front and back faces.
  657. // NOTE: We are allowing to go over by 2 and then destroy the surface later. The old system
  658. // allowed for some bad data and we need to be able to load the map and destroy the surface!
  659. int nMaxPointCount = pClipFace->m_nPointCount + 1;
  660. ClipFace_t *pFront = ClipFace_Create( nMaxPointCount + 2 );
  661. ClipFace_t *pBack = ClipFace_Create( nMaxPointCount + 2 );
  662. if ( !pFront || !pBack )
  663. {
  664. ClipFace_Destroy( &pFront );
  665. ClipFace_Destroy( &pBack );
  666. return;
  667. }
  668. // Reset the counts as they are used to build the surface.
  669. pFront->m_nPointCount = 0;
  670. pBack->m_nPointCount = 0;
  671. for ( iPoint = 0; iPoint < pClipFace->m_nPointCount; iPoint++ )
  672. {
  673. // "On" clip plane.
  674. if ( nSides[iPoint] == SIDE_ON )
  675. {
  676. pFront->m_aPoints[pFront->m_nPointCount] = pClipFace->m_aPoints[iPoint];
  677. pFront->m_aNormals[pFront->m_nPointCount] = pClipFace->m_aNormals[iPoint];
  678. pFront->m_aDispPointUVs[pFront->m_nPointCount] = pClipFace->m_aDispPointUVs[iPoint];
  679. for ( int iTexCoord=0; iTexCoord < NUM_CLIPFACE_TEXCOORDS; iTexCoord++ )
  680. pFront->m_aTexCoords[iTexCoord][pFront->m_nPointCount] = pClipFace->m_aTexCoords[iTexCoord][iPoint];
  681. ClipFace_CopyBlendFrom( pFront, &pClipFace->m_aBlends[iPoint] );
  682. pFront->m_nPointCount++;
  683. pBack->m_aPoints[pBack->m_nPointCount] = pClipFace->m_aPoints[iPoint];
  684. pBack->m_aNormals[pBack->m_nPointCount] = pClipFace->m_aNormals[iPoint];
  685. pBack->m_aDispPointUVs[pBack->m_nPointCount] = pClipFace->m_aDispPointUVs[iPoint];
  686. for ( int iTexCoord=0; iTexCoord < NUM_CLIPFACE_TEXCOORDS; iTexCoord++ )
  687. pBack->m_aTexCoords[iTexCoord][pBack->m_nPointCount] = pClipFace->m_aTexCoords[iTexCoord][iPoint];
  688. ClipFace_CopyBlendFrom( pBack, &pClipFace->m_aBlends[iPoint] );
  689. pBack->m_nPointCount++;
  690. continue;
  691. }
  692. // "In back" of clip plane.
  693. if ( nSides[iPoint] == SIDE_BACK )
  694. {
  695. pBack->m_aPoints[pBack->m_nPointCount] = pClipFace->m_aPoints[iPoint];
  696. pBack->m_aNormals[pBack->m_nPointCount] = pClipFace->m_aNormals[iPoint];
  697. pBack->m_aDispPointUVs[pBack->m_nPointCount] = pClipFace->m_aDispPointUVs[iPoint];
  698. for ( int iTexCoord=0; iTexCoord < NUM_CLIPFACE_TEXCOORDS; iTexCoord++ )
  699. pBack->m_aTexCoords[iTexCoord][pBack->m_nPointCount] = pClipFace->m_aTexCoords[iTexCoord][iPoint];
  700. ClipFace_CopyBlendFrom( pBack, &pClipFace->m_aBlends[iPoint] );
  701. pBack->m_nPointCount++;
  702. }
  703. // "In front" of clip plane.
  704. if ( nSides[iPoint] == SIDE_FRONT )
  705. {
  706. pFront->m_aPoints[pFront->m_nPointCount] = pClipFace->m_aPoints[iPoint];
  707. pFront->m_aNormals[pFront->m_nPointCount] = pClipFace->m_aNormals[iPoint];
  708. pFront->m_aDispPointUVs[pFront->m_nPointCount] = pClipFace->m_aDispPointUVs[iPoint];
  709. for ( int iTexCoord=0; iTexCoord < NUM_CLIPFACE_TEXCOORDS; iTexCoord++ )
  710. pFront->m_aTexCoords[iTexCoord][pFront->m_nPointCount] = pClipFace->m_aTexCoords[iTexCoord][iPoint];
  711. ClipFace_CopyBlendFrom( pFront, &pClipFace->m_aBlends[iPoint] );
  712. pFront->m_nPointCount++;
  713. }
  714. if ( nSides[iPoint+1] == SIDE_ON || nSides[iPoint+1] == nSides[iPoint] )
  715. continue;
  716. // Split!
  717. float fraction = flDists[iPoint] / ( flDists[iPoint] - flDists[iPoint+1] );
  718. Vector vecPoint = pClipFace->m_aPoints[iPoint] + ( pClipFace->m_aPoints[(iPoint+1)%pClipFace->m_nPointCount] - pClipFace->m_aPoints[iPoint] ) * fraction;
  719. Vector vecNormal = pClipFace->m_aNormals[iPoint] + ( pClipFace->m_aNormals[(iPoint+1)%pClipFace->m_nPointCount] - pClipFace->m_aNormals[iPoint] ) * fraction;
  720. vecNormal.NormalizeInPlace();
  721. Vector vecDispPointUV = pClipFace->m_aDispPointUVs[iPoint] + ( pClipFace->m_aDispPointUVs[(iPoint+1)%pClipFace->m_nPointCount] - pClipFace->m_aDispPointUVs[iPoint] ) * fraction;
  722. Vector2D vecUV, vecTexCoord;
  723. PointInQuadToBarycentric( m_pOverlayFace->m_aPoints[0], m_pOverlayFace->m_aPoints[3],
  724. m_pOverlayFace->m_aPoints[2], m_pOverlayFace->m_aPoints[1],
  725. vecPoint, vecUV );
  726. vecUV.x = clamp( vecUV.x, 0.0f, 1.0f );
  727. vecUV.y = clamp( vecUV.y, 0.0f, 1.0f );
  728. for ( int iTexCoord=0; iTexCoord < NUM_CLIPFACE_TEXCOORDS; iTexCoord++ )
  729. {
  730. TexCoordInQuadFromBarycentric( m_pOverlayFace->m_aTexCoords[iTexCoord][0], m_pOverlayFace->m_aTexCoords[iTexCoord][3],
  731. m_pOverlayFace->m_aTexCoords[iTexCoord][2], m_pOverlayFace->m_aTexCoords[iTexCoord][1],
  732. vecUV, vecTexCoord );
  733. pFront->m_aTexCoords[iTexCoord][pFront->m_nPointCount] = vecTexCoord;
  734. pBack->m_aTexCoords[iTexCoord][pBack->m_nPointCount] = vecTexCoord;
  735. }
  736. pFront->m_aPoints[pFront->m_nPointCount] = vecPoint;
  737. pFront->m_aNormals[pFront->m_nPointCount] = vecNormal;
  738. pFront->m_aDispPointUVs[pFront->m_nPointCount] = vecDispPointUV;
  739. ClipFace_BuildBlend( pFront, pDisp, pClipPlane, iClip, vecDispPointUV, vecPoint );
  740. pFront->m_nPointCount++;
  741. pBack->m_aPoints[pBack->m_nPointCount] = vecPoint;
  742. pBack->m_aNormals[pBack->m_nPointCount] = vecNormal;
  743. pBack->m_aDispPointUVs[pBack->m_nPointCount] = vecDispPointUV;
  744. ClipFace_BuildBlend( pBack, pDisp, pClipPlane, iClip, vecDispPointUV, vecPoint );
  745. pBack->m_nPointCount++;
  746. }
  747. // Check for a bad surface.
  748. if ( ( pFront->m_nPointCount > nMaxPointCount ) || ( pBack->m_nPointCount > nMaxPointCount ) )
  749. return;
  750. *ppFront = pFront;
  751. *ppBack = pBack;
  752. }
  753. //-----------------------------------------------------------------------------
  754. //-----------------------------------------------------------------------------
  755. void CMapOverlay::ClipFace_PreClipDisp( ClipFace_t *pClipFace, CMapDisp *pDisp )
  756. {
  757. // Valid clip face and/or displacement surface.
  758. if ( !pClipFace || !pDisp )
  759. return;
  760. // Transform all of the overlay points into disp uv space.
  761. for ( int iPoint = 0; iPoint < pClipFace->m_nPointCount; iPoint++ )
  762. {
  763. Vector2D vecTmp;
  764. pDisp->BaseFacePlaneToDispUV( pClipFace->m_aPoints[iPoint], vecTmp );
  765. pClipFace->m_aDispPointUVs[iPoint].x = clamp(vecTmp.x, 0.0f, 1.0f);
  766. pClipFace->m_aDispPointUVs[iPoint].y = clamp(vecTmp.y, 0.0f, 1.0f);
  767. pClipFace->m_aDispPointUVs[iPoint].z = 0.0f;
  768. }
  769. // Set initial point barycentric blend types.
  770. for ( int iPoint = 0; iPoint < pClipFace->m_nPointCount; ++iPoint )
  771. {
  772. Vector2D vecDispUV;
  773. vecDispUV.x = pClipFace->m_aDispPointUVs[iPoint].x;
  774. vecDispUV.y = pClipFace->m_aDispPointUVs[iPoint].y;
  775. int iTris[3];
  776. Vector2D vecVertsUV[3];
  777. GetTriVerts( pDisp, vecDispUV, iTris, vecVertsUV );
  778. float flCoefs[3];
  779. if ( ClipFace_CalcBarycentricCooefs( pDisp, vecVertsUV, vecDispUV, flCoefs ) )
  780. {
  781. ClipFace_ResolveBarycentricClip( pDisp, pClipFace, iPoint, vecDispUV, flCoefs, iTris, vecVertsUV );
  782. }
  783. }
  784. }
  785. //-----------------------------------------------------------------------------
  786. //-----------------------------------------------------------------------------
  787. void CMapOverlay::ClipFace_PostClipDisp( void )
  788. {
  789. }
  790. //-----------------------------------------------------------------------------
  791. //-----------------------------------------------------------------------------
  792. bool CMapOverlay::ClipFace_CalcBarycentricCooefs( CMapDisp *pDisp, Vector2D *pVertsUV,
  793. const Vector2D &vecPointUV, float *pCoefs )
  794. {
  795. // Area in disp UV space is always the same.
  796. float flTotalArea = 0.5f;
  797. float flOOTotalArea = 1.0f / flTotalArea;
  798. int nInterval = pDisp->GetWidth();
  799. Vector2D vecScaledPointUV = vecPointUV * ( nInterval - 1.000001f );
  800. Vector2D vecSegment0, vecSegment1;
  801. // Get the area for cooeficient 0 (pt, v1, v2).
  802. vecSegment0 = pVertsUV[1] - vecScaledPointUV;
  803. vecSegment1 = pVertsUV[2] - vecScaledPointUV;
  804. // Cross
  805. float flSubArea = ( ( vecSegment1.x * vecSegment0.y ) - ( vecSegment0.x * vecSegment1.y ) ) * 0.5f;
  806. pCoefs[0] = flSubArea * flOOTotalArea;
  807. // Get the area for cooeficient 1 (v0, pt, v2).
  808. vecSegment0 = vecScaledPointUV - pVertsUV[0];
  809. vecSegment1 = pVertsUV[2] - pVertsUV[0];
  810. // Cross
  811. flSubArea = ( ( vecSegment1.x * vecSegment0.y ) - ( vecSegment0.x * vecSegment1.y ) ) * 0.5f;
  812. pCoefs[1] = flSubArea * flOOTotalArea;
  813. // Get the area for cooeficient 2 (v0, v1, pt).
  814. vecSegment0 = pVertsUV[1] - pVertsUV[0];
  815. vecSegment1 = vecScaledPointUV - pVertsUV[0];
  816. // Cross
  817. flSubArea = ( ( vecSegment1.x * vecSegment0.y ) - ( vecSegment0.x * vecSegment1.y ) ) * 0.5f;
  818. pCoefs[2] = flSubArea * flOOTotalArea;
  819. float flCoefTotal = pCoefs[0] + pCoefs[1] + pCoefs[2];
  820. if ( FloatMakePositive( 1.0f - flCoefTotal ) < 0.00001f )
  821. return true;
  822. return false;
  823. }
  824. //-----------------------------------------------------------------------------
  825. //-----------------------------------------------------------------------------
  826. void CMapOverlay::ClipFace_ResolveBarycentricClip( CMapDisp *pDisp, ClipFace_t *pClipFace, int iClipFacePoint,
  827. const Vector2D &vecPointUV, float *pCoefs,
  828. int *pTris, Vector2D *pVertsUV )
  829. {
  830. int nInterval = pDisp->GetWidth();
  831. Vector2D vecScaledPointUV = vecPointUV * ( nInterval - 1.000001f );
  832. // Find the number of coefficients "equal" to zero.
  833. int nZeroCount = 0;
  834. bool bZeroPoint[3];
  835. for ( int iVert = 0; iVert < 3; ++iVert )
  836. {
  837. bZeroPoint[iVert] = false;
  838. if ( fabs( pCoefs[iVert] ) < OVERLAY_BARYCENTRIC_EPSILON )
  839. {
  840. nZeroCount++;
  841. bZeroPoint[iVert] = true;
  842. }
  843. }
  844. // Check for points - set to a point.
  845. if ( nZeroCount == 2 )
  846. {
  847. for ( int iVert = 0; iVert < 3; ++iVert )
  848. {
  849. if ( !bZeroPoint[iVert] )
  850. {
  851. pClipFace->m_aBlends[iClipFacePoint].m_nType = OVERLAY_BLENDTYPE_VERT;
  852. pClipFace->m_aBlends[iClipFacePoint].m_iPoints[0] = pTris[iVert];
  853. return;
  854. }
  855. }
  856. }
  857. // Check for edges - setup edge blend.
  858. if ( nZeroCount == 1 )
  859. {
  860. for ( int iVert = 0; iVert < 3; ++iVert )
  861. {
  862. if ( bZeroPoint[iVert] )
  863. {
  864. pClipFace->m_aBlends[iClipFacePoint].m_nType = OVERLAY_BLENDTYPE_EDGE;
  865. pClipFace->m_aBlends[iClipFacePoint].m_iPoints[0] = pTris[(iVert+1)%3];
  866. pClipFace->m_aBlends[iClipFacePoint].m_iPoints[1] = pTris[(iVert+2)%3];
  867. Vector2D vecLength1, vecLength2;
  868. vecLength1 = vecScaledPointUV - pVertsUV[(iVert+1)%3];
  869. vecLength2 = pVertsUV[(iVert+2)%3] - pVertsUV[(iVert+1)%3];
  870. float flBlend = vecLength1.Length() / vecLength2.Length();
  871. pClipFace->m_aBlends[iClipFacePoint].m_flBlends[0] = flBlend;
  872. return;
  873. }
  874. }
  875. }
  876. // Lies inside triangles - setup full barycentric blend.
  877. pClipFace->m_aBlends[iClipFacePoint].m_nType = OVERLAY_BLENDTYPE_BARY;
  878. pClipFace->m_aBlends[iClipFacePoint].m_iPoints[0] = pTris[0];
  879. pClipFace->m_aBlends[iClipFacePoint].m_iPoints[1] = pTris[1];
  880. pClipFace->m_aBlends[iClipFacePoint].m_iPoints[2] = pTris[2];
  881. pClipFace->m_aBlends[iClipFacePoint].m_flBlends[0] = pCoefs[0];
  882. pClipFace->m_aBlends[iClipFacePoint].m_flBlends[1] = pCoefs[1];
  883. pClipFace->m_aBlends[iClipFacePoint].m_flBlends[2] = pCoefs[2];
  884. }
  885. //-----------------------------------------------------------------------------
  886. //-----------------------------------------------------------------------------
  887. int CMapOverlay::ClipFace_GetAxisType( cplane_t *pClipPlane )
  888. {
  889. if ( pClipPlane->normal[0] == 1.0f ) { return OVERLAY_ANGLE90; }
  890. if ( pClipPlane->normal[1] == 1.0f ) { return OVERLAY_ANGLE0; }
  891. if ( ( pClipPlane->normal[0] == 0.707f ) && ( pClipPlane->normal[1] == 0.707f ) ) { return OVERLAY_ANGLE45; }
  892. if ( ( pClipPlane->normal[0] == -0.707f ) && ( pClipPlane->normal[1] == 0.707f ) ) { return OVERLAY_ANGLE135; }
  893. return OVERLAY_ANGLE0;
  894. }
  895. //-----------------------------------------------------------------------------
  896. //-----------------------------------------------------------------------------
  897. void CMapOverlay::ClipFace_BuildBlend( ClipFace_t *pClipFace, CMapDisp *pDisp,
  898. cplane_t *pClipPlane, int iClip,
  899. const Vector &vecUV, const Vector &vecPoint )
  900. {
  901. // Get the displacement space interval.
  902. int nWidth = pDisp->GetWidth();
  903. int nHeight = pDisp->GetHeight();
  904. float flU = vecUV.x * ( nWidth - 1.000001f );
  905. float flV = vecUV.y * ( nHeight - 1.000001f );
  906. // find the triangle the "uv spot" resides in
  907. int nSnapU = static_cast<int>( flU );
  908. int nSnapV = static_cast<int>( flV );
  909. if ( nSnapU == ( nWidth - 1 ) ) { --nSnapU; }
  910. if ( nSnapV == ( nHeight - 1 ) ) { --nSnapV; }
  911. int nNextU = nSnapU + 1;
  912. int nNextV = nSnapV + 1;
  913. float flFracU = flU - static_cast<float>( nSnapU );
  914. float flFracV = flV - static_cast<float>( nSnapV );
  915. int iAxisType = ClipFace_GetAxisType( pClipPlane );
  916. switch( iAxisType )
  917. {
  918. case OVERLAY_ANGLE0:
  919. {
  920. // Vert type
  921. if ( fabs( flFracU ) < OVERLAY_DISPSPACE_EPSILON )
  922. {
  923. pClipFace->m_aBlends[pClipFace->m_nPointCount].m_nType = OVERLAY_BLENDTYPE_VERT;
  924. pClipFace->m_aBlends[pClipFace->m_nPointCount].m_iPoints[0] = ( nWidth * iClip ) + nSnapU;
  925. }
  926. // Edge type
  927. else
  928. {
  929. pClipFace->m_aBlends[pClipFace->m_nPointCount].m_nType = OVERLAY_BLENDTYPE_EDGE;
  930. int iPoint0 = ( nWidth * iClip ) + nSnapU;
  931. int iPoint1 = ( nWidth * iClip ) + nNextU;
  932. pClipFace->m_aBlends[pClipFace->m_nPointCount].m_iPoints[0] = iPoint0;
  933. pClipFace->m_aBlends[pClipFace->m_nPointCount].m_iPoints[1] = iPoint1;
  934. pClipFace->m_aBlends[pClipFace->m_nPointCount].m_flBlends[0] = flFracU;
  935. }
  936. return;
  937. }
  938. case OVERLAY_ANGLE45:
  939. {
  940. // Vert type
  941. if ( ( fabs( flFracU ) < OVERLAY_DISPSPACE_EPSILON ) &&
  942. ( fabs( flFracV ) < OVERLAY_DISPSPACE_EPSILON ) )
  943. {
  944. pClipFace->m_aBlends[pClipFace->m_nPointCount].m_nType = OVERLAY_BLENDTYPE_VERT;
  945. pClipFace->m_aBlends[pClipFace->m_nPointCount].m_iPoints[0] = ( nWidth * nSnapV ) + nSnapU;
  946. }
  947. // Edge type
  948. else
  949. {
  950. pClipFace->m_aBlends[pClipFace->m_nPointCount].m_nType = OVERLAY_BLENDTYPE_EDGE;
  951. int iPoint0 = ( nWidth * nNextV ) + nSnapU;
  952. int iPoint1 = ( nWidth * nSnapV ) + nNextU;
  953. pClipFace->m_aBlends[pClipFace->m_nPointCount].m_iPoints[0] = iPoint0;
  954. pClipFace->m_aBlends[pClipFace->m_nPointCount].m_iPoints[1] = iPoint1;
  955. pClipFace->m_aBlends[pClipFace->m_nPointCount].m_flBlends[0] = flFracU;
  956. }
  957. return;
  958. }
  959. case OVERLAY_ANGLE90:
  960. {
  961. // Vert type
  962. if ( fabs( flFracV ) < OVERLAY_DISPSPACE_EPSILON )
  963. {
  964. pClipFace->m_aBlends[pClipFace->m_nPointCount].m_nType = OVERLAY_BLENDTYPE_VERT;
  965. pClipFace->m_aBlends[pClipFace->m_nPointCount].m_iPoints[0] = ( nWidth * nSnapV ) + iClip;
  966. }
  967. // Edge type
  968. else
  969. {
  970. pClipFace->m_aBlends[pClipFace->m_nPointCount].m_nType = OVERLAY_BLENDTYPE_EDGE;
  971. int iPoint0 = ( nWidth * nSnapV ) + iClip;
  972. int iPoint1 = ( nWidth * nNextV ) + iClip;
  973. pClipFace->m_aBlends[pClipFace->m_nPointCount].m_iPoints[0] = iPoint0;
  974. pClipFace->m_aBlends[pClipFace->m_nPointCount].m_iPoints[1] = iPoint1;
  975. pClipFace->m_aBlends[pClipFace->m_nPointCount].m_flBlends[0] = flFracV;
  976. }
  977. return;
  978. }
  979. case OVERLAY_ANGLE135:
  980. {
  981. // Vert type
  982. if ( ( fabs( flFracU ) < OVERLAY_DISPSPACE_EPSILON ) &&
  983. ( fabs( flFracV ) < OVERLAY_DISPSPACE_EPSILON ) )
  984. {
  985. pClipFace->m_aBlends[pClipFace->m_nPointCount].m_nType = OVERLAY_BLENDTYPE_VERT;
  986. pClipFace->m_aBlends[pClipFace->m_nPointCount].m_iPoints[0] = ( nWidth * nSnapV ) + nSnapU;
  987. }
  988. // Edge type
  989. else
  990. {
  991. pClipFace->m_aBlends[pClipFace->m_nPointCount].m_nType = OVERLAY_BLENDTYPE_EDGE;
  992. int iPoint0 = ( nWidth * nSnapV ) + nSnapU;
  993. int iPoint1 = ( nWidth * nNextV ) + nNextU;
  994. pClipFace->m_aBlends[pClipFace->m_nPointCount].m_iPoints[0] = iPoint0;
  995. pClipFace->m_aBlends[pClipFace->m_nPointCount].m_iPoints[1] = iPoint1;
  996. pClipFace->m_aBlends[pClipFace->m_nPointCount].m_flBlends[0] = flFracU;
  997. }
  998. return;
  999. }
  1000. }
  1001. }
  1002. //-----------------------------------------------------------------------------
  1003. //-----------------------------------------------------------------------------
  1004. void CMapOverlay::ClipFace_CopyBlendFrom( ClipFace_t *pClipFace, BlendData_t *pBlendFrom )
  1005. {
  1006. pClipFace->m_aBlends[pClipFace->m_nPointCount].m_nType = pBlendFrom->m_nType;
  1007. for ( int iPoint = 0; iPoint < 3; iPoint++ )
  1008. {
  1009. pClipFace->m_aBlends[pClipFace->m_nPointCount].m_iPoints[iPoint] = pBlendFrom->m_iPoints[iPoint];
  1010. pClipFace->m_aBlends[pClipFace->m_nPointCount].m_flBlends[iPoint] = pBlendFrom->m_flBlends[iPoint];
  1011. }
  1012. }
  1013. //-----------------------------------------------------------------------------
  1014. //-----------------------------------------------------------------------------
  1015. void CMapOverlay::ClipFace_BuildFacesFromBlendedData( ClipFace_t *pClipFace )
  1016. {
  1017. if( pClipFace->m_pBuildFace->HasDisp() )
  1018. {
  1019. EditDispHandle_t handle = pClipFace->m_pBuildFace->GetDisp();
  1020. CMapDisp *pDisp = EditDispMgr()->GetDisp( handle );
  1021. Vector vecPos[3];
  1022. Vector vecNormal[3];
  1023. for ( int iPoint = 0; iPoint < pClipFace->m_nPointCount; iPoint++ )
  1024. {
  1025. if ( pClipFace->m_aBlends[iPoint].m_nType == OVERLAY_BLENDTYPE_VERT )
  1026. {
  1027. pDisp->GetVert( pClipFace->m_aBlends[iPoint].m_iPoints[0], vecPos[0] );
  1028. pClipFace->m_aPoints[iPoint] = vecPos[0];
  1029. }
  1030. else if ( pClipFace->m_aBlends[iPoint].m_nType == OVERLAY_BLENDTYPE_EDGE )
  1031. {
  1032. pDisp->GetVert( pClipFace->m_aBlends[iPoint].m_iPoints[0], vecPos[0] );
  1033. pDisp->GetVert( pClipFace->m_aBlends[iPoint].m_iPoints[1], vecPos[1] );
  1034. pClipFace->m_aPoints[iPoint] = vecPos[0] + ( vecPos[1] - vecPos[0] ) * pClipFace->m_aBlends[iPoint].m_flBlends[0];
  1035. }
  1036. else if ( pClipFace->m_aBlends[iPoint].m_nType == OVERLAY_BLENDTYPE_BARY )
  1037. {
  1038. pDisp->GetVert( pClipFace->m_aBlends[iPoint].m_iPoints[0], vecPos[0] );
  1039. pDisp->GetVert( pClipFace->m_aBlends[iPoint].m_iPoints[1], vecPos[1] );
  1040. pDisp->GetVert( pClipFace->m_aBlends[iPoint].m_iPoints[2], vecPos[2] );
  1041. pClipFace->m_aPoints[iPoint] = ( vecPos[0] * pClipFace->m_aBlends[iPoint].m_flBlends[0] ) +
  1042. ( vecPos[1] * pClipFace->m_aBlends[iPoint].m_flBlends[1] ) +
  1043. ( vecPos[2] * pClipFace->m_aBlends[iPoint].m_flBlends[2] );
  1044. }
  1045. }
  1046. }
  1047. }
  1048. //=============================================================================
  1049. //
  1050. // CMapOverlay Material Functions
  1051. //
  1052. int MaxComponent( const Vector &v0 )
  1053. {
  1054. int nMax = 0;
  1055. if ( FloatMakePositive( v0[1] ) > FloatMakePositive( v0[nMax] ) )
  1056. {
  1057. nMax = 1;
  1058. }
  1059. if ( FloatMakePositive( v0[2] ) > FloatMakePositive( v0[nMax] ) )
  1060. {
  1061. nMax = 2;
  1062. }
  1063. return nMax;
  1064. }
  1065. //-----------------------------------------------------------------------------
  1066. //-----------------------------------------------------------------------------
  1067. void CMapOverlay::Material_Clear( void )
  1068. {
  1069. m_Material.m_pTexture = NULL;
  1070. m_Material.m_vecTextureU.Init( 0.0f, 1.0f );
  1071. m_Material.m_vecTextureV.Init( 0.0f, 1.0f );
  1072. }
  1073. //-----------------------------------------------------------------------------
  1074. // Purpose:
  1075. //-----------------------------------------------------------------------------
  1076. void CMapOverlay::Material_TexCoordInit( void )
  1077. {
  1078. int nMaxU = MaxComponent( m_Basis.m_vecAxes[OVERLAY_BASIS_U] );
  1079. int nMaxV = MaxComponent( m_Basis.m_vecAxes[OVERLAY_BASIS_V] );
  1080. bool bUPos = m_Basis.m_vecAxes[OVERLAY_BASIS_U][nMaxU] >= 0.0f;
  1081. bool bVPos = m_Basis.m_vecAxes[OVERLAY_BASIS_V][nMaxV] >= 0.0f;
  1082. m_Material.m_vecTextureU.Init( 0.0f, 1.0f );
  1083. m_Material.m_vecTextureV.Init( 1.0f, 0.0f );
  1084. if ( ( bUPos && !bVPos ) || ( !bUPos && bVPos ) )
  1085. {
  1086. m_Material.m_vecTextureU.Init( 1.0f, 0.0f );
  1087. m_Material.m_vecTextureV.Init( 0.0f, 1.0f );
  1088. }
  1089. Material_UpdateParentKey();
  1090. }
  1091. //-----------------------------------------------------------------------------
  1092. //-----------------------------------------------------------------------------
  1093. void CMapOverlay::Material_Copy( Material_t *pSrc, Material_t *pDst )
  1094. {
  1095. pDst->m_pTexture = pSrc->m_pTexture;
  1096. pDst->m_vecTextureU = pSrc->m_vecTextureU;
  1097. pDst->m_vecTextureV = pSrc->m_vecTextureV;
  1098. }
  1099. //-----------------------------------------------------------------------------
  1100. // Purpose:
  1101. //-----------------------------------------------------------------------------
  1102. void CMapOverlay::Material_UpdateParentKey( void )
  1103. {
  1104. char szValue[80];
  1105. CMapEntity *pEntity = ( CMapEntity* )GetParent();
  1106. if ( pEntity )
  1107. {
  1108. sprintf( szValue, "%g", m_Material.m_vecTextureU.x );
  1109. pEntity->NotifyChildKeyChanged( this, "StartU", szValue );
  1110. sprintf( szValue, "%g", m_Material.m_vecTextureU.y );
  1111. pEntity->NotifyChildKeyChanged( this, "EndU", szValue );
  1112. sprintf( szValue, "%g", m_Material.m_vecTextureV.x );
  1113. pEntity->NotifyChildKeyChanged( this, "StartV", szValue );
  1114. sprintf( szValue, "%g", m_Material.m_vecTextureV.y );
  1115. pEntity->NotifyChildKeyChanged( this, "EndV", szValue );
  1116. }
  1117. }
  1118. //=============================================================================
  1119. //
  1120. // CMapOverlay Functions
  1121. //
  1122. //-----------------------------------------------------------------------------
  1123. // Purpose: Construct a CMapOverlay instance.
  1124. //-----------------------------------------------------------------------------
  1125. CMapOverlay::CMapOverlay() : CMapSideList( "sides" )
  1126. {
  1127. Basis_Clear();
  1128. Handles_Clear();
  1129. Material_Clear();
  1130. m_bLoaded = false;
  1131. m_pOverlayFace = NULL;
  1132. m_uiFlags = 0;
  1133. }
  1134. //-----------------------------------------------------------------------------
  1135. // Purpose: Destruct a CMapOverlay instance.
  1136. //-----------------------------------------------------------------------------
  1137. CMapOverlay::~CMapOverlay()
  1138. {
  1139. ClipFace_Destroy( &m_pOverlayFace );
  1140. m_aRenderFaces.PurgeAndDeleteElements();
  1141. }
  1142. //-----------------------------------------------------------------------------
  1143. //-----------------------------------------------------------------------------
  1144. CMapClass *CMapOverlay::CreateMapOverlay( CHelperInfo *pInfo, CMapEntity *pParent )
  1145. {
  1146. CMapOverlay *pOverlay = new CMapOverlay;
  1147. return pOverlay;
  1148. }
  1149. //-----------------------------------------------------------------------------
  1150. // Purpose: Called after the entire map has been loaded. This allows the object
  1151. // to perform any linking with other map objects or to do other operations
  1152. // that require all world objects to be present.
  1153. // Input : pWorld - The world that we are in.
  1154. //-----------------------------------------------------------------------------
  1155. void CMapOverlay::PostloadWorld( CMapWorld *pWorld )
  1156. {
  1157. CMapSideList::PostloadWorld( pWorld );
  1158. // Support older overlay versions which didn't have specific basis axes.
  1159. if ( !Basis_IsValid() )
  1160. {
  1161. Basis_BuildFromSideList();
  1162. }
  1163. Handles_Build3D();
  1164. DoClip();
  1165. CalcBounds();
  1166. m_bLoaded = true;
  1167. }
  1168. //-----------------------------------------------------------------------------
  1169. //-----------------------------------------------------------------------------
  1170. CMapClass *CMapOverlay::Copy( bool bUpdateDependencies )
  1171. {
  1172. CMapOverlay *pCopy = new CMapOverlay;
  1173. if ( pCopy )
  1174. {
  1175. pCopy->CopyFrom( this, bUpdateDependencies );
  1176. }
  1177. return pCopy;
  1178. }
  1179. void CMapOverlay::Handles_FixOrder()
  1180. {
  1181. static bool s_FixingHandles = false;
  1182. // make sure that handle order and plane normal are in sync so CCW culling works correctly
  1183. Vector vNormal = GetNormalFromPoints( m_Handles.m_vec3D[0], m_Handles.m_vec3D[1], m_Handles.m_vec3D[2] );
  1184. if ( DotProduct( vNormal, m_Basis.m_vecAxes[OVERLAY_BASIS_NORMAL]) < 0.5 )
  1185. {
  1186. // dont try to fix twice
  1187. if ( s_FixingHandles )
  1188. {
  1189. Assert( !s_FixingHandles );
  1190. return;
  1191. }
  1192. s_FixingHandles = true;
  1193. // Flip handles.
  1194. Vector2D vecCoords[OVERLAY_HANDLES_COUNT];
  1195. for ( int iHandle = 0; iHandle < OVERLAY_HANDLES_COUNT; iHandle++ )
  1196. {
  1197. vecCoords[4-iHandle-1] = m_Handles.m_vecBasisCoords[iHandle];
  1198. }
  1199. for ( int iHandle = 0; iHandle < OVERLAY_HANDLES_COUNT; iHandle++ )
  1200. {
  1201. m_Handles.m_vecBasisCoords[iHandle] = vecCoords[iHandle];
  1202. }
  1203. // rebuild handles
  1204. Handles_Build3D();
  1205. s_FixingHandles = false;
  1206. }
  1207. }
  1208. //-----------------------------------------------------------------------------
  1209. //-----------------------------------------------------------------------------
  1210. CMapClass *CMapOverlay::CopyFrom( CMapClass *pObject, bool bUpdateDependencies )
  1211. {
  1212. // Verify the object is of the correct type and cast.
  1213. Assert( pObject->IsMapClass( MAPCLASS_TYPE( CMapOverlay ) ) );
  1214. CMapOverlay *pFrom = ( CMapOverlay* )pObject;
  1215. if ( pFrom )
  1216. {
  1217. // Copy the parent class data.
  1218. CMapSideList::CopyFrom( pObject, bUpdateDependencies );
  1219. // Copy basis data.
  1220. Basis_Copy( &pFrom->m_Basis, &m_Basis );
  1221. // Copy handle data.
  1222. Handles_Copy( &pFrom->m_Handles, &m_Handles );
  1223. // Copy material data.
  1224. Material_Copy( &pFrom->m_Material, &m_Material );
  1225. }
  1226. return this;
  1227. }
  1228. //-----------------------------------------------------------------------------
  1229. // Purpose: Notify me when a key has had a data change, so the overlay can
  1230. // update itself appropriately.
  1231. // Input: szKey - the key that changed
  1232. // szValue - the new value (key/data pair)
  1233. //-----------------------------------------------------------------------------
  1234. void CMapOverlay::OnParentKeyChanged( const char* szKey, const char* szValue )
  1235. {
  1236. // Pass this to the sidelist first.
  1237. CMapSideList::OnParentKeyChanged( szKey, szValue );
  1238. // Read side data.
  1239. if ( !stricmp( szKey, "sides" ) )
  1240. {
  1241. if ( m_Faces.Count() > 0 )
  1242. {
  1243. Basis_SetFace( m_Faces.Element( 0 ) );
  1244. }
  1245. }
  1246. // Read geometry data.
  1247. float flDummy;
  1248. if ( !stricmp( szKey, "uv0" ) )
  1249. {
  1250. sscanf( szValue, "%f %f %f", &m_Handles.m_vecBasisCoords[0].x, &m_Handles.m_vecBasisCoords[0].y, &flDummy );
  1251. m_Basis.m_nAxesFlip[0] = ( int )flDummy;
  1252. }
  1253. if ( !stricmp( szKey, "uv1" ) )
  1254. {
  1255. sscanf( szValue, "%f %f %f", &m_Handles.m_vecBasisCoords[1].x, &m_Handles.m_vecBasisCoords[1].y, &flDummy );
  1256. m_Basis.m_nAxesFlip[1] = ( int )flDummy;
  1257. }
  1258. if ( !stricmp( szKey, "uv2" ) )
  1259. {
  1260. sscanf( szValue, "%f %f %f", &m_Handles.m_vecBasisCoords[2].x, &m_Handles.m_vecBasisCoords[2].y, &flDummy );
  1261. m_Basis.m_nAxesFlip[2] = ( int )flDummy;
  1262. }
  1263. if ( !stricmp( szKey, "uv3" ) )
  1264. {
  1265. sscanf( szValue, "%f %f %f", &m_Handles.m_vecBasisCoords[3].x, &m_Handles.m_vecBasisCoords[3].y, &flDummy );
  1266. }
  1267. // Read basis data.
  1268. if ( !stricmp( szKey, "BasisOrigin" ) )
  1269. {
  1270. sscanf( szValue, "%f %f %f", &m_Basis.m_vecOrigin.x, &m_Basis.m_vecOrigin.y, &m_Basis.m_vecOrigin.z );
  1271. }
  1272. if ( !stricmp( szKey, "BasisU" ) )
  1273. {
  1274. sscanf( szValue, "%f %f %f", &m_Basis.m_vecAxes[OVERLAY_BASIS_U].x, &m_Basis.m_vecAxes[OVERLAY_BASIS_U].y, &m_Basis.m_vecAxes[OVERLAY_BASIS_U].z );
  1275. }
  1276. if ( !stricmp( szKey, "BasisV" ) )
  1277. {
  1278. sscanf( szValue, "%f %f %f", &m_Basis.m_vecAxes[OVERLAY_BASIS_V].x, &m_Basis.m_vecAxes[OVERLAY_BASIS_V].y, &m_Basis.m_vecAxes[OVERLAY_BASIS_V].z );
  1279. }
  1280. if ( !stricmp( szKey, "BasisNormal" ) )
  1281. {
  1282. sscanf( szValue, "%f %f %f", &m_Basis.m_vecAxes[OVERLAY_BASIS_NORMAL].x, &m_Basis.m_vecAxes[OVERLAY_BASIS_NORMAL].y, &m_Basis.m_vecAxes[OVERLAY_BASIS_NORMAL].z );
  1283. }
  1284. // Read material data.
  1285. if ( !stricmp( szKey, "material" ) )
  1286. {
  1287. // Get the new material.
  1288. IEditorTexture *pTex = g_Textures.FindActiveTexture( szValue );
  1289. if ( !pTex )
  1290. return;
  1291. // Save the new material.
  1292. m_Material.m_pTexture = pTex;
  1293. }
  1294. if ( !stricmp( szKey, "StartU" ) )
  1295. {
  1296. m_Material.m_vecTextureU.x = atof( szValue );
  1297. }
  1298. if ( !stricmp( szKey, "EndU" ) )
  1299. {
  1300. m_Material.m_vecTextureU.y = atof( szValue );
  1301. }
  1302. if ( !stricmp( szKey, "StartV" ) )
  1303. {
  1304. m_Material.m_vecTextureV.x = atof( szValue );
  1305. }
  1306. if ( !stricmp( szKey, "EndV" ) )
  1307. {
  1308. m_Material.m_vecTextureV.y = atof( szValue );
  1309. }
  1310. if ( m_bLoaded )
  1311. {
  1312. // Clip - this needs to be done for everything other than a material change, so go ahead.
  1313. DoClip();
  1314. // Post updated.
  1315. PostUpdate( Notify_Changed );
  1316. }
  1317. }
  1318. //-----------------------------------------------------------------------------
  1319. //-----------------------------------------------------------------------------
  1320. void CMapOverlay::OnUndoRedo( void )
  1321. {
  1322. PostModified();
  1323. }
  1324. //-----------------------------------------------------------------------------
  1325. //-----------------------------------------------------------------------------
  1326. void CMapOverlay::CalcBounds( BOOL bFullUpdate )
  1327. {
  1328. // Pass the info along.
  1329. CMapSideList::CalcBounds( bFullUpdate );
  1330. // Verify that we have valid data.
  1331. if ( !Basis_IsValid() )
  1332. return;
  1333. // Calculate the 2d bounds.
  1334. Vector vecMins, vecMaxs;
  1335. vecMins = m_Origin - Vector( 2.0f, 2.0f, 2.0f );
  1336. vecMaxs = m_Origin + Vector( 2.0f, 2.0f, 2.0f );
  1337. // Reset bounds
  1338. m_CullBox.ResetBounds();
  1339. m_Render2DBox.ResetBounds();
  1340. for ( int iHandle = 0; iHandle < 4; ++iHandle )
  1341. {
  1342. for ( int iAxis = 0; iAxis < 3; ++iAxis )
  1343. {
  1344. // Min
  1345. if ( m_Handles.m_vec3D[iHandle][iAxis] < vecMins[iAxis] )
  1346. {
  1347. vecMins[iAxis] = m_Handles.m_vec3D[iHandle][iAxis];
  1348. }
  1349. // Max
  1350. if ( m_Handles.m_vec3D[iHandle][iAxis] > vecMaxs[iAxis] )
  1351. {
  1352. vecMaxs[iAxis] = m_Handles.m_vec3D[iHandle][iAxis];
  1353. }
  1354. }
  1355. }
  1356. // Don't allow for NULL bounds.
  1357. for ( int iAxis = 0; iAxis < 3; ++iAxis )
  1358. {
  1359. if( ( vecMaxs[iAxis] - vecMins[iAxis] ) == 0.0f )
  1360. {
  1361. vecMins[iAxis] -= 0.5f;
  1362. vecMaxs[iAxis] += 0.5f;
  1363. }
  1364. }
  1365. // Update the bounds.
  1366. m_CullBox.UpdateBounds( vecMins, vecMaxs );
  1367. m_BoundingBox = m_CullBox;
  1368. m_Render2DBox.UpdateBounds( vecMins, vecMaxs );
  1369. }
  1370. //-----------------------------------------------------------------------------
  1371. // Purpose:
  1372. //-----------------------------------------------------------------------------
  1373. void CMapOverlay::PostModified( void )
  1374. {
  1375. // update face and origin
  1376. if ( m_Faces.Count() > 0 )
  1377. {
  1378. Basis_SetFace( m_Faces.Element( 0 ) );
  1379. Basis_UpdateOrigin();
  1380. }
  1381. else
  1382. {
  1383. m_Basis.m_pFace = NULL;
  1384. }
  1385. Handles_Build3D();
  1386. DoClip();
  1387. }
  1388. //-----------------------------------------------------------------------------
  1389. // Purpose:
  1390. // Input : pTransBox -
  1391. //-----------------------------------------------------------------------------
  1392. void CMapOverlay::DoTransform( const VMatrix &matrix )
  1393. {
  1394. BaseClass::DoTransform( matrix );
  1395. VMatrix tmpMatrix = matrix;
  1396. // erase move component
  1397. tmpMatrix.SetTranslation( vec3_origin );
  1398. // check if matrix would still change something
  1399. if ( !tmpMatrix.IsIdentity() )
  1400. {
  1401. // make sure axes are normalized (they should be anyways)
  1402. m_Basis.m_vecAxes[OVERLAY_BASIS_U].NormalizeInPlace();
  1403. m_Basis.m_vecAxes[OVERLAY_BASIS_V].NormalizeInPlace();
  1404. Vector vecU = m_Basis.m_vecAxes[OVERLAY_BASIS_U];
  1405. Vector vecV = m_Basis.m_vecAxes[OVERLAY_BASIS_V];
  1406. Vector vecNormal = m_Basis.m_vecAxes[OVERLAY_BASIS_NORMAL];
  1407. TransformPoint( tmpMatrix, vecU );
  1408. TransformPoint( tmpMatrix, vecV );
  1409. TransformPoint( tmpMatrix, vecNormal );
  1410. float fScaleU = vecU.Length();
  1411. float fScaleV = vecV.Length();
  1412. float flScaleNormal = vecNormal.Length();
  1413. bool bIsUnit = ( fequal( fScaleU, 1.0f, 0.0001 ) && fequal( fScaleV, 1.0f, 0.0001 ) && fequal( flScaleNormal, 1.0f, 0.0001 ) );
  1414. bool bIsPerp = ( fequal( DotProduct( vecU, vecV ), 0.0f, 0.0025 ) && fequal( DotProduct( vecU, vecNormal ), 0.0f, 0.0025 ) && fequal( DotProduct( vecV, vecNormal ), 0.0f, 0.0025 ) );
  1415. // if ( fequal(fScaleU,1,0.0001) && fequal(fScaleV,1,0.0001) && fequal(DotProduct( vecU, vecV ),0,0.0025) )
  1416. if ( bIsUnit && bIsPerp )
  1417. {
  1418. // transformation doesnt scale or shear anything, so just update base axes
  1419. m_Basis.m_vecAxes[OVERLAY_BASIS_U] = vecU;
  1420. m_Basis.m_vecAxes[OVERLAY_BASIS_V] = vecV;
  1421. m_Basis.m_vecAxes[OVERLAY_BASIS_NORMAL] = vecNormal;
  1422. }
  1423. else
  1424. {
  1425. // more complex transformation, move UV coordinates, but leave base axes
  1426. for ( int iHandle=0; iHandle<OVERLAY_HANDLES_COUNT;iHandle++)
  1427. {
  1428. Vector2D vecUV = m_Handles.m_vecBasisCoords[iHandle];
  1429. Vector vecPos = ( vecUV.x * m_Basis.m_vecAxes[OVERLAY_BASIS_U] + vecUV.y * m_Basis.m_vecAxes[OVERLAY_BASIS_V] );
  1430. // to transform in world space
  1431. TransformPoint( tmpMatrix, vecPos );
  1432. vecUV.x = m_Basis.m_vecAxes[OVERLAY_BASIS_U].Dot( vecPos );
  1433. vecUV.y = m_Basis.m_vecAxes[OVERLAY_BASIS_V].Dot( vecPos );
  1434. m_Handles.m_vecBasisCoords[iHandle] = vecUV;
  1435. }
  1436. if ( !Options.IsLockingTextures() )
  1437. {
  1438. // scale textures if locking is off
  1439. m_Material.m_vecTextureU *= fScaleU;
  1440. m_Material.m_vecTextureV *= fScaleV;
  1441. Material_UpdateParentKey();
  1442. }
  1443. }
  1444. }
  1445. // Send modified notice.
  1446. PostModified();
  1447. Handles_UpdateParentKey();
  1448. }
  1449. //-----------------------------------------------------------------------------
  1450. // Purpose: Notifies us that a copy of ourselves was pasted.
  1451. //-----------------------------------------------------------------------------
  1452. void CMapOverlay::OnPaste( CMapClass *pCopy, CMapWorld *pSourceWorld, CMapWorld *pDestWorld,
  1453. const CMapObjectList &OriginalList, CMapObjectList &NewList)
  1454. {
  1455. //
  1456. // NOTE: currently pCopy is the Overlay being pasted into the world, "this" is
  1457. // what is being copied from
  1458. //
  1459. CMapSideList::OnPaste( pCopy, pSourceWorld, pDestWorld, OriginalList, NewList );
  1460. CMapOverlay *pOverlay = dynamic_cast<CMapOverlay*>( pCopy );
  1461. if ( pOverlay )
  1462. {
  1463. pOverlay->PostModified();
  1464. }
  1465. }
  1466. //-----------------------------------------------------------------------------
  1467. // Purpose: Notifies us that we created a copy of ourselves (a clone).
  1468. //-----------------------------------------------------------------------------
  1469. void CMapOverlay::OnClone( CMapClass *pClone, CMapWorld *pWorld,
  1470. const CMapObjectList &OriginalList, CMapObjectList &NewList )
  1471. {
  1472. CMapSideList::OnClone( pClone, pWorld, OriginalList, NewList );
  1473. CMapOverlay *pOverlay = dynamic_cast<CMapOverlay*>( pClone );
  1474. if ( pOverlay )
  1475. {
  1476. if ( ( GetOverlayType() && OVERLAY_TYPE_SHORE ) == 0 )
  1477. {
  1478. // Update the clone's solid dependencies (this doesn't happen on clone generally).
  1479. int nFaceCount = pOverlay->GetFaceCount();
  1480. for ( int iFace = 0; iFace < nFaceCount; ++iFace )
  1481. {
  1482. CMapFace *pFace = pOverlay->GetFace( iFace );
  1483. CMapSolid *pSolid = ( CMapSolid* )pFace->GetParent();
  1484. pOverlay->UpdateDependency( NULL, pSolid );
  1485. }
  1486. }
  1487. pOverlay->PostModified();
  1488. }
  1489. }
  1490. //-----------------------------------------------------------------------------
  1491. // Purpose: Notifys this decal of a change to a solid that it is attached to.
  1492. //-----------------------------------------------------------------------------
  1493. void CMapOverlay::OnNotifyDependent( CMapClass *pObject, Notify_Dependent_t eNotifyType )
  1494. {
  1495. // Chain to base class FIRST so it can rebuild the face list if necessary.
  1496. CMapSideList::OnNotifyDependent( pObject, eNotifyType );
  1497. //
  1498. // NOTE: the solid moving (changing) can update the overlay/solid(face) dependency
  1499. // so "rebuild" the overlay
  1500. //
  1501. switch ( eNotifyType )
  1502. {
  1503. case Notify_Changed:
  1504. case Notify_Undo:
  1505. case Notify_Transform:
  1506. {
  1507. PostModified();
  1508. break;
  1509. }
  1510. case Notify_Removed:
  1511. case Notify_Clipped:
  1512. {
  1513. m_aRenderFaces.Purge();
  1514. PostModified();
  1515. break;
  1516. }
  1517. case Notify_Rebuild:
  1518. {
  1519. UpdateDispBarycentric();
  1520. break;
  1521. }
  1522. case Notify_Rebuild_Full:
  1523. {
  1524. DoClip();
  1525. CenterEntity();
  1526. Handles_Build3D();
  1527. break;
  1528. }
  1529. }
  1530. }
  1531. //-----------------------------------------------------------------------------
  1532. //-----------------------------------------------------------------------------
  1533. void CMapOverlay::Render3D( CRender3D *pRender )
  1534. {
  1535. int nFaceCount = m_aRenderFaces.Count();
  1536. if ( nFaceCount != 0 )
  1537. {
  1538. // dont draw textured during manipulating
  1539. if ( GetSelectionState() != SELECT_MODIFY )
  1540. {
  1541. // Bind the matrial -- if there is one!!
  1542. bool bTextured = false;
  1543. if ( m_Material.m_pTexture )
  1544. {
  1545. pRender->BindTexture( m_Material.m_pTexture );
  1546. pRender->PushRenderMode( RENDER_MODE_TEXTURED );
  1547. bTextured = true;
  1548. }
  1549. else
  1550. {
  1551. // Default state.
  1552. pRender->PushRenderMode( RENDER_MODE_FLAT );
  1553. }
  1554. for ( int iFace = 0; iFace < nFaceCount; iFace++ )
  1555. {
  1556. ClipFace_t *pRenderFace = m_aRenderFaces.Element( iFace );
  1557. if( !pRenderFace )
  1558. continue;
  1559. MaterialPrimitiveType_t type = MATERIAL_POLYGON;
  1560. // Get a dynamic mesh.
  1561. CMeshBuilder meshBuilder;
  1562. CMatRenderContextPtr pRenderContext( MaterialSystemInterface() );
  1563. IMesh* pMesh = pRenderContext->GetDynamicMesh();
  1564. meshBuilder.Begin( pMesh, type, pRenderFace->m_nPointCount );
  1565. for ( int iPoint = 0; iPoint < pRenderFace->m_nPointCount; iPoint++ )
  1566. {
  1567. if ( !bTextured )
  1568. {
  1569. meshBuilder.Color3ub( 0, 128, 0 );
  1570. }
  1571. else
  1572. {
  1573. meshBuilder.TexCoord2f( 0, pRenderFace->m_aTexCoords[0][iPoint].x, pRenderFace->m_aTexCoords[0][iPoint].y );
  1574. meshBuilder.TexCoord2f( 2, pRenderFace->m_aTexCoords[1][iPoint].x, pRenderFace->m_aTexCoords[1][iPoint].y );
  1575. meshBuilder.Color4ub( 255, 255, 255, 255 );
  1576. }
  1577. meshBuilder.Position3f( pRenderFace->m_aPoints[iPoint].x, pRenderFace->m_aPoints[iPoint].y, pRenderFace->m_aPoints[iPoint].z );
  1578. meshBuilder.Normal3f( pRenderFace->m_aNormals[iPoint].x, pRenderFace->m_aNormals[iPoint].y, pRenderFace->m_aNormals[iPoint].z );
  1579. meshBuilder.AdvanceVertex();
  1580. }
  1581. meshBuilder.End();
  1582. pMesh->Draw();
  1583. }
  1584. pRender->PopRenderMode();
  1585. }
  1586. // Render wireframe on top when seleted.
  1587. if ( GetSelectionState() != SELECT_NONE )
  1588. {
  1589. pRender->PushRenderMode( RENDER_MODE_WIREFRAME );
  1590. for ( int iFace = 0; iFace < nFaceCount; iFace++ )
  1591. {
  1592. ClipFace_t *pRenderFace = m_aRenderFaces.Element( iFace );
  1593. if( !pRenderFace )
  1594. continue;
  1595. MaterialPrimitiveType_t type = MATERIAL_LINE_LOOP;
  1596. // get a dynamic mesh
  1597. CMeshBuilder meshBuilder;
  1598. CMatRenderContextPtr pRenderContext( MaterialSystemInterface() );
  1599. IMesh* pMesh = pRenderContext->GetDynamicMesh();
  1600. meshBuilder.Begin( pMesh, type, pRenderFace->m_nPointCount );
  1601. for( int iPoint = 0; iPoint < pRenderFace->m_nPointCount; iPoint++ )
  1602. {
  1603. meshBuilder.Color3ub( 0, 255, 0 );
  1604. meshBuilder.Position3f( pRenderFace->m_aPoints[iPoint].x, pRenderFace->m_aPoints[iPoint].y, pRenderFace->m_aPoints[iPoint].z );
  1605. meshBuilder.Normal3f( pRenderFace->m_aNormals[iPoint].x, pRenderFace->m_aNormals[iPoint].y, pRenderFace->m_aNormals[iPoint].z );
  1606. meshBuilder.AdvanceVertex();
  1607. }
  1608. meshBuilder.End();
  1609. pMesh->Draw();
  1610. }
  1611. pRender->PopRenderMode();
  1612. }
  1613. }
  1614. // Render the handles - if selected or in overlay tool mode.
  1615. if ( ( ToolManager()->GetActiveToolID() == TOOL_OVERLAY ) && Basis_IsValid() && IsSelected() )
  1616. {
  1617. Handles_Render3D( pRender );
  1618. }
  1619. }
  1620. //-----------------------------------------------------------------------------
  1621. // Purpose: Clip the overlay "face" to all of the faces in the overlay sidelist.
  1622. // The sidelist defines all faces affected by the "overlay."
  1623. //-----------------------------------------------------------------------------
  1624. void CMapOverlay::DoClip( void )
  1625. {
  1626. // Check to see if we have any faces to clip against.
  1627. int nFaceCount = m_Faces.Count();
  1628. if( nFaceCount == 0 )
  1629. return;
  1630. // Destroy the render face cache.
  1631. m_aRenderFaces.Purge();
  1632. // clip the overlay against all faces in the sidelist
  1633. for ( int iFace = 0; iFace < nFaceCount; iFace++ )
  1634. {
  1635. CMapFace *pFace = m_Faces.Element( iFace );
  1636. if ( pFace )
  1637. {
  1638. PreClip();
  1639. DoClipFace( pFace );
  1640. PostClip();
  1641. }
  1642. }
  1643. }
  1644. //-----------------------------------------------------------------------------
  1645. //-----------------------------------------------------------------------------
  1646. void CMapOverlay::PreClip( void )
  1647. {
  1648. //
  1649. // Create the initial face to be clipped - the overlay.
  1650. //
  1651. m_pOverlayFace = ClipFace_Create( OVERLAY_HANDLES_COUNT );
  1652. if ( m_pOverlayFace )
  1653. {
  1654. for ( int iPoint = 0; iPoint < OVERLAY_HANDLES_COUNT; iPoint++ )
  1655. {
  1656. OverlayUVToOverlayPlane( m_Handles.m_vecBasisCoords[iPoint], m_pOverlayFace->m_aPoints[iPoint] );
  1657. // translate texture UV to texture coords:
  1658. Vector2D vTexCoord;
  1659. switch( iPoint )
  1660. {
  1661. case 0 : vTexCoord = Vector2D(m_Material.m_vecTextureU.x, m_Material.m_vecTextureV.x); break;
  1662. case 1 : vTexCoord = Vector2D(m_Material.m_vecTextureU.x, m_Material.m_vecTextureV.y); break;
  1663. case 2 : vTexCoord = Vector2D(m_Material.m_vecTextureU.y, m_Material.m_vecTextureV.y); break;
  1664. case 3 : vTexCoord = Vector2D(m_Material.m_vecTextureU.y, m_Material.m_vecTextureV.x); break;
  1665. default : Assert( iPoint <= OVERLAY_HANDLES_COUNT);
  1666. }
  1667. m_pOverlayFace->m_aTexCoords[0][iPoint] = vTexCoord;
  1668. if ( m_Basis.m_pFace->HasDisp() )
  1669. {
  1670. EditDispHandle_t handle = m_Basis.m_pFace->GetDisp();
  1671. CMapDisp *pDisp = EditDispMgr()->GetDisp( handle );
  1672. if ( pDisp )
  1673. {
  1674. Vector2D vecTmp;
  1675. pDisp->BaseFacePlaneToDispUV( m_pOverlayFace->m_aPoints[iPoint], vecTmp );
  1676. m_pOverlayFace->m_aDispPointUVs[iPoint].x = vecTmp.x;
  1677. m_pOverlayFace->m_aDispPointUVs[iPoint].y = vecTmp.y;
  1678. m_pOverlayFace->m_aDispPointUVs[iPoint].z = 0.0f;
  1679. }
  1680. }
  1681. }
  1682. // The second set of texcoords on the overlay is used for alpha by certain shaders,
  1683. // and they want to stretch the texture across the whole overlay.
  1684. m_pOverlayFace->m_aTexCoords[1][0].Init( 0, 0 );
  1685. m_pOverlayFace->m_aTexCoords[1][1].Init( 0, 1 );
  1686. m_pOverlayFace->m_aTexCoords[1][2].Init( 1, 1 );
  1687. m_pOverlayFace->m_aTexCoords[1][3].Init( 1, 0 );
  1688. }
  1689. }
  1690. //-----------------------------------------------------------------------------
  1691. //-----------------------------------------------------------------------------
  1692. void CMapOverlay::PostClip( void )
  1693. {
  1694. ClipFace_Destroy( &m_pOverlayFace );
  1695. }
  1696. //-----------------------------------------------------------------------------
  1697. //-----------------------------------------------------------------------------
  1698. void CMapOverlay::DoClipFace( CMapFace *pFace )
  1699. {
  1700. // Valid face?
  1701. Assert( pFace != NULL );
  1702. if( !pFace )
  1703. return;
  1704. // Copy the original overlay to the "clipped" overlay.
  1705. ClipFace_t *pClippedFace = ClipFace_Copy( m_pOverlayFace );
  1706. if ( !pClippedFace )
  1707. return;
  1708. //
  1709. // Project all face points into the overlay plane.
  1710. //
  1711. int nPointCount = pFace->nPoints;
  1712. Vector *pPoints = new Vector[nPointCount];
  1713. int nEdgePlaneCount = nPointCount;
  1714. cplane_t *pEdgePlanes = new cplane_t[nEdgePlaneCount];
  1715. if ( !pPoints || !pEdgePlanes )
  1716. {
  1717. delete [] pPoints;
  1718. delete [] pEdgePlanes;
  1719. return;
  1720. }
  1721. for ( int iPoint = 0; iPoint < nPointCount; iPoint++ )
  1722. {
  1723. WorldToOverlayPlane( pFace->Points[iPoint], pPoints[iPoint] );
  1724. }
  1725. // Create the face clipping planes (edges cross overlay plane normal).
  1726. BuildEdgePlanes( pPoints, nPointCount, pEdgePlanes, nEdgePlaneCount );
  1727. //
  1728. // Clip overlay against all the edge planes.
  1729. //
  1730. for ( int iClipPlane = 0; iClipPlane < nEdgePlaneCount; iClipPlane++ )
  1731. {
  1732. ClipFace_t *pFront = NULL;
  1733. ClipFace_t *pBack = NULL;
  1734. if ( pClippedFace )
  1735. {
  1736. // Clip the overlay and delete the data (we are done with it - we are only interested in what is left).
  1737. ClipFace_Clip( pClippedFace, &pEdgePlanes[iClipPlane], OVERLAY_WORLDSPACE_EPSILON, &pFront, &pBack );
  1738. ClipFace_Destroy( &pClippedFace );
  1739. // Keep the backside -- if it exists and continue clipping.
  1740. if ( pBack )
  1741. {
  1742. pClippedFace = pBack;
  1743. }
  1744. // Destroy the front side -- if it exists.
  1745. if ( pFront )
  1746. {
  1747. ClipFace_Destroy( &pFront );
  1748. }
  1749. }
  1750. }
  1751. //
  1752. // Free temporary memory (clip planes and point).
  1753. //
  1754. delete [] pPoints;
  1755. delete [] pEdgePlanes;
  1756. //
  1757. // If it exists, move points from the overlay plane back into
  1758. // the base face plane.
  1759. //
  1760. if ( !pClippedFace )
  1761. return;
  1762. for ( int iPoint = 0; iPoint < pClippedFace->m_nPointCount; iPoint++ )
  1763. {
  1764. Vector2D vecUV;
  1765. PointInQuadToBarycentric( m_pOverlayFace->m_aPoints[0], m_pOverlayFace->m_aPoints[3],
  1766. m_pOverlayFace->m_aPoints[2], m_pOverlayFace->m_aPoints[1],
  1767. pClippedFace->m_aPoints[iPoint], vecUV );
  1768. Vector vecTmp;
  1769. OverlayPlaneToWorld( pFace, pClippedFace->m_aPoints[iPoint], vecTmp );
  1770. pClippedFace->m_aPoints[iPoint] = vecTmp;
  1771. Vector2D vecTexCoord;
  1772. for ( int iTexCoord=0; iTexCoord < NUM_CLIPFACE_TEXCOORDS; iTexCoord++ )
  1773. {
  1774. TexCoordInQuadFromBarycentric( m_pOverlayFace->m_aTexCoords[iTexCoord][0], m_pOverlayFace->m_aTexCoords[iTexCoord][3],
  1775. m_pOverlayFace->m_aTexCoords[iTexCoord][2], m_pOverlayFace->m_aTexCoords[iTexCoord][1],
  1776. vecUV, vecTexCoord );
  1777. pClippedFace->m_aTexCoords[iTexCoord][iPoint] = vecTexCoord;
  1778. }
  1779. }
  1780. //
  1781. // If the face has a displacement map -- continue clipping.
  1782. //
  1783. if( pFace->HasDisp() )
  1784. {
  1785. DoClipDisp( pFace, pClippedFace );
  1786. }
  1787. // Done - save it!
  1788. else
  1789. {
  1790. pClippedFace->m_pBuildFace = pFace;
  1791. m_aRenderFaces.AddToTail( pClippedFace );
  1792. }
  1793. }
  1794. //-----------------------------------------------------------------------------
  1795. //-----------------------------------------------------------------------------
  1796. bool CMapOverlay::BuildEdgePlanes( Vector const *pPoints, int nPointCount,
  1797. cplane_t *pEdgePlanes, int nEdgePlaneCount )
  1798. {
  1799. for ( int iPoint = 0; iPoint < nPointCount; iPoint++ )
  1800. {
  1801. Vector vecEdge;
  1802. vecEdge = pPoints[(iPoint+1)%nPointCount] - pPoints[iPoint];
  1803. VectorNormalize( vecEdge );
  1804. pEdgePlanes[iPoint].normal = m_Basis.m_vecAxes[OVERLAY_BASIS_NORMAL].Cross( vecEdge );
  1805. pEdgePlanes[iPoint].dist = pEdgePlanes[iPoint].normal.Dot( pPoints[iPoint] );
  1806. // Check normal facing.
  1807. float flDist = pEdgePlanes[iPoint].normal.Dot( pPoints[(iPoint+2)%nPointCount] ) - pEdgePlanes[iPoint].dist;
  1808. if( flDist > 0.0f )
  1809. {
  1810. // flip
  1811. pEdgePlanes[iPoint].normal.Negate();
  1812. pEdgePlanes[iPoint].dist = -pEdgePlanes[iPoint].dist;
  1813. }
  1814. }
  1815. return true;
  1816. }
  1817. //-----------------------------------------------------------------------------
  1818. // Purpose:
  1819. //-----------------------------------------------------------------------------
  1820. void CMapOverlay::Disp_ClipFragments( CMapDisp *pDisp, ClipFaces_t &aDispFragments )
  1821. {
  1822. cplane_t clipPlane;
  1823. // Cache the displacement interval.
  1824. int nInterval = pDisp->GetWidth() - 1;
  1825. // Displacement-space clipping in V.
  1826. clipPlane.normal.Init( 1.0f, 0.0f, 0.0f );
  1827. Disp_DoClip( pDisp, aDispFragments, clipPlane, 1.0f, nInterval, 1, nInterval, 1 );
  1828. // Displacement-space clipping in U.
  1829. clipPlane.normal.Init( 0.0f, 1.0f, 0.0f );
  1830. Disp_DoClip( pDisp, aDispFragments, clipPlane, 1.0f, nInterval, 1, nInterval, 1 );
  1831. // Displacement-space clipping UV from top-left to bottom-right.
  1832. clipPlane.normal.Init( 0.707f, 0.707f, 0.0f ); // 45 degrees
  1833. Disp_DoClip( pDisp, aDispFragments, clipPlane, 0.707f, nInterval, 2, ( nInterval * 2 - 1 ), 2 );
  1834. // Displacement-space clipping UV from bottom-left to top-right.
  1835. clipPlane.normal.Init( -0.707f, 0.707f, 0.0f ); // 135 degrees
  1836. Disp_DoClip( pDisp, aDispFragments, clipPlane, 0.707f, nInterval, -( nInterval - 2 ), ( nInterval - 1 ), 2 );
  1837. }
  1838. //-----------------------------------------------------------------------------
  1839. // Purpose:
  1840. //-----------------------------------------------------------------------------
  1841. void CMapOverlay::Disp_DoClip( CMapDisp *pDisp, ClipFaces_t &aDispFragments,
  1842. cplane_t &clipPlane, float clipDistStart, int nInterval,
  1843. int nLoopStart, int nLoopEnd, int nLoopInc )
  1844. {
  1845. // Setup interval information.
  1846. float flInterval = static_cast<float>( nInterval );
  1847. float flOOInterval = 1.0f / flInterval;
  1848. // Holds the current set of clipped faces.
  1849. ClipFaces_t aClippedFragments;
  1850. for ( int iInterval = nLoopStart; iInterval < nLoopEnd; iInterval += nLoopInc )
  1851. {
  1852. // Copy the current list to clipped face list.
  1853. aClippedFragments.CopyArray( aDispFragments.Base(), aDispFragments.Count() );
  1854. aDispFragments.Purge();
  1855. // Clip in V.
  1856. int nFragCount = aClippedFragments.Count();
  1857. for ( int iFrag = 0; iFrag < nFragCount; iFrag++ )
  1858. {
  1859. ClipFace_t *pClipFrag = aClippedFragments[iFrag];
  1860. if ( pClipFrag )
  1861. {
  1862. ClipFace_t *pFront = NULL, *pBack = NULL;
  1863. clipPlane.dist = clipDistStart * ( ( float )iInterval * flOOInterval );
  1864. ClipFace_ClipBarycentric( pClipFrag, &clipPlane, OVERLAY_DISPSPACE_EPSILON, iInterval, pDisp, &pFront, &pBack );
  1865. ClipFace_Destroy( &pClipFrag );
  1866. if ( pFront )
  1867. {
  1868. aDispFragments.AddToTail( pFront );
  1869. }
  1870. if ( pBack )
  1871. {
  1872. aDispFragments.AddToTail( pBack );
  1873. }
  1874. }
  1875. }
  1876. }
  1877. // Clean up!
  1878. aClippedFragments.Purge();
  1879. }
  1880. //-----------------------------------------------------------------------------
  1881. //-----------------------------------------------------------------------------
  1882. void CMapOverlay::DoClipDisp( CMapFace *pFace, ClipFace_t *pClippedFace )
  1883. {
  1884. // Get the displacement data.
  1885. EditDispHandle_t handle = pFace->GetDisp();
  1886. CMapDisp *pDisp = EditDispMgr()->GetDisp( handle );
  1887. // Initialize local clip data.
  1888. ClipFace_PreClipDisp( pClippedFace, pDisp );
  1889. // Setup clipped face lists.
  1890. ClipFaces_t aCurrentFaces;
  1891. aCurrentFaces.AddToTail( pClippedFace );
  1892. Disp_ClipFragments( pDisp, aCurrentFaces );
  1893. //
  1894. // Project points back onto the displacement surface.
  1895. //
  1896. int nFaceCount = aCurrentFaces.Count();
  1897. for( int iFace = 0; iFace < nFaceCount; iFace++ )
  1898. {
  1899. ClipFace_t *pClipFace = aCurrentFaces[iFace];
  1900. if ( pClipFace )
  1901. {
  1902. // Save for re-building later!
  1903. pClipFace->m_pBuildFace = pFace;
  1904. m_aRenderFaces.AddToTail( aCurrentFaces[iFace] );
  1905. ClipFace_BuildFacesFromBlendedData( pClipFace );
  1906. }
  1907. }
  1908. // Clean up!
  1909. aCurrentFaces.Purge();
  1910. }
  1911. //-----------------------------------------------------------------------------
  1912. //-----------------------------------------------------------------------------
  1913. void CMapOverlay::HandlesReset( void )
  1914. {
  1915. m_Handles.m_iHit = -1;
  1916. }
  1917. //-----------------------------------------------------------------------------
  1918. //-----------------------------------------------------------------------------
  1919. bool CMapOverlay::HandlesHitTest( CMapView *pView, const Vector2D &vPoint )
  1920. {
  1921. int handleRadius = 8;
  1922. for ( int iPoint = 0; iPoint < 4; iPoint++ )
  1923. {
  1924. Vector2D vHandle;
  1925. pView->WorldToClient( vHandle, m_Handles.m_vec3D[iPoint] );
  1926. if ( vPoint.x < (vHandle.x-handleRadius) || vPoint.x > ( vHandle.x+handleRadius) )
  1927. continue;
  1928. if ( vPoint.y < (vHandle.y-handleRadius) || vPoint.y > ( vHandle.y+handleRadius) )
  1929. continue;
  1930. m_Handles.m_iHit = iPoint;
  1931. return true;
  1932. }
  1933. return false;
  1934. }
  1935. //-----------------------------------------------------------------------------
  1936. //-----------------------------------------------------------------------------
  1937. void CMapOverlay::HandlesDragTo( Vector &vecImpact, CMapFace *pFace )
  1938. {
  1939. // Check handle index range.
  1940. if ( ( m_Handles.m_iHit < 0 ) || ( m_Handles.m_iHit > 3 ) )
  1941. return;
  1942. // Save
  1943. m_Handles.m_vec3D[m_Handles.m_iHit] = vecImpact;
  1944. // Project the point into the overlay plane (from face/disp).
  1945. Vector vecOverlay;
  1946. Vector2D vecUVOverlay;
  1947. Handles_SurfToOverlayPlane( pFace, vecImpact, vecOverlay );
  1948. OverlayPlaneToOverlayUV( vecOverlay, vecUVOverlay );
  1949. m_Handles.m_vecBasisCoords[m_Handles.m_iHit] = vecUVOverlay;
  1950. }
  1951. //-----------------------------------------------------------------------------
  1952. //-----------------------------------------------------------------------------
  1953. void CMapOverlay::HandleMoveTo( int iHandle, Vector &vecPoint, CMapFace *pFace )
  1954. {
  1955. if ( ( iHandle < 0 ) || ( iHandle > 3 ) )
  1956. return;
  1957. m_Handles.m_vec3D[iHandle] = vecPoint;
  1958. // Project the point into the overlay plane (from face/disp).
  1959. Vector vecOverlay;
  1960. Vector2D vecUVOverlay;
  1961. Handles_SurfToOverlayPlane( pFace, vecPoint, vecOverlay );
  1962. OverlayPlaneToOverlayUV( vecOverlay, vecUVOverlay );
  1963. m_Handles.m_vecBasisCoords[iHandle] = vecUVOverlay;
  1964. }
  1965. //-----------------------------------------------------------------------------
  1966. // Purpose:
  1967. //-----------------------------------------------------------------------------
  1968. void CMapOverlay::SetTexCoords( Vector2D vecTexCoords[4] )
  1969. {
  1970. m_Material.m_vecTextureU.x = vecTexCoords[0][0];
  1971. m_Material.m_vecTextureV.x = vecTexCoords[0][1];
  1972. // m_Material.m_vecTextureU.x = vecTexCoord[1][0];
  1973. m_Material.m_vecTextureV.y = vecTexCoords[1][1];
  1974. m_Material.m_vecTextureU.y = vecTexCoords[2][0];
  1975. // m_Material.m_vecTextureV.y = vecTexCoord[2][1];
  1976. // m_Material.m_vecTextureU.y = vecTexCoord[3][0];
  1977. // m_Material.m_vecTextureV.x = vecTexCoord[3][1];
  1978. }
  1979. //-----------------------------------------------------------------------------
  1980. //-----------------------------------------------------------------------------
  1981. void CMapOverlay::UpdateDispBarycentric( void )
  1982. {
  1983. //
  1984. // Project points back onto the displacement surface.
  1985. //
  1986. int nFaceCount = m_aRenderFaces.Count();
  1987. for ( int iFace = 0; iFace < nFaceCount; iFace++ )
  1988. {
  1989. // Get the current face and remove it from the list.
  1990. ClipFace_t *pClipFace = m_aRenderFaces[iFace];
  1991. if ( pClipFace )
  1992. {
  1993. if ( pClipFace->m_pBuildFace->HasDisp() )
  1994. {
  1995. ClipFace_BuildFacesFromBlendedData( pClipFace );
  1996. }
  1997. }
  1998. }
  1999. // Update the entity position.
  2000. CenterEntity();
  2001. // Update the handles.
  2002. Handles_Build3D();
  2003. }
  2004. //-----------------------------------------------------------------------------
  2005. // Purpose:
  2006. //-----------------------------------------------------------------------------
  2007. void CMapOverlay::CenterEntity( void )
  2008. {
  2009. // Center in overlay plane.
  2010. Vector vecTotal;
  2011. Vector vecHandle;
  2012. vecTotal.Init();
  2013. for( int iHandle = 0; iHandle < OVERLAY_HANDLES_COUNT; ++iHandle )
  2014. {
  2015. OverlayUVToOverlayPlane( m_Handles.m_vecBasisCoords[iHandle], vecHandle );
  2016. vecTotal += vecHandle;
  2017. }
  2018. vecTotal *= 0.25f;
  2019. // Center in overlay uv-space.
  2020. Vector2D vecNewCenter;
  2021. OverlayPlaneToOverlayUV( vecTotal, vecNewCenter );
  2022. for( int iHandle = 0; iHandle < OVERLAY_HANDLES_COUNT; ++iHandle )
  2023. {
  2024. m_Handles.m_vecBasisCoords[iHandle] -= vecNewCenter;
  2025. }
  2026. // Update the entity's origin.
  2027. m_Basis.m_vecOrigin = vecTotal;
  2028. CMapEntity *pEntity = ( CMapEntity* )GetParent();
  2029. if ( pEntity )
  2030. {
  2031. Vector vecSurfPoint;
  2032. OverlayPlaneToSurfFromList( vecTotal, vecSurfPoint );
  2033. pEntity->SetOrigin( vecSurfPoint );
  2034. }
  2035. // Update the property box.
  2036. Basis_UpdateParentKey();
  2037. Handles_UpdateParentKey();
  2038. }
  2039. //-----------------------------------------------------------------------------
  2040. //-----------------------------------------------------------------------------
  2041. void CMapOverlay::GetPlane( cplane_t &plane )
  2042. {
  2043. plane.normal = m_Basis.m_vecAxes[OVERLAY_BASIS_NORMAL];
  2044. plane.dist = plane.normal.Dot( m_Basis.m_vecOrigin );
  2045. }
  2046. //-----------------------------------------------------------------------------
  2047. //-----------------------------------------------------------------------------
  2048. void CMapOverlay::GetHandlePos( int iHandle, Vector &vecPos )
  2049. {
  2050. Assert( iHandle >= 0 );
  2051. Assert( iHandle < 4 );
  2052. vecPos = m_Handles.m_vec3D[iHandle];
  2053. }
  2054. //-----------------------------------------------------------------------------
  2055. //-----------------------------------------------------------------------------
  2056. void CMapOverlay::SideList_Init( CMapFace *pFace )
  2057. {
  2058. // Valid face?
  2059. if ( !pFace )
  2060. return;
  2061. // Purge side list as this should be the initial face!
  2062. m_Faces.Purge();
  2063. m_Faces.AddToTail( pFace );
  2064. if ( ( GetOverlayType() && OVERLAY_TYPE_SHORE ) == 0 )
  2065. {
  2066. // Update dependencies.
  2067. UpdateDependency( NULL, ( CMapSolid* )pFace->GetParent() );
  2068. UpdateParentKey();
  2069. }
  2070. // Initialize the overlay.
  2071. Basis_Init( pFace );
  2072. PostModified();
  2073. }
  2074. //-----------------------------------------------------------------------------
  2075. // Purpose:
  2076. //-----------------------------------------------------------------------------
  2077. void CMapOverlay::SideList_AddFace( CMapFace *pFace )
  2078. {
  2079. // Valid face?
  2080. if ( !pFace )
  2081. return;
  2082. // Purge side list as this should be the initial face!
  2083. m_Faces.AddToTail( pFace );
  2084. if ( ( GetOverlayType() && OVERLAY_TYPE_SHORE ) == 0 )
  2085. {
  2086. // Update dependencies.
  2087. UpdateDependency( NULL, ( CMapSolid* )pFace->GetParent() );
  2088. UpdateParentKey();
  2089. }
  2090. PostModified();
  2091. }
  2092. //=============================================================================
  2093. //
  2094. // Overlay Utility Functions
  2095. //
  2096. //-----------------------------------------------------------------------------
  2097. //-----------------------------------------------------------------------------
  2098. void CMapOverlay::OverlayUVToOverlayPlane( const Vector2D &vecUV, Vector &vecOverlayPoint )
  2099. {
  2100. vecOverlayPoint = ( vecUV.x * m_Basis.m_vecAxes[OVERLAY_BASIS_U] +
  2101. vecUV.y * m_Basis.m_vecAxes[OVERLAY_BASIS_V] );
  2102. vecOverlayPoint += m_Basis.m_vecOrigin;
  2103. }
  2104. //-----------------------------------------------------------------------------
  2105. //-----------------------------------------------------------------------------
  2106. void CMapOverlay::OverlayPlaneToOverlayUV( const Vector &vecOverlayPoint, Vector2D &vecUV )
  2107. {
  2108. Vector vecDelta;
  2109. vecDelta = vecOverlayPoint - m_Basis.m_vecOrigin;
  2110. vecUV.x = m_Basis.m_vecAxes[OVERLAY_BASIS_U].Dot( vecDelta );
  2111. vecUV.y = m_Basis.m_vecAxes[OVERLAY_BASIS_V].Dot( vecDelta );
  2112. }
  2113. //-----------------------------------------------------------------------------
  2114. //-----------------------------------------------------------------------------
  2115. void CMapOverlay::WorldToOverlayPlane( const Vector &vecWorldPoint, Vector &vecOverlayPoint )
  2116. {
  2117. Vector vecDelta = vecWorldPoint - m_Basis.m_vecOrigin;
  2118. float flDist = m_Basis.m_vecAxes[OVERLAY_BASIS_NORMAL].Dot( vecDelta );
  2119. vecOverlayPoint = vecWorldPoint - ( m_Basis.m_vecAxes[OVERLAY_BASIS_NORMAL] * flDist );
  2120. }
  2121. //-----------------------------------------------------------------------------
  2122. //-----------------------------------------------------------------------------
  2123. void CMapOverlay::OverlayPlaneToWorld( CMapFace *pFace, const Vector &vecOverlayPoint,
  2124. Vector &vecWorldPoint )
  2125. {
  2126. // Create the overlay plane - the base face plane.
  2127. cplane_t surfacePlane;
  2128. pFace->GetFaceNormal( surfacePlane.normal );
  2129. VectorNormalize( surfacePlane.normal );
  2130. Vector vecPoint;
  2131. pFace->GetPoint( vecPoint, 0 );
  2132. surfacePlane.dist = surfacePlane.normal.Dot( vecPoint );
  2133. float flDistToSurface = surfacePlane.normal.Dot( vecOverlayPoint ) - surfacePlane.dist;
  2134. float flDist = flDistToSurface;
  2135. float flDot = surfacePlane.normal.Dot( m_Basis.m_vecAxes[OVERLAY_BASIS_NORMAL] );
  2136. if ( flDot != 0.0f )
  2137. {
  2138. flDist = ( 1.0f / flDot ) * flDistToSurface;
  2139. }
  2140. vecWorldPoint = vecOverlayPoint - ( m_Basis.m_vecAxes[OVERLAY_BASIS_NORMAL] * flDist );
  2141. }
  2142. //-----------------------------------------------------------------------------
  2143. //-----------------------------------------------------------------------------
  2144. void CMapOverlay::OverlayPlaneToSurfFromList( const Vector &vecOverlayPoint, Vector &vecSurfPoint )
  2145. {
  2146. // Initialize the point with the overlay point.
  2147. vecSurfPoint = vecOverlayPoint;
  2148. int nFaceCount = GetFaceCount();
  2149. CUtlVector<Vector> aPoints;
  2150. CUtlVector<cplane_t> aPlanes;
  2151. for ( int iFace = 0; iFace < nFaceCount; ++iFace )
  2152. {
  2153. CMapFace *pFace = GetFace( iFace );
  2154. if ( !pFace )
  2155. continue;
  2156. // Set points.
  2157. aPoints.Purge();
  2158. aPoints.SetSize( pFace->nPoints );
  2159. aPlanes.Purge();
  2160. aPlanes.SetSize( pFace->nPoints );
  2161. // Project all the face points into the overlay plane.
  2162. for ( int iPoint = 0; iPoint < pFace->nPoints; ++iPoint )
  2163. {
  2164. WorldToOverlayPlane( pFace->Points[iPoint], aPoints[iPoint] );
  2165. }
  2166. // Create edge planes for clipping.
  2167. BuildEdgePlanes( aPoints.Base(), aPoints.Count(), aPlanes.Base(), aPlanes.Count() );
  2168. // Check to see if a point lies behind all of the edge planes - this is our face.
  2169. int iPlane;
  2170. for ( iPlane = 0; iPlane < aPlanes.Count(); ++iPlane )
  2171. {
  2172. float flDist = aPlanes[iPlane].normal.Dot( vecOverlayPoint ) - aPlanes[iPlane].dist;
  2173. if( flDist >= 0.0f )
  2174. break;
  2175. }
  2176. // Point lies outside off at least one plane.
  2177. if( iPlane != aPlanes.Count() )
  2178. {
  2179. continue;
  2180. }
  2181. // Project the point up to the base face plane (displacement if necessary).
  2182. OverlayPlaneToWorld( pFace, vecOverlayPoint, vecSurfPoint );
  2183. if( pFace->HasDisp() )
  2184. {
  2185. Vector2D vecTmp;
  2186. EditDispHandle_t handle = pFace->GetDisp();
  2187. CMapDisp *pDisp = EditDispMgr()->GetDisp( handle );
  2188. pDisp->BaseFacePlaneToDispUV( vecSurfPoint, vecTmp );
  2189. pDisp->DispUVToSurf( vecTmp, vecSurfPoint, NULL, NULL );
  2190. }
  2191. // Clean-up.
  2192. aPoints.Purge();
  2193. aPlanes.Purge();
  2194. return;
  2195. }
  2196. // Clean-up.
  2197. aPoints.Purge();
  2198. aPlanes.Purge();
  2199. }
  2200. //-----------------------------------------------------------------------------
  2201. // Purpose:
  2202. //-----------------------------------------------------------------------------
  2203. bool CMapOverlay::EntityOnSurfFromListToBaseFacePlane( const Vector &vecWorldPoint, Vector &vecBasePoint )
  2204. {
  2205. int nFaceCount = GetFaceCount();
  2206. for ( int iFace = 0; iFace < nFaceCount; ++iFace )
  2207. {
  2208. CMapFace *pFace = GetFace( iFace );
  2209. if ( !pFace )
  2210. continue;
  2211. if ( !pFace->HasDisp() )
  2212. continue;
  2213. EditDispHandle_t handle = pFace->GetDisp();
  2214. CMapDisp *pDisp = EditDispMgr()->GetDisp( handle );
  2215. if ( pDisp->SurfToBaseFacePlane( vecWorldPoint, vecBasePoint ) )
  2216. return true;
  2217. }
  2218. return false;
  2219. }
  2220. //-----------------------------------------------------------------------------
  2221. // Purpose:
  2222. //-----------------------------------------------------------------------------
  2223. void CMapOverlay::GetTriVerts( CMapDisp *pDisp, const Vector2D &vecSurfUV, int *pTris, Vector2D *pVertsUV )
  2224. {
  2225. // Get the displacement width.
  2226. int nWidth = pDisp->GetWidth();
  2227. int nHeight = pDisp->GetHeight();
  2228. // scale the u, v coordinates the displacement grid size
  2229. float flU = vecSurfUV.x * ( nWidth - 1.000001f );
  2230. float flV = vecSurfUV.y * ( nHeight - 1.000001f );
  2231. // find the triangle the "uv spot" resides in
  2232. int nSnapU = static_cast<int>( flU );
  2233. int nSnapV = static_cast<int>( flV );
  2234. if ( nSnapU == ( nWidth - 1 ) ) { --nSnapU; }
  2235. if ( nSnapV == ( nHeight - 1 ) ) { --nSnapV; }
  2236. int nNextU = nSnapU + 1;
  2237. int nNextV = nSnapV + 1;
  2238. // Fractional portion
  2239. float flFracU = flU - static_cast<float>( nSnapU );
  2240. float flFracV = flV - static_cast<float>( nSnapV );
  2241. bool bOdd = ( ( ( nSnapV * nWidth ) + nSnapU ) % 2 ) == 1;
  2242. if ( bOdd )
  2243. {
  2244. if( ( flFracU + flFracV ) >= ( 1.0f + OVERLAY_DISPSPACE_EPSILON ) )
  2245. {
  2246. pVertsUV[0].x = nSnapU; pVertsUV[0].y = nNextV;
  2247. pVertsUV[1].x = nNextU; pVertsUV[1].y = nNextV;
  2248. pVertsUV[2].x = nNextU; pVertsUV[2].y = nSnapV;
  2249. }
  2250. else
  2251. {
  2252. pVertsUV[0].x = nSnapU; pVertsUV[0].y = nSnapV;
  2253. pVertsUV[1].x = nSnapU; pVertsUV[1].y = nNextV;
  2254. pVertsUV[2].x = nNextU; pVertsUV[2].y = nSnapV;
  2255. }
  2256. }
  2257. else
  2258. {
  2259. if ( flFracU < flFracV )
  2260. {
  2261. pVertsUV[0].x = nSnapU; pVertsUV[0].y = nSnapV;
  2262. pVertsUV[1].x = nSnapU; pVertsUV[1].y = nNextV;
  2263. pVertsUV[2].x = nNextU; pVertsUV[2].y = nNextV;
  2264. }
  2265. else
  2266. {
  2267. pVertsUV[0].x = nSnapU; pVertsUV[0].y = nSnapV;
  2268. pVertsUV[1].x = nNextU; pVertsUV[1].y = nNextV;
  2269. pVertsUV[2].x = nNextU; pVertsUV[2].y = nSnapV;
  2270. }
  2271. }
  2272. // Calculate the triangle indices.
  2273. for( int iVert = 0; iVert < 3; ++iVert )
  2274. {
  2275. pTris[iVert] = pVertsUV[iVert].y * nWidth + pVertsUV[iVert].x;
  2276. }
  2277. }
  2278. //-----------------------------------------------------------------------------
  2279. // Purpose:
  2280. //-----------------------------------------------------------------------------
  2281. void CMapOverlay::SetMaterial( const char *szMaterialName )
  2282. {
  2283. // Get the new material.
  2284. IEditorTexture *pTex = g_Textures.FindActiveTexture( szMaterialName );
  2285. if ( !pTex )
  2286. return;
  2287. // Save the new material.
  2288. m_Material.m_pTexture = pTex;
  2289. }
  2290. //-----------------------------------------------------------------------------
  2291. // Purpose:
  2292. //-----------------------------------------------------------------------------
  2293. ChunkFileResult_t CMapOverlay::SaveDataToVMF( CChunkFile *pFile, CSaveInfo *pSaveInfo )
  2294. {
  2295. ChunkFileResult_t eResult = pFile->BeginChunk("overlaydata");
  2296. // Save the material name.
  2297. if ( eResult == ChunkFile_Ok )
  2298. {
  2299. eResult = pFile->WriteKeyValue( "material", m_Material.m_pTexture->GetName() );
  2300. }
  2301. // Save the u,v data.
  2302. if ( eResult == ChunkFile_Ok )
  2303. {
  2304. eResult = pFile->WriteKeyValueFloat( "StartU", m_Material.m_vecTextureU.x );
  2305. }
  2306. if ( eResult == ChunkFile_Ok )
  2307. {
  2308. eResult = pFile->WriteKeyValueFloat( "EndU", m_Material.m_vecTextureU.y );
  2309. }
  2310. if ( eResult == ChunkFile_Ok )
  2311. {
  2312. eResult = pFile->WriteKeyValueFloat( "StartV", m_Material.m_vecTextureV.x );
  2313. }
  2314. if ( eResult == ChunkFile_Ok )
  2315. {
  2316. eResult = pFile->WriteKeyValueFloat( "EndV", m_Material.m_vecTextureV.y );
  2317. }
  2318. // Basis data.
  2319. Vector vecTmp;
  2320. if ( eResult == ChunkFile_Ok )
  2321. {
  2322. eResult = pFile->WriteKeyValueVector3( "BasisOrigin", m_Basis.m_vecOrigin );
  2323. }
  2324. if ( eResult == ChunkFile_Ok )
  2325. {
  2326. eResult = pFile->WriteKeyValueVector3( "BasisU", m_Basis.m_vecAxes[OVERLAY_BASIS_U] );
  2327. }
  2328. if ( eResult == ChunkFile_Ok )
  2329. {
  2330. eResult = pFile->WriteKeyValueVector3( "BasisV", m_Basis.m_vecAxes[OVERLAY_BASIS_V] );
  2331. }
  2332. if ( eResult == ChunkFile_Ok )
  2333. {
  2334. eResult = pFile->WriteKeyValueVector3( "BasisNormal", m_Basis.m_vecAxes[OVERLAY_BASIS_NORMAL] );
  2335. }
  2336. if ( eResult == ChunkFile_Ok )
  2337. {
  2338. Vector vecTmp( m_Handles.m_vecBasisCoords[0].x, m_Handles.m_vecBasisCoords[0].y, ( float )m_Basis.m_nAxesFlip[0] );
  2339. eResult = pFile->WriteKeyValueVector3( "uv0", vecTmp );
  2340. }
  2341. if ( eResult == ChunkFile_Ok )
  2342. {
  2343. Vector vecTmp( m_Handles.m_vecBasisCoords[1].x, m_Handles.m_vecBasisCoords[1].y, ( float )m_Basis.m_nAxesFlip[1] );
  2344. eResult = pFile->WriteKeyValueVector3( "uv1", vecTmp );
  2345. }
  2346. if ( eResult == ChunkFile_Ok )
  2347. {
  2348. Vector vecTmp( m_Handles.m_vecBasisCoords[2].x, m_Handles.m_vecBasisCoords[2].y, ( float )m_Basis.m_nAxesFlip[2] );
  2349. eResult = pFile->WriteKeyValueVector3( "uv2", vecTmp );
  2350. }
  2351. if ( eResult == ChunkFile_Ok )
  2352. {
  2353. Vector vecTmp( m_Handles.m_vecBasisCoords[3].x, m_Handles.m_vecBasisCoords[3].y, 0.0f );
  2354. eResult = pFile->WriteKeyValueVector3( "uv3", vecTmp );
  2355. }
  2356. // Sidelist.
  2357. if ( eResult == ChunkFile_Ok )
  2358. {
  2359. char szSetValue[KEYVALUE_MAX_VALUE_LENGTH];
  2360. CMapWorld::FaceID_FaceListsToString( szSetValue, sizeof( szSetValue ), &m_Faces, NULL );
  2361. eResult = pFile->WriteKeyValue( "sides", szSetValue );
  2362. }
  2363. if ( eResult == ChunkFile_Ok )
  2364. {
  2365. eResult = pFile->EndChunk();
  2366. }
  2367. return eResult;
  2368. }