594 lines
14 KiB
C++
594 lines
14 KiB
C++
//========= 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);
|
|
}
|
|
|