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.

510 lines
14 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: This helper is used for entities that represent a line between two
  4. // entities. Examples of these are: beams and special node connections.
  5. //
  6. // The helper factory parameters are:
  7. //
  8. // <red> <green> <blue> <start key> <start key value> <end key> <end key value>
  9. //
  10. // The line helper looks in the given keys in its parent entity and
  11. // attaches itself to the entities with those key values. If only one
  12. // endpoint entity is specified, the other end is assumed to be the parent
  13. // entity.
  14. //
  15. //=============================================================================//
  16. #include "stdafx.h"
  17. #include "Box3D.h"
  18. #include "MapEntity.h"
  19. #include "MapLine.h"
  20. #include "MapWorld.h"
  21. #include "Render2D.h"
  22. #include "Render3D.h"
  23. #include "TextureSystem.h"
  24. #include "materialsystem/imesh.h"
  25. #include "Material.h"
  26. // memdbgon must be the last include file in a .cpp file!!!
  27. #include <tier0/memdbgon.h>
  28. IMPLEMENT_MAPCLASS(CMapLine);
  29. //-----------------------------------------------------------------------------
  30. // Purpose: Factory function. Used for creating a CMapLine from a set
  31. // of string parameters from the FGD file.
  32. // Input : *pInfo - Pointer to helper info class which gives us information
  33. // about how to create the class.
  34. // Output : Returns a pointer to the class, NULL if an error occurs.
  35. //-----------------------------------------------------------------------------
  36. CMapClass *CMapLine::Create(CHelperInfo *pHelperInfo, CMapEntity *pParent)
  37. {
  38. CMapLine *pLine = NULL;
  39. //
  40. // Extract the line color from the parameter list.
  41. //
  42. unsigned char chRed = 255;
  43. unsigned char chGreen = 255;
  44. unsigned char chBlue = 255;
  45. const char *pszParam = pHelperInfo->GetParameter(0);
  46. if (pszParam != NULL)
  47. {
  48. chRed = atoi(pszParam);
  49. }
  50. pszParam = pHelperInfo->GetParameter(1);
  51. if (pszParam != NULL)
  52. {
  53. chGreen = atoi(pszParam);
  54. }
  55. pszParam = pHelperInfo->GetParameter(2);
  56. if (pszParam != NULL)
  57. {
  58. chBlue = atoi(pszParam);
  59. }
  60. const char *pszStartKey = pHelperInfo->GetParameter(3);
  61. const char *pszStartValueKey = pHelperInfo->GetParameter(4);
  62. const char *pszEndKey = pHelperInfo->GetParameter(5);
  63. const char *pszEndValueKey = pHelperInfo->GetParameter(6);
  64. //
  65. // Make sure we'll have at least one endpoint to work with.
  66. //
  67. if ((pszStartKey == NULL) || (pszStartValueKey == NULL))
  68. {
  69. return NULL;
  70. }
  71. pLine = new CMapLine(pszStartKey, pszStartValueKey, pszEndKey, pszEndValueKey);
  72. pLine->SetRenderColor(chRed, chGreen, chBlue);
  73. //
  74. // If they only specified a start entity, use our parent as the end entity.
  75. //
  76. if ((pszEndKey == NULL) || (pszEndValueKey == NULL))
  77. {
  78. pLine->m_pEndEntity = pParent;
  79. }
  80. return(pLine);
  81. }
  82. //-----------------------------------------------------------------------------
  83. // Purpose:
  84. //-----------------------------------------------------------------------------
  85. CMapLine::CMapLine(void)
  86. {
  87. Initialize();
  88. }
  89. //-----------------------------------------------------------------------------
  90. // Purpose: Constructor. Initializes data members.
  91. // Input : pszStartKey - The key to search in other entities for a match against the value of pszStartValueKey, ex 'targetname'.
  92. // pszStartValueKey - The key in our parent entity from which to get a search term for the start entity ex 'beamstart01'.
  93. // pszEndKey - The key to search in other entities for a match against the value of pszEndValueKey ex 'targetname'.
  94. // pszEndValueKey - The key in our parent entity from which to get a search term for the end entity ex 'beamend01'.
  95. //-----------------------------------------------------------------------------
  96. CMapLine::CMapLine(const char *pszStartKey, const char *pszStartValueKey, const char *pszEndKey, const char *pszEndValueKey)
  97. {
  98. Initialize();
  99. strcpy(m_szStartKey, pszStartKey);
  100. strcpy(m_szStartValueKey, pszStartValueKey);
  101. if ((pszEndKey != NULL) && (pszEndValueKey != NULL))
  102. {
  103. strcpy(m_szEndKey, pszEndKey);
  104. strcpy(m_szEndValueKey, pszEndValueKey);
  105. }
  106. }
  107. //-----------------------------------------------------------------------------
  108. // Purpose: Sets data members to initial values.
  109. //-----------------------------------------------------------------------------
  110. void CMapLine::Initialize(void)
  111. {
  112. m_szStartKey[0] = '\0';
  113. m_szStartValueKey[0] = '\0';
  114. m_szEndKey[0] = '\0';
  115. m_szEndValueKey[0] = '\0';
  116. m_pStartEntity = NULL;
  117. m_pEndEntity = NULL;
  118. }
  119. //-----------------------------------------------------------------------------
  120. // Purpose: Destructor.
  121. //-----------------------------------------------------------------------------
  122. CMapLine::~CMapLine(void)
  123. {
  124. }
  125. //-----------------------------------------------------------------------------
  126. // Purpose: Calculates the midpoint of the line and sets our origin there.
  127. //-----------------------------------------------------------------------------
  128. void CMapLine::BuildLine(void)
  129. {
  130. if ((m_pStartEntity != NULL) && (m_pEndEntity != NULL))
  131. {
  132. //
  133. // Set our origin to our midpoint. This moves our selection handle box to the
  134. // midpoint.
  135. //
  136. Vector Start;
  137. Vector End;
  138. m_pStartEntity->GetOrigin(Start);
  139. m_pEndEntity->GetOrigin(End);
  140. SetOrigin((Start + End) / 2);
  141. }
  142. CalcBounds();
  143. }
  144. //-----------------------------------------------------------------------------
  145. // Purpose: Recalculates our bounding box.
  146. // Input : bFullUpdate - Whether to force our children to recalculate or not.
  147. //-----------------------------------------------------------------------------
  148. void CMapLine::CalcBounds(BOOL bFullUpdate)
  149. {
  150. CMapClass::CalcBounds(bFullUpdate);
  151. //
  152. // Don't calculate 2D bounds - we don't occupy any space in 2D. This keeps our
  153. // parent entity's bounds from expanding to encompass our endpoints.
  154. //
  155. //
  156. // Update our 3D culling box and possibly our origin.
  157. //
  158. // If our start and end entities are resolved, calcuate our bounds
  159. // based on the positions of the start and end entities.
  160. //
  161. if (m_pStartEntity && m_pEndEntity)
  162. {
  163. //
  164. // Update the 3D bounds.
  165. //
  166. Vector Start;
  167. Vector End;
  168. m_pStartEntity->GetOrigin(Start);
  169. m_CullBox.UpdateBounds(Start);
  170. m_pEndEntity->GetOrigin(End);
  171. m_CullBox.UpdateBounds(End);
  172. }
  173. m_BoundingBox = m_CullBox;
  174. }
  175. //-----------------------------------------------------------------------------
  176. // Purpose:
  177. // Input : bUpdateDependencies -
  178. // Output : CMapClass
  179. //-----------------------------------------------------------------------------
  180. CMapClass *CMapLine::Copy(bool bUpdateDependencies)
  181. {
  182. CMapLine *pCopy = new CMapLine;
  183. if (pCopy != NULL)
  184. {
  185. pCopy->CopyFrom(this, bUpdateDependencies);
  186. }
  187. return(pCopy);
  188. }
  189. //-----------------------------------------------------------------------------
  190. // Purpose: Turns 'this' into an exact replica of 'pObject'.
  191. // Input : pObject - Object to replicate.
  192. // bUpdateDependencies -
  193. // Output :
  194. //-----------------------------------------------------------------------------
  195. CMapClass *CMapLine::CopyFrom(CMapClass *pObject, bool bUpdateDependencies)
  196. {
  197. CMapLine *pFrom = dynamic_cast <CMapLine *>(pObject);
  198. if (pFrom != NULL)
  199. {
  200. CMapClass::CopyFrom(pObject, bUpdateDependencies);
  201. if (bUpdateDependencies)
  202. {
  203. m_pStartEntity = (CMapEntity *)UpdateDependency(m_pStartEntity, pFrom->m_pStartEntity);
  204. m_pEndEntity = (CMapEntity *)UpdateDependency(m_pEndEntity, pFrom->m_pEndEntity);
  205. }
  206. else
  207. {
  208. m_pStartEntity = pFrom->m_pStartEntity;
  209. m_pEndEntity = pFrom->m_pEndEntity;
  210. }
  211. strcpy(m_szStartValueKey, pFrom->m_szStartValueKey);
  212. strcpy(m_szStartKey, pFrom->m_szStartKey);
  213. strcpy(m_szEndValueKey, pFrom->m_szEndValueKey);
  214. strcpy(m_szEndKey, pFrom->m_szEndKey);
  215. }
  216. return(this);
  217. }
  218. //-----------------------------------------------------------------------------
  219. // Purpose: Called after this object is added to the world.
  220. //
  221. // NOTE: This function is NOT called during serialization. Use PostloadWorld
  222. // to do similar bookkeeping after map load.
  223. //
  224. // Input : pWorld - The world that we have been added to.
  225. //-----------------------------------------------------------------------------
  226. void CMapLine::OnAddToWorld(CMapWorld *pWorld)
  227. {
  228. CMapClass::OnAddToWorld(pWorld);
  229. //
  230. // Updates our start and end entity pointers since we are being added
  231. // into the world.
  232. //
  233. UpdateDependencies(pWorld, NULL);
  234. }
  235. //-----------------------------------------------------------------------------
  236. // Purpose: Called just after this object has been removed from the world so
  237. // that it can unlink itself from other objects in the world.
  238. // Input : pWorld - The world that we were just removed from.
  239. // bNotifyChildren - Whether we should forward notification to our children.
  240. //-----------------------------------------------------------------------------
  241. void CMapLine::OnRemoveFromWorld(CMapWorld *pWorld, bool bNotifyChildren)
  242. {
  243. CMapClass::OnRemoveFromWorld(pWorld, bNotifyChildren);
  244. //
  245. // Detach ourselves from the endpoint entities.
  246. //
  247. m_pStartEntity = (CMapEntity *)UpdateDependency(m_pStartEntity, NULL);
  248. m_pEndEntity = (CMapEntity *)UpdateDependency(m_pEndEntity, NULL);
  249. }
  250. //-----------------------------------------------------------------------------
  251. // Purpose: Our start or end entity has changed; recalculate our bounds and midpoint.
  252. // Input : pObject - Entity that changed.
  253. //-----------------------------------------------------------------------------
  254. void CMapLine::OnNotifyDependent(CMapClass *pObject, Notify_Dependent_t eNotifyType)
  255. {
  256. CMapClass::OnNotifyDependent(pObject, eNotifyType);
  257. CMapWorld *pWorld = (CMapWorld *)GetWorldObject(this);
  258. UpdateDependencies(pWorld, NULL);
  259. }
  260. //-----------------------------------------------------------------------------
  261. // Purpose:
  262. // Input : key -
  263. // value -
  264. //-----------------------------------------------------------------------------
  265. void CMapLine::OnParentKeyChanged( const char* key, const char* value )
  266. {
  267. CMapWorld *pWorld = (CMapWorld *)GetWorldObject(this);
  268. if (pWorld != NULL)
  269. {
  270. if (stricmp(key, m_szStartValueKey) == 0)
  271. {
  272. m_pStartEntity = (CMapEntity *)UpdateDependency(m_pStartEntity, pWorld->FindChildByKeyValue(m_szStartKey, value));
  273. BuildLine();
  274. }
  275. else if (stricmp(key, m_szEndValueKey) == 0)
  276. {
  277. m_pEndEntity = (CMapEntity *)UpdateDependency(m_pEndEntity, pWorld->FindChildByKeyValue(m_szEndKey, value));
  278. BuildLine();
  279. }
  280. }
  281. }
  282. //-----------------------------------------------------------------------------
  283. // Purpose: Renders the line helper in the 2D view.
  284. // Input : pRender - 2D rendering interface.
  285. //-----------------------------------------------------------------------------
  286. void CMapLine::Render2D(CRender2D *pRender)
  287. {
  288. if ((m_pStartEntity != NULL) && (m_pEndEntity != NULL))
  289. {
  290. Vector Start;
  291. Vector End;
  292. m_pStartEntity->GetOrigin(Start);
  293. m_pEndEntity->GetOrigin(End);
  294. if (IsSelected())
  295. {
  296. pRender->SetDrawColor( SELECT_FACE_RED, SELECT_FACE_GREEN, SELECT_FACE_BLUE );
  297. }
  298. else
  299. {
  300. pRender->SetDrawColor( r, g, b );
  301. }
  302. pRender->DrawLine(Start, End);
  303. }
  304. }
  305. //-----------------------------------------------------------------------------
  306. // Purpose:
  307. // Input : pRender -
  308. //-----------------------------------------------------------------------------
  309. void CMapLine::Render3D(CRender3D *pRender)
  310. {
  311. if ( (m_pStartEntity == NULL) || (m_pEndEntity == NULL) )
  312. return;
  313. pRender->BeginRenderHitTarget(this);
  314. pRender->PushRenderMode(RENDER_MODE_WIREFRAME);
  315. Vector Start, End;
  316. m_pStartEntity->GetOrigin(Start);
  317. m_pEndEntity->GetOrigin(End);
  318. CMeshBuilder meshBuilder;
  319. CMatRenderContextPtr pRenderContext( MaterialSystemInterface() );
  320. IMesh* pMesh = pRenderContext->GetDynamicMesh();
  321. // FIXME: Can't do this...! glLineWidth(2);
  322. meshBuilder.Begin( pMesh, MATERIAL_LINES, 1 );
  323. unsigned char color[3];
  324. if (IsSelected())
  325. {
  326. color[0] = SELECT_EDGE_RED;
  327. color[1] = SELECT_EDGE_GREEN;
  328. color[2] = SELECT_EDGE_BLUE;
  329. }
  330. else
  331. {
  332. color[0] = r;
  333. color[1] = g;
  334. color[2] = b;
  335. }
  336. meshBuilder.Color3ubv( color );
  337. meshBuilder.Position3f(Start.x, Start.y, Start.z);
  338. meshBuilder.AdvanceVertex();
  339. meshBuilder.Color3ubv( color );
  340. meshBuilder.Position3f(End.x, End.y, End.z);
  341. meshBuilder.AdvanceVertex();
  342. meshBuilder.End();
  343. pMesh->Draw();
  344. pRender->EndRenderHitTarget();
  345. pRender->PopRenderMode();
  346. }
  347. //-----------------------------------------------------------------------------
  348. // Purpose:
  349. // Input : File -
  350. // bRMF -
  351. // Output : int
  352. //-----------------------------------------------------------------------------
  353. int CMapLine::SerializeRMF(std::fstream &File, BOOL bRMF)
  354. {
  355. return(0);
  356. }
  357. //-----------------------------------------------------------------------------
  358. // Purpose:
  359. // Input : File -
  360. // bRMF -
  361. // Output : int
  362. //-----------------------------------------------------------------------------
  363. int CMapLine::SerializeMAP(std::fstream &File, BOOL bRMF)
  364. {
  365. return(0);
  366. }
  367. //-----------------------------------------------------------------------------
  368. // Purpose:
  369. // Input : pTransBox -
  370. //-----------------------------------------------------------------------------
  371. void CMapLine::DoTransform(const VMatrix &matrix)
  372. {
  373. BaseClass::DoTransform(matrix);
  374. BuildLine();
  375. }
  376. //-----------------------------------------------------------------------------
  377. // Purpose: Updates the cached pointers to our start and end entities by looking
  378. // for them in the given world.
  379. // Input : pWorld - World to search.
  380. //-----------------------------------------------------------------------------
  381. void CMapLine::UpdateDependencies(CMapWorld *pWorld, CMapClass *pObject)
  382. {
  383. CMapClass::UpdateDependencies(pWorld, pObject);
  384. if (pWorld == NULL)
  385. {
  386. return;
  387. }
  388. CMapEntity *pEntity = dynamic_cast <CMapEntity *> (m_pParent);
  389. Assert(pEntity != NULL);
  390. if (pEntity != NULL)
  391. {
  392. const char *pszValue = pEntity->GetKeyValue(m_szStartValueKey);
  393. m_pStartEntity = (CMapEntity *)UpdateDependency(m_pStartEntity, pWorld->FindChildByKeyValue(m_szStartKey, pszValue));
  394. if (m_szEndValueKey[0] != '\0')
  395. {
  396. pszValue = pEntity->GetKeyValue(m_szEndValueKey);
  397. m_pEndEntity = (CMapEntity *)UpdateDependency(m_pEndEntity, pWorld->FindChildByKeyValue(m_szEndKey, pszValue));
  398. }
  399. else
  400. {
  401. // We don't have an end entity specified, use our parent as the end point.
  402. m_pEndEntity = (CMapEntity *)UpdateDependency(m_pEndEntity, GetParent());
  403. }
  404. BuildLine();
  405. }
  406. }
  407. //-----------------------------------------------------------------------------
  408. // Purpose: Never select anything because of this helper.
  409. //-----------------------------------------------------------------------------
  410. CMapClass *CMapLine::PrepareSelection(SelectMode_t eSelectMode)
  411. {
  412. return NULL;
  413. }