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.

1900 lines
53 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "stdafx.h"
  7. #include "ChunkFile.h"
  8. #include "SaveInfo.h"
  9. #include "MapClass.h"
  10. #include "MapEntity.h" // dvs: evil - base knows about the derived class
  11. #include "MapGroup.h" // dvs: evil - base knows about the derived class
  12. #include "MapInstance.h" // dvs: evil - base knows about the derived class
  13. #include "MapWorld.h" // dvs: evil - base knows about the derived class
  14. #include "GlobalFunctions.h"
  15. #include "MapDoc.h"
  16. #include "VisGroup.h"
  17. #include "mapdefs.h"
  18. #include "tier0/minidump.h"
  19. int CMapAtom::s_nObjectIDCtr = 1;
  20. int CMapClass::sm_nDropTraceMarker = 0;
  21. static CUtlVector<MCMSTRUCT> s_Classes;
  22. // memdbgon must be the last include file in a .cpp file!!!
  23. #include <tier0/memdbgon.h>
  24. bool CMapClass::s_bLoadingVMF = false;
  25. //-----------------------------------------------------------------------------
  26. // Purpose:
  27. // Input : Type -
  28. // pfnNew -
  29. //-----------------------------------------------------------------------------
  30. CMapClassManager::CMapClassManager(MAPCLASSTYPE Type, CMapClass *(*pfnNew)())
  31. {
  32. MCMSTRUCT mcms;
  33. mcms.Type = Type;
  34. mcms.pfnNew = pfnNew;
  35. s_Classes.AddToTail(mcms);
  36. }
  37. //-----------------------------------------------------------------------------
  38. // Purpose:
  39. //-----------------------------------------------------------------------------
  40. CMapClassManager::~CMapClassManager(void)
  41. {
  42. s_Classes.RemoveAll();
  43. }
  44. //-----------------------------------------------------------------------------
  45. // Purpose:
  46. // Input : Type -
  47. // Output : CMapClass
  48. //-----------------------------------------------------------------------------
  49. CMapClass *CMapClassManager::CreateObject(MAPCLASSTYPE Type)
  50. {
  51. unsigned uLen = strlen(Type)+1;
  52. for (int i = s_Classes.Count() - 1; i >= 0; i--)
  53. {
  54. MCMSTRUCT &mcms = s_Classes[i];
  55. if (!memcmp(mcms.Type, Type, uLen))
  56. {
  57. return (*mcms.pfnNew)();
  58. }
  59. }
  60. Assert(FALSE);
  61. return(NULL);
  62. }
  63. //-----------------------------------------------------------------------------
  64. // Purpose: Constructor. Initializes data members.
  65. //-----------------------------------------------------------------------------
  66. CMapClass::CMapClass(void)
  67. {
  68. //
  69. // The document manages the unique object IDs. Eventually all object construction
  70. // should be done through the document, eliminating the need for CMapClass to know
  71. // about CMapDoc.
  72. //
  73. CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
  74. if (pDoc != NULL)
  75. {
  76. m_nID = pDoc->GetNextMapObjectID();
  77. }
  78. else
  79. {
  80. m_nID = 0;
  81. }
  82. // PORTAL2 SHIP: keep track of load order to preserve it on save so that maps can be diffed.
  83. m_nLoadID = 0;
  84. dwKept = 0;
  85. m_bTemporary = FALSE;
  86. m_bVisible = true;
  87. m_bVisible2D = true;
  88. m_bVisGroupShown = true;
  89. m_bVisGroupAutoShown = true;
  90. m_pColorVisGroup = NULL;
  91. r = g = b = 220;
  92. m_pParent = NULL;
  93. m_nRenderFrame = 0;
  94. m_pEditorKeys = NULL;
  95. m_Dependents.RemoveAll();
  96. m_nDropTraceMarker = 0;
  97. }
  98. //-----------------------------------------------------------------------------
  99. // Purpose: Destructor. Deletes all children.
  100. //-----------------------------------------------------------------------------
  101. CMapClass::~CMapClass(void)
  102. {
  103. // Delete all of our children.
  104. m_Children.RemoveAll();
  105. delete m_pEditorKeys;
  106. }
  107. //-----------------------------------------------------------------------------
  108. // Purpose:
  109. // Input : pDependent -
  110. //-----------------------------------------------------------------------------
  111. void CMapClass::AddDependent(CMapClass *pDependent)
  112. {
  113. Assert( pDependent != NULL );
  114. if ( !pDependent )
  115. return;
  116. //
  117. // Never add ourselves to our dependents. It creates a circular dependency
  118. // which is bad.
  119. //
  120. if (pDependent == this)
  121. return;
  122. //
  123. // Don't add the same dependent twice.
  124. //
  125. int nIndex = m_Dependents.Find(pDependent);
  126. if (nIndex != -1)
  127. return;
  128. //
  129. // Also, never add one of our ancestors as a dependent. This too creates a
  130. // nasty circular dependency.
  131. //
  132. bool bIsOurAncestor = false;
  133. CMapClass *pTestParent = GetParent();
  134. while (pTestParent != NULL)
  135. {
  136. if (pTestParent == pDependent)
  137. {
  138. bIsOurAncestor = true;
  139. break;
  140. }
  141. pTestParent = pTestParent->GetParent();
  142. }
  143. if (!bIsOurAncestor)
  144. {
  145. m_Dependents.AddToTail(pDependent);
  146. Assert(m_Dependents.Count() < 1000);
  147. }
  148. }
  149. //-----------------------------------------------------------------------------
  150. // Purpose: Returns a copy of this object. We should never call this implementation
  151. // since CMapClass cannot be instantiated.
  152. // Input : bUpdateDependencies - Whether to update object dependencies when copying object pointers.
  153. //-----------------------------------------------------------------------------
  154. CMapClass *CMapClass::Copy(bool bUpdateDependencies)
  155. {
  156. Assert(FALSE);
  157. return(NULL);
  158. }
  159. //-----------------------------------------------------------------------------
  160. // Purpose: Turns this object into a duplicate of the given object.
  161. // Input : pFrom - The object to replicate.
  162. // Output : Returns a pointer to this object.
  163. //-----------------------------------------------------------------------------
  164. CMapClass *CMapClass::CopyFrom(CMapClass *pFrom, bool bUpdateDependencies)
  165. {
  166. // Copy CMapPoint stuff. dvs: should be in CMapPoint implementation!
  167. m_Origin = pFrom->m_Origin;
  168. //
  169. // Copy CMapClass stuff.
  170. //
  171. int nVisGroupCount = pFrom->GetVisGroupCount();
  172. for (int nVisGroup = 0; nVisGroup < nVisGroupCount; nVisGroup++)
  173. {
  174. CVisGroup *pVisGroup = pFrom->GetVisGroup(nVisGroup);
  175. if (!pVisGroup->IsAutoVisGroup())
  176. {
  177. AddVisGroup(pVisGroup);
  178. }
  179. }
  180. //m_bVisible = pFrom->m_bVisible;
  181. //m_bVisGroupShown = pFrom->m_bVisGroupShown;
  182. m_bTemporary = pFrom->m_bTemporary;
  183. m_bVisible2D = pFrom->m_bVisible2D;
  184. m_nRenderFrame = pFrom->m_nRenderFrame;
  185. m_CullBox = pFrom->m_CullBox;
  186. m_BoundingBox = pFrom->m_BoundingBox;
  187. m_Render2DBox = pFrom->m_Render2DBox;
  188. r = pFrom->r;
  189. g = pFrom->g;
  190. b = pFrom->b;
  191. m_Dependents.RemoveAll();
  192. m_Dependents.AddVectorToTail(pFrom->m_Dependents);
  193. // dvs: should I copy m_pEditorKeys?
  194. //
  195. // Don't link to the parent if we're not updating dependencies, just copy the pointer.
  196. //
  197. if (bUpdateDependencies)
  198. {
  199. UpdateParent( pFrom->GetParent() );
  200. }
  201. else
  202. {
  203. m_pParent = pFrom->GetParent();
  204. }
  205. return(this);
  206. }
  207. //-----------------------------------------------------------------------------
  208. // Purpose: Returns the culling bbox of this object.
  209. // Input : mins - receives the minima for culling
  210. // maxs - receives the maxima for culling.
  211. //-----------------------------------------------------------------------------
  212. void CMapClass::GetCullBox(Vector &mins, Vector &maxs) const
  213. {
  214. m_CullBox.GetBounds(mins, maxs);
  215. }
  216. //-----------------------------------------------------------------------------
  217. // Purpose: Initialize the cull box with the bounds of the faces.
  218. //-----------------------------------------------------------------------------
  219. void CMapClass::SetCullBoxFromFaceList( CMapFaceList *pFaces )
  220. {
  221. SetBoxFromFaceList( pFaces, m_CullBox );
  222. }
  223. //-----------------------------------------------------------------------------
  224. // Purpose: Returns the bounding bbox of this object.
  225. // Input : mins - receives the minima for culling
  226. // maxs - receives the maxima for culling.
  227. //-----------------------------------------------------------------------------
  228. void CMapClass::GetBoundingBox( Vector &mins, Vector &maxs )
  229. {
  230. m_BoundingBox.GetBounds( mins, maxs );
  231. }
  232. //-----------------------------------------------------------------------------
  233. // Purpose: Initialize the bounding box with the bounds of the faces.
  234. //-----------------------------------------------------------------------------
  235. void CMapClass::SetBoundingBoxFromFaceList( CMapFaceList *pFaces )
  236. {
  237. SetBoxFromFaceList( pFaces, m_BoundingBox );
  238. }
  239. //-----------------------------------------------------------------------------
  240. // Purpose: Initialize box with the bounds of the faces.
  241. //-----------------------------------------------------------------------------
  242. void CMapClass::SetBoxFromFaceList( CMapFaceList *pFaces, BoundBox &Box )
  243. {
  244. //
  245. // Calculate our 3D bounds.
  246. //
  247. Box.ResetBounds();
  248. for (int i = 0; i < pFaces->Count(); i++)
  249. {
  250. CMapFace *pFace = pFaces->Element(i);
  251. int nPoints = pFace->GetPointCount();
  252. for (int i = 0; i < nPoints; i++)
  253. {
  254. Vector point;
  255. pFace->GetPoint(point, i);
  256. //
  257. // Push the culling box out in all directions.
  258. // TODO: rotate the culling box based on the cone orientation
  259. //
  260. for (int nDim = 0; nDim < 3; nDim++)
  261. {
  262. Box.bmins[0] = min(Box.bmins[0], m_Origin[0] - point[nDim]);
  263. Box.bmins[1] = min(Box.bmins[1], m_Origin[1] - point[nDim]);
  264. Box.bmins[2] = min(Box.bmins[2], m_Origin[2] - point[nDim]);
  265. Box.bmaxs[0] = max(Box.bmaxs[0], m_Origin[0] + point[nDim]);
  266. Box.bmaxs[1] = max(Box.bmaxs[1], m_Origin[1] + point[nDim]);
  267. Box.bmaxs[2] = max(Box.bmaxs[2], m_Origin[2] + point[nDim]);
  268. }
  269. }
  270. }
  271. }
  272. //-----------------------------------------------------------------------------
  273. // Purpose: Returns the bbox for 2D rendering of this object.
  274. // FIXME: this can be removed if we do all our 2D rendering in this->Render2D.
  275. // Input : mins - receives the minima for culling
  276. // maxs - receives the maxima for culling.
  277. //-----------------------------------------------------------------------------
  278. void CMapClass::GetRender2DBox(Vector &mins, Vector &maxs)
  279. {
  280. m_Render2DBox.GetBounds(mins, maxs);
  281. }
  282. //-----------------------------------------------------------------------------
  283. // Purpose: Returns the number of keys that were loaded from the "editor"
  284. // section of the VMF. These keys are held until they are handled, then
  285. // the memory is freed.
  286. //-----------------------------------------------------------------------------
  287. int CMapClass::GetEditorKeyCount(void)
  288. {
  289. if (m_pEditorKeys == NULL)
  290. {
  291. return NULL;
  292. }
  293. return m_pEditorKeys->GetCount();
  294. }
  295. //-----------------------------------------------------------------------------
  296. // Purpose: Returns the key name for the given editor key index.
  297. //-----------------------------------------------------------------------------
  298. const char *CMapClass::GetEditorKey(int nIndex)
  299. {
  300. if (m_pEditorKeys == NULL)
  301. {
  302. return NULL;
  303. }
  304. return m_pEditorKeys->GetKey(nIndex);
  305. }
  306. //-----------------------------------------------------------------------------
  307. // Purpose: Returns the value for the given editor key index.
  308. //-----------------------------------------------------------------------------
  309. const char *CMapClass::GetEditorKeyValue(int nIndex)
  310. {
  311. if (m_pEditorKeys == NULL)
  312. {
  313. return NULL;
  314. }
  315. return m_pEditorKeys->GetValue(nIndex);
  316. }
  317. //-----------------------------------------------------------------------------
  318. // Purpose: Returns the value for the given editor key name.
  319. // NOTE: this is used for unique keys and will return the value for the
  320. // FIRST key with the given name.
  321. //-----------------------------------------------------------------------------
  322. const char *CMapClass::GetEditorKeyValue(const char *szKey)
  323. {
  324. if (m_pEditorKeys == NULL)
  325. {
  326. return NULL;
  327. }
  328. return m_pEditorKeys->GetValue(szKey);
  329. }
  330. //-----------------------------------------------------------------------------
  331. // Purpose: Begins a depth-first search of the map heirarchy.
  332. // Input : pos - An iterator
  333. // Output : CMapClass
  334. //-----------------------------------------------------------------------------
  335. CMapClass *CMapClass::GetFirstDescendent(EnumChildrenPos_t &pos)
  336. {
  337. pos.nDepth = 0;
  338. pos.Stack[0].pParent = this;
  339. if ( m_Children.Count() )
  340. {
  341. pos.Stack[0].pos = 0;
  342. return(GetNextDescendent(pos));
  343. }
  344. else
  345. {
  346. pos.Stack[0].pos = -1;
  347. return NULL;
  348. }
  349. }
  350. //-----------------------------------------------------------------------------
  351. // Purpose: Continues a depth-first search of the map heirarchy.
  352. // Input : &pos -
  353. // Output : CMapClass
  354. //-----------------------------------------------------------------------------
  355. CMapClass *CMapClass::GetNextDescendent(EnumChildrenPos_t &pos)
  356. {
  357. while (pos.nDepth >= 0)
  358. {
  359. while (pos.Stack[pos.nDepth].pos != -1)
  360. {
  361. //
  362. // Get the next child of the parent on top of the stack.
  363. //
  364. CMapClass *pParent = pos.Stack[pos.nDepth].pParent;
  365. CMapClass *pChild = pParent->m_Children[pos.Stack[pos.nDepth].pos];
  366. pos.Stack[pos.nDepth].pos++;
  367. if ( pos.Stack[pos.nDepth].pos == pParent->m_Children.Count() )
  368. pos.Stack[pos.nDepth].pos= -1;
  369. // If this object has children, push it onto the stack.
  370. if ( pChild && pChild->m_Children.Count() )
  371. {
  372. pos.nDepth++;
  373. if (pos.nDepth < MAX_ENUM_CHILD_DEPTH)
  374. {
  375. pos.Stack[pos.nDepth].pParent = pChild;
  376. pos.Stack[pos.nDepth].pos = 0;
  377. }
  378. else
  379. {
  380. // dvs: stack overflow!
  381. pos.nDepth--;
  382. }
  383. }
  384. //
  385. // If this object has no children, return it.
  386. //
  387. else
  388. {
  389. return(pChild);
  390. }
  391. }
  392. //
  393. // Finished with this object's children, pop the stack and return the object.
  394. //
  395. pos.nDepth--;
  396. if (pos.nDepth >= 0)
  397. {
  398. return(pos.Stack[pos.nDepth + 1].pParent);
  399. }
  400. }
  401. return(NULL);
  402. }
  403. //-----------------------------------------------------------------------------
  404. // Purpose: Returns the world object that the given object belongs to.
  405. // Input : pStart - Object to traverse up from to find the world object.
  406. //-----------------------------------------------------------------------------
  407. CMapWorld *CMapClass::GetWorldObject(CMapAtom *pStart)
  408. {
  409. CMapAtom *pObject = pStart;
  410. while (pObject != NULL)
  411. {
  412. if ( IsWorldObject( pObject ) )
  413. {
  414. return (CMapWorld*)pObject;
  415. }
  416. pObject = pObject->GetParent();
  417. }
  418. // has no world:
  419. return NULL;
  420. }
  421. BOOL CMapClass::IsChildOf(CMapAtom *pObject)
  422. {
  423. CMapAtom *pParent = m_pParent;
  424. while( pParent )
  425. {
  426. if( pParent == pObject )
  427. return TRUE;
  428. if( IsWorldObject(pParent) )
  429. return FALSE; // world object, not parent .. return false.
  430. pParent = pParent->GetParent();
  431. }
  432. return FALSE;
  433. }
  434. //-----------------------------------------------------------------------------
  435. // Purpose: Returns whether this object belongs to the given visgroup.
  436. // Input : pVisGroup -
  437. //-----------------------------------------------------------------------------
  438. int CMapClass::IsInVisGroup(CVisGroup *pVisGroup)
  439. {
  440. if (pVisGroup != NULL)
  441. {
  442. if ( m_VisGroups.Find( pVisGroup ) != -1 )
  443. {
  444. return 1;
  445. }
  446. else
  447. {
  448. return 0;
  449. }
  450. }
  451. return 0;
  452. }
  453. //-----------------------------------------------------------------------------
  454. // Purpose:
  455. // Output : Returns true if the color was specified by this call, false if not.
  456. //-----------------------------------------------------------------------------
  457. bool CMapClass::UpdateObjectColor(void)
  458. {
  459. //
  460. // The user can choose a visgroup from which to get the color from.
  461. // If one was chosen, set our color from that visgroup.
  462. //
  463. if (m_pColorVisGroup)
  464. {
  465. color32 rgbColor = m_pColorVisGroup->GetColor();
  466. SetRenderColor(rgbColor);
  467. return true;
  468. }
  469. else if (m_pParent && !IsWorldObject(m_pParent))
  470. {
  471. color32 rgbColor = m_pParent->GetRenderColor();
  472. SetRenderColor(rgbColor);
  473. return true;
  474. }
  475. return false;
  476. }
  477. //-----------------------------------------------------------------------------
  478. // Purpose: Sets the visgroup that this object gets its color from.
  479. //-----------------------------------------------------------------------------
  480. void CMapClass::SetColorVisGroup(CVisGroup *pVisGroup)
  481. {
  482. m_pColorVisGroup = pVisGroup;
  483. UpdateObjectColor();
  484. }
  485. //-----------------------------------------------------------------------------
  486. // Purpose: Adds the given visgroup to the list of visgroups that this object
  487. // belongs to.
  488. //-----------------------------------------------------------------------------
  489. void CMapClass::AddVisGroup(CVisGroup *pVisGroup)
  490. {
  491. if (m_VisGroups.Find(pVisGroup) == -1)
  492. {
  493. m_VisGroups.AddToTail(pVisGroup);
  494. }
  495. }
  496. //-----------------------------------------------------------------------------
  497. // Purpose: Removes the given visgroup from the list of visgroups that this object
  498. // belongs to.
  499. //-----------------------------------------------------------------------------
  500. void CMapClass::RemoveVisGroup(CVisGroup *pVisGroup)
  501. {
  502. int nIndex = m_VisGroups.Find(pVisGroup);
  503. if (nIndex != -1 )
  504. {
  505. m_VisGroups.FastRemove(nIndex);
  506. CheckVisibility();
  507. }
  508. }
  509. //-----------------------------------------------------------------------------
  510. // Purpose:
  511. //-----------------------------------------------------------------------------
  512. int CMapClass::GetVisGroupCount(void)
  513. {
  514. return m_VisGroups.Count();
  515. }
  516. //-----------------------------------------------------------------------------
  517. // Purpose:
  518. //-----------------------------------------------------------------------------
  519. CVisGroup *CMapClass::GetVisGroup(int nIndex)
  520. {
  521. return m_VisGroups.Element(nIndex);
  522. }
  523. //-----------------------------------------------------------------------------
  524. // Purpose:
  525. //-----------------------------------------------------------------------------
  526. void CMapClass::RemoveAllVisGroups(void)
  527. {
  528. m_VisGroups.RemoveAll();
  529. // Remove all visgroups from children as well.
  530. FOR_EACH_OBJ( m_Children, pos )
  531. {
  532. CMapClass *pChild = m_Children.Element(pos);
  533. pChild->RemoveAllVisGroups();
  534. }
  535. // Not in any visgroups; can't be hidden that way.
  536. VisGroupShow(true);
  537. }
  538. //-----------------------------------------------------------------------------
  539. // Purpose: Adds the specified child to this object.
  540. // Input : pChild - Object to add as a child of this object.
  541. //-----------------------------------------------------------------------------
  542. void CMapClass::AddChild(CMapClass *pChild)
  543. {
  544. if ( m_Children.Find(pChild) != -1 )
  545. {
  546. pChild->m_pParent = this;
  547. return;
  548. }
  549. m_Children.AddToTail(pChild);
  550. pChild->SetParent( this );
  551. //
  552. // Update our bounds with the child's bounds.
  553. //
  554. Vector vecMins;
  555. Vector vecMaxs;
  556. pChild->GetCullBox(vecMins, vecMaxs);
  557. m_CullBox.UpdateBounds(vecMins, vecMaxs);
  558. pChild->GetBoundingBox( vecMins, vecMaxs );
  559. m_BoundingBox.UpdateBounds( vecMins, vecMaxs );
  560. pChild->GetRender2DBox(vecMins, vecMaxs);
  561. m_Render2DBox.UpdateBounds(vecMins, vecMaxs);
  562. if (m_pParent != NULL)
  563. {
  564. GetParent()->UpdateChild(this);
  565. }
  566. }
  567. //-----------------------------------------------------------------------------
  568. // Purpose: Removes all of this object's children.
  569. //-----------------------------------------------------------------------------
  570. void CMapClass::RemoveAllChildren(void)
  571. {
  572. //
  573. // Detach the children from us. They are no longer in our world heirarchy.
  574. //
  575. FOR_EACH_OBJ( m_Children, pos )
  576. {
  577. m_Children[pos]->m_pParent = NULL;
  578. }
  579. //
  580. // Remove them from our list.
  581. //
  582. m_Children.RemoveAll();
  583. }
  584. //-----------------------------------------------------------------------------
  585. // Purpose: Removes the specified child from this object.
  586. // Input : pChild - The child to remove.
  587. // bUpdateBounds - TRUE to calculate new bounds, FALSE not to.
  588. //-----------------------------------------------------------------------------
  589. void CMapClass::RemoveChild(CMapClass *pChild, bool bUpdateBounds)
  590. {
  591. int index = m_Children.Find(pChild);
  592. if (index == -1)
  593. {
  594. pChild->m_pParent = NULL;
  595. return;
  596. }
  597. m_Children.FastRemove(index);
  598. pChild->m_pParent = NULL;
  599. if (bUpdateBounds)
  600. {
  601. PostUpdate(Notify_Removed);
  602. }
  603. }
  604. //-----------------------------------------------------------------------------
  605. // Purpose: Copies all children of a given object as children of this object.
  606. // NOTE: The child objects are replicated, not merely added as children.
  607. // Input : pobj - The object whose children are to be copied.
  608. //-----------------------------------------------------------------------------
  609. void CMapClass::CopyChildrenFrom(CMapClass *pobj, bool bUpdateDependencies)
  610. {
  611. FOR_EACH_OBJ( pobj->m_Children, pos )
  612. {
  613. CMapClass *pChild = pobj->m_Children.Element(pos);
  614. CMapClass *pChildCopy = pChild->Copy(bUpdateDependencies);
  615. pChildCopy->CopyChildrenFrom(pChild, bUpdateDependencies);
  616. AddChild(pChildCopy);
  617. }
  618. }
  619. //-----------------------------------------------------------------------------
  620. // Purpose: Recalculate's this object's bounding boxes. CMapClass-derived classes
  621. // should call this first, then update using their local data.
  622. // Input : bFullUpdate - When set to TRUE, call CalcBounds on all children
  623. // before updating our bounds.
  624. //-----------------------------------------------------------------------------
  625. void CMapClass::CalcBounds(BOOL bFullUpdate)
  626. {
  627. if ( CMapClass::s_bLoadingVMF )
  628. return;
  629. m_CullBox.ResetBounds();
  630. m_BoundingBox.ResetBounds();
  631. m_Render2DBox.ResetBounds();
  632. FOR_EACH_OBJ( m_Children, pos )
  633. {
  634. CMapClass *pChild = m_Children.Element(pos);
  635. if ( !pChild )
  636. {
  637. continue;
  638. }
  639. if (bFullUpdate)
  640. {
  641. pChild->CalcBounds(TRUE);
  642. }
  643. m_CullBox.UpdateBounds(&pChild->m_CullBox);
  644. m_BoundingBox.UpdateBounds(&pChild->m_BoundingBox);
  645. m_Render2DBox.UpdateBounds(&pChild->m_Render2DBox);
  646. }
  647. }
  648. //-----------------------------------------------------------------------------
  649. // Purpose: Sets the render color of this object and all its children.
  650. // Input : uchRed, uchGreen, uchBlue - Color components.
  651. //-----------------------------------------------------------------------------
  652. void CMapClass::SetRenderColor(color32 rgbColor)
  653. {
  654. CMapAtom::SetRenderColor(rgbColor);
  655. //
  656. // Set the render color of all our children.
  657. //
  658. FOR_EACH_OBJ( m_Children, pos )
  659. {
  660. CMapClass *pChild = m_Children.Element(pos);
  661. if (pChild != NULL)
  662. {
  663. pChild->SetRenderColor(rgbColor);
  664. }
  665. }
  666. }
  667. //-----------------------------------------------------------------------------
  668. // Purpose: Sets the render color of this object and all its children.
  669. // Input : uchRed, uchGreen, uchBlue - Color components.
  670. //-----------------------------------------------------------------------------
  671. void CMapClass::SetRenderColor(unsigned char uchRed, unsigned char uchGreen, unsigned char uchBlue)
  672. {
  673. CMapAtom::SetRenderColor(uchRed, uchGreen, uchBlue);
  674. //
  675. // Set the render color of all our children.
  676. //
  677. FOR_EACH_OBJ( m_Children, pos )
  678. {
  679. CMapClass *pChild = m_Children.Element(pos);
  680. if (pChild != NULL)
  681. {
  682. pChild->SetRenderColor(uchRed, uchGreen, uchBlue);
  683. }
  684. }
  685. }
  686. //-----------------------------------------------------------------------------
  687. // Purpose: Returns a pointer to the object that should be added to the selection
  688. // list because this object was clicked on with a given selection mode.
  689. // Input : eSelectMode -
  690. //-----------------------------------------------------------------------------
  691. CMapClass *CMapClass::PrepareSelection(SelectMode_t eSelectMode)
  692. {
  693. if ((eSelectMode == selectGroups) && (m_pParent != NULL) && !IsWorldObject(m_pParent))
  694. {
  695. return GetParent()->PrepareSelection(eSelectMode);
  696. }
  697. return this;
  698. }
  699. //-----------------------------------------------------------------------------
  700. // Purpose: Calls an enumerating function for each of our children that are of
  701. // of a given type, recursively enumerating their children also.
  702. // Input : pfn - Enumeration callback function. Called once per child.
  703. // dwParam - User data to pass into the enumerating callback.
  704. // Type - Unless NULL, only objects of the given type will be enumerated.
  705. // Output : Returns FALSE if the enumeration was terminated early, TRUE if it completed.
  706. //-----------------------------------------------------------------------------
  707. BOOL CMapClass::EnumChildren(ENUMMAPCHILDRENPROC pfn, unsigned int dwParam, MAPCLASSTYPE Type)
  708. {
  709. FOR_EACH_OBJ( m_Children, pos )
  710. {
  711. CMapClass *pChild = m_Children.Element(pos);
  712. if ( !pChild )
  713. continue;
  714. if (!Type || pChild->IsMapClass(Type))
  715. {
  716. if(!(*pfn)(pChild, dwParam))
  717. {
  718. return FALSE;
  719. }
  720. }
  721. // enum this child's children
  722. if (!pChild->EnumChildren(pfn, dwParam, Type))
  723. {
  724. return FALSE;
  725. }
  726. }
  727. return TRUE;
  728. }
  729. //-----------------------------------------------------------------------------
  730. // Purpose: Calls an enumerating function for each of our children that are of
  731. // of a given type, recursively enumerating their children also.
  732. // Input : pfn - Enumeration callback function. Called once per child.
  733. // dwParam - User data to pass into the enumerating callback.
  734. // Type - Unless NULL, only objects of the given type will be enumerated.
  735. // Output : Returns FALSE if the enumeration was terminated early, TRUE if it completed.
  736. //-----------------------------------------------------------------------------
  737. BOOL CMapClass::EnumChildrenAndInstances( ENUMMAPCHILDRENPROC pfn, unsigned int dwParam, MAPCLASSTYPE Type )
  738. {
  739. FOR_EACH_OBJ( m_Children, pos )
  740. {
  741. CMapClass *pChild = m_Children.Element(pos);
  742. if (!Type || pChild->IsMapClass(Type))
  743. {
  744. if (!(*pfn)(pChild, dwParam))
  745. {
  746. return FALSE;
  747. }
  748. }
  749. // enum this child's children
  750. if (!pChild->EnumChildren(pfn, dwParam, Type))
  751. {
  752. return FALSE;
  753. }
  754. //
  755. // If this is an instance, enumerate the stuff inside it also.
  756. //
  757. if ( pChild->IsMapClass( MAPCLASS_TYPE( CMapEntity ) ) )
  758. {
  759. CMapEntity *pEntity = (CMapEntity *)pChild;
  760. const char *pszClassName = pEntity->GetClassName();
  761. if ( pszClassName && !stricmp( pszClassName, "func_instance" ) )
  762. {
  763. CMapInstance *pMapInstance = pEntity->GetChildOfType( ( CMapInstance * )NULL );
  764. if ( pMapInstance )
  765. {
  766. CMapDoc *pMapDoc = pMapInstance->GetInstancedMap();
  767. if ( pMapDoc )
  768. {
  769. CMapWorld *pWorld = pMapDoc->GetMapWorld();
  770. if ( !pWorld->EnumChildren( pfn, dwParam, Type ) )
  771. return FALSE;
  772. }
  773. }
  774. }
  775. }
  776. }
  777. return TRUE;
  778. }
  779. //-----------------------------------------------------------------------------
  780. // Purpose: Enumerates a this object's children, only recursing into groups.
  781. // Children of entities will not be enumerated.
  782. // Input : pfn - Enumeration callback function. Called once per child.
  783. // dwParam - User data to pass into the enumerating callback.
  784. // Type - Unless NULL, only objects of the given type will be enumerated.
  785. // Output : Returns FALSE if the enumeration was terminated early, TRUE if it completed.
  786. //-----------------------------------------------------------------------------
  787. BOOL CMapClass::EnumChildrenRecurseGroupsOnly(ENUMMAPCHILDRENPROC pfn, unsigned int dwParam, MAPCLASSTYPE Type)
  788. {
  789. FOR_EACH_OBJ( m_Children, pos )
  790. {
  791. CMapClass *pChild = m_Children.Element(pos);
  792. if (!Type || pChild->IsMapClass(Type))
  793. {
  794. if (!(*pfn)(pChild, dwParam))
  795. {
  796. return FALSE;
  797. }
  798. }
  799. if (pChild->IsGroup())
  800. {
  801. if (!pChild->EnumChildrenRecurseGroupsOnly(pfn, dwParam, Type))
  802. {
  803. return FALSE;
  804. }
  805. }
  806. }
  807. return TRUE;
  808. }
  809. //-----------------------------------------------------------------------------
  810. // Purpose: Iterates through an object, and all it's children, looking for an
  811. // entity with a matching key and value
  812. // Input : key -
  813. // value -
  814. // Output : CMapEntity - the entity found
  815. //-----------------------------------------------------------------------------
  816. CMapEntity *CMapClass::FindChildByKeyValue( const char* key, const char* value, bool *bIsInInstance, VMatrix *InstanceMatrix )
  817. {
  818. if ( !key || !value )
  819. return NULL;
  820. FOR_EACH_OBJ( m_Children, pos )
  821. {
  822. CMapClass *pChild = m_Children.Element( pos );
  823. if ( !pChild )
  824. {
  825. continue;
  826. }
  827. CMapEntity *e = pChild->FindChildByKeyValue( key, value, bIsInInstance, InstanceMatrix );
  828. if ( e )
  829. return e;
  830. }
  831. return NULL;
  832. }
  833. //-----------------------------------------------------------------------------
  834. // Purpose: Called after this object is added to the world.
  835. //
  836. // NOTE: This function is NOT called during serialization. Use PostloadWorld
  837. // to do similar bookkeeping after map load.
  838. //
  839. // Input : pWorld - The world that we have been added to.
  840. //-----------------------------------------------------------------------------
  841. void CMapClass::OnAddToWorld(CMapWorld *pWorld)
  842. {
  843. //
  844. // Notify all our children.
  845. //
  846. FOR_EACH_OBJ( m_Children, pos )
  847. {
  848. CMapClass *pChild = m_Children.Element(pos);
  849. pChild->OnAddToWorld(pWorld);
  850. }
  851. }
  852. //-----------------------------------------------------------------------------
  853. // Purpose: Called to notify the object that it has just been cloned
  854. // iterates through and notifies all the children of their cloned state
  855. // NOTE: assumes that the children are in the same order in both the
  856. // original and the clone
  857. // Input : pNewObj - the clone of this object
  858. // OriginalList - The list of objects that were cloned
  859. // NewList - The parallel list of clones of objects in OriginalList
  860. //-----------------------------------------------------------------------------
  861. void CMapClass::OnClone( CMapClass *pNewObj, CMapWorld *pWorld, const CMapObjectList &OriginalList, CMapObjectList &NewList )
  862. {
  863. Assert( m_Children.Count() == pNewObj->m_Children.Count() );
  864. FOR_EACH_OBJ( m_Children, pos )
  865. {
  866. CMapClass *pChild = m_Children.Element( pos );
  867. CMapClass *pNewChild = pNewObj->m_Children.Element( pos );
  868. pChild->OnClone( pNewChild, pWorld, OriginalList, NewList );
  869. }
  870. }
  871. //-----------------------------------------------------------------------------
  872. // Purpose: Called to notify the object that it has just been cloned
  873. // iterates through and notifies all the children of their cloned state
  874. // NOTE: assumes that the children are in the same order in both the
  875. // original and the clone
  876. // Input : pNewObj - the clone of this object
  877. // OriginalList - The list of objects that were cloned
  878. // NewList - The parallel list of clones of objects in OriginalList
  879. //-----------------------------------------------------------------------------
  880. void CMapClass::OnPreClone( CMapClass *pNewObj, CMapWorld *pWorld, const CMapObjectList &OriginalList, CMapObjectList &NewList )
  881. {
  882. Assert( m_Children.Count() == pNewObj->m_Children.Count() );
  883. FOR_EACH_OBJ( m_Children, pos )
  884. {
  885. CMapClass *pChild = m_Children.Element( pos );
  886. CMapClass *pNewChild = pNewObj->m_Children.Element( pos );
  887. pChild->OnPreClone( pNewChild, pWorld, OriginalList, NewList );
  888. }
  889. }
  890. //-----------------------------------------------------------------------------
  891. // Purpose: Notifies this object that a copy of itself is about to be pasted.
  892. // Allows the object to generate new unique IDs in the copy of itself.
  893. // Input : pCopy -
  894. // pSourceWorld -
  895. // pDestWorld -
  896. // OriginalList -
  897. // NewList -
  898. //-----------------------------------------------------------------------------
  899. void CMapClass::OnPrePaste(CMapClass *pCopy, CMapWorld *pSourceWorld, CMapWorld *pDestWorld, const CMapObjectList &OriginalList, CMapObjectList &NewList)
  900. {
  901. Assert( m_Children.Count() == pCopy->m_Children.Count() );
  902. FOR_EACH_OBJ( m_Children, pos )
  903. {
  904. CMapClass *pChild = m_Children.Element(pos);
  905. CMapClass *pCopyChild = pCopy->m_Children.Element(pos);
  906. pChild->OnPrePaste(pCopyChild, pSourceWorld, pDestWorld, OriginalList, NewList);
  907. }
  908. }
  909. //-----------------------------------------------------------------------------
  910. // Purpose: Notifies this object that a copy of itself is being pasted.
  911. // Allows the object to fixup any references to other objects in the
  912. // clipboard with references to their copies.
  913. // Input : pCopy -
  914. // pSourceWorld -
  915. // pDestWorld -
  916. // OriginalList -
  917. // NewList -
  918. //-----------------------------------------------------------------------------
  919. void CMapClass::OnPaste(CMapClass *pCopy, CMapWorld *pSourceWorld, CMapWorld *pDestWorld, const CMapObjectList &OriginalList, CMapObjectList &NewList)
  920. {
  921. Assert( m_Children.Count() == pCopy->m_Children.Count() );
  922. FOR_EACH_OBJ( m_Children, pos )
  923. {
  924. CMapClass *pChild = m_Children.Element(pos);
  925. CMapClass *pCopyChild = pCopy->m_Children.Element(pos);
  926. pChild->OnPaste(pCopyChild, pSourceWorld, pDestWorld, OriginalList, NewList);
  927. }
  928. }
  929. //-----------------------------------------------------------------------------
  930. // Purpose: Called just after this object has been removed from the world so
  931. // that it can unlink itself from other objects in the world.
  932. // Input : pWorld - The world that we were just removed from.
  933. // bNotifyChildren - Whether we should forward notification to our children.
  934. //-----------------------------------------------------------------------------
  935. void CMapClass::OnRemoveFromWorld(CMapWorld *pWorld, bool bNotifyChildren)
  936. {
  937. //
  938. // Since we are being removed from the world, we cannot have any dependents.
  939. // Notify any dependent objects, so they can release pointers to us.
  940. // Our dependencies will be regenerated if we are added back into the world.
  941. //
  942. NotifyDependents(Notify_Removed);
  943. m_Dependents.RemoveAll();
  944. if (bNotifyChildren)
  945. {
  946. FOR_EACH_OBJ( m_Children, pos )
  947. {
  948. CMapClass *pChild = m_Children.Element(pos);
  949. pChild->OnRemoveFromWorld(pWorld, true);
  950. }
  951. }
  952. }
  953. //-----------------------------------------------------------------------------
  954. // Purpose: Called after a map file has been completely loaded.
  955. // Input : pWorld - The world that we are in.
  956. //-----------------------------------------------------------------------------
  957. void CMapClass::PostloadWorld(CMapWorld *pWorld)
  958. {
  959. FOR_EACH_OBJ( m_Children, pos )
  960. {
  961. CMapClass *pChild = m_Children.Element(pos);
  962. pChild->PostloadWorld(pWorld);
  963. }
  964. }
  965. //-----------------------------------------------------------------------------
  966. // Purpose: Called after all visgroups have been completely loaded. Checks for
  967. // objects hidden but without a visgroup.
  968. // Input : void
  969. //-----------------------------------------------------------------------------
  970. bool CMapClass::PostloadVisGroups( bool bLoading )
  971. {
  972. FOR_EACH_OBJ( m_Children, pos )
  973. {
  974. CMapClass *pChild = m_Children.Element(pos);
  975. pChild->PostloadVisGroups( bLoading);
  976. }
  977. return CheckVisibility( bLoading );
  978. }
  979. //-----------------------------------------------------------------------------
  980. // Purpose: Calls RenderPreload for each of our children. This allows them to
  981. // cache any resources that they need for rendering.
  982. // Input : pRender - Pointer to the 3D renderer.
  983. //-----------------------------------------------------------------------------
  984. bool CMapClass::RenderPreload(CRender3D *pRender, bool bNewContext)
  985. {
  986. FOR_EACH_OBJ( m_Children, pos )
  987. {
  988. CMapClass *pChild = m_Children.Element(pos);
  989. pChild->RenderPreload(pRender, bNewContext);
  990. }
  991. return(true);
  992. }
  993. //-----------------------------------------------------------------------------
  994. // Purpose:
  995. // Input : *pRender -
  996. //-----------------------------------------------------------------------------
  997. void CMapClass::Render2D(CRender2D *pRender)
  998. {
  999. // This is not needed because the recursion is performed in CMapView2D::Render
  1000. // POSITION pos = Children.GetHeadPosition();
  1001. // while (pos != NULL)
  1002. // {
  1003. // CMapClass *pChild = Children.GetNext(pos);
  1004. // if (pChild->IsVisible() && pChild->IsVisible2D())
  1005. // {
  1006. // pChild->Render2D(pRender);
  1007. // }
  1008. // }
  1009. }
  1010. //-----------------------------------------------------------------------------
  1011. // Purpose:
  1012. // Input : pRender -
  1013. //-----------------------------------------------------------------------------
  1014. void CMapClass::Render3D(CRender3D *pRender)
  1015. {
  1016. }
  1017. //-----------------------------------------------------------------------------
  1018. // Purpose: Transforms all children. Derived implementations should call this,
  1019. // then do their own thing.
  1020. // Input : t - Pointer to class containing transformation information.
  1021. //-----------------------------------------------------------------------------
  1022. void CMapClass::DoTransform(const VMatrix &matrix)
  1023. {
  1024. CMapPoint::DoTransform(matrix);
  1025. FOR_EACH_OBJ( m_Children, pos )
  1026. {
  1027. CMapClass *pChild = m_Children.Element(pos);
  1028. pChild->Transform( matrix );
  1029. }
  1030. }
  1031. //-----------------------------------------------------------------------------
  1032. // Default logical box
  1033. //-----------------------------------------------------------------------------
  1034. void CMapClass::GetRenderLogicalBox( Vector2D &mins, Vector2D &maxs )
  1035. {
  1036. mins.Init( COORD_NOTINIT, COORD_NOTINIT );
  1037. maxs.Init( COORD_NOTINIT, COORD_NOTINIT );
  1038. }
  1039. const Vector2D& CMapClass::GetLogicalPosition( )
  1040. {
  1041. static Vector2D pos( COORD_NOTINIT, COORD_NOTINIT );
  1042. return pos;
  1043. }
  1044. //-----------------------------------------------------------------------------
  1045. // Purpose:
  1046. //-----------------------------------------------------------------------------
  1047. size_t CMapClass::GetSize(void)
  1048. {
  1049. return(sizeof(*this));
  1050. }
  1051. //-----------------------------------------------------------------------------
  1052. // Purpose:
  1053. //-----------------------------------------------------------------------------
  1054. bool CMapClass::HitTest2D(CMapView2D *pView, const Vector2D &point, HitInfo_t &HitData)
  1055. {
  1056. HitData.pObject = NULL;
  1057. HitData.nDepth = g_MAX_MAP_COORD*3;
  1058. HitData.uData = 0;
  1059. bool bFoundHit = false;
  1060. if ( !IsVisible() )
  1061. return false;
  1062. FOR_EACH_OBJ( m_Children, pos )
  1063. {
  1064. CMapClass *pChild = m_Children.Element(pos);
  1065. HitInfo_t testHitData;
  1066. if ( pChild->HitTest2D(pView, point, testHitData) )
  1067. {
  1068. Assert( testHitData.pObject != NULL );
  1069. if ( testHitData.nDepth < HitData.nDepth )
  1070. {
  1071. HitData = testHitData;
  1072. bFoundHit = true;
  1073. }
  1074. }
  1075. }
  1076. return bFoundHit;
  1077. }
  1078. //-----------------------------------------------------------------------------
  1079. // Purpose:
  1080. //-----------------------------------------------------------------------------
  1081. bool CMapClass::HitTestLogical(CMapViewLogical *pView, const Vector2D &point, HitInfo_t &hitData)
  1082. {
  1083. if ( !IsVisibleLogical() )
  1084. return false;
  1085. FOR_EACH_OBJ( m_Children, pos )
  1086. {
  1087. CMapClass *pChild = m_Children.Element(pos);
  1088. if ( pChild->HitTestLogical(pView, point, hitData) )
  1089. return true;
  1090. }
  1091. return false;
  1092. }
  1093. //-----------------------------------------------------------------------------
  1094. // Purpose: Sets the selection state of this object's children.
  1095. // Input : eSelectionState -
  1096. //-----------------------------------------------------------------------------
  1097. SelectionState_t CMapClass::SetSelectionState(SelectionState_t eSelectionState)
  1098. {
  1099. FOR_EACH_OBJ( m_Children, pos )
  1100. {
  1101. CMapAtom *pObject = m_Children.Element(pos);
  1102. pObject->SetSelectionState(eSelectionState);
  1103. }
  1104. return CMapAtom::SetSelectionState(eSelectionState);
  1105. }
  1106. //-----------------------------------------------------------------------------
  1107. // Purpose: Our child's bounding box has changed - notify our parent. The real
  1108. // work will be done in CMapWorld::UpdateChild.
  1109. // Input : pChild - The child whose bounding box changed.
  1110. //-----------------------------------------------------------------------------
  1111. void CMapClass::UpdateChild(CMapClass *pChild)
  1112. {
  1113. if (m_pParent != NULL)
  1114. {
  1115. GetParent()->UpdateChild(this);
  1116. }
  1117. }
  1118. //-----------------------------------------------------------------------------
  1119. // Purpose: Returns a coordinate frame to render in
  1120. // Input : matrix -
  1121. // Output : returns true if a new matrix is returned, false if it is invalid
  1122. //-----------------------------------------------------------------------------
  1123. bool CMapClass::GetTransformMatrix( VMatrix& matrix )
  1124. {
  1125. // try and get our parents transform matrix
  1126. CMapClass *p = CMapClass::GetParent();
  1127. if ( p )
  1128. {
  1129. return p->GetTransformMatrix( matrix );
  1130. }
  1131. return false;
  1132. }
  1133. //-----------------------------------------------------------------------------
  1134. // Purpose:
  1135. // Input : pLoadInfo -
  1136. // pWorld -
  1137. // Output :
  1138. //-----------------------------------------------------------------------------
  1139. ChunkFileResult_t CMapClass::LoadEditorCallback(CChunkFile *pFile, CMapClass *pObject)
  1140. {
  1141. return(pFile->ReadChunk((KeyHandler_t)LoadEditorKeyCallback, pObject));
  1142. }
  1143. //-----------------------------------------------------------------------------
  1144. // Purpose: Handles keyvalues when loading the editor chunk of an object from the
  1145. // MAP file. Keys are transferred to a special keyvalue list for use after
  1146. // the entire map has been loaded.
  1147. // Input : szKey - Key to handle.
  1148. // szValue - Value of key.
  1149. // pObject - Object being loaded.
  1150. // Output : Returns ChunkFile_Ok.
  1151. //-----------------------------------------------------------------------------
  1152. ChunkFileResult_t CMapClass::LoadEditorKeyCallback(const char *szKey, const char *szValue, CMapClass *pObject)
  1153. {
  1154. if (!stricmp(szKey, "color"))
  1155. {
  1156. CChunkFile::ReadKeyValueColor(szValue, pObject->r, pObject->g, pObject->b);
  1157. }
  1158. else if (!stricmp(szKey, "id"))
  1159. {
  1160. CChunkFile::ReadKeyValueInt(szValue, pObject->m_nID);
  1161. // PORTAL2 SHIP: keep track of load order to preserve it on save so that maps can be diffed.
  1162. pObject->m_nLoadID = CMapDoc::GetActiveMapDoc()->GetNextLoadID();
  1163. }
  1164. else if (!stricmp(szKey, "comments"))
  1165. {
  1166. //
  1167. // Load the object comments.
  1168. // HACK: upcast to CEditGameClass *
  1169. //
  1170. CEditGameClass *pEdit = dynamic_cast <CEditGameClass *> (pObject);
  1171. if (pEdit != NULL)
  1172. {
  1173. pEdit->SetComments(szValue);
  1174. }
  1175. }
  1176. else if (!stricmp(szKey, "visgroupshown"))
  1177. {
  1178. CChunkFile::ReadKeyValueBool(szValue, pObject->m_bVisGroupShown);
  1179. }
  1180. else if ( !stricmp(szKey, "visgroupautoshown") )
  1181. {
  1182. CChunkFile::ReadKeyValueBool(szValue, pObject->m_bVisGroupAutoShown);
  1183. }
  1184. else
  1185. {
  1186. pObject->SetEditorKeyValue(szKey, szValue);
  1187. }
  1188. return(ChunkFile_Ok);
  1189. }
  1190. //-----------------------------------------------------------------------------
  1191. // Purpose: Call this function after changing this object via transformation,
  1192. // etc. Notifies dependents and updates the parent with this object's
  1193. // new size.
  1194. //-----------------------------------------------------------------------------
  1195. void CMapClass::PostUpdate(Notify_Dependent_t eNotifyType)
  1196. {
  1197. if (m_pParent != NULL)
  1198. {
  1199. GetParent()->UpdateChild(this);
  1200. }
  1201. else if (eNotifyType != Notify_Removed)
  1202. {
  1203. CalcBounds(TRUE);
  1204. }
  1205. NotifyDependents(eNotifyType);
  1206. }
  1207. //-----------------------------------------------------------------------------
  1208. // Purpose: Notifies all our dependents that something about us has changed,
  1209. // giving them the chance to update themselves.
  1210. //-----------------------------------------------------------------------------
  1211. void CMapClass::NotifyDependents(Notify_Dependent_t eNotifyType)
  1212. {
  1213. Assert(m_Dependents.Count() < 1000);
  1214. if (m_Dependents.Count() != 0)
  1215. {
  1216. CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
  1217. if (pDoc)
  1218. {
  1219. pDoc->NotifyDependents(this, eNotifyType);
  1220. }
  1221. }
  1222. }
  1223. //-----------------------------------------------------------------------------
  1224. // Purpose: Informs us that an object that we are dependent upon has changed,
  1225. // giving us the opportunity to update ourselves accordingly.
  1226. // Input : pObject - Object that we are dependent upon that has changed.
  1227. //-----------------------------------------------------------------------------
  1228. void CMapClass::OnNotifyDependent(CMapClass *pObject, Notify_Dependent_t eNotifyType)
  1229. {
  1230. }
  1231. //-----------------------------------------------------------------------------
  1232. // Purpose: Default implementation for saving editor-specific data. Does nothing.
  1233. // Input : pFile -
  1234. // Output : ChunkFileResult_t
  1235. //-----------------------------------------------------------------------------
  1236. ChunkFileResult_t CMapClass::SaveEditorData(CChunkFile *pFile)
  1237. {
  1238. return(ChunkFile_Ok);
  1239. }
  1240. //-----------------------------------------------------------------------------
  1241. // Purpose:
  1242. // Input : *pFile -
  1243. // Output : ChunkFileResult_t
  1244. //-----------------------------------------------------------------------------
  1245. ChunkFileResult_t CMapClass::SaveVMF(CChunkFile *pFile, CSaveInfo *pSaveInfo)
  1246. {
  1247. //
  1248. // Write the editor chunk.
  1249. //
  1250. ChunkFileResult_t eResult = pFile->BeginChunk("editor");
  1251. //
  1252. // Save the object's color.
  1253. //
  1254. if (eResult == ChunkFile_Ok)
  1255. {
  1256. eResult = pFile->WriteKeyValueColor("color", r, g, b);
  1257. }
  1258. //
  1259. // Save the group ID, if any.
  1260. //
  1261. if (eResult == ChunkFile_Ok)
  1262. {
  1263. CMapGroup *pGroup = dynamic_cast<CMapGroup *>(m_pParent);
  1264. if (pGroup != NULL)
  1265. {
  1266. eResult = pFile->WriteKeyValueInt("groupid", pGroup->GetID());
  1267. }
  1268. }
  1269. //
  1270. // Save the visgroup IDs, if any.
  1271. //
  1272. if (m_VisGroups.Count())
  1273. {
  1274. if ((eResult == ChunkFile_Ok) && m_VisGroups.Count())
  1275. {
  1276. for (int i = 0; i < m_VisGroups.Count(); i++)
  1277. {
  1278. CVisGroup *pVisGroup = m_VisGroups.Element(i);
  1279. if ( !pVisGroup->IsAutoVisGroup() )
  1280. {
  1281. eResult = pFile->WriteKeyValueInt("visgroupid", pVisGroup->GetID());
  1282. if (eResult != ChunkFile_Ok)
  1283. {
  1284. break;
  1285. }
  1286. }
  1287. }
  1288. }
  1289. }
  1290. if (eResult == ChunkFile_Ok)
  1291. {
  1292. eResult = pFile->WriteKeyValueBool("visgroupshown", m_bVisGroupShown);
  1293. }
  1294. if (eResult == ChunkFile_Ok)
  1295. {
  1296. eResult = pFile->WriteKeyValueBool("visgroupautoshown", m_bVisGroupAutoShown);
  1297. }
  1298. //
  1299. // Save the object comments, if any.
  1300. // HACK: upcast to CEditGameClass *
  1301. //
  1302. CEditGameClass *pEdit = dynamic_cast <CEditGameClass *> (this);
  1303. if (pEdit != NULL)
  1304. {
  1305. if ((eResult == ChunkFile_Ok) && (strlen(pEdit->GetComments()) > 0))
  1306. {
  1307. eResult = pFile->WriteKeyValue("comments", pEdit->GetComments());
  1308. }
  1309. }
  1310. //
  1311. // Save any other editor-specific data.
  1312. //
  1313. if (eResult == ChunkFile_Ok)
  1314. {
  1315. eResult = SaveEditorData(pFile);
  1316. }
  1317. if (eResult == ChunkFile_Ok)
  1318. {
  1319. eResult = pFile->EndChunk();
  1320. }
  1321. return(eResult);
  1322. }
  1323. //-----------------------------------------------------------------------------
  1324. // Purpose:
  1325. // Input : *pDependent -
  1326. //-----------------------------------------------------------------------------
  1327. void CMapClass::RemoveDependent(CMapClass *pDependent)
  1328. {
  1329. int nIndex = m_Dependents.Find(pDependent);
  1330. if (nIndex != -1)
  1331. {
  1332. m_Dependents.FastRemove(nIndex);
  1333. }
  1334. }
  1335. //-----------------------------------------------------------------------------
  1336. // Purpose: Frees all the keys that were loaded from the editor chunk of the MAP file.
  1337. //-----------------------------------------------------------------------------
  1338. void CMapClass::RemoveEditorKeys(void)
  1339. {
  1340. delete m_pEditorKeys;
  1341. m_pEditorKeys = NULL;
  1342. }
  1343. //-----------------------------------------------------------------------------
  1344. // Purpose:
  1345. // Input : *szOldName -
  1346. // *szNewName -
  1347. //-----------------------------------------------------------------------------
  1348. void CMapClass::ReplaceTargetname(const char *szOldName, const char *szNewName)
  1349. {
  1350. FOR_EACH_OBJ( m_Children, pos )
  1351. {
  1352. CMapClass *pObject = m_Children.Element(pos);
  1353. pObject->ReplaceTargetname(szOldName, szNewName);
  1354. }
  1355. }
  1356. //-----------------------------------------------------------------------------
  1357. // Purpose: Updates an object attachment, making this object no longer dependent
  1358. // on changes to the old object, and dependent on changes to the new object.
  1359. // Input : pOldAttached - Object that this object was attached to (possibly NULL).
  1360. // pNewAttached - New object being attached to (possibly NULL).
  1361. // Output : Returns pNewAttached.
  1362. //-----------------------------------------------------------------------------
  1363. CMapClass *CMapClass::UpdateDependency(CMapClass *pOldAttached, CMapClass *pNewAttached)
  1364. {
  1365. if (pOldAttached != pNewAttached)
  1366. {
  1367. //
  1368. // If we were attached to another object via this pointer, detach us now.
  1369. //
  1370. if (pOldAttached != NULL)
  1371. {
  1372. pOldAttached->RemoveDependent(this);
  1373. }
  1374. //
  1375. // Attach ourselves as a dependent of the other object. We will now be notified
  1376. // of any changes to that object.
  1377. //
  1378. if (pNewAttached != NULL)
  1379. {
  1380. pNewAttached->AddDependent(this);
  1381. }
  1382. }
  1383. return(pNewAttached);
  1384. }
  1385. //-----------------------------------------------------------------------------
  1386. // Purpose: Updates this object's parent, removing it from it's old parent (if any)
  1387. // attaching it to the new parent (if any).
  1388. // Input : pNewParent - A pointer to the new parent for this object.
  1389. // Output : Returns a pointer to the new parent.
  1390. //-----------------------------------------------------------------------------
  1391. void CMapClass::UpdateParent(CMapClass *pNewParent)
  1392. {
  1393. CMapClass *pOldParent = GetParent();
  1394. if (pOldParent != pNewParent)
  1395. {
  1396. if (pOldParent != NULL)
  1397. {
  1398. pOldParent->RemoveChild(this);
  1399. }
  1400. if (pNewParent != NULL)
  1401. {
  1402. pNewParent->AddChild(this);
  1403. }
  1404. m_pParent = pNewParent;
  1405. UpdateObjectColor();
  1406. }
  1407. }
  1408. //-----------------------------------------------------------------------------
  1409. // Purpose:
  1410. // Input : *szKey -
  1411. // Output : const char
  1412. //-----------------------------------------------------------------------------
  1413. void CMapClass::SetEditorKeyValue(const char *szKey, const char *szValue)
  1414. {
  1415. if (m_pEditorKeys == NULL)
  1416. {
  1417. m_pEditorKeys = new WCKeyValuesVector;
  1418. }
  1419. Assert( m_pEditorKeys != NULL );
  1420. m_pEditorKeys->AddKeyValue(szKey, szValue);
  1421. }
  1422. //-----------------------------------------------------------------------------
  1423. // Purpose: Sets the origin of this object and its children.
  1424. // FIXME: Should our children necessarily have the same origin as us?
  1425. // Seems like we should translate our children by our origin delta
  1426. //-----------------------------------------------------------------------------
  1427. void CMapClass::SetOrigin( Vector &origin )
  1428. {
  1429. CMapPoint::SetOrigin( origin );
  1430. FOR_EACH_OBJ( m_Children, pos )
  1431. {
  1432. CMapClass *pChild = m_Children.Element( pos );
  1433. pChild->SetOrigin( origin );
  1434. }
  1435. PostUpdate(Notify_Changed);
  1436. }
  1437. //-----------------------------------------------------------------------------
  1438. // Purpose:
  1439. // Input : bVisible -
  1440. //-----------------------------------------------------------------------------
  1441. void CMapClass::SetVisible(bool bVisible)
  1442. {
  1443. FOR_EACH_OBJ( m_Children, pos )
  1444. {
  1445. CMapClass *pChild = m_Children.Element(pos);
  1446. pChild ? pChild->SetVisible(bVisible) : NULL;;
  1447. }
  1448. m_bVisible = bVisible;
  1449. }
  1450. //-----------------------------------------------------------------------------
  1451. // Purpose:
  1452. // Input : bShow -
  1453. //-----------------------------------------------------------------------------
  1454. void CMapClass::VisGroupShow(bool bShow, VisGroupSelection eVisGroup)
  1455. {
  1456. FOR_EACH_OBJ( m_Children, pos )
  1457. {
  1458. CMapClass *pChild = m_Children.Element(pos);
  1459. pChild->VisGroupShow(bShow, eVisGroup);
  1460. }
  1461. if ( eVisGroup == AUTO )
  1462. {
  1463. m_bVisGroupAutoShown = bShow;
  1464. }
  1465. if ( eVisGroup == USER )
  1466. {
  1467. //since user visgroup visibility has precedence over auto, it is possible to change an object's auto
  1468. //visibility through an action in a user visgroup.
  1469. if ( bShow )
  1470. {
  1471. m_bVisGroupAutoShown = bShow;
  1472. }
  1473. m_bVisGroupShown = bShow;
  1474. }
  1475. }
  1476. //-----------------------------------------------------------------------------
  1477. // Purpose: Causes all objects in the world to update any object dependencies (pointers)
  1478. // that they might be holding. This is a static function.
  1479. //-----------------------------------------------------------------------------
  1480. void CMapClass::UpdateAllDependencies(CMapClass *pObject)
  1481. {
  1482. //
  1483. // Try to locate the world object.
  1484. //
  1485. CMapWorld *pWorld;
  1486. if (pObject == NULL)
  1487. {
  1488. CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
  1489. if ((pDoc == NULL) || (pDoc->IsLoading()))
  1490. {
  1491. return;
  1492. }
  1493. pWorld = pDoc->GetMapWorld();
  1494. }
  1495. else
  1496. {
  1497. pWorld = pObject->GetWorldObject(pObject);
  1498. }
  1499. if (pWorld == NULL)
  1500. {
  1501. return;
  1502. }
  1503. pWorld->UpdateAllDependencies( pObject );
  1504. EnumChildrenPos_t pos;
  1505. CMapClass *pChild = pWorld->GetFirstDescendent( pos );
  1506. while ( pChild != NULL )
  1507. {
  1508. pChild->UpdateDependencies( pWorld, pObject );
  1509. pChild = pWorld->GetNextDescendent( pos );
  1510. }
  1511. }
  1512. //-----------------------------------------------------------------------------
  1513. // Returns whether this object intersects the given cordon bounds.
  1514. // Return true to keep the object, false to cull it.
  1515. //-----------------------------------------------------------------------------
  1516. bool CMapClass::IsIntersectingCordon(const Vector &vecMins, const Vector &vecMaxs)
  1517. {
  1518. return IsIntersectingBox(vecMins, vecMaxs);
  1519. }
  1520. //-----------------------------------------------------------------------------
  1521. // Purpose: Checks to see if the object is hidden by auto or user visgroups
  1522. // without being assigned to one. This solves the problem of objects
  1523. // being destructively hidden by obsolete visgroups.
  1524. //-----------------------------------------------------------------------------
  1525. bool CMapClass::CheckVisibility( bool bLoading )
  1526. {
  1527. CVisGroup* pVisGroup;
  1528. bool bInUser = false;
  1529. bool bInAuto = false;
  1530. int nVisGroupCount = m_VisGroups.Count();
  1531. bool bFoundOrphans = false;
  1532. CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
  1533. for ( int i = 0; i < nVisGroupCount; i++ )
  1534. {
  1535. pVisGroup = m_VisGroups.Element( i );
  1536. if ( pVisGroup->IsAutoVisGroup() )
  1537. {
  1538. bInAuto = true;
  1539. }
  1540. else
  1541. {
  1542. bInUser = true;
  1543. }
  1544. }
  1545. if ( !bInAuto && !m_bVisGroupAutoShown )
  1546. {
  1547. VisGroupShow( true, AUTO );
  1548. }
  1549. if ( !bInUser && !m_bVisGroupShown )
  1550. {
  1551. VisGroupShow( true, USER );
  1552. if ( bLoading && pDoc->VisGroups_ObjectCanBelongToVisGroup( this ) )
  1553. {
  1554. //if this object is an orphan, we want it to be hidden but placed in a new visgroup.
  1555. bFoundOrphans = true;
  1556. VisGroupShow( false, USER );
  1557. }
  1558. }
  1559. return bFoundOrphans;
  1560. }
  1561. //-----------------------------------------------------------------------------
  1562. // Purpose: this routine will indicate if the object is editable. Generally it
  1563. // will not be editable if it is located in a separate instance or
  1564. // submap.
  1565. //-----------------------------------------------------------------------------
  1566. bool CMapClass::IsEditable( void )
  1567. {
  1568. if ( GetParent() )
  1569. {
  1570. return GetParent()->IsEditable();
  1571. }
  1572. return true;
  1573. }
  1574. //-----------------------------------------------------------------------------
  1575. // Purpose: this function will notify all children that the instance they belong to has been moved.
  1576. // it will also notify dependents of a translation. this function is currently not
  1577. // used but may be.
  1578. //-----------------------------------------------------------------------------
  1579. void CMapClass::InstanceMoved( void )
  1580. {
  1581. #if 0
  1582. FOR_EACH_OBJ( m_Children, pos )
  1583. {
  1584. CMapClass *pChild = m_Children.Element(pos);
  1585. pChild->InstanceMoved();
  1586. }
  1587. CMapWorld *pThisWorld = GetWorldObject( this );
  1588. for (int i = 0; i < m_Dependents.Count(); i++)
  1589. {
  1590. CMapClass *pDependent = m_Dependents.Element(i);
  1591. CMapWorld *pDependentWorld = GetWorldObject( pDependent );
  1592. if ( pDependentWorld != pThisWorld )
  1593. {
  1594. pDependent->OnNotifyDependent( this, Notify_Transform );
  1595. }
  1596. }
  1597. #endif
  1598. }