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.

361 lines
9.5 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Implements a sphere helper for entities that have a radius of effect.
  4. // Renders only when the parent entity is selected.
  5. //
  6. //=============================================================================//
  7. #include "stdafx.h"
  8. #include "Box3D.h"
  9. #include "fgdlib/HelperInfo.h"
  10. #include "materialsystem/imaterialsystem.h"
  11. #include "materialsystem/imesh.h"
  12. #include "MapDoc.h"
  13. #include "MapSphere.h"
  14. #include "MapView2D.h"
  15. #include "Material.h"
  16. #include "mathlib/MathLib.h"
  17. #include "Render2D.h"
  18. #include "Render3D.h"
  19. #include "ToolManager.h"
  20. #include "ToolSphere.h"
  21. // memdbgon must be the last include file in a .cpp file!!!
  22. #include <tier0/memdbgon.h>
  23. IMPLEMENT_MAPCLASS(CMapSphere)
  24. //-----------------------------------------------------------------------------
  25. // Purpose: Factory function. Used for creating a CMapSphere helper from a
  26. // set of string parameters from the FGD file.
  27. // Input : pInfo - Pointer to helper info class which gives us information
  28. // about how to create the helper.
  29. // Output : Returns a pointer to the helper, NULL if an error occurs.
  30. //-----------------------------------------------------------------------------
  31. CMapClass *CMapSphere::Create(CHelperInfo *pHelperInfo, CMapEntity *pParent)
  32. {
  33. CMapSphere *pSphere = new CMapSphere;
  34. if (pSphere != NULL)
  35. {
  36. //
  37. // The first parameter should be the key name to represent. If it isn't
  38. // there we assume "radius".
  39. //
  40. const char *pszKeyName = pHelperInfo->GetParameter(0);
  41. if (pszKeyName != NULL)
  42. {
  43. strcpy(pSphere->m_szKeyName, pszKeyName);
  44. }
  45. else
  46. {
  47. strcpy(pSphere->m_szKeyName, "radius");
  48. }
  49. //
  50. // Extract the line color from the parameter list.
  51. //
  52. unsigned char chRed = 255;
  53. unsigned char chGreen = 255;
  54. unsigned char chBlue = 255;
  55. const char *pszParam = pHelperInfo->GetParameter(1);
  56. if (pszParam != NULL)
  57. {
  58. chRed = atoi(pszParam);
  59. }
  60. pszParam = pHelperInfo->GetParameter(2);
  61. if (pszParam != NULL)
  62. {
  63. chGreen = atoi(pszParam);
  64. }
  65. pszParam = pHelperInfo->GetParameter(3);
  66. if (pszParam != NULL)
  67. {
  68. chBlue = atoi(pszParam);
  69. }
  70. pSphere->SetRenderColor(chRed, chGreen, chBlue);
  71. }
  72. return pSphere;
  73. }
  74. //-----------------------------------------------------------------------------
  75. // Purpose: Constructor.
  76. //-----------------------------------------------------------------------------
  77. CMapSphere::CMapSphere(void)
  78. {
  79. m_szKeyName[0] = '\0';
  80. m_flRadius = 0;
  81. r = 255;
  82. g = 255;
  83. b = 0;
  84. }
  85. //-----------------------------------------------------------------------------
  86. // Purpose: Destructor.
  87. //-----------------------------------------------------------------------------
  88. CMapSphere::~CMapSphere(void)
  89. {
  90. }
  91. //-----------------------------------------------------------------------------
  92. // Purpose:
  93. // Input : bFullUpdate -
  94. //-----------------------------------------------------------------------------
  95. void CMapSphere::CalcBounds(BOOL bFullUpdate)
  96. {
  97. CMapClass::CalcBounds(bFullUpdate);
  98. //
  99. // Pretend we're a point so that we don't change our parent entity bounds
  100. // in the 2D view.
  101. //
  102. m_Render2DBox.ResetBounds();
  103. m_Render2DBox.UpdateBounds(m_Origin);
  104. //
  105. // Build our bounds for frustum culling in the 3D views.
  106. //
  107. m_CullBox.ResetBounds();
  108. Vector mins = m_Origin - Vector(m_flRadius, m_flRadius, m_flRadius);
  109. Vector maxs = m_Origin + Vector(m_flRadius, m_flRadius, m_flRadius);
  110. m_CullBox.UpdateBounds(mins, maxs);
  111. m_BoundingBox.ResetBounds(); // we don't want to use the bounds of the sphere for our bounding box
  112. }
  113. //-----------------------------------------------------------------------------
  114. // Purpose:
  115. // Output : CMapClass
  116. //-----------------------------------------------------------------------------
  117. CMapClass *CMapSphere::Copy(bool bUpdateDependencies)
  118. {
  119. CMapSphere *pCopy = new CMapSphere;
  120. if (pCopy != NULL)
  121. {
  122. pCopy->CopyFrom(this, bUpdateDependencies);
  123. }
  124. return(pCopy);
  125. }
  126. //-----------------------------------------------------------------------------
  127. // Purpose: Makes this an exact duplicate of pObject.
  128. // Input : pObject - Object to copy.
  129. // Output : Returns this.
  130. //-----------------------------------------------------------------------------
  131. CMapClass *CMapSphere::CopyFrom(CMapClass *pObject, bool bUpdateDependencies)
  132. {
  133. Assert(pObject->IsMapClass(MAPCLASS_TYPE(CMapSphere)));
  134. CMapSphere *pFrom = (CMapSphere *)pObject;
  135. CMapClass::CopyFrom(pObject, bUpdateDependencies);
  136. m_flRadius = pFrom->m_flRadius;
  137. strcpy(m_szKeyName, pFrom->m_szKeyName);
  138. return(this);
  139. }
  140. //-----------------------------------------------------------------------------
  141. // Purpose: Sets the radius of the sphere helper and updates our parent
  142. // entity's keyvalue.
  143. //-----------------------------------------------------------------------------
  144. void CMapSphere::SetRadius(float flRadius)
  145. {
  146. m_flRadius = V_rint(flRadius);
  147. CMapEntity *pEntity = dynamic_cast <CMapEntity *>(m_pParent);
  148. if (pEntity != NULL)
  149. {
  150. char szValue[80];
  151. sprintf(szValue, "%g", m_flRadius);
  152. pEntity->NotifyChildKeyChanged(this, m_szKeyName, szValue);
  153. }
  154. }
  155. //-----------------------------------------------------------------------------
  156. // Purpose: Gets the tool object for a given context data from HitTest2D.
  157. //-----------------------------------------------------------------------------
  158. CBaseTool *CMapSphere::GetToolObject(int nHitData, bool bAttachObject)
  159. {
  160. CToolSphere *pTool = (CToolSphere *)ToolManager()->GetToolForID(TOOL_SPHERE);
  161. if ( bAttachObject )
  162. pTool->Attach(this);
  163. return pTool;
  164. }
  165. //-----------------------------------------------------------------------------
  166. // Purpose:
  167. // Input : pView -
  168. // point - point in client coordinates
  169. // Output :
  170. //-----------------------------------------------------------------------------
  171. bool CMapSphere::HitTest2D(CMapView2D *pView, const Vector2D &point, HitInfo_t &HitData)
  172. {
  173. if (!IsVisible() || m_flRadius <= 0 || !IsSelected() )
  174. {
  175. return NULL;
  176. }
  177. Vector2D vecClientOrigin;
  178. pView->WorldToClient(vecClientOrigin, m_Origin);
  179. Vector vecRadius = m_Origin;
  180. vecRadius[pView->axHorz] += m_flRadius;
  181. Vector2D vecClientRadius;
  182. pView->WorldToClient(vecClientRadius, vecRadius);
  183. int nRadius = abs(vecClientRadius.x - vecClientOrigin.x);
  184. vecClientRadius.x = nRadius;
  185. vecClientRadius.y = nRadius;
  186. HitData.pObject = this;
  187. HitData.nDepth = 0; // handles have no depth
  188. HitData.uData = nRadius;
  189. Vector2D vecClientMin = vecClientOrigin - vecClientRadius;
  190. Vector2D vecClientMax = vecClientOrigin + vecClientRadius;
  191. //
  192. // Check the four resize handles.
  193. //
  194. Vector2D vecTemp(vecClientOrigin.x, vecClientMin.y - HANDLE_OFFSET);
  195. if (pView->CheckDistance(point, vecTemp, 6))
  196. {
  197. // Top handle
  198. SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENS));
  199. return true;
  200. }
  201. vecTemp.x = vecClientOrigin.x;
  202. vecTemp.y = vecClientMax.y + HANDLE_OFFSET;
  203. if (pView->CheckDistance(point, vecTemp, HANDLE_RADIUS))
  204. {
  205. // Bottom handle
  206. SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENS));
  207. return true;
  208. }
  209. vecTemp.x = vecClientMin.x - HANDLE_OFFSET;
  210. vecTemp.y = vecClientOrigin.y;
  211. if (pView->CheckDistance(point, vecTemp, HANDLE_RADIUS))
  212. {
  213. // Left handle
  214. SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEWE));
  215. return true;
  216. }
  217. vecTemp.x = vecClientMax.x + HANDLE_OFFSET;
  218. vecTemp.y = vecClientOrigin.y;
  219. if (pView->CheckDistance(point, vecTemp, HANDLE_RADIUS))
  220. {
  221. // Right handle
  222. SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEWE));
  223. return true;
  224. }
  225. HitData.pObject = NULL;
  226. return false;
  227. }
  228. //-----------------------------------------------------------------------------
  229. // Purpose: Notifies that this object's parent entity has had a key value change.
  230. // Input : szKey - The key that changed.
  231. // szValue - The new value of the key.
  232. //-----------------------------------------------------------------------------
  233. void CMapSphere::OnParentKeyChanged(const char *szKey, const char *szValue)
  234. {
  235. if (!stricmp(szKey, m_szKeyName))
  236. {
  237. m_flRadius = atof(szValue);
  238. PostUpdate(Notify_Changed);
  239. }
  240. }
  241. //-----------------------------------------------------------------------------
  242. // Purpose:
  243. // Input : pRender -
  244. //-----------------------------------------------------------------------------
  245. void CMapSphere::Render2D(CRender2D *pRender)
  246. {
  247. if (m_pParent->IsSelected() && (m_flRadius > 0) )
  248. {
  249. pRender->SetDrawColor( 255, 255, 0 );
  250. Vector2D ptClientRadius;
  251. pRender->TransformNormal(ptClientRadius, Vector(m_flRadius,m_flRadius,m_flRadius) );
  252. int radius = ptClientRadius.x;
  253. pRender->DrawCircle( m_Origin, m_flRadius );
  254. bool bPopMode = pRender->BeginClientSpace();
  255. //
  256. // Draw the four resize handles.
  257. //
  258. pRender->SetHandleStyle( HANDLE_RADIUS, CRender::HANDLE_SQUARE );
  259. pRender->SetHandleColor( 255,255,255 );
  260. Vector2D offset;
  261. offset.x = 0;
  262. offset.y = -(radius + HANDLE_OFFSET);
  263. pRender->DrawHandle( m_Origin, &offset );
  264. offset.x = 0;
  265. offset.y = radius + HANDLE_OFFSET;
  266. pRender->DrawHandle( m_Origin, &offset );
  267. offset.x = -(radius + HANDLE_OFFSET);
  268. offset.y = 0;
  269. pRender->DrawHandle( m_Origin, &offset );
  270. offset.x = radius + HANDLE_OFFSET;
  271. offset.y = 0;
  272. pRender->DrawHandle( m_Origin, &offset );
  273. if ( bPopMode )
  274. pRender->EndClientSpace();
  275. }
  276. }
  277. //-----------------------------------------------------------------------------
  278. // Purpose: Renders the wireframe sphere.
  279. // Input : pRender - Interface to renderer.
  280. //-----------------------------------------------------------------------------
  281. void CMapSphere::Render3D(CRender3D *pRender)
  282. {
  283. if (m_pParent->IsSelected() && (m_flRadius > 0))
  284. {
  285. pRender->RenderWireframeSphere(m_Origin, m_flRadius, 12, 12, 255, 255, 0);
  286. }
  287. }