Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

593 lines
14 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "stdafx.h"
  8. #include <sys\types.h>
  9. #include <sys\stat.h>
  10. #include "ChunkFile.h"
  11. #include "Prefab3D.h"
  12. #include "Options.h"
  13. #include "History.h"
  14. #include "MapGroup.h"
  15. #include "MapWorld.h"
  16. #include "GlobalFunctions.h"
  17. // memdbgon must be the last include file in a .cpp file!!!
  18. #include <tier0/memdbgon.h>
  19. //-----------------------------------------------------------------------------
  20. // Purpose:
  21. //-----------------------------------------------------------------------------
  22. CPrefab3D::CPrefab3D()
  23. {
  24. m_pWorld = NULL;
  25. }
  26. //-----------------------------------------------------------------------------
  27. // Purpose:
  28. //-----------------------------------------------------------------------------
  29. CPrefab3D::~CPrefab3D()
  30. {
  31. FreeData();
  32. }
  33. //-----------------------------------------------------------------------------
  34. // Purpose:
  35. //-----------------------------------------------------------------------------
  36. void CPrefab3D::FreeData()
  37. {
  38. delete m_pWorld;
  39. m_pWorld = NULL;
  40. }
  41. //-----------------------------------------------------------------------------
  42. // Purpose:
  43. //-----------------------------------------------------------------------------
  44. CMapClass *CPrefab3D::Create(void)
  45. {
  46. if (!IsLoaded() && (Load() == -1))
  47. {
  48. return(NULL);
  49. }
  50. CMapClass *pCopy;
  51. CMapClass *pOriginal;
  52. //
  53. // Check for just one object - if only one, don't group it.
  54. //
  55. if (m_pWorld->GetChildCount() == 1)
  56. {
  57. pOriginal = m_pWorld->GetChildren()->Element(0);
  58. pCopy = pOriginal->Copy(false);
  59. }
  60. else
  61. {
  62. // Original object is world
  63. pOriginal = m_pWorld;
  64. // New object is a new group
  65. pCopy = (CMapClass *)new CMapGroup;
  66. }
  67. //
  68. // Copy children from original (if any).
  69. //
  70. pCopy->CopyChildrenFrom(pOriginal, false);
  71. // HACK: must calculate bounds here due to a hack in CMapClass::CopyChildrenFrom
  72. pCopy->CalcBounds();
  73. return(pCopy);
  74. }
  75. //-----------------------------------------------------------------------------
  76. // Purpose:
  77. // Input : point - Where to center the prefab.
  78. // Output : CMapClass
  79. //-----------------------------------------------------------------------------
  80. CMapClass *CPrefab3D::CreateAtPoint(const Vector &point)
  81. {
  82. //
  83. // Create the prefab object. It will either be a single object
  84. // or a group containing the prefab objects.
  85. //
  86. CMapClass *pObject = Create();
  87. if (pObject != NULL)
  88. {
  89. //
  90. // Move the prefab center to match the given point.
  91. //
  92. Vector move = point;
  93. Vector center;
  94. pObject->GetBoundsCenter(center);
  95. for (int i = 0; i < 3; i++)
  96. {
  97. move[i] -= center[i];
  98. }
  99. BOOL bOldLock = Options.SetLockingTextures(TRUE);
  100. pObject->TransMove(move);
  101. Options.SetLockingTextures(bOldLock);
  102. }
  103. return(pObject);
  104. }
  105. //-----------------------------------------------------------------------------
  106. // Purpose:
  107. // Input :
  108. // Output :
  109. //-----------------------------------------------------------------------------
  110. CMapClass *CPrefab3D::CreateAtPointAroundOrigin( Vector const &point )
  111. {
  112. //
  113. // Create the prefab object. It will either be a single object
  114. // or a group containing the prefab objects.
  115. //
  116. CMapClass *pObject = Create();
  117. if( !pObject )
  118. return NULL;
  119. Vector move = point;
  120. BOOL bOldLock = Options.SetLockingTextures( TRUE );
  121. pObject->TransMove( move );
  122. Options.SetLockingTextures( bOldLock );
  123. return ( pObject );
  124. }
  125. //-----------------------------------------------------------------------------
  126. // Purpose:
  127. // Input : pBox -
  128. // Output :
  129. //-----------------------------------------------------------------------------
  130. CMapClass *CPrefab3D::CreateInBox(BoundBox *pBox)
  131. {
  132. //
  133. // Create the prefab object. It will either be a single object
  134. // or a group containing the prefab objects.
  135. //
  136. CMapClass *pObject = Create();
  137. if (pObject != NULL)
  138. {
  139. //
  140. // Scale the prefab to match the box bounds.
  141. //
  142. Vector NewSize;
  143. pBox->GetBoundsSize(NewSize);
  144. Vector CurSize;
  145. pObject->GetBoundsSize(CurSize);
  146. Vector scale;
  147. for (int i = 0; i < 3; i++)
  148. {
  149. scale[i] = NewSize[i] / CurSize[i];
  150. }
  151. Vector zero(0, 0, 0);
  152. pObject->TransScale(zero, scale);
  153. //
  154. // Move the prefab center to match the box center.
  155. //
  156. Vector move;
  157. pBox->GetBoundsCenter(move);
  158. Vector center;
  159. pObject->GetBoundsCenter(center);
  160. for (int i = 0; i < 3; i++)
  161. {
  162. move[i] -= center[i];
  163. }
  164. BOOL bOldLock = Options.SetLockingTextures(TRUE);
  165. pObject->TransMove(move);
  166. Options.SetLockingTextures(bOldLock);
  167. }
  168. return(pObject);
  169. }
  170. //-----------------------------------------------------------------------------
  171. // Purpose:
  172. //-----------------------------------------------------------------------------
  173. void CPrefab3D::CenterOnZero()
  174. {
  175. Vector ptCenter;
  176. m_pWorld->GetBoundsCenter(ptCenter);
  177. ptCenter[0] = -ptCenter[0];
  178. ptCenter[1] = -ptCenter[1];
  179. ptCenter[2] = -ptCenter[2];
  180. BOOL bOldLock = Options.SetLockingTextures(TRUE);
  181. m_pWorld->TransMove(ptCenter);
  182. Options.SetLockingTextures(bOldLock);
  183. }
  184. //-----------------------------------------------------------------------------
  185. // Purpose: Returns true if the prefab data has been loaded from disk, false if not.
  186. //-----------------------------------------------------------------------------
  187. bool CPrefab3D::IsLoaded(void)
  188. {
  189. return (m_pWorld != NULL);
  190. }
  191. //-----------------------------------------------------------------------------
  192. // Purpose:
  193. //-----------------------------------------------------------------------------
  194. CPrefabRMF::CPrefabRMF()
  195. {
  196. }
  197. //-----------------------------------------------------------------------------
  198. // Purpose:
  199. //-----------------------------------------------------------------------------
  200. CPrefabRMF::~CPrefabRMF()
  201. {
  202. }
  203. //-----------------------------------------------------------------------------
  204. // Purpose:
  205. // Input : file -
  206. // dwFlags -
  207. // Output : int
  208. //-----------------------------------------------------------------------------
  209. int CPrefabRMF::DoLoad(std::fstream& file, DWORD dwFlags)
  210. {
  211. int iRvl;
  212. GetHistory()->Pause();
  213. AddMRU(this);
  214. if(m_pWorld)
  215. delete m_pWorld;
  216. m_pWorld = new CMapWorld( NULL );
  217. // read data
  218. if(dwFlags & lsMAP)
  219. iRvl = m_pWorld->SerializeMAP(file, FALSE);
  220. else
  221. iRvl = m_pWorld->SerializeRMF(file, FALSE);
  222. // error?
  223. if(iRvl == -1)
  224. {
  225. GetHistory()->Resume();
  226. return iRvl;
  227. }
  228. m_pWorld->CalcBounds(TRUE);
  229. GetHistory()->Resume();
  230. return 1;
  231. }
  232. //-----------------------------------------------------------------------------
  233. // Purpose:
  234. // Input : file -
  235. // dwFlags -
  236. // Output : int
  237. //-----------------------------------------------------------------------------
  238. int CPrefabRMF::DoSave(std::fstream& file, DWORD dwFlags)
  239. {
  240. // save world
  241. if(dwFlags & lsMAP)
  242. return m_pWorld->SerializeMAP(file, TRUE);
  243. return m_pWorld->SerializeRMF(file, TRUE);
  244. }
  245. //-----------------------------------------------------------------------------
  246. // Purpose:
  247. // Input : dwFlags -
  248. // Output : int
  249. //-----------------------------------------------------------------------------
  250. int CPrefabRMF::Load(DWORD dwFlags)
  251. {
  252. //
  253. // Get parent library's file handle.
  254. //
  255. CPrefabLibraryRMF *pLibrary = dynamic_cast <CPrefabLibraryRMF *>(CPrefabLibrary::FindID(dwLibID));
  256. if (!pLibrary)
  257. {
  258. return -1;
  259. }
  260. std::fstream &file = pLibrary->m_file;
  261. file.seekg(dwFileOffset);
  262. return(DoLoad(file, dwFlags));
  263. }
  264. //-----------------------------------------------------------------------------
  265. // Purpose:
  266. // Input : pszFilename -
  267. // bLoadNow -
  268. // dwFlags -
  269. // Output : int
  270. //-----------------------------------------------------------------------------
  271. int CPrefabRMF::Init(LPCTSTR pszFilename, BOOL bLoadNow, DWORD dwFlags)
  272. {
  273. std::fstream file(pszFilename, std::ios::in | std::ios::binary);
  274. // ensure we're named
  275. memset(szName, 0, sizeof szName);
  276. strncpy(szName, pszFilename, sizeof szName - 1);
  277. return Init(file, bLoadNow, dwFlags);
  278. }
  279. //-----------------------------------------------------------------------------
  280. // Purpose:
  281. // Input : file -
  282. // bLoadNow -
  283. // dwFlags -
  284. // Output : int
  285. //-----------------------------------------------------------------------------
  286. int CPrefabRMF::Init(std::fstream &file, BOOL bLoadNow, DWORD dwFlags)
  287. {
  288. int iRvl = 1; // start off ok
  289. if(bLoadNow)
  290. {
  291. // do load now
  292. iRvl = DoLoad(file, dwFlags);
  293. }
  294. if(!szName[0])
  295. {
  296. // ensure we're named
  297. strcpy(szName, "Prefab");
  298. }
  299. return iRvl;
  300. }
  301. //-----------------------------------------------------------------------------
  302. // Purpose:
  303. // Input : pszFilename -
  304. // dwFlags -
  305. // Output : int
  306. //-----------------------------------------------------------------------------
  307. int CPrefabRMF::Save(LPCTSTR pszFilename, DWORD dwFlags)
  308. {
  309. std::fstream file(pszFilename, std::ios::out | std::ios::binary);
  310. return Save(file, dwFlags);
  311. }
  312. //-----------------------------------------------------------------------------
  313. // Purpose:
  314. // Input : file -
  315. // dwFlags -
  316. // Output : int
  317. //-----------------------------------------------------------------------------
  318. int CPrefabRMF::Save(std::fstream& file, DWORD dwFlags)
  319. {
  320. if (!IsLoaded() && (Load() == -1))
  321. {
  322. AfxMessageBox("Couldn't Load prefab to Save it.");
  323. return -1;
  324. }
  325. return DoSave(file, dwFlags);
  326. }
  327. //-----------------------------------------------------------------------------
  328. // Purpose:
  329. //-----------------------------------------------------------------------------
  330. CPrefabVMF::CPrefabVMF()
  331. {
  332. }
  333. //-----------------------------------------------------------------------------
  334. // Purpose:
  335. //-----------------------------------------------------------------------------
  336. CPrefabVMF::~CPrefabVMF()
  337. {
  338. }
  339. //-----------------------------------------------------------------------------
  340. // Purpose: Returns true if the prefab data has been loaded from disk, false if not.
  341. //-----------------------------------------------------------------------------
  342. bool CPrefabVMF::IsLoaded(void)
  343. {
  344. if (m_pWorld == NULL)
  345. {
  346. return false;
  347. }
  348. //
  349. // We have loaded this prefab at least once this session. Check the file date/time
  350. // against our cached date/time to see if we need to reload it.
  351. //
  352. struct _stat info;
  353. if (_stat(m_szFilename, &info) == 0)
  354. {
  355. if (info.st_mtime > m_nFileTime)
  356. {
  357. return false;
  358. }
  359. }
  360. return true;
  361. }
  362. //-----------------------------------------------------------------------------
  363. // Purpose:
  364. // Input : dwFlags -
  365. // Output : int
  366. //-----------------------------------------------------------------------------
  367. int CPrefabVMF::Load(DWORD dwFlags)
  368. {
  369. //
  370. // Create a new world to hold the loaded objects.
  371. //
  372. if (m_pWorld != NULL)
  373. {
  374. delete m_pWorld;
  375. }
  376. m_pWorld = new CMapWorld( NULL );
  377. //
  378. // Open the file.
  379. //
  380. CChunkFile File;
  381. ChunkFileResult_t eResult = File.Open(m_szFilename, ChunkFile_Read);
  382. //
  383. // Read the file.
  384. //
  385. if (eResult == ChunkFile_Ok)
  386. {
  387. //
  388. // Set up handlers for the subchunks that we are interested in.
  389. //
  390. CChunkHandlerMap Handlers;
  391. Handlers.AddHandler("world", (ChunkHandler_t)CPrefabVMF::LoadWorldCallback, this);
  392. Handlers.AddHandler("entity", (ChunkHandler_t)CPrefabVMF::LoadEntityCallback, this);
  393. // dvs: Handlers.SetErrorHandler((ChunkErrorHandler_t)CPrefabVMF::HandleLoadError, this);
  394. File.PushHandlers(&Handlers);
  395. //CMapDoc::SetLoadingMapDoc( this ); dvs: fix - without this, no displacements in prefabs
  396. //
  397. // Read the sub-chunks. We ignore keys in the root of the file, so we don't pass a
  398. // key value callback to ReadChunk.
  399. //
  400. while (eResult == ChunkFile_Ok)
  401. {
  402. eResult = File.ReadChunk();
  403. }
  404. if (eResult == ChunkFile_EOF)
  405. {
  406. eResult = ChunkFile_Ok;
  407. }
  408. //CMapDoc::SetLoadingMapDoc( NULL );
  409. File.PopHandlers();
  410. }
  411. if (eResult == ChunkFile_Ok)
  412. {
  413. m_pWorld->PostloadWorld();
  414. m_pWorld->CalcBounds();
  415. File.Close();
  416. //
  417. // Store the file modification time to use as a cache check.
  418. //
  419. struct _stat info;
  420. if (_stat(m_szFilename, &info) == 0)
  421. {
  422. m_nFileTime = info.st_mtime;
  423. }
  424. }
  425. else
  426. {
  427. //GetMainWnd()->MessageBox(File.GetErrorText(eResult), "Error loading prefab", MB_OK | MB_ICONEXCLAMATION);
  428. }
  429. return(eResult == ChunkFile_Ok);
  430. }
  431. //-----------------------------------------------------------------------------
  432. // Purpose:
  433. // Input : pFile -
  434. // pData -
  435. // Output : ChunkFileResult_t
  436. //-----------------------------------------------------------------------------
  437. ChunkFileResult_t CPrefabVMF::LoadEntityCallback(CChunkFile *pFile, CPrefabVMF *pPrefab)
  438. {
  439. CMapEntity *pEntity = new CMapEntity;
  440. ChunkFileResult_t eResult = pEntity->LoadVMF(pFile);
  441. if (eResult == ChunkFile_Ok)
  442. {
  443. CMapWorld *pWorld = pPrefab->GetWorld();
  444. pWorld->AddChild(pEntity);
  445. }
  446. return(ChunkFile_Ok);
  447. }
  448. //-----------------------------------------------------------------------------
  449. // Purpose:
  450. // Input : pFile -
  451. // pData -
  452. // Output : ChunkFileResult_t
  453. //-----------------------------------------------------------------------------
  454. ChunkFileResult_t CPrefabVMF::LoadWorldCallback(CChunkFile *pFile, CPrefabVMF *pPrefab)
  455. {
  456. CMapWorld *pWorld = pPrefab->GetWorld();
  457. ChunkFileResult_t eResult = pWorld->LoadVMF(pFile);
  458. return(eResult);
  459. }
  460. //-----------------------------------------------------------------------------
  461. // Purpose:
  462. // Input : pszFilename -
  463. // dwFlags -
  464. // Output : int
  465. //-----------------------------------------------------------------------------
  466. int CPrefabVMF::Save(LPCTSTR pszFilename, DWORD dwFlags)
  467. {
  468. return 1;
  469. }
  470. //-----------------------------------------------------------------------------
  471. // Purpose:
  472. //-----------------------------------------------------------------------------
  473. void CPrefabVMF::SetFilename(const char *szFilename)
  474. {
  475. //
  476. // Extract the file name without the path or extension as the prefab name.
  477. //
  478. _splitpath(szFilename, NULL, NULL, szName, NULL);
  479. strcpy(m_szFilename, szFilename);
  480. }