Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

14176 lines
374 KiB

  1. //===================== Copyright (c) Valve Corporation. All Rights Reserved. ======================
  2. //
  3. // The map document. Exposes functions for object creation, deletion, and manipulation.
  4. // Holds a pointer to the world, which may contain func_instances which contain sub-worlds.
  5. // Holds the current tool. Handles GUI messages that are 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 "PasteSpecialDlg.h"
  42. #include "Prefabs.h"
  43. #include "Prefab3D.h"
  44. #include "ReplaceTexDlg.h"
  45. #include "RunMap.h"
  46. #include "RunMapExpertDlg.h"
  47. #include "SaveInfo.h"
  48. #include "Manifest.h"
  49. #include "ManifestDialog.h"
  50. #include "ToolManager.h"
  51. #include "ToolCamera.h"
  52. #include "ToolEntity.h"
  53. #include "SelectEntityDlg.h"
  54. #include "Shell.h"
  55. #include "StatusBarIDs.h"
  56. #include "StrDlg.h"
  57. #include "TextureSystem.h"
  58. #include "TextureConverter.h"
  59. #include "TransformDlg.h"
  60. #include "VisGroup.h"
  61. #include "hammer.h"
  62. #include "ibsplighting.h"
  63. #include "camera.h"
  64. #include "MapDiffDlg.h"
  65. #include "StockSolids.h"
  66. #include "ToolMorph.h"
  67. #include "ToolBlock.h"
  68. #include "foundrytool.h"
  69. #include "fadedlg.h"
  70. #include "p4lib/ip4.h"
  71. #include "culltreenode.h"
  72. #include "gridnav.h"
  73. #include "configmanager.h"
  74. #include "..\fow\fow.h"
  75. #include "mapdoc.h"
  76. #include "assetpickerdefs.h"
  77. #include "versioncontroldialog.h"
  78. #include "p4lib/ip4.h"
  79. // memdbgon must be the last include file in a .cpp file!!!
  80. #include <tier0/memdbgon.h>
  81. #define KeyInt( key, dest ) \
  82. if (stricmp(szKey, key) != 0) \
  83. ; \
  84. else \
  85. { \
  86. CChunkFile::ReadKeyValueInt(szValue, dest); \
  87. }
  88. #define KeyBool( key, dest ) \
  89. if (stricmp(szKey, key) != 0) \
  90. ; \
  91. else \
  92. { \
  93. CChunkFile::ReadKeyValueBool(szValue, dest); \
  94. }
  95. #define MAX_REPLACE_LINE_LENGTH 256
  96. #define LOGICAL_SPACING 500
  97. #define HALF_LIFE_2_EYE_HEIGHT 64
  98. #define VMF_FORMAT_VERSION 100
  99. static int g_nFileFormatVersion = 0;
  100. extern BOOL bSaveVisiblesOnly;
  101. extern CShell g_Shell;
  102. IMPLEMENT_DYNCREATE(CMapDoc, CDocument)
  103. BEGIN_MESSAGE_MAP(CMapDoc, CDocument)
  104. //{{AFX_MSG_MAP(CMapDoc)
  105. ON_COMMAND(ID_EDIT_DELETE, OnEditDelete)
  106. ON_COMMAND(ID_MAP_SNAPTOGRID, OnMapSnaptogrid)
  107. ON_UPDATE_COMMAND_UI(ID_MAP_SNAPTOGRID, OnUpdateMapSnaptogrid)
  108. ON_COMMAND(ID_MAP_ENTITY_GALLERY, OnMapEntityGallery)
  109. ON_COMMAND(ID_EDIT_APPLYTEXTURE, OnEditApplytexture)
  110. ON_COMMAND(ID_TOOLS_SUBTRACTSELECTION, OnToolsSubtractselection)
  111. ON_UPDATE_COMMAND_UI(ID_TOOLS_SUBTRACTSELECTION, OnUpdateEditSelection)
  112. ON_COMMAND(ID_MAP_ENABLELIGHTPREVIEW, OnEnableLightPreview)
  113. ON_COMMAND(ID_ENABLE_LIGHT_PREVIEW_CUSTOM_FILENAME, OnEnableLightPreviewCustomFilename)
  114. ON_COMMAND(ID_MAP_DISABLELIGHTPREVIEW, OnDisableLightPreview)
  115. ON_COMMAND(ID_MAP_UPDATELIGHTPREVIEW, OnUpdateLightPreview)
  116. ON_COMMAND(ID_MAP_TOGGLELIGHTPREVIEW, OnToggleLightPreview)
  117. ON_COMMAND(ID_MAP_ABORTLIGHTCALCULATION, OnAbortLightCalculation)
  118. ON_COMMAND(ID_EDIT_COPYWC, OnEditCopy)
  119. ON_UPDATE_COMMAND_UI(ID_EDIT_COPYWC, OnUpdateEditSelection)
  120. ON_COMMAND(ID_EDIT_PASTEWC, OnEditPaste)
  121. ON_UPDATE_COMMAND_UI(ID_EDIT_PASTEWC, OnUpdateEditPaste)
  122. ON_COMMAND(ID_EDIT_CUTWC, OnEditCut)
  123. ON_UPDATE_COMMAND_UI(ID_EDIT_CUTWC, OnUpdateEditSelection)
  124. ON_COMMAND(ID_TOOLS_GROUP, OnToolsGroup)
  125. ON_UPDATE_COMMAND_UI(ID_TOOLS_GROUP, OnUpdateEditSelection)
  126. ON_COMMAND(ID_TOOLS_UNGROUP, OnToolsUngroup)
  127. ON_UPDATE_COMMAND_UI(ID_TOOLS_UNGROUP, OnUpdateEditSelection)
  128. ON_COMMAND(ID_VIEW_GRID, OnViewGrid)
  129. ON_UPDATE_COMMAND_UI(ID_VIEW_GRID, OnUpdateViewGrid)
  130. ON_COMMAND(ID_VIEW_LOGICAL_GRID, OnViewLogicalGrid)
  131. ON_UPDATE_COMMAND_UI(ID_VIEW_LOGICAL_GRID, OnUpdateViewLogicalGrid)
  132. ON_COMMAND(ID_EDIT_SELECTALL, OnEditSelectall)
  133. ON_UPDATE_COMMAND_UI(ID_EDIT_SELECTALL, OnUpdateEditFunction)
  134. ON_COMMAND(ID_EDIT_REPLACE, OnEditReplace)
  135. ON_UPDATE_COMMAND_UI(ID_EDIT_REPLACE, OnUpdateEditFunction)
  136. ON_COMMAND(ID_FILE_SAVE_AS, OnFileSaveAs)
  137. ON_COMMAND(ID_FILE_SAVE, OnFileSave)
  138. ON_COMMAND(ID_MAP_GRIDLOWER, OnMapGridlower)
  139. ON_COMMAND(ID_MAP_GRIDHIGHER, OnMapGridhigher)
  140. ON_COMMAND(ID_EDIT_TOWORLD, OnEditToWorld)
  141. ON_UPDATE_COMMAND_UI(ID_EDIT_TOWORLD, OnUpdateEditSelection)
  142. ON_COMMAND(ID_FILE_EXPORT, OnFileExport)
  143. ON_COMMAND(ID_FILE_EXPORTAGAIN, OnFileExportAgain)
  144. ON_COMMAND(ID_EDIT_MAPPROPERTIES, OnEditMapproperties)
  145. ON_UPDATE_COMMAND_UI(ID_EDIT_MAPPROPERTIES, OnUpdateEditFunction)
  146. ON_COMMAND(ID_FILE_CONVERT_WAD, OnFileConvertWAD)
  147. ON_UPDATE_COMMAND_UI(ID_FILE_CONVERT_WAD, OnUpdateFileConvertWAD)
  148. ON_COMMAND(ID_FILE_RUNMAP, OnFileRunmap)
  149. ON_COMMAND(ID_TOOLS_HIDEITEMS, OnToolsHideitems)
  150. ON_UPDATE_COMMAND_UI(ID_TOOLS_HIDEITEMS, OnUpdateToolsHideitems)
  151. ON_COMMAND(ID_VIEW_HIDEUNCONNECTED, OnViewHideUnconnectedEntities)
  152. ON_UPDATE_COMMAND_UI(ID_VIEW_HIDEUNCONNECTED, OnUpdateViewHideUnconnectedEntities)
  153. ON_COMMAND(ID_TOOLS_HIDE_ENTITY_NAMES, OnToolsHideEntityNames)
  154. ON_UPDATE_COMMAND_UI(ID_TOOLS_HIDE_ENTITY_NAMES, OnUpdateToolsHideEntityNames)
  155. ON_UPDATE_COMMAND_UI(ID_EDIT_DELETE, OnUpdateEditSelection)
  156. ON_COMMAND(ID_MAP_INFORMATION, OnMapInformation)
  157. ON_COMMAND(ID_VIEW_CENTERONSELECTION, OnViewCenterOnSelection)
  158. ON_COMMAND(ID_VIEW_CENTER3DVIEWSONSELECTION, OnViewCenter3DViewsOnSelection)
  159. ON_COMMAND(ID_EDIT_PASTESPECIAL, OnEditPastespecial)
  160. ON_UPDATE_COMMAND_UI(ID_EDIT_PASTESPECIAL, OnUpdateEditPastespecial)
  161. ON_COMMAND(ID_EDIT_SELNEXT, OnEditSelnext)
  162. ON_COMMAND(ID_EDIT_SELPREV, OnEditSelprev)
  163. ON_COMMAND(ID_EDIT_SELNEXT_CASCADING, OnEditSelnextCascading)
  164. ON_COMMAND(ID_EDIT_SELPREV_CASCADING, OnEditSelprevCascading)
  165. ON_COMMAND(ID_LOGICALOBJECT_MOVETOGETHER, OnLogicalMoveBlock)
  166. ON_COMMAND(ID_LOGICALOBJECT_SELECTALLCASCADING, OnLogicalSelectAllCascading)
  167. ON_COMMAND(ID_LOGICALOBJECT_SELECTALLCONNECTED, OnLogicalSelectAllConnected)
  168. ON_COMMAND_EX(ID_VIEW_HIDESELECTEDOBJECTS, OnViewHideObjects)
  169. ON_COMMAND(ID_MAP_CHECK, OnMapCheck)
  170. ON_COMMAND(ID_VIEW_DOTACAMERA, OnViewDotACamera)
  171. ON_UPDATE_COMMAND_UI(ID_VIEW_DOTACAMERA, OnUpdateViewDotACamera)
  172. ON_COMMAND(ID_VIEW_SHOWCONNECTIONS, OnViewShowconnections)
  173. ON_UPDATE_COMMAND_UI(ID_VIEW_SHOWCONNECTIONS, OnUpdateViewShowconnections)
  174. ON_UPDATE_COMMAND_UI(ID_FILE_SAVE, OnUpdateFileSave)
  175. ON_COMMAND(ID_TOOLS_CREATEPREFAB, OnToolsCreateprefab)
  176. ON_UPDATE_COMMAND_UI(ID_TOOLS_CREATEPREFAB, OnUpdateEditSelection)
  177. ON_COMMAND(ID_INSERTPREFAB_ORIGINAL, OnInsertprefabOriginal)
  178. ON_COMMAND(ID_EDIT_REPLACETEX, OnEditReplacetex)
  179. ON_UPDATE_COMMAND_UI(ID_EDIT_REPLACETEX, OnUpdateEditFunction)
  180. ON_COMMAND(ID_TOOLS_HOLLOW, OnToolsHollow)
  181. ON_UPDATE_COMMAND_UI(ID_TOOLS_HOLLOW, OnUpdateEditSelection)
  182. ON_COMMAND(ID_TOOLS_SNAPSELECTEDTOGRID, OnToolsSnapselectedtogrid)
  183. ON_UPDATE_COMMAND_UI(ID_TOOLS_SNAPSELECTEDTOGRID, OnUpdateEditSelection)
  184. ON_COMMAND(ID_TOOLS_SNAP_SELECTED_TO_GRID_INDIVIDUALLY, OnToolsSnapSelectedToGridIndividually)
  185. ON_UPDATE_COMMAND_UI(ID_TOOLS_SNAP_SELECTED_TO_GRID_INDIVIDUALLY, OnUpdateEditSelection)
  186. ON_COMMAND(ID_TOOLS_SPLITFACE, OnToolsSplitface)
  187. ON_UPDATE_COMMAND_UI(ID_TOOLS_SPLITFACE, OnUpdateToolsSplitface)
  188. ON_COMMAND(ID_TOOLS_TRANSFORM, OnToolsTransform)
  189. ON_UPDATE_COMMAND_UI(ID_TOOLS_TRANSFORM, OnUpdateEditSelection)
  190. ON_COMMAND(ID_TOOLS_TOGGLETEXLOCK, OnToolsToggletexlock)
  191. ON_UPDATE_COMMAND_UI(ID_TOOLS_TOGGLETEXLOCK, OnUpdateToolsToggletexlock)
  192. ON_COMMAND(ID_TOOLS_TOGGLETEXLOCKSCALE, OnToolsToggletexlockScale)
  193. ON_UPDATE_COMMAND_UI(ID_TOOLS_TOGGLETEXLOCKSCALE, OnUpdateToolsToggletexlockScale)
  194. ON_COMMAND(ID_TOOLS_TEXTUREALIGN, OnToolsTextureAlignment)
  195. ON_UPDATE_COMMAND_UI(ID_TOOLS_TEXTUREALIGN, OnUpdateToolsTextureAlignment)
  196. ON_COMMAND(ID_TOGGLE_CORDON, OnToggleCordon)
  197. ON_UPDATE_COMMAND_UI(ID_TOGGLE_CORDON, OnUpdateToggleCordon)
  198. ON_COMMAND_EX(ID_VIEW_HIDENONSELECTEDOBJECTS, OnViewHideObjects)
  199. ON_UPDATE_COMMAND_UI(ID_VIEW_HIDENONSELECTEDOBJECTS, OnUpdateViewHideUnselectedObjects)
  200. ON_UPDATE_COMMAND_UI(ID_VIEW_SHOW_HELPERS, OnUpdateViewShowHelpers)
  201. ON_COMMAND(ID_VIEW_SHOW_HELPERS, OnViewShowHelpers)
  202. ON_COMMAND(ID_VIEW_SHOWMODELSIN2D, OnViewShowModelsIn2D)
  203. ON_UPDATE_COMMAND_UI(ID_VIEW_SHOWMODELSIN2D, OnUpdateViewShowModelsIn2D)
  204. ON_COMMAND(ID_VIEW_PREVIEW_MODEL_FADE, OnViewPreviewModelFade)
  205. ON_UPDATE_COMMAND_UI(ID_VIEW_PREVIEW_MODEL_FADE, OnUpdateViewPreviewModelFade)
  206. ON_COMMAND(ID_VIEW_PREVIEWGRIDNAV, OnViewPreviewGridNav)
  207. ON_UPDATE_COMMAND_UI(ID_VIEW_PREVIEWGRIDNAV, OnUpdateViewPreviewGridNav)
  208. ON_COMMAND(ID_COLLISION_WIREFRAME, OnCollisionWireframe)
  209. ON_UPDATE_COMMAND_UI(ID_COLLISION_WIREFRAME, OnUpdateCollisionWireframe)
  210. ON_COMMAND(ID_SHOW_DETAIL_OBJECTS, OnShowDetailObjects)
  211. ON_UPDATE_COMMAND_UI(ID_SHOW_DETAIL_OBJECTS, OnUpdateShowDetailObjects)
  212. ON_COMMAND(ID_SHOW_NODRAW_BRUSHES, OnShowNoDrawBrushes)
  213. ON_UPDATE_COMMAND_UI(ID_SHOW_NODRAW_BRUSHES, OnUpdateShowNoDrawBrushes)
  214. ON_COMMAND(ID_TOGGLE_GROUPIGNORE, OnToggleGroupignore)
  215. ON_UPDATE_COMMAND_UI(ID_TOGGLE_GROUPIGNORE, OnUpdateToggleGroupignore)
  216. ON_COMMAND(ID_VSCALE_TOGGLE, OnVscaleToggle)
  217. ON_COMMAND(ID_MAP_ENTITYREPORT, OnMapEntityreport)
  218. ON_COMMAND(ID_TOGGLE_SELECTBYHANDLE, OnToggleSelectbyhandle)
  219. ON_UPDATE_COMMAND_UI(ID_TOGGLE_SELECTBYHANDLE, OnUpdateToggleSelectbyhandle)
  220. ON_COMMAND(ID_TOGGLE_INFINITESELECT, OnToggleInfiniteselect)
  221. ON_UPDATE_COMMAND_UI(ID_TOGGLE_INFINITESELECT, OnUpdateToggleInfiniteselect)
  222. ON_COMMAND(ID_FILE_EXPORTTODXF, OnFileExporttodxf)
  223. ON_UPDATE_COMMAND_UI(ID_EDIT_APPLYTEXTURE, OnUpdateEditApplytexture)
  224. ON_COMMAND(ID_EDIT_CLEARSELECTION, OnEditClearselection)
  225. ON_UPDATE_COMMAND_UI(ID_EDIT_CLEARSELECTION, OnUpdateEditSelection)
  226. ON_COMMAND(ID_TOOLS_CENTER_ORIGINS, OnToolsCenterOrigins)
  227. ON_UPDATE_COMMAND_UI(ID_TOOLS_CENTER_ORIGINS, OnUpdateEditSelection)
  228. ON_COMMAND(ID_MAP_LOADPOINTFILE, OnMapLoadpointfile)
  229. ON_COMMAND(ID_MAP_UNLOADPOINTFILE, OnMapUnloadpointfile)
  230. ON_COMMAND(ID_MAP_LOADPORTALFILE, OnMapLoadportalfile)
  231. ON_COMMAND(ID_MAP_UNLOADPORTALFILE, OnMapUnloadportalfile)
  232. ON_COMMAND(ID_TOGGLE_3D_GRID, OnToggle3DGrid)
  233. ON_UPDATE_COMMAND_UI(ID_TOGGLE_3D_GRID, OnUpdateToggle3DGrid)
  234. ON_COMMAND(ID_EDIT_TOENTITY, OnEditToEntity)
  235. ON_UPDATE_COMMAND_UI(ID_EDIT_TOENTITY, OnUpdateEditSelection)
  236. ON_COMMAND_EX(ID_EDIT_UNDO, OnUndoRedo)
  237. ON_COMMAND_EX(ID_EDIT_REDO, OnUndoRedo)
  238. ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, OnUpdateUndoRedo)
  239. ON_UPDATE_COMMAND_UI(ID_EDIT_REDO, OnUpdateUndoRedo)
  240. ON_COMMAND(ID_VSCALE_CHANGED, OnChangeVertexscale)
  241. ON_COMMAND(ID_GOTO_BRUSH, OnViewGotoBrush)
  242. ON_COMMAND(ID_GOTO_COORDS, OnViewGotoCoords)
  243. ON_COMMAND(ID_SHOW_SELECTED_BRUSH_NUMBER, OnMapShowSelectedBrushNumber)
  244. ON_COMMAND(ID_EDIT_FINDENTITIES, OnEditFindEntities)
  245. ON_UPDATE_COMMAND_UI(ID_EDIT_FINDENTITIES, OnUpdateEditFunction)
  246. ON_COMMAND( ID_TOOLS_DISP_SOLIDDRAW, OnToggleDispSolidMask )
  247. ON_UPDATE_COMMAND_UI( ID_TOOLS_DISP_SOLIDDRAW, OnUpdateToggleSolidMask )
  248. ON_COMMAND( ID_TOOLS_DISP_DRAWWALKABLE, OnToggleDispDrawWalkable )
  249. ON_UPDATE_COMMAND_UI( ID_TOOLS_DISP_DRAWWALKABLE, OnUpdateToggleDispDrawWalkable )
  250. ON_COMMAND( ID_TOOLS_DISP_DRAW3D, OnToggleDispDraw3D )
  251. ON_UPDATE_COMMAND_UI( ID_TOOLS_DISP_DRAW3D, OnUpdateToggleDispDraw3D )
  252. ON_COMMAND( ID_TOOLS_DISP_DRAWBUILDABLE, OnToggleDispDrawBuildable )
  253. ON_UPDATE_COMMAND_UI( ID_TOOLS_DISP_DRAWBUILDABLE, OnUpdateToggleDispDrawBuildable )
  254. ON_COMMAND( ID_TOOLS_DISP_DRAWREMOVEDVERTS, OnToggleDispDrawRemovedVerts )
  255. ON_UPDATE_COMMAND_UI( ID_TOOLS_DISP_DRAWREMOVEDVERTS, OnUpdateToggleDispDrawRemovedVerts )
  256. ON_COMMAND(ID_MAP_DIFFMAPFILE, OnMapDiff)
  257. ON_COMMAND(ID_LOGICALOBJECT_LAYOUTGEOMETRIC, OnLogicalobjectLayoutgeometric)
  258. ON_COMMAND(ID_LOGICALOBJECT_LAYOUTDEFAULT, OnLogicalobjectLayoutdefault)
  259. ON_COMMAND(ID_LOGICALOBJECT_LAYOUTLOGICAL, OnLogicalobjectLayoutlogical)
  260. ON_COMMAND(ID_TOOLS_INSTANCES_HIDE, OnToolsInstancesHide)
  261. ON_UPDATE_COMMAND_UI(ID_TOOLS_INSTANCES_HIDE, OnUpdateToolsInstancesHide)
  262. ON_COMMAND(ID_TOOLS_INSTANCES_SHOWTINTED, OnToolsInstancesShowTinted)
  263. ON_UPDATE_COMMAND_UI(ID_TOOLS_INSTANCES_SHOWTINTED, OnUpdateToolsInstancesShowTinted)
  264. ON_COMMAND(ID_TOOLS_INSTANCES_SHOWNORMAL, OnToolsInstancesShowNormal)
  265. ON_UPDATE_COMMAND_UI(ID_TOOLS_INSTANCES_SHOWNORMAL, OnUpdateToolsInstancesShowNormal)
  266. ON_COMMAND(ID_INSTANCES_HIDEALL, OnInstancesHideAll)
  267. ON_COMMAND(ID_INSTANCES_SHOWALL, OnInstancesShowAll)
  268. ON_COMMAND(ID_TOOLS_NEWCORDON, OnNewCordon)
  269. //}}AFX_MSG_MAP
  270. ON_COMMAND(ID_INSTANCING_CREATEMANIFEST, &CMapDoc::OnInstancingCreatemanifest)
  271. ON_UPDATE_COMMAND_UI(ID_INSTANCING_CREATEMANIFEST, &CMapDoc::OnUpdateInstancingCreatemanifest)
  272. ON_COMMAND(ID_VERSIONCONTROL_CHECKINALL, &CMapDoc::OnInstancingCheckinAll)
  273. ON_UPDATE_COMMAND_UI(ID_VERSIONCONTROL_CHECKINALL, &CMapDoc::OnUpdateInstancingCheckinAll)
  274. ON_COMMAND(ID_VERSIONCONTROL_CHECKOUTMANIFEST, &CMapDoc::OnInstancingCheckOutManifest)
  275. ON_UPDATE_COMMAND_UI(ID_VERSIONCONTROL_CHECKOUTMANIFEST, &CMapDoc::OnUpdateInstancingCheckOutManifest)
  276. ON_COMMAND(ID_VERSIONCONTROL_ADDMANIFEST, &CMapDoc::OnInstancingAddManifest)
  277. ON_UPDATE_COMMAND_UI(ID_VERSIONCONTROL_ADDMANIFEST, &CMapDoc::OnUpdateInstancingAddManifest)
  278. ON_COMMAND(ID_INSTANCES_COLLAPSEALL, &CMapDoc::OnInstancesCollapseAll)
  279. ON_COMMAND(ID_INSTANCES_COLLAPSESELECTION, &CMapDoc::OnInstancesCollapseSelection)
  280. ON_COMMAND(ID_INSTANCES_COLLAPSEALLRECURSIVE, &CMapDoc::OnInstancesCollapseAllRecursive)
  281. ON_COMMAND(ID_INSTANCES_COLLAPSESELECTIONRECURSIVE, &CMapDoc::OnInstancesCollapseSelectionRecursive)
  282. ON_COMMAND(ID_FILE_VERSIONCONTROL_ADD, &CMapDoc::OnFileVersionControlAdd)
  283. ON_UPDATE_COMMAND_UI(ID_FILE_VERSIONCONTROL_ADD, OnUpdateVersionControlAdd)
  284. ON_COMMAND(ID_FILE_VERSIONCONTROL_CHECKOUT, &CMapDoc::OnFileVersionControlCheckOut)
  285. ON_UPDATE_COMMAND_UI(ID_FILE_VERSIONCONTROL_CHECKOUT, OnUpdateVersionControlCheckOut)
  286. ON_COMMAND(ID_FILE_VERSIONCONTROL_CHECKOUTBSP, &CMapDoc::OnFileVersionControlCheckOutBsp)
  287. ON_UPDATE_COMMAND_UI(ID_FILE_VERSIONCONTROL_CHECKOUTBSP, OnUpdateVersionControlCheckOutBsp)
  288. ON_COMMAND(ID_FILE_VERSIONCONTROL_CHECKIN, &CMapDoc::OnFileVersionControlCheckIn)
  289. ON_UPDATE_COMMAND_UI(ID_FILE_VERSIONCONTROL_CHECKIN, OnUpdateVersionControlCheckIn)
  290. ON_COMMAND(ID_FILE_VERSIONCONTROL_CHECKINALL, &CMapDoc::OnFileVersionControlCheckInAll)
  291. ON_UPDATE_COMMAND_UI(ID_FILE_VERSIONCONTROL_CHECKINALL, OnUpdateVersionControlCheckInAll)
  292. ON_COMMAND(ID_FILE_VERSIONCONTROL_OVERVIEW, &CMapDoc::OnFileVersionControlOverview)
  293. ON_COMMAND(ID_TOOLS_SPRINKLE, &CMapDoc::OnToolsSprinkle)
  294. ON_UPDATE_COMMAND_UI(ID_TOOLS_SPRINKLE, &CMapDoc::OnUpdateToolsSprinkle)
  295. ON_COMMAND( ID_VIEW_QUICKHIDE, OnQuickHide_HideObjects )
  296. ON_UPDATE_COMMAND_UI(ID_VIEW_QUICKHIDE, OnUpdateEditSelection)
  297. ON_COMMAND( ID_VIEW_QUICKHIDEUNSELECTED, OnQuickHide_HideUnselectedObjects )
  298. ON_UPDATE_COMMAND_UI(ID_VIEW_QUICKHIDEUNSELECTED, OnUpdateEditSelection)
  299. ON_COMMAND( ID_VIEW_QUICKUNHIDE, OnQuickHide_Unhide )
  300. ON_UPDATE_COMMAND_UI(ID_VIEW_QUICKUNHIDE, OnQuickHide_UpdateUnHide)
  301. ON_COMMAND( ID_TOGGLE_RADIUSCULLING, OnRadiusCulling )
  302. ON_UPDATE_COMMAND_UI(ID_TOGGLE_RADIUSCULLING, OnUpdateRadiusCulling )
  303. ON_COMMAND( ID_VIEW_QUICKHIDEVISGROUP, OnQuickHide_CreateVisGroupFromHidden )
  304. ON_UPDATE_COMMAND_UI(ID_VIEW_QUICKHIDEVISGROUP, OnQuickHide_UpdateCreateVisGroupFromHidden)
  305. END_MESSAGE_MAP()
  306. static CUtlVector<CMapDoc*> s_ActiveDocs;
  307. CMapDoc *CMapDoc::m_pMapDoc = NULL;
  308. CManifest *CMapDoc::m_pManifest = NULL;
  309. int CMapDoc::m_nInLevelLoad = 0;
  310. static CProgressDlg *pProgDlg;
  311. //
  312. // Clipboard. Global to all documents to allow copying from one document and
  313. // pasting in another.
  314. //
  315. class CHammerClipboard : public IHammerClipboard
  316. {
  317. public:
  318. CHammerClipboard(){}
  319. public:
  320. virtual void Destroy() { delete this; }
  321. public:
  322. CMapObjectList Objects;
  323. CMapWorld *pSourceWorld;
  324. BoundBox Bounds;
  325. Vector vecOriginalCenter;
  326. };
  327. IHammerClipboard * IHammerClipboard::CreateInstance()
  328. {
  329. return new CHammerClipboard;
  330. }
  331. // Get the global Hammer clipboard
  332. CHammerClipboard * GetHammerClipboard()
  333. {
  334. static class CGlobalHammerClipboard :
  335. public CHammerClipboard
  336. {
  337. virtual void Destroy() { Assert( 0 ); }
  338. }
  339. s_Clipboard;
  340. return &s_Clipboard;
  341. }
  342. // Convert a clipboard interface
  343. CHammerClipboard * GetHammerClipboard( IHammerClipboard *pInterface )
  344. {
  345. return static_cast< CHammerClipboard * >( pInterface );
  346. }
  347. struct BatchReplaceTextures_t
  348. {
  349. char szFindTexName[MAX_REPLACE_LINE_LENGTH]; // Texture to find.
  350. char szReplaceTexName[MAX_REPLACE_LINE_LENGTH]; // Texture to replace the found texture with.
  351. };
  352. struct AddNonSelectedInfo_t
  353. {
  354. CVisGroup *pGroup;
  355. int nCount;
  356. CMapObjectList *pList;
  357. BoundBox *pBox;
  358. CMapWorld *pWorld;
  359. };
  360. struct ReplaceTexInfo_t
  361. {
  362. char szFind[128];
  363. char szReplace[128];
  364. int iAction;
  365. int nReplaced;
  366. int iFindLen; // strlen(szFind) - for speed
  367. CMapWorld *pWorld;
  368. CMapDoc *pDoc;
  369. BOOL bMarkOnly;
  370. BOOL bHidden;
  371. bool m_bRescaleTextureCoordinates;
  372. };
  373. struct FindEntity_t
  374. {
  375. char szClassName[MAX_PATH]; //
  376. Vector Pos; //
  377. CMapEntity *pEntityFound; // Points to object found, NULL if unsuccessful.
  378. };
  379. struct SelectBoxInfo_t
  380. {
  381. CMapDoc *pDoc;
  382. BoundBox *pBox;
  383. BOOL bInside;
  384. SelectMode_t eSelectMode;
  385. };
  386. struct SelectLogicalBoxInfo_t
  387. {
  388. CMapDoc *pDoc;
  389. Vector2D vecMins;
  390. Vector2D vecMaxs;
  391. bool bInside;
  392. SelectMode_t eSelectMode;
  393. };
  394. #include <tier0/memdbgoff.h>
  395. //-----------------------------------------------------------------------------
  396. // Purpose: Constructor. Attaches all tools members to this document. Adds this
  397. // document to the list of active documents.
  398. //-----------------------------------------------------------------------------
  399. CMapDoc::CMapDoc(void)
  400. {
  401. m_nLogicalPositionCount = 0;
  402. int nSize = sizeof(CMapFace);
  403. nSize = sizeof(CMapSolid);
  404. m_bHasInitialUpdate = false;
  405. m_bLoading = false;
  406. m_pWorld = NULL;
  407. //
  408. // Set up undo/redo system.
  409. //
  410. m_pUndo = new CHistory;
  411. m_pRedo = new CHistory;
  412. m_pUndo->SetDocument(this);
  413. m_pUndo->SetOpposite(TRUE, m_pRedo);
  414. m_pRedo->SetDocument(this);
  415. m_pRedo->SetOpposite(FALSE, m_pUndo);
  416. // init object selection
  417. m_pSelection = new CSelection;
  418. m_pSelection->Init( this );
  419. m_VisGroups = new CUtlVector<CVisGroup *>();
  420. m_RootVisGroups = new CUtlVector<CVisGroup *>();
  421. // init tool manager
  422. m_pToolManager = new CToolManager;
  423. m_pToolManager->Init( this );
  424. Assert(GetMainWnd());
  425. m_bHideItems = false;
  426. m_bSnapToGrid = true;
  427. m_bShowGrid = true;
  428. m_bShowLogicalGrid = false;
  429. m_nGridSpacing = Options.view2d.iDefaultGrid;
  430. m_bShow3DGrid = false;
  431. m_tShowInstance = (ShowInstance_t)(Options.view3d.iViewInstancesMode);
  432. m_nExternalReferenceCount = 0;
  433. m_nDocVersion = 0;
  434. m_nNextMapObjectID = 1;
  435. m_nNextLoadID = 1; // PORTAL2 SHIP: keep track of load order to preserve it on save so that maps can be diffed.
  436. m_nNextNodeID = 1;
  437. m_pGame = NULL;
  438. m_flAnimationTime = 0.0f;
  439. m_bEditingPrefab = false;
  440. m_bPrefab = false;
  441. m_bIsAnimating = false;
  442. m_strLastExportFileName = "";
  443. m_bDispSolidDrawMask = true;
  444. m_bDispDrawWalkable = false;
  445. m_bDispDrawBuildable = false;
  446. m_bDispDraw3D = true;
  447. m_bDispDrawRemovedVerts = false;
  448. m_bVisGroupUpdatesLocked = false;
  449. s_ActiveDocs.AddToTail(this);
  450. m_pBSPLighting = 0;
  451. m_pPortalFile = NULL;
  452. m_SmoothingGroupVisual = 0;
  453. UpdateStatusBarSnap();
  454. //setup autosave members
  455. m_bNeedsAutosave = false;
  456. m_bIsAutosave = false;
  457. m_strAutosavedFrom = "";
  458. m_bIsCordoning = false;
  459. m_nEditCordon = 0;
  460. m_nEditCordonBox = 0;
  461. m_bIsEditable = true;
  462. m_pManifestOwner = NULL;
  463. m_bCollapsingInstances = false;
  464. m_bReadOnly = true;
  465. m_bIsVersionControlled = false;
  466. m_bCheckedOut = false;
  467. m_bDefaultCheckin = false;
  468. m_bDeferredSave = false;
  469. m_pGridNav = NULL;
  470. #if 0
  471. #define DOTA_FOW_MAX_HEIGHT_LEVELS 4
  472. #define DOTA_HEIGHT_FILENAME "scripts/height_levels.txt"
  473. KeyValues *kv = new KeyValues( "heightfile" );
  474. Assert( kv );
  475. float flHeightLevels[DOTA_FOW_MAX_HEIGHT_LEVELS];
  476. int nNumHeights = -1;
  477. if ( kv->LoadFromFile( g_pFullFileSystem, DOTA_HEIGHT_FILENAME, "MOD" ) )
  478. {
  479. char temp[ 128 ];
  480. for ( int i = 0; i < DOTA_FOW_MAX_HEIGHT_LEVELS; i++ )
  481. {
  482. sprintf( temp, "%d", i );
  483. flHeightLevels[i] = kv->GetFloat( temp, 64.0f );
  484. }
  485. kv->deleteThis();
  486. nNumHeights = DOTA_FOW_MAX_HEIGHT_LEVELS;
  487. }
  488. m_pFoW = new CFoW();
  489. m_pFoW->SetNumberOfTeams( 1 );
  490. m_pFoW->SetSize( Vector( -8192.0f, -8192.0f, -1024.0f ), Vector( 8192.0f, 8192.0f, 1024.0f ), 128, ( nNumHeights == -1 ? 64 : -1 ) );
  491. if ( nNumHeights != -1 )
  492. {
  493. m_pFoW->SetCustomVerticalLevels( flHeightLevels, nNumHeights );
  494. }
  495. #else
  496. m_pFoW = NULL;
  497. #endif
  498. }
  499. //-----------------------------------------------------------------------------
  500. // Purpose: Destructor.
  501. //-----------------------------------------------------------------------------
  502. CMapDoc::~CMapDoc(void)
  503. {
  504. if ( g_pFoundryTool )
  505. g_pFoundryTool->OnMapDocDestroy( this );
  506. GetMainWnd()->pObjectProperties->MarkDataDirty();
  507. //
  508. // Remove this doc from the list of active docs.
  509. //
  510. s_ActiveDocs.FindAndRemove(this);
  511. if (this == GetActiveMapDoc())
  512. {
  513. SetActiveMapDoc(NULL);
  514. }
  515. DeleteContents();
  516. delete m_pUndo;
  517. delete m_pRedo;
  518. delete m_pToolManager;
  519. if ( m_VisGroups )
  520. {
  521. delete m_VisGroups;
  522. m_VisGroups = NULL;
  523. }
  524. if ( m_RootVisGroups )
  525. {
  526. delete m_RootVisGroups;
  527. m_RootVisGroups = NULL;
  528. }
  529. if ( m_pManifestOwner == NULL && m_pSelection )
  530. {
  531. delete m_pSelection;
  532. m_pSelection = NULL;
  533. }
  534. if ( m_pFoW )
  535. {
  536. delete m_pFoW;
  537. m_pFoW = NULL;
  538. }
  539. OnDisableLightPreview();
  540. }
  541. //-----------------------------------------------------------------------------
  542. // Default logical placement for new entities
  543. //-----------------------------------------------------------------------------
  544. void CMapDoc::GetDefaultNewLogicalPosition( Vector2D &vecPosition )
  545. {
  546. int nMaxDim = ( g_MAX_MAP_COORD - g_MIN_MAP_COORD ) / LOGICAL_SPACING;
  547. int x = m_nLogicalPositionCount / nMaxDim;
  548. int y = m_nLogicalPositionCount - x * nMaxDim;
  549. x = x % nMaxDim;
  550. vecPosition.x = x * LOGICAL_SPACING;
  551. if ( vecPosition.x > g_MAX_MAP_COORD )
  552. {
  553. vecPosition.x += g_MIN_MAP_COORD - g_MAX_MAP_COORD;
  554. }
  555. vecPosition.y = y * LOGICAL_SPACING;
  556. if ( vecPosition.y > g_MAX_MAP_COORD )
  557. {
  558. vecPosition.y += g_MIN_MAP_COORD - g_MAX_MAP_COORD;
  559. }
  560. ++m_nLogicalPositionCount;
  561. }
  562. //-----------------------------------------------------------------------------
  563. // Purpose: Removes any object groups with no members or only one member.
  564. //-----------------------------------------------------------------------------
  565. void CMapDoc::RemoveEmptyGroups(void)
  566. {
  567. int nEmptyGroupCount = 0;
  568. CUtlVector<CMapGroup *> GroupList;
  569. m_pWorld->GetGroupList(GroupList);
  570. int nGroupCount = GroupList.Count();
  571. for (int i = nGroupCount - 1; i >= 0; i--)
  572. {
  573. CMapGroup *pGroup = GroupList.Element(i);
  574. if (!pGroup->GetChildCount())
  575. {
  576. // We found an empty group. Remove it.
  577. nEmptyGroupCount++;
  578. RemoveObjectFromWorld(pGroup, false);
  579. GroupList.FastRemove(i);
  580. delete pGroup;
  581. }
  582. }
  583. if (nEmptyGroupCount)
  584. {
  585. Msg(mwWarning, "Removed %d object group(s) with no children.\n", nEmptyGroupCount);
  586. }
  587. }
  588. void CMapDoc::AssignToGroups()
  589. {
  590. //
  591. // Get a list of all the groups.
  592. //
  593. CUtlVector<CMapGroup *> GroupList;
  594. int nGroupCount = m_pWorld->GetGroupList(GroupList);
  595. //
  596. // Assign all loaded objects to their proper groups.
  597. //
  598. CUtlVector<MapObjectPair_t> GroupedObjects;
  599. const CMapObjectList *pChildren = m_pWorld->GetChildren();
  600. FOR_EACH_OBJ( *pChildren, pos )
  601. {
  602. // Assign the object to its group, if any.
  603. CMapClass *pChild = (CUtlReference< CMapClass >)pChildren->Element(pos);
  604. const char *pszGroupID = pChild->GetEditorKeyValue("groupid");
  605. if (pszGroupID != NULL)
  606. {
  607. int nID;
  608. CChunkFile::ReadKeyValueInt(pszGroupID, nID);
  609. MapObjectPair_t pair;
  610. for (int i = 0; i < nGroupCount; i++)
  611. {
  612. CMapGroup *pGroup = GroupList.Element(i);
  613. if (pGroup->GetID() == nID)
  614. {
  615. // Add the object to a list for removal from the world.
  616. pair.pObject1 = pChild;
  617. pair.pObject2 = pGroup;
  618. GroupedObjects.AddToTail(pair);
  619. break;
  620. }
  621. }
  622. }
  623. }
  624. //
  625. // Remove all the objects that were added to groups from the world, since they are
  626. // now children of CMapGroup objects that are already in the world.
  627. //
  628. int nPairCount = GroupedObjects.Count();
  629. for (int i = 0; i < nPairCount; i++)
  630. {
  631. m_pWorld->RemoveChild(GroupedObjects.Element(i).pObject1);
  632. GroupedObjects.Element(i).pObject2->AddChild(GroupedObjects.Element(i).pObject1);
  633. }
  634. }
  635. //-----------------------------------------------------------------------------
  636. // Purpose: Called after loading a VMF file. Assigns all objects to their proper
  637. // visgroups. It also finds the next unique ID to use when creating new objects.
  638. //-----------------------------------------------------------------------------
  639. void CMapDoc::AssignToVisGroups(void)
  640. {
  641. EnumChildrenPos_t pos;
  642. CMapClass *pChild = m_pWorld->GetFirstDescendent(pos);
  643. while (pChild != NULL)
  644. {
  645. //
  646. // HACK: If this entity needs a node ID and doesn't have one, set it now.
  647. // Would be better implemented more generically.
  648. //
  649. CMapEntity *pEntity = dynamic_cast<CMapEntity *>(pChild);
  650. if (pEntity != NULL)
  651. {
  652. if (pEntity->IsNodeClass() && (pEntity->GetNodeID() == 0))
  653. {
  654. int nID = GetNextNodeID();
  655. char szID[80];
  656. itoa(nID, szID, 10);
  657. pEntity->SetKeyValue("nodeid", szID);
  658. }
  659. }
  660. //
  661. // Assign the object to its visgroups, if any. Visgroup IDs are held
  662. // in a temporary keyvalue list that was loaded from the VMF.
  663. //
  664. int nKeyCount = pChild->GetEditorKeyCount();
  665. for (int i = 0; i < nKeyCount; i++)
  666. {
  667. const char *pszKey = pChild->GetEditorKey(i);
  668. if (!stricmp(pszKey, "visgroupid"))
  669. {
  670. const char *pszVisGroupID = pChild->GetEditorKeyValue(i);
  671. Assert(pszVisGroupID != NULL);
  672. if (pszVisGroupID != NULL)
  673. {
  674. unsigned int nID = (unsigned int)atoi(pszVisGroupID);
  675. CVisGroup *pVisGroup = VisGroups_GroupForID(nID);
  676. // If an object is assigned to a nonexistent visgroup, we do nothing here,
  677. // which effectively discards the bogus visgroup assignment.
  678. if (pVisGroup)
  679. {
  680. pChild->AddVisGroup(pVisGroup);
  681. if (CVisGroup::IsConvertingOldVisGroups() && (pVisGroup->GetVisible() != VISGROUP_SHOWN))
  682. {
  683. pChild->VisGroupShow(false);
  684. }
  685. }
  686. }
  687. }
  688. else if (!stricmp(pszKey, "colorvisgroupid"))
  689. {
  690. const char *pszVisGroupID = pChild->GetEditorKeyValue(i);
  691. Assert(pszVisGroupID != NULL);
  692. if (pszVisGroupID != NULL)
  693. {
  694. unsigned int nID = (unsigned int)atoi(pszVisGroupID);
  695. CVisGroup *pVisGroup = VisGroups_GroupForID(nID);
  696. Assert(pVisGroup != NULL);
  697. pChild->SetColorVisGroup(pVisGroup);
  698. }
  699. }
  700. }
  701. //
  702. // Free the temporary keyvalue list.
  703. //
  704. pChild->RemoveEditorKeys();
  705. pChild = m_pWorld->GetNextDescendent(pos);
  706. }
  707. VisGroups_Validate();
  708. AssignAllToAutoVisGroups();
  709. VisGroups_UpdateAll();
  710. }
  711. //-----------------------------------------------------------------------------
  712. // Purpose: Makes sure that the visgroup assignments are valid.
  713. //-----------------------------------------------------------------------------
  714. void CMapDoc::VisGroups_Validate()
  715. {
  716. EnumChildrenPos_t pos;
  717. CMapClass *pChild = m_pWorld->GetFirstDescendent(pos);
  718. while (pChild)
  719. {
  720. CMapClass *pParent = pChild->GetParent();
  721. // Old versions of Hammer had wacky visgroup assignments -- solid children of groups or entities
  722. // could belong to visgroups, even if those visgroups no longer existed.
  723. // For new versions of Hammer, just make sure that the object is allowed to belong to a visgroup.
  724. if (((g_nFileFormatVersion < 100) && (!IsWorldObject(pParent))) ||
  725. !VisGroups_ObjectCanBelongToVisGroup(pChild))
  726. {
  727. int nCount = pChild->GetVisGroupCount();
  728. if (nCount != 0)
  729. {
  730. Msg(mwWarning, "'%s', child of '%s', was in visgroups illegally. Removed from visgroups.", pChild->GetDescription(), pParent->GetDescription());
  731. pChild->RemoveAllVisGroups();
  732. }
  733. }
  734. pChild = m_pWorld->GetNextDescendent(pos);
  735. }
  736. }
  737. //-----------------------------------------------------------------------------
  738. // Purpose: Begins a remote shell editing session. This causes the GUI to be
  739. // disabled to avoid version mismatches between the editor's map and the
  740. // shell client's map.
  741. //-----------------------------------------------------------------------------
  742. void CMapDoc::BeginShellSession(void)
  743. {
  744. //
  745. // Disable all our views.
  746. //
  747. POSITION pos = GetFirstViewPosition();
  748. while (pos != NULL)
  749. {
  750. CView *pView = GetNextView(pos);
  751. pView->EnableWindow(FALSE);
  752. }
  753. //
  754. // Set the modified flag to update our version number. This marks the working
  755. // version of the map in memory as different from the saved version on disk.
  756. //
  757. SetModifiedFlag();
  758. GetMainWnd()->BeginShellSession();
  759. }
  760. void CMapDoc::GetSelectedCenter(Vector &vCenter)
  761. {
  762. Morph3D *pMorphTool = dynamic_cast<Morph3D*>( m_pToolManager->GetActiveTool() );
  763. CToolBlock *pBlockTool = dynamic_cast<CToolBlock*>( m_pToolManager->GetActiveTool() );
  764. if ( pMorphTool )
  765. {
  766. pMorphTool->GetSelectedCenter(vCenter);
  767. }
  768. else if ( pBlockTool )
  769. {
  770. pBlockTool->GetBoundsCenter(vCenter);
  771. }
  772. else if (!m_pSelection->IsEmpty())
  773. {
  774. m_pSelection->GetBoundsCenter(vCenter);
  775. }
  776. else if ( m_pWorld )
  777. {
  778. m_pWorld->GetBoundsCenter(vCenter);
  779. }
  780. else
  781. {
  782. vCenter.Init();
  783. }
  784. }
  785. //-----------------------------------------------------------------------------
  786. // Purpose:
  787. //-----------------------------------------------------------------------------
  788. void CMapDoc::CenterViewsOnSelection()
  789. {
  790. Vector vecCenter;
  791. GetSelectedCenter( vecCenter );
  792. Center2DViewsOn(vecCenter);
  793. Center3DViewsOn(vecCenter);
  794. CenterLogicalViewsOnSelection();
  795. }
  796. //-----------------------------------------------------------------------------
  797. // Purpose: Handles the View | Center On Selection menu item.
  798. //-----------------------------------------------------------------------------
  799. void CMapDoc::Center2DViewsOnSelection(void)
  800. {
  801. Vector vecCenter;
  802. GetSelectedCenter( vecCenter );
  803. Center2DViewsOn( vecCenter );
  804. }
  805. //-----------------------------------------------------------------------------
  806. // Purpose: Handles the View | Center 3D Views On Selection menu item.
  807. //-----------------------------------------------------------------------------
  808. void CMapDoc::Center3DViewsOnSelection()
  809. {
  810. Vector vecCenter;
  811. GetSelectedCenter( vecCenter );
  812. Center3DViewsOn( vecCenter );
  813. }
  814. void CMapDoc::CenterLogicalViewsOnSelection()
  815. {
  816. Vector2D vecLogicalCenter;
  817. if ( m_pSelection->GetLogicalBoundsCenter( vecLogicalCenter ) )
  818. {
  819. CenterLogicalViewsOn(vecLogicalCenter);
  820. }
  821. }
  822. //-----------------------------------------------------------------------------
  823. // Purpose: Called after loading a VMF file. Finds the next unique IDs to use
  824. // when creating new objects, nodes, and faces.
  825. //-----------------------------------------------------------------------------
  826. void CMapDoc::CountGUIDs(void)
  827. {
  828. CTypedPtrList<CPtrList, MapObjectPair_t *> GroupedObjects;
  829. // This increments the CMapWorld face ID but it doesn't matter since we're setting it below.
  830. int nNextFaceID = m_pWorld->FaceID_GetNext();
  831. EnumChildrenPos_t pos;
  832. CMapClass *pChild = m_pWorld->GetFirstDescendent(pos);
  833. while (pChild != NULL)
  834. {
  835. //
  836. // Keep track of the highest numbered object ID in this document.
  837. //
  838. if (pChild->GetID() >= m_nNextMapObjectID)
  839. {
  840. m_nNextMapObjectID = pChild->GetID() + 1;
  841. }
  842. //
  843. // Keep track of the highest numbered node ID in this document.
  844. //
  845. CMapEntity *pEntity = dynamic_cast<CMapEntity *>(pChild);
  846. if (pEntity != NULL)
  847. {
  848. //
  849. // Blah. Classes aren't assigned until PostLoadWorld, so we have to
  850. // look at our classname keyvalue to determine whether we are a node class.
  851. //
  852. const char *pszClass = pEntity->GetKeyValue("classname");
  853. if (pEntity->IsNodeClass(pszClass))
  854. {
  855. int nID = pEntity->GetNodeID();
  856. if (nID >= m_nNextNodeID)
  857. {
  858. m_nNextNodeID = nID + 1;
  859. }
  860. }
  861. }
  862. else
  863. {
  864. //
  865. // Keep track of the highest numbered face ID in this document.
  866. //
  867. CMapSolid *pSolid = dynamic_cast<CMapSolid *>(pChild);
  868. if (pSolid != NULL)
  869. {
  870. for (int nFace = 0; nFace < pSolid->GetFaceCount(); nFace++)
  871. {
  872. CMapFace *pFace = pSolid->GetFace(nFace);
  873. int nFaceID = pFace->GetFaceID();
  874. if (nFaceID >= nNextFaceID)
  875. {
  876. nNextFaceID = nFaceID + 1;
  877. }
  878. }
  879. }
  880. }
  881. pChild = m_pWorld->GetNextDescendent(pos);
  882. }
  883. m_pWorld->FaceID_SetNext(nNextFaceID);
  884. }
  885. //-----------------------------------------------------------------------------
  886. // Purpose:
  887. // Input : pszClassName -
  888. // x -
  889. // y -
  890. // z -
  891. // Output : Returns true on success, false on failure.
  892. //-----------------------------------------------------------------------------
  893. CMapEntity *CMapDoc::CreateEntity(const char *pszClassName, float x, float y, float z)
  894. {
  895. CMapEntity *pEntity = new CMapEntity;
  896. if (pEntity != NULL)
  897. {
  898. GetHistory()->MarkUndoPosition(NULL, "New Entity");
  899. pEntity->SetPlaceholder(TRUE);
  900. Vector Pos;
  901. Pos[0] = x;
  902. Pos[1] = y;
  903. Pos[2] = z;
  904. pEntity->SetOrigin(Pos);
  905. pEntity->SetClass(pszClassName);
  906. AddObjectToWorld(pEntity);
  907. GetHistory()->KeepNew(pEntity);
  908. //
  909. // Update all the views.
  910. //
  911. /* UpdateBox ub;
  912. CMapObjectList ObjectList;
  913. ObjectList.AddTail(pEntity);
  914. ub.Objects = &ObjectList;
  915. ub.Box = *((BoundBox *)pEntity); */
  916. SetModifiedFlag();
  917. }
  918. return(pEntity);
  919. }
  920. //-----------------------------------------------------------------------------
  921. // Purpose:
  922. // Input : pszClassName -
  923. // x -
  924. // y -
  925. // z -
  926. // Output : Returns true on success, false on failure.
  927. //-----------------------------------------------------------------------------
  928. // dvs: Seems better to move some of this functionality into DeleteObject and replace calls to this with FindEntity/DeleteObject calls.
  929. // Probably need to replicate all functions in the doc as follows: DeleteObject, DeleteObjectList to optimize updates. Either that
  930. // or we need a way to lock and unlock updates.
  931. bool CMapDoc::DeleteEntity(const char *pszClassName, float x, float y, float z)
  932. {
  933. CMapEntity *pEntity = FindEntity(pszClassName, x, y, z);
  934. if (pEntity != NULL)
  935. {
  936. GetHistory()->MarkUndoPosition(NULL, "Delete");
  937. DeleteObject(pEntity);
  938. SetModifiedFlag();
  939. return(true);
  940. }
  941. return(false);
  942. }
  943. //-----------------------------------------------------------------------------
  944. // Purpose: Ends a remote shell editing session. This enables the GUI that was
  945. // disabled by BeginShellSession.
  946. //-----------------------------------------------------------------------------
  947. void CMapDoc::EndShellSession(void)
  948. {
  949. //
  950. // Enable all our views.
  951. //
  952. POSITION pos = GetFirstViewPosition();
  953. while (pos != NULL)
  954. {
  955. CView *pView = GetNextView(pos);
  956. pView->EnableWindow(TRUE);
  957. }
  958. GetMainWnd()->EndShellSession();
  959. }
  960. //-----------------------------------------------------------------------------
  961. // Purpose: Finds an object in the map by number. The number corresponds to the
  962. // order in which the object is written to the map file. Thus, through
  963. // this function, brushes and entities can be located by ordinal, as
  964. // reported by the MAP compile tools.
  965. // Input : pObject - Object being checked for a match.
  966. // pFindInfo - Structure containing the search criterea.
  967. // Output : Returns FALSE if this is the object that we are looking for, TRUE
  968. // to continue iterating.
  969. //-----------------------------------------------------------------------------
  970. BOOL CMapDoc::FindEntityCallback(CMapClass *pObject, FindEntity_t *pFindInfo)
  971. {
  972. CMapEntity *pEntity = dynamic_cast<CMapEntity *>(pObject);
  973. if (pEntity != NULL)
  974. {
  975. Vector Pos;
  976. pEntity->GetOrigin(Pos);
  977. // HACK: Round to origin integers since entity origins are rounded when
  978. // saving to MAP file. This makes finding entities from the engine
  979. // in the editor work.
  980. Pos[0] = rint(Pos[0]);
  981. Pos[1] = rint(Pos[1]);
  982. Pos[2] = rint(Pos[2]);
  983. if (VectorCompare(Pos, pFindInfo->Pos))
  984. {
  985. if (stricmp(pEntity->GetClassName(), pFindInfo->szClassName) == 0)
  986. {
  987. pFindInfo->pEntityFound = pEntity;
  988. return(FALSE);
  989. }
  990. }
  991. }
  992. return(TRUE);
  993. }
  994. //-----------------------------------------------------------------------------
  995. // Purpose: Finds an entity by classname and position. Some ambiguity if two
  996. // entities of the same name are at the same position.
  997. // Input : pszClassName - Class name of entity to find, ie "info_node".
  998. // x, y, z - Position of entity in world coordinates.
  999. // Output : Returns a pointer to the entity, NULL if none was found.
  1000. //-----------------------------------------------------------------------------
  1001. CMapEntity *CMapDoc::FindEntity(const char *pszClassName, float x, float y, float z)
  1002. {
  1003. CMapEntity *pEntity = NULL;
  1004. if (pszClassName != NULL)
  1005. {
  1006. FindEntity_t FindInfo;
  1007. memset(&FindInfo, 0, sizeof(FindInfo));
  1008. strcpy(FindInfo.szClassName, pszClassName);
  1009. // dvs: HACK - only find by integer coordinates because the editor rounds
  1010. // entity origins when saving the MAP file.
  1011. FindInfo.Pos[0] = rint(x);
  1012. FindInfo.Pos[1] = rint(y);
  1013. FindInfo.Pos[2] = rint(z);
  1014. m_pWorld->EnumChildren((ENUMMAPCHILDRENPROC)FindEntityCallback, (DWORD)&FindInfo, MAPCLASS_TYPE(CMapEntity));
  1015. if (FindInfo.pEntityFound != NULL)
  1016. {
  1017. Assert(FindInfo.pEntityFound->IsMapClass(MAPCLASS_TYPE(CMapEntity)));
  1018. }
  1019. pEntity = FindInfo.pEntityFound;
  1020. }
  1021. return(pEntity);
  1022. }
  1023. //-----------------------------------------------------------------------------
  1024. //-----------------------------------------------------------------------------
  1025. CMapEntity *CMapDoc::FindEntityByName( const char *pszName, bool bVisiblesOnly )
  1026. {
  1027. return m_pWorld->FindEntityByName( pszName, bVisiblesOnly );
  1028. }
  1029. BOOL CMapDoc::FindEntityByHammerIDCallback( CMapClass *pObject, FindEntityByHammerID_t *pFindInfo )
  1030. {
  1031. CMapEntity *pEntity = dynamic_cast<CMapEntity *>(pObject);
  1032. if ( pEntity != NULL )
  1033. {
  1034. if ( pObject->GetHammerID() == pFindInfo->m_nHammerID )
  1035. {
  1036. pFindInfo->m_pEntityFound = pEntity;
  1037. return(FALSE);
  1038. }
  1039. }
  1040. return(TRUE);
  1041. }
  1042. //-------------------------------------------------------------------------------------------------
  1043. //-------------------------------------------------------------------------------------------------
  1044. CMapEntity *CMapDoc::FindEntityByHammerID( int nHammerID )
  1045. {
  1046. FindEntityByHammerID_t FindInfo;
  1047. memset(&FindInfo, 0, sizeof(FindInfo));
  1048. FindInfo.m_nHammerID = nHammerID;
  1049. m_pWorld->EnumChildren( (ENUMMAPCHILDRENPROC)FindEntityByHammerIDCallback, (DWORD)&FindInfo, MAPCLASS_TYPE(CMapEntity) );
  1050. return FindInfo.m_pEntityFound;
  1051. }
  1052. //-----------------------------------------------------------------------------
  1053. // Purpose: Finds all entities in the map with a given class name.
  1054. // Input : pFound - List of entities with the class name.
  1055. // pszClassName - Class name to match, case insensitive.
  1056. // Output : Returns true if any matches were found, false if not.
  1057. //-----------------------------------------------------------------------------
  1058. bool CMapDoc::FindEntitiesByClassName(CMapEntityList &Found, const char *pszClassName, bool bVisiblesOnly)
  1059. {
  1060. return m_pWorld->FindEntitiesByClassName( Found, pszClassName, bVisiblesOnly );
  1061. }
  1062. //-----------------------------------------------------------------------------
  1063. //
  1064. //-----------------------------------------------------------------------------
  1065. bool CMapDoc::FindEntitiesByKeyValue(CMapEntityList &Found, const char *pszKey, const char *pszValue, bool bVisiblesOnly)
  1066. {
  1067. return m_pWorld->FindEntitiesByKeyValue( Found, pszKey, pszValue, bVisiblesOnly );
  1068. }
  1069. //-----------------------------------------------------------------------------
  1070. //
  1071. //-----------------------------------------------------------------------------
  1072. bool CMapDoc::FindEntitiesByName( CMapEntityList &Found, const char *pszName, bool bVisiblesOnly )
  1073. {
  1074. return m_pWorld->FindEntitiesByName( Found, pszName, bVisiblesOnly );
  1075. }
  1076. //-----------------------------------------------------------------------------
  1077. //
  1078. //-----------------------------------------------------------------------------
  1079. bool CMapDoc::FindEntitiesByNameOrClassName(CMapEntityList &Found, const char *pszName, bool bVisiblesOnly)
  1080. {
  1081. return m_pWorld->FindEntitiesByNameOrClassName(Found, pszName, bVisiblesOnly);
  1082. }
  1083. //-----------------------------------------------------------------------------
  1084. // Purpose:
  1085. //-----------------------------------------------------------------------------
  1086. int CMapDoc::GetDocumentCount(void)
  1087. {
  1088. return s_ActiveDocs.Count();
  1089. }
  1090. //-----------------------------------------------------------------------------
  1091. // Purpose:
  1092. //-----------------------------------------------------------------------------
  1093. CMapDoc *CMapDoc::GetDocument(int index)
  1094. {
  1095. return s_ActiveDocs.Element(index);
  1096. }
  1097. //-----------------------------------------------------------------------------
  1098. //-----------------------------------------------------------------------------
  1099. void CMapDoc::OnNewCordon()
  1100. {
  1101. BoundBox *pBox;
  1102. Cordon_t *pCordon = Cordon_CreateNewCordon( NULL, &pBox );
  1103. if ( !pCordon || !pBox )
  1104. return;
  1105. // Not very useful to do this without editing it after.
  1106. GetTools()->SetTool( TOOL_EDITCORDON );
  1107. Cordon_SelectCordonForEditing( pCordon, pBox );
  1108. }
  1109. //-----------------------------------------------------------------------------
  1110. // Purpose:
  1111. //-----------------------------------------------------------------------------
  1112. void CMapDoc::OnViewGotoCoords()
  1113. {
  1114. 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");
  1115. while (dlg.DoModal() == IDOK)
  1116. {
  1117. Vector posVec;
  1118. Vector angVec;
  1119. char setposString[255];
  1120. char setangString[255];
  1121. if (sscanf(dlg.m_string, "%f %f %f", &posVec.x, &posVec.y, &posVec.z) == 3)
  1122. {
  1123. // SILLY:
  1124. if ((posVec.x == 200) && (posVec.y == -4096) && (posVec.z == 1154))
  1125. {
  1126. 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)
  1127. continue;
  1128. }
  1129. CenterViewsOn(posVec);
  1130. return;
  1131. }
  1132. if ( sscanf( dlg.m_string, "%s %f %f %f%s %f %f %f", setposString, &posVec.x, &posVec.y, &posVec.z, setangString, &angVec.x, &angVec.y, &angVec.z ) == 8 )
  1133. {
  1134. posVec.z += HALF_LIFE_2_EYE_HEIGHT;
  1135. CenterViewsOn( posVec );
  1136. Set3DViewsPosAng( posVec, angVec );
  1137. return;
  1138. }
  1139. AfxMessageBox("Please enter 3 coordinates, space-delimited or use\nsetpos x y z;setang u v w format.", MB_OK | MB_ICONEXCLAMATION);
  1140. }
  1141. }
  1142. //-----------------------------------------------------------------------------
  1143. // Purpose: Invokes a dialog for finding entities by targetname.
  1144. //-----------------------------------------------------------------------------
  1145. void CMapDoc::OnEditFindEntities(void)
  1146. {
  1147. CStrDlg dlg(0, "", "Targetname to find:", "Find Entities");
  1148. if (dlg.DoModal() == IDOK)
  1149. {
  1150. CMapEntityList Found;
  1151. FindEntitiesByName(Found, dlg.m_string, false);
  1152. if (Found.Count() != 0)
  1153. {
  1154. CMapObjectList Select;
  1155. FOR_EACH_OBJ( Found, pos )
  1156. {
  1157. CMapEntity *pEntity = Found.Element(pos);
  1158. Select.AddToTail(pEntity);
  1159. }
  1160. SelectObjectList(&Select);
  1161. CenterViewsOnSelection();
  1162. }
  1163. }
  1164. }
  1165. //-----------------------------------------------------------------------------
  1166. // Purpose: Brings up the 'Go to Brush ID' dialog and selects the indicated
  1167. // brush, if it can be found.
  1168. //-----------------------------------------------------------------------------
  1169. void CMapDoc::OnViewGotoBrush(void)
  1170. {
  1171. CGotoBrushDlg dlg;
  1172. if (dlg.DoModal() == IDOK)
  1173. {
  1174. CMapSolid *pFoundSolid = NULL;
  1175. EnumChildrenPos_t pos;
  1176. CMapClass *pChild = m_pWorld->GetFirstDescendent(pos);
  1177. while (pChild)
  1178. {
  1179. CMapSolid *pSolid = dynamic_cast<CMapSolid *>(pChild);
  1180. if (pSolid && (pSolid->GetID() == dlg.m_nBrushID))
  1181. {
  1182. pFoundSolid = pSolid;
  1183. break;
  1184. }
  1185. pChild = m_pWorld->GetNextDescendent(pos);
  1186. }
  1187. //
  1188. // If we found the brush, select it and center the 2D views on it.
  1189. //
  1190. if (pFoundSolid != NULL)
  1191. {
  1192. SelectObject(pFoundSolid, scSelect|scClear|scSaveChanges );
  1193. CenterViewsOnSelection();
  1194. }
  1195. else
  1196. {
  1197. AfxMessageBox("That brush ID does not exist.");
  1198. }
  1199. }
  1200. }
  1201. class CFindBrushInfo
  1202. {
  1203. public:
  1204. CMapSolid *m_pBrush; // The brush to find.
  1205. int m_nObjectCount;
  1206. bool m_bFound;
  1207. };
  1208. BOOL CMapDoc::GetBrushNumberCallback(CMapClass *pObject, void *pFindInfoVoid)
  1209. {
  1210. CFindBrushInfo *pFindInfo = (CFindBrushInfo*)pFindInfoVoid;
  1211. if ( pObject->IsVisible() )
  1212. {
  1213. if ( pObject == pFindInfo->m_pBrush )
  1214. {
  1215. pFindInfo->m_bFound = true;
  1216. return FALSE; // found it!
  1217. }
  1218. else
  1219. {
  1220. pFindInfo->m_nObjectCount++;
  1221. return TRUE;
  1222. }
  1223. }
  1224. else
  1225. {
  1226. return TRUE;
  1227. }
  1228. }
  1229. void CMapDoc::OnMapShowSelectedBrushNumber()
  1230. {
  1231. CFindBrushInfo info;
  1232. info.m_nObjectCount = 0;
  1233. info.m_bFound = false;
  1234. if ( m_pSelection->IsEmpty() )
  1235. {
  1236. AfxMessageBox( ID_NO_BRUSH_SELECTED, MB_OK );
  1237. return;
  1238. }
  1239. const CMapObjectList *pSelList = m_pSelection->GetList();
  1240. CMapClass *pMapClass = (CUtlReference< CMapClass >)pSelList->Element( 0 );
  1241. info.m_pBrush = dynamic_cast< CMapSolid* >( pMapClass );
  1242. if ( !info.m_pBrush )
  1243. {
  1244. AfxMessageBox( ID_NO_BRUSH_SELECTED, MB_OK );
  1245. return;
  1246. }
  1247. // Enumerate the visible brushes..
  1248. m_pWorld->EnumChildrenRecurseGroupsOnly(
  1249. (ENUMMAPCHILDRENPROC)&CMapDoc::GetBrushNumberCallback, (DWORD)&info, MAPCLASS_TYPE(CMapSolid));
  1250. CString str;
  1251. if ( info.m_bFound )
  1252. {
  1253. str.FormatMessage( ID_BRUSH_NUMBER, info.m_nObjectCount );
  1254. }
  1255. else
  1256. {
  1257. str.FormatMessage( ID_BRUSH_NOT_FOUND );
  1258. }
  1259. AfxMessageBox( str, MB_OK );
  1260. }
  1261. //-----------------------------------------------------------------------------
  1262. // Purpose:
  1263. // Output : TRUE if the document was successfully initialized; otherwise FALSE.
  1264. //-----------------------------------------------------------------------------
  1265. BOOL CMapDoc::OnNewDocument(void)
  1266. {
  1267. if (!CDocument::OnNewDocument())
  1268. {
  1269. return(FALSE);
  1270. }
  1271. if (!SelectDocType())
  1272. {
  1273. return(FALSE);
  1274. }
  1275. Initialize();
  1276. return(TRUE);
  1277. }
  1278. //-----------------------------------------------------------------------------
  1279. // Purpose: Creates an empty world and initializes the path list.
  1280. //-----------------------------------------------------------------------------
  1281. void CMapDoc::Initialize(void)
  1282. {
  1283. Assert(!m_pWorld);
  1284. m_pWorld = new CMapWorld( this );
  1285. m_pWorld->CullTree_Build();
  1286. m_pGridNav = new CGridNav;
  1287. }
  1288. //-----------------------------------------------------------------------------
  1289. // Purpose:
  1290. // Input :
  1291. // Output :
  1292. //-----------------------------------------------------------------------------
  1293. bool CMapDoc::CheckOut( )
  1294. {
  1295. if ( !p4 )
  1296. {
  1297. return false;
  1298. }
  1299. P4File_t FileInfo;
  1300. if ( p4->GetFileInfo( GetPathName(), &FileInfo ) == true )
  1301. {
  1302. if ( FileInfo.m_iHeadRevision != FileInfo.m_iHaveRevision )
  1303. {
  1304. char szMessage[MAX_PATH+MAX_PATH+256];
  1305. sprintf( szMessage, "The map is not at the head revision! The file needs to be at the head revision in order to be checked out. Do you want to sync to the head revision?\n\n%s\n\nLocal Revision: %d Head Revision: %d", GetPathName(), FileInfo.m_iHaveRevision, FileInfo.m_iHeadRevision );
  1306. if ( AfxMessageBox( szMessage, MB_ICONHAND | MB_YESNO ) == IDYES )
  1307. {
  1308. if ( SyncToHeadRevision() == false )
  1309. {
  1310. AfxMessageBox( "Sync operation was NOT successful!", MB_OK ) ;
  1311. return false;
  1312. }
  1313. }
  1314. else
  1315. {
  1316. return false;
  1317. }
  1318. }
  1319. }
  1320. if ( !p4->OpenFileForEdit( GetPathName() ) )
  1321. {
  1322. return false;
  1323. }
  1324. CheckFileStatus();
  1325. return true;
  1326. }
  1327. //-----------------------------------------------------------------------------
  1328. // Checks out the BSP for the currently loaded VMF, if possible
  1329. //-----------------------------------------------------------------------------
  1330. bool CMapDoc::CheckOutBsp( )
  1331. {
  1332. if ( !p4 )
  1333. return false;
  1334. if ( !BspOkToCheckOut() )
  1335. {
  1336. return false;
  1337. }
  1338. // get the BSP file path based on the opened map
  1339. CUtlString bspPath;
  1340. GetBspPathFromVmfPath( bspPath );
  1341. P4File_t FileInfo;
  1342. if ( p4->GetFileInfo( bspPath.Get(), &FileInfo ) == false )
  1343. return false;
  1344. if ( FileInfo.m_iHeadRevision != FileInfo.m_iHaveRevision )
  1345. {
  1346. CUtlString message;
  1347. sprintf( message.Get(), "The BSP is not at the head revision! The file needs to be at the head revision in order to be checked out. Do you want to sync to the head revision?\n\n%s\n\nLocal Revision: %d Head Revision: %d", GetPathName(), FileInfo.m_iHaveRevision, FileInfo.m_iHeadRevision );
  1348. if ( AfxMessageBox( message, MB_ICONHAND | MB_YESNO ) == IDNO )
  1349. return false;
  1350. if ( SyncBspToHeadRevision() == false )
  1351. {
  1352. AfxMessageBox( "Sync operation was NOT successful!", MB_OK ) ;
  1353. return false;
  1354. }
  1355. }
  1356. // Check out the file
  1357. if ( !p4->OpenFileForEdit( bspPath.Get() ) )
  1358. {
  1359. AfxMessageBox( "BSP Checkout was NOT successful!", MB_OK );
  1360. return false;
  1361. }
  1362. return true;
  1363. }
  1364. //-----------------------------------------------------------------------------
  1365. // Composes a BSP path string based on the open document
  1366. //-----------------------------------------------------------------------------
  1367. void CMapDoc::GetBspPathFromVmfPath( CUtlString &bspPath )
  1368. {
  1369. CUtlString bspFileName;
  1370. // Extract the VMF file name
  1371. bspFileName = GetPathName();
  1372. bspFileName = bspFileName.UnqualifiedFilename();
  1373. // Change .VMF extension to .BSP
  1374. V_SetExtension( bspFileName.Get(), ".bsp", bspFileName.Length()+1 );
  1375. // Compose BSP path string and BSP file name
  1376. bspPath = CUtlString::PathJoin( g_pGameConfig->szBSPDir, bspFileName );
  1377. }
  1378. //-----------------------------------------------------------------------------
  1379. // Determines the file state of the BSP for the currently loaded VMF
  1380. //-----------------------------------------------------------------------------
  1381. bool CMapDoc::GetBspFileStatus( unsigned char &FileStatus )
  1382. {
  1383. P4File_t FileInfo;
  1384. CUtlString bspPath;
  1385. GetBspPathFromVmfPath( bspPath );
  1386. // bitfield for file status
  1387. FileStatus = 0;
  1388. // does the file exist?
  1389. if( !g_pFileSystem->FileExists( bspPath ) )
  1390. {
  1391. return false;
  1392. }
  1393. // is the file version controlled?
  1394. if ( p4 != NULL && p4->GetFileInfo( bspPath, &FileInfo ) == true )
  1395. {
  1396. FileStatus |= FILE_IS_VERSION_CONTROLLED;
  1397. if ( FileInfo.m_eOpenState == P4FILE_OPENED_FOR_ADD || FileInfo.m_eOpenState == P4FILE_OPENED_FOR_EDIT )
  1398. {
  1399. FileStatus |= FILE_IS_CHECKED_OUT;
  1400. }
  1401. }
  1402. // is the file is read only?
  1403. if( !g_pFullFileSystem->IsFileWritable( bspPath ) )
  1404. {
  1405. FileStatus |= FILE_IS_READ_ONLY;
  1406. }
  1407. return true;
  1408. }
  1409. //-----------------------------------------------------------------------------
  1410. // Returns true if the BSP for the current VMF exists, is not checked out, and
  1411. // is under version control
  1412. //-----------------------------------------------------------------------------
  1413. bool CMapDoc::BspOkToCheckOut()
  1414. {
  1415. unsigned char FileStatus;
  1416. if ( !GetBspFileStatus( FileStatus ) )
  1417. return false;
  1418. if ( FileStatus & FILE_IS_CHECKED_OUT )
  1419. return false;
  1420. if ( !( FileStatus & FILE_IS_VERSION_CONTROLLED ) )
  1421. return false;
  1422. return true;
  1423. }
  1424. //-----------------------------------------------------------------------------
  1425. // Purpose:
  1426. // Input :
  1427. // Output :
  1428. //-----------------------------------------------------------------------------
  1429. bool CMapDoc::AddToVersionControl( )
  1430. {
  1431. if ( !p4 )
  1432. {
  1433. return false;
  1434. }
  1435. if ( p4->OpenFileForAdd( GetPathName() ) == false )
  1436. {
  1437. return false;
  1438. }
  1439. CheckFileStatus();
  1440. return true;
  1441. }
  1442. //-----------------------------------------------------------------------------
  1443. // Purpose:
  1444. // Input :
  1445. // Output :
  1446. //-----------------------------------------------------------------------------
  1447. bool CMapDoc::SyncToHeadRevision( )
  1448. {
  1449. if ( !p4 )
  1450. {
  1451. return false;
  1452. }
  1453. if ( p4->SyncFile( GetPathName() ) == false )
  1454. {
  1455. return false;
  1456. }
  1457. DeleteContents();
  1458. OnOpenDocument( GetPathName() );
  1459. CheckFileStatus();
  1460. return true;
  1461. }
  1462. //-----------------------------------------------------------------------------
  1463. // Syncs BSP to head revision. Returns true if successful.
  1464. //-----------------------------------------------------------------------------
  1465. bool CMapDoc::SyncBspToHeadRevision()
  1466. {
  1467. if ( !p4 )
  1468. {
  1469. return false;
  1470. }
  1471. CUtlString bspPath;
  1472. GetBspPathFromVmfPath( bspPath );
  1473. if ( p4->SyncFile( bspPath ) == false )
  1474. {
  1475. return false;
  1476. }
  1477. return true;
  1478. }
  1479. //-----------------------------------------------------------------------------
  1480. // Purpose:
  1481. // Input :
  1482. // Output :
  1483. //-----------------------------------------------------------------------------
  1484. bool CMapDoc::Revert( )
  1485. {
  1486. if ( !p4 )
  1487. {
  1488. return false;
  1489. }
  1490. if ( p4->RevertFile( GetPathName() ) == false )
  1491. {
  1492. return false;
  1493. }
  1494. DeleteContents();
  1495. OnOpenDocument( GetPathName() );
  1496. CheckFileStatus();
  1497. return true;
  1498. }
  1499. //-----------------------------------------------------------------------------
  1500. // Purpose:
  1501. // Input :
  1502. // Output :
  1503. //-----------------------------------------------------------------------------
  1504. void CMapDoc::CheckFileStatus( )
  1505. {
  1506. P4File_t FileInfo;
  1507. bool bOriginalReadOnly = m_bReadOnly;
  1508. bool bOriginalCheckedOut = m_bCheckedOut;
  1509. bool bOriginalIsVersionControlled = m_bIsVersionControlled;
  1510. m_bReadOnly = !g_pFullFileSystem->IsFileWritable( GetPathName() );
  1511. m_bCheckedOut = false;
  1512. m_bIsVersionControlled = false;
  1513. if ( p4 != NULL && Options.general.bEnablePerforceIntegration == TRUE )
  1514. {
  1515. if ( p4->GetFileInfo( GetPathName(), &FileInfo ) == true )
  1516. {
  1517. m_bIsVersionControlled = true;
  1518. if ( FileInfo.m_eOpenState == P4FILE_OPENED_FOR_ADD || FileInfo.m_eOpenState == P4FILE_OPENED_FOR_EDIT )
  1519. {
  1520. m_bCheckedOut = true;
  1521. }
  1522. }
  1523. }
  1524. if ( bOriginalReadOnly != m_bReadOnly ||
  1525. bOriginalCheckedOut != m_bCheckedOut ||
  1526. bOriginalIsVersionControlled != m_bIsVersionControlled )
  1527. {
  1528. CView *pView = GetMainWnd()->GetActiveFrame()->GetActiveView();
  1529. if ( pView != NULL && GetMainWnd()->GetActiveFrame()->GetActiveDocument() == this )
  1530. {
  1531. UpdateTitle( pView );
  1532. }
  1533. }
  1534. }
  1535. //-----------------------------------------------------------------------------
  1536. // Purpose:
  1537. // Input :
  1538. // Output :
  1539. //-----------------------------------------------------------------------------
  1540. void CMapDoc::OnFileVersionControlAdd( void )
  1541. {
  1542. CMapDoc *activeDoc = CMapDoc::GetActiveMapDoc();
  1543. if ( !activeDoc )
  1544. {
  1545. return;
  1546. }
  1547. if ( AddToVersionControl() == false && p4 )
  1548. {
  1549. char temp[ 2048 ];
  1550. sprintf( temp, "Could not add file to version control: %s", p4->GetLastError() );
  1551. AfxMessageBox( temp, MB_ICONHAND | MB_OK );
  1552. }
  1553. }
  1554. //-----------------------------------------------------------------------------
  1555. // Purpose:
  1556. // Input :
  1557. // Output :
  1558. //-----------------------------------------------------------------------------
  1559. void CMapDoc::OnUpdateVersionControlAdd(CCmdUI *pCmdUI)
  1560. {
  1561. if ( p4 == NULL || m_bIsVersionControlled == true || Options.general.bEnablePerforceIntegration == FALSE )
  1562. {
  1563. pCmdUI->Enable( false );
  1564. return;
  1565. }
  1566. pCmdUI->Enable( true );
  1567. }
  1568. //-----------------------------------------------------------------------------
  1569. // Purpose:
  1570. // Input :
  1571. // Output :
  1572. //-----------------------------------------------------------------------------
  1573. void CMapDoc::OnFileVersionControlCheckOut( void )
  1574. {
  1575. CMapDoc *activeDoc = CMapDoc::GetActiveMapDoc();
  1576. if ( !activeDoc )
  1577. {
  1578. return;
  1579. }
  1580. if ( p4 == NULL )
  1581. return;
  1582. if ( CheckOut() == false )
  1583. {
  1584. char temp[ 2048 ];
  1585. sprintf( temp, "Could not check out file: %s", p4->GetLastError() );
  1586. AfxMessageBox( temp, MB_ICONHAND | MB_OK );
  1587. }
  1588. }
  1589. //-----------------------------------------------------------------------------
  1590. // Checks out BSP for the currently loaded VMF, if it exists.
  1591. //-----------------------------------------------------------------------------
  1592. void CMapDoc::OnFileVersionControlCheckOutBsp( void )
  1593. {
  1594. CMapDoc *activeDoc = CMapDoc::GetActiveMapDoc();
  1595. if ( !activeDoc )
  1596. {
  1597. return;
  1598. }
  1599. if ( p4 == NULL )
  1600. return;
  1601. if ( !BspOkToCheckOut() )
  1602. {
  1603. return;
  1604. }
  1605. if ( CheckOutBsp() == false )
  1606. {
  1607. CUtlString temp;
  1608. sprintf( temp.Get(), "Could not check out file: %s", p4->GetLastError() );
  1609. AfxMessageBox( temp, MB_ICONHAND | MB_OK );
  1610. }
  1611. }
  1612. //-----------------------------------------------------------------------------
  1613. // Purpose:
  1614. // Input :
  1615. // Output :
  1616. //-----------------------------------------------------------------------------
  1617. void CMapDoc::OnUpdateVersionControlCheckOut(CCmdUI *pCmdUI)
  1618. {
  1619. // update the vmf file status before checking state since it may have changed externally
  1620. CheckFileStatus();
  1621. if ( p4 == NULL || m_bCheckedOut == true || m_bIsVersionControlled == false || Options.general.bEnablePerforceIntegration == FALSE )
  1622. {
  1623. pCmdUI->Enable( false );
  1624. return;
  1625. }
  1626. pCmdUI->Enable( true );
  1627. }
  1628. //-----------------------------------------------------------------------------
  1629. // Disables the version control -> check out bsp option if BSP is not OK to check out
  1630. //-----------------------------------------------------------------------------
  1631. void CMapDoc::OnUpdateVersionControlCheckOutBsp(CCmdUI *pCmdUI)
  1632. {
  1633. if ( p4 == NULL || BspOkToCheckOut() == false || Options.general.bEnablePerforceIntegration == FALSE )
  1634. {
  1635. pCmdUI->Enable( false );
  1636. return;
  1637. }
  1638. pCmdUI->Enable( true );
  1639. }
  1640. //-----------------------------------------------------------------------------
  1641. // Purpose:
  1642. // Input :
  1643. // Output :
  1644. //-----------------------------------------------------------------------------
  1645. void CMapDoc::OnFileVersionControlCheckIn( void )
  1646. {
  1647. if ( !p4 )
  1648. {
  1649. return;
  1650. }
  1651. CMapDoc *activeDoc = CMapDoc::GetActiveMapDoc();
  1652. if ( !activeDoc )
  1653. {
  1654. return;
  1655. }
  1656. m_bDefaultCheckin = true;
  1657. CMapDocCheckin MapDocCheckin;
  1658. if ( MapDocCheckin.DoModal() == IDOK )
  1659. {
  1660. }
  1661. }
  1662. //-----------------------------------------------------------------------------
  1663. // Purpose:
  1664. // Input :
  1665. // Output :
  1666. //-----------------------------------------------------------------------------
  1667. void CMapDoc::OnUpdateVersionControlCheckIn(CCmdUI *pCmdUI)
  1668. {
  1669. if ( p4 == NULL || m_bCheckedOut == false || Options.general.bEnablePerforceIntegration == FALSE )
  1670. {
  1671. pCmdUI->Enable( false );
  1672. return;
  1673. }
  1674. pCmdUI->Enable( true );
  1675. }
  1676. //-----------------------------------------------------------------------------
  1677. // Purpose:
  1678. // Input :
  1679. // Output :
  1680. //-----------------------------------------------------------------------------
  1681. void CMapDoc::OnFileVersionControlCheckInAll( void )
  1682. {
  1683. if ( !p4 )
  1684. {
  1685. return;
  1686. }
  1687. POSITION pos = APP()->pMapDocTemplate->GetFirstDocPosition();
  1688. while( pos != NULL )
  1689. {
  1690. CDocument *pDoc = APP()->pMapDocTemplate->GetNextDoc( pos );
  1691. CMapDoc *pMapDoc = dynamic_cast< CMapDoc * >( pDoc );
  1692. if ( pMapDoc != NULL && pMapDoc->IsCheckedOut() )
  1693. {
  1694. pMapDoc->m_bDefaultCheckin = true;
  1695. }
  1696. }
  1697. CMapDocCheckin MapDocCheckin;
  1698. if ( MapDocCheckin.DoModal() == IDOK )
  1699. {
  1700. }
  1701. }
  1702. //-----------------------------------------------------------------------------
  1703. // Purpose:
  1704. // Input :
  1705. // Output :
  1706. //-----------------------------------------------------------------------------
  1707. void CMapDoc::OnUpdateVersionControlCheckInAll(CCmdUI *pCmdUI)
  1708. {
  1709. if ( p4 == NULL || Options.general.bEnablePerforceIntegration == FALSE )
  1710. {
  1711. pCmdUI->Enable( false );
  1712. return;
  1713. }
  1714. pCmdUI->Enable( true );
  1715. }
  1716. //-----------------------------------------------------------------------------
  1717. // Purpose:
  1718. // Input :
  1719. // Output :
  1720. //-----------------------------------------------------------------------------
  1721. void CMapDoc::OnFileVersionControlOverview( void )
  1722. {
  1723. CMapDocStatus MapDocStatus;
  1724. if ( MapDocStatus.DoModal() == IDOK )
  1725. {
  1726. }
  1727. }
  1728. //-----------------------------------------------------------------------------
  1729. // Purpose:
  1730. // Input : pFile -
  1731. // pData -
  1732. // Output : ChunkFileResult_t
  1733. //-----------------------------------------------------------------------------
  1734. ChunkFileResult_t CMapDoc::LoadEntityCallback(CChunkFile *pFile, CMapDoc *pDoc)
  1735. {
  1736. CMapEntity *pEntity = new CMapEntity;
  1737. ChunkFileResult_t eResult = pEntity->LoadVMF(pFile);
  1738. if (eResult == ChunkFile_Ok)
  1739. {
  1740. CMapWorld *pWorld = pDoc->GetMapWorld();
  1741. pWorld->AddChild(pEntity);
  1742. }
  1743. return(ChunkFile_Ok);
  1744. }
  1745. //-----------------------------------------------------------------------------
  1746. // Purpose:
  1747. // Input : pFile -
  1748. // pData -
  1749. // Output : ChunkFileResult_t
  1750. //-----------------------------------------------------------------------------
  1751. ChunkFileResult_t CMapDoc::LoadHiddenCallback(CChunkFile *pFile, CMapDoc *pDoc)
  1752. {
  1753. CChunkHandlerMap Handlers;
  1754. Handlers.AddHandler("entity", (ChunkHandler_t)CMapDoc::LoadEntityCallback, pDoc);
  1755. pFile->PushHandlers(&Handlers);
  1756. ChunkFileResult_t eResult = pFile->ReadChunk();
  1757. pFile->PopHandlers();
  1758. return(eResult);
  1759. }
  1760. //-----------------------------------------------------------------------------
  1761. // Purpose:
  1762. // Input : pFile -
  1763. // szChunkName -
  1764. // eError -
  1765. // Output : Returns true to continue loading, false to stop loading.
  1766. //-----------------------------------------------------------------------------
  1767. bool CMapDoc::HandleLoadError(CChunkFile *pFile, const char *szChunkName, ChunkFileResult_t eError, CMapDoc *pDoc)
  1768. {
  1769. return(false);
  1770. }
  1771. //-----------------------------------------------------------------------------
  1772. // Purpose: Loads this document from a VMF file.
  1773. // Input : pszFileName - Full path of file to load.
  1774. // Output : Returns true on success, false on failure.
  1775. //-----------------------------------------------------------------------------
  1776. bool CMapDoc::LoadVMF( const char *pszFileName, int LoadFlags )
  1777. {
  1778. bool CreateProgressDlg = m_nInLevelLoad == 0;
  1779. m_nInLevelLoad++;
  1780. //
  1781. // Create a new world to hold the loaded objects.
  1782. //
  1783. if (m_pWorld == NULL)
  1784. {
  1785. m_pWorld = new CMapWorld( this );
  1786. }
  1787. // Show our progress dialog.
  1788. if ( CreateProgressDlg )
  1789. {
  1790. pProgDlg = new CProgressDlg;
  1791. pProgDlg->Create();
  1792. pProgDlg->SetRange(0,18000);
  1793. pProgDlg->SetStep(1000);
  1794. }
  1795. // Set the progress dialog title
  1796. CString caption;
  1797. caption.LoadString(IDS_LOADINGFILE);
  1798. pProgDlg->SetWindowText(caption);
  1799. g_nFileFormatVersion = 0;
  1800. bool bLocked = VisGroups_LockUpdates( true );
  1801. //
  1802. // Open the file.
  1803. //
  1804. CChunkFile File;
  1805. ChunkFileResult_t eResult = File.Open(pszFileName, ChunkFile_Read);
  1806. pProgDlg->StepIt();
  1807. //
  1808. // Read the file.
  1809. //
  1810. if (eResult == ChunkFile_Ok)
  1811. {
  1812. DetailObjects::EnableBuildDetailObjects( false );
  1813. //
  1814. // Set up handlers for the subchunks that we are interested in.
  1815. //
  1816. CChunkHandlerMap Handlers;
  1817. Handlers.AddHandler("world", (ChunkHandler_t)CMapDoc::LoadWorldCallback, this);
  1818. Handlers.AddHandler("hidden", (ChunkHandler_t)CMapDoc::LoadHiddenCallback, this);
  1819. Handlers.AddHandler("entity", (ChunkHandler_t)CMapDoc::LoadEntityCallback, this);
  1820. Handlers.AddHandler("versioninfo", (ChunkHandler_t)CMapDoc::LoadVersionInfoCallback, this);
  1821. Handlers.AddHandler("autosave", (ChunkHandler_t)CMapDoc::LoadAutosaveCallback, this);
  1822. Handlers.AddHandler("visgroups", (ChunkHandler_t)CVisGroup::LoadVisGroupsCallback, this);
  1823. Handlers.AddHandler("viewsettings", (ChunkHandler_t)CMapDoc::LoadViewSettingsCallback, this);
  1824. Handlers.AddHandler("cordons", (ChunkHandler_t)CMapDoc::LoadCordonsCallback, this);
  1825. Handlers.AddHandler("cordon", (ChunkHandler_t)CMapDoc::LoadCordonCallback_Legacy, this); // Legacy support for maps with only one cordon
  1826. m_pToolManager->AddToolHandlers( &Handlers );
  1827. Handlers.SetErrorHandler((ChunkErrorHandler_t)CMapDoc::HandleLoadError, this);
  1828. File.PushHandlers(&Handlers);
  1829. if ( ( LoadFlags & VMF_LOAD_ACTIVATE ) )
  1830. {
  1831. SetActiveMapDoc( this );
  1832. }
  1833. m_bLoading = true;
  1834. //
  1835. // Read the sub-chunks. We ignore keys in the root of the file, so we don't pass a
  1836. // key value callback to ReadChunk.
  1837. //
  1838. pProgDlg->SetWindowText( "Reading Chunks..." );
  1839. while (eResult == ChunkFile_Ok)
  1840. {
  1841. eResult = File.ReadChunk();
  1842. }
  1843. pProgDlg->SetStep(5000);
  1844. pProgDlg->StepIt();
  1845. if (eResult == ChunkFile_EOF)
  1846. {
  1847. eResult = ChunkFile_Ok;
  1848. }
  1849. File.PopHandlers();
  1850. }
  1851. if (eResult == ChunkFile_Ok)
  1852. {
  1853. pProgDlg->SetWindowText( "Postload Processing..." );
  1854. PostloadDocument( pszFileName );
  1855. pProgDlg->StepIt();
  1856. m_bLoading = false;
  1857. }
  1858. else
  1859. {
  1860. GetMainWnd()->MessageBox(File.GetErrorText(eResult), "Error loading file", MB_OK | MB_ICONEXCLAMATION);
  1861. }
  1862. GetMainWnd()->m_FilterControl.UpdateCordonList();
  1863. if ( bLocked )
  1864. VisGroups_LockUpdates( false );
  1865. if ( pProgDlg && CreateProgressDlg )
  1866. {
  1867. pProgDlg->DestroyWindow();
  1868. delete pProgDlg;
  1869. pProgDlg = NULL;
  1870. }
  1871. if ( ( LoadFlags & VMF_LOAD_ACTIVATE ) )
  1872. { // force rendering even if application is not active
  1873. UpdateAllViews( MAPVIEW_UPDATE_OBJECTS );
  1874. APP()->SetForceRenderNextFrame();
  1875. }
  1876. m_nInLevelLoad--;
  1877. return(eResult == ChunkFile_Ok);
  1878. }
  1879. void CMapDoc::BuildAllDetailObjects()
  1880. {
  1881. EnumChildrenPos_t pos;
  1882. CMapClass *pChild = m_pWorld->GetFirstDescendent(pos);
  1883. while (pChild != NULL)
  1884. {
  1885. CMapSolid *pSolid = dynamic_cast <CMapSolid *> (pChild);
  1886. if (pSolid != NULL)
  1887. {
  1888. int nFaces = pSolid->GetFaceCount();
  1889. for(int i = 0; i < nFaces; i++)
  1890. {
  1891. CMapFace *pFace = pSolid->GetFace( i );
  1892. if ( pFace )
  1893. DetailObjects::BuildAnyDetailObjects( pFace );
  1894. }
  1895. }
  1896. pChild = m_pWorld->GetNextDescendent(pos);
  1897. }
  1898. }
  1899. //-----------------------------------------------------------------------------
  1900. // Purpose:
  1901. // Input : pLoadInfo -
  1902. // Output : ChunkFileResult_t
  1903. //-----------------------------------------------------------------------------
  1904. ChunkFileResult_t CMapDoc::LoadVersionInfoCallback(CChunkFile *pFile, CMapDoc *pDoc)
  1905. {
  1906. return(pFile->ReadChunk((KeyHandler_t)LoadVersionInfoKeyCallback, pDoc));
  1907. }
  1908. //-----------------------------------------------------------------------------
  1909. // Purpose: Handles keyvalues when loading the version info chunk of VMF files.
  1910. // Input : szKey - Key to handle.
  1911. // szValue - Value of key.
  1912. // pDoc - Document being loaded.
  1913. // Output : Returns ChunkFile_Ok if all is well.
  1914. //-----------------------------------------------------------------------------
  1915. ChunkFileResult_t CMapDoc::LoadVersionInfoKeyCallback(const char *szKey, const char *szValue, CMapDoc *pDoc)
  1916. {
  1917. KeyInt("mapversion", pDoc->m_nDocVersion);
  1918. KeyInt("formatversion", g_nFileFormatVersion);
  1919. KeyBool("prefab", pDoc->m_bPrefab);
  1920. return(ChunkFile_Ok);
  1921. }
  1922. //-----------------------------------------------------------------------------
  1923. //-----------------------------------------------------------------------------
  1924. ChunkFileResult_t CMapDoc::LoadAutosaveCallback( CChunkFile *pFile, CMapDoc *pDoc)
  1925. {
  1926. return(pFile->ReadChunk((KeyHandler_t)LoadAutosaveKeyCallback, pDoc));
  1927. }
  1928. //-----------------------------------------------------------------------------
  1929. //-----------------------------------------------------------------------------
  1930. ChunkFileResult_t CMapDoc::LoadAutosaveKeyCallback(const char *szKey, const char *szValue, CMapDoc *pDoc)
  1931. {
  1932. if (!stricmp(szKey, "originalname"))
  1933. {
  1934. pDoc->m_bIsAutosave = true;
  1935. char szTempName[MAX_PATH];
  1936. Q_strcpy( szTempName, szValue );
  1937. Q_FixSlashes( szTempName, '\\' );
  1938. pDoc->m_strAutosavedFrom = szTempName;
  1939. }
  1940. return(ChunkFile_Ok);
  1941. }
  1942. //-----------------------------------------------------------------------------
  1943. //-----------------------------------------------------------------------------
  1944. ChunkFileResult_t CMapDoc::LoadCordonBoxCallback( CChunkFile *pFile, Cordon_t *pCordon )
  1945. {
  1946. // Add a box to this cordon.
  1947. pCordon->m_Boxes.AddToTail();
  1948. BoundBox &box = pCordon->m_Boxes.Tail();
  1949. // Fill it in with the data from the VMF.
  1950. return pFile->ReadChunk( (KeyHandler_t)LoadCordonBoxKeyCallback, (void *)&box );
  1951. }
  1952. //-----------------------------------------------------------------------------
  1953. //-----------------------------------------------------------------------------
  1954. ChunkFileResult_t CMapDoc::LoadCordonBoxKeyCallback(const char *szKey, const char *szValue, BoundBox *pBox)
  1955. {
  1956. if (!stricmp(szKey, "mins"))
  1957. {
  1958. CChunkFile::ReadKeyValuePoint(szValue, pBox->bmins);
  1959. }
  1960. else if (!stricmp(szKey, "maxs"))
  1961. {
  1962. CChunkFile::ReadKeyValuePoint(szValue, pBox->bmaxs);
  1963. }
  1964. return ChunkFile_Ok;
  1965. }
  1966. //-----------------------------------------------------------------------------
  1967. //-----------------------------------------------------------------------------
  1968. ChunkFileResult_t CMapDoc::LoadCordonCallback(CChunkFile *pFile, CMapDoc *pDoc)
  1969. {
  1970. // Add a new cordon which will be filled in by the key callback
  1971. pDoc->m_Cordons.AddToTail();
  1972. Cordon_t &cordon = pDoc->m_Cordons.Tail();
  1973. CChunkHandlerMap Handlers;
  1974. Handlers.AddHandler( "box", (ChunkHandler_t)CMapDoc::LoadCordonBoxCallback, (void *)&cordon );
  1975. pFile->PushHandlers(&Handlers);
  1976. ChunkFileResult_t eResult = pFile->ReadChunk( (KeyHandler_t)LoadCordonKeyCallback, (void *)&cordon );
  1977. pFile->PopHandlers();
  1978. return(eResult);
  1979. }
  1980. //-----------------------------------------------------------------------------
  1981. //-----------------------------------------------------------------------------
  1982. ChunkFileResult_t CMapDoc::LoadCordonKeyCallback( const char *szKey, const char *szValue, Cordon_t *pCordon )
  1983. {
  1984. if (!stricmp(szKey, "name"))
  1985. {
  1986. pCordon->m_szName.Set( szValue );
  1987. }
  1988. // Whether this particular cordon volume is active.
  1989. else if (!stricmp(szKey, "active"))
  1990. {
  1991. CChunkFile::ReadKeyValueBool(szValue, pCordon->m_bActive);
  1992. }
  1993. return ChunkFile_Ok;
  1994. }
  1995. //-----------------------------------------------------------------------------------------------------------
  1996. // Parses keys that are applicable to all cordons in the map.
  1997. //-----------------------------------------------------------------------------
  1998. ChunkFileResult_t CMapDoc::LoadCordonsKeyCallback( const char *szKey, const char *szValue, CMapDoc *pDoc )
  1999. {
  2000. // Whether the cordoning system is enabled or disabled.
  2001. if ( !stricmp( szKey, "active" ) )
  2002. {
  2003. CChunkFile::ReadKeyValueBool( szValue, pDoc->m_bIsCordoning );
  2004. }
  2005. return ChunkFile_Ok;
  2006. }
  2007. //-----------------------------------------------------------------------------
  2008. // Parses the VMF chunk that pertains to all the cordons in the map:
  2009. //
  2010. // cordons
  2011. // {
  2012. // "active" "true"
  2013. // cordon
  2014. // {
  2015. // "active" "true"
  2016. // "box"
  2017. // {
  2018. // "mins" "-1024, -1024, -1024"
  2019. // "maxs" "1024, 1024, 1024"
  2020. // }
  2021. // ...may be more boxes...
  2022. // }
  2023. // ...may be more cordons...
  2024. // }
  2025. //
  2026. //-----------------------------------------------------------------------------
  2027. ChunkFileResult_t CMapDoc::LoadCordonsCallback(CChunkFile *pFile, CMapDoc *pDoc)
  2028. {
  2029. CChunkHandlerMap Handlers;
  2030. Handlers.AddHandler( "cordon", (ChunkHandler_t)CMapDoc::LoadCordonCallback, pDoc );
  2031. pFile->PushHandlers(&Handlers);
  2032. ChunkFileResult_t eResult = pFile->ReadChunk( (KeyHandler_t)LoadCordonsKeyCallback, pDoc );
  2033. pFile->PopHandlers();
  2034. return(eResult);
  2035. }
  2036. //-----------------------------------------------------------------------------
  2037. // Legacy support: loading old files before multiple cordons were implemented.
  2038. //-----------------------------------------------------------------------------
  2039. ChunkFileResult_t CMapDoc::LoadCordonKeyCallback_Legacy( const char *szKey, const char *szValue, CMapDoc *pDoc )
  2040. {
  2041. // Whether the cordon is active.
  2042. if ( !stricmp( szKey, "active" ) )
  2043. {
  2044. CChunkFile::ReadKeyValueBool( szValue, pDoc->m_bIsCordoning );
  2045. }
  2046. else if ( !stricmp( szKey, "mins" ) || !stricmp( szKey, "maxs" ) )
  2047. {
  2048. // Make sure there's a cordon to fill in.
  2049. if ( pDoc->m_Cordons.Count() < 1 )
  2050. {
  2051. pDoc->m_Cordons.AddToTail();
  2052. pDoc->m_Cordons[0].m_szName = DEFAULT_CORDON_NAME;
  2053. pDoc->m_Cordons[0].m_bActive = true; // The lone cordon was always "active" the current sense.
  2054. pDoc->m_Cordons[0].m_Boxes.AddToTail();
  2055. }
  2056. if ( !stricmp( szKey, "mins" ) )
  2057. {
  2058. CChunkFile::ReadKeyValuePoint( szValue, pDoc->m_Cordons[0].m_Boxes[0].bmins );
  2059. }
  2060. else
  2061. {
  2062. CChunkFile::ReadKeyValuePoint( szValue, pDoc->m_Cordons[0].m_Boxes[0].bmaxs );
  2063. }
  2064. }
  2065. return ChunkFile_Ok;
  2066. }
  2067. //-----------------------------------------------------------------------------
  2068. // This loads old VMFs whose cordon chunk looked like this:
  2069. //
  2070. // cordon
  2071. // {
  2072. // "mins" "-1024, -1024, -1024"
  2073. // "maxs" "1024, 1024, 1024"
  2074. // "active" "true"
  2075. // }
  2076. //
  2077. //-----------------------------------------------------------------------------
  2078. ChunkFileResult_t CMapDoc::LoadCordonCallback_Legacy(CChunkFile *pFile, CMapDoc *pDoc)
  2079. {
  2080. ChunkFileResult_t eResult = pFile->ReadChunk( (KeyHandler_t)LoadCordonKeyCallback_Legacy, pDoc );
  2081. return(eResult);
  2082. }
  2083. //-----------------------------------------------------------------------------
  2084. // Purpose:
  2085. // Input : pFile -
  2086. // pData -
  2087. // Output : ChunkFileResult_t
  2088. //-----------------------------------------------------------------------------
  2089. ChunkFileResult_t CMapDoc::LoadViewSettingsKeyCallback(const char *szKey, const char *szValue, CMapDoc *pDoc)
  2090. {
  2091. KeyBool( "bSnapToGrid", pDoc->m_bSnapToGrid);
  2092. KeyBool( "bShowGrid", pDoc->m_bShowGrid);
  2093. KeyBool( "bShowLogicalGrid", pDoc->m_bShowLogicalGrid);
  2094. KeyInt( "nGridSpacing", pDoc->m_nGridSpacing);
  2095. KeyBool( "bShow3DGrid", pDoc->m_bShow3DGrid);
  2096. return(ChunkFile_Ok);
  2097. }
  2098. //-----------------------------------------------------------------------------
  2099. // Purpose: Loads the view settings chunk, where per-map view settings are kept.
  2100. //-----------------------------------------------------------------------------
  2101. ChunkFileResult_t CMapDoc::LoadViewSettingsCallback(CChunkFile *pFile, CMapDoc *pDoc)
  2102. {
  2103. ChunkFileResult_t eResult = pFile->ReadChunk((KeyHandler_t)LoadViewSettingsKeyCallback, pDoc);
  2104. if (eResult == ChunkFile_Ok)
  2105. {
  2106. pDoc->UpdateStatusBarSnap();
  2107. }
  2108. return eResult;
  2109. }
  2110. //-----------------------------------------------------------------------------
  2111. // Purpose:
  2112. // Input : pFile -
  2113. // pData -
  2114. // Output : ChunkFileResult_t
  2115. //-----------------------------------------------------------------------------
  2116. ChunkFileResult_t CMapDoc::LoadWorldCallback(CChunkFile *pFile, CMapDoc *pDoc)
  2117. {
  2118. CMapWorld *pWorld = pDoc->GetMapWorld();
  2119. ChunkFileResult_t eResult = pWorld->LoadVMF(pFile);
  2120. return(eResult);
  2121. }
  2122. //-----------------------------------------------------------------------------
  2123. // Called just before a map is loaded from disk.
  2124. //-----------------------------------------------------------------------------
  2125. void CMapDoc::PreloadDocument()
  2126. {
  2127. // Purge the default cordon so we don't append new ones to it.
  2128. m_Cordons.RemoveAll();
  2129. //
  2130. // Call any per-class PreloadWorld functions here.
  2131. //
  2132. CMapSolid::PreloadWorld();
  2133. }
  2134. //-------------------------------------------------------------------------------------------------
  2135. // Called after loading a map file from disk.
  2136. //-------------------------------------------------------------------------------------------------
  2137. void CMapDoc::PostloadDocument(const char *pszFileName)
  2138. {
  2139. if ( pszFileName[ 0 ] )
  2140. { // this path needs to be set early so that instances may properly find their base path
  2141. SetPathName( pszFileName, FALSE );
  2142. }
  2143. //
  2144. // Report any noncritical loading errors here.
  2145. //
  2146. if (CMapSolid::GetBadSolidCount() > 0)
  2147. {
  2148. char szError[256];
  2149. char szSoidIds[256]; szSoidIds[0] = 0;
  2150. char szId[256];
  2151. for (int i=0; i<CMapSolid::GetRecordedBadSolidCount(); ++i)
  2152. {
  2153. sprintf (szId, "%d ", CMapSolid::GetBadSolidId( i ) );
  2154. strcat( szSoidIds, szId );
  2155. }
  2156. V_snprintf( szError, sizeof(szError), "For your information, %d solid(s) were not loaded due to errors in the file.\nIDs:( %s)\nWould you like to Re-Save your map with the invalid solids removed?", CMapSolid::GetBadSolidCount(), szSoidIds );
  2157. if ( GetMainWnd()->MessageBox(szError, "Warning", MB_YESNO | MB_ICONQUESTION) == IDYES )
  2158. {
  2159. // Mark that we should save the map at the end of our loading process
  2160. m_bDeferredSave = true;
  2161. }
  2162. }
  2163. // Fix single-cordon maps that were loaded and then saved with incomplete cordon data.
  2164. if ( ( m_Cordons.Count() == 1 ) && ( m_Cordons[0].m_szName.Length() == 0 ) && !m_Cordons[0].m_bActive )
  2165. {
  2166. m_Cordons[0].m_szName = DEFAULT_CORDON_NAME;
  2167. m_Cordons[0].m_bActive = true;
  2168. }
  2169. Cordon_SetCordoning( m_bIsCordoning );
  2170. //
  2171. // Count GUIDs before calling PostLoadWorld because objects that need to generate GUIDs
  2172. // may do so in PostLoadWorld.
  2173. //
  2174. CountGUIDs();
  2175. m_pWorld->PostloadWorld();
  2176. if ( pProgDlg )
  2177. {
  2178. pProgDlg->StepIt();
  2179. pProgDlg->SetStep(1000);
  2180. }
  2181. if ( pProgDlg )
  2182. {
  2183. pProgDlg->SetWindowText( "Assigning to groups..." );
  2184. }
  2185. AssignToGroups();
  2186. AssignToVisGroups();
  2187. if ( pProgDlg )
  2188. {
  2189. pProgDlg->StepIt();
  2190. }
  2191. if ( pProgDlg )
  2192. {
  2193. pProgDlg->SetWindowText( "Postprocessing VisGroups..." );
  2194. }
  2195. m_pWorld->PostloadVisGroups();
  2196. if ( pProgDlg )
  2197. {
  2198. pProgDlg->StepIt();
  2199. }
  2200. // Do this after AssignToVisGroups, because deleting objects causes empty visgroups to be purged,
  2201. // and until AssignToVisGroups is called all the visgroups are empty!
  2202. if ( pProgDlg )
  2203. {
  2204. pProgDlg->SetWindowText( "Updating Visibility..." );
  2205. }
  2206. RemoveEmptyGroups();
  2207. UpdateVisibilityAll();
  2208. if ( pProgDlg )
  2209. {
  2210. pProgDlg->StepIt();
  2211. }
  2212. // update displacement neighbors
  2213. if ( pProgDlg )
  2214. {
  2215. pProgDlg->SetWindowText( "Updating Displacements..." );
  2216. }
  2217. IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager();
  2218. if( pDispMgr )
  2219. {
  2220. int count = pDispMgr->WorldCount();
  2221. for( int ndx = 0; ndx < count; ndx++ )
  2222. {
  2223. CMapDisp *pDisp = pDispMgr->GetFromWorld( ndx );
  2224. if( pDisp )
  2225. {
  2226. CMapFace *pFace = ( CMapFace* )pDisp->GetParent();
  2227. pDispMgr->FindWorldNeighbors( pFace->GetDisp() );
  2228. }
  2229. }
  2230. }
  2231. if ( pProgDlg )
  2232. {
  2233. pProgDlg->StepIt();
  2234. }
  2235. //
  2236. // Do batch search and replace of textures from trans.txt if it exists.
  2237. //
  2238. if ( pProgDlg )
  2239. {
  2240. pProgDlg->SetWindowText( "Updating Texture Names..." );
  2241. }
  2242. char translationFilename[MAX_PATH];
  2243. Q_snprintf( translationFilename, sizeof( translationFilename ), "materials/trans.txt" );
  2244. FileHandle_t searchReplaceFP = g_pFileSystem->Open( translationFilename, "r" );
  2245. if( searchReplaceFP )
  2246. {
  2247. BatchReplaceTextures( searchReplaceFP );
  2248. g_pFileSystem->Close( searchReplaceFP );
  2249. }
  2250. if ( pProgDlg )
  2251. {
  2252. pProgDlg->StepIt();
  2253. }
  2254. if ( pProgDlg )
  2255. {
  2256. pProgDlg->SetWindowText( "Building Cull Tree..." );
  2257. }
  2258. m_pWorld->CullTree_Build();
  2259. if ( pProgDlg )
  2260. {
  2261. pProgDlg->StepIt();
  2262. }
  2263. // We disabled building detail objects above to prevent it from generating them extra times.
  2264. // Now generate the ones that need to be generated.
  2265. if ( pProgDlg )
  2266. {
  2267. pProgDlg->SetWindowText( "Building Detail Objects..." );
  2268. }
  2269. DetailObjects::EnableBuildDetailObjects( true );
  2270. BuildAllDetailObjects();
  2271. if ( pProgDlg )
  2272. {
  2273. pProgDlg->SetWindowText( "Finished Loading!" );
  2274. }
  2275. }
  2276. //-----------------------------------------------------------------------------
  2277. // Purpose: this function will hook up the manifest document to this map document
  2278. // Input : pManifest - the manifest document
  2279. //-----------------------------------------------------------------------------
  2280. void CMapDoc::SetManifest( CManifest *pManifest )
  2281. {
  2282. m_pManifest = pManifest;
  2283. m_pManifestOwner = pManifest;
  2284. if ( m_pSelection )
  2285. {
  2286. delete m_pSelection;
  2287. }
  2288. m_pSelection = pManifest->GetSelection();
  2289. }
  2290. //-----------------------------------------------------------------------------
  2291. // Purpose: this routine will check to see if all objects are editable within
  2292. // the selection. If one is not editable, the entire selection is not
  2293. // editable.
  2294. // Output : the editable state of the selection
  2295. //-----------------------------------------------------------------------------
  2296. bool CMapDoc::IsSelectionEditable( void )
  2297. {
  2298. bool bResult = true;
  2299. int nCount = m_pSelection->GetCount();
  2300. for( int i = 0; i < nCount; i++ )
  2301. {
  2302. CMapClass *pObj = (CUtlReference< CMapClass >)m_pSelection->GetList()->Element( i );
  2303. if ( !pObj->IsEditable() )
  2304. {
  2305. bResult = false;
  2306. break;
  2307. }
  2308. }
  2309. return bResult;
  2310. }
  2311. //-----------------------------------------------------------------------------
  2312. // Purpose: this routine will take a single map document and turn it into a
  2313. // manifest document containing just this one map document.
  2314. // Output : true if the conversion worked
  2315. //-----------------------------------------------------------------------------
  2316. bool CMapDoc::CreateNewManifest( void )
  2317. {
  2318. OnFileSave();
  2319. if ( IsModified() )
  2320. {
  2321. AfxMessageBox( "Manifest was NOT created!", MB_OK );
  2322. return false;
  2323. }
  2324. CManifest *pManifest = dynamic_cast< CManifest * >( APP()->pManifestDocTemplate->OpenDocumentFile( NULL ) );
  2325. if(Options.general.bLoadwinpos && Options.general.bIndependentwin)
  2326. {
  2327. ::GetMainWnd()->LoadWindowStates();
  2328. }
  2329. if ( pManifest->AddExistingMap( GetPathName(), false ) )
  2330. {
  2331. OnCloseDocument();
  2332. pManifest->SetActiveMapDoc( pManifest );
  2333. pManifest->ActivateMapDoc( pManifest );
  2334. ToolManager()->SetTool( TOOL_POINTER );
  2335. GetMainWnd()->GlobalNotify( WM_MAPDOC_CHANGED );
  2336. pManifest->UpdateAllViews( MAPVIEW_UPDATE_SELECTION | MAPVIEW_UPDATE_TOOL | MAPVIEW_RENDER_NOW );
  2337. AfxMessageBox( "Manifest was successfully created and has automatically been saved.", MB_OK );
  2338. }
  2339. else
  2340. {
  2341. pManifest->OnCloseDocument();
  2342. AfxMessageBox( "Manifest was NOT created!", MB_OK );
  2343. return false;
  2344. }
  2345. return true;
  2346. }
  2347. int CMapDoc::GetClipboardCount( void )
  2348. {
  2349. return GetHammerClipboard()->Objects.Count();
  2350. }
  2351. //-----------------------------------------------------------------------------
  2352. // Purpose: this does a special paste for manifest maps
  2353. // Input : pDestWorld
  2354. // vecOffset
  2355. // vecRotate
  2356. // pParent
  2357. // bMakeEntityNamesUnique
  2358. // pszEntityNamePrefix
  2359. //-----------------------------------------------------------------------------
  2360. void CMapDoc::ManifestPaste( CMapWorld *pDestWorld, Vector vecOffset, QAngle vecRotate, CMapClass *pParent, bool bMakeEntityNamesUnique, const char *pszEntityNamePrefix )
  2361. {
  2362. Paste( GetHammerClipboard()->Objects, GetHammerClipboard()->pSourceWorld, pDestWorld, vecOffset, vecRotate, pParent, bMakeEntityNamesUnique, pszEntityNamePrefix );
  2363. GetHammerClipboard()->Objects.RemoveAll();
  2364. SetModifiedFlag( true );
  2365. }
  2366. //-----------------------------------------------------------------------------
  2367. // Purpose: this handles the routing of letting instances know their map may have been updated
  2368. // Input : pInstanceMapDoc - the map that was updated
  2369. //-----------------------------------------------------------------------------
  2370. void CMapDoc::UpdateInstanceMap( CMapDoc *pInstanceMapDoc )
  2371. {
  2372. bool bUpdated = false;
  2373. if ( m_bCollapsingInstances )
  2374. {
  2375. return;
  2376. }
  2377. const CMapObjectList *pChildren = m_pWorld->GetChildren();
  2378. FOR_EACH_OBJ( *pChildren, pos )
  2379. {
  2380. CMapClass *pChild = (CUtlReference< CMapClass >)pChildren->Element( pos );
  2381. CMapEntity *pEntity = dynamic_cast< CMapEntity * >( pChild );
  2382. if ( pEntity && stricmp( pEntity->GetClassName(), "func_instance" ) == 0 )
  2383. {
  2384. CMapInstance *pMapInstance = pEntity->GetChildOfType( ( CMapInstance * )NULL );
  2385. if ( pMapInstance )
  2386. {
  2387. if ( pMapInstance->GetInstancedMap() == pInstanceMapDoc )
  2388. {
  2389. pMapInstance->UpdateInstanceMap();
  2390. bUpdated = true;
  2391. }
  2392. }
  2393. }
  2394. }
  2395. if ( bUpdated )
  2396. {
  2397. APP()->pMapDocTemplate->UpdateInstanceMap( this );
  2398. }
  2399. }
  2400. //-----------------------------------------------------------------------------
  2401. // Purpose: This function will collapse a single instance into the map
  2402. //-----------------------------------------------------------------------------
  2403. bool CMapDoc::CollapseInstance( CMapEntity *pEntity, int &InstanceCount )
  2404. {
  2405. CMapInstance *pMapInstance = pEntity->GetChildOfType( ( CMapInstance * )NULL );
  2406. if ( pMapInstance )
  2407. {
  2408. if ( pMapInstance->GetInstancedMap() )
  2409. {
  2410. char temp[ 256 ];
  2411. Vector origin;
  2412. QAngle angles;
  2413. pMapInstance->GetInstancedMap()->OnEditSelectall();
  2414. pMapInstance->GetInstancedMap()->Copy();
  2415. pMapInstance->GetInstancedMap()->OnEditClearselection();
  2416. SetActiveMapDoc( this ); // just in case the last instance copy forces the map to close, we need to make ourselves active again
  2417. InstanceCount++;
  2418. sprintf( temp, "AutoInstance%d-", InstanceCount );
  2419. pEntity->GetOrigin( origin );
  2420. pEntity->GetAngles( angles );
  2421. PasteInstance( GetHammerClipboard()->Objects, pMapInstance->GetInstancedMap()->GetMapWorld(), GetMapWorld(), origin, angles, NULL, true, temp );
  2422. Update();
  2423. }
  2424. DeleteObject( pEntity );
  2425. m_UpdateList.RemoveAll();
  2426. SetActiveMapDoc( this ); // just in case the last instance copy forces the map to close, we need to make ourselves active again
  2427. return true;
  2428. }
  2429. return false;
  2430. }
  2431. //-----------------------------------------------------------------------------
  2432. // Purpose: This function will collapse instances into the map
  2433. //-----------------------------------------------------------------------------
  2434. void CMapDoc::CollapseInstances( bool bOnlySelected )
  2435. {
  2436. int InstanceCount = 0;
  2437. 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 )
  2438. {
  2439. return;
  2440. }
  2441. m_bCollapsingInstances = true;
  2442. CUtlVector< CMapEntity* > EntitiesToCollapse;
  2443. // collect up entities to collapse
  2444. const CMapObjectList *pChildren = m_pWorld->GetChildren();
  2445. FOR_EACH_OBJ( *pChildren, pos )
  2446. {
  2447. CMapClass *pChild = (CUtlReference< CMapClass >)pChildren->Element( pos );
  2448. CMapEntity *pEntity = dynamic_cast< CMapEntity * >( pChild );
  2449. if ( pEntity && stricmp( pEntity->GetClassName(), "func_instance" ) == 0 && ( !bOnlySelected || pEntity->GetSelectionState() != SELECT_NONE ) )
  2450. {
  2451. EntitiesToCollapse.AddToTail( pEntity );
  2452. }
  2453. }
  2454. // now collapse them
  2455. while( EntitiesToCollapse.Count() )
  2456. {
  2457. CMapEntity *pEntity = EntitiesToCollapse.Head();
  2458. EntitiesToCollapse.RemoveMultipleFromHead(1);
  2459. CollapseInstance( pEntity, InstanceCount );
  2460. }
  2461. m_bCollapsingInstances = false;
  2462. APP()->pMapDocTemplate->UpdateInstanceMap( this );
  2463. APP()->pManifestDocTemplate->UpdateInstanceMap( this );
  2464. SetModifiedFlag( true );
  2465. UpdateAllViews( MAPVIEW_UPDATE_SELECTION | MAPVIEW_UPDATE_TOOL | MAPVIEW_RENDER_NOW );
  2466. char temp[ 256 ];
  2467. sprintf( temp, "A total of %d instances were collapsed into the main map.", InstanceCount );
  2468. AfxMessageBox( temp, MB_OK | MB_ICONEXCLAMATION );
  2469. }
  2470. void CMapDoc::CollapseInstancesRecursive( bool bOnlySelected )
  2471. {
  2472. int InstanceCount = 0;
  2473. 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 )
  2474. {
  2475. return;
  2476. }
  2477. m_bCollapsingInstances = true;
  2478. const CMapObjectList *pChildren = m_pWorld->GetChildren();
  2479. FOR_EACH_OBJ( *pChildren, pos )
  2480. {
  2481. CMapClass *pChild = (CUtlReference< CMapClass >)pChildren->Element( pos );
  2482. CMapEntity *pEntity = dynamic_cast< CMapEntity * >( pChild );
  2483. if ( pEntity && stricmp( pEntity->GetClassName(), "func_instance" ) == 0 && ( !bOnlySelected || pEntity->GetSelectionState() != SELECT_NONE ) )
  2484. {
  2485. if ( CollapseInstance( pEntity, InstanceCount ) )
  2486. {
  2487. pos = -1; // start over so that we find any instances within instances
  2488. }
  2489. }
  2490. }
  2491. m_bCollapsingInstances = false;
  2492. APP()->pMapDocTemplate->UpdateInstanceMap( this );
  2493. APP()->pManifestDocTemplate->UpdateInstanceMap( this );
  2494. SetModifiedFlag( true );
  2495. UpdateAllViews( MAPVIEW_UPDATE_SELECTION | MAPVIEW_UPDATE_TOOL | MAPVIEW_RENDER_NOW );
  2496. char temp[ 256 ];
  2497. sprintf( temp, "A total of %d instances were collapsed into the main map.", InstanceCount );
  2498. AfxMessageBox( temp, MB_OK | MB_ICONEXCLAMATION );
  2499. }
  2500. //-----------------------------------------------------------------------------
  2501. // Purpose: this function will allow you to iterate through a string looking for $variables
  2502. // Input : Text - the string to search through
  2503. // StartPos - the starting index in the string
  2504. // Output : Result - returns the $variable if it exists
  2505. // returns the string index after the variable if one is found, otherwise -1 if not found
  2506. //-----------------------------------------------------------------------------
  2507. int FindInstanceParm( char *Text, int StartPos, CString &Result )
  2508. {
  2509. char *found;
  2510. found = strchr( Text + StartPos, '$' );
  2511. if ( found == NULL )
  2512. {
  2513. return -1;
  2514. }
  2515. StartPos = found - Text;
  2516. // Grab the $
  2517. Result += Text[ StartPos ];
  2518. StartPos++;
  2519. while( Text[ StartPos ] )
  2520. {
  2521. if ( V_isalnum ( Text[ StartPos ] ) == 0 && Text[ StartPos ] != '_' )
  2522. {
  2523. break;
  2524. }
  2525. Result += Text[ StartPos ];
  2526. StartPos++;
  2527. }
  2528. return StartPos;
  2529. }
  2530. void CMapDoc::PopulateInstanceParms_r( CMapEntity *pEntity, const CMapObjectList *pChildren, CUtlVector< CString > &ParmList )
  2531. {
  2532. FOR_EACH_OBJ( *pChildren, pos )
  2533. {
  2534. CMapClass *pChild = (CUtlReference< CMapClass >)pChildren->Element( pos );
  2535. CMapEntity *pInstanceEntity = dynamic_cast< CMapEntity * >( pChild );
  2536. if ( pInstanceEntity && pInstanceEntity != pEntity )
  2537. {
  2538. for ( int i = pInstanceEntity->GetFirstKeyValue(); i != pInstanceEntity->GetInvalidKeyValue(); i = pInstanceEntity->GetNextKeyValue( i ) )
  2539. {
  2540. LPCTSTR pValue = pInstanceEntity->GetKeyValue( i );
  2541. int StartPos = 0;
  2542. CString Result;
  2543. while( ( StartPos = FindInstanceParm( (char * )pValue, StartPos, Result ) ) != -1 )
  2544. {
  2545. if ( ParmList.Find( Result ) == -1 )
  2546. {
  2547. ParmList.AddToTail( Result );
  2548. }
  2549. }
  2550. }
  2551. int nCount = pInstanceEntity->Connections_GetCount();
  2552. for ( int j = 0; j < nCount; ++j )
  2553. {
  2554. CEntityConnection *pConn = pInstanceEntity->Connections_Get( j );
  2555. const char *pValue = pConn->GetTargetName();
  2556. int StartPos = 0;
  2557. CString Result;
  2558. while( ( StartPos = FindInstanceParm( (char * )pValue, StartPos, Result ) ) != -1 )
  2559. {
  2560. if ( ParmList.Find( Result ) == -1 )
  2561. {
  2562. ParmList.AddToTail( Result );
  2563. }
  2564. }
  2565. }
  2566. }
  2567. if ( pInstanceEntity != pEntity )
  2568. {
  2569. PopulateInstanceParms_r( pEntity, pChild->GetChildren(), ParmList );
  2570. }
  2571. }
  2572. }
  2573. //-----------------------------------------------------------------------------
  2574. // Purpose: this function will iterate through all entities of the current map looking for $variables.
  2575. // any ones that are found will be populated as Parm key values.
  2576. // Input : pEntity - the entity to populate
  2577. //-----------------------------------------------------------------------------
  2578. void CMapDoc::PopulateInstanceParms( CMapEntity *pEntity )
  2579. {
  2580. CUtlVector< CString > ParmList;
  2581. PopulateInstanceParms_r( pEntity, m_pWorld->GetChildren(), ParmList );
  2582. for( int i = 0; i < ParmList.Count(); i++ )
  2583. {
  2584. bool bFound = false;
  2585. for ( int j = pEntity->GetFirstKeyValue(); j != pEntity->GetInvalidKeyValue(); j = pEntity->GetNextKeyValue( j ) )
  2586. {
  2587. LPCTSTR pValue = pEntity->GetKeyValue( j );
  2588. if ( strnicmp( pValue, ParmList[ i ], strlen( ParmList[ i ] ) ) == 0 )
  2589. {
  2590. bFound = true;
  2591. break;
  2592. }
  2593. }
  2594. if ( bFound == false )
  2595. {
  2596. int j = 1;
  2597. while( 1 )
  2598. {
  2599. char tempKey[ 128 ];
  2600. sprintf( tempKey, "parm%d", j );
  2601. if ( pEntity->GetKeyValue( tempKey ) == NULL )
  2602. {
  2603. char tempValue[ MAX_KEYVALUE_LEN ];
  2604. sprintf( tempValue, "%s string", ParmList[ i ] );
  2605. pEntity->SetKeyValue( tempKey, tempValue );
  2606. break;
  2607. }
  2608. j++;
  2609. }
  2610. }
  2611. }
  2612. }
  2613. //-----------------------------------------------------------------------------
  2614. // Purpose: this function will look through the instance for a func_instance_parms. If one is
  2615. // found, then it will populate the replace fields with the parm fields.
  2616. // Input : pEntity - the func_instance
  2617. //-----------------------------------------------------------------------------
  2618. void CMapDoc::PopulateInstance( CMapEntity *pEntity )
  2619. {
  2620. CMapInstance *pMapInstance = pEntity->GetChildOfType( ( CMapInstance * )NULL );
  2621. if ( pMapInstance == NULL || pMapInstance->GetInstancedMap() == NULL )
  2622. {
  2623. return;
  2624. }
  2625. CMapEntityList entityList;
  2626. pMapInstance->GetInstancedMap()->FindEntitiesByClassName( entityList, "func_instance_parms", false );
  2627. if ( entityList.Count() != 1 )
  2628. {
  2629. return;
  2630. }
  2631. CMapEntity *pInstanceParmsEntity = entityList.Element( 0 );
  2632. for ( int i = pInstanceParmsEntity->GetFirstKeyValue(); i != pInstanceParmsEntity->GetInvalidKeyValue(); i = pInstanceParmsEntity->GetNextKeyValue( i ) )
  2633. {
  2634. LPCTSTR pKey = pInstanceParmsEntity->GetKey( i );
  2635. LPCTSTR pValue = pInstanceParmsEntity->GetKeyValue( i );
  2636. if ( strnicmp( pKey, "parm", strlen( "parm" ) ) == 0 )
  2637. {
  2638. const char *pos = strchr( pValue, ' ' );
  2639. if ( pos == NULL )
  2640. {
  2641. continue;
  2642. }
  2643. int len = pos - pValue;
  2644. bool bFound = false;
  2645. for ( int j = pEntity->GetFirstKeyValue(); j != pEntity->GetInvalidKeyValue(); j = pEntity->GetNextKeyValue( j ) )
  2646. {
  2647. LPCTSTR pInstanceKey = pEntity->GetKey( j );
  2648. LPCTSTR pInstanceValue = pEntity->GetKeyValue( j );
  2649. if ( strnicmp( pInstanceKey, "replace", strlen( "replace" ) ) == 0 &&
  2650. strnicmp( pInstanceValue, pValue, len ) == 0 )
  2651. {
  2652. bFound = true;
  2653. break;
  2654. }
  2655. }
  2656. if ( bFound == false )
  2657. {
  2658. int j = 1;
  2659. while( 1 )
  2660. {
  2661. char tempKey[ MAX_KEYVALUE_LEN ];
  2662. sprintf( tempKey, "replace%02d", j );
  2663. if ( pEntity->GetKeyValue( tempKey ) == NULL )
  2664. {
  2665. char tempValue[ MAX_KEYVALUE_LEN ];
  2666. strcpy( tempValue, pValue );
  2667. strcpy( &tempValue[ len ], " ???" );
  2668. pEntity->SetKeyValue( tempKey, tempValue );
  2669. break;
  2670. }
  2671. j++;
  2672. }
  2673. }
  2674. }
  2675. }
  2676. }
  2677. //-----------------------------------------------------------------------------
  2678. // Purpose: this function will notify all children that their owning instance has been moved.
  2679. // currently not used.
  2680. //-----------------------------------------------------------------------------
  2681. void CMapDoc::InstanceMoved( void )
  2682. {
  2683. #if 0
  2684. const CMapObjectList *pChildren = m_pWorld->GetChildren();
  2685. FOR_EACH_OBJ( *pChildren, pos )
  2686. {
  2687. CMapClass *pChild = pChildren->Element( pos );
  2688. pChild->InstanceMoved();
  2689. }
  2690. #endif
  2691. }
  2692. //-----------------------------------------------------------------------------
  2693. // Purpose: this function will return the current primary map document of the
  2694. // manifest. Generally this is the map layer that is editable where all
  2695. // entity / brush operations will take place.
  2696. // Output : the primary map document
  2697. //-----------------------------------------------------------------------------
  2698. CMapWorld *CMapDoc::GetCurrentWorld( void )
  2699. {
  2700. if ( m_pManifest )
  2701. {
  2702. return m_pManifest->GetActiveMapDoc()->m_pWorld;
  2703. }
  2704. else
  2705. {
  2706. return m_pWorld;
  2707. }
  2708. }
  2709. //-----------------------------------------------------------------------------
  2710. // Purpose:
  2711. // Output : Returns TRUE on success, FALSE on failure.
  2712. //-----------------------------------------------------------------------------
  2713. BOOL CMapDoc::SelectDocType(void)
  2714. {
  2715. // dvs: Disabled for single-config running.
  2716. // if no game configs are set up, we must set them up
  2717. //if (Options.configs.nConfigs == 0)
  2718. //{
  2719. // if (AfxMessageBox(IDS_NO_CONFIGS_AVAILABLE, MB_YESNO) == IDYES)
  2720. // {
  2721. // APP()->OpenURL(ID_HELP_FIRST_TIME_SETUP, GetMainWnd()->GetSafeHwnd());
  2722. // }
  2723. //
  2724. // COptionProperties dlg("Configure Hammer", NULL, 0);
  2725. // dlg.DoModal();
  2726. // if (Options.configs.nConfigs == 0)
  2727. // {
  2728. // return FALSE;
  2729. // }
  2730. //}
  2731. //
  2732. //
  2733. // Prompt the user to select a game configuration.
  2734. //
  2735. //CGameConfig *pGame = APP()->PromptForGameConfig();
  2736. //if (!pGame)
  2737. //{
  2738. // return FALSE;
  2739. //}
  2740. CGameConfig *pGame = g_pGameConfig;
  2741. //
  2742. // Try to find some textures that this game can use.
  2743. //
  2744. if (!g_Textures.HasTexturesForConfig(pGame))
  2745. {
  2746. AfxMessageBox(IDS_NO_TEXTURES_AVAILABLE);
  2747. COptionProperties dlg("Configure Hammer", NULL, 0);
  2748. dlg.DoModal();
  2749. if (!g_Textures.HasTexturesForConfig(pGame))
  2750. {
  2751. return FALSE;
  2752. }
  2753. }
  2754. m_pGame = pGame;
  2755. if (GetActiveMapDoc() != this)
  2756. {
  2757. SetActiveMapDoc(this);
  2758. }
  2759. return(TRUE);
  2760. }
  2761. //-----------------------------------------------------------------------------
  2762. // Purpose: set up this document to edit a prefab data .. when the object is saved,
  2763. // save it back to the library instead of to a file.
  2764. // Input : dwPrefabID -
  2765. //-----------------------------------------------------------------------------
  2766. void CMapDoc::EditPrefab3D(DWORD dwPrefabID)
  2767. {
  2768. CPrefab3D *pPrefab = (CPrefab3D *)CPrefab::FindID(dwPrefabID);
  2769. Assert(pPrefab);
  2770. // set up local variables
  2771. m_dwPrefabID = dwPrefabID;
  2772. m_dwPrefabLibraryID = pPrefab->GetLibraryID();
  2773. m_bEditingPrefab = TRUE;
  2774. SetPathName(pPrefab->GetName(), FALSE);
  2775. SetTitle(pPrefab->GetName());
  2776. // copy prefab data to world
  2777. if (!pPrefab->IsLoaded())
  2778. {
  2779. pPrefab->Load();
  2780. }
  2781. //
  2782. // Copying into world, so we update the object dependencies to insure
  2783. // that any object references in the prefab get resolved.
  2784. //
  2785. m_pWorld->CopyFrom(pPrefab->GetWorld(), false);
  2786. m_pWorld->CopyChildrenFrom(pPrefab->GetWorld(), false);
  2787. }
  2788. //-----------------------------------------------------------------------------
  2789. //-----------------------------------------------------------------------------
  2790. CMapWorld *CMapDoc::Cordon_AddTempObjectsToWorld( CMapObjectList &CordonList )
  2791. {
  2792. CMapWorld *pCordonWorld = Cordon_CreateWorld();
  2793. const CMapObjectList *pChildren = pCordonWorld->GetChildren();
  2794. FOR_EACH_OBJ( *pChildren, pos )
  2795. {
  2796. CMapClass *pChild = (CUtlReference< CMapClass >)pChildren->Element(pos);
  2797. pChild->SetTemporary(TRUE);
  2798. m_pWorld->AddObjectToWorld(pChild);
  2799. CordonList.AddToTail(pChild);
  2800. }
  2801. return pCordonWorld;
  2802. }
  2803. //-----------------------------------------------------------------------------
  2804. // Purpose:
  2805. // Input : file -
  2806. // fIsStoring -
  2807. // bRMF -
  2808. // Output : Returns TRUE on success, FALSE on failure.
  2809. //-----------------------------------------------------------------------------
  2810. BOOL CMapDoc::Serialize(std::fstream& file, BOOL fIsStoring, BOOL bRMF)
  2811. {
  2812. SetActiveMapDoc(this);
  2813. // check for editing prefab
  2814. if(m_bEditingPrefab)
  2815. {
  2816. // save prefab in library
  2817. CPrefabLibrary *pLibrary = CPrefabLibrary::FindID(m_dwPrefabLibraryID);
  2818. if(!pLibrary)
  2819. {
  2820. static int id = 1;
  2821. AfxMessageBox("The library this prefab object belongs to has been\n"
  2822. "deleted. This document will now behave as a regular file\n"
  2823. "document.");
  2824. m_bEditingPrefab = FALSE;
  2825. CString str;
  2826. str.Format("Prefab%d.rmf", id++);
  2827. SetPathName(str);
  2828. return 1;
  2829. }
  2830. CPrefab3D *pPrefab = (CPrefab3D *)CPrefab::FindID(m_dwPrefabID);
  2831. if (!pPrefab)
  2832. {
  2833. // Not found, create a new prefab.
  2834. pPrefab = new CPrefabRMF;
  2835. }
  2836. pPrefab->SetWorld(m_pWorld);
  2837. m_pWorld = NULL;
  2838. pLibrary->Add(pPrefab);
  2839. pLibrary->Save();
  2840. return 1;
  2841. }
  2842. GetHistory()->Pause();
  2843. if(bRMF)
  2844. {
  2845. if (m_pWorld->SerializeRMF(file, fIsStoring) < 0)
  2846. {
  2847. AfxMessageBox("There was a file error.", MB_OK | MB_ICONEXCLAMATION);
  2848. return FALSE;
  2849. }
  2850. Camera3D *pCamTool = dynamic_cast<Camera3D*>(m_pToolManager->GetToolForID(TOOL_CAMERA));
  2851. if ( pCamTool )
  2852. {
  2853. char sig[8] = "DOCINFO";
  2854. if(fIsStoring)
  2855. {
  2856. file.write(sig, sizeof sig);
  2857. pCamTool->SerializeRMF(file, fIsStoring);
  2858. }
  2859. else
  2860. {
  2861. char buf[sizeof sig];
  2862. memset(buf, 0, sizeof buf);
  2863. file.read(buf, sizeof buf);
  2864. if(memcmp(buf, sig, sizeof sig))
  2865. goto Done;
  2866. pCamTool->SerializeRMF(file, fIsStoring);
  2867. }
  2868. }
  2869. Done:;
  2870. }
  2871. else
  2872. {
  2873. CMapObjectList CordonList;
  2874. CMapWorld *pCordonWorld = NULL;
  2875. BoundBox CordonBox;
  2876. Cordon_GetBounds( CordonBox.bmins, CordonBox.bmaxs );
  2877. if ( m_bIsCordoning )
  2878. {
  2879. //
  2880. // Create "cordon world", add its objects to our real world, create a list in
  2881. // CordonList so we can remove them again.
  2882. //
  2883. pCordonWorld = Cordon_CreateWorld();
  2884. const CMapObjectList *pChildren = pCordonWorld->GetChildren();
  2885. FOR_EACH_OBJ( *pChildren, pos )
  2886. {
  2887. CMapClass *pChild = (CUtlReference< CMapClass >)pChildren->Element(pos);
  2888. pChild->SetTemporary(TRUE);
  2889. m_pWorld->AddObjectToWorld(pChild);
  2890. CordonList.AddToTail(pChild);
  2891. }
  2892. //
  2893. // HACK: (not mine) - make the cordon bounds bigger so that the cordon brushes
  2894. // overlap the cordon bounds during serialization.
  2895. CordonBox.bmins -= Vector(1,1,1);
  2896. CordonBox.bmaxs += Vector(1,1,1);
  2897. }
  2898. if (fIsStoring)
  2899. {
  2900. void SetMapFormat(MAPFORMAT mf);
  2901. SetMapFormat(m_pGame->mapformat);
  2902. }
  2903. if (m_pWorld->SerializeMAP(file, fIsStoring, m_bIsCordoning? &CordonBox : NULL) < 0)
  2904. {
  2905. AfxMessageBox("There was a file error.", MB_OK | MB_ICONEXCLAMATION);
  2906. return(FALSE);
  2907. }
  2908. //
  2909. // Remove cordon objects.
  2910. //
  2911. if ( m_bIsCordoning )
  2912. {
  2913. FOR_EACH_OBJ( CordonList, pos )
  2914. {
  2915. CMapClass *pobj = CordonList.Element(pos);
  2916. m_pWorld->RemoveChild(pobj);
  2917. }
  2918. delete pCordonWorld;
  2919. }
  2920. }
  2921. GetHistory()->Resume();
  2922. if (!fIsStoring)
  2923. {
  2924. UpdateVisibilityAll();
  2925. GetMainWnd()->GlobalNotify(WM_MAPDOC_CHANGED);
  2926. }
  2927. return TRUE;
  2928. }
  2929. #ifdef _DEBUG
  2930. //-----------------------------------------------------------------------------
  2931. // Purpose:
  2932. //-----------------------------------------------------------------------------
  2933. void CMapDoc::AssertValid(void) const
  2934. {
  2935. CDocument::AssertValid();
  2936. }
  2937. //-----------------------------------------------------------------------------
  2938. // Purpose:
  2939. // Input : dc -
  2940. //-----------------------------------------------------------------------------
  2941. void CMapDoc::Dump(CDumpContext& dc) const
  2942. {
  2943. CDocument::Dump(dc);
  2944. }
  2945. #endif //_DEBUG
  2946. //-----------------------------------------------------------------------------
  2947. // Purpose: Frees all dynamically allocated memory from this document.
  2948. //-----------------------------------------------------------------------------
  2949. void CMapDoc::DeleteContents(void)
  2950. {
  2951. m_NotifyList.PurgeAndDeleteElements();
  2952. //
  2953. // Don't leave pointers to deleted worlds lying around!
  2954. //
  2955. if (GetHammerClipboard()->pSourceWorld == m_pWorld)
  2956. {
  2957. GetHammerClipboard()->pSourceWorld = NULL;
  2958. }
  2959. if ( m_VisGroups )
  2960. {
  2961. m_VisGroups->PurgeAndDeleteElements();
  2962. // delete m_VisGroups;
  2963. // m_VisGroups = NULL;
  2964. }
  2965. if ( m_RootVisGroups )
  2966. {
  2967. m_RootVisGroups->RemoveAll();
  2968. // delete m_RootVisGroups;
  2969. // m_RootVisGroups = NULL;
  2970. }
  2971. if ( m_pManifestOwner == NULL && m_pSelection )
  2972. {
  2973. m_pSelection->RemoveAll();
  2974. // delete m_pSelection;
  2975. // m_pSelection = NULL;
  2976. }
  2977. if ( m_pWorld )
  2978. {
  2979. delete m_pWorld;
  2980. m_pWorld = NULL;
  2981. }
  2982. if ( m_pGridNav )
  2983. {
  2984. delete m_pGridNav;
  2985. m_pGridNav = NULL;
  2986. }
  2987. GetMainWnd()->m_pFaceEditSheet->ClearFaceListByMapDoc( this );
  2988. CDocument::DeleteContents();
  2989. CMainFrame *pwndMain = GetMainWnd();
  2990. if (pwndMain != NULL)
  2991. {
  2992. pwndMain->OnDeleteActiveDocument();
  2993. }
  2994. }
  2995. //-----------------------------------------------------------------------------
  2996. // Purpose:
  2997. // Input : id -
  2998. // Output : Returns a pointer to the visgroup with the given ID, NULL if none.
  2999. //-----------------------------------------------------------------------------
  3000. CVisGroup *CMapDoc::VisGroups_GroupForID(DWORD id)
  3001. {
  3002. int nCount = m_VisGroups->Count();
  3003. for (int i = 0; i < nCount; i++)
  3004. {
  3005. CVisGroup *pGroup = m_VisGroups->Element(i);
  3006. if (pGroup->GetID() == id)
  3007. {
  3008. return(pGroup);
  3009. }
  3010. }
  3011. return(NULL);
  3012. }
  3013. CVisGroup *CMapDoc::VisGroups_GroupForName( const char *pszName, bool bIsAuto )
  3014. {
  3015. int nCount = m_VisGroups->Count();
  3016. for ( int i = 0; i < nCount; i++ )
  3017. {
  3018. CVisGroup *pGroup = m_VisGroups->Element(i);
  3019. if ( !Q_stricmp( pGroup->GetName(), pszName ) && ( pGroup->IsAutoVisGroup() == bIsAuto ) )
  3020. {
  3021. return pGroup;
  3022. }
  3023. }
  3024. return NULL;
  3025. }
  3026. //-----------------------------------------------------------------------------
  3027. // Purpose: Prompts the user through the process of hiding a set of objects.
  3028. // Returns true if the objects were hidden.
  3029. //-----------------------------------------------------------------------------
  3030. void CMapDoc::ShowNewVisGroupsDialog(CMapObjectList &Objects, bool bUnselectObjects)
  3031. {
  3032. int nCount = Objects.Count();
  3033. if (!nCount)
  3034. {
  3035. return;
  3036. }
  3037. //
  3038. // Let the user input a name for the new visgroup.
  3039. //
  3040. CString str;
  3041. str.Format("%d object%s", nCount, nCount == 1 ? "" : "s");
  3042. CNewVisGroupDlg dlg(str);
  3043. if (dlg.DoModal() == IDCANCEL)
  3044. {
  3045. return;
  3046. }
  3047. //
  3048. // Create the visgroup (or use the one they picked).
  3049. //
  3050. CVisGroup *pVisGroup = dlg.GetPickedVisGroup();
  3051. if (!pVisGroup)
  3052. {
  3053. dlg.GetName(str);
  3054. pVisGroup = VisGroups_AddGroup(str);
  3055. }
  3056. VisGroups_AddObjectsToVisGroup(Objects, pVisGroup, dlg.GetHideObjectsOption(), dlg.GetRemoveFromOtherGroups());
  3057. if ( bUnselectObjects && dlg.GetHideObjectsOption() )
  3058. {
  3059. // We don't want hidden objects still selected, so clear the selection.
  3060. m_pSelection->SelectObject( NULL, scClear );
  3061. }
  3062. }
  3063. //-----------------------------------------------------------------------------
  3064. // Purpose: Creates a new visgroup with the given objects in it.
  3065. //-----------------------------------------------------------------------------
  3066. void CMapDoc::VisGroups_CreateNamedVisGroup(CMapObjectList &Objects, const char *szName, bool bHide, bool bRemoveFromOtherVisGroups)
  3067. {
  3068. CVisGroup *pVisGroup = VisGroups_AddGroup(szName);
  3069. VisGroups_AddObjectsToVisGroup(Objects, pVisGroup, bHide, bRemoveFromOtherVisGroups);
  3070. }
  3071. //-----------------------------------------------------------------------------
  3072. // Purpose: Adds the objects to the given visgroup and does hiding as specified.
  3073. //-----------------------------------------------------------------------------
  3074. void CMapDoc::VisGroups_AddObjectsToVisGroup(CMapObjectList &Objects, CVisGroup *pVisGroup, bool bHide, bool bRemoveFromOtherVisGroups)
  3075. {
  3076. //
  3077. // Assign the objects to it.
  3078. //
  3079. FOR_EACH_OBJ( Objects, pos )
  3080. {
  3081. CMapClass *pObject = Objects.Element(pos);
  3082. if (VisGroups_ObjectCanBelongToVisGroup(pObject))
  3083. {
  3084. if (bRemoveFromOtherVisGroups)
  3085. {
  3086. pObject->RemoveAllVisGroups();
  3087. }
  3088. pObject->AddVisGroup(pVisGroup);
  3089. }
  3090. }
  3091. if ( m_bVisGroupUpdatesLocked )
  3092. return;
  3093. //
  3094. // Clean up any visgroups with no members.
  3095. //
  3096. VisGroups_PurgeGroups();
  3097. //
  3098. // Update object visiblity and refresh views.
  3099. //
  3100. if ( bHide )
  3101. {
  3102. VisGroups_ShowVisGroup(pVisGroup, !bHide);
  3103. }
  3104. else
  3105. {
  3106. //this is currently inside of ShowVisGroup
  3107. //needs called even if we are not showing a group
  3108. VisGroups_UpdateAll();
  3109. UpdateVisibilityAll();
  3110. SetModifiedFlag();
  3111. }
  3112. CMainFrame *pwndMain = GetMainWnd();
  3113. if (pwndMain)
  3114. {
  3115. pwndMain->UpdateAllDocViews(MAPVIEW_UPDATE_VISGROUP_ALL);
  3116. }
  3117. }
  3118. //-----------------------------------------------------------------------------
  3119. // Purpose: Returns whether or not this object is eligible for inclusion in a visgroup.
  3120. //-----------------------------------------------------------------------------
  3121. bool CMapDoc::VisGroups_ObjectCanBelongToVisGroup(CMapClass *pObject)
  3122. {
  3123. if (!pObject)
  3124. return false;
  3125. CMapClass *pParent = pObject->GetParent();
  3126. if (pParent)
  3127. {
  3128. if ( IsWorldObject(pParent) )
  3129. return true;
  3130. if (pParent->IsGroup())
  3131. return true;
  3132. // Children of entities cannot belong to visgroups independent of their parent.
  3133. Assert(dynamic_cast <CMapEntity *>(pParent));
  3134. return false;
  3135. }
  3136. return false;
  3137. }
  3138. //-----------------------------------------------------------------------------
  3139. // Purpose:
  3140. // Input : pVisGroup -
  3141. // pParent -
  3142. //-----------------------------------------------------------------------------
  3143. void CMapDoc::VisGroups_SetParent(CVisGroup *pVisGroup, CVisGroup *pNewParent)
  3144. {
  3145. // Can't make a group a child of one of its descendents.
  3146. Assert(!pVisGroup->FindDescendent(pNewParent));
  3147. CVisGroup *pOldParent = pVisGroup->GetParent();
  3148. if (pOldParent != pNewParent)
  3149. {
  3150. if (pOldParent)
  3151. {
  3152. pOldParent->RemoveChild(pVisGroup);
  3153. }
  3154. else
  3155. {
  3156. int nIndex = m_RootVisGroups->Find(pVisGroup);
  3157. if (nIndex != -1)
  3158. {
  3159. m_RootVisGroups->Remove(nIndex);
  3160. }
  3161. }
  3162. if (pNewParent)
  3163. {
  3164. pNewParent->AddChild(pVisGroup);
  3165. }
  3166. else
  3167. {
  3168. m_RootVisGroups->AddToTail(pVisGroup);
  3169. }
  3170. pVisGroup->SetParent(pNewParent);
  3171. }
  3172. }
  3173. //-----------------------------------------------------------------------------
  3174. // Purpose: Update the visgroup visibility state for all groups that
  3175. // this child belongs to.
  3176. //
  3177. // NOTE: Assumes that all visgroups were initialized to VISGROUP_UNDEFINED
  3178. // before calling this with the first object.
  3179. //-----------------------------------------------------------------------------
  3180. void CMapDoc::VisGroups_UpdateForObject(CMapClass *pObject)
  3181. {
  3182. //Msg("Object: 0x%X is ", pObject);
  3183. int nVisGroupCount = pObject->GetVisGroupCount();
  3184. for (int i = 0; i < nVisGroupCount; i++)
  3185. {
  3186. CVisGroup *pGroup = pObject->GetVisGroup(i);
  3187. VisGroupState_t eVisState = pGroup->GetVisible();
  3188. if (eVisState != VISGROUP_PARTIAL)
  3189. {
  3190. if (pObject->IsVisGroupShown())
  3191. {
  3192. //if (i == 0)
  3193. // Msg("shown\n");
  3194. if (eVisState == VISGROUP_HIDDEN)
  3195. {
  3196. //Msg(" Visgroup %s was hidden, now partial\n", pGroup->GetName());
  3197. pGroup->SetVisible(VISGROUP_PARTIAL);
  3198. }
  3199. else
  3200. {
  3201. //Msg(" Visgroup %s is shown\n", pGroup->GetName());
  3202. pGroup->SetVisible(VISGROUP_SHOWN);
  3203. }
  3204. }
  3205. else
  3206. {
  3207. //if (i == 0)
  3208. // Msg("hidden\n");
  3209. if (eVisState == VISGROUP_SHOWN)
  3210. {
  3211. //Msg(" Visgroup %s was shown, now partial\n", pGroup->GetName());
  3212. pGroup->SetVisible(VISGROUP_PARTIAL);
  3213. }
  3214. else
  3215. {
  3216. //Msg(" Visgroup %s is hidden\n", pGroup->GetName());
  3217. pGroup->SetVisible(VISGROUP_HIDDEN);
  3218. }
  3219. }
  3220. }
  3221. //else
  3222. //{
  3223. // Msg(" Visgroup %s is partial\n", pGroup->GetName());
  3224. //}
  3225. }
  3226. }
  3227. //-----------------------------------------------------------------------------
  3228. // Purpose:
  3229. //-----------------------------------------------------------------------------
  3230. void CMapDoc::VisGroups_UpdateParents(void)
  3231. {
  3232. int nVisGroupCount = VisGroups_GetCount();
  3233. for (int i = 0; i < nVisGroupCount; i++)
  3234. {
  3235. CVisGroup *pTempGroup = VisGroups_GetVisGroup(i);
  3236. if ( pTempGroup->GetVisible() != VISGROUP_UNDEFINED && pTempGroup->GetParent() != NULL )
  3237. {
  3238. pTempGroup->VisGroups_UpdateParent( pTempGroup->GetVisible() );
  3239. }
  3240. }
  3241. }
  3242. //-----------------------------------------------------------------------------
  3243. // Purpose:
  3244. //-----------------------------------------------------------------------------
  3245. void CMapDoc::VisGroups_UpdateAll(void)
  3246. {
  3247. //Msg("======= Visgroups_UpdateAll ========\n");
  3248. //
  3249. // Mark all visgroups as having an undefined state so we
  3250. // can update the visibility state of all visgroups while we
  3251. // hide and show the member objects.
  3252. //
  3253. int nVisGroupCount = VisGroups_GetCount();
  3254. for (int i = 0; i < nVisGroupCount; i++)
  3255. {
  3256. CVisGroup *pTempGroup = VisGroups_GetVisGroup(i);
  3257. pTempGroup->SetVisible(VISGROUP_UNDEFINED);
  3258. }
  3259. //
  3260. // Show or hide all the objects that belong to the given visgroup.
  3261. //
  3262. EnumChildrenPos_t pos;
  3263. CMapClass *pChild = m_pWorld->GetFirstDescendent(pos);
  3264. while (pChild)
  3265. {
  3266. //
  3267. // Update the visgroup visibility state for all groups that
  3268. // this child belongs to.
  3269. //
  3270. VisGroups_UpdateForObject(pChild);
  3271. pChild = m_pWorld->GetNextDescendent(pos);
  3272. }
  3273. // Update parent state
  3274. VisGroups_UpdateParents();
  3275. //
  3276. // Look for visgroups still set as undefined -- these are empty.
  3277. //
  3278. for (int i = nVisGroupCount - 1; i >= 0; i--)
  3279. {
  3280. CVisGroup *pTempGroup = VisGroups_GetVisGroup(i);
  3281. Assert(pTempGroup->GetVisible() != VISGROUP_UNDEFINED);
  3282. }
  3283. }
  3284. //-----------------------------------------------------------------------------
  3285. // Purpose: Returns whether the object belongs to the given visgroup or any
  3286. // of that visgroup's children.
  3287. //-----------------------------------------------------------------------------
  3288. static bool IsInVisGroupRecursive(CMapClass *pObject, CVisGroup *pGroup)
  3289. {
  3290. if (pObject->IsInVisGroup(pGroup))
  3291. {
  3292. return true;
  3293. }
  3294. int nChildCount = pGroup->GetChildCount();
  3295. if (nChildCount > 0)
  3296. {
  3297. for (int i = 0; i < nChildCount; i++)
  3298. {
  3299. CVisGroup *pChild = pGroup->GetChild(i);
  3300. if (IsInVisGroupRecursive(pObject, pChild))
  3301. {
  3302. return true;
  3303. }
  3304. }
  3305. }
  3306. return false;
  3307. }
  3308. //-----------------------------------------------------------------------------
  3309. // Purpose: Hides or shows the given visgroup.
  3310. //-----------------------------------------------------------------------------
  3311. void CMapDoc::VisGroups_ShowVisGroup(CVisGroup *pGroup, bool bShow)
  3312. {
  3313. //Msg("-------- Visgroups_ShowVisGroup --------\n");
  3314. if (pGroup == NULL)
  3315. return;
  3316. VisGroupSelection eVisGroupType = USER;
  3317. if ( pGroup->IsAutoVisGroup() )
  3318. {
  3319. eVisGroupType = AUTO;
  3320. }
  3321. //
  3322. // Show or hide all the objects that belong to the given visgroup.
  3323. //
  3324. EnumChildrenPos_t pos;
  3325. CMapClass *pChild = m_pWorld->GetFirstDescendent(pos);
  3326. while (pChild)
  3327. {
  3328. if (IsInVisGroupRecursive(pChild, pGroup))
  3329. {
  3330. pChild->VisGroupShow(bShow, eVisGroupType);
  3331. }
  3332. pChild = m_pWorld->GetNextDescendent(pos);
  3333. }
  3334. VisGroups_UpdateAll();
  3335. UpdateVisibilityAll();
  3336. SetModifiedFlag();
  3337. }
  3338. //-----------------------------------------------------------------------------
  3339. // Purpose:
  3340. // Output : Returns TRUE on success, FALSE on failure.
  3341. //-----------------------------------------------------------------------------
  3342. BOOL CMapDoc::SaveModified(void)
  3343. {
  3344. if (!IsModified())
  3345. return TRUE; // ok to continue
  3346. // editing prefab and modified - update data?
  3347. if(m_bEditingPrefab)
  3348. {
  3349. switch(AfxMessageBox("Do you want to save the changes to this prefab object?", MB_YESNOCANCEL))
  3350. {
  3351. case IDYES:
  3352. {
  3353. std::fstream file;
  3354. Serialize(file, 0, 0);
  3355. return TRUE;
  3356. }
  3357. case IDNO:
  3358. return TRUE; // no save
  3359. case IDCANCEL:
  3360. return FALSE; // forget this cmd
  3361. }
  3362. }
  3363. return CDocument::SaveModified();
  3364. }
  3365. //-----------------------------------------------------------------------------
  3366. // Purpose:
  3367. // Input : lpszPathName -
  3368. // Output : Returns TRUE on success, FALSE on failure.
  3369. //-----------------------------------------------------------------------------
  3370. BOOL CMapDoc::OnOpenDocument(LPCTSTR lpszPathName)
  3371. {
  3372. Initialize();
  3373. if (!SelectDocType())
  3374. {
  3375. return FALSE;
  3376. }
  3377. //
  3378. // Look for either the RMF or MAP extension to indicate an old file format.
  3379. //
  3380. BOOL bRMF = FALSE;
  3381. BOOL bMAP = FALSE;
  3382. if (!stricmp(lpszPathName + strlen(lpszPathName) - 3, "rmf"))
  3383. {
  3384. bRMF = TRUE;
  3385. }
  3386. else if (!stricmp(lpszPathName + strlen(lpszPathName) - 3, "map"))
  3387. {
  3388. bMAP = TRUE;
  3389. }
  3390. PreloadDocument();
  3391. if ((bRMF) || (bMAP))
  3392. {
  3393. std::fstream file(lpszPathName, std::ios::in | std::ios::binary);
  3394. if (!file.is_open())
  3395. {
  3396. return(FALSE);
  3397. }
  3398. if (!Serialize(file, FALSE, bRMF))
  3399. {
  3400. return(FALSE);
  3401. }
  3402. }
  3403. else
  3404. {
  3405. if (!LoadVMF(lpszPathName))
  3406. {
  3407. return(FALSE);
  3408. }
  3409. }
  3410. SetModifiedFlag(FALSE);
  3411. Msg(mwStatus, "Opened %s", lpszPathName);
  3412. SetActiveMapDoc(this);
  3413. //
  3414. // We set the active doc before loading for displacements (and maybe other
  3415. // things), but visgroups aren't available until after map load. We have to refresh
  3416. // the visgroups here or they won't be correct.
  3417. //
  3418. GetMainWnd()->GlobalNotify(WM_MAPDOC_CHANGED);
  3419. m_pToolManager->SetTool( TOOL_POINTER );
  3420. // Clear any deferred saves until this point
  3421. if ( m_bDeferredSave )
  3422. {
  3423. OnFileSave();
  3424. m_bDeferredSave = false;
  3425. }
  3426. return(TRUE);
  3427. }
  3428. //-----------------------------------------------------------------------------
  3429. // Purpose: Called when the document is closed.
  3430. //-----------------------------------------------------------------------------
  3431. void CMapDoc::OnCloseDocument(void)
  3432. {
  3433. if ( m_nExternalReferenceCount > 0 )
  3434. { // this is an instance, so hide the window
  3435. ShowWindow( false );
  3436. if ( IsModified() )
  3437. {
  3438. DeleteContents();
  3439. OnOpenDocument( m_strPathName );
  3440. }
  3441. return;
  3442. }
  3443. //
  3444. // Deactivate the current tool now because doing it later can cause side-effects.
  3445. //
  3446. m_pToolManager->Shutdown();
  3447. //
  3448. // Call DeleteContents ourselves because in the framework implementation
  3449. // of OnCloseDocument the doc window is closed first, which activates the
  3450. // document beneath us. This is bad because we must be the active document
  3451. // during the close process for things like displacements to clean themselves
  3452. // up properly.
  3453. //
  3454. SetActiveMapDoc(this);
  3455. CDocument::OnCloseDocument();
  3456. }
  3457. //-----------------------------------------------------------------------------
  3458. // Purpose:
  3459. // Input : lpszPathName -
  3460. // Output : Returns TRUE on success, FALSE on failure.
  3461. //-----------------------------------------------------------------------------
  3462. BOOL CMapDoc::OnSaveDocument(LPCTSTR lpszPathName)
  3463. {
  3464. if( m_pBSPLighting )
  3465. m_pBSPLighting->Serialize();
  3466. // UNDONE: prefab serialization must be redone
  3467. if (m_bEditingPrefab)
  3468. {
  3469. std::fstream file;
  3470. Serialize(file, 0, 0);
  3471. SetModifiedFlag(FALSE);
  3472. OnCloseDocument();
  3473. return(TRUE);
  3474. }
  3475. //
  3476. // If a file with the same name exists, back it up before saving the new one.
  3477. //
  3478. char szFile[MAX_PATH];
  3479. strcpy(szFile, lpszPathName);
  3480. szFile[strlen(szFile) - 1] = 'x';
  3481. if (access(lpszPathName, 0) != -1)
  3482. {
  3483. if (!CopyFile(lpszPathName, szFile, FALSE))
  3484. {
  3485. CheckFileStatus();
  3486. DWORD dwError = GetLastError();
  3487. char szError[_MAX_PATH];
  3488. 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);
  3489. AfxMessageBox(szError);
  3490. return(FALSE);
  3491. }
  3492. }
  3493. //
  3494. // Use the file extension to determine how to save the file.
  3495. //
  3496. BOOL bRMF = FALSE;
  3497. BOOL bMAP = FALSE;
  3498. if (!stricmp(lpszPathName + strlen(lpszPathName) - 3, "rmf"))
  3499. {
  3500. bRMF = TRUE;
  3501. }
  3502. else if (!stricmp(lpszPathName + strlen(lpszPathName) - 3, "map"))
  3503. {
  3504. bMAP = TRUE;
  3505. }
  3506. //
  3507. // HalfLife 2 and beyond use heirarchical chunk files.
  3508. //
  3509. if ((m_pGame->mapformat == mfHalfLife2) && (!bRMF) && (!bMAP))
  3510. {
  3511. BOOL bSaved = FALSE;
  3512. BeginWaitCursor();
  3513. if (SaveVMF(lpszPathName, 0))
  3514. {
  3515. bSaved = TRUE;
  3516. SetModifiedFlag(FALSE);
  3517. }
  3518. EndWaitCursor();
  3519. CheckFileStatus();
  3520. return(bSaved);
  3521. }
  3522. //
  3523. // Half-Life used RMFs and MAPs.
  3524. //
  3525. std::fstream file(lpszPathName, std::ios::out | std::ios::binary);
  3526. if (!file.is_open())
  3527. {
  3528. CheckFileStatus();
  3529. char szError[_MAX_PATH];
  3530. 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);
  3531. AfxMessageBox(szError);
  3532. return(FALSE);
  3533. }
  3534. BeginWaitCursor();
  3535. if (!Serialize(file, TRUE, bRMF))
  3536. {
  3537. EndWaitCursor();
  3538. CheckFileStatus();
  3539. return(FALSE);
  3540. }
  3541. EndWaitCursor();
  3542. SetModifiedFlag(FALSE);
  3543. CheckFileStatus();
  3544. return(TRUE);
  3545. }
  3546. //-----------------------------------------------------------------------------
  3547. // Purpose:
  3548. // Input : st2 -
  3549. // st1 -
  3550. // Output : DWORD
  3551. //-----------------------------------------------------------------------------
  3552. DWORD SubTime(SYSTEMTIME& st2, SYSTEMTIME& st1)
  3553. {
  3554. DWORD dwMil = 0;
  3555. if(st2.wMinute != st1.wMinute)
  3556. {
  3557. dwMil += (59 - st1.wSecond) * 1000;
  3558. }
  3559. if(st2.wSecond != st1.wSecond)
  3560. {
  3561. dwMil += 1000 - st1.wMilliseconds;
  3562. }
  3563. if(!dwMil)
  3564. {
  3565. dwMil = st2.wMilliseconds - st1.wMilliseconds;
  3566. }
  3567. else
  3568. dwMil += st2.wMilliseconds;
  3569. return dwMil;
  3570. }
  3571. //-----------------------------------------------------------------------------
  3572. //-----------------------------------------------------------------------------
  3573. void CMapDoc::RenderDocument(CRender *pRender)
  3574. {
  3575. // Render every cordon that is active.
  3576. if ( m_bIsCordoning )
  3577. {
  3578. pRender->PushRenderMode( RENDER_MODE_WIREFRAME );
  3579. pRender->SetDrawColor( Color(255,0,0,255) );
  3580. for ( int i = 0; i < m_Cordons.Count(); i++ )
  3581. {
  3582. if ( m_Cordons[i].m_bActive )
  3583. {
  3584. for ( int j = 0; j < m_Cordons[i].m_Boxes.Count(); j++ )
  3585. {
  3586. pRender->DrawBox( m_Cordons[i].m_Boxes[j].bmins, m_Cordons[i].m_Boxes[j].bmaxs, false );
  3587. }
  3588. }
  3589. }
  3590. pRender->PopRenderMode();
  3591. }
  3592. }
  3593. //-----------------------------------------------------------------------------
  3594. // Purpose: Forces a render of all the 3D views. Called from OnIdle to render
  3595. // the 3D views.
  3596. //-----------------------------------------------------------------------------
  3597. void CMapDoc::RenderAllViews(void)
  3598. {
  3599. //
  3600. // Make sure the document is up to date.
  3601. //
  3602. Update();
  3603. bool bViewRendered = false;
  3604. POSITION p = GetFirstViewPosition();
  3605. while (p)
  3606. {
  3607. CMapView *pView = dynamic_cast<CMapView*>(GetNextView(p));
  3608. if ( !pView )
  3609. continue;
  3610. if ( pView->IsActive() )
  3611. {
  3612. pView->ProcessInput();
  3613. }
  3614. if ( pView->ShouldRender() )
  3615. {
  3616. pView->RenderView();
  3617. bViewRendered = true;
  3618. }
  3619. }
  3620. if ( !bViewRendered )
  3621. {
  3622. // not a single view did update this frame
  3623. // so the application seems to be idle
  3624. Sleep( 1 );
  3625. }
  3626. else
  3627. {
  3628. UpdateStatusbar();
  3629. }
  3630. }
  3631. //-----------------------------------------------------------------------------
  3632. // Purpose:
  3633. //-----------------------------------------------------------------------------
  3634. void CMapDoc::UpdateAllCameras(const Vector *vecViewPos, const Vector *vecLookAt, const float *fZoom)
  3635. {
  3636. POSITION pos = GetFirstViewPosition();
  3637. while (pos != NULL)
  3638. {
  3639. CMapView *pView = dynamic_cast<CMapView*>(GetNextView(pos));
  3640. CCamera *pCamera = pView->GetCamera();
  3641. if ( vecViewPos )
  3642. {
  3643. pCamera->SetViewPoint( *vecViewPos );
  3644. }
  3645. if ( vecLookAt && !pCamera->IsOrthographic() )
  3646. {
  3647. pCamera->SetViewTarget( *vecLookAt );
  3648. }
  3649. if ( fZoom && pCamera->IsOrthographic() )
  3650. {
  3651. pCamera->SetZoom( *fZoom );
  3652. }
  3653. pView->UpdateView( MAPVIEW_OPTIONS_CHANGED );
  3654. }
  3655. }
  3656. // walk through all views
  3657. void CMapDoc::UpdateAllViews(int nFlags, UpdateBox *ub )
  3658. {
  3659. POSITION p = GetFirstViewPosition();
  3660. while (p)
  3661. {
  3662. CMapView *pView = dynamic_cast<CMapView*>(GetNextView(p));
  3663. if ( pView )
  3664. {
  3665. pView->UpdateView( nFlags );
  3666. }
  3667. }
  3668. }
  3669. //-----------------------------------------------------------------------------
  3670. // Purpose: used during iteration, tells an map entity to
  3671. //-----------------------------------------------------------------------------
  3672. static BOOL _UpdateAnimation( CMapClass *mapClass, float animTime )
  3673. {
  3674. mapClass->UpdateAnimation( animTime );
  3675. return TRUE;
  3676. }
  3677. //-----------------------------------------------------------------------------
  3678. // Purpose: Sets up for drawing animated objects
  3679. // Needs to be called each frame before any animating object are rendered
  3680. //-----------------------------------------------------------------------------
  3681. void CMapDoc::UpdateAnimation( void )
  3682. {
  3683. if ( m_pFoW )
  3684. {
  3685. static float LastTime = m_flCurrentTime;
  3686. float diff = m_flCurrentTime - LastTime;
  3687. if ( diff >= 0.1f )
  3688. {
  3689. LastTime = m_flCurrentTime;
  3690. m_pFoW->SolveVisibility( diff );
  3691. UpdateAllViews( MAPVIEW_UPDATE_ANIMATION | MAPVIEW_UPDATE_ONLY_2D );
  3692. }
  3693. }
  3694. //GetMainWnd()->m_AnimationDlg.RunFrame();
  3695. // check to see if the animation needs to be updated
  3696. if ( !IsAnimating() )
  3697. return;
  3698. // if the animation time is 0, turn it off
  3699. if ( GetAnimationTime() == 0.0f )
  3700. {
  3701. m_bIsAnimating = false;
  3702. }
  3703. // get current animation time from animation toolbar
  3704. union {
  3705. float fl;
  3706. DWORD dw;
  3707. } animTime;
  3708. animTime.fl = GetAnimationTime();
  3709. // iterate through all CMapEntity object and update their animation frame matrix
  3710. m_pWorld->EnumChildren( ENUMMAPCHILDRENPROC(_UpdateAnimation), animTime.dw, MAPCLASS_TYPE(CMapAnimator) );
  3711. }
  3712. //-----------------------------------------------------------------------------
  3713. // Purpose: Sets the current time in the animation
  3714. // Input : time - a time, from 0 to 1
  3715. //-----------------------------------------------------------------------------
  3716. void CMapDoc::SetAnimationTime( float time )
  3717. {
  3718. m_flAnimationTime = time;
  3719. if ( m_flAnimationTime != 0.0f )
  3720. {
  3721. m_bIsAnimating = true;
  3722. }
  3723. }
  3724. //-----------------------------------------------------------------------------
  3725. // Purpose: Gets the current time and stores it in the doc, for use during the frame
  3726. //-----------------------------------------------------------------------------
  3727. void CMapDoc::UpdateCurrentTime( void )
  3728. {
  3729. m_flCurrentTime = (float)timeGetTime() / 1000;
  3730. }
  3731. //-----------------------------------------------------------------------------
  3732. // Purpose:
  3733. //-----------------------------------------------------------------------------
  3734. static BOOL SelectInBox(CMapClass *pObject, SelectBoxInfo_t *pInfo)
  3735. {
  3736. //
  3737. // Skip hidden objects.
  3738. //
  3739. if (!pObject->IsVisible())
  3740. {
  3741. return TRUE;
  3742. }
  3743. //
  3744. // Skip anything with children. We only are interested in leaf objects because
  3745. // PrepareSelection will call up to tree to get the proper ancestor.
  3746. //
  3747. if (pObject->GetChildCount())
  3748. {
  3749. return TRUE;
  3750. }
  3751. //
  3752. // Skip groups. Groups are selected via their members through PrepareSelection.
  3753. //
  3754. if (pObject->IsGroup())
  3755. {
  3756. // Shouldn't ever have empty groups lying around!
  3757. Assert(false);
  3758. return TRUE;
  3759. }
  3760. //
  3761. // Skip clutter helpers.
  3762. //
  3763. if (pObject->IsClutter())
  3764. {
  3765. return TRUE;
  3766. }
  3767. // FIXME: We're calling PrepareSelection on nearly everything in the world,
  3768. // then doing the box test against the object that we get back from that!
  3769. // We should use the octree to cull out most of the world up front.
  3770. CMapClass *pSelObject = pObject->PrepareSelection(pInfo->eSelectMode);
  3771. if (pSelObject)
  3772. {
  3773. if (Options.view2d.bSelectbyhandles)
  3774. {
  3775. Vector ptCenter;
  3776. pObject->GetBoundsCenter(ptCenter);
  3777. if (pInfo->pBox->ContainsPoint(ptCenter))
  3778. {
  3779. pInfo->pDoc->SelectObject(pSelObject, scSelect);
  3780. }
  3781. return TRUE;
  3782. }
  3783. bool bSelect;
  3784. if (pInfo->bInside)
  3785. {
  3786. bSelect = pObject->IsInsideBox(pInfo->pBox->bmins, pInfo->pBox->bmaxs);
  3787. }
  3788. else
  3789. {
  3790. bSelect = pObject->IsIntersectingBox(pInfo->pBox->bmins, pInfo->pBox->bmaxs);
  3791. }
  3792. if (bSelect)
  3793. {
  3794. pInfo->pDoc->SelectObject(pSelObject, scSelect);
  3795. }
  3796. }
  3797. return TRUE;
  3798. }
  3799. //-----------------------------------------------------------------------------
  3800. // Purpose:
  3801. //-----------------------------------------------------------------------------
  3802. static BOOL SelectInLogicalBox( CMapClass *pObject, SelectLogicalBoxInfo_t *pInfo)
  3803. {
  3804. // Skip hidden objects.
  3805. if ( !pObject->IsVisible() || !pObject->IsLogical() || !pObject->IsVisibleLogical() )
  3806. return TRUE;
  3807. // FIXME: Box selection doesn't work when this is uncommented. Why?
  3808. // Skip anything with children. We only are interested in leaf objects because
  3809. // PrepareSelection will call up to tree to get the proper ancestor.
  3810. // if ( pObject->GetChildCount() )
  3811. // return TRUE;
  3812. // Skip groups. Groups are selected via their members through PrepareSelection.
  3813. if ( pObject->IsGroup() )
  3814. {
  3815. // Shouldn't ever have empty groups lying around!
  3816. // Except if you drag select an empty area!
  3817. // Assert(false);
  3818. return TRUE;
  3819. }
  3820. // Skip clutter helpers.
  3821. if ( pObject->IsClutter() )
  3822. return TRUE;
  3823. // FIXME: We're calling PrepareSelection on nearly everything in the world,
  3824. // then doing the box test against the object that we get back from that!
  3825. // We should use the octree to cull out most of the world up front.
  3826. CMapClass *pSelObject = pObject->PrepareSelection(pInfo->eSelectMode);
  3827. if ( pSelObject )
  3828. {
  3829. Vector2D mins, maxs;
  3830. pObject->GetRenderLogicalBox( mins, maxs );
  3831. bool bSelect;
  3832. if ( pInfo->bInside )
  3833. {
  3834. bSelect = IsBoxInside( mins, maxs, pInfo->vecMins, pInfo->vecMaxs );
  3835. }
  3836. else
  3837. {
  3838. bSelect = IsBoxIntersecting( mins, maxs, pInfo->vecMins, pInfo->vecMaxs );
  3839. }
  3840. if (bSelect)
  3841. {
  3842. pInfo->pDoc->SelectObject( pSelObject, scSelect );
  3843. }
  3844. }
  3845. return TRUE;
  3846. }
  3847. //-----------------------------------------------------------------------------
  3848. // Purpose:
  3849. //-----------------------------------------------------------------------------
  3850. void CMapDoc::SelectRegion( BoundBox *pBox, bool bInsideOnly, bool ResetSelection )
  3851. {
  3852. SelectBoxInfo_t info;
  3853. info.pDoc = this;
  3854. info.pBox = pBox;
  3855. info.bInside = bInsideOnly;
  3856. info.eSelectMode = m_pSelection->GetMode();
  3857. if ( ResetSelection )
  3858. {
  3859. SelectObject(NULL, scSaveChanges);
  3860. }
  3861. m_pWorld->EnumChildren((ENUMMAPCHILDRENPROC)SelectInBox, (DWORD)&info);
  3862. }
  3863. //-----------------------------------------------------------------------------
  3864. // Purpose:
  3865. //-----------------------------------------------------------------------------
  3866. void CMapDoc::SelectLogicalRegion( const Vector2D &vecMins, const Vector2D &vecMaxs, bool bInsideOnly)
  3867. {
  3868. SelectLogicalBoxInfo_t info;
  3869. info.pDoc = this;
  3870. info.vecMins = vecMins;
  3871. info.vecMaxs = vecMaxs;
  3872. info.bInside = bInsideOnly;
  3873. info.eSelectMode = m_pSelection->GetMode();
  3874. SelectObject(NULL, scSaveChanges);
  3875. m_pWorld->EnumChildren((ENUMMAPCHILDRENPROC)SelectInLogicalBox, (DWORD)&info);
  3876. }
  3877. bool CMapDoc::SelectObject(CMapClass *pObj, int cmd)
  3878. {
  3879. return m_pSelection->SelectObject( pObj, cmd );
  3880. }
  3881. void CMapDoc::SelectObjectList(const CMapObjectList *pList, int cmd)
  3882. {
  3883. m_pSelection->SelectObjectList( pList, cmd );
  3884. }
  3885. //-----------------------------------------------------------------------------
  3886. // Purpose:
  3887. //-----------------------------------------------------------------------------
  3888. void CMapDoc::UpdateStatusbar(void)
  3889. {
  3890. if (m_pToolManager->GetActiveToolID() == TOOL_FACEEDIT_MATERIAL)
  3891. {
  3892. CString str;
  3893. str.Format("%d faces selected", GetMainWnd()->m_pFaceEditSheet->GetFaceListCount() );
  3894. SetStatusText(SBI_SELECTION, str);
  3895. SetStatusText(SBI_SIZE, "");
  3896. return;
  3897. }
  3898. CBaseTool *pTool = m_pToolManager->GetActiveTool();
  3899. if (pTool != NULL)
  3900. {
  3901. pTool->UpdateStatusBar();
  3902. }
  3903. CString str;
  3904. if ( m_pSelection )
  3905. {
  3906. int nCount = m_pSelection->GetCount();
  3907. switch (nCount)
  3908. {
  3909. case 0:
  3910. {
  3911. str = "no selection.";
  3912. break;
  3913. }
  3914. case 1:
  3915. {
  3916. CMapClass *pobj = (CUtlReference< CMapClass >)m_pSelection->GetList()->Element(0);
  3917. str = pobj->GetDescription();
  3918. // Look for the 3D view so we can also add the distance to the object.
  3919. POSITION p = GetFirstViewPosition();
  3920. while (p)
  3921. {
  3922. CMapView3D *pView = dynamic_cast<CMapView3D*>(GetNextView(p));
  3923. if (pView)
  3924. {
  3925. // Get the position of the 3D camera.
  3926. Vector vViewPoint( 0, 0, 0 );
  3927. CCamera *pCam = pView->GetCamera();
  3928. pCam->GetViewPoint(vViewPoint);
  3929. // Get the position of the object.
  3930. Vector vObjOrigin;
  3931. pobj->GetOrigin( vObjOrigin );
  3932. float flDist = vViewPoint.DistTo( vObjOrigin );
  3933. // Add the distance to the status bar string.
  3934. char strDist[512];
  3935. V_snprintf( strDist, sizeof( strDist ), " [dist: %.1f]", flDist );
  3936. str += strDist;
  3937. break;
  3938. }
  3939. }
  3940. break;
  3941. }
  3942. default:
  3943. {
  3944. str.Format("%d objects selected.", nCount);
  3945. break;
  3946. }
  3947. }
  3948. }
  3949. SetStatusText(SBI_SELECTION, str);
  3950. }
  3951. //-----------------------------------------------------------------------------
  3952. // Purpose:
  3953. //-----------------------------------------------------------------------------
  3954. void CMapDoc::BuildCascadingSelectionList( CMapClass *pObj, CUtlRBTree< CMapClass*, unsigned short > &list, bool bRecursive )
  3955. {
  3956. // Also add all entities connected to outputs of this selection
  3957. CEditGameClass *pClass = dynamic_cast< CEditGameClass * >( pObj );
  3958. if ( !pClass )
  3959. return;
  3960. int nCount = pClass->Connections_GetCount();
  3961. for ( int j = 0; j < nCount; ++j )
  3962. {
  3963. CEntityConnection *pConn = pClass->Connections_Get( j );
  3964. CMapEntityList entityList;
  3965. FindEntitiesByName( entityList, pConn->GetTargetName(), true );
  3966. int nOutputCount = entityList.Count();
  3967. for ( int k = 0; k < nOutputCount; ++k )
  3968. {
  3969. CMapEntity *pEntity = entityList.Element(k);
  3970. if ( pEntity == pObj )
  3971. continue;
  3972. if ( list.InsertIfNotFound( pEntity ) != list.InvalidIndex() )
  3973. {
  3974. if ( bRecursive )
  3975. {
  3976. BuildCascadingSelectionList( pEntity, list, bRecursive );
  3977. }
  3978. }
  3979. }
  3980. }
  3981. }
  3982. //-----------------------------------------------------------------------------
  3983. // Purpose:
  3984. // Input : pDoc -
  3985. //-----------------------------------------------------------------------------
  3986. void CMapDoc::SetActiveMapDoc(CMapDoc *pDoc)
  3987. {
  3988. // Only do the work when the doc actually changes.
  3989. if (pDoc == m_pMapDoc)
  3990. {
  3991. return;
  3992. }
  3993. if ( m_pMapDoc != NULL )
  3994. {
  3995. // disable active views in all map doc
  3996. m_pMapDoc->SetActiveView(NULL);
  3997. }
  3998. m_pMapDoc = pDoc;
  3999. m_pManifest = dynamic_cast< CManifest * >( m_pMapDoc );
  4000. //
  4001. // Set the new document in the shell.
  4002. //
  4003. g_Shell.SetDocument(m_pMapDoc);
  4004. //
  4005. // Set the history to the document's history.
  4006. //
  4007. if (m_pMapDoc != NULL)
  4008. {
  4009. // attach document selection to property box
  4010. GetMainWnd()->pObjectProperties->SetObjectList( m_pMapDoc->GetSelection()->GetList() );
  4011. if ( m_pManifest && m_pManifest->GetPrimaryMap() )
  4012. {
  4013. CHistory::SetHistory( m_pManifest->GetPrimaryMap()->m_Map->GetDocHistory() );
  4014. }
  4015. else
  4016. {
  4017. CHistory::SetHistory(m_pMapDoc->GetDocHistory());
  4018. }
  4019. m_pMapDoc->SetUndoActive(GetMainWnd()->IsUndoActive() == TRUE);
  4020. m_pMapDoc->UpdateAllViews( MAPVIEW_UPDATE_OBJECTS );
  4021. }
  4022. else
  4023. {
  4024. CHistory::SetHistory(NULL);
  4025. GetMainWnd()->pObjectProperties->SetObjectList( NULL );
  4026. }
  4027. //
  4028. // Notify that the active document has changed.
  4029. //
  4030. GetMainWnd()->GlobalNotify(WM_MAPDOC_CHANGED);
  4031. // dvs: don't do this anymore because we run single-config only
  4032. // Set global game config to type found in doc.
  4033. //
  4034. //CGameConfig *pOldGame = CGameConfig::GetActiveGame();
  4035. //if (pDoc != NULL)
  4036. //{
  4037. // CGameConfig::SetActiveGame(pDoc->GetGame());
  4038. //}
  4039. //else
  4040. //{
  4041. // CGameConfig::SetActiveGame(NULL);
  4042. //}
  4043. //
  4044. //
  4045. // Update everything the first time we create a document or when the
  4046. // game configuration changes between documents.
  4047. //
  4048. //static bool bFirst = true;
  4049. //if ((pOldGame != CGameConfig::GetActiveGame()) || (bFirst))
  4050. //{
  4051. // bFirst = false;
  4052. // GetMainWnd()->GlobalNotify(WM_GAME_CHANGED);
  4053. //}
  4054. // Update everything the first time we create a document.
  4055. static bool bFirst = true;
  4056. if (bFirst)
  4057. {
  4058. bFirst = false;
  4059. GetMainWnd()->GlobalNotify(WM_GAME_CHANGED);
  4060. }
  4061. }
  4062. //-----------------------------------------------------------------------------
  4063. // Purpose: this will activate and bring to front the supplied map document
  4064. // Input : pDoc - the document to activate
  4065. // Output : none
  4066. //-----------------------------------------------------------------------------
  4067. void CMapDoc::ActivateMapDoc( CMapDoc *pDoc )
  4068. {
  4069. POSITION posView = pDoc->GetFirstViewPosition( );
  4070. if( posView )
  4071. {
  4072. CView* pView = pDoc->GetNextView( posView );
  4073. ((CMDIChildWnd*) pView->GetParentFrame( ))->MDIActivate( );
  4074. }
  4075. }
  4076. //-----------------------------------------------------------------------------
  4077. // Purpose:
  4078. //-----------------------------------------------------------------------------
  4079. CMapWorld *GetActiveWorld(void)
  4080. {
  4081. CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
  4082. if (pDoc != NULL)
  4083. {
  4084. return(pDoc->GetMapWorld());
  4085. }
  4086. return(NULL);
  4087. }
  4088. //-----------------------------------------------------------------------------
  4089. //-----------------------------------------------------------------------------
  4090. IWorldEditDispMgr *GetActiveWorldEditDispManager( void )
  4091. {
  4092. CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
  4093. if( pDoc )
  4094. {
  4095. CMapWorld *pWorld = pDoc->GetMapWorld();
  4096. if( pWorld )
  4097. {
  4098. return pWorld->GetWorldEditDispManager();
  4099. }
  4100. }
  4101. return NULL;
  4102. }
  4103. //-----------------------------------------------------------------------------
  4104. // Purpose: Deletes the object by removing it from its parent. The object is
  4105. // kept in the Undo history. If the object being deleted is the only
  4106. // child of a solid entity, that entity is also deleted.
  4107. // Input : pObject - The object to delete.
  4108. //-----------------------------------------------------------------------------
  4109. void CMapDoc::DeleteObject(CMapClass *pObject)
  4110. {
  4111. GetHistory()->KeepForDestruction(pObject);
  4112. CMapClass *pParent = pObject->GetParent();
  4113. RemoveObjectFromWorld(pObject, true);
  4114. // If we are deleting the last child of a solid entity, or the last member of
  4115. // a group, delete the parent object also. This avoids ghost objects at the origin.
  4116. pObject->SignalChanged();
  4117. if (pParent)
  4118. {
  4119. if (pParent->IsGroup())
  4120. {
  4121. if (pParent->GetChildCount() == 0)
  4122. {
  4123. DeleteObject(pParent);
  4124. }
  4125. }
  4126. else
  4127. {
  4128. CMapEntity *pParentEntity = dynamic_cast <CMapEntity *>(pParent);
  4129. if (pParentEntity != NULL)
  4130. {
  4131. if (!pParentEntity->IsPlaceholder() && !pParentEntity->HasSolidChildren())
  4132. {
  4133. DeleteObject(pParentEntity);
  4134. }
  4135. }
  4136. }
  4137. }
  4138. }
  4139. //-----------------------------------------------------------------------------
  4140. // Purpose: Call this to delete multiple objects in a single operation.
  4141. // Input : List -
  4142. //-----------------------------------------------------------------------------
  4143. void CMapDoc::DeleteObjectList(CMapObjectList &List)
  4144. {
  4145. FOR_EACH_OBJ( List, pos )
  4146. {
  4147. CMapClass *pObject = List.Element(pos);
  4148. Assert(pObject != NULL);
  4149. DeleteObject(pObject);
  4150. }
  4151. m_pSelection->RemoveAll();
  4152. SetModifiedFlag();
  4153. }
  4154. //-----------------------------------------------------------------------------
  4155. // Purpose: Delete selected objects.
  4156. //-----------------------------------------------------------------------------
  4157. void CMapDoc::OnEditDelete(void)
  4158. {
  4159. Delete();
  4160. }
  4161. //-----------------------------------------------------------------------------
  4162. // Purpose: Invokes the search/replace dialog.
  4163. //-----------------------------------------------------------------------------
  4164. void CMapDoc::OnEditReplace(void)
  4165. {
  4166. GetMainWnd()->ShowSearchReplaceDialog();
  4167. }
  4168. //-----------------------------------------------------------------------------
  4169. // Purpose:
  4170. //-----------------------------------------------------------------------------
  4171. void CMapDoc::OnMapSnaptogrid(void)
  4172. {
  4173. m_bSnapToGrid = !m_bSnapToGrid;
  4174. UpdateStatusBarSnap();
  4175. }
  4176. //-----------------------------------------------------------------------------
  4177. // Purpose:
  4178. //-----------------------------------------------------------------------------
  4179. void CMapDoc::UpdateStatusBarSnap(void)
  4180. {
  4181. CString strSnap;
  4182. strSnap.Format(" Snap: %s Grid: %d ", m_bSnapToGrid ? "On" : "Off", m_nGridSpacing);
  4183. SetStatusText(SBI_SNAP, strSnap);
  4184. }
  4185. //-----------------------------------------------------------------------------
  4186. // Purpose:
  4187. //-----------------------------------------------------------------------------
  4188. void CMapDoc::OnUpdateMapSnaptogrid(CCmdUI* pCmdUI)
  4189. {
  4190. pCmdUI->SetCheck(m_bSnapToGrid);
  4191. }
  4192. //-----------------------------------------------------------------------------
  4193. // Purpose: Deselects everything.
  4194. //-----------------------------------------------------------------------------
  4195. void CMapDoc::OnEditClearselection(void)
  4196. {
  4197. if (m_pToolManager->GetActiveToolID() == TOOL_MORPH)
  4198. {
  4199. // clear morph
  4200. m_pToolManager->GetActiveTool()->SetEmpty();
  4201. UpdateAllViews( MAPVIEW_UPDATE_OBJECTS );
  4202. }
  4203. else if (m_pToolManager->GetActiveToolID() == TOOL_FACEEDIT_MATERIAL)
  4204. {
  4205. SelectFace(NULL, 0, scClear|scSaveChanges);
  4206. }
  4207. else
  4208. {
  4209. ClearEntitySelection();
  4210. }
  4211. }
  4212. void CMapDoc::ClearEntitySelection()
  4213. {
  4214. if ( m_pSelection->GetCount() > 2)
  4215. {
  4216. GetHistory()->MarkUndoPosition( m_pSelection->GetList(), "Clear Selection");
  4217. }
  4218. SelectObject(NULL, scClear|scSaveChanges);
  4219. }
  4220. //-----------------------------------------------------------------------------
  4221. // Purpose:
  4222. // Input : pSolid -
  4223. // pszTexture -
  4224. // Output : Returns TRUE to continue iterating.
  4225. //-----------------------------------------------------------------------------
  4226. static BOOL ApplyTextureToSolid(CMapSolid *pSolid, LPCTSTR pszTexture)
  4227. {
  4228. pSolid->SetTexture(pszTexture);
  4229. return TRUE;
  4230. }
  4231. //-----------------------------------------------------------------------------
  4232. // Purpose: Manages the state of the Apply Current Texture toolbar button.
  4233. //-----------------------------------------------------------------------------
  4234. void CMapDoc::OnUpdateEditApplytexture(CCmdUI* pCmdUI)
  4235. {
  4236. if ( IsSelectionEditable() == false )
  4237. {
  4238. pCmdUI->Enable( FALSE );
  4239. }
  4240. else
  4241. {
  4242. pCmdUI->Enable( ( m_pToolManager->GetActiveToolID() != TOOL_FACEEDIT_MATERIAL ) && !GetMainWnd()->IsShellSessionActive() );
  4243. }
  4244. }
  4245. //-----------------------------------------------------------------------------
  4246. // Purpose: Applies the current default texture to all faces of all selected solids.
  4247. //-----------------------------------------------------------------------------
  4248. void CMapDoc::OnEditApplytexture(void)
  4249. {
  4250. const CMapObjectList *pSelList = m_pSelection->GetList();
  4251. GetHistory()->MarkUndoPosition( pSelList, "Apply Texture");
  4252. // texturebar.cpp:
  4253. LPCTSTR GetDefaultTextureName();
  4254. for (int i = 0; i < pSelList->Count(); i++)
  4255. {
  4256. CMapClass *pobj = (CUtlReference< CMapClass >)pSelList->Element(i);
  4257. if (pobj->IsMapClass(MAPCLASS_TYPE(CMapSolid)))
  4258. {
  4259. GetHistory()->Keep(pobj);
  4260. ((CMapSolid*)pobj)->SetTexture(GetDefaultTextureName());
  4261. }
  4262. pobj->EnumChildren((ENUMMAPCHILDRENPROC)ApplyTextureToSolid, (DWORD)GetDefaultTextureName(), MAPCLASS_TYPE(CMapSolid));
  4263. }
  4264. SetModifiedFlag();
  4265. }
  4266. //-----------------------------------------------------------------------------
  4267. // Purpose: Callback for EnumChildren. Adds the object to the given list.
  4268. // Input : pObject - Object to add to the list.
  4269. // pList - List to add the object to.
  4270. // Output : Returns TRUE to continue iterating.
  4271. //-----------------------------------------------------------------------------
  4272. static BOOL CopyObjectsToList(CMapClass *pObject, CMapObjectList *pList)
  4273. {
  4274. pList->AddToTail(pObject);
  4275. return(TRUE);
  4276. }
  4277. //-----------------------------------------------------------------------------
  4278. // Purpose: Makes all selected brushes the children of a solid entity. The
  4279. // class will be the default solid class from the game configuration.
  4280. //-----------------------------------------------------------------------------
  4281. void CMapDoc::OnEditToEntity(void)
  4282. {
  4283. extern GameData *pGD;
  4284. CMapEntity *pNewEntity = NULL;
  4285. BOOL bMadeEntity = TRUE;
  4286. BOOL bUseSelectionDialog = FALSE;
  4287. //
  4288. // Build a list of every solid in the selection, whether part of a solid entity or not.
  4289. //
  4290. CMapObjectList newobjects;
  4291. const CMapObjectList *pSelList = m_pSelection->GetList();
  4292. for (int i = 0; i < pSelList->Count(); i++)
  4293. {
  4294. CMapClass *pObject = (CUtlReference< CMapClass >)pSelList->Element(i);
  4295. //
  4296. // If the object is a solid, add it to our list.
  4297. //
  4298. if (pObject->IsMapClass(MAPCLASS_TYPE(CMapSolid)))
  4299. {
  4300. newobjects.AddToTail(pObject);
  4301. }
  4302. //
  4303. // If the object is a group, add any solids in the group to our list.
  4304. //
  4305. else if (pObject->IsGroup())
  4306. {
  4307. pObject->EnumChildren(ENUMMAPCHILDRENPROC(CopyObjectsToList), DWORD(&newobjects), MAPCLASS_TYPE(CMapSolid));
  4308. }
  4309. //
  4310. // If the object is an entity, add any solid children of the entity to our list.
  4311. //
  4312. else if (pObject->IsMapClass(MAPCLASS_TYPE(CMapEntity)))
  4313. {
  4314. pObject->EnumChildren(ENUMMAPCHILDRENPROC(CopyObjectsToList), DWORD(&newobjects), MAPCLASS_TYPE(CMapSolid));
  4315. //
  4316. // See if there is more than one solid entity selected. If so, we'll need to prompt the user
  4317. // to pick one.
  4318. //
  4319. CMapEntity *pEntity = (CMapEntity *)pObject;
  4320. if (!pEntity->IsPlaceholder())
  4321. {
  4322. //
  4323. // Already found an eligible entity, so we want
  4324. // to call up the entity selection dialog.
  4325. //
  4326. if (pNewEntity != NULL)
  4327. {
  4328. bUseSelectionDialog = TRUE;
  4329. }
  4330. pNewEntity = pEntity;
  4331. }
  4332. }
  4333. }
  4334. //
  4335. // If the list is empty, we have nothing to do.
  4336. //
  4337. if ( newobjects.Count() == 0)
  4338. {
  4339. AfxMessageBox("There are no eligible selected objects.");
  4340. return;
  4341. }
  4342. //
  4343. // If already have an entity selected, ask if they want to
  4344. // add solids to it.
  4345. //
  4346. if (pNewEntity && !bUseSelectionDialog)
  4347. {
  4348. CString str;
  4349. str.Format("You have selected an existing entity (a '%s'.)\n"
  4350. "Would you like to add the selected solids to the existing entity?\n"
  4351. "If you select 'No', a new entity will be created.",
  4352. pNewEntity->GetClassName());
  4353. if (AfxMessageBox(str, MB_YESNO) == IDNO)
  4354. {
  4355. pNewEntity = NULL; // it'll be made down there
  4356. }
  4357. else
  4358. {
  4359. bMadeEntity = FALSE;
  4360. }
  4361. }
  4362. //
  4363. // If there were multiple solid entities selected, bring up the selection dialog.
  4364. //
  4365. else if (bUseSelectionDialog)
  4366. {
  4367. CSelectEntityDlg dlg(m_pSelection->GetList());
  4368. GetMainWnd()->pObjectProperties->ShowWindow(SW_SHOW);
  4369. if (dlg.DoModal() == IDCANCEL)
  4370. {
  4371. return; // forget about it
  4372. }
  4373. pNewEntity = dlg.m_pFinalEntity;
  4374. bMadeEntity = FALSE;
  4375. }
  4376. GetHistory()->MarkUndoPosition(m_pSelection->GetList(), "To Entity");
  4377. GetHistory()->Keep(m_pSelection->GetList());
  4378. //
  4379. // If they haven't already picked an entity to add the solids to, create a new
  4380. // solid entity.
  4381. //
  4382. if (!pNewEntity)
  4383. {
  4384. pNewEntity = new CMapEntity;
  4385. bMadeEntity = TRUE;
  4386. }
  4387. //
  4388. // Add all the solids in our list to the solid entity.
  4389. //
  4390. FOR_EACH_OBJ( newobjects, pos )
  4391. {
  4392. CMapClass *pObject = newobjects.Element(pos);
  4393. CMapClass *pOldParent = pObject->GetParent();
  4394. //
  4395. // If the solid is changing parents...
  4396. //
  4397. if (pOldParent != pNewEntity)
  4398. {
  4399. Assert(pOldParent != NULL);
  4400. if (pOldParent != NULL)
  4401. {
  4402. //
  4403. // Remove the solid from its current parent.
  4404. //
  4405. pOldParent->RemoveChild(pObject);
  4406. //
  4407. // If this solid was the child of a solid entity, check to see if the entity has
  4408. // any children left - if not, we remove it from the world because it's useless without
  4409. // solid children.
  4410. //
  4411. CMapEntity *pOldParentEnt = dynamic_cast<CMapEntity *>(pOldParent);
  4412. if (pOldParentEnt && (!pOldParentEnt->IsPlaceholder()) && (!pOldParentEnt->HasSolidChildren()))
  4413. {
  4414. DeleteObject(pOldParentEnt);
  4415. }
  4416. }
  4417. //
  4418. // Add visgroups from the solid to the new entity.
  4419. //
  4420. int nVisGroupCount = pObject->GetVisGroupCount();
  4421. for (int nVisGroup = 0; nVisGroup < nVisGroupCount; nVisGroup++)
  4422. {
  4423. CVisGroup *pVisGroup = pObject->GetVisGroup(nVisGroup);
  4424. // Don't transfer autovisgroups
  4425. if ( pVisGroup->IsAutoVisGroup() )
  4426. continue;
  4427. pNewEntity->AddVisGroup(pVisGroup);
  4428. }
  4429. //
  4430. // Remove the child from all visgroups
  4431. //
  4432. pObject->RemoveAllVisGroups();
  4433. //
  4434. // Add the solid as a child of the new parent entity.
  4435. //
  4436. pNewEntity->AddChild(pObject);
  4437. }
  4438. }
  4439. //
  4440. // If we created a new entity, add it to the world.
  4441. //
  4442. if (bMadeEntity)
  4443. {
  4444. pNewEntity->SetPlaceholder(FALSE);
  4445. pNewEntity->SetClass(g_pGameConfig->szDefaultSolid);
  4446. AddObjectToWorld(pNewEntity);
  4447. //
  4448. // Don't keep our children because they are not new to the world.
  4449. //
  4450. GetHistory()->KeepNew(pNewEntity, false);
  4451. }
  4452. SelectObject(pNewEntity, scClear|scSelect|scSaveChanges );
  4453. m_pToolManager->SetTool(TOOL_POINTER);
  4454. if (bMadeEntity)
  4455. {
  4456. GetMainWnd()->pObjectProperties->ShowWindow(SW_SHOW);
  4457. GetMainWnd()->pObjectProperties->SetActiveWindow();
  4458. }
  4459. SetModifiedFlag();
  4460. }
  4461. //-----------------------------------------------------------------------------
  4462. // Purpose: Moves all solid children of selected entities to the world.
  4463. //-----------------------------------------------------------------------------
  4464. void CMapDoc::OnEditToWorld(void)
  4465. {
  4466. CMapObjectList SelList;
  4467. SelList.AddVectorToTail( *m_pSelection->GetList());
  4468. if ( SelList.Count()>0 )
  4469. {
  4470. GetHistory()->MarkUndoPosition(m_pSelection->GetList(), "To World");
  4471. GetHistory()->Keep(m_pSelection->GetList());
  4472. //
  4473. // Remove selection rect from screen & clear selection list.
  4474. //
  4475. SelectObject(NULL, scClear|scSaveChanges );
  4476. FOR_EACH_OBJ( SelList, pos )
  4477. {
  4478. CMapClass *pObject = SelList.Element(pos);
  4479. CMapEntity *pEntity = dynamic_cast<CMapEntity *>(pObject);
  4480. //
  4481. // If this is a solid entity, move all its children to the world.
  4482. //
  4483. if ((pEntity != NULL) && (!pEntity->IsPlaceholder()))
  4484. {
  4485. //
  4486. // Build a list of the entity's solid children.
  4487. //
  4488. CMapObjectList ChildList;
  4489. const CMapObjectList *pChildren = pEntity->GetChildren();
  4490. FOR_EACH_OBJ( *pChildren, pos2 )
  4491. {
  4492. CMapClass *pChild = (CUtlReference< CMapClass >)pChildren->Element(pos2);
  4493. if ((dynamic_cast<CMapSolid *>(pChild)) != NULL)
  4494. {
  4495. ChildList.AddToTail(pChild);
  4496. }
  4497. }
  4498. //
  4499. // Detach all the children from the entity. This throws out
  4500. // all non-solid children, since they aren't in our list.
  4501. //
  4502. pEntity->RemoveAllChildren();
  4503. //
  4504. // Move the entity's former solid children to the world.
  4505. //
  4506. int nChildCount = ChildList.Count();
  4507. for (int i = 0; i < nChildCount; i++)
  4508. {
  4509. CMapClass *pChild = ChildList.Element(i);
  4510. m_pWorld->AddChild(pChild);
  4511. int nVisGroupCount = pEntity->GetVisGroupCount();
  4512. for (int nVisGroup = 0; nVisGroup < nVisGroupCount; nVisGroup++)
  4513. {
  4514. CVisGroup *pVisGroup = pEntity->GetVisGroup(nVisGroup);
  4515. // Don't add autovisgroups when moving back
  4516. if ( pVisGroup->IsAutoVisGroup() )
  4517. continue;
  4518. pChild->AddVisGroup(pVisGroup);
  4519. }
  4520. // Add autovisgroups for the child
  4521. RemoveFromAutoVisGroups( pChild );
  4522. AddToAutoVisGroup( pChild );
  4523. pChild->SetRenderColor(0, 100 + (random() % 156), 100 + (random() % 156));
  4524. SelectObject(pChild, scSelect);
  4525. }
  4526. //
  4527. // The entity is empty; delete it.
  4528. //
  4529. DeleteObject(pEntity);
  4530. }
  4531. }
  4532. }
  4533. m_pToolManager->SetTool(TOOL_POINTER);
  4534. SetModifiedFlag();
  4535. }
  4536. //-----------------------------------------------------------------------------
  4537. // Purpose: Subtracts the first object in the selection set (by index) from
  4538. // all solids in the world.
  4539. //-----------------------------------------------------------------------------
  4540. void CMapDoc::OnToolsSubtractselection(void)
  4541. {
  4542. if ( m_pSelection->IsEmpty())
  4543. {
  4544. return;
  4545. }
  4546. //
  4547. // Subtract with the first object in the selection list.
  4548. //
  4549. const CMapObjectList *pSelList = m_pSelection->GetList();
  4550. CMapClass *pSubtractWith = (CUtlReference< CMapClass >)pSelList->Element(0);
  4551. Assert( pSubtractWith != NULL );
  4552. GetHistory()->MarkUndoPosition(pSelList, "Carve");
  4553. GetHistory()->Keep(pSelList);
  4554. //
  4555. // Build a list of every solid in the world.
  4556. //
  4557. CMapObjectList WorldSolids;
  4558. EnumChildrenPos_t pos;
  4559. CMapClass *pChild = m_pWorld->GetFirstDescendent(pos);
  4560. while (pChild != NULL)
  4561. {
  4562. CMapSolid *pSolid = dynamic_cast <CMapSolid *> (pChild);
  4563. if (pSolid != NULL)
  4564. {
  4565. WorldSolids.AddToTail(pSolid);
  4566. }
  4567. pChild = m_pWorld->GetNextDescendent(pos);
  4568. }
  4569. if (WorldSolids.Count() == 0)
  4570. {
  4571. return;
  4572. }
  4573. bool bLocked = VisGroups_LockUpdates( true );
  4574. //
  4575. // Subtract the 'subtract with' object from every solid in the world.
  4576. //
  4577. FOR_EACH_OBJ( WorldSolids, p )
  4578. {
  4579. CMapClass *pMapClass = (CUtlReference< CMapClass >)WorldSolids.Element(p);
  4580. CMapSolid *pSubtractFrom = (CMapSolid *)pMapClass;
  4581. CMapClass *pDestParent = pSubtractFrom->GetParent();
  4582. //
  4583. // Perform the subtraction. If the two objects intersected...
  4584. //
  4585. CMapObjectList Outside;
  4586. if (pSubtractFrom->Subtract(NULL, &Outside, pSubtractWith))
  4587. {
  4588. if (Outside.Count() > 0)
  4589. {
  4590. CMapClass *pResult = NULL;
  4591. //
  4592. // If the subtraction resulted in more than one object, create a group
  4593. // to place the results in.
  4594. //
  4595. if (Outside.Count() > 1)
  4596. {
  4597. pResult = (CMapClass *)(new CMapGroup);
  4598. FOR_EACH_OBJ( Outside, pos2 )
  4599. {
  4600. CMapClass *pTemp = Outside.Element(pos2);
  4601. pResult->AddChild(pTemp);
  4602. }
  4603. }
  4604. //
  4605. // Otherwise, the results are the single object.
  4606. //
  4607. else if (Outside.Count() == 1)
  4608. {
  4609. pResult = Outside[0];
  4610. }
  4611. //
  4612. // Replace the 'subtract from' object with the subtraction results.
  4613. //
  4614. DeleteObject(pSubtractFrom);
  4615. AddObjectToWorld(pResult, pDestParent);
  4616. GetHistory()->KeepNew(pResult);
  4617. }
  4618. }
  4619. }
  4620. if ( bLocked )
  4621. VisGroups_LockUpdates( false );
  4622. SetModifiedFlag();
  4623. }
  4624. //-----------------------------------------------------------------------------
  4625. // Purpose: Copies the selected objects to the clipboard.
  4626. //-----------------------------------------------------------------------------
  4627. void CMapDoc::OnEditCopy(void)
  4628. {
  4629. if ( m_pSelection->IsEmpty() )
  4630. {
  4631. return;
  4632. }
  4633. // Copy into the global clipboard
  4634. Copy( GetHammerClipboard() );
  4635. }
  4636. //-----------------------------------------------------------------------------
  4637. // Create paste position at center of most recently used 2D view.
  4638. // NOTE: Only fills in dimensions that are initialized with COORD_NOTINIT
  4639. //-----------------------------------------------------------------------------
  4640. void CMapDoc::GetBestVisiblePoint( Vector &ptOrg )
  4641. {
  4642. CMapView2D *pView = MRU2DViews.Head();
  4643. if ( pView )
  4644. {
  4645. pView->GetCenterPoint( ptOrg );
  4646. }
  4647. for ( int i = 0; i < 3; i++ )
  4648. {
  4649. if ( ptOrg[i] == COORD_NOTINIT )
  4650. {
  4651. ptOrg[i] = 0;
  4652. }
  4653. }
  4654. }
  4655. //-----------------------------------------------------------------------------
  4656. //-----------------------------------------------------------------------------
  4657. void CMapDoc::GetBestVisibleBox( Vector &vecMins, Vector &vecMaxs )
  4658. {
  4659. Vector vecCenter( COORD_NOTINIT, COORD_NOTINIT, COORD_NOTINIT );
  4660. GetBestVisiblePoint( vecCenter );
  4661. float flZoom = 1.0f;
  4662. CMapView2D *pView = MRU2DViews.Head();
  4663. if ( pView )
  4664. {
  4665. flZoom = pView->GetZoom();
  4666. }
  4667. // Don't make a cordon smaller than (2 x 2 x 2)
  4668. if ( flZoom > 128 )
  4669. {
  4670. flZoom = 128;
  4671. }
  4672. vecMins = vecCenter - Vector( 128, 128, 128 ) / flZoom;
  4673. vecMaxs = vecCenter + Vector( 128, 128, 128 ) / flZoom;
  4674. for ( int i = 0; i < 3; i++ )
  4675. {
  4676. if ( vecMaxs[i] > g_MAX_MAP_COORD )
  4677. {
  4678. float flShift = vecMaxs[i] - g_MAX_MAP_COORD;
  4679. vecMaxs[i] = g_MAX_MAP_COORD;
  4680. vecMins[i] = max( vecMins[i] - flShift, g_MIN_MAP_COORD );
  4681. }
  4682. if ( vecMins[i] < g_MIN_MAP_COORD )
  4683. {
  4684. float flShift = g_MIN_MAP_COORD - vecMins[i];
  4685. vecMins[i] = g_MIN_MAP_COORD;
  4686. vecMaxs[i] = min( vecMaxs[i] + flShift, g_MAX_MAP_COORD );
  4687. }
  4688. }
  4689. }
  4690. //-----------------------------------------------------------------------------
  4691. // Purpose: Allows picking into the world from an arbitrary position and direction,
  4692. // not restricted to the camera position.
  4693. // Requires an open 3D view.
  4694. // Returns true if an object was picked.
  4695. // Fills pHitPosition with the pick location if an object was detected.
  4696. //-----------------------------------------------------------------------------
  4697. //
  4698. bool CMapDoc::PickTrace( const Vector &vPosition, const Vector &vDirection, Vector *pHitPosition )
  4699. {
  4700. Assert( pHitPosition );
  4701. // requires an open 3D view, use the first one.
  4702. CMapView3D *pView = GetFirst3DView();
  4703. if ( !pView )
  4704. return false;
  4705. CCamera *pCam = pView->GetCamera();
  4706. Assert( pCam );
  4707. int nViewportWidth, nViewportHeight;
  4708. pCam->GetViewPort( nViewportWidth, nViewportHeight );
  4709. // save off old camera values before we hijack them
  4710. Vector vSavedViewPoint;
  4711. pCam->GetViewPoint( vSavedViewPoint );
  4712. const float flSavedYaw = pCam->GetYaw();
  4713. const float flSavedPitch = pCam->GetPitch();
  4714. // hijack the camera
  4715. pCam->SetViewPoint( vPosition );
  4716. pCam->SetViewTarget( vPosition + vDirection );
  4717. bool bPickSuccess = false;
  4718. ULONG ulFace;
  4719. VMatrix LocalMatrix, LocalMatrixNeg;
  4720. const Vector2D vViewportPickPos( ((float)nViewportWidth) * 0.5f, ((float)nViewportHeight) * 0.5f );
  4721. CMapClass *pObj = pView->NearestObjectAt( vViewportPickPos, ulFace, FLAG_OBJECTS_AT_ONLY_SOLIDS | FLAG_OBJECTS_AT_RESOLVE_INSTANCES, &LocalMatrix );
  4722. if ( pObj )
  4723. {
  4724. CMapSolid *pSolid = dynamic_cast <CMapSolid *> ( pObj );
  4725. if ( pSolid )
  4726. {
  4727. LocalMatrix.InverseTR( LocalMatrixNeg );
  4728. // Build a ray to trace against the face that they clicked on to
  4729. // find the point of intersection.
  4730. Vector vStart,vEnd;
  4731. pView->GetCamera()->BuildRay( vViewportPickPos, vStart, vEnd );
  4732. Vector vHitPos, vHitNormal;
  4733. CMapFace *pFace = pSolid->GetFace( ulFace );
  4734. Vector vFinalStart, vFinalEnd;
  4735. LocalMatrixNeg.V3Mul( vStart, vFinalStart );
  4736. LocalMatrixNeg.V3Mul( vEnd, vFinalEnd );
  4737. if ( pFace->TraceLine( vHitPos, vHitNormal, vFinalStart, vFinalEnd ) )
  4738. {
  4739. Vector vFinalHitPos;
  4740. LocalMatrix.V3Mul( vHitPos, vFinalHitPos );
  4741. *pHitPosition = vHitPos;
  4742. bPickSuccess = true;
  4743. }
  4744. }
  4745. }
  4746. // restore saved camera values
  4747. pCam->SetViewPoint( vSavedViewPoint );
  4748. pCam->SetYaw( flSavedYaw );
  4749. pCam->SetPitch( flSavedPitch );
  4750. return bPickSuccess;
  4751. }
  4752. //-----------------------------------------------------------------------------
  4753. static int DropTraceBBoxSort( CMapSolid * const *pLeft, CMapSolid * const *pRight )
  4754. {
  4755. // sort the objects from highest to lowest bounding box top
  4756. Vector vLeftMins, vLeftMaxs, vRightMins, vRightMaxs;
  4757. (*pLeft)->GetCullBox( vLeftMins, vLeftMaxs );
  4758. (*pRight)->GetCullBox( vRightMins, vRightMaxs );
  4759. if ( vLeftMaxs.z > vRightMaxs.z )
  4760. return -1;
  4761. else if ( vLeftMaxs.z < vRightMaxs.z )
  4762. return 1; // positive return value = swap order
  4763. else
  4764. return 0;
  4765. }
  4766. //-----------------------------------------------------------------------------
  4767. // Purpose: From a given point, determine the highest point below it that rests on
  4768. // a displacement or a clip brush.
  4769. //-----------------------------------------------------------------------------
  4770. //
  4771. bool CMapDoc::DropTraceOnDisplacementsAndClips( const Vector &vPosition, Vector *pHitPosition, bool *pHitClip )
  4772. {
  4773. CMapWorld *pMapWorld = GetMapWorld();
  4774. CManifest *pManifest = GetManifest();
  4775. if ( pManifest )
  4776. {
  4777. pMapWorld = pManifest->GetManifestWorld();
  4778. }
  4779. if ( pMapWorld == NULL )
  4780. return false;
  4781. CCullTreeNode *pTree = pMapWorld->CullTree_GetCullTree();
  4782. if ( pTree == NULL )
  4783. return false;
  4784. // begin marker for keeping track of which map class objects we have touched so far while searching for objects
  4785. CMapClass::MakeNewDropTraceMarker();
  4786. CUtlVector< CMapSolid* > objects;
  4787. DropTraceRecurse( pTree, vPosition, objects );
  4788. // sort the objects from highest bounding box top to lowest
  4789. objects.Sort( DropTraceBBoxSort );
  4790. const Vector vUnderground = vPosition + Vector( 0.0f, 0.0f, -99999.f ); // end of trace, hopefully below the ground.
  4791. bool bHitSomething = false;
  4792. bool bHitClip = false;
  4793. float flHitHeight = 0.0f;
  4794. FOR_EACH_VEC( objects, it )
  4795. {
  4796. CMapSolid *obj = objects[ it ];
  4797. Assert( obj );
  4798. // if we have already hit something, and this object's bounding box top is below the hit height,
  4799. // we have no need to proceed since the objects are sorted with descending bbox tops.
  4800. if ( bHitSomething )
  4801. {
  4802. Vector vObjMins, vObjMaxs;
  4803. obj->GetCullBox( vObjMins, vObjMaxs );
  4804. if ( vObjMaxs.z < flHitHeight )
  4805. break;
  4806. }
  4807. int nFaces = obj->GetFaceCount();
  4808. if ( nFaces > 50 )
  4809. exit(0);
  4810. for ( int nFace = 0; nFace < nFaces; ++nFace )
  4811. {
  4812. CMapFace *pFace = obj->GetFace( nFace );
  4813. // trivially reject faces with cull box that does not overlap 2D point
  4814. Vector vMins, vMaxs;
  4815. pFace->GetCullBox( vMins, vMaxs );
  4816. if ( vMins.x <= vPosition.x && vPosition.x <= vMaxs.x &&
  4817. vMins.y <= vPosition.y && vPosition.y <= vMaxs.y )
  4818. {
  4819. // We only care about two kinds of faces: Those with displacements, and those with a clip texture.
  4820. bool bIsClip = false;
  4821. if ( !pFace->HasDisp() )
  4822. {
  4823. char texName[256];
  4824. pFace->GetTextureName( texName );
  4825. if ( V_strcmp( texName, "tools/toolsnpcclip" ) != 0 )
  4826. continue;
  4827. bIsClip = true;
  4828. }
  4829. Vector vHitPos, vHitNormal;
  4830. if ( pFace->TraceLine( vHitPos, vHitNormal, vPosition, vUnderground ) )
  4831. {
  4832. if ( !bHitSomething || vHitPos.z > flHitHeight )
  4833. {
  4834. // Test whether the point is inside the bounds of the face. Necessary for rotated brushes.
  4835. const int nPoints = pFace->nPoints;
  4836. const Vector *pPoints = pFace->Points;
  4837. bool bInFace = true;
  4838. for ( int i = 0; i < nPoints; ++i )
  4839. {
  4840. const int n1 = i;
  4841. const int n2 = ( i != nPoints - 1 ? i + 1 : 0 );
  4842. const Vector &p1 = pPoints[n1];
  4843. const Vector &p2 = pPoints[n2];
  4844. const Vector v = p2 - p1;
  4845. const Vector toHitPos = vHitPos - p1;
  4846. if ( toHitPos.x * v.y - toHitPos.y * v.x < 0.0f ) // 2D cross product, z = 0
  4847. {
  4848. bInFace = false;
  4849. break;
  4850. }
  4851. }
  4852. if ( bInFace )
  4853. {
  4854. bHitSomething = true;
  4855. bHitClip = bIsClip;
  4856. flHitHeight = vHitPos.z;
  4857. }
  4858. }
  4859. }
  4860. }
  4861. }
  4862. }
  4863. if ( bHitSomething )
  4864. {
  4865. if ( pHitPosition )
  4866. {
  4867. *pHitPosition = vPosition;
  4868. pHitPosition->z = flHitHeight;
  4869. }
  4870. if ( pHitClip )
  4871. {
  4872. *pHitClip = bHitClip;
  4873. }
  4874. }
  4875. return bHitSomething;
  4876. }
  4877. void CMapDoc::DropTraceRecurse( CCullTreeNode *pCullTreeNode, const Vector &vTraceStart, CUtlVector< CMapSolid* > &objects )
  4878. {
  4879. int nChildren = pCullTreeNode->GetChildCount();
  4880. if ( nChildren != 0 )
  4881. {
  4882. for ( int nChild = 0; nChild < nChildren; ++nChild )
  4883. {
  4884. CCullTreeNode *pChild = pCullTreeNode->GetCullTreeChild( nChild );
  4885. Assert( pChild != NULL );
  4886. if ( pChild != NULL )
  4887. {
  4888. Vector vMins;
  4889. Vector vMaxs;
  4890. pChild->GetBounds( vMins, vMaxs );
  4891. if ( vMins.x <= vTraceStart.x && vTraceStart.x <= vMaxs.x &&
  4892. vMins.y <= vTraceStart.y && vTraceStart.y <= vMaxs.y )
  4893. {
  4894. DropTraceRecurse( pChild, vTraceStart, objects );
  4895. }
  4896. }
  4897. }
  4898. }
  4899. else
  4900. {
  4901. int nObjects = pCullTreeNode->GetObjectCount();
  4902. for ( int nObject = 0; nObject < nObjects; ++nObject )
  4903. {
  4904. CMapClass *pObject = pCullTreeNode->GetCullTreeObject( nObject );
  4905. Assert( pObject != NULL );
  4906. DropTraceObjectRecurse( pObject, vTraceStart, objects );
  4907. }
  4908. }
  4909. }
  4910. void CMapDoc::DropTraceObjectRecurse( CMapClass *pObject, const Vector &vTraceStart, CUtlVector< CMapSolid* > &objects )
  4911. {
  4912. // If we have already tested this object, no need to do so again.
  4913. if ( pObject->IsDropTraceMarkerCurrent() )
  4914. return;
  4915. pObject->DropTraceMark();
  4916. // skip invisible objects
  4917. if ( !pObject->IsVisible() )
  4918. return;
  4919. const Vector &vMins = pObject->GetCullBoxMins();
  4920. const Vector &vMaxs = pObject->GetCullBoxMaxs();
  4921. if ( vMins.x <= vTraceStart.x && vTraceStart.x <= vMaxs.x &&
  4922. vMins.y <= vTraceStart.y && vTraceStart.y <= vMaxs.y &&
  4923. vMins.z < vTraceStart.z )
  4924. {
  4925. if ( pObject->IsMapClass( MAPCLASS_TYPE(CMapSolid) ) )
  4926. {
  4927. CMapSolid *pMapSolid = static_cast< CMapSolid* >( pObject );
  4928. if ( objects.Find( pMapSolid ) == -1 )
  4929. objects.AddToTail( pMapSolid );
  4930. }
  4931. const CMapObjectList *pChildren = pObject->GetChildren();
  4932. Assert( pChildren );
  4933. int nChildren = pObject->GetChildCount();
  4934. for ( int nChild = 0; nChild < nChildren; ++nChild )
  4935. {
  4936. CMapClass *pChild = (CUtlReference< CMapClass >)(*pChildren)[nChild];
  4937. Assert( pChild );
  4938. DropTraceObjectRecurse( pChild, vTraceStart, objects );
  4939. }
  4940. }
  4941. }
  4942. //-----------------------------------------------------------------------------
  4943. // Purpose: Gets a point on the screen to paste to. Functionalized because it
  4944. // is called from OnEditPaste and OnEditPasteSpecial.
  4945. //-----------------------------------------------------------------------------
  4946. void CMapDoc::GetBestPastePoint(Vector &vecPasteOrigin, IHammerClipboard *pClipboard)
  4947. {
  4948. //
  4949. // Start with a visible grid point near the center of the screen.
  4950. //
  4951. vecPasteOrigin = Vector(COORD_NOTINIT, COORD_NOTINIT, COORD_NOTINIT);
  4952. CMapView *pView = GetActiveMapView();
  4953. CView *pMFCView = dynamic_cast<CView*>(pView);
  4954. if ( pView )
  4955. {
  4956. // zoom in on cursor position
  4957. POINT ptClient;
  4958. GetCursorPos(&ptClient);
  4959. pMFCView->ScreenToClient(&ptClient);
  4960. int width, height;
  4961. pView->GetCamera()->GetViewPort( width, height );
  4962. if ( ptClient.x >= 0 && ptClient.x < width &&
  4963. ptClient.y >= 0 && ptClient.y < height )
  4964. {
  4965. // if mouse pos is inside a view, figure out whic one
  4966. CMapView3D *p3DView = dynamic_cast<CMapView3D*>(pView);
  4967. CMapView2D *p2DView = dynamic_cast<CMapView2D*>(pView);
  4968. Vector2D vPoint(ptClient.x,ptClient.y);
  4969. if ( p3DView )
  4970. {
  4971. HitInfo_t Hits;
  4972. if ( p3DView->ObjectsAt( vPoint, &Hits, 1, FLAG_OBJECTS_AT_RESOLVE_INSTANCES ) )
  4973. {
  4974. VMatrix LocalMatrixNeg;
  4975. Hits.m_LocalMatrix.InverseTR( LocalMatrixNeg );
  4976. // If they clicked on a solid, the index of the face they clicked on is stored
  4977. // in array index [1].
  4978. CMapClass *pObject = Hits.pObject;
  4979. CMapSolid *pSolid = dynamic_cast<CMapSolid *>(pObject);
  4980. Vector HitPos,HitNormal;
  4981. Vector start,end,mins,maxs,delta;
  4982. float dist;
  4983. int face;
  4984. bool bOk = false;
  4985. p3DView->GetCamera()->BuildRay( vPoint, start, end);
  4986. Vector vFinalStart, vFinalEnd;
  4987. LocalMatrixNeg.V3Mul( start, vFinalStart );
  4988. LocalMatrixNeg.V3Mul( end, vFinalEnd );
  4989. if (pSolid != NULL)
  4990. {
  4991. // Build a ray to trace against the face that they clicked on to
  4992. // find the point of intersection.
  4993. CMapFace *pFace = pSolid->GetFace(Hits.uData);
  4994. bOk = pFace->TraceLine(HitPos, HitNormal, vFinalStart, vFinalEnd);
  4995. }
  4996. else if ( pObject != NULL )
  4997. {
  4998. // we hit something, just trace against bound box
  4999. pObject->GetRender2DBox( mins, maxs );
  5000. dist = IntersectionLineAABBox( mins, maxs, vFinalStart, vFinalEnd, face );
  5001. if ( dist > 0 )
  5002. {
  5003. delta = vFinalEnd-vFinalStart;
  5004. VectorNormalize( delta );
  5005. HitPos = vFinalStart + dist * delta;
  5006. HitNormal = GetNormalFromFace( face );
  5007. bOk = true;
  5008. }
  5009. }
  5010. if ( bOk )
  5011. {
  5012. Vector vFinalHitPos, vFinalHitNormal;
  5013. Hits.m_LocalMatrix.V3Mul( HitPos, vFinalHitPos );
  5014. vFinalHitNormal = Hits.m_LocalMatrix.ApplyRotation( HitNormal );
  5015. mins = GetHammerClipboard( pClipboard )->Bounds.bmins;
  5016. maxs = GetHammerClipboard( pClipboard )->Bounds.bmaxs;
  5017. delta = vFinalHitPos - (mins+maxs)/2;
  5018. mins += delta;
  5019. maxs += delta;
  5020. start = vFinalHitPos;
  5021. end = vFinalHitPos + vFinalHitNormal*4096;
  5022. dist = IntersectionLineAABBox( mins, maxs, start, end, face );
  5023. if ( dist > 0 )
  5024. {
  5025. vecPasteOrigin = vFinalHitPos + vFinalHitNormal * dist;
  5026. }
  5027. else
  5028. {
  5029. vecPasteOrigin = vFinalHitPos;
  5030. }
  5031. }
  5032. }
  5033. }
  5034. else if ( p2DView )
  5035. {
  5036. p2DView->ClientToWorld( vecPasteOrigin, vPoint );
  5037. vecPasteOrigin[p2DView->axThird] = COORD_NOTINIT;
  5038. GetBestVisiblePoint(vecPasteOrigin);
  5039. Snap(vecPasteOrigin);
  5040. }
  5041. }
  5042. }
  5043. // ok, no mouse over any active view, use center of last used 2D views
  5044. if ( vecPasteOrigin.x == COORD_NOTINIT )
  5045. {
  5046. GetBestVisiblePoint(vecPasteOrigin);
  5047. Snap(vecPasteOrigin);
  5048. // Offset the center relative to the grid the same as it was originally.
  5049. Vector vecSnappedOriginalCenter = GetHammerClipboard( pClipboard )->vecOriginalCenter;
  5050. Snap(vecSnappedOriginalCenter);
  5051. vecPasteOrigin += GetHammerClipboard( pClipboard )->vecOriginalCenter - vecSnappedOriginalCenter;
  5052. }
  5053. }
  5054. void CMapDoc::Paste( IHammerClipboard *pClipboard, CMapWorld *pDestWorld, Vector vecOffset, QAngle vecRotate, CMapClass *pParent, bool bMakeEntityNamesUnique, const char *pszEntityNamePrefix )
  5055. {
  5056. CHammerClipboard *pSrc = GetHammerClipboard( pClipboard );
  5057. Paste( pSrc->Objects, pSrc->pSourceWorld, pDestWorld, vecOffset, vecRotate, pParent, bMakeEntityNamesUnique, pszEntityNamePrefix );
  5058. }
  5059. //-----------------------------------------------------------------------------
  5060. // Purpose: This function will peform a 'cut' operation on the selected entities.
  5061. //-----------------------------------------------------------------------------
  5062. void CMapDoc::Cut( IHammerClipboard *pClipboard )
  5063. {
  5064. Copy( pClipboard );
  5065. Delete();
  5066. }
  5067. //-----------------------------------------------------------------------------
  5068. // Purpose: This function will perform a 'copy' operation on the selected entities.
  5069. //-----------------------------------------------------------------------------
  5070. void CMapDoc::Copy( IHammerClipboard *pClipboard )
  5071. {
  5072. if ( m_pSelection->IsEmpty() )
  5073. {
  5074. return;
  5075. }
  5076. if ( !m_pSelection->IsCopyable() )
  5077. {
  5078. return;
  5079. }
  5080. if ( pClipboard == NULL )
  5081. {
  5082. pClipboard = GetHammerClipboard();
  5083. }
  5084. BeginWaitCursor();
  5085. // Delete the contents of the clipboard.
  5086. GetHammerClipboard( pClipboard )->Objects.RemoveAll();
  5087. m_pSelection->GetBoundsCenter(GetHammerClipboard( pClipboard )->vecOriginalCenter);
  5088. m_pSelection->GetBounds(GetHammerClipboard( pClipboard )->Bounds.bmins, GetHammerClipboard( pClipboard )->Bounds.bmaxs);
  5089. GetHistory()->Pause();
  5090. GetHammerClipboard( pClipboard )->pSourceWorld = m_pWorld;
  5091. // Copy the selected objects to the clipboard.
  5092. const CMapObjectList *pSelList = m_pSelection->GetList();
  5093. for (int i = 0; i < pSelList->Count() ; i++)
  5094. {
  5095. CMapClass *pobj = (CUtlReference< CMapClass >)pSelList->Element(i);
  5096. CMapClass *pNewobj = pobj->Copy(false);
  5097. //
  5098. // Prune the object from the world tree without calling RemoveObjectFromWorld.
  5099. // This prevents CopyChildrenFrom from updating the culling tree.
  5100. //
  5101. //pNewobj->SetObjParent(NULL);
  5102. //
  5103. // Copy all the children from the original object into the copied object.
  5104. //
  5105. pNewobj->CopyChildrenFrom(pobj, false);
  5106. //
  5107. // Remove the copied object from the world.
  5108. //
  5109. RemoveObjectFromWorld(pNewobj, true);
  5110. pNewobj->RemoveAllVisGroups();
  5111. GetHammerClipboard( pClipboard )->Objects.AddToTail(pNewobj);
  5112. }
  5113. GetHistory()->Resume();
  5114. EndWaitCursor();
  5115. }
  5116. //-----------------------------------------------------------------------------
  5117. // Purpose:
  5118. // Input : Objects -
  5119. // pSourceWorld -
  5120. // pDestWorld -
  5121. // vecOffset -
  5122. // vecRotate -
  5123. // pParent -
  5124. //-----------------------------------------------------------------------------
  5125. void CMapDoc::Paste(CMapObjectList &Objects, CMapWorld *pSourceWorld, CMapWorld *pDestWorld, Vector vecOffset, QAngle vecRotate, CMapClass *pParent, bool bMakeEntityNamesUnique, const char *pszEntityNamePrefix)
  5126. {
  5127. //
  5128. // Copy the objects in the clipboard and build a list of objects to paste
  5129. // into the world.
  5130. //
  5131. CMapObjectList PasteList;
  5132. bool bLocked = VisGroups_LockUpdates( true );
  5133. if ( GetManifest() && pSourceWorld != pDestWorld )
  5134. {
  5135. bMakeEntityNamesUnique = true;
  5136. }
  5137. FOR_EACH_OBJ( Objects, pos )
  5138. {
  5139. CMapClass *pOriginal = Objects.Element(pos);
  5140. CMapClass *pCopy = pOriginal->Copy(false);
  5141. pCopy->CopyChildrenFrom(pOriginal, false);
  5142. PasteList.AddToTail(pCopy);
  5143. }
  5144. if ( bMakeEntityNamesUnique || ( pszEntityNamePrefix && ( pszEntityNamePrefix[0] != '\0' ) ) )
  5145. {
  5146. //
  5147. // Make all the pasted objects with names have new, unique names within the destination world.
  5148. //
  5149. // Stick the objects into a temporary world object for renaming the entities.
  5150. CMapWorld temp( this );
  5151. FOR_EACH_OBJ( PasteList, pos )
  5152. {
  5153. CMapClass *pObject = PasteList.Element( pos );
  5154. temp.AddChild( pObject );
  5155. }
  5156. RenameEntities( &temp, pDestWorld, bMakeEntityNamesUnique, pszEntityNamePrefix );
  5157. // So they don't get deleted when temp goes out of scope.
  5158. temp.RemoveAllChildren();
  5159. }
  5160. //
  5161. // Notification happens in two-passes. The first pass lets objects generate new unique
  5162. // IDs in the destination world, the second pass lets objects fixup references to other
  5163. // objects in the clipboard.
  5164. //
  5165. Assert( Objects.Count() == PasteList.Count() );
  5166. FOR_EACH_OBJ( Objects, pos )
  5167. {
  5168. CMapClass *pOriginal = Objects.Element(pos);
  5169. CMapClass *pCopy = PasteList.Element(pos);
  5170. pOriginal->OnPrePaste(pCopy, pSourceWorld, pDestWorld, Objects, PasteList);
  5171. }
  5172. //
  5173. // Add the objects to the world.
  5174. //
  5175. FOR_EACH_OBJ( PasteList, pos )
  5176. {
  5177. CMapClass *pCopy = PasteList.Element(pos);
  5178. if (vecOffset != vec3_origin)
  5179. {
  5180. pCopy->TransMove(vecOffset);
  5181. }
  5182. if (vecRotate != vec3_angle)
  5183. {
  5184. Vector ptCenter;
  5185. pCopy->GetBoundsCenter(ptCenter);
  5186. pCopy->TransRotate(ptCenter, vecRotate);
  5187. }
  5188. AddObjectToWorld(pCopy, pParent);
  5189. }
  5190. //
  5191. // Do the second pass of notification. The second pass of notification lets objects
  5192. // fixup references to other objects that were pasted. We don't do it in the loop above
  5193. // because then not all the pasted objects would be in the world yet.
  5194. //
  5195. Assert( Objects.Count() == PasteList.Count() );
  5196. FOR_EACH_OBJ( Objects, pos )
  5197. {
  5198. CMapClass *pOriginal = Objects.Element(pos);
  5199. CMapClass *pCopy = PasteList.Element(pos);
  5200. pOriginal->OnPaste(pCopy, pSourceWorld, pDestWorld, Objects, PasteList);
  5201. //
  5202. // Semi-HACK: If we aren't pasting into a group, keep the new object in the Undo stack.
  5203. // Otherwise, we'll keep the group in OnEditPasteSpecial.
  5204. //
  5205. if ((pParent == NULL) || (pParent == pDestWorld))
  5206. {
  5207. GetHistory()->KeepNew(pCopy);
  5208. SelectObject(pCopy, scSelect);
  5209. }
  5210. }
  5211. if ( bLocked )
  5212. {
  5213. VisGroups_LockUpdates( false );
  5214. }
  5215. }
  5216. //-----------------------------------------------------------------------------
  5217. // Purpose:
  5218. // Input : Objects -
  5219. // pSourceWorld -
  5220. // pDestWorld -
  5221. // vecOffset -
  5222. // vecRotate -
  5223. // pParent -
  5224. //-----------------------------------------------------------------------------
  5225. void CMapDoc::PasteInstance(CMapObjectList &Objects, CMapWorld *pSourceWorld, CMapWorld *pDestWorld, Vector vecOffset, QAngle vecRotate, CMapClass *pParent, bool bMakeEntityNamesUnique, const char *pszEntityNamePrefix)
  5226. {
  5227. QAngle vecRotateFix;
  5228. vecRotateFix.x = vecRotate.z;
  5229. vecRotateFix.y = -vecRotate.x;
  5230. vecRotateFix.z = vecRotate.y;
  5231. //
  5232. // Copy the objects in the clipboard and build a list of objects to paste
  5233. // into the world.
  5234. //
  5235. CMapObjectList PasteList;
  5236. bool bLocked = VisGroups_LockUpdates( true );
  5237. if ( GetManifest() && pSourceWorld != pDestWorld )
  5238. {
  5239. bMakeEntityNamesUnique = true;
  5240. }
  5241. FOR_EACH_OBJ( Objects, pos )
  5242. {
  5243. CMapClass *pOriginal = Objects.Element(pos);
  5244. CMapClass *pCopy = pOriginal->Copy(false);
  5245. pCopy->CopyChildrenFrom(pOriginal, false);
  5246. PasteList.AddToTail(pCopy);
  5247. }
  5248. if ( bMakeEntityNamesUnique || ( pszEntityNamePrefix && ( pszEntityNamePrefix[0] != '\0' ) ) )
  5249. {
  5250. //
  5251. // Make all the pasted objects with names have new, unique names within the destination world.
  5252. //
  5253. // Stick the objects into a temporary world object for renaming the entities.
  5254. CMapWorld temp( this );
  5255. FOR_EACH_OBJ( PasteList, pos )
  5256. {
  5257. CMapClass *pObject = PasteList.Element( pos );
  5258. temp.AddChild( pObject );
  5259. }
  5260. RenameEntities( &temp, pDestWorld, bMakeEntityNamesUnique, pszEntityNamePrefix );
  5261. // So they don't get deleted when temp goes out of scope.
  5262. temp.RemoveAllChildren();
  5263. }
  5264. //
  5265. // Notification happens in two-passes. The first pass lets objects generate new unique
  5266. // IDs in the destination world, the second pass lets objects fixup references to other
  5267. // objects in the clipboard.
  5268. //
  5269. Assert( Objects.Count() == PasteList.Count() );
  5270. FOR_EACH_OBJ( Objects, pos )
  5271. {
  5272. CMapClass *pOriginal = Objects.Element(pos);
  5273. CMapClass *pCopy = PasteList.Element(pos);
  5274. pOriginal->OnPrePaste(pCopy, pSourceWorld, pDestWorld, Objects, PasteList);
  5275. }
  5276. //
  5277. // Add the objects to the world.
  5278. //
  5279. FOR_EACH_OBJ( PasteList, pos )
  5280. {
  5281. CMapClass *pCopy = PasteList.Element(pos);
  5282. if (vecRotateFix != vec3_angle)
  5283. {
  5284. pCopy->TransRotate( vec3_origin, vecRotateFix );
  5285. }
  5286. if (vecOffset != vec3_origin)
  5287. {
  5288. pCopy->TransMove(vecOffset);
  5289. }
  5290. AddObjectToWorld(pCopy, pParent);
  5291. }
  5292. //
  5293. // Do the second pass of notification. The second pass of notification lets objects
  5294. // fixup references to other objects that were pasted. We don't do it in the loop above
  5295. // because then not all the pasted objects would be in the world yet.
  5296. //
  5297. Assert( Objects.Count() == PasteList.Count() );
  5298. FOR_EACH_OBJ( Objects, pos )
  5299. {
  5300. CMapClass *pOriginal = Objects.Element(pos);
  5301. CMapClass *pCopy = PasteList.Element(pos);
  5302. pOriginal->OnPaste(pCopy, pSourceWorld, pDestWorld, Objects, PasteList);
  5303. //
  5304. // Semi-HACK: If we aren't pasting into a group, keep the new object in the Undo stack.
  5305. // Otherwise, we'll keep the group in OnEditPasteSpecial.
  5306. //
  5307. if ((pParent == NULL) || (pParent == pDestWorld))
  5308. {
  5309. GetHistory()->KeepNew(pCopy);
  5310. SelectObject(pCopy, scSelect);
  5311. }
  5312. }
  5313. if ( bLocked )
  5314. {
  5315. VisGroups_LockUpdates( false );
  5316. }
  5317. }
  5318. //-----------------------------------------------------------------------------
  5319. // Purpose: This function will perform a 'delete' operation on the selected entities.
  5320. //-----------------------------------------------------------------------------
  5321. void CMapDoc::Delete( void )
  5322. {
  5323. if (m_pToolManager->GetActiveToolID() == TOOL_MORPH)
  5324. {
  5325. // Can't delete stuff while morphing.
  5326. return;
  5327. }
  5328. if ( m_pSelection->IsEmpty() || !m_pSelection->IsCopyable() )
  5329. {
  5330. return;
  5331. }
  5332. const CMapObjectList *pSelList = m_pSelection->GetList();
  5333. GetHistory()->MarkUndoPosition(pSelList, "Delete");
  5334. // Delete objects in selection.
  5335. while ( !m_pSelection->IsEmpty() )
  5336. {
  5337. CMapClass *pobj = (CUtlReference< CMapClass >)pSelList->Element(0);
  5338. DeleteObject(pobj);
  5339. }
  5340. SetModifiedFlag();
  5341. }
  5342. //-----------------------------------------------------------------------------
  5343. // Purpose: Pastes the clipboard contents into the active world.
  5344. //-----------------------------------------------------------------------------
  5345. void CMapDoc::OnEditPaste(void)
  5346. {
  5347. BeginWaitCursor();
  5348. GetHistory()->MarkUndoPosition( m_pSelection->GetList(), "Paste");
  5349. // first, clear selection so we can select all pasted objects
  5350. SelectObject(NULL, scClear|scSaveChanges );
  5351. //
  5352. // Build a translation that will put the pasted objects in the center of the view.
  5353. //
  5354. Vector vecPasteOffset;
  5355. GetBestPastePoint(vecPasteOffset, GetHammerClipboard());
  5356. vecPasteOffset -= GetHammerClipboard()->vecOriginalCenter;
  5357. //
  5358. // Paste the objects into the active world.
  5359. //
  5360. Paste(GetHammerClipboard(), GetActiveWorld(), vecPasteOffset, QAngle(0, 0, 0), NULL, false, NULL);
  5361. m_pToolManager->SetTool(TOOL_POINTER);
  5362. SetModifiedFlag();
  5363. EndWaitCursor();
  5364. }
  5365. //-----------------------------------------------------------------------------
  5366. // Disable the unhide option when the quickhide list is empty.
  5367. //-----------------------------------------------------------------------------
  5368. void CMapDoc::OnQuickHide_UpdateUnHide(CCmdUI *pCmdUI)
  5369. {
  5370. pCmdUI->Enable( m_QuickHideGroup.Count() > 0 );
  5371. }
  5372. //-----------------------------------------------------------------------------
  5373. // Disable the Create VisGroup menu option when QuickHide is empty.
  5374. //-----------------------------------------------------------------------------
  5375. void CMapDoc::OnQuickHide_UpdateCreateVisGroupFromHidden(CCmdUI *pCmdUI)
  5376. {
  5377. pCmdUI->Enable( m_QuickHideGroup.Count() > 0 );
  5378. }
  5379. //-----------------------------------------------------------------------------
  5380. // Purpose: Manages the state of the Copy menu item.
  5381. //-----------------------------------------------------------------------------
  5382. void CMapDoc::OnUpdateEditSelection(CCmdUI *pCmdUI)
  5383. {
  5384. pCmdUI->Enable( ( m_pSelection->GetCount() != 0 ) && m_pSelection->IsCopyable() &&
  5385. ( m_pToolManager->GetActiveToolID() != TOOL_FACEEDIT_MATERIAL ) &&
  5386. !GetMainWnd()->IsShellSessionActive() );
  5387. }
  5388. //-----------------------------------------------------------------------------
  5389. // Purpose: Manages the state of the Paste menu item.
  5390. //-----------------------------------------------------------------------------
  5391. void CMapDoc::OnUpdateEditPaste(CCmdUI *pCmdUI)
  5392. {
  5393. pCmdUI->Enable( GetHammerClipboard()->Objects.Count() &&
  5394. ( m_pToolManager->GetActiveToolID() != TOOL_FACEEDIT_MATERIAL ) &&
  5395. !GetMainWnd()->IsShellSessionActive() );
  5396. }
  5397. //-----------------------------------------------------------------------------
  5398. // Purpose: Handles the Edit | Cut command. Copies the selection to the clipboard,
  5399. // then deletes it from the document.
  5400. //-----------------------------------------------------------------------------
  5401. void CMapDoc::OnEditCut(void)
  5402. {
  5403. if ( !m_pSelection->IsCopyable() )
  5404. {
  5405. return;
  5406. }
  5407. Cut( GetHammerClipboard() );
  5408. }
  5409. //-----------------------------------------------------------------------------
  5410. // Purpose: Manages the state of the various Edit menu items.
  5411. //-----------------------------------------------------------------------------
  5412. void CMapDoc::OnUpdateGroupEditFunction(CCmdUI* pCmdUI)
  5413. {
  5414. //
  5415. // Edit functions are disabled when we're applying textures or editing via a shell session.
  5416. //
  5417. pCmdUI->Enable( ( m_pToolManager->GetActiveToolID() != TOOL_FACEEDIT_MATERIAL ) &&
  5418. !GetMainWnd()->IsShellSessionActive() );
  5419. }
  5420. //-----------------------------------------------------------------------------
  5421. // Purpose: Creates a new group and adds all selected items to it.
  5422. //-----------------------------------------------------------------------------
  5423. void CMapDoc::OnToolsGroup(void)
  5424. {
  5425. if ( m_pSelection->IsEmpty() )
  5426. {
  5427. AfxMessageBox("No objects are selected.");
  5428. return;
  5429. }
  5430. if (( m_pSelection->GetMode() == selectSolids) && !Options.general.bGroupWhileIgnore)
  5431. {
  5432. return;
  5433. }
  5434. const CMapObjectList *pSelList = m_pSelection->GetList();
  5435. // First see if grouping these objects will remove them from an existing entity or group.
  5436. for (int i = 0; i < pSelList->Count(); i++)
  5437. {
  5438. CMapClass *pobj = (CUtlReference< CMapClass >)pSelList->Element(i);
  5439. if ((pobj->GetParent() != NULL) && (!IsWorldObject(pobj->GetParent())))
  5440. {
  5441. 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)
  5442. {
  5443. return;
  5444. }
  5445. break;
  5446. }
  5447. }
  5448. GetHistory()->MarkUndoPosition(m_pSelection->GetList(), "Group Objects");
  5449. GetHistory()->Keep(m_pSelection->GetList());
  5450. //
  5451. // Create a new group containing the selected objects.
  5452. //
  5453. CMapGroup *pGroup = new CMapGroup;
  5454. AddObjectToWorld(pGroup);
  5455. pGroup->SetRenderColor(100 + (random() % 156), 100 + (random() % 156), 0);
  5456. for (int i = 0; i < pSelList->Count(); i++)
  5457. {
  5458. CMapClass *pobj = (CUtlReference< CMapClass >)pSelList->Element(i);
  5459. if (pobj->GetParent() != NULL)
  5460. {
  5461. pobj->GetParent()->RemoveChild(pobj);
  5462. }
  5463. pGroup->AddChild(pobj);
  5464. }
  5465. //
  5466. // Keep the group as a new object. Don't keep its children here,
  5467. // because they are not new.
  5468. //
  5469. GetHistory()->KeepNew(pGroup, false);
  5470. // Clear selection and add the new group to it.
  5471. SelectObject(pGroup, scClear|scSelect|scSaveChanges );
  5472. SetModifiedFlag();
  5473. }
  5474. //-----------------------------------------------------------------------------
  5475. // Purpose: Ungroups all selected objects.
  5476. //-----------------------------------------------------------------------------
  5477. void CMapDoc::OnToolsUngroup(void)
  5478. {
  5479. if (( m_pSelection->GetMode() == selectSolids) && !Options.general.bGroupWhileIgnore)
  5480. {
  5481. return;
  5482. }
  5483. const CMapObjectList *pSelList = m_pSelection->GetList();
  5484. GetHistory()->MarkUndoPosition(pSelList, "Ungroup");
  5485. GetHistory()->Keep(pSelList);
  5486. // create new selected list
  5487. CMapObjectList NewSelList;
  5488. NewSelList.AddVectorToTail( *pSelList );
  5489. m_pSelection->SelectObject( NULL, scClear );
  5490. FOR_EACH_OBJ( NewSelList, pos )
  5491. {
  5492. CMapClass *pobj = NewSelList.Element(pos);
  5493. if(!pobj->IsMapClass(MAPCLASS_TYPE(CMapGroup)))
  5494. {
  5495. // make sure it is selected in the map
  5496. SelectObject(pobj, scSelect);
  5497. continue;
  5498. }
  5499. //
  5500. // Build a list of the group's children.
  5501. //
  5502. CMapObjectList ChildList;
  5503. const CMapObjectList *pChildren = pobj->GetChildren();
  5504. FOR_EACH_OBJ( *pChildren, pos2 )
  5505. {
  5506. ChildList.AddToTail(pChildren->Element(pos2));
  5507. }
  5508. //
  5509. // Detach the children from the group.
  5510. //
  5511. pobj->RemoveAllChildren();
  5512. //
  5513. // Move the group's former children to the group's parent.
  5514. //
  5515. int nChildCount = ChildList.Count();
  5516. for (int i = 0; i < nChildCount; i++)
  5517. {
  5518. CMapClass *pChild = ChildList.Element(i);
  5519. pobj->GetParent()->AddChild(pChild);
  5520. int nVisGroupCount = pobj->GetVisGroupCount();
  5521. for (int nVisGroup = 0; nVisGroup < nVisGroupCount; nVisGroup++)
  5522. {
  5523. CVisGroup *pVisGroup = pobj->GetVisGroup(nVisGroup);
  5524. pChild->AddVisGroup(pVisGroup);
  5525. }
  5526. pChild->SetRenderColor(0, 100 + (random() % 156), 100 + (random() % 156));
  5527. SelectObject(pChild, scSelect);
  5528. }
  5529. //
  5530. // The group is empty; delete it.
  5531. //
  5532. DeleteObject(pobj);
  5533. }
  5534. SetModifiedFlag();
  5535. }
  5536. //-----------------------------------------------------------------------------
  5537. // Purpose: Toggles the visibility of the grid in the 2D views.
  5538. //-----------------------------------------------------------------------------
  5539. void CMapDoc::OnViewGrid(void)
  5540. {
  5541. m_bShowGrid = !m_bShowGrid;
  5542. UpdateAllViews( MAPVIEW_OPTIONS_CHANGED );
  5543. }
  5544. //-----------------------------------------------------------------------------
  5545. // Purpose: Sets the check state of the Show Grid toolbar button and menu item.
  5546. //-----------------------------------------------------------------------------
  5547. void CMapDoc::OnUpdateViewGrid(CCmdUI *pCmdUI)
  5548. {
  5549. pCmdUI->SetCheck(m_bShowGrid);
  5550. }
  5551. //-----------------------------------------------------------------------------
  5552. // Purpose: Toggles the visibility of the grid in the 2D views.
  5553. //-----------------------------------------------------------------------------
  5554. void CMapDoc::OnViewLogicalGrid(void)
  5555. {
  5556. m_bShowLogicalGrid = !m_bShowLogicalGrid;
  5557. UpdateAllViews( MAPVIEW_UPDATE_ONLY_LOGICAL );
  5558. }
  5559. //-----------------------------------------------------------------------------
  5560. // Purpose: Sets the check state of the Show Grid toolbar button and menu item.
  5561. //-----------------------------------------------------------------------------
  5562. void CMapDoc::OnUpdateViewLogicalGrid(CCmdUI *pCmdUI)
  5563. {
  5564. pCmdUI->SetCheck(m_bShowLogicalGrid);
  5565. }
  5566. //-----------------------------------------------------------------------------
  5567. // Purpose: Selects all objects that are not hidden.
  5568. //-----------------------------------------------------------------------------
  5569. void CMapDoc::OnEditSelectall(void)
  5570. {
  5571. if (m_pToolManager->GetActiveToolID() == TOOL_MORPH)
  5572. {
  5573. // select all vertices
  5574. Morph3D *pMorph = (Morph3D*) m_pToolManager->GetActiveTool();
  5575. pMorph->SelectHandle(NULL, scSelectAll);
  5576. return;
  5577. }
  5578. SelectObject(NULL, scClear|scSaveChanges );
  5579. const CMapObjectList *pChildren = m_pWorld->GetChildren();
  5580. FOR_EACH_OBJ( *pChildren, pos )
  5581. {
  5582. CMapClass *pChild = (CUtlReference< CMapClass >)pChildren->Element(pos);
  5583. if (pChild->IsVisible())
  5584. {
  5585. SelectObject(pChild, scSelect);
  5586. }
  5587. }
  5588. }
  5589. //-----------------------------------------------------------------------------
  5590. // Purpose:
  5591. //-----------------------------------------------------------------------------
  5592. void CMapDoc::OnFileSaveAs(void)
  5593. {
  5594. static char szBaseDir[MAX_PATH] = "";
  5595. bool bSave = true;
  5596. CString str;
  5597. do
  5598. {
  5599. //
  5600. // The default directory for the Save As dialog is either:
  5601. // 1. The directory from which the document was loaded.
  5602. // 2. The last directory they saved any document into.
  5603. // 3. The maps directory as set up in Options | Game Configurations.
  5604. //
  5605. str = GetPathName();
  5606. if (str.ReverseFind('.') != -1)
  5607. {
  5608. str = str.Left(str.ReverseFind('.'));
  5609. strcpy(szBaseDir, str);
  5610. Q_StripFilename(szBaseDir);
  5611. }
  5612. else if (szBaseDir[0] =='\0')
  5613. {
  5614. strcpy(szBaseDir, m_pGame->szMapDir);
  5615. }
  5616. char *pszFilter;
  5617. if ( m_pManifest )
  5618. {
  5619. pszFilter = "Valve Manifest Map Files (*.vmm)|*.vmm||";
  5620. }
  5621. else if (m_pGame->mapformat == mfHalfLife2)
  5622. {
  5623. pszFilter = "Valve Map Files (*.vmf)|*.vmf||";
  5624. }
  5625. else
  5626. {
  5627. pszFilter = "Worldcraft Maps (*.rmf)|*.rmf|Game Maps (*.map)|*.map||";
  5628. }
  5629. CFileDialog dlg(FALSE, NULL, str, OFN_LONGNAMES | OFN_NOCHANGEDIR | OFN_HIDEREADONLY, pszFilter);
  5630. dlg.m_ofn.lpstrInitialDir = szBaseDir;
  5631. int rvl = dlg.DoModal();
  5632. if (rvl == IDCANCEL)
  5633. {
  5634. return;
  5635. }
  5636. str = dlg.GetPathName();
  5637. // Make sure we've got a .vmt extension, or else compile tools won't work.
  5638. CString wantedExtension = ".vmf";
  5639. if ( m_pManifest )
  5640. {
  5641. wantedExtension = ".vmm";
  5642. }
  5643. if ( m_pGame->mapformat != mfHalfLife2 )
  5644. {
  5645. if ( dlg.m_ofn.nFilterIndex == 1 )
  5646. {
  5647. wantedExtension = ".rmf";
  5648. }
  5649. else if ( dlg.m_ofn.nFilterIndex == 2 )
  5650. {
  5651. wantedExtension = ".map";
  5652. }
  5653. }
  5654. int pos = str.ReverseFind( '.' );
  5655. if ( pos != -1 )
  5656. {
  5657. CString extension = str.Right( str.GetLength() - pos );
  5658. extension.MakeLower();
  5659. if ( extension != wantedExtension )
  5660. str = str.Left( pos ) + wantedExtension;
  5661. }
  5662. else
  5663. { // no extension
  5664. str += wantedExtension;
  5665. }
  5666. //
  5667. // Save the default directory for next time.
  5668. //
  5669. strcpy(szBaseDir, str);
  5670. Q_StripFilename(szBaseDir);
  5671. bSave = true;
  5672. if (access(str, 0) != -1)
  5673. {
  5674. // The file exists.
  5675. char szConfirm[_MAX_PATH];
  5676. if (access(str, 2) == -1)
  5677. {
  5678. // The file is read-only
  5679. wsprintf(szConfirm, "The file %s is read-only. You must change the file's attributes to overwrite it.", str);
  5680. AfxMessageBox(szConfirm, MB_OK | MB_ICONEXCLAMATION);
  5681. bSave = false;
  5682. }
  5683. else
  5684. {
  5685. wsprintf(szConfirm, "Overwrite existing file %s?", str);
  5686. if (AfxMessageBox(szConfirm, MB_YESNO | MB_ICONQUESTION) != IDYES)
  5687. {
  5688. bSave = false;
  5689. }
  5690. }
  5691. }
  5692. } while (!bSave);
  5693. OnSaveDocument(str);
  5694. SetPathName(str);
  5695. }
  5696. //-----------------------------------------------------------------------------
  5697. // Purpose:
  5698. //-----------------------------------------------------------------------------
  5699. void CMapDoc::OnFileSave(void)
  5700. {
  5701. DWORD dwAttrib = GetFileAttributes(GetPathName());
  5702. if (dwAttrib & FILE_ATTRIBUTE_READONLY)
  5703. {
  5704. // we do not have read-write access or the file does not (now) exist
  5705. OnFileSaveAs();
  5706. }
  5707. else
  5708. {
  5709. if(m_strPathName.IsEmpty())
  5710. {
  5711. OnFileSaveAs();
  5712. }
  5713. else
  5714. {
  5715. OnSaveDocument(GetPathName());
  5716. }
  5717. }
  5718. }
  5719. //-----------------------------------------------------------------------------
  5720. // Purpose: Manages the state of the File | Save menu item.
  5721. //-----------------------------------------------------------------------------
  5722. void CMapDoc::OnUpdateFileSave(CCmdUI *pCmdUI)
  5723. {
  5724. pCmdUI->SetText(m_bEditingPrefab ? "Update Prefab\tCtrl+S" : "&Save\tCtrl+S");
  5725. }
  5726. //-----------------------------------------------------------------------------
  5727. // Purpose:
  5728. //-----------------------------------------------------------------------------
  5729. void CMapDoc::OnMapGridlower(void)
  5730. {
  5731. if (m_nGridSpacing <= 1)
  5732. {
  5733. return;
  5734. }
  5735. m_nGridSpacing = m_nGridSpacing / 2;
  5736. UpdateAllViews( MAPVIEW_OPTIONS_CHANGED );
  5737. UpdateStatusBarSnap();
  5738. }
  5739. //-----------------------------------------------------------------------------
  5740. // Purpose:
  5741. //-----------------------------------------------------------------------------
  5742. void CMapDoc::OnMapGridhigher(void)
  5743. {
  5744. if(m_nGridSpacing >= 512)
  5745. return;
  5746. m_nGridSpacing = m_nGridSpacing * 2;
  5747. UpdateAllViews( MAPVIEW_OPTIONS_CHANGED );
  5748. UpdateStatusBarSnap();
  5749. }
  5750. class CExportDlg : public CFileDialog
  5751. {
  5752. public:
  5753. CExportDlg(CString& strFile, LPCTSTR pszExt, LPCTSTR pszDesc) :
  5754. CFileDialog(FALSE, pszExt, strFile,
  5755. OFN_NOCHANGEDIR | OFN_LONGNAMES | OFN_HIDEREADONLY | OFN_EXPLORER |
  5756. OFN_ENABLETEMPLATE, pszDesc)
  5757. {
  5758. m_ofn.lpTemplateName = MAKEINTRESOURCE(IDD_MAPEXPORT);
  5759. bVisibles = FALSE;
  5760. }
  5761. afx_msg BOOL OnInitDialog()
  5762. {
  5763. m_Visibles.SubclassDlgItem(IDC_SAVEVISIBLES, this);
  5764. m_Visibles.SetCheck(bVisibles);
  5765. return TRUE;
  5766. }
  5767. afx_msg void OnToggleVisibles()
  5768. {
  5769. bVisibles = m_Visibles.GetCheck();
  5770. }
  5771. CButton m_Visibles;
  5772. BOOL bVisibles;
  5773. DECLARE_MESSAGE_MAP()
  5774. };
  5775. BEGIN_MESSAGE_MAP(CExportDlg, CFileDialog)
  5776. ON_BN_CLICKED(IDC_SAVEVISIBLES, OnToggleVisibles)
  5777. END_MESSAGE_MAP()
  5778. static BOOL bLastVis;
  5779. //-----------------------------------------------------------------------------
  5780. // Purpose:
  5781. //-----------------------------------------------------------------------------
  5782. void CMapDoc::OnFileExport(void)
  5783. {
  5784. //
  5785. // If we haven't saved the file yet, save it now.
  5786. //
  5787. CString strFile = GetPathName();
  5788. if (strFile.IsEmpty())
  5789. {
  5790. OnFileSave();
  5791. strFile = GetPathName();
  5792. if (strFile.IsEmpty())
  5793. {
  5794. return;
  5795. }
  5796. }
  5797. //
  5798. // Build a name for the exported file.
  5799. //
  5800. int iIndex = strFile.Find('.');
  5801. char *pszFilter;
  5802. char *pszExtension;
  5803. if (m_pGame->mapformat == mfHalfLife2)
  5804. {
  5805. strFile.SetAt(iIndex, '\0');
  5806. pszFilter = "Valve Map Files (*.vmf)|*.vmf||";
  5807. pszExtension = "vmf";
  5808. }
  5809. else
  5810. {
  5811. //
  5812. // Use the same filename with a .map extension.
  5813. //
  5814. strcpy(strFile.GetBuffer(1) + iIndex, ".map");
  5815. strFile.ReleaseBuffer();
  5816. pszFilter = "Game Maps (*.map)|*.map||";
  5817. pszExtension = "map";
  5818. }
  5819. //
  5820. // Bring up a dialog to allow them to name the exported file.
  5821. //
  5822. CExportDlg dlg(strFile, pszExtension, pszFilter);
  5823. dlg.m_ofn.lpstrTitle = "Export As";
  5824. dlg.bVisibles = bLastVis;
  5825. if (dlg.DoModal() == IDOK)
  5826. {
  5827. BOOL bModified = IsModified();
  5828. if (strFile.CompareNoCase(dlg.GetPathName()) == 0)
  5829. {
  5830. 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)
  5831. {
  5832. return;
  5833. }
  5834. }
  5835. bSaveVisiblesOnly = dlg.bVisibles;
  5836. m_strLastExportFileName = dlg.GetPathName();
  5837. OnSaveDocument(dlg.GetPathName());
  5838. bSaveVisiblesOnly = FALSE;
  5839. SetModifiedFlag(bModified);
  5840. bLastVis = dlg.bVisibles;
  5841. }
  5842. }
  5843. //-----------------------------------------------------------------------------
  5844. // Purpose: Exports using the last exported pathname. Brings up the Export dialog
  5845. // only if this document has never been exported.
  5846. //-----------------------------------------------------------------------------
  5847. void CMapDoc::OnFileExportAgain(void)
  5848. {
  5849. CString strFile = m_strLastExportFileName;
  5850. //
  5851. // If we have never exported this map, bring up the Export dialog.
  5852. //
  5853. if (strFile.IsEmpty())
  5854. {
  5855. OnFileExport();
  5856. return;
  5857. }
  5858. BOOL bModified = IsModified();
  5859. bSaveVisiblesOnly = bLastVis;
  5860. OnSaveDocument(strFile);
  5861. bSaveVisiblesOnly = FALSE;
  5862. SetModifiedFlag(bModified);
  5863. }
  5864. //-----------------------------------------------------------------------------
  5865. // Purpose:
  5866. //-----------------------------------------------------------------------------
  5867. void CMapDoc::OnEditMapproperties(void)
  5868. {
  5869. m_pSelection->SelectObject( m_pWorld, scClear|scSelect );
  5870. GetMainWnd()->pObjectProperties->ShowWindow(SW_SHOW);
  5871. }
  5872. //-----------------------------------------------------------------------------
  5873. // Purpose: Converts a map's textures from WAD3 to VMT.
  5874. //-----------------------------------------------------------------------------
  5875. void CMapDoc::OnFileConvertWAD( void )
  5876. {
  5877. CTextureConverter::ConvertWorldTextures( m_pWorld );
  5878. }
  5879. //-----------------------------------------------------------------------------
  5880. // Purpose: Manages the state of the File | Convert WAD -> VMT menu item.
  5881. //-----------------------------------------------------------------------------
  5882. void CMapDoc::OnUpdateFileConvertWAD( CCmdUI * pCmdUI )
  5883. {
  5884. pCmdUI->Enable( ( m_pWorld != NULL ) && ( g_pGameConfig->GetTextureFormat() == tfVMT ) );
  5885. }
  5886. //-----------------------------------------------------------------------------
  5887. // Purpose: Gets the relevant file extensions for the given map format.
  5888. // Input : mf -
  5889. // strEditExtension - The extension of the edit file (eg. .VMF, .RMF)
  5890. // strCompileExtension - The extension of the file to compile (eg. .VMF, .MAP)
  5891. //-----------------------------------------------------------------------------
  5892. void GetFileExtensions(MAPFORMAT mf, CString &strEditExtension, CString &strCompileExtension)
  5893. {
  5894. if (mf == mfHalfLife2)
  5895. {
  5896. strEditExtension = ".vmf";
  5897. strCompileExtension = ".vmf";
  5898. }
  5899. else
  5900. {
  5901. strEditExtension = ".rmf";
  5902. strCompileExtension = ".map";
  5903. }
  5904. }
  5905. //-----------------------------------------------------------------------------
  5906. // Purpose: Does a normal map compile.
  5907. //-----------------------------------------------------------------------------
  5908. void CMapDoc::OnFileRunmap(void)
  5909. {
  5910. //
  5911. // Check for texture wads first if the current game config uses them.
  5912. //
  5913. if ((g_pGameConfig->GetTextureFormat() == tfWAD) && !Options.textures.nTextureFiles)
  5914. {
  5915. AfxMessageBox("There are no texture files defined yet. Add some texture files before you run the map.");
  5916. GetMainWnd()->Configure();
  5917. return;
  5918. }
  5919. CString strEditExtension;
  5920. CString strCompileExtension;
  5921. GetFileExtensions(g_pGameConfig->GetMapFormat(), strEditExtension, strCompileExtension);
  5922. CRunMap dlg;
  5923. CRunMapExpertDlg dlgExpert;
  5924. dlg.m_bWaitForKeypress = dlgExpert.m_bWaitForKeypress = (AfxGetApp()->GetProfileInt("Run Map", "WaitForKeypress", 0) != 0);
  5925. bSaveVisiblesOnly = FALSE;
  5926. // Always save the map in case there's a dirty flag bug
  5927. CString strFile = GetPathName();
  5928. OnFileSave();
  5929. strFile = GetPathName();
  5930. if (strFile.IsEmpty() || IsModified())
  5931. return;
  5932. strFile.MakeLower();
  5933. // Make sure it has the correct extension for compilation (.VMF or .MAP).
  5934. int iPos = strFile.Find(strEditExtension);
  5935. Assert(iPos != -1);
  5936. if ((iPos != -1) && (strEditExtension.CompareNoCase(strCompileExtension) != 0))
  5937. {
  5938. strcpy(strFile.GetBuffer(0) + iPos, strCompileExtension);
  5939. strFile.ReleaseBuffer();
  5940. }
  5941. // make "bsp" string
  5942. CString strBspFile(strFile);
  5943. iPos = strBspFile.Find(strCompileExtension);
  5944. strcpy(strBspFile.GetBuffer(0) + iPos, ".bsp");
  5945. strBspFile.ReleaseBuffer();
  5946. // if no bsp file, make sure it's checked
  5947. if (GetFileAttributes(strBspFile) == 0xFFFFFFFF)
  5948. {
  5949. dlg.m_iQBSP = 1;
  5950. }
  5951. while (1)
  5952. {
  5953. if (AfxGetApp()->GetProfileInt("Run Map", "Mode", 0) == 0)
  5954. {
  5955. // run normal dialog
  5956. if(dlg.DoModal() == IDCANCEL)
  5957. return;
  5958. // switching mode?
  5959. if(dlg.m_bSwitchMode)
  5960. {
  5961. dlg.m_bSwitchMode = FALSE;
  5962. AfxGetApp()->WriteProfileInt("Run Map", "Mode", 1);
  5963. dlgExpert.m_bWaitForKeypress = dlg.m_bWaitForKeypress;
  5964. }
  5965. else
  5966. {
  5967. dlg.SaveToIni();
  5968. break; // clicked OK
  5969. }
  5970. }
  5971. else
  5972. {
  5973. // run expert dialog
  5974. if (dlgExpert.DoModal() == IDCANCEL)
  5975. return;
  5976. // switching mode?
  5977. if (dlgExpert.m_bSwitchMode)
  5978. {
  5979. AfxGetApp()->WriteProfileInt("Run Map", "Mode", 0);
  5980. dlgExpert.m_bSwitchMode = FALSE;
  5981. dlg.m_bWaitForKeypress = dlgExpert.m_bWaitForKeypress;
  5982. }
  5983. else if (dlgExpert.m_pActiveSequence) // clicked ok
  5984. {
  5985. // run the commands in the active sequence
  5986. RunCommands(dlgExpert.m_pActiveSequence->m_Commands, strFile, dlgExpert.m_bWaitForKeypress == TRUE);
  5987. AfxGetApp()->WriteProfileInt("Run Map", "WaitForKeypress", dlgExpert.m_bWaitForKeypress);
  5988. return;
  5989. }
  5990. else
  5991. {
  5992. return;
  5993. }
  5994. }
  5995. }
  5996. if (GetFileAttributes(strBspFile) == 0xFFFFFFFF)
  5997. {
  5998. if (!dlg.m_iQBSP)
  5999. {
  6000. dlg.m_iQBSP = 1;
  6001. }
  6002. }
  6003. CCOMMAND cmd;
  6004. memset(&cmd, 0, sizeof cmd);
  6005. cmd.bEnable = TRUE;
  6006. cmd.bLongFilenames = TRUE;
  6007. CCommandArray cmds;
  6008. // Change to the game drive and directory.
  6009. //cmd.iSpecialCmd = CCChangeDir;
  6010. //Q_snprintf( cmd.szParms, sizeof(cmd.szParms), "\"%s\"", m_pGame->m_szGameExeDir);
  6011. //strcpy(cmd.szRun, "Change Directory");
  6012. //cmds.Add(cmd);
  6013. //cmd.iSpecialCmd = 0;
  6014. // bsp
  6015. if ((dlg.m_iQBSP) && (m_pGame->szBSP[0] != '\0'))
  6016. {
  6017. strcpy(cmd.szRun, "$bsp_exe");
  6018. sprintf(cmd.szParms, "-game $gamedir %s$path\\$file.$ext", dlg.m_iQBSP == 2 ? "-onlyents " : "");
  6019. // check for bsp existence only in quake maps, because
  6020. // we're using the editor's utilities
  6021. if (g_pGameConfig->mapformat == mfQuake)
  6022. {
  6023. cmd.bEnsureCheck = TRUE;
  6024. strcpy(cmd.szEnsureFn, "$path\\$file.bsp");
  6025. }
  6026. cmds.Add(cmd);
  6027. cmd.bEnsureCheck = FALSE;
  6028. }
  6029. // vis
  6030. if ((dlg.m_iVis) && (m_pGame->szVIS[0] != '\0'))
  6031. {
  6032. strcpy(cmd.szRun, "$vis_exe");
  6033. sprintf(cmd.szParms, "-game $gamedir %s$path\\$file", dlg.m_iVis == 2 ? "-fast " : "");
  6034. cmds.Add(cmd);
  6035. }
  6036. // rad
  6037. if ((dlg.m_iLight) && (m_pGame->szLIGHT[0] != '\0'))
  6038. {
  6039. strcpy(cmd.szRun, "$light_exe");
  6040. sprintf(cmd.szParms, "%s -game $gamedir %s$path\\$file", dlg.m_bHDRLight ? "-both" : "", dlg.m_iLight == 2 ? "-noextra " : "" );
  6041. cmds.Add(cmd);
  6042. }
  6043. // Copy BSP file to BSP directory for running
  6044. cmd.iSpecialCmd = CCCopyFile;
  6045. strcpy(cmd.szRun, "Copy File");
  6046. sprintf(cmd.szParms, "$path\\$file.bsp $bspdir\\$file.bsp");
  6047. cmds.Add(cmd);
  6048. cmd.iSpecialCmd = 0;
  6049. // Run the game.
  6050. if (dlg.m_bNoQuake == FALSE)
  6051. {
  6052. cmd.bNoWait = TRUE;
  6053. //When running under steam, use applaunch always because if a user forgets to run the game they're trying to launch, it will fail
  6054. //with an obscure error they won't understand.
  6055. if ( CGameConfigManager::IsSDKDeployment() )
  6056. {
  6057. CString strSteamExe;
  6058. m_pGame->GetSteamExe(strSteamExe);
  6059. CString strSteamAppID;
  6060. m_pGame->GetSteamAppID(strSteamAppID);
  6061. strcpy(cmd.szRun, strSteamExe);
  6062. if (strSteamAppID.GetLength() != 0)
  6063. {
  6064. sprintf(cmd.szParms, "-applaunch %s -game $gamedir %s +map $file", strSteamAppID, dlg.m_strQuakeParms);
  6065. }
  6066. else
  6067. {
  6068. // If the appid can't be found for whatever reason just launch normally. *sigh*
  6069. strcpy(cmd.szRun, "$game_exe");
  6070. sprintf(cmd.szParms, "-game $gamedir %s +map $file", dlg.m_strQuakeParms);
  6071. }
  6072. }
  6073. else
  6074. {
  6075. strcpy(cmd.szRun, "$game_exe");
  6076. sprintf(cmd.szParms, "-game $gamedir %s +map $file", dlg.m_strQuakeParms);
  6077. }
  6078. cmds.Add(cmd);
  6079. }
  6080. AfxGetApp()->WriteProfileInt("Run Map", "WaitForKeypress", dlg.m_bWaitForKeypress);
  6081. RunCommands(cmds, GetPathName(), dlg.m_bWaitForKeypress == TRUE);
  6082. }
  6083. //-----------------------------------------------------------------------------
  6084. // Purpose: Updates the title of the doc based on the filename and the
  6085. // active view type.
  6086. // Input : pView -
  6087. //-----------------------------------------------------------------------------
  6088. void CMapDoc::UpdateTitle(CView *pView)
  6089. {
  6090. CString strFile = GetPathName();
  6091. LPCTSTR pszFilename = strFile;
  6092. // Leaving the partial-filename code in here in case we want to make it an option someday.
  6093. bool bShowPartialFilename = false;
  6094. if ( bShowPartialFilename )
  6095. {
  6096. int iPos = strFile.ReverseFind('\\');
  6097. if (iPos != -1)
  6098. {
  6099. pszFilename = strFile.GetBuffer(0) + iPos + 1;
  6100. }
  6101. else
  6102. {
  6103. pszFilename = "Untitled";
  6104. }
  6105. }
  6106. char *pViewType = NULL;
  6107. CMapView2D *pView2D = dynamic_cast <CMapView2D *> (pView);
  6108. if (pView2D != NULL)
  6109. {
  6110. switch (pView2D->GetDrawType())
  6111. {
  6112. case VIEW2D_XY:
  6113. {
  6114. pViewType = "Top";
  6115. break;
  6116. }
  6117. case VIEW2D_XZ:
  6118. {
  6119. pViewType = "Right";
  6120. break;
  6121. }
  6122. case VIEW2D_YZ:
  6123. {
  6124. pViewType = "Front";
  6125. break;
  6126. }
  6127. }
  6128. }
  6129. CMapViewLogical *pViewLogical = dynamic_cast <CMapViewLogical *> (pView);
  6130. if (pViewLogical != NULL)
  6131. {
  6132. pViewType = "Logical";
  6133. }
  6134. CMapView3D *pView3D = dynamic_cast <CMapView3D *> (pView);
  6135. if (pView3D != NULL)
  6136. {
  6137. switch (pView3D->GetDrawType())
  6138. {
  6139. case VIEW3D_WIREFRAME:
  6140. {
  6141. pViewType = "Wireframe";
  6142. break;
  6143. }
  6144. case VIEW3D_POLYGON:
  6145. {
  6146. pViewType = "Polygon";
  6147. break;
  6148. }
  6149. case VIEW3D_TEXTURED:
  6150. {
  6151. pViewType = "Textured";
  6152. break;
  6153. }
  6154. case VIEW3D_TEXTURED_SHADED:
  6155. {
  6156. pViewType = "Textured Shaded";
  6157. break;
  6158. }
  6159. case VIEW3D_LIGHTMAP_GRID:
  6160. {
  6161. pViewType = "Lightmap grid";
  6162. break;
  6163. }
  6164. case VIEW3D_SMOOTHING_GROUP:
  6165. {
  6166. pViewType = "Smoothing Group";
  6167. break;
  6168. }
  6169. //case VIEW3D_ENGINE:
  6170. //{
  6171. // pViewType = "Engine";
  6172. // break;
  6173. //}
  6174. }
  6175. }
  6176. CString str;
  6177. if (pViewType)
  6178. {
  6179. str.Format("%s - %s", pszFilename, pViewType);
  6180. }
  6181. else
  6182. {
  6183. str.Format("%s", pszFilename);
  6184. }
  6185. if ( m_bReadOnly == true )
  6186. {
  6187. str += " [ READ ONLY ]";
  6188. }
  6189. if ( m_bCheckedOut == true )
  6190. {
  6191. str += " [ CHECKED OUT ]";
  6192. }
  6193. SetTitle(str);
  6194. }
  6195. //-----------------------------------------------------------------------------
  6196. // Purpose: Toggles the state of Hide Items. When enabled, entities are hidden.
  6197. //-----------------------------------------------------------------------------
  6198. void CMapDoc::OnToolsHideitems(void)
  6199. {
  6200. m_bHideItems = !m_bHideItems;
  6201. UpdateVisibilityAll();
  6202. }
  6203. //-----------------------------------------------------------------------------
  6204. // Purpose: Manages the state of the Tools | Hide Items menu item.
  6205. //-----------------------------------------------------------------------------
  6206. void CMapDoc::OnUpdateToolsHideitems(CCmdUI *pCmdUI)
  6207. {
  6208. pCmdUI->Enable(!GetMainWnd()->IsShellSessionActive());
  6209. pCmdUI->SetCheck(m_bHideItems ? TRUE : FALSE);
  6210. }
  6211. //-----------------------------------------------------------------------------
  6212. // Purpose: Hides and shows entity names in the 2D views.
  6213. //-----------------------------------------------------------------------------
  6214. void CMapDoc::OnToolsHideEntityNames(void)
  6215. {
  6216. bool bShowEntityNames = !CMapEntity::GetShowEntityNames();
  6217. CMapEntity::ShowEntityNames(bShowEntityNames);
  6218. UpdateAllViews( MAPVIEW_UPDATE_ONLY_2D );
  6219. }
  6220. //-----------------------------------------------------------------------------
  6221. // Purpose: Manages the state of the Tools | Hide Entity Names menu item.
  6222. //-----------------------------------------------------------------------------
  6223. void CMapDoc::OnUpdateToolsHideEntityNames(CCmdUI *pCmdUI)
  6224. {
  6225. pCmdUI->Enable(!GetMainWnd()->IsShellSessionActive());
  6226. pCmdUI->SetCheck(CMapEntity::GetShowEntityNames() ? FALSE : TRUE);
  6227. }
  6228. //-----------------------------------------------------------------------------
  6229. // Purpose: Hides and shows entity names in the 2D views.
  6230. //-----------------------------------------------------------------------------
  6231. void CMapDoc::OnViewHideUnconnectedEntities(void)
  6232. {
  6233. bool bHideUnconnectedEntities = !CMapEntity::GetShowUnconnectedEntities();
  6234. CMapEntity::ShowUnconnectedEntities(bHideUnconnectedEntities);
  6235. UpdateAllViews( MAPVIEW_UPDATE_ONLY_LOGICAL );
  6236. }
  6237. //-----------------------------------------------------------------------------
  6238. // Purpose: Manages the state of the Tools | Hide Entity Names menu item.
  6239. //-----------------------------------------------------------------------------
  6240. void CMapDoc::OnUpdateViewHideUnconnectedEntities(CCmdUI *pCmdUI)
  6241. {
  6242. pCmdUI->Enable(!GetMainWnd()->IsShellSessionActive());
  6243. pCmdUI->SetCheck(CMapEntity::GetShowUnconnectedEntities() ? FALSE : TRUE);
  6244. }
  6245. //-----------------------------------------------------------------------------
  6246. // Purpose:
  6247. // Input : *pView -
  6248. //-----------------------------------------------------------------------------
  6249. void CMapDoc::SetMRU(CMapView2D *pView)
  6250. {
  6251. RemoveMRU(pView);
  6252. MRU2DViews.AddToHead(pView);
  6253. }
  6254. //-----------------------------------------------------------------------------
  6255. // Purpose:
  6256. // Input : *pView -
  6257. //-----------------------------------------------------------------------------
  6258. void CMapDoc::RemoveMRU(CMapView2D *pView)
  6259. {
  6260. MRU2DViews.FindAndRemove(pView);
  6261. }
  6262. //-----------------------------------------------------------------------------
  6263. // Purpose: Manages the state of all Edit menu items and toolbar buttons.
  6264. //-----------------------------------------------------------------------------
  6265. void CMapDoc::OnUpdateEditFunction(CCmdUI *pCmdUI)
  6266. {
  6267. pCmdUI->Enable( ( m_pToolManager->GetActiveToolID() != TOOL_FACEEDIT_MATERIAL ) &&
  6268. !GetMainWnd()->IsShellSessionActive() );
  6269. }
  6270. //-----------------------------------------------------------------------------
  6271. // Purpose: This is called for each doc when the texture application mode changes.
  6272. // Input : bApplicator - TRUE if entering texture applicator mode, FALSE if
  6273. // leaving texture applicator mode.
  6274. //-----------------------------------------------------------------------------
  6275. void CMapDoc::UpdateForApplicator(BOOL bApplicator)
  6276. {
  6277. if (bApplicator)
  6278. {
  6279. //
  6280. // Build a list of all selected solids.
  6281. //
  6282. CMapObjectList Solids;
  6283. const CMapObjectList *pSelList = m_pSelection->GetList();
  6284. for (int i = 0; i < pSelList->Count(); i++)
  6285. {
  6286. CMapClass *pObject = (CUtlReference< CMapClass >)pSelList->Element(i);
  6287. CMapSolid *pSolid = dynamic_cast<CMapSolid*>(pObject);
  6288. if (pSolid != NULL)
  6289. {
  6290. Solids.AddToTail(pSolid);
  6291. }
  6292. pObject->EnumChildren((ENUMMAPCHILDRENPROC)AddLeavesToListCallback, (DWORD)&Solids, MAPCLASS_TYPE(CMapSolid));
  6293. }
  6294. //
  6295. // Clear the object selection.
  6296. //
  6297. SelectObject(NULL, scClear);
  6298. //
  6299. // Select all faces of all solids that were selected originally. Disable updates
  6300. // in the face properties dialog beforehand or this could take a LONG time.
  6301. //
  6302. HCURSOR hCursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
  6303. GetMainWnd()->m_pFaceEditSheet->EnableUpdate( false );
  6304. bool bFirst = true;
  6305. FOR_EACH_OBJ( Solids, pos )
  6306. {
  6307. CMapClass *pObject = Solids.Element(pos);
  6308. CMapSolid *pSolid = dynamic_cast<CMapSolid*>(pObject);
  6309. Assert(pSolid != NULL);
  6310. if (pSolid != NULL)
  6311. {
  6312. SelectFace(pSolid, -1, scSelect | (bFirst ? scClear : 0));
  6313. bFirst = false;
  6314. }
  6315. }
  6316. GetMainWnd()->m_pFaceEditSheet->EnableUpdate( true );
  6317. SetCursor(hCursorOld);
  6318. }
  6319. else
  6320. {
  6321. //
  6322. // Remove all faces from the dialog's list and update their selection state to be
  6323. // not selected, then update the display.
  6324. //
  6325. GetMainWnd()->m_pFaceEditSheet->ClickFace( NULL, -1, CFaceEditSheet::cfClear );
  6326. UpdateStatusbar();
  6327. }
  6328. }
  6329. //-----------------------------------------------------------------------------
  6330. // Purpose:
  6331. // Input : *pSolid -
  6332. // iFace -
  6333. // cmd -
  6334. //-----------------------------------------------------------------------------
  6335. void CMapDoc::SelectFace(CMapSolid *pSolid, int iFace, int cmd)
  6336. {
  6337. bool bFirst = true;
  6338. if(iFace == -1 && pSolid)
  6339. {
  6340. // Get draw solid/disp mask.
  6341. bool bDispSolidMask = CMapDoc::GetActiveMapDoc()->IsDispSolidDrawMask() && pSolid->HasDisp();
  6342. // select entire object
  6343. int nFaces = pSolid->GetFaceCount();
  6344. for(int i = 0; i < nFaces; i++)
  6345. {
  6346. if ( bDispSolidMask )
  6347. {
  6348. CMapFace *pFace = pSolid->GetFace( i );
  6349. if( pFace && pFace->HasDisp() )
  6350. {
  6351. SelectFace(pSolid, i, cmd);
  6352. if ( bFirst )
  6353. {
  6354. cmd &= ~scClear;
  6355. bFirst = false;
  6356. }
  6357. }
  6358. }
  6359. else
  6360. {
  6361. SelectFace(pSolid, i, cmd);
  6362. if ( bFirst )
  6363. {
  6364. cmd &= ~scClear;
  6365. bFirst = false;
  6366. }
  6367. }
  6368. }
  6369. return;
  6370. }
  6371. CFaceEditSheet *pSheet = GetMainWnd()->m_pFaceEditSheet;
  6372. UINT uFaceCmd = 0;
  6373. if(cmd & scClear)
  6374. {
  6375. uFaceCmd |= CFaceEditSheet::cfClear;
  6376. }
  6377. if(cmd & scToggle)
  6378. {
  6379. uFaceCmd |= CFaceEditSheet::cfToggle;
  6380. }
  6381. if(cmd & scSelect)
  6382. {
  6383. uFaceCmd |= CFaceEditSheet::cfSelect;
  6384. }
  6385. if(cmd & scUnselect)
  6386. {
  6387. uFaceCmd |= CFaceEditSheet::cfUnselect;
  6388. }
  6389. //
  6390. // Change the click mode to ModeSelect if the scNoLift flag is set.
  6391. //
  6392. int nClickMode;
  6393. if (cmd & scNoLift) // dvs: this is lame
  6394. {
  6395. nClickMode = CFaceEditSheet::ModeSelect;
  6396. }
  6397. else
  6398. {
  6399. nClickMode = -1;
  6400. }
  6401. //
  6402. // Check the current click mode and perform the texture application if appropriate.
  6403. //
  6404. BOOL bApply = FALSE;
  6405. if (!(cmd & scNoApply))
  6406. {
  6407. int iFaceMode = pSheet->GetClickMode();
  6408. bApply = ( ( iFaceMode == CFaceEditSheet::ModeApply ) || ( iFaceMode == CFaceEditSheet::ModeApplyAll ) );
  6409. if (bApply && pSolid)
  6410. {
  6411. GetHistory()->MarkUndoPosition(NULL, "Apply texture");
  6412. GetHistory()->Keep(pSolid);
  6413. }
  6414. }
  6415. pSheet->ClickFace( pSolid, iFace, uFaceCmd, nClickMode );
  6416. // update display?
  6417. if (bApply)
  6418. {
  6419. UpdateStatusbar();
  6420. }
  6421. }
  6422. //-----------------------------------------------------------------------------
  6423. //-----------------------------------------------------------------------------
  6424. void CMapDoc::OnMapInformation()
  6425. {
  6426. CMapInfoDlg dlg(m_pWorld);
  6427. dlg.DoModal();
  6428. }
  6429. //-----------------------------------------------------------------------------
  6430. // Purpose: Forces a render of all the 3D views. Called from OnIdle to render
  6431. // the 3D views.
  6432. //-----------------------------------------------------------------------------
  6433. void CMapDoc::SetActiveView(CMapView *pViewActivate)
  6434. {
  6435. POSITION p = GetFirstViewPosition();
  6436. while (p)
  6437. {
  6438. CMapView *pView = dynamic_cast<CMapView*>(GetNextView(p));
  6439. if ( pView )
  6440. {
  6441. pView->ActivateView(pView == pViewActivate);
  6442. }
  6443. }
  6444. }
  6445. //-----------------------------------------------------------------------------
  6446. // releases video memory
  6447. //-----------------------------------------------------------------------------
  6448. void CMapDoc::ReleaseVideoMemory( )
  6449. {
  6450. POSITION p = GetFirstViewPosition();
  6451. while (p)
  6452. {
  6453. CMapView3D *pView = dynamic_cast<CMapView3D*>(GetNextView(p));
  6454. if (pView)
  6455. {
  6456. pView->ReleaseVideoMemory();
  6457. }
  6458. }
  6459. }
  6460. //-----------------------------------------------------------------------------
  6461. // Purpose:
  6462. // Input : vi -
  6463. //-----------------------------------------------------------------------------
  6464. void CMapDoc::SetView2dInfo(VIEW2DINFO& vi)
  6465. {
  6466. POSITION p = GetFirstViewPosition();
  6467. while(p)
  6468. {
  6469. CView *pView = GetNextView(p);
  6470. if(!pView->IsKindOf(RUNTIME_CLASS(CMapView2D)))
  6471. continue;
  6472. CMapView2D *pView2D = (CMapView2D*) pView;
  6473. // set zoom value
  6474. if(vi.wFlags & VI_ZOOM)
  6475. {
  6476. pView2D->SetZoom(vi.fZoom);
  6477. }
  6478. // center on point
  6479. if(vi.wFlags & VI_CENTER)
  6480. {
  6481. pView2D->CenterView(&vi.ptCenter);
  6482. }
  6483. pView2D->UpdateView( MAPVIEW_UPDATE_OBJECTS );
  6484. }
  6485. }
  6486. void CMapDoc::SetViewLogicalInfo(VIEW2DINFO& vi)
  6487. {
  6488. POSITION p = GetFirstViewPosition();
  6489. while(p)
  6490. {
  6491. CView *pView = GetNextView(p);
  6492. if(!pView->IsKindOf(RUNTIME_CLASS(CMapViewLogical)))
  6493. continue;
  6494. CMapViewLogical *pViewLogical = (CMapViewLogical*) pView;
  6495. // set zoom value
  6496. if(vi.wFlags & VI_ZOOM)
  6497. {
  6498. pViewLogical->SetZoom(vi.fZoom);
  6499. }
  6500. // center on point
  6501. if(vi.wFlags & VI_CENTER)
  6502. {
  6503. pViewLogical->CenterView(&vi.ptCenter);
  6504. }
  6505. pViewLogical->UpdateView( MAPVIEW_UPDATE_OBJECTS );
  6506. }
  6507. }
  6508. //-----------------------------------------------------------------------------
  6509. // Purpose:
  6510. // Input : &vec -
  6511. //-----------------------------------------------------------------------------
  6512. void CMapDoc::CenterViewsOn(const Vector &vec)
  6513. {
  6514. Center2DViewsOn(vec);
  6515. Center3DViewsOn(vec);
  6516. }
  6517. //-----------------------------------------------------------------------------
  6518. // Purpose:
  6519. //-----------------------------------------------------------------------------
  6520. void CMapDoc::Center2DViewsOn(const Vector &vec)
  6521. {
  6522. VIEW2DINFO vi;
  6523. vi.wFlags = VI_CENTER;
  6524. vi.ptCenter = vec;
  6525. SetView2dInfo(vi);
  6526. }
  6527. //-----------------------------------------------------------------------------
  6528. // Purpose: Centers the 3D views on the given point.
  6529. //-----------------------------------------------------------------------------
  6530. void CMapDoc::Center3DViewsOn( const Vector &vPos )
  6531. {
  6532. POSITION p = GetFirstViewPosition();
  6533. while(p)
  6534. {
  6535. CView *pView = GetNextView(p);
  6536. if(!pView->IsKindOf(RUNTIME_CLASS(CMapView3D)))
  6537. continue;
  6538. CMapView3D *pView3D = (CMapView3D*) pView;
  6539. //what's happening here?
  6540. Vector vForward;
  6541. pView3D->GetCamera()->GetViewForward( vForward );
  6542. pView3D->SetCamera( vPos - Vector( 0, 100, 0 ), vPos );
  6543. pView3D->UpdateView( MAPVIEW_UPDATE_OBJECTS );
  6544. }
  6545. }
  6546. //-----------------------------------------------------------------------------
  6547. // Purpose: Sets 3D views with the input position and angle vectors.
  6548. //-----------------------------------------------------------------------------
  6549. void CMapDoc::Set3DViewsPosAng( const Vector &vPos, const Vector &vAng )
  6550. {
  6551. POSITION p = GetFirstViewPosition();
  6552. while(p)
  6553. {
  6554. CView *pView = GetNextView(p);
  6555. if(!pView->IsKindOf(RUNTIME_CLASS(CMapView3D)))
  6556. continue;
  6557. CMapView3D *pView3D = (CMapView3D*) pView;
  6558. QAngle angles;
  6559. angles.x = vAng.x;
  6560. angles.y = vAng.y;
  6561. angles.z = vAng.z;
  6562. Vector forward;
  6563. AngleVectors( angles, &forward );
  6564. pView3D->SetCamera( vPos, forward + vPos );
  6565. pView3D->UpdateView( MAPVIEW_UPDATE_OBJECTS );
  6566. }
  6567. }
  6568. //-----------------------------------------------------------------------------
  6569. // Purpose:
  6570. //-----------------------------------------------------------------------------
  6571. void CMapDoc::CenterLogicalViewsOn(const Vector2D &vecLogical)
  6572. {
  6573. VIEW2DINFO vi;
  6574. vi.wFlags = VI_CENTER;
  6575. vi.ptCenter = Vector( vecLogical.x, vecLogical.y, 0.0f );
  6576. SetViewLogicalInfo(vi);
  6577. }
  6578. //-----------------------------------------------------------------------------
  6579. // Purpose: Centers the 2D views on selected objects.
  6580. //-----------------------------------------------------------------------------
  6581. void CMapDoc::OnViewCenterOnSelection(void)
  6582. {
  6583. Center2DViewsOnSelection();
  6584. CenterLogicalViewsOnSelection();
  6585. }
  6586. //-----------------------------------------------------------------------------
  6587. // Purpose: Centers the 3D views on selected objects.
  6588. //-----------------------------------------------------------------------------
  6589. void CMapDoc::OnViewCenter3DViewsOnSelection(void)
  6590. {
  6591. Center3DViewsOnSelection();
  6592. }
  6593. //-----------------------------------------------------------------------------
  6594. // Purpose: Hollows selected solids by carving them with a scaled version of
  6595. // themselves.
  6596. //-----------------------------------------------------------------------------
  6597. void CMapDoc::OnToolsHollow(void)
  6598. {
  6599. //
  6600. // Confirm the operation if there is more than one object selected.
  6601. //
  6602. if ( m_pSelection->GetCount() > 1)
  6603. {
  6604. if (AfxMessageBox("Do you want to turn each of the selected solids into a hollow room?", MB_YESNO) == IDNO)
  6605. {
  6606. return;
  6607. }
  6608. }
  6609. //
  6610. // Prompt for the wall thickness, which is remembered from one hollow to another.
  6611. //
  6612. static int iWallWidth = 32;
  6613. char szBuf[128];
  6614. itoa(iWallWidth, szBuf, 10);
  6615. CStrDlg dlg(CStrDlg::Spin, szBuf, "How thick do you want the walls? Use a negative number to hollow outward.", "Hammer");
  6616. dlg.SetRange(-1024, 1024, 4);
  6617. if (dlg.DoModal() == IDCANCEL)
  6618. {
  6619. return;
  6620. }
  6621. iWallWidth = atoi(dlg.m_string);
  6622. if (abs(iWallWidth) < 2)
  6623. {
  6624. AfxMessageBox("The width of the walls must be less than -1 or greater than 1.");
  6625. return;
  6626. }
  6627. const CMapObjectList *pSelList = m_pSelection->GetList();
  6628. GetHistory()->MarkUndoPosition(pSelList, "Hollow");
  6629. //
  6630. // Build a list of all solids in the selection.
  6631. //
  6632. CMapObjectList SelectedSolids;
  6633. for (int i = 0; i < pSelList->Count(); i++)
  6634. {
  6635. CMapClass *pObject = (CUtlReference< CMapClass >)pSelList->Element(i);
  6636. CMapSolid *pSolid = dynamic_cast <CMapSolid *> (pObject);
  6637. if (pSolid != NULL)
  6638. {
  6639. SelectedSolids.AddToTail(pSolid);
  6640. }
  6641. EnumChildrenPos_t pos2;
  6642. CMapClass *pChild = pObject->GetFirstDescendent(pos2);
  6643. while (pChild != NULL)
  6644. {
  6645. CMapSolid *pSolid = dynamic_cast <CMapSolid *> (pChild);
  6646. if (pSolid != NULL)
  6647. {
  6648. SelectedSolids.AddToTail(pSolid);
  6649. }
  6650. pChild = pObject->GetNextDescendent(pos2);
  6651. }
  6652. }
  6653. //
  6654. // Carve every solid in the selection with a scaled copy of itself. This accomplishes
  6655. // the goal of hollowing them.
  6656. //
  6657. CMapSolid ScaledCopy;
  6658. FOR_EACH_OBJ( SelectedSolids, pos )
  6659. {
  6660. CMapClass *pMapClass = (CUtlReference< CMapClass >)SelectedSolids.Element(pos);
  6661. CMapSolid *pSelectedSolid = (CMapSolid *)pMapClass;
  6662. CMapClass *pDestParent = pSelectedSolid->GetParent();
  6663. GetHistory()->Keep(pSelectedSolid);
  6664. ScaledCopy.CopyFrom(pSelectedSolid, false);
  6665. ScaledCopy.SetParent(NULL);
  6666. //
  6667. // Get bounds of the solid to be hollowed and calculate scaling required to
  6668. // reduce by iWallWidth.
  6669. //
  6670. BoundBox box;
  6671. Vector ptCenter;
  6672. Vector vecScale;
  6673. pSelectedSolid->GetRender2DBox(box.bmins, box.bmaxs);
  6674. for (int i = 0; i < 3; i++)
  6675. {
  6676. float fHalf = (box.bmaxs[i] - box.bmins[i]) / 2;
  6677. vecScale[i] = (fHalf - iWallWidth) / fHalf;
  6678. }
  6679. ScaledCopy.GetBoundsCenter(ptCenter);
  6680. ScaledCopy.TransScale(ptCenter, vecScale);
  6681. //
  6682. // Set up the operands for the subtraction operation.
  6683. //
  6684. CMapSolid *pSubtractWith;
  6685. CMapSolid *pSubtractFrom;
  6686. if (iWallWidth > 0)
  6687. {
  6688. pSubtractFrom = pSelectedSolid;
  6689. pSubtractWith = &ScaledCopy;
  6690. }
  6691. //
  6692. // Negative wall widths reverse the subtraction.
  6693. //
  6694. else
  6695. {
  6696. pSubtractFrom = &ScaledCopy;
  6697. pSubtractWith = pSelectedSolid;
  6698. }
  6699. //
  6700. // Perform the subtraction. If the two objects intersected...
  6701. //
  6702. CMapObjectList Outside;
  6703. if (pSubtractFrom->Subtract(NULL, &Outside, pSubtractWith))
  6704. {
  6705. //
  6706. // If there were pieces outside the 'subtract with' object...
  6707. //
  6708. if (Outside.Count() > 0)
  6709. {
  6710. CMapClass *pResult = NULL;
  6711. //
  6712. // If the subtraction resulted in more than one object, create a group
  6713. // to place the results in.
  6714. //
  6715. if (Outside.Count() > 1)
  6716. {
  6717. pResult = (CMapClass *)(new CMapGroup);
  6718. FOR_EACH_OBJ( Outside, pos2 )
  6719. {
  6720. CMapClass *pTemp = Outside.Element(pos2);
  6721. pResult->AddChild(pTemp);
  6722. }
  6723. }
  6724. //
  6725. // Otherwise, the results are the single object.
  6726. //
  6727. else if (Outside.Count() == 1)
  6728. {
  6729. pResult = Outside[0];
  6730. }
  6731. //
  6732. // Replace the current solid with the subtraction results.
  6733. //
  6734. DeleteObject(pSelectedSolid);
  6735. AddObjectToWorld(pResult, pDestParent);
  6736. GetHistory()->KeepNew(pResult);
  6737. }
  6738. }
  6739. }
  6740. // Objects in selection no longer exist.
  6741. m_pSelection->SelectObject( NULL, scClear );
  6742. SetModifiedFlag();
  6743. }
  6744. //-----------------------------------------------------------------------------
  6745. // Purpose:
  6746. //-----------------------------------------------------------------------------
  6747. void CMapDoc::OnEditPastespecial(void)
  6748. {
  6749. CPasteSpecialDlg dlg(GetMainWnd(), &GetHammerClipboard()->Bounds);
  6750. if (dlg.DoModal() == IDCANCEL)
  6751. {
  6752. return;
  6753. }
  6754. dlg.SaveToIni();
  6755. BeginWaitCursor();
  6756. GetHistory()->MarkUndoPosition( m_pSelection->GetList(), "Paste");
  6757. // first, clear selection so we can select all pasted objects
  6758. SelectObject(NULL, scClear|scSaveChanges );
  6759. //
  6760. // Build a paste translation.
  6761. //
  6762. Vector vecPasteOffset( COORD_NOTINIT, COORD_NOTINIT, COORD_NOTINIT );
  6763. if (!dlg.m_bCenterOriginal)
  6764. {
  6765. GetBestPastePoint(vecPasteOffset, GetHammerClipboard());
  6766. vecPasteOffset -= GetHammerClipboard()->vecOriginalCenter;
  6767. }
  6768. else
  6769. {
  6770. vecPasteOffset[0] = dlg.m_iOffsetX;
  6771. vecPasteOffset[1] = dlg.m_iOffsetY;
  6772. vecPasteOffset[2] = dlg.m_iOffsetZ;
  6773. }
  6774. //
  6775. // Build the paste rotation angles.
  6776. //
  6777. QAngle vecPasteAngles;
  6778. vecPasteAngles[0] = dlg.m_fRotateX;
  6779. vecPasteAngles[1] = dlg.m_fRotateY;
  6780. vecPasteAngles[2] = dlg.m_fRotateZ;
  6781. CMapWorld *pWorld = GetActiveWorld();
  6782. CMapClass *pParent = NULL;
  6783. CMapGroup *pGroup = NULL;
  6784. if (dlg.m_bGroup)
  6785. {
  6786. pGroup = new CMapGroup;
  6787. pParent = (CMapClass *)pGroup;
  6788. AddObjectToWorld(pGroup, pWorld);
  6789. }
  6790. Options.SetLockingTextures(TRUE);
  6791. bool bMakeNamesUnique = (dlg.m_bMakeEntityNamesUnique == TRUE);
  6792. const char *pszPrefix = (dlg.m_bAddPrefix == TRUE) ? dlg.m_strPrefix : "";
  6793. for (int i = 0; i < dlg.m_iCopies; i++)
  6794. {
  6795. //
  6796. // Paste the objects with the current offset and rotation.
  6797. //
  6798. Paste(GetHammerClipboard(), pWorld, vecPasteOffset, vecPasteAngles, pParent, bMakeNamesUnique, pszPrefix );
  6799. //
  6800. // Increment the paste offset.
  6801. //
  6802. vecPasteOffset[0] += dlg.m_iOffsetX;
  6803. vecPasteOffset[1] += dlg.m_iOffsetY;
  6804. vecPasteOffset[2] += dlg.m_iOffsetZ;
  6805. //
  6806. // Increment the paste angles.
  6807. //
  6808. vecPasteAngles[0] += dlg.m_fRotateX;
  6809. vecPasteAngles[1] += dlg.m_fRotateY;
  6810. vecPasteAngles[2] += dlg.m_fRotateZ;
  6811. }
  6812. //
  6813. // If we pasted into a group, keep the group now.
  6814. //
  6815. if (pGroup != NULL)
  6816. {
  6817. GetHistory()->KeepNew(pGroup);
  6818. SelectObject(pGroup, scSelect);
  6819. }
  6820. m_pToolManager->SetTool(TOOL_POINTER);
  6821. SetModifiedFlag();
  6822. EndWaitCursor();
  6823. }
  6824. //-----------------------------------------------------------------------------
  6825. // Purpose: Manages the state of the Edit | Paste Special menu item.
  6826. //-----------------------------------------------------------------------------
  6827. void CMapDoc::OnUpdateEditPastespecial(CCmdUI *pCmdUI)
  6828. {
  6829. pCmdUI->Enable((GetHammerClipboard()->Objects.Count() != 0) && !GetMainWnd()->IsShellSessionActive());
  6830. }
  6831. void DumpWorldRecursive( CMapClass *pObj, int nDepth )
  6832. {
  6833. Msg( "%*s\n", 10 + ( 4 * nDepth ), pObj->GetType() );
  6834. const CMapObjectList *children = pObj->GetChildren();
  6835. for ( int i = 0; i < children->Count(); i++ )
  6836. {
  6837. DumpWorldRecursive( (CUtlReference< CMapClass >)children->Element( i ), nDepth + 1 );
  6838. }
  6839. }
  6840. //-----------------------------------------------------------------------------
  6841. // Purpose: Does the undo or redo and restores the selection to the state at
  6842. // which it was marked in the Undo system.
  6843. // Input : nID - ID_EDIT_UNDO or ID_EDIT_REDO.
  6844. // Output : Always returns TRUE.
  6845. //-----------------------------------------------------------------------------
  6846. BOOL CMapDoc::OnUndoRedo(UINT nID)
  6847. {
  6848. //
  6849. // Morph operations are not undo-friendly because they use a non-CMapClass
  6850. // derived object (SSolid) to store intermediate object state.
  6851. //
  6852. if (m_pToolManager->GetActiveToolID() == TOOL_MORPH)
  6853. {
  6854. AfxMessageBox("You must exit morph mode to undo changes you've made.");
  6855. return(TRUE);
  6856. }
  6857. // Do the undo/redo.
  6858. CMapObjectList NewSelection;
  6859. if (nID == ID_EDIT_UNDO)
  6860. {
  6861. m_pUndo->Undo(&NewSelection);
  6862. }
  6863. else
  6864. {
  6865. m_pRedo->Undo(&NewSelection);
  6866. }
  6867. // Change the selection to the objects that the undo system says
  6868. // should be selected now. Don't save changes and create new undo entrys
  6869. SelectObjectList( &NewSelection, scClear|scSelect );
  6870. m_pSelection->RemoveDead();
  6871. CMapClass::UpdateAllDependencies(NULL);
  6872. UpdateAllViews( MAPVIEW_UPDATE_OBJECTS );
  6873. return(TRUE);
  6874. }
  6875. //-----------------------------------------------------------------------------
  6876. // Purpose: Manages the state of the Undo/Redo menu item.
  6877. //-----------------------------------------------------------------------------
  6878. void CMapDoc::OnUpdateUndoRedo(CCmdUI *pCmdUI)
  6879. {
  6880. CHistory *pHistory = (pCmdUI->m_nID == ID_EDIT_UNDO) ? m_pUndo : m_pRedo;
  6881. char *pszAction = (pCmdUI->m_nID == ID_EDIT_UNDO) ? "Undo" : "Redo";
  6882. char *pszHotkey = (pCmdUI->m_nID == ID_EDIT_UNDO) ? "Ctrl+Z" : "Ctrl+Y";
  6883. if (pHistory->IsUndoable())
  6884. {
  6885. pCmdUI->Enable(!GetMainWnd()->IsShellSessionActive());
  6886. CString str;
  6887. str.Format("%s %s\t%s", pszAction, pHistory->GetCurTrackName(), pszHotkey);
  6888. pCmdUI->SetText(str);
  6889. }
  6890. else
  6891. {
  6892. CString str;
  6893. str.Format("Can't %s\t%s", pszAction, pszHotkey);
  6894. pCmdUI->SetText(str);
  6895. pCmdUI->Enable(FALSE);
  6896. }
  6897. }
  6898. //-----------------------------------------------------------------------------
  6899. // Purpose:
  6900. // Input : pObject -
  6901. // pWorld -
  6902. //-----------------------------------------------------------------------------
  6903. bool CMapDoc::ExpandTargetNameKeywords(char *szNewTargetName, const char *szOldTargetName, CMapWorld *pWorld)
  6904. {
  6905. const char *pszKeyword = strstr(szOldTargetName, "&i");
  6906. if (pszKeyword != NULL)
  6907. {
  6908. char szPrefix[100];
  6909. char szSuffix[100];
  6910. strncpy(szPrefix, szOldTargetName, pszKeyword - szOldTargetName);
  6911. szPrefix[pszKeyword - szOldTargetName] = '\0';
  6912. strcpy(szSuffix, pszKeyword + 2);
  6913. int nHighestIndex = 0;
  6914. const CMapEntityList *pEntityList = pWorld->EntityList_GetList();
  6915. FOR_EACH_OBJ( *pEntityList, pos )
  6916. {
  6917. const CMapEntity *pEntity = pEntityList->Element(pos).GetObject();
  6918. const char *pszTargetName = pEntity ? pEntity->GetKeyValue("targetname") : NULL;
  6919. //
  6920. // If this entity has a targetname, check to see if it is of the
  6921. // form <prefix><number><suffix>. If so, it must be counted as
  6922. // we search for the highest instance number.
  6923. //
  6924. if (pszTargetName != NULL)
  6925. {
  6926. char szTemp[MAX_PATH];
  6927. strcpy(szTemp, pszTargetName);
  6928. int nPrefixLen = strlen(szPrefix);
  6929. int nSuffixLen = strlen(szSuffix);
  6930. int nFullLen = strlen(szTemp);
  6931. //
  6932. // It must be longer than the prefix and the suffix combined to be
  6933. // of the form <prefix><number><suffix>.
  6934. //
  6935. if (nFullLen > nPrefixLen + nSuffixLen)
  6936. {
  6937. char *pszTempSuffix = szTemp + nFullLen - nSuffixLen;
  6938. //
  6939. // If the prefix and the suffix match ours, extract the instance number
  6940. // from between them and check it against our highest instance number.
  6941. //
  6942. if ((strnicmp(szTemp, szPrefix, nPrefixLen) == 0) && (stricmp(pszTempSuffix, szSuffix) == 0))
  6943. {
  6944. *pszTempSuffix = '\0';
  6945. bool bAllDigits = true;
  6946. for (int i = 0; i < (int)strlen(&szTemp[nPrefixLen]); i++)
  6947. {
  6948. if (!V_isdigit(szTemp[nPrefixLen + i]))
  6949. {
  6950. bAllDigits = false;
  6951. break;
  6952. }
  6953. }
  6954. if (bAllDigits)
  6955. {
  6956. int nIndex = atoi(&szTemp[nPrefixLen]);
  6957. if (nIndex > nHighestIndex)
  6958. {
  6959. nHighestIndex = nIndex;
  6960. }
  6961. }
  6962. }
  6963. }
  6964. }
  6965. }
  6966. sprintf(szNewTargetName, "%s%d%s", szPrefix, nHighestIndex + 1, szSuffix);
  6967. return(true);
  6968. }
  6969. return(false);
  6970. }
  6971. //-----------------------------------------------------------------------------
  6972. // Purpose: Expands keywords in pObject, if there are any. Returns whether
  6973. // keyword expansion was performed.
  6974. // Input : pObject -
  6975. // pWorld -
  6976. //-----------------------------------------------------------------------------
  6977. bool CMapDoc::DoExpandKeywords(CMapClass *pObject, CMapWorld *pWorld, char *szOldKeyword, char *szNewKeyword)
  6978. {
  6979. CEditGameClass *pEditGameClass = dynamic_cast <CEditGameClass *>(pObject);
  6980. if (pEditGameClass != NULL)
  6981. {
  6982. const char *pszOldTargetName = pEditGameClass->GetKeyValue("targetname");
  6983. if (pszOldTargetName != NULL)
  6984. {
  6985. char szNewTargetName[MAX_PATH];
  6986. if (ExpandTargetNameKeywords(szNewTargetName, pszOldTargetName, pWorld))
  6987. {
  6988. strcpy(szOldKeyword, pszOldTargetName);
  6989. strcpy(szNewKeyword, szNewTargetName);
  6990. pEditGameClass->SetKeyValue("targetname", szNewTargetName);
  6991. return(true);
  6992. }
  6993. }
  6994. }
  6995. return(false);
  6996. }
  6997. //-----------------------------------------------------------------------------
  6998. // Gets this object's name if it has one. Returns false if it has none.
  6999. //-----------------------------------------------------------------------------
  7000. static bool GetName( CMapClass *pObject, char *szName )
  7001. {
  7002. CEditGameClass *pEditGameClass = dynamic_cast <CEditGameClass *>( pObject );
  7003. if ( pEditGameClass == NULL )
  7004. return false;
  7005. const char *pszName = pEditGameClass->GetKeyValue( "targetname" );
  7006. if ( !pszName )
  7007. return false;
  7008. Q_strcpy( szName, pszName );
  7009. return true;
  7010. }
  7011. static const char *CopyName( const char * pszString )
  7012. {
  7013. int length = Q_strlen(pszString)+1;
  7014. char *pNewString = new char[length];
  7015. Q_memcpy( pNewString, pszString, length );
  7016. return pNewString;
  7017. }
  7018. static bool FindName( CUtlVector<const char*>*pList, const char * pszString )
  7019. {
  7020. for ( int i=0; i<pList->Count(); i++ )
  7021. {
  7022. if ( Q_stricmp( pszString, pList->Element(i)) == 0 )
  7023. return true;
  7024. }
  7025. return false;
  7026. }
  7027. //-----------------------------------------------------------------------------
  7028. // Renames all named entities in the tree pointed to by pRoot.
  7029. // pRoot - Points to a tree of objects.
  7030. // pWorld - If making the names unique, the world that they should be unique within.
  7031. // bMakeUnique - Whether to guarantee that the names are unique in the world.
  7032. // If necessary, numbers will be appended to make the names unique.
  7033. // szPrefix - A string to prepend to all named entities in the tree.
  7034. //-----------------------------------------------------------------------------
  7035. void CMapDoc::RenameEntities( CMapClass *pRoot, CMapWorld *pWorld, bool bMakeUnique, const char *szAddPrefix )
  7036. {
  7037. if ( !bMakeUnique && ( !szAddPrefix || ( szAddPrefix[0] == '\0' ) ) )
  7038. return;
  7039. CUtlVector<const char*> oldNames;
  7040. char szName[MAX_PATH];
  7041. pRoot->FindTargetNames( oldNames );
  7042. // find all names we have to replace
  7043. if ( GetName( pRoot, szName ) )
  7044. {
  7045. oldNames.AddToTail( CopyName(szName) );
  7046. }
  7047. // Expand keywords in this object's children as well.
  7048. EnumChildrenPos_t pos;
  7049. CMapClass *pChild = pRoot->GetFirstDescendent( pos );
  7050. while ( pChild != NULL )
  7051. {
  7052. pChild->FindTargetNames( oldNames );
  7053. if ( GetName(pChild, szName ) )
  7054. {
  7055. if ( !FindName( &oldNames, szName) )
  7056. {
  7057. oldNames.AddToTail( CopyName(szName) );
  7058. }
  7059. }
  7060. pChild = pRoot->GetNextDescendent( pos );
  7061. }
  7062. for ( int i=0; i<oldNames.Count(); i++ )
  7063. {
  7064. if ( pWorld->GenerateNewTargetname( oldNames[i], szName, sizeof( szName ), bMakeUnique, szAddPrefix, pRoot ) )
  7065. {
  7066. pRoot->ReplaceTargetname( oldNames[i], szName );
  7067. }
  7068. }
  7069. oldNames.PurgeAndDeleteElements();
  7070. }
  7071. //-----------------------------------------------------------------------------
  7072. // Purpose: Iterates the children of the given object and expands any keywords
  7073. // in the object's properties.
  7074. // Input : pObject -
  7075. // pWorld -
  7076. //-----------------------------------------------------------------------------
  7077. void CMapDoc::ExpandObjectKeywords(CMapClass *pObject, CMapWorld *pWorld)
  7078. {
  7079. char szOldName[MAX_PATH];
  7080. char szNewName[MAX_PATH];
  7081. if (DoExpandKeywords(pObject, pWorld, szOldName, szNewName))
  7082. {
  7083. pObject->ReplaceTargetname(szOldName, szNewName);
  7084. }
  7085. //
  7086. // Expand keywords in this object's children as well.
  7087. //
  7088. EnumChildrenPos_t pos;
  7089. CMapClass *pChild = pObject->GetFirstDescendent(pos);
  7090. while (pChild != NULL)
  7091. {
  7092. if (DoExpandKeywords(pChild, pWorld, szOldName, szNewName))
  7093. {
  7094. pObject->ReplaceTargetname(szOldName, szNewName);
  7095. }
  7096. pChild = pObject->GetNextDescendent(pos);
  7097. }
  7098. }
  7099. //-----------------------------------------------------------------------------
  7100. // Purpose: Selects the next object by depth in the 3D view.
  7101. //-----------------------------------------------------------------------------
  7102. void CMapDoc::OnEditSelnext(void)
  7103. {
  7104. m_pSelection->SetCurrentHit(hitNext);
  7105. }
  7106. //-----------------------------------------------------------------------------
  7107. // Purpose: Selects the previous object by depth in the 3D view.
  7108. //-----------------------------------------------------------------------------
  7109. void CMapDoc::OnEditSelprev(void)
  7110. {
  7111. m_pSelection->SetCurrentHit(hitPrev);
  7112. }
  7113. //-----------------------------------------------------------------------------
  7114. // Purpose: Selects the next object by depth
  7115. //-----------------------------------------------------------------------------
  7116. void CMapDoc::OnEditSelnextCascading(void)
  7117. {
  7118. m_pSelection->SetCurrentHit(hitNext, true );
  7119. }
  7120. //-----------------------------------------------------------------------------
  7121. // Purpose: Selects the previous object by depth
  7122. //-----------------------------------------------------------------------------
  7123. void CMapDoc::OnEditSelprevCascading(void)
  7124. {
  7125. m_pSelection->SetCurrentHit(hitPrev, true );
  7126. }
  7127. //-----------------------------------------------------------------------------
  7128. // Moves selected objects close to each other in logical space
  7129. //-----------------------------------------------------------------------------
  7130. void CMapDoc::OnLogicalMoveBlock(void)
  7131. {
  7132. Vector2D vecLogicalCenter;
  7133. if ( !m_pSelection->GetLogicalBoundsCenter( vecLogicalCenter ) )
  7134. return;
  7135. const CMapObjectList *pSelList = m_pSelection->GetList();
  7136. if ( pSelList->Count() <= 1 )
  7137. return;
  7138. GetHistory()->MarkUndoPosition( pSelList, "Move Block" );
  7139. GetHistory()->Keep( pSelList );
  7140. // Lay out in a squarish region that has the same center as the current one
  7141. int nCount = pSelList->Count();
  7142. int nDim = sqrt( (float)nCount );
  7143. if ( nDim * nDim < nCount )
  7144. {
  7145. ++nDim;
  7146. }
  7147. CMapViewLogical *pCurrentView = NULL;
  7148. if ( GetMainWnd()->GetActiveFrame() )
  7149. {
  7150. pCurrentView = dynamic_cast<CMapViewLogical*>( GetMainWnd()->GetActiveFrame()->GetActiveView() );
  7151. }
  7152. bool bCenterView;
  7153. Vector2D vecPositionCenter;
  7154. if ( pCurrentView )
  7155. {
  7156. Vector vecCenter( COORD_NOTINIT, COORD_NOTINIT, COORD_NOTINIT );
  7157. pCurrentView->GetCenterPoint( vecCenter );
  7158. vecPositionCenter = vecCenter.AsVector2D();
  7159. bCenterView = false;
  7160. }
  7161. else
  7162. {
  7163. vecPositionCenter = vecLogicalCenter;
  7164. bCenterView = true;
  7165. }
  7166. vecPositionCenter.x -= (nDim / 2.0f) * LOGICAL_SPACING;
  7167. vecPositionCenter.y -= (nDim / 2.0f) * LOGICAL_SPACING;
  7168. for ( int i = 0; i < pSelList->Count(); ++i )
  7169. {
  7170. CMapClass *pClass = (CUtlReference< CMapClass >)pSelList->Element( i );
  7171. if ( !pClass->IsLogical() )
  7172. continue;
  7173. int x = i % nDim;
  7174. int y = ( i / nDim );
  7175. Vector2D newLogicalCenter;
  7176. newLogicalCenter.x = vecPositionCenter.x + x * LOGICAL_SPACING;
  7177. newLogicalCenter.y = vecPositionCenter.y + y * LOGICAL_SPACING;
  7178. pClass->SetLogicalPosition( newLogicalCenter );
  7179. }
  7180. UpdateAllViews( MAPVIEW_UPDATE_OBJECTS | MAPVIEW_UPDATE_SELECTION | MAPVIEW_UPDATE_ONLY_LOGICAL );
  7181. m_pSelection->SetBoundsDirty();
  7182. if ( bCenterView )
  7183. {
  7184. CenterLogicalViewsOnSelection();
  7185. }
  7186. }
  7187. //-----------------------------------------------------------------------------
  7188. // Select all entities connected to outputs of all entities in the selection list recursively
  7189. //-----------------------------------------------------------------------------
  7190. void CMapDoc::OnLogicalSelectAllCascading(void)
  7191. {
  7192. if ( m_pSelection->IsEmpty() )
  7193. return;
  7194. const CMapObjectList *pSelList = m_pSelection->GetList();
  7195. GetHistory()->MarkUndoPosition( pSelList, "Select All Cascading" );
  7196. CUtlRBTree< CMapClass*, unsigned short > list( 0, 0, DefLessFunc( CMapClass* ) );
  7197. for ( int i = 0; i < pSelList->Count(); ++i )
  7198. {
  7199. CMapClass *pMapClass = (CUtlReference< CMapClass >)pSelList->Element(i);
  7200. list.InsertIfNotFound( pMapClass );
  7201. BuildCascadingSelectionList( pMapClass, list, true );
  7202. }
  7203. for ( unsigned short h = list.FirstInorder(); h != list.InvalidIndex(); h = list.NextInorder(h) )
  7204. {
  7205. SelectObject( list[h], scSelect );
  7206. }
  7207. }
  7208. //-----------------------------------------------------------------------------
  7209. // Add all entities connected to inputs of all entities in the selection list recursively
  7210. //-----------------------------------------------------------------------------
  7211. void CMapDoc::AddConnectedNodes( CMapClass *pObject, CUtlRBTree< CMapClass*, unsigned short >& visited )
  7212. {
  7213. // Make sure we havent visited this entity before
  7214. if ( visited.Find( pObject ) == visited.InvalidIndex() )
  7215. {
  7216. // Is this node actually a visible entity?
  7217. if ( pObject->IsLogical() && pObject->IsVisibleLogical() )
  7218. {
  7219. // Is this node NOT a group entity
  7220. if ( !pObject->IsGroup() )
  7221. {
  7222. // Mark this entity visited
  7223. visited.Insert( pObject );
  7224. // See if this class has any connections
  7225. CEditGameClass *pClass = dynamic_cast< CEditGameClass * >( pObject );
  7226. if ( pClass )
  7227. {
  7228. // Iterate through each of the upstream connections
  7229. int nCount = pClass->Upstream_GetCount();
  7230. for ( int i = 0; i < nCount; ++i )
  7231. {
  7232. CEntityConnection *pConn = pClass->Upstream_Get( i );
  7233. // Iterate through the source entities on this connection
  7234. FOR_EACH_OBJ( *pConn->GetSourceEntityList(), pos )
  7235. {
  7236. CMapEntity *pEntity = pConn->GetSourceEntityList()->Element( pos );
  7237. // Don't bother recursing back into this current node
  7238. if ( pEntity != pObject )
  7239. {
  7240. // Recurse to the adjacent source entity
  7241. AddConnectedNodes( pEntity, visited );
  7242. }
  7243. }
  7244. }
  7245. // Iterate through each of the downstream connections
  7246. nCount = pClass->Connections_GetCount();
  7247. for ( int i = 0; i < nCount; ++i )
  7248. {
  7249. CEntityConnection *pConn = pClass->Connections_Get( i );
  7250. // Iterate through the target entities on this connection
  7251. FOR_EACH_OBJ( *pConn->GetTargetEntityList(), pos )
  7252. {
  7253. CMapEntity *pEntity = pConn->GetTargetEntityList()->Element( pos );
  7254. // If you hit this assert it means that an entity was deleted but not removed
  7255. // from this entity's list of targets.
  7256. ASSERT( pEntity != NULL );
  7257. // Don't bother recursing back into this current node
  7258. if ( pEntity && ( pEntity != pObject ) )
  7259. {
  7260. // Recurse to the adjacent target entity
  7261. AddConnectedNodes( pEntity, visited );
  7262. }
  7263. }
  7264. }
  7265. }
  7266. }
  7267. // Recurse into any children and add them as well
  7268. const CMapObjectList *pChildren = pObject->GetChildren();
  7269. FOR_EACH_OBJ( *pChildren, pos )
  7270. {
  7271. AddConnectedNodes( (CUtlReference< CMapClass >)pChildren->Element(pos), visited );
  7272. }
  7273. }
  7274. }
  7275. }
  7276. //-----------------------------------------------------------------------------
  7277. // Select all entities connected to outputs of all entities in the selection list recursively
  7278. //-----------------------------------------------------------------------------
  7279. void CMapDoc::OnLogicalSelectAllConnected(void)
  7280. {
  7281. const CMapObjectList *pSelList = m_pSelection->GetList();
  7282. int nSelected = pSelList->Count();
  7283. if ( nSelected )
  7284. {
  7285. GetHistory()->MarkUndoPosition( pSelList, "Select All Connected" );
  7286. CUtlRBTree< CMapClass*, unsigned short > visited( 0, 0, DefLessFunc( CMapClass* ) );
  7287. for ( int i = 0; i < nSelected; ++i )
  7288. {
  7289. CMapClass *pMapClass = (CUtlReference< CMapClass >)pSelList->Element(i);
  7290. AddConnectedNodes( pMapClass, visited );
  7291. }
  7292. for ( unsigned short h = visited.FirstInorder(); h != visited.InvalidIndex(); h = visited.NextInorder(h) )
  7293. {
  7294. SelectObject( visited[h], scSelect );
  7295. }
  7296. }
  7297. }
  7298. //-----------------------------------------------------------------------------
  7299. // Purpose: Adds all selected or deselected objects to a new VisGroup and hides
  7300. // the group.
  7301. //-----------------------------------------------------------------------------
  7302. BOOL CMapDoc::OnViewHideObjects(UINT nID)
  7303. {
  7304. bool bSelected = (nID == ID_VIEW_HIDESELECTEDOBJECTS);
  7305. if ( m_pSelection->IsEmpty() )
  7306. {
  7307. return TRUE;
  7308. }
  7309. //
  7310. // Build a list of eligible selected objects.
  7311. //
  7312. CMapObjectList Objects;
  7313. GetChildrenToHide(m_pWorld, bSelected, Objects);
  7314. int nOriginalCount = Objects.Count();
  7315. for (int pos = Objects.Count()-1; pos>=0; pos --)
  7316. {
  7317. CMapClass *pObject = Objects.Element(pos);
  7318. if (!VisGroups_ObjectCanBelongToVisGroup(pObject))
  7319. {
  7320. Objects.FastRemove(pos);
  7321. }
  7322. }
  7323. int nFinalCount = Objects.Count();
  7324. //
  7325. // If no eligible selected objects were found, exit.
  7326. //
  7327. if (!nFinalCount)
  7328. {
  7329. CString str;
  7330. str.Format("There are no eligible %sselected objects. The only objects\n"
  7331. "that can be put in a Visible Group are objects that are not\n"
  7332. "part of an entity.", bSelected ? "" : "un");
  7333. AfxMessageBox(str);
  7334. return TRUE;
  7335. }
  7336. else if (nFinalCount < nOriginalCount)
  7337. {
  7338. AfxMessageBox("Some objects could not put in the new Visible Group because\n"
  7339. "they are part of an entity.");
  7340. }
  7341. ShowNewVisGroupsDialog(Objects, bSelected);
  7342. return TRUE;
  7343. }
  7344. //-----------------------------------------------------------------------------
  7345. // Purpose: Fills out a list with all the children of this object that:
  7346. //
  7347. // A) Are visible
  7348. // B) Match the bSelected criteria
  7349. // C) Whose children all match the bSelected criteria
  7350. // D) Have no hidden children
  7351. //
  7352. // Output : Returns true if all top-level children satisfied the above criteria, false if not.
  7353. //-----------------------------------------------------------------------------
  7354. bool CMapDoc::GetChildrenToHide(CMapClass *pObject, bool bSelected, CMapObjectList &List)
  7355. {
  7356. int nAddedCount = 0;
  7357. const CMapObjectList *pChildren = pObject->GetChildren();
  7358. FOR_EACH_OBJ( *pChildren, pos )
  7359. {
  7360. CMapClass *pChild = (CUtlReference< CMapClass >)pChildren->Element(pos);
  7361. CMapGroup *pGroup = dynamic_cast<CMapGroup *>(pChild);
  7362. CMapSolid *pSolid = dynamic_cast<CMapSolid *>(pChild);
  7363. CMapEntity *pEntity = dynamic_cast<CMapEntity *>(pChild);
  7364. if (pGroup || pSolid || pEntity)
  7365. {
  7366. if (pChild->IsVisible())
  7367. {
  7368. CMapEntity *pEntity = dynamic_cast<CMapEntity *>(pChild);
  7369. if (pGroup || (pEntity && pEntity->IsSolidClass()))
  7370. {
  7371. // This child is a group or a solid entity -- check all its children.
  7372. CMapObjectList ChildList;
  7373. if (GetChildrenToHide(pChild, bSelected, ChildList))
  7374. {
  7375. // All this child's children match the criteria, so add the child to the list.
  7376. List.AddToTail(pChild);
  7377. nAddedCount++;
  7378. }
  7379. else if (ChildList.Count())
  7380. {
  7381. // Some of this child's children satisfy the criteria, or have descendents that do.
  7382. // Add the children to the list.
  7383. List.AddVectorToTail(ChildList);
  7384. }
  7385. else
  7386. {
  7387. // None of this child's children satisfy the criteria, so skip this child.
  7388. }
  7389. }
  7390. else if (bSelected == pChild->IsSelected())
  7391. {
  7392. // Unselected point entity or solid, add it to the list.
  7393. List.AddToTail(pChild);
  7394. nAddedCount++;
  7395. }
  7396. }
  7397. }
  7398. else
  7399. {
  7400. // Don't add helpers, but count them anyway.
  7401. nAddedCount++;
  7402. }
  7403. }
  7404. return nAddedCount == pObject->GetChildCount();
  7405. }
  7406. //-----------------------------------------------------------------------------
  7407. // Purpose: Reflects the current handle mode of the selection tool.
  7408. //-----------------------------------------------------------------------------
  7409. void CMapDoc::OnUpdateViewShowHelpers(CCmdUI *pCmdUI)
  7410. {
  7411. // if (pCmdUI->m_nID == ID_VIEW_SELECTION_ONLY)
  7412. // {
  7413. // pCmdUI->SetCheck(m_pToolSelection->GetHandleMode() == HandleMode_SelectionOnly);
  7414. // }
  7415. // else if (pCmdUI->m_nID == ID_VIEW_HELPERS_ONLY)
  7416. // {
  7417. pCmdUI->SetCheck( Options.GetShowHelpers() );
  7418. // }
  7419. // else if (pCmdUI->m_nID == ID_VIEW_SELECTION_AND_HELPERS)
  7420. // {
  7421. // pCmdUI->SetCheck(m_pToolSelection->GetHandleMode() == HandleMode_Both);
  7422. // }
  7423. pCmdUI->Enable(!GetMainWnd()->IsShellSessionActive());
  7424. }
  7425. //-----------------------------------------------------------------------------
  7426. // Purpose: Reflects the current 2D model drawing
  7427. //-----------------------------------------------------------------------------
  7428. void CMapDoc::OnUpdateViewShowModelsIn2D(CCmdUI *pCmdUI)
  7429. {
  7430. pCmdUI->SetCheck( Options.view2d.bDrawModels?1:0 );
  7431. pCmdUI->Enable(!GetMainWnd()->IsShellSessionActive());
  7432. }
  7433. void CMapDoc::OnViewShowModelsIn2D(void)
  7434. {
  7435. Options.view2d.bDrawModels = !Options.view2d.bDrawModels;
  7436. UpdateVisibilityAll();
  7437. }
  7438. void CMapDoc::OnViewShowHelpers(void)
  7439. {
  7440. // FIXME: this only sets the handle mode for the active document's selection tool!
  7441. Options.SetShowHelpers(!Options.GetShowHelpers());
  7442. UpdateVisibilityAll();
  7443. UpdateAllViews( MAPVIEW_UPDATE_OBJECTS );
  7444. }
  7445. //-----------------------------------------------------------------------------
  7446. // Purpose: Manages the state of 3D model fade preview.
  7447. //-----------------------------------------------------------------------------
  7448. void CMapDoc::OnUpdateViewPreviewModelFade(CCmdUI *pCmdUI)
  7449. {
  7450. pCmdUI->SetCheck( Options.view3d.bPreviewModelFade ? 1 : 0 );
  7451. pCmdUI->Enable(!GetMainWnd()->IsShellSessionActive());
  7452. }
  7453. //-----------------------------------------------------------------------------
  7454. // Purpose:
  7455. //-----------------------------------------------------------------------------
  7456. void CMapDoc::OnViewPreviewModelFade(void)
  7457. {
  7458. Options.view3d.bPreviewModelFade = !Options.view3d.bPreviewModelFade;
  7459. // Bring up the Low, Med, High modes.
  7460. if ( Options.view3d.bPreviewModelFade )
  7461. {
  7462. CMainFrame *pMainFrame = GetMainWnd();
  7463. if( pMainFrame )
  7464. {
  7465. CFadeDlg dlg( &pMainFrame->m_wndMapOps );
  7466. dlg.DoModal();
  7467. }
  7468. }
  7469. UpdateAllViews( MAPVIEW_UPDATE_ONLY_3D );
  7470. }
  7471. //-----------------------------------------------------------------------------
  7472. // Purpose: Toggles the state of the grid nav preview.
  7473. //-----------------------------------------------------------------------------
  7474. void CMapDoc::OnViewPreviewGridNav(void)
  7475. {
  7476. if ( !m_pGridNav || !m_pGridNav->IsEnabled() )
  7477. return;
  7478. m_pGridNav->TogglePreview();
  7479. UpdateVisibilityAll();
  7480. }
  7481. //-----------------------------------------------------------------------------
  7482. // Purpose: Manages the state of the View | Preview Grid Nav menu item.
  7483. //-----------------------------------------------------------------------------
  7484. void CMapDoc::OnUpdateViewPreviewGridNav(CCmdUI *pCmdUI)
  7485. {
  7486. if ( !m_pGridNav || !m_pGridNav->IsEnabled() )
  7487. {
  7488. pCmdUI->Enable( false );
  7489. return;
  7490. }
  7491. pCmdUI->Enable( !GetMainWnd()->IsShellSessionActive() );
  7492. pCmdUI->SetCheck(m_pGridNav->IsPreviewActive() ? TRUE : FALSE);
  7493. }
  7494. //-----------------------------------------------------------------------------
  7495. // Purpose: Manages the state of 3D model fade preview.
  7496. //-----------------------------------------------------------------------------
  7497. void CMapDoc::OnUpdateCollisionWireframe(CCmdUI *pCmdUI)
  7498. {
  7499. pCmdUI->SetCheck( Options.general.bShowCollisionModels ? 1 : 0 );
  7500. pCmdUI->Enable(!GetMainWnd()->IsShellSessionActive());
  7501. }
  7502. void CMapDoc::OnCollisionWireframe(void)
  7503. {
  7504. Options.general.bShowCollisionModels = !Options.general.bShowCollisionModels;
  7505. UpdateAllViews( MAPVIEW_UPDATE_TOOL );
  7506. }
  7507. //-----------------------------------------------------------------------------
  7508. // Purpose: Manages the state of 3D model fade preview.
  7509. //-----------------------------------------------------------------------------
  7510. void CMapDoc::OnUpdateShowDetailObjects(CCmdUI *pCmdUI)
  7511. {
  7512. pCmdUI->SetCheck( Options.general.bShowDetailObjects ? 1 : 0 );
  7513. pCmdUI->Enable(!GetMainWnd()->IsShellSessionActive());
  7514. }
  7515. void CMapDoc::OnShowDetailObjects(void)
  7516. {
  7517. Options.general.bShowDetailObjects = !Options.general.bShowDetailObjects;
  7518. UpdateAllViews( MAPVIEW_UPDATE_TOOL );
  7519. }
  7520. void CMapDoc::OnShowNoDrawBrushes(void)
  7521. {
  7522. Options.general.bShowNoDrawBrushes = !Options.general.bShowNoDrawBrushes;
  7523. UpdateAllViews( MAPVIEW_UPDATE_TOOL );
  7524. }
  7525. void CMapDoc::OnUpdateShowNoDrawBrushes(CCmdUI *pCmdUI)
  7526. {
  7527. pCmdUI->SetCheck( Options.general.bShowNoDrawBrushes ? 1 : 0 );
  7528. pCmdUI->Enable(!GetMainWnd()->IsShellSessionActive());
  7529. }
  7530. //-----------------------------------------------------------------------------
  7531. // Purpose: Manages the state of the View | Hide Unselected menu item and toolbar button.
  7532. //-----------------------------------------------------------------------------
  7533. void CMapDoc::OnUpdateViewHideUnselectedObjects(CCmdUI *pCmdUI)
  7534. {
  7535. pCmdUI->Enable(!GetMainWnd()->IsShellSessionActive());
  7536. }
  7537. //-----------------------------------------------------------------------------
  7538. // Purpose:
  7539. //-----------------------------------------------------------------------------
  7540. void CMapDoc::OnMapCheck(void)
  7541. {
  7542. CMapCheckDlg::CheckForProblems(GetMainWnd());
  7543. }
  7544. void CMapDoc::OnMapDiff(void)
  7545. {
  7546. CMapDiffDlg::MapDiff(GetMainWnd(), this);
  7547. }
  7548. //-----------------------------------------------------------------------------
  7549. // Purpose:
  7550. //-----------------------------------------------------------------------------
  7551. void CMapDoc::OnViewDotACamera(void)
  7552. {
  7553. bool bShow = CMapEntity::GetShowDotACamera();
  7554. CMapEntity::ShowDotACamera(!bShow);
  7555. UpdateAllViews( MAPVIEW_UPDATE_ONLY_3D | MAPVIEW_OPTIONS_CHANGED );
  7556. }
  7557. //-----------------------------------------------------------------------------
  7558. // Purpose:
  7559. //-----------------------------------------------------------------------------
  7560. void CMapDoc::OnViewShowconnections(void)
  7561. {
  7562. bool bShow = CMapEntity::GetShowEntityConnections();
  7563. CMapEntity::ShowEntityConnections(!bShow);
  7564. UpdateAllViews( MAPVIEW_UPDATE_ONLY_2D );
  7565. }
  7566. //-----------------------------------------------------------------------------
  7567. // Purpose: Puts one of every point entity in the current FGD set in the current
  7568. // map on a 128 grid.
  7569. //-----------------------------------------------------------------------------
  7570. void CMapDoc::OnMapEntityGallery(void)
  7571. {
  7572. 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)
  7573. {
  7574. int x = -1024;
  7575. int y = -1024;
  7576. CString str;
  7577. int nCount = pGD->GetClassCount();
  7578. for (int i = 0; i < nCount; i++)
  7579. {
  7580. GDclass *pc = pGD->GetClass(i);
  7581. if (!pc->IsBaseClass())
  7582. {
  7583. if (!pc->IsSolidClass())
  7584. {
  7585. if (!pc->IsClass("worldspawn"))
  7586. {
  7587. CreateEntity(pc->GetName(), x, y, 0);
  7588. x += 128;
  7589. if (x > 1024)
  7590. {
  7591. x = -1024;
  7592. y += 128;
  7593. }
  7594. }
  7595. }
  7596. }
  7597. }
  7598. }
  7599. }
  7600. //-----------------------------------------------------------------------------
  7601. // Purpose:
  7602. //-----------------------------------------------------------------------------
  7603. void CMapDoc::OnUpdateViewDotACamera(CCmdUI *pCmdUI)
  7604. {
  7605. pCmdUI->SetCheck(CMapEntity::GetShowDotACamera());
  7606. }
  7607. //-----------------------------------------------------------------------------
  7608. // Purpose:
  7609. //-----------------------------------------------------------------------------
  7610. void CMapDoc::OnUpdateViewShowconnections(CCmdUI *pCmdUI)
  7611. {
  7612. pCmdUI->SetCheck(CMapEntity::GetShowEntityConnections());
  7613. }
  7614. //-----------------------------------------------------------------------------
  7615. // Purpose:
  7616. // Input : *pszFileName -
  7617. // nSize -
  7618. //-----------------------------------------------------------------------------
  7619. bool GetSaveAsFilename(const char *pszBaseDir, char *pszFileName, int nSize)
  7620. {
  7621. CString str;
  7622. CFileDialog dlg(FALSE, NULL, str, OFN_LONGNAMES | OFN_NOCHANGEDIR | OFN_HIDEREADONLY, "Valve Map Files (*.vmf)|*.vmf||");
  7623. dlg.m_ofn.lpstrInitialDir = pszBaseDir;
  7624. int nRet = dlg.DoModal();
  7625. if (nRet != IDCANCEL)
  7626. {
  7627. str = dlg.GetPathName();
  7628. if (str.Find('.') == -1)
  7629. {
  7630. str += ".vmf";
  7631. }
  7632. lstrcpyn(pszFileName, str, nSize);
  7633. return(true);
  7634. }
  7635. return(false);
  7636. }
  7637. //-----------------------------------------------------------------------------
  7638. // Purpose: Takes the current selection and saves it as a prefab. The user is
  7639. // prompted for a folder under the prefabs folder in which to place
  7640. // the prefab.
  7641. //-----------------------------------------------------------------------------
  7642. void CMapDoc::OnToolsCreateprefab(void)
  7643. {
  7644. if ( m_pSelection->IsEmpty() )
  7645. {
  7646. AfxMessageBox("This feature creates a prefab with the selected objects. You must select some objects before you can use it.", MB_ICONINFORMATION | MB_OK);
  7647. return;
  7648. }
  7649. //
  7650. // Get a file to save the prefab into. The first time through the default folder
  7651. // is the prefabs folder.
  7652. //
  7653. static char szBaseDir[MAX_PATH] = "";
  7654. if (szBaseDir[0] == '\0')
  7655. {
  7656. APP()->GetDirectory(DIR_PREFABS, szBaseDir);
  7657. }
  7658. char szFilename[MAX_PATH];
  7659. if (!GetSaveAsFilename(szBaseDir, szFilename, sizeof(szFilename)))
  7660. {
  7661. return;
  7662. }
  7663. //
  7664. // Save the default folder for next time.
  7665. //
  7666. strcpy(szBaseDir, szFilename);
  7667. char *pch = strrchr(szBaseDir, '\\');
  7668. if (pch != NULL)
  7669. {
  7670. *pch = '\0';
  7671. }
  7672. //
  7673. // Create a prefab world to contain the selected items. Add the selected
  7674. // items to the new world.
  7675. //
  7676. CMapWorld *pNewWorld = new CMapWorld( NULL );
  7677. pNewWorld->SetTemporary(TRUE);
  7678. const CMapObjectList *pSelList = m_pSelection->GetList();
  7679. for (int i = 0; i < pSelList->Count(); i++)
  7680. {
  7681. CMapClass *pObject = (CUtlReference< CMapClass >)pSelList->Element(i);
  7682. CMapClass *pNew = pObject->Copy(false);
  7683. // HACK: prune the object from the tree without doing any notification
  7684. // this prevents CopyChildrenFrom from updating the current world's culling tree
  7685. pNew->SetParent(NULL);
  7686. pNew->CopyChildrenFrom(pObject, false);
  7687. pNewWorld->AddObjectToWorld(pNew);
  7688. }
  7689. pNewWorld->CalcBounds(TRUE);
  7690. //
  7691. // Create a prefab object and attach the world to it.
  7692. //
  7693. CPrefabVMF *pPrefab = new CPrefabVMF;
  7694. pPrefab->SetWorld(pNewWorld);
  7695. pPrefab->SetFilename(szFilename);
  7696. //
  7697. // Save the world to the chosen filename.
  7698. //
  7699. CChunkFile File;
  7700. ChunkFileResult_t eResult = File.Open(szFilename, ChunkFile_Write);
  7701. if (eResult == ChunkFile_Ok)
  7702. {
  7703. CSaveInfo SaveInfo;
  7704. SaveInfo.SetVisiblesOnly(false);
  7705. //
  7706. // Write the map file version.
  7707. //
  7708. if (eResult == ChunkFile_Ok)
  7709. {
  7710. // HACK: make sure we save it as a prefab, not as a normal map
  7711. bool bPrefab = m_bPrefab;
  7712. m_bPrefab = true;
  7713. eResult = SaveVersionInfoVMF(&File);
  7714. m_bPrefab = bPrefab;
  7715. }
  7716. //
  7717. // Save the world.
  7718. //
  7719. if (eResult == ChunkFile_Ok)
  7720. {
  7721. eResult = pNewWorld->SaveVMF(&File, &SaveInfo, false);
  7722. }
  7723. }
  7724. //
  7725. // Try to locate the prefab library that corresponds to the folder where
  7726. // we saved the prefab. If it doesn't exist, try refreshing the prefab library
  7727. // list. Maybe the user just created the folder during this save.
  7728. //
  7729. CPrefabLibrary *pLibrary = CPrefabLibrary::FindOpenLibrary(szBaseDir);
  7730. if (pLibrary == NULL)
  7731. {
  7732. delete pPrefab;
  7733. //
  7734. // This will take care of finding the prefab and adding it to the list.
  7735. //
  7736. CPrefabLibrary::LoadAllLibraries();
  7737. }
  7738. else
  7739. {
  7740. pLibrary->Add(pPrefab);
  7741. }
  7742. //
  7743. // Update the object bar so the new prefab shows up.
  7744. //
  7745. GetMainWnd()->m_ObjectBar.UpdateListForTool(m_pToolManager->GetActiveToolID());
  7746. }
  7747. //-----------------------------------------------------------------------------
  7748. // Purpose:
  7749. //-----------------------------------------------------------------------------
  7750. void CMapDoc::OnInsertprefabOriginal(void)
  7751. {
  7752. int iCurTool = m_pToolManager->GetActiveToolID();
  7753. if ((iCurTool != TOOL_POINTER) && (iCurTool != TOOL_BLOCK) && (iCurTool != TOOL_ENTITY))
  7754. {
  7755. return;
  7756. }
  7757. BoundBox box;
  7758. if (GetMainWnd()->m_ObjectBar.GetPrefabBounds(&box) == FALSE)
  7759. {
  7760. return; // not a prefab listing
  7761. }
  7762. Vector pt( COORD_NOTINIT, COORD_NOTINIT, COORD_NOTINIT );
  7763. if (iCurTool != TOOL_ENTITY)
  7764. {
  7765. GetBestVisiblePoint(pt);
  7766. }
  7767. else
  7768. {
  7769. CToolEntity *pTool = dynamic_cast<CToolEntity*>(m_pToolManager->GetActiveTool() );
  7770. pTool->GetPos(pt);
  7771. }
  7772. Vector ptCenter;
  7773. box.GetBoundsCenter(ptCenter);
  7774. for(int i = 0; i < 3; i++)
  7775. {
  7776. box.bmins[i] += pt[i] - ptCenter[i];
  7777. box.bmaxs[i] += pt[i] - ptCenter[i];
  7778. }
  7779. // create object
  7780. box.SnapToGrid(m_nGridSpacing); // snap to grid first
  7781. CMapClass *pObject = GetMainWnd()->m_ObjectBar.CreateInBox(&box);
  7782. if (pObject == NULL)
  7783. {
  7784. return;
  7785. }
  7786. ExpandObjectKeywords(pObject, m_pWorld);
  7787. GetHistory()->MarkUndoPosition(NULL, "Insert Prefab");
  7788. AddObjectToWorld(pObject);
  7789. GetHistory()->KeepNew(pObject);
  7790. SelectObject(pObject, scClear|scSelect|scSaveChanges );
  7791. // set modified
  7792. SetModifiedFlag();
  7793. }
  7794. //-----------------------------------------------------------------------------
  7795. // Purpose: Find a substring within a string:
  7796. // Input : *pszSub -
  7797. // *pszMain -
  7798. // Output : static char *
  7799. //-----------------------------------------------------------------------------
  7800. static char * FindInString(char *pszSub, char *pszMain)
  7801. {
  7802. char *p = pszMain;
  7803. int nSub = strlen(pszSub);
  7804. char ch1 = toupper(pszSub[0]);
  7805. while(p[0])
  7806. {
  7807. if(ch1 == toupper(p[0]))
  7808. {
  7809. if(!strnicmp(pszSub, p, nSub))
  7810. return p;
  7811. }
  7812. ++p;
  7813. }
  7814. return NULL;
  7815. }
  7816. //-----------------------------------------------------------------------------
  7817. // Purpose:
  7818. // Input : *pSolid -
  7819. // *pInfo -
  7820. // Output : static BOOL
  7821. //-----------------------------------------------------------------------------
  7822. static BOOL ReplaceTexFunc(CMapSolid *pSolid, ReplaceTexInfo_t *pInfo)
  7823. {
  7824. // make sure it's visible
  7825. if (!pInfo->bHidden && !pSolid->IsVisible())
  7826. {
  7827. return TRUE;
  7828. }
  7829. int nFaces = pSolid->GetFaceCount();
  7830. char *p;
  7831. BOOL bSaved = FALSE;
  7832. BOOL bMarkOnly = pInfo->bMarkOnly;
  7833. for(int i = 0; i < nFaces; i++)
  7834. {
  7835. CMapFace *pFace = pSolid->GetFace(i);
  7836. char *pszFaceTex = pFace->texture.texture;
  7837. BOOL bDoMarkSolid = FALSE;
  7838. switch(pInfo->iAction)
  7839. {
  7840. case 0: // replace exact matches only:
  7841. {
  7842. if(!strcmpi(pszFaceTex, pInfo->szFind))
  7843. {
  7844. if(bMarkOnly)
  7845. {
  7846. bDoMarkSolid = TRUE;
  7847. break;
  7848. }
  7849. if(!bSaved)
  7850. {
  7851. bSaved = TRUE;
  7852. GetHistory()->Keep(pSolid);
  7853. }
  7854. pFace->SetTexture(pInfo->szReplace, pInfo->m_bRescaleTextureCoordinates);
  7855. ++pInfo->nReplaced;
  7856. }
  7857. break;
  7858. }
  7859. case 1: // find partials, replace entire string:
  7860. {
  7861. p = FindInString(pInfo->szFind, pszFaceTex);
  7862. if(p)
  7863. {
  7864. if(bMarkOnly)
  7865. {
  7866. bDoMarkSolid = TRUE;
  7867. break;
  7868. }
  7869. if(!bSaved)
  7870. {
  7871. bSaved = TRUE;
  7872. GetHistory()->Keep(pSolid);
  7873. }
  7874. pFace->SetTexture(pInfo->szReplace, pInfo->m_bRescaleTextureCoordinates);
  7875. ++pInfo->nReplaced;
  7876. }
  7877. break;
  7878. }
  7879. case 2: // find partials, substitute replacement:
  7880. {
  7881. p = FindInString(pInfo->szFind, pszFaceTex);
  7882. if(p)
  7883. {
  7884. if(bMarkOnly)
  7885. {
  7886. bDoMarkSolid = TRUE;
  7887. break;
  7888. }
  7889. if(!bSaved)
  7890. {
  7891. bSaved = TRUE;
  7892. GetHistory()->Keep(pSolid);
  7893. }
  7894. // create a new string
  7895. char szNewTex[128];
  7896. strcpy(szNewTex, pszFaceTex);
  7897. strcpy(szNewTex + int(p - pszFaceTex), pInfo->szReplace);
  7898. strcat(szNewTex, pszFaceTex + int(p - pszFaceTex) + pInfo->iFindLen);
  7899. pFace->SetTexture(szNewTex, pInfo->m_bRescaleTextureCoordinates);
  7900. ++pInfo->nReplaced;
  7901. }
  7902. break;
  7903. }
  7904. }
  7905. if (bDoMarkSolid)
  7906. {
  7907. if( pInfo->pDoc->GetTools()->GetActiveToolID() == TOOL_FACEEDIT_MATERIAL )
  7908. {
  7909. pInfo->pDoc->SelectFace(pSolid, i, scSelect);
  7910. pInfo->nReplaced++;
  7911. }
  7912. else
  7913. {
  7914. if (!pSolid->IsSelected())
  7915. {
  7916. pInfo->pDoc->SelectObject(pSolid, scSelect);
  7917. pInfo->nReplaced++;
  7918. }
  7919. }
  7920. }
  7921. }
  7922. return(TRUE);
  7923. }
  7924. //-----------------------------------------------------------------------------
  7925. // Purpose:
  7926. // Input : pszFind -
  7927. // pszReplace -
  7928. // bEverything -
  7929. // iAction -
  7930. // bHidden -
  7931. //-----------------------------------------------------------------------------
  7932. void CMapDoc::ReplaceTextures(LPCTSTR pszFind, LPCTSTR pszReplace, BOOL bEverything, int iAction, BOOL bHidden, bool bRescaleTextureCoordinates)
  7933. {
  7934. CFaceEditSheet *pSheet = GetMainWnd()->m_pFaceEditSheet;
  7935. HCURSOR hCursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
  7936. pSheet->EnableUpdate(false);
  7937. // set up info struct to pass to callback
  7938. ReplaceTexInfo_t info;
  7939. strcpy(info.szFind, pszFind);
  7940. strcpy(info.szReplace, pszReplace);
  7941. info.pDoc = this;
  7942. info.bHidden = bHidden;
  7943. if (iAction & 0x100)
  7944. {
  7945. iAction &= ~0x100;
  7946. info.bMarkOnly = TRUE;
  7947. info.bHidden = FALSE; // do not mark hidden objects
  7948. }
  7949. else
  7950. {
  7951. info.bMarkOnly = FALSE;
  7952. }
  7953. info.iAction = iAction;
  7954. info.nReplaced = 0;
  7955. info.iFindLen = strlen(pszFind);
  7956. info.pWorld = m_pWorld;
  7957. info.m_bRescaleTextureCoordinates = bRescaleTextureCoordinates;
  7958. if (bEverything)
  7959. {
  7960. // Mark/Replace textures in entire map.
  7961. if (info.bMarkOnly)
  7962. {
  7963. // About to mark solids, set solids mode and clear the selection.
  7964. m_pSelection->SetMode(selectSolids);
  7965. SelectObject(NULL, scClear);
  7966. }
  7967. m_pWorld->EnumChildren((ENUMMAPCHILDRENPROC)ReplaceTexFunc, (DWORD)&info, MAPCLASS_TYPE(CMapSolid));
  7968. }
  7969. else
  7970. {
  7971. // Mark/Replace textures in the selection only.
  7972. // Copy the selection into another list since we might be changing the selection
  7973. // during this process.
  7974. CMapObjectList tempSelection;
  7975. tempSelection.AddVectorToTail( *m_pSelection->GetList() );
  7976. if (info.bMarkOnly)
  7977. {
  7978. // About to mark solids, set solids mode and clear the selection.
  7979. m_pSelection->SetMode(selectSolids);
  7980. SelectObject(NULL, scClear);
  7981. }
  7982. FOR_EACH_OBJ( tempSelection, pos )
  7983. {
  7984. CMapClass *pobj = tempSelection.Element(pos);
  7985. //
  7986. // Call the texture replacement callback for this object (if it is a solid) and
  7987. // all of its children (no matter what).
  7988. //
  7989. if (pobj->IsMapClass(MAPCLASS_TYPE(CMapSolid)))
  7990. {
  7991. ReplaceTexFunc((CMapSolid *)pobj, &info);
  7992. }
  7993. pobj->EnumChildren((ENUMMAPCHILDRENPROC)ReplaceTexFunc, (DWORD)&info, MAPCLASS_TYPE(CMapSolid));
  7994. }
  7995. }
  7996. CString str;
  7997. if (!info.bMarkOnly)
  7998. {
  7999. str.Format("%d textures replaced.", info.nReplaced);
  8000. if (info.nReplaced > 0)
  8001. {
  8002. SetModifiedFlag();
  8003. }
  8004. }
  8005. else
  8006. {
  8007. str.Format("%d %s marked.", info.nReplaced, (m_pToolManager->GetActiveToolID() == TOOL_FACEEDIT_MATERIAL) ? "faces" : "solids");
  8008. }
  8009. pSheet->EnableUpdate(true);
  8010. SetCursor(hCursorOld);
  8011. AfxMessageBox(str);
  8012. }
  8013. //-----------------------------------------------------------------------------
  8014. // Purpose:
  8015. // Input : pObject -
  8016. // pInfo - Pointer to the structure with info about how to do the find/replace.
  8017. // Output :
  8018. //-----------------------------------------------------------------------------
  8019. static BOOL BatchReplaceTextureCallback( CMapClass *pObject, BatchReplaceTextures_t *pInfo )
  8020. {
  8021. CMapSolid *solid;
  8022. int numFaces, i;
  8023. CMapFace *face;
  8024. char szCurrentTexture[MAX_PATH];
  8025. solid = ( CMapSolid * )pObject;
  8026. numFaces = solid->GetFaceCount();
  8027. for( i = 0; i < numFaces; i++ )
  8028. {
  8029. face = solid->GetFace( i );
  8030. face->GetTextureName( szCurrentTexture );
  8031. if( stricmp( szCurrentTexture, pInfo->szFindTexName ) == 0 )
  8032. {
  8033. face->SetTexture( pInfo->szReplaceTexName );
  8034. }
  8035. }
  8036. return TRUE; // return TRUE to continue enumerating, FALSE to stop.
  8037. }
  8038. //-----------------------------------------------------------------------------
  8039. // Purpose:
  8040. // Input : *fp -
  8041. //-----------------------------------------------------------------------------
  8042. void CMapDoc::BatchReplaceTextures( FileHandle_t fp )
  8043. {
  8044. char *scan, *keyStart, *valStart;
  8045. char buf[MAX_REPLACE_LINE_LENGTH];
  8046. BatchReplaceTextures_t Info;
  8047. while( g_pFullFileSystem->ReadLine( buf, sizeof( buf ), fp ) )
  8048. {
  8049. scan = buf;
  8050. // skip whitespace.
  8051. while( *scan == ' ' || *scan == '\t' )
  8052. {
  8053. scan++;
  8054. }
  8055. // get the key.
  8056. keyStart = scan;
  8057. while( *scan != ' ' && *scan != '\t' )
  8058. {
  8059. if( *scan == '\0' || *scan == '\n' )
  8060. {
  8061. goto next_line;
  8062. }
  8063. scan++;
  8064. }
  8065. memcpy( Info.szFindTexName, keyStart, scan - keyStart );
  8066. Info.szFindTexName[scan - keyStart] = '\0';
  8067. // skip whitespace.
  8068. while( *scan == ' ' || *scan == '\t' )
  8069. {
  8070. scan++;
  8071. }
  8072. // get the value
  8073. valStart = scan;
  8074. while( *scan != ' ' && *scan != '\t' && *scan != '\0' && *scan != '\n' )
  8075. {
  8076. scan++;
  8077. }
  8078. memcpy( Info.szReplaceTexName, valStart, scan - valStart );
  8079. Info.szReplaceTexName[scan - valStart] = '\0';
  8080. // Get rid of the file extension in val if there is one.
  8081. char *period;
  8082. period = Info.szReplaceTexName + strlen( Info.szReplaceTexName ) - 4;
  8083. if( period > Info.szReplaceTexName && *period == '.' )
  8084. {
  8085. *period = '\0';
  8086. }
  8087. // Get of backslashes in both key and val.
  8088. for( scan = Info.szFindTexName; *scan; scan++ )
  8089. {
  8090. if( *scan == '\\' )
  8091. {
  8092. *scan = '/';
  8093. }
  8094. }
  8095. for( scan = Info.szReplaceTexName; *scan; scan++ )
  8096. {
  8097. if( *scan == '\\' )
  8098. {
  8099. *scan = '/';
  8100. }
  8101. }
  8102. // Search and replace all key textures with val.
  8103. m_pWorld->EnumChildren( ( ENUMMAPCHILDRENPROC )BatchReplaceTextureCallback, ( DWORD )&Info, MAPCLASS_TYPE( CMapSolid ) );
  8104. next_line:;
  8105. }
  8106. }
  8107. //-----------------------------------------------------------------------------
  8108. // Purpose: Invokes the replace textures dialog.
  8109. //-----------------------------------------------------------------------------
  8110. void CMapDoc::OnEditReplacetex(void)
  8111. {
  8112. CReplaceTexDlg dlg( m_pSelection->GetCount());
  8113. dlg.m_strFind = GetDefaultTextureName();
  8114. if (dlg.DoModal() != IDOK)
  8115. {
  8116. return;
  8117. }
  8118. GetHistory()->MarkUndoPosition( m_pSelection->GetList(), "Replace Textures");
  8119. if (dlg.m_bMarkOnly)
  8120. {
  8121. SelectObject(NULL, scClear|scSaveChanges); // clear selection first
  8122. }
  8123. dlg.DoReplaceTextures();
  8124. }
  8125. //-----------------------------------------------------------------------------
  8126. // Purpose: Snaps the selected objects to the grid. This uses the selection
  8127. // bounds as a reference point.
  8128. //-----------------------------------------------------------------------------
  8129. void CMapDoc::OnToolsSnapselectedtogrid(void)
  8130. {
  8131. if (m_pSelection->IsEmpty())
  8132. return;
  8133. const CMapObjectList *pSelList = m_pSelection->GetList();
  8134. BoundBox NewObjectBox;
  8135. m_pSelection->GetBounds(NewObjectBox.bmins, NewObjectBox.bmaxs);
  8136. Vector vecMove(0, 0, 0);
  8137. // If we have a single point entity selected, just snap its origin.
  8138. bool bOnePointEntity = false;
  8139. if (pSelList->Count() == 1)
  8140. {
  8141. CMapClass *pObject = (CUtlReference< CMapClass >)pSelList->Element(0);
  8142. CMapEntity *pEntity = dynamic_cast<CMapEntity *>(pObject);
  8143. if (pEntity && pEntity->IsPlaceholder())
  8144. {
  8145. Vector vecOrigin;
  8146. pEntity->GetOrigin(vecOrigin);
  8147. Vector vecOriginSnap = vecOrigin;
  8148. Snap(vecOriginSnap);
  8149. vecMove = vecOriginSnap - vecOrigin;
  8150. bOnePointEntity = true;
  8151. }
  8152. }
  8153. if (!bOnePointEntity)
  8154. {
  8155. // Something other than a single point entity is selected.
  8156. // Just snap the bmins of the selection bounding box.
  8157. Vector vOldMins = NewObjectBox.bmins;
  8158. NewObjectBox.SnapToGrid(m_nGridSpacing);
  8159. // Calculate the amount to move.
  8160. vecMove = NewObjectBox.bmins - vOldMins;
  8161. }
  8162. GetHistory()->MarkUndoPosition(pSelList, "Snap Objects");
  8163. GetHistory()->Keep(pSelList);
  8164. // do move
  8165. for (int i = 0; i < pSelList->Count(); i++)
  8166. {
  8167. CMapClass *pObject = (CUtlReference< CMapClass >)pSelList->Element(i);
  8168. pObject->TransMove(vecMove);
  8169. }
  8170. SetModifiedFlag();
  8171. }
  8172. //-----------------------------------------------------------------------------
  8173. // Purpose:
  8174. // Input : pObject -
  8175. //-----------------------------------------------------------------------------
  8176. void CMapDoc::SnapObjectsRecursive(CMapClass *pObject)
  8177. {
  8178. if (!pObject->IsGroup())
  8179. {
  8180. CMapEntity *pEntity = dynamic_cast<CMapEntity *>(pObject);
  8181. Vector vecRefPoint;
  8182. if (pEntity && pEntity->IsPlaceholder())
  8183. {
  8184. // Point entities snap based on their origin.
  8185. pEntity->GetOrigin(vecRefPoint);
  8186. }
  8187. else
  8188. {
  8189. // Everthing else snaps based on the mins of it's bounding box.
  8190. Vector maxs;
  8191. pObject->GetRender2DBox(vecRefPoint, maxs);
  8192. }
  8193. Vector vecRefPointSnap = vecRefPoint;
  8194. Snap(vecRefPointSnap);
  8195. Vector vecMove = vecRefPointSnap - vecRefPoint;
  8196. pObject->TransMove(vecMove);
  8197. }
  8198. else
  8199. {
  8200. // Recurse into children of non-entities (since entities can't have
  8201. // entity children).
  8202. const CMapObjectList *pChildren = pObject->GetChildren();
  8203. FOR_EACH_OBJ( *pChildren, pos )
  8204. {
  8205. SnapObjectsRecursive((CUtlReference< CMapClass >)pChildren->Element(pos));
  8206. }
  8207. }
  8208. }
  8209. //-----------------------------------------------------------------------------
  8210. // Purpose: Snaps the selected objects to the grid. This uses the selection
  8211. // bounds as a reference point.
  8212. //-----------------------------------------------------------------------------
  8213. void CMapDoc::OnToolsSnapSelectedToGridIndividually()
  8214. {
  8215. if ( m_pSelection->IsEmpty() )
  8216. return;
  8217. const CMapObjectList *pSelList = m_pSelection->GetList();
  8218. Vector vecMove(0, 0, 0);
  8219. GetHistory()->MarkUndoPosition(pSelList, "Snap Objects Individually");
  8220. GetHistory()->Keep(pSelList);
  8221. for (int i = 0; i < pSelList->Count(); i++)
  8222. {
  8223. CMapClass *pObject = (CUtlReference< CMapClass >)pSelList->Element(i);
  8224. SnapObjectsRecursive(pObject);
  8225. }
  8226. SetModifiedFlag();
  8227. }
  8228. //-----------------------------------------------------------------------------
  8229. // Purpose:
  8230. // Input : pCmdUI -
  8231. //-----------------------------------------------------------------------------
  8232. void CMapDoc::OnUpdateToolsSplitface(CCmdUI* pCmdUI)
  8233. {
  8234. if ( m_pToolManager->GetActiveToolID() != TOOL_MORPH )
  8235. {
  8236. pCmdUI->SetCheck( false );
  8237. }
  8238. else
  8239. {
  8240. Morph3D *pMorph = (Morph3D*) m_pToolManager->GetActiveTool();
  8241. pCmdUI->SetCheck( pMorph->CanSplitFace());
  8242. }
  8243. }
  8244. //-----------------------------------------------------------------------------
  8245. // Purpose:
  8246. //-----------------------------------------------------------------------------
  8247. void CMapDoc::OnToolsSplitface(void)
  8248. {
  8249. if (m_pToolManager->GetActiveToolID() == TOOL_MORPH)
  8250. {
  8251. Morph3D *pMorph = (Morph3D*) m_pToolManager->GetActiveTool();
  8252. pMorph->SplitFace();
  8253. }
  8254. }
  8255. //-----------------------------------------------------------------------------
  8256. // Purpose: Centers the origin of any entities in the given object tree.
  8257. // Input : pObject - root of the object tree.
  8258. //-----------------------------------------------------------------------------
  8259. void CMapDoc::CenterOriginsRecursive(CMapClass *pObject)
  8260. {
  8261. CMapEntity *pEntity = dynamic_cast<CMapEntity *>(pObject);
  8262. if (pEntity != NULL)
  8263. {
  8264. const char *pszOrigin = pEntity->GetKeyValue("origin");
  8265. if (pszOrigin)
  8266. {
  8267. // This entity has an origin key.
  8268. GetHistory()->Keep(pEntity);
  8269. Vector vecCenter;
  8270. pEntity->GetBoundsCenter(vecCenter);
  8271. // dvs: make key parse/unparse code common to Hammer and the engine
  8272. char szOrigin[50];
  8273. sprintf(szOrigin, "%g %g %g", vecCenter.x, vecCenter.y, vecCenter.z);
  8274. pEntity->SetKeyValue("origin", szOrigin);
  8275. }
  8276. }
  8277. else
  8278. {
  8279. // Recurse into children of non-entities (since entities can't have
  8280. // entity children).
  8281. const CMapObjectList *pChildren = pObject->GetChildren();
  8282. FOR_EACH_OBJ( *pChildren, pos )
  8283. {
  8284. CenterOriginsRecursive((CUtlReference< CMapClass >)pChildren->Element(pos));
  8285. }
  8286. }
  8287. }
  8288. //-----------------------------------------------------------------------------
  8289. // Purpose: Centers the origins of all selected entities.
  8290. //-----------------------------------------------------------------------------
  8291. void CMapDoc::OnToolsCenterOrigins()
  8292. {
  8293. const CMapObjectList *pSelList = m_pSelection->GetList();
  8294. GetHistory()->MarkUndoPosition(pSelList, "Center Origins");
  8295. for (int i = 0; i < pSelList->Count(); i++)
  8296. {
  8297. CMapClass *pObject = (CUtlReference< CMapClass >)pSelList->Element(i);
  8298. CenterOriginsRecursive(pObject);
  8299. }
  8300. UpdateAllViews( MAPVIEW_UPDATE_OBJECTS );
  8301. }
  8302. //-----------------------------------------------------------------------------
  8303. // Purpose: Snaps a point to the grid, or to integer values if snap is disabled.
  8304. // Input : pt - Point in world coordinates to snap.
  8305. //-----------------------------------------------------------------------------
  8306. void CMapDoc::Snap(Vector &pt, int nFlags)
  8307. {
  8308. if ( m_bSnapToGrid )
  8309. nFlags |= constrainSnap;
  8310. else
  8311. nFlags |= constrainIntSnap;
  8312. if ( nFlags & constrainIntSnap )
  8313. {
  8314. for (int i = 0; i < 3; i++)
  8315. {
  8316. pt[i] = rint(pt[i]);
  8317. }
  8318. }
  8319. else if (nFlags & constrainSnap )
  8320. {
  8321. float flGridSpacing = m_nGridSpacing;
  8322. if ( nFlags & constrainHalfSnap )
  8323. flGridSpacing *= 0.5f;
  8324. for (int i = 0; i < 3; i++)
  8325. {
  8326. pt[i] = rint(pt[i] / flGridSpacing) * flGridSpacing;
  8327. }
  8328. }
  8329. }
  8330. //-----------------------------------------------------------------------------
  8331. // Purpose:
  8332. //-----------------------------------------------------------------------------
  8333. void CMapDoc::OnToolsTransform(void)
  8334. {
  8335. if(m_pSelection->IsEmpty())
  8336. {
  8337. AfxMessageBox("You must select some objects before you can\n"
  8338. "transform them.");
  8339. return;
  8340. }
  8341. CTransformDlg dlg;
  8342. dlg.m_iMode = 0;
  8343. if(dlg.DoModal() != IDOK)
  8344. return;
  8345. Vector vDelta( dlg.m_X, dlg.m_Y, dlg.m_Z );
  8346. if (dlg.m_iMode == 1)
  8347. {
  8348. // make sure no 0.0 values
  8349. for (int i = 0; i < 3; i++)
  8350. {
  8351. if (vDelta[i] == 0.0f)
  8352. {
  8353. vDelta[i] = 1.0f;
  8354. }
  8355. }
  8356. }
  8357. const CMapObjectList *pSelList = m_pSelection->GetList();
  8358. // find origin
  8359. Vector vOrigin;
  8360. m_pSelection->GetBoundsCenter( vOrigin );
  8361. GetHistory()->MarkUndoPosition(pSelList, "Transformation");
  8362. GetHistory()->Keep(pSelList);
  8363. //
  8364. // Save any properties that may have been changed in the entity properties dialog.
  8365. // This prevents the LoadData below from losing any changes that were made in the
  8366. // object properties dialog.
  8367. //
  8368. GetMainWnd()->pObjectProperties->SaveData( SAVEDATA_TOOL_TRANSFORM );
  8369. for (int i = 0; i < pSelList->Count(); i++)
  8370. {
  8371. CMapClass *pObject = (CUtlReference< CMapClass >)pSelList->Element(i);
  8372. if ( dlg.m_iMode == 0 )
  8373. {
  8374. pObject->TransRotate( vOrigin, (QAngle&)vDelta );
  8375. }
  8376. else if ( dlg.m_iMode == 1 )
  8377. {
  8378. pObject->TransScale( vOrigin, vDelta );
  8379. }
  8380. else if ( dlg.m_iMode == 2 )
  8381. {
  8382. pObject->TransMove( vDelta );
  8383. }
  8384. }
  8385. SetModifiedFlag();
  8386. }
  8387. //-----------------------------------------------------------------------------
  8388. // Purpose:
  8389. //-----------------------------------------------------------------------------
  8390. void CMapDoc::OnToggleDispSolidMask( void )
  8391. {
  8392. UpdateAllViews( MAPVIEW_UPDATE_ONLY_3D );
  8393. m_bDispSolidDrawMask = !m_bDispSolidDrawMask;
  8394. }
  8395. //-----------------------------------------------------------------------------
  8396. // Purpose:
  8397. //-----------------------------------------------------------------------------
  8398. void CMapDoc::OnUpdateToggleSolidMask(CCmdUI* pCmdUI)
  8399. {
  8400. pCmdUI->SetCheck( m_bDispSolidDrawMask );
  8401. }
  8402. //-----------------------------------------------------------------------------
  8403. //-----------------------------------------------------------------------------
  8404. void CMapDoc::OnToggleDispDrawWalkable( void )
  8405. {
  8406. UpdateAllViews( MAPVIEW_UPDATE_ONLY_3D );
  8407. m_bDispDrawWalkable = !m_bDispDrawWalkable;
  8408. }
  8409. //-----------------------------------------------------------------------------
  8410. //-----------------------------------------------------------------------------
  8411. void CMapDoc::OnUpdateToggleDispDrawWalkable( CCmdUI *pCmdUI )
  8412. {
  8413. pCmdUI->SetCheck( m_bDispDrawWalkable );
  8414. }
  8415. //-----------------------------------------------------------------------------
  8416. // Purpose:
  8417. //-----------------------------------------------------------------------------
  8418. void CMapDoc::OnToggleDispDrawBuildable( void )
  8419. {
  8420. UpdateAllViews( MAPVIEW_UPDATE_ONLY_3D );
  8421. m_bDispDrawBuildable = !m_bDispDrawBuildable;
  8422. }
  8423. //-----------------------------------------------------------------------------
  8424. // Toggles between rendering disps in 3D.
  8425. //-----------------------------------------------------------------------------
  8426. void CMapDoc::OnToggleDispDraw3D( void )
  8427. {
  8428. UpdateAllViews( MAPVIEW_UPDATE_ONLY_3D );
  8429. m_bDispDraw3D = !m_bDispDraw3D;
  8430. }
  8431. //-----------------------------------------------------------------------------
  8432. //-----------------------------------------------------------------------------
  8433. void CMapDoc::OnUpdateToggleDispDraw3D( CCmdUI *pCmdUI )
  8434. {
  8435. pCmdUI->SetCheck( m_bDispDraw3D );
  8436. }
  8437. //-----------------------------------------------------------------------------
  8438. // Purpose:
  8439. //-----------------------------------------------------------------------------
  8440. void CMapDoc::OnUpdateToggleDispDrawBuildable( CCmdUI *pCmdUI )
  8441. {
  8442. pCmdUI->SetCheck( m_bDispDrawBuildable );
  8443. }
  8444. //-----------------------------------------------------------------------------
  8445. // Purpose:
  8446. //-----------------------------------------------------------------------------
  8447. void CMapDoc::OnToggleDispDrawRemovedVerts( void )
  8448. {
  8449. UpdateAllViews( MAPVIEW_UPDATE_ONLY_3D );
  8450. m_bDispDrawRemovedVerts = !m_bDispDrawRemovedVerts;
  8451. }
  8452. //-----------------------------------------------------------------------------
  8453. // Purpose:
  8454. //-----------------------------------------------------------------------------
  8455. void CMapDoc::OnUpdateToggleDispDrawRemovedVerts( CCmdUI *pCmdUI )
  8456. {
  8457. pCmdUI->SetCheck( m_bDispDrawRemovedVerts );
  8458. }
  8459. void CMapDoc::OnToolsToggletexlock(void)
  8460. {
  8461. Options.SetLockingTextures(!Options.IsLockingTextures());
  8462. SetStatusText(SBI_PROMPT, Options.IsLockingTextures() ? "Texture locking on" : "Texture locking off");
  8463. }
  8464. void CMapDoc::OnUpdateToolsToggletexlock(CCmdUI* pCmdUI)
  8465. {
  8466. pCmdUI->SetCheck(Options.IsLockingTextures());
  8467. }
  8468. void CMapDoc::OnToolsToggletexlockScale(void)
  8469. {
  8470. Options.SetScaleLockingTextures(!Options.IsScaleLockingTextures());
  8471. SetStatusText(SBI_PROMPT, Options.IsScaleLockingTextures() ? "Scale texture locking on" : "Scale texture locking off");
  8472. }
  8473. void CMapDoc::OnUpdateToolsToggletexlockScale(CCmdUI* pCmdUI)
  8474. {
  8475. pCmdUI->SetCheck(Options.IsScaleLockingTextures());
  8476. }
  8477. //-----------------------------------------------------------------------------
  8478. // Purpose:
  8479. //-----------------------------------------------------------------------------
  8480. void CMapDoc::OnToolsTextureAlignment(void)
  8481. {
  8482. TextureAlignment_t eTextureAlignment;
  8483. eTextureAlignment = Options.GetTextureAlignment();
  8484. if (eTextureAlignment == TEXTURE_ALIGN_WORLD)
  8485. {
  8486. Options.SetTextureAlignment(TEXTURE_ALIGN_FACE);
  8487. SetStatusText(SBI_PROMPT, "Face aligned textures");
  8488. }
  8489. else
  8490. {
  8491. Options.SetTextureAlignment(TEXTURE_ALIGN_WORLD);
  8492. SetStatusText(SBI_PROMPT, "World aligned textures");
  8493. }
  8494. }
  8495. //-----------------------------------------------------------------------------
  8496. // Purpose:
  8497. // Input : *pCmdUI -
  8498. //-----------------------------------------------------------------------------
  8499. void CMapDoc::OnUpdateToolsTextureAlignment(CCmdUI *pCmdUI)
  8500. {
  8501. pCmdUI->SetCheck(Options.GetTextureAlignment() == TEXTURE_ALIGN_FACE);
  8502. }
  8503. //-----------------------------------------------------------------------------
  8504. // Purpose: Returns whether a remote shell editing session has been initiated
  8505. // through a "session_begin" shell command.
  8506. //-----------------------------------------------------------------------------
  8507. bool CMapDoc::IsShellSessionActive(void)
  8508. {
  8509. return(GetMainWnd()->IsShellSessionActive());
  8510. }
  8511. //-----------------------------------------------------------------------------
  8512. //-----------------------------------------------------------------------------
  8513. bool CMapDoc::Cordon_SetCordoning( bool bState)
  8514. {
  8515. if ( m_bIsCordoning != bState )
  8516. {
  8517. m_bIsCordoning = bState;
  8518. UpdateVisibilityAll();
  8519. SetModifiedFlag( true );
  8520. return true;
  8521. }
  8522. return false;
  8523. }
  8524. //-----------------------------------------------------------------------------
  8525. // Called when the selection changes in the filter dialog. Picks a cordon to
  8526. // edit when the cordon tool is active.
  8527. //-----------------------------------------------------------------------------
  8528. void CMapDoc::Cordon_SelectCordonForEditing( Cordon_t *cordon, BoundBox *box, int nFlags )
  8529. {
  8530. for ( int i = 0; i < m_Cordons.Count(); i++ )
  8531. {
  8532. if ( &m_Cordons[i] != cordon )
  8533. continue;
  8534. for ( int j = 0; j < m_Cordons[i].m_Boxes.Count(); j++ )
  8535. {
  8536. if ( &m_Cordons[i].m_Boxes[j] == box )
  8537. {
  8538. m_nEditCordon = i;
  8539. m_nEditCordonBox = j;
  8540. if ( !( nFlags & SELECT_CORDON_FROM_TOOL ) && ( m_pToolManager->GetActiveToolID() == TOOL_EDITCORDON ) )
  8541. {
  8542. m_pToolManager->GetActiveTool()->OnActivate();
  8543. UpdateAllViews( MAPVIEW_UPDATE_TOOL );
  8544. }
  8545. if ( !(nFlags & SELECT_CORDON_FROM_DIALOG ) )
  8546. {
  8547. GetMainWnd()->m_FilterControl.SelectCordon( cordon, box );
  8548. }
  8549. return;
  8550. }
  8551. }
  8552. }
  8553. Assert( false );
  8554. }
  8555. //-----------------------------------------------------------------------------
  8556. //-----------------------------------------------------------------------------
  8557. void CMapDoc::Cordon_GetEditCordon( Vector &mins, Vector &maxs )
  8558. {
  8559. if ( m_Cordons.Count() == 0 )
  8560. {
  8561. Cordon_CreateNewCordon( DEFAULT_CORDON_NAME );
  8562. m_nEditCordon = m_nEditCordonBox = 0;
  8563. }
  8564. else
  8565. {
  8566. mins = m_Cordons[m_nEditCordon].m_Boxes[m_nEditCordonBox].bmins;
  8567. maxs = m_Cordons[m_nEditCordon].m_Boxes[m_nEditCordonBox].bmaxs;
  8568. }
  8569. }
  8570. //-----------------------------------------------------------------------------
  8571. //-----------------------------------------------------------------------------
  8572. void CMapDoc::Cordon_SetEditCordon( const Vector &mins, const Vector &maxs )
  8573. {
  8574. if ( m_Cordons.Count() == 0 )
  8575. {
  8576. Cordon_CreateNewCordon( DEFAULT_CORDON_NAME );
  8577. m_nEditCordon = m_nEditCordonBox = 0;
  8578. }
  8579. m_Cordons[m_nEditCordon].m_Boxes[m_nEditCordonBox].bmins = mins;
  8580. m_Cordons[m_nEditCordon].m_Boxes[m_nEditCordonBox].bmaxs = maxs;
  8581. UpdateVisibilityAll();
  8582. SetModifiedFlag( true );
  8583. }
  8584. //-----------------------------------------------------------------------------
  8585. //-----------------------------------------------------------------------------
  8586. Cordon_t *CMapDoc::Cordon_CreateNewCordon( const char *name, BoundBox **ppBox )
  8587. {
  8588. CUtlString cordonName;
  8589. if ( !name )
  8590. {
  8591. CStrDlg dlg( 0, "cordon", "Name:", "New Cordon" );
  8592. if ( dlg.DoModal() != IDOK )
  8593. return NULL;
  8594. cordonName.Set( dlg.m_string );
  8595. }
  8596. else
  8597. {
  8598. cordonName = name;
  8599. }
  8600. Cordon_t *pCordon = Cordon_AddCordon( cordonName );
  8601. if ( pCordon )
  8602. {
  8603. pCordon->m_bActive = true;
  8604. BoundBox *pBox = Cordon_AddBox( pCordon );
  8605. if ( ppBox )
  8606. {
  8607. *ppBox = pBox;
  8608. }
  8609. GetBestVisibleBox( pBox->bmins, pBox->bmaxs );
  8610. if ( m_bIsCordoning )
  8611. {
  8612. UpdateVisibilityAll();
  8613. }
  8614. SetModifiedFlag( true );
  8615. }
  8616. return pCordon;
  8617. }
  8618. //-----------------------------------------------------------------------------
  8619. //-----------------------------------------------------------------------------
  8620. bool CMapDoc::Cordon_IsCulledByCordon( CMapClass *pObject )
  8621. {
  8622. if ( !pObject->CanBeCulledByCordon() )
  8623. return false;
  8624. // If this object intersects any active cordons, it's visible.
  8625. for ( int i = 0; i < m_Cordons.Count(); i++ )
  8626. {
  8627. if ( !m_Cordons[i].m_bActive )
  8628. continue;
  8629. for ( int j = 0; j < m_Cordons[i].m_Boxes.Count(); j++ )
  8630. {
  8631. if ( pObject->IsIntersectingCordon( m_Cordons[i].m_Boxes[j].bmins, m_Cordons[i].m_Boxes[j].bmaxs ) )
  8632. return false;
  8633. }
  8634. }
  8635. return true;
  8636. }
  8637. //-----------------------------------------------------------------------------
  8638. // Together, the cordon/box indices uniquely identify the cordon box within the doc.
  8639. // NOTE: These indices change as cordons and boxes are added and removed.
  8640. //-----------------------------------------------------------------------------
  8641. void CMapDoc::Cordon_GetIndices( Cordon_t *pCordon, BoundBox *pBox, int *pnCordon, int *pnBox )
  8642. {
  8643. *pnCordon = *pnBox = -1;
  8644. for ( int i = 0; i < m_Cordons.Count(); i++ )
  8645. {
  8646. if ( &m_Cordons[i] == pCordon )
  8647. {
  8648. *pnCordon = i;
  8649. break;
  8650. }
  8651. }
  8652. if ( pBox )
  8653. {
  8654. for ( int j = 0; j < pCordon->m_Boxes.Count(); j++ )
  8655. {
  8656. if ( &pCordon->m_Boxes[j] == pBox )
  8657. {
  8658. *pnBox = j;
  8659. break;
  8660. }
  8661. }
  8662. }
  8663. }
  8664. //-----------------------------------------------------------------------------
  8665. //-----------------------------------------------------------------------------
  8666. Cordon_t *CMapDoc::Cordon_AddCordon( const char *szName )
  8667. {
  8668. m_Cordons.AddToTail();
  8669. m_Cordons.Tail().m_szName.Set( szName ? szName : DEFAULT_CORDON_NAME );
  8670. return &m_Cordons.Tail();
  8671. }
  8672. //-----------------------------------------------------------------------------
  8673. //-----------------------------------------------------------------------------
  8674. BoundBox *CMapDoc::Cordon_AddBox( Cordon_t *cordon )
  8675. {
  8676. Assert( cordon );
  8677. if ( !cordon )
  8678. return NULL;
  8679. cordon->m_Boxes.AddToTail();
  8680. // The above call to AddToTail may have moved memory and invalidated pointers
  8681. // held by m_cCordonBox in CFilterControl, so we need to refresh the list.
  8682. GetMainWnd()->m_FilterControl.UpdateCordonList();
  8683. return &cordon->m_Boxes.Tail();
  8684. }
  8685. //-----------------------------------------------------------------------------
  8686. //-----------------------------------------------------------------------------
  8687. void CMapDoc::Cordon_RemoveBox( Cordon_t *cordon, BoundBox *box )
  8688. {
  8689. Assert( cordon );
  8690. if ( !cordon )
  8691. return;
  8692. Assert( box );
  8693. if ( !box)
  8694. return;
  8695. bool bRemoved = false;
  8696. for ( int i = 0; i < cordon->m_Boxes.Count(); i++ )
  8697. {
  8698. if ( &cordon->m_Boxes[i] == box )
  8699. {
  8700. cordon->m_Boxes.Remove( i );
  8701. bRemoved = true;
  8702. break;
  8703. }
  8704. }
  8705. Assert( bRemoved );
  8706. // The above call to Remove may have moved memory and invalidated pointers
  8707. // held by m_cCordonBox in CFilterControl, so we need to refresh the list.
  8708. GetMainWnd()->m_FilterControl.UpdateCordonList();
  8709. if ( m_bIsCordoning )
  8710. {
  8711. UpdateVisibilityAll();
  8712. }
  8713. SetModifiedFlag( true );
  8714. }
  8715. //-----------------------------------------------------------------------------
  8716. //-----------------------------------------------------------------------------
  8717. void CMapDoc::Cordon_RemoveCordon( Cordon_t *cordon )
  8718. {
  8719. Assert( cordon );
  8720. if ( !cordon )
  8721. return;
  8722. bool bRemoved = false;
  8723. for ( int i = 0; i < m_Cordons.Count(); i++ )
  8724. {
  8725. if ( &m_Cordons[i] == cordon )
  8726. {
  8727. m_Cordons.Remove( i );
  8728. bRemoved = true;
  8729. break;
  8730. }
  8731. }
  8732. Assert( bRemoved );
  8733. // The above call to Remove may have moved memory and invalidated pointers
  8734. // held by m_cCordonList in CFilterControl, so we need to refresh the list.
  8735. GetMainWnd()->m_FilterControl.UpdateCordonList();
  8736. if ( ( m_Cordons.Count() <= 0 ) && ( m_pToolManager->GetActiveToolID() == TOOL_EDITCORDON ) )
  8737. {
  8738. m_pToolManager->GetActiveTool()->RefreshToolState();
  8739. }
  8740. if ( m_bIsCordoning )
  8741. {
  8742. UpdateVisibilityAll();
  8743. }
  8744. SetModifiedFlag( true );
  8745. }
  8746. //-----------------------------------------------------------------------------
  8747. //-----------------------------------------------------------------------------
  8748. void CMapDoc::Cordon_CombineCordons( Cordon_t *pSourceCordon, BoundBox *pSourceBox, Cordon_t *pDestCordon )
  8749. {
  8750. if ( ( !pSourceCordon || !pDestCordon ) || ( pSourceCordon == pDestCordon ) )
  8751. return;
  8752. if ( pSourceBox )
  8753. {
  8754. pDestCordon->m_Boxes.AddToTail( *pSourceBox );
  8755. // This will also update the UI
  8756. Cordon_RemoveBox( pSourceCordon, pSourceBox );
  8757. }
  8758. else
  8759. {
  8760. pDestCordon->m_Boxes.AddVectorToTail( pSourceCordon->m_Boxes );
  8761. // This will also update the UI
  8762. Cordon_RemoveCordon( pSourceCordon );
  8763. }
  8764. }
  8765. //-----------------------------------------------------------------------------
  8766. //-----------------------------------------------------------------------------
  8767. Cordon_t *CMapDoc::Cordon_GetSelectedCordonForEditing( BoundBox **ppBox )
  8768. {
  8769. if ( m_Cordons.Count() <= 0 )
  8770. {
  8771. if ( ppBox )
  8772. {
  8773. *ppBox = NULL;
  8774. }
  8775. return NULL;
  8776. }
  8777. if ( ppBox )
  8778. {
  8779. *ppBox = &m_Cordons[m_nEditCordon].m_Boxes[m_nEditCordonBox];
  8780. }
  8781. return &m_Cordons[m_nEditCordon];
  8782. }
  8783. //-----------------------------------------------------------------------------
  8784. //-----------------------------------------------------------------------------
  8785. void CMapDoc::OnToggleCordon(void)
  8786. {
  8787. Cordon_SetCordoning( !m_bIsCordoning );
  8788. }
  8789. //-----------------------------------------------------------------------------
  8790. //-----------------------------------------------------------------------------
  8791. void CMapDoc::OnUpdateToggleCordon(CCmdUI* pCmdUI)
  8792. {
  8793. pCmdUI->Enable( m_Cordons.Count() > 0 );
  8794. pCmdUI->SetCheck( m_bIsCordoning ? 1 : 0 );
  8795. }
  8796. //-----------------------------------------------------------------------------
  8797. // Purpose: Toggles between Groups selection mode and Solids selection mode.
  8798. //-----------------------------------------------------------------------------
  8799. void CMapDoc::OnToggleGroupignore(void)
  8800. {
  8801. SelectMode_t eSelectMode = m_pSelection->GetMode();
  8802. if (eSelectMode == selectSolids)
  8803. {
  8804. eSelectMode = selectGroups;
  8805. }
  8806. else
  8807. {
  8808. eSelectMode = selectSolids;
  8809. }
  8810. m_pSelection->SetMode(eSelectMode);
  8811. }
  8812. //-----------------------------------------------------------------------------
  8813. // Purpose:
  8814. // Input : pCmdUI -
  8815. //-----------------------------------------------------------------------------
  8816. void CMapDoc::OnUpdateToggleGroupignore(CCmdUI *pCmdUI)
  8817. {
  8818. pCmdUI->SetCheck(m_pSelection->GetMode() == selectSolids);
  8819. }
  8820. //-----------------------------------------------------------------------------
  8821. // Purpose:
  8822. //-----------------------------------------------------------------------------
  8823. void CMapDoc::OnChangeVertexscale(void)
  8824. {
  8825. if (m_pToolManager->GetActiveToolID() == TOOL_MORPH)
  8826. {
  8827. Morph3D *pMorph = (Morph3D*) m_pToolManager->GetActiveTool();
  8828. pMorph->UpdateScale();
  8829. }
  8830. }
  8831. //-----------------------------------------------------------------------------
  8832. // Purpose:
  8833. //-----------------------------------------------------------------------------
  8834. void CMapDoc::OnVscaleToggle(void)
  8835. {
  8836. if (m_pToolManager->GetActiveToolID() == TOOL_MORPH)
  8837. {
  8838. Morph3D *pMorph = (Morph3D*) m_pToolManager->GetActiveTool();
  8839. pMorph->OnScaleCmd();
  8840. }
  8841. }
  8842. //-----------------------------------------------------------------------------
  8843. // Purpose:
  8844. //-----------------------------------------------------------------------------
  8845. void CMapDoc::OnMapEntityreport(void)
  8846. {
  8847. CEntityReportDlg::ShowEntityReport(this, GetMainWnd());
  8848. }
  8849. //-----------------------------------------------------------------------------
  8850. // Purpose:
  8851. //-----------------------------------------------------------------------------
  8852. void CMapDoc::OnToggleSelectbyhandle(void)
  8853. {
  8854. Options.view2d.bSelectbyhandles = !Options.view2d.bSelectbyhandles;
  8855. }
  8856. //-----------------------------------------------------------------------------
  8857. // Purpose:
  8858. // Input : pCmdUI -
  8859. //-----------------------------------------------------------------------------
  8860. void CMapDoc::OnUpdateToggleSelectbyhandle(CCmdUI* pCmdUI)
  8861. {
  8862. pCmdUI->SetCheck(Options.view2d.bSelectbyhandles);
  8863. }
  8864. //-----------------------------------------------------------------------------
  8865. // Purpose:
  8866. // Input :
  8867. //-----------------------------------------------------------------------------
  8868. void CMapDoc::OnToggleInfiniteselect()
  8869. {
  8870. Options.view2d.bAutoSelect = !Options.view2d.bAutoSelect;
  8871. }
  8872. //-----------------------------------------------------------------------------
  8873. // Purpose:
  8874. // Input : pCmdUI -
  8875. //-----------------------------------------------------------------------------
  8876. void CMapDoc::OnUpdateToggleInfiniteselect(CCmdUI* pCmdUI)
  8877. {
  8878. pCmdUI->SetCheck(Options.view2d.bAutoSelect);
  8879. }
  8880. static BOOL SaveDXF(CMapSolid *pSolid, ExportDXFInfo_s *pInfo)
  8881. {
  8882. return pSolid->SaveDXF( pInfo );
  8883. }
  8884. //-----------------------------------------------------------------------------
  8885. // Purpose:
  8886. //-----------------------------------------------------------------------------
  8887. void CMapDoc::OnFileExporttodxf(void)
  8888. {
  8889. static CString str;
  8890. if (str.IsEmpty())
  8891. {
  8892. int nDot;
  8893. // Replace the extension with DXF.
  8894. str = GetPathName();
  8895. if ((nDot = str.ReverseFind('.')) != -1)
  8896. {
  8897. str = str.Left(nDot);
  8898. }
  8899. str += ".dxf";
  8900. }
  8901. CExportDlg dlg(str, "dxf", "DXF files (*.dxf)|*.dxf||");
  8902. if(dlg.DoModal() == IDCANCEL)
  8903. return;
  8904. str = dlg.GetPathName();
  8905. if(str.ReverseFind('.') == -1)
  8906. str += ".dxf";
  8907. FILE *fp = fopen(str, "wb");
  8908. m_pWorld->CalcBounds(TRUE);
  8909. BoundBox box;
  8910. m_pWorld->GetRender2DBox(box.bmins, box.bmaxs);
  8911. fprintf(fp,"0\nSECTION\n2\nHEADER\n");
  8912. fprintf(fp,"9\n$ACADVER\n1\nAC1008\n");
  8913. fprintf(fp,"9\n$UCSORG\n10\n0.0\n20\n0.0\n30\n0.0\n");
  8914. fprintf(fp,"9\n$UCSXDIR\n10\n1.0\n20\n0.0\n30\n0.0\n");
  8915. fprintf(fp,"9\n$TILEMODE\n70\n1\n");
  8916. fprintf(fp,"9\n$UCSYDIR\n10\n0.0\n20\n1.0\n30\n0.0\n");
  8917. fprintf(fp,"9\n$EXTMIN\n10\n%f\n20\n%f\n30\n%f\n",
  8918. box.bmins[0], box.bmins[1], box.bmins[2]);
  8919. fprintf(fp,"9\n$EXTMAX\n10\n%f\n20\n%f\n30\n%f\n",
  8920. box.bmaxs[0], box.bmaxs[1], box.bmaxs[2]);
  8921. fprintf(fp,"0\nENDSEC\n");
  8922. /* Tables section */
  8923. fprintf(fp,"0\nSECTION\n2\nTABLES\n");
  8924. /* Continuous line type */
  8925. fprintf(fp,"0\nTABLE\n2\nLTYPE\n70\n1\n0\nLTYPE\n2\nCONTINUOUS"
  8926. "\n70\n64\n3\nSolid line\n72\n65\n73\n0\n40\n0.0\n");
  8927. fprintf(fp,"0\nENDTAB\n");
  8928. /* Object names for layers */
  8929. fprintf(fp,"0\nTABLE\n2\nLAYER\n70\n%d\n",1);
  8930. fprintf(fp,"0\nLAYER\n2\n0\n70\n0\n62\n7\n6\nCONTINUOUS\n");
  8931. fprintf(fp,"0\nENDTAB\n");
  8932. fprintf(fp,"0\nTABLE\n2\nSTYLE\n70\n1\n0\nSTYLE\n2\nSTANDARD\n70\n0\n"
  8933. "40\n0.0\n41\n1.0\n50\n0.0\n71\n0\n42\n0.2\n3\ntxt\n4\n\n0\nENDTAB\n");
  8934. /* Default View? */
  8935. /* UCS */
  8936. fprintf(fp,"0\nTABLE\n2\nUCS\n70\n0\n0\nENDTAB\n");
  8937. fprintf(fp,"0\nENDSEC\n");
  8938. /* Entities section */
  8939. fprintf(fp,"0\nSECTION\n2\nENTITIES\n");
  8940. // export solids
  8941. BeginWaitCursor();
  8942. ExportDXFInfo_s info;
  8943. info.bVisOnly = dlg.bVisibles!=0;
  8944. info.nObject = 0;
  8945. info.pWorld = m_pWorld;
  8946. info.fp = fp;
  8947. m_pWorld->EnumChildren(ENUMMAPCHILDRENPROC(SaveDXF), DWORD(&info), MAPCLASS_TYPE(CMapSolid));
  8948. EndWaitCursor();
  8949. fprintf(fp,"0\nENDSEC\n0\nEOF\n");
  8950. fclose(fp);
  8951. }
  8952. //-----------------------------------------------------------------------------
  8953. // Purpose: Toggles the 3D grid.
  8954. //-----------------------------------------------------------------------------
  8955. void CMapDoc::OnToggle3DGrid(void)
  8956. {
  8957. m_bShow3DGrid = !m_bShow3DGrid;
  8958. UpdateAllViews( MAPVIEW_UPDATE_ONLY_3D|MAPVIEW_OPTIONS_CHANGED );
  8959. }
  8960. //-----------------------------------------------------------------------------
  8961. // Purpose: Sets the check state of the 3D grid toggle button.
  8962. // Input : *pCmdUI -
  8963. //-----------------------------------------------------------------------------
  8964. void CMapDoc::OnUpdateToggle3DGrid(CCmdUI *pCmdUI)
  8965. {
  8966. pCmdUI->SetCheck(m_bShow3DGrid);
  8967. }
  8968. static void SetFilenameExtension( CString &fileName, const char *pExt )
  8969. {
  8970. char *p = fileName.GetBuffer(MAX_PATH);
  8971. p = strrchr(p, '.');
  8972. if (p)
  8973. {
  8974. strcpy(p, pExt);
  8975. }
  8976. fileName.ReleaseBuffer();
  8977. }
  8978. //-----------------------------------------------------------------------------
  8979. // Purpose: Load data from the map's portal file for visualization
  8980. //-----------------------------------------------------------------------------
  8981. void CMapDoc::OnMapLoadportalfile(void)
  8982. {
  8983. delete m_pPortalFile;
  8984. m_pPortalFile = NULL;
  8985. m_pPortalFile = new portalfile_t;
  8986. m_pPortalFile->fileName = GetPathName();
  8987. m_pPortalFile->totalVerts = 0;
  8988. SetFilenameExtension( m_pPortalFile->fileName, ".prt" );
  8989. CString str;
  8990. str.Format("Load default portal file?\n(%s)", m_pPortalFile->fileName);
  8991. if(GetFileAttributes(m_pPortalFile->fileName) == 0xFFFFFFFF ||
  8992. AfxMessageBox(str, MB_ICONQUESTION | MB_YESNO) == IDNO)
  8993. {
  8994. CFileDialog dlg(TRUE, ".prt", m_pPortalFile->fileName, OFN_HIDEREADONLY |
  8995. OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR,
  8996. "Portal files (*.prt)|*.prt|");
  8997. if(dlg.DoModal() != IDOK)
  8998. return;
  8999. m_pPortalFile->fileName = dlg.GetPathName();
  9000. }
  9001. // load the file
  9002. if(GetFileAttributes(m_pPortalFile->fileName) == 0xFFFFFFFF)
  9003. {
  9004. AfxMessageBox("Couldn't find portal file.");
  9005. return;
  9006. }
  9007. FILE *fp = fopen(m_pPortalFile->fileName, "r");
  9008. char szLine[256];
  9009. int clusterCount;
  9010. int portalCount;
  9011. if (fscanf (fp,"%79s\n%i\n%i\n",szLine, &clusterCount, &portalCount) == 3)
  9012. {
  9013. if ( !Q_stricmp( szLine, "PRT1") )
  9014. {
  9015. for ( int i = 0; i < portalCount; i++ )
  9016. {
  9017. int pointCount, leaf0, leaf1;
  9018. if (fscanf (fp, "%i %i %i ", &pointCount, &leaf0, &leaf1 ) == 3 )
  9019. {
  9020. m_pPortalFile->vertCount.AddToTail( pointCount );
  9021. m_pPortalFile->totalVerts += pointCount;
  9022. for ( int i = 0; i < pointCount; i++ )
  9023. {
  9024. Vector v;
  9025. if ( fscanf (fp, "(%f %f %f ) ", &v[0], &v[1], &v[2]) == 3 )
  9026. {
  9027. m_pPortalFile->verts.AddToTail(v);
  9028. }
  9029. else
  9030. {
  9031. break;
  9032. }
  9033. }
  9034. fscanf (fp, "\n");
  9035. }
  9036. else
  9037. {
  9038. break;
  9039. }
  9040. }
  9041. }
  9042. // if this is not true we parsed incorrectly
  9043. Assert( m_pPortalFile->vertCount.Count() == portalCount );
  9044. }
  9045. fclose(fp);
  9046. if ( m_pPortalFile )
  9047. {
  9048. if ( m_pPortalFile->vertCount.Count() != portalCount || portalCount <= 0 )
  9049. {
  9050. delete m_pPortalFile;
  9051. m_pPortalFile = NULL;
  9052. }
  9053. }
  9054. UpdateAllViews( MAPVIEW_UPDATE_ONLY_2D );
  9055. }
  9056. //-----------------------------------------------------------------------------
  9057. // Purpose: Free the memory associate with the portal file
  9058. //-----------------------------------------------------------------------------
  9059. void CMapDoc::OnMapUnloadportalfile(void)
  9060. {
  9061. delete m_pPortalFile;
  9062. m_pPortalFile = NULL;
  9063. }
  9064. //-----------------------------------------------------------------------------
  9065. // Purpose:
  9066. //-----------------------------------------------------------------------------
  9067. void CMapDoc::OnMapLoadpointfile(void)
  9068. {
  9069. if(m_strLastPointFile.IsEmpty())
  9070. {
  9071. m_strLastPointFile = GetPathName();
  9072. const char *pExt = (m_pGame->mapformat == mfHalfLife2) ? ".lin" : ".pts";
  9073. SetFilenameExtension( m_strLastPointFile, pExt );
  9074. }
  9075. CString str;
  9076. str.Format("Load default pointfile?\n(%s)", m_strLastPointFile);
  9077. if(GetFileAttributes(m_strLastPointFile) == 0xFFFFFFFF ||
  9078. AfxMessageBox(str, MB_ICONQUESTION | MB_YESNO) == IDNO)
  9079. {
  9080. CFileDialog dlg(TRUE, ".pts", m_strLastPointFile, OFN_HIDEREADONLY |
  9081. OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR,
  9082. "Pointfiles (*.pts;*.lin)|*.pts; *.lin||");
  9083. if(dlg.DoModal() != IDOK)
  9084. return;
  9085. m_strLastPointFile = dlg.GetPathName();
  9086. }
  9087. // load the file
  9088. if(GetFileAttributes(m_strLastPointFile) == 0xFFFFFFFF)
  9089. {
  9090. AfxMessageBox("Couldn't load pointfile.");
  9091. return;
  9092. }
  9093. std::ifstream file(m_strLastPointFile);
  9094. m_PFPoints.Purge();
  9095. while(!file.eof())
  9096. {
  9097. char szLine[256];
  9098. file.getline(szLine, 256);
  9099. Vector v;
  9100. if(sscanf(szLine, "%f %f %f", &v.x, &v.y, &v.z) == 3)
  9101. {
  9102. m_PFPoints.AddToTail( v );
  9103. }
  9104. else
  9105. {
  9106. break;
  9107. }
  9108. }
  9109. file.close();
  9110. m_iCurPFPoint = -1;
  9111. UpdateAllViews( MAPVIEW_UPDATE_ONLY_2D );
  9112. }
  9113. //-----------------------------------------------------------------------------
  9114. // Purpose:
  9115. //-----------------------------------------------------------------------------
  9116. void CMapDoc::OnMapUnloadpointfile(void)
  9117. {
  9118. m_PFPoints.Purge();
  9119. UpdateAllViews( MAPVIEW_UPDATE_ONLY_2D );
  9120. }
  9121. //-----------------------------------------------------------------------------
  9122. // Purpose:
  9123. // Input : iDirection -
  9124. //-----------------------------------------------------------------------------
  9125. void CMapDoc::GotoPFPoint(int iDirection)
  9126. {
  9127. if (m_PFPoints.Count() == 0)
  9128. return;
  9129. m_iCurPFPoint = m_iCurPFPoint + iDirection;
  9130. if (m_iCurPFPoint == m_PFPoints.Count())
  9131. {
  9132. m_iCurPFPoint = 0;
  9133. }
  9134. else if (m_iCurPFPoint < 0)
  9135. {
  9136. m_iCurPFPoint = m_PFPoints.Count() - 1;
  9137. }
  9138. CenterViewsOn(m_PFPoints[m_iCurPFPoint]);
  9139. }
  9140. //-----------------------------------------------------------------------------
  9141. // Determine visgroup
  9142. //-----------------------------------------------------------------------------
  9143. CVisGroup *CMapDoc::GetRootAutoVisGroup()
  9144. {
  9145. // Find the 'auto' visgroup
  9146. CVisGroup *pFoundVisGroup = NULL;
  9147. int nVisGroupCount = VisGroups_GetRootCount();
  9148. for ( int i = 0; i < nVisGroupCount; ++i )
  9149. {
  9150. CVisGroup *pVisGroup = VisGroups_GetRootVisGroup(i);
  9151. if ( !Q_stricmp( "Auto", pVisGroup->GetName() ) )
  9152. {
  9153. pFoundVisGroup = pVisGroup;
  9154. break;
  9155. }
  9156. }
  9157. if ( !pFoundVisGroup )
  9158. {
  9159. pFoundVisGroup = VisGroups_AddGroup( "Auto", true );
  9160. }
  9161. return pFoundVisGroup;
  9162. }
  9163. //-----------------------------------------------------------------------------
  9164. // Determine visgroup and add it to that.
  9165. //-----------------------------------------------------------------------------
  9166. void CMapDoc::AddToAutoVisGroup( CMapClass *pObject )
  9167. {
  9168. if ( !pObject || !VisGroups_ObjectCanBelongToVisGroup( pObject ) )
  9169. return;
  9170. if ( pObject->IsMapClass( MAPCLASS_TYPE(CMapEntity) ) )
  9171. {
  9172. CMapEntity *pMapEntity = assert_cast<CMapEntity*>( pObject );
  9173. if ( pMapEntity->IsPointClass() )
  9174. {
  9175. // Point entities.
  9176. if ( !pMapEntity->IsNodeClass() )
  9177. {
  9178. AddChildGroupToAutoVisGroup( pObject, "Point Entities", "Entities" );
  9179. }
  9180. else
  9181. {
  9182. AddChildGroupToAutoVisGroup( pObject, "Nodes", "Entities" );
  9183. }
  9184. if ( pMapEntity->IsNPCClass() )
  9185. {
  9186. AddChildGroupToAutoVisGroup( pObject, "NPCs", "Entities" );
  9187. }
  9188. if ( !Q_stricmp( pMapEntity->GetClassName(), "func_instance" ) )
  9189. {
  9190. AddToAutoVisGroup( pObject, "Instances" );
  9191. }
  9192. if ( !Q_strnicmp( pMapEntity->GetClassName(), "light_", strlen("light_") ) )
  9193. {
  9194. AddChildGroupToAutoVisGroup( pObject, "Lights", "Entities" );
  9195. }
  9196. if ( !Q_strnicmp( pMapEntity->GetClassName(), "prop_", strlen("prop_") ) )
  9197. {
  9198. AddChildGroupToAutoVisGroup( pObject, "Props", "World Details" );
  9199. }
  9200. if ( !Q_strnicmp( pMapEntity->GetClassName(), "prop_physics", strlen("prop_physics") ) )
  9201. {
  9202. AddChildGroupToAutoVisGroup( pObject, "Physics Props", "Entities" );
  9203. }
  9204. if ( !Q_stricmp( pMapEntity->GetClassName(), "env_sprite" ) )
  9205. {
  9206. AddChildGroupToAutoVisGroup( pObject, "Sprites", "Entities" );
  9207. }
  9208. }
  9209. else
  9210. {
  9211. // Solid entities.
  9212. if ( !pMapEntity->IsClass("func_detail") )
  9213. {
  9214. AddChildGroupToAutoVisGroup( pObject, "Brush Entities", "Entities" );
  9215. }
  9216. else
  9217. {
  9218. AddChildGroupToAutoVisGroup( pObject, "Func Detail", "World Details" );
  9219. }
  9220. if ( !Q_strnicmp( pMapEntity->GetClassName(), "trigger_", strlen("trigger_") ) )
  9221. {
  9222. AddChildGroupToAutoVisGroup( pObject, "Triggers", "Entities" );
  9223. }
  9224. // Area portals and area portal windows.
  9225. if ( !Q_strnicmp( pMapEntity->GetClassName(), "func_areaportal", strlen("func_areaportal") ) )
  9226. {
  9227. AddChildGroupToAutoVisGroup( pObject, "Areaportals", "Tool Brushes" );
  9228. }
  9229. if ( pMapEntity->IsClass("func_viscluster") )
  9230. {
  9231. AddChildGroupToAutoVisGroup( pObject, "Visclusters", "Tool Brushes" );
  9232. }
  9233. if ( pMapEntity->IsClass("func_occluder") )
  9234. {
  9235. AddChildGroupToAutoVisGroup( pObject, "Occluders", "Tool Brushes" );
  9236. }
  9237. }
  9238. }
  9239. else if ( pObject->IsMapClass( MAPCLASS_TYPE(CMapSolid) ) )
  9240. {
  9241. CMapSolid *pMapSolid = assert_cast<CMapSolid*>( pObject );
  9242. if ( pMapSolid->HasDisp() )
  9243. {
  9244. AddChildGroupToAutoVisGroup( pObject, "Displacements", "World Geometry" );
  9245. }
  9246. else
  9247. {
  9248. CMapClass *pParent = pObject->GetParent();
  9249. CMapEntity *pParentEntity = dynamic_cast<CMapEntity*>( pParent );
  9250. if ( !pParentEntity )
  9251. {
  9252. AddToAutoVisGroup( pObject, "World Geometry" );
  9253. }
  9254. }
  9255. char buf[1024];
  9256. bool bWaterAdded = false;
  9257. for ( int i = 0; i < pMapSolid->GetFaceCount(); i++ )
  9258. {
  9259. //this check will ensure that an object with a water material on multiple faces will only be added once
  9260. if ( !bWaterAdded )
  9261. {
  9262. IMaterial *pMaterial = pMapSolid->GetFace( i )->GetTexture()->GetMaterial();
  9263. if ( pMaterial )
  9264. {
  9265. pMaterial->FindVar( "%compileWater", &bWaterAdded, false );
  9266. if ( bWaterAdded )
  9267. {
  9268. AddChildGroupToAutoVisGroup( pObject, "Water", "World Geometry" );
  9269. }
  9270. }
  9271. }
  9272. //same check for tool objects
  9273. pMapSolid->GetFace( i )->GetTextureName( buf );
  9274. if ( strstr( buf, "tools/tools" ) )
  9275. {
  9276. if ( strstr( buf, "tools/toolsnodraw" ) )
  9277. {
  9278. AddChildGroupToAutoVisGroup( pObject, "Nodraw", "World Geometry" );
  9279. continue;
  9280. }
  9281. if ( strstr( buf, "tools/toolssky" ) )
  9282. {
  9283. AddChildGroupToAutoVisGroup( pObject, "Sky", "World Geometry" );
  9284. continue;
  9285. }
  9286. if ( strstr( buf, "tools/toolsblock" ) )
  9287. {
  9288. AddAutoVisGroup( "Block", "Tool Brushes" );
  9289. if ( strstr( buf, "block_los" ) )
  9290. {
  9291. AddChildGroupToAutoVisGroup( pObject, "LOS", "Block" );
  9292. continue;
  9293. }
  9294. else if ( strstr( buf, "blockbullets" ) )
  9295. {
  9296. AddChildGroupToAutoVisGroup( pObject, "Bullets", "Block" );
  9297. continue;
  9298. }
  9299. else if ( strstr( buf, "blocklight" ) )
  9300. {
  9301. AddChildGroupToAutoVisGroup( pObject, "Light", "Block" );
  9302. continue;
  9303. }
  9304. }
  9305. if ( strstr( buf, "tools/tools" ) && strstr( buf, "clip" ) )
  9306. {
  9307. AddAutoVisGroup( "Clips", "Tool Brushes" );
  9308. if ( strstr( buf, "npcclip" ) )
  9309. {
  9310. AddChildGroupToAutoVisGroup( pObject, "NPC", "Clips" );
  9311. continue;
  9312. }
  9313. else if ( strstr( buf, "playerclip" ) )
  9314. {
  9315. AddChildGroupToAutoVisGroup( pObject, "Player", "Clips" );
  9316. continue;
  9317. }
  9318. else if ( strstr( buf, "controlclip" ) )
  9319. {
  9320. AddChildGroupToAutoVisGroup( pObject, "Control", "Clips" );
  9321. continue;
  9322. }
  9323. else if ( strstr( buf, "clip" ) )
  9324. {
  9325. AddChildGroupToAutoVisGroup( pObject, "Clip", "Clips" );
  9326. continue;
  9327. }
  9328. }
  9329. if ( strstr( buf, "occluder" ) )
  9330. {
  9331. AddChildGroupToAutoVisGroup( pObject, "Occluder", "Tool Brushes");
  9332. continue;
  9333. }
  9334. if ( strstr( buf, "areaportal") )
  9335. {
  9336. AddChildGroupToAutoVisGroup( pObject, "Area Portal", "Tool Brushes");
  9337. continue;
  9338. }
  9339. if ( strstr( buf, "invisible") )
  9340. {
  9341. AddAutoVisGroup( "Invisible", "Tool Brushes" );
  9342. if ( strstr( buf, "invisibleladder") )
  9343. {
  9344. AddChildGroupToAutoVisGroup( pObject, "Ladder", "Invisible");
  9345. continue;
  9346. }
  9347. else if ( strstr( buf, "invisible") )
  9348. {
  9349. AddChildGroupToAutoVisGroup( pObject, "Invisible", "Invisible");
  9350. continue;
  9351. }
  9352. }
  9353. if ( strstr( buf, "skip" ) )
  9354. {
  9355. AddChildGroupToAutoVisGroup( pObject, "Skip", "Tool Brushes" );
  9356. continue;
  9357. }
  9358. if ( strstr( buf, "trigger" ) )
  9359. {
  9360. AddChildGroupToAutoVisGroup( pObject, "Trigger", "Tool Brushes" );
  9361. continue;
  9362. }
  9363. if ( strstr( buf, "origin" ) )
  9364. {
  9365. AddChildGroupToAutoVisGroup( pObject, "Origin", "Tool Brushes" );
  9366. continue;
  9367. }
  9368. if ( strstr( buf, "hint" ) )
  9369. {
  9370. AddChildGroupToAutoVisGroup( pObject, "Hint", "Tool Brushes" );
  9371. continue;
  9372. }
  9373. if ( strstr( buf, "fog" ) )
  9374. {
  9375. AddChildGroupToAutoVisGroup( pObject, "Fog", "Tool Brushes" );
  9376. continue;
  9377. }
  9378. if ( strstr( buf, "black" ) )
  9379. {
  9380. AddChildGroupToAutoVisGroup( pObject, "Black", "World Geometry" );
  9381. continue;
  9382. }
  9383. }
  9384. }
  9385. }
  9386. else if (pObject->IsGroup())
  9387. {
  9388. // Recurse into the children of groups.
  9389. const CMapObjectList *pChildren = pObject->GetChildren();
  9390. FOR_EACH_OBJ( *pChildren, pos )
  9391. {
  9392. AddToAutoVisGroup( (CUtlReference< CMapClass >)pChildren->Element(pos) );
  9393. AddToFGDAutoVisGroups( (CUtlReference< CMapClass >)pChildren->Element( pos ) );
  9394. }
  9395. }
  9396. // See if this Object type exists in FGD AutoVisGroups
  9397. if ( pGD->m_FGDAutoVisGroups.Count() > 0 && !( pObject->IsGroup() ) )
  9398. {
  9399. AddToFGDAutoVisGroups( pObject );
  9400. }
  9401. }
  9402. //-----------------------------------------------------------------------------
  9403. // Purpose:
  9404. // Input : *pObject -
  9405. //-----------------------------------------------------------------------------
  9406. void CMapDoc::AddToAutoVisGroup( CMapClass *pObject, const char *pAutoVisGroup )
  9407. {
  9408. CVisGroup *pFoundVisGroup = VisGroups_GroupForName( pAutoVisGroup, true );
  9409. if ( !pFoundVisGroup )
  9410. {
  9411. pFoundVisGroup = VisGroups_AddGroup( pAutoVisGroup, true );
  9412. VisGroups_SetParent( pFoundVisGroup, GetRootAutoVisGroup() );
  9413. }
  9414. CMapObjectList Objects;
  9415. Objects.AddToTail( pObject );
  9416. VisGroups_AddObjectsToVisGroup( Objects, pFoundVisGroup, false, false );
  9417. }
  9418. //-----------------------------------------------------------------------------
  9419. // Creates an auto visgroup with no members.
  9420. //-----------------------------------------------------------------------------
  9421. void CMapDoc::AddAutoVisGroup( const char *pNewGroupName, const char *pParentName )
  9422. {
  9423. // If the group already exists, bail.
  9424. CVisGroup *pNewGroup = VisGroups_GroupForName( pNewGroupName, true );
  9425. if ( pNewGroup )
  9426. return;
  9427. // Ensure that the parent exists.
  9428. CVisGroup *pParentGroup = VisGroups_GroupForName( pParentName, true );
  9429. if ( !pParentGroup )
  9430. {
  9431. pParentGroup = VisGroups_AddGroup( pParentName, true );
  9432. VisGroups_SetParent( pParentGroup, GetRootAutoVisGroup() );
  9433. }
  9434. // Create the new group and link it in.
  9435. pNewGroup = VisGroups_AddGroup( pNewGroupName, true );
  9436. VisGroups_SetParent( pNewGroup, pParentGroup );
  9437. }
  9438. //-----------------------------------------------------------------------------
  9439. // Adds the object to the given auto visgroup, creating the visgroup if it
  9440. // doesn't exist.
  9441. //-----------------------------------------------------------------------------
  9442. void CMapDoc::AddChildGroupToAutoVisGroup( CMapClass *pObject, const char *pAutoVisGroup, const char *pParentName )
  9443. {
  9444. AddAutoVisGroup( pAutoVisGroup, pParentName );
  9445. if ( pObject )
  9446. {
  9447. AddToAutoVisGroup( pObject, pAutoVisGroup );
  9448. }
  9449. }
  9450. //-----------------------------------------------------------------------------
  9451. // Remove from all auto visgroup
  9452. //-----------------------------------------------------------------------------
  9453. void CMapDoc::RemoveFromAutoVisGroups( CMapClass *pObject )
  9454. {
  9455. if ( !pObject )
  9456. return;
  9457. bool bChanged = false;
  9458. int nVisGroupCount = pObject->GetVisGroupCount();
  9459. for (int nVisGroup = nVisGroupCount - 1; nVisGroup >= 0; nVisGroup--)
  9460. {
  9461. CVisGroup *pVisGroup = pObject->GetVisGroup(nVisGroup);
  9462. // Don't add autovisgroups when moving back
  9463. if ( pVisGroup->IsAutoVisGroup() )
  9464. {
  9465. pObject->RemoveVisGroup(pVisGroup);
  9466. bChanged = true;
  9467. }
  9468. }
  9469. if ( bChanged )
  9470. {
  9471. UpdateVisibility(pObject);
  9472. }
  9473. }
  9474. //-----------------------------------------------------------------------------
  9475. // Determine visgroup
  9476. //-----------------------------------------------------------------------------
  9477. void CMapDoc::AssignAllToAutoVisGroups()
  9478. {
  9479. bool bLocked = VisGroups_LockUpdates( true );
  9480. EnumChildrenPos_t pos;
  9481. CMapClass *pChild = m_pWorld->GetFirstDescendent(pos);
  9482. while (pChild)
  9483. {
  9484. AddToAutoVisGroup( pChild );
  9485. pChild = m_pWorld->GetNextDescendent(pos);
  9486. }
  9487. if ( bLocked )
  9488. {
  9489. VisGroups_LockUpdates( false );
  9490. }
  9491. }
  9492. //-----------------------------------------------------------------------------
  9493. // Purpose: Adds an object to the world. This is the ONLY correct way to add an
  9494. // object to the world. Calling directly through AddChild skips a bunch
  9495. // of necessary bookkeeping.
  9496. // Input : pObject - object being added to the world.
  9497. //-----------------------------------------------------------------------------
  9498. void CMapDoc::AddObjectToWorld(CMapClass *pObject, CMapClass *pParent)
  9499. {
  9500. Assert(pObject != NULL);
  9501. if (pObject != NULL)
  9502. {
  9503. m_pWorld->AddObjectToWorld(pObject, pParent);
  9504. // Auto visgroups!
  9505. AddToAutoVisGroup( pObject );
  9506. //
  9507. // Give the renderer a chance to precache data.
  9508. //
  9509. RenderPreloadObject(pObject);
  9510. //
  9511. // Update the object's visibility. This will recurse into solid children of entities as well.
  9512. //
  9513. UpdateVisibility(pObject);
  9514. // Set a reasonable default
  9515. Vector2D vecLogicalPos = pObject->GetLogicalPosition();
  9516. if ( vecLogicalPos.x == COORD_NOTINIT )
  9517. {
  9518. GetDefaultNewLogicalPosition( vecLogicalPos );
  9519. pObject->SetLogicalPosition( vecLogicalPos );
  9520. }
  9521. }
  9522. }
  9523. //-----------------------------------------------------------------------------
  9524. // Purpose: Removes an object from the world object tree.
  9525. // Input : pObject - object being removed from the world.
  9526. //-----------------------------------------------------------------------------
  9527. void CMapDoc::RemoveObjectFromWorld(CMapClass *pObject, bool bRemoveChildren)
  9528. {
  9529. Assert(pObject != NULL);
  9530. if (pObject != NULL)
  9531. {
  9532. m_pWorld->RemoveObjectFromWorld(pObject, bRemoveChildren);
  9533. //
  9534. // Clean up any visgroups with no members.
  9535. //
  9536. VisGroups_PurgeGroups();
  9537. // Remove the object from the update list.
  9538. m_UpdateList.FindAndFastRemove(pObject);
  9539. // remove object from selection list
  9540. m_pSelection->SelectObject(pObject, scUnselect );
  9541. pObject->SignalChanged();
  9542. }
  9543. }
  9544. //-----------------------------------------------------------------------------
  9545. // Purpose:
  9546. // Input : pObject -
  9547. //-----------------------------------------------------------------------------
  9548. void CMapDoc::RenderPreloadObject(CMapClass *pObject)
  9549. {
  9550. POSITION p = GetFirstViewPosition();
  9551. while (p)
  9552. {
  9553. CView *pView = GetNextView(p);
  9554. if (pView->IsKindOf(RUNTIME_CLASS(CMapView3D)))
  9555. {
  9556. CMapView3D *pView3D = (CMapView3D *)pView;
  9557. pView3D->RenderPreloadObject(pObject);
  9558. }
  9559. }
  9560. }
  9561. //-----------------------------------------------------------------------------
  9562. // Calculates the aggregate bounds of all the active cordons.
  9563. // CORDON TODO: this can go away when MAP file serialization is deleted
  9564. //-----------------------------------------------------------------------------
  9565. void CMapDoc::Cordon_GetBounds( Vector &mins, Vector &maxs )
  9566. {
  9567. mins.Init(COORD_NOTINIT, COORD_NOTINIT, COORD_NOTINIT);
  9568. maxs.Init(-COORD_NOTINIT, -COORD_NOTINIT, -COORD_NOTINIT);
  9569. for ( int i = 0; i < m_Cordons.Count(); i++ )
  9570. {
  9571. if ( !m_Cordons[i].m_bActive )
  9572. continue;
  9573. for ( int nBox = 0; nBox < m_Cordons[i].m_Boxes.Count(); nBox++ )
  9574. {
  9575. // Push out maxs
  9576. for ( int j = 0; j < 3; j++ )
  9577. {
  9578. if ( m_Cordons[i].m_Boxes[nBox].bmaxs[j] > maxs[j] )
  9579. {
  9580. maxs[j] = m_Cordons[i].m_Boxes[nBox].bmaxs[j];
  9581. }
  9582. }
  9583. // Push out mins
  9584. for ( int j = 0; j < 3; j++ )
  9585. {
  9586. if ( m_Cordons[i].m_Boxes[nBox].bmins[j] < mins[j] )
  9587. {
  9588. mins[j] = m_Cordons[i].m_Boxes[nBox].bmins[j];
  9589. }
  9590. }
  9591. }
  9592. }
  9593. }
  9594. //-----------------------------------------------------------------------------
  9595. // Purpose: Creates a world with the brushes that make up the cordoned area.
  9596. // It does this by creating a solid of the size of the cordon
  9597. // box, and another solid 1200 units bigger. Subtract A from B, and
  9598. // keep those brushes.
  9599. // Output : Returns a pointer to the newly-created world.
  9600. //-----------------------------------------------------------------------------
  9601. CMapWorld *CMapDoc::Cordon_CreateWorld()
  9602. {
  9603. CMapWorld *pWorld = new CMapWorld( NULL );
  9604. GetHistory()->Pause();
  9605. //
  9606. // Make a giant box the size of the maximum map extents.
  9607. //
  9608. CMapSolid *pBigSolid = new CMapSolid;
  9609. pBigSolid->SetCordonBrush( true );
  9610. // dvs: FIXME: vbsp barfs if I go all the way out to the full mins & maxs
  9611. BoundBox bigbounds( Vector( g_MIN_MAP_COORD + 8, g_MIN_MAP_COORD + 8, g_MIN_MAP_COORD + 8 ),
  9612. Vector( g_MAX_MAP_COORD - 8, g_MAX_MAP_COORD - 8, g_MAX_MAP_COORD - 8 ) );
  9613. StockBlock box;
  9614. box.SetFromBox( &bigbounds );
  9615. box.CreateMapSolid( pBigSolid, Options.GetTextureAlignment() );
  9616. // Add the big solid to our list of outer solids. It's our first cordon brush.
  9617. CUtlVector<CMapSolid *> outerSolids;
  9618. outerSolids.AddToTail( pBigSolid );
  9619. //
  9620. // Create brush proxies for our cordon boxes so that we can use them in subtraction operations.
  9621. // They'll be the inner solids.
  9622. //
  9623. CUtlVector<CMapSolid *> innerSolids;
  9624. for ( int i = 0; i < m_Cordons.Count(); i++ )
  9625. {
  9626. if ( !m_Cordons[i].m_bActive )
  9627. continue;
  9628. for ( int j = 0; j < m_Cordons[i].m_Boxes.Count(); j++ )
  9629. {
  9630. CMapSolid *pSolid = new CMapSolid;
  9631. box.SetFromBox( &m_Cordons[i].m_Boxes[j] );
  9632. box.CreateMapSolid( pSolid, Options.GetTextureAlignment() );
  9633. innerSolids.AddToTail( pSolid );
  9634. }
  9635. }
  9636. //
  9637. // Subtract each cordon brush from everything in the outerSolids list,
  9638. // adding the results to the outerSolids list. This will yield a list
  9639. // of brushes surrounding the cordoned-off areas.
  9640. //
  9641. for ( int j = 0; j < innerSolids.Count(); j++ )
  9642. {
  9643. CUtlVector<CMapSolid *> tempResults;
  9644. for ( int i = 0; i < outerSolids.Count(); i++ )
  9645. {
  9646. CMapObjectList outside;
  9647. if ( !outerSolids[i]->Subtract( NULL, &outside, innerSolids[j] ) )
  9648. {
  9649. tempResults.AddToTail( outerSolids[i] );
  9650. continue;
  9651. }
  9652. for ( int k = 0; k < outside.Count(); k++ )
  9653. {
  9654. CMapClass *pResult = outside[k];
  9655. if ( pResult->IsMapClass( MAPCLASS_TYPE(CMapSolid) ) )
  9656. {
  9657. tempResults.AddToTail( (CMapSolid *)pResult );
  9658. }
  9659. else
  9660. {
  9661. Assert( false );
  9662. }
  9663. }
  9664. outside.RemoveAll();
  9665. }
  9666. // Transfer the results of those subtractions to the list of outer solids.
  9667. outerSolids.RemoveAll();
  9668. outerSolids.AddVectorToTail( tempResults );
  9669. tempResults.RemoveAll();
  9670. }
  9671. //
  9672. // Add all the resulting brushes to the cordon world for return to the caller.
  9673. //
  9674. const char *cordonTexture = g_pGameConfig->GetCordonTexture();
  9675. for ( int i = 0; i < outerSolids.Count(); i++ )
  9676. {
  9677. outerSolids[i]->SetCordonBrush( true );
  9678. outerSolids[i]->SetTexture( cordonTexture );
  9679. pWorld->AddObjectToWorld( outerSolids[i] );
  9680. }
  9681. GetHistory()->Resume();
  9682. return pWorld;
  9683. }
  9684. //-----------------------------------------------------------------------------
  9685. //-----------------------------------------------------------------------------
  9686. ChunkFileResult_t CMapDoc::Cordon_SaveVMF(CChunkFile *pFile, CSaveInfo *pSaveInfo)
  9687. {
  9688. ChunkFileResult_t eResult = ChunkFile_Ok;
  9689. if ((eResult = pFile->BeginChunk("cordons")) != ChunkFile_Ok)
  9690. return eResult;
  9691. if ((eResult = pFile->WriteKeyValueBool("active", m_bIsCordoning )) != ChunkFile_Ok)
  9692. return eResult;
  9693. for (int i = 0; i < m_Cordons.Count(); i++)
  9694. {
  9695. // Each cordon is in its own subchunk
  9696. if ((eResult = pFile->BeginChunk("cordon")) != ChunkFile_Ok)
  9697. return eResult;
  9698. if ((eResult = pFile->WriteKeyValue("name", m_Cordons[i].m_szName)) != ChunkFile_Ok)
  9699. return eResult;
  9700. if ((eResult = pFile->WriteKeyValueBool("active", m_Cordons[i].m_bActive)) != ChunkFile_Ok)
  9701. return eResult;
  9702. // This stuff is in the box subchunk
  9703. for (int j = 0; j < m_Cordons[i].m_Boxes.Count(); j++)
  9704. {
  9705. if ((eResult = pFile->BeginChunk("box")) != ChunkFile_Ok)
  9706. return eResult;
  9707. if ((eResult = pFile->WriteKeyValuePoint("mins", m_Cordons[i].m_Boxes[j].bmins)) != ChunkFile_Ok)
  9708. return eResult;
  9709. if ((eResult = pFile->WriteKeyValuePoint("maxs", m_Cordons[i].m_Boxes[j].bmaxs)) != ChunkFile_Ok)
  9710. return eResult;
  9711. if ((eResult = pFile->EndChunk()) != ChunkFile_Ok)
  9712. return eResult;
  9713. }
  9714. if ((eResult = pFile->EndChunk()) != ChunkFile_Ok)
  9715. return eResult;
  9716. }
  9717. return pFile->EndChunk();
  9718. }
  9719. //-----------------------------------------------------------------------------
  9720. // Purpose:
  9721. // Input : *pszFileName -
  9722. //-----------------------------------------------------------------------------
  9723. bool CMapDoc::SaveVMF(const char *pszFileName, int saveFlags )
  9724. {
  9725. CChunkFile File;
  9726. ChunkFileResult_t eResult = File.Open(pszFileName, ChunkFile_Write);
  9727. BeginWaitCursor();
  9728. // Change the main title bar.
  9729. GetMainWnd()->SetWindowText( "Saving..." );
  9730. // We can optionally use these calls if we want the document name to go away so the title bar only says "Saving...".
  9731. //GetMainWnd()->ModifyStyle( FWS_ADDTOTITLE, 0 ); //GetMainWnd()->ModifyStyle( 0, FWS_ADDTOTITLE );
  9732. if (eResult == ChunkFile_Ok)
  9733. {
  9734. CSaveInfo SaveInfo;
  9735. CMapObjectList CordonList;
  9736. CMapWorld *pCordonWorld = NULL;
  9737. if (!m_bPrefab && !(saveFlags & SAVEFLAGS_LIGHTSONLY))
  9738. {
  9739. SaveInfo.SetVisiblesOnly(bSaveVisiblesOnly == TRUE);
  9740. //
  9741. // Add cordon objects.
  9742. //
  9743. if ( m_bIsCordoning )
  9744. {
  9745. //
  9746. // Create "cordon world", add its objects to our real world, create a list in
  9747. // CordonList so we can remove them again.
  9748. //
  9749. pCordonWorld = Cordon_CreateWorld();
  9750. const CMapObjectList *pChildren = pCordonWorld->GetChildren();
  9751. // AddObjectToWorld magically removes our children, so keep going until all
  9752. // of our children have left us to enter the world.
  9753. while( pCordonWorld->GetChildren()->Count() )
  9754. {
  9755. CMapClass *pChild = (CUtlReference< CMapClass >)pChildren->Element(0); // each time we remove the first element so we can just get this every time.
  9756. pChild->SetTemporary(TRUE);
  9757. m_pWorld->AddObjectToWorld(pChild);
  9758. CordonList.AddToTail(pChild);
  9759. }
  9760. }
  9761. }
  9762. //
  9763. // Write the map file version.
  9764. //
  9765. if (eResult == ChunkFile_Ok)
  9766. {
  9767. bool bIsAutosave = false;
  9768. if ( SAVEFLAGS_AUTOSAVE & saveFlags )
  9769. {
  9770. bIsAutosave = true;
  9771. }
  9772. eResult = SaveVersionInfoVMF(&File, bIsAutosave);
  9773. }
  9774. //
  9775. // Save VisGroups information. Save this first so that we can assign visgroups while loading objects.
  9776. //
  9777. if (!m_bPrefab && !(saveFlags & SAVEFLAGS_LIGHTSONLY))
  9778. {
  9779. eResult = VisGroups_SaveVMF(&File, &SaveInfo);
  9780. }
  9781. //
  9782. // Save view related settings (grid setting, splitter proportions, etc)
  9783. //
  9784. if (eResult == ChunkFile_Ok)
  9785. {
  9786. eResult = SaveViewSettingsVMF(&File, &SaveInfo);
  9787. }
  9788. // Save the world.
  9789. if (eResult == ChunkFile_Ok)
  9790. {
  9791. eResult = m_pWorld->SaveVMF(&File, &SaveInfo, saveFlags & SAVEFLAGS_LIGHTSONLY);
  9792. }
  9793. if (!m_bPrefab && !(saveFlags & SAVEFLAGS_LIGHTSONLY))
  9794. {
  9795. //
  9796. // Remove cordon objects from the real world.
  9797. //
  9798. if ( m_bIsCordoning )
  9799. {
  9800. FOR_EACH_OBJ( CordonList, pos )
  9801. {
  9802. CMapClass *pobj = CordonList.Element(pos);
  9803. m_pWorld->RemoveObjectFromWorld(pobj, true);
  9804. }
  9805. //
  9806. // The cordon objects will be deleted in the cordon world's destructor.
  9807. //
  9808. delete pCordonWorld;
  9809. }
  9810. // Save tool information.
  9811. if (eResult == ChunkFile_Ok)
  9812. {
  9813. eResult = m_pToolManager->SaveVMF(&File, &SaveInfo);
  9814. }
  9815. if (eResult == ChunkFile_Ok)
  9816. {
  9817. eResult = Cordon_SaveVMF(&File, &SaveInfo);
  9818. }
  9819. // We use this to flag VMFs checked-in to P4 with QuickHide active
  9820. if ( eResult == ChunkFile_Ok )
  9821. {
  9822. eResult = QuickHide_SaveVMF( &File, &SaveInfo );
  9823. }
  9824. }
  9825. File.Close();
  9826. }
  9827. // Restore the main window's title.
  9828. GetMainWnd()->OnUpdateFrameTitle( true );
  9829. if (eResult != ChunkFile_Ok)
  9830. {
  9831. GetMainWnd()->MessageBox(File.GetErrorText(eResult), "Error Saving File", MB_OK);
  9832. }
  9833. else
  9834. {
  9835. //save filename into registry for last known good file for crash recovery purposes.
  9836. AfxGetApp()->WriteProfileString("General", "Last Good Save", pszFileName);
  9837. }
  9838. EndWaitCursor();
  9839. return( eResult == ChunkFile_Ok );
  9840. }
  9841. //-----------------------------------------------------------------------------
  9842. // Purpose: Saves the version information chunk.
  9843. // Input : *pFile -
  9844. // Output : Returns ChunkFile_Ok on success, an error code on failure.
  9845. //-----------------------------------------------------------------------------
  9846. ChunkFileResult_t CMapDoc::SaveVersionInfoVMF(CChunkFile *pFile, bool bIsAutoSave)
  9847. {
  9848. ChunkFileResult_t eResult = pFile->BeginChunk("versioninfo");
  9849. if (eResult == ChunkFile_Ok)
  9850. {
  9851. eResult = pFile->WriteKeyValueInt("editorversion", 400);
  9852. }
  9853. if (eResult == ChunkFile_Ok)
  9854. {
  9855. eResult = pFile->WriteKeyValueInt("editorbuild", build_number());
  9856. }
  9857. if (eResult == ChunkFile_Ok)
  9858. {
  9859. eResult = pFile->WriteKeyValueInt("mapversion", GetDocVersion());
  9860. }
  9861. if (eResult == ChunkFile_Ok)
  9862. {
  9863. eResult = pFile->WriteKeyValueInt("formatversion", VMF_FORMAT_VERSION);
  9864. }
  9865. if (eResult == ChunkFile_Ok)
  9866. {
  9867. eResult = pFile->WriteKeyValueBool("prefab", m_bPrefab);
  9868. }
  9869. if ( eResult == ChunkFile_Ok && bIsAutoSave )
  9870. {
  9871. eResult = pFile->BeginChunk("autosave");
  9872. if ( eResult == ChunkFile_Ok )
  9873. {
  9874. char szOriginalName[MAX_PATH];
  9875. strcpy(szOriginalName, GetPathName());
  9876. if ( strlen( szOriginalName ) == 0 )
  9877. {
  9878. strcpy(szOriginalName, g_pGameConfig->szMapDir);
  9879. strcat(szOriginalName, "\\untitled.vmf");
  9880. //put in the default map path + untitled.vmf
  9881. }
  9882. Q_FixSlashes( szOriginalName, '/' );
  9883. eResult = pFile->WriteKeyValue( "originalname", szOriginalName );
  9884. if ( eResult == ChunkFile_Ok )
  9885. {
  9886. eResult = pFile->EndChunk();
  9887. }
  9888. }
  9889. }
  9890. if (eResult == ChunkFile_Ok)
  9891. {
  9892. eResult = pFile->EndChunk();
  9893. }
  9894. return(eResult);
  9895. }
  9896. //-----------------------------------------------------------------------------
  9897. // Purpose: Call this function after you have made any modifications to the document.
  9898. // By calling this function consistently, you ensure that the framework
  9899. // prompts the user to save changes before closing a document.
  9900. // Input : bModified - TRUE to mark the doc as modified, FALSE to mark it as clean.
  9901. //-----------------------------------------------------------------------------
  9902. void CMapDoc::SetModifiedFlag(BOOL bModified)
  9903. {
  9904. //
  9905. // Increment internal version number when the doc changes from clean to dirty.
  9906. // CShell::BeginSession checks this version number, enabling us to detect
  9907. // out-of-sync problems when editing the map in the engine.
  9908. //
  9909. if ((bModified) && !IsModified())
  9910. {
  9911. m_nDocVersion++;
  9912. }
  9913. if ( bModified )
  9914. {
  9915. SetAutosaveFlag( bModified );
  9916. m_pSelection->SetBoundsDirty();
  9917. GetMainWnd()->pObjectProperties->MarkDataDirty();
  9918. UpdateAllViews( MAPVIEW_UPDATE_OBJECTS );
  9919. }
  9920. CDocument::SetModifiedFlag(bModified);
  9921. }
  9922. void CMapDoc::SetAutosaveFlag( BOOL bNeedsAutosave )
  9923. {
  9924. m_bNeedsAutosave = bNeedsAutosave;
  9925. }
  9926. BOOL CMapDoc::NeedsAutosave()
  9927. {
  9928. return m_bNeedsAutosave;
  9929. }
  9930. BOOL CMapDoc::IsAutosave()
  9931. {
  9932. return m_bIsAutosave;
  9933. }
  9934. CString *CMapDoc::AutosavedFrom()
  9935. {
  9936. return &m_strAutosavedFrom;
  9937. }
  9938. //-----------------------------------------------------------------------------
  9939. // Purpose: this function adds an external reference count to a map
  9940. //-----------------------------------------------------------------------------
  9941. void CMapDoc::AddReference( void )
  9942. {
  9943. m_nExternalReferenceCount++;
  9944. }
  9945. //-----------------------------------------------------------------------------
  9946. // Purpose: this function removes an external reference count from a map. If it is hidden
  9947. // and modified, the document will be made visible.
  9948. //-----------------------------------------------------------------------------
  9949. void CMapDoc::RemoveReference( void )
  9950. {
  9951. m_nExternalReferenceCount--;
  9952. if ( m_nExternalReferenceCount <= 0 )
  9953. {
  9954. if ( !IsVisible() )
  9955. {
  9956. if ( IsModified() )
  9957. {
  9958. ShowWindow( true );
  9959. }
  9960. else
  9961. {
  9962. OnCloseDocument();
  9963. }
  9964. }
  9965. }
  9966. }
  9967. //-----------------------------------------------------------------------------
  9968. // Purpose:
  9969. // Input : bActive -
  9970. //-----------------------------------------------------------------------------
  9971. void CMapDoc::SetUndoActive(bool bActive)
  9972. {
  9973. m_pUndo->SetActive(bActive);
  9974. m_pRedo->SetActive(bActive);
  9975. }
  9976. bool CMapDoc::IsCulledBy3DCameraDistance( CMapClass *pObject, UpdateVisibilityData_t *pData )
  9977. {
  9978. if ( pObject->IsWorld() || pObject->IsGroup() )
  9979. return false;
  9980. if ( pObject->IsSelected() )
  9981. return false;
  9982. Vector objectPos;
  9983. pObject->GetOrigin( objectPos );
  9984. float flDistance = ( pData->vecRadiusCullCenter - objectPos ).LengthSqr();
  9985. if ( flDistance >= pData->flRadiusCullDistSq )
  9986. return true;
  9987. return false;
  9988. }
  9989. //-----------------------------------------------------------------------------
  9990. // Purpose: Returns the hidden/shown state of the given object based on the current
  9991. // settings including selection mode, visgroups, and cordon bounds.
  9992. // Input : pObject -
  9993. //-----------------------------------------------------------------------------
  9994. bool CMapDoc::ShouldObjectBeVisible(CMapClass *pObject, UpdateVisibilityData_t *pData)
  9995. {
  9996. #if defined(_DEBUG) && 0
  9997. CMapEntity *pEntity = dynamic_cast<CMapEntity *>(pObject);
  9998. if (pEntity)
  9999. {
  10000. LPCTSTR pszTargetName = pEntity->GetKeyValue("targetname");
  10001. if ( pszTargetName && !strcmp(pszTargetName, "relay_cancelVCDs") )
  10002. {
  10003. // Set breakpoint here for debugging this entity's visiblity
  10004. int foo = 0;
  10005. }
  10006. }
  10007. #endif
  10008. if ( QuickHide_IsObjectHidden( pObject ) )
  10009. {
  10010. return false;
  10011. }
  10012. if ( pData->bRadiusCullingEnabled )
  10013. {
  10014. if ( IsCulledBy3DCameraDistance( pObject, pData ) )
  10015. {
  10016. return false;
  10017. }
  10018. }
  10019. //
  10020. // If hide entities is enabled and the object is an entity, hide the object.
  10021. //
  10022. if (m_bHideItems)
  10023. {
  10024. CMapEntity *pEntity = dynamic_cast<CMapEntity *>(pObject);
  10025. if ((pEntity != NULL) && (pEntity->IsPlaceholder()))
  10026. {
  10027. return(false);
  10028. }
  10029. }
  10030. //
  10031. // If the object hides as clutter and clutter is currently hidden, hide it.
  10032. //
  10033. if (pObject->IsClutter() && !Options.GetShowHelpers() )
  10034. {
  10035. return false;
  10036. }
  10037. //
  10038. // If the object was hidden by visgroups, hide it unless visgroup hiding is disabled.
  10039. //
  10040. if (!CVisGroup::IsShowAllActive() && !pObject->IsVisGroupShown())
  10041. {
  10042. return false;
  10043. }
  10044. //
  10045. // If the cordon tool is active and the object is not within the cordon bounds,
  10046. // hide the object. The exception to this is some helpers, which only hide if their
  10047. // parent entity is culled by the cordon.
  10048. //
  10049. if ( m_bIsCordoning && !IsManifest() && Cordon_IsCulledByCordon( pObject ) )
  10050. return false;
  10051. return(true);
  10052. }
  10053. //-----------------------------------------------------------------------------
  10054. // Purpose: Notifies the document when an object has changed. The object is
  10055. // added to a list which will be processed before the next view is rendered.
  10056. // Input : pObject - Object that has changed.
  10057. //-----------------------------------------------------------------------------
  10058. void CMapDoc::UpdateObject(CMapClass *pObject)
  10059. {
  10060. Assert(!pObject->IsTemporary());
  10061. if ( m_UpdateList.Find(pObject) == -1)
  10062. {
  10063. m_UpdateList.AddToTail(pObject);
  10064. }
  10065. UpdateAllViews( MAPVIEW_UPDATE_OBJECTS );
  10066. }
  10067. //-----------------------------------------------------------------------------
  10068. // Purpose: Processes any objects that have changed since the last call.
  10069. // Updates each object's visiblity and makes sure that there are no
  10070. // invisible objects in the selection set.
  10071. //
  10072. // This must be called from the outer loop, as selection.RemoveInvisibles
  10073. // may change the contents of the selection. Therefore, this should never
  10074. // be called from low-level code that might be inside an iteration of the
  10075. // selection.
  10076. //-----------------------------------------------------------------------------
  10077. void CMapDoc::Update(void)
  10078. {
  10079. ProcessNotifyList();
  10080. if (m_UpdateList.Count()>0)
  10081. {
  10082. //
  10083. // Process every object in the update list.
  10084. //
  10085. FOR_EACH_OBJ( m_UpdateList, pos )
  10086. {
  10087. CMapClass *pObject = m_UpdateList.Element(pos);
  10088. UpdateVisibility(pObject);
  10089. }
  10090. //
  10091. // Make sure there aren't any invisible objects in the selection.
  10092. //
  10093. m_pSelection->RemoveInvisibles();
  10094. //
  10095. // Empty the update list now that it has been processed.
  10096. //
  10097. m_UpdateList.RemoveAll();
  10098. }
  10099. }
  10100. //-----------------------------------------------------------------------------
  10101. // Purpose: Callback for updating the visibility status of a single object and
  10102. // its children.
  10103. // Input : pObject -
  10104. // pDoc -
  10105. //-----------------------------------------------------------------------------
  10106. BOOL CMapDoc::UpdateVisibilityCallback(CMapClass *pObject, UpdateVisibilityData_t *pData )
  10107. {
  10108. Assert(!pObject->IsTemporary());
  10109. bool bVisible = pData->pDoc->ShouldObjectBeVisible(pObject, pData);
  10110. pObject->SetVisible(bVisible);
  10111. if (bVisible)
  10112. {
  10113. //
  10114. // If this is an entity and it is visible, recurse into any children.
  10115. //
  10116. if ( ( dynamic_cast< CMapEntity * >( pObject ) ) != NULL || ( dynamic_cast< CMapWorld * >( pObject ) ) != NULL )
  10117. {
  10118. pObject->EnumChildren((ENUMMAPCHILDRENPROC)UpdateVisibilityCallback, (DWORD)pData);
  10119. }
  10120. }
  10121. return(TRUE);
  10122. }
  10123. void CMapDoc::InitUpdateVisibilityData( UpdateVisibilityData_t &data )
  10124. {
  10125. memset( &data, 0, sizeof( data ) );
  10126. data.pDoc = this;
  10127. data.bRadiusCullingEnabled = ( Options.general.bRadiusCulling == TRUE );
  10128. if ( data.bRadiusCullingEnabled )
  10129. {
  10130. POSITION viewpos = GetFirstViewPosition();
  10131. while ( viewpos )
  10132. {
  10133. CMapView3D *pView = dynamic_cast<CMapView3D*>( GetNextView( viewpos ) );
  10134. if ( pView )
  10135. {
  10136. CCamera *pCamera = pView->GetCamera();
  10137. if ( pCamera )
  10138. {
  10139. pCamera->GetViewPoint( data.vecRadiusCullCenter );
  10140. data.flRadiusCullDistSq = pCamera->GetFarClip();
  10141. data.flRadiusCullDistSq *= data.flRadiusCullDistSq;
  10142. return;
  10143. }
  10144. }
  10145. }
  10146. // Can't use radius culling without a 3D view.
  10147. data.bRadiusCullingEnabled = false;
  10148. }
  10149. };
  10150. //-----------------------------------------------------------------------------
  10151. // Purpose: Updates the visibility of the given object and its children.
  10152. // Input : pObject -
  10153. //-----------------------------------------------------------------------------
  10154. void CMapDoc::UpdateVisibility(CMapClass *pObject)
  10155. {
  10156. UpdateVisibilityData_t data;
  10157. InitUpdateVisibilityData( data );
  10158. UpdateVisibilityCallback(pObject, &data);
  10159. if (pObject->IsGroup())
  10160. {
  10161. pObject->EnumChildrenRecurseGroupsOnly((ENUMMAPCHILDRENPROC)UpdateVisibilityCallback, (DWORD)&data);
  10162. }
  10163. }
  10164. //-----------------------------------------------------------------------------
  10165. // Purpose: Updates the visibility of all objects in the world.
  10166. //-----------------------------------------------------------------------------
  10167. void CMapDoc::UpdateVisibilityAll(void)
  10168. {
  10169. UpdateVisibilityData_t data;
  10170. InitUpdateVisibilityData( data );
  10171. //
  10172. // Two stage recursion: first we recurse groups only, then from the callback we recurse
  10173. // solid children of entities.
  10174. //
  10175. m_pWorld->EnumChildrenRecurseGroupsOnly((ENUMMAPCHILDRENPROC)UpdateVisibilityCallback, (DWORD)&data);
  10176. m_pSelection->RemoveInvisibles();
  10177. CMainFrame *pwndMain = GetMainWnd();
  10178. if (pwndMain)
  10179. {
  10180. pwndMain->UpdateAllDocViews( MAPVIEW_UPDATE_VISGROUP_STATE );
  10181. // Some entity I/O connections may have become valid/invalid after this hide/show.
  10182. pwndMain->pObjectProperties->MarkDataDirty();
  10183. }
  10184. }
  10185. //-----------------------------------------------------------------------------
  10186. // Purpose: Adds a visgroup to this document.
  10187. // Input : pszName - The name to assign the visgroup
  10188. // bAuto - should this be an auto visgroup (default: false)
  10189. // Output : Returns a pointer to the newly created visgroup.
  10190. //-----------------------------------------------------------------------------
  10191. CVisGroup *CMapDoc::VisGroups_AddGroup(LPCTSTR pszName, bool bAuto)
  10192. {
  10193. CVisGroup *pGroup = new CVisGroup;
  10194. pGroup->SetName(pszName);
  10195. pGroup->SetAuto( bAuto );
  10196. //
  10197. // Generate a random color for the group.
  10198. //
  10199. pGroup->SetColor(80 + (random() % 176), 80 + (random() % 176), 80 + (random() % 176));
  10200. //
  10201. // Generate a unique id for this visgroup.
  10202. //
  10203. int id = 0;
  10204. while (id++ < 2000)
  10205. {
  10206. if (!VisGroups_GroupForID(id))
  10207. {
  10208. break;
  10209. }
  10210. }
  10211. pGroup->SetID(id);
  10212. return VisGroups_AddGroup(pGroup);
  10213. }
  10214. //-----------------------------------------------------------------------------
  10215. // Purpose: Adds a visgroup to this document.
  10216. // Input : pGroup - Visgroup to add.
  10217. // Output : Returns a pointer to the given visgroup.
  10218. //-----------------------------------------------------------------------------
  10219. CVisGroup *CMapDoc::VisGroups_AddGroup(CVisGroup *pGroup)
  10220. {
  10221. Assert( pGroup != NULL );
  10222. m_VisGroups->AddToTail(pGroup);
  10223. if (!pGroup->GetParent())
  10224. {
  10225. m_RootVisGroups->AddToTail(pGroup);
  10226. }
  10227. return pGroup;
  10228. }
  10229. //-----------------------------------------------------------------------------
  10230. // Purpose:
  10231. //-----------------------------------------------------------------------------
  10232. bool CMapDoc::VisGroups_CanMoveUp(CVisGroup *pGroup)
  10233. {
  10234. CVisGroup *pParent = pGroup->GetParent();
  10235. if (pParent)
  10236. {
  10237. return pParent->CanMoveUp(pGroup);
  10238. }
  10239. else
  10240. {
  10241. return (m_RootVisGroups->Find(pGroup) > 0);
  10242. }
  10243. }
  10244. //-----------------------------------------------------------------------------
  10245. // Purpose:
  10246. //-----------------------------------------------------------------------------
  10247. bool CMapDoc::VisGroups_CanMoveDown(CVisGroup *pGroup)
  10248. {
  10249. CVisGroup *pParent = pGroup->GetParent();
  10250. if (pParent)
  10251. {
  10252. return pParent->CanMoveDown(pGroup);
  10253. }
  10254. else
  10255. {
  10256. int nIndex = m_RootVisGroups->Find(pGroup);
  10257. return (nIndex >= 0) && (nIndex < m_RootVisGroups->Count() - 1);
  10258. }
  10259. }
  10260. //-----------------------------------------------------------------------------
  10261. // Purpose:
  10262. // Input : pObject -
  10263. // pGroup -
  10264. // Output : Returns FALSE to stop enumerating if the object belonged to the given
  10265. // visgroup. Otherwise, returns TRUE to continue enumerating.
  10266. //-----------------------------------------------------------------------------
  10267. BOOL CMapDoc::VisGroups_CheckForGroupCallback(CMapClass *pObject, CVisGroup *pGroup)
  10268. {
  10269. if (pObject->IsInVisGroup(pGroup))
  10270. {
  10271. return(FALSE);
  10272. }
  10273. return(TRUE);
  10274. }
  10275. //-----------------------------------------------------------------------------
  10276. // Purpose: Returns the number of visgroups in this document.
  10277. //-----------------------------------------------------------------------------
  10278. int CMapDoc::VisGroups_GetCount(void)
  10279. {
  10280. return(m_VisGroups->Count());
  10281. }
  10282. //-----------------------------------------------------------------------------
  10283. // Purpose: Returns a visgroup by index.
  10284. //-----------------------------------------------------------------------------
  10285. CVisGroup *CMapDoc::VisGroups_GetVisGroup(int nIndex)
  10286. {
  10287. return(m_VisGroups->Element(nIndex));
  10288. }
  10289. //-----------------------------------------------------------------------------
  10290. // Purpose: Returns the number of root-level visgroups in this document.
  10291. //-----------------------------------------------------------------------------
  10292. int CMapDoc::VisGroups_GetRootCount(void)
  10293. {
  10294. if ( m_RootVisGroups )
  10295. {
  10296. return( m_RootVisGroups->Count() );
  10297. }
  10298. return 0;
  10299. }
  10300. //-----------------------------------------------------------------------------
  10301. // Purpose: Returns a root-level visgroup by index.
  10302. //-----------------------------------------------------------------------------
  10303. CVisGroup *CMapDoc::VisGroups_GetRootVisGroup(int nIndex)
  10304. {
  10305. return(m_RootVisGroups->Element(nIndex));
  10306. }
  10307. //-----------------------------------------------------------------------------
  10308. // FIXME: Currently the sort order in the visgroups and cordon tree views is
  10309. // exactly the order that they are in the document. It would be better
  10310. // if those controls kept their sort order independent of the document
  10311. // and could save that into the VMF.
  10312. //-----------------------------------------------------------------------------
  10313. void CMapDoc::VisGroups_MoveUp(CVisGroup *pGroup)
  10314. {
  10315. CVisGroup *pParent = pGroup->GetParent();
  10316. if (pParent)
  10317. {
  10318. pParent->MoveUp(pGroup);
  10319. }
  10320. else
  10321. {
  10322. int nIndex = m_RootVisGroups->Find(pGroup);
  10323. if (nIndex > 0)
  10324. {
  10325. m_RootVisGroups->Remove(nIndex);
  10326. m_RootVisGroups->InsertBefore(nIndex - 1, pGroup);
  10327. }
  10328. }
  10329. }
  10330. //-----------------------------------------------------------------------------
  10331. //-----------------------------------------------------------------------------
  10332. void CMapDoc::VisGroups_MoveDown(CVisGroup *pGroup)
  10333. {
  10334. CVisGroup *pParent = pGroup->GetParent();
  10335. if (pParent)
  10336. {
  10337. pParent->MoveDown(pGroup);
  10338. }
  10339. else
  10340. {
  10341. int nIndex = m_RootVisGroups->Find(pGroup);
  10342. if (nIndex < (m_RootVisGroups->Count() - 1))
  10343. {
  10344. m_RootVisGroups->Remove(nIndex);
  10345. m_RootVisGroups->InsertAfter(nIndex, pGroup);
  10346. }
  10347. }
  10348. }
  10349. //-----------------------------------------------------------------------------
  10350. //-----------------------------------------------------------------------------
  10351. void CMapDoc::Cordon_MoveUp( Cordon_t *cordon )
  10352. {
  10353. int nIndex = -1;
  10354. for ( int i = 0; i < m_Cordons.Count(); i++ )
  10355. {
  10356. if ( &m_Cordons.Element( i ) == cordon )
  10357. {
  10358. nIndex = i;
  10359. break;
  10360. }
  10361. }
  10362. if (nIndex > 0)
  10363. {
  10364. Cordon_t temp;
  10365. temp = *cordon;
  10366. m_Cordons.Remove( nIndex );
  10367. m_Cordons.InsertBefore( nIndex - 1 );
  10368. m_Cordons.Element( nIndex - 1 ) = temp;
  10369. }
  10370. }
  10371. //-----------------------------------------------------------------------------
  10372. //-----------------------------------------------------------------------------
  10373. void CMapDoc::Cordon_MoveDown( Cordon_t *cordon )
  10374. {
  10375. int nIndex = -1;
  10376. for ( int i = 0; i < m_Cordons.Count(); i++ )
  10377. {
  10378. if ( &m_Cordons.Element( i ) == cordon )
  10379. {
  10380. nIndex = i;
  10381. break;
  10382. }
  10383. }
  10384. if ( ( nIndex != -1 ) && ( nIndex < m_Cordons.Count() - 1 ) )
  10385. {
  10386. Cordon_t temp;
  10387. temp = *cordon;
  10388. m_Cordons.Remove( nIndex );
  10389. m_Cordons.InsertAfter( nIndex );
  10390. m_Cordons.Element( nIndex + 1 ) = temp;
  10391. }
  10392. }
  10393. //-----------------------------------------------------------------------------
  10394. // Purpose: Deletes any visgroups that no longer have any members.
  10395. //-----------------------------------------------------------------------------
  10396. void CMapDoc::VisGroups_PurgeGroups(void)
  10397. {
  10398. bool bUpdate = false;
  10399. int nCount = VisGroups_GetCount();
  10400. for (int i = nCount - 1; i >= 0; i--)
  10401. {
  10402. CVisGroup *pGroup = VisGroups_GetVisGroup(i);
  10403. // Don't purge groups with children
  10404. if ( pGroup->GetChildCount() )
  10405. continue;
  10406. bool bKill = true;
  10407. EnumChildrenPos_t pos2;
  10408. CMapClass *pObject = m_pWorld->GetFirstDescendent(pos2);
  10409. while (pObject != NULL)
  10410. {
  10411. if (pObject->IsInVisGroup(pGroup))
  10412. {
  10413. bKill = false;
  10414. break;
  10415. }
  10416. pObject = m_pWorld->GetNextDescendent(pos2);
  10417. }
  10418. if (bKill)
  10419. {
  10420. bUpdate = true;
  10421. VisGroups_UnlinkGroup(pGroup);
  10422. delete pGroup;
  10423. }
  10424. }
  10425. if (bUpdate)
  10426. {
  10427. GetMainWnd()->m_FilterControl.UpdateGroupList();
  10428. }
  10429. }
  10430. //-----------------------------------------------------------------------------
  10431. // Purpose: Removes the given visgroup from the visgroup hierarchy.
  10432. //-----------------------------------------------------------------------------
  10433. void CMapDoc::VisGroups_RemoveGroup(CVisGroup *pGroup)
  10434. {
  10435. VisGroups_DoRemoveOrCombine(pGroup, NULL);
  10436. VisGroups_UnlinkGroup(pGroup);
  10437. delete pGroup;
  10438. VisGroups_UpdateAll();
  10439. UpdateVisibilityAll();
  10440. SetModifiedFlag();
  10441. }
  10442. //-----------------------------------------------------------------------------
  10443. // Purpose: Combines two visgroups, moving member objects and child visgroups
  10444. // into the 'to' group, and deletes the 'from' group.
  10445. //-----------------------------------------------------------------------------
  10446. void CMapDoc::VisGroups_CombineGroups(CVisGroup *pFrom, CVisGroup *pTo)
  10447. {
  10448. // Can't combine a group into one of it's descendents.
  10449. Assert(!pFrom->FindDescendent(pTo));
  10450. VisGroups_DoRemoveOrCombine(pFrom, pTo);
  10451. VisGroups_UnlinkGroup(pFrom);
  10452. delete pFrom;
  10453. VisGroups_UpdateAll();
  10454. UpdateVisibilityAll();
  10455. SetModifiedFlag();
  10456. }
  10457. //-----------------------------------------------------------------------------
  10458. // Purpose: Removes the visgroup from the visgroup lists.
  10459. // Input : *pGroup -
  10460. //-----------------------------------------------------------------------------
  10461. void CMapDoc::VisGroups_UnlinkGroup(CVisGroup *pGroup)
  10462. {
  10463. m_VisGroups->FindAndRemove(pGroup);
  10464. m_RootVisGroups->FindAndRemove(pGroup);
  10465. CVisGroup *pParent = pGroup->GetParent();
  10466. if (pParent)
  10467. {
  10468. pParent->RemoveChild(pGroup);
  10469. }
  10470. GetHistory()->OnRemoveVisGroup(pGroup);
  10471. }
  10472. //-----------------------------------------------------------------------------
  10473. // Purpose: Combines two visgroups, moving member objects and child visgroups
  10474. // into the 'to' group.
  10475. // Input : pFrom -
  10476. // pTo -
  10477. //-----------------------------------------------------------------------------
  10478. void CMapDoc::VisGroups_DoRemoveOrCombine(CVisGroup *pFrom, CVisGroup *pTo)
  10479. {
  10480. if (!pFrom)
  10481. return;
  10482. //
  10483. // Replace membership in pFrom with membership in pTo.
  10484. //
  10485. CMapWorld *pWorld = GetMapWorld();
  10486. EnumChildrenPos_t pos;
  10487. CMapClass *pObject = pWorld->GetFirstDescendent(pos);
  10488. while (pObject != NULL)
  10489. {
  10490. if (pObject->IsInVisGroup(pFrom))
  10491. {
  10492. //must add the object to the new visgroup before removing from the old
  10493. //this solves the problem of incorrectly forcing visibilty when an object becomes
  10494. //temporarily orphaned.
  10495. if (pTo)
  10496. {
  10497. pObject->AddVisGroup(pTo);
  10498. }
  10499. pObject->RemoveVisGroup(pFrom);
  10500. }
  10501. pObject = pWorld->GetNextDescendent(pos);
  10502. }
  10503. if (pTo)
  10504. {
  10505. //
  10506. // Move child visgroups into pTo.
  10507. //
  10508. for (int i = 0; i < pFrom->GetChildCount(); i++)
  10509. {
  10510. CVisGroup *pChild = pFrom->GetChild(i);
  10511. pTo->AddChild(pChild);
  10512. }
  10513. //
  10514. // Make sure pTo has the proper visibility state.
  10515. //
  10516. if (pFrom->GetVisible() != pTo->GetVisible())
  10517. {
  10518. pTo->SetVisible(VISGROUP_PARTIAL);
  10519. }
  10520. }
  10521. }
  10522. //-----------------------------------------------------------------------------
  10523. // Purpose:
  10524. // Input : *pFile -
  10525. // Output : ChunkFileResult_t
  10526. //-----------------------------------------------------------------------------
  10527. ChunkFileResult_t CMapDoc::VisGroups_SaveVMF(CChunkFile *pFile, CSaveInfo *pSaveInfo)
  10528. {
  10529. if (VisGroups_GetCount() == 0)
  10530. {
  10531. return(ChunkFile_Ok);
  10532. }
  10533. ChunkFileResult_t eResult = pFile->BeginChunk("visgroups");
  10534. if (eResult == ChunkFile_Ok)
  10535. {
  10536. // Save the root level visgroups; children are saved recursively.
  10537. int nCount = VisGroups_GetRootCount();
  10538. for (int i = 0; i < nCount; i++)
  10539. {
  10540. CVisGroup *pVisGroup = this->VisGroups_GetRootVisGroup(i);
  10541. if ( pVisGroup != NULL && !pVisGroup->IsAutoVisGroup() && strcmp( pVisGroup->GetName(), "Auto" ) )
  10542. {
  10543. eResult = pVisGroup->SaveVMF(pFile, pSaveInfo);
  10544. if (eResult != ChunkFile_Ok)
  10545. {
  10546. break;
  10547. }
  10548. }
  10549. }
  10550. }
  10551. if (eResult == ChunkFile_Ok)
  10552. {
  10553. eResult = pFile->EndChunk();
  10554. }
  10555. return(eResult);
  10556. }
  10557. //-----------------------------------------------------------------------------
  10558. // Purpose:
  10559. // Input : *pFile -
  10560. // Output : ChunkFileResult_t
  10561. //-----------------------------------------------------------------------------
  10562. ChunkFileResult_t CMapDoc::SaveViewSettingsVMF(CChunkFile *pFile, CSaveInfo *pSaveInfo)
  10563. {
  10564. ChunkFileResult_t eResult = pFile->BeginChunk("viewsettings");
  10565. eResult = pFile->WriteKeyValueBool("bSnapToGrid", m_bSnapToGrid);
  10566. if (eResult != ChunkFile_Ok)
  10567. return eResult;
  10568. eResult = pFile->WriteKeyValueBool("bShowGrid", m_bShowGrid);
  10569. if (eResult != ChunkFile_Ok)
  10570. return eResult;
  10571. #ifndef SDK_BUILD
  10572. eResult = pFile->WriteKeyValueBool("bShowLogicalGrid", m_bShowLogicalGrid);
  10573. if (eResult != ChunkFile_Ok)
  10574. return eResult;
  10575. #endif // SDK_BUILD
  10576. eResult = pFile->WriteKeyValueInt("nGridSpacing", m_nGridSpacing);
  10577. if (eResult != ChunkFile_Ok)
  10578. return eResult;
  10579. eResult = pFile->WriteKeyValueBool("bShow3DGrid", m_bShow3DGrid);
  10580. if (eResult != ChunkFile_Ok)
  10581. return eResult;
  10582. return(pFile->EndChunk());
  10583. }
  10584. //-----------------------------------------------------------------------------
  10585. // Purpose: Turns on lighting preview mode by loading the BSP file with the
  10586. // same named as the VMF being edited.
  10587. //-----------------------------------------------------------------------------
  10588. void CMapDoc::InternalEnableLightPreview( bool bCustomFilename )
  10589. {
  10590. #if 0
  10591. OnDisableLightPreview();
  10592. m_pBSPLighting = CreateBSPLighting();
  10593. // Either use the VMF filename or the last-exported VMF name.
  10594. CString strFile;
  10595. if( m_strLastExportFileName.GetLength() == 0 )
  10596. strFile = GetPathName();
  10597. else
  10598. strFile = m_strLastExportFileName;
  10599. // Convert the extension to .bsp
  10600. char *p = strFile.GetBuffer(MAX_PATH);
  10601. char *ext = strrchr(p, '.');
  10602. if( ext )
  10603. {
  10604. strcpy( ext, ".bsp" );
  10605. }
  10606. // Strip out the directory.
  10607. char *cur = p;
  10608. while ((cur = strstr(cur, "/")) != NULL)
  10609. {
  10610. *cur = '\\';
  10611. }
  10612. char fileName[MAX_PATH];
  10613. char *pLastSlash = p;
  10614. char *pTest;
  10615. while ((pTest = strstr(pLastSlash, "\\")) != NULL)
  10616. {
  10617. pLastSlash = pTest + 1;
  10618. }
  10619. if( pLastSlash )
  10620. strcpy( fileName, pLastSlash );
  10621. else
  10622. strcpy( fileName, p );
  10623. strFile.ReleaseBuffer();
  10624. // Use <mod directory> + "/maps/" + <filename>
  10625. char fullPath[MAX_PATH*2];
  10626. sprintf( fullPath, "%s\\maps\\%s", g_pGameConfig->m_szModDir, fileName );
  10627. // Only do the dialog if they said to or if the default BSP file doesn't exist.
  10628. if( !bCustomFilename )
  10629. {
  10630. FILE *fp = fopen( fullPath, "rb" );
  10631. if( fp )
  10632. fclose( fp );
  10633. else
  10634. bCustomFilename = true;
  10635. }
  10636. CString finalPath;
  10637. if( bCustomFilename )
  10638. {
  10639. CFileDialog dlg(
  10640. TRUE, // bOpenFile
  10641. "bsp", // default extension
  10642. fullPath, // default filename,
  10643. OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, // flags
  10644. "BSP Files (*.bsp)|*.bsp|All Files (*.*)|*.*||",
  10645. NULL // filter
  10646. );
  10647. if( dlg.DoModal() != IDOK )
  10648. return;
  10649. finalPath = dlg.GetPathName();
  10650. }
  10651. else
  10652. {
  10653. finalPath = fullPath;
  10654. }
  10655. if( !m_pBSPLighting->Load( finalPath ) )
  10656. {
  10657. char str[256];
  10658. Q_snprintf( str, sizeof(str), "Can't load lighting from '%s'.", finalPath );
  10659. AfxMessageBox( str );
  10660. }
  10661. // Switch the first mapview we find into 3D lighting preview.
  10662. POSITION viewPos = GetFirstViewPosition();
  10663. while( viewPos )
  10664. {
  10665. CView *pView = GetNextView( viewPos );
  10666. if (pView->IsKindOf(RUNTIME_CLASS(CMapView3D)))
  10667. {
  10668. CMapView3D *pView3D = (CMapView3D *)pView;
  10669. pView3D->SetDrawType( VIEW3D_LIGHTING_PREVIEW );
  10670. break;
  10671. }
  10672. }
  10673. #endif
  10674. }
  10675. void CMapDoc::OnEnableLightPreview()
  10676. {
  10677. InternalEnableLightPreview( false );
  10678. }
  10679. void CMapDoc::OnEnableLightPreviewCustomFilename()
  10680. {
  10681. InternalEnableLightPreview( true );
  10682. }
  10683. //-----------------------------------------------------------------------------
  10684. // Purpose: Turns off lighting preview mode.
  10685. //-----------------------------------------------------------------------------
  10686. void CMapDoc::OnDisableLightPreview()
  10687. {
  10688. #if 0
  10689. // Change any light preview views back to regular 3D.
  10690. POSITION p = GetFirstViewPosition();
  10691. while (p)
  10692. {
  10693. CView *pView = GetNextView(p);
  10694. if (pView->IsKindOf(RUNTIME_CLASS(CMapView3D)))
  10695. {
  10696. CMapView3D *pView3D = (CMapView3D *)pView;
  10697. if( pView3D->GetDrawType() == VIEW3D_LIGHTING_PREVIEW )
  10698. pView3D->SetDrawType( VIEW3D_TEXTURED );
  10699. }
  10700. }
  10701. if( m_pBSPLighting )
  10702. {
  10703. m_pBSPLighting->Release();
  10704. m_pBSPLighting = 0;
  10705. }
  10706. #endif
  10707. }
  10708. void CMapDoc::OnUpdateLightPreview()
  10709. {
  10710. if( !m_pBSPLighting )
  10711. return;
  10712. // Save out a file with just the ents.
  10713. char szFile[MAX_PATH];
  10714. strcpy(szFile, GetPathName());
  10715. szFile[strlen(szFile) - 1] = 'e';
  10716. if( !SaveVMF( szFile, SAVEFLAGS_LIGHTSONLY ) )
  10717. {
  10718. CString str;
  10719. str.FormatMessage( IDS_CANT_SAVE_ENTS_FILE, szFile );
  10720. return;
  10721. }
  10722. // Get it in memory.
  10723. CUtlVector<char> fileData;
  10724. FILE *fp = fopen( szFile, "rb" );
  10725. if( !fp )
  10726. {
  10727. CString str;
  10728. str.FormatMessage( IDS_CANT_OPEN_ENTS_FILE, szFile );
  10729. AfxMessageBox( str, MB_OK );
  10730. return;
  10731. }
  10732. fseek( fp, 0, SEEK_END );
  10733. fileData.SetSize( ftell( fp ) + 1 );
  10734. fseek( fp, 0, SEEK_SET );
  10735. fread( fileData.Base(), 1, fileData.Count(), fp );
  10736. fclose( fp );
  10737. // Null-terminate it.
  10738. fileData[ fileData.Count() - 1 ] = 0;
  10739. // Tell the incremental lighting manager to relight.
  10740. m_pBSPLighting->StartLighting( fileData.Base() );
  10741. }
  10742. //-----------------------------------------------------------------------------
  10743. // Purpose:
  10744. //-----------------------------------------------------------------------------
  10745. void CMapDoc::OnToggleLightPreview()
  10746. {
  10747. #if 0
  10748. if( m_pBSPLighting )
  10749. {
  10750. POSITION p = GetFirstViewPosition();
  10751. while (p)
  10752. {
  10753. CView *pView = GetNextView(p);
  10754. if (pView->IsKindOf(RUNTIME_CLASS(CMapView3D)))
  10755. {
  10756. CMapView3D *pView3D = (CMapView3D *)pView;
  10757. if( pView3D->GetDrawType() == VIEW3D_LIGHTING_PREVIEW )
  10758. pView3D->SetDrawType( VIEW3D_TEXTURED );
  10759. else if( pView3D->GetDrawType() == VIEW3D_TEXTURED )
  10760. pView3D->SetDrawType( VIEW3D_LIGHTING_PREVIEW );
  10761. }
  10762. }
  10763. }
  10764. else
  10765. {
  10766. // If no lighting is loaded, then load it.
  10767. OnEnableLightPreview();
  10768. }
  10769. #endif
  10770. }
  10771. void CMapDoc::OnAbortLightCalculation()
  10772. {
  10773. if( !m_pBSPLighting )
  10774. return;
  10775. m_pBSPLighting->Interrupt();
  10776. }
  10777. //-----------------------------------------------------------------------------
  10778. // Used to avoid adding redundant notifications to the list.
  10779. //-----------------------------------------------------------------------------
  10780. bool CMapDoc::FindNotification(CMapClass *pObject, Notify_Dependent_t eNotifyType)
  10781. {
  10782. int nCount = m_NotifyList.Count();
  10783. for (int i = 0; i < nCount; i++)
  10784. {
  10785. if ((m_NotifyList.Element(i)->pObject == pObject) &&
  10786. (m_NotifyList.Element(i)->eNotifyType == eNotifyType))
  10787. {
  10788. return true;
  10789. }
  10790. }
  10791. return false;
  10792. }
  10793. bool CMapDoc::AnyNotificationsForObject(CMapClass *pObject)
  10794. {
  10795. int nCount = m_NotifyList.Count();
  10796. for (int i = 0; i < nCount; i++)
  10797. {
  10798. if ( m_NotifyList.Element(i)->pObject == pObject )
  10799. return true;
  10800. }
  10801. return false;
  10802. }
  10803. //-----------------------------------------------------------------------------
  10804. // Purpose: Adds the notification event to the list for processing.
  10805. // Input : pObject -
  10806. // eNotifyType -
  10807. //-----------------------------------------------------------------------------
  10808. static bool s_bDispatchingNotifications = false;
  10809. void CMapDoc::NotifyDependents(CMapClass *pObject, Notify_Dependent_t eNotifyType)
  10810. {
  10811. Assert( !s_bDispatchingNotifications );
  10812. if ( s_bDispatchingNotifications )
  10813. return;
  10814. if (pObject->IsTemporary())
  10815. {
  10816. return;
  10817. }
  10818. if (eNotifyType != Notify_Removed)
  10819. {
  10820. if (!FindNotification(pObject, eNotifyType))
  10821. {
  10822. NotifyListEntry_t *pEntry = new NotifyListEntry_t;
  10823. pEntry->pObject = pObject;
  10824. pEntry->eNotifyType = eNotifyType;
  10825. m_NotifyList.AddToTail(pEntry);
  10826. }
  10827. }
  10828. else
  10829. {
  10830. DispatchNotifyDependents(pObject, eNotifyType);
  10831. }
  10832. }
  10833. //-----------------------------------------------------------------------------
  10834. // Dispatches notifications to dependent objects. Called once per frame, this
  10835. // allows objects to update themselves based on changes made to other objects
  10836. // before they are rendered.
  10837. //-----------------------------------------------------------------------------
  10838. void CMapDoc::ProcessNotifyList()
  10839. {
  10840. s_bDispatchingNotifications = true;
  10841. int nCount = m_NotifyList.Count();
  10842. if (nCount)
  10843. {
  10844. for (int i = 0; i < nCount; i++)
  10845. {
  10846. NotifyListEntry_t *pEntry = m_NotifyList.Element(i);
  10847. if ( pEntry->pObject.IsValid() )
  10848. {
  10849. DispatchNotifyDependents(pEntry->pObject, pEntry->eNotifyType);
  10850. }
  10851. else
  10852. {
  10853. static bool bShowedWarning = false;
  10854. if ( !bShowedWarning )
  10855. {
  10856. bShowedWarning = true;
  10857. AfxMessageBox( "ProcessNotifyList: encountered a deleted object. Tell a programmer.", MB_OK );
  10858. }
  10859. }
  10860. }
  10861. m_NotifyList.PurgeAndDeleteElements();
  10862. }
  10863. s_bDispatchingNotifications = false;
  10864. }
  10865. //-----------------------------------------------------------------------------
  10866. // Purpose:
  10867. // Input : pObject -
  10868. // eNotifyType -
  10869. //-----------------------------------------------------------------------------
  10870. void CMapDoc::DispatchNotifyDependents(CUtlReference< CMapClass > pObject, Notify_Dependent_t eNotifyType)
  10871. {
  10872. if ( !pObject.IsValid() )
  10873. {
  10874. Assert( 0 );
  10875. return;
  10876. }
  10877. const CMapObjectRefList *pDependents = pObject->GetDependents();
  10878. if ( pDependents->Count() == 0 )
  10879. return;
  10880. // Get a copy of the dependecies list because it may change during iteration.
  10881. CMapObjectRefList TempDependents;
  10882. TempDependents.AddVectorToTail( *pDependents );
  10883. for (int i = 0; i < TempDependents.Count(); i++)
  10884. {
  10885. CMapClass *pDependent = TempDependents.Element(i);
  10886. if ( !pDependent )
  10887. continue;
  10888. //
  10889. // Maybe we should give our dependents the opportunity to unlink themselves here?
  10890. // Returning false from OnNotify could indicate a desire to sever the dependency.
  10891. // Currently this is accomplished by calling UpdateDependency from OnNotifyDependent.
  10892. //
  10893. pDependent->OnNotifyDependent(pObject, eNotifyType);
  10894. }
  10895. }
  10896. //-----------------------------------------------------------------------------
  10897. // Purpose: Replicates the given list of objects, then selects the duplicates.
  10898. // Input : Objects -
  10899. //-----------------------------------------------------------------------------
  10900. void CMapDoc::CloneObjects(const CMapObjectList &Objects)
  10901. {
  10902. CMapObjectList NewObjects;
  10903. bool bLocked = VisGroups_LockUpdates( true );
  10904. //
  10905. // Run through list of objects and copy each to build a list of cloned
  10906. // objects.
  10907. //
  10908. FOR_EACH_OBJ( Objects, pos )
  10909. {
  10910. CMapClass *pobj = (CUtlReference< CMapClass >)Objects.Element(pos);
  10911. CMapClass *pNewobj = pobj->Copy(false);
  10912. pNewobj->CopyChildrenFrom(pobj, false);
  10913. if (!Options.view2d.bKeepclonegroup)
  10914. {
  10915. pNewobj->RemoveAllVisGroups();
  10916. }
  10917. NewObjects.AddToTail(pNewobj);
  10918. }
  10919. // Notification happens in two-passes. The first pass lets objects generate new unique
  10920. // IDs, the second pass lets objects fixup references to other cloned objects.
  10921. Assert( Objects.Count() == NewObjects.Count() );
  10922. FOR_EACH_OBJ( Objects, pos )
  10923. {
  10924. CMapClass *pobj = (CUtlReference< CMapClass >)Objects.Element(pos);
  10925. CMapClass *pNewobj = (CUtlReference< CMapClass >)NewObjects.Element(pos);
  10926. pobj->OnPreClone(pNewobj, m_pWorld, Objects, NewObjects);
  10927. }
  10928. // Do the second pass of notification and add the objects to the world. The second pass
  10929. // of notification lets objects fixup references to other cloned objects.
  10930. FOR_EACH_OBJ( Objects, pos )
  10931. {
  10932. CMapClass *pobj = (CUtlReference< CMapClass >)Objects.Element(pos);
  10933. CMapClass *pNewobj = (CUtlReference< CMapClass >)NewObjects.Element(pos);
  10934. pobj->OnClone(pNewobj, m_pWorld, Objects, NewObjects);
  10935. AddObjectToWorld(pNewobj);
  10936. }
  10937. SelectObjectList( &NewObjects );
  10938. if ( bLocked )
  10939. {
  10940. VisGroups_LockUpdates( false );
  10941. }
  10942. }
  10943. //-----------------------------------------------------------------------------
  10944. // Purpose:
  10945. // Input : &axes -
  10946. // vecNudge -
  10947. //-----------------------------------------------------------------------------
  10948. void CMapDoc::GetNudgeVector(const Vector& vHorz, const Vector& vVert, int nChar, bool bSnap, Vector &vecNudge)
  10949. {
  10950. vecNudge.Init();
  10951. float fUnit = ((bSnap && IsSnapEnabled()) ? GetGridSpacing() : 1);
  10952. switch ( nChar )
  10953. {
  10954. case VK_RIGHT : vecNudge += fUnit*vHorz; break;
  10955. case VK_LEFT : vecNudge -= fUnit*vHorz; break;
  10956. case VK_UP : vecNudge += fUnit*vVert; break;
  10957. case VK_DOWN : vecNudge -= fUnit*vVert; break;
  10958. }
  10959. }
  10960. //-----------------------------------------------------------------------------
  10961. // Purpose:
  10962. //-----------------------------------------------------------------------------
  10963. void CMapDoc::NudgeObjects(const Vector &Delta, bool bClone)
  10964. {
  10965. const CMapObjectList *pSelList = m_pSelection->GetList();
  10966. // If they held down shift, clone the selection then nudge the clones.
  10967. if (bClone)
  10968. {
  10969. GetHistory()->MarkUndoPosition(pSelList, "Clone Objects");
  10970. CloneObjects(*pSelList);
  10971. GetHistory()->KeepNew(pSelList);
  10972. }
  10973. else
  10974. {
  10975. GetHistory()->MarkUndoPosition(pSelList, "Nudge objects");
  10976. GetHistory()->Keep(pSelList);
  10977. }
  10978. for (int i = 0; i < pSelList->Count(); i++)
  10979. {
  10980. CMapClass *pObject = (CUtlReference< CMapClass >)pSelList->Element(i);
  10981. pObject->TransMove(Delta);
  10982. }
  10983. SetModifiedFlag();
  10984. }
  10985. //-----------------------------------------------------------------------------
  10986. // Purpose: deals with update problems when changing multiple visgroup settings
  10987. //-----------------------------------------------------------------------------
  10988. bool CMapDoc::VisGroups_LockUpdates( bool bLock )
  10989. {
  10990. // check if already locked/unlocked
  10991. if ( m_bVisGroupUpdatesLocked == bLock )
  10992. return false;
  10993. m_bVisGroupUpdatesLocked = bLock;
  10994. if ( !bLock )
  10995. {
  10996. //
  10997. // Clean up any visgroups with no members.
  10998. //
  10999. VisGroups_PurgeGroups();
  11000. //
  11001. // Update object visiblity and refresh views.
  11002. //
  11003. VisGroups_UpdateAll();
  11004. CMainFrame *pwndMain = GetMainWnd();
  11005. if (pwndMain)
  11006. {
  11007. pwndMain->UpdateAllDocViews(MAPVIEW_UPDATE_VISGROUP_ALL);
  11008. }
  11009. }
  11010. return true;
  11011. }
  11012. //-----------------------------------------------------------------------------
  11013. // Purpose: Checks visgroup-membership for all objects in a visgroup.
  11014. //-----------------------------------------------------------------------------
  11015. void CMapDoc::VisGroups_CheckMemberVisibility(CVisGroup *pGroup)
  11016. {
  11017. //Msg("-------- Visgroups_ShowVisGroup --------\n");
  11018. if (pGroup == NULL)
  11019. return;
  11020. //
  11021. // Show or hide all the objects that belong to the given visgroup.
  11022. //
  11023. EnumChildrenPos_t pos;
  11024. CMapClass *pChild = m_pWorld->GetFirstDescendent(pos);
  11025. while (pChild)
  11026. {
  11027. if (IsInVisGroupRecursive(pChild, pGroup))
  11028. {
  11029. pChild->CheckVisibility();
  11030. }
  11031. pChild = m_pWorld->GetNextDescendent(pos);
  11032. }
  11033. VisGroups_UpdateAll();
  11034. UpdateVisibilityAll();
  11035. SetModifiedFlag();
  11036. }
  11037. CMapView3D *CMapDoc::GetFirst3DView()
  11038. {
  11039. POSITION pos = this->GetFirstViewPosition();
  11040. while ( pos )
  11041. {
  11042. CView *pView = GetNextView(pos);
  11043. if (pView->IsKindOf(RUNTIME_CLASS(CMapView3D)))
  11044. {
  11045. CMapView3D *pView3D = (CMapView3D *)pView;
  11046. return pView3D;
  11047. }
  11048. }
  11049. return NULL;
  11050. }
  11051. CMapView *CMapDoc::GetActiveMapView()
  11052. {
  11053. POSITION p = GetFirstViewPosition();
  11054. while (p)
  11055. {
  11056. CMapView *pView = dynamic_cast<CMapView*>(GetNextView(p));
  11057. if ( !pView )
  11058. continue;
  11059. if ( pView->IsActive() )
  11060. return pView;
  11061. }
  11062. return NULL;
  11063. }
  11064. void CMapDoc::OnLogicalobjectLayoutgeometric()
  11065. {
  11066. Vector2D vecLogicalCenter;
  11067. if ( !m_pSelection->GetLogicalBoundsCenter( vecLogicalCenter ) )
  11068. return;
  11069. const CMapObjectList *pSelList = m_pSelection->GetList();
  11070. if ( pSelList->Count() <= 1 )
  11071. return;
  11072. GetHistory()->MarkUndoPosition( pSelList, "Layout Geometric" );
  11073. GetHistory()->Keep( pSelList );
  11074. bool bCenterView = false;
  11075. CMapViewLogical *pCurrentView = NULL;
  11076. if ( GetMainWnd()->GetActiveFrame() )
  11077. {
  11078. pCurrentView = dynamic_cast<CMapViewLogical*>( GetMainWnd()->GetActiveFrame()->GetActiveView() );
  11079. if ( pCurrentView )
  11080. bCenterView = true;
  11081. }
  11082. for ( int i = 0; i < pSelList->Count(); ++i )
  11083. {
  11084. CMapClass *pClass = (CUtlReference< CMapClass >)pSelList->Element( i );
  11085. if ( !pClass->IsLogical() )
  11086. continue;
  11087. Vector oldCenter;
  11088. pClass->GetBoundsCenter( oldCenter );
  11089. Vector2D newLogicalCenter;
  11090. newLogicalCenter.x = oldCenter.x + oldCenter.z/4;
  11091. newLogicalCenter.y = oldCenter.y + oldCenter.z/4;
  11092. pClass->SetLogicalPosition( newLogicalCenter );
  11093. }
  11094. UpdateAllViews( MAPVIEW_UPDATE_OBJECTS | MAPVIEW_UPDATE_SELECTION | MAPVIEW_UPDATE_ONLY_LOGICAL );
  11095. m_pSelection->SetBoundsDirty();
  11096. if ( bCenterView )
  11097. {
  11098. CenterLogicalViewsOnSelection();
  11099. }
  11100. }
  11101. void CMapDoc::OnLogicalobjectLayoutdefault()
  11102. {
  11103. Vector2D vecLogicalCenter;
  11104. if ( !m_pSelection->GetLogicalBoundsCenter( vecLogicalCenter ) )
  11105. return;
  11106. const CMapObjectList *pSelList = m_pSelection->GetList();
  11107. if ( pSelList->Count() <= 1 )
  11108. return;
  11109. GetHistory()->MarkUndoPosition( pSelList, "Layout Default" );
  11110. GetHistory()->Keep( pSelList );
  11111. bool bCenterView = false;
  11112. CMapViewLogical *pCurrentView = NULL;
  11113. if ( GetMainWnd()->GetActiveFrame() )
  11114. {
  11115. pCurrentView = dynamic_cast<CMapViewLogical*>( GetMainWnd()->GetActiveFrame()->GetActiveView() );
  11116. if ( pCurrentView )
  11117. bCenterView = true;
  11118. }
  11119. m_nLogicalPositionCount = 0;
  11120. for ( int i = 0; i < pSelList->Count(); ++i )
  11121. {
  11122. CMapClass *pClass = (CUtlReference< CMapClass >)pSelList->Element( i );
  11123. if ( !pClass->IsLogical() )
  11124. continue;
  11125. Vector2D newLogicalCenter;
  11126. GetDefaultNewLogicalPosition( newLogicalCenter );
  11127. pClass->SetLogicalPosition( newLogicalCenter );
  11128. }
  11129. UpdateAllViews( MAPVIEW_UPDATE_OBJECTS | MAPVIEW_UPDATE_SELECTION | MAPVIEW_UPDATE_ONLY_LOGICAL );
  11130. m_pSelection->SetBoundsDirty();
  11131. if ( bCenterView )
  11132. {
  11133. CenterLogicalViewsOnSelection();
  11134. }
  11135. }
  11136. void CMapDoc::OnLogicalobjectLayoutlogical()
  11137. {
  11138. // TODO: Add your command handler code here
  11139. }
  11140. void CMapDoc::NoteEngineGotFocus()
  11141. {
  11142. for ( int i=0; i < s_ActiveDocs.Count(); i++ )
  11143. {
  11144. CMapDoc *pDoc = s_ActiveDocs[i];
  11145. POSITION p = pDoc->GetFirstViewPosition();
  11146. while ( p )
  11147. {
  11148. CMapView *pView = dynamic_cast<CMapView*>( pDoc->GetNextView( p ) );
  11149. if ( pView )
  11150. pView->ActivateView( false );
  11151. }
  11152. }
  11153. }
  11154. //-----------------------------------------------------------------------------
  11155. // Purpose: Toggles the state of Tools | Instances | Hide. When enabled, instances are hidden.
  11156. //-----------------------------------------------------------------------------
  11157. void CMapDoc::OnToolsInstancesHide(void)
  11158. {
  11159. m_tShowInstance = INSTANCES_HIDE;
  11160. Options.view3d.iViewInstancesMode = INSTANCES_HIDE;
  11161. UpdateAllViews( MAPVIEW_RENDER_NOW );
  11162. }
  11163. //-----------------------------------------------------------------------------
  11164. // Purpose: Manages the state of the Tools | Instances | Hide menu item.
  11165. //-----------------------------------------------------------------------------
  11166. void CMapDoc::OnUpdateToolsInstancesHide(CCmdUI *pCmdUI)
  11167. {
  11168. pCmdUI->Enable(!GetMainWnd()->IsShellSessionActive());
  11169. pCmdUI->SetCheck( ( m_tShowInstance == INSTANCES_HIDE ) );
  11170. }
  11171. //-----------------------------------------------------------------------------
  11172. // Purpose: Toggles the state of Tools | Instances | Show Tinted. When enabled, instances are tinted.
  11173. //-----------------------------------------------------------------------------
  11174. void CMapDoc::OnToolsInstancesShowTinted(void)
  11175. {
  11176. m_tShowInstance = INSTANCES_SHOW_TINTED;
  11177. Options.view3d.iViewInstancesMode = INSTANCES_SHOW_TINTED;
  11178. UpdateAllViews( MAPVIEW_RENDER_NOW );
  11179. }
  11180. //-----------------------------------------------------------------------------
  11181. // Purpose: Manages the state of the Tools | Instances | Show Tinted menu item.
  11182. //-----------------------------------------------------------------------------
  11183. void CMapDoc::OnUpdateToolsInstancesShowTinted(CCmdUI *pCmdUI)
  11184. {
  11185. pCmdUI->Enable(!GetMainWnd()->IsShellSessionActive());
  11186. pCmdUI->SetCheck( ( m_tShowInstance == INSTANCES_SHOW_TINTED ) );
  11187. }
  11188. //-----------------------------------------------------------------------------
  11189. // Purpose: Toggles the state of Tools | Instances | Show Normal. When enabled, instances are shown just like the rest of the world.
  11190. //-----------------------------------------------------------------------------
  11191. void CMapDoc::OnToolsInstancesShowNormal(void)
  11192. {
  11193. m_tShowInstance = INSTANCES_SHOW_NORMAL;
  11194. Options.view3d.iViewInstancesMode = INSTANCES_SHOW_NORMAL;
  11195. UpdateAllViews( MAPVIEW_RENDER_NOW );
  11196. }
  11197. //-----------------------------------------------------------------------------
  11198. // Purpose: Manages the state of the Tools | Instances | Show Normal menu item.
  11199. //-----------------------------------------------------------------------------
  11200. void CMapDoc::OnUpdateToolsInstancesShowNormal(CCmdUI *pCmdUI)
  11201. {
  11202. pCmdUI->Enable(!GetMainWnd()->IsShellSessionActive());
  11203. pCmdUI->SetCheck( ( m_tShowInstance == INSTANCES_SHOW_NORMAL ) );
  11204. }
  11205. //-----------------------------------------------------------------------------
  11206. // Purpose: this function will show or hide the map doc
  11207. // Input : bIsVisible - flag to indicate the visibility status
  11208. //-----------------------------------------------------------------------------
  11209. void CMapDoc::ShowWindow( bool bIsVisible )
  11210. {
  11211. bool bNeedsInitialUpdate = !HasInitialUpdate();
  11212. POSITION posOpenDoc = GetFirstViewPosition();
  11213. while ( posOpenDoc != NULL )
  11214. {
  11215. CView *pView = GetNextView( posOpenDoc );
  11216. CFrameWnd *pFrame = pView->GetParentFrame();
  11217. if ( pFrame )
  11218. {
  11219. if ( bIsVisible && bNeedsInitialUpdate )
  11220. {
  11221. APP()->pMapDocTemplate->InitialUpdateFrame( pFrame, this, true );
  11222. }
  11223. pFrame->ActivateFrame( bIsVisible ? SW_SHOW : SW_HIDE );
  11224. pFrame->ShowWindow( bIsVisible ? SW_SHOW : SW_HIDE );
  11225. CMainFrame *pwndMain = GetMainWnd();
  11226. ::SendMessage( pwndMain->m_hWndMDIClient, WM_MDIREFRESHMENU, 0, 0 );
  11227. pwndMain->DrawMenuBar();
  11228. }
  11229. }
  11230. if ( bIsVisible && !HasInitialUpdate() )
  11231. {
  11232. SetInitialUpdate();
  11233. }
  11234. }
  11235. //-----------------------------------------------------------------------------
  11236. // Purpose: this function checks to see if the map doc is visible
  11237. // Output : returns true if the document is visible
  11238. //-----------------------------------------------------------------------------
  11239. bool CMapDoc::IsVisible( void )
  11240. {
  11241. POSITION posOpenDoc = GetFirstViewPosition();
  11242. while ( posOpenDoc != NULL )
  11243. {
  11244. CView *pView = GetNextView( posOpenDoc );
  11245. CFrameWnd *pFrame = pView->GetParentFrame();
  11246. if ( pFrame )
  11247. {
  11248. return ( pFrame->IsWindowVisible() == TRUE );
  11249. }
  11250. }
  11251. return false;
  11252. }
  11253. //-----------------------------------------------------------------------------
  11254. // Purpose: this function will hide all instance map windows
  11255. //-----------------------------------------------------------------------------
  11256. void CMapDoc::OnInstancesHideAll( void )
  11257. {
  11258. POSITION pos = APP()->pMapDocTemplate->GetFirstDocPosition();
  11259. while( pos != NULL )
  11260. {
  11261. CDocument *pDoc = APP()->pMapDocTemplate->GetNextDoc( pos );
  11262. CMapDoc *pMapDoc = dynamic_cast< CMapDoc * >( pDoc );
  11263. if ( pMapDoc && pMapDoc->GetReferenceCount() != 0 && !pMapDoc->IsModified() )
  11264. {
  11265. pMapDoc->ShowWindow( false );
  11266. }
  11267. }
  11268. }
  11269. //-----------------------------------------------------------------------------
  11270. // Purpose: this function will show all instance map windows
  11271. //-----------------------------------------------------------------------------
  11272. void CMapDoc::OnInstancesShowAll( void )
  11273. {
  11274. POSITION pos = APP()->pMapDocTemplate->GetFirstDocPosition();
  11275. while( pos != NULL )
  11276. {
  11277. CDocument *pDoc = APP()->pMapDocTemplate->GetNextDoc( pos );
  11278. CMapDoc *pMapDoc = dynamic_cast< CMapDoc * >( pDoc );
  11279. if ( pMapDoc && pMapDoc->GetReferenceCount() != 0 )
  11280. {
  11281. pMapDoc->ShowWindow( true );
  11282. }
  11283. }
  11284. }
  11285. //-----------------------------------------------------------------------------
  11286. // Purpose: This routine will open up the manifest dialog. If the map is not
  11287. // a manifest, it will being the prompted to ask the user if he wants
  11288. // to convert it to one.
  11289. //-----------------------------------------------------------------------------
  11290. void CMapDoc::OnInstancingCreatemanifest()
  11291. {
  11292. CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
  11293. if (!pDoc)
  11294. {
  11295. return;
  11296. }
  11297. CManifest *pManifest = CMapDoc::GetManifest();
  11298. if ( !pManifest )
  11299. {
  11300. if ( AfxMessageBox( "Do you want to create a new manifest from this map?", MB_YESNO ) == IDNO )
  11301. {
  11302. return;
  11303. }
  11304. if ( !CreateNewManifest() )
  11305. {
  11306. return;
  11307. }
  11308. }
  11309. }
  11310. //-----------------------------------------------------------------------------
  11311. // Purpose:
  11312. // Input :
  11313. // Output :
  11314. //-----------------------------------------------------------------------------
  11315. void CMapDoc::OnInstancingCheckinAll( )
  11316. {
  11317. CMapDoc *activeDoc = CMapDoc::GetActiveMapDoc();
  11318. if ( !activeDoc || !activeDoc->GetManifest() )
  11319. {
  11320. return;
  11321. }
  11322. CManifest *pManifest = activeDoc->GetManifest();
  11323. pManifest->m_bDefaultCheckin = true;
  11324. for( int i = 0; i < pManifest->GetNumMaps(); i++ )
  11325. {
  11326. CManifestMap *pManifestMap = pManifest->GetMap( i );
  11327. pManifestMap->m_bDefaultCheckin = true;
  11328. }
  11329. CManifestCheckin ManifestCheckin;
  11330. if ( ManifestCheckin.DoModal() == IDOK )
  11331. {
  11332. pManifest->CheckFileStatus();
  11333. GetMainWnd()->m_ManifestFilterControl.Invalidate();
  11334. }
  11335. }
  11336. //-----------------------------------------------------------------------------
  11337. // Purpose:
  11338. // Input :
  11339. // Output :
  11340. //-----------------------------------------------------------------------------
  11341. void CMapDoc::OnInstancingCheckOutManifest( )
  11342. {
  11343. CMapDoc *activeDoc = CMapDoc::GetActiveMapDoc();
  11344. if ( !activeDoc || !activeDoc->GetManifest() )
  11345. {
  11346. return;
  11347. }
  11348. CManifest *pManifest = activeDoc->GetManifest();
  11349. if ( pManifest->CheckOut() == false && p4 )
  11350. {
  11351. char temp[ 2048 ];
  11352. sprintf( temp, "Could not check out manifest: %s", p4->GetLastError() );
  11353. AfxMessageBox( temp, MB_ICONHAND | MB_OK );
  11354. }
  11355. }
  11356. //-----------------------------------------------------------------------------
  11357. // Purpose:
  11358. // Input :
  11359. // Output :
  11360. //-----------------------------------------------------------------------------
  11361. void CMapDoc::OnInstancingAddManifest( )
  11362. {
  11363. CMapDoc *activeDoc = CMapDoc::GetActiveMapDoc();
  11364. if ( !activeDoc || !activeDoc->GetManifest() )
  11365. {
  11366. return;
  11367. }
  11368. CManifest *pManifest = activeDoc->GetManifest();
  11369. if ( pManifest->AddToVersionControl() == false && p4 )
  11370. {
  11371. char temp[ 2048 ];
  11372. sprintf( temp, "Could not check out manifest: %s", p4->GetLastError() );
  11373. AfxMessageBox( temp, MB_ICONHAND | MB_OK );
  11374. }
  11375. }
  11376. //-----------------------------------------------------------------------------
  11377. // Purpose: This function checks to see if it should enable the Create Manifest menu item
  11378. //-----------------------------------------------------------------------------
  11379. void CMapDoc::OnUpdateInstancingCreatemanifest(CCmdUI *pCmdUI)
  11380. {
  11381. CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
  11382. if ( !pDoc )
  11383. {
  11384. pCmdUI->Enable( false );
  11385. return;
  11386. }
  11387. CManifest *pManifest = CMapDoc::GetManifest();
  11388. pCmdUI->Enable( ( pManifest == NULL ) );
  11389. }
  11390. //-----------------------------------------------------------------------------
  11391. // Purpose:
  11392. // Input :
  11393. // Output :
  11394. //-----------------------------------------------------------------------------
  11395. void CMapDoc::OnUpdateInstancingCheckinAll( CCmdUI *pCmdUI )
  11396. {
  11397. CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
  11398. if ( !pDoc || !p4 )
  11399. {
  11400. pCmdUI->Enable( false );
  11401. return;
  11402. }
  11403. CManifest *pManifest = CMapDoc::GetManifest();
  11404. if ( pManifest == NULL )
  11405. {
  11406. pCmdUI->Enable( false );
  11407. return;
  11408. }
  11409. if ( pManifest->m_bCheckedOut == true )
  11410. {
  11411. pCmdUI->Enable( true );
  11412. return;
  11413. }
  11414. for( int i = 0; i < pManifest->GetNumMaps(); i++ )
  11415. {
  11416. CManifestMap *pManifestMap = pManifest->GetMap( i );
  11417. if ( pManifestMap->m_bCheckedOut == true )
  11418. {
  11419. pCmdUI->Enable( true );
  11420. return;
  11421. }
  11422. }
  11423. pCmdUI->Enable( false );
  11424. }
  11425. //-----------------------------------------------------------------------------
  11426. // Purpose:
  11427. // Input :
  11428. // Output :
  11429. //-----------------------------------------------------------------------------
  11430. void CMapDoc::OnUpdateInstancingCheckOutManifest( CCmdUI *pCmdUI )
  11431. {
  11432. CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
  11433. if ( !pDoc || !p4 )
  11434. {
  11435. pCmdUI->Enable( false );
  11436. return;
  11437. }
  11438. CManifest *pManifest = CMapDoc::GetManifest();
  11439. if ( pManifest == NULL )
  11440. {
  11441. pCmdUI->Enable( false );
  11442. return;
  11443. }
  11444. if ( pManifest->m_bIsVersionControlled == true && pManifest->m_bCheckedOut == false )
  11445. {
  11446. pCmdUI->Enable( true );
  11447. }
  11448. else
  11449. {
  11450. pCmdUI->Enable( false );
  11451. }
  11452. }
  11453. //-----------------------------------------------------------------------------
  11454. // Purpose:
  11455. // Input :
  11456. // Output :
  11457. //-----------------------------------------------------------------------------
  11458. void CMapDoc::OnUpdateInstancingAddManifest( CCmdUI *pCmdUI )
  11459. {
  11460. CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
  11461. if ( !pDoc || !p4 )
  11462. {
  11463. pCmdUI->Enable( false );
  11464. return;
  11465. }
  11466. CManifest *pManifest = CMapDoc::GetManifest();
  11467. if ( pManifest == NULL )
  11468. {
  11469. pCmdUI->Enable( false );
  11470. return;
  11471. }
  11472. if ( pManifest->m_bIsVersionControlled == false )
  11473. {
  11474. pCmdUI->Enable( true );
  11475. }
  11476. else
  11477. {
  11478. pCmdUI->Enable( false );
  11479. }
  11480. }
  11481. //-----------------------------------------------------------------------------
  11482. // Purpose: This function will collapse all instances into the map
  11483. //-----------------------------------------------------------------------------
  11484. void CMapDoc::OnInstancesCollapseAll()
  11485. {
  11486. CollapseInstances( false );
  11487. }
  11488. //-----------------------------------------------------------------------------
  11489. // Purpose: This function will collapse all instances that are selected into the map
  11490. //-----------------------------------------------------------------------------
  11491. void CMapDoc::OnInstancesCollapseSelection()
  11492. {
  11493. CollapseInstances( true );
  11494. }
  11495. //-----------------------------------------------------------------------------
  11496. // Purpose: This function will collapse all instances into the map ( and any children instances )
  11497. //-----------------------------------------------------------------------------
  11498. void CMapDoc::OnInstancesCollapseAllRecursive()
  11499. {
  11500. CollapseInstancesRecursive( false );
  11501. }
  11502. //-----------------------------------------------------------------------------
  11503. // Purpose: This function will collapse all instances that are selected into the map ( and any children instances )
  11504. //-----------------------------------------------------------------------------
  11505. void CMapDoc::OnInstancesCollapseSelectionRecursive()
  11506. {
  11507. CollapseInstancesRecursive( true );
  11508. }
  11509. //--------------------------------------------------------------------------------------------------
  11510. //--------------------------------------------------------------------------------------------------
  11511. static BOOL CountUsedModels( CMapClass *pobj, unsigned int dwParam )
  11512. {
  11513. CUtlVector<AssetUsageInfo_t> *pUsedModels = ( CUtlVector<AssetUsageInfo_t> * )dwParam;
  11514. if ( pobj->IsMapClass( MAPCLASS_TYPE( CMapEntity ) ) )
  11515. {
  11516. CMapEntity *pEntity = ( CMapEntity * )pobj;
  11517. if (pEntity->IsPlaceholder())
  11518. {
  11519. if ( pEntity->ClassNameMatches( "prop_*" ) )
  11520. {
  11521. const char *name = pEntity->GetKeyValue( "model" );
  11522. if ( name )
  11523. {
  11524. CUtlString modelName;
  11525. modelName.Set( name );
  11526. Q_FixSlashes( modelName.Get() );
  11527. for ( int i = 0; i < pUsedModels->Count(); i++ )
  11528. {
  11529. if ( !Q_stricmp( modelName.Get(), pUsedModels->Element( i ).m_assetName.Get() ) )
  11530. {
  11531. pUsedModels->Element( i ).m_nTimesUsed++;
  11532. return TRUE;
  11533. }
  11534. }
  11535. pUsedModels->AddToTail();
  11536. pUsedModels->Tail().m_assetName.Set( modelName );
  11537. pUsedModels->Tail().m_nTimesUsed = 1;
  11538. }
  11539. }
  11540. }
  11541. }
  11542. return TRUE;
  11543. }
  11544. //--------------------------------------------------------------------------------------------------
  11545. //--------------------------------------------------------------------------------------------------
  11546. void CMapDoc::GetUsedModels( CUtlVector<AssetUsageInfo_t> &usedModels )
  11547. {
  11548. m_pWorld->EnumChildrenAndInstances( ( ENUMMAPCHILDRENPROC )CountUsedModels, ( unsigned int )&usedModels );
  11549. }
  11550. //-----------------------------------------------------------------------------
  11551. // Purpose:
  11552. // Input :
  11553. // Output :
  11554. //-----------------------------------------------------------------------------
  11555. void CMapDoc::OnUpdateToolsSprinkle( CCmdUI *pCmdUI )
  11556. {
  11557. int iCurTool = m_pToolManager->GetActiveToolID();
  11558. pCmdUI->Enable( ( iCurTool != TOOL_ENTITY_SPRINKLE ) );
  11559. }
  11560. //-----------------------------------------------------------------------------
  11561. // Purpose:
  11562. // Input :
  11563. // Output :
  11564. //-----------------------------------------------------------------------------
  11565. void CMapDoc::OnToolsSprinkle()
  11566. {
  11567. ToolManager()->SetTool( TOOL_ENTITY_SPRINKLE );
  11568. }
  11569. //-----------------------------------------------------------------------------
  11570. // Purpose: Finds if this object/entity belongs to any FGD-defined AutoVisGroups
  11571. //-----------------------------------------------------------------------------
  11572. void CMapDoc::AddToFGDAutoVisGroups( CMapClass *pObject )
  11573. {
  11574. if ( pGD != NULL )
  11575. {
  11576. CMapEntity *pEntity = dynamic_cast< CMapEntity * >( pObject );
  11577. if ( pEntity != NULL )
  11578. {
  11579. int gindex = 0; // Index of FGD-defined AutoVisGroups
  11580. int cindex = 0; // Index of Classes
  11581. int eindex = 0; // Index of Entities
  11582. // Parent
  11583. for( gindex = 0; gindex < pGD->m_FGDAutoVisGroups.Count(); gindex++ )
  11584. {
  11585. // Class
  11586. for ( cindex = 0; cindex < pGD->m_FGDAutoVisGroups[gindex].m_Classes.Count(); cindex++ )
  11587. {
  11588. // Object/Entity
  11589. for ( eindex = 0; eindex < pGD->m_FGDAutoVisGroups[gindex].m_Classes[cindex].szEntities.Count(); eindex++ )
  11590. {
  11591. //
  11592. if ( !V_stricmp( pEntity->GetClassName(), pGD->m_FGDAutoVisGroups[gindex].m_Classes[cindex].szEntities[eindex] ) )
  11593. {
  11594. AddChildGroupToAutoVisGroup( pEntity, pGD->m_FGDAutoVisGroups[gindex].m_Classes[cindex].szClass, pGD->m_FGDAutoVisGroups[gindex].szParent );
  11595. }
  11596. }
  11597. }
  11598. }
  11599. }
  11600. }
  11601. }
  11602. //-----------------------------------------------------------------------------
  11603. // Purpose: Add objects/entities to QuickHide
  11604. //-----------------------------------------------------------------------------
  11605. void CMapDoc::QuickHide_HideObjects( void )
  11606. {
  11607. const CMapObjectList *pSelList = m_pSelection->GetList();
  11608. for ( int index = 0; index < pSelList->Count(); index++ )
  11609. {
  11610. CMapClass *pObject = (CUtlReference< CMapClass >)pSelList->Element( index );
  11611. // Hide the object
  11612. m_QuickHideGroup.AddToTail( pObject );
  11613. // If it's a Group or Entity, add each child - otherwise we get ghost group selection (driller: FIXME)
  11614. if ( pObject->IsGroup() || pObject->IsMapClass( MAPCLASS_TYPE( CMapEntity ) ) )
  11615. {
  11616. EnumChildrenPos_t pos;
  11617. CMapClass *pChild = pObject->GetFirstDescendent( pos );
  11618. while ( pChild )
  11619. {
  11620. m_QuickHideGroup.AddToTail( pChild );
  11621. pChild = pObject->GetNextDescendent( pos );
  11622. }
  11623. }
  11624. // Does this object have a parent?
  11625. if ( pObject->GetParent() )
  11626. {
  11627. CMapClass *pParent = pObject->GetParent();
  11628. // Track all parents, so we can check if all children (eventually) end up hidden
  11629. while ( pParent )
  11630. {
  11631. if ( pParent->IsGroup() || pParent->IsMapClass( MAPCLASS_TYPE( CMapEntity ) ) )
  11632. {
  11633. if ( m_QuickHideGroupedParents.Find( pParent ) == m_QuickHideGroupedParents.InvalidIndex() )
  11634. {
  11635. m_QuickHideGroupedParents.AddToTail( pParent );
  11636. }
  11637. }
  11638. pParent = pParent->GetParent();
  11639. }
  11640. }
  11641. }
  11642. // Now check any parents
  11643. if ( m_QuickHideGroupedParents.Count() > 0 )
  11644. {
  11645. int nHiddenChildCount = 0;
  11646. for ( int index = 0; index < m_QuickHideGroupedParents.Count(); index++ )
  11647. {
  11648. EnumChildrenPos_t posParent;
  11649. CMapClass *pParent = m_QuickHideGroupedParents[ index ];
  11650. int nChildCount = pParent->GetChildCount();
  11651. if ( pParent )
  11652. {
  11653. CMapClass *pChild = pParent->GetFirstDescendent( posParent );
  11654. // Child visible?
  11655. while ( pChild )
  11656. {
  11657. // With the way GetChildCount() works, we need to count nested children, too
  11658. nChildCount += pChild->GetChildCount();
  11659. if ( m_QuickHideGroup.Find( pChild ) != m_QuickHideGroup.InvalidIndex() )
  11660. {
  11661. nHiddenChildCount++;
  11662. }
  11663. pChild = pParent->GetNextDescendent( posParent );
  11664. }
  11665. }
  11666. // If none of the children are visible...
  11667. if ( nHiddenChildCount == nChildCount )
  11668. {
  11669. // ...also add the parent
  11670. m_QuickHideGroup.AddToTail( pParent );
  11671. }
  11672. nHiddenChildCount = 0;
  11673. }
  11674. }
  11675. m_pToolManager->GetActiveTool()->SetEmpty();
  11676. UpdateVisibilityAll();
  11677. }
  11678. //-----------------------------------------------------------------------------
  11679. // Purpose: Add unselected objects/entities to QuickHide
  11680. //-----------------------------------------------------------------------------
  11681. void CMapDoc::QuickHide_HideUnselectedObjects( void )
  11682. {
  11683. EnumChildrenPos_t pos;
  11684. CMapWorld *pWorld = GetMapWorld();
  11685. CMapClass *pObject = pWorld->GetFirstDescendent( pos );
  11686. while ( pObject )
  11687. {
  11688. if ( !pObject->IsSelected() )
  11689. {
  11690. m_QuickHideGroup.AddToTail( pObject );
  11691. }
  11692. pObject = pWorld->GetNextDescendent( pos );
  11693. }
  11694. // Check each selected object for a parent...
  11695. const CMapObjectList *pSelList = m_pSelection->GetList();
  11696. for ( int index = 0; index < pSelList->Count(); index++ )
  11697. {
  11698. CMapClass *pSelectedObject = (CUtlReference< CMapClass >)pSelList->Element( index );
  11699. CMapClass *pSelectedParent = (CUtlReference< CMapClass >)pSelectedObject->GetParent();
  11700. while ( pSelectedParent )
  11701. {
  11702. // ...and nuke them from QuickHide
  11703. m_QuickHideGroup.FindAndRemove( pSelectedParent );
  11704. pSelectedParent = pSelectedParent->GetParent();
  11705. }
  11706. }
  11707. UpdateVisibilityAll();
  11708. }
  11709. //-----------------------------------------------------------------------------
  11710. // Purpose: Restore any hidden objects and purge data
  11711. //-----------------------------------------------------------------------------
  11712. void CMapDoc::QuickHide_Unhide( void )
  11713. {
  11714. if ( m_QuickHideGroup.Count() > 0 )
  11715. {
  11716. m_QuickHideGroup.RemoveAll();
  11717. m_QuickHideGroupedParents.RemoveAll();
  11718. UpdateVisibilityAll();
  11719. }
  11720. }
  11721. //-----------------------------------------------------------------------------
  11722. // Purpose: Checks the QuickHideGroup for pObject
  11723. //-----------------------------------------------------------------------------
  11724. bool CMapDoc::QuickHide_IsObjectHidden( CMapClass *pObject )
  11725. {
  11726. for ( int index = 0; index < m_QuickHideGroup.Count(); index++ )
  11727. {
  11728. // FIXME: use references to detect objects being deleted
  11729. if ( pObject == m_QuickHideGroup[index] )
  11730. {
  11731. return true;
  11732. }
  11733. }
  11734. return false;
  11735. }
  11736. //-----------------------------------------------------------------------------
  11737. // Purpose: Creates a visgroup with currently hidden objects
  11738. //-----------------------------------------------------------------------------
  11739. void CMapDoc::OnQuickHide_CreateVisGroupFromHidden( void )
  11740. {
  11741. int iQuickHideObjects = m_QuickHideGroup.Count();
  11742. if ( iQuickHideObjects > 0 )
  11743. {
  11744. CMapObjectList Objects;
  11745. FOR_EACH_OBJ( m_QuickHideGroup, pos )
  11746. {
  11747. CMapClass *pChild = m_QuickHideGroup[pos];
  11748. Objects.AddToTail( pChild );
  11749. }
  11750. CString str;
  11751. str.Format( "_FromQuickHide(%d)", iQuickHideObjects );
  11752. VisGroups_CreateNamedVisGroup( Objects, str, true, false );
  11753. }
  11754. QuickHide_Unhide();
  11755. }
  11756. //-----------------------------------------------------------------------------
  11757. // Purpose: Creates a token in the VMF, which we use for P4 check-in testing
  11758. //-----------------------------------------------------------------------------
  11759. ChunkFileResult_t CMapDoc::QuickHide_SaveVMF( CChunkFile *pFile, CSaveInfo *pSaveInfo )
  11760. {
  11761. if ( m_QuickHideGroup.Count() == 0)
  11762. {
  11763. return( ChunkFile_Ok );
  11764. }
  11765. ChunkFileResult_t eResult = pFile->BeginChunk( "quickhide" );
  11766. if ( eResult == ChunkFile_Ok )
  11767. {
  11768. int nCount = m_QuickHideGroup.Count();
  11769. eResult = pFile->WriteKeyValueInt( "count", nCount );
  11770. }
  11771. if ( eResult == ChunkFile_Ok )
  11772. {
  11773. eResult = pFile->EndChunk();
  11774. }
  11775. return( eResult );
  11776. }
  11777. //-----------------------------------------------------------------------------
  11778. // Purpose: Menu/Button version of QuickHide_HideObjects
  11779. //-----------------------------------------------------------------------------
  11780. void CMapDoc::OnQuickHide_HideObjects( void )
  11781. {
  11782. QuickHide_HideObjects();
  11783. }
  11784. //-----------------------------------------------------------------------------
  11785. // Purpose: Menu/Button version of QuickHide_HideUnselectedObjects
  11786. //-----------------------------------------------------------------------------
  11787. void CMapDoc::OnQuickHide_HideUnselectedObjects( void )
  11788. {
  11789. QuickHide_HideUnselectedObjects();
  11790. }
  11791. //-----------------------------------------------------------------------------
  11792. // Purpose: Menu/Button version of OnQuickHide_Unhide
  11793. //-----------------------------------------------------------------------------
  11794. void CMapDoc::OnQuickHide_Unhide( void )
  11795. {
  11796. QuickHide_Unhide();
  11797. }
  11798. //-----------------------------------------------------------------------------
  11799. // Purpose:
  11800. //-----------------------------------------------------------------------------
  11801. void CMapDoc::OnRadiusCulling( void )
  11802. {
  11803. Options.general.bRadiusCulling = !Options.general.bRadiusCulling;
  11804. UpdateVisibilityAll();
  11805. }
  11806. //-----------------------------------------------------------------------------
  11807. // Purpose:
  11808. //-----------------------------------------------------------------------------
  11809. void CMapDoc::OnUpdateRadiusCulling( CCmdUI *pCmdUI )
  11810. {
  11811. pCmdUI->SetCheck( Options.general.bRadiusCulling ? 1 : 0 );
  11812. pCmdUI->Enable(!GetMainWnd()->IsShellSessionActive());
  11813. }
  11814. #include <tier0/memdbgoff.h>