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.
926 lines
20 KiB
926 lines
20 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
|
|
#include "stdafx.h" |
|
#include <io.h> |
|
#include "hammer.h" |
|
#include "MapEntity.h" |
|
#include "MapFace.h" |
|
#include "MapSolid.h" |
|
#include "MapStudioModel.h" |
|
#include "MapWorld.h" |
|
#include "GlobalFunctions.h" |
|
#include "VisGroup.h" |
|
#include "MapDoc.h" |
|
#include "MapDisp.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include <tier0/memdbgon.h> |
|
|
|
static CMapWorld *pLoadingWorld; |
|
static float fThisVersion; |
|
static BOOL bCorrupt; |
|
|
|
class COldVisGroup |
|
{ |
|
public: |
|
|
|
char m_szName[128]; |
|
color32 m_rgbColor; |
|
|
|
DWORD m_dwID; |
|
bool m_bVisible; |
|
}; |
|
|
|
|
|
float GetFileVersion() { return fThisVersion; } |
|
|
|
|
|
static void WriteString(std::fstream& file, LPCTSTR pszString) |
|
{ |
|
BYTE cLen = strlen(pszString)+1; |
|
file.write((char*)&cLen, 1); |
|
file.write(pszString, cLen); |
|
} |
|
|
|
static void ReadString(std::fstream& file, char * pszString) |
|
{ |
|
BYTE cLen; |
|
file.read((char *)&cLen, 1); |
|
file.read(pszString, cLen); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Loads a solid face from RMF. |
|
//----------------------------------------------------------------------------- |
|
int CMapFace::SerializeRMF(std::fstream& file, BOOL fIsStoring) |
|
{ |
|
int iSize; |
|
|
|
if (fIsStoring) |
|
{ |
|
// |
|
// After 3.3 the alignment of vec4_t's changed. We never save the new format, |
|
// since RMF is no longer being revved. |
|
// |
|
TEXTURE_33 OldTex33; |
|
memset(&OldTex33, 0, sizeof(OldTex33)); |
|
|
|
memcpy(OldTex33.texture, texture.texture, sizeof(OldTex33.texture)); |
|
|
|
OldTex33.UAxis[0] = texture.UAxis[0]; |
|
OldTex33.UAxis[1] = texture.UAxis[1]; |
|
OldTex33.UAxis[2] = texture.UAxis[2]; |
|
OldTex33.UAxis[3] = texture.UAxis[3]; |
|
|
|
OldTex33.VAxis[0] = texture.VAxis[0]; |
|
OldTex33.VAxis[1] = texture.VAxis[1]; |
|
OldTex33.VAxis[2] = texture.VAxis[2]; |
|
OldTex33.VAxis[3] = texture.VAxis[3]; |
|
|
|
OldTex33.rotate = texture.rotate; |
|
|
|
OldTex33.scale[0] = texture.scale[0]; |
|
OldTex33.scale[1] = texture.scale[1]; |
|
|
|
OldTex33.smooth = texture.smooth; |
|
OldTex33.material = texture.material; |
|
OldTex33.q2surface = texture.q2surface; |
|
OldTex33.q2contents = texture.q2contents; |
|
OldTex33.nLightmapScale = texture.nLightmapScale; |
|
|
|
file.write((char *)&OldTex33, sizeof(OldTex33)); |
|
|
|
iSize = nPoints; |
|
file.write((char *)&iSize, sizeof(int)); |
|
|
|
// |
|
// Save face points. We don't serialize the Vectors directly because the memory |
|
// layout changed with SSE optimizations. |
|
// |
|
float SavePoints[256][3]; |
|
for (int i = 0; i < iSize; i++) |
|
{ |
|
SavePoints[i][0] = Points[i].x; |
|
SavePoints[i][1] = Points[i].y; |
|
SavePoints[i][2] = Points[i].z; |
|
} |
|
|
|
file.write((char *)SavePoints, nPoints * 3 * sizeof(float)); |
|
|
|
// |
|
// Save plane points. We don't serialize the Vectors directly because the memory |
|
// layout changed with SSE optimizations. |
|
// |
|
for (int i = 0; i < 3; i++) |
|
{ |
|
SavePoints[i][0] = plane.planepts[i].x; |
|
SavePoints[i][1] = plane.planepts[i].y; |
|
SavePoints[i][2] = plane.planepts[i].z; |
|
} |
|
|
|
file.write((char *)SavePoints, 3 * 3 * sizeof(float)); |
|
} |
|
else |
|
{ |
|
// Pre-2.2 used a different texture structure format. |
|
TEXTURE_21 OldTex; |
|
memset(&OldTex, 0, sizeof(OldTex)); |
|
|
|
if (fThisVersion < 0.9f) |
|
{ |
|
// Read the name |
|
file.read(OldTex.texture, 16); |
|
|
|
// Ensure name is ASCIIZ |
|
OldTex.texture[16] = 0; |
|
|
|
// Read the rest - skip the name |
|
file.read((char *)&OldTex.rotate, sizeof(OldTex.rotate) + sizeof(OldTex.shift) + sizeof(OldTex.scale)); |
|
} |
|
else if (fThisVersion < 1.2f) |
|
{ |
|
// Didn't have smooth/material groups: |
|
file.read((char *)&OldTex, 40); |
|
file.read((char *)&OldTex, sizeof(OldTex.texture) - (MAX_PATH) + sizeof(OldTex.rotate) + sizeof(OldTex.shift) + sizeof(OldTex.scale)); |
|
} |
|
else if (fThisVersion < 1.7f) |
|
{ |
|
// No quake2 fields yet and smaller texture size. |
|
file.read((char *)&OldTex, 40); |
|
file.read((char *)&OldTex.rotate, sizeof(OldTex) - (sizeof(int) * 3) - MAX_PATH); |
|
} |
|
else if (fThisVersion < 1.8f) |
|
{ |
|
// Texture name field changed from 40 to MAX_PATH in size. |
|
file.read((char *)&OldTex, 40); |
|
file.read((char *)&OldTex.rotate, sizeof(OldTex) - MAX_PATH); |
|
} |
|
else if (fThisVersion < 2.2f) |
|
{ |
|
file.read((char *)&OldTex, sizeof(OldTex)); |
|
} |
|
else |
|
{ |
|
// |
|
// After 3.3 the alignment of vec4_t's changed. We never save the new format, |
|
// since RMF is no longer being revved. |
|
// |
|
TEXTURE_33 OldTex33; |
|
memset(&OldTex33, 0, sizeof(OldTex33)); |
|
|
|
file.read((char *)&OldTex33, sizeof(OldTex33)); |
|
|
|
memcpy(texture.texture, OldTex33.texture, sizeof(texture.texture)); |
|
|
|
texture.UAxis[0] = OldTex33.UAxis[0]; |
|
texture.UAxis[1] = OldTex33.UAxis[1]; |
|
texture.UAxis[2] = OldTex33.UAxis[2]; |
|
texture.UAxis[3] = OldTex33.UAxis[3]; |
|
|
|
texture.VAxis[0] = OldTex33.VAxis[0]; |
|
texture.VAxis[1] = OldTex33.VAxis[1]; |
|
texture.VAxis[2] = OldTex33.VAxis[2]; |
|
texture.VAxis[3] = OldTex33.VAxis[3]; |
|
|
|
texture.rotate = OldTex33.rotate; |
|
|
|
texture.scale[0] = OldTex33.scale[0]; |
|
texture.scale[1] = OldTex33.scale[1]; |
|
|
|
texture.smooth = OldTex33.smooth; |
|
texture.material = OldTex33.material; |
|
texture.q2surface = OldTex33.q2surface; |
|
texture.q2contents = OldTex33.q2contents; |
|
texture.nLightmapScale = OldTex33.nLightmapScale; |
|
|
|
if (texture.nLightmapScale == 0) |
|
{ |
|
texture.nLightmapScale = g_pGameConfig->GetDefaultLightmapScale(); |
|
} |
|
} |
|
|
|
// If reading from a pre-2.2 RMF file, copy the texture info from the old format. |
|
if (fThisVersion < 2.2f) |
|
{ |
|
memcpy(texture.texture, OldTex.texture, sizeof(texture.texture)); |
|
memcpy(texture.scale, OldTex.scale, sizeof(texture.scale)); |
|
texture.rotate = OldTex.rotate; |
|
texture.smooth = OldTex.smooth; |
|
texture.material = OldTex.material; |
|
texture.q2surface = OldTex.q2surface; |
|
texture.q2contents = OldTex.q2contents; |
|
texture.UAxis[3] = OldTex.shift[0]; |
|
texture.VAxis[3] = OldTex.shift[1]; |
|
} |
|
|
|
if (fThisVersion < 1.8f) |
|
{ |
|
texture.texture[40] = 0; |
|
} |
|
|
|
// |
|
// Reverse forward slashes if we are not using materials. |
|
// |
|
if (g_pGameConfig->GetTextureFormat() != tfVMT) |
|
{ |
|
for (int i = strlen(texture.texture) - 1; i >= 0; i--) |
|
{ |
|
if (texture.texture[i] == '/') |
|
{ |
|
texture.texture[i] = '\\'; |
|
} |
|
} |
|
} |
|
|
|
if (texture.texture[1] == ':') |
|
{ |
|
char szBuf[MAX_PATH]; |
|
char *psz; |
|
strcpy(szBuf, texture.texture); |
|
psz = strstr(szBuf, "textures\\"); |
|
if (psz) |
|
{ |
|
memset(texture.texture, 0, sizeof(texture.texture)); |
|
psz += strlen("textures\\"); |
|
strcpy(texture.texture, psz); |
|
} |
|
} |
|
|
|
if (fThisVersion < 0.6f) |
|
{ |
|
float light; |
|
file.read((char*) &light, sizeof(light)); |
|
} |
|
|
|
// |
|
// Load the points into an array of float[3]'s and transfer them into |
|
// an array of Vectors which will be used for face creation. We can't |
|
// load directly into the Vectors because the memory layout changed |
|
// when SSE optimizations were added. |
|
// |
|
float LoadPoints[256][3]; |
|
|
|
file.read((char *)&iSize, sizeof(int)); |
|
file.read((char *)&LoadPoints, iSize * 3 * sizeof(float)); |
|
|
|
Vector CreatePoints[256]; |
|
for (int i = 0; i < iSize; i++) |
|
{ |
|
CreatePoints[i].x = LoadPoints[i][0]; |
|
CreatePoints[i].y = LoadPoints[i][1]; |
|
CreatePoints[i].z = LoadPoints[i][2]; |
|
|
|
// |
|
// Negate Z for older RMF files. |
|
// |
|
if (fThisVersion < 0.5f) |
|
{ |
|
CreatePoints[i].z = -CreatePoints[i].z; |
|
} |
|
} |
|
|
|
if (fThisVersion < 2.2f) |
|
{ |
|
CreateFace(CreatePoints, iSize); |
|
} |
|
|
|
// |
|
// Load the plane points. We don't really need them, but they can fix the face if, somehow, it |
|
// was saved without any points. RMF could have been smaller if we only saved these plane points. |
|
// |
|
if (fThisVersion >= 0.7f) |
|
{ |
|
// |
|
// Load the points into an array of float[3]'s and transfer them into |
|
// the array of Vectors. We can't load directly into the Vectors because the memory |
|
// layout changed when SSE optimizations were added. |
|
// |
|
float LoadPlanePoints[3][3]; |
|
file.read((char *)LoadPlanePoints, sizeof(LoadPlanePoints)); |
|
|
|
for (int i = 0; i < 3; i++) |
|
{ |
|
plane.planepts[i].x = LoadPlanePoints[i][0]; |
|
plane.planepts[i].y = LoadPlanePoints[i][1]; |
|
plane.planepts[i].z = LoadPlanePoints[i][2]; |
|
} |
|
|
|
CalcPlane(); |
|
|
|
// If reading from an older RMF file, set up the texture axes Quake-style. |
|
if (fThisVersion < 2.2f) |
|
{ |
|
InitializeTextureAxes(TEXTURE_ALIGN_QUAKE, INIT_TEXTURE_AXES | INIT_TEXTURE_FORCE); |
|
} |
|
} |
|
|
|
if( fThisVersion < 2.2f ) |
|
{ |
|
SetTexture(texture.texture); |
|
} |
|
|
|
// |
|
// version 3.4 -- added displacement info to faces |
|
// |
|
if( ( fThisVersion >= 3.4f ) && ( fThisVersion <= 3.6f ) ) |
|
{ |
|
bool bHasMapDisp; |
|
|
|
if( fThisVersion >= 3.5f ) |
|
{ |
|
int nLoadHasMapDisp; |
|
|
|
// check displacement mapping flag |
|
file.read( ( char* )&nLoadHasMapDisp, sizeof( int ) ); |
|
bHasMapDisp = nLoadHasMapDisp != 0; |
|
} |
|
else |
|
{ |
|
// check displacement mapping flag |
|
file.read( ( char* )&bHasMapDisp, sizeof( bool ) ); |
|
} |
|
|
|
if( bHasMapDisp ) |
|
{ |
|
EditDispHandle_t handle = EditDispMgr()->Create(); |
|
SetDisp( handle ); |
|
|
|
CMapDisp *pDisp = EditDispMgr()->GetDisp( handle ); |
|
pDisp->SetParent( this ); |
|
pDisp->SerializedLoadRMF( file, this, fThisVersion ); |
|
} |
|
} |
|
|
|
if (fThisVersion >= 2.2f) |
|
{ |
|
CreateFace(CreatePoints, iSize); |
|
SetTexture(texture.texture); |
|
} |
|
} |
|
|
|
if (file.bad()) |
|
{ |
|
return(-1); |
|
} |
|
|
|
return(0); |
|
} |
|
|
|
|
|
int MDkeyvalue::SerializeRMF(std::fstream& file, BOOL fIsStoring) |
|
{ |
|
// load/save a keyvalue |
|
if( fIsStoring ) |
|
{ |
|
WriteString(file, szKey); |
|
WriteString(file, szValue); |
|
} |
|
else |
|
{ |
|
ReadString(file, szKey); |
|
ReadString(file, szValue); |
|
} |
|
|
|
if( file.bad() ) |
|
return -1; |
|
return 0; |
|
} |
|
|
|
|
|
int CMapSolid::SerializeRMF(std::fstream& file, BOOL fIsStoring) |
|
{ |
|
int iRvl, iSize; |
|
|
|
// load/save children |
|
CMapClass::SerializeRMF(file, fIsStoring); |
|
|
|
// load/save a brush |
|
if(fIsStoring) |
|
{ |
|
// serialize the Faces |
|
iSize = Faces.GetCount(); |
|
file.write((char*) &iSize, sizeof(int)); |
|
for(int i = 0; i < iSize; i++) |
|
{ |
|
iRvl = Faces[i].SerializeRMF(file, fIsStoring); |
|
if(iRvl < 0) |
|
return iRvl; |
|
} |
|
} |
|
else |
|
{ |
|
// There once was a bug that caused black solids. Fix it here. |
|
if ((r == 0) && (g == 0) || (b == 0)) |
|
{ |
|
PickRandomColor(); |
|
} |
|
|
|
// read Faces |
|
file.read((char*) &iSize, sizeof(int)); |
|
Faces.SetCount(iSize); |
|
|
|
for(int i = 0; i < iSize; i++) |
|
{ |
|
// extract face |
|
iRvl = Faces[i].SerializeRMF(file, fIsStoring); |
|
if (iRvl < 0) |
|
{ |
|
return(iRvl); |
|
} |
|
|
|
Faces[i].SetRenderColor(r, g, b); |
|
Faces[i].SetParent(this); |
|
} |
|
|
|
CalcBounds(); |
|
|
|
// |
|
// Set solid type based on texture name. |
|
// |
|
m_eSolidType = HL1SolidTypeFromTextureName(Faces[0].texture.texture); |
|
} |
|
|
|
if (file.bad()) |
|
{ |
|
return -1; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : file - |
|
// fIsStoring - |
|
// Output : int |
|
//----------------------------------------------------------------------------- |
|
int CEditGameClass::SerializeRMF(std::fstream& file, BOOL fIsStoring) |
|
{ |
|
int iSize, iRvl; |
|
int iAngle = 0; |
|
|
|
if (fIsStoring) |
|
{ |
|
// save data |
|
WriteString(file, GetClassName()); |
|
file.write((char*) &iAngle, sizeof(iAngle)); |
|
|
|
int nSpawnFlags = GetSpawnFlags(); |
|
file.write((char *)&nSpawnFlags, sizeof(nSpawnFlags)); |
|
|
|
// |
|
// Write the number of keyvalues. |
|
// |
|
iSize = 0; |
|
for ( int z=m_KeyValues.GetFirst(); z != m_KeyValues.GetInvalidIndex(); z=m_KeyValues.GetNext( z ) ) |
|
{ |
|
iSize++; |
|
} |
|
file.write((char*) &iSize, sizeof(int)); |
|
|
|
// |
|
// Write the keyvalues. |
|
// |
|
for ( int z=m_KeyValues.GetFirst(); z != m_KeyValues.GetInvalidIndex(); z=m_KeyValues.GetNext( z ) ) |
|
{ |
|
MDkeyvalue KeyValue = m_KeyValues.GetKeyValue(z); |
|
|
|
iRvl = KeyValue.SerializeRMF(file, fIsStoring); |
|
if (iRvl < 0) |
|
{ |
|
return iRvl; |
|
} |
|
} |
|
|
|
// |
|
// Save dummy timeline info. |
|
// |
|
BOOL bTimeline = FALSE; |
|
int nTime = 0; |
|
file.write((char*) &bTimeline, sizeof bTimeline); |
|
file.write((char*) &nTime, sizeof nTime); |
|
file.write((char*) &nTime, sizeof nTime); |
|
} |
|
else |
|
{ |
|
char buf[128]; |
|
ReadString(file, buf); |
|
file.read((char*) &iAngle, sizeof(iAngle)); |
|
|
|
int nSpawnFlags; |
|
file.read((char *)&nSpawnFlags, sizeof(nSpawnFlags)); |
|
|
|
Assert(buf[0]); |
|
|
|
CEditGameClass::SetClass(buf, true); |
|
|
|
// |
|
// Read the keyvalues. |
|
// |
|
file.read((char *) &iSize, sizeof(int)); |
|
for (int i = 0; i < iSize; i++ ) |
|
{ |
|
MDkeyvalue KeyValue; |
|
iRvl = KeyValue.SerializeRMF(file, fIsStoring); |
|
if (iRvl < 0) |
|
{ |
|
return iRvl; |
|
} |
|
m_KeyValues.SetValue(KeyValue.szKey, KeyValue.szValue); |
|
} |
|
|
|
SetSpawnFlags(nSpawnFlags); |
|
m_KeyValues.SetValue("classname", buf); |
|
|
|
// backwards compatibility for old iAngle |
|
if (iAngle) |
|
{ |
|
ImportAngle(iAngle); |
|
} |
|
|
|
// |
|
// Dummy timeline information - unused. |
|
// |
|
if (fThisVersion >= 1.5f) |
|
{ |
|
BOOL bTimeline; |
|
int nTime; |
|
|
|
file.read((char*) &bTimeline, sizeof bTimeline); |
|
file.read((char*) &nTime, sizeof nTime); |
|
file.read((char*) &nTime, sizeof nTime); |
|
} |
|
} |
|
|
|
return file.bad() ? -1 : 0; |
|
} |
|
|
|
|
|
int CMapClass::SerializeRMF(std::fstream& file, BOOL fIsStoring) |
|
{ |
|
int iSize, iRvl; |
|
|
|
if(fIsStoring) |
|
{ |
|
// write type |
|
WriteString(file, GetType()); |
|
|
|
// |
|
// Write the visgroup ID (zero if none). |
|
// |
|
DWORD dwID = 0; |
|
|
|
/*if (m_pVisGroup) |
|
{ |
|
// visgroupfixme: how to handle saving RMF? save the first group?? |
|
dwID = m_pVisGroup->GetID(); |
|
}*/ |
|
|
|
file.write((char *)&dwID, sizeof(dwID)); |
|
|
|
// |
|
// Write the object color. |
|
// |
|
file.write((char *)&r, sizeof(BYTE)); |
|
file.write((char *)&g, sizeof(BYTE)); |
|
file.write((char *)&b, sizeof(BYTE)); |
|
|
|
// |
|
// Save children. |
|
// |
|
int nChildCount = 0; |
|
|
|
FOR_EACH_OBJ( m_Children, pos ) |
|
{ |
|
CMapClass *pChild = m_Children.Element(pos); |
|
if (pChild->ShouldSerialize()) |
|
{ |
|
nChildCount++; |
|
} |
|
} |
|
|
|
file.write((char *)&nChildCount, sizeof(int)); |
|
|
|
FOR_EACH_OBJ( m_Children, pos ) |
|
{ |
|
CMapClass *pChild = m_Children.Element(pos); |
|
if (pChild->ShouldSerialize()) |
|
{ |
|
iRvl = pChild->SerializeRMF(file, fIsStoring); |
|
if (iRvl < 0) |
|
{ |
|
return iRvl; |
|
} |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
// read our stuff |
|
if(fThisVersion < 1.0f) |
|
{ |
|
// kill group information .. unfortunate |
|
file.read((char*) &iSize, sizeof(int)); |
|
file.seekg(iSize, std::ios::cur); |
|
} |
|
else |
|
{ |
|
// just read the visgroup ID but ignore it |
|
DWORD dwGroupID; |
|
file.read((char*) &dwGroupID, sizeof(DWORD)); |
|
} |
|
|
|
// |
|
// Read the object color. |
|
// |
|
file.read((char *)&r, sizeof(BYTE)); |
|
file.read((char *)&g, sizeof(BYTE)); |
|
file.read((char *)&b, sizeof(BYTE)); |
|
|
|
// load children |
|
file.read((char*) &iSize, sizeof(int)); |
|
for(int i = 0; i < iSize; i++) |
|
{ |
|
char buf[128]; |
|
ReadString(file, buf); |
|
CMapClass *pChild = CMapClassManager::CreateObject(buf); |
|
if(!pChild) |
|
{ |
|
bCorrupt = TRUE; |
|
return -1; |
|
} |
|
iRvl = pChild->SerializeRMF(file, fIsStoring); |
|
if(iRvl < 0) |
|
return iRvl; |
|
AddChild(pChild); |
|
} |
|
} |
|
|
|
return file.bad() ? -1 : 0; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : file - |
|
// fIsStoring - |
|
// Output : |
|
//----------------------------------------------------------------------------- |
|
int CMapEntity::SerializeRMF(std::fstream &file, BOOL fIsStoring) |
|
{ |
|
int iSize; |
|
Vector Origin; |
|
|
|
// |
|
// Read/write base class. |
|
// |
|
CMapClass::SerializeRMF(file, fIsStoring); |
|
CEditGameClass::SerializeRMF(file, fIsStoring); |
|
|
|
if (fIsStoring) |
|
{ |
|
// Write flags |
|
file.write((char*) &flags, sizeof(flags)); |
|
|
|
// Write origin |
|
GetOrigin(Origin); |
|
file.write((char *)Origin.Base(), 3 * sizeof(float)); |
|
|
|
// Save padding for unused "complex" field |
|
iSize = 0; |
|
file.write((char*) &iSize, sizeof(int)); |
|
} |
|
else |
|
{ |
|
// Read flags |
|
file.read((char *)&flags, sizeof(flags)); |
|
|
|
// Read origin |
|
file.read((char *)Origin.Base(), 3 * sizeof(float)); |
|
SetOrigin(Origin); |
|
|
|
if (IsClass()) |
|
{ |
|
// Known class. Determine flags based on the class. |
|
flags = IsSolidClass() ? (flags & ~flagPlaceholder) : (flags | flagPlaceholder); |
|
} |
|
else |
|
{ |
|
// Unknown class. Determine flags by looking for children (only solid ents have children at this point). |
|
flags = (m_Children.Count() > 0) ? (flags & ~flagPlaceholder) : (flags | flagPlaceholder); |
|
} |
|
|
|
if (!(IsPlaceholder())) |
|
{ |
|
CMapPoint::SetOrigin(Vector(0, 0, 0)); |
|
} |
|
|
|
GetOrigin(Origin); |
|
|
|
// import for previous to 0.5 |
|
if (fThisVersion < 0.5f) |
|
{ |
|
Origin.z = -Origin.z; |
|
} |
|
|
|
// load unused "complex" field |
|
file.read((char *)&iSize, sizeof(int)); |
|
|
|
SetOrigin(Origin); |
|
|
|
// |
|
// HACK: Set our class to NULL so that it is properly set from our "classname" |
|
// key in PostloadWorld. |
|
// |
|
m_szClass[0] = '\0'; |
|
|
|
CalcBounds(TRUE); |
|
} |
|
|
|
if (file.bad()) |
|
{ |
|
return -1; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
|
|
int CMapWorld::SerializeRMF(std::fstream &file, BOOL fIsStoring) |
|
{ |
|
float fVersion = 3.7f; |
|
float fLastCompat = 0.3f; |
|
|
|
int nSolids = 0; |
|
int iSize; |
|
|
|
pLoadingWorld = this; |
|
bCorrupt = FALSE; |
|
|
|
// load/save a world |
|
if(fIsStoring) |
|
{ |
|
// write version |
|
file.write((char*) &fVersion, sizeof(fVersion)); |
|
|
|
file.write("RMF", 3); |
|
|
|
// we don't save vis groups |
|
iSize = 0; |
|
file.write((char*) &iSize, sizeof(int)); |
|
|
|
// save children & local data |
|
if(CMapClass::SerializeRMF(file, fIsStoring) == -1) |
|
goto FatalError; |
|
|
|
// save ceditgameclass |
|
if(CEditGameClass::SerializeRMF(file, fIsStoring) == -1) |
|
goto FatalError; |
|
|
|
// save paths |
|
iSize = m_Paths.Count(); |
|
file.write((char*) &iSize, sizeof(iSize)); |
|
|
|
FOR_EACH_OBJ( m_Paths, pos ) |
|
{ |
|
CMapPath *pPath = m_Paths.Element(pos); |
|
pPath->SerializeRMF(file, TRUE); |
|
} |
|
|
|
if(file.bad()) |
|
goto FatalError; |
|
} |
|
else |
|
{ |
|
// read & check version |
|
file.read((char*) &fThisVersion, sizeof(fThisVersion)); |
|
if(fThisVersion < fLastCompat || fThisVersion > fVersion) |
|
{ |
|
CString str; |
|
str.Format("Oops! SerializeRMF() v%1.1f tried to load a file v%1.1f. Aborting.", |
|
fVersion, fThisVersion); |
|
AfxMessageBox(str); |
|
return -1; |
|
} |
|
|
|
char buf[128]; |
|
|
|
if(fThisVersion >= 0.8f) |
|
{ |
|
file.read(buf, 3); |
|
if(strncmp(buf, "RMF", 3)) |
|
{ |
|
AfxMessageBox("Invalid file type."); |
|
return -1; |
|
} |
|
} |
|
|
|
// load groups |
|
if (fThisVersion >= 1.0f) |
|
{ |
|
file.read((char*) &iSize, sizeof(int)); |
|
|
|
for ( int i = 0; i < iSize; i++) |
|
{ |
|
// just skip vis groups |
|
COldVisGroup oldVisGroup; |
|
file.read((char*) &oldVisGroup, sizeof(COldVisGroup)); |
|
} |
|
} |
|
|
|
m_Render2DBox.ResetBounds(); |
|
|
|
// make sure it's a CMapWorld |
|
ReadString(file, buf); |
|
if(strcmp(buf, GetType())) |
|
{ |
|
AfxMessageBox("Invalid file type."); |
|
return -1; |
|
} |
|
|
|
// load children & local data |
|
if(CMapClass::SerializeRMF(file, fIsStoring) == -1) |
|
goto FatalError; |
|
|
|
// load ceditgameclass & CMapClass |
|
if(CEditGameClass::SerializeRMF(file, fIsStoring) == -1) |
|
goto FatalError; |
|
|
|
if(fThisVersion < 1.0f) |
|
{ |
|
const int old_group_bytes = 134; |
|
file.read((char*) &iSize, sizeof(int)); |
|
file.seekg(old_group_bytes * iSize, std::ios::cur); |
|
} |
|
|
|
// load paths |
|
if(fThisVersion >= 1.1f) |
|
{ |
|
file.read((char*) &iSize, sizeof iSize); |
|
for(int i = 0; i < iSize; i++) |
|
{ |
|
CMapPath *pPath = new CMapPath; |
|
pPath->SerializeRMF(file, FALSE); |
|
if(pPath->GetNodeCount() == 0) |
|
{ |
|
delete pPath; |
|
continue; // no add dead paths |
|
} |
|
m_Paths.AddToTail(pPath); |
|
} |
|
} |
|
|
|
// read camera |
|
if(fThisVersion < 1.4f) |
|
{ |
|
float unused[3]; |
|
file.read((char*) unused, sizeof(float)*3); |
|
file.read((char*) unused, sizeof(float)*3); |
|
} |
|
|
|
if(file.bad()) |
|
goto FatalError; |
|
|
|
PostloadWorld(); |
|
|
|
if (g_pGameConfig->GetTextureFormat() == tfVMT) |
|
{ |
|
// do batch search and replace of textures from trans.txt if it exists. |
|
char translationFilename[MAX_PATH]; |
|
Q_snprintf( translationFilename, sizeof( translationFilename ), "materials/trans.txt" ); |
|
FileHandle_t searchReplaceFP = fopen( translationFilename, "r" ); |
|
if( searchReplaceFP ) |
|
{ |
|
CMapDoc::GetActiveMapDoc()->BatchReplaceTextures( searchReplaceFP ); |
|
g_pFileSystem->Close( searchReplaceFP ); |
|
} |
|
} |
|
} |
|
|
|
return nSolids; |
|
|
|
FatalError: |
|
CString str; |
|
if(bCorrupt) |
|
{ |
|
// file-is-corrupt error |
|
str.Format("The file is corrupt."); |
|
AfxMessageBox(str); |
|
|
|
return -1; |
|
} |
|
|
|
// OS error. |
|
str.Format("The OS reported an error %s the file: %s", |
|
fIsStoring ? "saving" : "loading", strerror(errno)); |
|
AfxMessageBox(str); |
|
|
|
return -1; |
|
}
|
|
|