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.

667 lines
20 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 "MapCylinder.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. #include "mapdoc.h"
  27. #include "options.h"
  28. // memdbgon must be the last include file in a .cpp file!!!
  29. #include <tier0/memdbgon.h>
  30. IMPLEMENT_MAPCLASS(CMapCylinder);
  31. #define CYLINDER_VERTEX_COUNT 16
  32. #define CYLINDER_VERTEX_COUNT_2D 8
  33. //-----------------------------------------------------------------------------
  34. // Purpose: Factory function. Used for creating a CMapCylinder from a set
  35. // of string parameters from the FGD file.
  36. // Input : *pInfo - Pointer to helper info class which gives us information
  37. // about how to create the class.
  38. // Output : Returns a pointer to the class, NULL if an error occurs.
  39. //-----------------------------------------------------------------------------
  40. CMapClass *CMapCylinder::Create(CHelperInfo *pHelperInfo, CMapEntity *pParent)
  41. {
  42. CMapCylinder *pCylinder = NULL;
  43. //
  44. // Extract the line color from the parameter list.
  45. //
  46. unsigned char chRed = 255;
  47. unsigned char chGreen = 255;
  48. unsigned char chBlue = 255;
  49. const char *pszParam = pHelperInfo->GetParameter(0);
  50. if (pszParam != NULL)
  51. {
  52. chRed = atoi(pszParam);
  53. }
  54. pszParam = pHelperInfo->GetParameter(1);
  55. if (pszParam != NULL)
  56. {
  57. chGreen = atoi(pszParam);
  58. }
  59. pszParam = pHelperInfo->GetParameter(2);
  60. if (pszParam != NULL)
  61. {
  62. chBlue = atoi(pszParam);
  63. }
  64. const char *pszStartKey = pHelperInfo->GetParameter(3);
  65. const char *pszStartValueKey = pHelperInfo->GetParameter(4);
  66. const char *pszStartRadiusKey = pHelperInfo->GetParameter(5);
  67. const char *pszEndKey = pHelperInfo->GetParameter(6);
  68. const char *pszEndValueKey = pHelperInfo->GetParameter(7);
  69. const char *pszEndRadiusKey = pHelperInfo->GetParameter(8);
  70. //
  71. // Make sure we'll have at least one endpoint to work with.
  72. //
  73. if ((pszStartKey == NULL) || (pszStartValueKey == NULL))
  74. {
  75. return NULL;
  76. }
  77. pCylinder = new CMapCylinder(pszStartKey, pszStartValueKey, pszStartRadiusKey, pszEndKey, pszEndValueKey, pszEndRadiusKey);
  78. pCylinder->SetRenderColor(chRed, chGreen, chBlue);
  79. //
  80. // If they only specified a start entity, use our parent as the end entity.
  81. //
  82. if ((pszEndKey == NULL) || (pszEndValueKey == NULL))
  83. {
  84. pCylinder->m_pEndEntity = pParent;
  85. }
  86. return(pCylinder);
  87. }
  88. //-----------------------------------------------------------------------------
  89. // Purpose:
  90. //-----------------------------------------------------------------------------
  91. CMapCylinder::CMapCylinder(void)
  92. {
  93. Initialize();
  94. }
  95. //-----------------------------------------------------------------------------
  96. // Purpose: Constructor. Initializes data members.
  97. // Input : pszStartKey - The key to search in other entities for a match against the value of pszStartValueKey, ex 'targetname'.
  98. // pszStartValueKey - The key in our parent entity from which to get a search term for the start entity ex 'beamstart01'.
  99. // pszEndKey - The key to search in other entities for a match against the value of pszEndValueKey ex 'targetname'.
  100. // pszEndValueKey - The key in our parent entity from which to get a search term for the end entity ex 'beamend01'.
  101. //-----------------------------------------------------------------------------
  102. CMapCylinder::CMapCylinder(const char *pszStartKey, const char *pszStartValueKey, const char *pszStartRadiusKey,
  103. const char *pszEndKey, const char *pszEndValueKey, const char *pszEndRadiusKey )
  104. {
  105. Initialize();
  106. strcpy(m_szStartKey, pszStartKey);
  107. strcpy(m_szStartValueKey, pszStartValueKey);
  108. if ( pszStartRadiusKey != NULL )
  109. {
  110. strcpy(m_szStartRadiusKey, pszStartRadiusKey);
  111. }
  112. if ((pszEndKey != NULL) && (pszEndValueKey != NULL))
  113. {
  114. strcpy(m_szEndKey, pszEndKey);
  115. strcpy(m_szEndValueKey, pszEndValueKey);
  116. if ( pszEndRadiusKey != NULL )
  117. {
  118. strcpy(m_szEndRadiusKey, pszEndRadiusKey);
  119. }
  120. }
  121. }
  122. //-----------------------------------------------------------------------------
  123. // Purpose: Sets data members to initial values.
  124. //-----------------------------------------------------------------------------
  125. void CMapCylinder::Initialize(void)
  126. {
  127. m_szStartKey[0] = '\0';
  128. m_szStartValueKey[0] = '\0';
  129. m_szStartRadiusKey[0] = '\0';
  130. m_szEndKey[0] = '\0';
  131. m_szEndValueKey[0] = '\0';
  132. m_szEndRadiusKey[0] = '\0';
  133. m_pStartEntity = NULL;
  134. m_pEndEntity = NULL;
  135. }
  136. //-----------------------------------------------------------------------------
  137. // Purpose: Destructor.
  138. //-----------------------------------------------------------------------------
  139. CMapCylinder::~CMapCylinder(void)
  140. {
  141. }
  142. //-----------------------------------------------------------------------------
  143. // Purpose: Calculates the midpoint of the line and sets our origin there.
  144. //-----------------------------------------------------------------------------
  145. void CMapCylinder::BuildCylinder(void)
  146. {
  147. if ((m_pStartEntity != NULL) && (m_pEndEntity != NULL))
  148. {
  149. //
  150. // Set our origin to our midpoint. This moves our selection handle box to the
  151. // midpoint.
  152. //
  153. Vector Start;
  154. Vector End;
  155. m_pStartEntity->GetOrigin(Start);
  156. m_pEndEntity->GetOrigin(End);
  157. SetOrigin((Start + End) / 2);
  158. }
  159. CalcBounds();
  160. }
  161. //-----------------------------------------------------------------------------
  162. // Purpose: Recalculates our bounding box.
  163. // Input : bFullUpdate - Whether to force our children to recalculate or not.
  164. //-----------------------------------------------------------------------------
  165. void CMapCylinder::CalcBounds(BOOL bFullUpdate)
  166. {
  167. CMapClass::CalcBounds(bFullUpdate);
  168. //
  169. // Don't calculate 2D bounds - we don't occupy any space in 2D. This keeps our
  170. // parent entity's bounds from expanding to encompass our endpoints.
  171. //
  172. //
  173. // Update our 3D culling box and possibly our origin.
  174. //
  175. // If our start and end entities are resolved, calcuate our bounds
  176. // based on the positions of the start and end entities.
  177. //
  178. if (m_pStartEntity && m_pEndEntity)
  179. {
  180. //
  181. // Update the 3D bounds.
  182. //
  183. Vector Start;
  184. Vector End;
  185. Vector pStartVerts[CYLINDER_VERTEX_COUNT];
  186. Vector pEndVerts[CYLINDER_VERTEX_COUNT];
  187. ComputeCylinderPoints( CYLINDER_VERTEX_COUNT, pStartVerts, pEndVerts );
  188. for ( int i = 0; i < CYLINDER_VERTEX_COUNT; ++i )
  189. {
  190. m_CullBox.UpdateBounds(pStartVerts[i]);
  191. m_CullBox.UpdateBounds(pEndVerts[i]);
  192. }
  193. m_BoundingBox = m_CullBox;
  194. }
  195. }
  196. //-----------------------------------------------------------------------------
  197. // Purpose:
  198. // Input : bUpdateDependencies -
  199. // Output : CMapClass
  200. //-----------------------------------------------------------------------------
  201. CMapClass *CMapCylinder::Copy(bool bUpdateDependencies)
  202. {
  203. CMapCylinder *pCopy = new CMapCylinder;
  204. if (pCopy != NULL)
  205. {
  206. pCopy->CopyFrom(this, bUpdateDependencies);
  207. }
  208. return(pCopy);
  209. }
  210. //-----------------------------------------------------------------------------
  211. // Purpose: Turns 'this' into an exact replica of 'pObject'.
  212. // Input : pObject - Object to replicate.
  213. // bUpdateDependencies -
  214. // Output :
  215. //-----------------------------------------------------------------------------
  216. CMapClass *CMapCylinder::CopyFrom(CMapClass *pObject, bool bUpdateDependencies)
  217. {
  218. CMapCylinder *pFrom = dynamic_cast <CMapCylinder *>(pObject);
  219. if (pFrom != NULL)
  220. {
  221. CMapClass::CopyFrom(pObject, bUpdateDependencies);
  222. if (bUpdateDependencies)
  223. {
  224. m_pStartEntity = (CMapEntity *)UpdateDependency(m_pStartEntity, pFrom->m_pStartEntity);
  225. m_pEndEntity = (CMapEntity *)UpdateDependency(m_pEndEntity, pFrom->m_pEndEntity);
  226. }
  227. else
  228. {
  229. m_pStartEntity = pFrom->m_pStartEntity;
  230. m_pEndEntity = pFrom->m_pEndEntity;
  231. }
  232. m_flStartRadius = pFrom->m_flStartRadius;
  233. m_flEndRadius = pFrom->m_flEndRadius;
  234. strcpy(m_szStartValueKey, pFrom->m_szStartValueKey);
  235. strcpy(m_szStartKey, pFrom->m_szStartKey);
  236. strcpy(m_szStartRadiusKey, pFrom->m_szStartRadiusKey);
  237. strcpy(m_szEndValueKey, pFrom->m_szEndValueKey);
  238. strcpy(m_szEndKey, pFrom->m_szEndKey);
  239. strcpy(m_szEndRadiusKey, pFrom->m_szEndRadiusKey);
  240. }
  241. return(this);
  242. }
  243. //-----------------------------------------------------------------------------
  244. // Purpose: Called after this object is added to the world.
  245. //
  246. // NOTE: This function is NOT called during serialization. Use PostloadWorld
  247. // to do similar bookkeeping after map load.
  248. //
  249. // Input : pWorld - The world that we have been added to.
  250. //-----------------------------------------------------------------------------
  251. void CMapCylinder::OnAddToWorld(CMapWorld *pWorld)
  252. {
  253. CMapClass::OnAddToWorld(pWorld);
  254. //
  255. // Updates our start and end entity pointers since we are being added
  256. // into the world.
  257. //
  258. UpdateDependencies(pWorld, NULL);
  259. }
  260. //-----------------------------------------------------------------------------
  261. // Purpose: Called just after this object has been removed from the world so
  262. // that it can unlink itself from other objects in the world.
  263. // Input : pWorld - The world that we were just removed from.
  264. // bNotifyChildren - Whether we should forward notification to our children.
  265. //-----------------------------------------------------------------------------
  266. void CMapCylinder::OnRemoveFromWorld(CMapWorld *pWorld, bool bNotifyChildren)
  267. {
  268. CMapClass::OnRemoveFromWorld(pWorld, bNotifyChildren);
  269. //
  270. // Detach ourselves from the endpoint entities.
  271. //
  272. m_pStartEntity = (CMapEntity *)UpdateDependency(m_pStartEntity, NULL);
  273. m_pEndEntity = (CMapEntity *)UpdateDependency(m_pEndEntity, NULL);
  274. }
  275. //-----------------------------------------------------------------------------
  276. // Purpose: Our start or end entity has changed; recalculate our bounds and midpoint.
  277. // Input : pObject - Entity that changed.
  278. //-----------------------------------------------------------------------------
  279. void CMapCylinder::OnNotifyDependent(CMapClass *pObject, Notify_Dependent_t eNotifyType)
  280. {
  281. CMapClass::OnNotifyDependent(pObject, eNotifyType);
  282. CMapWorld *pWorld = (CMapWorld *)GetWorldObject(this);
  283. UpdateDependencies(pWorld, pObject);
  284. }
  285. //-----------------------------------------------------------------------------
  286. // Purpose:
  287. // Input : key -
  288. // value -
  289. //-----------------------------------------------------------------------------
  290. void CMapCylinder::OnParentKeyChanged( const char* key, const char* value )
  291. {
  292. CMapWorld *pWorld = (CMapWorld *)GetWorldObject(this);
  293. if (pWorld != NULL)
  294. {
  295. if (stricmp(key, m_szStartValueKey) == 0)
  296. {
  297. m_pStartEntity = (CMapEntity *)UpdateDependency(m_pStartEntity, pWorld->FindChildByKeyValue(m_szStartKey, value));
  298. BuildCylinder();
  299. }
  300. else if (stricmp(key, m_szEndValueKey) == 0)
  301. {
  302. m_pEndEntity = (CMapEntity *)UpdateDependency(m_pEndEntity, pWorld->FindChildByKeyValue(m_szEndKey, value));
  303. BuildCylinder();
  304. }
  305. if (m_pStartEntity && stricmp(key, m_szStartRadiusKey) == 0)
  306. {
  307. const char *pRadiusKey = m_pStartEntity->GetKeyValue( m_szStartRadiusKey );
  308. m_flStartRadius = pRadiusKey ? atof( pRadiusKey ) : 0.0f;
  309. BuildCylinder();
  310. }
  311. if (m_pEndEntity && stricmp(key, m_szEndRadiusKey) == 0)
  312. {
  313. const char *pRadiusKey = m_pEndEntity->GetKeyValue( m_szEndRadiusKey );
  314. m_flEndRadius = pRadiusKey ? atof( pRadiusKey ) : 0.0f;
  315. BuildCylinder();
  316. }
  317. }
  318. }
  319. //-----------------------------------------------------------------------------
  320. // Computes the vertices of the cylinder
  321. //-----------------------------------------------------------------------------
  322. void CMapCylinder::ComputeCylinderPoints( int nCount, Vector *pStartVerts, Vector *pEndVerts )
  323. {
  324. Assert ((m_pStartEntity != NULL) && (m_pEndEntity != NULL));
  325. Vector vecStart;
  326. Vector vecEnd;
  327. m_pStartEntity->GetOrigin(vecStart);
  328. m_pEndEntity->GetOrigin(vecEnd);
  329. // Compute a basis perpendicular to the entities
  330. Vector xvec, yvec, zvec;
  331. VectorSubtract( vecEnd, vecStart, zvec );
  332. float flLength = VectorNormalize( zvec );
  333. if ( flLength < 1e-3 )
  334. {
  335. zvec.Init( 0, 0, 1 );
  336. }
  337. VectorVectors( zvec, xvec, yvec );
  338. int i;
  339. float flDAngle = 2.0f * M_PI / nCount;
  340. for ( i = 0; i < nCount; ++i )
  341. {
  342. float flCosAngle = cos( flDAngle * i );
  343. float flSinAngle = sin( flDAngle * i );
  344. VectorMA( vecStart, flCosAngle * m_flStartRadius, xvec, pStartVerts[i] );
  345. VectorMA( pStartVerts[i], flSinAngle * m_flStartRadius, yvec, pStartVerts[i] );
  346. VectorMA( vecEnd, flCosAngle * m_flEndRadius, xvec, pEndVerts[i] );
  347. VectorMA( pEndVerts[i], flSinAngle * m_flEndRadius, yvec, pEndVerts[i] );
  348. }
  349. }
  350. //-----------------------------------------------------------------------------
  351. // Should we draw the cylinder as a line?
  352. //-----------------------------------------------------------------------------
  353. bool CMapCylinder::ShouldDrawAsLine()
  354. {
  355. return !IsSelected() || ((m_flStartRadius == 0.0f) && (m_flEndRadius == 0.0f)) || !Options.GetShowHelpers();
  356. }
  357. //-----------------------------------------------------------------------------
  358. // Purpose: Renders the line helper in the 2D view.
  359. // Input : pRender - 2D rendering interface.
  360. //-----------------------------------------------------------------------------
  361. void CMapCylinder::Render2D(CRender2D *pRender)
  362. {
  363. if ((m_pStartEntity != NULL) && (m_pEndEntity != NULL))
  364. {
  365. if (!ShouldDrawAsLine())
  366. {
  367. pRender->SetDrawColor( SELECT_FACE_RED, SELECT_FACE_GREEN, SELECT_FACE_BLUE );
  368. Vector pStartVerts[CYLINDER_VERTEX_COUNT_2D];
  369. Vector pEndVerts[CYLINDER_VERTEX_COUNT_2D];
  370. ComputeCylinderPoints( CYLINDER_VERTEX_COUNT_2D, pStartVerts, pEndVerts );
  371. int j = CYLINDER_VERTEX_COUNT_2D - 1;
  372. for (int i = 0; i < CYLINDER_VERTEX_COUNT_2D; j = i++ )
  373. {
  374. pRender->DrawLine(pStartVerts[i], pStartVerts[j]);
  375. pRender->DrawLine(pEndVerts[i], pEndVerts[j]);
  376. pRender->DrawLine(pStartVerts[i], pEndVerts[i]);
  377. }
  378. }
  379. else
  380. {
  381. pRender->SetDrawColor( r, g, b );
  382. Vector Start;
  383. Vector End;
  384. m_pStartEntity->GetOrigin(Start);
  385. m_pEndEntity->GetOrigin(End);
  386. pRender->DrawLine(Start, End);
  387. }
  388. }
  389. }
  390. //-----------------------------------------------------------------------------
  391. // Purpose:
  392. // Input : pRender -
  393. //-----------------------------------------------------------------------------
  394. void CMapCylinder::Render3D(CRender3D *pRender)
  395. {
  396. if ( (m_pStartEntity == NULL) || (m_pEndEntity == NULL))
  397. return;
  398. pRender->BeginRenderHitTarget(this);
  399. pRender->PushRenderMode(RENDER_MODE_WIREFRAME);
  400. Vector Start,End;
  401. m_pStartEntity->GetOrigin(Start);
  402. m_pEndEntity->GetOrigin(End);
  403. unsigned char color[3];
  404. if (IsSelected())
  405. {
  406. color[0] = SELECT_EDGE_RED;
  407. color[1] = SELECT_EDGE_GREEN;
  408. color[2] = SELECT_EDGE_BLUE;
  409. }
  410. else
  411. {
  412. color[0] = r;
  413. color[1] = g;
  414. color[2] = b;
  415. }
  416. CMeshBuilder meshBuilder;
  417. CMatRenderContextPtr pRenderContext( MaterialSystemInterface() );
  418. IMesh* pMesh = pRenderContext->GetDynamicMesh();
  419. if ( !ShouldDrawAsLine() )
  420. {
  421. Vector pStartVerts[CYLINDER_VERTEX_COUNT];
  422. Vector pEndVerts[CYLINDER_VERTEX_COUNT];
  423. ComputeCylinderPoints( CYLINDER_VERTEX_COUNT, pStartVerts, pEndVerts );
  424. meshBuilder.Begin( pMesh, MATERIAL_LINES, 3 * CYLINDER_VERTEX_COUNT );
  425. int j = CYLINDER_VERTEX_COUNT - 1;
  426. for ( int i = 0; i < CYLINDER_VERTEX_COUNT; j = i++ )
  427. {
  428. meshBuilder.Color3ubv( color );
  429. meshBuilder.Position3f(pStartVerts[i].x, pStartVerts[i].y, pStartVerts[i].z);
  430. meshBuilder.AdvanceVertex();
  431. meshBuilder.Color3ubv( color );
  432. meshBuilder.Position3f(pStartVerts[j].x, pStartVerts[j].y, pStartVerts[j].z);
  433. meshBuilder.AdvanceVertex();
  434. meshBuilder.Color3ubv( color );
  435. meshBuilder.Position3f(pEndVerts[i].x, pEndVerts[i].y, pEndVerts[i].z);
  436. meshBuilder.AdvanceVertex();
  437. meshBuilder.Color3ubv( color );
  438. meshBuilder.Position3f(pEndVerts[j].x, pEndVerts[j].y, pEndVerts[j].z);
  439. meshBuilder.AdvanceVertex();
  440. meshBuilder.Color3ubv( color );
  441. meshBuilder.Position3f(pStartVerts[i].x, pStartVerts[i].y, pStartVerts[i].z);
  442. meshBuilder.AdvanceVertex();
  443. meshBuilder.Color3ubv( color );
  444. meshBuilder.Position3f(pEndVerts[i].x, pEndVerts[i].y, pEndVerts[i].z);
  445. meshBuilder.AdvanceVertex();
  446. }
  447. meshBuilder.End();
  448. }
  449. else
  450. {
  451. meshBuilder.Begin( pMesh, MATERIAL_LINES, 1 );
  452. meshBuilder.Color3ubv( color );
  453. meshBuilder.Position3f(Start.x, Start.y, Start.z);
  454. meshBuilder.AdvanceVertex();
  455. meshBuilder.Color3ubv( color );
  456. meshBuilder.Position3f(End.x, End.y, End.z);
  457. meshBuilder.AdvanceVertex();
  458. meshBuilder.End();
  459. }
  460. pMesh->Draw();
  461. pRender->PopRenderMode();
  462. pRender->EndRenderHitTarget();
  463. }
  464. //-----------------------------------------------------------------------------
  465. // Purpose:
  466. // Input : File -
  467. // bRMF -
  468. // Output : int
  469. //-----------------------------------------------------------------------------
  470. int CMapCylinder::SerializeRMF(std::fstream &File, BOOL bRMF)
  471. {
  472. return(0);
  473. }
  474. //-----------------------------------------------------------------------------
  475. // Purpose:
  476. // Input : File -
  477. // bRMF -
  478. // Output : int
  479. //-----------------------------------------------------------------------------
  480. int CMapCylinder::SerializeMAP(std::fstream &File, BOOL bRMF)
  481. {
  482. return(0);
  483. }
  484. //-----------------------------------------------------------------------------
  485. // Purpose:
  486. // Input : pTransBox -
  487. //-----------------------------------------------------------------------------
  488. void CMapCylinder::DoTransform(const VMatrix &matrix)
  489. {
  490. CMapClass::DoTransform(matrix);
  491. BuildCylinder();
  492. }
  493. //-----------------------------------------------------------------------------
  494. // Purpose: Updates the cached pointers to our start and end entities by looking
  495. // for them in the given world.
  496. // Input : pWorld - World to search.
  497. //-----------------------------------------------------------------------------
  498. void CMapCylinder::UpdateDependencies(CMapWorld *pWorld, CMapClass *pObject)
  499. {
  500. CMapClass::UpdateDependencies(pWorld, pObject);
  501. if (pWorld == NULL)
  502. {
  503. return;
  504. }
  505. CMapEntity *pEntity = dynamic_cast <CMapEntity *> (m_pParent);
  506. Assert(pEntity != NULL);
  507. if (pEntity != NULL)
  508. {
  509. const char *pszValue = pEntity->GetKeyValue(m_szStartValueKey);
  510. m_pStartEntity = (CMapEntity *)UpdateDependency(m_pStartEntity, pWorld->FindChildByKeyValue(m_szStartKey, pszValue));
  511. if (m_szEndValueKey[0] != '\0')
  512. {
  513. pszValue = pEntity->GetKeyValue(m_szEndValueKey);
  514. m_pEndEntity = (CMapEntity *)UpdateDependency(m_pEndEntity, pWorld->FindChildByKeyValue(m_szEndKey, pszValue));
  515. }
  516. else
  517. {
  518. // We don't have an end entity specified, use our parent as the end point.
  519. m_pEndEntity = (CMapEntity *)UpdateDependency(m_pEndEntity, GetParent());
  520. }
  521. if (pObject == m_pStartEntity)
  522. {
  523. m_flStartRadius = 0.0f;
  524. if ( m_pStartEntity && m_szStartRadiusKey[0] != '\0' )
  525. {
  526. const char *pRadiusKey = m_pStartEntity->GetKeyValue( m_szStartRadiusKey );
  527. m_flStartRadius = pRadiusKey ? atof( pRadiusKey ) : 0.0f;
  528. }
  529. }
  530. if (pObject == m_pEndEntity)
  531. {
  532. m_flEndRadius = 0.0f;
  533. if ( m_pEndEntity && m_szEndRadiusKey[0] != '\0' )
  534. {
  535. const char *pRadiusKey = m_pEndEntity->GetKeyValue( m_szEndRadiusKey );
  536. m_flEndRadius = pRadiusKey ? atof( pRadiusKey ) : 0.0f;
  537. }
  538. }
  539. BuildCylinder();
  540. }
  541. }
  542. //-----------------------------------------------------------------------------
  543. // Purpose: Never select anything because of this helper.
  544. //-----------------------------------------------------------------------------
  545. CMapClass *CMapCylinder::PrepareSelection(SelectMode_t eSelectMode)
  546. {
  547. return NULL;
  548. }