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.

483 lines
13 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Tool used for picking brush faces.
  4. //
  5. // Left click - single select face
  6. // +Ctrl - multiselect a single face
  7. // +Shift - all faces on the brush
  8. //
  9. // $NoKeywords: $
  10. //=============================================================================//
  11. #include "stdafx.h"
  12. #include "MapFace.h"
  13. #include "resource.h"
  14. #include "ToolPickFace.h"
  15. #include "MapSolid.h"
  16. #include "MapView3D.h"
  17. #include "mapdoc.h"
  18. // memdbgon must be the last include file in a .cpp file!!!
  19. #include <tier0/memdbgon.h>
  20. //-----------------------------------------------------------------------------
  21. // Purpose: Constructor. Inits data members.
  22. //-----------------------------------------------------------------------------
  23. CToolPickFace::CToolPickFace(void)
  24. {
  25. m_pNotifyTarget = NULL;
  26. m_bAllowMultiSelect = false;
  27. }
  28. //-----------------------------------------------------------------------------
  29. // Purpose: Destructor.
  30. //-----------------------------------------------------------------------------
  31. CToolPickFace::~CToolPickFace(void)
  32. {
  33. }
  34. //-----------------------------------------------------------------------------
  35. // Purpose: Enables or disables multiselect for this tool.
  36. //-----------------------------------------------------------------------------
  37. void CToolPickFace::AllowMultiSelect(bool bAllow)
  38. {
  39. m_bAllowMultiSelect = bAllow;
  40. //
  41. // Shouldn't ever happen, but you never know.
  42. //
  43. if ((!bAllow) && (m_Faces.Count() > 1))
  44. {
  45. CMapFace *pFace = m_Faces[0].pFace;
  46. DeselectAll();
  47. SelectFace(pFace);
  48. }
  49. }
  50. //-----------------------------------------------------------------------------
  51. // Purpose: Called when the tool is deactivated.
  52. // Input : eNewTool - The ID of the tool that is being activated.
  53. //-----------------------------------------------------------------------------
  54. void CToolPickFace::OnDeactivate()
  55. {
  56. DeselectAll();
  57. }
  58. //-----------------------------------------------------------------------------
  59. // Purpose: Handles the left mouse button up message in the 3D view.
  60. // Input : pView - The view that the event occurred in.
  61. // nFlags - Flags per the Windows mouse message.
  62. // point - Point in client coordinates where the event occurred.
  63. // Output : Returns true if the message was handled by the tool, false if not.
  64. //-----------------------------------------------------------------------------
  65. bool CToolPickFace::OnLMouseUp3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
  66. {
  67. return true;
  68. }
  69. //-----------------------------------------------------------------------------
  70. // Purpose: Handles the left mouse button up message in the 3D view.
  71. // Input : pView - The view that the event occurred in.
  72. // nFlags - Flags per the Windows mouse message.
  73. // point - Point in client coordinates where the event occurred.
  74. // Output : Returns true if the message was handled by the tool, false if not.
  75. //-----------------------------------------------------------------------------
  76. bool CToolPickFace::OnLMouseDown3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
  77. {
  78. bool bControl = ((nFlags & MK_CONTROL) != 0);
  79. bool bShift = ((nFlags & MK_SHIFT) != 0);
  80. if (!m_bAllowMultiSelect)
  81. {
  82. // Ignore shift click for single selection mode.
  83. bShift = false;
  84. }
  85. unsigned long uFace;
  86. CMapClass *pObject = pView->NearestObjectAt( vPoint, uFace);
  87. if (pObject != NULL)
  88. {
  89. CMapSolid *pSolid = dynamic_cast <CMapSolid *>(pObject);
  90. if (pSolid != NULL)
  91. {
  92. //
  93. // We clicked on a solid.
  94. //
  95. if (!bShift)
  96. {
  97. //
  98. // Get the face that we clicked on.
  99. //
  100. CMapFace *pFace = pSolid->GetFace(uFace);
  101. Assert(pFace != NULL);
  102. if (pFace != NULL)
  103. {
  104. if ((!m_bAllowMultiSelect) || (!bControl))
  105. {
  106. // Single select.
  107. DeselectAll();
  108. SelectFace(pFace);
  109. }
  110. else
  111. {
  112. // Multiselect.
  113. CycleSelectFace(pFace);
  114. }
  115. }
  116. }
  117. else
  118. {
  119. //
  120. // Holding down shift. Select or deselect all the faces on the solid.
  121. // Only deselect if all the faces in the solid were selected.
  122. //
  123. bool bAllSelected = true;
  124. int nFaceCount = pSolid->GetFaceCount();
  125. for (int nFace = 0; nFace < nFaceCount; nFace++)
  126. {
  127. CMapFace *pFace = pSolid->GetFace(nFace);
  128. int nIndex = FindFace(pFace);
  129. if ((nIndex == -1) || (m_Faces[nIndex].eState != FaceState_Select))
  130. {
  131. bAllSelected = false;
  132. break;
  133. }
  134. }
  135. if (!bControl)
  136. {
  137. DeselectAll();
  138. }
  139. nFaceCount = pSolid->GetFaceCount();
  140. for (int nFace = 0; nFace < nFaceCount; nFace++)
  141. {
  142. CMapFace *pFace = pSolid->GetFace(nFace);
  143. if (bAllSelected)
  144. {
  145. DeselectFace(pFace);
  146. }
  147. else
  148. {
  149. SelectFace(pFace);
  150. }
  151. }
  152. }
  153. if (m_pNotifyTarget)
  154. {
  155. m_pNotifyTarget->OnNotifyPickFace(this);
  156. }
  157. }
  158. }
  159. return true;
  160. }
  161. //-----------------------------------------------------------------------------
  162. // Purpose: Handles the left mouse button double click message in the 3D view.
  163. // Input : pView - The view that the event occurred in.
  164. // nFlags - Flags per the Windows mouse message.
  165. // point - Point in client coordinates where the event occurred.
  166. // Output : Returns true if the message was handled by the tool, false if not.
  167. //-----------------------------------------------------------------------------
  168. bool CToolPickFace::OnLMouseDblClk3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
  169. {
  170. return true;
  171. }
  172. //-----------------------------------------------------------------------------
  173. // Purpose: Handles the right mouse button up message in the 3D view.
  174. // Input : pView - The view that the event occurred in.
  175. // nFlags - Flags per the Windows mouse message.
  176. // point - Point in client coordinates where the event occurred.
  177. // Output : Returns true if the message was handled by the tool, false if not.
  178. //-----------------------------------------------------------------------------
  179. bool CToolPickFace::OnRMouseUp3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
  180. {
  181. return true;
  182. }
  183. //-----------------------------------------------------------------------------
  184. // Purpose: Handles the mouse button up message in the 3D view.
  185. // Input : pView - The view that the event occurred in.
  186. // nFlags - Flags per the Windows mouse message.
  187. // point - Point in client coordinates where the event occurred.
  188. // Output : Returns true if the message was handled by the tool, false if not.
  189. //-----------------------------------------------------------------------------
  190. bool CToolPickFace::OnRMouseDown3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
  191. {
  192. return true;
  193. }
  194. //-----------------------------------------------------------------------------
  195. // Purpose: Handles the mouse move message in the 3D view.
  196. // Input : pView - The view that the event occurred in.
  197. // nFlags - Flags per the Windows mouse message.
  198. // point - Point in client coordinates where the event occurred.
  199. // Output : Returns true if the message was handled by the tool, false if not.
  200. //-----------------------------------------------------------------------------
  201. bool CToolPickFace::OnMouseMove3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
  202. {
  203. SetEyedropperCursor();
  204. return true;
  205. }
  206. //-----------------------------------------------------------------------------
  207. // Purpose: Sets the cursor to the eyedropper cursor.
  208. //-----------------------------------------------------------------------------
  209. void CToolPickFace::SetEyedropperCursor(void)
  210. {
  211. static HCURSOR hcurEyedropper = NULL;
  212. if (!hcurEyedropper)
  213. {
  214. hcurEyedropper = LoadCursor(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDC_EYEDROPPER));
  215. }
  216. SetCursor(hcurEyedropper);
  217. }
  218. //-----------------------------------------------------------------------------
  219. // Purpose:
  220. // Input : pFace -
  221. //-----------------------------------------------------------------------------
  222. void CToolPickFace::CycleSelectFace(CMapFace *pFace)
  223. {
  224. int nIndex = FindFace(pFace);
  225. if (nIndex != -1)
  226. {
  227. //
  228. // The face is in our list, update its selection state.
  229. //
  230. if (m_Faces[nIndex].eState == FaceState_Partial)
  231. {
  232. DeselectFace(nIndex);
  233. }
  234. else if (m_Faces[nIndex].eState == FaceState_Select)
  235. {
  236. if (m_Faces[nIndex].eOriginalState == FaceState_Partial)
  237. {
  238. m_Faces[nIndex].eState = FaceState_Partial;
  239. pFace->SetSelectionState(SELECT_MULTI_PARTIAL);
  240. }
  241. else
  242. {
  243. DeselectFace(nIndex);
  244. }
  245. }
  246. else if (m_Faces[nIndex].eState == FaceState_None)
  247. {
  248. m_Faces[nIndex].eState = FaceState_Select;
  249. pFace->SetSelectionState(SELECT_NORMAL);
  250. }
  251. }
  252. else
  253. {
  254. //
  255. // The face is not in our list, add it.
  256. //
  257. AddToList(pFace, FaceState_Select);
  258. pFace->SetSelectionState(SELECT_NORMAL);
  259. }
  260. }
  261. //-----------------------------------------------------------------------------
  262. // Purpose: Sets the fully selected and partially selected faces for the picker.
  263. // Input : FaceListFull -
  264. // FaceListPartial -
  265. //-----------------------------------------------------------------------------
  266. void CToolPickFace::SetSelectedFaces(CMapFaceList &FaceListFull, CMapFaceList &FaceListPartial)
  267. {
  268. m_Faces.RemoveAll();
  269. for (int i = 0; i < FaceListFull.Count(); i++)
  270. {
  271. CMapFace *pFace = FaceListFull.Element(i);
  272. AddToList(pFace, FaceState_Select);
  273. pFace->SetSelectionState(SELECT_NORMAL);
  274. }
  275. for (int i = 0; i < FaceListPartial.Count(); i++)
  276. {
  277. CMapFace *pFace = FaceListPartial.Element(i);
  278. AddToList(pFace, FaceState_Partial);
  279. pFace->SetSelectionState(SELECT_MULTI_PARTIAL);
  280. }
  281. }
  282. //-----------------------------------------------------------------------------
  283. // Purpose:
  284. // Input : pFace -
  285. //-----------------------------------------------------------------------------
  286. int CToolPickFace::FindFace(CMapFace *pFace)
  287. {
  288. for (int i = 0; i < m_Faces.Count(); i++)
  289. {
  290. if (m_Faces[i].pFace == pFace)
  291. {
  292. return i;
  293. }
  294. }
  295. return -1;
  296. }
  297. //-----------------------------------------------------------------------------
  298. // Purpose: Clears the selection set.
  299. //-----------------------------------------------------------------------------
  300. void CToolPickFace::DeselectAll(void)
  301. {
  302. for (int i = 0; i < m_Faces.Count(); i++)
  303. {
  304. m_Faces[i].pFace->SetSelectionState(SELECT_NONE);
  305. }
  306. m_Faces.RemoveAll();
  307. m_pDocument->UpdateAllViews( MAPVIEW_UPDATE_ONLY_3D );
  308. }
  309. //-----------------------------------------------------------------------------
  310. // Purpose: Selects the face unconditionally.
  311. // Input : pFace - face to select.
  312. //-----------------------------------------------------------------------------
  313. void CToolPickFace::SelectFace(CMapFace *pFace)
  314. {
  315. int nIndex = FindFace(pFace);
  316. if (nIndex != -1)
  317. {
  318. //
  319. // The face is in our list, update its selection state.
  320. //
  321. m_Faces[nIndex].eState = FaceState_Select;
  322. pFace->SetSelectionState(SELECT_NORMAL);
  323. }
  324. else
  325. {
  326. //
  327. // The face is not in our list, add it.
  328. //
  329. AddToList(pFace, FaceState_Select);
  330. pFace->SetSelectionState(SELECT_NORMAL);
  331. }
  332. }
  333. //-----------------------------------------------------------------------------
  334. // Purpose: Deselects the given face.
  335. //-----------------------------------------------------------------------------
  336. void CToolPickFace::DeselectFace(CMapFace *pFace)
  337. {
  338. int nIndex = FindFace(pFace);
  339. if (nIndex != -1)
  340. {
  341. DeselectFace(nIndex);
  342. }
  343. }
  344. //-----------------------------------------------------------------------------
  345. // Purpose: Removes the face at the given index from the selection set.
  346. // Input : nIndex - Index of the face in the selection list.
  347. //-----------------------------------------------------------------------------
  348. void CToolPickFace::DeselectFace(int nIndex)
  349. {
  350. Assert(m_Faces.IsValidIndex(nIndex));
  351. if (m_Faces.IsValidIndex(nIndex))
  352. {
  353. if (m_Faces[nIndex].eOriginalState != FaceState_Partial)
  354. {
  355. m_Faces[nIndex].pFace->SetSelectionState(SELECT_NONE);
  356. //
  357. // Remove the face from our list.
  358. //
  359. RemoveFromList(nIndex);
  360. }
  361. else
  362. {
  363. //
  364. // Just set the state to deselected so we can cycle back to partial selection.
  365. //
  366. m_Faces[nIndex].pFace->SetSelectionState(SELECT_NONE);
  367. m_Faces[nIndex].eState = FaceState_None;
  368. }
  369. }
  370. }
  371. //-----------------------------------------------------------------------------
  372. // Purpose:
  373. // Input : pFace -
  374. // eState -
  375. //-----------------------------------------------------------------------------
  376. void CToolPickFace::AddToList(CMapFace *pFace, FaceState_t eState)
  377. {
  378. int nIndex = m_Faces.AddToTail();
  379. m_Faces[nIndex].pFace = pFace;
  380. m_Faces[nIndex].eState = eState;
  381. m_Faces[nIndex].eOriginalState = eState;
  382. m_pDocument->UpdateAllViews( MAPVIEW_UPDATE_ONLY_3D );
  383. }
  384. //-----------------------------------------------------------------------------
  385. // Purpose:
  386. // Input : nIndex -
  387. //-----------------------------------------------------------------------------
  388. void CToolPickFace::RemoveFromList(int nIndex)
  389. {
  390. Assert(m_Faces.IsValidIndex(nIndex));
  391. if (m_Faces.IsValidIndex(nIndex))
  392. {
  393. m_Faces.FastRemove(nIndex);
  394. m_pDocument->UpdateAllViews( MAPVIEW_UPDATE_ONLY_3D );
  395. }
  396. }
  397. //-----------------------------------------------------------------------------
  398. // Purpose: Returns lists of fully selected and partially selected faces.
  399. //-----------------------------------------------------------------------------
  400. void CToolPickFace::GetSelectedFaces(CMapFaceList &FaceListFull, CMapFaceList &FaceListPartial)
  401. {
  402. FaceListFull.RemoveAll();
  403. FaceListPartial.RemoveAll();
  404. for (int i = 0; i < m_Faces.Count(); i++)
  405. {
  406. if (m_Faces[i].eState == FaceState_Select)
  407. {
  408. FaceListFull.AddToTail(m_Faces[i].pFace);
  409. }
  410. else if (m_Faces[i].eState == FaceState_Partial)
  411. {
  412. FaceListPartial.AddToTail(m_Faces[i].pFace);
  413. }
  414. }
  415. }