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.

12182 lines
319 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: The document. Exposes functions for object creation, deletion, and
  4. // manipulation. Holds the current tool. Handles GUI messages that are
  5. // view-independent.
  6. //
  7. //=============================================================================//
  8. #include "stdafx.h"
  9. #include <direct.h>
  10. #include <io.h>
  11. #include <mmsystem.h>
  12. #include <process.h>
  13. #include <direct.h>
  14. #include "BuildNum.h"
  15. #include "CustomMessages.h"
  16. #include "EditPrefabDlg.h"
  17. #include "EntityReportDlg.h"
  18. #include "FaceEditSheet.h"
  19. #include "GlobalFunctions.h"
  20. #include "GotoBrushDlg.h"
  21. #include "History.h"
  22. #include "MainFrm.h"
  23. #include "MapAnimator.h"
  24. #include "MapCheckDlg.h"
  25. #include "MapDefs.h" // dvs: For COORD_NOTINIT
  26. #include "MapDisp.h"
  27. #include "MapDoc.h"
  28. #include "MapEntity.h"
  29. #include "MapGroup.h"
  30. #include "MapInfoDlg.h"
  31. #include "MapInstance.h"
  32. #include "MapSolid.h"
  33. #include "MapView2D.h"
  34. #include "MapViewLogical.h"
  35. #include "MapView3D.h"
  36. #include "MapWorld.h"
  37. #include "NewVisGroupDlg.h"
  38. #include "ObjectProperties.h"
  39. #include "OptionProperties.h"
  40. #include "Options.h"
  41. #include "ProcessWnd.h"
  42. #include "PasteSpecialDlg.h"
  43. #include "Prefabs.h"
  44. #include "Prefab3D.h"
  45. #include "ReplaceTexDlg.h"
  46. #include "RunMap.h"
  47. #include "RunMapExpertDlg.h"
  48. #include "SaveInfo.h"
  49. #include "Manifest.h"
  50. #include "ManifestDialog.h"
  51. #include "ToolManager.h"
  52. #include "ToolCamera.h"
  53. #include "ToolEntity.h"
  54. #include "SelectEntityDlg.h"
  55. #include "Shell.h"
  56. #include "StatusBarIDs.h"
  57. #include "StrDlg.h"
  58. #include "TextureSystem.h"
  59. #include "TextureConverter.h"
  60. #include "TransformDlg.h"
  61. #include "VisGroup.h"
  62. #include "hammer.h"
  63. #include "ibsplighting.h"
  64. #include "camera.h"
  65. #include "MapDiffDlg.h"
  66. #include "StockSolids.h"
  67. #include "ToolMorph.h"
  68. #include "ToolBlock.h"
  69. #include "p4lib/ip4.h"
  70. #include "mapdoc.h"
  71. // memdbgon must be the last include file in a .cpp file!!!
  72. #include <tier0/memdbgon.h>
  73. #define KeyInt( key, dest ) \
  74. if (stricmp(szKey, key) != 0) \
  75. ; \
  76. else \
  77. { \
  78. CChunkFile::ReadKeyValueInt(szValue, dest); \
  79. }
  80. #define KeyBool( key, dest ) \
  81. if (stricmp(szKey, key) != 0) \
  82. ; \
  83. else \
  84. { \
  85. CChunkFile::ReadKeyValueBool(szValue, dest); \
  86. }
  87. #define MAX_REPLACE_LINE_LENGTH 256
  88. #define LOGICAL_SPACING 500
  89. #define HALF_LIFE_2_EYE_HEIGHT 64
  90. #define VMF_FORMAT_VERSION 100
  91. static int g_nFileFormatVersion = 0;
  92. extern BOOL bSaveVisiblesOnly;
  93. extern CShell g_Shell;
  94. IMPLEMENT_DYNCREATE(CMapDoc, CDocument)
  95. BEGIN_MESSAGE_MAP(CMapDoc, CDocument)
  96. //{{AFX_MSG_MAP(CMapDoc)
  97. ON_COMMAND(ID_EDIT_DELETE, OnEditDelete)
  98. ON_COMMAND(ID_MAP_SNAPTOGRID, OnMapSnaptogrid)
  99. ON_UPDATE_COMMAND_UI(ID_MAP_SNAPTOGRID, OnUpdateMapSnaptogrid)
  100. ON_COMMAND(ID_MAP_ENTITY_GALLERY, OnMapEntityGallery)
  101. ON_COMMAND(ID_EDIT_APPLYTEXTURE, OnEditApplytexture)
  102. ON_COMMAND(ID_TOOLS_SUBTRACTSELECTION, OnToolsSubtractselection)
  103. ON_UPDATE_COMMAND_UI(ID_TOOLS_SUBTRACTSELECTION, OnUpdateEditSelection)
  104. ON_COMMAND(ID_MAP_ENABLELIGHTPREVIEW, OnEnableLightPreview)
  105. ON_COMMAND(ID_ENABLE_LIGHT_PREVIEW_CUSTOM_FILENAME, OnEnableLightPreviewCustomFilename)
  106. ON_COMMAND(ID_MAP_DISABLELIGHTPREVIEW, OnDisableLightPreview)
  107. ON_COMMAND(ID_MAP_UPDATELIGHTPREVIEW, OnUpdateLightPreview)
  108. ON_COMMAND(ID_MAP_TOGGLELIGHTPREVIEW, OnToggleLightPreview)
  109. ON_COMMAND(ID_MAP_ABORTLIGHTCALCULATION, OnAbortLightCalculation)
  110. ON_COMMAND(ID_EDIT_COPYWC, OnEditCopy)
  111. ON_UPDATE_COMMAND_UI(ID_EDIT_COPYWC, OnUpdateEditSelection)
  112. ON_COMMAND(ID_EDIT_PASTEWC, OnEditPaste)
  113. ON_UPDATE_COMMAND_UI(ID_EDIT_PASTEWC, OnUpdateEditPaste)
  114. ON_COMMAND(ID_EDIT_CUTWC, OnEditCut)
  115. ON_UPDATE_COMMAND_UI(ID_EDIT_CUTWC, OnUpdateEditSelection)
  116. ON_COMMAND(ID_TOOLS_GROUP, OnToolsGroup)
  117. ON_UPDATE_COMMAND_UI(ID_TOOLS_GROUP, OnUpdateEditSelection)
  118. ON_COMMAND(ID_TOOLS_UNGROUP, OnToolsUngroup)
  119. ON_UPDATE_COMMAND_UI(ID_TOOLS_UNGROUP, OnUpdateEditSelection)
  120. ON_COMMAND(ID_VIEW_GRID, OnViewGrid)
  121. ON_UPDATE_COMMAND_UI(ID_VIEW_GRID, OnUpdateViewGrid)
  122. ON_COMMAND(ID_VIEW_LOGICAL_GRID, OnViewLogicalGrid)
  123. ON_UPDATE_COMMAND_UI(ID_VIEW_LOGICAL_GRID, OnUpdateViewLogicalGrid)
  124. ON_COMMAND(ID_EDIT_SELECTALL, OnEditSelectall)
  125. ON_UPDATE_COMMAND_UI(ID_EDIT_SELECTALL, OnUpdateEditFunction)
  126. ON_COMMAND(ID_EDIT_REPLACE, OnEditReplace)
  127. ON_UPDATE_COMMAND_UI(ID_EDIT_REPLACE, OnUpdateEditFunction)
  128. ON_COMMAND(ID_FILE_SAVE_AS, OnFileSaveAs)
  129. ON_COMMAND(ID_FILE_SAVE, OnFileSave)
  130. ON_COMMAND(ID_MAP_GRIDLOWER, OnMapGridlower)
  131. ON_COMMAND(ID_MAP_GRIDHIGHER, OnMapGridhigher)
  132. ON_COMMAND(ID_EDIT_TOWORLD, OnEditToWorld)
  133. ON_UPDATE_COMMAND_UI(ID_EDIT_TOWORLD, OnUpdateEditSelection)
  134. ON_COMMAND(ID_FILE_EXPORT, OnFileExport)
  135. ON_COMMAND(ID_FILE_EXPORTAGAIN, OnFileExportAgain)
  136. ON_COMMAND(ID_EDIT_MAPPROPERTIES, OnEditMapproperties)
  137. ON_UPDATE_COMMAND_UI(ID_EDIT_MAPPROPERTIES, OnUpdateEditFunction)
  138. ON_COMMAND(ID_FILE_CONVERT_WAD, OnFileConvertWAD)
  139. ON_UPDATE_COMMAND_UI(ID_FILE_CONVERT_WAD, OnUpdateFileConvertWAD)
  140. ON_COMMAND(ID_FILE_RUNMAP, OnFileRunmap)
  141. ON_COMMAND(ID_TOOLS_HIDEITEMS, OnToolsHideitems)
  142. ON_UPDATE_COMMAND_UI(ID_TOOLS_HIDEITEMS, OnUpdateToolsHideitems)
  143. ON_COMMAND(ID_VIEW_HIDEUNCONNECTED, OnViewHideUnconnectedEntities)
  144. ON_UPDATE_COMMAND_UI(ID_VIEW_HIDEUNCONNECTED, OnUpdateViewHideUnconnectedEntities)
  145. ON_COMMAND(ID_TOOLS_HIDE_ENTITY_NAMES, OnToolsHideEntityNames)
  146. ON_UPDATE_COMMAND_UI(ID_TOOLS_HIDE_ENTITY_NAMES, OnUpdateToolsHideEntityNames)
  147. ON_UPDATE_COMMAND_UI(ID_EDIT_DELETE, OnUpdateEditSelection)
  148. ON_COMMAND(ID_MAP_INFORMATION, OnMapInformation)
  149. ON_COMMAND(ID_VIEW_CENTERONSELECTION, OnViewCenterOnSelection)
  150. ON_COMMAND(ID_VIEW_CENTER3DVIEWSONSELECTION, OnViewCenter3DViewsOnSelection)
  151. ON_COMMAND(ID_EDIT_PASTESPECIAL, OnEditPastespecial)
  152. ON_UPDATE_COMMAND_UI(ID_EDIT_PASTESPECIAL, OnUpdateEditPastespecial)
  153. ON_COMMAND(ID_EDIT_SELNEXT, OnEditSelnext)
  154. ON_COMMAND(ID_EDIT_SELPREV, OnEditSelprev)
  155. ON_COMMAND(ID_EDIT_SELNEXT_CASCADING, OnEditSelnextCascading)
  156. ON_COMMAND(ID_EDIT_SELPREV_CASCADING, OnEditSelprevCascading)
  157. ON_COMMAND(ID_LOGICALOBJECT_MOVETOGETHER, OnLogicalMoveBlock)
  158. ON_COMMAND(ID_LOGICALOBJECT_SELECTALLCASCADING, OnLogicalSelectAllCascading)
  159. ON_COMMAND(ID_LOGICALOBJECT_SELECTALLCONNECTED, OnLogicalSelectAllConnected)
  160. ON_COMMAND_EX(ID_VIEW_HIDESELECTEDOBJECTS, OnViewHideObjects)
  161. ON_COMMAND(ID_MAP_CHECK, OnMapCheck)
  162. ON_COMMAND(ID_VIEW_SHOWCONNECTIONS, OnViewShowconnections)
  163. ON_UPDATE_COMMAND_UI(ID_VIEW_SHOWCONNECTIONS, OnUpdateViewShowconnections)
  164. ON_UPDATE_COMMAND_UI(ID_FILE_SAVE, OnUpdateFileSave)
  165. ON_COMMAND(ID_TOOLS_CREATEPREFAB, OnToolsCreateprefab)
  166. ON_UPDATE_COMMAND_UI(ID_TOOLS_CREATEPREFAB, OnUpdateEditSelection)
  167. ON_COMMAND(ID_INSERTPREFAB_ORIGINAL, OnInsertprefabOriginal)
  168. ON_COMMAND(ID_EDIT_REPLACETEX, OnEditReplacetex)
  169. ON_UPDATE_COMMAND_UI(ID_EDIT_REPLACETEX, OnUpdateEditFunction)
  170. ON_COMMAND(ID_TOOLS_HOLLOW, OnToolsHollow)
  171. ON_UPDATE_COMMAND_UI(ID_TOOLS_HOLLOW, OnUpdateEditSelection)
  172. ON_COMMAND(ID_TOOLS_SNAPSELECTEDTOGRID, OnToolsSnapselectedtogrid)
  173. ON_UPDATE_COMMAND_UI(ID_TOOLS_SNAPSELECTEDTOGRID, OnUpdateEditSelection)
  174. ON_COMMAND(ID_TOOLS_SNAP_SELECTED_TO_GRID_INDIVIDUALLY, OnToolsSnapSelectedToGridIndividually)
  175. ON_UPDATE_COMMAND_UI(ID_TOOLS_SNAP_SELECTED_TO_GRID_INDIVIDUALLY, OnUpdateEditSelection)
  176. ON_COMMAND(ID_TOOLS_SPLITFACE, OnToolsSplitface)
  177. ON_UPDATE_COMMAND_UI(ID_TOOLS_SPLITFACE, OnUpdateToolsSplitface)
  178. ON_COMMAND(ID_TOOLS_TRANSFORM, OnToolsTransform)
  179. ON_UPDATE_COMMAND_UI(ID_TOOLS_TRANSFORM, OnUpdateEditSelection)
  180. ON_COMMAND(ID_TOOLS_TOGGLETEXLOCK, OnToolsToggletexlock)
  181. ON_UPDATE_COMMAND_UI(ID_TOOLS_TOGGLETEXLOCK, OnUpdateToolsToggletexlock)
  182. ON_COMMAND(ID_TOOLS_TOGGLETEXLOCKSCALE, OnToolsToggletexlockScale)
  183. ON_UPDATE_COMMAND_UI(ID_TOOLS_TOGGLETEXLOCKSCALE, OnUpdateToolsToggletexlockScale)
  184. ON_COMMAND(ID_TOOLS_TEXTUREALIGN, OnToolsTextureAlignment)
  185. ON_UPDATE_COMMAND_UI(ID_TOOLS_TEXTUREALIGN, OnUpdateToolsTextureAlignment)
  186. ON_COMMAND(ID_TOGGLE_CORDON, OnToggleCordon)
  187. ON_UPDATE_COMMAND_UI(ID_TOGGLE_CORDON, OnUpdateToggleCordon)
  188. ON_COMMAND_EX(ID_VIEW_HIDENONSELECTEDOBJECTS, OnViewHideObjects)
  189. ON_UPDATE_COMMAND_UI(ID_VIEW_HIDENONSELECTEDOBJECTS, OnUpdateViewHideUnselectedObjects)
  190. ON_UPDATE_COMMAND_UI(ID_VIEW_SHOW_HELPERS, OnUpdateViewShowHelpers)
  191. ON_COMMAND(ID_VIEW_SHOW_HELPERS, OnViewShowHelpers)
  192. ON_COMMAND(ID_VIEW_SHOWMODELSIN2D, OnViewShowModelsIn2D)
  193. ON_UPDATE_COMMAND_UI(ID_VIEW_SHOWMODELSIN2D, OnUpdateViewShowModelsIn2D)
  194. ON_COMMAND(ID_VIEW_PREVIEW_MODEL_FADE, OnViewPreviewModelFade)
  195. ON_UPDATE_COMMAND_UI(ID_VIEW_PREVIEW_MODEL_FADE, OnUpdateViewPreviewModelFade)
  196. ON_COMMAND(ID_COLLISION_WIREFRAME, OnCollisionWireframe)
  197. ON_UPDATE_COMMAND_UI(ID_COLLISION_WIREFRAME, OnUpdateCollisionWireframe)
  198. ON_COMMAND(ID_SHOW_DETAIL_OBJECTS, OnShowDetailObjects)
  199. ON_UPDATE_COMMAND_UI(ID_SHOW_DETAIL_OBJECTS, OnUpdateShowDetailObjects)
  200. ON_COMMAND(ID_SHOW_NODRAW_BRUSHES, OnShowNoDrawBrushes)
  201. ON_UPDATE_COMMAND_UI(ID_SHOW_NODRAW_BRUSHES, OnUpdateShowNoDrawBrushes)
  202. ON_COMMAND(ID_TOGGLE_GROUPIGNORE, OnToggleGroupignore)
  203. ON_UPDATE_COMMAND_UI(ID_TOGGLE_GROUPIGNORE, OnUpdateToggleGroupignore)
  204. ON_COMMAND(ID_VSCALE_TOGGLE, OnVscaleToggle)
  205. ON_COMMAND(ID_MAP_ENTITYREPORT, OnMapEntityreport)
  206. ON_COMMAND(ID_TOGGLE_SELECTBYHANDLE, OnToggleSelectbyhandle)
  207. ON_UPDATE_COMMAND_UI(ID_TOGGLE_SELECTBYHANDLE, OnUpdateToggleSelectbyhandle)
  208. ON_COMMAND(ID_TOGGLE_INFINITESELECT, OnToggleInfiniteselect)
  209. ON_UPDATE_COMMAND_UI(ID_TOGGLE_INFINITESELECT, OnUpdateToggleInfiniteselect)
  210. ON_COMMAND(ID_FILE_EXPORTTODXF, OnFileExporttodxf)
  211. ON_UPDATE_COMMAND_UI(ID_EDIT_APPLYTEXTURE, OnUpdateEditApplytexture)
  212. ON_COMMAND(ID_EDIT_CLEARSELECTION, OnEditClearselection)
  213. ON_UPDATE_COMMAND_UI(ID_EDIT_CLEARSELECTION, OnUpdateEditSelection)
  214. ON_COMMAND(ID_TOOLS_CENTER_ORIGINS, OnToolsCenterOrigins)
  215. ON_UPDATE_COMMAND_UI(ID_TOOLS_CENTER_ORIGINS, OnUpdateEditSelection)
  216. ON_COMMAND(ID_MAP_LOADPOINTFILE, OnMapLoadpointfile)
  217. ON_COMMAND(ID_MAP_UNLOADPOINTFILE, OnMapUnloadpointfile)
  218. ON_COMMAND(ID_MAP_LOADPORTALFILE, OnMapLoadportalfile)
  219. ON_COMMAND(ID_MAP_UNLOADPORTALFILE, OnMapUnloadportalfile)
  220. ON_COMMAND(ID_TOGGLE_3D_GRID, OnToggle3DGrid)
  221. ON_UPDATE_COMMAND_UI(ID_TOGGLE_3D_GRID, OnUpdateToggle3DGrid)
  222. ON_COMMAND(ID_EDIT_TOENTITY, OnEditToEntity)
  223. ON_UPDATE_COMMAND_UI(ID_EDIT_TOENTITY, OnUpdateEditSelection)
  224. ON_COMMAND_EX(ID_EDIT_UNDO, OnUndoRedo)
  225. ON_COMMAND_EX(ID_EDIT_REDO, OnUndoRedo)
  226. ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, OnUpdateUndoRedo)
  227. ON_UPDATE_COMMAND_UI(ID_EDIT_REDO, OnUpdateUndoRedo)
  228. ON_COMMAND(ID_VSCALE_CHANGED, OnChangeVertexscale)
  229. ON_COMMAND(ID_GOTO_BRUSH, OnViewGotoBrush)
  230. ON_COMMAND(ID_GOTO_COORDS, OnViewGotoCoords)
  231. ON_COMMAND(ID_SHOW_SELECTED_BRUSH_NUMBER, OnMapShowSelectedBrushNumber)
  232. ON_COMMAND(ID_EDIT_FINDENTITIES, OnEditFindEntities)
  233. ON_UPDATE_COMMAND_UI(ID_EDIT_FINDENTITIES, OnUpdateEditFunction)
  234. ON_COMMAND( ID_TOOLS_DISP_SOLIDDRAW, OnToggleDispSolidMask )
  235. ON_UPDATE_COMMAND_UI( ID_TOOLS_DISP_SOLIDDRAW, OnUpdateToggleSolidMask )
  236. ON_COMMAND( ID_TOOLS_DISP_DRAWWALKABLE, OnToggleDispDrawWalkable )
  237. ON_UPDATE_COMMAND_UI( ID_TOOLS_DISP_DRAWWALKABLE, OnUpdateToggleDispDrawWalkable )
  238. ON_COMMAND( ID_TOOLS_DISP_DRAW3D, OnToggleDispDraw3D )
  239. ON_UPDATE_COMMAND_UI( ID_TOOLS_DISP_DRAW3D, OnUpdateToggleDispDraw3D )
  240. ON_COMMAND( ID_TOOLS_DISP_DRAWBUILDABLE, OnToggleDispDrawBuildable )
  241. ON_UPDATE_COMMAND_UI( ID_TOOLS_DISP_DRAWBUILDABLE, OnUpdateToggleDispDrawBuildable )
  242. ON_COMMAND( ID_TOOLS_DISP_DRAWREMOVEDVERTS, OnToggleDispDrawRemovedVerts )
  243. ON_UPDATE_COMMAND_UI( ID_TOOLS_DISP_DRAWREMOVEDVERTS, OnUpdateToggleDispDrawRemovedVerts )
  244. ON_COMMAND(ID_MAP_DIFFMAPFILE, OnMapDiff)
  245. ON_COMMAND(ID_LOGICALOBJECT_LAYOUTGEOMETRIC, OnLogicalobjectLayoutgeometric)
  246. ON_COMMAND(ID_LOGICALOBJECT_LAYOUTDEFAULT, OnLogicalobjectLayoutdefault)
  247. ON_COMMAND(ID_LOGICALOBJECT_LAYOUTLOGICAL, OnLogicalobjectLayoutlogical)
  248. ON_COMMAND(ID_TOOLS_INSTANCES_HIDE, OnToolsInstancesHide)
  249. ON_UPDATE_COMMAND_UI(ID_TOOLS_INSTANCES_HIDE, OnUpdateToolsInstancesHide)
  250. ON_COMMAND(ID_TOOLS_INSTANCES_SHOWTINTED, OnToolsInstancesShowTinted)
  251. ON_UPDATE_COMMAND_UI(ID_TOOLS_INSTANCES_SHOWTINTED, OnUpdateToolsInstancesShowTinted)
  252. ON_COMMAND(ID_TOOLS_INSTANCES_SHOWNORMAL, OnToolsInstancesShowNormal)
  253. ON_UPDATE_COMMAND_UI(ID_TOOLS_INSTANCES_SHOWNORMAL, OnUpdateToolsInstancesShowNormal)
  254. ON_COMMAND(ID_INSTANCES_HIDEALL, OnInstancesHideAll)
  255. ON_COMMAND(ID_INSTANCES_SHOWALL, OnInstancesShowAll)
  256. //}}AFX_MSG_MAP
  257. ON_COMMAND(ID_INSTANCING_CREATEMANIFEST, &CMapDoc::OnInstancingCreatemanifest)
  258. ON_UPDATE_COMMAND_UI(ID_INSTANCING_CREATEMANIFEST, &CMapDoc::OnUpdateInstancingCreatemanifest)
  259. ON_COMMAND(ID_VERSIONCONTROL_CHECKINALL, &CMapDoc::OnInstancingCheckinAll)
  260. ON_UPDATE_COMMAND_UI(ID_VERSIONCONTROL_CHECKINALL, &CMapDoc::OnUpdateInstancingCheckinAll)
  261. ON_COMMAND(ID_VERSIONCONTROL_CHECKOUTMANIFEST, &CMapDoc::OnInstancingCheckOutManifest)
  262. ON_UPDATE_COMMAND_UI(ID_VERSIONCONTROL_CHECKOUTMANIFEST, &CMapDoc::OnUpdateInstancingCheckOutManifest)
  263. ON_COMMAND(ID_VERSIONCONTROL_ADDMANIFEST, &CMapDoc::OnInstancingAddManifest)
  264. ON_UPDATE_COMMAND_UI(ID_VERSIONCONTROL_ADDMANIFEST, &CMapDoc::OnUpdateInstancingAddManifest)
  265. ON_COMMAND(ID_INSTANCES_COLLAPSEALL, &CMapDoc::OnInstancesCollapseAll)
  266. ON_COMMAND(ID_INSTANCES_COLLAPSESELECTION, &CMapDoc::OnInstancesCollapseSelection)
  267. ON_COMMAND( ID_VIEW_QUICKHIDE, OnQuickHide_HideObjects )
  268. ON_UPDATE_COMMAND_UI(ID_VIEW_QUICKHIDE, OnUpdateEditSelection)
  269. ON_COMMAND( ID_VIEW_QUICKHIDEUNSELECTED, OnQuickHide_HideUnselectedObjects )
  270. ON_UPDATE_COMMAND_UI(ID_VIEW_QUICKHIDEUNSELECTED, OnUpdateEditSelection)
  271. ON_COMMAND( ID_VIEW_QUICKUNHIDE, OnQuickHide_Unhide )
  272. ON_UPDATE_COMMAND_UI(ID_VIEW_QUICKUNHIDE, OnQuickHide_UpdateUnHide)
  273. ON_COMMAND( ID_TOGGLE_RADIUSCULLING, OnRadiusCulling )
  274. ON_UPDATE_COMMAND_UI(ID_TOGGLE_RADIUSCULLING, OnUpdateRadiusCulling )
  275. ON_COMMAND( ID_VIEW_QUICKHIDEVISGROUP, OnQuickHide_CreateVisGroupFromHidden )
  276. ON_UPDATE_COMMAND_UI(ID_VIEW_QUICKHIDEVISGROUP, OnQuickHide_UpdateCreateVisGroupFromHidden)
  277. END_MESSAGE_MAP()
  278. static CUtlVector<CMapDoc*> s_ActiveDocs;
  279. CMapDoc *CMapDoc::m_pMapDoc = NULL;
  280. CManifest *CMapDoc::m_pManifest = NULL;
  281. int CMapDoc::m_nInLevelLoad = 0;
  282. static CProgressDlg *pProgDlg;
  283. //
  284. // Clipboard. Global to all documents to allow copying from one document and
  285. // pasting in another.
  286. //
  287. class CHammerClipboard : public IHammerClipboard
  288. {
  289. public:
  290. CHammerClipboard(){}
  291. public:
  292. virtual void Destroy() { delete this; }
  293. public:
  294. CMapObjectList Objects;
  295. CMapWorld *pSourceWorld;
  296. BoundBox Bounds;
  297. Vector vecOriginalCenter;
  298. };
  299. IHammerClipboard * IHammerClipboard::CreateInstance()
  300. {
  301. return new CHammerClipboard;
  302. }
  303. // Get the global Hammer clipboard
  304. CHammerClipboard * GetHammerClipboard()
  305. {
  306. static class CGlobalHammerClipboard :
  307. public CHammerClipboard
  308. {
  309. virtual void Destroy() { Assert( 0 ); }
  310. }
  311. s_Clipboard;
  312. return &s_Clipboard;
  313. }
  314. // Convert a clipboard interface
  315. CHammerClipboard * GetHammerClipboard( IHammerClipboard *pInterface )
  316. {
  317. return static_cast< CHammerClipboard * >( pInterface );
  318. }
  319. struct BatchReplaceTextures_t
  320. {
  321. char szFindTexName[MAX_REPLACE_LINE_LENGTH]; // Texture to find.
  322. char szReplaceTexName[MAX_REPLACE_LINE_LENGTH]; // Texture to replace the found texture with.
  323. };
  324. struct AddNonSelectedInfo_t
  325. {
  326. CVisGroup *pGroup;
  327. int nCount;
  328. CMapObjectList *pList;
  329. BoundBox *pBox;
  330. CMapWorld *pWorld;
  331. };
  332. struct ReplaceTexInfo_t
  333. {
  334. char szFind[128];
  335. char szReplace[128];
  336. int iAction;
  337. int nReplaced;
  338. int iFindLen; // strlen(szFind) - for speed
  339. CMapWorld *pWorld;
  340. CMapDoc *pDoc;
  341. BOOL bMarkOnly;
  342. BOOL bHidden;
  343. bool m_bRescaleTextureCoordinates;
  344. };
  345. struct FindEntity_t
  346. {
  347. char szClassName[MAX_PATH]; //
  348. Vector Pos; //
  349. CMapEntity *pEntityFound; // Points to object found, NULL if unsuccessful.
  350. };
  351. struct SelectBoxInfo_t
  352. {
  353. CMapDoc *pDoc;
  354. BoundBox *pBox;
  355. BOOL bInside;
  356. SelectMode_t eSelectMode;
  357. };
  358. struct SelectLogicalBoxInfo_t
  359. {
  360. CMapDoc *pDoc;
  361. Vector2D vecMins;
  362. Vector2D vecMaxs;
  363. bool bInside;
  364. SelectMode_t eSelectMode;
  365. };
  366. //-----------------------------------------------------------------------------
  367. // Purpose: Constructor. Attaches all tools members to this document. Adds this
  368. // document to the list of active documents.
  369. //-----------------------------------------------------------------------------
  370. CMapDoc::CMapDoc(void)
  371. {
  372. m_nLogicalPositionCount = 0;
  373. int nSize = sizeof(CMapFace);
  374. nSize = sizeof(CMapSolid);
  375. m_bHasInitialUpdate = false;
  376. m_bLoading = false;
  377. m_pWorld = NULL;
  378. //
  379. // Set up undo/redo system.
  380. //
  381. m_pUndo = new CHistory;
  382. m_pRedo = new CHistory;
  383. m_pUndo->SetDocument(this);
  384. m_pUndo->SetOpposite(TRUE, m_pRedo);
  385. m_pRedo->SetDocument(this);
  386. m_pRedo->SetOpposite(FALSE, m_pUndo);
  387. // init object selection
  388. m_pSelection = new CSelection;
  389. m_pSelection->Init( this );
  390. m_VisGroups = new CUtlVector<CVisGroup *>();
  391. m_RootVisGroups = new CUtlVector<CVisGroup *>();
  392. // init tool manager
  393. m_pToolManager = new CToolManager;
  394. m_pToolManager->Init( this );
  395. Assert(GetMainWnd());
  396. m_bHideItems = false;
  397. m_bSnapToGrid = true;
  398. m_bShowGrid = true;
  399. m_bShowLogicalGrid = false;
  400. m_nGridSpacing = Options.view2d.iDefaultGrid;
  401. m_bShow3DGrid = false;
  402. m_tShowInstance = INSTANCES_SHOW_TINTED;
  403. m_nExternalReferenceCount = 0;
  404. m_nDocVersion = 0;
  405. m_nNextMapObjectID = 1;
  406. m_nNextNodeID = 1;
  407. m_pGame = NULL;
  408. m_flAnimationTime = 0.0f;
  409. m_bEditingPrefab = false;
  410. m_bPrefab = false;
  411. m_bIsAnimating = false;
  412. m_strLastExportFileName = "";
  413. m_bDispSolidDrawMask = true;
  414. m_bDispDrawWalkable = false;
  415. m_bDispDrawBuildable = false;
  416. m_bDispDraw3D = true;
  417. m_bDispDrawRemovedVerts = false;
  418. m_bVisGroupUpdatesLocked = false;
  419. s_ActiveDocs.AddToTail(this);
  420. m_pBSPLighting = 0;
  421. m_pPortalFile = NULL;
  422. m_SmoothingGroupVisual = 0;
  423. UpdateStatusBarSnap();
  424. //setup autosave members
  425. m_bNeedsAutosave = false;
  426. m_bIsAutosave = false;
  427. m_strAutosavedFrom = "";
  428. m_bIsCordoning = false;
  429. m_vCordonMins = Vector(-1024,-1024,-1024);
  430. m_vCordonMaxs = Vector( 1024,1024,1024);
  431. m_bIsEditable = true;
  432. m_pManifestOwner = NULL;
  433. m_bCollapsingInstances = false;
  434. }
  435. //-----------------------------------------------------------------------------
  436. // Purpose: Destructor.
  437. //-----------------------------------------------------------------------------
  438. CMapDoc::~CMapDoc(void)
  439. {
  440. GetMainWnd()->pObjectProperties->MarkDataDirty();
  441. //
  442. // Remove this doc from the list of active docs.
  443. //
  444. s_ActiveDocs.FindAndRemove(this);
  445. if (this == GetActiveMapDoc())
  446. {
  447. SetActiveMapDoc(NULL);
  448. }
  449. DeleteContents();
  450. delete m_pUndo;
  451. delete m_pRedo;
  452. delete m_pToolManager;
  453. if ( m_VisGroups )
  454. {
  455. delete m_VisGroups;
  456. m_VisGroups = NULL;
  457. }
  458. if ( m_RootVisGroups )
  459. {
  460. delete m_RootVisGroups;
  461. m_RootVisGroups = NULL;
  462. }
  463. if ( m_pManifestOwner == NULL && m_pSelection )
  464. {
  465. delete m_pSelection;
  466. m_pSelection = NULL;
  467. }
  468. OnDisableLightPreview();
  469. }
  470. //-----------------------------------------------------------------------------
  471. // Default logical placement for new entities
  472. //-----------------------------------------------------------------------------
  473. void CMapDoc::GetDefaultNewLogicalPosition( Vector2D &vecPosition )
  474. {
  475. int nMaxDim = ( g_MAX_MAP_COORD - g_MIN_MAP_COORD ) / LOGICAL_SPACING;
  476. int x = m_nLogicalPositionCount / nMaxDim;
  477. int y = m_nLogicalPositionCount - x * nMaxDim;
  478. x = x % nMaxDim;
  479. vecPosition.x = x * LOGICAL_SPACING;
  480. if ( vecPosition.x > g_MAX_MAP_COORD )
  481. {
  482. vecPosition.x += g_MIN_MAP_COORD - g_MAX_MAP_COORD;
  483. }
  484. vecPosition.y = y * LOGICAL_SPACING;
  485. if ( vecPosition.y > g_MAX_MAP_COORD )
  486. {
  487. vecPosition.y += g_MIN_MAP_COORD - g_MAX_MAP_COORD;
  488. }
  489. ++m_nLogicalPositionCount;
  490. }
  491. //-----------------------------------------------------------------------------
  492. // Purpose: Removes any object groups with no members or only one member.
  493. //-----------------------------------------------------------------------------
  494. void CMapDoc::RemoveEmptyGroups(void)
  495. {
  496. int nEmptyGroupCount = 0;
  497. CUtlVector<CMapGroup *> GroupList;
  498. m_pWorld->GetGroupList(GroupList);
  499. int nGroupCount = GroupList.Count();
  500. for (int i = nGroupCount - 1; i >= 0; i--)
  501. {
  502. CMapGroup *pGroup = GroupList.Element(i);
  503. if (!pGroup->GetChildCount())
  504. {
  505. // We found an empty group. Remove it.
  506. nEmptyGroupCount++;
  507. RemoveObjectFromWorld(pGroup, false);
  508. GroupList.FastRemove(i);
  509. delete pGroup;
  510. }
  511. }
  512. if (nEmptyGroupCount)
  513. {
  514. Msg(mwWarning, "Removed %d object group(s) with no children.\n", nEmptyGroupCount);
  515. }
  516. }
  517. //-----------------------------------------------------------------------------
  518. // Purpose:
  519. //-----------------------------------------------------------------------------
  520. void CMapDoc::AssignToGroups()
  521. {
  522. //
  523. // Get a list of all the groups.
  524. //
  525. CUtlVector<CMapGroup *> GroupList;
  526. int nGroupCount = m_pWorld->GetGroupList(GroupList);
  527. //
  528. // Assign all loaded objects to their proper groups.
  529. //
  530. CUtlVector<MapObjectPair_t> GroupedObjects;
  531. const CMapObjectList *pChildren = m_pWorld->GetChildren();
  532. FOR_EACH_OBJ( *pChildren, pos )
  533. {
  534. // Assign the object to its group, if any.
  535. CMapClass *pChild = pChildren->Element(pos);
  536. const char *pszGroupID = pChild->GetEditorKeyValue("groupid");
  537. if (pszGroupID != NULL)
  538. {
  539. int nID;
  540. CChunkFile::ReadKeyValueInt(pszGroupID, nID);
  541. MapObjectPair_t pair;
  542. for (int i = 0; i < nGroupCount; i++)
  543. {
  544. CMapGroup *pGroup = GroupList.Element(i);
  545. if (pGroup->GetID() == nID)
  546. {
  547. // Add the object to a list for removal from the world.
  548. pair.pObject1 = pChild;
  549. pair.pObject2 = pGroup;
  550. GroupedObjects.AddToTail(pair);
  551. break;
  552. }
  553. }
  554. }
  555. }
  556. //
  557. // Remove all the objects that were added to groups from the world, since they are
  558. // now children of CMapGroup objects that are already in the world.
  559. //
  560. int nPairCount = GroupedObjects.Count();
  561. for (int i = 0; i < nPairCount; i++)
  562. {
  563. m_pWorld->RemoveChild(GroupedObjects.Element(i).pObject1);
  564. GroupedObjects.Element(i).pObject2->AddChild(GroupedObjects.Element(i).pObject1);
  565. }
  566. }
  567. //-----------------------------------------------------------------------------
  568. // Purpose: Called after loading a VMF file. Assigns all objects to their proper
  569. // visgroups. It also finds the next unique ID to use when creating new objects.
  570. //-----------------------------------------------------------------------------
  571. void CMapDoc::AssignToVisGroups(void)
  572. {
  573. EnumChildrenPos_t pos;
  574. CMapClass *pChild = m_pWorld->GetFirstDescendent(pos);
  575. while (pChild != NULL)
  576. {
  577. //
  578. // HACK: If this entity needs a node ID and doesn't have one, set it now.
  579. // Would be better implemented more generically.
  580. //
  581. CMapEntity *pEntity = dynamic_cast<CMapEntity *>(pChild);
  582. if (pEntity != NULL)
  583. {
  584. if (pEntity->IsNodeClass() && (pEntity->GetNodeID() == 0))
  585. {
  586. int nID = GetNextNodeID();
  587. char szID[80];
  588. itoa(nID, szID, 10);
  589. pEntity->SetKeyValue("nodeid", szID);
  590. }
  591. }
  592. //
  593. // Assign the object to its visgroups, if any. Visgroup IDs are held
  594. // in a temporary keyvalue list that was loaded from the VMF.
  595. //
  596. int nKeyCount = pChild->GetEditorKeyCount();
  597. for (int i = 0; i < nKeyCount; i++)
  598. {
  599. const char *pszKey = pChild->GetEditorKey(i);
  600. if (!stricmp(pszKey, "visgroupid"))
  601. {
  602. const char *pszVisGroupID = pChild->GetEditorKeyValue(i);
  603. Assert(pszVisGroupID != NULL);
  604. if (pszVisGroupID != NULL)
  605. {
  606. unsigned int nID = (unsigned int)atoi(pszVisGroupID);
  607. CVisGroup *pVisGroup = VisGroups_GroupForID(nID);
  608. // If an object is assigned to a nonexistent visgroup, we do nothing here,
  609. // which effectively discards the bogus visgroup assignment.
  610. if (pVisGroup)
  611. {
  612. pChild->AddVisGroup(pVisGroup);
  613. if (CVisGroup::IsConvertingOldVisGroups() && (pVisGroup->GetVisible() != VISGROUP_SHOWN))
  614. {
  615. pChild->VisGroupShow(false);
  616. }
  617. }
  618. }
  619. }
  620. else if (!stricmp(pszKey, "colorvisgroupid"))
  621. {
  622. const char *pszVisGroupID = pChild->GetEditorKeyValue(i);
  623. Assert(pszVisGroupID != NULL);
  624. if (pszVisGroupID != NULL)
  625. {
  626. unsigned int nID = (unsigned int)atoi(pszVisGroupID);
  627. CVisGroup *pVisGroup = VisGroups_GroupForID(nID);
  628. Assert(pVisGroup != NULL);
  629. pChild->SetColorVisGroup(pVisGroup);
  630. }
  631. }
  632. }
  633. //
  634. // Free the temporary keyvalue list.
  635. //
  636. pChild->RemoveEditorKeys();
  637. pChild = m_pWorld->GetNextDescendent(pos);
  638. }
  639. VisGroups_Validate();
  640. AssignAllToAutoVisGroups();
  641. VisGroups_UpdateAll();
  642. }
  643. //-----------------------------------------------------------------------------
  644. // Purpose: Makes sure that the visgroup assignments are valid.
  645. //-----------------------------------------------------------------------------
  646. void CMapDoc::VisGroups_Validate()
  647. {
  648. EnumChildrenPos_t pos;
  649. CMapClass *pChild = m_pWorld->GetFirstDescendent(pos);
  650. while (pChild)
  651. {
  652. CMapClass *pParent = pChild->GetParent();
  653. // Old versions of Hammer had wacky visgroup assignments -- solid children of groups or entities
  654. // could belong to visgroups, even if those visgroups no longer existed.
  655. // For new versions of Hammer, just make sure that the object is allowed to belong to a visgroup.
  656. if (((g_nFileFormatVersion < 100) && (!IsWorldObject(pParent))) ||
  657. !VisGroups_ObjectCanBelongToVisGroup(pChild))
  658. {
  659. int nCount = pChild->GetVisGroupCount();
  660. if (nCount != 0)
  661. {
  662. Msg(mwWarning, "'%s', child of '%s', was in visgroups illegally. Removed from visgroups.", pChild->GetDescription(), pParent->GetDescription());
  663. pChild->RemoveAllVisGroups();
  664. }
  665. }
  666. pChild = m_pWorld->GetNextDescendent(pos);
  667. }
  668. }
  669. //-----------------------------------------------------------------------------
  670. // Purpose: Begins a remote shell editing session. This causes the GUI to be
  671. // disabled to avoid version mismatches between the editor's map and the
  672. // shell client's map.
  673. //-----------------------------------------------------------------------------
  674. void CMapDoc::BeginShellSession(void)
  675. {
  676. //
  677. // Disable all our views.
  678. //
  679. POSITION pos = GetFirstViewPosition();
  680. while (pos != NULL)
  681. {
  682. CView *pView = GetNextView(pos);
  683. pView->EnableWindow(FALSE);
  684. }
  685. //
  686. // Set the modified flag to update our version number. This marks the working
  687. // version of the map in memory as different from the saved version on disk.
  688. //
  689. SetModifiedFlag();
  690. GetMainWnd()->BeginShellSession();
  691. }
  692. void CMapDoc::GetSelectedCenter(Vector &vCenter)
  693. {
  694. Morph3D *pMorphTool = dynamic_cast<Morph3D*>( m_pToolManager->GetActiveTool() );
  695. CToolBlock *pBlockTool = dynamic_cast<CToolBlock*>( m_pToolManager->GetActiveTool() );
  696. if ( pMorphTool )
  697. {
  698. pMorphTool->GetSelectedCenter(vCenter);
  699. }
  700. else if ( pBlockTool )
  701. {
  702. pBlockTool->GetBoundsCenter(vCenter);
  703. }
  704. else if (!m_pSelection->IsEmpty())
  705. {
  706. m_pSelection->GetBoundsCenter(vCenter);
  707. }
  708. else if ( m_pWorld )
  709. {
  710. m_pWorld->GetBoundsCenter(vCenter);
  711. }
  712. else
  713. {
  714. vCenter.Init();
  715. }
  716. }
  717. //-----------------------------------------------------------------------------
  718. // Purpose:
  719. //-----------------------------------------------------------------------------
  720. void CMapDoc::CenterViewsOnSelection()
  721. {
  722. Vector vecCenter;
  723. GetSelectedCenter( vecCenter );
  724. Center2DViewsOn(vecCenter);
  725. Center3DViewsOn(vecCenter);
  726. CenterLogicalViewsOnSelection();
  727. }
  728. //-----------------------------------------------------------------------------
  729. // Purpose: Handles the View | Center On Selection menu item.
  730. //-----------------------------------------------------------------------------
  731. void CMapDoc::Center2DViewsOnSelection(void)
  732. {
  733. Vector vecCenter;
  734. GetSelectedCenter( vecCenter );
  735. Center2DViewsOn( vecCenter );
  736. }
  737. //-----------------------------------------------------------------------------
  738. // Purpose: Handles the View | Center 3D Views On Selection menu item.
  739. //-----------------------------------------------------------------------------
  740. void CMapDoc::Center3DViewsOnSelection()
  741. {
  742. Vector vecCenter;
  743. GetSelectedCenter( vecCenter );
  744. Center3DViewsOn( vecCenter );
  745. }
  746. void CMapDoc::CenterLogicalViewsOnSelection()
  747. {
  748. Vector2D vecLogicalCenter;
  749. if ( m_pSelection->GetLogicalBoundsCenter( vecLogicalCenter ) )
  750. {
  751. CenterLogicalViewsOn(vecLogicalCenter);
  752. }
  753. }
  754. //-----------------------------------------------------------------------------
  755. // Purpose: Called after loading a VMF file. Finds the next unique IDs to use
  756. // when creating new objects, nodes, and faces.
  757. //-----------------------------------------------------------------------------
  758. void CMapDoc::CountGUIDs(void)
  759. {
  760. CTypedPtrList<CPtrList, MapObjectPair_t *> GroupedObjects;
  761. // This increments the CMapWorld face ID but it doesn't matter since we're setting it below.
  762. int nNextFaceID = m_pWorld->FaceID_GetNext();
  763. EnumChildrenPos_t pos;
  764. CMapClass *pChild = m_pWorld->GetFirstDescendent(pos);
  765. while (pChild != NULL)
  766. {
  767. //
  768. // Keep track of the highest numbered object ID in this document.
  769. //
  770. if (pChild->GetID() >= m_nNextMapObjectID)
  771. {
  772. m_nNextMapObjectID = pChild->GetID() + 1;
  773. }
  774. //
  775. // Keep track of the highest numbered node ID in this document.
  776. //
  777. CMapEntity *pEntity = dynamic_cast<CMapEntity *>(pChild);
  778. if (pEntity != NULL)
  779. {
  780. //
  781. // Blah. Classes aren't assigned until PostLoadWorld, so we have to
  782. // look at our classname keyvalue to determine whether we are a node class.
  783. //
  784. const char *pszClass = pEntity->GetKeyValue("classname");
  785. if (pEntity->IsNodeClass(pszClass))
  786. {
  787. int nID = pEntity->GetNodeID();
  788. if (nID >= m_nNextNodeID)
  789. {
  790. m_nNextNodeID = nID + 1;
  791. }
  792. }
  793. }
  794. else
  795. {
  796. //
  797. // Keep track of the highest numbered face ID in this document.
  798. //
  799. CMapSolid *pSolid = dynamic_cast<CMapSolid *>(pChild);
  800. if (pSolid != NULL)
  801. {
  802. for (int nFace = 0; nFace < pSolid->GetFaceCount(); nFace++)
  803. {
  804. CMapFace *pFace = pSolid->GetFace(nFace);
  805. int nFaceID = pFace->GetFaceID();
  806. if (nFaceID >= nNextFaceID)
  807. {
  808. nNextFaceID = nFaceID + 1;
  809. }
  810. }
  811. }
  812. }
  813. pChild = m_pWorld->GetNextDescendent(pos);
  814. }
  815. m_pWorld->FaceID_SetNext(nNextFaceID);
  816. }
  817. //-----------------------------------------------------------------------------
  818. // Purpose:
  819. // Input : pszClassName -
  820. // x -
  821. // y -
  822. // z -
  823. // Output : Returns true on success, false on failure.
  824. //-----------------------------------------------------------------------------
  825. CMapEntity *CMapDoc::CreateEntity(const char *pszClassName, float x, float y, float z)
  826. {
  827. CMapEntity *pEntity = new CMapEntity;
  828. if (pEntity != NULL)
  829. {
  830. GetHistory()->MarkUndoPosition(NULL, "New Entity");
  831. pEntity->SetPlaceholder(TRUE);
  832. Vector Pos;
  833. Pos[0] = x;
  834. Pos[1] = y;
  835. Pos[2] = z;
  836. pEntity->SetOrigin(Pos);
  837. pEntity->SetClass(pszClassName);
  838. AddObjectToWorld(pEntity);
  839. GetHistory()->KeepNew(pEntity);
  840. //
  841. // Update all the views.
  842. //
  843. /* UpdateBox ub;
  844. CMapObjectList ObjectList;
  845. ObjectList.AddTail(pEntity);
  846. ub.Objects = &ObjectList;
  847. ub.Box = *((BoundBox *)pEntity); */
  848. SetModifiedFlag();
  849. }
  850. return(pEntity);
  851. }
  852. //-----------------------------------------------------------------------------
  853. // Purpose:
  854. // Input : pszClassName -
  855. // x -
  856. // y -
  857. // z -
  858. // Output : Returns true on success, false on failure.
  859. //-----------------------------------------------------------------------------
  860. // dvs: Seems better to move some of this functionality into DeleteObject and replace calls to this with FindEntity/DeleteObject calls.
  861. // Probably need to replicate all functions in the doc as follows: DeleteObject, DeleteObjectList to optimize updates. Either that
  862. // or we need a way to lock and unlock updates.
  863. bool CMapDoc::DeleteEntity(const char *pszClassName, float x, float y, float z)
  864. {
  865. CMapEntity *pEntity = FindEntity(pszClassName, x, y, z);
  866. if (pEntity != NULL)
  867. {
  868. GetHistory()->MarkUndoPosition(NULL, "Delete");
  869. DeleteObject(pEntity);
  870. SetModifiedFlag();
  871. return(true);
  872. }
  873. return(false);
  874. }
  875. //-----------------------------------------------------------------------------
  876. // Purpose: Ends a remote shell editing session. This enables the GUI that was
  877. // disabled by BeginShellSession.
  878. //-----------------------------------------------------------------------------
  879. void CMapDoc::EndShellSession(void)
  880. {
  881. //
  882. // Enable all our views.
  883. //
  884. POSITION pos = GetFirstViewPosition();
  885. while (pos != NULL)
  886. {
  887. CView *pView = GetNextView(pos);
  888. pView->EnableWindow(TRUE);
  889. }
  890. GetMainWnd()->EndShellSession();
  891. }
  892. //-----------------------------------------------------------------------------
  893. // Purpose: Finds an object in the map by number. The number corresponds to the
  894. // order in which the object is written to the map file. Thus, through
  895. // this function, brushes and entities can be located by ordinal, as
  896. // reported by the MAP compile tools.
  897. // Input : pObject - Object being checked for a match.
  898. // pFindInfo - Structure containing the search criterea.
  899. // Output : Returns FALSE if this is the object that we are looking for, TRUE
  900. // to continue iterating.
  901. //-----------------------------------------------------------------------------
  902. BOOL CMapDoc::FindEntityCallback(CMapClass *pObject, FindEntity_t *pFindInfo)
  903. {
  904. CMapEntity *pEntity = dynamic_cast<CMapEntity *>(pObject);
  905. if (pEntity != NULL)
  906. {
  907. Vector Pos;
  908. pEntity->GetOrigin(Pos);
  909. // HACK: Round to origin integers since entity origins are rounded when
  910. // saving to MAP file. This makes finding entities from the engine
  911. // in the editor work.
  912. Pos[0] = V_rint(Pos[0]);
  913. Pos[1] = V_rint(Pos[1]);
  914. Pos[2] = V_rint(Pos[2]);
  915. if (VectorCompare(Pos, pFindInfo->Pos))
  916. {
  917. if (stricmp(pEntity->GetClassName(), pFindInfo->szClassName) == 0)
  918. {
  919. pFindInfo->pEntityFound = pEntity;
  920. return(FALSE);
  921. }
  922. }
  923. }
  924. return(TRUE);
  925. }
  926. //-----------------------------------------------------------------------------
  927. // Purpose: Finds an entity by classname and position. Some ambiguity if two
  928. // entities of the same name are at the same position.
  929. // Input : pszClassName - Class name of entity to find, ie "info_node".
  930. // x, y, z - Position of entity in world coordinates.
  931. // Output : Returns a pointer to the entity, NULL if none was found.
  932. //-----------------------------------------------------------------------------
  933. CMapEntity *CMapDoc::FindEntity(const char *pszClassName, float x, float y, float z)
  934. {
  935. CMapEntity *pEntity = NULL;
  936. if (pszClassName != NULL)
  937. {
  938. FindEntity_t FindInfo;
  939. memset(&FindInfo, 0, sizeof(FindInfo));
  940. strcpy(FindInfo.szClassName, pszClassName);
  941. // dvs: HACK - only find by integer coordinates because the editor rounds
  942. // entity origins when saving the MAP file.
  943. FindInfo.Pos[0] = V_rint(x);
  944. FindInfo.Pos[1] = V_rint(y);
  945. FindInfo.Pos[2] = V_rint(z);
  946. m_pWorld->EnumChildren((ENUMMAPCHILDRENPROC)FindEntityCallback, (DWORD)&FindInfo, MAPCLASS_TYPE(CMapEntity));
  947. if (FindInfo.pEntityFound != NULL)
  948. {
  949. Assert(FindInfo.pEntityFound->IsMapClass(MAPCLASS_TYPE(CMapEntity)));
  950. }
  951. pEntity = FindInfo.pEntityFound;
  952. }
  953. return(pEntity);
  954. }
  955. //-----------------------------------------------------------------------------
  956. //-----------------------------------------------------------------------------
  957. CMapEntity *CMapDoc::FindEntityByName( const char *pszName, bool bVisiblesOnly )
  958. {
  959. return m_pWorld->FindEntityByName( pszName, bVisiblesOnly );
  960. }
  961. //-----------------------------------------------------------------------------
  962. // Purpose: Finds all entities in the map with a given class name.
  963. // Input : pFound - List of entities with the class name.
  964. // pszClassName - Class name to match, case insensitive.
  965. // Output : Returns true if any matches were found, false if not.
  966. //-----------------------------------------------------------------------------
  967. bool CMapDoc::FindEntitiesByClassName(CMapEntityList &Found, const char *pszClassName, bool bVisiblesOnly)
  968. {
  969. return m_pWorld->FindEntitiesByClassName( Found, pszClassName, bVisiblesOnly );
  970. }
  971. //-----------------------------------------------------------------------------
  972. //
  973. //-----------------------------------------------------------------------------
  974. bool CMapDoc::FindEntitiesByKeyValue(CMapEntityList &Found, const char *pszKey, const char *pszValue, bool bVisiblesOnly)
  975. {
  976. return m_pWorld->FindEntitiesByKeyValue( Found, pszKey, pszValue, bVisiblesOnly );
  977. }
  978. //-----------------------------------------------------------------------------
  979. //
  980. //-----------------------------------------------------------------------------
  981. bool CMapDoc::FindEntitiesByName( CMapEntityList &Found, const char *pszName, bool bVisiblesOnly )
  982. {
  983. return m_pWorld->FindEntitiesByName( Found, pszName, bVisiblesOnly );
  984. }
  985. //-----------------------------------------------------------------------------
  986. //
  987. //-----------------------------------------------------------------------------
  988. bool CMapDoc::FindEntitiesByNameOrClassName(CMapEntityList &Found, const char *pszName, bool bVisiblesOnly)
  989. {
  990. return m_pWorld->FindEntitiesByNameOrClassName(Found, pszName, bVisiblesOnly);
  991. }
  992. //-----------------------------------------------------------------------------
  993. // Purpose:
  994. //-----------------------------------------------------------------------------
  995. int CMapDoc::GetDocumentCount(void)
  996. {
  997. return s_ActiveDocs.Count();
  998. }
  999. //-----------------------------------------------------------------------------
  1000. // Purpose:
  1001. //-----------------------------------------------------------------------------
  1002. CMapDoc *CMapDoc::GetDocument(int index)
  1003. {
  1004. return s_ActiveDocs.Element(index);
  1005. }
  1006. //-----------------------------------------------------------------------------
  1007. // Purpose:
  1008. //-----------------------------------------------------------------------------
  1009. void CMapDoc::OnViewGotoCoords()
  1010. {
  1011. CStrDlg dlg(0, "", "Coordinates to go to (x y z), ex: 200 -4096 1154\nex: setpos -1 2 3; setang 4 5 6", "Go to coordinates");
  1012. while (dlg.DoModal() == IDOK)
  1013. {
  1014. Vector posVec;
  1015. Vector angVec;
  1016. char setposString[255];
  1017. char setangString[255];
  1018. char semicolonString[2];
  1019. if (sscanf(dlg.m_string, "%f %f %f", &posVec.x, &posVec.y, &posVec.z) == 3)
  1020. {
  1021. // SILLY:
  1022. if ((posVec.x == 200) && (posVec.y == -4096) && (posVec.z == 1154))
  1023. {
  1024. if (AfxMessageBox("Seriously?\n\n(I mean, that was just an example, you were supposed to type in your own numbers)", MB_YESNO | MB_ICONQUESTION) != IDYES)
  1025. continue;
  1026. }
  1027. CenterViewsOn(posVec);
  1028. return;
  1029. }
  1030. if ( sscanf( dlg.m_string, "%s %f %f %f%s %s %f %f %f", setposString, &posVec.x, &posVec.y, &posVec.z, semicolonString, setangString, &angVec.x, &angVec.y, &angVec.z ) == 9 )
  1031. {
  1032. posVec.z += HALF_LIFE_2_EYE_HEIGHT;
  1033. CenterViewsOn( posVec );
  1034. Set3DViewsPosAng( posVec, angVec );
  1035. return;
  1036. }
  1037. AfxMessageBox("Please enter 3 coordinates, space-delimited or use\nsetpos x y z; setang u v w format.", MB_OK | MB_ICONEXCLAMATION);
  1038. }
  1039. }
  1040. //-----------------------------------------------------------------------------
  1041. // Purpose: Invokes a dialog for finding entities by targetname.
  1042. //-----------------------------------------------------------------------------
  1043. void CMapDoc::OnEditFindEntities(void)
  1044. {
  1045. CStrDlg dlg(0, "", "Targetname to find:", "Find Entities");
  1046. if (dlg.DoModal() == IDOK)
  1047. {
  1048. CMapEntityList Found;
  1049. FindEntitiesByName(Found, dlg.m_string, false);
  1050. if (Found.Count() != 0)
  1051. {
  1052. CMapObjectList Select;
  1053. FOR_EACH_OBJ( Found, pos )
  1054. {
  1055. CMapEntity *pEntity = Found.Element(pos);
  1056. Select.AddToTail(pEntity);
  1057. }
  1058. SelectObjectList(&Select);
  1059. CenterViewsOnSelection();
  1060. }
  1061. }
  1062. }
  1063. //-----------------------------------------------------------------------------
  1064. // Purpose: Brings up the 'Go to Brush ID' dialog and selects the indicated
  1065. // brush, if it can be found.
  1066. //-----------------------------------------------------------------------------
  1067. void CMapDoc::OnViewGotoBrush(void)
  1068. {
  1069. CGotoBrushDlg dlg;
  1070. if (dlg.DoModal() == IDOK)
  1071. {
  1072. CMapSolid *pFoundSolid = NULL;
  1073. EnumChildrenPos_t pos;
  1074. CMapClass *pChild = m_pWorld->GetFirstDescendent(pos);
  1075. while (pChild)
  1076. {
  1077. CMapSolid *pSolid = dynamic_cast<CMapSolid *>(pChild);
  1078. if (pSolid && (pSolid->GetID() == dlg.m_nBrushID))
  1079. {
  1080. pFoundSolid = pSolid;
  1081. break;
  1082. }
  1083. pChild = m_pWorld->GetNextDescendent(pos);
  1084. }
  1085. //
  1086. // If we found the brush, select it and center the 2D views on it.
  1087. //
  1088. if (pFoundSolid != NULL)
  1089. {
  1090. SelectObject(pFoundSolid, scSelect|scClear|scSaveChanges );
  1091. CenterViewsOnSelection();
  1092. }
  1093. else
  1094. {
  1095. AfxMessageBox("That brush ID does not exist.");
  1096. }
  1097. }
  1098. }
  1099. class CFindBrushInfo
  1100. {
  1101. public:
  1102. CMapSolid *m_pBrush; // The brush to find.
  1103. int m_nObjectCount;
  1104. bool m_bFound;
  1105. };
  1106. BOOL CMapDoc::GetBrushNumberCallback(CMapClass *pObject, void *pFindInfoVoid)
  1107. {
  1108. CFindBrushInfo *pFindInfo = (CFindBrushInfo*)pFindInfoVoid;
  1109. if ( pObject->IsVisible() )
  1110. {
  1111. if ( pObject == pFindInfo->m_pBrush )
  1112. {
  1113. pFindInfo->m_bFound = true;
  1114. return FALSE; // found it!
  1115. }
  1116. else
  1117. {
  1118. pFindInfo->m_nObjectCount++;
  1119. return TRUE;
  1120. }
  1121. }
  1122. else
  1123. {
  1124. return TRUE;
  1125. }
  1126. }
  1127. void CMapDoc::OnMapShowSelectedBrushNumber()
  1128. {
  1129. CFindBrushInfo info;
  1130. info.m_nObjectCount = 0;
  1131. info.m_bFound = false;
  1132. if ( m_pSelection->IsEmpty() )
  1133. {
  1134. AfxMessageBox( ID_NO_BRUSH_SELECTED, MB_OK );
  1135. return;
  1136. }
  1137. const CMapObjectList *pSelList = m_pSelection->GetList();
  1138. info.m_pBrush = dynamic_cast< CMapSolid* >( pSelList->Element( 0 ) );
  1139. if ( !info.m_pBrush )
  1140. {
  1141. AfxMessageBox( ID_NO_BRUSH_SELECTED, MB_OK );
  1142. return;
  1143. }
  1144. // Enumerate the visible brushes..
  1145. m_pWorld->EnumChildrenRecurseGroupsOnly(
  1146. (ENUMMAPCHILDRENPROC)&CMapDoc::GetBrushNumberCallback, (DWORD)&info, MAPCLASS_TYPE(CMapSolid));
  1147. CString str;
  1148. if ( info.m_bFound )
  1149. {
  1150. str.FormatMessage( ID_BRUSH_NUMBER, info.m_nObjectCount );
  1151. }
  1152. else
  1153. {
  1154. str.FormatMessage( ID_BRUSH_NOT_FOUND );
  1155. }
  1156. AfxMessageBox( str, MB_OK );
  1157. }
  1158. //-----------------------------------------------------------------------------
  1159. // Purpose:
  1160. // Output : TRUE if the document was successfully initialized; otherwise FALSE.
  1161. //-----------------------------------------------------------------------------
  1162. BOOL CMapDoc::OnNewDocument(void)
  1163. {
  1164. if (!CDocument::OnNewDocument())
  1165. {
  1166. return(FALSE);
  1167. }
  1168. if (!SelectDocType())
  1169. {
  1170. return(FALSE);
  1171. }
  1172. Initialize();
  1173. return(TRUE);
  1174. }
  1175. //-----------------------------------------------------------------------------
  1176. // Purpose: Creates an empty world and initializes the path list.
  1177. //-----------------------------------------------------------------------------
  1178. void CMapDoc::Initialize(void)
  1179. {
  1180. Assert(!m_pWorld);
  1181. m_pWorld = new CMapWorld( this );
  1182. m_pWorld->CullTree_Build();
  1183. }
  1184. //-----------------------------------------------------------------------------
  1185. // Purpose:
  1186. // Input : pFile -
  1187. // pData -
  1188. // Output : ChunkFileResult_t
  1189. //-----------------------------------------------------------------------------
  1190. ChunkFileResult_t CMapDoc::LoadEntityCallback(CChunkFile *pFile, CMapDoc *pDoc)
  1191. {
  1192. CMapEntity *pEntity = new CMapEntity;
  1193. ChunkFileResult_t eResult = pEntity->LoadVMF(pFile);
  1194. if (eResult == ChunkFile_Ok)
  1195. {
  1196. CMapWorld *pWorld = pDoc->GetMapWorld();
  1197. pWorld->AddChild(pEntity);
  1198. }
  1199. return(ChunkFile_Ok);
  1200. }
  1201. //-----------------------------------------------------------------------------
  1202. // Purpose:
  1203. // Input : pFile -
  1204. // pData -
  1205. // Output : ChunkFileResult_t
  1206. //-----------------------------------------------------------------------------
  1207. ChunkFileResult_t CMapDoc::LoadHiddenCallback(CChunkFile *pFile, CMapDoc *pDoc)
  1208. {
  1209. CChunkHandlerMap Handlers;
  1210. Handlers.AddHandler("entity", (ChunkHandler_t)CMapDoc::LoadEntityCallback, pDoc);
  1211. pFile->PushHandlers(&Handlers);
  1212. ChunkFileResult_t eResult = pFile->ReadChunk();
  1213. pFile->PopHandlers();
  1214. return(eResult);
  1215. }
  1216. //-----------------------------------------------------------------------------
  1217. // Purpose:
  1218. // Input : pFile -
  1219. // szChunkName -
  1220. // eError -
  1221. // Output : Returns true to continue loading, false to stop loading.
  1222. //-----------------------------------------------------------------------------
  1223. bool CMapDoc::HandleLoadError(CChunkFile *pFile, const char *szChunkName, ChunkFileResult_t eError, CMapDoc *pDoc)
  1224. {
  1225. return(false);
  1226. }
  1227. //-----------------------------------------------------------------------------
  1228. // Purpose: Loads this document from a VMF file.
  1229. // Input : pszFileName - Full path of file to load.
  1230. // Output : Returns true on success, false on failure.
  1231. //-----------------------------------------------------------------------------
  1232. bool CMapDoc::LoadVMF( const char *pszFileName, int LoadFlags )
  1233. {
  1234. bool CreateProgressDlg = m_nInLevelLoad == 0;
  1235. m_nInLevelLoad++;
  1236. //
  1237. // Create a new world to hold the loaded objects.
  1238. //
  1239. if (m_pWorld == NULL)
  1240. {
  1241. m_pWorld = new CMapWorld( this );
  1242. }
  1243. // Show our progress dialog.
  1244. if ( CreateProgressDlg )
  1245. {
  1246. pProgDlg = new CProgressDlg;
  1247. pProgDlg->Create();
  1248. pProgDlg->SetRange(0,18000);
  1249. pProgDlg->SetStep(1000);
  1250. }
  1251. // Set the progress dialog title
  1252. CString caption;
  1253. caption.LoadString(IDS_LOADINGFILE);
  1254. pProgDlg->SetWindowText(caption);
  1255. g_nFileFormatVersion = 0;
  1256. bool bLocked = VisGroups_LockUpdates( true );
  1257. //
  1258. // Open the file.
  1259. //
  1260. CChunkFile File;
  1261. ChunkFileResult_t eResult = File.Open(pszFileName, ChunkFile_Read);
  1262. pProgDlg->StepIt();
  1263. //
  1264. // Read the file.
  1265. //
  1266. if (eResult == ChunkFile_Ok)
  1267. {
  1268. DetailObjects::EnableBuildDetailObjects( false );
  1269. //
  1270. // Set up handlers for the subchunks that we are interested in.
  1271. //
  1272. CChunkHandlerMap Handlers;
  1273. Handlers.AddHandler("world", (ChunkHandler_t)CMapDoc::LoadWorldCallback, this);
  1274. Handlers.AddHandler("hidden", (ChunkHandler_t)CMapDoc::LoadHiddenCallback, this);
  1275. Handlers.AddHandler("entity", (ChunkHandler_t)CMapDoc::LoadEntityCallback, this);
  1276. Handlers.AddHandler("versioninfo", (ChunkHandler_t)CMapDoc::LoadVersionInfoCallback, this);
  1277. Handlers.AddHandler("autosave", (ChunkHandler_t)CMapDoc::LoadAutosaveCallback, this);
  1278. Handlers.AddHandler("visgroups", (ChunkHandler_t)CVisGroup::LoadVisGroupsCallback, this);
  1279. Handlers.AddHandler("viewsettings", (ChunkHandler_t)CMapDoc::LoadViewSettingsCallback, this);
  1280. Handlers.AddHandler("cordon", (ChunkHandler_t)CMapDoc::LoadCordonCallback, this);
  1281. m_pToolManager->AddToolHandlers( &Handlers );
  1282. Handlers.SetErrorHandler((ChunkErrorHandler_t)CMapDoc::HandleLoadError, this);
  1283. File.PushHandlers(&Handlers);
  1284. if ( ( LoadFlags & VMF_LOAD_ACTIVATE ) )
  1285. {
  1286. SetActiveMapDoc( this );
  1287. }
  1288. m_bLoading = true;
  1289. //
  1290. // Read the sub-chunks. We ignore keys in the root of the file, so we don't pass a
  1291. // key value callback to ReadChunk.
  1292. //
  1293. pProgDlg->SetWindowText( "Reading Chunks..." );
  1294. while (eResult == ChunkFile_Ok)
  1295. {
  1296. eResult = File.ReadChunk();
  1297. }
  1298. pProgDlg->SetStep(5000);
  1299. pProgDlg->StepIt();
  1300. if (eResult == ChunkFile_EOF)
  1301. {
  1302. eResult = ChunkFile_Ok;
  1303. }
  1304. File.PopHandlers();
  1305. }
  1306. if (eResult == ChunkFile_Ok)
  1307. {
  1308. pProgDlg->SetWindowText( "Postload Processing..." );
  1309. Postload( pszFileName );
  1310. pProgDlg->StepIt();
  1311. m_bLoading = false;
  1312. }
  1313. else
  1314. {
  1315. GetMainWnd()->MessageBox(File.GetErrorText(eResult), "Error loading file", MB_OK | MB_ICONEXCLAMATION);
  1316. }
  1317. if ( bLocked )
  1318. VisGroups_LockUpdates( false );
  1319. if ( pProgDlg && CreateProgressDlg )
  1320. {
  1321. pProgDlg->DestroyWindow();
  1322. delete pProgDlg;
  1323. pProgDlg = NULL;
  1324. }
  1325. if ( ( LoadFlags & VMF_LOAD_ACTIVATE ) )
  1326. { // force rendering even if application is not active
  1327. UpdateAllViews( MAPVIEW_UPDATE_OBJECTS );
  1328. APP()->SetForceRenderNextFrame();
  1329. }
  1330. m_nInLevelLoad--;
  1331. return(eResult == ChunkFile_Ok);
  1332. }
  1333. void CMapDoc::BuildAllDetailObjects()
  1334. {
  1335. EnumChildrenPos_t pos;
  1336. CMapClass *pChild = m_pWorld->GetFirstDescendent(pos);
  1337. while (pChild != NULL)
  1338. {
  1339. CMapSolid *pSolid = dynamic_cast <CMapSolid *> (pChild);
  1340. if (pSolid != NULL)
  1341. {
  1342. int nFaces = pSolid->GetFaceCount();
  1343. for(int i = 0; i < nFaces; i++)
  1344. {
  1345. CMapFace *pFace = pSolid->GetFace( i );
  1346. if ( pFace )
  1347. DetailObjects::BuildAnyDetailObjects( pFace );
  1348. }
  1349. }
  1350. pChild = m_pWorld->GetNextDescendent(pos);
  1351. }
  1352. }
  1353. //-----------------------------------------------------------------------------
  1354. // Purpose:
  1355. // Input : pLoadInfo -
  1356. // Output : ChunkFileResult_t
  1357. //-----------------------------------------------------------------------------
  1358. ChunkFileResult_t CMapDoc::LoadVersionInfoCallback(CChunkFile *pFile, CMapDoc *pDoc)
  1359. {
  1360. return(pFile->ReadChunk((KeyHandler_t)LoadVersionInfoKeyCallback, pDoc));
  1361. }
  1362. //-----------------------------------------------------------------------------
  1363. // Purpose: Handles keyvalues when loading the version info chunk of VMF files.
  1364. // Input : szKey - Key to handle.
  1365. // szValue - Value of key.
  1366. // pDoc - Document being loaded.
  1367. // Output : Returns ChunkFile_Ok if all is well.
  1368. //-----------------------------------------------------------------------------
  1369. ChunkFileResult_t CMapDoc::LoadVersionInfoKeyCallback(const char *szKey, const char *szValue, CMapDoc *pDoc)
  1370. {
  1371. KeyInt("mapversion", pDoc->m_nDocVersion);
  1372. KeyInt("formatversion", g_nFileFormatVersion);
  1373. KeyBool("prefab", pDoc->m_bPrefab);
  1374. return(ChunkFile_Ok);
  1375. }
  1376. ChunkFileResult_t CMapDoc::LoadAutosaveCallback( CChunkFile *pFile, CMapDoc *pDoc)
  1377. {
  1378. return(pFile->ReadChunk((KeyHandler_t)LoadAutosaveKeyCallback, pDoc));
  1379. }
  1380. ChunkFileResult_t CMapDoc::LoadAutosaveKeyCallback(const char *szKey, const char *szValue, CMapDoc *pDoc)
  1381. {
  1382. if (!stricmp(szKey, "originalname"))
  1383. {
  1384. pDoc->m_bIsAutosave = true;
  1385. char szTempName[MAX_PATH];
  1386. Q_strcpy( szTempName, szValue );
  1387. Q_FixSlashes( szTempName, '\\' );
  1388. pDoc->m_strAutosavedFrom = szTempName;
  1389. }
  1390. return(ChunkFile_Ok);
  1391. }
  1392. ChunkFileResult_t CMapDoc::LoadCordonCallback(CChunkFile *pFile, CMapDoc *pDoc)
  1393. {
  1394. return pFile->ReadChunk((KeyHandler_t)LoadCordonKeyCallback, pDoc);
  1395. }
  1396. ChunkFileResult_t CMapDoc::LoadCordonKeyCallback(const char *szKey, const char *szValue, CMapDoc *pDoc)
  1397. {
  1398. if (!stricmp(szKey, "mins"))
  1399. {
  1400. CChunkFile::ReadKeyValuePoint(szValue, pDoc->m_vCordonMins);
  1401. }
  1402. else if (!stricmp(szKey, "maxs"))
  1403. {
  1404. CChunkFile::ReadKeyValuePoint(szValue, pDoc->m_vCordonMaxs);
  1405. }
  1406. else if (!stricmp(szKey, "active"))
  1407. {
  1408. bool bActive;
  1409. CChunkFile::ReadKeyValueBool(szValue, bActive );
  1410. pDoc->SetCordoning( bActive );
  1411. }
  1412. return(ChunkFile_Ok);
  1413. }
  1414. //-----------------------------------------------------------------------------
  1415. // Purpose:
  1416. // Input : pFile -
  1417. // pData -
  1418. // Output : ChunkFileResult_t
  1419. //-----------------------------------------------------------------------------
  1420. ChunkFileResult_t CMapDoc::LoadViewSettingsKeyCallback(const char *szKey, const char *szValue, CMapDoc *pDoc)
  1421. {
  1422. KeyBool( "bSnapToGrid", pDoc->m_bSnapToGrid);
  1423. KeyBool( "bShowGrid", pDoc->m_bShowGrid);
  1424. KeyBool( "bShowLogicalGrid", pDoc->m_bShowLogicalGrid);
  1425. KeyInt( "nGridSpacing", pDoc->m_nGridSpacing);
  1426. KeyBool( "bShow3DGrid", pDoc->m_bShow3DGrid);
  1427. return(ChunkFile_Ok);
  1428. }
  1429. //-----------------------------------------------------------------------------
  1430. // Purpose: Loads the view settings chunk, where per-map view settings are kept.
  1431. //-----------------------------------------------------------------------------
  1432. ChunkFileResult_t CMapDoc::LoadViewSettingsCallback(CChunkFile *pFile, CMapDoc *pDoc)
  1433. {
  1434. ChunkFileResult_t eResult = pFile->ReadChunk((KeyHandler_t)LoadViewSettingsKeyCallback, pDoc);
  1435. if (eResult == ChunkFile_Ok)
  1436. {
  1437. pDoc->UpdateStatusBarSnap();
  1438. }
  1439. return eResult;
  1440. }
  1441. //-----------------------------------------------------------------------------
  1442. // Purpose:
  1443. // Input : pFile -
  1444. // pData -
  1445. // Output : ChunkFileResult_t
  1446. //-----------------------------------------------------------------------------
  1447. ChunkFileResult_t CMapDoc::LoadWorldCallback(CChunkFile *pFile, CMapDoc *pDoc)
  1448. {
  1449. CMapWorld *pWorld = pDoc->GetMapWorld();
  1450. ChunkFileResult_t eResult = pWorld->LoadVMF(pFile);
  1451. return(eResult);
  1452. }
  1453. //-----------------------------------------------------------------------------
  1454. // Purpose: Called after loading a map file.
  1455. //-----------------------------------------------------------------------------
  1456. void CMapDoc::Postload(const char *pszFileName)
  1457. {
  1458. if ( pszFileName[ 0 ] )
  1459. { // this path needs to be set early so that instances may properly find their base path
  1460. SetPathName( pszFileName, FALSE );
  1461. }
  1462. //
  1463. // Report any noncritical loading errors here.
  1464. //
  1465. if (CMapSolid::GetBadSolidCount() > 0)
  1466. {
  1467. char szError[ 1024 ];
  1468. V_sprintf_safe( szError, "For your information, %d solid(s) were not loaded due to errors in the file. Would you like to Re-Save your map with the invalid solids removed?", CMapSolid::GetBadSolidCount() );
  1469. if ( GetMainWnd()->MessageBox(szError, "Warning", MB_YESNO | MB_ICONQUESTION) == IDYES )
  1470. {
  1471. OnFileSave();
  1472. }
  1473. }
  1474. //
  1475. // Count GUIDs before calling PostLoadWorld because objects that need to generate GUIDs
  1476. // may do so in PostLoadWorld.
  1477. //
  1478. CountGUIDs();
  1479. m_pWorld->PostloadWorld();
  1480. if ( pProgDlg )
  1481. {
  1482. pProgDlg->StepIt();
  1483. pProgDlg->SetStep(1000);
  1484. }
  1485. if ( pProgDlg )
  1486. {
  1487. pProgDlg->SetWindowText( "Assigning to groups..." );
  1488. }
  1489. AssignToGroups();
  1490. AssignToVisGroups();
  1491. if ( pProgDlg )
  1492. {
  1493. pProgDlg->StepIt();
  1494. }
  1495. if ( pProgDlg )
  1496. {
  1497. pProgDlg->SetWindowText( "Postprocessing VisGroups..." );
  1498. }
  1499. m_pWorld->PostloadVisGroups();
  1500. if ( pProgDlg )
  1501. {
  1502. pProgDlg->StepIt();
  1503. }
  1504. // Do this after AssignToVisGroups, because deleting objects causes empty visgroups to be purged,
  1505. // and until AssignToVisGroups is called all the visgroups are empty!
  1506. if ( pProgDlg )
  1507. {
  1508. pProgDlg->SetWindowText( "Updating Visibility..." );
  1509. }
  1510. RemoveEmptyGroups();
  1511. UpdateVisibilityAll();
  1512. if ( pProgDlg )
  1513. {
  1514. pProgDlg->StepIt();
  1515. }
  1516. // update displacement neighbors
  1517. if ( pProgDlg )
  1518. {
  1519. pProgDlg->SetWindowText( "Updating Displacements..." );
  1520. }
  1521. IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager();
  1522. if( pDispMgr )
  1523. {
  1524. int count = pDispMgr->WorldCount();
  1525. for( int ndx = 0; ndx < count; ndx++ )
  1526. {
  1527. CMapDisp *pDisp = pDispMgr->GetFromWorld( ndx );
  1528. if( pDisp )
  1529. {
  1530. CMapFace *pFace = ( CMapFace* )pDisp->GetParent();
  1531. pDispMgr->FindWorldNeighbors( pFace->GetDisp() );
  1532. }
  1533. }
  1534. }
  1535. if ( pProgDlg )
  1536. {
  1537. pProgDlg->StepIt();
  1538. }
  1539. //
  1540. // Do batch search and replace of textures from trans.txt if it exists.
  1541. //
  1542. if ( pProgDlg )
  1543. {
  1544. pProgDlg->SetWindowText( "Updating Texture Names..." );
  1545. }
  1546. char translationFilename[MAX_PATH];
  1547. Q_snprintf( translationFilename, sizeof( translationFilename ), "materials/trans.txt" );
  1548. FileHandle_t searchReplaceFP = g_pFileSystem->Open( translationFilename, "r" );
  1549. if( searchReplaceFP )
  1550. {
  1551. BatchReplaceTextures( searchReplaceFP );
  1552. g_pFileSystem->Close( searchReplaceFP );
  1553. }
  1554. if ( pProgDlg )
  1555. {
  1556. pProgDlg->StepIt();
  1557. }
  1558. if ( pProgDlg )
  1559. {
  1560. pProgDlg->SetWindowText( "Building Cull Tree..." );
  1561. }
  1562. m_pWorld->CullTree_Build();
  1563. if ( pProgDlg )
  1564. {
  1565. pProgDlg->StepIt();
  1566. }
  1567. // We disabled building detail objects above to prevent it from generating them extra times.
  1568. // Now generate the ones that need to be generated.
  1569. if ( pProgDlg )
  1570. {
  1571. pProgDlg->SetWindowText( "Building Detail Objects..." );
  1572. }
  1573. DetailObjects::EnableBuildDetailObjects( true );
  1574. BuildAllDetailObjects();
  1575. if ( pProgDlg )
  1576. {
  1577. pProgDlg->SetWindowText( "Finished Loading!" );
  1578. }
  1579. }
  1580. //-----------------------------------------------------------------------------
  1581. // Purpose: this function will hook up the manifest document to this map document
  1582. // Input : pManifest - the manifest document
  1583. //-----------------------------------------------------------------------------
  1584. void CMapDoc::SetManifest( CManifest *pManifest )
  1585. {
  1586. m_pManifest = pManifest;
  1587. m_pManifestOwner = pManifest;
  1588. if ( m_pSelection )
  1589. {
  1590. delete m_pSelection;
  1591. }
  1592. m_pSelection = pManifest->GetSelection();
  1593. }
  1594. //-----------------------------------------------------------------------------
  1595. // Purpose: this routine will check to see if all objects are editable within
  1596. // the selection. If one is not editable, the entire selection is not
  1597. // editable.
  1598. // Output : the editable state of the selection
  1599. //-----------------------------------------------------------------------------
  1600. bool CMapDoc::IsSelectionEditable( void )
  1601. {
  1602. bool bResult = true;
  1603. int nCount = m_pSelection->GetCount();
  1604. for( int i = 0; i < nCount; i++ )
  1605. {
  1606. CMapClass *pObj = m_pSelection->GetList()->Element( i );
  1607. if ( !pObj->IsEditable() )
  1608. {
  1609. bResult = false;
  1610. break;
  1611. }
  1612. }
  1613. return bResult;
  1614. }
  1615. //-----------------------------------------------------------------------------
  1616. // Purpose: this routine will take a single map document and turn it into a
  1617. // manifest document containing just this one map document.
  1618. // Output : true if the conversion worked
  1619. //-----------------------------------------------------------------------------
  1620. bool CMapDoc::CreateNewManifest( void )
  1621. {
  1622. if ( IsModified() )
  1623. {
  1624. OnFileSave();
  1625. }
  1626. if ( IsModified() )
  1627. {
  1628. AfxMessageBox( "Manifest was NOT created as map was not able to be saved!", MB_OK );
  1629. return false;
  1630. }
  1631. CManifest *pManifest = dynamic_cast< CManifest * >( APP()->pManifestDocTemplate->OpenDocumentFile( NULL ) );
  1632. if(Options.general.bLoadwinpos && Options.general.bIndependentwin)
  1633. {
  1634. ::GetMainWnd()->LoadWindowStates();
  1635. }
  1636. if ( pManifest->AddExistingMap( GetPathName(), false ) )
  1637. {
  1638. OnCloseDocument();
  1639. pManifest->SetActiveMapDoc( pManifest );
  1640. pManifest->ActivateMapDoc( pManifest );
  1641. ToolManager()->SetTool( TOOL_POINTER );
  1642. GetMainWnd()->GlobalNotify( WM_MAPDOC_CHANGED );
  1643. pManifest->UpdateAllViews( MAPVIEW_UPDATE_SELECTION | MAPVIEW_UPDATE_TOOL | MAPVIEW_RENDER_NOW );
  1644. AfxMessageBox( "Manifest was successfully created and has automatically been saved.", MB_OK );
  1645. }
  1646. else
  1647. {
  1648. pManifest->OnCloseDocument();
  1649. AfxMessageBox( "Manifest was NOT created!", MB_OK );
  1650. return false;
  1651. }
  1652. return true;
  1653. }
  1654. int CMapDoc::GetClipboardCount( void )
  1655. {
  1656. return GetHammerClipboard()->Objects.Count();
  1657. }
  1658. //-----------------------------------------------------------------------------
  1659. // Purpose: this does a special paste for manifest maps
  1660. // Input : pDestWorld
  1661. // vecOffset
  1662. // vecRotate
  1663. // pParent
  1664. // bMakeEntityNamesUnique
  1665. // pszEntityNamePrefix
  1666. //-----------------------------------------------------------------------------
  1667. void CMapDoc::ManifestPaste( CMapWorld *pDestWorld, Vector vecOffset, QAngle vecRotate, CMapClass *pParent, bool bMakeEntityNamesUnique, const char *pszEntityNamePrefix )
  1668. {
  1669. Paste( GetHammerClipboard()->Objects, GetHammerClipboard()->pSourceWorld, pDestWorld, vecOffset, vecRotate, pParent, bMakeEntityNamesUnique, pszEntityNamePrefix );
  1670. GetHammerClipboard()->Objects.PurgeAndDeleteElements();
  1671. SetModifiedFlag( true );
  1672. }
  1673. //-----------------------------------------------------------------------------
  1674. // Purpose: this handles the routing of letting instances know their map may have been updated
  1675. // Input : pInstanceMapDoc - the map that was updated
  1676. //-----------------------------------------------------------------------------
  1677. void CMapDoc::UpdateInstanceMap( CMapDoc *pInstanceMapDoc )
  1678. {
  1679. bool bUpdated = false;
  1680. if ( m_bCollapsingInstances )
  1681. {
  1682. return;
  1683. }
  1684. const CMapObjectList *pChildren = m_pWorld->GetChildren();
  1685. FOR_EACH_OBJ( *pChildren, pos )
  1686. {
  1687. CMapClass *pChild = pChildren->Element( pos );
  1688. CMapEntity *pEntity = dynamic_cast< CMapEntity * >( pChild );
  1689. if ( pEntity && stricmp( pEntity->GetClassName(), "func_instance" ) == 0 )
  1690. {
  1691. CMapInstance *pMapInstance = pEntity->GetChildOfType( ( CMapInstance * )NULL );
  1692. if ( pMapInstance )
  1693. {
  1694. if ( pMapInstance->GetInstancedMap() == pInstanceMapDoc )
  1695. {
  1696. pMapInstance->UpdateInstanceMap();
  1697. bUpdated = true;
  1698. }
  1699. }
  1700. }
  1701. }
  1702. if ( bUpdated )
  1703. {
  1704. APP()->pMapDocTemplate->UpdateInstanceMap( this );
  1705. }
  1706. }
  1707. //-----------------------------------------------------------------------------
  1708. // Purpose: This function will collapse instances into the map ( and any children instances )
  1709. //-----------------------------------------------------------------------------
  1710. void CMapDoc::CollapseInstances( bool bOnlySelected )
  1711. {
  1712. int InstanceCount = 0;
  1713. if ( AfxMessageBox( "Collapsing does not perform all of the operations that the BSP process does for instancing. There may be some issues or differences between results. Are you sure you want to do this?", MB_YESNO | MB_ICONQUESTION ) == IDNO )
  1714. {
  1715. return;
  1716. }
  1717. m_bCollapsingInstances = true;
  1718. const CMapObjectList *pChildren = m_pWorld->GetChildren();
  1719. FOR_EACH_OBJ( *pChildren, pos )
  1720. {
  1721. CMapClass *pChild = pChildren->Element( pos );
  1722. CMapEntity *pEntity = dynamic_cast< CMapEntity * >( pChild );
  1723. if ( pEntity && stricmp( pEntity->GetClassName(), "func_instance" ) == 0 && ( !bOnlySelected || pEntity->GetSelectionState() != SELECT_NONE ) )
  1724. {
  1725. CMapInstance *pMapInstance = pEntity->GetChildOfType( ( CMapInstance * )NULL );
  1726. if ( pMapInstance )
  1727. {
  1728. if ( pMapInstance->GetInstancedMap() )
  1729. {
  1730. char temp[ 256 ];
  1731. Vector origin;
  1732. QAngle angles;
  1733. pMapInstance->GetInstancedMap()->OnEditSelectall();
  1734. pMapInstance->GetInstancedMap()->Copy();
  1735. pMapInstance->GetInstancedMap()->OnEditClearselection();
  1736. SetActiveMapDoc( this ); // just in case the last instance copy forces the map to close, we need to make ourselves active again
  1737. InstanceCount++;
  1738. sprintf( temp, "AutoInstance%d-", InstanceCount );
  1739. pEntity->GetOrigin( origin );
  1740. pEntity->GetAngles( angles );
  1741. PasteInstance( GetHammerClipboard()->Objects, pMapInstance->GetInstancedMap()->GetMapWorld(), GetMapWorld(), origin, angles, NULL, true, temp );
  1742. Update();
  1743. }
  1744. DeleteObject( pEntity );
  1745. m_UpdateList.RemoveAll();
  1746. SetActiveMapDoc( this ); // just in case the last instance copy forces the map to close, we need to make ourselves active again
  1747. pos = -1; // start over so that we find any instances within instances
  1748. }
  1749. }
  1750. }
  1751. m_bCollapsingInstances = false;
  1752. APP()->pMapDocTemplate->UpdateInstanceMap( this );
  1753. APP()->pManifestDocTemplate->UpdateInstanceMap( this );
  1754. SetModifiedFlag( true );
  1755. UpdateAllViews( MAPVIEW_UPDATE_SELECTION | MAPVIEW_UPDATE_TOOL | MAPVIEW_RENDER_NOW );
  1756. char temp[ 256 ];
  1757. sprintf( temp, "A total of %d instances were collapsed into the main map.", InstanceCount );
  1758. AfxMessageBox( temp, MB_OK | MB_ICONEXCLAMATION );
  1759. }
  1760. //-----------------------------------------------------------------------------
  1761. // Purpose: this function will allow you to iterate through a string looking for $variables
  1762. // Input : Text - the string to search through
  1763. // StartPos - the starting index in the string
  1764. // Output : Result - returns the $variable if it exists
  1765. // returns the string index after the variable if one is found, otherwise -1 if not found
  1766. //-----------------------------------------------------------------------------
  1767. int FindInstanceParm( char *Text, int StartPos, CString &Result )
  1768. {
  1769. char *found;
  1770. found = strchr( Text + StartPos, '$' );
  1771. if ( found == NULL )
  1772. {
  1773. return -1;
  1774. }
  1775. StartPos = found - Text;
  1776. // Grab the $
  1777. Result += Text[ StartPos ];
  1778. StartPos++;
  1779. while( Text[ StartPos ] )
  1780. {
  1781. if ( V_isalnum ( Text[ StartPos ] ) == 0 && Text[ StartPos ] != '_' )
  1782. {
  1783. break;
  1784. }
  1785. Result += Text[ StartPos ];
  1786. StartPos++;
  1787. }
  1788. return StartPos;
  1789. }
  1790. void CMapDoc::PopulateInstanceParms_r( CMapEntity *pEntity, const CMapObjectList *pChildren, CUtlVector< CString > &ParmList )
  1791. {
  1792. FOR_EACH_OBJ( *pChildren, pos )
  1793. {
  1794. CMapClass *pChild = pChildren->Element( pos );
  1795. CMapEntity *pInstanceEntity = dynamic_cast< CMapEntity * >( pChild );
  1796. if ( pInstanceEntity && pInstanceEntity != pEntity )
  1797. {
  1798. for ( int i = pInstanceEntity->GetFirstKeyValue(); i != pInstanceEntity->GetInvalidKeyValue(); i = pInstanceEntity->GetNextKeyValue( i ) )
  1799. {
  1800. LPCTSTR pValue = pInstanceEntity->GetKeyValue( i );
  1801. int StartPos = 0;
  1802. CString Result;
  1803. while( ( StartPos = FindInstanceParm( (char * )pValue, StartPos, Result ) ) != -1 )
  1804. {
  1805. if ( ParmList.Find( Result ) == -1 )
  1806. {
  1807. ParmList.AddToTail( Result );
  1808. }
  1809. }
  1810. }
  1811. int nCount = pInstanceEntity->Connections_GetCount();
  1812. for ( int j = 0; j < nCount; ++j )
  1813. {
  1814. CEntityConnection *pConn = pInstanceEntity->Connections_Get( j );
  1815. const char *pValue = pConn->GetTargetName();
  1816. int StartPos = 0;
  1817. CString Result;
  1818. while( ( StartPos = FindInstanceParm( (char * )pValue, StartPos, Result ) ) != -1 )
  1819. {
  1820. if ( ParmList.Find( Result ) == -1 )
  1821. {
  1822. ParmList.AddToTail( Result );
  1823. }
  1824. }
  1825. }
  1826. }
  1827. if ( pInstanceEntity != pEntity )
  1828. {
  1829. PopulateInstanceParms_r( pEntity, pChild->GetChildren(), ParmList );
  1830. }
  1831. }
  1832. }
  1833. //-----------------------------------------------------------------------------
  1834. // Purpose: this function will iterate through all entities of the current map looking for $variables.
  1835. // any ones that are found will be populated as Parm key values.
  1836. // Input : pEntity - the entity to populate
  1837. //-----------------------------------------------------------------------------
  1838. void CMapDoc::PopulateInstanceParms( CMapEntity *pEntity )
  1839. {
  1840. CUtlVector< CString > ParmList;
  1841. PopulateInstanceParms_r( pEntity, m_pWorld->GetChildren(), ParmList );
  1842. for( int i = 0; i < ParmList.Count(); i++ )
  1843. {
  1844. bool bFound = false;
  1845. for ( int j = pEntity->GetFirstKeyValue(); j != pEntity->GetInvalidKeyValue(); j = pEntity->GetNextKeyValue( j ) )
  1846. {
  1847. LPCTSTR pValue = pEntity->GetKeyValue( j );
  1848. if ( strnicmp( pValue, ParmList[ i ], strlen( ParmList[ i ] ) ) == 0 )
  1849. {
  1850. bFound = true;
  1851. break;
  1852. }
  1853. }
  1854. if ( bFound == false )
  1855. {
  1856. int j = 1;
  1857. while( 1 )
  1858. {
  1859. char tempKey[ 128 ];
  1860. sprintf( tempKey, "parm%d", j );
  1861. if ( pEntity->GetKeyValue( tempKey ) == NULL )
  1862. {
  1863. char tempValue[ MAX_KEYVALUE_LEN ];
  1864. sprintf( tempValue, "%s string", (const char*)ParmList[ i ] );
  1865. pEntity->SetKeyValue( tempKey, tempValue );
  1866. break;
  1867. }
  1868. j++;
  1869. }
  1870. }
  1871. }
  1872. }
  1873. //-----------------------------------------------------------------------------
  1874. // Purpose: this function will look through the instance for a func_instance_parms. If one is
  1875. // found, then it will populate the replace fields with the parm fields.
  1876. // Input : pEntity - the func_instance
  1877. //-----------------------------------------------------------------------------
  1878. void CMapDoc::PopulateInstance( CMapEntity *pEntity )
  1879. {
  1880. CMapInstance *pMapInstance = pEntity->GetChildOfType( ( CMapInstance * )NULL );
  1881. if ( pMapInstance == NULL || pMapInstance->GetInstancedMap() == NULL )
  1882. {
  1883. return;
  1884. }
  1885. CMapEntityList entityList;
  1886. pMapInstance->GetInstancedMap()->FindEntitiesByClassName( entityList, "func_instance_parms", false );
  1887. if ( entityList.Count() != 1 )
  1888. {
  1889. return;
  1890. }
  1891. CMapEntity *pInstanceParmsEntity = entityList.Element( 0 );
  1892. for ( int i = pInstanceParmsEntity->GetFirstKeyValue(); i != pInstanceParmsEntity->GetInvalidKeyValue(); i = pInstanceParmsEntity->GetNextKeyValue( i ) )
  1893. {
  1894. LPCTSTR pKey = pInstanceParmsEntity->GetKey( i );
  1895. LPCTSTR pValue = pInstanceParmsEntity->GetKeyValue( i );
  1896. if ( strnicmp( pKey, "parm", strlen( "parm" ) ) == 0 )
  1897. {
  1898. const char *pos = strchr( pValue, ' ' );
  1899. if ( pos == NULL )
  1900. {
  1901. continue;
  1902. }
  1903. int len = pos - pValue;
  1904. bool bFound = false;
  1905. for ( int j = pEntity->GetFirstKeyValue(); j != pEntity->GetInvalidKeyValue(); j = pEntity->GetNextKeyValue( j ) )
  1906. {
  1907. LPCTSTR pInstanceKey = pEntity->GetKey( j );
  1908. LPCTSTR pInstanceValue = pEntity->GetKeyValue( j );
  1909. if ( strnicmp( pInstanceKey, "replace", strlen( "replace" ) ) == 0 &&
  1910. strnicmp( pInstanceValue, pValue, len ) == 0 )
  1911. {
  1912. bFound = true;
  1913. break;
  1914. }
  1915. }
  1916. if ( bFound == false )
  1917. {
  1918. int j = 1;
  1919. while( 1 )
  1920. {
  1921. char tempKey[ MAX_KEYVALUE_LEN ];
  1922. sprintf( tempKey, "replace%02d", j );
  1923. if ( pEntity->GetKeyValue( tempKey ) == NULL )
  1924. {
  1925. char tempValue[ MAX_KEYVALUE_LEN ];
  1926. strcpy( tempValue, pValue );
  1927. strcpy( &tempValue[ len ], " ???" );
  1928. pEntity->SetKeyValue( tempKey, tempValue );
  1929. break;
  1930. }
  1931. j++;
  1932. }
  1933. }
  1934. }
  1935. }
  1936. }
  1937. //-----------------------------------------------------------------------------
  1938. // Purpose: this function will notify all children that their owning instance has been moved.
  1939. // currently not used.
  1940. //-----------------------------------------------------------------------------
  1941. void CMapDoc::InstanceMoved( void )
  1942. {
  1943. #if 0
  1944. const CMapObjectList *pChildren = m_pWorld->GetChildren();
  1945. FOR_EACH_OBJ( *pChildren, pos )
  1946. {
  1947. CMapClass *pChild = pChildren->Element( pos );
  1948. pChild->InstanceMoved();
  1949. }
  1950. #endif
  1951. }
  1952. //-----------------------------------------------------------------------------
  1953. // Purpose: this function will return the current primary map document of the
  1954. // manifest. Generally this is the map layer that is editable where all
  1955. // entity / brush operations will take place.
  1956. // Output : the primary map document
  1957. //-----------------------------------------------------------------------------
  1958. CMapWorld *CMapDoc::GetCurrentWorld( void )
  1959. {
  1960. if ( m_pManifest )
  1961. {
  1962. return m_pManifest->GetActiveMapDoc()->m_pWorld;
  1963. }
  1964. else
  1965. {
  1966. return m_pWorld;
  1967. }
  1968. }
  1969. //-----------------------------------------------------------------------------
  1970. // Purpose:
  1971. // Output : Returns TRUE on success, FALSE on failure.
  1972. //-----------------------------------------------------------------------------
  1973. BOOL CMapDoc::SelectDocType(void)
  1974. {
  1975. // dvs: Disabled for single-config running.
  1976. // if no game configs are set up, we must set them up
  1977. //if (Options.configs.nConfigs == 0)
  1978. //{
  1979. // if (AfxMessageBox(IDS_NO_CONFIGS_AVAILABLE, MB_YESNO) == IDYES)
  1980. // {
  1981. // APP()->OpenURL(ID_HELP_FIRST_TIME_SETUP, GetMainWnd()->GetSafeHwnd());
  1982. // }
  1983. //
  1984. // COptionProperties dlg("Configure Hammer", NULL, 0);
  1985. // dlg.DoModal();
  1986. // if (Options.configs.nConfigs == 0)
  1987. // {
  1988. // return FALSE;
  1989. // }
  1990. //}
  1991. //
  1992. //
  1993. // Prompt the user to select a game configuration.
  1994. //
  1995. //CGameConfig *pGame = APP()->PromptForGameConfig();
  1996. //if (!pGame)
  1997. //{
  1998. // return FALSE;
  1999. //}
  2000. CGameConfig *pGame = g_pGameConfig;
  2001. //
  2002. // Try to find some textures that this game can use.
  2003. //
  2004. if (!g_Textures.HasTexturesForConfig(pGame))
  2005. {
  2006. AfxMessageBox(IDS_NO_TEXTURES_AVAILABLE);
  2007. COptionProperties dlg("Configure Hammer", NULL, 0);
  2008. dlg.DoModal();
  2009. if (!g_Textures.HasTexturesForConfig(pGame))
  2010. {
  2011. return FALSE;
  2012. }
  2013. }
  2014. m_pGame = pGame;
  2015. if (GetActiveMapDoc() != this)
  2016. {
  2017. SetActiveMapDoc(this);
  2018. }
  2019. return(TRUE);
  2020. }
  2021. //-----------------------------------------------------------------------------
  2022. // Purpose: set up this document to edit a prefab data .. when the object is saved,
  2023. // save it back to the library instead of to a file.
  2024. // Input : dwPrefabID -
  2025. //-----------------------------------------------------------------------------
  2026. void CMapDoc::EditPrefab3D(DWORD dwPrefabID)
  2027. {
  2028. CPrefab3D *pPrefab = (CPrefab3D *)CPrefab::FindID(dwPrefabID);
  2029. Assert(pPrefab);
  2030. // set up local variables
  2031. m_dwPrefabID = dwPrefabID;
  2032. m_dwPrefabLibraryID = pPrefab->GetLibraryID();
  2033. m_bEditingPrefab = TRUE;
  2034. SetPathName(pPrefab->GetName(), FALSE);
  2035. SetTitle(pPrefab->GetName());
  2036. // copy prefab data to world
  2037. if (!pPrefab->IsLoaded())
  2038. {
  2039. pPrefab->Load();
  2040. }
  2041. //
  2042. // Copying into world, so we update the object dependencies to insure
  2043. // that any object references in the prefab get resolved.
  2044. //
  2045. m_pWorld->CopyFrom(pPrefab->GetWorld(), false);
  2046. m_pWorld->CopyChildrenFrom(pPrefab->GetWorld(), false);
  2047. }
  2048. //-----------------------------------------------------------------------------
  2049. // Purpose:
  2050. // Input : file -
  2051. // fIsStoring -
  2052. // bRMF -
  2053. // Output : Returns TRUE on success, FALSE on failure.
  2054. //-----------------------------------------------------------------------------
  2055. BOOL CMapDoc::Serialize(std::fstream& file, BOOL fIsStoring, BOOL bRMF)
  2056. {
  2057. SetActiveMapDoc(this);
  2058. // check for editing prefab
  2059. if(m_bEditingPrefab)
  2060. {
  2061. // save prefab in library
  2062. CPrefabLibrary *pLibrary = CPrefabLibrary::FindID(m_dwPrefabLibraryID);
  2063. if(!pLibrary)
  2064. {
  2065. static int id = 1;
  2066. AfxMessageBox("The library this prefab object belongs to has been\n"
  2067. "deleted. This document will now behave as a regular file\n"
  2068. "document.");
  2069. m_bEditingPrefab = FALSE;
  2070. CString str;
  2071. str.Format("Prefab%d.rmf", id++);
  2072. SetPathName(str);
  2073. return 1;
  2074. }
  2075. CPrefab3D *pPrefab = (CPrefab3D *)CPrefab::FindID(m_dwPrefabID);
  2076. if (!pPrefab)
  2077. {
  2078. // Not found, create a new prefab.
  2079. pPrefab = new CPrefabRMF;
  2080. }
  2081. pPrefab->SetWorld(m_pWorld);
  2082. m_pWorld = NULL;
  2083. pLibrary->Add(pPrefab);
  2084. pLibrary->Save();
  2085. return 1;
  2086. }
  2087. GetHistory()->Pause();
  2088. if(bRMF)
  2089. {
  2090. if (m_pWorld->SerializeRMF(file, fIsStoring) < 0)
  2091. {
  2092. AfxMessageBox("There was a file error.", MB_OK | MB_ICONEXCLAMATION);
  2093. return FALSE;
  2094. }
  2095. Camera3D *pCamTool = dynamic_cast<Camera3D*>(m_pToolManager->GetToolForID(TOOL_CAMERA));
  2096. if ( pCamTool )
  2097. {
  2098. char sig[8] = "DOCINFO";
  2099. if(fIsStoring)
  2100. {
  2101. file.write(sig, sizeof sig);
  2102. pCamTool->SerializeRMF(file, fIsStoring);
  2103. }
  2104. else
  2105. {
  2106. char buf[sizeof sig];
  2107. memset(buf, 0, sizeof buf);
  2108. file.read(buf, sizeof buf);
  2109. if(memcmp(buf, sig, sizeof sig))
  2110. goto Done;
  2111. pCamTool->SerializeRMF(file, fIsStoring);
  2112. }
  2113. }
  2114. Done:;
  2115. }
  2116. else
  2117. {
  2118. CMapObjectList CordonList;
  2119. CMapWorld *pCordonWorld = NULL;
  2120. BoundBox CordonBox(m_vCordonMins, m_vCordonMaxs);
  2121. if ( m_bIsCordoning )
  2122. {
  2123. //
  2124. // Create "cordon world", add its objects to our real world, create a list in
  2125. // CordonList so we can remove them again.
  2126. //
  2127. pCordonWorld = CordonCreateWorld();
  2128. const CMapObjectList *pChildren = pCordonWorld->GetChildren();
  2129. FOR_EACH_OBJ( *pChildren, pos )
  2130. {
  2131. CMapClass *pChild = pChildren->Element(pos);
  2132. pChild->SetTemporary(TRUE);
  2133. m_pWorld->AddObjectToWorld(pChild);
  2134. CordonList.AddToTail(pChild);
  2135. }
  2136. //
  2137. // HACK: (not mine) - make the cordon bounds bigger so that the cordon brushes
  2138. // overlap the cordon bounds during serialization.
  2139. CordonBox.bmins -= Vector(1,1,1);
  2140. CordonBox.bmaxs += Vector(1,1,1);
  2141. }
  2142. if (fIsStoring)
  2143. {
  2144. void SetMapFormat(MAPFORMAT mf);
  2145. SetMapFormat(m_pGame->mapformat);
  2146. }
  2147. if (m_pWorld->SerializeMAP(file, fIsStoring, m_bIsCordoning? &CordonBox : NULL) < 0)
  2148. {
  2149. AfxMessageBox("There was a file error.", MB_OK | MB_ICONEXCLAMATION);
  2150. return(FALSE);
  2151. }
  2152. //
  2153. // Remove cordon objects.
  2154. //
  2155. if ( m_bIsCordoning )
  2156. {
  2157. FOR_EACH_OBJ( CordonList, pos )
  2158. {
  2159. CMapClass *pobj = CordonList.Element(pos);
  2160. m_pWorld->RemoveChild(pobj);
  2161. }
  2162. delete pCordonWorld;
  2163. }
  2164. }
  2165. GetHistory()->Resume();
  2166. if (!fIsStoring)
  2167. {
  2168. UpdateVisibilityAll();
  2169. GetMainWnd()->GlobalNotify(WM_MAPDOC_CHANGED);
  2170. }
  2171. return TRUE;
  2172. }
  2173. #ifdef _DEBUG
  2174. //-----------------------------------------------------------------------------
  2175. // Purpose:
  2176. //-----------------------------------------------------------------------------
  2177. void CMapDoc::AssertValid(void) const
  2178. {
  2179. CDocument::AssertValid();
  2180. }
  2181. //-----------------------------------------------------------------------------
  2182. // Purpose:
  2183. // Input : dc -
  2184. //-----------------------------------------------------------------------------
  2185. void CMapDoc::Dump(CDumpContext& dc) const
  2186. {
  2187. CDocument::Dump(dc);
  2188. }
  2189. #endif //_DEBUG
  2190. //-----------------------------------------------------------------------------
  2191. // Purpose: Frees all dynamically allocated memory from this document.
  2192. //-----------------------------------------------------------------------------
  2193. void CMapDoc::DeleteContents(void)
  2194. {
  2195. m_NotifyList.RemoveAll();
  2196. //
  2197. // Don't leave pointers to deleted worlds lying around!
  2198. //
  2199. if (GetHammerClipboard()->pSourceWorld == m_pWorld)
  2200. {
  2201. GetHammerClipboard()->pSourceWorld = NULL;
  2202. }
  2203. if ( m_VisGroups )
  2204. {
  2205. m_VisGroups->PurgeAndDeleteElements();
  2206. // delete m_VisGroups;
  2207. // m_VisGroups = NULL;
  2208. }
  2209. if ( m_RootVisGroups )
  2210. {
  2211. m_RootVisGroups->RemoveAll();
  2212. // delete m_RootVisGroups;
  2213. // m_RootVisGroups = NULL;
  2214. }
  2215. if ( m_pManifestOwner == NULL && m_pSelection )
  2216. {
  2217. m_pSelection->RemoveAll();
  2218. // delete m_pSelection;
  2219. // m_pSelection = NULL;
  2220. }
  2221. if ( m_pWorld )
  2222. {
  2223. delete m_pWorld;
  2224. m_pWorld = NULL;
  2225. }
  2226. GetMainWnd()->m_pFaceEditSheet->ClearFaceListByMapDoc( this );
  2227. CDocument::DeleteContents();
  2228. CMainFrame *pwndMain = GetMainWnd();
  2229. if (pwndMain != NULL)
  2230. {
  2231. pwndMain->OnDeleteActiveDocument();
  2232. }
  2233. }
  2234. //-----------------------------------------------------------------------------
  2235. // Purpose:
  2236. // Input : id -
  2237. // Output : Returns a pointer to the visgroup with the given ID, NULL if none.
  2238. //-----------------------------------------------------------------------------
  2239. CVisGroup *CMapDoc::VisGroups_GroupForID(DWORD id)
  2240. {
  2241. int nCount = m_VisGroups->Count();
  2242. for (int i = 0; i < nCount; i++)
  2243. {
  2244. CVisGroup *pGroup = m_VisGroups->Element(i);
  2245. if (pGroup->GetID() == id)
  2246. {
  2247. return(pGroup);
  2248. }
  2249. }
  2250. return(NULL);
  2251. }
  2252. CVisGroup *CMapDoc::VisGroups_GroupForName( const char *pszName, bool bIsAuto )
  2253. {
  2254. int nCount = m_VisGroups->Count();
  2255. for ( int i = 0; i < nCount; i++ )
  2256. {
  2257. CVisGroup *pGroup = m_VisGroups->Element(i);
  2258. if ( !Q_stricmp( pGroup->GetName(), pszName ) && ( pGroup->IsAutoVisGroup() == bIsAuto ) )
  2259. {
  2260. return pGroup;
  2261. }
  2262. }
  2263. return NULL;
  2264. }
  2265. //-----------------------------------------------------------------------------
  2266. // Purpose: Prompts the user through the process of hiding a set of objects.
  2267. // Returns true if the objects were hidden.
  2268. //-----------------------------------------------------------------------------
  2269. void CMapDoc::ShowNewVisGroupsDialog(CMapObjectList &Objects, bool bUnselectObjects)
  2270. {
  2271. int nCount = Objects.Count();
  2272. if (!nCount)
  2273. {
  2274. return;
  2275. }
  2276. //
  2277. // Let the user input a name for the new visgroup.
  2278. //
  2279. CString str;
  2280. str.Format("%d object%s", nCount, nCount == 1 ? "" : "s");
  2281. CNewVisGroupDlg dlg(str);
  2282. if (dlg.DoModal() == IDCANCEL)
  2283. {
  2284. return;
  2285. }
  2286. //
  2287. // Create the visgroup (or use the one they picked).
  2288. //
  2289. CVisGroup *pVisGroup = dlg.GetPickedVisGroup();
  2290. if (!pVisGroup)
  2291. {
  2292. dlg.GetName(str);
  2293. pVisGroup = VisGroups_AddGroup(str);
  2294. }
  2295. VisGroups_AddObjectsToVisGroup(Objects, pVisGroup, dlg.GetHideObjectsOption(), dlg.GetRemoveFromOtherGroups());
  2296. if ( bUnselectObjects && dlg.GetHideObjectsOption() )
  2297. {
  2298. // We don't want hidden objects still selected, so clear the selection.
  2299. m_pSelection->SelectObject( NULL, scClear );
  2300. }
  2301. }
  2302. //-----------------------------------------------------------------------------
  2303. // Purpose: Creates a new visgroup with the given objects in it.
  2304. //-----------------------------------------------------------------------------
  2305. void CMapDoc::VisGroups_CreateNamedVisGroup(CMapObjectList &Objects, const char *szName, bool bHide, bool bRemoveFromOtherVisGroups)
  2306. {
  2307. CVisGroup *pVisGroup = VisGroups_AddGroup(szName);
  2308. VisGroups_AddObjectsToVisGroup(Objects, pVisGroup, bHide, bRemoveFromOtherVisGroups);
  2309. }
  2310. //-----------------------------------------------------------------------------
  2311. // Purpose: Adds the objects to the given visgroup and does hiding as specified.
  2312. //-----------------------------------------------------------------------------
  2313. void CMapDoc::VisGroups_AddObjectsToVisGroup(CMapObjectList &Objects, CVisGroup *pVisGroup, bool bHide, bool bRemoveFromOtherVisGroups)
  2314. {
  2315. //
  2316. // Assign the objects to it.
  2317. //
  2318. FOR_EACH_OBJ( Objects, pos )
  2319. {
  2320. CMapClass *pObject = Objects.Element(pos);
  2321. if (VisGroups_ObjectCanBelongToVisGroup(pObject))
  2322. {
  2323. if (bRemoveFromOtherVisGroups)
  2324. {
  2325. pObject->RemoveAllVisGroups();
  2326. }
  2327. pObject->AddVisGroup(pVisGroup);
  2328. }
  2329. }
  2330. if ( m_bVisGroupUpdatesLocked )
  2331. return;
  2332. //
  2333. // Clean up any visgroups with no members.
  2334. //
  2335. VisGroups_PurgeGroups();
  2336. //
  2337. // Update object visiblity and refresh views.
  2338. //
  2339. if ( bHide )
  2340. {
  2341. VisGroups_ShowVisGroup(pVisGroup, !bHide);
  2342. }
  2343. else
  2344. {
  2345. //this is currently inside of ShowVisGroup
  2346. //needs called even if we are not showing a group
  2347. VisGroups_UpdateAll();
  2348. UpdateVisibilityAll();
  2349. SetModifiedFlag();
  2350. }
  2351. CMainFrame *pwndMain = GetMainWnd();
  2352. if (pwndMain)
  2353. {
  2354. pwndMain->UpdateAllDocViews(MAPVIEW_UPDATE_VISGROUP_ALL);
  2355. }
  2356. }
  2357. //-----------------------------------------------------------------------------
  2358. // Purpose: Returns whether or not this object is eligible for inclusion in a visgroup.
  2359. //-----------------------------------------------------------------------------
  2360. bool CMapDoc::VisGroups_ObjectCanBelongToVisGroup(CMapClass *pObject)
  2361. {
  2362. if (!pObject)
  2363. return false;
  2364. CMapClass *pParent = pObject->GetParent();
  2365. if (pParent)
  2366. {
  2367. if ( IsWorldObject(pParent) )
  2368. return true;
  2369. if (pParent->IsGroup())
  2370. return true;
  2371. // Children of entities cannot belong to visgroups independent of their parent.
  2372. Assert(dynamic_cast <CMapEntity *>(pParent));
  2373. return false;
  2374. }
  2375. return false;
  2376. }
  2377. //-----------------------------------------------------------------------------
  2378. // Purpose:
  2379. // Input : pVisGroup -
  2380. // pParent -
  2381. //-----------------------------------------------------------------------------
  2382. void CMapDoc::VisGroups_SetParent(CVisGroup *pVisGroup, CVisGroup *pNewParent)
  2383. {
  2384. // Can't make a group a child of one of its descendents.
  2385. Assert(!pVisGroup->FindDescendent(pNewParent));
  2386. CVisGroup *pOldParent = pVisGroup->GetParent();
  2387. if (pOldParent != pNewParent)
  2388. {
  2389. if (pOldParent)
  2390. {
  2391. pOldParent->RemoveChild(pVisGroup);
  2392. }
  2393. else
  2394. {
  2395. int nIndex = m_RootVisGroups->Find(pVisGroup);
  2396. if (nIndex != -1)
  2397. {
  2398. m_RootVisGroups->Remove(nIndex);
  2399. }
  2400. }
  2401. if (pNewParent)
  2402. {
  2403. pNewParent->AddChild(pVisGroup);
  2404. }
  2405. else
  2406. {
  2407. m_RootVisGroups->AddToTail(pVisGroup);
  2408. }
  2409. pVisGroup->SetParent(pNewParent);
  2410. }
  2411. }
  2412. //-----------------------------------------------------------------------------
  2413. // Purpose: Update the visgroup visibility state for all groups that
  2414. // this child belongs to.
  2415. //
  2416. // NOTE: Assumes that all visgroups were initialized to VISGROUP_UNDEFINED
  2417. // before calling this with the first object.
  2418. //-----------------------------------------------------------------------------
  2419. void CMapDoc::VisGroups_UpdateForObject(CMapClass *pObject)
  2420. {
  2421. //Msg("Object: 0x%X is ", pObject);
  2422. int nVisGroupCount = pObject->GetVisGroupCount();
  2423. for (int i = 0; i < nVisGroupCount; i++)
  2424. {
  2425. CVisGroup *pGroup = pObject->GetVisGroup(i);
  2426. VisGroupState_t eVisState = pGroup->GetVisible();
  2427. if (eVisState != VISGROUP_PARTIAL)
  2428. {
  2429. if (pObject->IsVisGroupShown())
  2430. {
  2431. //if (i == 0)
  2432. // Msg("shown\n");
  2433. if (eVisState == VISGROUP_HIDDEN)
  2434. {
  2435. //Msg(" Visgroup %s was hidden, now partial\n", pGroup->GetName());
  2436. pGroup->SetVisible(VISGROUP_PARTIAL);
  2437. }
  2438. else
  2439. {
  2440. //Msg(" Visgroup %s is shown\n", pGroup->GetName());
  2441. pGroup->SetVisible(VISGROUP_SHOWN);
  2442. }
  2443. }
  2444. else
  2445. {
  2446. //if (i == 0)
  2447. // Msg("hidden\n");
  2448. if (eVisState == VISGROUP_SHOWN)
  2449. {
  2450. //Msg(" Visgroup %s was shown, now partial\n", pGroup->GetName());
  2451. pGroup->SetVisible(VISGROUP_PARTIAL);
  2452. }
  2453. else
  2454. {
  2455. //Msg(" Visgroup %s is hidden\n", pGroup->GetName());
  2456. pGroup->SetVisible(VISGROUP_HIDDEN);
  2457. }
  2458. }
  2459. }
  2460. //else
  2461. //{
  2462. // Msg(" Visgroup %s is partial\n", pGroup->GetName());
  2463. //}
  2464. }
  2465. }
  2466. //-----------------------------------------------------------------------------
  2467. // Purpose:
  2468. //-----------------------------------------------------------------------------
  2469. void CMapDoc::VisGroups_UpdateParents(void)
  2470. {
  2471. int nVisGroupCount = VisGroups_GetCount();
  2472. for (int i = 0; i < nVisGroupCount; i++)
  2473. {
  2474. CVisGroup *pTempGroup = VisGroups_GetVisGroup(i);
  2475. if ( pTempGroup->GetVisible() != VISGROUP_UNDEFINED && pTempGroup->GetParent() != NULL )
  2476. {
  2477. pTempGroup->VisGroups_UpdateParent( pTempGroup->GetVisible() );
  2478. }
  2479. }
  2480. }
  2481. //-----------------------------------------------------------------------------
  2482. // Purpose:
  2483. //-----------------------------------------------------------------------------
  2484. void CMapDoc::VisGroups_UpdateAll(void)
  2485. {
  2486. //Msg("======= Visgroups_UpdateAll ========\n");
  2487. //
  2488. // Mark all visgroups as having an undefined state so we
  2489. // can update the visibility state of all visgroups while we
  2490. // hide and show the member objects.
  2491. //
  2492. int nVisGroupCount = VisGroups_GetCount();
  2493. for (int i = 0; i < nVisGroupCount; i++)
  2494. {
  2495. CVisGroup *pTempGroup = VisGroups_GetVisGroup(i);
  2496. pTempGroup->SetVisible(VISGROUP_UNDEFINED);
  2497. }
  2498. //
  2499. // Show or hide all the objects that belong to the given visgroup.
  2500. //
  2501. EnumChildrenPos_t pos;
  2502. CMapClass *pChild = m_pWorld->GetFirstDescendent(pos);
  2503. while (pChild)
  2504. {
  2505. //
  2506. // Update the visgroup visibility state for all groups that
  2507. // this child belongs to.
  2508. //
  2509. VisGroups_UpdateForObject(pChild);
  2510. pChild = m_pWorld->GetNextDescendent(pos);
  2511. }
  2512. // Update parent state
  2513. VisGroups_UpdateParents();
  2514. //
  2515. // Look for visgroups still set as undefined -- these are empty.
  2516. //
  2517. for (int i = nVisGroupCount - 1; i >= 0; i--)
  2518. {
  2519. CVisGroup *pTempGroup = VisGroups_GetVisGroup(i);
  2520. Assert(pTempGroup->GetVisible() != VISGROUP_UNDEFINED);
  2521. }
  2522. }
  2523. //-----------------------------------------------------------------------------
  2524. // Purpose: Returns whether the object belongs to the given visgroup or any
  2525. // of that visgroup's children.
  2526. //-----------------------------------------------------------------------------
  2527. static bool IsInVisGroupRecursive(CMapClass *pObject, CVisGroup *pGroup)
  2528. {
  2529. if (pObject->IsInVisGroup(pGroup))
  2530. {
  2531. return true;
  2532. }
  2533. int nChildCount = pGroup->GetChildCount();
  2534. if (nChildCount > 0)
  2535. {
  2536. for (int i = 0; i < nChildCount; i++)
  2537. {
  2538. CVisGroup *pChild = pGroup->GetChild(i);
  2539. if (IsInVisGroupRecursive(pObject, pChild))
  2540. {
  2541. return true;
  2542. }
  2543. }
  2544. }
  2545. return false;
  2546. }
  2547. //-----------------------------------------------------------------------------
  2548. // Purpose: Hides or shows the given visgroup.
  2549. //-----------------------------------------------------------------------------
  2550. void CMapDoc::VisGroups_ShowVisGroup(CVisGroup *pGroup, bool bShow)
  2551. {
  2552. //Msg("-------- Visgroups_ShowVisGroup --------\n");
  2553. if (pGroup == NULL)
  2554. return;
  2555. VisGroupSelection eVisGroupType = USER;
  2556. if ( pGroup->IsAutoVisGroup() )
  2557. {
  2558. eVisGroupType = AUTO;
  2559. }
  2560. //
  2561. // Show or hide all the objects that belong to the given visgroup.
  2562. //
  2563. EnumChildrenPos_t pos;
  2564. CMapClass *pChild = m_pWorld->GetFirstDescendent(pos);
  2565. while (pChild)
  2566. {
  2567. if (IsInVisGroupRecursive(pChild, pGroup))
  2568. {
  2569. pChild->VisGroupShow(bShow, eVisGroupType);
  2570. }
  2571. pChild = m_pWorld->GetNextDescendent(pos);
  2572. }
  2573. VisGroups_UpdateAll();
  2574. UpdateVisibilityAll();
  2575. SetModifiedFlag();
  2576. }
  2577. //-----------------------------------------------------------------------------
  2578. // Purpose:
  2579. // Output : Returns TRUE on success, FALSE on failure.
  2580. //-----------------------------------------------------------------------------
  2581. BOOL CMapDoc::SaveModified(void)
  2582. {
  2583. if (!IsModified())
  2584. return TRUE; // ok to continue
  2585. // editing prefab and modified - update data?
  2586. if(m_bEditingPrefab)
  2587. {
  2588. switch(AfxMessageBox("Do you want to save the changes to this prefab object?", MB_YESNOCANCEL))
  2589. {
  2590. case IDYES:
  2591. {
  2592. std::fstream file;
  2593. Serialize(file, 0, 0);
  2594. return TRUE;
  2595. }
  2596. case IDNO:
  2597. return TRUE; // no save
  2598. case IDCANCEL:
  2599. return FALSE; // forget this cmd
  2600. }
  2601. }
  2602. return CDocument::SaveModified();
  2603. }
  2604. //-----------------------------------------------------------------------------
  2605. // Purpose:
  2606. // Input : lpszPathName -
  2607. // Output : Returns TRUE on success, FALSE on failure.
  2608. //-----------------------------------------------------------------------------
  2609. BOOL CMapDoc::OnOpenDocument(LPCTSTR lpszPathName)
  2610. {
  2611. Initialize();
  2612. if (!SelectDocType())
  2613. {
  2614. return FALSE;
  2615. }
  2616. //
  2617. // Look for either the RMF or MAP extension to indicate an old file format.
  2618. //
  2619. BOOL bRMF = FALSE;
  2620. BOOL bMAP = FALSE;
  2621. if (!stricmp(lpszPathName + strlen(lpszPathName) - 3, "rmf"))
  2622. {
  2623. bRMF = TRUE;
  2624. }
  2625. else if (!stricmp(lpszPathName + strlen(lpszPathName) - 3, "map"))
  2626. {
  2627. bMAP = TRUE;
  2628. }
  2629. //
  2630. // Call any per-class PreloadWorld functions here.
  2631. //
  2632. CMapSolid::PreloadWorld();
  2633. if ((bRMF) || (bMAP))
  2634. {
  2635. std::fstream file(lpszPathName, std::ios::in | std::ios::binary);
  2636. if (!file.is_open())
  2637. {
  2638. return(FALSE);
  2639. }
  2640. if (!Serialize(file, FALSE, bRMF))
  2641. {
  2642. return(FALSE);
  2643. }
  2644. }
  2645. else
  2646. {
  2647. if (!LoadVMF(lpszPathName))
  2648. {
  2649. return(FALSE);
  2650. }
  2651. }
  2652. SetModifiedFlag(FALSE);
  2653. Msg(mwStatus, "Opened %s", lpszPathName);
  2654. SetActiveMapDoc(this);
  2655. //
  2656. // We set the active doc before loading for displacements (and maybe other
  2657. // things), but visgroups aren't available until after map load. We have to refresh
  2658. // the visgroups here or they won't be correct.
  2659. //
  2660. GetMainWnd()->GlobalNotify(WM_MAPDOC_CHANGED);
  2661. m_pToolManager->SetTool( TOOL_POINTER );
  2662. return(TRUE);
  2663. }
  2664. //-----------------------------------------------------------------------------
  2665. // Purpose: Called when the document is closed.
  2666. //-----------------------------------------------------------------------------
  2667. void CMapDoc::OnCloseDocument(void)
  2668. {
  2669. if ( m_nExternalReferenceCount > 0 )
  2670. { // this is an instance, so hide the window
  2671. ShowWindow( false );
  2672. if ( IsModified() )
  2673. {
  2674. DeleteContents();
  2675. OnOpenDocument( m_strPathName );
  2676. }
  2677. return;
  2678. }
  2679. //
  2680. // Deactivate the current tool now because doing it later can cause side-effects.
  2681. //
  2682. m_pToolManager->Shutdown();
  2683. //
  2684. // Call DeleteContents ourselves because in the framework implementation
  2685. // of OnCloseDocument the doc window is closed first, which activates the
  2686. // document beneath us. This is bad because we must be the active document
  2687. // during the close process for things like displacements to clean themselves
  2688. // up properly.
  2689. //
  2690. SetActiveMapDoc(this);
  2691. CDocument::OnCloseDocument();
  2692. }
  2693. //-----------------------------------------------------------------------------
  2694. // Purpose:
  2695. // Input : lpszPathName -
  2696. // Output : Returns TRUE on success, FALSE on failure.
  2697. //-----------------------------------------------------------------------------
  2698. BOOL CMapDoc::OnSaveDocument(LPCTSTR lpszPathName)
  2699. {
  2700. if( m_pBSPLighting )
  2701. m_pBSPLighting->Serialize();
  2702. // UNDONE: prefab serialization must be redone
  2703. if (m_bEditingPrefab)
  2704. {
  2705. std::fstream file;
  2706. Serialize(file, 0, 0);
  2707. SetModifiedFlag(FALSE);
  2708. OnCloseDocument();
  2709. return(TRUE);
  2710. }
  2711. //
  2712. // If a file with the same name exists, back it up before saving the new one.
  2713. //
  2714. char szFile[MAX_PATH];
  2715. strcpy(szFile, lpszPathName);
  2716. szFile[strlen(szFile) - 1] = 'x';
  2717. if (access(lpszPathName, 0) != -1)
  2718. {
  2719. if (!CopyFile(lpszPathName, szFile, FALSE))
  2720. {
  2721. DWORD dwError = GetLastError();
  2722. char szError[_MAX_PATH];
  2723. wsprintf(szError, "Hammer was unable to backup the existing file \"%s\" (Error: 0x%lX). Please verify that the there is space on the hard drive and that the path still exists.", lpszPathName, dwError);
  2724. AfxMessageBox(szError);
  2725. return(FALSE);
  2726. }
  2727. }
  2728. //
  2729. // Use the file extension to determine how to save the file.
  2730. //
  2731. BOOL bRMF = FALSE;
  2732. BOOL bMAP = FALSE;
  2733. if (!stricmp(lpszPathName + strlen(lpszPathName) - 3, "rmf"))
  2734. {
  2735. bRMF = TRUE;
  2736. }
  2737. else if (!stricmp(lpszPathName + strlen(lpszPathName) - 3, "map"))
  2738. {
  2739. bMAP = TRUE;
  2740. }
  2741. //
  2742. // HalfLife 2 and beyond use heirarchical chunk files.
  2743. //
  2744. if ((m_pGame->mapformat == mfHalfLife2) && (!bRMF) && (!bMAP))
  2745. {
  2746. BOOL bSaved = FALSE;
  2747. BeginWaitCursor();
  2748. if (SaveVMF(lpszPathName, 0))
  2749. {
  2750. bSaved = TRUE;
  2751. SetModifiedFlag(FALSE);
  2752. }
  2753. EndWaitCursor();
  2754. return(bSaved);
  2755. }
  2756. //
  2757. // Half-Life used RMFs and MAPs.
  2758. //
  2759. std::fstream file(lpszPathName, std::ios::out | std::ios::binary);
  2760. if (!file.is_open())
  2761. {
  2762. char szError[_MAX_PATH];
  2763. wsprintf(szError, "Hammer was unable to open the file \"%s\" for writing. Please verify that the file is writable and that the path exists.", lpszPathName);
  2764. AfxMessageBox(szError);
  2765. return(FALSE);
  2766. }
  2767. BeginWaitCursor();
  2768. if (!Serialize(file, TRUE, bRMF))
  2769. {
  2770. EndWaitCursor();
  2771. return(FALSE);
  2772. }
  2773. EndWaitCursor();
  2774. SetModifiedFlag(FALSE);
  2775. return(TRUE);
  2776. }
  2777. //-----------------------------------------------------------------------------
  2778. // Purpose:
  2779. // Input : st2 -
  2780. // st1 -
  2781. // Output : DWORD
  2782. //-----------------------------------------------------------------------------
  2783. DWORD SubTime(SYSTEMTIME& st2, SYSTEMTIME& st1)
  2784. {
  2785. DWORD dwMil = 0;
  2786. if(st2.wMinute != st1.wMinute)
  2787. {
  2788. dwMil += (59 - st1.wSecond) * 1000;
  2789. }
  2790. if(st2.wSecond != st1.wSecond)
  2791. {
  2792. dwMil += 1000 - st1.wMilliseconds;
  2793. }
  2794. if(!dwMil)
  2795. {
  2796. dwMil = st2.wMilliseconds - st1.wMilliseconds;
  2797. }
  2798. else
  2799. dwMil += st2.wMilliseconds;
  2800. return dwMil;
  2801. }
  2802. void CMapDoc::RenderDocument(CRender *pRender)
  2803. {
  2804. if ( m_bIsCordoning )
  2805. {
  2806. pRender->PushRenderMode( RENDER_MODE_WIREFRAME );
  2807. pRender->SetDrawColor( Color(255,0,0,255) );
  2808. pRender->DrawBox( m_vCordonMins, m_vCordonMaxs, false );
  2809. pRender->PopRenderMode();
  2810. }
  2811. }
  2812. //-----------------------------------------------------------------------------
  2813. // Purpose: Forces a render of all the 3D views. Called from OnIdle to render
  2814. // the 3D views.
  2815. //-----------------------------------------------------------------------------
  2816. void CMapDoc::RenderAllViews(void)
  2817. {
  2818. //
  2819. // Make sure the document is up to date.
  2820. //
  2821. Update();
  2822. bool bViewRendered = false;
  2823. POSITION p = GetFirstViewPosition();
  2824. while (p)
  2825. {
  2826. CMapView *pView = dynamic_cast<CMapView*>(GetNextView(p));
  2827. if ( !pView )
  2828. continue;
  2829. if ( pView->IsActive() )
  2830. {
  2831. pView->ProcessInput();
  2832. }
  2833. if ( pView->ShouldRender() )
  2834. {
  2835. pView->RenderView();
  2836. bViewRendered = true;
  2837. }
  2838. }
  2839. if ( !bViewRendered )
  2840. {
  2841. // not a single view did update this frame
  2842. // so the application seems to be idle
  2843. Sleep( 1 );
  2844. }
  2845. else
  2846. {
  2847. UpdateStatusbar();
  2848. }
  2849. }
  2850. //-----------------------------------------------------------------------------
  2851. // Purpose:
  2852. //-----------------------------------------------------------------------------
  2853. void CMapDoc::UpdateAllCameras(const Vector *vecViewPos, const Vector *vecLookAt, const float *fZoom)
  2854. {
  2855. POSITION pos = GetFirstViewPosition();
  2856. while (pos != NULL)
  2857. {
  2858. CMapView *pView = dynamic_cast<CMapView*>(GetNextView(pos));
  2859. CCamera *pCamera = pView->GetCamera();
  2860. if ( vecViewPos )
  2861. {
  2862. pCamera->SetViewPoint( *vecViewPos );
  2863. }
  2864. if ( vecLookAt && !pCamera->IsOrthographic() )
  2865. {
  2866. pCamera->SetViewTarget( *vecLookAt );
  2867. }
  2868. if ( fZoom && pCamera->IsOrthographic() )
  2869. {
  2870. pCamera->SetZoom( *fZoom );
  2871. }
  2872. pView->UpdateView( MAPVIEW_OPTIONS_CHANGED );
  2873. }
  2874. }
  2875. // walk through all views
  2876. void CMapDoc::UpdateAllViews(int nFlags, UpdateBox *ub )
  2877. {
  2878. POSITION p = GetFirstViewPosition();
  2879. while (p)
  2880. {
  2881. CMapView *pView = dynamic_cast<CMapView*>(GetNextView(p));
  2882. if ( pView )
  2883. {
  2884. pView->UpdateView( nFlags );
  2885. }
  2886. }
  2887. }
  2888. //-----------------------------------------------------------------------------
  2889. // Purpose: used during iteration, tells an map entity to
  2890. //-----------------------------------------------------------------------------
  2891. static BOOL _UpdateAnimation( CMapClass *mapClass, float animTime )
  2892. {
  2893. mapClass->UpdateAnimation( animTime );
  2894. return TRUE;
  2895. }
  2896. //-----------------------------------------------------------------------------
  2897. // Purpose: Sets up for drawing animated objects
  2898. // Needs to be called each frame before any animating object are rendered
  2899. //-----------------------------------------------------------------------------
  2900. void CMapDoc::UpdateAnimation( void )
  2901. {
  2902. //GetMainWnd()->m_AnimationDlg.RunFrame();
  2903. // check to see if the animation needs to be updated
  2904. if ( !IsAnimating() )
  2905. return;
  2906. // if the animation time is 0, turn it off
  2907. if ( GetAnimationTime() == 0.0f )
  2908. {
  2909. m_bIsAnimating = false;
  2910. }
  2911. // get current animation time from animation toolbar
  2912. union {
  2913. float fl;
  2914. DWORD dw;
  2915. } animTime;
  2916. animTime.fl = GetAnimationTime();
  2917. // iterate through all CMapEntity object and update their animation frame matrix
  2918. m_pWorld->EnumChildren( ENUMMAPCHILDRENPROC(_UpdateAnimation), animTime.dw, MAPCLASS_TYPE(CMapAnimator) );
  2919. }
  2920. //-----------------------------------------------------------------------------
  2921. // Purpose: Sets the current time in the animation
  2922. // Input : time - a time, from 0 to 1
  2923. //-----------------------------------------------------------------------------
  2924. void CMapDoc::SetAnimationTime( float time )
  2925. {
  2926. m_flAnimationTime = time;
  2927. if ( m_flAnimationTime != 0.0f )
  2928. {
  2929. m_bIsAnimating = true;
  2930. }
  2931. }
  2932. //-----------------------------------------------------------------------------
  2933. // Purpose: Gets the current time and stores it in the doc, for use during the frame
  2934. //-----------------------------------------------------------------------------
  2935. void CMapDoc::UpdateCurrentTime( void )
  2936. {
  2937. m_flCurrentTime = (float)timeGetTime() / 1000;
  2938. }
  2939. //-----------------------------------------------------------------------------
  2940. // Purpose:
  2941. //-----------------------------------------------------------------------------
  2942. static BOOL SelectInBox(CMapClass *pObject, SelectBoxInfo_t *pInfo)
  2943. {
  2944. //
  2945. // Skip hidden objects.
  2946. //
  2947. if (!pObject->IsVisible())
  2948. {
  2949. return TRUE;
  2950. }
  2951. //
  2952. // Skip anything with children. We only are interested in leaf objects because
  2953. // PrepareSelection will call up to tree to get the proper ancestor.
  2954. //
  2955. if (pObject->GetChildCount())
  2956. {
  2957. return TRUE;
  2958. }
  2959. //
  2960. // Skip groups. Groups are selected via their members through PrepareSelection.
  2961. //
  2962. if (pObject->IsGroup())
  2963. {
  2964. // Shouldn't ever have empty groups lying around!
  2965. Assert(false);
  2966. return TRUE;
  2967. }
  2968. //
  2969. // Skip clutter helpers.
  2970. //
  2971. if (pObject->IsClutter())
  2972. {
  2973. return TRUE;
  2974. }
  2975. // FIXME: We're calling PrepareSelection on nearly everything in the world,
  2976. // then doing the box test against the object that we get back from that!
  2977. // We should use the octree to cull out most of the world up front.
  2978. CMapClass *pSelObject = pObject->PrepareSelection(pInfo->eSelectMode);
  2979. if (pSelObject)
  2980. {
  2981. if (Options.view2d.bSelectbyhandles)
  2982. {
  2983. Vector ptCenter;
  2984. pObject->GetBoundsCenter(ptCenter);
  2985. if (pInfo->pBox->ContainsPoint(ptCenter))
  2986. {
  2987. pInfo->pDoc->SelectObject(pSelObject, scSelect);
  2988. }
  2989. return TRUE;
  2990. }
  2991. bool bSelect;
  2992. if (pInfo->bInside)
  2993. {
  2994. bSelect = pObject->IsInsideBox(pInfo->pBox->bmins, pInfo->pBox->bmaxs);
  2995. }
  2996. else
  2997. {
  2998. bSelect = pObject->IsIntersectingBox(pInfo->pBox->bmins, pInfo->pBox->bmaxs);
  2999. }
  3000. if (bSelect)
  3001. {
  3002. pInfo->pDoc->SelectObject(pSelObject, scSelect);
  3003. }
  3004. }
  3005. return TRUE;
  3006. }
  3007. //-----------------------------------------------------------------------------
  3008. // Purpose:
  3009. //-----------------------------------------------------------------------------
  3010. static BOOL SelectInLogicalBox( CMapClass *pObject, SelectLogicalBoxInfo_t *pInfo)
  3011. {
  3012. // Skip hidden objects.
  3013. if ( !pObject->IsVisible() || !pObject->IsLogical() || !pObject->IsVisibleLogical() )
  3014. return TRUE;
  3015. // FIXME: Box selection doesn't work when this is uncommented. Why?
  3016. // Skip anything with children. We only are interested in leaf objects because
  3017. // PrepareSelection will call up to tree to get the proper ancestor.
  3018. // if ( pObject->GetChildCount() )
  3019. // return TRUE;
  3020. // Skip groups. Groups are selected via their members through PrepareSelection.
  3021. if ( pObject->IsGroup() )
  3022. {
  3023. // Shouldn't ever have empty groups lying around!
  3024. // Except if you drag select an empty area!
  3025. // Assert(false);
  3026. return TRUE;
  3027. }
  3028. // Skip clutter helpers.
  3029. if ( pObject->IsClutter() )
  3030. return TRUE;
  3031. // FIXME: We're calling PrepareSelection on nearly everything in the world,
  3032. // then doing the box test against the object that we get back from that!
  3033. // We should use the octree to cull out most of the world up front.
  3034. CMapClass *pSelObject = pObject->PrepareSelection(pInfo->eSelectMode);
  3035. if ( pSelObject )
  3036. {
  3037. Vector2D mins, maxs;
  3038. pObject->GetRenderLogicalBox( mins, maxs );
  3039. bool bSelect;
  3040. if ( pInfo->bInside )
  3041. {
  3042. bSelect = IsBoxInside( mins, maxs, pInfo->vecMins, pInfo->vecMaxs );
  3043. }
  3044. else
  3045. {
  3046. bSelect = IsBoxIntersecting( mins, maxs, pInfo->vecMins, pInfo->vecMaxs );
  3047. }
  3048. if (bSelect)
  3049. {
  3050. pInfo->pDoc->SelectObject( pSelObject, scSelect );
  3051. }
  3052. }
  3053. return TRUE;
  3054. }
  3055. //-----------------------------------------------------------------------------
  3056. // Purpose:
  3057. //-----------------------------------------------------------------------------
  3058. void CMapDoc::SelectRegion( BoundBox *pBox, bool bInsideOnly, bool ResetSelection )
  3059. {
  3060. SelectBoxInfo_t info;
  3061. info.pDoc = this;
  3062. info.pBox = pBox;
  3063. info.bInside = bInsideOnly;
  3064. info.eSelectMode = m_pSelection->GetMode();
  3065. if ( ResetSelection )
  3066. {
  3067. SelectObject(NULL, scSaveChanges);
  3068. }
  3069. m_pWorld->EnumChildren((ENUMMAPCHILDRENPROC)SelectInBox, (DWORD)&info);
  3070. }
  3071. //-----------------------------------------------------------------------------
  3072. // Purpose:
  3073. //-----------------------------------------------------------------------------
  3074. void CMapDoc::SelectLogicalRegion( const Vector2D &vecMins, const Vector2D &vecMaxs, bool bInsideOnly)
  3075. {
  3076. SelectLogicalBoxInfo_t info;
  3077. info.pDoc = this;
  3078. info.vecMins = vecMins;
  3079. info.vecMaxs = vecMaxs;
  3080. info.bInside = bInsideOnly;
  3081. info.eSelectMode = m_pSelection->GetMode();
  3082. SelectObject(NULL, scSaveChanges);
  3083. m_pWorld->EnumChildren((ENUMMAPCHILDRENPROC)SelectInLogicalBox, (DWORD)&info);
  3084. }
  3085. bool CMapDoc::SelectObject(CMapClass *pObj, int cmd)
  3086. {
  3087. return m_pSelection->SelectObject( pObj, cmd );
  3088. }
  3089. void CMapDoc::SelectObjectList(const CMapObjectList *pList, int cmd)
  3090. {
  3091. m_pSelection->SelectObjectList( pList, cmd );
  3092. }
  3093. //-----------------------------------------------------------------------------
  3094. // Purpose:
  3095. //-----------------------------------------------------------------------------
  3096. void CMapDoc::UpdateStatusbar(void)
  3097. {
  3098. if (m_pToolManager->GetActiveToolID() == TOOL_FACEEDIT_MATERIAL)
  3099. {
  3100. CString str;
  3101. str.Format("%d faces selected", GetMainWnd()->m_pFaceEditSheet->GetFaceListCount() );
  3102. SetStatusText(SBI_SELECTION, str);
  3103. SetStatusText(SBI_SIZE, "");
  3104. return;
  3105. }
  3106. CBaseTool *pTool = m_pToolManager->GetActiveTool();
  3107. if (pTool != NULL)
  3108. {
  3109. pTool->UpdateStatusBar();
  3110. }
  3111. CString str;
  3112. if ( m_pSelection )
  3113. {
  3114. int nCount = m_pSelection->GetCount();
  3115. switch (nCount)
  3116. {
  3117. case 0:
  3118. {
  3119. str = "no selection.";
  3120. break;
  3121. }
  3122. case 1:
  3123. {
  3124. CMapClass *pobj = m_pSelection->GetList()->Element(0);
  3125. str = pobj->GetDescription();
  3126. // Look for the 3D view so we can also add the distance to the object.
  3127. POSITION p = GetFirstViewPosition();
  3128. while (p)
  3129. {
  3130. CMapView3D *pView = dynamic_cast<CMapView3D*>(GetNextView(p));
  3131. if (pView)
  3132. {
  3133. // Get the position of the 3D camera.
  3134. Vector vViewPoint( 0, 0, 0 );
  3135. CCamera *pCam = pView->GetCamera();
  3136. pCam->GetViewPoint(vViewPoint);
  3137. // Get the position of the object.
  3138. Vector vObjOrigin;
  3139. pobj->GetOrigin( vObjOrigin );
  3140. float flDist = vViewPoint.DistTo( vObjOrigin );
  3141. // Add the distance to the status bar string.
  3142. char strDist[512];
  3143. V_snprintf( strDist, sizeof( strDist ), " [dist: %.1f]", flDist );
  3144. str += strDist;
  3145. break;
  3146. }
  3147. }
  3148. break;
  3149. }
  3150. default:
  3151. {
  3152. str.Format("%d objects selected.", nCount);
  3153. break;
  3154. }
  3155. }
  3156. }
  3157. SetStatusText(SBI_SELECTION, str);
  3158. }
  3159. //-----------------------------------------------------------------------------
  3160. // Purpose:
  3161. //-----------------------------------------------------------------------------
  3162. void CMapDoc::BuildCascadingSelectionList( CMapClass *pObj, CUtlRBTree< CMapClass*, unsigned short > &list, bool bRecursive )
  3163. {
  3164. // Also add all entities connected to outputs of this selection
  3165. CEditGameClass *pClass = dynamic_cast< CEditGameClass * >( pObj );
  3166. if ( !pClass )
  3167. return;
  3168. int nCount = pClass->Connections_GetCount();
  3169. for ( int j = 0; j < nCount; ++j )
  3170. {
  3171. CEntityConnection *pConn = pClass->Connections_Get( j );
  3172. CMapEntityList entityList;
  3173. FindEntitiesByName( entityList, pConn->GetTargetName(), true );
  3174. int nOutputCount = entityList.Count();
  3175. for ( int k = 0; k < nOutputCount; ++k )
  3176. {
  3177. CMapEntity *pEntity = entityList.Element(k);
  3178. if ( pEntity == pObj )
  3179. continue;
  3180. if ( list.InsertIfNotFound( pEntity ) != list.InvalidIndex() )
  3181. {
  3182. if ( bRecursive )
  3183. {
  3184. BuildCascadingSelectionList( pEntity, list, bRecursive );
  3185. }
  3186. }
  3187. }
  3188. }
  3189. }
  3190. //-----------------------------------------------------------------------------
  3191. // Purpose:
  3192. // Input : pDoc -
  3193. //-----------------------------------------------------------------------------
  3194. void CMapDoc::SetActiveMapDoc(CMapDoc *pDoc)
  3195. {
  3196. // Only do the work when the doc actually changes.
  3197. if (pDoc == m_pMapDoc)
  3198. {
  3199. return;
  3200. }
  3201. if ( m_pMapDoc != NULL )
  3202. {
  3203. // disable active views in all map doc
  3204. m_pMapDoc->SetActiveView(NULL);
  3205. }
  3206. m_pMapDoc = pDoc;
  3207. m_pManifest = dynamic_cast< CManifest * >( m_pMapDoc );
  3208. //
  3209. // Set the new document in the shell.
  3210. //
  3211. g_Shell.SetDocument(m_pMapDoc);
  3212. //
  3213. // Set the history to the document's history.
  3214. //
  3215. if (m_pMapDoc != NULL)
  3216. {
  3217. // attach document selection to property box
  3218. GetMainWnd()->pObjectProperties->SetObjectList( m_pMapDoc->GetSelection()->GetList() );
  3219. if ( m_pManifest && m_pManifest->GetPrimaryMap() )
  3220. {
  3221. CHistory::SetHistory( m_pManifest->GetPrimaryMap()->m_Map->GetDocHistory() );
  3222. }
  3223. else
  3224. {
  3225. CHistory::SetHistory(m_pMapDoc->GetDocHistory());
  3226. }
  3227. m_pMapDoc->SetUndoActive(GetMainWnd()->IsUndoActive() == TRUE);
  3228. m_pMapDoc->UpdateAllViews( MAPVIEW_UPDATE_OBJECTS );
  3229. }
  3230. else
  3231. {
  3232. CHistory::SetHistory(NULL);
  3233. GetMainWnd()->pObjectProperties->SetObjectList( NULL );
  3234. }
  3235. //
  3236. // Notify that the active document has changed.
  3237. //
  3238. GetMainWnd()->GlobalNotify(WM_MAPDOC_CHANGED);
  3239. // dvs: don't do this anymore because we run single-config only
  3240. // Set global game config to type found in doc.
  3241. //
  3242. //CGameConfig *pOldGame = CGameConfig::GetActiveGame();
  3243. //if (pDoc != NULL)
  3244. //{
  3245. // CGameConfig::SetActiveGame(pDoc->GetGame());
  3246. //}
  3247. //else
  3248. //{
  3249. // CGameConfig::SetActiveGame(NULL);
  3250. //}
  3251. //
  3252. //
  3253. // Update everything the first time we create a document or when the
  3254. // game configuration changes between documents.
  3255. //
  3256. //static bool bFirst = true;
  3257. //if ((pOldGame != CGameConfig::GetActiveGame()) || (bFirst))
  3258. //{
  3259. // bFirst = false;
  3260. // GetMainWnd()->GlobalNotify(WM_GAME_CHANGED);
  3261. //}
  3262. // Update everything the first time we create a document.
  3263. static bool bFirst = true;
  3264. if (bFirst)
  3265. {
  3266. bFirst = false;
  3267. GetMainWnd()->GlobalNotify(WM_GAME_CHANGED);
  3268. }
  3269. }
  3270. //-----------------------------------------------------------------------------
  3271. // Purpose: this will activate and bring to front the supplied map document
  3272. // Input : pDoc - the document to activate
  3273. // Output : none
  3274. //-----------------------------------------------------------------------------
  3275. void CMapDoc::ActivateMapDoc( CMapDoc *pDoc )
  3276. {
  3277. POSITION posView = pDoc->GetFirstViewPosition( );
  3278. if( posView )
  3279. {
  3280. CView* pView = pDoc->GetNextView( posView );
  3281. ((CMDIChildWnd*) pView->GetParentFrame( ))->MDIActivate( );
  3282. }
  3283. }
  3284. //-----------------------------------------------------------------------------
  3285. // Purpose:
  3286. //-----------------------------------------------------------------------------
  3287. CMapWorld *GetActiveWorld(void)
  3288. {
  3289. CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
  3290. if (pDoc != NULL)
  3291. {
  3292. return(pDoc->GetMapWorld());
  3293. }
  3294. return(NULL);
  3295. }
  3296. //-----------------------------------------------------------------------------
  3297. //-----------------------------------------------------------------------------
  3298. IWorldEditDispMgr *GetActiveWorldEditDispManager( void )
  3299. {
  3300. CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
  3301. if( pDoc )
  3302. {
  3303. CMapWorld *pWorld = pDoc->GetMapWorld();
  3304. if( pWorld )
  3305. {
  3306. return pWorld->GetWorldEditDispManager();
  3307. }
  3308. }
  3309. return NULL;
  3310. }
  3311. //-----------------------------------------------------------------------------
  3312. // Purpose: Deletes the object by removing it from its parent. The object is
  3313. // kept in the Undo history. If the object being deleted is the only
  3314. // child of a solid entity, that entity is also deleted.
  3315. // Input : pObject - The object to delete.
  3316. //-----------------------------------------------------------------------------
  3317. void CMapDoc::DeleteObject(CMapClass *pObject)
  3318. {
  3319. GetHistory()->KeepForDestruction(pObject);
  3320. CMapClass *pParent = pObject->GetParent();
  3321. RemoveObjectFromWorld(pObject, true);
  3322. // If we are deleting the last child of a solid entity, or the last member of
  3323. // a group, delete the parent object also. This avoids ghost objects at the origin.
  3324. pObject->SignalChanged();
  3325. if (pParent)
  3326. {
  3327. if (pParent->IsGroup())
  3328. {
  3329. if (pParent->GetChildCount() == 0)
  3330. {
  3331. DeleteObject(pParent);
  3332. }
  3333. }
  3334. else
  3335. {
  3336. CMapEntity *pParentEntity = dynamic_cast <CMapEntity *>(pParent);
  3337. if (pParentEntity != NULL)
  3338. {
  3339. if (!pParentEntity->IsPlaceholder() && !pParentEntity->HasSolidChildren())
  3340. {
  3341. DeleteObject(pParentEntity);
  3342. }
  3343. }
  3344. }
  3345. }
  3346. }
  3347. //-----------------------------------------------------------------------------
  3348. // Purpose: Call this to delete multiple objects in a single operation.
  3349. // Input : List -
  3350. //-----------------------------------------------------------------------------
  3351. void CMapDoc::DeleteObjectList(CMapObjectList &List)
  3352. {
  3353. FOR_EACH_OBJ( List, pos )
  3354. {
  3355. CMapClass *pObject = List.Element(pos);
  3356. Assert(pObject != NULL);
  3357. DeleteObject(pObject);
  3358. }
  3359. m_pSelection->RemoveAll();
  3360. SetModifiedFlag();
  3361. }
  3362. //-----------------------------------------------------------------------------
  3363. // Purpose: Delete selected objects.
  3364. //-----------------------------------------------------------------------------
  3365. void CMapDoc::OnEditDelete(void)
  3366. {
  3367. Delete();
  3368. }
  3369. //-----------------------------------------------------------------------------
  3370. // Purpose: Invokes the search/replace dialog.
  3371. //-----------------------------------------------------------------------------
  3372. void CMapDoc::OnEditReplace(void)
  3373. {
  3374. GetMainWnd()->ShowSearchReplaceDialog();
  3375. }
  3376. //-----------------------------------------------------------------------------
  3377. // Purpose:
  3378. //-----------------------------------------------------------------------------
  3379. void CMapDoc::OnMapSnaptogrid(void)
  3380. {
  3381. m_bSnapToGrid = !m_bSnapToGrid;
  3382. UpdateStatusBarSnap();
  3383. }
  3384. //-----------------------------------------------------------------------------
  3385. // Purpose:
  3386. //-----------------------------------------------------------------------------
  3387. void CMapDoc::UpdateStatusBarSnap(void)
  3388. {
  3389. CString strSnap;
  3390. strSnap.Format(" Snap: %s Grid: %d ", m_bSnapToGrid ? "On" : "Off", m_nGridSpacing);
  3391. SetStatusText(SBI_SNAP, strSnap);
  3392. }
  3393. //-----------------------------------------------------------------------------
  3394. // Purpose:
  3395. //-----------------------------------------------------------------------------
  3396. void CMapDoc::OnUpdateMapSnaptogrid(CCmdUI* pCmdUI)
  3397. {
  3398. pCmdUI->SetCheck(m_bSnapToGrid);
  3399. }
  3400. //-----------------------------------------------------------------------------
  3401. // Purpose: Deselects everything.
  3402. //-----------------------------------------------------------------------------
  3403. void CMapDoc::OnEditClearselection(void)
  3404. {
  3405. if (m_pToolManager->GetActiveToolID() == TOOL_MORPH)
  3406. {
  3407. // clear morph
  3408. m_pToolManager->GetActiveTool()->SetEmpty();
  3409. UpdateAllViews( MAPVIEW_UPDATE_OBJECTS );
  3410. }
  3411. else if (m_pToolManager->GetActiveToolID() == TOOL_FACEEDIT_MATERIAL)
  3412. {
  3413. SelectFace(NULL, 0, scClear|scSaveChanges);
  3414. }
  3415. else
  3416. {
  3417. if ( m_pSelection->GetCount() > 2)
  3418. {
  3419. GetHistory()->MarkUndoPosition( m_pSelection->GetList(), "Clear Selection");
  3420. }
  3421. SelectObject(NULL, scClear|scSaveChanges);
  3422. }
  3423. }
  3424. //-----------------------------------------------------------------------------
  3425. // Purpose:
  3426. // Input : pSolid -
  3427. // pszTexture -
  3428. // Output : Returns TRUE to continue iterating.
  3429. //-----------------------------------------------------------------------------
  3430. static BOOL ApplyTextureToSolid(CMapSolid *pSolid, LPCTSTR pszTexture)
  3431. {
  3432. pSolid->SetTexture(pszTexture);
  3433. return TRUE;
  3434. }
  3435. //-----------------------------------------------------------------------------
  3436. // Purpose: Manages the state of the Apply Current Texture toolbar button.
  3437. //-----------------------------------------------------------------------------
  3438. void CMapDoc::OnUpdateEditApplytexture(CCmdUI* pCmdUI)
  3439. {
  3440. if ( IsSelectionEditable() == false )
  3441. {
  3442. pCmdUI->Enable( FALSE );
  3443. }
  3444. else
  3445. {
  3446. pCmdUI->Enable( ( m_pToolManager->GetActiveToolID() != TOOL_FACEEDIT_MATERIAL ) && !GetMainWnd()->IsShellSessionActive() );
  3447. }
  3448. }
  3449. //-----------------------------------------------------------------------------
  3450. // Purpose: Applies the current default texture to all faces of all selected solids.
  3451. //-----------------------------------------------------------------------------
  3452. void CMapDoc::OnEditApplytexture(void)
  3453. {
  3454. const CMapObjectList *pSelList = m_pSelection->GetList();
  3455. GetHistory()->MarkUndoPosition( pSelList, "Apply Texture");
  3456. // texturebar.cpp:
  3457. LPCTSTR GetDefaultTextureName();
  3458. for (int i = 0; i < pSelList->Count(); i++)
  3459. {
  3460. CMapClass *pobj = pSelList->Element(i);
  3461. if (pobj->IsMapClass(MAPCLASS_TYPE(CMapSolid)))
  3462. {
  3463. GetHistory()->Keep(pobj);
  3464. ((CMapSolid*)pobj)->SetTexture(GetDefaultTextureName());
  3465. }
  3466. pobj->EnumChildren((ENUMMAPCHILDRENPROC)ApplyTextureToSolid, (DWORD)GetDefaultTextureName(), MAPCLASS_TYPE(CMapSolid));
  3467. }
  3468. SetModifiedFlag();
  3469. }
  3470. //-----------------------------------------------------------------------------
  3471. // Purpose: Callback for EnumChildren. Adds the object to the given list.
  3472. // Input : pObject - Object to add to the list.
  3473. // pList - List to add the object to.
  3474. // Output : Returns TRUE to continue iterating.
  3475. //-----------------------------------------------------------------------------
  3476. static BOOL CopyObjectsToList(CMapClass *pObject, CMapObjectList *pList)
  3477. {
  3478. pList->AddToTail(pObject);
  3479. return(TRUE);
  3480. }
  3481. //-----------------------------------------------------------------------------
  3482. // Purpose: Makes all selected brushes the children of a solid entity. The
  3483. // class will be the default solid class from the game configuration.
  3484. //-----------------------------------------------------------------------------
  3485. void CMapDoc::OnEditToEntity(void)
  3486. {
  3487. extern GameData *pGD;
  3488. CMapEntity *pNewEntity = NULL;
  3489. BOOL bMadeEntity = TRUE;
  3490. BOOL bUseSelectionDialog = FALSE;
  3491. //
  3492. // Build a list of every solid in the selection, whether part of a solid entity or not.
  3493. //
  3494. CMapObjectList newobjects;
  3495. const CMapObjectList *pSelList = m_pSelection->GetList();
  3496. for (int i = 0; i < pSelList->Count(); i++)
  3497. {
  3498. CMapClass *pObject = pSelList->Element(i);
  3499. //
  3500. // If the object is a solid, add it to our list.
  3501. //
  3502. if (pObject->IsMapClass(MAPCLASS_TYPE(CMapSolid)))
  3503. {
  3504. newobjects.AddToTail(pObject);
  3505. }
  3506. //
  3507. // If the object is a group, add any solids in the group to our list.
  3508. //
  3509. else if (pObject->IsGroup())
  3510. {
  3511. pObject->EnumChildren(ENUMMAPCHILDRENPROC(CopyObjectsToList), DWORD(&newobjects), MAPCLASS_TYPE(CMapSolid));
  3512. }
  3513. //
  3514. // If the object is an entity, add any solid children of the entity to our list.
  3515. //
  3516. else if (pObject->IsMapClass(MAPCLASS_TYPE(CMapEntity)))
  3517. {
  3518. pObject->EnumChildren(ENUMMAPCHILDRENPROC(CopyObjectsToList), DWORD(&newobjects), MAPCLASS_TYPE(CMapSolid));
  3519. //
  3520. // See if there is more than one solid entity selected. If so, we'll need to prompt the user
  3521. // to pick one.
  3522. //
  3523. CMapEntity *pEntity = (CMapEntity *)pObject;
  3524. if (!pEntity->IsPlaceholder())
  3525. {
  3526. //
  3527. // Already found an eligible entity, so we want
  3528. // to call up the entity selection dialog.
  3529. //
  3530. if (pNewEntity != NULL)
  3531. {
  3532. bUseSelectionDialog = TRUE;
  3533. }
  3534. pNewEntity = pEntity;
  3535. }
  3536. }
  3537. }
  3538. //
  3539. // If the list is empty, we have nothing to do.
  3540. //
  3541. if ( newobjects.Count() == 0)
  3542. {
  3543. AfxMessageBox("There are no eligible selected objects.");
  3544. return;
  3545. }
  3546. //
  3547. // If already have an entity selected, ask if they want to
  3548. // add solids to it.
  3549. //
  3550. if (pNewEntity && !bUseSelectionDialog)
  3551. {
  3552. CString str;
  3553. str.Format("You have selected an existing entity (a '%s'.)\n"
  3554. "Would you like to add the selected solids to the existing entity?\n"
  3555. "If you select 'No', a new entity will be created.",
  3556. pNewEntity->GetClassName());
  3557. if (AfxMessageBox(str, MB_YESNO) == IDNO)
  3558. {
  3559. pNewEntity = NULL; // it'll be made down there
  3560. }
  3561. else
  3562. {
  3563. bMadeEntity = FALSE;
  3564. }
  3565. }
  3566. //
  3567. // If there were multiple solid entities selected, bring up the selection dialog.
  3568. //
  3569. else if (bUseSelectionDialog)
  3570. {
  3571. CSelectEntityDlg dlg(m_pSelection->GetList());
  3572. GetMainWnd()->pObjectProperties->ShowWindow(SW_SHOW);
  3573. if (dlg.DoModal() == IDCANCEL)
  3574. {
  3575. return; // forget about it
  3576. }
  3577. pNewEntity = dlg.m_pFinalEntity;
  3578. bMadeEntity = FALSE;
  3579. }
  3580. GetHistory()->MarkUndoPosition(m_pSelection->GetList(), "To Entity");
  3581. GetHistory()->Keep(m_pSelection->GetList());
  3582. //
  3583. // If they haven't already picked an entity to add the solids to, create a new
  3584. // solid entity.
  3585. //
  3586. if (!pNewEntity)
  3587. {
  3588. pNewEntity = new CMapEntity;
  3589. bMadeEntity = TRUE;
  3590. }
  3591. //
  3592. // Add all the solids in our list to the solid entity.
  3593. //
  3594. FOR_EACH_OBJ( newobjects, pos )
  3595. {
  3596. CMapClass *pObject = newobjects.Element(pos);
  3597. CMapClass *pOldParent = pObject->GetParent();
  3598. //
  3599. // If the solid is changing parents...
  3600. //
  3601. if (pOldParent != pNewEntity)
  3602. {
  3603. Assert(pOldParent != NULL);
  3604. if (pOldParent != NULL)
  3605. {
  3606. //
  3607. // Remove the solid from its current parent.
  3608. //
  3609. pOldParent->RemoveChild(pObject);
  3610. //
  3611. // If this solid was the child of a solid entity, check to see if the entity has
  3612. // any children left - if not, we remove it from the world because it's useless without
  3613. // solid children.
  3614. //
  3615. CMapEntity *pOldParentEnt = dynamic_cast<CMapEntity *>(pOldParent);
  3616. if (pOldParentEnt && (!pOldParentEnt->IsPlaceholder()) && (!pOldParentEnt->HasSolidChildren()))
  3617. {
  3618. DeleteObject(pOldParentEnt);
  3619. }
  3620. }
  3621. //
  3622. // Add visgroups from the solid to the new entity.
  3623. //
  3624. int nVisGroupCount = pObject->GetVisGroupCount();
  3625. for (int nVisGroup = 0; nVisGroup < nVisGroupCount; nVisGroup++)
  3626. {
  3627. CVisGroup *pVisGroup = pObject->GetVisGroup(nVisGroup);
  3628. // Don't transfer autovisgroups
  3629. if ( pVisGroup->IsAutoVisGroup() )
  3630. continue;
  3631. pNewEntity->AddVisGroup(pVisGroup);
  3632. }
  3633. //
  3634. // Remove the child from all visgroups
  3635. //
  3636. pObject->RemoveAllVisGroups();
  3637. //
  3638. // Add the solid as a child of the new parent entity.
  3639. //
  3640. pNewEntity->AddChild(pObject);
  3641. }
  3642. }
  3643. //
  3644. // If we created a new entity, add it to the world.
  3645. //
  3646. if (bMadeEntity)
  3647. {
  3648. pNewEntity->SetPlaceholder(FALSE);
  3649. pNewEntity->SetClass(g_pGameConfig->szDefaultSolid);
  3650. AddObjectToWorld(pNewEntity);
  3651. //
  3652. // Don't keep our children because they are not new to the world.
  3653. //
  3654. GetHistory()->KeepNew(pNewEntity, false);
  3655. }
  3656. SelectObject(pNewEntity, scClear|scSelect|scSaveChanges );
  3657. m_pToolManager->SetTool(TOOL_POINTER);
  3658. if (bMadeEntity)
  3659. {
  3660. GetMainWnd()->pObjectProperties->ShowWindow(SW_SHOW);
  3661. GetMainWnd()->pObjectProperties->SetActiveWindow();
  3662. }
  3663. SetModifiedFlag();
  3664. }
  3665. //-----------------------------------------------------------------------------
  3666. // Purpose: Moves all solid children of selected entities to the world.
  3667. //-----------------------------------------------------------------------------
  3668. void CMapDoc::OnEditToWorld(void)
  3669. {
  3670. CMapObjectList SelList;
  3671. SelList.AddVectorToTail( *m_pSelection->GetList());
  3672. if ( SelList.Count()>0 )
  3673. {
  3674. GetHistory()->MarkUndoPosition(m_pSelection->GetList(), "To World");
  3675. GetHistory()->Keep(m_pSelection->GetList());
  3676. //
  3677. // Remove selection rect from screen & clear selection list.
  3678. //
  3679. SelectObject(NULL, scClear|scSaveChanges );
  3680. FOR_EACH_OBJ( SelList, pos )
  3681. {
  3682. CMapClass *pObject = SelList.Element(pos);
  3683. CMapEntity *pEntity = dynamic_cast<CMapEntity *>(pObject);
  3684. //
  3685. // If this is a solid entity, move all its children to the world.
  3686. //
  3687. if ((pEntity != NULL) && (!pEntity->IsPlaceholder()))
  3688. {
  3689. //
  3690. // Build a list of the entity's solid children.
  3691. //
  3692. CMapObjectList ChildList;
  3693. const CMapObjectList *pChildren = pEntity->GetChildren();
  3694. FOR_EACH_OBJ( *pChildren, pos2 )
  3695. {
  3696. CMapClass *pChild = pChildren->Element(pos2);
  3697. if ((dynamic_cast<CMapSolid *>(pChild)) != NULL)
  3698. {
  3699. ChildList.AddToTail(pChild);
  3700. }
  3701. }
  3702. //
  3703. // Detach all the children from the entity. This throws out
  3704. // all non-solid children, since they aren't in our list.
  3705. //
  3706. pEntity->RemoveAllChildren();
  3707. //
  3708. // Move the entity's former solid children to the world.
  3709. //
  3710. int nChildCount = ChildList.Count();
  3711. for (int i = 0; i < nChildCount; i++)
  3712. {
  3713. CMapClass *pChild = ChildList.Element(i);
  3714. m_pWorld->AddChild(pChild);
  3715. int nVisGroupCount = pEntity->GetVisGroupCount();
  3716. for (int nVisGroup = 0; nVisGroup < nVisGroupCount; nVisGroup++)
  3717. {
  3718. CVisGroup *pVisGroup = pEntity->GetVisGroup(nVisGroup);
  3719. // Don't add autovisgroups when moving back
  3720. if ( pVisGroup->IsAutoVisGroup() )
  3721. continue;
  3722. pChild->AddVisGroup(pVisGroup);
  3723. }
  3724. // Add autovisgroups for the child
  3725. RemoveFromAutoVisGroups( pChild );
  3726. AddToAutoVisGroup( pChild );
  3727. pChild->SetRenderColor(0, 100 + (random() % 156), 100 + (random() % 156));
  3728. SelectObject(pChild, scSelect);
  3729. }
  3730. //
  3731. // The entity is empty; delete it.
  3732. //
  3733. DeleteObject(pEntity);
  3734. }
  3735. }
  3736. }
  3737. m_pToolManager->SetTool(TOOL_POINTER);
  3738. SetModifiedFlag();
  3739. }
  3740. //-----------------------------------------------------------------------------
  3741. // Purpose: Subtracts the first object in the selection set (by index) from
  3742. // all solids in the world.
  3743. //-----------------------------------------------------------------------------
  3744. void CMapDoc::OnToolsSubtractselection(void)
  3745. {
  3746. if ( m_pSelection->IsEmpty())
  3747. {
  3748. return;
  3749. }
  3750. //
  3751. // Subtract with the first object in the selection list.
  3752. //
  3753. const CMapObjectList *pSelList = m_pSelection->GetList();
  3754. CMapClass *pSubtractWith = pSelList->Element(0);
  3755. Assert( pSubtractWith != NULL );
  3756. GetHistory()->MarkUndoPosition(pSelList, "Carve");
  3757. GetHistory()->Keep(pSelList);
  3758. //
  3759. // Build a list of every solid in the world.
  3760. //
  3761. CMapObjectList WorldSolids;
  3762. EnumChildrenPos_t pos;
  3763. CMapClass *pChild = m_pWorld->GetFirstDescendent(pos);
  3764. while (pChild != NULL)
  3765. {
  3766. CMapSolid *pSolid = dynamic_cast <CMapSolid *> (pChild);
  3767. if (pSolid != NULL)
  3768. {
  3769. WorldSolids.AddToTail(pSolid);
  3770. }
  3771. pChild = m_pWorld->GetNextDescendent(pos);
  3772. }
  3773. if (WorldSolids.Count() == 0)
  3774. {
  3775. return;
  3776. }
  3777. bool bLocked = VisGroups_LockUpdates( true );
  3778. //
  3779. // Subtract the 'subtract with' object from every solid in the world.
  3780. //
  3781. FOR_EACH_OBJ( WorldSolids, p )
  3782. {
  3783. CMapSolid *pSubtractFrom = (CMapSolid *)WorldSolids.Element(p);
  3784. CMapClass *pDestParent = pSubtractFrom->GetParent();
  3785. //
  3786. // Perform the subtraction. If the two objects intersected...
  3787. //
  3788. CMapObjectList Outside;
  3789. if (pSubtractFrom->Subtract(NULL, &Outside, pSubtractWith))
  3790. {
  3791. if (Outside.Count() > 0)
  3792. {
  3793. CMapClass *pResult = NULL;
  3794. //
  3795. // If the subtraction resulted in more than one object, create a group
  3796. // to place the results in.
  3797. //
  3798. if (Outside.Count() > 1)
  3799. {
  3800. pResult = (CMapClass *)(new CMapGroup);
  3801. FOR_EACH_OBJ( Outside, pos2 )
  3802. {
  3803. CMapClass *pTemp = Outside.Element(pos2);
  3804. pResult->AddChild(pTemp);
  3805. }
  3806. }
  3807. //
  3808. // Otherwise, the results are the single object.
  3809. //
  3810. else if (Outside.Count() == 1)
  3811. {
  3812. pResult = Outside[0];
  3813. }
  3814. //
  3815. // Replace the 'subtract from' object with the subtraction results.
  3816. //
  3817. DeleteObject(pSubtractFrom);
  3818. AddObjectToWorld(pResult, pDestParent);
  3819. GetHistory()->KeepNew(pResult);
  3820. }
  3821. }
  3822. }
  3823. if ( bLocked )
  3824. VisGroups_LockUpdates( false );
  3825. SetModifiedFlag();
  3826. }
  3827. //-----------------------------------------------------------------------------
  3828. // Purpose: Copies the selected objects to the clipboard.
  3829. //-----------------------------------------------------------------------------
  3830. void CMapDoc::OnEditCopy(void)
  3831. {
  3832. if ( !m_pSelection->IsCopyable() )
  3833. {
  3834. return;
  3835. }
  3836. Copy();
  3837. }
  3838. //-----------------------------------------------------------------------------
  3839. // Purpose:
  3840. // Input : ptOrg -
  3841. //-----------------------------------------------------------------------------
  3842. void CMapDoc::GetBestVisiblePoint(Vector& ptOrg)
  3843. {
  3844. // create paste position at center of 1st 2d view
  3845. FOR_EACH_OBJ( MRU2DViews, pos )
  3846. {
  3847. CMapView2D *pView = MRU2DViews.Element(pos);
  3848. pView->GetCenterPoint(ptOrg);
  3849. }
  3850. for(int i = 0; i < 3; i++)
  3851. {
  3852. if(ptOrg[i] == COORD_NOTINIT)
  3853. ptOrg[i] = 0;
  3854. }
  3855. }
  3856. //-----------------------------------------------------------------------------
  3857. // Purpose: Gets a point on the screen to paste to. Functionalized because it
  3858. // is called from OnEditPaste and OnEditPasteSpecial.
  3859. //-----------------------------------------------------------------------------
  3860. void CMapDoc::GetBestPastePoint(Vector &vecPasteOrigin)
  3861. {
  3862. //
  3863. // Start with a visible grid point near the center of the screen.
  3864. //
  3865. vecPasteOrigin = Vector(COORD_NOTINIT, COORD_NOTINIT, COORD_NOTINIT);
  3866. CMapView *pView = GetActiveMapView();
  3867. CView *pMFCView = dynamic_cast<CView*>(pView);
  3868. if ( pView )
  3869. {
  3870. // zoom in on cursor position
  3871. POINT ptClient;
  3872. GetCursorPos(&ptClient);
  3873. pMFCView->ScreenToClient(&ptClient);
  3874. int width, height;
  3875. pView->GetCamera()->GetViewPort( width, height );
  3876. if ( ptClient.x >= 0 && ptClient.x < width &&
  3877. ptClient.y >= 0 && ptClient.y < height )
  3878. {
  3879. // if mouse pos is inside a view, figure out whic one
  3880. CMapView3D *p3DView = dynamic_cast<CMapView3D*>(pView);
  3881. CMapView2D *p2DView = dynamic_cast<CMapView2D*>(pView);
  3882. Vector2D vPoint(ptClient.x,ptClient.y);
  3883. if ( p3DView )
  3884. {
  3885. HitInfo_t Hits;
  3886. if ( p3DView->ObjectsAt( vPoint, &Hits, 1, FLAG_OBJECTS_AT_RESOLVE_INSTANCES ) )
  3887. {
  3888. VMatrix LocalMatrixNeg;
  3889. Hits.m_LocalMatrix.InverseTR( LocalMatrixNeg );
  3890. // If they clicked on a solid, the index of the face they clicked on is stored
  3891. // in array index [1].
  3892. CMapClass *pObject = Hits.pObject;
  3893. CMapSolid *pSolid = dynamic_cast<CMapSolid *>(pObject);
  3894. Vector HitPos,HitNormal;
  3895. Vector start,end,mins,maxs,delta;
  3896. float dist;
  3897. int face;
  3898. bool bOk = false;
  3899. p3DView->GetCamera()->BuildRay( vPoint, start, end);
  3900. Vector vFinalStart, vFinalEnd;
  3901. LocalMatrixNeg.V3Mul( start, vFinalStart );
  3902. LocalMatrixNeg.V3Mul( end, vFinalEnd );
  3903. if (pSolid != NULL)
  3904. {
  3905. // Build a ray to trace against the face that they clicked on to
  3906. // find the point of intersection.
  3907. CMapFace *pFace = pSolid->GetFace(Hits.uData);
  3908. bOk = pFace->TraceLine(HitPos, HitNormal, vFinalStart, vFinalEnd);
  3909. }
  3910. else if ( pObject != NULL )
  3911. {
  3912. // we hit something, just trace against bound box
  3913. pObject->GetRender2DBox( mins, maxs );
  3914. dist = IntersectionLineAABBox( mins, maxs, vFinalStart, vFinalEnd, face );
  3915. if ( dist > 0 )
  3916. {
  3917. delta = vFinalEnd-vFinalStart;
  3918. VectorNormalize( delta );
  3919. HitPos = vFinalStart + dist * delta;
  3920. HitNormal = GetNormalFromFace( face );
  3921. bOk = true;
  3922. }
  3923. }
  3924. if ( bOk )
  3925. {
  3926. Vector vFinalHitPos, vFinalHitNormal;
  3927. Hits.m_LocalMatrix.V3Mul( HitPos, vFinalHitPos );
  3928. vFinalHitNormal = Hits.m_LocalMatrix.ApplyRotation( HitNormal );
  3929. mins = GetHammerClipboard()->Bounds.bmins;
  3930. maxs = GetHammerClipboard()->Bounds.bmaxs;
  3931. delta = vFinalHitPos - (mins+maxs)/2;
  3932. mins += delta;
  3933. maxs += delta;
  3934. start = vFinalHitPos;
  3935. end = vFinalHitPos + vFinalHitNormal*4096;
  3936. dist = IntersectionLineAABBox( mins, maxs, start, end, face );
  3937. if ( dist > 0 )
  3938. {
  3939. vecPasteOrigin = vFinalHitPos + vFinalHitNormal * dist;
  3940. }
  3941. else
  3942. {
  3943. vecPasteOrigin = vFinalHitPos;
  3944. }
  3945. }
  3946. }
  3947. }
  3948. else if ( p2DView )
  3949. {
  3950. p2DView->ClientToWorld( vecPasteOrigin, vPoint );
  3951. vecPasteOrigin[p2DView->axThird] = COORD_NOTINIT;
  3952. GetBestVisiblePoint(vecPasteOrigin);
  3953. Snap(vecPasteOrigin);
  3954. }
  3955. }
  3956. }
  3957. // ok, no mouse over any active view, use center of last used 2D views
  3958. if ( vecPasteOrigin.x == COORD_NOTINIT )
  3959. {
  3960. GetBestVisiblePoint(vecPasteOrigin);
  3961. Snap(vecPasteOrigin);
  3962. // Offset the center relative to the grid the same as it was originally.
  3963. Vector vecSnappedOriginalCenter = GetHammerClipboard()->vecOriginalCenter;
  3964. Snap(vecSnappedOriginalCenter);
  3965. vecPasteOrigin += GetHammerClipboard()->vecOriginalCenter - vecSnappedOriginalCenter;
  3966. }
  3967. }
  3968. void CMapDoc::Paste( IHammerClipboard *pClipboard, CMapWorld *pDestWorld, Vector vecOffset, QAngle vecRotate, CMapClass *pParent, bool bMakeEntityNamesUnique, const char *pszEntityNamePrefix )
  3969. {
  3970. CHammerClipboard *pSrc = GetHammerClipboard( pClipboard );
  3971. Paste( pSrc->Objects, pSrc->pSourceWorld, pDestWorld, vecOffset, vecRotate, pParent, bMakeEntityNamesUnique, pszEntityNamePrefix );
  3972. }
  3973. //-----------------------------------------------------------------------------
  3974. // Purpose: This function will peform a 'cut' operation on the selected entities.
  3975. //-----------------------------------------------------------------------------
  3976. void CMapDoc::Cut( IHammerClipboard *pClipboard )
  3977. {
  3978. Copy( pClipboard );
  3979. Delete();
  3980. }
  3981. //-----------------------------------------------------------------------------
  3982. // Purpose: This function will perform a 'copy' operation on the selected entities.
  3983. //-----------------------------------------------------------------------------
  3984. void CMapDoc::Copy( IHammerClipboard *pClipboard )
  3985. {
  3986. if ( m_pSelection->IsEmpty() )
  3987. {
  3988. return;
  3989. }
  3990. if ( pClipboard == NULL )
  3991. {
  3992. pClipboard = GetHammerClipboard();
  3993. }
  3994. BeginWaitCursor();
  3995. // Delete the contents of the clipboard.
  3996. GetHammerClipboard( pClipboard )->Objects.PurgeAndDeleteElements();
  3997. m_pSelection->GetBoundsCenter(GetHammerClipboard( pClipboard )->vecOriginalCenter);
  3998. m_pSelection->GetBounds(GetHammerClipboard( pClipboard )->Bounds.bmins, GetHammerClipboard( pClipboard )->Bounds.bmaxs);
  3999. GetHistory()->Pause();
  4000. GetHammerClipboard( pClipboard )->pSourceWorld = m_pWorld;
  4001. // Copy the selected objects to the clipboard.
  4002. const CMapObjectList *pSelList = m_pSelection->GetList();
  4003. for (int i = 0; i < pSelList->Count() ; i++)
  4004. {
  4005. CMapClass *pobj = pSelList->Element(i);
  4006. CMapClass *pNewobj = pobj->Copy(false);
  4007. //
  4008. // Prune the object from the world tree without calling RemoveObjectFromWorld.
  4009. // This prevents CopyChildrenFrom from updating the culling tree.
  4010. //
  4011. //pNewobj->SetObjParent(NULL);
  4012. //
  4013. // Copy all the children from the original object into the copied object.
  4014. //
  4015. pNewobj->CopyChildrenFrom(pobj, false);
  4016. //
  4017. // Remove the copied object from the world.
  4018. //
  4019. RemoveObjectFromWorld(pNewobj, true);
  4020. pNewobj->RemoveAllVisGroups();
  4021. GetHammerClipboard( pClipboard )->Objects.AddToTail(pNewobj);
  4022. }
  4023. GetHistory()->Resume();
  4024. EndWaitCursor();
  4025. }
  4026. //-----------------------------------------------------------------------------
  4027. // Purpose:
  4028. // Input : Objects -
  4029. // pSourceWorld -
  4030. // pDestWorld -
  4031. // vecOffset -
  4032. // vecRotate -
  4033. // pParent -
  4034. //-----------------------------------------------------------------------------
  4035. void CMapDoc::Paste(CMapObjectList &Objects, CMapWorld *pSourceWorld, CMapWorld *pDestWorld, Vector vecOffset, QAngle vecRotate, CMapClass *pParent, bool bMakeEntityNamesUnique, const char *pszEntityNamePrefix)
  4036. {
  4037. //
  4038. // Copy the objects in the clipboard and build a list of objects to paste
  4039. // into the world.
  4040. //
  4041. CMapObjectList PasteList;
  4042. bool bLocked = VisGroups_LockUpdates( true );
  4043. if ( GetManifest() && pSourceWorld != pDestWorld )
  4044. {
  4045. bMakeEntityNamesUnique = true;
  4046. }
  4047. FOR_EACH_OBJ( Objects, pos )
  4048. {
  4049. CMapClass *pOriginal = Objects.Element(pos);
  4050. CMapClass *pCopy = pOriginal->Copy(false);
  4051. pCopy->CopyChildrenFrom(pOriginal, false);
  4052. PasteList.AddToTail(pCopy);
  4053. }
  4054. if ( bMakeEntityNamesUnique || ( pszEntityNamePrefix && ( pszEntityNamePrefix[0] != '\0' ) ) )
  4055. {
  4056. //
  4057. // Make all the pasted objects with names have new, unique names within the destination world.
  4058. //
  4059. // Stick the objects into a temporary world object for renaming the entities.
  4060. CMapWorld temp( this );
  4061. FOR_EACH_OBJ( PasteList, pos )
  4062. {
  4063. CMapClass *pObject = PasteList.Element( pos );
  4064. temp.AddChild( pObject );
  4065. }
  4066. RenameEntities( &temp, pDestWorld, bMakeEntityNamesUnique, pszEntityNamePrefix );
  4067. // So they don't get deleted when temp goes out of scope.
  4068. temp.RemoveAllChildren();
  4069. }
  4070. //
  4071. // Notification happens in two-passes. The first pass lets objects generate new unique
  4072. // IDs in the destination world, the second pass lets objects fixup references to other
  4073. // objects in the clipboard.
  4074. //
  4075. Assert( Objects.Count() == PasteList.Count() );
  4076. FOR_EACH_OBJ( Objects, pos )
  4077. {
  4078. CMapClass *pOriginal = Objects.Element(pos);
  4079. CMapClass *pCopy = PasteList.Element(pos);
  4080. pOriginal->OnPrePaste(pCopy, pSourceWorld, pDestWorld, Objects, PasteList);
  4081. }
  4082. //
  4083. // Add the objects to the world.
  4084. //
  4085. FOR_EACH_OBJ( PasteList, pos )
  4086. {
  4087. CMapClass *pCopy = PasteList.Element(pos);
  4088. if (vecOffset != vec3_origin)
  4089. {
  4090. pCopy->TransMove(vecOffset);
  4091. }
  4092. if (vecRotate != vec3_angle)
  4093. {
  4094. Vector ptCenter;
  4095. pCopy->GetBoundsCenter(ptCenter);
  4096. pCopy->TransRotate(ptCenter, vecRotate);
  4097. }
  4098. AddObjectToWorld(pCopy, pParent);
  4099. }
  4100. //
  4101. // Do the second pass of notification. The second pass of notification lets objects
  4102. // fixup references to other objects that were pasted. We don't do it in the loop above
  4103. // because then not all the pasted objects would be in the world yet.
  4104. //
  4105. Assert( Objects.Count() == PasteList.Count() );
  4106. FOR_EACH_OBJ( Objects, pos )
  4107. {
  4108. CMapClass *pOriginal = Objects.Element(pos);
  4109. CMapClass *pCopy = PasteList.Element(pos);
  4110. pOriginal->OnPaste(pCopy, pSourceWorld, pDestWorld, Objects, PasteList);
  4111. //
  4112. // Semi-HACK: If we aren't pasting into a group, keep the new object in the Undo stack.
  4113. // Otherwise, we'll keep the group in OnEditPasteSpecial.
  4114. //
  4115. if ((pParent == NULL) || (pParent == pDestWorld))
  4116. {
  4117. GetHistory()->KeepNew(pCopy);
  4118. SelectObject(pCopy, scSelect);
  4119. }
  4120. }
  4121. if ( bLocked )
  4122. {
  4123. VisGroups_LockUpdates( false );
  4124. }
  4125. }
  4126. //-----------------------------------------------------------------------------
  4127. // Purpose:
  4128. // Input : Objects -
  4129. // pSourceWorld -
  4130. // pDestWorld -
  4131. // vecOffset -
  4132. // vecRotate -
  4133. // pParent -
  4134. //-----------------------------------------------------------------------------
  4135. void CMapDoc::PasteInstance(CMapObjectList &Objects, CMapWorld *pSourceWorld, CMapWorld *pDestWorld, Vector vecOffset, QAngle vecRotate, CMapClass *pParent, bool bMakeEntityNamesUnique, const char *pszEntityNamePrefix)
  4136. {
  4137. QAngle vecRotateFix;
  4138. vecRotateFix.x = vecRotate[ PITCH ];
  4139. vecRotateFix.y = vecRotate[ ROLL ];
  4140. vecRotateFix.z = vecRotate[ YAW ];
  4141. //
  4142. // Copy the objects in the clipboard and build a list of objects to paste
  4143. // into the world.
  4144. //
  4145. CMapObjectList PasteList;
  4146. bool bLocked = VisGroups_LockUpdates( true );
  4147. if ( GetManifest() && pSourceWorld != pDestWorld )
  4148. {
  4149. bMakeEntityNamesUnique = true;
  4150. }
  4151. FOR_EACH_OBJ( Objects, pos )
  4152. {
  4153. CMapClass *pOriginal = Objects.Element(pos);
  4154. CMapClass *pCopy = pOriginal->Copy(false);
  4155. pCopy->CopyChildrenFrom(pOriginal, false);
  4156. PasteList.AddToTail(pCopy);
  4157. }
  4158. if ( bMakeEntityNamesUnique || ( pszEntityNamePrefix && ( pszEntityNamePrefix[0] != '\0' ) ) )
  4159. {
  4160. //
  4161. // Make all the pasted objects with names have new, unique names within the destination world.
  4162. //
  4163. // Stick the objects into a temporary world object for renaming the entities.
  4164. CMapWorld temp( this );
  4165. FOR_EACH_OBJ( PasteList, pos )
  4166. {
  4167. CMapClass *pObject = PasteList.Element( pos );
  4168. temp.AddChild( pObject );
  4169. }
  4170. RenameEntities( &temp, pDestWorld, bMakeEntityNamesUnique, pszEntityNamePrefix );
  4171. // So they don't get deleted when temp goes out of scope.
  4172. temp.RemoveAllChildren();
  4173. }
  4174. //
  4175. // Notification happens in two-passes. The first pass lets objects generate new unique
  4176. // IDs in the destination world, the second pass lets objects fixup references to other
  4177. // objects in the clipboard.
  4178. //
  4179. Assert( Objects.Count() == PasteList.Count() );
  4180. FOR_EACH_OBJ( Objects, pos )
  4181. {
  4182. CMapClass *pOriginal = Objects.Element(pos);
  4183. CMapClass *pCopy = PasteList.Element(pos);
  4184. pOriginal->OnPrePaste(pCopy, pSourceWorld, pDestWorld, Objects, PasteList);
  4185. }
  4186. //
  4187. // Add the objects to the world.
  4188. //
  4189. FOR_EACH_OBJ( PasteList, pos )
  4190. {
  4191. CMapClass *pCopy = PasteList.Element(pos);
  4192. if (vecRotateFix != vec3_angle)
  4193. {
  4194. pCopy->TransRotate( vec3_origin, vecRotateFix );
  4195. }
  4196. if (vecOffset != vec3_origin)
  4197. {
  4198. pCopy->TransMove(vecOffset);
  4199. }
  4200. AddObjectToWorld(pCopy, pParent);
  4201. }
  4202. //
  4203. // Do the second pass of notification. The second pass of notification lets objects
  4204. // fixup references to other objects that were pasted. We don't do it in the loop above
  4205. // because then not all the pasted objects would be in the world yet.
  4206. //
  4207. Assert( Objects.Count() == PasteList.Count() );
  4208. FOR_EACH_OBJ( Objects, pos )
  4209. {
  4210. CMapClass *pOriginal = Objects.Element(pos);
  4211. CMapClass *pCopy = PasteList.Element(pos);
  4212. pOriginal->OnPaste(pCopy, pSourceWorld, pDestWorld, Objects, PasteList);
  4213. //
  4214. // Semi-HACK: If we aren't pasting into a group, keep the new object in the Undo stack.
  4215. // Otherwise, we'll keep the group in OnEditPasteSpecial.
  4216. //
  4217. if ((pParent == NULL) || (pParent == pDestWorld))
  4218. {
  4219. GetHistory()->KeepNew(pCopy);
  4220. SelectObject(pCopy, scSelect);
  4221. }
  4222. }
  4223. if ( bLocked )
  4224. {
  4225. VisGroups_LockUpdates( false );
  4226. }
  4227. }
  4228. //-----------------------------------------------------------------------------
  4229. // Purpose: This function will perform a 'delete' operation on the selected entities.
  4230. //-----------------------------------------------------------------------------
  4231. void CMapDoc::Delete( void )
  4232. {
  4233. if (m_pToolManager->GetActiveToolID() == TOOL_MORPH)
  4234. {
  4235. // Can't delete stuff while morphing.
  4236. return;
  4237. }
  4238. if ( m_pSelection->IsEmpty() || !m_pSelection->IsCopyable() )
  4239. {
  4240. return;
  4241. }
  4242. const CMapObjectList *pSelList = m_pSelection->GetList();
  4243. GetHistory()->MarkUndoPosition(pSelList, "Delete");
  4244. // Delete objects in selection.
  4245. while ( !m_pSelection->IsEmpty() )
  4246. {
  4247. CMapClass *pobj = pSelList->Element(0);
  4248. DeleteObject(pobj);
  4249. }
  4250. SetModifiedFlag();
  4251. }
  4252. //-----------------------------------------------------------------------------
  4253. // Purpose: Pastes the clipboard contents into the active world.
  4254. //-----------------------------------------------------------------------------
  4255. void CMapDoc::OnEditPaste(void)
  4256. {
  4257. BeginWaitCursor();
  4258. GetHistory()->MarkUndoPosition( m_pSelection->GetList(), "Paste");
  4259. // first, clear selection so we can select all pasted objects
  4260. SelectObject(NULL, scClear|scSaveChanges );
  4261. //
  4262. // Build a translation that will put the pasted objects in the center of the view.
  4263. //
  4264. Vector vecPasteOffset;
  4265. GetBestPastePoint(vecPasteOffset);
  4266. vecPasteOffset -= GetHammerClipboard()->vecOriginalCenter;
  4267. //
  4268. // Paste the objects into the active world.
  4269. //
  4270. CMapWorld *pWorld = GetActiveWorld();
  4271. Paste(GetHammerClipboard()->Objects, GetHammerClipboard()->pSourceWorld, pWorld, vecPasteOffset, QAngle(0, 0, 0), NULL, false, NULL);
  4272. m_pToolManager->SetTool(TOOL_POINTER);
  4273. SetModifiedFlag();
  4274. EndWaitCursor();
  4275. }
  4276. //-----------------------------------------------------------------------------
  4277. // Disable the unhide option when the quickhide list is empty.
  4278. //-----------------------------------------------------------------------------
  4279. void CMapDoc::OnQuickHide_UpdateUnHide(CCmdUI *pCmdUI)
  4280. {
  4281. pCmdUI->Enable( m_QuickHideGroup.Count() > 0 );
  4282. }
  4283. //-----------------------------------------------------------------------------
  4284. // Disable the Create VisGroup menu option when QuickHide is empty.
  4285. //-----------------------------------------------------------------------------
  4286. void CMapDoc::OnQuickHide_UpdateCreateVisGroupFromHidden(CCmdUI *pCmdUI)
  4287. {
  4288. pCmdUI->Enable( m_QuickHideGroup.Count() > 0 );
  4289. }
  4290. //-----------------------------------------------------------------------------
  4291. // Purpose: Manages the state of the Copy menu item.
  4292. //-----------------------------------------------------------------------------
  4293. void CMapDoc::OnUpdateEditSelection(CCmdUI *pCmdUI)
  4294. {
  4295. bool bMorphSnap = m_pToolManager->GetActiveToolID() == TOOL_MORPH && pCmdUI->m_nID == ID_TOOLS_SNAPSELECTEDTOGRID;
  4296. bool bStandardCommand = ( m_pSelection->GetCount() != 0 ) && m_pSelection->IsCopyable() &&
  4297. ( m_pToolManager->GetActiveToolID() != TOOL_FACEEDIT_MATERIAL ) &&
  4298. !GetMainWnd()->IsShellSessionActive();
  4299. pCmdUI->Enable( bMorphSnap || bStandardCommand );
  4300. }
  4301. //-----------------------------------------------------------------------------
  4302. // Purpose: Manages the state of the Paste menu item.
  4303. //-----------------------------------------------------------------------------
  4304. void CMapDoc::OnUpdateEditPaste(CCmdUI *pCmdUI)
  4305. {
  4306. pCmdUI->Enable( GetHammerClipboard()->Objects.Count() &&
  4307. ( m_pToolManager->GetActiveToolID() != TOOL_FACEEDIT_MATERIAL ) &&
  4308. !GetMainWnd()->IsShellSessionActive() );
  4309. }
  4310. //-----------------------------------------------------------------------------
  4311. // Purpose: Handles the Edit | Cut command. Copies the selection to the clipboard,
  4312. // then deletes it from the document.
  4313. //-----------------------------------------------------------------------------
  4314. void CMapDoc::OnEditCut(void)
  4315. {
  4316. if ( !m_pSelection->IsCopyable() )
  4317. {
  4318. return;
  4319. }
  4320. Cut( GetHammerClipboard() );
  4321. }
  4322. //-----------------------------------------------------------------------------
  4323. // Purpose: Manages the state of the various Edit menu items.
  4324. //-----------------------------------------------------------------------------
  4325. void CMapDoc::OnUpdateGroupEditFunction(CCmdUI* pCmdUI)
  4326. {
  4327. //
  4328. // Edit functions are disabled when we're applying textures or editing via a shell session.
  4329. //
  4330. pCmdUI->Enable( ( m_pToolManager->GetActiveToolID() != TOOL_FACEEDIT_MATERIAL ) &&
  4331. !GetMainWnd()->IsShellSessionActive() );
  4332. }
  4333. //-----------------------------------------------------------------------------
  4334. // Purpose: Creates a new group and adds all selected items to it.
  4335. //-----------------------------------------------------------------------------
  4336. void CMapDoc::OnToolsGroup(void)
  4337. {
  4338. if ( m_pSelection->IsEmpty() )
  4339. {
  4340. AfxMessageBox("No objects are selected.");
  4341. return;
  4342. }
  4343. if (( m_pSelection->GetMode() == selectSolids) && !Options.general.bGroupWhileIgnore)
  4344. {
  4345. return;
  4346. }
  4347. const CMapObjectList *pSelList = m_pSelection->GetList();
  4348. // First see if grouping these objects will remove them from an existing entity or group.
  4349. for (int i = 0; i < pSelList->Count(); i++)
  4350. {
  4351. CMapClass *pobj = pSelList->Element(i);
  4352. if ((pobj->GetParent() != NULL) && (!IsWorldObject(pobj->GetParent())))
  4353. {
  4354. if (GetMainWnd()->MessageBox("Some selected objects are part of an entity or belong to a group. Grouping them now will remove them from the entity or group! Continue?", "Warning", MB_YESNO | MB_ICONEXCLAMATION) != IDYES)
  4355. {
  4356. return;
  4357. }
  4358. break;
  4359. }
  4360. }
  4361. GetHistory()->MarkUndoPosition(m_pSelection->GetList(), "Group Objects");
  4362. GetHistory()->Keep(m_pSelection->GetList());
  4363. //
  4364. // Create a new group containing the selected objects.
  4365. //
  4366. CMapGroup *pGroup = new CMapGroup;
  4367. AddObjectToWorld(pGroup);
  4368. pGroup->SetRenderColor(100 + (random() % 156), 100 + (random() % 156), 0);
  4369. for (int i = 0; i < pSelList->Count(); i++)
  4370. {
  4371. CMapClass *pobj = pSelList->Element(i);
  4372. if (pobj->GetParent() != NULL)
  4373. {
  4374. pobj->GetParent()->RemoveChild(pobj);
  4375. }
  4376. pGroup->AddChild(pobj);
  4377. }
  4378. //
  4379. // Keep the group as a new object. Don't keep its children here,
  4380. // because they are not new.
  4381. //
  4382. GetHistory()->KeepNew(pGroup, false);
  4383. // Clear selection and add the new group to it.
  4384. SelectObject(pGroup, scClear|scSelect|scSaveChanges );
  4385. SetModifiedFlag();
  4386. }
  4387. //-----------------------------------------------------------------------------
  4388. // Purpose: Ungroups all selected objects.
  4389. //-----------------------------------------------------------------------------
  4390. void CMapDoc::OnToolsUngroup(void)
  4391. {
  4392. if (( m_pSelection->GetMode() == selectSolids) && !Options.general.bGroupWhileIgnore)
  4393. {
  4394. return;
  4395. }
  4396. const CMapObjectList *pSelList = m_pSelection->GetList();
  4397. GetHistory()->MarkUndoPosition(pSelList, "Ungroup");
  4398. GetHistory()->Keep(pSelList);
  4399. // create new selected list
  4400. CMapObjectList NewSelList;
  4401. NewSelList.AddVectorToTail( *pSelList );
  4402. m_pSelection->SelectObject( NULL, scClear );
  4403. FOR_EACH_OBJ( NewSelList, pos )
  4404. {
  4405. CMapClass *pobj = NewSelList.Element(pos);
  4406. if(!pobj->IsMapClass(MAPCLASS_TYPE(CMapGroup)))
  4407. {
  4408. // make sure it is selected in the map
  4409. SelectObject(pobj, scSelect);
  4410. continue;
  4411. }
  4412. //
  4413. // Build a list of the group's children.
  4414. //
  4415. CMapObjectList ChildList;
  4416. const CMapObjectList *pChildren = pobj->GetChildren();
  4417. FOR_EACH_OBJ( *pChildren, pos2 )
  4418. {
  4419. ChildList.AddToTail(pChildren->Element(pos2));
  4420. }
  4421. //
  4422. // Detach the children from the group.
  4423. //
  4424. pobj->RemoveAllChildren();
  4425. //
  4426. // Move the group's former children to the group's parent.
  4427. //
  4428. int nChildCount = ChildList.Count();
  4429. for (int i = 0; i < nChildCount; i++)
  4430. {
  4431. CMapClass *pChild = ChildList.Element(i);
  4432. pobj->GetParent()->AddChild(pChild);
  4433. int nVisGroupCount = pobj->GetVisGroupCount();
  4434. for (int nVisGroup = 0; nVisGroup < nVisGroupCount; nVisGroup++)
  4435. {
  4436. CVisGroup *pVisGroup = pobj->GetVisGroup(nVisGroup);
  4437. pChild->AddVisGroup(pVisGroup);
  4438. }
  4439. pChild->SetRenderColor(0, 100 + (random() % 156), 100 + (random() % 156));
  4440. SelectObject(pChild, scSelect);
  4441. }
  4442. //
  4443. // The group is empty; delete it.
  4444. //
  4445. DeleteObject(pobj);
  4446. }
  4447. SetModifiedFlag();
  4448. }
  4449. //-----------------------------------------------------------------------------
  4450. // Purpose: Toggles the visibility of the grid in the 2D views.
  4451. //-----------------------------------------------------------------------------
  4452. void CMapDoc::OnViewGrid(void)
  4453. {
  4454. m_bShowGrid = !m_bShowGrid;
  4455. UpdateAllViews( MAPVIEW_OPTIONS_CHANGED );
  4456. }
  4457. //-----------------------------------------------------------------------------
  4458. // Purpose: Sets the check state of the Show Grid toolbar button and menu item.
  4459. //-----------------------------------------------------------------------------
  4460. void CMapDoc::OnUpdateViewGrid(CCmdUI *pCmdUI)
  4461. {
  4462. pCmdUI->SetCheck(m_bShowGrid);
  4463. }
  4464. //-----------------------------------------------------------------------------
  4465. // Purpose: Toggles the visibility of the grid in the 2D views.
  4466. //-----------------------------------------------------------------------------
  4467. void CMapDoc::OnViewLogicalGrid(void)
  4468. {
  4469. m_bShowLogicalGrid = !m_bShowLogicalGrid;
  4470. UpdateAllViews( MAPVIEW_UPDATE_ONLY_LOGICAL );
  4471. }
  4472. //-----------------------------------------------------------------------------
  4473. // Purpose: Sets the check state of the Show Grid toolbar button and menu item.
  4474. //-----------------------------------------------------------------------------
  4475. void CMapDoc::OnUpdateViewLogicalGrid(CCmdUI *pCmdUI)
  4476. {
  4477. pCmdUI->SetCheck(m_bShowLogicalGrid);
  4478. }
  4479. //-----------------------------------------------------------------------------
  4480. // Purpose: Selects all objects that are not hidden.
  4481. //-----------------------------------------------------------------------------
  4482. void CMapDoc::OnEditSelectall(void)
  4483. {
  4484. if (m_pToolManager->GetActiveToolID() == TOOL_MORPH)
  4485. {
  4486. // select all vertices
  4487. Morph3D *pMorph = (Morph3D*) m_pToolManager->GetActiveTool();
  4488. pMorph->SelectHandle(NULL, scSelectAll);
  4489. return;
  4490. }
  4491. SelectObject(NULL, scClear|scSaveChanges );
  4492. const CMapObjectList *pChildren = m_pWorld->GetChildren();
  4493. FOR_EACH_OBJ( *pChildren, pos )
  4494. {
  4495. CMapClass *pChild = pChildren->Element(pos);
  4496. if (pChild->IsVisible())
  4497. {
  4498. SelectObject(pChild, scSelect);
  4499. }
  4500. }
  4501. }
  4502. //-----------------------------------------------------------------------------
  4503. // Purpose:
  4504. //-----------------------------------------------------------------------------
  4505. void CMapDoc::OnFileSaveAs(void)
  4506. {
  4507. static char szBaseDir[MAX_PATH] = "";
  4508. bool bSave = true;
  4509. CString str;
  4510. do
  4511. {
  4512. //
  4513. // The default directory for the Save As dialog is either:
  4514. // 1. The directory from which the document was loaded.
  4515. // 2. The last directory they saved any document into.
  4516. // 3. The maps directory as set up in Options | Game Configurations.
  4517. //
  4518. str = GetPathName();
  4519. if (str.ReverseFind('.') != -1)
  4520. {
  4521. str = str.Left(str.ReverseFind('.'));
  4522. strcpy(szBaseDir, str);
  4523. Q_StripFilename(szBaseDir);
  4524. }
  4525. else if (szBaseDir[0] =='\0')
  4526. {
  4527. strcpy(szBaseDir, m_pGame->szMapDir);
  4528. }
  4529. char *pszFilter;
  4530. if ( m_pManifest )
  4531. {
  4532. pszFilter = "Valve Manifest Map Files (*.vmm)|*.vmm||";
  4533. }
  4534. else if (m_pGame->mapformat == mfHalfLife2)
  4535. {
  4536. pszFilter = "Valve Map Files (*.vmf)|*.vmf||";
  4537. }
  4538. else
  4539. {
  4540. pszFilter = "Worldcraft Maps (*.rmf)|*.rmf|Game Maps (*.map)|*.map||";
  4541. }
  4542. CFileDialog dlg(FALSE, NULL, str, OFN_LONGNAMES | OFN_NOCHANGEDIR | OFN_HIDEREADONLY, pszFilter);
  4543. dlg.m_ofn.lpstrInitialDir = szBaseDir;
  4544. int rvl = dlg.DoModal();
  4545. if (rvl == IDCANCEL)
  4546. {
  4547. return;
  4548. }
  4549. str = dlg.GetPathName();
  4550. // Make sure we've got a .vmt extension, or else compile tools won't work.
  4551. CString wantedExtension = ".vmf";
  4552. if ( m_pManifest )
  4553. {
  4554. wantedExtension = ".vmm";
  4555. }
  4556. if ( m_pGame->mapformat != mfHalfLife2 )
  4557. {
  4558. if ( dlg.m_ofn.nFilterIndex == 1 )
  4559. {
  4560. wantedExtension = ".rmf";
  4561. }
  4562. else if ( dlg.m_ofn.nFilterIndex == 2 )
  4563. {
  4564. wantedExtension = ".map";
  4565. }
  4566. }
  4567. int pos = str.ReverseFind( '.' );
  4568. if ( pos != -1 )
  4569. {
  4570. CString extension = str.Right( str.GetLength() - pos );
  4571. extension.MakeLower();
  4572. if ( extension != wantedExtension )
  4573. str = str.Left( pos ) + wantedExtension;
  4574. }
  4575. else
  4576. { // no extension
  4577. str += wantedExtension;
  4578. }
  4579. //
  4580. // Save the default directory for next time.
  4581. //
  4582. strcpy(szBaseDir, str);
  4583. Q_StripFilename(szBaseDir);
  4584. bSave = true;
  4585. if (access(str, 0) != -1)
  4586. {
  4587. // The file exists.
  4588. char szConfirm[_MAX_PATH];
  4589. if (access(str, 2) == -1)
  4590. {
  4591. // The file is read-only
  4592. wsprintf(szConfirm, "The file %s is read-only. You must change the file's attributes to overwrite it.", (const char*)str);
  4593. AfxMessageBox(szConfirm, MB_OK | MB_ICONEXCLAMATION);
  4594. bSave = false;
  4595. }
  4596. else
  4597. {
  4598. wsprintf(szConfirm, "Overwrite existing file %s?", (const char*)str);
  4599. if (AfxMessageBox(szConfirm, MB_YESNO | MB_ICONQUESTION) != IDYES)
  4600. {
  4601. bSave = false;
  4602. }
  4603. }
  4604. }
  4605. } while (!bSave);
  4606. OnSaveDocument(str);
  4607. SetPathName(str);
  4608. }
  4609. //-----------------------------------------------------------------------------
  4610. // Purpose:
  4611. //-----------------------------------------------------------------------------
  4612. void CMapDoc::OnFileSave(void)
  4613. {
  4614. DWORD dwAttrib = GetFileAttributes(GetPathName());
  4615. if (dwAttrib & FILE_ATTRIBUTE_READONLY)
  4616. {
  4617. // we do not have read-write access or the file does not (now) exist
  4618. OnFileSaveAs();
  4619. }
  4620. else
  4621. {
  4622. if(m_strPathName.IsEmpty())
  4623. {
  4624. OnFileSaveAs();
  4625. }
  4626. else
  4627. {
  4628. OnSaveDocument(GetPathName());
  4629. }
  4630. }
  4631. }
  4632. //-----------------------------------------------------------------------------
  4633. // Purpose: Manages the state of the File | Save menu item.
  4634. //-----------------------------------------------------------------------------
  4635. void CMapDoc::OnUpdateFileSave(CCmdUI *pCmdUI)
  4636. {
  4637. pCmdUI->SetText(m_bEditingPrefab ? "Update Prefab\tCtrl+S" : "&Save\tCtrl+S");
  4638. }
  4639. //-----------------------------------------------------------------------------
  4640. // Purpose:
  4641. //-----------------------------------------------------------------------------
  4642. void CMapDoc::OnMapGridlower(void)
  4643. {
  4644. if (m_nGridSpacing <= 1)
  4645. {
  4646. return;
  4647. }
  4648. m_nGridSpacing = m_nGridSpacing / 2;
  4649. UpdateAllViews( MAPVIEW_OPTIONS_CHANGED );
  4650. UpdateStatusBarSnap();
  4651. }
  4652. //-----------------------------------------------------------------------------
  4653. // Purpose:
  4654. //-----------------------------------------------------------------------------
  4655. void CMapDoc::OnMapGridhigher(void)
  4656. {
  4657. if(m_nGridSpacing >= 512)
  4658. return;
  4659. m_nGridSpacing = m_nGridSpacing * 2;
  4660. UpdateAllViews( MAPVIEW_OPTIONS_CHANGED );
  4661. UpdateStatusBarSnap();
  4662. }
  4663. class CExportDlg : public CFileDialog
  4664. {
  4665. public:
  4666. CExportDlg(CString& strFile, LPCTSTR pszExt, LPCTSTR pszDesc) :
  4667. CFileDialog(FALSE, pszExt, strFile,
  4668. OFN_NOCHANGEDIR | OFN_LONGNAMES | OFN_HIDEREADONLY | OFN_EXPLORER |
  4669. OFN_ENABLETEMPLATE, pszDesc)
  4670. {
  4671. m_ofn.lpTemplateName = MAKEINTRESOURCE(IDD_MAPEXPORT);
  4672. bVisibles = FALSE;
  4673. }
  4674. afx_msg BOOL OnInitDialog()
  4675. {
  4676. m_Visibles.SubclassDlgItem(IDC_SAVEVISIBLES, this);
  4677. m_Visibles.SetCheck(bVisibles);
  4678. return TRUE;
  4679. }
  4680. afx_msg void OnToggleVisibles()
  4681. {
  4682. bVisibles = m_Visibles.GetCheck();
  4683. }
  4684. CButton m_Visibles;
  4685. BOOL bVisibles;
  4686. DECLARE_MESSAGE_MAP()
  4687. };
  4688. BEGIN_MESSAGE_MAP(CExportDlg, CFileDialog)
  4689. ON_BN_CLICKED(IDC_SAVEVISIBLES, OnToggleVisibles)
  4690. END_MESSAGE_MAP()
  4691. static BOOL bLastVis;
  4692. //-----------------------------------------------------------------------------
  4693. // Purpose:
  4694. //-----------------------------------------------------------------------------
  4695. void CMapDoc::OnFileExport(void)
  4696. {
  4697. //
  4698. // If we haven't saved the file yet, save it now.
  4699. //
  4700. CString strFile = GetPathName();
  4701. if (strFile.IsEmpty())
  4702. {
  4703. OnFileSave();
  4704. strFile = GetPathName();
  4705. if (strFile.IsEmpty())
  4706. {
  4707. return;
  4708. }
  4709. }
  4710. //
  4711. // Build a name for the exported file.
  4712. //
  4713. int iIndex = strFile.Find('.');
  4714. char *pszFilter;
  4715. char *pszExtension;
  4716. if (m_pGame->mapformat == mfHalfLife2)
  4717. {
  4718. strFile.SetAt(iIndex, '\0');
  4719. pszFilter = "Valve Map Files (*.vmf)|*.vmf||";
  4720. pszExtension = "vmf";
  4721. }
  4722. else
  4723. {
  4724. //
  4725. // Use the same filename with a .map extension.
  4726. //
  4727. strcpy(strFile.GetBuffer(1) + iIndex, ".map");
  4728. strFile.ReleaseBuffer();
  4729. pszFilter = "Game Maps (*.map)|*.map||";
  4730. pszExtension = "map";
  4731. }
  4732. //
  4733. // Bring up a dialog to allow them to name the exported file.
  4734. //
  4735. CExportDlg dlg(strFile, pszExtension, pszFilter);
  4736. dlg.m_ofn.lpstrTitle = "Export As";
  4737. dlg.bVisibles = bLastVis;
  4738. if (dlg.DoModal() == IDOK)
  4739. {
  4740. BOOL bModified = IsModified();
  4741. if (strFile.CompareNoCase(dlg.GetPathName()) == 0)
  4742. {
  4743. if (GetMainWnd()->MessageBox("You are about to export over your current work file. Some data loss will occur if you have any objects hidden. Continue?", "Export Warning", MB_YESNO | MB_ICONEXCLAMATION) != IDYES)
  4744. {
  4745. return;
  4746. }
  4747. }
  4748. bSaveVisiblesOnly = dlg.bVisibles;
  4749. m_strLastExportFileName = dlg.GetPathName();
  4750. OnSaveDocument(dlg.GetPathName());
  4751. bSaveVisiblesOnly = FALSE;
  4752. SetModifiedFlag(bModified);
  4753. bLastVis = dlg.bVisibles;
  4754. }
  4755. }
  4756. //-----------------------------------------------------------------------------
  4757. // Purpose: Exports using the last exported pathname. Brings up the Export dialog
  4758. // only if this document has never been exported.
  4759. //-----------------------------------------------------------------------------
  4760. void CMapDoc::OnFileExportAgain(void)
  4761. {
  4762. CString strFile = m_strLastExportFileName;
  4763. //
  4764. // If we have never exported this map, bring up the Export dialog.
  4765. //
  4766. if (strFile.IsEmpty())
  4767. {
  4768. OnFileExport();
  4769. return;
  4770. }
  4771. BOOL bModified = IsModified();
  4772. bSaveVisiblesOnly = bLastVis;
  4773. OnSaveDocument(strFile);
  4774. bSaveVisiblesOnly = FALSE;
  4775. SetModifiedFlag(bModified);
  4776. }
  4777. //-----------------------------------------------------------------------------
  4778. // Purpose:
  4779. //-----------------------------------------------------------------------------
  4780. void CMapDoc::OnEditMapproperties(void)
  4781. {
  4782. m_pSelection->SelectObject( m_pWorld, scClear|scSelect );
  4783. GetMainWnd()->pObjectProperties->ShowWindow(SW_SHOW);
  4784. }
  4785. //-----------------------------------------------------------------------------
  4786. // Purpose: Converts a map's textures from WAD3 to VMT.
  4787. //-----------------------------------------------------------------------------
  4788. void CMapDoc::OnFileConvertWAD( void )
  4789. {
  4790. CTextureConverter::ConvertWorldTextures( m_pWorld );
  4791. }
  4792. //-----------------------------------------------------------------------------
  4793. // Purpose: Manages the state of the File | Convert WAD -> VMT menu item.
  4794. //-----------------------------------------------------------------------------
  4795. void CMapDoc::OnUpdateFileConvertWAD( CCmdUI * pCmdUI )
  4796. {
  4797. pCmdUI->Enable( ( m_pWorld != NULL ) && ( g_pGameConfig->GetTextureFormat() == tfVMT ) );
  4798. }
  4799. //-----------------------------------------------------------------------------
  4800. // Purpose: Gets the relevant file extensions for the given map format.
  4801. // Input : mf -
  4802. // strEditExtension - The extension of the edit file (eg. .VMF, .RMF)
  4803. // strCompileExtension - The extension of the file to compile (eg. .VMF, .MAP)
  4804. //-----------------------------------------------------------------------------
  4805. void GetFileExtensions(MAPFORMAT mf, CString &strEditExtension, CString &strCompileExtension)
  4806. {
  4807. if (mf == mfHalfLife2)
  4808. {
  4809. strEditExtension = ".vmf";
  4810. strCompileExtension = ".vmf";
  4811. }
  4812. else
  4813. {
  4814. strEditExtension = ".rmf";
  4815. strCompileExtension = ".map";
  4816. }
  4817. }
  4818. //-----------------------------------------------------------------------------
  4819. // Purpose: Does a normal map compile.
  4820. //-----------------------------------------------------------------------------
  4821. void CMapDoc::OnFileRunmap(void)
  4822. {
  4823. //
  4824. // Check for texture wads first if the current game config uses them.
  4825. //
  4826. if ((g_pGameConfig->GetTextureFormat() == tfWAD) && !Options.textures.nTextureFiles)
  4827. {
  4828. AfxMessageBox("There are no texture files defined yet. Add some texture files before you run the map.");
  4829. GetMainWnd()->Configure();
  4830. return;
  4831. }
  4832. CString strEditExtension;
  4833. CString strCompileExtension;
  4834. GetFileExtensions(g_pGameConfig->GetMapFormat(), strEditExtension, strCompileExtension);
  4835. CRunMap dlg;
  4836. CRunMapExpertDlg dlgExpert;
  4837. CString strFile = GetPathName();
  4838. bool bWasModified = (IsModified() == TRUE);
  4839. bSaveVisiblesOnly = FALSE;
  4840. // Make sure the .VMF or .RMF is saved first.
  4841. if (strFile.IsEmpty() || bWasModified)
  4842. {
  4843. OnFileSave();
  4844. strFile = GetPathName();
  4845. if (strFile.IsEmpty() || IsModified())
  4846. {
  4847. return;
  4848. }
  4849. }
  4850. strFile.MakeLower();
  4851. // Make sure it has the correct extension for compilation (.VMF or .MAP).
  4852. int iPos = strFile.Find(strEditExtension);
  4853. Assert(iPos != -1);
  4854. if ((iPos != -1) && (strEditExtension.CompareNoCase(strCompileExtension) != 0))
  4855. {
  4856. strcpy(strFile.GetBuffer(0) + iPos, strCompileExtension);
  4857. strFile.ReleaseBuffer();
  4858. // Make sure the .MAP version is up to date.
  4859. if (bWasModified)
  4860. {
  4861. OnSaveDocument(strFile);
  4862. }
  4863. }
  4864. // make "bsp" string
  4865. CString strBspFile(strFile);
  4866. iPos = strBspFile.Find(strCompileExtension);
  4867. strcpy(strBspFile.GetBuffer(0) + iPos, ".bsp");
  4868. strBspFile.ReleaseBuffer();
  4869. // if no bsp file, make sure it's checked
  4870. if (GetFileAttributes(strBspFile) == 0xFFFFFFFF)
  4871. {
  4872. dlg.m_iQBSP = 1;
  4873. }
  4874. while (1)
  4875. {
  4876. if (AfxGetApp()->GetProfileInt("Run Map", "Mode", 0) == 0)
  4877. {
  4878. // run normal dialog
  4879. if(dlg.DoModal() == IDCANCEL)
  4880. return;
  4881. // switching mode?
  4882. if(dlg.m_bSwitchMode)
  4883. {
  4884. dlg.m_bSwitchMode = FALSE;
  4885. AfxGetApp()->WriteProfileInt("Run Map", "Mode", 1);
  4886. }
  4887. else
  4888. {
  4889. dlg.SaveToIni();
  4890. break; // clicked OK
  4891. }
  4892. }
  4893. else
  4894. {
  4895. // run expert dialog
  4896. if (dlgExpert.DoModal() == IDCANCEL)
  4897. return;
  4898. // switching mode?
  4899. if (dlgExpert.m_bSwitchMode)
  4900. {
  4901. AfxGetApp()->WriteProfileInt("Run Map", "Mode", 0);
  4902. dlgExpert.m_bSwitchMode = FALSE;
  4903. }
  4904. else if (dlgExpert.m_pActiveSequence) // clicked ok
  4905. {
  4906. // run the commands in the active sequence
  4907. RunCommands(dlgExpert.m_pActiveSequence->m_Commands, strFile);
  4908. return;
  4909. }
  4910. else
  4911. {
  4912. return;
  4913. }
  4914. }
  4915. }
  4916. if (GetFileAttributes(strBspFile) == 0xFFFFFFFF)
  4917. {
  4918. if (!dlg.m_iQBSP)
  4919. {
  4920. dlg.m_iQBSP = 1;
  4921. }
  4922. }
  4923. CCOMMAND cmd;
  4924. memset(&cmd, 0, sizeof cmd);
  4925. cmd.bEnable = TRUE;
  4926. cmd.bUseProcessWnd = TRUE;
  4927. cmd.bLongFilenames = TRUE;
  4928. CCommandArray cmds;
  4929. // Change to the game drive and directory.
  4930. //cmd.iSpecialCmd = CCChangeDir;
  4931. //Q_snprintf( cmd.szParms, sizeof(cmd.szParms), "\"%s\"", m_pGame->m_szGameExeDir);
  4932. //strcpy(cmd.szRun, "Change Directory");
  4933. //cmds.Add(cmd);
  4934. //cmd.iSpecialCmd = 0;
  4935. // bsp
  4936. if ((dlg.m_iQBSP) && (m_pGame->szBSP[0] != '\0'))
  4937. {
  4938. strcpy(cmd.szRun, "$bsp_exe");
  4939. sprintf(cmd.szParms, "-game $gamedir %s$path\\$file.$ext", dlg.m_iQBSP == 2 ? "-onlyents " : "");
  4940. // check for bsp existence only in quake maps, because
  4941. // we're using the editor's utilities
  4942. if (g_pGameConfig->mapformat == mfQuake)
  4943. {
  4944. cmd.bEnsureCheck = TRUE;
  4945. strcpy(cmd.szEnsureFn, "$path\\$file.bsp");
  4946. }
  4947. cmds.Add(cmd);
  4948. cmd.bEnsureCheck = FALSE;
  4949. }
  4950. // vis
  4951. if ((dlg.m_iVis) && (m_pGame->szVIS[0] != '\0'))
  4952. {
  4953. strcpy(cmd.szRun, "$vis_exe");
  4954. sprintf(cmd.szParms, "-game $gamedir %s$path\\$file", dlg.m_iVis == 2 ? "-fast " : "");
  4955. cmds.Add(cmd);
  4956. }
  4957. // rad
  4958. if ((dlg.m_iLight) && (m_pGame->szLIGHT[0] != '\0'))
  4959. {
  4960. strcpy(cmd.szRun, "$light_exe");
  4961. sprintf(cmd.szParms, "%s -game $gamedir %s$path\\$file", dlg.m_bHDRLight ? "-both" : "", dlg.m_iLight == 2 ? "-noextra " : "" );
  4962. cmds.Add(cmd);
  4963. }
  4964. // Copy BSP file to BSP directory for running
  4965. cmd.iSpecialCmd = CCCopyFile;
  4966. strcpy(cmd.szRun, "Copy File");
  4967. sprintf(cmd.szParms, "$path\\$file.bsp $bspdir\\$file.bsp");
  4968. cmds.Add(cmd);
  4969. cmd.iSpecialCmd = 0;
  4970. // Run the game.
  4971. if (dlg.m_bNoQuake == FALSE)
  4972. {
  4973. cmd.bUseProcessWnd = FALSE;
  4974. cmd.bNoWait = TRUE;
  4975. //When running under steam, use applaunch always because if a user forgets to run the game they're trying to launch, it will fail
  4976. //with an obscure error they won't understand.
  4977. {
  4978. strcpy(cmd.szRun, "$game_exe");
  4979. sprintf(cmd.szParms, "-game $gamedir %s +map $file -steam", (const char*)dlg.m_strQuakeParms);
  4980. }
  4981. cmds.Add(cmd);
  4982. }
  4983. RunCommands(cmds, GetPathName());
  4984. }
  4985. //-----------------------------------------------------------------------------
  4986. // Purpose: Updates the title of the doc based on the filename and the
  4987. // active view type.
  4988. // Input : pView -
  4989. //-----------------------------------------------------------------------------
  4990. void CMapDoc::UpdateTitle(CView *pView)
  4991. {
  4992. CString strFile = GetPathName();
  4993. LPCTSTR pszFilename = strFile;
  4994. // Leaving the partial-filename code in here in case we want to make it an option someday.
  4995. bool bShowPartialFilename = false;
  4996. if ( bShowPartialFilename )
  4997. {
  4998. int iPos = strFile.ReverseFind('\\');
  4999. if (iPos != -1)
  5000. {
  5001. pszFilename = strFile.GetBuffer(0) + iPos + 1;
  5002. }
  5003. else
  5004. {
  5005. pszFilename = "Untitled";
  5006. }
  5007. }
  5008. char *pViewType = NULL;
  5009. CMapView2D *pView2D = dynamic_cast <CMapView2D *> (pView);
  5010. if (pView2D != NULL)
  5011. {
  5012. switch (pView2D->GetDrawType())
  5013. {
  5014. case VIEW2D_XY:
  5015. {
  5016. pViewType = "Top";
  5017. break;
  5018. }
  5019. case VIEW2D_XZ:
  5020. {
  5021. pViewType = "Right";
  5022. break;
  5023. }
  5024. case VIEW2D_YZ:
  5025. {
  5026. pViewType = "Front";
  5027. break;
  5028. }
  5029. }
  5030. }
  5031. CMapViewLogical *pViewLogical = dynamic_cast <CMapViewLogical *> (pView);
  5032. if (pViewLogical != NULL)
  5033. {
  5034. pViewType = "Logical";
  5035. }
  5036. CMapView3D *pView3D = dynamic_cast <CMapView3D *> (pView);
  5037. if (pView3D != NULL)
  5038. {
  5039. switch (pView3D->GetDrawType())
  5040. {
  5041. case VIEW3D_WIREFRAME:
  5042. {
  5043. pViewType = "Wireframe";
  5044. break;
  5045. }
  5046. case VIEW3D_POLYGON:
  5047. {
  5048. pViewType = "Polygon";
  5049. break;
  5050. }
  5051. case VIEW3D_TEXTURED:
  5052. {
  5053. pViewType = "Textured";
  5054. break;
  5055. }
  5056. case VIEW3D_TEXTURED_SHADED:
  5057. {
  5058. pViewType = "Textured Shaded";
  5059. break;
  5060. }
  5061. case VIEW3D_LIGHTMAP_GRID:
  5062. {
  5063. pViewType = "Lightmap grid";
  5064. break;
  5065. }
  5066. case VIEW3D_SMOOTHING_GROUP:
  5067. {
  5068. pViewType = "Smoothing Group";
  5069. break;
  5070. }
  5071. //case VIEW3D_ENGINE:
  5072. //{
  5073. // pViewType = "Engine";
  5074. // break;
  5075. //}
  5076. }
  5077. }
  5078. CString str;
  5079. if (pViewType)
  5080. {
  5081. str.Format("%s - %s", pszFilename, pViewType);
  5082. }
  5083. else
  5084. {
  5085. str.Format("%s", pszFilename);
  5086. }
  5087. SetTitle(str);
  5088. }
  5089. //-----------------------------------------------------------------------------
  5090. // Purpose: Toggles the state of Hide Items. When enabled, entities are hidden.
  5091. //-----------------------------------------------------------------------------
  5092. void CMapDoc::OnToolsHideitems(void)
  5093. {
  5094. m_bHideItems = !m_bHideItems;
  5095. UpdateVisibilityAll();
  5096. }
  5097. //-----------------------------------------------------------------------------
  5098. // Purpose: Manages the state of the Tools | Hide Items menu item.
  5099. //-----------------------------------------------------------------------------
  5100. void CMapDoc::OnUpdateToolsHideitems(CCmdUI *pCmdUI)
  5101. {
  5102. pCmdUI->Enable(!GetMainWnd()->IsShellSessionActive());
  5103. pCmdUI->SetCheck(m_bHideItems ? TRUE : FALSE);
  5104. }
  5105. //-----------------------------------------------------------------------------
  5106. // Purpose: Hides and shows entity names in the 2D views.
  5107. //-----------------------------------------------------------------------------
  5108. void CMapDoc::OnToolsHideEntityNames(void)
  5109. {
  5110. bool bShowEntityNames = !CMapEntity::GetShowEntityNames();
  5111. CMapEntity::ShowEntityNames(bShowEntityNames);
  5112. UpdateAllViews( MAPVIEW_UPDATE_ONLY_2D );
  5113. }
  5114. //-----------------------------------------------------------------------------
  5115. // Purpose: Manages the state of the Tools | Hide Entity Names menu item.
  5116. //-----------------------------------------------------------------------------
  5117. void CMapDoc::OnUpdateToolsHideEntityNames(CCmdUI *pCmdUI)
  5118. {
  5119. pCmdUI->Enable(!GetMainWnd()->IsShellSessionActive());
  5120. pCmdUI->SetCheck(CMapEntity::GetShowEntityNames() ? FALSE : TRUE);
  5121. }
  5122. //-----------------------------------------------------------------------------
  5123. // Purpose: Hides and shows entity names in the 2D views.
  5124. //-----------------------------------------------------------------------------
  5125. void CMapDoc::OnViewHideUnconnectedEntities(void)
  5126. {
  5127. bool bHideUnconnectedEntities = !CMapEntity::GetShowUnconnectedEntities();
  5128. CMapEntity::ShowUnconnectedEntities(bHideUnconnectedEntities);
  5129. UpdateAllViews( MAPVIEW_UPDATE_ONLY_LOGICAL );
  5130. }
  5131. //-----------------------------------------------------------------------------
  5132. // Purpose: Manages the state of the Tools | Hide Entity Names menu item.
  5133. //-----------------------------------------------------------------------------
  5134. void CMapDoc::OnUpdateViewHideUnconnectedEntities(CCmdUI *pCmdUI)
  5135. {
  5136. pCmdUI->Enable(!GetMainWnd()->IsShellSessionActive());
  5137. pCmdUI->SetCheck(CMapEntity::GetShowUnconnectedEntities() ? FALSE : TRUE);
  5138. }
  5139. //-----------------------------------------------------------------------------
  5140. // Purpose:
  5141. // Input : *pView -
  5142. //-----------------------------------------------------------------------------
  5143. void CMapDoc::SetMRU(CMapView2D *pView)
  5144. {
  5145. RemoveMRU(pView);
  5146. MRU2DViews.AddToHead(pView);
  5147. }
  5148. //-----------------------------------------------------------------------------
  5149. // Purpose:
  5150. // Input : *pView -
  5151. //-----------------------------------------------------------------------------
  5152. void CMapDoc::RemoveMRU(CMapView2D *pView)
  5153. {
  5154. MRU2DViews.FindAndRemove(pView);
  5155. }
  5156. //-----------------------------------------------------------------------------
  5157. // Purpose: Manages the state of all Edit menu items and toolbar buttons.
  5158. //-----------------------------------------------------------------------------
  5159. void CMapDoc::OnUpdateEditFunction(CCmdUI *pCmdUI)
  5160. {
  5161. pCmdUI->Enable( ( m_pToolManager->GetActiveToolID() != TOOL_FACEEDIT_MATERIAL ) &&
  5162. !GetMainWnd()->IsShellSessionActive() );
  5163. }
  5164. //-----------------------------------------------------------------------------
  5165. // Purpose: This is called for each doc when the texture application mode changes.
  5166. // Input : bApplicator - TRUE if entering texture applicator mode, FALSE if
  5167. // leaving texture applicator mode.
  5168. //-----------------------------------------------------------------------------
  5169. void CMapDoc::UpdateForApplicator(BOOL bApplicator)
  5170. {
  5171. if (bApplicator)
  5172. {
  5173. //
  5174. // Build a list of all selected solids.
  5175. //
  5176. CMapObjectList Solids;
  5177. const CMapObjectList *pSelList = m_pSelection->GetList();
  5178. for (int i = 0; i < pSelList->Count(); i++)
  5179. {
  5180. CMapClass *pObject = pSelList->Element(i);
  5181. CMapSolid *pSolid = dynamic_cast<CMapSolid*>(pObject);
  5182. if (pSolid != NULL)
  5183. {
  5184. Solids.AddToTail(pSolid);
  5185. }
  5186. pObject->EnumChildren((ENUMMAPCHILDRENPROC)AddLeavesToListCallback, (DWORD)&Solids, MAPCLASS_TYPE(CMapSolid));
  5187. }
  5188. //
  5189. // Clear the object selection.
  5190. //
  5191. SelectObject(NULL, scClear);
  5192. //
  5193. // Select all faces of all solids that were selected originally. Disable updates
  5194. // in the face properties dialog beforehand or this could take a LONG time.
  5195. //
  5196. HCURSOR hCursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
  5197. GetMainWnd()->m_pFaceEditSheet->EnableUpdate( false );
  5198. bool bFirst = true;
  5199. FOR_EACH_OBJ( Solids, pos )
  5200. {
  5201. CMapClass *pObject = Solids.Element(pos);
  5202. CMapSolid *pSolid = dynamic_cast<CMapSolid*>(pObject);
  5203. Assert(pSolid != NULL);
  5204. if (pSolid != NULL)
  5205. {
  5206. SelectFace(pSolid, -1, scSelect | (bFirst ? scClear : 0));
  5207. bFirst = false;
  5208. }
  5209. }
  5210. GetMainWnd()->m_pFaceEditSheet->EnableUpdate( true );
  5211. SetCursor(hCursorOld);
  5212. }
  5213. else
  5214. {
  5215. //
  5216. // Remove all faces from the dialog's list and update their selection state to be
  5217. // not selected, then update the display.
  5218. //
  5219. GetMainWnd()->m_pFaceEditSheet->ClickFace( NULL, -1, CFaceEditSheet::cfClear );
  5220. UpdateStatusbar();
  5221. }
  5222. }
  5223. //-----------------------------------------------------------------------------
  5224. // Purpose:
  5225. // Input : *pSolid -
  5226. // iFace -
  5227. // cmd -
  5228. //-----------------------------------------------------------------------------
  5229. void CMapDoc::SelectFace(CMapSolid *pSolid, int iFace, int cmd)
  5230. {
  5231. bool bFirst = true;
  5232. if(iFace == -1 && pSolid)
  5233. {
  5234. // Get draw solid/disp mask.
  5235. bool bDispSolidMask = CMapDoc::GetActiveMapDoc()->IsDispSolidDrawMask() && pSolid->HasDisp();
  5236. // select entire object
  5237. int nFaces = pSolid->GetFaceCount();
  5238. for(int i = 0; i < nFaces; i++)
  5239. {
  5240. if ( bDispSolidMask )
  5241. {
  5242. CMapFace *pFace = pSolid->GetFace( i );
  5243. if( pFace && pFace->HasDisp() )
  5244. {
  5245. SelectFace(pSolid, i, cmd);
  5246. if ( bFirst )
  5247. {
  5248. cmd &= ~scClear;
  5249. bFirst = false;
  5250. }
  5251. }
  5252. }
  5253. else
  5254. {
  5255. SelectFace(pSolid, i, cmd);
  5256. if ( bFirst )
  5257. {
  5258. cmd &= ~scClear;
  5259. bFirst = false;
  5260. }
  5261. }
  5262. }
  5263. return;
  5264. }
  5265. CFaceEditSheet *pSheet = GetMainWnd()->m_pFaceEditSheet;
  5266. UINT uFaceCmd = 0;
  5267. if(cmd & scClear)
  5268. {
  5269. uFaceCmd |= CFaceEditSheet::cfClear;
  5270. }
  5271. if(cmd & scToggle)
  5272. {
  5273. uFaceCmd |= CFaceEditSheet::cfToggle;
  5274. }
  5275. if(cmd & scSelect)
  5276. {
  5277. uFaceCmd |= CFaceEditSheet::cfSelect;
  5278. }
  5279. if(cmd & scUnselect)
  5280. {
  5281. uFaceCmd |= CFaceEditSheet::cfUnselect;
  5282. }
  5283. //
  5284. // Change the click mode to ModeSelect if the scNoLift flag is set.
  5285. //
  5286. int nClickMode;
  5287. if (cmd & scNoLift) // dvs: this is lame
  5288. {
  5289. nClickMode = CFaceEditSheet::ModeSelect;
  5290. }
  5291. else
  5292. {
  5293. nClickMode = -1;
  5294. }
  5295. //
  5296. // Check the current click mode and perform the texture application if appropriate.
  5297. //
  5298. BOOL bApply = FALSE;
  5299. if (!(cmd & scNoApply))
  5300. {
  5301. int iFaceMode = pSheet->GetClickMode();
  5302. bApply = ( ( iFaceMode == CFaceEditSheet::ModeApply ) || ( iFaceMode == CFaceEditSheet::ModeApplyAll ) );
  5303. if (bApply && pSolid)
  5304. {
  5305. GetHistory()->MarkUndoPosition(NULL, "Apply texture");
  5306. GetHistory()->Keep(pSolid);
  5307. }
  5308. }
  5309. pSheet->ClickFace( pSolid, iFace, uFaceCmd, nClickMode );
  5310. // update display?
  5311. if (bApply)
  5312. {
  5313. UpdateStatusbar();
  5314. }
  5315. }
  5316. //-----------------------------------------------------------------------------
  5317. // Purpose:
  5318. //-----------------------------------------------------------------------------
  5319. void CMapDoc::OnMapInformation(void)
  5320. {
  5321. CMapInfoDlg dlg(m_pWorld);
  5322. dlg.DoModal();
  5323. }
  5324. //-----------------------------------------------------------------------------
  5325. // Purpose: Forces a render of all the 3D views. Called from OnIdle to render
  5326. // the 3D views.
  5327. //-----------------------------------------------------------------------------
  5328. void CMapDoc::SetActiveView(CMapView *pViewActivate)
  5329. {
  5330. POSITION p = GetFirstViewPosition();
  5331. while (p)
  5332. {
  5333. CMapView *pView = dynamic_cast<CMapView*>(GetNextView(p));
  5334. if ( pView )
  5335. {
  5336. pView->ActivateView(pView == pViewActivate);
  5337. }
  5338. }
  5339. }
  5340. //-----------------------------------------------------------------------------
  5341. // releases video memory
  5342. //-----------------------------------------------------------------------------
  5343. void CMapDoc::ReleaseVideoMemory( )
  5344. {
  5345. POSITION p = GetFirstViewPosition();
  5346. while (p)
  5347. {
  5348. CMapView3D *pView = dynamic_cast<CMapView3D*>(GetNextView(p));
  5349. if (pView)
  5350. {
  5351. pView->ReleaseVideoMemory();
  5352. }
  5353. }
  5354. }
  5355. //-----------------------------------------------------------------------------
  5356. // Purpose:
  5357. // Input : vi -
  5358. //-----------------------------------------------------------------------------
  5359. void CMapDoc::SetView2dInfo(VIEW2DINFO& vi)
  5360. {
  5361. POSITION p = GetFirstViewPosition();
  5362. while(p)
  5363. {
  5364. CView *pView = GetNextView(p);
  5365. if(!pView->IsKindOf(RUNTIME_CLASS(CMapView2D)))
  5366. continue;
  5367. CMapView2D *pView2D = (CMapView2D*) pView;
  5368. // set zoom value
  5369. if(vi.wFlags & VI_ZOOM)
  5370. {
  5371. pView2D->SetZoom(vi.fZoom);
  5372. }
  5373. // center on point
  5374. if(vi.wFlags & VI_CENTER)
  5375. {
  5376. pView2D->CenterView(&vi.ptCenter);
  5377. }
  5378. pView2D->UpdateView( MAPVIEW_UPDATE_OBJECTS );
  5379. }
  5380. }
  5381. void CMapDoc::SetViewLogicalInfo(VIEW2DINFO& vi)
  5382. {
  5383. POSITION p = GetFirstViewPosition();
  5384. while(p)
  5385. {
  5386. CView *pView = GetNextView(p);
  5387. if(!pView->IsKindOf(RUNTIME_CLASS(CMapViewLogical)))
  5388. continue;
  5389. CMapViewLogical *pViewLogical = (CMapViewLogical*) pView;
  5390. // set zoom value
  5391. if(vi.wFlags & VI_ZOOM)
  5392. {
  5393. pViewLogical->SetZoom(vi.fZoom);
  5394. }
  5395. // center on point
  5396. if(vi.wFlags & VI_CENTER)
  5397. {
  5398. pViewLogical->CenterView(&vi.ptCenter);
  5399. }
  5400. pViewLogical->UpdateView( MAPVIEW_UPDATE_OBJECTS );
  5401. }
  5402. }
  5403. //-----------------------------------------------------------------------------
  5404. // Purpose:
  5405. // Input : &vec -
  5406. //-----------------------------------------------------------------------------
  5407. void CMapDoc::CenterViewsOn(const Vector &vec)
  5408. {
  5409. Center2DViewsOn(vec);
  5410. Center3DViewsOn(vec);
  5411. }
  5412. //-----------------------------------------------------------------------------
  5413. // Purpose:
  5414. //-----------------------------------------------------------------------------
  5415. void CMapDoc::Center2DViewsOn(const Vector &vec)
  5416. {
  5417. VIEW2DINFO vi;
  5418. vi.wFlags = VI_CENTER;
  5419. vi.ptCenter = vec;
  5420. SetView2dInfo(vi);
  5421. }
  5422. //-----------------------------------------------------------------------------
  5423. // Purpose: Centers the 3D views on the given point.
  5424. //-----------------------------------------------------------------------------
  5425. void CMapDoc::Center3DViewsOn( const Vector &vPos )
  5426. {
  5427. POSITION p = GetFirstViewPosition();
  5428. while(p)
  5429. {
  5430. CView *pView = GetNextView(p);
  5431. if(!pView->IsKindOf(RUNTIME_CLASS(CMapView3D)))
  5432. continue;
  5433. CMapView3D *pView3D = (CMapView3D*) pView;
  5434. //what's happening here?
  5435. Vector vForward;
  5436. pView3D->GetCamera()->GetViewForward( vForward );
  5437. pView3D->SetCamera( vPos - Vector( 0, 100, 0 ), vPos );
  5438. pView3D->UpdateView( MAPVIEW_UPDATE_OBJECTS );
  5439. }
  5440. }
  5441. //-----------------------------------------------------------------------------
  5442. // Purpose: Sets 3D views with the input position and angle vectors.
  5443. //-----------------------------------------------------------------------------
  5444. void CMapDoc::Set3DViewsPosAng( const Vector &vPos, const Vector &vAng )
  5445. {
  5446. POSITION p = GetFirstViewPosition();
  5447. while(p)
  5448. {
  5449. CView *pView = GetNextView(p);
  5450. if(!pView->IsKindOf(RUNTIME_CLASS(CMapView3D)))
  5451. continue;
  5452. CMapView3D *pView3D = (CMapView3D*) pView;
  5453. QAngle angles;
  5454. angles.x = vAng.x;
  5455. angles.y = vAng.y;
  5456. angles.z = vAng.z;
  5457. Vector forward;
  5458. AngleVectors( angles, &forward );
  5459. pView3D->SetCamera( vPos, forward + vPos );
  5460. pView3D->UpdateView( MAPVIEW_UPDATE_OBJECTS );
  5461. }
  5462. }
  5463. //-----------------------------------------------------------------------------
  5464. // Purpose:
  5465. //-----------------------------------------------------------------------------
  5466. void CMapDoc::CenterLogicalViewsOn(const Vector2D &vecLogical)
  5467. {
  5468. VIEW2DINFO vi;
  5469. vi.wFlags = VI_CENTER;
  5470. vi.ptCenter = Vector( vecLogical.x, vecLogical.y, 0.0f );
  5471. SetViewLogicalInfo(vi);
  5472. }
  5473. //-----------------------------------------------------------------------------
  5474. // Purpose: Centers the 2D views on selected objects.
  5475. //-----------------------------------------------------------------------------
  5476. void CMapDoc::OnViewCenterOnSelection(void)
  5477. {
  5478. Center2DViewsOnSelection();
  5479. CenterLogicalViewsOnSelection();
  5480. }
  5481. //-----------------------------------------------------------------------------
  5482. // Purpose: Centers the 3D views on selected objects.
  5483. //-----------------------------------------------------------------------------
  5484. void CMapDoc::OnViewCenter3DViewsOnSelection(void)
  5485. {
  5486. Center3DViewsOnSelection();
  5487. }
  5488. //-----------------------------------------------------------------------------
  5489. // Purpose: Hollows selected solids by carving them with a scaled version of
  5490. // themselves.
  5491. //-----------------------------------------------------------------------------
  5492. void CMapDoc::OnToolsHollow(void)
  5493. {
  5494. //
  5495. // Confirm the operation if there is more than one object selected.
  5496. //
  5497. if ( m_pSelection->GetCount() > 1)
  5498. {
  5499. if (AfxMessageBox("Do you want to turn each of the selected solids into a hollow room?", MB_YESNO) == IDNO)
  5500. {
  5501. return;
  5502. }
  5503. }
  5504. //
  5505. // Prompt for the wall thickness, which is remembered from one hollow to another.
  5506. //
  5507. static int iWallWidth = 32;
  5508. char szBuf[128];
  5509. itoa(iWallWidth, szBuf, 10);
  5510. CStrDlg dlg(CStrDlg::Spin, szBuf, "How thick do you want the walls? Use a negative number to hollow outward.", "Hammer");
  5511. dlg.SetRange(-1024, 1024, 4);
  5512. if (dlg.DoModal() == IDCANCEL)
  5513. {
  5514. return;
  5515. }
  5516. iWallWidth = atoi(dlg.m_string);
  5517. if (abs(iWallWidth) < 2)
  5518. {
  5519. AfxMessageBox("The width of the walls must be less than -1 or greater than 1.");
  5520. return;
  5521. }
  5522. const CMapObjectList *pSelList = m_pSelection->GetList();
  5523. GetHistory()->MarkUndoPosition(pSelList, "Hollow");
  5524. //
  5525. // Build a list of all solids in the selection.
  5526. //
  5527. CMapObjectList SelectedSolids;
  5528. for (int i = 0; i < pSelList->Count(); i++)
  5529. {
  5530. CMapClass *pObject = pSelList->Element(i);
  5531. CMapSolid *pSolid = dynamic_cast <CMapSolid *> (pObject);
  5532. if (pSolid != NULL)
  5533. {
  5534. SelectedSolids.AddToTail(pSolid);
  5535. }
  5536. EnumChildrenPos_t pos2;
  5537. CMapClass *pChild = pObject->GetFirstDescendent(pos2);
  5538. while (pChild != NULL)
  5539. {
  5540. pSolid = dynamic_cast <CMapSolid *> (pChild);
  5541. if (pSolid != NULL)
  5542. {
  5543. SelectedSolids.AddToTail(pSolid);
  5544. }
  5545. pChild = pObject->GetNextDescendent(pos2);
  5546. }
  5547. }
  5548. //
  5549. // Carve every solid in the selection with a scaled copy of itself. This accomplishes
  5550. // the goal of hollowing them.
  5551. //
  5552. CMapSolid ScaledCopy;
  5553. FOR_EACH_OBJ( SelectedSolids, pos )
  5554. {
  5555. CMapSolid *pSelectedSolid = (CMapSolid *)SelectedSolids.Element(pos);
  5556. CMapClass *pDestParent = pSelectedSolid->GetParent();
  5557. GetHistory()->Keep(pSelectedSolid);
  5558. ScaledCopy.CopyFrom(pSelectedSolid, false);
  5559. ScaledCopy.SetParent(NULL);
  5560. //
  5561. // Get bounds of the solid to be hollowed and calculate scaling required to
  5562. // reduce by iWallWidth.
  5563. //
  5564. BoundBox box;
  5565. Vector ptCenter;
  5566. Vector vecScale;
  5567. pSelectedSolid->GetRender2DBox(box.bmins, box.bmaxs);
  5568. for (int i = 0; i < 3; i++)
  5569. {
  5570. float fHalf = (box.bmaxs[i] - box.bmins[i]) / 2;
  5571. vecScale[i] = (fHalf - iWallWidth) / fHalf;
  5572. }
  5573. ScaledCopy.GetBoundsCenter(ptCenter);
  5574. ScaledCopy.TransScale(ptCenter, vecScale);
  5575. //
  5576. // Set up the operands for the subtraction operation.
  5577. //
  5578. CMapSolid *pSubtractWith;
  5579. CMapSolid *pSubtractFrom;
  5580. if (iWallWidth > 0)
  5581. {
  5582. pSubtractFrom = pSelectedSolid;
  5583. pSubtractWith = &ScaledCopy;
  5584. }
  5585. //
  5586. // Negative wall widths reverse the subtraction.
  5587. //
  5588. else
  5589. {
  5590. pSubtractFrom = &ScaledCopy;
  5591. pSubtractWith = pSelectedSolid;
  5592. }
  5593. //
  5594. // Perform the subtraction. If the two objects intersected...
  5595. //
  5596. CMapObjectList Outside;
  5597. if (pSubtractFrom->Subtract(NULL, &Outside, pSubtractWith))
  5598. {
  5599. //
  5600. // If there were pieces outside the 'subtract with' object...
  5601. //
  5602. if (Outside.Count() > 0)
  5603. {
  5604. CMapClass *pResult = NULL;
  5605. //
  5606. // If the subtraction resulted in more than one object, create a group
  5607. // to place the results in.
  5608. //
  5609. if (Outside.Count() > 1)
  5610. {
  5611. pResult = (CMapClass *)(new CMapGroup);
  5612. FOR_EACH_OBJ( Outside, pos2 )
  5613. {
  5614. CMapClass *pTemp = Outside.Element(pos2);
  5615. pResult->AddChild(pTemp);
  5616. }
  5617. }
  5618. //
  5619. // Otherwise, the results are the single object.
  5620. //
  5621. else if (Outside.Count() == 1)
  5622. {
  5623. pResult = Outside[0];
  5624. }
  5625. //
  5626. // Replace the current solid with the subtraction results.
  5627. //
  5628. DeleteObject(pSelectedSolid);
  5629. AddObjectToWorld(pResult, pDestParent);
  5630. GetHistory()->KeepNew(pResult);
  5631. }
  5632. }
  5633. }
  5634. // Objects in selection no longer exist.
  5635. m_pSelection->SelectObject( NULL, scClear );
  5636. SetModifiedFlag();
  5637. }
  5638. //-----------------------------------------------------------------------------
  5639. // Purpose:
  5640. //-----------------------------------------------------------------------------
  5641. void CMapDoc::OnEditPastespecial(void)
  5642. {
  5643. CPasteSpecialDlg dlg(GetMainWnd(), &GetHammerClipboard()->Bounds);
  5644. if (dlg.DoModal() == IDCANCEL)
  5645. {
  5646. return;
  5647. }
  5648. dlg.SaveToIni();
  5649. BeginWaitCursor();
  5650. GetHistory()->MarkUndoPosition( m_pSelection->GetList(), "Paste");
  5651. // first, clear selection so we can select all pasted objects
  5652. SelectObject(NULL, scClear|scSaveChanges );
  5653. //
  5654. // Build a paste translation.
  5655. //
  5656. Vector vecPasteOffset( COORD_NOTINIT, COORD_NOTINIT, COORD_NOTINIT );
  5657. if (!dlg.m_bCenterOriginal)
  5658. {
  5659. GetBestPastePoint(vecPasteOffset);
  5660. vecPasteOffset -= GetHammerClipboard()->vecOriginalCenter;
  5661. }
  5662. else
  5663. {
  5664. vecPasteOffset[0] = dlg.m_iOffsetX;
  5665. vecPasteOffset[1] = dlg.m_iOffsetY;
  5666. vecPasteOffset[2] = dlg.m_iOffsetZ;
  5667. }
  5668. //
  5669. // Build the paste rotation angles.
  5670. //
  5671. QAngle vecPasteAngles;
  5672. vecPasteAngles[0] = dlg.m_fRotateX;
  5673. vecPasteAngles[1] = dlg.m_fRotateY;
  5674. vecPasteAngles[2] = dlg.m_fRotateZ;
  5675. CMapWorld *pWorld = GetActiveWorld();
  5676. CMapClass *pParent = NULL;
  5677. CMapGroup *pGroup = NULL;
  5678. if (dlg.m_bGroup)
  5679. {
  5680. pGroup = new CMapGroup;
  5681. pParent = (CMapClass *)pGroup;
  5682. AddObjectToWorld(pGroup, pWorld);
  5683. }
  5684. Options.SetLockingTextures(TRUE);
  5685. bool bMakeNamesUnique = (dlg.m_bMakeEntityNamesUnique == TRUE);
  5686. const char *pszPrefix = (dlg.m_bAddPrefix == TRUE) ? dlg.m_strPrefix : "";
  5687. for (int i = 0; i < dlg.m_iCopies; i++)
  5688. {
  5689. //
  5690. // Paste the objects with the current offset and rotation.
  5691. //
  5692. Paste(GetHammerClipboard()->Objects, GetHammerClipboard()->pSourceWorld, pWorld, vecPasteOffset, vecPasteAngles, pParent, bMakeNamesUnique, pszPrefix );
  5693. //
  5694. // Increment the paste offset.
  5695. //
  5696. vecPasteOffset[0] += dlg.m_iOffsetX;
  5697. vecPasteOffset[1] += dlg.m_iOffsetY;
  5698. vecPasteOffset[2] += dlg.m_iOffsetZ;
  5699. //
  5700. // Increment the paste angles.
  5701. //
  5702. vecPasteAngles[0] += dlg.m_fRotateX;
  5703. vecPasteAngles[1] += dlg.m_fRotateY;
  5704. vecPasteAngles[2] += dlg.m_fRotateZ;
  5705. }
  5706. //
  5707. // If we pasted into a group, keep the group now.
  5708. //
  5709. if (pGroup != NULL)
  5710. {
  5711. GetHistory()->KeepNew(pGroup);
  5712. SelectObject(pGroup, scSelect);
  5713. }
  5714. m_pToolManager->SetTool(TOOL_POINTER);
  5715. SetModifiedFlag();
  5716. EndWaitCursor();
  5717. }
  5718. //-----------------------------------------------------------------------------
  5719. // Purpose: Manages the state of the Edit | Paste Special menu item.
  5720. //-----------------------------------------------------------------------------
  5721. void CMapDoc::OnUpdateEditPastespecial(CCmdUI *pCmdUI)
  5722. {
  5723. pCmdUI->Enable((GetHammerClipboard()->Objects.Count() != 0) && !GetMainWnd()->IsShellSessionActive());
  5724. }
  5725. //-----------------------------------------------------------------------------
  5726. // Purpose: Does the undo or redo and restores the selection to the state at
  5727. // which it was marked in the Undo system.
  5728. // Input : nID - ID_EDIT_UNDO or ID_EDIT_REDO.
  5729. // Output : Always returns TRUE.
  5730. //-----------------------------------------------------------------------------
  5731. BOOL CMapDoc::OnUndoRedo(UINT nID)
  5732. {
  5733. //
  5734. // Morph operations are not undo-friendly because they use a non-CMapClass
  5735. // derived object (SSolid) to store intermediate object state.
  5736. //
  5737. if (m_pToolManager->GetActiveToolID() == TOOL_MORPH)
  5738. {
  5739. AfxMessageBox("You must exit morph mode to undo changes you've made.");
  5740. return(TRUE);
  5741. }
  5742. // Do the undo/redo.
  5743. CMapObjectList NewSelection;
  5744. if (nID == ID_EDIT_UNDO)
  5745. {
  5746. m_pUndo->Undo(&NewSelection);
  5747. }
  5748. else
  5749. {
  5750. m_pRedo->Undo(&NewSelection);
  5751. }
  5752. // Change the selection to the objects that the undo system says
  5753. // should be selected now. Don't save changes and create new undo entrys
  5754. SelectObjectList( &NewSelection, scClear|scSelect );
  5755. m_pSelection->RemoveDead();
  5756. CMapClass::UpdateAllDependencies(NULL);
  5757. UpdateAllViews( MAPVIEW_UPDATE_OBJECTS );
  5758. return(TRUE);
  5759. }
  5760. //-----------------------------------------------------------------------------
  5761. // Purpose: Manages the state of the Undo/Redo menu item.
  5762. //-----------------------------------------------------------------------------
  5763. void CMapDoc::OnUpdateUndoRedo(CCmdUI *pCmdUI)
  5764. {
  5765. CHistory *pHistory = (pCmdUI->m_nID == ID_EDIT_UNDO) ? m_pUndo : m_pRedo;
  5766. char *pszAction = (pCmdUI->m_nID == ID_EDIT_UNDO) ? "Undo" : "Redo";
  5767. char *pszHotkey = (pCmdUI->m_nID == ID_EDIT_UNDO) ? "Ctrl+Z" : "Ctrl+Y";
  5768. if (pHistory->IsUndoable())
  5769. {
  5770. pCmdUI->Enable(!GetMainWnd()->IsShellSessionActive());
  5771. CString str;
  5772. str.Format("%s %s\t%s", pszAction, pHistory->GetCurTrackName(), pszHotkey);
  5773. pCmdUI->SetText(str);
  5774. }
  5775. else
  5776. {
  5777. CString str;
  5778. str.Format("Can't %s\t%s", pszAction, pszHotkey);
  5779. pCmdUI->SetText(str);
  5780. pCmdUI->Enable(FALSE);
  5781. }
  5782. }
  5783. //-----------------------------------------------------------------------------
  5784. // Purpose:
  5785. // Input : pObject -
  5786. // pWorld -
  5787. //-----------------------------------------------------------------------------
  5788. bool CMapDoc::ExpandTargetNameKeywords(char *szNewTargetName, const char *szOldTargetName, CMapWorld *pWorld)
  5789. {
  5790. const char *pszKeyword = strstr(szOldTargetName, "&i");
  5791. if (pszKeyword != NULL)
  5792. {
  5793. char szPrefix[100];
  5794. char szSuffix[100];
  5795. strncpy(szPrefix, szOldTargetName, pszKeyword - szOldTargetName);
  5796. szPrefix[pszKeyword - szOldTargetName] = '\0';
  5797. strcpy(szSuffix, pszKeyword + 2);
  5798. int nHighestIndex = 0;
  5799. const CMapEntityList *pEntityList = pWorld->EntityList_GetList();
  5800. FOR_EACH_OBJ( *pEntityList, pos )
  5801. {
  5802. CMapEntity *pEntity = pEntityList->Element( pos );
  5803. const char *pszTargetName = pEntity->GetKeyValue("targetname");
  5804. //
  5805. // If this entity has a targetname, check to see if it is of the
  5806. // form <prefix><number><suffix>. If so, it must be counted as
  5807. // we search for the highest instance number.
  5808. //
  5809. if (pszTargetName != NULL)
  5810. {
  5811. char szTemp[MAX_PATH];
  5812. strcpy(szTemp, pszTargetName);
  5813. int nPrefixLen = strlen(szPrefix);
  5814. int nSuffixLen = strlen(szSuffix);
  5815. int nFullLen = strlen(szTemp);
  5816. //
  5817. // It must be longer than the prefix and the suffix combined to be
  5818. // of the form <prefix><number><suffix>.
  5819. //
  5820. if (nFullLen > nPrefixLen + nSuffixLen)
  5821. {
  5822. char *pszTempSuffix = szTemp + nFullLen - nSuffixLen;
  5823. //
  5824. // If the prefix and the suffix match ours, extract the instance number
  5825. // from between them and check it against our highest instance number.
  5826. //
  5827. if ((strnicmp(szTemp, szPrefix, nPrefixLen) == 0) && (stricmp(pszTempSuffix, szSuffix) == 0))
  5828. {
  5829. *pszTempSuffix = '\0';
  5830. bool bAllDigits = true;
  5831. for (int i = 0; i < (int)strlen(&szTemp[nPrefixLen]); i++)
  5832. {
  5833. if (!V_isdigit(szTemp[nPrefixLen + i]))
  5834. {
  5835. bAllDigits = false;
  5836. break;
  5837. }
  5838. }
  5839. if (bAllDigits)
  5840. {
  5841. int nIndex = atoi(&szTemp[nPrefixLen]);
  5842. if (nIndex > nHighestIndex)
  5843. {
  5844. nHighestIndex = nIndex;
  5845. }
  5846. }
  5847. }
  5848. }
  5849. }
  5850. }
  5851. sprintf(szNewTargetName, "%s%d%s", szPrefix, nHighestIndex + 1, szSuffix);
  5852. return(true);
  5853. }
  5854. return(false);
  5855. }
  5856. //-----------------------------------------------------------------------------
  5857. // Purpose: Expands keywords in pObject, if there are any. Returns whether
  5858. // keyword expansion was performed.
  5859. // Input : pObject -
  5860. // pWorld -
  5861. //-----------------------------------------------------------------------------
  5862. bool CMapDoc::DoExpandKeywords(CMapClass *pObject, CMapWorld *pWorld, char *szOldKeyword, char *szNewKeyword)
  5863. {
  5864. CEditGameClass *pEditGameClass = dynamic_cast <CEditGameClass *>(pObject);
  5865. if (pEditGameClass != NULL)
  5866. {
  5867. const char *pszOldTargetName = pEditGameClass->GetKeyValue("targetname");
  5868. if (pszOldTargetName != NULL)
  5869. {
  5870. char szNewTargetName[MAX_PATH];
  5871. if (ExpandTargetNameKeywords(szNewTargetName, pszOldTargetName, pWorld))
  5872. {
  5873. strcpy(szOldKeyword, pszOldTargetName);
  5874. strcpy(szNewKeyword, szNewTargetName);
  5875. pEditGameClass->SetKeyValue("targetname", szNewTargetName);
  5876. return(true);
  5877. }
  5878. }
  5879. }
  5880. return(false);
  5881. }
  5882. //-----------------------------------------------------------------------------
  5883. // Gets this object's name if it has one. Returns false if it has none.
  5884. //-----------------------------------------------------------------------------
  5885. static bool GetName( CMapClass *pObject, char *szName )
  5886. {
  5887. CEditGameClass *pEditGameClass = dynamic_cast <CEditGameClass *>( pObject );
  5888. if ( pEditGameClass == NULL )
  5889. return false;
  5890. const char *pszName = pEditGameClass->GetKeyValue( "targetname" );
  5891. if ( !pszName )
  5892. return false;
  5893. Q_strcpy( szName, pszName );
  5894. return true;
  5895. }
  5896. static const char *CopyName( const char * pszString )
  5897. {
  5898. int length = Q_strlen(pszString)+1;
  5899. char *pNewString = new char[length];
  5900. Q_memcpy( pNewString, pszString, length );
  5901. return pNewString;
  5902. }
  5903. static bool FindName( CUtlVector<const char*>*pList, const char * pszString )
  5904. {
  5905. for ( int i=0; i<pList->Count(); i++ )
  5906. {
  5907. if ( Q_stricmp( pszString, pList->Element(i)) == 0 )
  5908. return true;
  5909. }
  5910. return false;
  5911. }
  5912. //-----------------------------------------------------------------------------
  5913. // Renames all named entities in the tree pointed to by pRoot.
  5914. // pRoot - Points to a tree of objects.
  5915. // pWorld - If making the names unique, the world that they should be unique within.
  5916. // bMakeUnique - Whether to guarantee that the names are unique in the world.
  5917. // If necessary, numbers will be appended to make the names unique.
  5918. // szPrefix - A string to prepend to all named entities in the tree.
  5919. //-----------------------------------------------------------------------------
  5920. void CMapDoc::RenameEntities( CMapClass *pRoot, CMapWorld *pWorld, bool bMakeUnique, const char *szAddPrefix )
  5921. {
  5922. if ( !bMakeUnique && ( !szAddPrefix || ( szAddPrefix[0] == '\0' ) ) )
  5923. return;
  5924. CUtlVector<const char*> oldNames;
  5925. char szName[MAX_PATH];
  5926. pRoot->FindTargetNames( oldNames );
  5927. // find all names we have to replace
  5928. if ( GetName( pRoot, szName ) )
  5929. {
  5930. oldNames.AddToTail( CopyName(szName) );
  5931. }
  5932. // Expand keywords in this object's children as well.
  5933. EnumChildrenPos_t pos;
  5934. CMapClass *pChild = pRoot->GetFirstDescendent( pos );
  5935. while ( pChild != NULL )
  5936. {
  5937. pChild->FindTargetNames( oldNames );
  5938. if ( GetName(pChild, szName ) )
  5939. {
  5940. if ( !FindName( &oldNames, szName) )
  5941. {
  5942. oldNames.AddToTail( CopyName(szName) );
  5943. }
  5944. }
  5945. pChild = pRoot->GetNextDescendent( pos );
  5946. }
  5947. for ( int i=0; i<oldNames.Count(); i++ )
  5948. {
  5949. if ( pWorld->GenerateNewTargetname( oldNames[i], szName, sizeof( szName ), bMakeUnique, szAddPrefix, pRoot ) )
  5950. {
  5951. pRoot->ReplaceTargetname( oldNames[i], szName );
  5952. }
  5953. }
  5954. oldNames.PurgeAndDeleteElements();
  5955. }
  5956. //-----------------------------------------------------------------------------
  5957. // Purpose: Iterates the children of the given object and expands any keywords
  5958. // in the object's properties.
  5959. // Input : pObject -
  5960. // pWorld -
  5961. //-----------------------------------------------------------------------------
  5962. void CMapDoc::ExpandObjectKeywords(CMapClass *pObject, CMapWorld *pWorld)
  5963. {
  5964. char szOldName[MAX_PATH];
  5965. char szNewName[MAX_PATH];
  5966. if (DoExpandKeywords(pObject, pWorld, szOldName, szNewName))
  5967. {
  5968. pObject->ReplaceTargetname(szOldName, szNewName);
  5969. }
  5970. //
  5971. // Expand keywords in this object's children as well.
  5972. //
  5973. EnumChildrenPos_t pos;
  5974. CMapClass *pChild = pObject->GetFirstDescendent(pos);
  5975. while (pChild != NULL)
  5976. {
  5977. if (DoExpandKeywords(pChild, pWorld, szOldName, szNewName))
  5978. {
  5979. pObject->ReplaceTargetname(szOldName, szNewName);
  5980. }
  5981. pChild = pObject->GetNextDescendent(pos);
  5982. }
  5983. }
  5984. //-----------------------------------------------------------------------------
  5985. // Purpose: Selects the next object by depth in the 3D view.
  5986. //-----------------------------------------------------------------------------
  5987. void CMapDoc::OnEditSelnext(void)
  5988. {
  5989. m_pSelection->SetCurrentHit(hitNext);
  5990. }
  5991. //-----------------------------------------------------------------------------
  5992. // Purpose: Selects the previous object by depth in the 3D view.
  5993. //-----------------------------------------------------------------------------
  5994. void CMapDoc::OnEditSelprev(void)
  5995. {
  5996. m_pSelection->SetCurrentHit(hitPrev);
  5997. }
  5998. //-----------------------------------------------------------------------------
  5999. // Purpose: Selects the next object by depth
  6000. //-----------------------------------------------------------------------------
  6001. void CMapDoc::OnEditSelnextCascading(void)
  6002. {
  6003. m_pSelection->SetCurrentHit(hitNext, true );
  6004. }
  6005. //-----------------------------------------------------------------------------
  6006. // Purpose: Selects the previous object by depth
  6007. //-----------------------------------------------------------------------------
  6008. void CMapDoc::OnEditSelprevCascading(void)
  6009. {
  6010. m_pSelection->SetCurrentHit(hitPrev, true );
  6011. }
  6012. //-----------------------------------------------------------------------------
  6013. // Moves selected objects close to each other in logical space
  6014. //-----------------------------------------------------------------------------
  6015. void CMapDoc::OnLogicalMoveBlock(void)
  6016. {
  6017. Vector2D vecLogicalCenter;
  6018. if ( !m_pSelection->GetLogicalBoundsCenter( vecLogicalCenter ) )
  6019. return;
  6020. const CMapObjectList *pSelList = m_pSelection->GetList();
  6021. if ( pSelList->Count() <= 1 )
  6022. return;
  6023. GetHistory()->MarkUndoPosition( pSelList, "Move Block" );
  6024. GetHistory()->Keep( pSelList );
  6025. // Lay out in a squarish region that has the same center as the current one
  6026. int nCount = pSelList->Count();
  6027. int nDim = sqrt( (float)nCount );
  6028. if ( nDim * nDim < nCount )
  6029. {
  6030. ++nDim;
  6031. }
  6032. CMapViewLogical *pCurrentView = NULL;
  6033. if ( GetMainWnd()->GetActiveFrame() )
  6034. {
  6035. pCurrentView = dynamic_cast<CMapViewLogical*>( GetMainWnd()->GetActiveFrame()->GetActiveView() );
  6036. }
  6037. bool bCenterView;
  6038. Vector2D vecPositionCenter;
  6039. if ( pCurrentView )
  6040. {
  6041. Vector vecCenter( COORD_NOTINIT, COORD_NOTINIT, COORD_NOTINIT );
  6042. pCurrentView->GetCenterPoint( vecCenter );
  6043. vecPositionCenter = vecCenter.AsVector2D();
  6044. bCenterView = false;
  6045. }
  6046. else
  6047. {
  6048. vecPositionCenter = vecLogicalCenter;
  6049. bCenterView = true;
  6050. }
  6051. vecPositionCenter.x -= (nDim / 2.0f) * LOGICAL_SPACING;
  6052. vecPositionCenter.y -= (nDim / 2.0f) * LOGICAL_SPACING;
  6053. for ( int i = 0; i < pSelList->Count(); ++i )
  6054. {
  6055. CMapClass *pClass = pSelList->Element( i );
  6056. if ( !pClass->IsLogical() )
  6057. continue;
  6058. int x = i % nDim;
  6059. int y = ( i / nDim );
  6060. Vector2D newLogicalCenter;
  6061. newLogicalCenter.x = vecPositionCenter.x + x * LOGICAL_SPACING;
  6062. newLogicalCenter.y = vecPositionCenter.y + y * LOGICAL_SPACING;
  6063. pClass->SetLogicalPosition( newLogicalCenter );
  6064. }
  6065. UpdateAllViews( MAPVIEW_UPDATE_OBJECTS | MAPVIEW_UPDATE_SELECTION | MAPVIEW_UPDATE_ONLY_LOGICAL );
  6066. m_pSelection->SetBoundsDirty();
  6067. if ( bCenterView )
  6068. {
  6069. CenterLogicalViewsOnSelection();
  6070. }
  6071. }
  6072. //-----------------------------------------------------------------------------
  6073. // Select all entities connected to outputs of all entities in the selection list recursively
  6074. //-----------------------------------------------------------------------------
  6075. void CMapDoc::OnLogicalSelectAllCascading(void)
  6076. {
  6077. if ( m_pSelection->IsEmpty() )
  6078. return;
  6079. const CMapObjectList *pSelList = m_pSelection->GetList();
  6080. GetHistory()->MarkUndoPosition( pSelList, "Select All Cascading" );
  6081. CUtlRBTree< CMapClass*, unsigned short > list( 0, 0, DefLessFunc( CMapClass* ) );
  6082. for ( int i = 0; i < pSelList->Count(); ++i )
  6083. {
  6084. CMapClass *pMapClass = pSelList->Element(i);
  6085. list.InsertIfNotFound( pMapClass );
  6086. BuildCascadingSelectionList( pMapClass, list, true );
  6087. }
  6088. for ( unsigned short h = list.FirstInorder(); h != list.InvalidIndex(); h = list.NextInorder(h) )
  6089. {
  6090. SelectObject( list[h], scSelect );
  6091. }
  6092. }
  6093. //-----------------------------------------------------------------------------
  6094. // Add all entities connected to inputs of all entities in the selection list recursively
  6095. //-----------------------------------------------------------------------------
  6096. void CMapDoc::AddConnectedNodes( CMapClass *pObject, CUtlRBTree< CMapClass*, unsigned short >& visited )
  6097. {
  6098. // Make sure we havent visited this entity before
  6099. if ( visited.Find( pObject ) == visited.InvalidIndex() )
  6100. {
  6101. // Is this node actually a visible entity?
  6102. if ( pObject->IsLogical() && pObject->IsVisibleLogical() )
  6103. {
  6104. // Is this node NOT a group entity
  6105. if ( !pObject->IsGroup() )
  6106. {
  6107. // Mark this entity visited
  6108. visited.Insert( pObject );
  6109. // See if this class has any connections
  6110. CEditGameClass *pClass = dynamic_cast< CEditGameClass * >( pObject );
  6111. if ( pClass )
  6112. {
  6113. // Iterate through each of the upstream connections
  6114. int nCount = pClass->Upstream_GetCount();
  6115. for ( int i = 0; i < nCount; ++i )
  6116. {
  6117. CEntityConnection *pConn = pClass->Upstream_Get( i );
  6118. // Iterate through the source entities on this connection
  6119. FOR_EACH_OBJ( *pConn->GetSourceEntityList(), pos )
  6120. {
  6121. CMapEntity *pEntity = pConn->GetSourceEntityList()->Element( pos );
  6122. // Don't bother recursing back into this current node
  6123. if ( pEntity != pObject )
  6124. {
  6125. // Recurse to the adjacent source entity
  6126. AddConnectedNodes( pEntity, visited );
  6127. }
  6128. }
  6129. }
  6130. // Iterate through each of the downstream connections
  6131. nCount = pClass->Connections_GetCount();
  6132. for ( int i = 0; i < nCount; ++i )
  6133. {
  6134. CEntityConnection *pConn = pClass->Connections_Get( i );
  6135. // Iterate through the target entities on this connection
  6136. FOR_EACH_OBJ( *pConn->GetTargetEntityList(), pos )
  6137. {
  6138. CMapEntity *pEntity = pConn->GetTargetEntityList()->Element( pos );
  6139. // Don't bother recursing back into this current node
  6140. if ( pEntity != pObject )
  6141. {
  6142. // Recurse to the adjacent target entity
  6143. AddConnectedNodes( pEntity, visited );
  6144. }
  6145. }
  6146. }
  6147. }
  6148. }
  6149. // Recurse into any children and add them as well
  6150. const CMapObjectList *pChildren = pObject->GetChildren();
  6151. FOR_EACH_OBJ( *pChildren, pos )
  6152. {
  6153. AddConnectedNodes( pChildren->Element(pos), visited );
  6154. }
  6155. }
  6156. }
  6157. }
  6158. //-----------------------------------------------------------------------------
  6159. // Select all entities connected to outputs of all entities in the selection list recursively
  6160. //-----------------------------------------------------------------------------
  6161. void CMapDoc::OnLogicalSelectAllConnected(void)
  6162. {
  6163. const CMapObjectList *pSelList = m_pSelection->GetList();
  6164. int nSelected = pSelList->Count();
  6165. if ( nSelected )
  6166. {
  6167. GetHistory()->MarkUndoPosition( pSelList, "Select All Connected" );
  6168. CUtlRBTree< CMapClass*, unsigned short > visited( 0, 0, DefLessFunc( CMapClass* ) );
  6169. for ( int i = 0; i < nSelected; ++i )
  6170. {
  6171. CMapClass *pMapClass = pSelList->Element(i);
  6172. AddConnectedNodes( pMapClass, visited );
  6173. }
  6174. for ( unsigned short h = visited.FirstInorder(); h != visited.InvalidIndex(); h = visited.NextInorder(h) )
  6175. {
  6176. SelectObject( visited[h], scSelect );
  6177. }
  6178. }
  6179. }
  6180. //-----------------------------------------------------------------------------
  6181. // Purpose: Adds all selected or deselected objects to a new VisGroup and hides
  6182. // the group.
  6183. //-----------------------------------------------------------------------------
  6184. BOOL CMapDoc::OnViewHideObjects(UINT nID)
  6185. {
  6186. bool bSelected = (nID == ID_VIEW_HIDESELECTEDOBJECTS);
  6187. if ( m_pSelection->IsEmpty() )
  6188. {
  6189. return TRUE;
  6190. }
  6191. //
  6192. // Build a list of eligible selected objects.
  6193. //
  6194. CMapObjectList Objects;
  6195. GetChildrenToHide(m_pWorld, bSelected, Objects);
  6196. int nOriginalCount = Objects.Count();
  6197. for (int pos = Objects.Count()-1; pos>=0; pos --)
  6198. {
  6199. CMapClass *pObject = Objects.Element(pos);
  6200. if (!VisGroups_ObjectCanBelongToVisGroup(pObject))
  6201. {
  6202. Objects.Remove(pos);
  6203. }
  6204. }
  6205. int nFinalCount = Objects.Count();
  6206. //
  6207. // If no eligible selected objects were found, exit.
  6208. //
  6209. if (!nFinalCount)
  6210. {
  6211. CString str;
  6212. str.Format("There are no eligible %sselected objects. The only objects\n"
  6213. "that can be put in a Visible Group are objects that are not\n"
  6214. "part of an entity.", bSelected ? "" : "un");
  6215. AfxMessageBox(str);
  6216. return TRUE;
  6217. }
  6218. else if (nFinalCount < nOriginalCount)
  6219. {
  6220. AfxMessageBox("Some objects could not put in the new Visible Group because\n"
  6221. "they are part of an entity.");
  6222. }
  6223. ShowNewVisGroupsDialog(Objects, bSelected);
  6224. return TRUE;
  6225. }
  6226. //-----------------------------------------------------------------------------
  6227. // Purpose: Fills out a list with all the children of this object that:
  6228. //
  6229. // A) Are visible
  6230. // B) Match the bSelected criteria
  6231. // C) Whose children all match the bSelected criteria
  6232. // D) Have no hidden children
  6233. //
  6234. // Output : Returns true if all top-level children satisfied the above criteria, false if not.
  6235. //-----------------------------------------------------------------------------
  6236. bool CMapDoc::GetChildrenToHide(CMapClass *pObject, bool bSelected, CMapObjectList &List)
  6237. {
  6238. int nAddedCount = 0;
  6239. const CMapObjectList *pChildren = pObject->GetChildren();
  6240. FOR_EACH_OBJ( *pChildren, pos )
  6241. {
  6242. CMapClass *pChild = pChildren->Element(pos);
  6243. CMapGroup *pGroup = dynamic_cast<CMapGroup *>(pChild);
  6244. CMapSolid *pSolid = dynamic_cast<CMapSolid *>(pChild);
  6245. CMapEntity *pEntity = dynamic_cast<CMapEntity *>(pChild);
  6246. if (pGroup || pSolid || pEntity)
  6247. {
  6248. if (pChild->IsVisible())
  6249. {
  6250. pEntity = dynamic_cast<CMapEntity *>(pChild);
  6251. if (pGroup || (pEntity && pEntity->IsSolidClass()))
  6252. {
  6253. // This child is a group or a solid entity -- check all its children.
  6254. CMapObjectList ChildList;
  6255. if (GetChildrenToHide(pChild, bSelected, ChildList))
  6256. {
  6257. // All this child's children match the criteria, so add the child to the list.
  6258. List.AddToTail(pChild);
  6259. nAddedCount++;
  6260. }
  6261. else if (ChildList.Count())
  6262. {
  6263. // Some of this child's children satisfy the criteria, or have descendents that do.
  6264. // Add the children to the list.
  6265. List.AddVectorToTail(ChildList);
  6266. }
  6267. else
  6268. {
  6269. // None of this child's children satisfy the criteria, so skip this child.
  6270. }
  6271. }
  6272. else if (bSelected == pChild->IsSelected())
  6273. {
  6274. // Unselected point entity or solid, add it to the list.
  6275. List.AddToTail(pChild);
  6276. nAddedCount++;
  6277. }
  6278. }
  6279. }
  6280. else
  6281. {
  6282. // Don't add helpers, but count them anyway.
  6283. nAddedCount++;
  6284. }
  6285. }
  6286. return nAddedCount == pObject->GetChildCount();
  6287. }
  6288. //-----------------------------------------------------------------------------
  6289. // Purpose: Reflects the current handle mode of the selection tool.
  6290. //-----------------------------------------------------------------------------
  6291. void CMapDoc::OnUpdateViewShowHelpers(CCmdUI *pCmdUI)
  6292. {
  6293. // if (pCmdUI->m_nID == ID_VIEW_SELECTION_ONLY)
  6294. // {
  6295. // pCmdUI->SetCheck(m_pToolSelection->GetHandleMode() == HandleMode_SelectionOnly);
  6296. // }
  6297. // else if (pCmdUI->m_nID == ID_VIEW_HELPERS_ONLY)
  6298. // {
  6299. pCmdUI->SetCheck( Options.GetShowHelpers() );
  6300. // }
  6301. // else if (pCmdUI->m_nID == ID_VIEW_SELECTION_AND_HELPERS)
  6302. // {
  6303. // pCmdUI->SetCheck(m_pToolSelection->GetHandleMode() == HandleMode_Both);
  6304. // }
  6305. pCmdUI->Enable(!GetMainWnd()->IsShellSessionActive());
  6306. }
  6307. //-----------------------------------------------------------------------------
  6308. // Purpose: Reflects the current 2D model drawing
  6309. //-----------------------------------------------------------------------------
  6310. void CMapDoc::OnUpdateViewShowModelsIn2D(CCmdUI *pCmdUI)
  6311. {
  6312. pCmdUI->SetCheck( Options.view2d.bDrawModels?1:0 );
  6313. pCmdUI->Enable(!GetMainWnd()->IsShellSessionActive());
  6314. }
  6315. void CMapDoc::OnViewShowModelsIn2D(void)
  6316. {
  6317. Options.view2d.bDrawModels = !Options.view2d.bDrawModels;
  6318. UpdateVisibilityAll();
  6319. }
  6320. void CMapDoc::OnViewShowHelpers(void)
  6321. {
  6322. // FIXME: this only sets the handle mode for the active document's selection tool!
  6323. Options.SetShowHelpers(!Options.GetShowHelpers());
  6324. UpdateVisibilityAll();
  6325. UpdateAllViews( MAPVIEW_UPDATE_OBJECTS );
  6326. }
  6327. //-----------------------------------------------------------------------------
  6328. // Purpose: Manages the state of 3D model fade preview.
  6329. //-----------------------------------------------------------------------------
  6330. void CMapDoc::OnUpdateViewPreviewModelFade(CCmdUI *pCmdUI)
  6331. {
  6332. pCmdUI->SetCheck( Options.view3d.bPreviewModelFade ? 1 : 0 );
  6333. pCmdUI->Enable(!GetMainWnd()->IsShellSessionActive());
  6334. }
  6335. void CMapDoc::OnViewPreviewModelFade(void)
  6336. {
  6337. Options.view3d.bPreviewModelFade = !Options.view3d.bPreviewModelFade;
  6338. UpdateAllViews( MAPVIEW_UPDATE_ONLY_3D );
  6339. }
  6340. //-----------------------------------------------------------------------------
  6341. // Purpose: Manages the state of 3D model fade preview.
  6342. //-----------------------------------------------------------------------------
  6343. void CMapDoc::OnUpdateCollisionWireframe(CCmdUI *pCmdUI)
  6344. {
  6345. pCmdUI->SetCheck( Options.general.bShowCollisionModels ? 1 : 0 );
  6346. pCmdUI->Enable(!GetMainWnd()->IsShellSessionActive());
  6347. }
  6348. void CMapDoc::OnCollisionWireframe(void)
  6349. {
  6350. Options.general.bShowCollisionModels = !Options.general.bShowCollisionModels;
  6351. UpdateAllViews( MAPVIEW_UPDATE_TOOL );
  6352. }
  6353. //-----------------------------------------------------------------------------
  6354. // Purpose: Manages the state of 3D model fade preview.
  6355. //-----------------------------------------------------------------------------
  6356. void CMapDoc::OnUpdateShowDetailObjects(CCmdUI *pCmdUI)
  6357. {
  6358. pCmdUI->SetCheck( Options.general.bShowDetailObjects ? 1 : 0 );
  6359. pCmdUI->Enable(!GetMainWnd()->IsShellSessionActive());
  6360. }
  6361. void CMapDoc::OnShowDetailObjects(void)
  6362. {
  6363. Options.general.bShowDetailObjects = !Options.general.bShowDetailObjects;
  6364. UpdateAllViews( MAPVIEW_UPDATE_TOOL );
  6365. }
  6366. void CMapDoc::OnShowNoDrawBrushes(void)
  6367. {
  6368. Options.general.bShowNoDrawBrushes = !Options.general.bShowNoDrawBrushes;
  6369. UpdateAllViews( MAPVIEW_UPDATE_TOOL );
  6370. }
  6371. void CMapDoc::OnUpdateShowNoDrawBrushes(CCmdUI *pCmdUI)
  6372. {
  6373. pCmdUI->SetCheck( Options.general.bShowNoDrawBrushes ? 1 : 0 );
  6374. pCmdUI->Enable(!GetMainWnd()->IsShellSessionActive());
  6375. }
  6376. //-----------------------------------------------------------------------------
  6377. // Purpose: Manages the state of the View | Hide Unselected menu item and toolbar button.
  6378. //-----------------------------------------------------------------------------
  6379. void CMapDoc::OnUpdateViewHideUnselectedObjects(CCmdUI *pCmdUI)
  6380. {
  6381. pCmdUI->Enable(!GetMainWnd()->IsShellSessionActive());
  6382. }
  6383. //-----------------------------------------------------------------------------
  6384. // Purpose:
  6385. //-----------------------------------------------------------------------------
  6386. void CMapDoc::OnMapCheck(void)
  6387. {
  6388. CMapCheckDlg::CheckForProblems(GetMainWnd());
  6389. }
  6390. void CMapDoc::OnMapDiff(void)
  6391. {
  6392. CMapDiffDlg::MapDiff(GetMainWnd(), this);
  6393. }
  6394. //-----------------------------------------------------------------------------
  6395. // Purpose:
  6396. //-----------------------------------------------------------------------------
  6397. void CMapDoc::OnViewShowconnections(void)
  6398. {
  6399. bool bShow = CMapEntity::GetShowEntityConnections();
  6400. CMapEntity::ShowEntityConnections(!bShow);
  6401. UpdateAllViews( MAPVIEW_UPDATE_ONLY_2D );
  6402. }
  6403. //-----------------------------------------------------------------------------
  6404. // Purpose: Puts one of every point entity in the current FGD set in the current
  6405. // map on a 128 grid.
  6406. //-----------------------------------------------------------------------------
  6407. void CMapDoc::OnMapEntityGallery(void)
  6408. {
  6409. if (GetMainWnd()->MessageBox("This will place one of every possible point entity in the current map! Performing this operation in an empty map is recommended. Continue?", "Create Entity Gallery", MB_ICONEXCLAMATION | MB_YESNO) == IDYES)
  6410. {
  6411. int x = -1024;
  6412. int y = -1024;
  6413. CString str;
  6414. int nCount = pGD->GetClassCount();
  6415. for (int i = 0; i < nCount; i++)
  6416. {
  6417. GDclass *pc = pGD->GetClass(i);
  6418. if (!pc->IsBaseClass())
  6419. {
  6420. if (!pc->IsSolidClass())
  6421. {
  6422. if (!pc->IsClass("worldspawn"))
  6423. {
  6424. CreateEntity(pc->GetName(), x, y, 0);
  6425. x += 128;
  6426. if (x > 1024)
  6427. {
  6428. x = -1024;
  6429. y += 128;
  6430. }
  6431. }
  6432. }
  6433. }
  6434. }
  6435. }
  6436. }
  6437. //-----------------------------------------------------------------------------
  6438. // Purpose:
  6439. //-----------------------------------------------------------------------------
  6440. void CMapDoc::OnUpdateViewShowconnections(CCmdUI *pCmdUI)
  6441. {
  6442. pCmdUI->SetCheck(CMapEntity::GetShowEntityConnections());
  6443. }
  6444. //-----------------------------------------------------------------------------
  6445. // Purpose:
  6446. // Input : *pszFileName -
  6447. // nSize -
  6448. //-----------------------------------------------------------------------------
  6449. bool GetSaveAsFilename(const char *pszBaseDir, char *pszFileName, int nSize)
  6450. {
  6451. CString str;
  6452. CFileDialog dlg(FALSE, NULL, str, OFN_LONGNAMES | OFN_NOCHANGEDIR | OFN_HIDEREADONLY, "Valve Map Files (*.vmf)|*.vmf||");
  6453. dlg.m_ofn.lpstrInitialDir = pszBaseDir;
  6454. int nRet = dlg.DoModal();
  6455. if (nRet != IDCANCEL)
  6456. {
  6457. str = dlg.GetPathName();
  6458. if (str.Find('.') == -1)
  6459. {
  6460. str += ".vmf";
  6461. }
  6462. lstrcpyn(pszFileName, str, nSize);
  6463. return(true);
  6464. }
  6465. return(false);
  6466. }
  6467. //-----------------------------------------------------------------------------
  6468. // Purpose: Takes the current selection and saves it as a prefab. The user is
  6469. // prompted for a folder under the prefabs folder in which to place
  6470. // the prefab.
  6471. //-----------------------------------------------------------------------------
  6472. void CMapDoc::OnToolsCreateprefab(void)
  6473. {
  6474. if ( m_pSelection->IsEmpty() )
  6475. {
  6476. AfxMessageBox("This feature creates a prefab with the selected objects. You must select some objects before you can use it.", MB_ICONINFORMATION | MB_OK);
  6477. return;
  6478. }
  6479. //
  6480. // Get a file to save the prefab into. The first time through the default folder
  6481. // is the prefabs folder.
  6482. //
  6483. static char szBaseDir[MAX_PATH] = "";
  6484. if (szBaseDir[0] == '\0')
  6485. {
  6486. APP()->GetDirectory(DIR_PREFABS, szBaseDir);
  6487. }
  6488. char szFilename[MAX_PATH];
  6489. if (!GetSaveAsFilename(szBaseDir, szFilename, sizeof(szFilename)))
  6490. {
  6491. return;
  6492. }
  6493. //
  6494. // Save the default folder for next time.
  6495. //
  6496. strcpy(szBaseDir, szFilename);
  6497. char *pch = strrchr(szBaseDir, '\\');
  6498. if (pch != NULL)
  6499. {
  6500. *pch = '\0';
  6501. }
  6502. //
  6503. // Create a prefab world to contain the selected items. Add the selected
  6504. // items to the new world.
  6505. //
  6506. CMapWorld *pNewWorld = new CMapWorld( NULL );
  6507. pNewWorld->SetTemporary(TRUE);
  6508. const CMapObjectList *pSelList = m_pSelection->GetList();
  6509. for (int i = 0; i < pSelList->Count(); i++)
  6510. {
  6511. CMapClass *pObject = pSelList->Element(i);
  6512. CMapClass *pNew = pObject->Copy(false);
  6513. // HACK: prune the object from the tree without doing any notification
  6514. // this prevents CopyChildrenFrom from updating the current world's culling tree
  6515. pNew->SetParent(NULL);
  6516. pNew->CopyChildrenFrom(pObject, false);
  6517. pNewWorld->AddObjectToWorld(pNew);
  6518. }
  6519. pNewWorld->CalcBounds(TRUE);
  6520. //
  6521. // Create a prefab object and attach the world to it.
  6522. //
  6523. CPrefabVMF *pPrefab = new CPrefabVMF;
  6524. pPrefab->SetWorld(pNewWorld);
  6525. pPrefab->SetFilename(szFilename);
  6526. //
  6527. // Save the world to the chosen filename.
  6528. //
  6529. CChunkFile File;
  6530. ChunkFileResult_t eResult = File.Open(szFilename, ChunkFile_Write);
  6531. if (eResult == ChunkFile_Ok)
  6532. {
  6533. CSaveInfo SaveInfo;
  6534. SaveInfo.SetVisiblesOnly(false);
  6535. //
  6536. // Write the map file version.
  6537. //
  6538. if (eResult == ChunkFile_Ok)
  6539. {
  6540. // HACK: make sure we save it as a prefab, not as a normal map
  6541. bool bPrefab = m_bPrefab;
  6542. m_bPrefab = true;
  6543. eResult = SaveVersionInfoVMF(&File);
  6544. m_bPrefab = bPrefab;
  6545. }
  6546. //
  6547. // Save the world.
  6548. //
  6549. if (eResult == ChunkFile_Ok)
  6550. {
  6551. eResult = pNewWorld->SaveVMF(&File, &SaveInfo, false);
  6552. }
  6553. }
  6554. //
  6555. // Try to locate the prefab library that corresponds to the folder where
  6556. // we saved the prefab. If it doesn't exist, try refreshing the prefab library
  6557. // list. Maybe the user just created the folder during this save.
  6558. //
  6559. CPrefabLibrary *pLibrary = CPrefabLibrary::FindOpenLibrary(szBaseDir);
  6560. if (pLibrary == NULL)
  6561. {
  6562. delete pPrefab;
  6563. //
  6564. // This will take care of finding the prefab and adding it to the list.
  6565. //
  6566. CPrefabLibrary::LoadAllLibraries();
  6567. }
  6568. else
  6569. {
  6570. pLibrary->Add(pPrefab);
  6571. }
  6572. //
  6573. // Update the object bar so the new prefab shows up.
  6574. //
  6575. GetMainWnd()->m_ObjectBar.UpdateListForTool(m_pToolManager->GetActiveToolID());
  6576. }
  6577. //-----------------------------------------------------------------------------
  6578. // Purpose:
  6579. //-----------------------------------------------------------------------------
  6580. void CMapDoc::OnInsertprefabOriginal(void)
  6581. {
  6582. int iCurTool = m_pToolManager->GetActiveToolID();
  6583. if ((iCurTool != TOOL_POINTER) && (iCurTool != TOOL_BLOCK) && (iCurTool != TOOL_ENTITY))
  6584. {
  6585. return;
  6586. }
  6587. BoundBox box;
  6588. if (GetMainWnd()->m_ObjectBar.GetPrefabBounds(&box) == FALSE)
  6589. {
  6590. return; // not a prefab listing
  6591. }
  6592. Vector pt( COORD_NOTINIT, COORD_NOTINIT, COORD_NOTINIT );
  6593. if (iCurTool != TOOL_ENTITY)
  6594. {
  6595. GetBestVisiblePoint(pt);
  6596. }
  6597. else
  6598. {
  6599. CToolEntity *pTool = dynamic_cast<CToolEntity*>(m_pToolManager->GetActiveTool() );
  6600. pTool->GetPos(pt);
  6601. }
  6602. Vector ptCenter;
  6603. box.GetBoundsCenter(ptCenter);
  6604. for(int i = 0; i < 3; i++)
  6605. {
  6606. box.bmins[i] += pt[i] - ptCenter[i];
  6607. box.bmaxs[i] += pt[i] - ptCenter[i];
  6608. }
  6609. // create object
  6610. box.SnapToGrid(m_nGridSpacing); // snap to grid first
  6611. CMapClass *pObject = GetMainWnd()->m_ObjectBar.CreateInBox(&box);
  6612. if (pObject == NULL)
  6613. {
  6614. return;
  6615. }
  6616. ExpandObjectKeywords(pObject, m_pWorld);
  6617. GetHistory()->MarkUndoPosition(NULL, "Insert Prefab");
  6618. AddObjectToWorld(pObject);
  6619. GetHistory()->KeepNew(pObject);
  6620. SelectObject(pObject, scClear|scSelect|scSaveChanges );
  6621. // set modified
  6622. SetModifiedFlag();
  6623. }
  6624. //-----------------------------------------------------------------------------
  6625. // Purpose: Find a substring within a string:
  6626. // Input : *pszSub -
  6627. // *pszMain -
  6628. // Output : static char *
  6629. //-----------------------------------------------------------------------------
  6630. static char * FindInString(char *pszSub, char *pszMain)
  6631. {
  6632. char *p = pszMain;
  6633. int nSub = strlen(pszSub);
  6634. char ch1 = toupper(pszSub[0]);
  6635. while(p[0])
  6636. {
  6637. if(ch1 == toupper(p[0]))
  6638. {
  6639. if(!strnicmp(pszSub, p, nSub))
  6640. return p;
  6641. }
  6642. ++p;
  6643. }
  6644. return NULL;
  6645. }
  6646. //-----------------------------------------------------------------------------
  6647. // Purpose:
  6648. // Input : *pSolid -
  6649. // *pInfo -
  6650. // Output : static BOOL
  6651. //-----------------------------------------------------------------------------
  6652. static BOOL ReplaceTexFunc(CMapSolid *pSolid, ReplaceTexInfo_t *pInfo)
  6653. {
  6654. // make sure it's visible
  6655. if (!pInfo->bHidden && !pSolid->IsVisible())
  6656. {
  6657. return TRUE;
  6658. }
  6659. int nFaces = pSolid->GetFaceCount();
  6660. char *p;
  6661. BOOL bSaved = FALSE;
  6662. BOOL bMarkOnly = pInfo->bMarkOnly;
  6663. for(int i = 0; i < nFaces; i++)
  6664. {
  6665. CMapFace *pFace = pSolid->GetFace(i);
  6666. char *pszFaceTex = pFace->texture.texture;
  6667. BOOL bDoMarkSolid = FALSE;
  6668. switch(pInfo->iAction)
  6669. {
  6670. case 0: // replace exact matches only:
  6671. {
  6672. if(!strcmpi(pszFaceTex, pInfo->szFind))
  6673. {
  6674. if(bMarkOnly)
  6675. {
  6676. bDoMarkSolid = TRUE;
  6677. break;
  6678. }
  6679. if(!bSaved)
  6680. {
  6681. bSaved = TRUE;
  6682. GetHistory()->Keep(pSolid);
  6683. }
  6684. pFace->SetTexture(pInfo->szReplace, pInfo->m_bRescaleTextureCoordinates);
  6685. ++pInfo->nReplaced;
  6686. }
  6687. break;
  6688. }
  6689. case 1: // find partials, replace entire string:
  6690. {
  6691. p = FindInString(pInfo->szFind, pszFaceTex);
  6692. if(p)
  6693. {
  6694. if(bMarkOnly)
  6695. {
  6696. bDoMarkSolid = TRUE;
  6697. break;
  6698. }
  6699. if(!bSaved)
  6700. {
  6701. bSaved = TRUE;
  6702. GetHistory()->Keep(pSolid);
  6703. }
  6704. pFace->SetTexture(pInfo->szReplace, pInfo->m_bRescaleTextureCoordinates);
  6705. ++pInfo->nReplaced;
  6706. }
  6707. break;
  6708. }
  6709. case 2: // find partials, substitute replacement:
  6710. {
  6711. p = FindInString(pInfo->szFind, pszFaceTex);
  6712. if(p)
  6713. {
  6714. if(bMarkOnly)
  6715. {
  6716. bDoMarkSolid = TRUE;
  6717. break;
  6718. }
  6719. if(!bSaved)
  6720. {
  6721. bSaved = TRUE;
  6722. GetHistory()->Keep(pSolid);
  6723. }
  6724. // create a new string
  6725. char szNewTex[128];
  6726. strcpy(szNewTex, pszFaceTex);
  6727. strcpy(szNewTex + int(p - pszFaceTex), pInfo->szReplace);
  6728. strcat(szNewTex, pszFaceTex + int(p - pszFaceTex) + pInfo->iFindLen);
  6729. pFace->SetTexture(szNewTex, pInfo->m_bRescaleTextureCoordinates);
  6730. ++pInfo->nReplaced;
  6731. }
  6732. break;
  6733. }
  6734. }
  6735. if (bDoMarkSolid)
  6736. {
  6737. if( pInfo->pDoc->GetTools()->GetActiveToolID() == TOOL_FACEEDIT_MATERIAL )
  6738. {
  6739. pInfo->pDoc->SelectFace(pSolid, i, scSelect);
  6740. pInfo->nReplaced++;
  6741. }
  6742. else
  6743. {
  6744. if (!pSolid->IsSelected())
  6745. {
  6746. pInfo->pDoc->SelectObject(pSolid, scSelect);
  6747. pInfo->nReplaced++;
  6748. }
  6749. }
  6750. }
  6751. }
  6752. return(TRUE);
  6753. }
  6754. //-----------------------------------------------------------------------------
  6755. // Purpose:
  6756. // Input : pszFind -
  6757. // pszReplace -
  6758. // bEverything -
  6759. // iAction -
  6760. // bHidden -
  6761. //-----------------------------------------------------------------------------
  6762. void CMapDoc::ReplaceTextures(LPCTSTR pszFind, LPCTSTR pszReplace, BOOL bEverything, int iAction, BOOL bHidden, bool bRescaleTextureCoordinates)
  6763. {
  6764. CFaceEditSheet *pSheet = GetMainWnd()->m_pFaceEditSheet;
  6765. HCURSOR hCursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
  6766. pSheet->EnableUpdate(false);
  6767. // set up info struct to pass to callback
  6768. ReplaceTexInfo_t info;
  6769. strcpy(info.szFind, pszFind);
  6770. strcpy(info.szReplace, pszReplace);
  6771. info.pDoc = this;
  6772. info.bHidden = bHidden;
  6773. if (iAction & 0x100)
  6774. {
  6775. iAction &= ~0x100;
  6776. info.bMarkOnly = TRUE;
  6777. info.bHidden = FALSE; // do not mark hidden objects
  6778. }
  6779. else
  6780. {
  6781. info.bMarkOnly = FALSE;
  6782. }
  6783. info.iAction = iAction;
  6784. info.nReplaced = 0;
  6785. info.iFindLen = strlen(pszFind);
  6786. info.pWorld = m_pWorld;
  6787. info.m_bRescaleTextureCoordinates = bRescaleTextureCoordinates;
  6788. if (bEverything)
  6789. {
  6790. // Mark/Replace textures in entire map.
  6791. if (info.bMarkOnly)
  6792. {
  6793. // About to mark solids, set solids mode and clear the selection.
  6794. m_pSelection->SetMode(selectSolids);
  6795. SelectObject(NULL, scClear);
  6796. }
  6797. m_pWorld->EnumChildren((ENUMMAPCHILDRENPROC)ReplaceTexFunc, (DWORD)&info, MAPCLASS_TYPE(CMapSolid));
  6798. }
  6799. else
  6800. {
  6801. // Mark/Replace textures in the selection only.
  6802. // Copy the selection into another list since we might be changing the selection
  6803. // during this process.
  6804. CMapObjectList tempSelection;
  6805. tempSelection.AddVectorToTail( *m_pSelection->GetList() );
  6806. if (info.bMarkOnly)
  6807. {
  6808. // About to mark solids, set solids mode and clear the selection.
  6809. m_pSelection->SetMode(selectSolids);
  6810. SelectObject(NULL, scClear);
  6811. }
  6812. FOR_EACH_OBJ( tempSelection, pos )
  6813. {
  6814. CMapClass *pobj = tempSelection.Element(pos);
  6815. //
  6816. // Call the texture replacement callback for this object (if it is a solid) and
  6817. // all of its children (no matter what).
  6818. //
  6819. if (pobj->IsMapClass(MAPCLASS_TYPE(CMapSolid)))
  6820. {
  6821. ReplaceTexFunc((CMapSolid *)pobj, &info);
  6822. }
  6823. pobj->EnumChildren((ENUMMAPCHILDRENPROC)ReplaceTexFunc, (DWORD)&info, MAPCLASS_TYPE(CMapSolid));
  6824. }
  6825. }
  6826. CString str;
  6827. if (!info.bMarkOnly)
  6828. {
  6829. str.Format("%d textures replaced.", info.nReplaced);
  6830. if (info.nReplaced > 0)
  6831. {
  6832. SetModifiedFlag();
  6833. }
  6834. }
  6835. else
  6836. {
  6837. str.Format("%d %s marked.", info.nReplaced, (m_pToolManager->GetActiveToolID() == TOOL_FACEEDIT_MATERIAL) ? "faces" : "solids");
  6838. }
  6839. pSheet->EnableUpdate(true);
  6840. SetCursor(hCursorOld);
  6841. AfxMessageBox(str);
  6842. }
  6843. //-----------------------------------------------------------------------------
  6844. // Purpose:
  6845. // Input : pObject -
  6846. // pInfo - Pointer to the structure with info about how to do the find/replace.
  6847. // Output :
  6848. //-----------------------------------------------------------------------------
  6849. static BOOL BatchReplaceTextureCallback( CMapClass *pObject, BatchReplaceTextures_t *pInfo )
  6850. {
  6851. CMapSolid *solid;
  6852. int numFaces, i;
  6853. CMapFace *face;
  6854. char szCurrentTexture[MAX_PATH];
  6855. solid = ( CMapSolid * )pObject;
  6856. numFaces = solid->GetFaceCount();
  6857. for( i = 0; i < numFaces; i++ )
  6858. {
  6859. face = solid->GetFace( i );
  6860. face->GetTextureName( szCurrentTexture );
  6861. if( stricmp( szCurrentTexture, pInfo->szFindTexName ) == 0 )
  6862. {
  6863. face->SetTexture( pInfo->szReplaceTexName );
  6864. }
  6865. }
  6866. return TRUE; // return TRUE to continue enumerating, FALSE to stop.
  6867. }
  6868. //-----------------------------------------------------------------------------
  6869. // Purpose:
  6870. // Input : *fp -
  6871. //-----------------------------------------------------------------------------
  6872. void CMapDoc::BatchReplaceTextures( FileHandle_t fp )
  6873. {
  6874. char *scan, *keyStart, *valStart;
  6875. char buf[MAX_REPLACE_LINE_LENGTH];
  6876. BatchReplaceTextures_t Info;
  6877. while( g_pFullFileSystem->ReadLine( buf, sizeof( buf ), fp ) )
  6878. {
  6879. scan = buf;
  6880. // skip whitespace.
  6881. while( *scan == ' ' || *scan == '\t' )
  6882. {
  6883. scan++;
  6884. }
  6885. // get the key.
  6886. keyStart = scan;
  6887. while( *scan != ' ' && *scan != '\t' )
  6888. {
  6889. if( *scan == '\0' || *scan == '\n' )
  6890. {
  6891. goto next_line;
  6892. }
  6893. scan++;
  6894. }
  6895. memcpy( Info.szFindTexName, keyStart, scan - keyStart );
  6896. Info.szFindTexName[scan - keyStart] = '\0';
  6897. // skip whitespace.
  6898. while( *scan == ' ' || *scan == '\t' )
  6899. {
  6900. scan++;
  6901. }
  6902. // get the value
  6903. valStart = scan;
  6904. while( *scan != ' ' && *scan != '\t' && *scan != '\0' && *scan != '\n' )
  6905. {
  6906. scan++;
  6907. }
  6908. memcpy( Info.szReplaceTexName, valStart, scan - valStart );
  6909. Info.szReplaceTexName[scan - valStart] = '\0';
  6910. // Get rid of the file extension in val if there is one.
  6911. char *period;
  6912. period = Info.szReplaceTexName + strlen( Info.szReplaceTexName ) - 4;
  6913. if( period > Info.szReplaceTexName && *period == '.' )
  6914. {
  6915. *period = '\0';
  6916. }
  6917. // Get of backslashes in both key and val.
  6918. for( scan = Info.szFindTexName; *scan; scan++ )
  6919. {
  6920. if( *scan == '\\' )
  6921. {
  6922. *scan = '/';
  6923. }
  6924. }
  6925. for( scan = Info.szReplaceTexName; *scan; scan++ )
  6926. {
  6927. if( *scan == '\\' )
  6928. {
  6929. *scan = '/';
  6930. }
  6931. }
  6932. // Search and replace all key textures with val.
  6933. m_pWorld->EnumChildren( ( ENUMMAPCHILDRENPROC )BatchReplaceTextureCallback, ( DWORD )&Info, MAPCLASS_TYPE( CMapSolid ) );
  6934. next_line:;
  6935. }
  6936. }
  6937. //-----------------------------------------------------------------------------
  6938. // Purpose: Invokes the replace textures dialog.
  6939. //-----------------------------------------------------------------------------
  6940. void CMapDoc::OnEditReplacetex(void)
  6941. {
  6942. CReplaceTexDlg dlg( m_pSelection->GetCount());
  6943. dlg.m_strFind = GetDefaultTextureName();
  6944. if (dlg.DoModal() != IDOK)
  6945. {
  6946. return;
  6947. }
  6948. GetHistory()->MarkUndoPosition( m_pSelection->GetList(), "Replace Textures");
  6949. if (dlg.m_bMarkOnly)
  6950. {
  6951. SelectObject(NULL, scClear|scSaveChanges); // clear selection first
  6952. }
  6953. dlg.DoReplaceTextures();
  6954. }
  6955. //-----------------------------------------------------------------------------
  6956. // Purpose: Snaps the selected objects to the grid. This uses the selection
  6957. // bounds as a reference point.
  6958. //-----------------------------------------------------------------------------
  6959. void CMapDoc::OnToolsSnapselectedtogrid(void)
  6960. {
  6961. if ( m_pToolManager->GetActiveToolID() == TOOL_MORPH )
  6962. {
  6963. Morph3D *pMorphTool = assert_cast< Morph3D* >( m_pToolManager->GetActiveTool() );
  6964. pMorphTool->SnapSelectedToGrid( m_nGridSpacing );
  6965. }
  6966. if (m_pSelection->IsEmpty())
  6967. return;
  6968. const CMapObjectList *pSelList = m_pSelection->GetList();
  6969. BoundBox NewObjectBox;
  6970. m_pSelection->GetBounds(NewObjectBox.bmins, NewObjectBox.bmaxs);
  6971. Vector vecMove(0, 0, 0);
  6972. // If we have a single point entity selected, just snap its origin.
  6973. bool bOnePointEntity = false;
  6974. if (pSelList->Count() == 1)
  6975. {
  6976. CMapClass *pObject = pSelList->Element(0);
  6977. CMapEntity *pEntity = dynamic_cast<CMapEntity *>(pObject);
  6978. if (pEntity && pEntity->IsPlaceholder())
  6979. {
  6980. Vector vecOrigin;
  6981. pEntity->GetOrigin(vecOrigin);
  6982. Vector vecOriginSnap = vecOrigin;
  6983. Snap(vecOriginSnap);
  6984. vecMove = vecOriginSnap - vecOrigin;
  6985. bOnePointEntity = true;
  6986. }
  6987. }
  6988. if (!bOnePointEntity)
  6989. {
  6990. // Something other than a single point entity is selected.
  6991. // Just snap the bmins of the selection bounding box.
  6992. Vector vOldMins = NewObjectBox.bmins;
  6993. NewObjectBox.SnapToGrid(m_nGridSpacing);
  6994. // Calculate the amount to move.
  6995. vecMove = NewObjectBox.bmins - vOldMins;
  6996. }
  6997. GetHistory()->MarkUndoPosition(pSelList, "Snap Objects");
  6998. GetHistory()->Keep(pSelList);
  6999. // do move
  7000. for (int i = 0; i < pSelList->Count(); i++)
  7001. {
  7002. CMapClass *pObject = pSelList->Element(i);
  7003. pObject->TransMove(vecMove);
  7004. }
  7005. SetModifiedFlag();
  7006. }
  7007. //-----------------------------------------------------------------------------
  7008. // Purpose:
  7009. // Input : pObject -
  7010. //-----------------------------------------------------------------------------
  7011. void CMapDoc::SnapObjectsRecursive(CMapClass *pObject)
  7012. {
  7013. if (!pObject->IsGroup())
  7014. {
  7015. CMapEntity *pEntity = dynamic_cast<CMapEntity *>(pObject);
  7016. Vector vecRefPoint;
  7017. if (pEntity && pEntity->IsPlaceholder())
  7018. {
  7019. // Point entities snap based on their origin.
  7020. pEntity->GetOrigin(vecRefPoint);
  7021. }
  7022. else
  7023. {
  7024. // Everthing else snaps based on the mins of it's bounding box.
  7025. Vector maxs;
  7026. pObject->GetRender2DBox(vecRefPoint, maxs);
  7027. }
  7028. Vector vecRefPointSnap = vecRefPoint;
  7029. Snap(vecRefPointSnap);
  7030. Vector vecMove = vecRefPointSnap - vecRefPoint;
  7031. pObject->TransMove(vecMove);
  7032. }
  7033. else
  7034. {
  7035. // Recurse into children of non-entities (since entities can't have
  7036. // entity children).
  7037. const CMapObjectList *pChildren = pObject->GetChildren();
  7038. FOR_EACH_OBJ( *pChildren, pos )
  7039. {
  7040. SnapObjectsRecursive(pChildren->Element(pos));
  7041. }
  7042. }
  7043. }
  7044. //-----------------------------------------------------------------------------
  7045. // Purpose: Snaps the selected objects to the grid. This uses the selection
  7046. // bounds as a reference point.
  7047. //-----------------------------------------------------------------------------
  7048. void CMapDoc::OnToolsSnapSelectedToGridIndividually()
  7049. {
  7050. if ( m_pSelection->IsEmpty() )
  7051. return;
  7052. const CMapObjectList *pSelList = m_pSelection->GetList();
  7053. Vector vecMove(0, 0, 0);
  7054. GetHistory()->MarkUndoPosition(pSelList, "Snap Objects Individually");
  7055. GetHistory()->Keep(pSelList);
  7056. for (int i = 0; i < pSelList->Count(); i++)
  7057. {
  7058. CMapClass *pObject = pSelList->Element(i);
  7059. SnapObjectsRecursive(pObject);
  7060. }
  7061. SetModifiedFlag();
  7062. }
  7063. //-----------------------------------------------------------------------------
  7064. // Purpose:
  7065. // Input : pCmdUI -
  7066. //-----------------------------------------------------------------------------
  7067. void CMapDoc::OnUpdateToolsSplitface(CCmdUI* pCmdUI)
  7068. {
  7069. if ( m_pToolManager->GetActiveToolID() != TOOL_MORPH )
  7070. {
  7071. pCmdUI->SetCheck( false );
  7072. }
  7073. else
  7074. {
  7075. Morph3D *pMorph = (Morph3D*) m_pToolManager->GetActiveTool();
  7076. pCmdUI->SetCheck( pMorph->CanSplitFace());
  7077. }
  7078. }
  7079. //-----------------------------------------------------------------------------
  7080. // Purpose:
  7081. //-----------------------------------------------------------------------------
  7082. void CMapDoc::OnToolsSplitface(void)
  7083. {
  7084. if (m_pToolManager->GetActiveToolID() == TOOL_MORPH)
  7085. {
  7086. Morph3D *pMorph = (Morph3D*) m_pToolManager->GetActiveTool();
  7087. pMorph->SplitFace();
  7088. }
  7089. }
  7090. //-----------------------------------------------------------------------------
  7091. // Purpose: Centers the origin of any entities in the given object tree.
  7092. // Input : pObject - root of the object tree.
  7093. //-----------------------------------------------------------------------------
  7094. void CMapDoc::CenterOriginsRecursive(CMapClass *pObject)
  7095. {
  7096. CMapEntity *pEntity = dynamic_cast<CMapEntity *>(pObject);
  7097. if (pEntity != NULL)
  7098. {
  7099. const char *pszOrigin = pEntity->GetKeyValue("origin");
  7100. if (pszOrigin)
  7101. {
  7102. // This entity has an origin key.
  7103. GetHistory()->Keep(pEntity);
  7104. Vector vecCenter;
  7105. pEntity->GetBoundsCenter(vecCenter);
  7106. // dvs: make key parse/unparse code common to Hammer and the engine
  7107. char szOrigin[50];
  7108. sprintf(szOrigin, "%g %g %g", vecCenter.x, vecCenter.y, vecCenter.z);
  7109. pEntity->SetKeyValue("origin", szOrigin);
  7110. }
  7111. }
  7112. else
  7113. {
  7114. // Recurse into children of non-entities (since entities can't have
  7115. // entity children).
  7116. const CMapObjectList *pChildren = pObject->GetChildren();
  7117. FOR_EACH_OBJ( *pChildren, pos )
  7118. {
  7119. CenterOriginsRecursive(pChildren->Element(pos));
  7120. }
  7121. }
  7122. }
  7123. //-----------------------------------------------------------------------------
  7124. // Purpose: Centers the origins of all selected entities.
  7125. //-----------------------------------------------------------------------------
  7126. void CMapDoc::OnToolsCenterOrigins()
  7127. {
  7128. const CMapObjectList *pSelList = m_pSelection->GetList();
  7129. GetHistory()->MarkUndoPosition(pSelList, "Center Origins");
  7130. for (int i = 0; i < pSelList->Count(); i++)
  7131. {
  7132. CMapClass *pObject = pSelList->Element(i);
  7133. CenterOriginsRecursive(pObject);
  7134. }
  7135. UpdateAllViews( MAPVIEW_UPDATE_OBJECTS );
  7136. }
  7137. //-----------------------------------------------------------------------------
  7138. // Purpose: Snaps a point to the grid, or to integer values if snap is disabled.
  7139. // Input : pt - Point in world coordinates to snap.
  7140. //-----------------------------------------------------------------------------
  7141. void CMapDoc::Snap(Vector &pt, int nFlags)
  7142. {
  7143. if ( m_bSnapToGrid )
  7144. nFlags |= constrainSnap;
  7145. else
  7146. nFlags |= constrainIntSnap;
  7147. if ( nFlags & constrainIntSnap )
  7148. {
  7149. for (int i = 0; i < 3; i++)
  7150. {
  7151. pt[i] = V_rint(pt[i]);
  7152. }
  7153. }
  7154. else if (nFlags & constrainSnap )
  7155. {
  7156. float flGridSpacing = m_nGridSpacing;
  7157. if ( nFlags & constrainHalfSnap )
  7158. flGridSpacing *= 0.5f;
  7159. for (int i = 0; i < 3; i++)
  7160. {
  7161. pt[i] = V_rint(pt[i] / flGridSpacing) * flGridSpacing;
  7162. }
  7163. }
  7164. }
  7165. //-----------------------------------------------------------------------------
  7166. // Purpose:
  7167. //-----------------------------------------------------------------------------
  7168. void CMapDoc::OnToolsTransform(void)
  7169. {
  7170. if(m_pSelection->IsEmpty())
  7171. {
  7172. AfxMessageBox("You must select some objects before you can\n"
  7173. "transform them.");
  7174. return;
  7175. }
  7176. CTransformDlg dlg;
  7177. dlg.m_iMode = 0;
  7178. if(dlg.DoModal() != IDOK)
  7179. return;
  7180. Vector vDelta( dlg.m_X, dlg.m_Y, dlg.m_Z );
  7181. if (dlg.m_iMode == 1)
  7182. {
  7183. // make sure no 0.0 values
  7184. for (int i = 0; i < 3; i++)
  7185. {
  7186. if (vDelta[i] == 0.0f)
  7187. {
  7188. vDelta[i] = 1.0f;
  7189. }
  7190. }
  7191. }
  7192. const CMapObjectList *pSelList = m_pSelection->GetList();
  7193. // find origin
  7194. Vector vOrigin;
  7195. m_pSelection->GetBoundsCenter( vOrigin );
  7196. GetHistory()->MarkUndoPosition(pSelList, "Transformation");
  7197. GetHistory()->Keep(pSelList);
  7198. //
  7199. // Save any properties that may have been changed in the entity properties dialog.
  7200. // This prevents the LoadData below from losing any changes that were made in the
  7201. // object properties dialog.
  7202. //
  7203. GetMainWnd()->pObjectProperties->SaveData();
  7204. for (int i = 0; i < pSelList->Count(); i++)
  7205. {
  7206. CMapClass *pObject = pSelList->Element(i);
  7207. if ( dlg.m_iMode == 0 )
  7208. {
  7209. pObject->TransRotate( vOrigin, (QAngle&)vDelta );
  7210. }
  7211. else if ( dlg.m_iMode == 1 )
  7212. {
  7213. pObject->TransScale( vOrigin, vDelta );
  7214. }
  7215. else if ( dlg.m_iMode == 2 )
  7216. {
  7217. pObject->TransMove( vDelta );
  7218. }
  7219. }
  7220. SetModifiedFlag();
  7221. }
  7222. //-----------------------------------------------------------------------------
  7223. // Purpose:
  7224. //-----------------------------------------------------------------------------
  7225. void CMapDoc::OnToggleDispSolidMask( void )
  7226. {
  7227. UpdateAllViews( MAPVIEW_UPDATE_ONLY_3D );
  7228. m_bDispSolidDrawMask = !m_bDispSolidDrawMask;
  7229. }
  7230. //-----------------------------------------------------------------------------
  7231. // Purpose:
  7232. //-----------------------------------------------------------------------------
  7233. void CMapDoc::OnUpdateToggleSolidMask(CCmdUI* pCmdUI)
  7234. {
  7235. pCmdUI->SetCheck( m_bDispSolidDrawMask );
  7236. }
  7237. //-----------------------------------------------------------------------------
  7238. //-----------------------------------------------------------------------------
  7239. void CMapDoc::OnToggleDispDrawWalkable( void )
  7240. {
  7241. UpdateAllViews( MAPVIEW_UPDATE_ONLY_3D );
  7242. m_bDispDrawWalkable = !m_bDispDrawWalkable;
  7243. }
  7244. //-----------------------------------------------------------------------------
  7245. //-----------------------------------------------------------------------------
  7246. void CMapDoc::OnUpdateToggleDispDrawWalkable( CCmdUI *pCmdUI )
  7247. {
  7248. pCmdUI->SetCheck( m_bDispDrawWalkable );
  7249. }
  7250. //-----------------------------------------------------------------------------
  7251. // Purpose:
  7252. //-----------------------------------------------------------------------------
  7253. void CMapDoc::OnToggleDispDrawBuildable( void )
  7254. {
  7255. UpdateAllViews( MAPVIEW_UPDATE_ONLY_3D );
  7256. m_bDispDrawBuildable = !m_bDispDrawBuildable;
  7257. }
  7258. //-----------------------------------------------------------------------------
  7259. // Toggles between rendering disps in 3D.
  7260. //-----------------------------------------------------------------------------
  7261. void CMapDoc::OnToggleDispDraw3D( void )
  7262. {
  7263. UpdateAllViews( MAPVIEW_UPDATE_ONLY_3D );
  7264. m_bDispDraw3D = !m_bDispDraw3D;
  7265. }
  7266. //-----------------------------------------------------------------------------
  7267. //-----------------------------------------------------------------------------
  7268. void CMapDoc::OnUpdateToggleDispDraw3D( CCmdUI *pCmdUI )
  7269. {
  7270. pCmdUI->SetCheck( m_bDispDraw3D );
  7271. }
  7272. //-----------------------------------------------------------------------------
  7273. // Purpose:
  7274. //-----------------------------------------------------------------------------
  7275. void CMapDoc::OnUpdateToggleDispDrawBuildable( CCmdUI *pCmdUI )
  7276. {
  7277. pCmdUI->SetCheck( m_bDispDrawBuildable );
  7278. }
  7279. //-----------------------------------------------------------------------------
  7280. // Purpose:
  7281. //-----------------------------------------------------------------------------
  7282. void CMapDoc::OnToggleDispDrawRemovedVerts( void )
  7283. {
  7284. UpdateAllViews( MAPVIEW_UPDATE_ONLY_3D );
  7285. m_bDispDrawRemovedVerts = !m_bDispDrawRemovedVerts;
  7286. }
  7287. //-----------------------------------------------------------------------------
  7288. // Purpose:
  7289. //-----------------------------------------------------------------------------
  7290. void CMapDoc::OnUpdateToggleDispDrawRemovedVerts( CCmdUI *pCmdUI )
  7291. {
  7292. pCmdUI->SetCheck( m_bDispDrawRemovedVerts );
  7293. }
  7294. void CMapDoc::OnToolsToggletexlock(void)
  7295. {
  7296. Options.SetLockingTextures(!Options.IsLockingTextures());
  7297. SetStatusText(SBI_PROMPT, Options.IsLockingTextures() ? "Texture locking on" : "Texture locking off");
  7298. }
  7299. void CMapDoc::OnUpdateToolsToggletexlock(CCmdUI* pCmdUI)
  7300. {
  7301. pCmdUI->SetCheck(Options.IsLockingTextures());
  7302. }
  7303. void CMapDoc::OnToolsToggletexlockScale(void)
  7304. {
  7305. Options.SetScaleLockingTextures(!Options.IsScaleLockingTextures());
  7306. SetStatusText(SBI_PROMPT, Options.IsScaleLockingTextures() ? "Scale texture locking on" : "Scale texture locking off");
  7307. }
  7308. void CMapDoc::OnUpdateToolsToggletexlockScale(CCmdUI* pCmdUI)
  7309. {
  7310. pCmdUI->SetCheck(Options.IsScaleLockingTextures());
  7311. }
  7312. //-----------------------------------------------------------------------------
  7313. // Purpose:
  7314. //-----------------------------------------------------------------------------
  7315. void CMapDoc::OnToolsTextureAlignment(void)
  7316. {
  7317. TextureAlignment_t eTextureAlignment;
  7318. eTextureAlignment = Options.GetTextureAlignment();
  7319. if (eTextureAlignment == TEXTURE_ALIGN_WORLD)
  7320. {
  7321. Options.SetTextureAlignment(TEXTURE_ALIGN_FACE);
  7322. SetStatusText(SBI_PROMPT, "Face aligned textures");
  7323. }
  7324. else
  7325. {
  7326. Options.SetTextureAlignment(TEXTURE_ALIGN_WORLD);
  7327. SetStatusText(SBI_PROMPT, "World aligned textures");
  7328. }
  7329. }
  7330. //-----------------------------------------------------------------------------
  7331. // Purpose:
  7332. // Input : *pCmdUI -
  7333. //-----------------------------------------------------------------------------
  7334. void CMapDoc::OnUpdateToolsTextureAlignment(CCmdUI *pCmdUI)
  7335. {
  7336. pCmdUI->SetCheck(Options.GetTextureAlignment() == TEXTURE_ALIGN_FACE);
  7337. }
  7338. //-----------------------------------------------------------------------------
  7339. // Purpose: Returns whether a remote shell editing session has been initiated
  7340. // through a "session_begin" shell command.
  7341. //-----------------------------------------------------------------------------
  7342. bool CMapDoc::IsShellSessionActive(void)
  7343. {
  7344. return(GetMainWnd()->IsShellSessionActive());
  7345. }
  7346. //-----------------------------------------------------------------------------
  7347. // Purpose: Returns the current active state of the cordon tool.
  7348. //-----------------------------------------------------------------------------
  7349. bool CMapDoc::IsCordoning(void)
  7350. {
  7351. return m_bIsCordoning;
  7352. }
  7353. bool CMapDoc::SetCordoning( bool bState)
  7354. {
  7355. if ( m_bIsCordoning != bState )
  7356. {
  7357. m_bIsCordoning = bState;
  7358. UpdateVisibilityAll();
  7359. SetModifiedFlag( true );
  7360. return true;
  7361. }
  7362. return false;
  7363. }
  7364. void CMapDoc::GetCordon( Vector &mins, Vector &maxs)
  7365. {
  7366. mins = m_vCordonMins;
  7367. maxs = m_vCordonMaxs;
  7368. }
  7369. void CMapDoc::SetCordon( const Vector &mins, const Vector &maxs)
  7370. {
  7371. m_vCordonMins = mins;
  7372. m_vCordonMaxs = maxs;
  7373. UpdateVisibilityAll();
  7374. SetModifiedFlag( true );
  7375. }
  7376. //-----------------------------------------------------------------------------
  7377. // Purpose:
  7378. //-----------------------------------------------------------------------------
  7379. void CMapDoc::OnToggleCordon(void)
  7380. {
  7381. SetCordoning( !m_bIsCordoning );
  7382. }
  7383. //-----------------------------------------------------------------------------
  7384. // Purpose:
  7385. // Input : pCmdUI -
  7386. //-----------------------------------------------------------------------------
  7387. void CMapDoc::OnUpdateToggleCordon(CCmdUI* pCmdUI)
  7388. {
  7389. pCmdUI->SetCheck( m_bIsCordoning?1:0 );
  7390. }
  7391. //-----------------------------------------------------------------------------
  7392. // Purpose: Toggles between Groups selection mode and Solids selection mode.
  7393. //-----------------------------------------------------------------------------
  7394. void CMapDoc::OnToggleGroupignore(void)
  7395. {
  7396. SelectMode_t eSelectMode = m_pSelection->GetMode();
  7397. if (eSelectMode == selectSolids)
  7398. {
  7399. eSelectMode = selectGroups;
  7400. }
  7401. else
  7402. {
  7403. eSelectMode = selectSolids;
  7404. }
  7405. m_pSelection->SetMode(eSelectMode);
  7406. }
  7407. //-----------------------------------------------------------------------------
  7408. // Purpose:
  7409. // Input : pCmdUI -
  7410. //-----------------------------------------------------------------------------
  7411. void CMapDoc::OnUpdateToggleGroupignore(CCmdUI *pCmdUI)
  7412. {
  7413. pCmdUI->SetCheck(m_pSelection->GetMode() == selectSolids);
  7414. }
  7415. //-----------------------------------------------------------------------------
  7416. // Purpose:
  7417. //-----------------------------------------------------------------------------
  7418. void CMapDoc::OnChangeVertexscale(void)
  7419. {
  7420. if (m_pToolManager->GetActiveToolID() == TOOL_MORPH)
  7421. {
  7422. Morph3D *pMorph = (Morph3D*) m_pToolManager->GetActiveTool();
  7423. pMorph->UpdateScale();
  7424. }
  7425. }
  7426. //-----------------------------------------------------------------------------
  7427. // Purpose:
  7428. //-----------------------------------------------------------------------------
  7429. void CMapDoc::OnVscaleToggle(void)
  7430. {
  7431. if (m_pToolManager->GetActiveToolID() == TOOL_MORPH)
  7432. {
  7433. Morph3D *pMorph = (Morph3D*) m_pToolManager->GetActiveTool();
  7434. pMorph->OnScaleCmd();
  7435. }
  7436. }
  7437. //-----------------------------------------------------------------------------
  7438. // Purpose:
  7439. //-----------------------------------------------------------------------------
  7440. void CMapDoc::OnMapEntityreport(void)
  7441. {
  7442. CEntityReportDlg::ShowEntityReport(this, GetMainWnd());
  7443. }
  7444. //-----------------------------------------------------------------------------
  7445. // Purpose:
  7446. //-----------------------------------------------------------------------------
  7447. void CMapDoc::OnToggleSelectbyhandle(void)
  7448. {
  7449. Options.view2d.bSelectbyhandles = !Options.view2d.bSelectbyhandles;
  7450. }
  7451. //-----------------------------------------------------------------------------
  7452. // Purpose:
  7453. // Input : pCmdUI -
  7454. //-----------------------------------------------------------------------------
  7455. void CMapDoc::OnUpdateToggleSelectbyhandle(CCmdUI* pCmdUI)
  7456. {
  7457. pCmdUI->SetCheck(Options.view2d.bSelectbyhandles);
  7458. }
  7459. //-----------------------------------------------------------------------------
  7460. // Purpose:
  7461. // Input :
  7462. //-----------------------------------------------------------------------------
  7463. void CMapDoc::OnToggleInfiniteselect()
  7464. {
  7465. Options.view2d.bAutoSelect = !Options.view2d.bAutoSelect;
  7466. }
  7467. //-----------------------------------------------------------------------------
  7468. // Purpose:
  7469. // Input : pCmdUI -
  7470. //-----------------------------------------------------------------------------
  7471. void CMapDoc::OnUpdateToggleInfiniteselect(CCmdUI* pCmdUI)
  7472. {
  7473. pCmdUI->SetCheck(Options.view2d.bAutoSelect);
  7474. }
  7475. static BOOL SaveDXF(CMapSolid *pSolid, ExportDXFInfo_s *pInfo)
  7476. {
  7477. return pSolid->SaveDXF( pInfo );
  7478. }
  7479. //-----------------------------------------------------------------------------
  7480. // Purpose:
  7481. //-----------------------------------------------------------------------------
  7482. void CMapDoc::OnFileExporttodxf(void)
  7483. {
  7484. static CString str;
  7485. if (str.IsEmpty())
  7486. {
  7487. int nDot;
  7488. // Replace the extension with DXF.
  7489. str = GetPathName();
  7490. if ((nDot = str.ReverseFind('.')) != -1)
  7491. {
  7492. str = str.Left(nDot);
  7493. }
  7494. str += ".dxf";
  7495. }
  7496. CExportDlg dlg(str, "dxf", "DXF files (*.dxf)|*.dxf||");
  7497. if(dlg.DoModal() == IDCANCEL)
  7498. return;
  7499. str = dlg.GetPathName();
  7500. if(str.ReverseFind('.') == -1)
  7501. str += ".dxf";
  7502. FILE *fp = fopen(str, "wb");
  7503. m_pWorld->CalcBounds(TRUE);
  7504. BoundBox box;
  7505. m_pWorld->GetRender2DBox(box.bmins, box.bmaxs);
  7506. fprintf(fp,"0\nSECTION\n2\nHEADER\n");
  7507. fprintf(fp,"9\n$ACADVER\n1\nAC1008\n");
  7508. fprintf(fp,"9\n$UCSORG\n10\n0.0\n20\n0.0\n30\n0.0\n");
  7509. fprintf(fp,"9\n$UCSXDIR\n10\n1.0\n20\n0.0\n30\n0.0\n");
  7510. fprintf(fp,"9\n$TILEMODE\n70\n1\n");
  7511. fprintf(fp,"9\n$UCSYDIR\n10\n0.0\n20\n1.0\n30\n0.0\n");
  7512. fprintf(fp,"9\n$EXTMIN\n10\n%f\n20\n%f\n30\n%f\n",
  7513. box.bmins[0], box.bmins[1], box.bmins[2]);
  7514. fprintf(fp,"9\n$EXTMAX\n10\n%f\n20\n%f\n30\n%f\n",
  7515. box.bmaxs[0], box.bmaxs[1], box.bmaxs[2]);
  7516. fprintf(fp,"0\nENDSEC\n");
  7517. /* Tables section */
  7518. fprintf(fp,"0\nSECTION\n2\nTABLES\n");
  7519. /* Continuous line type */
  7520. fprintf(fp,"0\nTABLE\n2\nLTYPE\n70\n1\n0\nLTYPE\n2\nCONTINUOUS"
  7521. "\n70\n64\n3\nSolid line\n72\n65\n73\n0\n40\n0.0\n");
  7522. fprintf(fp,"0\nENDTAB\n");
  7523. /* Object names for layers */
  7524. fprintf(fp,"0\nTABLE\n2\nLAYER\n70\n%d\n",1);
  7525. fprintf(fp,"0\nLAYER\n2\n0\n70\n0\n62\n7\n6\nCONTINUOUS\n");
  7526. fprintf(fp,"0\nENDTAB\n");
  7527. fprintf(fp,"0\nTABLE\n2\nSTYLE\n70\n1\n0\nSTYLE\n2\nSTANDARD\n70\n0\n"
  7528. "40\n0.0\n41\n1.0\n50\n0.0\n71\n0\n42\n0.2\n3\ntxt\n4\n\n0\nENDTAB\n");
  7529. /* Default View? */
  7530. /* UCS */
  7531. fprintf(fp,"0\nTABLE\n2\nUCS\n70\n0\n0\nENDTAB\n");
  7532. fprintf(fp,"0\nENDSEC\n");
  7533. /* Entities section */
  7534. fprintf(fp,"0\nSECTION\n2\nENTITIES\n");
  7535. // export solids
  7536. BeginWaitCursor();
  7537. ExportDXFInfo_s info;
  7538. info.bVisOnly = dlg.bVisibles!=0;
  7539. info.nObject = 0;
  7540. info.pWorld = m_pWorld;
  7541. info.fp = fp;
  7542. m_pWorld->EnumChildren(ENUMMAPCHILDRENPROC(SaveDXF), DWORD(&info), MAPCLASS_TYPE(CMapSolid));
  7543. EndWaitCursor();
  7544. fprintf(fp,"0\nENDSEC\n0\nEOF\n");
  7545. fclose(fp);
  7546. }
  7547. //-----------------------------------------------------------------------------
  7548. // Purpose: Toggles the 3D grid.
  7549. //-----------------------------------------------------------------------------
  7550. void CMapDoc::OnToggle3DGrid(void)
  7551. {
  7552. m_bShow3DGrid = !m_bShow3DGrid;
  7553. UpdateAllViews( MAPVIEW_UPDATE_ONLY_3D|MAPVIEW_OPTIONS_CHANGED );
  7554. }
  7555. //-----------------------------------------------------------------------------
  7556. // Purpose: Sets the check state of the 3D grid toggle button.
  7557. // Input : *pCmdUI -
  7558. //-----------------------------------------------------------------------------
  7559. void CMapDoc::OnUpdateToggle3DGrid(CCmdUI *pCmdUI)
  7560. {
  7561. pCmdUI->SetCheck(m_bShow3DGrid);
  7562. }
  7563. static void SetFilenameExtension( CString &fileName, const char *pExt )
  7564. {
  7565. char *p = fileName.GetBuffer(MAX_PATH);
  7566. p = strrchr(p, '.');
  7567. if (p)
  7568. {
  7569. strcpy(p, pExt);
  7570. }
  7571. fileName.ReleaseBuffer();
  7572. }
  7573. //-----------------------------------------------------------------------------
  7574. // Purpose: Load data from the map's portal file for visualization
  7575. //-----------------------------------------------------------------------------
  7576. void CMapDoc::OnMapLoadportalfile(void)
  7577. {
  7578. delete m_pPortalFile;
  7579. m_pPortalFile = NULL;
  7580. m_pPortalFile = new portalfile_t;
  7581. m_pPortalFile->fileName = GetPathName();
  7582. m_pPortalFile->totalVerts = 0;
  7583. SetFilenameExtension( m_pPortalFile->fileName, ".prt" );
  7584. CString str;
  7585. str.Format("Load default portal file?\n(%s)", m_pPortalFile->fileName.GetBuffer());
  7586. if(GetFileAttributes(m_pPortalFile->fileName) == 0xFFFFFFFF ||
  7587. AfxMessageBox(str, MB_ICONQUESTION | MB_YESNO) == IDNO)
  7588. {
  7589. CFileDialog dlg(TRUE, ".prt", m_pPortalFile->fileName, OFN_HIDEREADONLY |
  7590. OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR,
  7591. "Portal files (*.prt)|*.prt|");
  7592. if(dlg.DoModal() != IDOK)
  7593. return;
  7594. m_pPortalFile->fileName = dlg.GetPathName();
  7595. }
  7596. // load the file
  7597. if(GetFileAttributes(m_pPortalFile->fileName) == 0xFFFFFFFF)
  7598. {
  7599. AfxMessageBox("Couldn't find portal file.");
  7600. return;
  7601. }
  7602. FILE *fp = fopen(m_pPortalFile->fileName, "r");
  7603. char szLine[256];
  7604. int clusterCount;
  7605. int portalCount;
  7606. if (fscanf (fp,"%79s\n%i\n%i\n",szLine, &clusterCount, &portalCount) == 3)
  7607. {
  7608. if ( !Q_stricmp( szLine, "PRT1") )
  7609. {
  7610. for ( int iPortal = 0; iPortal < portalCount; iPortal++ )
  7611. {
  7612. int pointCount, leaf0, leaf1;
  7613. if (fscanf (fp, "%i %i %i ", &pointCount, &leaf0, &leaf1 ) == 3 )
  7614. {
  7615. m_pPortalFile->vertCount.AddToTail( pointCount );
  7616. m_pPortalFile->totalVerts += pointCount;
  7617. for ( int i = 0; i < pointCount; i++ )
  7618. {
  7619. Vector v;
  7620. if ( fscanf (fp, "(%f %f %f ) ", &v[0], &v[1], &v[2]) == 3 )
  7621. {
  7622. m_pPortalFile->verts.AddToTail(v);
  7623. }
  7624. else
  7625. {
  7626. break;
  7627. }
  7628. }
  7629. fscanf (fp, "\n");
  7630. }
  7631. else
  7632. {
  7633. break;
  7634. }
  7635. }
  7636. }
  7637. // if this is not true we parsed incorrectly
  7638. Assert( m_pPortalFile->vertCount.Count() == portalCount );
  7639. }
  7640. fclose(fp);
  7641. if ( m_pPortalFile )
  7642. {
  7643. if ( m_pPortalFile->vertCount.Count() != portalCount || portalCount <= 0 )
  7644. {
  7645. delete m_pPortalFile;
  7646. m_pPortalFile = NULL;
  7647. }
  7648. }
  7649. UpdateAllViews( MAPVIEW_UPDATE_ONLY_2D );
  7650. }
  7651. //-----------------------------------------------------------------------------
  7652. // Purpose: Free the memory associate with the portal file
  7653. //-----------------------------------------------------------------------------
  7654. void CMapDoc::OnMapUnloadportalfile(void)
  7655. {
  7656. delete m_pPortalFile;
  7657. m_pPortalFile = NULL;
  7658. }
  7659. //-----------------------------------------------------------------------------
  7660. // Purpose:
  7661. //-----------------------------------------------------------------------------
  7662. void CMapDoc::OnMapLoadpointfile(void)
  7663. {
  7664. if(m_strLastPointFile.IsEmpty())
  7665. {
  7666. m_strLastPointFile = GetPathName();
  7667. const char *pExt = (m_pGame->mapformat == mfHalfLife2) ? ".lin" : ".pts";
  7668. SetFilenameExtension( m_strLastPointFile, pExt );
  7669. }
  7670. CString str;
  7671. str.Format("Load default pointfile?\n(%s)", m_strLastPointFile.GetBuffer());
  7672. if(GetFileAttributes(m_strLastPointFile) == 0xFFFFFFFF ||
  7673. AfxMessageBox(str, MB_ICONQUESTION | MB_YESNO) == IDNO)
  7674. {
  7675. CFileDialog dlg(TRUE, ".pts", m_strLastPointFile, OFN_HIDEREADONLY |
  7676. OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR,
  7677. "Pointfiles (*.pts;*.lin)|*.pts; *.lin||");
  7678. if(dlg.DoModal() != IDOK)
  7679. return;
  7680. m_strLastPointFile = dlg.GetPathName();
  7681. }
  7682. // load the file
  7683. if(GetFileAttributes(m_strLastPointFile) == 0xFFFFFFFF)
  7684. {
  7685. AfxMessageBox("Couldn't load pointfile.");
  7686. return;
  7687. }
  7688. std::ifstream file(m_strLastPointFile);
  7689. m_PFPoints.Purge();
  7690. while(!file.eof())
  7691. {
  7692. char szLine[256];
  7693. file.getline(szLine, 256);
  7694. Vector v;
  7695. if(sscanf(szLine, "%f %f %f", &v.x, &v.y, &v.z) == 3)
  7696. {
  7697. m_PFPoints.AddToTail( v );
  7698. }
  7699. else
  7700. {
  7701. break;
  7702. }
  7703. }
  7704. file.close();
  7705. m_iCurPFPoint = -1;
  7706. UpdateAllViews( MAPVIEW_UPDATE_ONLY_2D );
  7707. }
  7708. //-----------------------------------------------------------------------------
  7709. // Purpose:
  7710. //-----------------------------------------------------------------------------
  7711. void CMapDoc::OnMapUnloadpointfile(void)
  7712. {
  7713. m_PFPoints.Purge();
  7714. UpdateAllViews( MAPVIEW_UPDATE_ONLY_2D );
  7715. }
  7716. //-----------------------------------------------------------------------------
  7717. // Purpose:
  7718. // Input : iDirection -
  7719. //-----------------------------------------------------------------------------
  7720. void CMapDoc::GotoPFPoint(int iDirection)
  7721. {
  7722. if (m_PFPoints.Count() == 0)
  7723. return;
  7724. m_iCurPFPoint = m_iCurPFPoint + iDirection;
  7725. if (m_iCurPFPoint == m_PFPoints.Count())
  7726. {
  7727. m_iCurPFPoint = 0;
  7728. }
  7729. else if (m_iCurPFPoint < 0)
  7730. {
  7731. m_iCurPFPoint = m_PFPoints.Count() - 1;
  7732. }
  7733. CenterViewsOn(m_PFPoints[m_iCurPFPoint]);
  7734. }
  7735. //-----------------------------------------------------------------------------
  7736. // Determine visgroup
  7737. //-----------------------------------------------------------------------------
  7738. CVisGroup *CMapDoc::GetRootAutoVisGroup()
  7739. {
  7740. // Find the 'auto' visgroup
  7741. CVisGroup *pFoundVisGroup = NULL;
  7742. int nVisGroupCount = VisGroups_GetRootCount();
  7743. for ( int i = 0; i < nVisGroupCount; ++i )
  7744. {
  7745. CVisGroup *pVisGroup = VisGroups_GetRootVisGroup(i);
  7746. if ( !Q_stricmp( "Auto", pVisGroup->GetName() ) )
  7747. {
  7748. pFoundVisGroup = pVisGroup;
  7749. break;
  7750. }
  7751. }
  7752. if ( !pFoundVisGroup )
  7753. {
  7754. pFoundVisGroup = VisGroups_AddGroup( "Auto", true );
  7755. }
  7756. return pFoundVisGroup;
  7757. }
  7758. //-----------------------------------------------------------------------------
  7759. // Determine visgroup and add it to that.
  7760. //-----------------------------------------------------------------------------
  7761. void CMapDoc::AddToAutoVisGroup( CMapClass *pObject )
  7762. {
  7763. if ( !pObject || !VisGroups_ObjectCanBelongToVisGroup( pObject ) )
  7764. return;
  7765. if ( pObject->IsMapClass( MAPCLASS_TYPE(CMapEntity) ) )
  7766. {
  7767. CMapEntity *pMapEntity = assert_cast<CMapEntity*>( pObject );
  7768. if ( pMapEntity->IsPointClass() )
  7769. {
  7770. // Point entities.
  7771. if ( !pMapEntity->IsNodeClass() )
  7772. {
  7773. AddChildGroupToAutoVisGroup( pObject, "Point Entities", "Entities" );
  7774. }
  7775. else
  7776. {
  7777. AddChildGroupToAutoVisGroup( pObject, "Nodes", "Entities" );
  7778. }
  7779. if ( pMapEntity->IsNPCClass() )
  7780. {
  7781. AddChildGroupToAutoVisGroup( pObject, "NPCs", "Entities" );
  7782. }
  7783. if ( !Q_strnicmp( pMapEntity->GetClassName(), "light_", strlen("light_") ) )
  7784. {
  7785. AddChildGroupToAutoVisGroup( pObject, "Lights", "Entities" );
  7786. }
  7787. if ( !Q_strnicmp( pMapEntity->GetClassName(), "prop_", strlen("prop_") ) )
  7788. {
  7789. AddChildGroupToAutoVisGroup( pObject, "Props", "World Details" );
  7790. }
  7791. }
  7792. else
  7793. {
  7794. // Solid entities.
  7795. if ( !pMapEntity->IsClass("func_detail") )
  7796. {
  7797. AddChildGroupToAutoVisGroup( pObject, "Brush Entities", "Entities" );
  7798. }
  7799. else
  7800. {
  7801. AddChildGroupToAutoVisGroup( pObject, "Func Detail", "World Details" );
  7802. }
  7803. if ( !Q_strnicmp( pMapEntity->GetClassName(), "trigger_", strlen("trigger_") ) )
  7804. {
  7805. AddChildGroupToAutoVisGroup( pObject, "Triggers", "Entities" );
  7806. }
  7807. // Area portals and area portal windows.
  7808. if ( !Q_strnicmp( pMapEntity->GetClassName(), "func_areaportal", strlen("func_areaportal") ) )
  7809. {
  7810. AddChildGroupToAutoVisGroup( pObject, "Areaportals", "Tool Brushes" );
  7811. }
  7812. if ( pMapEntity->IsClass("func_occluder") )
  7813. {
  7814. AddChildGroupToAutoVisGroup( pObject, "Occluders", "Tool Brushes" );
  7815. }
  7816. }
  7817. }
  7818. else if ( pObject->IsMapClass( MAPCLASS_TYPE(CMapSolid) ) )
  7819. {
  7820. CMapSolid *pMapSolid = assert_cast<CMapSolid*>( pObject );
  7821. if ( pMapSolid->HasDisp() )
  7822. {
  7823. AddChildGroupToAutoVisGroup( pObject, "Displacements", "World Geometry" );
  7824. }
  7825. else
  7826. {
  7827. CMapClass *pParent = pObject->GetParent();
  7828. CMapEntity *pParentEntity = dynamic_cast<CMapEntity*>( pParent );
  7829. if ( !pParentEntity )
  7830. {
  7831. AddToAutoVisGroup( pObject, "World Geometry" );
  7832. }
  7833. }
  7834. char buf[1024];
  7835. bool bWaterAdded = false;
  7836. for ( int i = 0; i < pMapSolid->GetFaceCount(); i++ )
  7837. {
  7838. //this check will ensure that an object with a water material on multiple faces will only be added once
  7839. if ( !bWaterAdded )
  7840. {
  7841. IMaterial *pMaterial = pMapSolid->GetFace( i )->GetTexture()->GetMaterial();
  7842. if ( pMaterial )
  7843. {
  7844. pMaterial->FindVar( "%compileWater", &bWaterAdded, false );
  7845. if ( bWaterAdded )
  7846. {
  7847. AddChildGroupToAutoVisGroup( pObject, "Water", "World Geometry" );
  7848. }
  7849. }
  7850. }
  7851. //same check for tool objects
  7852. pMapSolid->GetFace( i )->GetTextureName( buf );
  7853. if ( strstr( buf, "tools/tools" ) )
  7854. {
  7855. if ( strstr( buf, "tools/toolsnodraw" ) )
  7856. {
  7857. AddChildGroupToAutoVisGroup( pObject, "Nodraw", "World Geometry" );
  7858. continue;
  7859. }
  7860. if ( strstr( buf, "tools/toolssky" ) )
  7861. {
  7862. AddChildGroupToAutoVisGroup( pObject, "Sky", "World Geometry" );
  7863. continue;
  7864. }
  7865. if ( strstr( buf, "tools/toolsblock" ) )
  7866. {
  7867. AddChildGroupToAutoVisGroup( NULL, "Block", "Tool Brushes" );
  7868. if ( strstr( buf, "block_los" ) )
  7869. {
  7870. AddChildGroupToAutoVisGroup( pObject, "LOS", "Block" );
  7871. continue;
  7872. }
  7873. else if ( strstr( buf, "blockbullets" ) )
  7874. {
  7875. AddChildGroupToAutoVisGroup( pObject, "Bullets", "Block" );
  7876. continue;
  7877. }
  7878. else if ( strstr( buf, "blocklight" ) )
  7879. {
  7880. AddChildGroupToAutoVisGroup( pObject, "Light", "Block" );
  7881. continue;
  7882. }
  7883. }
  7884. if ( strstr( buf, "tools/tools" ) && strstr( buf, "clip" ) )
  7885. {
  7886. AddChildGroupToAutoVisGroup( NULL, "Clips", "Tool Brushes" );
  7887. if ( strstr( buf, "npcclip" ) )
  7888. {
  7889. AddChildGroupToAutoVisGroup( pObject, "NPC", "Clips" );
  7890. continue;
  7891. }
  7892. else if ( strstr( buf, "playerclip" ) )
  7893. {
  7894. AddChildGroupToAutoVisGroup( pObject, "Player", "Clips" );
  7895. continue;
  7896. }
  7897. else if ( strstr( buf, "controlclip" ) )
  7898. {
  7899. AddChildGroupToAutoVisGroup( pObject, "Control", "Clips" );
  7900. continue;
  7901. }
  7902. else if ( strstr( buf, "clip" ) )
  7903. {
  7904. AddChildGroupToAutoVisGroup( pObject, "Clip", "Clips" );
  7905. continue;
  7906. }
  7907. }
  7908. if ( strstr( buf, "occluder" ) )
  7909. {
  7910. AddChildGroupToAutoVisGroup( pObject, "Occluder", "Tool Brushes");
  7911. continue;
  7912. }
  7913. if ( strstr( buf, "areaportal") )
  7914. {
  7915. AddChildGroupToAutoVisGroup( pObject, "Area Portal", "Tool Brushes");
  7916. continue;
  7917. }
  7918. if ( strstr( buf, "invisible") )
  7919. {
  7920. AddChildGroupToAutoVisGroup( NULL, "Invisible", "Tool Brushes");
  7921. if ( strstr( buf, "invisibleladder") )
  7922. {
  7923. AddChildGroupToAutoVisGroup( pObject, "Ladder", "Invisible");
  7924. continue;
  7925. }
  7926. else if ( strstr( buf, "invisible") )
  7927. {
  7928. AddChildGroupToAutoVisGroup( pObject, "Invisible", "Invisible");
  7929. continue;
  7930. }
  7931. }
  7932. if ( strstr( buf, "skip" ) )
  7933. {
  7934. AddChildGroupToAutoVisGroup( pObject, "Skip", "Tool Brushes" );
  7935. continue;
  7936. }
  7937. if ( strstr( buf, "trigger" ) )
  7938. {
  7939. AddChildGroupToAutoVisGroup( pObject, "Trigger", "Tool Brushes" );
  7940. continue;
  7941. }
  7942. if ( strstr( buf, "origin" ) )
  7943. {
  7944. AddChildGroupToAutoVisGroup( pObject, "Origin", "Tool Brushes" );
  7945. continue;
  7946. }
  7947. if ( strstr( buf, "hint" ) )
  7948. {
  7949. AddChildGroupToAutoVisGroup( pObject, "Hint", "Tool Brushes" );
  7950. continue;
  7951. }
  7952. if ( strstr( buf, "fog" ) )
  7953. {
  7954. AddChildGroupToAutoVisGroup( pObject, "Fog", "Tool Brushes" );
  7955. continue;
  7956. }
  7957. if ( strstr( buf, "black" ) )
  7958. {
  7959. AddChildGroupToAutoVisGroup( pObject, "Black", "World Geometry" );
  7960. continue;
  7961. }
  7962. }
  7963. }
  7964. }
  7965. else if (pObject->IsGroup())
  7966. {
  7967. // Recurse into the children of groups.
  7968. const CMapObjectList *pChildren = pObject->GetChildren();
  7969. FOR_EACH_OBJ( *pChildren, pos )
  7970. {
  7971. AddToAutoVisGroup(pChildren->Element(pos));
  7972. AddToFGDAutoVisGroups( pChildren->Element( pos ) );
  7973. }
  7974. }
  7975. // See if this Object type exists in FGD AutoVisGroups
  7976. if ( pGD->m_FGDAutoVisGroups.Count() > 0 && !( pObject->IsGroup() ) )
  7977. {
  7978. AddToFGDAutoVisGroups( pObject );
  7979. }
  7980. }
  7981. //-----------------------------------------------------------------------------
  7982. // Purpose:
  7983. // Input : *pObject -
  7984. //-----------------------------------------------------------------------------
  7985. void CMapDoc::AddToAutoVisGroup( CMapClass *pObject, const char *pAutoVisGroup )
  7986. {
  7987. CVisGroup *pRootVisGroup = GetRootAutoVisGroup();
  7988. // Find the desired visgroup
  7989. CVisGroup *pFoundVisGroup = NULL;
  7990. int nVisGroupCount = pRootVisGroup->GetChildCount();
  7991. for ( int i = 0; i < nVisGroupCount; ++i )
  7992. {
  7993. CVisGroup *pVisGroup = pRootVisGroup->GetChild(i);
  7994. if ( !Q_stricmp( pAutoVisGroup, pVisGroup->GetName() ) )
  7995. {
  7996. pFoundVisGroup = pVisGroup;
  7997. break;
  7998. }
  7999. }
  8000. if ( !pFoundVisGroup )
  8001. {
  8002. pFoundVisGroup = VisGroups_AddGroup( pAutoVisGroup, true );
  8003. VisGroups_SetParent( pFoundVisGroup, pRootVisGroup );
  8004. }
  8005. CMapObjectList Objects;
  8006. Objects.AddToTail( pObject );
  8007. VisGroups_AddObjectsToVisGroup( Objects, pFoundVisGroup, false, false );
  8008. }
  8009. //-----------------------------------------------------------------------------
  8010. // Purpose:
  8011. // Input : *pObject -
  8012. //-----------------------------------------------------------------------------
  8013. void CMapDoc::AddChildGroupToAutoVisGroup( CMapClass *pObject, const char *pAutoVisGroup, const char *pParentName )
  8014. {
  8015. CVisGroup *pRootVisGroup = VisGroups_GroupForName( pParentName, true );
  8016. if ( !pRootVisGroup )
  8017. {
  8018. CVisGroup *pRootAutoVisGroup = GetRootAutoVisGroup();
  8019. pRootVisGroup = VisGroups_AddGroup( pParentName, true );
  8020. VisGroups_SetParent( pRootVisGroup, pRootAutoVisGroup );
  8021. }
  8022. // Find the desired visgroup
  8023. CVisGroup *pFoundVisGroup = NULL;
  8024. int nVisGroupCount = pRootVisGroup->GetChildCount();
  8025. for ( int i = 0; i < nVisGroupCount; ++i )
  8026. {
  8027. CVisGroup *pVisGroup = pRootVisGroup->GetChild(i);
  8028. if ( !Q_stricmp( pAutoVisGroup, pVisGroup->GetName() ) )//&& pVisGroup->IsAutoVisGroup() )
  8029. {
  8030. pFoundVisGroup = pVisGroup;
  8031. break;
  8032. }
  8033. }
  8034. if ( !pFoundVisGroup )
  8035. {
  8036. pFoundVisGroup = VisGroups_AddGroup( pAutoVisGroup, true );
  8037. VisGroups_SetParent( pFoundVisGroup, pRootVisGroup );
  8038. }
  8039. CMapObjectList Objects;
  8040. Objects.AddToTail( pObject );
  8041. VisGroups_AddObjectsToVisGroup( Objects, pFoundVisGroup, false, false );
  8042. }
  8043. // Remove from all auto visgroup
  8044. //-----------------------------------------------------------------------------
  8045. void CMapDoc::RemoveFromAutoVisGroups( CMapClass *pObject )
  8046. {
  8047. if ( !pObject )
  8048. return;
  8049. bool bChanged = false;
  8050. int nVisGroupCount = pObject->GetVisGroupCount();
  8051. for (int nVisGroup = nVisGroupCount - 1; nVisGroup >= 0; nVisGroup--)
  8052. {
  8053. CVisGroup *pVisGroup = pObject->GetVisGroup(nVisGroup);
  8054. // Don't add autovisgroups when moving back
  8055. if ( pVisGroup->IsAutoVisGroup() )
  8056. {
  8057. pObject->RemoveVisGroup(pVisGroup);
  8058. bChanged = true;
  8059. }
  8060. }
  8061. if ( bChanged )
  8062. {
  8063. UpdateVisibility(pObject);
  8064. }
  8065. }
  8066. //-----------------------------------------------------------------------------
  8067. // Determine visgroup
  8068. //-----------------------------------------------------------------------------
  8069. void CMapDoc::AssignAllToAutoVisGroups()
  8070. {
  8071. bool bLocked = VisGroups_LockUpdates( true );
  8072. EnumChildrenPos_t pos;
  8073. CMapClass *pChild = m_pWorld->GetFirstDescendent(pos);
  8074. while (pChild)
  8075. {
  8076. AddToAutoVisGroup( pChild );
  8077. pChild = m_pWorld->GetNextDescendent(pos);
  8078. }
  8079. if ( bLocked )
  8080. {
  8081. VisGroups_LockUpdates( false );
  8082. }
  8083. }
  8084. //-----------------------------------------------------------------------------
  8085. // Purpose: Adds an object to the world. This is the ONLY correct way to add an
  8086. // object to the world. Calling directly through AddChild skips a bunch
  8087. // of necessary bookkeeping.
  8088. // Input : pObject - object being added to the world.
  8089. //-----------------------------------------------------------------------------
  8090. void CMapDoc::AddObjectToWorld(CMapClass *pObject, CMapClass *pParent)
  8091. {
  8092. Assert(pObject != NULL);
  8093. if (pObject != NULL)
  8094. {
  8095. m_pWorld->AddObjectToWorld(pObject, pParent);
  8096. // Auto visgroups!
  8097. AddToAutoVisGroup( pObject );
  8098. //
  8099. // Give the renderer a chance to precache data.
  8100. //
  8101. RenderPreloadObject(pObject);
  8102. //
  8103. // Update the object's visibility. This will recurse into solid children of entities as well.
  8104. //
  8105. UpdateVisibility(pObject);
  8106. // Set a reasonable default
  8107. Vector2D vecLogicalPos = pObject->GetLogicalPosition();
  8108. if ( vecLogicalPos.x == COORD_NOTINIT )
  8109. {
  8110. GetDefaultNewLogicalPosition( vecLogicalPos );
  8111. pObject->SetLogicalPosition( vecLogicalPos );
  8112. }
  8113. }
  8114. }
  8115. //-----------------------------------------------------------------------------
  8116. // Purpose: Removes an object from the world object tree.
  8117. // Input : pObject - object being removed from the world.
  8118. //-----------------------------------------------------------------------------
  8119. void CMapDoc::RemoveObjectFromWorld(CMapClass *pObject, bool bRemoveChildren)
  8120. {
  8121. Assert(pObject != NULL);
  8122. if (pObject != NULL)
  8123. {
  8124. m_pWorld->RemoveObjectFromWorld(pObject, bRemoveChildren);
  8125. //
  8126. // Clean up any visgroups with no members.
  8127. //
  8128. VisGroups_PurgeGroups();
  8129. // Remove the object from the update list.
  8130. m_UpdateList.FindAndRemove(pObject);
  8131. // remove object from selection list
  8132. m_pSelection->SelectObject(pObject, scUnselect );
  8133. pObject->SignalChanged();
  8134. }
  8135. }
  8136. //-----------------------------------------------------------------------------
  8137. // Purpose:
  8138. // Input : pObject -
  8139. //-----------------------------------------------------------------------------
  8140. void CMapDoc::RenderPreloadObject(CMapClass *pObject)
  8141. {
  8142. POSITION p = GetFirstViewPosition();
  8143. while (p)
  8144. {
  8145. CView *pView = GetNextView(p);
  8146. if (pView->IsKindOf(RUNTIME_CLASS(CMapView3D)))
  8147. {
  8148. CMapView3D *pView3D = (CMapView3D *)pView;
  8149. pView3D->RenderPreloadObject(pObject);
  8150. }
  8151. }
  8152. }
  8153. //-----------------------------------------------------------------------------
  8154. // Purpose: CreateTempWorld creates a world with the brushes that make up the
  8155. // cordoned area. it does this by creating a solid of the size of the
  8156. // box, and another solid 1200 units bigger. subtract A from B, and
  8157. // keep those brushes.
  8158. // Output : Returns a pointer to the newly-created world.
  8159. //-----------------------------------------------------------------------------
  8160. CMapWorld *CMapDoc::CordonCreateWorld()
  8161. {
  8162. CMapWorld *pWorld = new CMapWorld( NULL );
  8163. GetHistory()->Pause();
  8164. // create solids
  8165. CMapSolid *pBigSolid = new CMapSolid;
  8166. pBigSolid->SetCordonBrush( true );
  8167. CMapSolid *pSmallSolid = new CMapSolid;
  8168. pSmallSolid->SetCordonBrush( true );
  8169. BoundBox bigbounds( m_vCordonMins, m_vCordonMaxs );
  8170. StockBlock box;
  8171. box.SetFromBox( &bigbounds );
  8172. box.CreateMapSolid(pSmallSolid, Options.GetTextureAlignment());
  8173. // make bigger box
  8174. for (int i = 0; i < 3; i++)
  8175. {
  8176. // dvs: FIXME: vbsp barfs if I go all the way out to the full mins & maxs
  8177. bigbounds.bmins[i] = g_MIN_MAP_COORD + 8;
  8178. if (bigbounds.bmins[i] > m_vCordonMins[i])
  8179. {
  8180. bigbounds.bmins[i] = g_MIN_MAP_COORD;
  8181. }
  8182. bigbounds.bmaxs[i] = g_MAX_MAP_COORD - 8;
  8183. if (bigbounds.bmaxs[i] < m_vCordonMaxs[i])
  8184. {
  8185. bigbounds.bmaxs[i] = g_MAX_MAP_COORD;
  8186. }
  8187. }
  8188. box.SetFromBox(&bigbounds);
  8189. box.CreateMapSolid(pBigSolid, Options.GetTextureAlignment());
  8190. //
  8191. // Subtract the small box from the large box and add the outside pieces to the
  8192. // cordon world. This gives a hollow box.
  8193. //
  8194. CMapObjectList Outside;
  8195. pBigSolid->Subtract(NULL, &Outside, pSmallSolid);
  8196. for (int p=0;p<Outside.Count();p++)
  8197. {
  8198. CMapClass *pObject = Outside.Element(p);
  8199. pWorld->AddObjectToWorld(pObject);
  8200. }
  8201. delete pBigSolid;
  8202. delete pSmallSolid;
  8203. //
  8204. // Set all the brush textures to the texture specified in the options.
  8205. //
  8206. const char *pszTexture = g_pGameConfig->GetCordonTexture();
  8207. EnumChildrenPos_t pos;
  8208. CMapClass *pChild = pWorld->GetFirstDescendent(pos);
  8209. while (pChild != NULL)
  8210. {
  8211. CMapSolid *pSolid = dynamic_cast<CMapSolid *>(pChild);
  8212. if (pSolid != NULL)
  8213. {
  8214. pSolid->SetCordonBrush(true);
  8215. pSolid->SetTexture(pszTexture);
  8216. }
  8217. pChild = pWorld->GetNextDescendent(pos);
  8218. }
  8219. GetHistory()->Resume();
  8220. return(pWorld);
  8221. }
  8222. //-----------------------------------------------------------------------------
  8223. // Purpose:
  8224. // Input : *pFile -
  8225. // Output : ChunkFileResult_t
  8226. //-----------------------------------------------------------------------------
  8227. ChunkFileResult_t CMapDoc::CordonSaveVMF(CChunkFile *pFile, CSaveInfo *pSaveInfo)
  8228. {
  8229. ChunkFileResult_t eResult = pFile->BeginChunk("cordon");
  8230. if (eResult == ChunkFile_Ok)
  8231. {
  8232. eResult = pFile->WriteKeyValuePoint("mins", m_vCordonMins);
  8233. }
  8234. if (eResult == ChunkFile_Ok)
  8235. {
  8236. eResult = pFile->WriteKeyValuePoint("maxs", m_vCordonMaxs);
  8237. }
  8238. if (eResult == ChunkFile_Ok)
  8239. {
  8240. eResult = pFile->WriteKeyValueBool("active", m_bIsCordoning );
  8241. }
  8242. if (eResult == ChunkFile_Ok)
  8243. {
  8244. eResult = pFile->EndChunk();
  8245. }
  8246. return(eResult);
  8247. }
  8248. //-----------------------------------------------------------------------------
  8249. // Purpose:
  8250. // Input : *pszFileName -
  8251. //-----------------------------------------------------------------------------
  8252. bool CMapDoc::SaveVMF(const char *pszFileName, int saveFlags )
  8253. {
  8254. CChunkFile File;
  8255. ChunkFileResult_t eResult = File.Open(pszFileName, ChunkFile_Write);
  8256. BeginWaitCursor();
  8257. // Change the main title bar.
  8258. GetMainWnd()->SetWindowText( "Saving..." );
  8259. // We can optionally use these calls if we want the document name to go away so the title bar only says "Saving...".
  8260. //GetMainWnd()->ModifyStyle( FWS_ADDTOTITLE, 0 ); //GetMainWnd()->ModifyStyle( 0, FWS_ADDTOTITLE );
  8261. if (eResult == ChunkFile_Ok)
  8262. {
  8263. CSaveInfo SaveInfo;
  8264. CMapObjectList CordonList;
  8265. CMapWorld *pCordonWorld = NULL;
  8266. if (!m_bPrefab && !(saveFlags & SAVEFLAGS_LIGHTSONLY))
  8267. {
  8268. SaveInfo.SetVisiblesOnly(bSaveVisiblesOnly == TRUE);
  8269. //
  8270. // Add cordon objects.
  8271. //
  8272. if ( m_bIsCordoning )
  8273. {
  8274. //
  8275. // Create "cordon world", add its objects to our real world, create a list in
  8276. // CordonList so we can remove them again.
  8277. //
  8278. pCordonWorld = CordonCreateWorld();
  8279. const CMapObjectList *pChildren = pCordonWorld->GetChildren();
  8280. FOR_EACH_OBJ( *pChildren, pos )
  8281. {
  8282. CMapClass *pChild = pChildren->Element(pos);
  8283. pChild->SetTemporary(TRUE);
  8284. m_pWorld->AddObjectToWorld(pChild);
  8285. CordonList.AddToTail(pChild);
  8286. }
  8287. }
  8288. }
  8289. //
  8290. // Write the map file version.
  8291. //
  8292. if (eResult == ChunkFile_Ok)
  8293. {
  8294. bool bIsAutosave = false;
  8295. if ( SAVEFLAGS_AUTOSAVE & saveFlags )
  8296. {
  8297. bIsAutosave = true;
  8298. }
  8299. eResult = SaveVersionInfoVMF(&File, bIsAutosave);
  8300. }
  8301. //
  8302. // Save VisGroups information. Save this first so that we can assign visgroups while loading objects.
  8303. //
  8304. if (!m_bPrefab && !(saveFlags & SAVEFLAGS_LIGHTSONLY))
  8305. {
  8306. eResult = VisGroups_SaveVMF(&File, &SaveInfo);
  8307. }
  8308. //
  8309. // Save view related settings (grid setting, splitter proportions, etc)
  8310. //
  8311. if (eResult == ChunkFile_Ok)
  8312. {
  8313. eResult = SaveViewSettingsVMF(&File, &SaveInfo);
  8314. }
  8315. // Save the world.
  8316. if (eResult == ChunkFile_Ok)
  8317. {
  8318. eResult = m_pWorld->SaveVMF(&File, &SaveInfo, saveFlags & SAVEFLAGS_LIGHTSONLY);
  8319. }
  8320. if (!m_bPrefab && !(saveFlags & SAVEFLAGS_LIGHTSONLY))
  8321. {
  8322. //
  8323. // Remove cordon objects from the real world.
  8324. //
  8325. if ( m_bIsCordoning )
  8326. {
  8327. FOR_EACH_OBJ( CordonList, pos )
  8328. {
  8329. CMapClass *pobj = CordonList.Element(pos);
  8330. m_pWorld->RemoveObjectFromWorld(pobj, true);
  8331. }
  8332. //
  8333. // The cordon objects will be deleted in the cordon world's destructor.
  8334. //
  8335. delete pCordonWorld;
  8336. }
  8337. // Save tool information.
  8338. if (eResult == ChunkFile_Ok)
  8339. {
  8340. eResult = m_pToolManager->SaveVMF(&File, &SaveInfo);
  8341. }
  8342. if (eResult == ChunkFile_Ok)
  8343. {
  8344. eResult = CordonSaveVMF(&File, &SaveInfo);
  8345. }
  8346. // We use this to flag VMFs checked-in to P4 with QuickHide active
  8347. if ( eResult == ChunkFile_Ok )
  8348. {
  8349. eResult = QuickHide_SaveVMF( &File, &SaveInfo );
  8350. }
  8351. }
  8352. File.Close();
  8353. }
  8354. // Restore the main window's title.
  8355. GetMainWnd()->OnUpdateFrameTitle( true );
  8356. if (eResult != ChunkFile_Ok)
  8357. {
  8358. GetMainWnd()->MessageBox(File.GetErrorText(eResult), "Error Saving File", MB_OK);
  8359. }
  8360. else
  8361. {
  8362. //save filename into registry for last known good file for crash recovery purposes.
  8363. AfxGetApp()->WriteProfileString("General", "Last Good Save", pszFileName);
  8364. }
  8365. EndWaitCursor();
  8366. return( eResult == ChunkFile_Ok );
  8367. }
  8368. //-----------------------------------------------------------------------------
  8369. // Purpose: Saves the version information chunk.
  8370. // Input : *pFile -
  8371. // Output : Returns ChunkFile_Ok on success, an error code on failure.
  8372. //-----------------------------------------------------------------------------
  8373. ChunkFileResult_t CMapDoc::SaveVersionInfoVMF(CChunkFile *pFile, bool bIsAutoSave)
  8374. {
  8375. ChunkFileResult_t eResult = pFile->BeginChunk("versioninfo");
  8376. if (eResult == ChunkFile_Ok)
  8377. {
  8378. eResult = pFile->WriteKeyValueInt("editorversion", 400);
  8379. }
  8380. if (eResult == ChunkFile_Ok)
  8381. {
  8382. eResult = pFile->WriteKeyValueInt("editorbuild", build_number());
  8383. }
  8384. if (eResult == ChunkFile_Ok)
  8385. {
  8386. eResult = pFile->WriteKeyValueInt("mapversion", GetDocVersion());
  8387. }
  8388. if (eResult == ChunkFile_Ok)
  8389. {
  8390. eResult = pFile->WriteKeyValueInt("formatversion", VMF_FORMAT_VERSION);
  8391. }
  8392. if (eResult == ChunkFile_Ok)
  8393. {
  8394. eResult = pFile->WriteKeyValueBool("prefab", m_bPrefab);
  8395. }
  8396. if ( eResult == ChunkFile_Ok && bIsAutoSave )
  8397. {
  8398. eResult = pFile->BeginChunk("autosave");
  8399. if ( eResult == ChunkFile_Ok )
  8400. {
  8401. char szOriginalName[MAX_PATH];
  8402. V_strcpy_safe( szOriginalName, GetPathName() );
  8403. if ( strlen( szOriginalName ) == 0 )
  8404. {
  8405. strcpy(szOriginalName, g_pGameConfig->szMapDir);
  8406. strcat(szOriginalName, "\\untitled.vmf");
  8407. //put in the default map path + untitled.vmf
  8408. }
  8409. Q_FixSlashes( szOriginalName, '/' );
  8410. eResult = pFile->WriteKeyValue( "originalname", szOriginalName );
  8411. if ( eResult == ChunkFile_Ok )
  8412. {
  8413. eResult = pFile->EndChunk();
  8414. }
  8415. }
  8416. }
  8417. if (eResult == ChunkFile_Ok)
  8418. {
  8419. eResult = pFile->EndChunk();
  8420. }
  8421. return(eResult);
  8422. }
  8423. //-----------------------------------------------------------------------------
  8424. // Purpose: Call this function after you have made any modifications to the document.
  8425. // By calling this function consistently, you ensure that the framework
  8426. // prompts the user to save changes before closing a document.
  8427. // Input : bModified - TRUE to mark the doc as modified, FALSE to mark it as clean.
  8428. //-----------------------------------------------------------------------------
  8429. void CMapDoc::SetModifiedFlag(BOOL bModified)
  8430. {
  8431. //
  8432. // Increment internal version number when the doc changes from clean to dirty.
  8433. // CShell::BeginSession checks this version number, enabling us to detect
  8434. // out-of-sync problems when editing the map in the engine.
  8435. //
  8436. if ((bModified) && !IsModified())
  8437. {
  8438. m_nDocVersion++;
  8439. }
  8440. if ( bModified )
  8441. {
  8442. SetAutosaveFlag( bModified );
  8443. m_pSelection->SetBoundsDirty();
  8444. GetMainWnd()->pObjectProperties->MarkDataDirty();
  8445. UpdateAllViews( MAPVIEW_UPDATE_OBJECTS );
  8446. }
  8447. CDocument::SetModifiedFlag(bModified);
  8448. }
  8449. void CMapDoc::SetAutosaveFlag( BOOL bNeedsAutosave )
  8450. {
  8451. m_bNeedsAutosave = bNeedsAutosave;
  8452. }
  8453. BOOL CMapDoc::NeedsAutosave()
  8454. {
  8455. return m_bNeedsAutosave;
  8456. }
  8457. BOOL CMapDoc::IsAutosave()
  8458. {
  8459. return m_bIsAutosave;
  8460. }
  8461. CString *CMapDoc::AutosavedFrom()
  8462. {
  8463. return &m_strAutosavedFrom;
  8464. }
  8465. //-----------------------------------------------------------------------------
  8466. // Purpose: this function adds an external reference count to a map
  8467. //-----------------------------------------------------------------------------
  8468. void CMapDoc::AddReference( void )
  8469. {
  8470. m_nExternalReferenceCount++;
  8471. }
  8472. //-----------------------------------------------------------------------------
  8473. // Purpose: this function removes an external reference count from a map. If it is hidden
  8474. // and modified, the document will be made visible.
  8475. //-----------------------------------------------------------------------------
  8476. void CMapDoc::RemoveReference( void )
  8477. {
  8478. m_nExternalReferenceCount--;
  8479. if ( m_nExternalReferenceCount <= 0 )
  8480. {
  8481. if ( !IsVisible() )
  8482. {
  8483. if ( IsModified() )
  8484. {
  8485. ShowWindow( true );
  8486. }
  8487. else
  8488. {
  8489. OnCloseDocument();
  8490. }
  8491. }
  8492. }
  8493. }
  8494. //-----------------------------------------------------------------------------
  8495. // Purpose:
  8496. // Input : bActive -
  8497. //-----------------------------------------------------------------------------
  8498. void CMapDoc::SetUndoActive(bool bActive)
  8499. {
  8500. m_pUndo->SetActive(bActive);
  8501. m_pRedo->SetActive(bActive);
  8502. }
  8503. bool CMapDoc::IsCulledBy3DCameraDistance( CMapClass *pObject, UpdateVisibilityData_t *pData )
  8504. {
  8505. if ( pObject->IsWorld() || pObject->IsGroup() )
  8506. return false;
  8507. if ( pObject->IsSelected() )
  8508. return false;
  8509. Vector objectPos;
  8510. pObject->GetOrigin( objectPos );
  8511. float flDistance = ( pData->vecRadiusCullCenter - objectPos ).LengthSqr();
  8512. if ( flDistance >= pData->flRadiusCullDistSq )
  8513. return true;
  8514. return false;
  8515. }
  8516. //-----------------------------------------------------------------------------
  8517. // Purpose: Returns the hidden/shown state of the given object based on the current
  8518. // settings including selection mode, visgroups, and cordon bounds.
  8519. // Input : pObject -
  8520. //-----------------------------------------------------------------------------
  8521. bool CMapDoc::ShouldObjectBeVisible(CMapClass *pObject, UpdateVisibilityData_t *pData)
  8522. {
  8523. #if defined(_DEBUG) && 0
  8524. CMapEntity *pEntity = dynamic_cast<CMapEntity *>(pObject);
  8525. if (pEntity)
  8526. {
  8527. LPCTSTR pszTargetName = pEntity->GetKeyValue("targetname");
  8528. if ( pszTargetName && !strcmp(pszTargetName, "relay_cancelVCDs") )
  8529. {
  8530. // Set breakpoint here for debugging this entity's visiblity
  8531. int foo = 0;
  8532. }
  8533. }
  8534. #endif
  8535. if ( QuickHide_IsObjectHidden( pObject ) )
  8536. {
  8537. return false;
  8538. }
  8539. if ( pData->bRadiusCullingEnabled )
  8540. {
  8541. if ( IsCulledBy3DCameraDistance( pObject, pData ) )
  8542. {
  8543. return false;
  8544. }
  8545. }
  8546. //
  8547. // If hide entities is enabled and the object is an entity, hide the object.
  8548. //
  8549. if (m_bHideItems)
  8550. {
  8551. CMapEntity *pEntity = dynamic_cast<CMapEntity *>(pObject);
  8552. if ((pEntity != NULL) && (pEntity->IsPlaceholder()))
  8553. {
  8554. return(false);
  8555. }
  8556. }
  8557. //
  8558. // If the object hides as clutter and clutter is currently hidden, hide it.
  8559. //
  8560. if (pObject->IsClutter() && !Options.GetShowHelpers() )
  8561. {
  8562. return false;
  8563. }
  8564. //
  8565. // If the object was hidden by visgroups, hide it unless visgroup hiding is disabled.
  8566. //
  8567. if (!CVisGroup::IsShowAllActive() && !pObject->IsVisGroupShown())
  8568. {
  8569. return false;
  8570. }
  8571. //
  8572. // If the cordon tool is active and the object is not within the cordon bounds,
  8573. // hide the object. The exception to this is some helpers, which only hide if their
  8574. // parent entity is culled by the cordon.
  8575. //
  8576. if ( m_bIsCordoning && !IsManifest() )
  8577. {
  8578. if (pObject->IsCulledByCordon(m_vCordonMins, m_vCordonMaxs))
  8579. {
  8580. return(false);
  8581. }
  8582. }
  8583. return(true);
  8584. }
  8585. //-----------------------------------------------------------------------------
  8586. // Purpose: Notifies the document when an object has changed. The object is
  8587. // added to a list which will be processed before the next view is rendered.
  8588. // Input : pObject - Object that has changed.
  8589. //-----------------------------------------------------------------------------
  8590. void CMapDoc::UpdateObject(CMapClass *pObject)
  8591. {
  8592. Assert(!pObject->IsTemporary());
  8593. if ( m_UpdateList.Find(pObject) == -1)
  8594. {
  8595. m_UpdateList.AddToTail(pObject);
  8596. }
  8597. UpdateAllViews( MAPVIEW_UPDATE_OBJECTS );
  8598. }
  8599. //-----------------------------------------------------------------------------
  8600. // Purpose: Processes any objects that have changed since the last call.
  8601. // Updates each object's visiblity and makes sure that there are no
  8602. // invisible objects in the selection set.
  8603. //
  8604. // This must be called from the outer loop, as selection.RemoveInvisibles
  8605. // may change the contents of the selection. Therefore, this should never
  8606. // be called from low-level code that might be inside an iteration of the
  8607. // selection.
  8608. //-----------------------------------------------------------------------------
  8609. void CMapDoc::Update(void)
  8610. {
  8611. ProcessNotifyList();
  8612. if (m_UpdateList.Count()>0)
  8613. {
  8614. //
  8615. // Process every object in the update list.
  8616. //
  8617. FOR_EACH_OBJ( m_UpdateList, pos )
  8618. {
  8619. CMapClass *pObject = m_UpdateList.Element(pos);
  8620. UpdateVisibility(pObject);
  8621. }
  8622. //
  8623. // Make sure there aren't any invisible objects in the selection.
  8624. //
  8625. m_pSelection->RemoveInvisibles();
  8626. //
  8627. // Empty the update list now that it has been processed.
  8628. //
  8629. m_UpdateList.RemoveAll();
  8630. }
  8631. }
  8632. //-----------------------------------------------------------------------------
  8633. // Purpose: Callback for updating the visibility status of a single object and
  8634. // its children.
  8635. // Input : pObject -
  8636. // pDoc -
  8637. //-----------------------------------------------------------------------------
  8638. BOOL CMapDoc::UpdateVisibilityCallback(CMapClass *pObject, UpdateVisibilityData_t *pData )
  8639. {
  8640. Assert(!pObject->IsTemporary());
  8641. bool bVisible = pData->pDoc->ShouldObjectBeVisible(pObject, pData);
  8642. pObject->SetVisible(bVisible);
  8643. if (bVisible)
  8644. {
  8645. //
  8646. // If this is an entity and it is visible, recurse into any children.
  8647. //
  8648. if ( ( dynamic_cast< CMapEntity * >( pObject ) ) != NULL || ( dynamic_cast< CMapWorld * >( pObject ) ) != NULL )
  8649. {
  8650. pObject->EnumChildren((ENUMMAPCHILDRENPROC)UpdateVisibilityCallback, (DWORD)pData);
  8651. }
  8652. }
  8653. return(TRUE);
  8654. }
  8655. void CMapDoc::InitUpdateVisibilityData( UpdateVisibilityData_t &data )
  8656. {
  8657. memset( &data, 0, sizeof( data ) );
  8658. data.pDoc = this;
  8659. data.bRadiusCullingEnabled = ( Options.general.bRadiusCulling == TRUE );
  8660. if ( data.bRadiusCullingEnabled )
  8661. {
  8662. POSITION viewpos = GetFirstViewPosition();
  8663. while ( viewpos )
  8664. {
  8665. CMapView3D *pView = dynamic_cast<CMapView3D*>( GetNextView( viewpos ) );
  8666. if ( pView )
  8667. {
  8668. CCamera *pCamera = pView->GetCamera();
  8669. if ( pCamera )
  8670. {
  8671. pCamera->GetViewPoint( data.vecRadiusCullCenter );
  8672. data.flRadiusCullDistSq = pCamera->GetFarClip();
  8673. data.flRadiusCullDistSq *= data.flRadiusCullDistSq;
  8674. return;
  8675. }
  8676. }
  8677. }
  8678. // Can't use radius culling without a 3D view.
  8679. data.bRadiusCullingEnabled = false;
  8680. }
  8681. };
  8682. //-----------------------------------------------------------------------------
  8683. // Purpose: Updates the visibility of the given object and its children.
  8684. // Input : pObject -
  8685. //-----------------------------------------------------------------------------
  8686. void CMapDoc::UpdateVisibility(CMapClass *pObject)
  8687. {
  8688. UpdateVisibilityData_t data;
  8689. InitUpdateVisibilityData( data );
  8690. UpdateVisibilityCallback(pObject, &data);
  8691. if (pObject->IsGroup())
  8692. {
  8693. pObject->EnumChildrenRecurseGroupsOnly((ENUMMAPCHILDRENPROC)UpdateVisibilityCallback, (DWORD)&data);
  8694. }
  8695. }
  8696. //-----------------------------------------------------------------------------
  8697. // Purpose: Updates the visibility of all objects in the world.
  8698. //-----------------------------------------------------------------------------
  8699. void CMapDoc::UpdateVisibilityAll(void)
  8700. {
  8701. UpdateVisibilityData_t data;
  8702. InitUpdateVisibilityData( data );
  8703. //
  8704. // Two stage recursion: first we recurse groups only, then from the callback we recurse
  8705. // solid children of entities.
  8706. //
  8707. m_pWorld->EnumChildrenRecurseGroupsOnly((ENUMMAPCHILDRENPROC)UpdateVisibilityCallback, (DWORD)&data);
  8708. m_pSelection->RemoveInvisibles();
  8709. CMainFrame *pwndMain = GetMainWnd();
  8710. if (pwndMain)
  8711. {
  8712. pwndMain->UpdateAllDocViews( MAPVIEW_UPDATE_VISGROUP_STATE );
  8713. // Some entity I/O connections may have become valid/invalid after this hide/show.
  8714. pwndMain->pObjectProperties->MarkDataDirty();
  8715. }
  8716. }
  8717. //-----------------------------------------------------------------------------
  8718. // Purpose: Adds a visgroup to this document.
  8719. // Input : pszName - The name to assign the visgroup
  8720. // bAuto - should this be an auto visgroup (default: false)
  8721. // Output : Returns a pointer to the newly created visgroup.
  8722. //-----------------------------------------------------------------------------
  8723. CVisGroup *CMapDoc::VisGroups_AddGroup(LPCTSTR pszName, bool bAuto)
  8724. {
  8725. CVisGroup *pGroup = new CVisGroup;
  8726. pGroup->SetName(pszName);
  8727. pGroup->SetAuto( bAuto );
  8728. //
  8729. // Generate a random color for the group.
  8730. //
  8731. pGroup->SetColor(80 + (random() % 176), 80 + (random() % 176), 80 + (random() % 176));
  8732. //
  8733. // Generate a unique id for this visgroup.
  8734. //
  8735. int id = 0;
  8736. while (id++ < 2000)
  8737. {
  8738. if (!VisGroups_GroupForID(id))
  8739. {
  8740. break;
  8741. }
  8742. }
  8743. pGroup->SetID(id);
  8744. return VisGroups_AddGroup(pGroup);
  8745. }
  8746. //-----------------------------------------------------------------------------
  8747. // Purpose: Adds a visgroup to this document.
  8748. // Input : pGroup - Visgroup to add.
  8749. // Output : Returns a pointer to the given visgroup.
  8750. //-----------------------------------------------------------------------------
  8751. CVisGroup *CMapDoc::VisGroups_AddGroup(CVisGroup *pGroup)
  8752. {
  8753. Assert( pGroup != NULL );
  8754. m_VisGroups->AddToTail(pGroup);
  8755. if (!pGroup->GetParent())
  8756. {
  8757. m_RootVisGroups->AddToTail(pGroup);
  8758. }
  8759. return pGroup;
  8760. }
  8761. //-----------------------------------------------------------------------------
  8762. // Purpose:
  8763. //-----------------------------------------------------------------------------
  8764. bool CMapDoc::VisGroups_CanMoveUp(CVisGroup *pGroup)
  8765. {
  8766. CVisGroup *pParent = pGroup->GetParent();
  8767. if (pParent)
  8768. {
  8769. return pParent->CanMoveUp(pGroup);
  8770. }
  8771. else
  8772. {
  8773. return (m_RootVisGroups->Find(pGroup) > 0);
  8774. }
  8775. }
  8776. //-----------------------------------------------------------------------------
  8777. // Purpose:
  8778. //-----------------------------------------------------------------------------
  8779. bool CMapDoc::VisGroups_CanMoveDown(CVisGroup *pGroup)
  8780. {
  8781. CVisGroup *pParent = pGroup->GetParent();
  8782. if (pParent)
  8783. {
  8784. return pParent->CanMoveDown(pGroup);
  8785. }
  8786. else
  8787. {
  8788. int nIndex = m_RootVisGroups->Find(pGroup);
  8789. return (nIndex >= 0) && (nIndex < m_RootVisGroups->Count() - 1);
  8790. }
  8791. }
  8792. //-----------------------------------------------------------------------------
  8793. // Purpose:
  8794. // Input : pObject -
  8795. // pGroup -
  8796. // Output : Returns FALSE to stop enumerating if the object belonged to the given
  8797. // visgroup. Otherwise, returns TRUE to continue enumerating.
  8798. //-----------------------------------------------------------------------------
  8799. BOOL CMapDoc::VisGroups_CheckForGroupCallback(CMapClass *pObject, CVisGroup *pGroup)
  8800. {
  8801. if (pObject->IsInVisGroup(pGroup))
  8802. {
  8803. return(FALSE);
  8804. }
  8805. return(TRUE);
  8806. }
  8807. //-----------------------------------------------------------------------------
  8808. // Purpose: Returns the number of visgroups in this document.
  8809. //-----------------------------------------------------------------------------
  8810. int CMapDoc::VisGroups_GetCount(void)
  8811. {
  8812. return(m_VisGroups->Count());
  8813. }
  8814. //-----------------------------------------------------------------------------
  8815. // Purpose: Returns a visgroup by index.
  8816. //-----------------------------------------------------------------------------
  8817. CVisGroup *CMapDoc::VisGroups_GetVisGroup(int nIndex)
  8818. {
  8819. return(m_VisGroups->Element(nIndex));
  8820. }
  8821. //-----------------------------------------------------------------------------
  8822. // Purpose: Returns the number of root-level visgroups in this document.
  8823. //-----------------------------------------------------------------------------
  8824. int CMapDoc::VisGroups_GetRootCount(void)
  8825. {
  8826. if ( m_RootVisGroups )
  8827. {
  8828. return( m_RootVisGroups->Count() );
  8829. }
  8830. return 0;
  8831. }
  8832. //-----------------------------------------------------------------------------
  8833. // Purpose: Returns a root-level visgroup by index.
  8834. //-----------------------------------------------------------------------------
  8835. CVisGroup *CMapDoc::VisGroups_GetRootVisGroup(int nIndex)
  8836. {
  8837. return(m_RootVisGroups->Element(nIndex));
  8838. }
  8839. //-----------------------------------------------------------------------------
  8840. // Purpose:
  8841. // Input : pGroup -
  8842. //-----------------------------------------------------------------------------
  8843. void CMapDoc::VisGroups_MoveUp(CVisGroup *pGroup)
  8844. {
  8845. CVisGroup *pParent = pGroup->GetParent();
  8846. if (pParent)
  8847. {
  8848. pParent->MoveUp(pGroup);
  8849. }
  8850. else
  8851. {
  8852. int nIndex = m_RootVisGroups->Find(pGroup);
  8853. if (nIndex > 0)
  8854. {
  8855. m_RootVisGroups->Remove(nIndex);
  8856. m_RootVisGroups->InsertBefore(nIndex - 1, pGroup);
  8857. }
  8858. }
  8859. }
  8860. //-----------------------------------------------------------------------------
  8861. // Purpose:
  8862. // Input : pGroup -
  8863. //-----------------------------------------------------------------------------
  8864. void CMapDoc::VisGroups_MoveDown(CVisGroup *pGroup)
  8865. {
  8866. CVisGroup *pParent = pGroup->GetParent();
  8867. if (pParent)
  8868. {
  8869. pParent->MoveDown(pGroup);
  8870. }
  8871. else
  8872. {
  8873. int nIndex = m_RootVisGroups->Find(pGroup);
  8874. if (nIndex < (m_RootVisGroups->Count() - 1))
  8875. {
  8876. m_RootVisGroups->Remove(nIndex);
  8877. m_RootVisGroups->InsertAfter(nIndex, pGroup);
  8878. }
  8879. }
  8880. }
  8881. //-----------------------------------------------------------------------------
  8882. // Purpose: Deletes any visgroups that no longer have any members.
  8883. //-----------------------------------------------------------------------------
  8884. void CMapDoc::VisGroups_PurgeGroups(void)
  8885. {
  8886. bool bUpdate = false;
  8887. int nCount = VisGroups_GetCount();
  8888. for (int i = nCount - 1; i >= 0; i--)
  8889. {
  8890. CVisGroup *pGroup = VisGroups_GetVisGroup(i);
  8891. // Don't purge groups with children
  8892. if ( pGroup->GetChildCount() )
  8893. continue;
  8894. bool bKill = true;
  8895. EnumChildrenPos_t pos2;
  8896. CMapClass *pObject = m_pWorld->GetFirstDescendent(pos2);
  8897. while (pObject != NULL)
  8898. {
  8899. if (pObject->IsInVisGroup(pGroup))
  8900. {
  8901. bKill = false;
  8902. break;
  8903. }
  8904. pObject = m_pWorld->GetNextDescendent(pos2);
  8905. }
  8906. if (bKill)
  8907. {
  8908. bUpdate = true;
  8909. VisGroups_UnlinkGroup(pGroup);
  8910. delete pGroup;
  8911. }
  8912. }
  8913. if (bUpdate)
  8914. {
  8915. GetMainWnd()->m_FilterControl.UpdateGroupList();
  8916. }
  8917. }
  8918. //-----------------------------------------------------------------------------
  8919. // Purpose: Removes the given visgroup from the visgroup hierarchy.
  8920. //-----------------------------------------------------------------------------
  8921. void CMapDoc::VisGroups_RemoveGroup(CVisGroup *pGroup)
  8922. {
  8923. VisGroups_DoRemoveOrCombine(pGroup, NULL);
  8924. VisGroups_UnlinkGroup(pGroup);
  8925. delete pGroup;
  8926. VisGroups_UpdateAll();
  8927. UpdateVisibilityAll();
  8928. SetModifiedFlag();
  8929. }
  8930. //-----------------------------------------------------------------------------
  8931. // Purpose: Combines two visgroups, moving member objects and child visgroups
  8932. // into the 'to' group, and deletes the 'from' group.
  8933. //-----------------------------------------------------------------------------
  8934. void CMapDoc::VisGroups_CombineGroups(CVisGroup *pFrom, CVisGroup *pTo)
  8935. {
  8936. // Can't combine a group into one of it's descendents.
  8937. Assert(!pFrom->FindDescendent(pTo));
  8938. VisGroups_DoRemoveOrCombine(pFrom, pTo);
  8939. VisGroups_UnlinkGroup(pFrom);
  8940. delete pFrom;
  8941. VisGroups_UpdateAll();
  8942. UpdateVisibilityAll();
  8943. SetModifiedFlag();
  8944. }
  8945. //-----------------------------------------------------------------------------
  8946. // Purpose: Removes the visgroup from the visgroup lists.
  8947. // Input : *pGroup -
  8948. //-----------------------------------------------------------------------------
  8949. void CMapDoc::VisGroups_UnlinkGroup(CVisGroup *pGroup)
  8950. {
  8951. m_VisGroups->FindAndRemove(pGroup);
  8952. m_RootVisGroups->FindAndRemove(pGroup);
  8953. CVisGroup *pParent = pGroup->GetParent();
  8954. if (pParent)
  8955. {
  8956. pParent->RemoveChild(pGroup);
  8957. }
  8958. GetHistory()->OnRemoveVisGroup(pGroup);
  8959. }
  8960. //-----------------------------------------------------------------------------
  8961. // Purpose: Combines two visgroups, moving member objects and child visgroups
  8962. // into the 'to' group.
  8963. // Input : pFrom -
  8964. // pTo -
  8965. //-----------------------------------------------------------------------------
  8966. void CMapDoc::VisGroups_DoRemoveOrCombine(CVisGroup *pFrom, CVisGroup *pTo)
  8967. {
  8968. if (!pFrom)
  8969. return;
  8970. //
  8971. // Replace membership in pFrom with membership in pTo.
  8972. //
  8973. CMapWorld *pWorld = GetMapWorld();
  8974. EnumChildrenPos_t pos;
  8975. CMapClass *pObject = pWorld->GetFirstDescendent(pos);
  8976. while (pObject != NULL)
  8977. {
  8978. if (pObject->IsInVisGroup(pFrom))
  8979. {
  8980. //must add the object to the new visgroup before removing from the old
  8981. //this solves the problem of incorrectly forcing visibilty when an object becomes
  8982. //temporarily orphaned.
  8983. if (pTo)
  8984. {
  8985. pObject->AddVisGroup(pTo);
  8986. }
  8987. pObject->RemoveVisGroup(pFrom);
  8988. }
  8989. pObject = pWorld->GetNextDescendent(pos);
  8990. }
  8991. if (pTo)
  8992. {
  8993. //
  8994. // Move child visgroups into pTo.
  8995. //
  8996. for (int i = 0; i < pFrom->GetChildCount(); i++)
  8997. {
  8998. CVisGroup *pChild = pFrom->GetChild(i);
  8999. pTo->AddChild(pChild);
  9000. }
  9001. //
  9002. // Make sure pTo has the proper visibility state.
  9003. //
  9004. if (pFrom->GetVisible() != pTo->GetVisible())
  9005. {
  9006. pTo->SetVisible(VISGROUP_PARTIAL);
  9007. }
  9008. }
  9009. }
  9010. //-----------------------------------------------------------------------------
  9011. // Purpose:
  9012. // Input : *pFile -
  9013. // Output : ChunkFileResult_t
  9014. //-----------------------------------------------------------------------------
  9015. ChunkFileResult_t CMapDoc::VisGroups_SaveVMF(CChunkFile *pFile, CSaveInfo *pSaveInfo)
  9016. {
  9017. if (VisGroups_GetCount() == 0)
  9018. {
  9019. return(ChunkFile_Ok);
  9020. }
  9021. ChunkFileResult_t eResult = pFile->BeginChunk("visgroups");
  9022. if (eResult == ChunkFile_Ok)
  9023. {
  9024. // Save the root level visgroups; children are saved recursively.
  9025. int nCount = VisGroups_GetRootCount();
  9026. for (int i = 0; i < nCount; i++)
  9027. {
  9028. CVisGroup *pVisGroup = this->VisGroups_GetRootVisGroup(i);
  9029. if ( pVisGroup != NULL && !pVisGroup->IsAutoVisGroup() && strcmp( pVisGroup->GetName(), "Auto" ) )
  9030. {
  9031. eResult = pVisGroup->SaveVMF(pFile, pSaveInfo);
  9032. if (eResult != ChunkFile_Ok)
  9033. {
  9034. break;
  9035. }
  9036. }
  9037. }
  9038. }
  9039. if (eResult == ChunkFile_Ok)
  9040. {
  9041. eResult = pFile->EndChunk();
  9042. }
  9043. return(eResult);
  9044. }
  9045. //-----------------------------------------------------------------------------
  9046. // Purpose:
  9047. // Input : *pFile -
  9048. // Output : ChunkFileResult_t
  9049. //-----------------------------------------------------------------------------
  9050. ChunkFileResult_t CMapDoc::SaveViewSettingsVMF(CChunkFile *pFile, CSaveInfo *pSaveInfo)
  9051. {
  9052. ChunkFileResult_t eResult = pFile->BeginChunk("viewsettings");
  9053. eResult = pFile->WriteKeyValueBool("bSnapToGrid", m_bSnapToGrid);
  9054. if (eResult != ChunkFile_Ok)
  9055. return eResult;
  9056. eResult = pFile->WriteKeyValueBool("bShowGrid", m_bShowGrid);
  9057. if (eResult != ChunkFile_Ok)
  9058. return eResult;
  9059. #ifndef SDK_BUILD
  9060. eResult = pFile->WriteKeyValueBool("bShowLogicalGrid", m_bShowLogicalGrid);
  9061. if (eResult != ChunkFile_Ok)
  9062. return eResult;
  9063. #endif // SDK_BUILD
  9064. eResult = pFile->WriteKeyValueInt("nGridSpacing", m_nGridSpacing);
  9065. if (eResult != ChunkFile_Ok)
  9066. return eResult;
  9067. eResult = pFile->WriteKeyValueBool("bShow3DGrid", m_bShow3DGrid);
  9068. if (eResult != ChunkFile_Ok)
  9069. return eResult;
  9070. return(pFile->EndChunk());
  9071. }
  9072. //-----------------------------------------------------------------------------
  9073. // Purpose: Turns on lighting preview mode by loading the BSP file with the
  9074. // same named as the VMF being edited.
  9075. //-----------------------------------------------------------------------------
  9076. void CMapDoc::InternalEnableLightPreview( bool bCustomFilename )
  9077. {
  9078. #if 0
  9079. OnDisableLightPreview();
  9080. m_pBSPLighting = CreateBSPLighting();
  9081. // Either use the VMF filename or the last-exported VMF name.
  9082. CString strFile;
  9083. if( m_strLastExportFileName.GetLength() == 0 )
  9084. strFile = GetPathName();
  9085. else
  9086. strFile = m_strLastExportFileName;
  9087. // Convert the extension to .bsp
  9088. char *p = strFile.GetBuffer(MAX_PATH);
  9089. char *ext = strrchr(p, '.');
  9090. if( ext )
  9091. {
  9092. strcpy( ext, ".bsp" );
  9093. }
  9094. // Strip out the directory.
  9095. char *cur = p;
  9096. while ((cur = strstr(cur, "/")) != NULL)
  9097. {
  9098. *cur = '\\';
  9099. }
  9100. char fileName[MAX_PATH];
  9101. char *pLastSlash = p;
  9102. char *pTest;
  9103. while ((pTest = strstr(pLastSlash, "\\")) != NULL)
  9104. {
  9105. pLastSlash = pTest + 1;
  9106. }
  9107. if( pLastSlash )
  9108. strcpy( fileName, pLastSlash );
  9109. else
  9110. strcpy( fileName, p );
  9111. strFile.ReleaseBuffer();
  9112. // Use <mod directory> + "/maps/" + <filename>
  9113. char fullPath[MAX_PATH*2];
  9114. sprintf( fullPath, "%s\\maps\\%s", g_pGameConfig->m_szModDir, fileName );
  9115. // Only do the dialog if they said to or if the default BSP file doesn't exist.
  9116. if( !bCustomFilename )
  9117. {
  9118. FILE *fp = fopen( fullPath, "rb" );
  9119. if( fp )
  9120. fclose( fp );
  9121. else
  9122. bCustomFilename = true;
  9123. }
  9124. CString finalPath;
  9125. if( bCustomFilename )
  9126. {
  9127. CFileDialog dlg(
  9128. TRUE, // bOpenFile
  9129. "bsp", // default extension
  9130. fullPath, // default filename,
  9131. OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, // flags
  9132. "BSP Files (*.bsp)|*.bsp|All Files (*.*)|*.*||",
  9133. NULL // filter
  9134. );
  9135. if( dlg.DoModal() != IDOK )
  9136. return;
  9137. finalPath = dlg.GetPathName();
  9138. }
  9139. else
  9140. {
  9141. finalPath = fullPath;
  9142. }
  9143. if( !m_pBSPLighting->Load( finalPath ) )
  9144. {
  9145. char str[256];
  9146. Q_snprintf( str, sizeof(str), "Can't load lighting from '%s'.", finalPath );
  9147. AfxMessageBox( str );
  9148. }
  9149. // Switch the first mapview we find into 3D lighting preview.
  9150. POSITION viewPos = GetFirstViewPosition();
  9151. while( viewPos )
  9152. {
  9153. CView *pView = GetNextView( viewPos );
  9154. if (pView->IsKindOf(RUNTIME_CLASS(CMapView3D)))
  9155. {
  9156. CMapView3D *pView3D = (CMapView3D *)pView;
  9157. pView3D->SetDrawType( VIEW3D_LIGHTING_PREVIEW );
  9158. break;
  9159. }
  9160. }
  9161. #endif
  9162. }
  9163. void CMapDoc::OnEnableLightPreview()
  9164. {
  9165. InternalEnableLightPreview( false );
  9166. }
  9167. void CMapDoc::OnEnableLightPreviewCustomFilename()
  9168. {
  9169. InternalEnableLightPreview( true );
  9170. }
  9171. //-----------------------------------------------------------------------------
  9172. // Purpose: Turns off lighting preview mode.
  9173. //-----------------------------------------------------------------------------
  9174. void CMapDoc::OnDisableLightPreview()
  9175. {
  9176. #if 0
  9177. // Change any light preview views back to regular 3D.
  9178. POSITION p = GetFirstViewPosition();
  9179. while (p)
  9180. {
  9181. CView *pView = GetNextView(p);
  9182. if (pView->IsKindOf(RUNTIME_CLASS(CMapView3D)))
  9183. {
  9184. CMapView3D *pView3D = (CMapView3D *)pView;
  9185. if( pView3D->GetDrawType() == VIEW3D_LIGHTING_PREVIEW )
  9186. pView3D->SetDrawType( VIEW3D_TEXTURED );
  9187. }
  9188. }
  9189. if( m_pBSPLighting )
  9190. {
  9191. m_pBSPLighting->Release();
  9192. m_pBSPLighting = 0;
  9193. }
  9194. #endif
  9195. }
  9196. void CMapDoc::OnUpdateLightPreview()
  9197. {
  9198. if( !m_pBSPLighting )
  9199. return;
  9200. // Save out a file with just the ents.
  9201. char szFile[MAX_PATH];
  9202. V_strcpy_safe( szFile, GetPathName() );
  9203. szFile[strlen(szFile) - 1] = 'e';
  9204. if( !SaveVMF( szFile, SAVEFLAGS_LIGHTSONLY ) )
  9205. {
  9206. CString str;
  9207. str.FormatMessage( IDS_CANT_SAVE_ENTS_FILE, szFile );
  9208. return;
  9209. }
  9210. // Get it in memory.
  9211. CUtlVector<char> fileData;
  9212. FILE *fp = fopen( szFile, "rb" );
  9213. if( !fp )
  9214. {
  9215. CString str;
  9216. str.FormatMessage( IDS_CANT_OPEN_ENTS_FILE, szFile );
  9217. AfxMessageBox( str, MB_OK );
  9218. return;
  9219. }
  9220. fseek( fp, 0, SEEK_END );
  9221. fileData.SetSize( ftell( fp ) + 1 );
  9222. fseek( fp, 0, SEEK_SET );
  9223. fread( fileData.Base(), 1, fileData.Count(), fp );
  9224. fclose( fp );
  9225. // Null-terminate it.
  9226. fileData[ fileData.Count() - 1 ] = 0;
  9227. // Tell the incremental lighting manager to relight.
  9228. m_pBSPLighting->StartLighting( fileData.Base() );
  9229. }
  9230. //-----------------------------------------------------------------------------
  9231. // Purpose:
  9232. //-----------------------------------------------------------------------------
  9233. void CMapDoc::OnToggleLightPreview()
  9234. {
  9235. #if 0
  9236. if( m_pBSPLighting )
  9237. {
  9238. POSITION p = GetFirstViewPosition();
  9239. while (p)
  9240. {
  9241. CView *pView = GetNextView(p);
  9242. if (pView->IsKindOf(RUNTIME_CLASS(CMapView3D)))
  9243. {
  9244. CMapView3D *pView3D = (CMapView3D *)pView;
  9245. if( pView3D->GetDrawType() == VIEW3D_LIGHTING_PREVIEW )
  9246. pView3D->SetDrawType( VIEW3D_TEXTURED );
  9247. else if( pView3D->GetDrawType() == VIEW3D_TEXTURED )
  9248. pView3D->SetDrawType( VIEW3D_LIGHTING_PREVIEW );
  9249. }
  9250. }
  9251. }
  9252. else
  9253. {
  9254. // If no lighting is loaded, then load it.
  9255. OnEnableLightPreview();
  9256. }
  9257. #endif
  9258. }
  9259. void CMapDoc::OnAbortLightCalculation()
  9260. {
  9261. if( !m_pBSPLighting )
  9262. return;
  9263. m_pBSPLighting->Interrupt();
  9264. }
  9265. //-----------------------------------------------------------------------------
  9266. // Used to avoid adding redundant notifications to the list.
  9267. //-----------------------------------------------------------------------------
  9268. bool CMapDoc::FindNotification(CMapClass *pObject, Notify_Dependent_t eNotifyType)
  9269. {
  9270. int nCount = m_NotifyList.Count();
  9271. for (int i = 0; i < nCount; i++)
  9272. {
  9273. if ((m_NotifyList.Element(i).pObject->m_pObject == pObject) &&
  9274. (m_NotifyList.Element(i).eNotifyType == eNotifyType))
  9275. {
  9276. return true;
  9277. }
  9278. }
  9279. return false;
  9280. }
  9281. bool CMapDoc::AnyNotificationsForObject(CMapClass *pObject)
  9282. {
  9283. int nCount = m_NotifyList.Count();
  9284. for (int i = 0; i < nCount; i++)
  9285. {
  9286. if ( m_NotifyList.Element(i).pObject->m_pObject == pObject )
  9287. return true;
  9288. }
  9289. return false;
  9290. }
  9291. //-----------------------------------------------------------------------------
  9292. // Purpose: Adds the notification event to the list for processing.
  9293. // Input : pObject -
  9294. // eNotifyType -
  9295. //-----------------------------------------------------------------------------
  9296. static bool s_bDispatchingNotifications = false;
  9297. void CMapDoc::NotifyDependents(CMapClass *pObject, Notify_Dependent_t eNotifyType)
  9298. {
  9299. Assert( !s_bDispatchingNotifications );
  9300. if ( s_bDispatchingNotifications )
  9301. return;
  9302. if (pObject->IsTemporary())
  9303. {
  9304. return;
  9305. }
  9306. if (eNotifyType != Notify_Removed)
  9307. {
  9308. if (!FindNotification(pObject, eNotifyType))
  9309. {
  9310. NotifyListEntry_t entry;
  9311. entry.pObject = pObject->GetSafeObjectSmartPtr();
  9312. entry.eNotifyType = eNotifyType;
  9313. m_NotifyList.AddToTail(entry);
  9314. }
  9315. }
  9316. else
  9317. {
  9318. DispatchNotifyDependents(pObject, eNotifyType);
  9319. }
  9320. }
  9321. //-----------------------------------------------------------------------------
  9322. // Dispatches notifications to dependent objects. Called once per frame, this
  9323. // allows objects to update themselves based on changes made to other objects
  9324. // before they are rendered.
  9325. //-----------------------------------------------------------------------------
  9326. void CMapDoc::ProcessNotifyList()
  9327. {
  9328. s_bDispatchingNotifications = true;
  9329. int nCount = m_NotifyList.Count();
  9330. if (nCount)
  9331. {
  9332. for (int i = 0; i < nCount; i++)
  9333. {
  9334. NotifyListEntry_t entry = m_NotifyList.Element(i);
  9335. if ( entry.pObject->m_pObject )
  9336. {
  9337. DispatchNotifyDependents(entry.pObject->m_pObject, entry.eNotifyType);
  9338. }
  9339. else
  9340. {
  9341. static bool bShowedWarning = false;
  9342. if ( !bShowedWarning )
  9343. {
  9344. bShowedWarning = true;
  9345. AfxMessageBox( "ProcessNotifyList: encountered a deleted object. Tell a programmer.", MB_OK );
  9346. }
  9347. }
  9348. }
  9349. m_NotifyList.RemoveAll();
  9350. }
  9351. s_bDispatchingNotifications = false;
  9352. }
  9353. //-----------------------------------------------------------------------------
  9354. // Purpose:
  9355. // Input : pObject -
  9356. // eNotifyType -
  9357. //-----------------------------------------------------------------------------
  9358. void CMapDoc::DispatchNotifyDependents(CMapClass *pObject, Notify_Dependent_t eNotifyType)
  9359. {
  9360. const CMapObjectList *pDependents = pObject->GetDependents();
  9361. if ( pDependents->Count() == 0 )
  9362. return;
  9363. // Get a copy of the dependecies list because it may change during iteration.
  9364. CMapObjectList TempDependents;
  9365. TempDependents.AddVectorToTail( *pDependents );
  9366. for (int i = 0; i < TempDependents.Count(); i++)
  9367. {
  9368. CMapClass *pDependent = TempDependents.Element(i);
  9369. //
  9370. // Maybe we should give our dependents the opportunity to unlink themselves here?
  9371. // Returning false from OnNotify could indicate a desire to sever the dependency.
  9372. // Currently this is accomplished by calling UpdateDependency from OnNotifyDependent.
  9373. //
  9374. pDependent->OnNotifyDependent(pObject, eNotifyType);
  9375. }
  9376. }
  9377. //-----------------------------------------------------------------------------
  9378. // Purpose: Replicates the given list of objects, then selects the duplicates.
  9379. // Input : Objects -
  9380. //-----------------------------------------------------------------------------
  9381. void CMapDoc::CloneObjects(const CMapObjectList &Objects)
  9382. {
  9383. CMapObjectList NewObjects;
  9384. bool bLocked = VisGroups_LockUpdates( true );
  9385. //
  9386. // Run through list of objects and copy each to build a list of cloned
  9387. // objects.
  9388. //
  9389. FOR_EACH_OBJ( Objects, pos )
  9390. {
  9391. CMapClass *pobj = Objects.Element(pos);
  9392. CMapClass *pNewobj = pobj->Copy(false);
  9393. pNewobj->CopyChildrenFrom(pobj, false);
  9394. if (!Options.view2d.bKeepclonegroup)
  9395. {
  9396. pNewobj->RemoveAllVisGroups();
  9397. }
  9398. NewObjects.AddToTail(pNewobj);
  9399. }
  9400. // Notification happens in two-passes. The first pass lets objects generate new unique
  9401. // IDs, the second pass lets objects fixup references to other cloned objects.
  9402. Assert( Objects.Count() == NewObjects.Count() );
  9403. FOR_EACH_OBJ( Objects, pos )
  9404. {
  9405. CMapClass *pobj = Objects.Element(pos);
  9406. CMapClass *pNewobj = NewObjects.Element(pos);
  9407. pobj->OnPreClone(pNewobj, m_pWorld, Objects, NewObjects);
  9408. }
  9409. // Do the second pass of notification and add the objects to the world. The second pass
  9410. // of notification lets objects fixup references to other cloned objects.
  9411. FOR_EACH_OBJ( Objects, pos )
  9412. {
  9413. CMapClass *pobj = Objects.Element(pos);
  9414. CMapClass *pNewobj = NewObjects.Element(pos);
  9415. pobj->OnClone(pNewobj, m_pWorld, Objects, NewObjects);
  9416. AddObjectToWorld(pNewobj);
  9417. }
  9418. SelectObjectList( &NewObjects );
  9419. if ( bLocked )
  9420. {
  9421. VisGroups_LockUpdates( false );
  9422. }
  9423. }
  9424. //-----------------------------------------------------------------------------
  9425. // Purpose:
  9426. // Input : &axes -
  9427. // vecNudge -
  9428. //-----------------------------------------------------------------------------
  9429. void CMapDoc::GetNudgeVector(const Vector& vHorz, const Vector& vVert, int nChar, bool bSnap, Vector &vecNudge)
  9430. {
  9431. vecNudge.Init();
  9432. float fUnit = ((bSnap && IsSnapEnabled()) ? GetGridSpacing() : 1);
  9433. switch ( nChar )
  9434. {
  9435. case VK_RIGHT : vecNudge += fUnit*vHorz; break;
  9436. case VK_LEFT : vecNudge -= fUnit*vHorz; break;
  9437. case VK_UP : vecNudge += fUnit*vVert; break;
  9438. case VK_DOWN : vecNudge -= fUnit*vVert; break;
  9439. }
  9440. }
  9441. //-----------------------------------------------------------------------------
  9442. // Purpose:
  9443. //-----------------------------------------------------------------------------
  9444. void CMapDoc::NudgeObjects(const Vector &Delta, bool bClone)
  9445. {
  9446. const CMapObjectList *pSelList = m_pSelection->GetList();
  9447. // If they held down shift, clone the selection then nudge the clones.
  9448. if (bClone)
  9449. {
  9450. GetHistory()->MarkUndoPosition(pSelList, "Clone Objects");
  9451. CloneObjects(*pSelList);
  9452. GetHistory()->KeepNew(pSelList);
  9453. }
  9454. else
  9455. {
  9456. GetHistory()->MarkUndoPosition(pSelList, "Nudge objects");
  9457. GetHistory()->Keep(pSelList);
  9458. }
  9459. for (int i = 0; i < pSelList->Count(); i++)
  9460. {
  9461. CMapClass *pObject = pSelList->Element(i);
  9462. pObject->TransMove(Delta);
  9463. }
  9464. SetModifiedFlag();
  9465. }
  9466. //-----------------------------------------------------------------------------
  9467. // Purpose: deals with update problems when changing multiple visgroup settings
  9468. //-----------------------------------------------------------------------------
  9469. bool CMapDoc::VisGroups_LockUpdates( bool bLock )
  9470. {
  9471. // check if already locked/unlocked
  9472. if ( m_bVisGroupUpdatesLocked == bLock )
  9473. return false;
  9474. m_bVisGroupUpdatesLocked = bLock;
  9475. if ( !bLock )
  9476. {
  9477. //
  9478. // Clean up any visgroups with no members.
  9479. //
  9480. VisGroups_PurgeGroups();
  9481. //
  9482. // Update object visiblity and refresh views.
  9483. //
  9484. VisGroups_UpdateAll();
  9485. CMainFrame *pwndMain = GetMainWnd();
  9486. if (pwndMain)
  9487. {
  9488. pwndMain->UpdateAllDocViews(MAPVIEW_UPDATE_VISGROUP_ALL);
  9489. }
  9490. }
  9491. return true;
  9492. }
  9493. //-----------------------------------------------------------------------------
  9494. // Purpose: Checks visgroup-membership for all objects in a visgroup.
  9495. //-----------------------------------------------------------------------------
  9496. void CMapDoc::VisGroups_CheckMemberVisibility(CVisGroup *pGroup)
  9497. {
  9498. //Msg("-------- Visgroups_ShowVisGroup --------\n");
  9499. if (pGroup == NULL)
  9500. return;
  9501. //
  9502. // Show or hide all the objects that belong to the given visgroup.
  9503. //
  9504. EnumChildrenPos_t pos;
  9505. CMapClass *pChild = m_pWorld->GetFirstDescendent(pos);
  9506. while (pChild)
  9507. {
  9508. if (IsInVisGroupRecursive(pChild, pGroup))
  9509. {
  9510. pChild->CheckVisibility();
  9511. }
  9512. pChild = m_pWorld->GetNextDescendent(pos);
  9513. }
  9514. VisGroups_UpdateAll();
  9515. UpdateVisibilityAll();
  9516. SetModifiedFlag();
  9517. }
  9518. CMapView3D *CMapDoc::GetFirst3DView()
  9519. {
  9520. POSITION pos = this->GetFirstViewPosition();
  9521. while ( pos )
  9522. {
  9523. CView *pView = GetNextView(pos);
  9524. if (pView->IsKindOf(RUNTIME_CLASS(CMapView3D)))
  9525. {
  9526. CMapView3D *pView3D = (CMapView3D *)pView;
  9527. return pView3D;
  9528. }
  9529. }
  9530. return NULL;
  9531. }
  9532. CMapView *CMapDoc::GetActiveMapView()
  9533. {
  9534. POSITION p = GetFirstViewPosition();
  9535. while (p)
  9536. {
  9537. CMapView *pView = dynamic_cast<CMapView*>(GetNextView(p));
  9538. if ( !pView )
  9539. continue;
  9540. if ( pView->IsActive() )
  9541. return pView;
  9542. }
  9543. return NULL;
  9544. }
  9545. void CMapDoc::OnLogicalobjectLayoutgeometric()
  9546. {
  9547. Vector2D vecLogicalCenter;
  9548. if ( !m_pSelection->GetLogicalBoundsCenter( vecLogicalCenter ) )
  9549. return;
  9550. const CMapObjectList *pSelList = m_pSelection->GetList();
  9551. if ( pSelList->Count() <= 1 )
  9552. return;
  9553. GetHistory()->MarkUndoPosition( pSelList, "Layout Geometric" );
  9554. GetHistory()->Keep( pSelList );
  9555. bool bCenterView = false;
  9556. CMapViewLogical *pCurrentView = NULL;
  9557. if ( GetMainWnd()->GetActiveFrame() )
  9558. {
  9559. pCurrentView = dynamic_cast<CMapViewLogical*>( GetMainWnd()->GetActiveFrame()->GetActiveView() );
  9560. if ( pCurrentView )
  9561. bCenterView = true;
  9562. }
  9563. for ( int i = 0; i < pSelList->Count(); ++i )
  9564. {
  9565. CMapClass *pClass = pSelList->Element( i );
  9566. if ( !pClass->IsLogical() )
  9567. continue;
  9568. Vector oldCenter;
  9569. pClass->GetBoundsCenter( oldCenter );
  9570. Vector2D newLogicalCenter;
  9571. newLogicalCenter.x = oldCenter.x + oldCenter.z/4;
  9572. newLogicalCenter.y = oldCenter.y + oldCenter.z/4;
  9573. pClass->SetLogicalPosition( newLogicalCenter );
  9574. }
  9575. UpdateAllViews( MAPVIEW_UPDATE_OBJECTS | MAPVIEW_UPDATE_SELECTION | MAPVIEW_UPDATE_ONLY_LOGICAL );
  9576. m_pSelection->SetBoundsDirty();
  9577. if ( bCenterView )
  9578. {
  9579. CenterLogicalViewsOnSelection();
  9580. }
  9581. }
  9582. void CMapDoc::OnLogicalobjectLayoutdefault()
  9583. {
  9584. Vector2D vecLogicalCenter;
  9585. if ( !m_pSelection->GetLogicalBoundsCenter( vecLogicalCenter ) )
  9586. return;
  9587. const CMapObjectList *pSelList = m_pSelection->GetList();
  9588. if ( pSelList->Count() <= 1 )
  9589. return;
  9590. GetHistory()->MarkUndoPosition( pSelList, "Layout Default" );
  9591. GetHistory()->Keep( pSelList );
  9592. bool bCenterView = false;
  9593. CMapViewLogical *pCurrentView = NULL;
  9594. if ( GetMainWnd()->GetActiveFrame() )
  9595. {
  9596. pCurrentView = dynamic_cast<CMapViewLogical*>( GetMainWnd()->GetActiveFrame()->GetActiveView() );
  9597. if ( pCurrentView )
  9598. bCenterView = true;
  9599. }
  9600. m_nLogicalPositionCount = 0;
  9601. for ( int i = 0; i < pSelList->Count(); ++i )
  9602. {
  9603. CMapClass *pClass = pSelList->Element( i );
  9604. if ( !pClass->IsLogical() )
  9605. continue;
  9606. Vector2D newLogicalCenter;
  9607. GetDefaultNewLogicalPosition( newLogicalCenter );
  9608. pClass->SetLogicalPosition( newLogicalCenter );
  9609. }
  9610. UpdateAllViews( MAPVIEW_UPDATE_OBJECTS | MAPVIEW_UPDATE_SELECTION | MAPVIEW_UPDATE_ONLY_LOGICAL );
  9611. m_pSelection->SetBoundsDirty();
  9612. if ( bCenterView )
  9613. {
  9614. CenterLogicalViewsOnSelection();
  9615. }
  9616. }
  9617. void CMapDoc::OnLogicalobjectLayoutlogical()
  9618. {
  9619. // TODO: Add your command handler code here
  9620. }
  9621. //-----------------------------------------------------------------------------
  9622. // Purpose: Toggles the state of Tools | Instances | Hide. When enabled, instances are hidden.
  9623. //-----------------------------------------------------------------------------
  9624. void CMapDoc::OnToolsInstancesHide(void)
  9625. {
  9626. m_tShowInstance = INSTANCES_HIDE;
  9627. UpdateAllViews( MAPVIEW_RENDER_NOW );
  9628. }
  9629. //-----------------------------------------------------------------------------
  9630. // Purpose: Manages the state of the Tools | Instances | Hide menu item.
  9631. //-----------------------------------------------------------------------------
  9632. void CMapDoc::OnUpdateToolsInstancesHide(CCmdUI *pCmdUI)
  9633. {
  9634. pCmdUI->Enable(!GetMainWnd()->IsShellSessionActive());
  9635. pCmdUI->SetCheck( ( m_tShowInstance == INSTANCES_HIDE ) );
  9636. }
  9637. //-----------------------------------------------------------------------------
  9638. // Purpose: Toggles the state of Tools | Instances | Show Tinted. When enabled, instances are tinted.
  9639. //-----------------------------------------------------------------------------
  9640. void CMapDoc::OnToolsInstancesShowTinted(void)
  9641. {
  9642. m_tShowInstance = INSTANCES_SHOW_TINTED;
  9643. UpdateAllViews( MAPVIEW_RENDER_NOW );
  9644. }
  9645. //-----------------------------------------------------------------------------
  9646. // Purpose: Manages the state of the Tools | Instances | Show Tinted menu item.
  9647. //-----------------------------------------------------------------------------
  9648. void CMapDoc::OnUpdateToolsInstancesShowTinted(CCmdUI *pCmdUI)
  9649. {
  9650. pCmdUI->Enable(!GetMainWnd()->IsShellSessionActive());
  9651. pCmdUI->SetCheck( ( m_tShowInstance == INSTANCES_SHOW_TINTED ) );
  9652. }
  9653. //-----------------------------------------------------------------------------
  9654. // Purpose: Toggles the state of Tools | Instances | Show Normal. When enabled, instances are shown just like the rest of the world.
  9655. //-----------------------------------------------------------------------------
  9656. void CMapDoc::OnToolsInstancesShowNormal(void)
  9657. {
  9658. m_tShowInstance = INSTANCES_SHOW_NORMAL;
  9659. UpdateAllViews( MAPVIEW_RENDER_NOW );
  9660. }
  9661. //-----------------------------------------------------------------------------
  9662. // Purpose: Manages the state of the Tools | Instances | Show Normal menu item.
  9663. //-----------------------------------------------------------------------------
  9664. void CMapDoc::OnUpdateToolsInstancesShowNormal(CCmdUI *pCmdUI)
  9665. {
  9666. pCmdUI->Enable(!GetMainWnd()->IsShellSessionActive());
  9667. pCmdUI->SetCheck( ( m_tShowInstance == INSTANCES_SHOW_NORMAL ) );
  9668. }
  9669. //-----------------------------------------------------------------------------
  9670. // Purpose: this function will show or hide the map doc
  9671. // Input : bIsVisible - flag to indicate the visibility status
  9672. //-----------------------------------------------------------------------------
  9673. void CMapDoc::ShowWindow( bool bIsVisible )
  9674. {
  9675. bool bNeedsInitialUpdate = !HasInitialUpdate();
  9676. POSITION posOpenDoc = GetFirstViewPosition();
  9677. while ( posOpenDoc != NULL )
  9678. {
  9679. CView *pView = GetNextView( posOpenDoc );
  9680. CFrameWnd *pFrame = pView->GetParentFrame();
  9681. if ( pFrame )
  9682. {
  9683. if ( bIsVisible && bNeedsInitialUpdate )
  9684. {
  9685. APP()->pMapDocTemplate->InitialUpdateFrame( pFrame, this, true );
  9686. }
  9687. pFrame->ActivateFrame( bIsVisible ? SW_SHOW : SW_HIDE );
  9688. pFrame->ShowWindow( bIsVisible ? SW_SHOW : SW_HIDE );
  9689. CMainFrame *pwndMain = GetMainWnd();
  9690. ::SendMessage( pwndMain->m_hWndMDIClient, WM_MDIREFRESHMENU, 0, 0 );
  9691. pwndMain->DrawMenuBar();
  9692. }
  9693. }
  9694. if ( bIsVisible && !HasInitialUpdate() )
  9695. {
  9696. SetInitialUpdate();
  9697. }
  9698. }
  9699. //-----------------------------------------------------------------------------
  9700. // Purpose: this function checks to see if the map doc is visible
  9701. // Output : returns true if the document is visible
  9702. //-----------------------------------------------------------------------------
  9703. bool CMapDoc::IsVisible( void )
  9704. {
  9705. POSITION posOpenDoc = GetFirstViewPosition();
  9706. while ( posOpenDoc != NULL )
  9707. {
  9708. CView *pView = GetNextView( posOpenDoc );
  9709. CFrameWnd *pFrame = pView->GetParentFrame();
  9710. if ( pFrame )
  9711. {
  9712. return ( pFrame->IsWindowVisible() == TRUE );
  9713. }
  9714. }
  9715. return false;
  9716. }
  9717. //-----------------------------------------------------------------------------
  9718. // Purpose: this function will hide all instance map windows
  9719. //-----------------------------------------------------------------------------
  9720. void CMapDoc::OnInstancesHideAll( void )
  9721. {
  9722. POSITION pos = APP()->pMapDocTemplate->GetFirstDocPosition();
  9723. while( pos != NULL )
  9724. {
  9725. CDocument *pDoc = APP()->pMapDocTemplate->GetNextDoc( pos );
  9726. CMapDoc *pMapDoc = dynamic_cast< CMapDoc * >( pDoc );
  9727. if ( pMapDoc && pMapDoc->GetReferenceCount() != 0 && !pMapDoc->IsModified() )
  9728. {
  9729. pMapDoc->ShowWindow( false );
  9730. }
  9731. }
  9732. }
  9733. //-----------------------------------------------------------------------------
  9734. // Purpose: this function will show all instance map windows
  9735. //-----------------------------------------------------------------------------
  9736. void CMapDoc::OnInstancesShowAll( void )
  9737. {
  9738. POSITION pos = APP()->pMapDocTemplate->GetFirstDocPosition();
  9739. while( pos != NULL )
  9740. {
  9741. CDocument *pDoc = APP()->pMapDocTemplate->GetNextDoc( pos );
  9742. CMapDoc *pMapDoc = dynamic_cast< CMapDoc * >( pDoc );
  9743. if ( pMapDoc && pMapDoc->GetReferenceCount() != 0 )
  9744. {
  9745. pMapDoc->ShowWindow( true );
  9746. }
  9747. }
  9748. }
  9749. //-----------------------------------------------------------------------------
  9750. // Purpose: This routine will open up the manifest dialog. If the map is not
  9751. // a manifest, it will being the prompted to ask the user if he wants
  9752. // to convert it to one.
  9753. //-----------------------------------------------------------------------------
  9754. void CMapDoc::OnInstancingCreatemanifest()
  9755. {
  9756. CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
  9757. if (!pDoc)
  9758. {
  9759. return;
  9760. }
  9761. CManifest *pManifest = CMapDoc::GetManifest();
  9762. if ( !pManifest )
  9763. {
  9764. if ( AfxMessageBox( "Do you want to create a new manifest from this map?", MB_YESNO ) == IDNO )
  9765. {
  9766. return;
  9767. }
  9768. if ( !CreateNewManifest() )
  9769. {
  9770. return;
  9771. }
  9772. }
  9773. }
  9774. //-----------------------------------------------------------------------------
  9775. // Purpose:
  9776. // Input :
  9777. // Output :
  9778. //-----------------------------------------------------------------------------
  9779. void CMapDoc::OnInstancingCheckinAll( )
  9780. {
  9781. CMapDoc *activeDoc = CMapDoc::GetActiveMapDoc();
  9782. if ( !activeDoc || !activeDoc->GetManifest() )
  9783. {
  9784. return;
  9785. }
  9786. CManifest *pManifest = activeDoc->GetManifest();
  9787. pManifest->m_bDefaultCheckin = true;
  9788. for( int i = 0; i < pManifest->GetNumMaps(); i++ )
  9789. {
  9790. CManifestMap *pManifestMap = pManifest->GetMap( i );
  9791. pManifestMap->m_bDefaultCheckin = true;
  9792. }
  9793. CManifestCheckin ManifestCheckin;
  9794. if ( ManifestCheckin.DoModal() == IDOK )
  9795. {
  9796. pManifest->CheckFileStatus();
  9797. GetMainWnd()->m_ManifestFilterControl.Invalidate();
  9798. }
  9799. }
  9800. //-----------------------------------------------------------------------------
  9801. // Purpose:
  9802. // Input :
  9803. // Output :
  9804. //-----------------------------------------------------------------------------
  9805. void CMapDoc::OnInstancingCheckOutManifest( )
  9806. {
  9807. CMapDoc *activeDoc = CMapDoc::GetActiveMapDoc();
  9808. if ( !activeDoc || !activeDoc->GetManifest() )
  9809. {
  9810. return;
  9811. }
  9812. CManifest *pManifest = activeDoc->GetManifest();
  9813. if ( pManifest->CheckOut() == false && p4 )
  9814. {
  9815. char temp[ 2048 ];
  9816. sprintf( temp, "Could not check out manifest: %s", p4->GetLastError() );
  9817. AfxMessageBox( temp, MB_ICONHAND | MB_OK );
  9818. }
  9819. }
  9820. //-----------------------------------------------------------------------------
  9821. // Purpose:
  9822. // Input :
  9823. // Output :
  9824. //-----------------------------------------------------------------------------
  9825. void CMapDoc::OnInstancingAddManifest( )
  9826. {
  9827. CMapDoc *activeDoc = CMapDoc::GetActiveMapDoc();
  9828. if ( !activeDoc || !activeDoc->GetManifest() )
  9829. {
  9830. return;
  9831. }
  9832. CManifest *pManifest = activeDoc->GetManifest();
  9833. if ( pManifest->AddToVersionControl() == false && p4 )
  9834. {
  9835. char temp[ 2048 ];
  9836. sprintf( temp, "Could not check out manifest: %s", p4->GetLastError() );
  9837. AfxMessageBox( temp, MB_ICONHAND | MB_OK );
  9838. }
  9839. }
  9840. //-----------------------------------------------------------------------------
  9841. // Purpose: This function checks to see if it should enable the Create Manifest menu item
  9842. //-----------------------------------------------------------------------------
  9843. void CMapDoc::OnUpdateInstancingCreatemanifest(CCmdUI *pCmdUI)
  9844. {
  9845. CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
  9846. if (!pDoc)
  9847. {
  9848. pCmdUI->Enable( false );
  9849. return;
  9850. }
  9851. CManifest *pManifest = CMapDoc::GetManifest();
  9852. pCmdUI->Enable( ( pManifest == NULL ) );
  9853. }
  9854. //-----------------------------------------------------------------------------
  9855. // Purpose:
  9856. // Input :
  9857. // Output :
  9858. //-----------------------------------------------------------------------------
  9859. void CMapDoc::OnUpdateInstancingCheckinAll( CCmdUI *pCmdUI )
  9860. {
  9861. CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
  9862. if ( !pDoc || !p4 )
  9863. {
  9864. pCmdUI->Enable( false );
  9865. return;
  9866. }
  9867. CManifest *pManifest = CMapDoc::GetManifest();
  9868. if ( pManifest == NULL )
  9869. {
  9870. pCmdUI->Enable( false );
  9871. return;
  9872. }
  9873. if ( pManifest->m_bCheckedOut == true )
  9874. {
  9875. pCmdUI->Enable( true );
  9876. return;
  9877. }
  9878. for( int i = 0; i < pManifest->GetNumMaps(); i++ )
  9879. {
  9880. CManifestMap *pManifestMap = pManifest->GetMap( i );
  9881. if ( pManifestMap->m_bCheckedOut == true )
  9882. {
  9883. pCmdUI->Enable( true );
  9884. return;
  9885. }
  9886. }
  9887. pCmdUI->Enable( false );
  9888. }
  9889. //-----------------------------------------------------------------------------
  9890. // Purpose:
  9891. // Input :
  9892. // Output :
  9893. //-----------------------------------------------------------------------------
  9894. void CMapDoc::OnUpdateInstancingCheckOutManifest( CCmdUI *pCmdUI )
  9895. {
  9896. CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
  9897. if ( !pDoc || !p4 )
  9898. {
  9899. pCmdUI->Enable( false );
  9900. return;
  9901. }
  9902. CManifest *pManifest = CMapDoc::GetManifest();
  9903. if ( pManifest == NULL )
  9904. {
  9905. pCmdUI->Enable( false );
  9906. return;
  9907. }
  9908. if ( pManifest->m_bIsVersionControlled == true && pManifest->m_bCheckedOut == false )
  9909. {
  9910. pCmdUI->Enable( true );
  9911. }
  9912. else
  9913. {
  9914. pCmdUI->Enable( false );
  9915. }
  9916. }
  9917. //-----------------------------------------------------------------------------
  9918. // Purpose:
  9919. // Input :
  9920. // Output :
  9921. //-----------------------------------------------------------------------------
  9922. void CMapDoc::OnUpdateInstancingAddManifest( CCmdUI *pCmdUI )
  9923. {
  9924. CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
  9925. if ( !pDoc || !p4 )
  9926. {
  9927. pCmdUI->Enable( false );
  9928. return;
  9929. }
  9930. CManifest *pManifest = CMapDoc::GetManifest();
  9931. if ( pManifest == NULL )
  9932. {
  9933. pCmdUI->Enable( false );
  9934. return;
  9935. }
  9936. if ( pManifest->m_bIsVersionControlled == false )
  9937. {
  9938. pCmdUI->Enable( true );
  9939. }
  9940. else
  9941. {
  9942. pCmdUI->Enable( false );
  9943. }
  9944. }
  9945. //-----------------------------------------------------------------------------
  9946. // Purpose: This function will collapse all instances into the map ( and any children instances )
  9947. //-----------------------------------------------------------------------------
  9948. void CMapDoc::OnInstancesCollapseAll()
  9949. {
  9950. CollapseInstances( false );
  9951. }
  9952. //-----------------------------------------------------------------------------
  9953. // Purpose: This function will collapse all instances that are selected into the map ( and any children instances )
  9954. //-----------------------------------------------------------------------------
  9955. void CMapDoc::OnInstancesCollapseSelection()
  9956. {
  9957. CollapseInstances( true );
  9958. }
  9959. //-----------------------------------------------------------------------------
  9960. // Purpose: Finds if this object/entity belongs to any FGD-defined AutoVisGroups
  9961. //-----------------------------------------------------------------------------
  9962. void CMapDoc::AddToFGDAutoVisGroups( CMapClass *pObject )
  9963. {
  9964. if ( pGD != NULL )
  9965. {
  9966. CMapEntity *pEntity = dynamic_cast< CMapEntity * >( pObject );
  9967. if ( pEntity != NULL )
  9968. {
  9969. int gindex = 0; // Index of FGD-defined AutoVisGroups
  9970. int cindex = 0; // Index of Classes
  9971. int eindex = 0; // Index of Entities
  9972. // Parent
  9973. for( gindex = 0; gindex < pGD->m_FGDAutoVisGroups.Count(); gindex++ )
  9974. {
  9975. // Class
  9976. for ( cindex = 0; cindex < pGD->m_FGDAutoVisGroups[gindex].m_Classes.Count(); cindex++ )
  9977. {
  9978. // Object/Entity
  9979. for ( eindex = 0; eindex < pGD->m_FGDAutoVisGroups[gindex].m_Classes[cindex].szEntities.Count(); eindex++ )
  9980. {
  9981. //
  9982. if ( !V_stricmp( pEntity->GetClassName(), pGD->m_FGDAutoVisGroups[gindex].m_Classes[cindex].szEntities[eindex] ) )
  9983. {
  9984. AddChildGroupToAutoVisGroup( pEntity, pGD->m_FGDAutoVisGroups[gindex].m_Classes[cindex].szClass, pGD->m_FGDAutoVisGroups[gindex].szParent );
  9985. }
  9986. }
  9987. }
  9988. }
  9989. }
  9990. }
  9991. }
  9992. //-----------------------------------------------------------------------------
  9993. // Purpose: Add objects/entities to QuickHide
  9994. //-----------------------------------------------------------------------------
  9995. void CMapDoc::QuickHide_HideObjects( void )
  9996. {
  9997. const CMapObjectList *pSelList = m_pSelection->GetList();
  9998. for ( int index = 0; index < pSelList->Count(); index++ )
  9999. {
  10000. CMapClass *pObject = pSelList->Element( index );
  10001. // Hide the object
  10002. m_QuickHideGroup.AddToTail( pObject );
  10003. // If it's a Group or Entity, add each child - otherwise we get ghost group selection (driller: FIXME)
  10004. if ( pObject->IsGroup() || pObject->IsMapClass( MAPCLASS_TYPE( CMapEntity ) ) )
  10005. {
  10006. EnumChildrenPos_t pos;
  10007. CMapClass *pChild = pObject->GetFirstDescendent( pos );
  10008. while ( pChild )
  10009. {
  10010. m_QuickHideGroup.AddToTail( pChild );
  10011. pChild = pObject->GetNextDescendent( pos );
  10012. }
  10013. }
  10014. // Does this object have a parent?
  10015. if ( pObject->GetParent() )
  10016. {
  10017. CMapClass *pParent = pObject->GetParent();
  10018. // Track all parents, so we can check if all children (eventually) end up hidden
  10019. while ( pParent )
  10020. {
  10021. if ( pParent->IsGroup() || pParent->IsMapClass( MAPCLASS_TYPE( CMapEntity ) ) )
  10022. {
  10023. if ( m_QuickHideGroupedParents.Find( pParent ) == m_QuickHideGroupedParents.InvalidIndex() )
  10024. {
  10025. m_QuickHideGroupedParents.AddToTail( pParent );
  10026. }
  10027. }
  10028. pParent = pParent->GetParent();
  10029. }
  10030. }
  10031. }
  10032. // Now check any parents
  10033. if ( m_QuickHideGroupedParents.Count() > 0 )
  10034. {
  10035. int nHiddenChildCount = 0;
  10036. for ( int index = 0; index < m_QuickHideGroupedParents.Count(); index++ )
  10037. {
  10038. EnumChildrenPos_t posParent;
  10039. CMapClass *pParent = m_QuickHideGroupedParents[ index ];
  10040. int nChildCount = pParent->GetChildCount();
  10041. if ( pParent )
  10042. {
  10043. CMapClass *pChild = pParent->GetFirstDescendent( posParent );
  10044. // Child visible?
  10045. while ( pChild )
  10046. {
  10047. // With the way GetChildCount() works, we need to count nested children, too
  10048. nChildCount += pChild->GetChildCount();
  10049. if ( m_QuickHideGroup.Find( pChild ) != m_QuickHideGroup.InvalidIndex() )
  10050. {
  10051. nHiddenChildCount++;
  10052. }
  10053. pChild = pParent->GetNextDescendent( posParent );
  10054. }
  10055. }
  10056. // If none of the children are visible...
  10057. if ( nHiddenChildCount == nChildCount )
  10058. {
  10059. // ...also add the parent
  10060. m_QuickHideGroup.AddToTail( pParent );
  10061. }
  10062. nHiddenChildCount = 0;
  10063. }
  10064. }
  10065. m_pToolManager->GetActiveTool()->SetEmpty();
  10066. UpdateVisibilityAll();
  10067. }
  10068. //-----------------------------------------------------------------------------
  10069. // Purpose: Add unselected objects/entities to QuickHide
  10070. //-----------------------------------------------------------------------------
  10071. void CMapDoc::QuickHide_HideUnselectedObjects( void )
  10072. {
  10073. EnumChildrenPos_t pos;
  10074. CMapWorld *pWorld = GetMapWorld();
  10075. CMapClass *pObject = pWorld->GetFirstDescendent( pos );
  10076. while ( pObject )
  10077. {
  10078. if ( !pObject->IsSelected() )
  10079. {
  10080. m_QuickHideGroup.AddToTail( pObject );
  10081. }
  10082. pObject = pWorld->GetNextDescendent( pos );
  10083. }
  10084. // Check each selected object for a parent...
  10085. const CMapObjectList *pSelList = m_pSelection->GetList();
  10086. for ( int index = 0; index < pSelList->Count(); index++ )
  10087. {
  10088. CMapClass *pSelectedObject = pSelList->Element( index );
  10089. CMapClass *pSelectedParent = pSelectedObject->GetParent();
  10090. while ( pSelectedParent )
  10091. {
  10092. // ...and nuke them from QuickHide
  10093. m_QuickHideGroup.FindAndRemove( pSelectedParent );
  10094. pSelectedParent = pSelectedParent->GetParent();
  10095. }
  10096. }
  10097. UpdateVisibilityAll();
  10098. }
  10099. //-----------------------------------------------------------------------------
  10100. // Purpose: Restore any hidden objects and purge data
  10101. //-----------------------------------------------------------------------------
  10102. void CMapDoc::QuickHide_Unhide( void )
  10103. {
  10104. if ( m_QuickHideGroup.Count() > 0 )
  10105. {
  10106. m_QuickHideGroup.RemoveAll();
  10107. m_QuickHideGroupedParents.RemoveAll();
  10108. UpdateVisibilityAll();
  10109. }
  10110. }
  10111. //-----------------------------------------------------------------------------
  10112. // Purpose: Checks the QuickHideGroup for pObject
  10113. //-----------------------------------------------------------------------------
  10114. bool CMapDoc::QuickHide_IsObjectHidden( CMapClass *pObject )
  10115. {
  10116. for ( int index = 0; index < m_QuickHideGroup.Count(); index++ )
  10117. {
  10118. // FIXME: use references to detect objects being deleted
  10119. if ( pObject == m_QuickHideGroup[index] )
  10120. {
  10121. return true;
  10122. }
  10123. }
  10124. return false;
  10125. }
  10126. //-----------------------------------------------------------------------------
  10127. // Purpose: Creates a visgroup with currently hidden objects
  10128. //-----------------------------------------------------------------------------
  10129. void CMapDoc::OnQuickHide_CreateVisGroupFromHidden( void )
  10130. {
  10131. int iQuickHideObjects = m_QuickHideGroup.Count();
  10132. if ( iQuickHideObjects > 0 )
  10133. {
  10134. CString str;
  10135. str.Format( "_FromQuickHide(%d)", iQuickHideObjects );
  10136. VisGroups_CreateNamedVisGroup( m_QuickHideGroup, str, true, false );
  10137. }
  10138. QuickHide_Unhide();
  10139. }
  10140. //-----------------------------------------------------------------------------
  10141. // Purpose: Creates a token in the VMF, which we use for P4 check-in testing
  10142. //-----------------------------------------------------------------------------
  10143. ChunkFileResult_t CMapDoc::QuickHide_SaveVMF( CChunkFile *pFile, CSaveInfo *pSaveInfo )
  10144. {
  10145. if ( m_QuickHideGroup.Count() == 0)
  10146. {
  10147. return( ChunkFile_Ok );
  10148. }
  10149. ChunkFileResult_t eResult = pFile->BeginChunk( "quickhide" );
  10150. if ( eResult == ChunkFile_Ok )
  10151. {
  10152. int nCount = m_QuickHideGroup.Count();
  10153. eResult = pFile->WriteKeyValueInt( "count", nCount );
  10154. }
  10155. if ( eResult == ChunkFile_Ok )
  10156. {
  10157. eResult = pFile->EndChunk();
  10158. }
  10159. return( eResult );
  10160. }
  10161. //-----------------------------------------------------------------------------
  10162. // Purpose: Menu/Button version of QuickHide_HideObjects
  10163. //-----------------------------------------------------------------------------
  10164. void CMapDoc::OnQuickHide_HideObjects( void )
  10165. {
  10166. QuickHide_HideObjects();
  10167. }
  10168. //-----------------------------------------------------------------------------
  10169. // Purpose: Menu/Button version of QuickHide_HideUnselectedObjects
  10170. //-----------------------------------------------------------------------------
  10171. void CMapDoc::OnQuickHide_HideUnselectedObjects( void )
  10172. {
  10173. QuickHide_HideUnselectedObjects();
  10174. }
  10175. //-----------------------------------------------------------------------------
  10176. // Purpose: Menu/Button version of OnQuickHide_Unhide
  10177. //-----------------------------------------------------------------------------
  10178. void CMapDoc::OnQuickHide_Unhide( void )
  10179. {
  10180. QuickHide_Unhide();
  10181. }
  10182. //-----------------------------------------------------------------------------
  10183. // Purpose:
  10184. //-----------------------------------------------------------------------------
  10185. void CMapDoc::OnRadiusCulling( void )
  10186. {
  10187. Options.general.bRadiusCulling = !Options.general.bRadiusCulling;
  10188. UpdateVisibilityAll();
  10189. }
  10190. //-----------------------------------------------------------------------------
  10191. // Purpose:
  10192. //-----------------------------------------------------------------------------
  10193. void CMapDoc::OnUpdateRadiusCulling( CCmdUI *pCmdUI )
  10194. {
  10195. pCmdUI->SetCheck( Options.general.bRadiusCulling ? 1 : 0 );
  10196. pCmdUI->Enable(!GetMainWnd()->IsShellSessionActive());
  10197. }
  10198. #include <tier0/memdbgoff.h>