Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1563 lines
40 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include <stdafx.h>
  8. #include "hammer.h"
  9. #include "ToolDisplace.h"
  10. #include "MainFrm.h"
  11. #include "FaceEditSheet.h"
  12. #include "GlobalFunctions.h"
  13. #include "MapAtom.h"
  14. #include "MapSolid.h"
  15. #include "MapView3D.h"
  16. #include "History.h"
  17. #include "Camera.h"
  18. #include "MapDoc.h"
  19. #include "ChunkFile.h"
  20. #include "ToolManager.h"
  21. #include "SculptOptions.h"
  22. // memdbgon must be the last include file in a .cpp file!!!
  23. #include <tier0/memdbgon.h>
  24. //=============================================================================
  25. //-----------------------------------------------------------------------------
  26. //-----------------------------------------------------------------------------
  27. CToolDisplace::CToolDisplace()
  28. {
  29. m_uiTool = DISPTOOL_SELECT;
  30. m_uiEffect = DISPPAINT_EFFECT_RAISELOWER;
  31. m_uiBrushType = DISPPAINT_BRUSHTYPE_SOFT;
  32. m_iPaintChannel = DISPPAINT_CHANNEL_POSITION;
  33. m_flPaintValueGeo = 5.0f;
  34. m_flPaintValueData = 25.0f;
  35. m_iPaintAxis = DISPPAINT_AXIS_FACE;
  36. m_vecPaintAxis.Init( 0.0f, 0.0f, 1.0f );
  37. m_bAutoSew = false;
  38. m_bSpatial = false;
  39. m_flSpatialRadius = 15.0f;
  40. m_bSpatialRadius = false;
  41. m_bSelectMaskTool = true;
  42. m_bGridMaskTool = false;
  43. m_bLMBDown = false;
  44. m_bRMBDown = false;
  45. m_bNudge = false;
  46. m_bNudgeInit = false;
  47. m_EditDispHandle = EDITDISPHANDLE_INVALID;
  48. // load filters from file
  49. static char szProgramDir[MAX_PATH];
  50. APP()->GetDirectory( DIR_PROGRAM, szProgramDir );
  51. strcat( szProgramDir, "filters\\dispfilters.txt" );
  52. LoadFilters( szProgramDir );
  53. AddFiltersToManagers();
  54. m_SculptTool = NULL;
  55. m_MousePoint.Init( 0.0f, 0.0f );
  56. }
  57. //-----------------------------------------------------------------------------
  58. //-----------------------------------------------------------------------------
  59. CToolDisplace::~CToolDisplace()
  60. {
  61. // destroy filters
  62. m_FilterRaiseLowerMgr.Destroy();
  63. m_FilterRaiseToMgr.Destroy();
  64. m_FilterSmoothMgr.Destroy();
  65. }
  66. //-----------------------------------------------------------------------------
  67. // Purpose: Called when the tool is activated.
  68. // Input : eOldTool - The ID of the previously active tool.
  69. //-----------------------------------------------------------------------------
  70. void CToolDisplace::OnActivate()
  71. {
  72. //
  73. // initialize masks
  74. //
  75. CMapDisp::SetSelectMask( m_bSelectMaskTool );
  76. CMapDisp::SetGridMask( m_bGridMaskTool );
  77. }
  78. //-----------------------------------------------------------------------------
  79. // Purpose: Called when the tool is deactivated.
  80. // Input : eNewTool - The ID of the tool that is being activated.
  81. //-----------------------------------------------------------------------------
  82. void CToolDisplace::OnDeactivate()
  83. {
  84. //
  85. // reset masks
  86. //
  87. CMapDisp::SetSelectMask( false );
  88. CMapDisp::SetGridMask( false );
  89. if ( m_pDocument->GetTools()->GetActiveToolID() != TOOL_FACEEDIT_MATERIAL )
  90. {
  91. // Clear the selected faces when we are deactivated.
  92. m_pDocument->SelectFace(NULL, 0, scClear );
  93. }
  94. }
  95. //-----------------------------------------------------------------------------
  96. //-----------------------------------------------------------------------------
  97. inline void CToolDisplace::UpdateMapViews( CMapView3D *pView )
  98. {
  99. CMapDoc *pDoc = pView->GetMapDoc();
  100. if( pDoc )
  101. {
  102. pDoc->SetModifiedFlag();
  103. }
  104. }
  105. //-----------------------------------------------------------------------------
  106. //-----------------------------------------------------------------------------
  107. inline void CToolDisplace::CalcViewCenter( CMapView3D *pView )
  108. {
  109. CRect windowRect;
  110. pView->GetWindowRect( windowRect );
  111. m_viewCenter = windowRect.CenterPoint();
  112. }
  113. //-----------------------------------------------------------------------------
  114. //-----------------------------------------------------------------------------
  115. bool CToolDisplace::OnLMouseDown3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
  116. {
  117. // Set down flags
  118. m_bLMBDown = true;
  119. if( m_uiTool == DISPTOOL_PAINT_SCULPT )
  120. {
  121. m_SculptTool->OnLMouseDown3D( pView, nFlags, vPoint );
  122. m_SculptTool->BeginPaint( pView, vPoint );
  123. ApplySculptSpatialPaintTool( pView, nFlags, vPoint );
  124. // update
  125. UpdateMapViews( pView );
  126. return true;
  127. }
  128. // Selection.
  129. if( m_uiTool == DISPTOOL_SELECT || ( GetAsyncKeyState( VK_CONTROL ) & 0x8000 ) )
  130. {
  131. // handle selection at point
  132. HandleSelection( pView, vPoint );
  133. // update
  134. UpdateMapViews( pView );
  135. return true;
  136. }
  137. // Tagging.
  138. if ( m_uiTool == DISPTOOL_TAG_WALKABLE || m_uiTool == DISPTOOL_TAG_BUILDABLE || m_uiTool == DISPTOOL_TAG_REMOVE )
  139. {
  140. // Do tagging.
  141. HandleTagging( pView, vPoint );
  142. return true;
  143. }
  144. // Resize the spatial painting sphere.
  145. if( ( m_uiTool == DISPTOOL_PAINT ) && ( IsSpatialPainting() ) &&
  146. ( GetAsyncKeyState( VK_MENU ) & 0x8000 ) )
  147. {
  148. ResizeSpatialRadius_Activate( pView );
  149. return true;
  150. }
  151. // Nudging.
  152. if( ( m_uiTool == DISPTOOL_PAINT ) && ( GetAsyncKeyState( VK_SHIFT ) & 0x8000 ) )
  153. {
  154. // is the current effect raise/lower (nudge only works in raise/lower mode)
  155. if( m_uiEffect == DISPPAINT_EFFECT_RAISELOWER )
  156. {
  157. EditDispHandle_t handle = GetHitPos( pView, vPoint );
  158. if( handle != EDITDISPHANDLE_INVALID )
  159. {
  160. m_EditDispHandle = handle;
  161. Nudge_Activate( pView, handle );
  162. UpdateMapViews( pView );
  163. return true;
  164. }
  165. }
  166. }
  167. // Painting.
  168. if( m_uiTool == DISPTOOL_PAINT )
  169. {
  170. // get hit info
  171. EditDispHandle_t handle = GetHitPos( pView, vPoint );
  172. if( handle == EDITDISPHANDLE_INVALID )
  173. return false;
  174. m_EditDispHandle = handle;
  175. CMapDisp *pDisp = EditDispMgr()->GetDisp( handle );
  176. IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager();
  177. if( !pDispMgr )
  178. return false;
  179. pDispMgr->PreUndo( "Displacement Modifier" );
  180. // Paint using the correct mode.
  181. if ( m_bSpatial )
  182. {
  183. int nDispCount = pDispMgr->SelectCount();
  184. for ( int iDisp = 0; iDisp < nDispCount; iDisp++ )
  185. {
  186. CMapDisp *pDispSelect = pDispMgr->GetFromSelect( iDisp );
  187. if ( pDispSelect )
  188. {
  189. pDispSelect->Paint_Init( DISPPAINT_CHANNEL_POSITION );
  190. }
  191. }
  192. // setup for undo - modifying the displacement (painting)
  193. ApplySpatialPaintTool( nFlags, vPoint, pDisp );
  194. }
  195. else
  196. {
  197. // setup for undo - modifying the displacement (painting)
  198. pDispMgr->Undo( handle, true );
  199. pDisp = EditDispMgr()->GetDisp( handle );
  200. ApplyPaintTool( nFlags, vPoint, pDisp );
  201. }
  202. // update
  203. UpdateMapViews( pView );
  204. }
  205. return true;
  206. }
  207. //-----------------------------------------------------------------------------
  208. //-----------------------------------------------------------------------------
  209. bool CToolDisplace::OnLMouseUp3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
  210. {
  211. // left button up
  212. m_bLMBDown = false;
  213. if( m_uiTool == DISPTOOL_PAINT_SCULPT )
  214. {
  215. m_SculptTool->OnLMouseUp3D( pView, nFlags, vPoint );
  216. return true;
  217. }
  218. if ( m_bNudge )
  219. {
  220. Nudge_Deactivate();
  221. }
  222. if ( m_bSpatialRadius )
  223. {
  224. ResizeSpatialRadius_Deactivate();
  225. }
  226. IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager();
  227. if( pDispMgr )
  228. {
  229. pDispMgr->PostUndo();
  230. }
  231. return true;
  232. }
  233. //-----------------------------------------------------------------------------
  234. //-----------------------------------------------------------------------------
  235. bool CToolDisplace::OnRMouseDown3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
  236. {
  237. // left button down
  238. m_bRMBDown = true;
  239. if( m_uiTool == DISPTOOL_PAINT_SCULPT )
  240. {
  241. m_SculptTool->OnRMouseDown3D( pView, nFlags, vPoint );
  242. m_SculptTool->BeginPaint( pView, vPoint );
  243. ApplySculptSpatialPaintTool( pView, nFlags, vPoint );
  244. // update
  245. UpdateMapViews( pView );
  246. return true;
  247. }
  248. //
  249. // lifting the face normal - painting with the axis set to "Face Normal"
  250. //
  251. if( ( m_uiTool == DISPTOOL_PAINT ) && ( m_iPaintAxis == DISPPAINT_AXIS_FACE ) &&
  252. ( GetAsyncKeyState( VK_MENU ) & 0x8000 ) )
  253. {
  254. LiftFaceNormal( pView, vPoint );
  255. return true;
  256. }
  257. // Tagging.
  258. if ( m_uiTool == DISPTOOL_TAG_WALKABLE || m_uiTool == DISPTOOL_TAG_BUILDABLE || m_uiTool == DISPTOOL_TAG_REMOVE )
  259. {
  260. // Do tagging.
  261. HandleTaggingReset( pView, vPoint );
  262. return true;
  263. }
  264. //
  265. // handle the normal paint procedure
  266. //
  267. if( m_uiTool == DISPTOOL_PAINT )
  268. {
  269. // get hit info
  270. EditDispHandle_t handle = GetHitPos( pView, vPoint );
  271. if( handle == EDITDISPHANDLE_INVALID )
  272. return false;
  273. m_EditDispHandle = handle;
  274. CMapDisp *pDisp = EditDispMgr()->GetDisp( handle );
  275. IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager();
  276. if( !pDispMgr )
  277. return false;
  278. pDispMgr->PreUndo( "Displacement Modifier" );
  279. // apply the current displacement tool
  280. if ( m_bSpatial )
  281. {
  282. int nDispCount = pDispMgr->SelectCount();
  283. for ( int iDisp = 0; iDisp < nDispCount; iDisp++ )
  284. {
  285. CMapDisp *pDispSelect = pDispMgr->GetFromSelect( iDisp );
  286. if ( pDispSelect )
  287. {
  288. pDispSelect->Paint_Init( DISPPAINT_CHANNEL_POSITION );
  289. }
  290. }
  291. ApplySpatialPaintTool( nFlags, vPoint, pDisp );
  292. }
  293. else
  294. {
  295. // setup for undo
  296. pDispMgr->Undo( handle, true );
  297. pDisp = EditDispMgr()->GetDisp( handle );
  298. ApplyPaintTool( nFlags, vPoint, pDisp );
  299. }
  300. // update
  301. UpdateMapViews( pView );
  302. }
  303. return true;
  304. }
  305. //-----------------------------------------------------------------------------
  306. //-----------------------------------------------------------------------------
  307. bool CToolDisplace::OnRMouseUp3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
  308. {
  309. // left button up
  310. m_bRMBDown = false;
  311. if( m_uiTool == DISPTOOL_PAINT_SCULPT )
  312. {
  313. m_SculptTool->OnRMouseUp3D( pView, nFlags, vPoint );
  314. return true;
  315. }
  316. IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager();
  317. if( pDispMgr )
  318. {
  319. pDispMgr->PostUndo();
  320. }
  321. return true;
  322. }
  323. //-----------------------------------------------------------------------------
  324. //-----------------------------------------------------------------------------
  325. bool CToolDisplace::OnMouseMove3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
  326. {
  327. m_MousePoint = vPoint;
  328. if( m_uiTool == DISPTOOL_PAINT_SCULPT )
  329. {
  330. m_SculptTool->OnMouseMove3D( pView, nFlags, vPoint );
  331. if( ( m_bLMBDown || m_bRMBDown ) )
  332. {
  333. ApplySculptSpatialPaintTool( pView, nFlags, vPoint );
  334. }
  335. // update
  336. UpdateMapViews( pView );
  337. return true;
  338. }
  339. // nudging
  340. if ( ( m_uiTool == DISPTOOL_PAINT ) && ( GetAsyncKeyState( VK_SHIFT ) & 0x8000 ) &&
  341. m_bLMBDown && m_bNudge )
  342. {
  343. Nudge_Do();
  344. }
  345. // Resizing the spatial sphere.
  346. else if ( ( m_uiTool == DISPTOOL_PAINT ) && ( GetAsyncKeyState( VK_MENU ) & 0x8000 ) &&
  347. m_bLMBDown && m_bSpatialRadius )
  348. {
  349. ResizeSpatialRadius_Do();
  350. }
  351. // painting
  352. else
  353. {
  354. // get hit info
  355. EditDispHandle_t handle = GetHitPos( pView, vPoint );
  356. if( handle == EDITDISPHANDLE_INVALID )
  357. return false;
  358. m_EditDispHandle = handle;
  359. CMapDisp *pDisp = EditDispMgr()->GetDisp( handle );
  360. //
  361. // continue with tool operation?!
  362. //
  363. if( ( m_bLMBDown || m_bRMBDown ) && !( GetAsyncKeyState( VK_CONTROL ) & 0x8000 ) &&
  364. ( m_uiTool == DISPTOOL_PAINT ) )
  365. {
  366. if ( m_bSpatial )
  367. {
  368. ApplySpatialPaintTool( nFlags, vPoint, pDisp );
  369. }
  370. else
  371. {
  372. ApplyPaintTool( nFlags, vPoint, pDisp );
  373. }
  374. }
  375. // not nudging anymore -- if we were
  376. if( m_bNudge )
  377. {
  378. Nudge_Deactivate();
  379. }
  380. if ( m_bSpatialRadius )
  381. {
  382. ResizeSpatialRadius_Deactivate();
  383. }
  384. }
  385. // update
  386. UpdateMapViews( pView );
  387. return true;
  388. }
  389. //-----------------------------------------------------------------------------
  390. //-----------------------------------------------------------------------------
  391. void CToolDisplace::LiftFaceNormal( CMapView3D *pView, const Vector2D &vPoint )
  392. {
  393. //
  394. // check for closest solid object
  395. //
  396. ULONG ulFace;
  397. CMapClass *pObject;
  398. if( ( ( pObject = pView->NearestObjectAt( vPoint, ulFace ) ) != NULL ) )
  399. {
  400. if( pObject->IsMapClass( MAPCLASS_TYPE( CMapSolid ) ) )
  401. {
  402. // get the solid
  403. CMapSolid *pSolid = ( CMapSolid* )pObject;
  404. if( !pSolid )
  405. return;
  406. // trace a line and get the normal -- will get a displacement normal
  407. // if one exists
  408. CMapFace *pFace = pSolid->GetFace( ulFace );
  409. if( !pFace )
  410. return;
  411. Vector vRayStart, vRayEnd;
  412. pView->GetCamera()->BuildRay( vPoint, vRayStart, vRayEnd );
  413. Vector vHitPos, vHitNormal;
  414. if( pFace->TraceLine( vHitPos, vHitNormal, vRayStart, vRayEnd ) )
  415. {
  416. // set the paint direction
  417. m_vecPaintAxis = vHitNormal;
  418. }
  419. else
  420. {
  421. // will default to z if no normal found
  422. m_vecPaintAxis.Init( 0.0f, 0.0f, 1.0f );
  423. }
  424. }
  425. }
  426. }
  427. //-----------------------------------------------------------------------------
  428. //-----------------------------------------------------------------------------
  429. void CToolDisplace::Nudge_Activate( CMapView3D *pView, EditDispHandle_t dispHandle )
  430. {
  431. IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager();
  432. if( !pDispMgr )
  433. return;
  434. pDispMgr->PreUndo( "Displacement Nudge" );
  435. // Setup paint (nudge) using the correct mode.
  436. if ( m_bSpatial )
  437. {
  438. int nDispCount = pDispMgr->SelectCount();
  439. for ( int iDisp = 0; iDisp < nDispCount; iDisp++ )
  440. {
  441. CMapDisp *pDisp = pDispMgr->GetFromSelect( iDisp );
  442. if ( pDisp )
  443. {
  444. pDisp->Paint_Init( DISPPAINT_CHANNEL_POSITION );
  445. }
  446. }
  447. }
  448. else
  449. {
  450. // setup for undo
  451. pDispMgr->Undo( dispHandle, true );
  452. }
  453. // setup the cursor for "nudging"
  454. CalcViewCenter( pView );
  455. SetCursorPos( m_viewCenter.x, m_viewCenter.y );
  456. pView->SetCapture();
  457. // set nudging
  458. m_bNudge = true;
  459. m_bNudgeInit = true;
  460. }
  461. //-----------------------------------------------------------------------------
  462. //-----------------------------------------------------------------------------
  463. void CToolDisplace::Nudge_Deactivate( void )
  464. {
  465. ReleaseCapture();
  466. m_bNudge = false;
  467. }
  468. //-----------------------------------------------------------------------------
  469. //-----------------------------------------------------------------------------
  470. void CToolDisplace::Nudge_Do( void )
  471. {
  472. CMapDisp *pNudgeDisp = GetEditDisp();
  473. if (pNudgeDisp == NULL)
  474. {
  475. return;
  476. }
  477. //
  478. // find the greatest delta and "nudge"
  479. //
  480. // NOTE: using get cursor position, because it is different than the
  481. // "point" incoming into mouse move????
  482. //
  483. CPoint nudgePos;
  484. GetCursorPos( &nudgePos );
  485. CPoint nudgeDelta;
  486. nudgeDelta.x = nudgePos.x - m_viewCenter.x;
  487. nudgeDelta.y = nudgePos.y - m_viewCenter.y;
  488. float delta;
  489. if( abs( nudgeDelta.x ) < abs( nudgeDelta.y ) )
  490. {
  491. delta = nudgeDelta.y;
  492. }
  493. else
  494. {
  495. delta = nudgeDelta.x;
  496. }
  497. delta = -delta;
  498. if ( !IsSpatialPainting() )
  499. {
  500. CDispMapImageFilter *pFilter = m_FilterRaiseLowerMgr.GetActiveFilter();
  501. if( !pFilter )
  502. return;
  503. // set the dynamic filter data
  504. pFilter->m_DataType = DISPPAINT_CHANNEL_POSITION;
  505. pFilter->m_Scale = ( delta * 0.25 ) * ( float )( ( int )( m_flPaintValueGeo / 10.0f ) + 1 ) ;
  506. // apply the filter to the displacement surface(s)
  507. m_FilterRaiseLowerMgr.Apply( pFilter, pNudgeDisp, m_iPaintAxis, m_vecPaintAxis, m_bAutoSew );
  508. }
  509. else
  510. {
  511. // Get the hit index and check for validity.
  512. int iHit = pNudgeDisp->GetTexelHitIndex();
  513. if ( iHit != -1 )
  514. {
  515. // Initialize the spatial paint data.
  516. SpatialPaintData_t spatialData;
  517. spatialData.m_nEffect = DISPPAINT_EFFECT_RAISELOWER;
  518. spatialData.m_uiBrushType = m_uiBrushType;
  519. spatialData.m_flRadius = m_flSpatialRadius;
  520. spatialData.m_flScalar = delta;
  521. spatialData.m_bNudge = true;
  522. spatialData.m_bNudgeInit = m_bNudgeInit;
  523. pNudgeDisp->GetVert( iHit, spatialData.m_vCenter );
  524. VectorCopy( m_vecPaintAxis, spatialData.m_vPaintAxis );
  525. m_DispPaintMgr.Paint( spatialData, m_bAutoSew );
  526. // Done with the init.
  527. m_bNudgeInit = false;
  528. }
  529. }
  530. // reset the cursor pos
  531. SetCursorPos( m_viewCenter.x, m_viewCenter.y );
  532. }
  533. //-----------------------------------------------------------------------------
  534. //-----------------------------------------------------------------------------
  535. void CToolDisplace::ApplyPaintTool( UINT nFlags, const Vector2D &vPoint, CMapDisp *pDisp )
  536. {
  537. switch( m_uiEffect )
  538. {
  539. case DISPPAINT_EFFECT_RAISELOWER:
  540. {
  541. CDispMapImageFilter *pFilter = m_FilterRaiseLowerMgr.GetActiveFilter();
  542. if( pFilter )
  543. {
  544. pFilter->m_DataType = m_iPaintChannel;
  545. if ( m_iPaintChannel == DISPPAINT_CHANNEL_POSITION )
  546. {
  547. pFilter->m_Scale = m_flPaintValueGeo;
  548. }
  549. else if ( m_iPaintChannel == DISPPAINT_CHANNEL_ALPHA )
  550. {
  551. pFilter->m_Scale = m_flPaintValueData;
  552. }
  553. if( m_bRMBDown )
  554. {
  555. pFilter->m_Scale = -pFilter->m_Scale;
  556. }
  557. // apply the filter to the displacement surface(s)
  558. m_FilterRaiseLowerMgr.Apply( pFilter, pDisp, m_iPaintAxis, m_vecPaintAxis, m_bAutoSew );
  559. }
  560. return;
  561. }
  562. case DISPPAINT_EFFECT_MODULATE:
  563. {
  564. // no modulate filters or filter manager currently!
  565. return;
  566. }
  567. case DISPPAINT_EFFECT_SMOOTH:
  568. {
  569. CDispMapImageFilter *pFilter = m_FilterSmoothMgr.GetActiveFilter();
  570. if( pFilter )
  571. {
  572. pFilter->m_DataType = m_iPaintChannel;
  573. pFilter->m_Scale = 1.0f;
  574. int areaValue = 3;
  575. if ( m_iPaintChannel == DISPPAINT_CHANNEL_POSITION )
  576. {
  577. areaValue = ( m_flPaintValueGeo * 2 ) + 1;
  578. }
  579. else if ( m_iPaintChannel == DISPPAINT_CHANNEL_ALPHA )
  580. {
  581. areaValue = ( m_flPaintValueData * 2 ) + 1;
  582. }
  583. if( areaValue < 3 ) { areaValue = 3; }
  584. if( areaValue > 7 ) { areaValue = 7; }
  585. pFilter->m_AreaHeight = areaValue;
  586. pFilter->m_AreaWidth = areaValue;
  587. // apply the filter to the displacement surface(s)
  588. m_FilterSmoothMgr.Apply( pFilter, pDisp, m_iPaintAxis, m_vecPaintAxis, m_bAutoSew );
  589. }
  590. return;
  591. }
  592. case DISPPAINT_EFFECT_RAISETO:
  593. {
  594. CDispMapImageFilter *pFilter = m_FilterRaiseToMgr.GetActiveFilter();
  595. if( pFilter )
  596. {
  597. pFilter->m_DataType = m_iPaintChannel;
  598. if ( m_iPaintChannel == DISPPAINT_CHANNEL_POSITION )
  599. {
  600. pFilter->m_Scale = m_flPaintValueGeo;
  601. }
  602. else if ( m_iPaintChannel == DISPPAINT_CHANNEL_ALPHA )
  603. {
  604. pFilter->m_Scale = m_flPaintValueData;
  605. }
  606. // apply the filter to the displacement surface(s)
  607. m_FilterRaiseToMgr.Apply( pFilter, pDisp, m_iPaintAxis, m_vecPaintAxis, m_bAutoSew );
  608. }
  609. return;
  610. }
  611. }
  612. }
  613. //-----------------------------------------------------------------------------
  614. //-----------------------------------------------------------------------------
  615. void CToolDisplace::ApplySpatialPaintTool( UINT nFlags, const Vector2D &vPoint, CMapDisp *pDisp )
  616. {
  617. // Right mouse button only used to paint in a Raise/Lower situation.
  618. if ( ( m_uiEffect != DISPPAINT_EFFECT_RAISELOWER ) && m_bRMBDown )
  619. return;
  620. // Get the hit index and check for validity.
  621. int iHit = pDisp->GetTexelHitIndex();
  622. if ( iHit == -1 )
  623. return;
  624. // Initialize the spatial paint data.
  625. SpatialPaintData_t spatialData;
  626. spatialData.m_nEffect = m_uiEffect;
  627. spatialData.m_uiBrushType = m_uiBrushType;
  628. spatialData.m_flRadius = m_flSpatialRadius;
  629. spatialData.m_flScalar = m_flPaintValueGeo;
  630. spatialData.m_bNudge = false;
  631. if ( m_bRMBDown )
  632. {
  633. spatialData.m_flScalar = -spatialData.m_flScalar;
  634. }
  635. pDisp->GetVert( iHit, spatialData.m_vCenter );
  636. VectorCopy( m_vecPaintAxis, spatialData.m_vPaintAxis );
  637. m_DispPaintMgr.Paint( spatialData, m_bAutoSew );
  638. }
  639. //-----------------------------------------------------------------------------
  640. //-----------------------------------------------------------------------------
  641. void CToolDisplace::ApplySculptSpatialPaintTool( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
  642. {
  643. // Initialize the spatial paint data.
  644. SpatialPaintData_t spatialData;
  645. spatialData.m_vCenter.Init();
  646. // get hit info
  647. EditDispHandle_t handle = GetHitPos( pView, vPoint );
  648. if( handle != EDITDISPHANDLE_INVALID )
  649. {
  650. m_EditDispHandle = handle;
  651. CMapDisp *pDisp = EditDispMgr()->GetDisp( handle );
  652. // Get the hit index and check for validity.
  653. int iHit = pDisp->GetTexelHitIndex();
  654. if ( iHit != -1 )
  655. {
  656. pDisp->GetVert( iHit, spatialData.m_vCenter );
  657. }
  658. }
  659. spatialData.m_nEffect = m_uiEffect;
  660. spatialData.m_uiBrushType = m_uiBrushType;
  661. spatialData.m_flRadius = m_flSpatialRadius;
  662. spatialData.m_flScalar = m_flPaintValueGeo;
  663. spatialData.m_bNudge = false;
  664. if ( m_bRMBDown )
  665. {
  666. spatialData.m_flScalar = -spatialData.m_flScalar;
  667. }
  668. VectorCopy( m_vecPaintAxis, spatialData.m_vPaintAxis );
  669. m_SculptTool->Paint( pView, vPoint, spatialData );
  670. }
  671. //-----------------------------------------------------------------------------
  672. //-----------------------------------------------------------------------------
  673. void CToolDisplace::ResizeSpatialRadius_Activate( CMapView3D *pView )
  674. {
  675. // Calculate the center of the view and capture the mouse cursor.
  676. CalcViewCenter( pView );
  677. SetCursorPos( m_viewCenter.x, m_viewCenter.y );
  678. pView->SetCapture();
  679. m_bSpatialRadius = true;
  680. }
  681. //-----------------------------------------------------------------------------
  682. //-----------------------------------------------------------------------------
  683. void CToolDisplace::ResizeSpatialRadius_Deactivate( void )
  684. {
  685. ReleaseCapture();
  686. m_bSpatialRadius = false;
  687. }
  688. //-----------------------------------------------------------------------------
  689. //-----------------------------------------------------------------------------
  690. void CToolDisplace::ResizeSpatialRadius_Do( void )
  691. {
  692. CPoint cursorPos;
  693. GetCursorPos( &cursorPos );
  694. // Calculate the delta between the cursor from last frame and this one.
  695. CPoint cursorDelta;
  696. cursorDelta.x = cursorPos.x - m_viewCenter.x;
  697. cursorDelta.y = cursorPos.y - m_viewCenter.y;
  698. float flDelta;
  699. if( abs( cursorDelta.x ) < abs( cursorDelta.y ) )
  700. {
  701. flDelta = cursorDelta.y;
  702. }
  703. else
  704. {
  705. flDelta = cursorDelta.x;
  706. }
  707. flDelta = -flDelta;
  708. // Adjust the sphere radius.
  709. m_flSpatialRadius += flDelta;
  710. // reset the cursor pos
  711. SetCursorPos( m_viewCenter.x, m_viewCenter.y );
  712. //
  713. // Update the paint dialog.
  714. //
  715. CFaceEditSheet *pSheet = GetMainWnd()->GetFaceEditSheet();
  716. if( pSheet )
  717. {
  718. pSheet->m_DispPage.UpdatePaintDialogs();
  719. }
  720. }
  721. //-----------------------------------------------------------------------------
  722. //-----------------------------------------------------------------------------
  723. void CToolDisplace::HandleSelection( CMapView3D *pView, const Vector2D &vPoint )
  724. {
  725. //
  726. // check for closest solid object
  727. //
  728. ULONG ulFace;
  729. CMapClass *pObject;
  730. bool bShift = ( ( GetAsyncKeyState( VK_SHIFT ) & 0x8000 ) != 0 );
  731. if( ( ( pObject = pView->NearestObjectAt( vPoint, ulFace ) ) != NULL ) )
  732. {
  733. if( pObject->IsMapClass( MAPCLASS_TYPE( CMapSolid ) ) )
  734. {
  735. // get the solid
  736. CMapSolid *pSolid = ( CMapSolid* )pObject;
  737. // setup initial command state
  738. int cmd = scToggle | scClear;
  739. //
  740. // don't "clear" if CTRL is pressed
  741. //
  742. if( GetAsyncKeyState( VK_CONTROL ) & 0x8000 )
  743. {
  744. cmd &= ~scClear;
  745. }
  746. CMapDoc *pDoc = pView->GetMapDoc();
  747. if( !pDoc )
  748. return;
  749. // If they are holding down SHIFT, select the entire solid.
  750. if ( bShift )
  751. {
  752. pDoc->SelectFace( pSolid, -1, cmd );
  753. }
  754. // Otherwise, select a single face.
  755. else
  756. {
  757. pDoc->SelectFace( pSolid, ulFace, cmd );
  758. }
  759. }
  760. }
  761. }
  762. //-----------------------------------------------------------------------------
  763. // Purpose: Handle the overriding of displacement triangle tag.
  764. //-----------------------------------------------------------------------------
  765. void CToolDisplace::HandleTagging( CMapView3D *pView, const Vector2D &vPoint )
  766. {
  767. // Get the displacement face (if any) at the 2d point.
  768. ULONG ulFace;
  769. CMapClass *pObject = NULL;
  770. if( ( ( pObject = pView->NearestObjectAt( vPoint, ulFace ) ) != NULL ) )
  771. {
  772. if( pObject->IsMapClass( MAPCLASS_TYPE( CMapSolid ) ) )
  773. {
  774. // Get the face and check for a displacement.
  775. CMapSolid *pSolid = ( CMapSolid* )pObject;
  776. CMapFace *pFace = pSolid->GetFace( ( int )ulFace );
  777. if ( pFace && pFace->HasDisp() )
  778. {
  779. EditDispHandle_t hDisp = pFace->GetDisp();
  780. CMapDisp *pDisp = EditDispMgr()->GetDisp( hDisp );
  781. Vector vecStart, vecEnd;
  782. pView->GetCamera()->BuildRay( vPoint, vecStart, vecEnd );
  783. float flFraction;
  784. int iTri = pDisp->CollideWithDispTri( vecStart, vecEnd, flFraction );
  785. if ( iTri != -1 )
  786. {
  787. if ( m_uiTool == DISPTOOL_TAG_WALKABLE )
  788. {
  789. if ( pDisp->IsTriTag( iTri, COREDISPTRI_TAG_FORCE_WALKABLE_BIT ) )
  790. {
  791. pDisp->ToggleTriTag( iTri, COREDISPTRI_TAG_FORCE_WALKABLE_VAL );
  792. }
  793. else
  794. {
  795. pDisp->SetTriTag( iTri, COREDISPTRI_TAG_FORCE_WALKABLE_BIT );
  796. if ( !pDisp->IsTriTag( iTri, COREDISPTRI_TAG_WALKABLE ) )
  797. {
  798. pDisp->SetTriTag( iTri, COREDISPTRI_TAG_FORCE_WALKABLE_VAL );
  799. }
  800. else
  801. {
  802. pDisp->ResetTriTag( iTri, COREDISPTRI_TAG_FORCE_WALKABLE_VAL );
  803. }
  804. }
  805. pDisp->UpdateWalkable();
  806. }
  807. else if ( m_uiTool == DISPTOOL_TAG_BUILDABLE )
  808. {
  809. if ( pDisp->IsTriTag( iTri, COREDISPTRI_TAG_FORCE_BUILDABLE_BIT ) )
  810. {
  811. pDisp->ToggleTriTag( iTri, COREDISPTRI_TAG_FORCE_BUILDABLE_VAL );
  812. }
  813. else
  814. {
  815. pDisp->SetTriTag( iTri, COREDISPTRI_TAG_FORCE_BUILDABLE_BIT );
  816. if ( !pDisp->IsTriTag( iTri, COREDISPTRI_TAG_BUILDABLE ) )
  817. {
  818. pDisp->SetTriTag( iTri, COREDISPTRI_TAG_FORCE_BUILDABLE_VAL );
  819. }
  820. else
  821. {
  822. pDisp->ResetTriTag( iTri, COREDISPTRI_TAG_FORCE_BUILDABLE_VAL );
  823. }
  824. }
  825. pDisp->UpdateBuildable();
  826. }
  827. else if ( m_uiTool == DISPTOOL_TAG_REMOVE )
  828. {
  829. HandleTaggingRemove( pDisp, iTri );
  830. }
  831. }
  832. }
  833. }
  834. }
  835. }
  836. //-----------------------------------------------------------------------------
  837. // Purpose:
  838. //-----------------------------------------------------------------------------
  839. void CToolDisplace::HandleTaggingRemove( CMapDisp *pDisp, int nTriIndex )
  840. {
  841. pDisp->ToggleTriTag( nTriIndex, COREDISPTRI_TAG_FORCE_REMOVE_BIT );
  842. pDisp->UpdateTriRemove();
  843. }
  844. //-----------------------------------------------------------------------------
  845. // Purpose: Handle the overriding of displacement triangle tag.
  846. //-----------------------------------------------------------------------------
  847. void CToolDisplace::HandleTaggingReset( CMapView3D *pView, const Vector2D &vPoint )
  848. {
  849. // Get the displacement face (if any) at the 2d point.
  850. ULONG ulFace;
  851. CMapClass *pObject = NULL;
  852. if( ( ( pObject = pView->NearestObjectAt( vPoint, ulFace ) ) != NULL ) )
  853. {
  854. if( pObject->IsMapClass( MAPCLASS_TYPE( CMapSolid ) ) )
  855. {
  856. // Get the face and check for a displacement.
  857. CMapSolid *pSolid = ( CMapSolid* )pObject;
  858. CMapFace *pFace = pSolid->GetFace( ( int )ulFace );
  859. if ( pFace && pFace->HasDisp() )
  860. {
  861. EditDispHandle_t hDisp = pFace->GetDisp();
  862. CMapDisp *pDisp = EditDispMgr()->GetDisp( hDisp );
  863. Vector vecStart, vecEnd;
  864. pView->GetCamera()->BuildRay( vPoint, vecStart, vecEnd );
  865. float flFraction;
  866. int iTri = pDisp->CollideWithDispTri( vecStart, vecEnd, flFraction );
  867. if ( iTri != -1 )
  868. {
  869. if ( m_uiTool == DISPTOOL_TAG_WALKABLE )
  870. {
  871. pDisp->ResetTriTag( iTri, COREDISPTRI_TAG_FORCE_WALKABLE_BIT );
  872. pDisp->UpdateWalkable();
  873. }
  874. else if ( m_uiTool == DISPTOOL_TAG_BUILDABLE )
  875. {
  876. pDisp->ResetTriTag( iTri, COREDISPTRI_TAG_FORCE_BUILDABLE_BIT );
  877. pDisp->UpdateBuildable();
  878. }
  879. else if ( m_uiTool == DISPTOOL_TAG_REMOVE )
  880. {
  881. pDisp->ResetTriTag( iTri, COREDISPTRI_TAG_FORCE_REMOVE_BIT );
  882. pDisp->UpdateBuildable();
  883. }
  884. }
  885. }
  886. }
  887. }
  888. }
  889. //-----------------------------------------------------------------------------
  890. //-----------------------------------------------------------------------------
  891. EditDispHandle_t CToolDisplace::GetHitPos( CMapView3D *pView, const Vector2D &vPoint )
  892. {
  893. //
  894. // get ray info
  895. //
  896. Vector rayStart, rayEnd;
  897. pView->GetCamera()->BuildRay( vPoint, rayStart, rayEnd );
  898. // generate selected displacement list
  899. int dispCount = GetSelectedDisps();
  900. if( dispCount == 0 )
  901. return NULL;
  902. // collide against all "active" displacements and set texel hit data
  903. return CollideWithSelectedDisps( rayStart, rayEnd );
  904. }
  905. //-----------------------------------------------------------------------------
  906. //-----------------------------------------------------------------------------
  907. int CToolDisplace::GetSelectedDisps( void )
  908. {
  909. //
  910. // get a valid displacement manager
  911. //
  912. IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager();
  913. if( !pDispMgr )
  914. return 0;
  915. // clear the selection list
  916. pDispMgr->SelectClear();
  917. //
  918. // add all selected displacements to "displacement manager"'s selection list
  919. //
  920. CFaceEditSheet *pSheet = GetMainWnd()->GetFaceEditSheet();
  921. if( !pSheet )
  922. return 0;
  923. int faceCount = pSheet->GetFaceListCount();
  924. for( int i = 0; i < faceCount; i++ )
  925. {
  926. CMapFace *pFace = pSheet->GetFaceListDataFace( i );
  927. if( !pFace )
  928. continue;
  929. if( pFace->HasDisp() )
  930. {
  931. EditDispHandle_t handle = pFace->GetDisp();
  932. CMapDisp *pDisp = EditDispMgr()->GetDisp( handle );
  933. pDisp->ResetTexelHitIndex();
  934. pDispMgr->AddToSelect( handle );
  935. }
  936. }
  937. // return the number of displacements in list
  938. return pDispMgr->SelectCount();
  939. }
  940. //-----------------------------------------------------------------------------
  941. //-----------------------------------------------------------------------------
  942. EditDispHandle_t CToolDisplace::CollideWithSelectedDisps( const Vector &rayStart, const Vector &rayEnd )
  943. {
  944. EditDispHandle_t handle = EDITDISPHANDLE_INVALID;
  945. float minDist = 99999.9f;
  946. int minIndex = -1;
  947. //
  948. // get a valid displacement manager
  949. //
  950. IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager();
  951. if( !pDispMgr )
  952. return NULL;
  953. int dispCount = pDispMgr->SelectCount();
  954. for( int i = 0; i < dispCount; i++ )
  955. {
  956. // get the current displacement
  957. CMapDisp *pDisp = pDispMgr->GetFromSelect( i );
  958. if( !pDisp )
  959. continue;
  960. bool bCollide = RayAABBTest( pDisp, rayStart, rayEnd );
  961. if( bCollide )
  962. {
  963. Vector point;
  964. int size = pDisp->GetSize();
  965. for( int j = 0; j < size; j++ )
  966. {
  967. // get current point
  968. pDisp->GetVert( j, point );
  969. // find point closest to ray
  970. float dist = DistFromPointToRay( rayStart, rayEnd, point );
  971. if( dist < minDist )
  972. {
  973. CMapFace *pFace = ( CMapFace* )pDisp->GetParent();
  974. handle = pFace->GetDisp();
  975. minDist = dist;
  976. minIndex = j;
  977. }
  978. }
  979. }
  980. }
  981. //
  982. // set the texel hit index
  983. //
  984. if( handle != EDITDISPHANDLE_INVALID )
  985. {
  986. CMapDisp *pDisp = EditDispMgr()->GetDisp( handle );
  987. pDisp->SetTexelHitIndex( minIndex );
  988. }
  989. return handle;
  990. }
  991. //-----------------------------------------------------------------------------
  992. //-----------------------------------------------------------------------------
  993. bool CToolDisplace::RayAABBTest( CMapDisp *pDisp, const Vector &rayStart, const Vector &rayEnd )
  994. {
  995. //
  996. // make planes
  997. //
  998. PLANE planes[6];
  999. Vector boxMin, boxMax;
  1000. pDisp->GetBoundingBox( boxMin, boxMax );
  1001. BuildParallelepiped( boxMin, boxMax, planes );
  1002. bool bCollide = false;
  1003. for( int planeIndex = 0; planeIndex < 6; planeIndex++ )
  1004. {
  1005. bCollide = RayPlaneTest( &planes[planeIndex], rayStart, rayEnd );
  1006. if( !bCollide )
  1007. return false;
  1008. }
  1009. return true;
  1010. }
  1011. //-----------------------------------------------------------------------------
  1012. //-----------------------------------------------------------------------------
  1013. void CToolDisplace::BuildParallelepiped( const Vector &boxMin, const Vector &boxMax,
  1014. PLANE planes[6] )
  1015. {
  1016. int planeIndex = 0;
  1017. for( int axis = 0; axis < 3; axis++ )
  1018. {
  1019. for( int direction = -1; direction < 2; direction += 2 )
  1020. {
  1021. // clear the current plane info
  1022. VectorClear( planes[planeIndex].normal );
  1023. planes[planeIndex].normal[axis] = direction;
  1024. if( direction == 1 )
  1025. {
  1026. planes[planeIndex].dist = boxMax[axis];
  1027. }
  1028. else
  1029. {
  1030. planes[planeIndex].dist = -boxMin[axis];
  1031. }
  1032. planeIndex++;
  1033. }
  1034. }
  1035. }
  1036. //-----------------------------------------------------------------------------
  1037. //-----------------------------------------------------------------------------
  1038. bool CToolDisplace::RayPlaneTest( PLANE *pPlane, const Vector& rayStart, const Vector& rayEnd /*, float *fraction*/ )
  1039. {
  1040. //
  1041. // get the distances both trace start and end from the bloated plane
  1042. //
  1043. float distStart = DotProduct( rayStart, pPlane->normal ) - pPlane->dist;
  1044. float distEnd = DotProduct( rayEnd, pPlane->normal ) - pPlane->dist;
  1045. //
  1046. // no collision - both points are in front or behind of the given plane
  1047. //
  1048. if( ( distStart > 0.0f ) && ( distEnd > 0.0f ) )
  1049. return false;
  1050. if( ( distStart > 0.0f ) && ( distEnd > 0.0f ) )
  1051. return false;
  1052. // calculate the parameterized "t" component along the ray
  1053. //*fraction = distStart / ( distStart - distEnd );
  1054. // collision
  1055. return true;
  1056. }
  1057. //-----------------------------------------------------------------------------
  1058. //-----------------------------------------------------------------------------
  1059. float CToolDisplace::DistFromPointToRay( const Vector& rayStart, const Vector& rayEnd,
  1060. const Vector& point )
  1061. {
  1062. //
  1063. // calculate the ray
  1064. //
  1065. Vector ray;
  1066. VectorSubtract( rayEnd, rayStart, ray );
  1067. VectorNormalize( ray );
  1068. //
  1069. // get a ray to point
  1070. //
  1071. Vector seg;
  1072. VectorSubtract( point, rayStart, seg );
  1073. //
  1074. // project point segment onto ray - get perpendicular point
  1075. //
  1076. float value = DotProduct( ray, seg );
  1077. VectorScale( ray, value, ray );
  1078. VectorAdd( rayStart, ray, ray );
  1079. //
  1080. // find the distance between the perpendicular point and point
  1081. //
  1082. VectorSubtract( ray, point, seg );
  1083. float dist = VectorLength( seg );
  1084. return dist;
  1085. }
  1086. //-----------------------------------------------------------------------------
  1087. //-----------------------------------------------------------------------------
  1088. void CToolDisplace::AddFiltersToManagers( void )
  1089. {
  1090. int count = m_FilterLoaderMgr.GetFilterCount();
  1091. for( int ndxFilter = 0; ndxFilter < count; ndxFilter++ )
  1092. {
  1093. CDispMapImageFilter *pFilter = m_FilterLoaderMgr.GetFilter( ndxFilter );
  1094. if( pFilter )
  1095. {
  1096. switch( pFilter->m_Type )
  1097. {
  1098. case DISPPAINT_EFFECT_RAISELOWER:
  1099. {
  1100. m_FilterRaiseLowerMgr.Add( pFilter );
  1101. break;
  1102. }
  1103. case DISPPAINT_EFFECT_RAISETO:
  1104. {
  1105. m_FilterRaiseToMgr.Add( pFilter );
  1106. break;
  1107. }
  1108. case DISPPAINT_EFFECT_SMOOTH:
  1109. {
  1110. m_FilterSmoothMgr.Add( pFilter );
  1111. break;
  1112. }
  1113. }
  1114. }
  1115. }
  1116. }
  1117. //-----------------------------------------------------------------------------
  1118. //-----------------------------------------------------------------------------
  1119. bool CToolDisplace::LoadFilters( const char *filename )
  1120. {
  1121. //
  1122. // Open the file.
  1123. //
  1124. CChunkFile File;
  1125. ChunkFileResult_t eResult = File.Open( filename, ChunkFile_Read );
  1126. if( eResult != ChunkFile_Ok )
  1127. {
  1128. Msg( mwError, "Couldn't load filter file %s!\n", filename );
  1129. }
  1130. //
  1131. // Read the file.
  1132. //
  1133. if (eResult == ChunkFile_Ok)
  1134. {
  1135. //
  1136. // Set up handlers for the subchunks that we are interested in.
  1137. //
  1138. CChunkHandlerMap Handlers;
  1139. Handlers.AddHandler( "Filter", ( ChunkHandler_t )CToolDisplace::LoadFiltersCallback, this );
  1140. File.PushHandlers( &Handlers );
  1141. //
  1142. // Read the sub-chunks. We ignore keys in the root of the file, so we don't pass a
  1143. // key value callback to ReadChunk.
  1144. //
  1145. while (eResult == ChunkFile_Ok)
  1146. {
  1147. eResult = File.ReadChunk();
  1148. }
  1149. if (eResult == ChunkFile_EOF)
  1150. {
  1151. eResult = ChunkFile_Ok;
  1152. }
  1153. File.PopHandlers();
  1154. }
  1155. return( eResult == ChunkFile_Ok );
  1156. }
  1157. //-----------------------------------------------------------------------------
  1158. //-----------------------------------------------------------------------------
  1159. ChunkFileResult_t CToolDisplace::LoadFiltersCallback( CChunkFile *pFile, CToolDisplace *pDisplaceTool )
  1160. {
  1161. //
  1162. // allocate a new filter
  1163. //
  1164. CDispMapImageFilter *pFilter = pDisplaceTool->m_FilterLoaderMgr.Create();
  1165. if( !pFilter )
  1166. return ChunkFile_Fail;
  1167. // load the filter data
  1168. ChunkFileResult_t eResult = pFilter->LoadFilter( pFile );
  1169. return( eResult );
  1170. }
  1171. //-----------------------------------------------------------------------------
  1172. // Purpose:
  1173. // Input : *pRender -
  1174. // *pTool -
  1175. //-----------------------------------------------------------------------------
  1176. void CToolDisplace::RenderPaintSphere( CRender3D *pRender )
  1177. {
  1178. CMapDisp *pDisp = GetEditDisp();
  1179. if (pDisp == NULL)
  1180. return;
  1181. // Get the sphere center.
  1182. int iHit = pDisp->GetTexelHitIndex();
  1183. if ( iHit == -1 )
  1184. return;
  1185. // Get the sphere center and radius.
  1186. Vector vCenter;
  1187. pDisp->GetVert( iHit, vCenter );
  1188. float flRadius = GetSpatialRadius();
  1189. int size = ( int )( flRadius * 0.05f );
  1190. if ( size < 6 ) { size = 6; }
  1191. if ( size > 12 ) { size = 12; }
  1192. // Render the sphere.
  1193. if ( !IsNudging() )
  1194. {
  1195. pRender->RenderWireframeSphere( vCenter, flRadius, size, size, 0, 255, 0 );
  1196. }
  1197. else
  1198. {
  1199. pRender->RenderWireframeSphere( vCenter, flRadius, size, size, 255, 255, 0 );
  1200. }
  1201. // Render the displacement axis (as an arrow).
  1202. int nPaintAxis;
  1203. Vector vPaintAxis;
  1204. GetPaintAxis( nPaintAxis, vPaintAxis );
  1205. if( nPaintAxis == DISPPAINT_AXIS_SUBDIV )
  1206. {
  1207. pDisp->GetSubdivNormal( iHit, vPaintAxis );
  1208. }
  1209. float flBloat = flRadius * 0.15f;
  1210. pRender->RenderArrow( vCenter, vCenter + ( vPaintAxis * ( flRadius + flBloat ) ), 255, 255, 0 );
  1211. // Render cube at center point.
  1212. Vector vBoxMin, vBoxMax;
  1213. for ( int iAxis = 0; iAxis < 3; iAxis++ )
  1214. {
  1215. vBoxMin[iAxis] = vCenter[iAxis] - ( flBloat * 0.25f );
  1216. vBoxMax[iAxis] = vCenter[iAxis] + ( flBloat * 0.25f );
  1217. }
  1218. pRender->RenderBox( vBoxMin, vBoxMax, 255, 255, 0, SELECT_NONE );
  1219. }
  1220. //-----------------------------------------------------------------------------
  1221. // Purpose:
  1222. // Input : pRender -
  1223. // bNudge -
  1224. //-----------------------------------------------------------------------------
  1225. void CToolDisplace::RenderHitBox( CRender3D *pRender )
  1226. {
  1227. CMapDisp *pDisp = GetEditDisp();
  1228. if (pDisp == NULL)
  1229. return;
  1230. //
  1231. // get selection
  1232. //
  1233. int index = pDisp->GetTexelHitIndex();
  1234. if( index == -1 )
  1235. return;
  1236. //
  1237. // get the displacement map width and height
  1238. //
  1239. int width = pDisp->GetWidth();
  1240. int height = pDisp->GetHeight();
  1241. Vector seg[2];
  1242. Vector points[2];
  1243. pDisp->GetVert( 0, points[0] );
  1244. pDisp->GetVert( ( width - 1 ), points[1] );
  1245. VectorSubtract( points[1], points[0], seg[0] );
  1246. pDisp->GetVert( ( ( width - 1 ) * height ), points[1] );
  1247. VectorSubtract( points[1], points[0], seg[1] );
  1248. VectorAdd( seg[0], seg[1], seg[0] );
  1249. VectorScale( seg[0], 0.5f, seg[0] );
  1250. //
  1251. // determine a good size to make the "box" surrounding the selected point
  1252. //
  1253. float length = VectorLength( seg[0] );
  1254. length *= 0.025f;
  1255. //
  1256. // render the box
  1257. //
  1258. pDisp->GetVert( index, points[0] );
  1259. Vector minb, maxb;
  1260. minb[0] = points[0][0] - length;
  1261. minb[1] = points[0][1] - length;
  1262. minb[2] = points[0][2] - length;
  1263. maxb[0] = points[0][0] + length;
  1264. maxb[1] = points[0][1] + length;
  1265. maxb[2] = points[0][2] + length;
  1266. if( !IsNudging() )
  1267. {
  1268. pRender->RenderWireframeBox( minb, maxb, 0, 255, 0 );
  1269. }
  1270. else
  1271. {
  1272. pRender->RenderWireframeBox( minb, maxb, 255, 255, 0 );
  1273. }
  1274. //
  1275. // render the normal
  1276. //
  1277. // get hit box origin
  1278. Vector hbOrigin;
  1279. pDisp->GetVert( index, hbOrigin );
  1280. // get 4x length
  1281. float length4 = length * 4.0f;
  1282. int paintAxis;
  1283. Vector vecPaint;
  1284. GetPaintAxis( paintAxis, vecPaint );
  1285. if( paintAxis == DISPPAINT_AXIS_SUBDIV )
  1286. {
  1287. pDisp->GetSubdivNormal( index, vecPaint );
  1288. }
  1289. //
  1290. // render the normal -- just a yellow line at this point
  1291. //
  1292. pRender->RenderArrow( hbOrigin, hbOrigin + ( vecPaint * length4 ), 255, 255, 0 );
  1293. #if 0
  1294. CMeshBuilder meshBuilder;
  1295. IMesh *pMesh = MaterialSystemInterface()->GetDynamicMesh();
  1296. meshBuilder.Begin( pMesh, MATERIAL_LINES, 1 );
  1297. meshBuilder.Position3f( hbOrigin.x, hbOrigin.y, hbOrigin.z );
  1298. meshBuilder.Color3ub( 255, 255, 0 );
  1299. meshBuilder.AdvanceVertex();
  1300. meshBuilder.Position3f( hbOrigin.x + ( normal.x * length4 ),
  1301. hbOrigin.y + ( normal.y * length4 ),
  1302. hbOrigin.z + ( normal.z * length4 ) );
  1303. meshBuilder.Color3ub( 255, 255, 0 );
  1304. meshBuilder.AdvanceVertex();
  1305. meshBuilder.End();
  1306. pMesh->Draw();
  1307. #endif
  1308. }
  1309. //-----------------------------------------------------------------------------
  1310. // Purpose:
  1311. // Input : *pRender -
  1312. //-----------------------------------------------------------------------------
  1313. void CToolDisplace::RenderTool3D(CRender3D *pRender)
  1314. {
  1315. unsigned int uiTool = GetTool();
  1316. if ( uiTool == DISPTOOL_PAINT )
  1317. {
  1318. if ( IsSpatialPainting() )
  1319. {
  1320. RenderPaintSphere( pRender );
  1321. }
  1322. else
  1323. {
  1324. RenderHitBox( pRender );
  1325. }
  1326. }
  1327. if ( uiTool == DISPTOOL_PAINT_SCULPT )
  1328. {
  1329. m_SculptTool->RenderTool3D( pRender );
  1330. }
  1331. }