//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //=============================================================================// #include "stdafx.h" #include #include #include "ChunkFile.h" #include "Prefab3D.h" #include "Options.h" #include "History.h" #include "MapGroup.h" #include "MapWorld.h" #include "GlobalFunctions.h" // memdbgon must be the last include file in a .cpp file!!! #include //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CPrefab3D::CPrefab3D() { m_pWorld = NULL; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CPrefab3D::~CPrefab3D() { FreeData(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CPrefab3D::FreeData() { delete m_pWorld; m_pWorld = NULL; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CMapClass *CPrefab3D::Create(void) { if (!IsLoaded() && (Load() == -1)) { return(NULL); } CMapClass *pCopy; CMapClass *pOriginal; // // Check for just one object - if only one, don't group it. // if (m_pWorld->GetChildCount() == 1) { pOriginal = (CUtlReference< CMapClass >)m_pWorld->GetChildren()->Element(0); pCopy = pOriginal->Copy(false); } else { // Original object is world pOriginal = m_pWorld; // New object is a new group pCopy = (CMapClass *)new CMapGroup; } // // Copy children from original (if any). // pCopy->CopyChildrenFrom(pOriginal, false); // HACK: must calculate bounds here due to a hack in CMapClass::CopyChildrenFrom pCopy->CalcBounds(); return(pCopy); } //----------------------------------------------------------------------------- // Purpose: // Input : point - Where to center the prefab. // Output : CMapClass //----------------------------------------------------------------------------- CMapClass *CPrefab3D::CreateAtPoint(const Vector &point) { // // Create the prefab object. It will either be a single object // or a group containing the prefab objects. // CMapClass *pObject = Create(); if (pObject != NULL) { // // Move the prefab center to match the given point. // Vector move = point; Vector center; pObject->GetBoundsCenter(center); for (int i = 0; i < 3; i++) { move[i] -= center[i]; } BOOL bOldLock = Options.SetLockingTextures(TRUE); pObject->TransMove(move); Options.SetLockingTextures(bOldLock); } return(pObject); } //----------------------------------------------------------------------------- // Purpose: // Input : // Output : //----------------------------------------------------------------------------- CMapClass *CPrefab3D::CreateAtPointAroundOrigin( Vector const &point ) { // // Create the prefab object. It will either be a single object // or a group containing the prefab objects. // CMapClass *pObject = Create(); if( !pObject ) return NULL; Vector move = point; BOOL bOldLock = Options.SetLockingTextures( TRUE ); pObject->TransMove( move ); Options.SetLockingTextures( bOldLock ); return ( pObject ); } //----------------------------------------------------------------------------- // Purpose: // Input : pBox - // Output : //----------------------------------------------------------------------------- CMapClass *CPrefab3D::CreateInBox(BoundBox *pBox) { // // Create the prefab object. It will either be a single object // or a group containing the prefab objects. // CMapClass *pObject = Create(); if (pObject != NULL) { // // Scale the prefab to match the box bounds. // Vector NewSize; pBox->GetBoundsSize(NewSize); Vector CurSize; pObject->GetBoundsSize(CurSize); Vector scale; for (int i = 0; i < 3; i++) { scale[i] = NewSize[i] / CurSize[i]; } Vector zero(0, 0, 0); pObject->TransScale(zero, scale); // // Move the prefab center to match the box center. // Vector move; pBox->GetBoundsCenter(move); Vector center; pObject->GetBoundsCenter(center); for (int i = 0; i < 3; i++) { move[i] -= center[i]; } BOOL bOldLock = Options.SetLockingTextures(TRUE); pObject->TransMove(move); Options.SetLockingTextures(bOldLock); } return(pObject); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CPrefab3D::CenterOnZero() { Vector ptCenter; m_pWorld->GetBoundsCenter(ptCenter); ptCenter[0] = -ptCenter[0]; ptCenter[1] = -ptCenter[1]; ptCenter[2] = -ptCenter[2]; BOOL bOldLock = Options.SetLockingTextures(TRUE); m_pWorld->TransMove(ptCenter); Options.SetLockingTextures(bOldLock); } //----------------------------------------------------------------------------- // Purpose: Returns true if the prefab data has been loaded from disk, false if not. //----------------------------------------------------------------------------- bool CPrefab3D::IsLoaded(void) { return (m_pWorld != NULL); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CPrefabRMF::CPrefabRMF() { } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CPrefabRMF::~CPrefabRMF() { } //----------------------------------------------------------------------------- // Purpose: // Input : file - // dwFlags - // Output : int //----------------------------------------------------------------------------- int CPrefabRMF::DoLoad(std::fstream& file, DWORD dwFlags) { int iRvl; GetHistory()->Pause(); AddMRU(this); if(m_pWorld) delete m_pWorld; m_pWorld = new CMapWorld( NULL ); // read data if(dwFlags & lsMAP) iRvl = m_pWorld->SerializeMAP(file, FALSE); else iRvl = m_pWorld->SerializeRMF(file, FALSE); // error? if(iRvl == -1) { GetHistory()->Resume(); return iRvl; } m_pWorld->CalcBounds(TRUE); GetHistory()->Resume(); return 1; } //----------------------------------------------------------------------------- // Purpose: // Input : file - // dwFlags - // Output : int //----------------------------------------------------------------------------- int CPrefabRMF::DoSave(std::fstream& file, DWORD dwFlags) { // save world if(dwFlags & lsMAP) return m_pWorld->SerializeMAP(file, TRUE); return m_pWorld->SerializeRMF(file, TRUE); } //----------------------------------------------------------------------------- // Purpose: // Input : dwFlags - // Output : int //----------------------------------------------------------------------------- int CPrefabRMF::Load(DWORD dwFlags) { // // Get parent library's file handle. // CPrefabLibraryRMF *pLibrary = dynamic_cast (CPrefabLibrary::FindID(dwLibID)); if (!pLibrary) { return -1; } std::fstream &file = pLibrary->m_file; file.seekg(dwFileOffset); return(DoLoad(file, dwFlags)); } //----------------------------------------------------------------------------- // Purpose: // Input : pszFilename - // bLoadNow - // dwFlags - // Output : int //----------------------------------------------------------------------------- int CPrefabRMF::Init(LPCTSTR pszFilename, BOOL bLoadNow, DWORD dwFlags) { std::fstream file(pszFilename, std::ios::in | std::ios::binary); // ensure we're named memset(szName, 0, sizeof szName); strncpy(szName, pszFilename, sizeof szName - 1); return Init(file, bLoadNow, dwFlags); } //----------------------------------------------------------------------------- // Purpose: // Input : file - // bLoadNow - // dwFlags - // Output : int //----------------------------------------------------------------------------- int CPrefabRMF::Init(std::fstream &file, BOOL bLoadNow, DWORD dwFlags) { int iRvl = 1; // start off ok if(bLoadNow) { // do load now iRvl = DoLoad(file, dwFlags); } if(!szName[0]) { // ensure we're named strcpy(szName, "Prefab"); } return iRvl; } //----------------------------------------------------------------------------- // Purpose: // Input : pszFilename - // dwFlags - // Output : int //----------------------------------------------------------------------------- int CPrefabRMF::Save(LPCTSTR pszFilename, DWORD dwFlags) { std::fstream file(pszFilename, std::ios::out | std::ios::binary); return Save(file, dwFlags); } //----------------------------------------------------------------------------- // Purpose: // Input : file - // dwFlags - // Output : int //----------------------------------------------------------------------------- int CPrefabRMF::Save(std::fstream& file, DWORD dwFlags) { if (!IsLoaded() && (Load() == -1)) { AfxMessageBox("Couldn't Load prefab to Save it."); return -1; } return DoSave(file, dwFlags); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CPrefabVMF::CPrefabVMF() { } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CPrefabVMF::~CPrefabVMF() { } //----------------------------------------------------------------------------- // Purpose: Returns true if the prefab data has been loaded from disk, false if not. //----------------------------------------------------------------------------- bool CPrefabVMF::IsLoaded(void) { if (m_pWorld == NULL) { return false; } // // We have loaded this prefab at least once this session. Check the file date/time // against our cached date/time to see if we need to reload it. // struct _stat info; if (_stat(m_szFilename, &info) == 0) { if (info.st_mtime > m_nFileTime) { return false; } } return true; } //----------------------------------------------------------------------------- // Purpose: // Input : dwFlags - // Output : int //----------------------------------------------------------------------------- int CPrefabVMF::Load(DWORD dwFlags) { // // Create a new world to hold the loaded objects. // if (m_pWorld != NULL) { delete m_pWorld; } m_pWorld = new CMapWorld( NULL ); // // Open the file. // CChunkFile File; ChunkFileResult_t eResult = File.Open(m_szFilename, ChunkFile_Read); // // Read the file. // if (eResult == ChunkFile_Ok) { // // Set up handlers for the subchunks that we are interested in. // CChunkHandlerMap Handlers; Handlers.AddHandler("world", (ChunkHandler_t)CPrefabVMF::LoadWorldCallback, this); Handlers.AddHandler("entity", (ChunkHandler_t)CPrefabVMF::LoadEntityCallback, this); // dvs: Handlers.SetErrorHandler((ChunkErrorHandler_t)CPrefabVMF::HandleLoadError, this); File.PushHandlers(&Handlers); //CMapDoc::SetLoadingMapDoc( this ); dvs: fix - without this, no displacements in prefabs // // Read the sub-chunks. We ignore keys in the root of the file, so we don't pass a // key value callback to ReadChunk. // while (eResult == ChunkFile_Ok) { eResult = File.ReadChunk(); } if (eResult == ChunkFile_EOF) { eResult = ChunkFile_Ok; } //CMapDoc::SetLoadingMapDoc( NULL ); File.PopHandlers(); } if (eResult == ChunkFile_Ok) { m_pWorld->PostloadWorld(); m_pWorld->CalcBounds(); File.Close(); // // Store the file modification time to use as a cache check. // struct _stat info; if (_stat(m_szFilename, &info) == 0) { m_nFileTime = info.st_mtime; } } else { //GetMainWnd()->MessageBox(File.GetErrorText(eResult), "Error loading prefab", MB_OK | MB_ICONEXCLAMATION); } return(eResult == ChunkFile_Ok); } //----------------------------------------------------------------------------- // Purpose: // Input : pFile - // pData - // Output : ChunkFileResult_t //----------------------------------------------------------------------------- ChunkFileResult_t CPrefabVMF::LoadEntityCallback(CChunkFile *pFile, CPrefabVMF *pPrefab) { CMapEntity *pEntity = new CMapEntity; ChunkFileResult_t eResult = pEntity->LoadVMF(pFile); if (eResult == ChunkFile_Ok) { CMapWorld *pWorld = pPrefab->GetWorld(); pWorld->AddChild(pEntity); } return(ChunkFile_Ok); } //----------------------------------------------------------------------------- // Purpose: // Input : pFile - // pData - // Output : ChunkFileResult_t //----------------------------------------------------------------------------- ChunkFileResult_t CPrefabVMF::LoadWorldCallback(CChunkFile *pFile, CPrefabVMF *pPrefab) { CMapWorld *pWorld = pPrefab->GetWorld(); ChunkFileResult_t eResult = pWorld->LoadVMF(pFile); return(eResult); } //----------------------------------------------------------------------------- // Purpose: // Input : pszFilename - // dwFlags - // Output : int //----------------------------------------------------------------------------- int CPrefabVMF::Save(LPCTSTR pszFilename, DWORD dwFlags) { return 1; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CPrefabVMF::SetFilename(const char *szFilename) { // // Extract the file name without the path or extension as the prefab name. // _splitpath(szFilename, NULL, NULL, szName, NULL); strcpy(m_szFilename, szFilename); }