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.

2106 lines
50 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "stdafx.h"
  7. #include "GlobalFunctions.h"
  8. #include "History.h"
  9. #include "materialsystem/IMaterialSystem.h"
  10. #include "materialsystem/IMesh.h"
  11. #include "MainFrm.h"
  12. #include "MapDefs.h"
  13. #include "MapDoc.h"
  14. #include "MapSolid.h"
  15. #include "MapView2D.h"
  16. #include "MapView3D.h"
  17. #include "Material.h"
  18. #include "ObjectProperties.h"
  19. #include "ToolManager.h"
  20. #include "ToolMorph.h"
  21. #include "Options.h"
  22. #include "Render2D.h"
  23. #include "StatusBarIDs.h"
  24. #include "hammer.h"
  25. #include "mathlib/vmatrix.h"
  26. #include "vgui/Cursor.h"
  27. #include "Selection.h"
  28. // memdbgon must be the last include file in a .cpp file!!!
  29. #include <tier0/memdbgon.h>
  30. //-----------------------------------------------------------------------------
  31. // Purpose: Callback function to add objects to the morph selection.
  32. // Input : pSolid - Solid to add.
  33. // pMorph - Morph tool.
  34. // Output : Returns TRUE to continue enumerating.
  35. //-----------------------------------------------------------------------------
  36. static BOOL AddToMorph(CMapSolid *pSolid, Morph3D *pMorph)
  37. {
  38. pMorph->SelectObject(pSolid, scSelect);
  39. return TRUE;
  40. }
  41. //-----------------------------------------------------------------------------
  42. // Purpose:
  43. //-----------------------------------------------------------------------------
  44. Morph3D::Morph3D(void)
  45. {
  46. m_SelectedType = shtNothing;
  47. m_HandleMode = hmBoth;
  48. m_bBoxSelecting = false;
  49. m_bScaling = false;
  50. m_pOrigPosList = NULL;
  51. m_vLastMouseMovement.Init();
  52. m_bHit = false;
  53. m_bUpdateOrg = false;
  54. m_bLButtonDownControlState = false;
  55. SetDrawColors(Options.colors.clrToolHandle, Options.colors.clrToolMorph);
  56. memset(&m_DragHandle, 0, sizeof(m_DragHandle));
  57. m_bMorphing = false;
  58. m_bMovingSelected = false;
  59. }
  60. //-----------------------------------------------------------------------------
  61. // Purpose:
  62. //-----------------------------------------------------------------------------
  63. Morph3D::~Morph3D(void)
  64. {
  65. }
  66. //-----------------------------------------------------------------------------
  67. // Purpose:
  68. //-----------------------------------------------------------------------------
  69. void Morph3D::OnActivate()
  70. {
  71. if (IsActiveTool())
  72. {
  73. //
  74. // Already active - change modes and redraw views.
  75. //
  76. ToggleMode();
  77. }
  78. else
  79. {
  80. //
  81. // Put all selected objects into morph
  82. //
  83. const CMapObjectList *pSelection = m_pDocument->GetSelection()->GetList();
  84. for (int i = 0; i < pSelection->Count(); i++)
  85. {
  86. CMapClass *pobj = (CUtlReference< CMapClass >)pSelection->Element(i);
  87. if (pobj->IsMapClass(MAPCLASS_TYPE(CMapSolid)))
  88. {
  89. SelectObject((CMapSolid *)pobj, scSelect);
  90. }
  91. pobj->EnumChildren((ENUMMAPCHILDRENPROC)AddToMorph, (DWORD)this, MAPCLASS_TYPE(CMapSolid));
  92. }
  93. m_pDocument->SelectObject(NULL, scClear|scSaveChanges );
  94. }
  95. }
  96. //-----------------------------------------------------------------------------
  97. // Purpose: Can we deactivate this tool.
  98. //-----------------------------------------------------------------------------
  99. bool Morph3D::CanDeactivate( void )
  100. {
  101. return CanDeselectList();
  102. }
  103. //-----------------------------------------------------------------------------
  104. // Purpose: Called when the tool is deactivated.
  105. // Input : eNewTool - The ID of the tool that is being activated.
  106. //-----------------------------------------------------------------------------
  107. void Morph3D::OnDeactivate()
  108. {
  109. if (IsScaling())
  110. {
  111. OnScaleCmd();
  112. }
  113. if ( !IsEmpty() )
  114. {
  115. CUtlVector <CMapClass *>List;
  116. GetMorphingObjects(List);
  117. // Empty morph tool (Save contents).
  118. SetEmpty();
  119. //
  120. // Select the solids that we were morphing.
  121. //
  122. int nObjectCount = List.Count();
  123. for (int i = 0; i < nObjectCount; i++)
  124. {
  125. CMapClass *pSolid = List.Element(i);
  126. CMapClass *pSelect = pSolid->PrepareSelection(m_pDocument->GetSelection()->GetMode());
  127. if (pSelect)
  128. {
  129. m_pDocument->SelectObject(pSelect, scSelect);
  130. }
  131. }
  132. m_pDocument->UpdateAllViews( MAPVIEW_UPDATE_TOOL );
  133. }
  134. }
  135. //-----------------------------------------------------------------------------
  136. // Purpose: Returns true if the given solid is being morphed, false if not.
  137. // Input : pSolid - The solid.
  138. // pStrucSolidRvl - The corresponding structured solid.
  139. //-----------------------------------------------------------------------------
  140. BOOL Morph3D::IsMorphing(CMapSolid *pSolid, CSSolid **pStrucSolidRvl)
  141. {
  142. FOR_EACH_OBJ( m_StrucSolids, pos )
  143. {
  144. CSSolid *pSSolid = m_StrucSolids.Element(pos);
  145. if(pSSolid->m_pMapSolid == pSolid)
  146. {
  147. if(pStrucSolidRvl)
  148. pStrucSolidRvl[0] = pSSolid;
  149. return TRUE;
  150. }
  151. }
  152. return FALSE;
  153. }
  154. //-----------------------------------------------------------------------------
  155. // Purpose: Returns the bounding box of the objects being morphed.
  156. // Input : bReset -
  157. //-----------------------------------------------------------------------------
  158. void Morph3D::GetMorphBounds(Vector &mins, Vector &maxs, bool bReset)
  159. {
  160. mins = m_MorphBounds.bmins;
  161. maxs = m_MorphBounds.bmaxs;
  162. if (bReset)
  163. {
  164. m_MorphBounds.ResetBounds();
  165. }
  166. }
  167. //-----------------------------------------------------------------------------
  168. // Purpose: Can we deslect the list? All current SSolid with displacements
  169. // are valid.
  170. //-----------------------------------------------------------------------------
  171. bool Morph3D::CanDeselectList( void )
  172. {
  173. FOR_EACH_OBJ( m_StrucSolids, pos )
  174. {
  175. CSSolid *pSSolid = m_StrucSolids.Element( pos );
  176. if ( pSSolid )
  177. {
  178. if ( !pSSolid->IsValidWithDisps() )
  179. {
  180. // Ask
  181. if( AfxMessageBox( "Invalid solid, destroy displacement(s)?", MB_YESNO ) == IDYES )
  182. {
  183. // Destroy the displacement data.
  184. pSSolid->DestroyDisps();
  185. }
  186. else
  187. {
  188. return false;
  189. }
  190. }
  191. }
  192. }
  193. return true;
  194. }
  195. //-----------------------------------------------------------------------------
  196. // Purpose: Selects a solid for vertex manipulation. An SSolid class is created
  197. // and the CMapSolid is attached to it. The map solid is removed from
  198. // the views, since it will be represented by the structured solid
  199. // until vertex manipulation is finished.
  200. // Input : pSolid - Map solid to select.
  201. // cmd - scClear, scToggle, scUnselect
  202. //-----------------------------------------------------------------------------
  203. void Morph3D::SelectObject(CMapSolid *pSolid, UINT cmd)
  204. {
  205. // construct temporary list to pass to document functions:
  206. CMapObjectList List;
  207. List.AddToTail( pSolid );
  208. if( cmd & scClear )
  209. SetEmpty();
  210. CSSolid *pStrucSolid;
  211. if ( IsMorphing( pSolid, &pStrucSolid ) )
  212. {
  213. if ( cmd & scToggle || cmd & scUnselect )
  214. {
  215. // stop morphing solid
  216. Vector mins,maxs;
  217. pSolid->GetRender2DBox(mins, maxs);
  218. m_MorphBounds.UpdateBounds(mins, maxs);
  219. pStrucSolid->Convert(FALSE);
  220. pSolid->GetRender2DBox(mins, maxs);
  221. m_MorphBounds.UpdateBounds(mins, maxs);
  222. pStrucSolid->Detach();
  223. m_pDocument->SetModifiedFlag();
  224. // want to draw in 2d views again
  225. pSolid->SetVisible2D(true);
  226. // remove from linked list
  227. m_StrucSolids.FindAndRemove(pStrucSolid);
  228. // make sure none of its handles are selected
  229. for(int i = m_SelectedHandles.Count()-1; i >=0; i--)
  230. {
  231. if(m_SelectedHandles[i].pStrucSolid == pStrucSolid)
  232. {
  233. m_SelectedHandles.Remove(i);
  234. }
  235. }
  236. delete pStrucSolid;
  237. pSolid->SetSelectionState(SELECT_NONE);
  238. }
  239. return;
  240. }
  241. pStrucSolid = new CSSolid;
  242. // convert to structured solid
  243. pStrucSolid->Attach(pSolid);
  244. pStrucSolid->Convert();
  245. pStrucSolid->ShowHandles(m_HandleMode & hmVertex, m_HandleMode & hmEdge);
  246. // don't draw this solid in the 2D views anymore
  247. pSolid->SetVisible2D(false);
  248. pSolid->SetSelectionState(SELECT_MORPH);
  249. // add to list of structured solids
  250. m_StrucSolids.AddToTail(pStrucSolid);
  251. }
  252. int Morph3D::HitTest(CMapView *pView, const Vector2D &ptClient, bool bTestHandles )
  253. {
  254. if (m_bBoxSelecting)
  255. {
  256. return Box3D::HitTest( pView, ptClient, bTestHandles);
  257. }
  258. return FALSE;
  259. }
  260. //-----------------------------------------------------------------------------
  261. // Purpose:
  262. //-----------------------------------------------------------------------------
  263. bool CompareMorphHandles(const MORPHHANDLE &mh1, const MORPHHANDLE &mh2)
  264. {
  265. return ((mh1.pMapSolid == mh2.pMapSolid) &&
  266. (mh1.pStrucSolid == mh2.pStrucSolid) &&
  267. (mh1.ssh == mh2.ssh));
  268. }
  269. //-----------------------------------------------------------------------------
  270. // Purpose: Returns whether or not the given morph handle is selected.
  271. //-----------------------------------------------------------------------------
  272. bool Morph3D::IsSelected(MORPHHANDLE &mh)
  273. {
  274. for (int i = 0; i < m_SelectedHandles.Count(); i++)
  275. {
  276. if (CompareMorphHandles(m_SelectedHandles[i], mh))
  277. {
  278. return true;
  279. }
  280. }
  281. return false;
  282. }
  283. //-----------------------------------------------------------------------------
  284. // Purpose: Hit tests against all the handles. Sets the mouse cursor if we are
  285. // over a handle.
  286. // Input : pt -
  287. // pInfo -
  288. // Output : Returns TRUE if the mouse cursor is over a handle, FALSE if not.
  289. //-----------------------------------------------------------------------------
  290. bool Morph3D::MorphHitTest(CMapView *pView, const Vector2D &vPoint, MORPHHANDLE *pInfo)
  291. {
  292. SSHANDLE hnd = 0;
  293. bool bIs2D = pView->IsOrthographic();
  294. if ( pInfo )
  295. {
  296. memset(pInfo, 0, sizeof(MORPHHANDLE));
  297. }
  298. // check scaling position first
  299. if ( bIs2D && m_bScaling && pInfo)
  300. {
  301. if ( HitRect( pView, vPoint, m_ScaleOrg, 8 ) )
  302. {
  303. pInfo->ssh = SSH_SCALEORIGIN;
  304. return true;
  305. }
  306. }
  307. FOR_EACH_OBJ( m_StrucSolids, pos )
  308. {
  309. CSSolid *pStrucSolid = m_StrucSolids.Element(pos);
  310. // do a hit test on all handles:
  311. if (m_HandleMode & hmVertex)
  312. {
  313. for(int i = 0; i < pStrucSolid->m_nVertices; i++)
  314. {
  315. CSSVertex &v = pStrucSolid->m_Vertices[i];
  316. if( HitRect( pView, vPoint, v.pos, HANDLE_RADIUS ) )
  317. {
  318. hnd = v.id;
  319. break;
  320. }
  321. }
  322. }
  323. if (!hnd && (m_HandleMode & hmEdge))
  324. {
  325. for (int i = 0; i < pStrucSolid->m_nEdges; i++)
  326. {
  327. CSSEdge &e = pStrucSolid->m_Edges[i];
  328. if( HitRect( pView, vPoint, e.ptCenter, HANDLE_RADIUS ) )
  329. {
  330. hnd = e.id;
  331. break;
  332. }
  333. }
  334. }
  335. if (hnd)
  336. {
  337. if ( bIs2D )
  338. {
  339. SSHANDLEINFO hi;
  340. pStrucSolid->GetHandleInfo(&hi, hnd);
  341. // see if there is a 2d match that is already selected - if
  342. // there is, select that instead
  343. SSHANDLE hMatch = Get2DMatches( dynamic_cast<CMapView2D*>(pView), pStrucSolid, hi);
  344. if(hMatch)
  345. hnd = hMatch;
  346. }
  347. if(pInfo)
  348. {
  349. pInfo->pMapSolid = pStrucSolid->m_pMapSolid;
  350. pInfo->pStrucSolid = pStrucSolid;
  351. pInfo->ssh = hnd;
  352. }
  353. break;
  354. }
  355. }
  356. return hnd != 0;
  357. }
  358. void Morph3D::GetHandlePos(MORPHHANDLE *pInfo, Vector& pt)
  359. {
  360. SSHANDLEINFO hi;
  361. pInfo->pStrucSolid->GetHandleInfo(&hi, pInfo->ssh);
  362. pt = hi.pos;
  363. }
  364. //-----------------------------------------------------------------------------
  365. // Purpose: Fills out a list of handles in the given solid that are at the same
  366. // position as the given handle in the current 2D view.
  367. // Input : pStrucSolid -
  368. // hi -
  369. // hAddSimilarList -
  370. // pnAddSimilar -
  371. // Output : Returns a selected handle at the same position as the given handle,
  372. // if one exists, otherwise returns 0.
  373. //-----------------------------------------------------------------------------
  374. SSHANDLE Morph3D::Get2DMatches( CMapView2D *pView, CSSolid *pStrucSolid, SSHANDLEINFO &hi, CUtlVector<SSHANDLE>*pSimilarList)
  375. {
  376. SSHANDLE hNewMoveHandle = 0;
  377. int axHorz = pView->axHorz;
  378. int axVert = pView->axVert;
  379. if(hi.Type == shtVertex)
  380. {
  381. for(int i = 0; i < pStrucSolid->m_nVertices; i++)
  382. {
  383. CSSVertex & v = pStrucSolid->m_Vertices[i];
  384. // YWB Fixme, scale olerance to zoom amount?
  385. if( (fabs(hi.pos[axHorz] - v.pos[axHorz]) < 0.5) &&
  386. (fabs(hi.pos[axVert] - v.pos[axVert]) < 0.5) )
  387. {
  388. if(v.m_bSelected)
  389. {
  390. hNewMoveHandle = v.id;
  391. }
  392. // add it to the array to select
  393. if( pSimilarList )
  394. pSimilarList->AddToTail(v.id);
  395. }
  396. }
  397. }
  398. else if(hi.Type == shtEdge)
  399. {
  400. for(int i = 0; i < pStrucSolid->m_nEdges; i++)
  401. {
  402. CSSEdge& e = pStrucSolid->m_Edges[i];
  403. if( (fabs(hi.pos[axHorz] - e.ptCenter[axHorz]) < 0.5) &&
  404. (fabs(hi.pos[axVert] - e.ptCenter[axVert]) < 0.5) )
  405. {
  406. if(e.m_bSelected)
  407. {
  408. hNewMoveHandle = e.id;
  409. }
  410. // add it to the array to select
  411. if( pSimilarList )
  412. pSimilarList->AddToTail(e.id);
  413. }
  414. }
  415. }
  416. return hNewMoveHandle;
  417. }
  418. //-----------------------------------------------------------------------------
  419. // Purpose: Selects all the handles that are of the same type and at the same
  420. // position in the current 2D projection as the given handle.
  421. // Input : pInfo -
  422. // cmd -
  423. // Output : Returns the number of handles that were selected by this call.
  424. //-----------------------------------------------------------------------------
  425. void Morph3D::SelectHandle2D( CMapView2D *pView, MORPHHANDLE *pInfo, UINT cmd)
  426. {
  427. SSHANDLEINFO hi;
  428. if ( !pInfo )
  429. return;
  430. if( pInfo->ssh == SSH_SCALEORIGIN )
  431. return;
  432. if (!pInfo->pStrucSolid->GetHandleInfo(&hi, pInfo->ssh))
  433. {
  434. // Can't find the handle info, bail.
  435. DeselectHandle(pInfo);
  436. return;
  437. }
  438. //
  439. // Check to see if there is a same type handle at the same
  440. // 2d coordinates.
  441. //
  442. CUtlVector<SSHANDLE> addSimilarList;
  443. Get2DMatches( pView, pInfo->pStrucSolid, hi, &addSimilarList );
  444. for (int i = 0; i < addSimilarList.Count(); i++)
  445. {
  446. MORPHHANDLE mh;
  447. mh.ssh = addSimilarList[i];
  448. mh.pStrucSolid = pInfo->pStrucSolid;
  449. mh.pMapSolid = pInfo->pStrucSolid->m_pMapSolid;
  450. SelectHandle(&mh, cmd);
  451. if (i == 0)
  452. {
  453. cmd &= ~scClear;
  454. }
  455. }
  456. m_pDocument->UpdateAllViews( MAPVIEW_UPDATE_TOOL );
  457. return;
  458. }
  459. //-----------------------------------------------------------------------------
  460. // Purpose:
  461. // Input : pInfo -
  462. //-----------------------------------------------------------------------------
  463. void Morph3D::DeselectHandle(MORPHHANDLE *pInfo)
  464. {
  465. for (int i = 0; i <m_SelectedHandles.Count(); i++)
  466. {
  467. if (!memcmp(&m_SelectedHandles[i], pInfo, sizeof(*pInfo)))
  468. {
  469. m_SelectedHandles.Remove(i);
  470. break;
  471. }
  472. }
  473. }
  474. //-----------------------------------------------------------------------------
  475. // Purpose:
  476. // Input : pInfo -
  477. // cmd -
  478. //-----------------------------------------------------------------------------
  479. void Morph3D::SelectHandle(MORPHHANDLE *pInfo, UINT cmd)
  480. {
  481. m_pDocument->UpdateAllViews( MAPVIEW_UPDATE_TOOL );
  482. if( pInfo && pInfo->ssh == SSH_SCALEORIGIN )
  483. return;
  484. if(cmd & scSelectAll)
  485. {
  486. MORPHHANDLE mh;
  487. FOR_EACH_OBJ( m_StrucSolids, pos )
  488. {
  489. CSSolid *pStrucSolid = m_StrucSolids.Element(pos);
  490. for(int i = 0; i < pStrucSolid->m_nVertices; i++)
  491. {
  492. CSSVertex& v = pStrucSolid->m_Vertices[i];
  493. mh.ssh = v.id;
  494. mh.pStrucSolid = pStrucSolid;
  495. mh.pMapSolid = pStrucSolid->m_pMapSolid;
  496. SelectHandle(&mh, scSelect);
  497. }
  498. }
  499. return;
  500. }
  501. if(cmd & scClear)
  502. {
  503. // clear handles first
  504. while( m_SelectedHandles.Count()>0)
  505. {
  506. SelectHandle(&m_SelectedHandles[0], scUnselect);
  507. }
  508. }
  509. if(cmd == scClear)
  510. {
  511. if(m_bScaling)
  512. OnScaleCmd(TRUE); // update scaling
  513. return; // nothing else to do here
  514. }
  515. SSHANDLEINFO hi;
  516. if (!pInfo->pStrucSolid->GetHandleInfo(&hi, pInfo->ssh))
  517. {
  518. // Can't find the handle info, bail.
  519. DeselectHandle(pInfo);
  520. return;
  521. }
  522. if(hi.Type != m_SelectedType)
  523. SelectHandle(NULL, scClear); // clear selection first
  524. m_SelectedType = hi.Type;
  525. bool bAlreadySelected = (hi.p2DHandle->m_bSelected == TRUE);
  526. bool bChanged = false;
  527. // toggle selection:
  528. if(cmd & scToggle)
  529. {
  530. cmd &= ~scToggle;
  531. cmd |= bAlreadySelected ? scUnselect : scSelect;
  532. }
  533. if(cmd & scSelect && !(hi.p2DHandle->m_bSelected))
  534. {
  535. hi.p2DHandle->m_bSelected = TRUE;
  536. bChanged = true;
  537. }
  538. else if(cmd & scUnselect && hi.p2DHandle->m_bSelected)
  539. {
  540. hi.p2DHandle->m_bSelected = FALSE;
  541. bChanged = true;
  542. }
  543. if(!bChanged)
  544. return;
  545. if(hi.p2DHandle->m_bSelected)
  546. {
  547. m_SelectedHandles.AddToTail(*pInfo);
  548. }
  549. else
  550. {
  551. DeselectHandle(pInfo);
  552. }
  553. if(m_bScaling)
  554. OnScaleCmd(TRUE);
  555. }
  556. void Morph3D::MoveSelectedHandles(const Vector &Delta)
  557. {
  558. FOR_EACH_OBJ( m_StrucSolids, pos )
  559. {
  560. CSSolid *pStrucSolid = m_StrucSolids.Element(pos);
  561. pStrucSolid->MoveSelectedHandles(Delta);
  562. }
  563. }
  564. //-----------------------------------------------------------------------------
  565. // Purpose:
  566. // Input : pRender -
  567. //-----------------------------------------------------------------------------
  568. void Morph3D::RenderTool2D(CRender2D *pRender)
  569. {
  570. pRender->SetHandleStyle( HANDLE_RADIUS, CRender::HANDLE_SQUARE );
  571. for (int nPass = 0; nPass < 2; nPass++)
  572. {
  573. FOR_EACH_OBJ( m_StrucSolids, pos )
  574. {
  575. CSSolid *pStrucSolid = m_StrucSolids.Element(pos);
  576. //
  577. // Draw the edges.
  578. //
  579. for (int i = 0; i < pStrucSolid->m_nEdges; i++)
  580. {
  581. CSSEdge *pEdge = & pStrucSolid->m_Edges[i];
  582. if (((pEdge->m_bSelected) && (nPass == 0)) ||
  583. ((!pEdge->m_bSelected) && (nPass == 1)))
  584. {
  585. continue;
  586. }
  587. pRender->SetDrawColor( 255, 0, 0 );
  588. SSHANDLEINFO hi1;
  589. SSHANDLEINFO hi2;
  590. pStrucSolid->GetHandleInfo(&hi1, pEdge->hvStart);
  591. pStrucSolid->GetHandleInfo(&hi2, pEdge->hvEnd);
  592. pRender->DrawLine(hi1.pos, hi2.pos);
  593. if (!(m_HandleMode & hmEdge))
  594. {
  595. // Don't draw edge handles.
  596. continue;
  597. }
  598. // Draw the edge center handle.
  599. if (pEdge->m_bSelected)
  600. {
  601. pRender->SetHandleColor( GetRValue(Options.colors.clrSelection), GetGValue(Options.colors.clrSelection), GetBValue(Options.colors.clrSelection) );
  602. }
  603. else
  604. {
  605. pRender->SetHandleColor( 255,255,0 ) ;
  606. }
  607. pRender->DrawHandle( pEdge->ptCenter );
  608. }
  609. if (!(m_HandleMode & hmVertex))
  610. {
  611. // Don't draw vertex handles.
  612. continue;
  613. }
  614. //
  615. // Draw vertex handles.
  616. bool bClientSpace = pRender->BeginClientSpace();
  617. for (int i = 0; i < pStrucSolid->m_nVertices; i++)
  618. {
  619. CSSVertex &v = pStrucSolid->m_Vertices[i];
  620. if (((v.m_bSelected) && (nPass == 0)) ||
  621. ((!v.m_bSelected) && (nPass == 1)))
  622. {
  623. continue;
  624. }
  625. if (v.m_bSelected)
  626. {
  627. pRender->SetHandleColor( GetRValue(Options.colors.clrSelection), GetGValue(Options.colors.clrSelection), GetBValue(Options.colors.clrSelection) );
  628. }
  629. else
  630. {
  631. pRender->SetHandleColor( GetRValue(Options.colors.clrToolHandle), GetGValue(Options.colors.clrToolHandle), GetBValue(Options.colors.clrToolHandle));
  632. }
  633. pRender->DrawHandle( v.pos );
  634. }
  635. if ( bClientSpace )
  636. pRender->EndClientSpace();
  637. }
  638. }
  639. //
  640. // Draw scaling point.
  641. //
  642. if (m_bScaling && m_SelectedHandles.Count() )
  643. {
  644. pRender->SetHandleStyle( 8, CRender::HANDLE_CIRCLE );
  645. pRender->SetHandleColor( GetRValue(Options.colors.clrToolHandle), GetGValue(Options.colors.clrToolHandle), GetBValue(Options.colors.clrToolHandle) );
  646. pRender->DrawHandle( m_ScaleOrg );
  647. }
  648. if ( m_bBoxSelecting )
  649. {
  650. Box3D::RenderTool2D(pRender);
  651. }
  652. }
  653. //-----------------------------------------------------------------------------
  654. // Purpose: Finishes the morph, committing changes made to the selected objects.
  655. //-----------------------------------------------------------------------------
  656. void Morph3D::SetEmpty()
  657. {
  658. GetHistory()->MarkUndoPosition(NULL, "Morphing");
  659. while(m_StrucSolids.Count()>0)
  660. {
  661. // keep getting the head position because SelectObject (below)
  662. // removes the object from the list.
  663. CSSolid *pStrucSolid = m_StrucSolids[0];
  664. //
  665. // Save this solid. BUT, before doing so, set it as visible in the 2D views.
  666. // Otherwise, it will vanish if the user does an "Undo Morphing".
  667. //
  668. pStrucSolid->m_pMapSolid->SetVisible2D(true);
  669. GetHistory()->Keep(pStrucSolid->m_pMapSolid);
  670. pStrucSolid->m_pMapSolid->SetVisible2D(false);
  671. // calling SelectObject with scUnselect SAVES the contents
  672. // of the morph.
  673. SelectObject(pStrucSolid->m_pMapSolid, scUnselect);
  674. }
  675. }
  676. // 3d translation --
  677. void Morph3D::StartTranslation( CMapView *pView, const Vector2D &vPoint, MORPHHANDLE *pInfo )
  678. {
  679. if(m_bScaling)
  680. {
  681. // back to 1
  682. m_bScaling = false; // don't want it to update here
  683. m_ScaleDlg.m_cScale.SetWindowText("1.0");
  684. m_bScaling = true;
  685. }
  686. if(pInfo->ssh == SSH_SCALEORIGIN)
  687. m_OrigHandlePos = m_ScaleOrg;
  688. else
  689. GetHandlePos(pInfo, m_OrigHandlePos);
  690. Vector vOrigin, vecHorz, vecVert, vecThird;
  691. pView->GetBestTransformPlane( vecHorz, vecVert, vecThird );
  692. SetTransformationPlane( m_OrigHandlePos, vecHorz, vecVert, vecThird );
  693. // align translation plane to world origin
  694. ProjectOnTranslationPlane( vec3_origin, vOrigin, 0 );
  695. // set transformation plane
  696. SetTransformationPlane(vOrigin, vecHorz, vecVert, vecThird );
  697. Tool3D::StartTranslation( pView, vPoint, false );
  698. m_DragHandle = *pInfo;
  699. }
  700. //-----------------------------------------------------------------------------
  701. // Purpose:
  702. // Input : pt -
  703. // uFlags -
  704. // & -
  705. // Output : Returns TRUE on success, FALSE on failure.
  706. //-----------------------------------------------------------------------------
  707. bool Morph3D::UpdateTranslation(const Vector &vUpdate, UINT uFlags)
  708. {
  709. if (m_bBoxSelecting)
  710. {
  711. return Box3D::UpdateTranslation(vUpdate, uFlags);
  712. }
  713. if ( !Tool3D::UpdateTranslation( vUpdate, uFlags) )
  714. return false;
  715. bool bSnap = ( uFlags & constrainSnap ) ? true : false;
  716. if (m_DragHandle.ssh == SSH_SCALEORIGIN)
  717. {
  718. m_ScaleOrg = m_OrigHandlePos + vUpdate;
  719. if (bSnap)
  720. {
  721. m_pDocument->Snap( m_ScaleOrg, uFlags );
  722. }
  723. m_bUpdateOrg = false;
  724. return true;
  725. }
  726. //
  727. // Get the current handle position.
  728. //
  729. Vector vCurPos;
  730. GetHandlePos(&m_DragHandle, vCurPos);
  731. // We don't want to snap edge handles to the grid, because they don't
  732. // necessarily belong on the grid in the first place.
  733. if ( uFlags!=0 )
  734. {
  735. ProjectOnTranslationPlane( m_OrigHandlePos+m_vTranslation, m_vTranslation, uFlags );
  736. m_vTranslation -= m_OrigHandlePos;
  737. }
  738. Vector vDelta = (m_OrigHandlePos+m_vTranslation)-vCurPos;
  739. //
  740. // Create delta and determine if it is large enough to warrant an update.
  741. //
  742. if ( vDelta.Length() < 0.5 )
  743. {
  744. return false; // no need to update.
  745. }
  746. MoveSelectedHandles( vDelta );
  747. return true;
  748. }
  749. bool Morph3D::StartBoxSelection(CMapView *pView, const Vector2D &vPoint, const Vector& vStart)
  750. {
  751. m_bBoxSelecting = true;
  752. SetDrawColors(RGB(255, 255, 255), RGB(50, 255, 255));
  753. Box3D::StartNew( pView, vPoint, vStart, Vector(0,0,0) );
  754. return true;
  755. }
  756. void Morph3D::SelectInBox()
  757. {
  758. if(!m_bBoxSelecting)
  759. return;
  760. // select all vertices within the box, and finish box
  761. // selection.
  762. EndBoxSelection(); // may as well do it here
  763. // expand box along 0-depth axes
  764. int countzero = 0;
  765. for(int i = 0; i < 3; i++)
  766. {
  767. if(bmaxs[i] - bmins[i] == 0)
  768. {
  769. bmaxs[i] = COORD_NOTINIT;
  770. bmins[i] = -COORD_NOTINIT;
  771. countzero++;
  772. }
  773. }
  774. if(countzero > 1)
  775. return;
  776. FOR_EACH_OBJ( m_StrucSolids, pos )
  777. {
  778. CSSolid *pStrucSolid = m_StrucSolids.Element(pos);
  779. for(int i = 0; i < pStrucSolid->m_nVertices; i++)
  780. {
  781. CSSVertex& v = pStrucSolid->m_Vertices[i];
  782. int i2;
  783. for(i2 = 0; i2 < 3; i2++)
  784. {
  785. if(v.pos[i2] < bmins[i2] || v.pos[i2] > bmaxs[i2])
  786. break;
  787. }
  788. if(i2 == 3)
  789. {
  790. // completed loop - intersects - select handle
  791. MORPHHANDLE mh;
  792. mh.ssh = v.id;
  793. mh.pStrucSolid = pStrucSolid;
  794. mh.pMapSolid = pStrucSolid->m_pMapSolid;
  795. SelectHandle(&mh, scSelect);
  796. }
  797. }
  798. }
  799. }
  800. void Morph3D::EndBoxSelection()
  801. {
  802. m_bBoxSelecting = false;
  803. m_pDocument->UpdateAllViews( MAPVIEW_UPDATE_TOOL );
  804. }
  805. //-----------------------------------------------------------------------------
  806. // Purpose:
  807. // Input : bSave -
  808. //-----------------------------------------------------------------------------
  809. void Morph3D::FinishTranslation(bool bSave)
  810. {
  811. if (m_bBoxSelecting)
  812. {
  813. Box3D::FinishTranslation(bSave);
  814. return;
  815. }
  816. else if (bSave && m_DragHandle.ssh != SSH_SCALEORIGIN)
  817. {
  818. // figure out all the affected solids
  819. CUtlVector<CSSolid*> Affected;
  820. FOR_EACH_OBJ( m_StrucSolids, pos )
  821. {
  822. CSSolid *pStrucSolid = m_StrucSolids.Element(pos);
  823. if(Affected.Find(pStrucSolid) == -1)
  824. Affected.AddToTail(pStrucSolid);
  825. }
  826. int iConfirm = -1;
  827. FOR_EACH_OBJ( Affected, pos )
  828. {
  829. CSSolid *pStrucSolid = Affected.Element(pos);
  830. if(pStrucSolid->CanMergeVertices() && iConfirm != 0)
  831. {
  832. if(iConfirm == -1)
  833. {
  834. // ask
  835. if(AfxMessageBox("Merge vertices?", MB_YESNO) == IDYES)
  836. iConfirm = 1;
  837. else
  838. iConfirm = 0;
  839. }
  840. if(iConfirm == 1)
  841. {
  842. int nDeleted;
  843. SSHANDLE *pDeleted = pStrucSolid->MergeSameVertices(nDeleted);
  844. // ensure deleted handles are not marked
  845. for(int i = 0; i < nDeleted; i++)
  846. {
  847. MORPHHANDLE mh;
  848. mh.ssh = pDeleted[i];
  849. mh.pStrucSolid = pStrucSolid;
  850. mh.pMapSolid = pStrucSolid->m_pMapSolid;
  851. SelectHandle(&mh, scUnselect);
  852. }
  853. }
  854. }
  855. // pStrucSolid->CheckFaces();
  856. }
  857. }
  858. Tool3D::FinishTranslation(bSave);
  859. if(!bSave)
  860. {
  861. // move back to original positions
  862. Vector curpos;
  863. GetHandlePos(&m_DragHandle, curpos);
  864. MoveSelectedHandles(m_OrigHandlePos - curpos);
  865. }
  866. else if(m_bScaling)
  867. {
  868. OnScaleCmd(TRUE);
  869. }
  870. }
  871. bool Morph3D::SplitFace()
  872. {
  873. if(!CanSplitFace())
  874. return false;
  875. if(m_SelectedHandles[0].pStrucSolid->SplitFace(m_SelectedHandles[0].ssh,
  876. m_SelectedHandles[1].ssh))
  877. {
  878. // unselect those invalid edges
  879. if(m_SelectedType == shtVertex)
  880. {
  881. // proper deselection
  882. SelectHandle(NULL, scClear);
  883. }
  884. else // selection is invalid; set count to 0
  885. m_SelectedHandles.RemoveAll();
  886. m_pDocument->UpdateAllViews( MAPVIEW_UPDATE_OBJECTS );
  887. return false;
  888. }
  889. return true;
  890. }
  891. bool Morph3D::CanSplitFace()
  892. {
  893. // along two edges.
  894. if(m_SelectedHandles.Count() != 2 || (m_SelectedType != shtEdge &&
  895. m_SelectedType != shtVertex))
  896. return false;
  897. // make sure same solid.
  898. if(m_SelectedHandles[0].pStrucSolid != m_SelectedHandles[1].pStrucSolid)
  899. return false;
  900. return true;
  901. }
  902. void Morph3D::ToggleMode()
  903. {
  904. if(m_HandleMode == hmBoth)
  905. m_HandleMode = hmVertex;
  906. else if(m_HandleMode == hmVertex)
  907. m_HandleMode = hmEdge;
  908. else
  909. m_HandleMode = hmBoth;
  910. // run through selected solids and tell them the new mode
  911. FOR_EACH_OBJ( m_StrucSolids, pos )
  912. {
  913. CSSolid *pStrucSolid = m_StrucSolids.Element(pos);
  914. pStrucSolid->ShowHandles(m_HandleMode & hmVertex, m_HandleMode & hmEdge);
  915. }
  916. m_pDocument->UpdateAllViews( MAPVIEW_UPDATE_TOOL );
  917. }
  918. //-----------------------------------------------------------------------------
  919. // Purpose: Returns the center of the morph selection.
  920. // Input : pt - Point at the center of the selection or selected handles.
  921. //-----------------------------------------------------------------------------
  922. void Morph3D::GetSelectedCenter(Vector& pt)
  923. {
  924. BoundBox box;
  925. //
  926. // If we have selected handles, our bounds center is the center of those handles.
  927. //
  928. if (m_SelectedHandles.Count() > 0)
  929. {
  930. SSHANDLEINFO hi;
  931. for (int i = 0; i < m_SelectedHandles.Count(); i++)
  932. {
  933. MORPHHANDLE *mh = &m_SelectedHandles[i];
  934. mh->pStrucSolid->GetHandleInfo(&hi, mh->ssh);
  935. box.UpdateBounds(hi.pos);
  936. }
  937. }
  938. //
  939. // If no handles are selected, our bounds center is the center of all selected solids.
  940. //
  941. else
  942. {
  943. FOR_EACH_OBJ( m_StrucSolids, pos )
  944. {
  945. CSSolid *pStrucSolid = m_StrucSolids.Element(pos);
  946. for (int nVertex = 0; nVertex < pStrucSolid->m_nVertices; nVertex++)
  947. {
  948. CSSVertex &v = pStrucSolid->m_Vertices[nVertex];
  949. box.UpdateBounds(v.pos);
  950. }
  951. }
  952. }
  953. box.GetBoundsCenter(pt);
  954. }
  955. //-----------------------------------------------------------------------------
  956. // Purpose: Fills out a list of the objects selected for morphing.
  957. //-----------------------------------------------------------------------------
  958. void Morph3D::GetMorphingObjects(CUtlVector<CMapClass *> &List)
  959. {
  960. FOR_EACH_OBJ( m_StrucSolids, pos )
  961. {
  962. CSSolid *pStrucSolid = m_StrucSolids.Element(pos);
  963. List.AddToTail(pStrucSolid->m_pMapSolid);
  964. }
  965. }
  966. void Morph3D::OnScaleCmd(BOOL bReInit)
  967. {
  968. if(m_pOrigPosList)
  969. {
  970. delete[] m_pOrigPosList;
  971. m_pOrigPosList = NULL;
  972. }
  973. if(m_bScaling && !bReInit)
  974. {
  975. m_ScaleDlg.ShowWindow(SW_HIDE);
  976. m_ScaleDlg.DestroyWindow();
  977. m_bScaling = false;
  978. return;
  979. }
  980. // start scaling
  981. if(!bReInit)
  982. {
  983. m_ScaleDlg.Create(IDD_SCALEVERTICES);
  984. CPoint pt;
  985. GetCursorPos(&pt);
  986. m_bUpdateOrg = true;
  987. m_ScaleDlg.SetWindowPos(NULL, pt.x, pt.y, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW);
  988. }
  989. else
  990. {
  991. m_bScaling = false; // don't want an update
  992. m_ScaleDlg.m_cScale.SetWindowText("1.0");
  993. m_bScaling = true;
  994. }
  995. if(m_SelectedHandles.Count()==0)
  996. {
  997. m_bScaling = true;
  998. return;
  999. }
  1000. m_pOrigPosList = new Vector[m_SelectedHandles.Count()];
  1001. BoundBox box;
  1002. // save original positions of vertices
  1003. for(int i = 0; i < m_SelectedHandles.Count(); i++)
  1004. {
  1005. MORPHHANDLE &hnd = m_SelectedHandles[i];
  1006. SSHANDLEINFO hi;
  1007. hnd.pStrucSolid->GetHandleInfo(&hi, hnd.ssh);
  1008. if(hi.Type != shtVertex)
  1009. continue;
  1010. m_pOrigPosList[i] = hi.pos;
  1011. box.UpdateBounds(hi.pos);
  1012. }
  1013. // center is default origin
  1014. if(m_bUpdateOrg)
  1015. box.GetBoundsCenter(m_ScaleOrg);
  1016. m_pDocument->UpdateAllViews( MAPVIEW_UPDATE_TOOL );
  1017. m_bScaling = true;
  1018. }
  1019. void Morph3D::UpdateScale()
  1020. {
  1021. // update scale with data in dialog box
  1022. if(!m_bScaling)
  1023. return;
  1024. float fScale = m_ScaleDlg.m_fScale;
  1025. // match up selected vertices to original position in m_pOrigPosList.
  1026. int iMoved = 0;
  1027. for(int i = 0; i < m_SelectedHandles.Count(); i++)
  1028. {
  1029. MORPHHANDLE &hnd = m_SelectedHandles[i];
  1030. SSHANDLEINFO hi;
  1031. hnd.pStrucSolid->GetHandleInfo(&hi, hnd.ssh);
  1032. if(hi.Type != shtVertex)
  1033. continue;
  1034. // ** scale **
  1035. Vector& pOrigPos = m_pOrigPosList[iMoved++];
  1036. Vector newpos;
  1037. for(int d = 0; d < 3; d++)
  1038. {
  1039. float delta = pOrigPos[d] - m_ScaleOrg[d];
  1040. // YWB rounding
  1041. newpos[d] = /*rint*/(m_ScaleOrg[d] + (delta * fScale));
  1042. }
  1043. hnd.pStrucSolid->SetVertexPosition(hi.iIndex, newpos[0],
  1044. newpos[1], newpos[2]);
  1045. // find edge that references this vertex
  1046. int nEdges;
  1047. CSSEdge **pEdges = hnd.pStrucSolid->FindAffectedEdges(&hnd.ssh, 1,
  1048. nEdges);
  1049. for(int e = 0; e < nEdges; e++)
  1050. {
  1051. hnd.pStrucSolid->CalcEdgeCenter(pEdges[e]);
  1052. }
  1053. }
  1054. m_pDocument->UpdateAllViews( MAPVIEW_UPDATE_TOOL );
  1055. }
  1056. //-----------------------------------------------------------------------------
  1057. // Purpose: Renders an object that is currently selected for morphing. The
  1058. // object is rendered in three passes:
  1059. //
  1060. // 1. Flat shaded grey with transparency.
  1061. // 2. Wireframe in white.
  1062. // 3. Edges and/or vertices are rendered as boxes.
  1063. //
  1064. // Input : pSolid - The structured solid to render.
  1065. //-----------------------------------------------------------------------------
  1066. void Morph3D::RenderSolid3D(CRender3D *pRender, CSSolid *pSolid)
  1067. {
  1068. VMatrix ViewMatrix;
  1069. Vector ViewPos;
  1070. bool bClientSpace = false;
  1071. CMatRenderContextPtr pRenderContext( MaterialSystemInterface() );
  1072. for (int nPass = 1; nPass <= 3; nPass++)
  1073. {
  1074. if (nPass == 1)
  1075. {
  1076. pRender->PushRenderMode( RENDER_MODE_SELECTION_OVERLAY );
  1077. }
  1078. else if (nPass == 2)
  1079. {
  1080. pRender->PushRenderMode( RENDER_MODE_WIREFRAME );
  1081. }
  1082. else
  1083. {
  1084. pRender->PushRenderMode( RENDER_MODE_FLAT_NOZ );
  1085. pRender->SetHandleStyle( HANDLE_RADIUS, CRender::HANDLE_SQUARE );
  1086. bClientSpace = pRender->BeginClientSpace();
  1087. pRender->GetCamera()->GetViewMatrix( ViewMatrix );
  1088. }
  1089. IMesh* pMesh = pRenderContext->GetDynamicMesh();
  1090. CMeshBuilder meshBuilder;
  1091. int nFaceCount = pSolid->GetFaceCount();
  1092. for (int nFace = 0; nFace < nFaceCount; nFace++)
  1093. {
  1094. CSSFace *pFace = pSolid->GetFace(nFace);
  1095. int nEdgeCount = pFace->GetEdgeCount();
  1096. unsigned char color[4];
  1097. if (nPass == 1)
  1098. {
  1099. meshBuilder.Begin( pMesh, MATERIAL_POLYGON, nEdgeCount );
  1100. color[0] = color[1] = color[2] = color[3] = 128;
  1101. }
  1102. else if (nPass == 2)
  1103. {
  1104. meshBuilder.Begin( pMesh, MATERIAL_LINE_LOOP, nEdgeCount );
  1105. color[0] = color[1] = color[2] = color[3] = 255;
  1106. }
  1107. for (int nEdge = 0; nEdge < nEdgeCount; nEdge++)
  1108. {
  1109. //
  1110. // Calc next edge so we can see which is the next clockwise point.
  1111. //
  1112. int nEdgeNext = nEdge + 1;
  1113. if (nEdgeNext == nEdgeCount)
  1114. {
  1115. nEdgeNext = 0;
  1116. }
  1117. SSHANDLE hEdge = pFace->GetEdgeHandle(nEdge);
  1118. CSSEdge *pEdgeCur = (CSSEdge *)pSolid->GetHandleData(hEdge);
  1119. SSHANDLE hEdgeNext = pFace->GetEdgeHandle(nEdgeNext);
  1120. CSSEdge *pEdgeNext = (CSSEdge *)pSolid->GetHandleData(hEdgeNext);
  1121. if (!pEdgeCur || !pEdgeNext)
  1122. {
  1123. return;
  1124. }
  1125. if ((nPass == 1) || (nPass == 2))
  1126. {
  1127. SSHANDLE hVertex = pSolid->GetConnectionVertex(pEdgeCur, pEdgeNext);
  1128. if (!hVertex)
  1129. {
  1130. return;
  1131. }
  1132. CSSVertex *pVertex = (CSSVertex *)pSolid->GetHandleData(hVertex);
  1133. if (!pVertex)
  1134. {
  1135. return;
  1136. }
  1137. Vector Vertex;
  1138. pVertex->GetPosition(Vertex);
  1139. meshBuilder.Position3f(Vertex[0], Vertex[1], Vertex[2]);
  1140. meshBuilder.Color4ubv( color );
  1141. meshBuilder.AdvanceVertex();
  1142. }
  1143. else
  1144. {
  1145. if (pSolid->ShowEdges())
  1146. {
  1147. //
  1148. // Project the edge midpoint into screen space.
  1149. //
  1150. Vector CenterPoint;
  1151. pEdgeCur->GetCenterPoint(CenterPoint);
  1152. ViewMatrix.V3Mul( CenterPoint, ViewPos );
  1153. if (ViewPos[2] < 0)
  1154. {
  1155. Vector2D ClientPos;
  1156. pRender->TransformPoint(ClientPos, CenterPoint);
  1157. pEdgeCur->m_bVisible = TRUE;
  1158. pEdgeCur->m_r.left = ClientPos.x - HANDLE_RADIUS;
  1159. pEdgeCur->m_r.top = ClientPos.y - HANDLE_RADIUS;
  1160. pEdgeCur->m_r.right = ClientPos.x + HANDLE_RADIUS + 1;
  1161. pEdgeCur->m_r.bottom = ClientPos.y + HANDLE_RADIUS + 1;
  1162. if (pEdgeCur->m_bSelected)
  1163. {
  1164. color[0] = 220; color[1] = color[2] = 0; color[3] = 255;
  1165. }
  1166. else
  1167. {
  1168. color[0] = color[1] = 255; color[2] = 0; color[3] = 255;
  1169. }
  1170. //
  1171. // Render the edge handle as a box.
  1172. //
  1173. pRender->SetHandleColor( color[0], color[1], color[2] );
  1174. pRender->DrawHandle( CenterPoint );
  1175. }
  1176. else
  1177. {
  1178. pEdgeCur->m_bVisible = FALSE;
  1179. }
  1180. }
  1181. if (pSolid->ShowVertices())
  1182. {
  1183. SSHANDLE hVertex = pSolid->GetConnectionVertex(pEdgeCur, pEdgeNext);
  1184. CSSVertex *pVertex = (CSSVertex *)pSolid->GetHandleData(hVertex);
  1185. //
  1186. // Project the vertex into screen space.
  1187. //
  1188. Vector vPoint;
  1189. pVertex->GetPosition(vPoint);
  1190. ViewMatrix.V3Mul( vPoint, ViewPos );
  1191. if (ViewPos[2] < 0)
  1192. {
  1193. Vector2D ClientPos;
  1194. pRender->TransformPoint(ClientPos, vPoint);
  1195. pVertex->m_bVisible = TRUE;
  1196. pVertex->m_r.left = ClientPos.x - HANDLE_RADIUS;
  1197. pVertex->m_r.top = ClientPos.y - HANDLE_RADIUS;
  1198. pVertex->m_r.right = ClientPos.x + HANDLE_RADIUS + 1;
  1199. pVertex->m_r.bottom = ClientPos.y + HANDLE_RADIUS + 1;
  1200. if (pVertex->m_bSelected)
  1201. {
  1202. color[0] = 220; color[1] = color[2] = 0; color[3] = 255;
  1203. }
  1204. else
  1205. {
  1206. color[0] = color[1] = color[2] = 255; color[3] = 255;
  1207. }
  1208. //
  1209. // Render the vertex as a box.
  1210. //
  1211. pRender->SetHandleColor( color[0], color[1], color[2] );
  1212. pRender->DrawHandle( vPoint );
  1213. }
  1214. else
  1215. {
  1216. pVertex->m_bVisible = FALSE;
  1217. }
  1218. }
  1219. }
  1220. }
  1221. if ((nPass == 1) || (nPass == 2))
  1222. {
  1223. meshBuilder.End();
  1224. pMesh->Draw();
  1225. }
  1226. }
  1227. if ( bClientSpace )
  1228. {
  1229. pRender->EndClientSpace();
  1230. bClientSpace = false;
  1231. }
  1232. pRender->PopRenderMode();
  1233. }
  1234. }
  1235. //-----------------------------------------------------------------------------
  1236. // Purpose: Renders a our selection bounds while we are drag-selecting.
  1237. // Input : pRender - Rendering interface.
  1238. //-----------------------------------------------------------------------------
  1239. void Morph3D::RenderTool3D(CRender3D *pRender)
  1240. {
  1241. if (m_bBoxSelecting)
  1242. {
  1243. Box3D::RenderTool3D(pRender);
  1244. }
  1245. for( int pos=0; pos < m_StrucSolids.Count(); pos++ )
  1246. {
  1247. RenderSolid3D(pRender, m_StrucSolids[pos] );
  1248. }
  1249. }
  1250. //-----------------------------------------------------------------------------
  1251. // Purpose: Handles key down events in the 2D view.
  1252. // Input : Per CWnd::OnKeyDown.
  1253. // Output : Returns true if the message was handled, false if not.
  1254. //-----------------------------------------------------------------------------
  1255. bool Morph3D::OnKeyDown2D(CMapView2D *pView, UINT nChar, UINT nRepCnt, UINT nFlags)
  1256. {
  1257. bool bSnap = m_pDocument->IsSnapEnabled() && !(GetKeyState(VK_CONTROL) & 0x8000);
  1258. if (nChar == VK_UP || nChar == VK_DOWN || nChar == VK_LEFT || nChar == VK_RIGHT)
  1259. {
  1260. if ( NudgeHandles( pView, nChar, bSnap ) )
  1261. return true;
  1262. }
  1263. switch (nChar)
  1264. {
  1265. case VK_RETURN:
  1266. {
  1267. if ( IsBoxSelecting() )
  1268. {
  1269. SelectInBox();
  1270. }
  1271. break;
  1272. }
  1273. case VK_ESCAPE:
  1274. {
  1275. OnEscape();
  1276. return true;
  1277. }
  1278. }
  1279. return false;
  1280. }
  1281. //-----------------------------------------------------------------------------
  1282. // Purpose: Handles character events in the 2D view.
  1283. // Input : Per CWnd::OnChar.
  1284. // Output : Returns true on success, false on failure.
  1285. //-----------------------------------------------------------------------------
  1286. bool Morph3D::OnChar2D(CMapView2D *pView, UINT nChar, UINT nRepCnt, UINT nFlags)
  1287. {
  1288. return false;
  1289. }
  1290. //-----------------------------------------------------------------------------
  1291. // Purpose: Handles left mouse button down events in the 2D view.
  1292. // Input : Per CWnd::OnLButtonDown.
  1293. // Output : Returns true if the message was handled, false if not.
  1294. //-----------------------------------------------------------------------------
  1295. bool Morph3D::OnLMouseDown2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
  1296. {
  1297. Tool3D::OnLMouseDown2D(pView, nFlags, vPoint);
  1298. m_bLButtonDownControlState = (nFlags & MK_CONTROL) != 0;
  1299. m_vLastMouseMovement = vPoint;
  1300. m_DragHandle.ssh = 0;
  1301. MORPHHANDLE mh;
  1302. if ( IsBoxSelecting() )
  1303. {
  1304. if ( HitTest( pView, vPoint, true ) )
  1305. {
  1306. Box3D::StartTranslation( pView, vPoint, m_LastHitTestHandle );
  1307. }
  1308. }
  1309. else if (MorphHitTest( pView, vPoint, &mh))
  1310. {
  1311. //
  1312. // If they clicked on a valid handle, remember which one. We may need it in
  1313. // left button up or mouse move messages.
  1314. //
  1315. m_DragHandle = mh;
  1316. if (!m_bLButtonDownControlState)
  1317. {
  1318. //
  1319. // If they are not holding down control and they clicked on an unselected
  1320. // handle, select the handle they clicked on straightaway.
  1321. //
  1322. if (!IsSelected(m_DragHandle))
  1323. {
  1324. // Clear the selected handles and select this handle.
  1325. UINT cmd = scClear | scSelect;
  1326. SelectHandle2D( pView, &m_DragHandle, cmd);
  1327. }
  1328. }
  1329. }
  1330. else
  1331. {
  1332. // Try to put another solid into morph mode.
  1333. SelectAt(pView, nFlags, vPoint);
  1334. }
  1335. return true;
  1336. }
  1337. //-----------------------------------------------------------------------------
  1338. // Purpose: Handles left mouse button up events in the 2D view.
  1339. // Input : Per CWnd::OnLButtonUp.
  1340. // Output : Returns true if the message was handled, false if not.
  1341. //-----------------------------------------------------------------------------
  1342. bool Morph3D::OnLMouseUp2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
  1343. {
  1344. Tool3D::OnLMouseUp2D(pView, nFlags, vPoint);
  1345. if (!IsTranslating())
  1346. {
  1347. if (m_DragHandle.ssh != 0)
  1348. {
  1349. //
  1350. // They clicked on a handle and released the left button without moving the mouse.
  1351. // Change the selection state of the handle that was clicked on.
  1352. //
  1353. UINT cmd = scClear | scSelect;
  1354. if (m_bLButtonDownControlState)
  1355. {
  1356. // Control-click: toggle.
  1357. cmd = scToggle;
  1358. }
  1359. SelectHandle2D( pView, &m_DragHandle, cmd);
  1360. }
  1361. }
  1362. else
  1363. {
  1364. //
  1365. // Dragging out a selection box or dragging the selected vertices.
  1366. //
  1367. FinishTranslation(true);
  1368. if (IsBoxSelecting() && Options.view2d.bAutoSelect)
  1369. {
  1370. SelectInBox();
  1371. }
  1372. }
  1373. m_pDocument->UpdateStatusbar();
  1374. return true;
  1375. }
  1376. unsigned int Morph3D::GetConstraints(unsigned int nFlags)
  1377. {
  1378. unsigned int uConstraints = Tool3D::GetConstraints(nFlags);
  1379. if ( !IsBoxSelecting() )
  1380. {
  1381. if ( nFlags & MK_CONTROL )
  1382. uConstraints |= constrainOnlyVert;
  1383. if ( nFlags & MK_SHIFT )
  1384. uConstraints |= constrainOnlyHorz;
  1385. }
  1386. return uConstraints;
  1387. }
  1388. //-----------------------------------------------------------------------------
  1389. // Purpose: Handles mouse move events in the 2D view.
  1390. // Input : Per CWnd::OnMouseMove.
  1391. // Output : Returns true if the message was handled, false if not.
  1392. //-----------------------------------------------------------------------------
  1393. bool Morph3D::OnMouseMove2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
  1394. {
  1395. vgui::HCursor hCursor = vgui::dc_none;
  1396. unsigned int uConstraints = GetConstraints( nFlags );
  1397. Tool3D::OnMouseMove2D(pView, nFlags, vPoint);
  1398. // Convert to world coords.
  1399. Vector vecWorld;
  1400. pView->ClientToWorld(vecWorld, vPoint);
  1401. //
  1402. // Update status bar position display.
  1403. //
  1404. char szBuf[128];
  1405. m_pDocument->Snap(vecWorld,uConstraints);
  1406. sprintf(szBuf, " @%.0f, %.0f ", vecWorld[pView->axHorz], vecWorld[pView->axVert] );
  1407. SetStatusText(SBI_COORDS, szBuf);
  1408. if ( m_bMouseDown[MOUSE_LEFT] )
  1409. {
  1410. if ( IsTranslating() )
  1411. {
  1412. // If they are dragging a selection box or one or more handles, update
  1413. // the drag based on the cursor position.
  1414. Tool3D::UpdateTranslation( pView, vPoint, uConstraints );
  1415. }
  1416. else if ( m_bMouseDragged[MOUSE_LEFT] && m_DragHandle.ssh != 0 )
  1417. {
  1418. //
  1419. // If they are not already dragging a handle and they clicked on a valid handle,
  1420. // see if they have moved the mouse far enough to begin dragging the handle.
  1421. //
  1422. if (m_bLButtonDownControlState && !IsSelected(m_DragHandle))
  1423. {
  1424. //
  1425. // If they control-clicked on an unselected handle and then dragged the mouse,
  1426. // select the handle that they clicked on now.
  1427. //
  1428. SelectHandle2D( pView, &m_DragHandle, scSelect);
  1429. }
  1430. StartTranslation( pView, m_vMouseStart[MOUSE_LEFT], &m_DragHandle );
  1431. }
  1432. else if ( m_bMouseDragged[MOUSE_LEFT] && !IsBoxSelecting() )
  1433. {
  1434. //
  1435. // Left dragging, didn't click on a handle, and we aren't yet dragging a
  1436. // selection box. Start dragging the selection box.
  1437. //
  1438. if (!(nFlags & MK_CONTROL))
  1439. {
  1440. SelectHandle(NULL, scClear);
  1441. }
  1442. Vector ptOrg;
  1443. pView->ClientToWorld(ptOrg, m_vMouseStart[MOUSE_LEFT] );
  1444. // set best third axis value
  1445. ptOrg[pView->axThird] = COORD_NOTINIT;
  1446. m_pDocument->GetBestVisiblePoint(ptOrg);
  1447. StartBoxSelection( pView, m_vMouseStart[MOUSE_LEFT], ptOrg);
  1448. }
  1449. }
  1450. else if (!IsEmpty())
  1451. {
  1452. //
  1453. // Left button is not down, just see what's under the cursor
  1454. // position to update the cursor.
  1455. //
  1456. hCursor = vgui::dc_arrow;
  1457. //
  1458. // Check to see if the mouse is over a vertex handle.
  1459. //
  1460. if (!IsBoxSelecting() && MorphHitTest( pView, vPoint, NULL))
  1461. {
  1462. hCursor = vgui::dc_crosshair;
  1463. }
  1464. //
  1465. // Check to see if the mouse is over a box handle.
  1466. //
  1467. else if ( HitTest(pView, vPoint, true) )
  1468. {
  1469. hCursor = UpdateCursor( pView, m_LastHitTestHandle, m_TranslateMode );
  1470. }
  1471. }
  1472. else
  1473. {
  1474. hCursor = vgui::dc_arrow;
  1475. }
  1476. if ( hCursor != vgui::dc_none )
  1477. pView->SetCursor( hCursor );
  1478. return true;
  1479. }
  1480. //-----------------------------------------------------------------------------
  1481. // Purpose: Handles left mouse button down events in the 3D view.
  1482. // Input : Per CWnd::OnLButtonDown.
  1483. // Output : Returns true if the message was handled, false if not.
  1484. //-----------------------------------------------------------------------------
  1485. bool Morph3D::OnLMouseDown3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
  1486. {
  1487. m_bHit = false;
  1488. Tool3D::OnLMouseDown3D(pView, nFlags, vPoint);
  1489. //
  1490. // Select morph handles?
  1491. //
  1492. MORPHHANDLE mh;
  1493. if ( MorphHitTest(pView, vPoint, &mh) )
  1494. {
  1495. m_bHit = true;
  1496. m_DragHandle = mh;
  1497. m_bMorphing = true;
  1498. m_vLastMouseMovement = vPoint;
  1499. m_bMovingSelected = false; // not moving them yet - might just select this
  1500. StartTranslation( pView, vPoint, &m_DragHandle );
  1501. SetCursor(AfxGetApp()->LoadStandardCursor(IDC_CROSS));
  1502. }
  1503. else
  1504. {
  1505. SelectAt( pView, nFlags, vPoint );
  1506. }
  1507. return true;
  1508. }
  1509. bool Morph3D::SelectAt( CMapView *pView, UINT nFlags, const Vector2D &vPoint )
  1510. {
  1511. CMapClass *pMorphObject = NULL;
  1512. bool bUpdateView = false;
  1513. m_pDocument->GetSelection()->ClearHitList();
  1514. CMapObjectList SelectList;
  1515. // Find out how many (and what) map objects are under the point clicked on.
  1516. HitInfo_t Objects[MAX_PICK_HITS];
  1517. int nHits = pView->ObjectsAt( vPoint, Objects, sizeof(Objects) / sizeof(Objects[0]));
  1518. // We now have an array of pointers to CMapAtoms. Any that can be upcast to CMapClass
  1519. // we add to a list of hits.
  1520. for (int i = 0; i < nHits; i++)
  1521. {
  1522. CMapClass *pMapClass = dynamic_cast <CMapClass *>(Objects[i].pObject);
  1523. if (pMapClass != NULL)
  1524. {
  1525. SelectList.AddToTail(pMapClass);
  1526. }
  1527. }
  1528. //
  1529. // Actual selection occurs here.
  1530. //
  1531. if (!SelectList.Count())
  1532. {
  1533. //
  1534. // Clicked on nothing - clear selection.
  1535. //
  1536. pView->GetMapDoc()->SelectFace(NULL, 0, scClear);
  1537. pView->GetMapDoc()->SelectObject(NULL, scClear );
  1538. return false;
  1539. }
  1540. bool bFirst = true;
  1541. SelectMode_t eSelectMode = m_pDocument->GetSelection()->GetMode();
  1542. // Can we de-select objects?
  1543. if ( !CanDeselectList() )
  1544. return true;
  1545. FOR_EACH_OBJ( SelectList, pos )
  1546. {
  1547. CMapClass *pObject = SelectList.Element(pos);
  1548. // get hit object type and add it to the hit list
  1549. CMapClass *pHitObject = pObject->PrepareSelection( eSelectMode );
  1550. if (pHitObject)
  1551. {
  1552. m_pDocument->GetSelection()->AddHit( pHitObject );
  1553. if (bFirst)
  1554. {
  1555. if (pObject->IsMapClass(MAPCLASS_TYPE(CMapSolid)))
  1556. {
  1557. CMapSolid *pSolid = (CMapSolid *)pObject;
  1558. UINT cmd = scClear | scSelect;
  1559. if (nFlags & MK_CONTROL)
  1560. {
  1561. cmd = scToggle;
  1562. }
  1563. SelectObject(pSolid, cmd);
  1564. pMorphObject = pSolid;
  1565. bUpdateView = true;
  1566. break;
  1567. }
  1568. }
  1569. bFirst = false;
  1570. }
  1571. }
  1572. // do we want to deselect all morphs?
  1573. if (!pMorphObject && !IsEmpty())
  1574. {
  1575. SetEmpty();
  1576. bUpdateView = true;
  1577. }
  1578. if (bUpdateView)
  1579. {
  1580. GetMainWnd()->pObjectProperties->MarkDataDirty();
  1581. m_pDocument->UpdateAllViews( MAPVIEW_UPDATE_SELECTION );
  1582. }
  1583. return true;
  1584. }
  1585. //-----------------------------------------------------------------------------
  1586. // Purpose: Handles left mouse button up events in the 3D view.
  1587. // Input : Per CWnd::OnLButtonUp.
  1588. // Output : Returns true if the message was handled, false if not.
  1589. //-----------------------------------------------------------------------------
  1590. bool Morph3D::OnLMouseUp3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
  1591. {
  1592. Tool3D::OnLMouseUp3D(pView, nFlags, vPoint);
  1593. if (m_bHit)
  1594. {
  1595. m_bHit = false;
  1596. UINT cmd = scClear | scSelect;
  1597. if (nFlags & MK_CONTROL)
  1598. {
  1599. cmd = scToggle;
  1600. }
  1601. SelectHandle(&m_DragHandle, cmd);
  1602. }
  1603. if (m_bMorphing)
  1604. {
  1605. FinishTranslation( true );
  1606. m_bMorphing = false;
  1607. }
  1608. ReleaseCapture();
  1609. return true;
  1610. }
  1611. //-----------------------------------------------------------------------------
  1612. // Purpose:
  1613. // Input : axes -
  1614. // nChar -
  1615. // bSnap -
  1616. //-----------------------------------------------------------------------------
  1617. bool Morph3D::NudgeHandles(CMapView *pView, UINT nChar, bool bSnap)
  1618. {
  1619. if ( GetSelectedHandleCount() < 1 || !Options.view2d.bNudge )
  1620. return false;
  1621. Vector vecDelta, vHorz, vVert, vThrd;
  1622. pView->GetBestTransformPlane( vHorz, vVert, vThrd );
  1623. m_pDocument->GetNudgeVector( vHorz, vVert, nChar, bSnap, vecDelta);
  1624. if ( bSnap && (GetSelectedHandleCount() == 1) && (GetSelectedType() == shtVertex))
  1625. {
  1626. // we have one vertex selected, so make sure
  1627. // it's going to snap to grid.
  1628. Vector pos; GetSelectedCenter(pos);
  1629. SetTransformationPlane( pos, vHorz, vVert, vThrd );
  1630. // calculate new delta
  1631. ProjectOnTranslationPlane( pos + vecDelta, vecDelta, constrainSnap );
  1632. vecDelta -= pos;
  1633. }
  1634. MoveSelectedHandles(vecDelta);
  1635. FinishTranslation( true ); // force checking for merges
  1636. m_pDocument->SetModifiedFlag();
  1637. return true;
  1638. }
  1639. //-----------------------------------------------------------------------------
  1640. // Purpose: Handles the key down event in the 3D view.
  1641. // Input : Per CWnd::OnKeyDown.
  1642. // Output : Returns true if the message was handled, false if not.
  1643. //-----------------------------------------------------------------------------
  1644. bool Morph3D::OnKeyDown3D(CMapView3D *pView, UINT nChar, UINT nRepCnt, UINT nFlags)
  1645. {
  1646. bool bSnap = m_pDocument->IsSnapEnabled() && !(GetAsyncKeyState(VK_CONTROL) & 0x8000);
  1647. switch (nChar)
  1648. {
  1649. case VK_ESCAPE:
  1650. {
  1651. OnEscape();
  1652. return true;
  1653. }
  1654. case VK_UP :
  1655. case VK_DOWN :
  1656. case VK_LEFT :
  1657. case VK_RIGHT :
  1658. {
  1659. if ( NudgeHandles( pView, nChar, bSnap ) )
  1660. return true;
  1661. }
  1662. }
  1663. return false;
  1664. }
  1665. //-----------------------------------------------------------------------------
  1666. // Purpose: Handles the escape key in the 2D or 3D views.
  1667. //-----------------------------------------------------------------------------
  1668. void Morph3D::OnEscape(void)
  1669. {
  1670. //
  1671. // If we're box selecting with the morph tool, stop.
  1672. //
  1673. if ( IsBoxSelecting() )
  1674. {
  1675. EndBoxSelection();
  1676. }
  1677. //
  1678. // If we have handle(s) selected, deselect them.
  1679. //
  1680. else if (!IsEmpty() && (GetSelectedHandleCount() != 0))
  1681. {
  1682. SelectHandle(NULL, scClear);
  1683. }
  1684. //
  1685. // Stop using the morph tool.
  1686. //
  1687. else
  1688. {
  1689. ToolManager()->SetTool(TOOL_POINTER);
  1690. }
  1691. }
  1692. //-----------------------------------------------------------------------------
  1693. // Purpose: Handles the move move event in the 3D view.
  1694. // Input : Per CWnd::OnMouseMove.
  1695. // Output : Returns true if the message was handled, false if not.
  1696. //-----------------------------------------------------------------------------
  1697. bool Morph3D::OnMouseMove3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
  1698. {
  1699. Tool3D::OnMouseMove3D(pView, nFlags, vPoint);
  1700. if (m_bMorphing)
  1701. {
  1702. //
  1703. // Check distance moved since left button down and don't start
  1704. // moving unless it's greater than the threshold.
  1705. //
  1706. if (!m_bMovingSelected)
  1707. {
  1708. Vector2D sizeMoved = vPoint - m_vLastMouseMovement;
  1709. if ((abs(sizeMoved.x) > 3) || (abs(sizeMoved.y) > 3))
  1710. {
  1711. m_bMovingSelected = true;
  1712. if (m_bHit)
  1713. {
  1714. m_bHit = false;
  1715. SSHANDLEINFO hi;
  1716. m_DragHandle.pStrucSolid->GetHandleInfo(&hi, m_DragHandle.ssh);
  1717. unsigned uSelFlags = scSelect;
  1718. if (!(nFlags & MK_CONTROL) && !hi.p2DHandle->m_bSelected)
  1719. {
  1720. uSelFlags |= scClear;
  1721. }
  1722. SelectHandle(&m_DragHandle, uSelFlags);
  1723. }
  1724. }
  1725. else
  1726. {
  1727. return true;
  1728. }
  1729. }
  1730. unsigned int uConstraints = GetConstraints( nFlags );
  1731. Tool3D::UpdateTranslation( pView, vPoint, uConstraints );
  1732. m_vLastMouseMovement = vPoint;
  1733. }
  1734. else if ( MorphHitTest(pView, vPoint, NULL ))
  1735. {
  1736. SetCursor(AfxGetApp()->LoadStandardCursor(IDC_CROSS));
  1737. }
  1738. else
  1739. {
  1740. SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
  1741. }
  1742. return true;
  1743. }