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
593 lines
14 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
|
|
#include "stdafx.h" |
|
#include <sys\types.h> |
|
#include <sys\stat.h> |
|
#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 <tier0/memdbgon.h> |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// 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 = 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 <CPrefabLibraryRMF *>(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); |
|
} |
|
|
|
|