Files
FC1/Editor/CryEditDoc.cpp
romkazvo 34d6c5d489 123
2023-08-07 19:29:24 +08:00

2128 lines
63 KiB
C++

////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: cryeditdoc.cpp
// Version: v1.00
// Created: 31/3/2003 by Timur.
// Compilers: Visual Studio.NET
// Description:
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include <ILMSerializationManager.h>
#include <IStreamEngine.h>
#include "CryEditDoc.h"
#include "MainFrm.h"
#include "OBJExporter1.h"
#include "PluginManager.h"
#include "DimensionsDialog.h"
#include "SurfaceType.h"
#include "Mission.h"
#include "Layer.h"
#include "equippacklib.h"
#include "StringDlg.h"
#include "VegetationMap.h"
#include "ViewManager.h"
#include "DisplaySettings.h"
#include "GameEngine.h"
#include "GameExporter.h"
#include "MissionSelectDialog.h"
#include "AnimationSerializer.h"
#include "TerrainTexGen.h"
#include "Util\FileUtil.h"
#include "Settings.h"
#include "Objects\ObjectManager.h"
#include "Objects\BaseObject.h"
#include "Objects\Entity.h"
#include "Objects\EntityScript.h"
#include "EntityPrototypeManager.h"
#include "Material\MaterialManager.h"
#include "Particles\ParticleManager.h"
#include "Music\MusicManager.h"
#include "Prefabs\PrefabManager.h"
#include <IAgent.h>
#include <IEntitySystem.h>
#include <ISound.h>
#include "LightmapGen.h"
#include "ErrorReportDialog.h"
//#define PROFILE_LOADING_WITH_VTUNE
// profilers api.
//#include "pure.h"
#ifdef PROFILE_LOADING_WITH_VTUNE
#include "D:\Intel\Vtune\Analyzer\Include\VTuneApi.h"
#pragma comment(lib,"D:\\Intel\\Vtune\\Analyzer\\Lib\\VTuneApi.lib")
#endif
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CCryEditDoc
IMPLEMENT_DYNCREATE(CCryEditDoc, CDocument)
BEGIN_MESSAGE_MAP(CCryEditDoc, CDocument)
//{{AFX_MSG_MAP(CCryEditDoc)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
//////////////////////////////////////////////////////////////////////////
CCryEditDoc* theDocument = 0;
/////////////////////////////////////////////////////////////////////////////
// CCryEditDoc construction/destruction
CCryEditDoc::CCryEditDoc()
{
////////////////////////////////////////////////////////////////////////
// Set member variables to initial values
////////////////////////////////////////////////////////////////////////
theDocument = this;
char szPath[_MAX_PATH];
m_loadFailed = false;
m_waterColor = RGB(0,0,255);
m_entityScripts = 0;
// Get the path of the editor
GetCurrentDirectory( _MAX_PATH,szPath );
// Add a backslash
PathAddBackslash(szPath);
// Save it in the member variable to be later returned by
// GetMasterCDFolder()
m_strMasterCDFolder = szPath;
// Create the terrain gradient curve
CreateNewCurve();
m_fogTemplate = GetIEditor()->FindTemplate( "Fog" );
m_environmentTemplate = GetIEditor()->FindTemplate( "Environment" );
if (m_environmentTemplate)
{
m_fogTemplate = m_environmentTemplate->findChild( "Fog" );
}
else
{
m_environmentTemplate = new CXmlNode( "Environment" );
}
m_entityScripts = new CEntityScriptRegistry;
m_bDocumentReady = false;
/*
uint w,h;
BYTE *p;
LoadJPEG( "c:\\mastercd\\background.jpg",&w,&h,&p );
DWORD *trg = new DWORD[w*h];
DWORD *tp = trg;
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
*tp = RGB(p[0],p[1],p[2]);
tp++;
p+=3;
}
}
SaveBitmap( "c:\\mastercd\\background.bmp",w,h,trg );
//SaveBit( )
*/
GetIEditor()->SetDocument(this);
CLogFile::WriteLine("Document created");
}
CCryEditDoc::~CCryEditDoc()
{
UnregisterListener( GetIEditor()->GetMaterialManager() );
ClearMissions();
ClearLayers();
theDocument = 0;
CLogFile::WriteLine("Document destroied");
}
bool CCryEditDoc::Save()
{
return OnSaveDocument(GetPathName()) == TRUE;
}
void CCryEditDoc::ChangeMission()
{
// Notify listeners.
for (std::list<IDocListener*>::iterator it = m_listeners.begin(); it != m_listeners.end(); ++it)
(*it)->OnMissionChange();
}
void CCryEditDoc::SetTerrainSize( int resolution,int unitSize )
{
m_cHeightmap.Resize( resolution,resolution,unitSize );
}
void CCryEditDoc::DeleteContents()
{
m_bDocumentReady = false;
//////////////////////////////////////////////////////////////////////////
// Clear all undo info.
//////////////////////////////////////////////////////////////////////////
GetIEditor()->FlushUndo();
// Notify listeners.
for (std::list<IDocListener*>::iterator it = m_listeners.begin(); it != m_listeners.end(); ++it)
(*it)->OnCloseDocument();
////////////////////////////////////////////////////////////////////////
// Reset Heightmap
////////////////////////////////////////////////////////////////////////
m_cHeightmap.SetWaterLevel(16); // Default water level.
m_cHeightmap.Resize(1024, 1024,m_cHeightmap.GetUnitSize() );
////////////////////////////////////////////////////////////////////////
// Layers
////////////////////////////////////////////////////////////////////////
ClearLayers();
////////////////////////////////////////////////////////////////////////
// Clouds
////////////////////////////////////////////////////////////////////////
m_cClouds.GetLastParam()->bValid = false;
////////////////////////////////////////////////////////////////////////
// Terrain gradient curve
////////////////////////////////////////////////////////////////////////
m_cTerrainCurve.RemoveAllKnots();
CreateNewCurve();
GetIEditor()->ResetViews();
GetIEditor()->SetEditTool(0); // Turn off any active edit tools.
//////////////////////////////////////////////////////////////////////////
// Objects.
//////////////////////////////////////////////////////////////////////////
// Delete all objects from Object Manager.
GetIEditor()->GetObjectManager()->DeleteAllObjects();
GetIEditor()->GetObjectManager()->GetLayersManager()->ClearLayers();
GetIEditor()->GetEquipPackLib()->Reset();
//@HACK: this is needed to force delete of entities.
if (GetIEditor()->GetSystem()->GetIEntitySystem())
GetIEditor()->GetSystem()->GetIEntitySystem()->Update();
for (int i=0; i < m_surfaceTypes.size(); i++)
delete m_surfaceTypes[i];
m_surfaceTypes.clear();
ClearMissions();
static bool firstTime = true;
if (!firstTime)
{
IRenderer *renderer = GetIEditor()->GetRenderer();
//if (renderer)
//renderer->FreeResources(FRR_SHADERS|FRR_TEXTURES|FRR_RESTORE);
}
firstTime = false;
// Load scripts data..
SetModifiedFlag(false);
{
// Notify listeners.
std::list<IDocListener*> listeners = m_listeners;
std::list<IDocListener*>::iterator it,next;
for (it = listeners.begin(); it != listeners.end(); it = next)
{
next = it; next++;
(*it)->OnNewDocument();
}
}
// Close error reports if open.
CErrorReportDialog::Close();
}
BOOL CCryEditDoc::OnNewDocument()
{
////////////////////////////////////////////////////////////////////////
// Reset the document to defaults and free all data
////////////////////////////////////////////////////////////////////////
if (!CDocument::OnNewDocument())
return FALSE;
CLogFile::WriteLine("Preparing new document...");
////////////////////////////////////////////////////////////////////////
// Reset the surface texture of the top render window
////////////////////////////////////////////////////////////////////////
if (GetIEditor())
{
/*
////////////////////////////////////////////////////////////////////////
// Initialize the source control
////////////////////////////////////////////////////////////////////////
m_pIDatabase.CreateInstance("CryVS.Database");
m_pIDatabase->PutLocalPath(GetMasterCDFolder().GetBuffer(1));
*/
////////////////////////////////////////////////////////////////////////
// Plugins
////////////////////////////////////////////////////////////////////////
GetIEditor()->GetPluginManager()->NewDocument();
}
//DeleteContents();
//////////////////////////////////////////////////////////////////////////
// Initialize defaults.
//////////////////////////////////////////////////////////////////////////
if (!GetIEditor()->IsInPreviewMode())
{
// Create default layer.
CLayer *layer = new CLayer;
AddLayer( layer );
layer->SetLayerName( "Default" );
layer->LoadTexture( "Textures\\Terrain\\Default.bmp" );
// Create default surface type.
CSurfaceType *sfType = new CSurfaceType;
sfType->SetName( "Default" );
sfType->SetDetailTexture( "Textures\\Terrain\\Detail\\Default.dds" );
AddSurfaceType( sfType );
layer->SetSurfaceType( sfType->GetName() );
// Make new mission.
GetCurrentMission();
GetIEditor()->GetGameEngine()->SetMissionName( GetCurrentMission()->GetName() );
}
SetModifiedFlag(FALSE);
m_bDocumentReady = true;
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CCryEditDoc serialization
void CCryEditDoc::Serialize(CArchive& ar)
{
unsigned char *pData = NULL, *pImageData = NULL;
CString currentMissionName;
CString szFilename = ar.GetFile()->GetFilePath();
m_level = Path::GetFileName( szFilename );
CXmlArchive xmlAr;
xmlAr.bLoading = ar.IsLoading() == TRUE;
if (ar.IsStoring())
{
Save( xmlAr );
CLogFile::WriteLine( "Writing binary data..." );
CString xml = xmlAr.root->getXML();
ar << xml;
xmlAr.pNamedData->Serialize( ar );
CLogFile::WriteString( "Done." );
//////////////////////////////////////////////////////////////////////////
AfterSave();
//////////////////////////////////////////////////////////////////////////
CLogFile::WriteLine("Level successfully saved");
}
else
{
m_bDocumentReady = false;
int t0 = GetTickCount();
#ifdef PROFILE_LOADING_WITH_VTUNE
VTResume();
#endif
// Check for 0 file length.
if (ar.GetFile()->GetLength() == 0)
{
AfxMessageBox( _T("ERROR: Bad Level cry file, size is 0 bytes" ) );
return;
}
CString str;
ar >> str;
xmlAr.pNamedData->Serialize( ar );
XmlParser parser;
xmlAr.root = parser.parseBuffer( str );
if (!xmlAr.root)
{
Warning( "Loading of %s failed\r\nError parsing Level XML, look at log file for more information",(const char*)szFilename );
m_loadFailed = true;
return;
}
Load( xmlAr,szFilename );
}
m_bDocumentReady = true;
}
//////////////////////////////////////////////////////////////////////////
void CCryEditDoc::Save( CXmlArchive& xmlAr )
{
CString currentMissionName;
//////////////////////////////////////////////////////////////////////////
// Create root xml node.
xmlAr.root = new CXmlNode("Level");
xmlAr.root->setAttr( "HeightmapWidth",m_cHeightmap.GetWidth() );
xmlAr.root->setAttr( "HeightmapHeight",m_cHeightmap.GetHeight() );
xmlAr.root->setAttr( "WaterColor",m_waterColor );
xmlAr.root->setAttr( "SandboxVersion",(const char*)GetIEditor()->GetFileVersion().ToFullString() );
SerializeViewSettings( xmlAr );
// Cloud parameters ////////////////////////////////////////////////////
//m_cClouds.Serialize(ar);
m_cClouds.Serialize( xmlAr );
// Heightmap ///////////////////////////////////////////////////////////
m_cHeightmap.Serialize( xmlAr,true );
//m_cHeightmap.Serialize(ar);
// Terrain texture /////////////////////////////////////////////////////
//SerializeLayerSettings(ar);
SerializeLayerSettings( xmlAr );
// Fog settings ///////////////////////////////////////////////////////
SerializeFogSettings( xmlAr );
// Surface Types ///////////////////////////////////////////////////////
SerializeSurfaceTypes( xmlAr );
// Serialize Missions //////////////////////////////////////////////////
SerializeMissions( xmlAr,currentMissionName );
// Terrain curve ///////////////////////////////////////////////////////
//m_cTerrainCurve.Serialize( xmlAr );
// Save objects.
//Timur[9/11/2002] GetIEditor()->GetObjectManager()->Serialize( xmlAr.root,xmlAr.bLoading,SERIALIZE_ONLY_SHARED );
// Save EquipPacks.
GetIEditor()->GetEquipPackLib()->Serialize(xmlAr.root, xmlAr.bLoading);
//! Serialize entity prototype manager.
GetIEditor()->GetEntityProtManager()->Serialize( xmlAr.root, xmlAr.bLoading );
//! Serialize prefabs manager.
GetIEditor()->GetPrefabManager()->Serialize( xmlAr.root, xmlAr.bLoading );
//! Serialize material manager.
GetIEditor()->GetMaterialManager()->Serialize( xmlAr.root, xmlAr.bLoading );
//! Serialize particles manager.
GetIEditor()->GetParticleManager()->Serialize( xmlAr.root, xmlAr.bLoading );
//! Serialize music manager.
GetIEditor()->GetMusicManager()->Serialize( xmlAr.root, xmlAr.bLoading );
CLightmapGen::Serialize(xmlAr);
//////////////////////////////////////////////////////////////////////////
AfterSave();
//////////////////////////////////////////////////////////////////////////
CLogFile::WriteLine("Level successfully saved");
m_bDocumentReady = true;
}
//////////////////////////////////////////////////////////////////////////
void CCryEditDoc::Load( CXmlArchive& xmlAr,const CString &szFilename,bool bReloadEngineLevel )
{
CLogFile::FormatLine("Loading from %s...", (const char*)szFilename );
CString currentMissionName;
CString szLevelPath = Path::GetPath(szFilename);
AutoSuspendTimeQuota AutoSuspender(GetIEditor()->GetSystem()->GetStreamEngine());
// Start recording errors.
CErrorsRecorder errorsRecorder;
m_bDocumentReady = false;
int t0 = GetTickCount();
#ifdef PROFILE_LOADING_WITH_VTUNE
VTResume();
#endif
GetIEditor()->GetSystem()->GetISoundSystem()->Mute(true);
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// Serialize Missions //////////////////////////////////////////////////
SerializeMissions( xmlAr,currentMissionName );
// If multiple missions, select specific mission to load.
if (GetMissionCount() > 1)
{
CMissionSelectDialog dlg;
if (dlg.DoModal() == IDOK)
{
currentMissionName = dlg.GetSelected();
}
}
if (bReloadEngineLevel)
{
//////////////////////////////////////////////////////////////////////////
// Load Level to The engine
// Must appear before loading any objects.
// Load level in engine.
GetIEditor()->GetGameEngine()->LoadLevel( szLevelPath,currentMissionName,true,true );
//////////////////////////////////////////////////////////////////////////
}
// Load water color.
xmlAr.root->getAttr( "WaterColor",m_waterColor );
//////////////////////////////////////////////////////////////////////////
// Load materials.
//////////////////////////////////////////////////////////////////////////
GetIEditor()->GetMaterialManager()->Serialize( xmlAr.root, xmlAr.bLoading );
//////////////////////////////////////////////////////////////////////////
// Load Particles.
//////////////////////////////////////////////////////////////////////////
GetIEditor()->GetParticleManager()->Serialize( xmlAr.root, xmlAr.bLoading );
//////////////////////////////////////////////////////////////////////////
// Load MusicManager.
//////////////////////////////////////////////////////////////////////////
GetIEditor()->GetMusicManager()->Serialize( xmlAr.root, xmlAr.bLoading );
//////////////////////////////////////////////////////////////////////////
// Load View Settings
//////////////////////////////////////////////////////////////////////////
SerializeViewSettings(xmlAr);
// Cloud parameters ////////////////////////////////////////////////////
//m_cClouds.Serialize(ar);
// Heightmap ///////////////////////////////////////////////////////////
//m_cHeightmap.Serialize(ar);
m_cHeightmap.Serialize(xmlAr,true);
// Terrain texture /////////////////////////////////////////////////////
//SerializeLayerSettings(ar);
SerializeLayerSettings(xmlAr);
//////////////////////////////////////////////////////////////////////////
// Fog settings ///////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
SerializeFogSettings(xmlAr);
// Surface Types ///////////////////////////////////////////////////////
CLogFile::WriteLine("Loading Surface Types...");
SerializeSurfaceTypes( xmlAr );
CLogFile::WriteString( "Done." );
// Load objects ////////////////////////////////////////////////////////
//GetIEditor()->GetObjectManager()->Serialize( xmlAr.root,xmlAr.bLoading,SERIALIZE_ONLY_SHARED );
// Load EquipPacks.
CLogFile::WriteLine( "Loading Equipment..." );
GetIEditor()->GetEquipPackLib()->Serialize(xmlAr.root, xmlAr.bLoading);
CLogFile::WriteString( "Done." );
//! Serialize entity prototype manager.
CLogFile::WriteLine( "Loading Entity Archetypes Database..." );
GetIEditor()->GetEntityProtManager()->Serialize( xmlAr.root, xmlAr.bLoading );
CLogFile::WriteString( "Done." );
//! Serialize prefabs manager.
CLogFile::WriteLine( "Loading Prefabs Database..." );
GetIEditor()->GetPrefabManager()->Serialize( xmlAr.root, xmlAr.bLoading );
CLogFile::WriteString( "Done." );
// Terrain curve ///////////////////////////////////////////////////////
//m_cTerrainCurve.Serialize(xmlAr);
#ifdef PROFILE_LOADING_WITH_VTUNE
VTPause();
#endif
CLogFile::FormatLine( "Activating Mission %s",(const char*)currentMissionName );
// Select current mission.
m_mission = FindMission(currentMissionName);
if (m_mission)
{
GetCurrentMission()->SyncContent( true,false );
} else {
GetCurrentMission();
}
CLogFile::FormatLine("Mission %s loaded",(const char*)currentMissionName );
// Notify listeners.
for (std::list<IDocListener*>::iterator it = m_listeners.begin(); it != m_listeners.end(); ++it)
(*it)->OnLoadDocument();
//QuantifyStopRecordingData();
//QuantifyDisableRecordingData();
GetIEditor()->GetSystem()->GetISoundSystem()->Mute(false);
CLightmapGen::Serialize(xmlAr);
LoadLightmaps();
#ifdef PROFILE_LOADING_WITH_VTUNE
VTPause();
#endif
int t1 = GetTickCount();
LogLoadTime( t1-t0 );
m_bDocumentReady = true;
}
// TODO: Move into LightmapGen.cpp
#include "I3DEngine.h"
#include "LMCompStructures.h"
#include "Objects\ObjectManager.h"
#include "Objects\BrushObject.h"
void CCryEditDoc::LoadLightmaps()
{
////////////////////////////////////////////////////////////////////////
// Restore lightmaps for all entities
////////////////////////////////////////////////////////////////////////
I3DEngine *pI3DEngine = GetIEditor()->GetSystem()->GetI3DEngine();
ILMSerializationManager *pISerializationManager = pI3DEngine->CreateLMSerializationManager();
std::vector<IEntityRender *> vGLMs;
std::vector<CBaseObject*> vObjects;
UINT i;
GetIEditor()->GetObjectManager()->GetObjects(vObjects);
for (i=0; i<vObjects.size(); i++)
{
if (vObjects[i]->GetType() != OBJTYPE_BRUSH)
continue;
CBrushObject *pBrshObj = (CBrushObject *) vObjects[i];
IEntityRender *pIEtyRender = pBrshObj->GetEngineNode();
if (pIEtyRender && (pIEtyRender->GetRndFlags() & ERF_USELIGHTMAPS))
vGLMs.push_back(pIEtyRender);
}
pISerializationManager->ApplyLightmapfile(pI3DEngine->GetLevelFilePath(LM_EXPORT_FILE_NAME), vGLMs);
pISerializationManager->Release();
pISerializationManager = NULL;
}
void CCryEditDoc::SerializeLayerSettings( CXmlArchive &xmlAr )
{
////////////////////////////////////////////////////////////////////////
// Load or restore the layer settings from an XML
////////////////////////////////////////////////////////////////////////
if (xmlAr.bLoading)
{
// Loading
CLogFile::WriteLine("Loading layer settings...");
CWaitProgress progress( _T("Loading Terrain Layers") );
// Clear old layers
ClearLayers();
// Load the layer count
XmlNodeRef layers = xmlAr.root->findChild( "Layers" );
if (!layers)
return;
// Read all layers
int numLayers = layers->getChildCount();
for (int i = 0; i < numLayers; i++)
{
progress.Step( 100*i/numLayers );
// Create a new layer
AddLayer( new CLayer );
CXmlArchive ar( xmlAr );
ar.root = layers->getChild(i);
// Fill the layer with the data
GetLayer(i)->Serialize( ar );
}
}
else
{
// Storing
CLogFile::WriteLine("Storing layer settings...");
// Save the layer count
XmlNodeRef layers = xmlAr.root->newChild( "Layers" );
// Write all layers
for (int i=0; i < GetLayerCount(); i++)
{
CXmlArchive ar( xmlAr );
ar.root = layers->newChild( "Layer" );;
GetLayer(i)->Serialize( ar );
}
}
}
//////////////////////////////////////////////////////////////////////////
void CCryEditDoc::AfterSave()
{
//////////////////////////////////////////////////////////////////////////
// When saving level also save editor settings.
//////////////////////////////////////////////////////////////////////////
// Save settings.
gSettings.Save();
GetIEditor()->GetDisplaySettings()->SaveRegistry();
((CMainFrame*)AfxGetMainWnd())->SaveConfig();
}
//////////////////////////////////////////////////////////////////////////
void CCryEditDoc::SerializeViewSettings( CXmlArchive &xmlAr )
{
////////////////////////////////////////////////////////////////////////
// Load or restore the viewer settings from an XML
////////////////////////////////////////////////////////////////////////
if (xmlAr.bLoading)
{
// Loading
CLogFile::WriteLine("Loading Fog settings...");
XmlNodeRef view = xmlAr.root->findChild( "View" );
if (!view)
return;
Vec3 vp,va;
view->getAttr( "ViewerPos",vp );
view->getAttr( "ViewerAngles",va );
GetIEditor()->SetViewerPos( vp );
GetIEditor()->SetViewerAngles( va );
// Load grid.
XmlNodeRef gridNode = xmlAr.root->findChild( "Grid" );
if (gridNode)
{
GetIEditor()->GetViewManager()->GetGrid()->Serialize( gridNode,xmlAr.bLoading );
}
}
else
{
// Storing
CLogFile::WriteLine("Storing Fog settings...");
XmlNodeRef view = xmlAr.root->newChild( "View" );
view->setAttr( "ViewerPos",GetIEditor()->GetViewerPos() );
view->setAttr( "ViewerAngles",GetIEditor()->GetViewerAngles() );
// Save grid.
XmlNodeRef gridNode = xmlAr.root->newChild( "Grid" );
GetIEditor()->GetViewManager()->GetGrid()->Serialize( gridNode,xmlAr.bLoading );
}
}
void CCryEditDoc::SerializeFogSettings( CXmlArchive &xmlAr )
{
////////////////////////////////////////////////////////////////////////
// Load or restore the layer settings from an XML
////////////////////////////////////////////////////////////////////////
if (xmlAr.bLoading)
{
// Loading
CLogFile::WriteLine("Loading Fog settings...");
XmlNodeRef fog = xmlAr.root->findChild( "Fog" );
if (!fog)
return;
/*
int mode = 0;
int rgbColor;
fog->getAttr( "Color",rgbColor );
fog->getAttr( "Mode",mode );
fog->getAttr( "Distance",m_sFogSettings.iFogDistance );
fog->getAttr( "Density",m_sFogSettings.iFogDensity );
fog->getAttr( "ViewDistance",m_sFogSettings.iViewDist );
m_sFogSettings.eFogMode = (FogMode)mode;
m_sFogSettings.rgbFogColor.rgbtRed = GetRValue(rgbColor);
m_sFogSettings.rgbFogColor.rgbtGreen = GetGValue(rgbColor);
m_sFogSettings.rgbFogColor.rgbtBlue = GetBValue(rgbColor);
*/
if (m_fogTemplate)
{
CXmlTemplate::GetValues( m_fogTemplate,fog );
}
}
else
{
// Storing
CLogFile::WriteLine("Storing Fog settings...");
XmlNodeRef fog = xmlAr.root->newChild( "Fog" );
/*
int rgbColor = RGB( m_sFogSettings.rgbFogColor.rgbtRed,m_sFogSettings.rgbFogColor.rgbtGreen,m_sFogSettings.rgbFogColor.rgbtBlue );
fog->setAttr( "Color",rgbColor );
fog->setAttr( "Mode",(int)m_sFogSettings.eFogMode );
fog->setAttr( "Distance",m_sFogSettings.iFogDistance );
fog->setAttr( "Density",m_sFogSettings.iFogDensity );
fog->setAttr( "ViewDistance",m_sFogSettings.iViewDist );
*/
if (m_fogTemplate)
{
CXmlTemplate::SetValues( m_fogTemplate,fog );
}
}
}
//////////////////////////////////////////////////////////////////////////
void CCryEditDoc::SerializeSurfaceTypes( CXmlArchive &xmlAr )
{
if (xmlAr.bLoading)
{
// Clear old layers
RemoveAllSurfaceTypes();
// Load the layer count
XmlNodeRef node = xmlAr.root->findChild( "SurfaceTypes" );
if (!node)
return;
// Read all node
for (int i=0; i < node->getChildCount(); i++)
{
CXmlArchive ar( xmlAr );
ar.root = node->getChild(i);
CSurfaceType *sf = new CSurfaceType;
sf->Serialize( ar );
AddSurfaceType( sf );
}
}
else
{
// Storing
CLogFile::WriteLine("Storing surface types...");
// Save the layer count
XmlNodeRef node = xmlAr.root->newChild( "SurfaceTypes" );
// Write all surface types.
for (int i = 0; i < m_surfaceTypes.size(); i++)
{
CXmlArchive ar( xmlAr );
ar.root = node->newChild( "SurfaceType" );
m_surfaceTypes[i]->Serialize( ar );
}
}
}
//////////////////////////////////////////////////////////////////////////
void CCryEditDoc::SerializeMissions( CXmlArchive &xmlAr,CString &currentMissionName )
{
if (xmlAr.bLoading)
{
// Loading
CLogFile::WriteLine("Loading missions...");
// Clear old layers
ClearMissions();
// Load shared objects and layers.
XmlNodeRef objectsNode = xmlAr.root->findChild( "Objects" );
XmlNodeRef objectLayersNode = xmlAr.root->findChild( "ObjectLayers" );
// Load the layer count
XmlNodeRef node = xmlAr.root->findChild( "Missions" );
if (!node)
return;
CString current;
node->getAttr( "Current",current );
currentMissionName = current;
// Read all node
for (int i=0; i < node->getChildCount(); i++)
{
CXmlArchive ar( xmlAr );
ar.root = node->getChild(i);
CMission *mission = new CMission( this );
mission->Serialize( ar );
//////////////////////////////////////////////////////////////////////////
//Timur[9/11/2002] For backward compatability with shared objects.
if (objectsNode)
mission->AddObjectsNode(objectsNode);
if (objectLayersNode)
mission->SetLayersNode(objectLayersNode);
//////////////////////////////////////////////////////////////////////////
AddMission( mission );
}
}
else
{
// Storing
CLogFile::WriteLine("Storing missions...");
// Save contents of current mission.
GetCurrentMission()->SyncContent( false,false );
XmlNodeRef node = xmlAr.root->newChild( "Missions" );
//! Store current mission name.
currentMissionName = GetCurrentMission()->GetName();
node->setAttr( "Current",currentMissionName );
// Write all surface types.
for (int i = 0; i < m_missions.size(); i++)
{
CXmlArchive ar( xmlAr );
ar.root = node->newChild( "Mission" );
m_missions[i]->Serialize( ar );
}
CLogFile::WriteString("Done");
}
}
/////////////////////////////////////////////////////////////////////////////
// CCryEditDoc diagnostics
#ifdef _DEBUG
void CCryEditDoc::AssertValid() const
{
CDocument::AssertValid();
}
void CCryEditDoc::Dump(CDumpContext& dc) const
{
CDocument::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CCryEditDoc commands
//////////////////////////////////////////////////////////////////////////
void CCryEditDoc::ClearLayers()
{
////////////////////////////////////////////////////////////////////////
// Clear all texture layers
////////////////////////////////////////////////////////////////////////
unsigned int i;
// Free the layer objects
for (i=0; i<GetLayerCount(); i++)
delete GetLayer(i);
// Clear the list
m_layers.clear();
}
//////////////////////////////////////////////////////////////////////////
void CCryEditDoc::RemoveLayer( int layer )
{
assert( layer >= 0 && layer < m_layers.size() );
delete m_layers[layer];
m_layers.erase( m_layers.begin() + layer );
}
//////////////////////////////////////////////////////////////////////////
CLayer* CCryEditDoc::FindLayer( const char *sLayerName ) const
{
for (int i = 0; i < GetLayerCount(); i++)
{
CLayer *layer = GetLayer(i);
if (strcmp(layer->GetLayerName(),sLayerName) == 0)
return layer;
}
return 0;
}
//////////////////////////////////////////////////////////////////////////
void CCryEditDoc::RemoveLayer( CLayer *layer )
{
if (layer)
{
delete layer;
m_layers.erase( std::remove(m_layers.begin(),m_layers.end(),layer),m_layers.end() );
}
}
//////////////////////////////////////////////////////////////////////////
void CCryEditDoc::SwapLayers( int layer1,int layer2 )
{
assert( layer1 >= 0 && layer1 < m_layers.size() );
assert( layer2 >= 0 && layer2 < m_layers.size() );
std::swap( m_layers[layer1],m_layers[layer2] );
}
//////////////////////////////////////////////////////////////////////////
void CCryEditDoc::InvalidateLayers()
{
////////////////////////////////////////////////////////////////////////
// Set the update needed flag for all layer
////////////////////////////////////////////////////////////////////////
unsigned int i;
// Free the layer objects
for (i=0; i< GetLayerCount(); i++)
GetLayer(i)->InvalidateMask();
}
BOOL CCryEditDoc::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
{
////////////////////////////////////////////////////////////////////////
// Handle plugin menus
////////////////////////////////////////////////////////////////////////
//DWORD dwPluginID, dwEvtID;
IUIEvent *pIEvt = NULL;
// If pHandlerInfo is NULL, then handle the message
if (pHandlerInfo == NULL)
{
if (nCode == CN_COMMAND)
{
////////////////////////////////////////////////////////////////////////
// Handle WM_COMMAND message
////////////////////////////////////////////////////////////////////////
/*
// Extract the plugin and event IDs
dwPluginID = GET_PLUGIN_ID_FROM_MENU_ID(nID);
dwEvtID = GET_UI_ELEMENT_ID_FROM_MENU_ID(nID);
// Ask the plugin manager for an event handler
pIEvt = GetIEditor()->GetPluginManager()->GetEventByIDAndPluginID(dwPluginID, (uint8)dwEvtID);
// Forward the event and return TRUE to indicate that
// the event has been processed
if (pIEvt)
{
pIEvt->OnClick(dwEvtID);
return TRUE;
}
*/
}
else if (nCode == CN_UPDATE_COMMAND_UI)
{
////////////////////////////////////////////////////////////////////////
// Update UI element state
////////////////////////////////////////////////////////////////////////
// TODO
}
}
return CDocument::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}
CString CCryEditDoc::GetMasterCDFolder()
{
////////////////////////////////////////////////////////////////////////
// Return the path of the Master CD folder (assumed to be the same as
// the editor's current directory)
////////////////////////////////////////////////////////////////////////
return m_strMasterCDFolder;
}
BOOL CCryEditDoc::CanCloseFrame(CFrameWnd* pFrame)
{
////////////////////////////////////////////////////////////////////////
// Ask the base clase to ask for saving, which also includes the save
// status of the plugins. Addionaly we query if all the plugins can exit
// now. A reason for a failure might be that one of the plugins isn
// currently processing data or has other unsaved information which
// are not serialized in the project file
////////////////////////////////////////////////////////////////////////
if (!CDocument::CanCloseFrame(pFrame))
return FALSE;
if (!GetIEditor()->GetPluginManager()->CanAllPluginsExitNow())
return FALSE;
return TRUE;
}
bool CCryEditDoc::OnExportTerrainAsGeometrie(const char *pszFileName, RECT rcExport)
{
////////////////////////////////////////////////////////////////////////
// Store the terrain in the OBJ format on the disk
////////////////////////////////////////////////////////////////////////
t_hmap *pHeigthmap = NULL;
unsigned int i, j;
COBJExporter cModel;
CVector3D vVertex[6];
CTexCoord2D cTexCoord[6];
float fScaling = m_cHeightmap.GetUnitSize();
int iWidth = m_cHeightmap.GetWidth();
CFace sNewFace;
char szBitmapPath[_MAX_PATH];
char szInfoPath[_MAX_PATH];
const int iSurfaceTexWidth = 4096;
DWORD *pSurface = NULL;
float fScale = (1.0f / m_cHeightmap.GetWidth()) * (float) iSurfaceTexWidth;
UINT iSrcX, iSrcY, iDestX, iDestY, iSrcWidth, iDestWidth,iDestHeight;
if ((int)rcExport.bottom - rcExport.top <= 0 && (int)rcExport.right - rcExport.left <= 0)
return false;
BeginWaitCursor();
// Get data from the heightmap
pHeigthmap = m_cHeightmap.GetData();
ASSERT(pHeigthmap);
// Adjust the rectangle to be valid
if (rcExport.right < 0)
rcExport.right = 0;
if (rcExport.left < 0)
rcExport.left = 0;
if (rcExport.top < 0)
rcExport.top = 0;
if (rcExport.bottom < 0)
rcExport.bottom = 0;
if (rcExport.right >= m_cHeightmap.GetWidth())
rcExport.right = m_cHeightmap.GetWidth() - 1;
if (rcExport.bottom >= m_cHeightmap.GetHeight())
rcExport.bottom = m_cHeightmap.GetHeight() - 1;
////////////////////////////////////////////////////////////////////////
// Create triangles, texture coordinates and indices
////////////////////////////////////////////////////////////////////////
for (j=rcExport.top; j<rcExport.bottom; j++)
for (i=rcExport.left; i<rcExport.right; i++)
{
int sx = i;
int sy = j;
int dx = i - rcExport.left;
int dy = j - rcExport.top;
// First triangle
vVertex[0].fY = dx * fScaling;
vVertex[0].fX = dy * fScaling;
vVertex[0].fZ = pHeigthmap[sx + sy * iWidth];
vVertex[2].fY = (dx + 1) * fScaling;
vVertex[2].fX = dy * fScaling;
vVertex[2].fZ = pHeigthmap[(sx + 1) + sy*iWidth];
vVertex[1].fY = dx * fScaling;
vVertex[1].fX = (dy + 1) * fScaling;
vVertex[1].fZ = pHeigthmap[sx + (sy + 1)*iWidth];
cTexCoord[0].fU = (float) (dx) / (float) (rcExport.right - rcExport.left);
cTexCoord[0].fV = -(float) (dy) / (float) (rcExport.bottom - rcExport.top);
cTexCoord[2].fU = (float) ((dx + 1)) / (float) (rcExport.right - rcExport.left);
cTexCoord[2].fV = -(float) (dy) / (float) (rcExport.bottom - rcExport.top);
cTexCoord[1].fU = (float) (dx) / (float) (rcExport.right - rcExport.left);
cTexCoord[1].fV = -(float) ((dy + 1)) / (float) (rcExport.bottom - rcExport.top);
// Second triangle
vVertex[3].fY = (dx + 1) * fScaling;
vVertex[3].fX = dy * fScaling;
vVertex[3].fZ = pHeigthmap[(sx + 1) + sy * iWidth];
vVertex[5].fY = (dx + 1) * fScaling;
vVertex[5].fX = (dy + 1) * fScaling;
vVertex[5].fZ = pHeigthmap[(sx + 1) + (sy + 1) * iWidth];
vVertex[4].fY = dx * fScaling;
vVertex[4].fX = (dy + 1) * fScaling;
vVertex[4].fZ = pHeigthmap[sx + (sy + 1) * iWidth];
cTexCoord[3].fU = (float) ((dx + 1)) / (float) (rcExport.right - rcExport.left);
cTexCoord[3].fV = -(float) (dy) / (float) (rcExport.bottom - rcExport.top);
cTexCoord[5].fU = (float) ((dx + 1)) / (float) (rcExport.right - rcExport.left);
cTexCoord[5].fV = -(float) ((dy + 1)) / (float) (rcExport.bottom - rcExport.top);
cTexCoord[4].fU = (float) (dx) / (float) (rcExport.right - rcExport.left);
cTexCoord[4].fV = -(float) ((dy + 1)) / (float) (rcExport.bottom - rcExport.top);
// Add the vertices to the model and store the indices in the face
memset(&sNewFace, 0, sizeof(CFace));
sNewFace.iVertexIndices[0] = cModel.GetVertexIdx(&vVertex[0]);
sNewFace.iVertexIndices[1] = cModel.GetVertexIdx(&vVertex[1]);
sNewFace.iVertexIndices[2] = cModel.GetVertexIdx(&vVertex[2]);
sNewFace.iTexCoordIndices[0] = cModel.GetTexCoordIdx(&cTexCoord[0]);
sNewFace.iTexCoordIndices[1] = cModel.GetTexCoordIdx(&cTexCoord[1]);
sNewFace.iTexCoordIndices[2] = cModel.GetTexCoordIdx(&cTexCoord[2]);
cModel.AddFace(sNewFace);
memset(&sNewFace, 0, sizeof(CFace));
sNewFace.iVertexIndices[0] = cModel.GetVertexIdx(&vVertex[3]);
sNewFace.iVertexIndices[1] = cModel.GetVertexIdx(&vVertex[4]);
sNewFace.iVertexIndices[2] = cModel.GetVertexIdx(&vVertex[5]);
sNewFace.iTexCoordIndices[0] = cModel.GetTexCoordIdx(&cTexCoord[3]);
sNewFace.iTexCoordIndices[1] = cModel.GetTexCoordIdx(&cTexCoord[4]);
sNewFace.iTexCoordIndices[2] = cModel.GetTexCoordIdx(&cTexCoord[5]);
cModel.AddFace(sNewFace);
}
////////////////////////////////////////////////////////////////////////
// Export .OBJ and .MTL files
////////////////////////////////////////////////////////////////////////
// Write the model into the file
if (!cModel.WriteOBJ(pszFileName))
{
CLogFile::WriteLine("Error while exporting part of the heightmap as OBJ model !");
AfxMessageBox("Crititcal error during exporting !");
return false;
}
////////////////////////////////////////////////////////////////////////
// Export Info
////////////////////////////////////////////////////////////////////////
{
strcpy(szInfoPath, pszFileName);
PathRemoveExtension(szInfoPath);
strcat(szInfoPath,".inf");
if (CFileUtil::OverwriteFile( szInfoPath ))
{
FILE *infoFile = fopen( szInfoPath,"wt" );
if (infoFile)
{
fprintf( infoFile,"x=%d,y=%d,width=%d,height=%d",rcExport.left,rcExport.top,rcExport.right-rcExport.left,rcExport.bottom-rcExport.top );
fclose( infoFile );
}
}
}
////////////////////////////////////////////////////////////////////////
// Generate the texture
////////////////////////////////////////////////////////////////////////
// Allocate memory and generate the surface
CImage terrainSurface;
terrainSurface.Allocate( iSurfaceTexWidth,iSurfaceTexWidth );
pSurface = (DWORD*)terrainSurface.GetData();
//cTexture.GenerateSurface(pSurface, iSurfaceTexWidth, iSurfaceTexWidth, GEN_USE_LIGHTING|GEN_STATOBJ_SHADOWS|GEN_SHOW_WATER, NULL );
CTerrainTexGen texGen;
texGen.GenerateSurfaceTexture( ETTG_LIGHTING|ETTG_STATOBJ_SHADOWS|ETTG_SHOW_WATER,terrainSurface );
//CImageUtil::SaveJPEG( "Terrain.jpg",iSurfaceTexWidth,iSurfaceTexWidth,pSurface );
// Scale the export rectangle to texture coordinates
rcExport.bottom *= fScale;
rcExport.left *= fScale;
rcExport.right *= fScale;
rcExport.top *= fScale;
CRect rc1 = rcExport;
rc1 &= CRect( 0,0,iSurfaceTexWidth,iSurfaceTexWidth );
rcExport = rc1;
iDestWidth = rcExport.right - rcExport.left;
iDestHeight = rcExport.bottom - rcExport.top;
iSrcWidth = iSurfaceTexWidth;
// Allocate memory for the needed portion of the surface
CImage exportImage;
exportImage.Allocate( iDestWidth,iDestHeight );
// Extract the needed portion of the surface
for (j=rcExport.top; j<rcExport.bottom; j++)
{
iSrcX = rcExport.left;
iSrcY = j;
iDestX = 0;
iDestY = j - rcExport.top;
memcpy( &exportImage.ValueAt(iDestX,iDestY), &pSurface[iSrcX + iSrcY * iSrcWidth], sizeof(DWORD)*iDestWidth );
}
////////////////////////////////////////////////////////////////////////
// Export the texture
////////////////////////////////////////////////////////////////////////
strcpy(szBitmapPath, pszFileName);
PathRemoveFileSpec(szBitmapPath);
PathAddBackslash(szBitmapPath);
strcat(szBitmapPath, "Terrain.bmp");
if (!CImageUtil::SaveImage( szBitmapPath, exportImage ))
return false;
EndWaitCursor();
return true;
}
void CCryEditDoc::CreateNewCurve()
{
m_cTerrainCurve.CreateCurve("Terrain", CRect(0, 0, 65536, 65536));
m_cTerrainCurve.m_bParabolic = true;
m_cTerrainCurve.m_bAveraging = true;
}
/*
bool CCryEditDoc::GetHeightmapData16(uint16 *pData, UINT iDestWidth,
bool bSmooth, bool bNoise)
{
////////////////////////////////////////////////////////////////////////
// Get the heightmap data interpolated & noised up to 2 byte
////////////////////////////////////////////////////////////////////////
unsigned int i, j;
long iXSrcFl, iXSrcCe, iYSrcFl, iYSrcCe;
float fXSrc, fYSrc;
float fHeight[4];
float fHeightWeight[4];
float fHeightBottom;
float fHeightTop;
DWORD *pHeightmapData = NULL;
UINT dwHeightmapWidth = m_cHeightmap.GetWidth();
int iYSrcCeSave, iXSrcCeSave;
uint16 *pDataStart = pData;
UINT iCurPos;
CNoise cNoise;
static bool bFirstQuery = true;
static CDynamicArray2D cHeightmap(256, 256);
//float fFrequency = 7.0f;
float fFrequency = 3.0f;
float fFrequencyStep = 2.0f;
float fYScale = 255;
float fFade = 0.46f;
float fLowestPoint = 512000.0f, fHighestPoint = -512000.0f;
float fValueRange;
// If this is the first run, we need a to generate noise array
if (bFirstQuery)
{
CLogFile::WriteLine("Calculating noise array...");
// Just once
bFirstQuery = false;
// Process layers
for (i=0; i<8; i++)
{
// Apply the fractal noise function to the array
cNoise.FracSynthPass(&cHeightmap, fFrequency, fYScale,
256, 256, TRUE);
// Modify noise generation parameters
fFrequency *= fFrequencyStep;
fYScale *= fFade;
}
// Find the value range
for (i=0; i<256; i++)
for (j=0; j<256; j++)
{
fLowestPoint = __min(fLowestPoint, cHeightmap.m_Array[i][j]);
fHighestPoint = __max(fHighestPoint, cHeightmap.m_Array[i][j]);
}
// Storing the value range in this way saves us a division and a multiplication
fValueRange = 1.0f / (fHighestPoint + (float) fabs(fLowestPoint)) * 2048.0f;
// Normalize the heightmap
for (i=0; i<256; i++)
for (j=0; j<256; j++)
{
cHeightmap.m_Array[i][j] += (float) (fLowestPoint);
cHeightmap.m_Array[i][j] *= fValueRange;
}
}
// Only log significant allocations. This also prevents us from cluttering the
// log file during the lightmap preview generation
if (iDestWidth >= 512)
CLogFile::FormatLine("Retrieving heightmap data (Width: %i)...", iDestWidth);
// Verify the pointer to the heightmap destination array
if (IsBadWritePtr(pData, sizeof(int16) * iDestWidth * iDestWidth))
{
ASSERT(FALSE);
return false;
}
// Get the data from the heightmap
pHeightmapData = new DWORD[m_cHeightmap.GetWidth() * m_cHeightmap.GetHeight()];
if (!pHeightmapData)
{
CLogFile::WriteLine("Memory allocation error while scaling the heightmap");
AfxMessageBox("Memory allocation error while scaling the heightmap !");
ASSERT(pHeightmapData);
return false;
}
VERIFY(m_bmpHeightmap.GetBitmapBits(m_cHeightmap.GetWidth() * m_cHeightmap.GetHeight() *
sizeof(DWORD), pHeightmapData));
// Loop trough each field of the new image and interpolate the value
// from the source heightmap
for (j=0; j<iDestWidth; j++)
{
// Calculate the average source array position
fYSrc = ((float) j / (float) iDestWidth) * dwHeightmapWidth;
assert(fYSrc >= 0.0f && fYSrc <= dwHeightmapWidth);
// Precalculate floor and ceiling values. Use fast asm integer floor and
// fast asm float / integer conversion
iYSrcFl = ifloor(fYSrc);
iYSrcCe = FloatToIntRet((float) ceil(fYSrc));
// Distribution between top and bottom height values
fHeightWeight[2] = (float) iYSrcCe - fYSrc;
fHeightWeight[3] = fYSrc - (float) iYSrcFl;
for (i=0; i<iDestWidth; i++)
{
// Calculate the average source array position
fXSrc = ((float) i / (float) iDestWidth) * dwHeightmapWidth;
assert(fXSrc >= 0.0f && fXSrc <= dwHeightmapWidth);
// Precalculate floor and ceiling values. Use fast asm integer floor and
// fast asm float / integer conversion
iXSrcFl = ifloor(fXSrc);
iXSrcCe = FloatToIntRet((float) ceil(fXSrc));
// Distribution between left and right height values
fHeightWeight[0] = (float) iXSrcCe - fXSrc;
fHeightWeight[1] = fXSrc - (float) iXSrcFl;
// Avoid error when floor() and ceil() return the same value
if (fHeightWeight[0] == 0.0f && fHeightWeight[1] == 0.0f)
{
fHeightWeight[0] = 0.5f;
fHeightWeight[1] = 0.5f;
}
// Calculate how much weight each height value has
// Avoid error when floor() and ceil() return the same value
if (fHeightWeight[2] == 0.0f && fHeightWeight[3] == 0.0f)
{
fHeightWeight[2] = 0.5f;
fHeightWeight[3] = 0.5f;
}
// Clamp the ceiling coordinates to a save range
if (iYSrcCe >= (int) dwHeightmapWidth)
iYSrcCeSave = dwHeightmapWidth - 1;
else
iYSrcCeSave = iYSrcCe;
if (iXSrcCe >= (int) dwHeightmapWidth)
iXSrcCeSave = dwHeightmapWidth - 1;
else
iXSrcCeSave = iXSrcCe;
// Get the four nearest height values
fHeight[0] = (float) (pHeightmapData[iXSrcFl + iYSrcFl * dwHeightmapWidth] & 0x000000FF) * 255;
fHeight[1] = (float) (pHeightmapData[iXSrcCeSave + iYSrcFl * dwHeightmapWidth] & 0x000000FF) * 255;
fHeight[2] = (float) (pHeightmapData[iXSrcFl + iYSrcCeSave * dwHeightmapWidth] & 0x000000FF) * 255;
fHeight[3] = (float) (pHeightmapData[iXSrcCeSave + iYSrcCeSave * dwHeightmapWidth] & 0x000000FF) * 255;
// Interpolate between the four nearest height values
// Get the height for the given X position trough interpolation between
// the left and the right height
fHeightBottom = (fHeight[0] * fHeightWeight[0] + fHeight[1] * fHeightWeight[1]);
fHeightTop = (fHeight[2] * fHeightWeight[0] + fHeight[3] * fHeightWeight[1]);
// Set the new value in the destination heightmap
*pData++ = (uint16) (fHeightBottom * fHeightWeight[2] + fHeightTop * fHeightWeight[3]);
}
}
// Smooth the heightmap data and add noise
iCurPos = 0;
for (j=1; j<iDestWidth - 1; j++)
{
// Precalculate for better speed
iCurPos = j * iDestWidth + 1;
for (i=1; i<iDestWidth - 1; i++)
{
// Next pixel
iCurPos++;
if (bSmooth)
{
// Smooth it out
pDataStart[iCurPos] = FloatToIntRet(
(pDataStart[iCurPos] + pDataStart[iCurPos + 1] +
pDataStart[iCurPos + iDestWidth] +
pDataStart[iCurPos + iDestWidth + 1] +
pDataStart[iCurPos - 1] +
pDataStart[iCurPos - iDestWidth] +
pDataStart[iCurPos - iDestWidth - 1] +
pDataStart[iCurPos - iDestWidth + 1] +
pDataStart[iCurPos + iDestWidth - 1])
* 0.11111111111f);
}
// Add the signed noise
if (bNoise)
{
pDataStart[iCurPos] = (uint16) __max(0.0f, pDataStart[iCurPos] +
cHeightmap.m_Array[i % 256][j % 256]);
}
}
}
// Free the heightmap data
delete [] pHeightmapData;
pHeightmapData = 0;
return true;
}
bool CCryEditDoc::GetHeightmapData(HEIGHTMAPVALUE *pData, UINT iDestWidth)
{
////////////////////////////////////////////////////////////////////////
// Get the data of the heightmap, resize it if neccessary. Heightmap
// has to be square and a power of two
//
// (TODO: Maybe this should be rewritten, can be done a hell lot faster)
////////////////////////////////////////////////////////////////////////
unsigned int i, j;
int iXSrcFl, iXSrcCe, iYSrcFl, iYSrcCe;
float fXSrc, fYSrc;
float fHeight[4];
float fHeightWeight[4];
float fHeightBottom;
float fHeightTop;
DWORD *pHeightmapData = NULL;
UINT dwHeightmapWidth = m_cHeightmap.GetWidth();
int iYSrcCeSave, iXSrcCeSave;
HEIGHTMAPVALUE *pDataStart = pData;
// Only log significat allocations. This also prevents us from cluttering the
// log file during the lightmap preview generation
if (iDestWidth >= 512)
CLogFile::FormatLine("Retrieving heightmap data (Width: %i)...", iDestWidth);
// Verify the pointer to the heightmap destination array
if (IsBadWritePtr(pData, sizeof(HEIGHTMAPVALUE) * iDestWidth * iDestWidth))
{
ASSERT(FALSE);
return false;
}
// Get the data from the heightmap
pHeightmapData = new DWORD[m_cHeightmap.GetWidth() * m_cHeightmap.GetHeight()];
if (!pHeightmapData)
{
CLogFile::WriteLine("Memory allocation error while scaling the heightmap");
AfxMessageBox("Memory allocation error while scaling the heightmap !");
ASSERT(pHeightmapData);
return false;
}
VERIFY(m_bmpHeightmap.GetBitmapBits(m_cHeightmap.GetWidth() * m_cHeightmap.GetHeight() *
sizeof(DWORD), pHeightmapData));
// Loop trough each field of the new image and interpolate the value
// from the source heightmap
for (j=0; j<iDestWidth; j++)
{
// Calculate the average source array position
fYSrc = ((float) j / (float) iDestWidth) * dwHeightmapWidth;
assert(fYSrc >= 0.0f && fYSrc <= dwHeightmapWidth);
// Precalculate floor and ceiling values. Use fast asm integer floor and
// fast asm float / integer conversion
iYSrcFl = ifloor(fYSrc);
iYSrcCe = FloatToIntRet((float) ceil(fYSrc));
// Distribution between top and bottom height values
fHeightWeight[2] = (float) iYSrcCe - fYSrc;
fHeightWeight[3] = fYSrc - (float) iYSrcFl;
for (i=0; i<iDestWidth; i++)
{
// Calculate the average source array position
fXSrc = ((float) i / (float) iDestWidth) * dwHeightmapWidth;
assert(fXSrc >= 0.0f && fXSrc <= dwHeightmapWidth);
// Precalculate floor and ceiling values. Use fast asm integer floor and
// fast asm float / integer conversion
iXSrcFl = ifloor(fXSrc);
iXSrcCe = FloatToIntRet((float) ceil(fXSrc));
// Distribution between left and right height values
fHeightWeight[0] = (float) iXSrcCe - fXSrc;
fHeightWeight[1] = fXSrc - (float) iXSrcFl;
// Avoid error when floor() and ceil() return the same value
if (fHeightWeight[0] == 0.0f && fHeightWeight[1] == 0.0f)
{
fHeightWeight[0] = 0.5f;
fHeightWeight[1] = 0.5f;
}
// Calculate how much weight each height value has
// Avoid error when floor() and ceil() return the same value
if (fHeightWeight[2] == 0.0f && fHeightWeight[3] == 0.0f)
{
fHeightWeight[2] = 0.5f;
fHeightWeight[3] = 0.5f;
}
// Clamp the ceiling coordinates to a save range
if (iYSrcCe >= (int) dwHeightmapWidth)
iYSrcCeSave = dwHeightmapWidth - 1;
else
iYSrcCeSave = iYSrcCe;
if (iXSrcCe >= (int) dwHeightmapWidth)
iXSrcCeSave = dwHeightmapWidth - 1;
else
iXSrcCeSave = iXSrcCe;
// Get the four nearest height values
fHeight[0] = (float) (pHeightmapData[iXSrcFl + iYSrcFl * dwHeightmapWidth] & 0x000000FF);
fHeight[1] = (float) (pHeightmapData[iXSrcCeSave + iYSrcFl * dwHeightmapWidth] & 0x000000FF);
fHeight[2] = (float) (pHeightmapData[iXSrcFl + iYSrcCeSave * dwHeightmapWidth] & 0x000000FF);
fHeight[3] = (float) (pHeightmapData[iXSrcCeSave + iYSrcCeSave * dwHeightmapWidth] & 0x000000FF);
// Interpolate between the four nearest height values
// Get the height for the given X position trough interpolation between
// the left and the right height
fHeightBottom = (fHeight[0] * fHeightWeight[0] + fHeight[1] * fHeightWeight[1]);
fHeightTop = (fHeight[2] * fHeightWeight[0] + fHeight[3] * fHeightWeight[1]);
// Set the new value in the destination heightmap
*pData++ = FloatToByte(fHeightBottom * fHeightWeight[2] + fHeightTop * fHeightWeight[3]);
}
}
// Free the heightmap data
delete [] pHeightmapData;
pHeightmapData = 0;
return true;
}
void CCryEditDoc::SetHeightmapData(HEIGHTMAPVALUE *pData)
{
////////////////////////////////////////////////////////////////////////
// Store heightmap data in the bitmap
////////////////////////////////////////////////////////////////////////
DWORD *pImageData = NULL;
DWORD *pImageDataStart = NULL;
DWORD *pImageDataEnd = NULL;
uint8 iColor;
CLogFile::WriteLine("Storing heightmap data in the document...");
// Allocate memory for the image
pImageData = new DWORD[m_cHeightmap.GetWidth() * m_cHeightmap.GetHeight()];
pImageDataStart = pImageData;
pImageDataEnd = &pImageData[m_cHeightmap.GetWidth() * m_cHeightmap.GetHeight()];
while (pImageData != pImageDataEnd)
{
// Get the color value from the source array
iColor = (uint8) (*pData++);
// Convert it into 0x00BBGGRR format and write the pixel
*pImageData++ = iColor | iColor << 8 | iColor << 16;
}
// Load the heightmap image into the bitmap
VERIFY(m_bmpHeightmap.SetBitmapBits(m_cHeightmap.GetWidth() * m_cHeightmap.GetHeight()
* sizeof(DWORD), pImageDataStart));
// Free the image memory
delete [] pImageDataStart;
pImageDataStart = 0;
}
*/
//////////////////////////////////////////////////////////////////////////
void CCryEditDoc::RemoveSurfaceType( int i )
{
SetModifiedFlag();
m_surfaceTypes.erase( m_surfaceTypes.begin()+i );
GetIEditor()->GetGameEngine()->PutSurfaceTypesToGame();
}
//////////////////////////////////////////////////////////////////////////
int CCryEditDoc::AddSurfaceType( CSurfaceType *srf )
{
SetModifiedFlag();
m_surfaceTypes.push_back(srf);
GetIEditor()->GetGameEngine()->PutSurfaceTypesToGame();
return m_surfaceTypes.size()-1;
}
//////////////////////////////////////////////////////////////////////////
void CCryEditDoc::RemoveAllSurfaceTypes()
{
SetModifiedFlag();
m_surfaceTypes.clear();
}
//////////////////////////////////////////////////////////////////////////
int CCryEditDoc::FindSurfaceType( const CString &name )
{
for (int i = 0; i < m_surfaceTypes.size(); i++)
{
if (stricmp(m_surfaceTypes[i]->GetName(),name) == 0)
return i;
}
return -1;
}
//////////////////////////////////////////////////////////////////////////
BOOL CCryEditDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
////////////////////////////////////////////////////////////////////////
// Write the full filename and path to the log
////////////////////////////////////////////////////////////////////////
m_loadFailed = false;
ICryPak *pIPak = GetIEditor()->GetSystem()->GetIPak();
if (pIPak->OpenPack( lpszPathName ))
{
CWaitCursor wait;
CString levelPath = Path::GetPath(lpszPathName);
CPakFile pakFile;
CXmlArchive xmlAr;
xmlAr.bLoading = true;
if (!xmlAr.LoadFromPak( levelPath,pakFile ))
return FALSE;
// After reading close this pak.
pIPak->ClosePack( lpszPathName );
DeleteContents();
SetModifiedFlag(); // dirty during de-serialize
Load( xmlAr,lpszPathName );
SetModifiedFlag(FALSE); // start off with unmodified
}
else
{
if (!CDocument::OnOpenDocument(lpszPathName))
return FALSE;
}
if (m_loadFailed)
return FALSE;
CLogFile::FormatLine("Successfully opened document %s", lpszPathName);
return TRUE;
}
//////////////////////////////////////////////////////////////////////////
BOOL CCryEditDoc::OnSaveDocument( LPCTSTR lpszPathName )
{
CLogFile::FormatLine("Saving to %s...", (const char*)lpszPathName );
SetCurrentDirectory( GetIEditor()->GetMasterCDFolder() );
CString prevPathName = GetPathName();
bool bFileChanged = prevPathName != CString(lpszPathName);
if (gSettings.bBackupOnSave)
CFileUtil::BackupFile( lpszPathName );
BOOL res = TRUE;
//BOOL res = CDocument::OnSaveDocument( lpszPathName );
// Save to Pak file.
CWaitCursor wait;
// Save level to XML archive.
CXmlArchive xmlAr;
Save( xmlAr );
if (!CFileUtil::OverwriteFile( lpszPathName ))
return FALSE;
CPakFile pakFile;
if (!pakFile.Open( lpszPathName,false ))
return FALSE;
// Save XML archive to pak file.
xmlAr.SaveToPak( Path::GetPath(lpszPathName),pakFile );
// Changes filename for this document.
SetPathName( lpszPathName );
if (bFileChanged)
{
// Save As.
SetPathName( lpszPathName );
GetIEditor()->GetGameEngine()->SetLevelPath( lpszPathName );
// Export to engine.
char szFilePath[_MAX_PATH];
char szRelativePath[_MAX_PATH];
strcpy( szFilePath,lpszPathName );
PathRemoveFileSpec( szFilePath );
CString masterLevelsFolder = CString(GetIEditor()->GetMasterCDFolder()) + "Levels\\";
if (PathRelativePathTo(szRelativePath, masterLevelsFolder,FILE_ATTRIBUTE_DIRECTORY, szFilePath, FILE_ATTRIBUTE_DIRECTORY))
{
CGameExporter exporter( GetIEditor()->GetSystem() );
exporter.Export( false,false );
char szPrevLevelPath[_MAX_PATH];
strcpy( szPrevLevelPath,prevPathName );
PathRemoveFileSpec( szPrevLevelPath );
PathAddBackslash( szPrevLevelPath );
PathAddBackslash( szFilePath );
// Copy cover texture.
//@TODO copy AI .bai files.
// Create terrain directory.
//CreateDirectory( CString(szFilePath)+"terrain",NULL );
//CopyFile( CString(szPrevLevelPath)+"LevelData.xml",CString(szFilePath)+"LevelData.xml",FALSE );
//CopyFile( CString(szPrevLevelPath)+"objects.idx",CString(szFilePath)+"objects.idx",FALSE );
//CopyFile( CString(szPrevLevelPath)+"objects.lst",CString(szFilePath)+"objects.lst",FALSE );
//CopyFile( CString(szPrevLevelPath)+"terrain\\land_map.h16",CString(szFilePath)+"terrain\\land_map.h16",FALSE );
CopyFile( CString(szPrevLevelPath)+"terrain\\cover.ctc",CString(szFilePath)+"terrain\\cover.ctc",FALSE );
CopyFile( CString(szPrevLevelPath)+"terrain\\cover_low.dds",CString(szFilePath)+"terrain\\cover_low.dds",FALSE );
CopyFile( CString(szPrevLevelPath)+"terrain\\map_preview.jpg",CString(szFilePath)+"terrain\\map_preview.jpg",FALSE );
}
else
{
AfxMessageBox( "Level mast be stored in MasterCD\\Levels\\LevelName folder" );
}
}
SetModifiedFlag(FALSE);
return res;
}
//////////////////////////////////////////////////////////////////////////
bool CCryEditDoc::SaveToFile( const CString &szFilename )
{
CFile cFile;
CString strOldPathName = GetIEditor()->GetDocument()->GetPathName();
CWaitCursor wait;
if (!CFileUtil::OverwriteFile( szFilename ))
return false;
CXmlArchive xmlAr;
GetIEditor()->GetDocument()->Save( xmlAr );
CPakFile pakFile;
if (!pakFile.Open( szFilename,false ))
return false;
DeleteFile( szFilename );
// Save XML archive to pak file.
xmlAr.SaveToPak( Path::GetPath(szFilename),pakFile );
return true;
}
//////////////////////////////////////////////////////////////////////////
bool CCryEditDoc::LoadFromFile( const CString &szFilename,bool bReloadEngineLevel )
{
ICryPak *pIPak = GetIEditor()->GetSystem()->GetIPak();
if (pIPak->OpenPack( szFilename ))
{
DeleteContents();
SetModifiedFlag(); // dirty during de-serialize
CWaitCursor wait;
CString levelPath = Path::GetPath(szFilename);
CPakFile pakFile;
CXmlArchive xmlAr;
xmlAr.bLoading = true;
if (!xmlAr.LoadFromPak( levelPath,pakFile ))
return FALSE;
// After reading close this pak.
pIPak->ClosePack( szFilename );
Load( xmlAr,szFilename,bReloadEngineLevel );
SetModifiedFlag(FALSE); // start off with unmodified
}
else
return false;
return true;
}
//////////////////////////////////////////////////////////////////////////
void CCryEditDoc::HoldToFile( const CString &szFilename )
{
CString filename = Path::Make( Path::GetPath(GetPathName()),szFilename );
SaveToFile( filename );
}
//////////////////////////////////////////////////////////////////////////
void CCryEditDoc::FetchFromFile( const CString &szFilename )
{
////////////////////////////////////////////////////////////////////////
// Get the latestf state back
////////////////////////////////////////////////////////////////////////
CString filename = Path::Make( Path::GetPath(GetPathName()),szFilename );
{
CFile cFile;
// Open the file for writing, create it if needed
if (!cFile.Open(filename, CFile::modeRead))
{
AfxMessageBox("You have to use 'Hold' before you can fetch !");
return;
}
}
// Does the document contain unsaved data ?
if (GetIEditor()->GetDocument()->IsModified())
{
if (AfxMessageBox("The document contains unsaved data, it will be lost if fetched\r\nReally fetch old state ?", MB_ICONQUESTION | MB_YESNO, NULL) != IDYES)
{
return;
}
}
GetIEditor()->FlushUndo();
// Load the state
LoadFromFile( filename,false );
// Update terrain in engine.
m_cHeightmap.UpdateEngineTerrain();
//GetIEditor()->UpdateViews( eUpdateHeightmap );
GetIEditor()->FlushUndo();
}
//////////////////////////////////////////////////////////////////////////
BOOL CCryEditDoc::DoSave(LPCTSTR lpszPathName, BOOL bReplace)
{
BOOL bResult = CDocument::DoSave(lpszPathName,bReplace);
// Presereve current directory at MasterCD.
SetCurrentDirectory( GetIEditor()->GetMasterCDFolder() );
return bResult;
}
/*
//////////////////////////////////////////////////////////////////////////
BOOL CCryEditDoc::DoSave(LPCTSTR lpszPathName, BOOL bReplace)
{
char currentDirectory[_MAX_PATH];
GetCurrentDirectory( sizeof(currentDirectory),currentDirectory );
CDocument::DoSave( lpszPathName,bReplace );
if (lpszPathName == NULL)
{
// Save As.
char szFilePath[_MAX_PATH];
char szRelativePath[_MAX_PATH];
strcpy( szFilePath,GetPathName() );
PathRemoveFileSpec( szFilePath );
CString masterLevelsFolder = CString(GetIEditor()->GetMasterCDFolder()) + "Levels\\";
if (PathRelativePathTo(szRelativePath, masterLevelsFolder,FILE_ATTRIBUTE_DIRECTORY, szFilePath, FILE_ATTRIBUTE_DIRECTORY))
{
CGameExporter gameExporter( GetIEditor()->GetSystem() );
gameExporter.Export(false,true);
}
else
{
AfxMessageBox( "Level mast be stored in MasterCD\\Levels\\LevelName folder" );
}
}
// Restore directory.
SetCurrentDirectory( currentDirectory );
return TRUE; // success
}
*/
//////////////////////////////////////////////////////////////////////////
CMission* CCryEditDoc::GetCurrentMission()
{
if (m_mission)
{
return m_mission;
}
if (!m_missions.empty())
{
// Choose first available mission.
SetCurrentMission( m_missions[0] );
return m_mission;
}
// Create initial mission.
m_mission = new CMission(this);
m_mission->SetName( "Mission0" );
AddMission( m_mission );
m_mission->SyncContent( true,false );
return m_mission;
}
//////////////////////////////////////////////////////////////////////////
void CCryEditDoc::SetCurrentMission( CMission *mission )
{
if (mission != m_mission)
{
//CObjectManager *objMan = GetIEditor()->GetObjectManager();
// This could take a loong time.
CWaitCursor wait;
if (m_mission)
m_mission->SyncContent( false,false );
m_mission = mission;
m_mission->SyncContent( true,false );
GetIEditor()->GetGameEngine()->LoadMission( m_mission->GetName() );
}
}
//////////////////////////////////////////////////////////////////////////
void CCryEditDoc::ClearMissions()
{
// Release missions.
for (int i = 0; i < m_missions.size(); i++)
{
delete m_missions[i];
}
m_missions.clear();
m_mission = 0;
}
//////////////////////////////////////////////////////////////////////////
CMission* CCryEditDoc::FindMission( const CString &name ) const
{
for (int i = 0; i < m_missions.size(); i++)
{
if (stricmp(name,m_missions[i]->GetName()) == 0)
return m_missions[i];
}
return 0;
}
//////////////////////////////////////////////////////////////////////////
void CCryEditDoc::AddMission( CMission *mission )
{
ASSERT( std::find( m_missions.begin(),m_missions.end(),mission ) == m_missions.end() );
m_missions.push_back( mission );
CMainFrame *wnd = (CMainFrame*)AfxGetMainWnd();
if (wnd)
wnd->OnMissionUpdate();
}
//////////////////////////////////////////////////////////////////////////
void CCryEditDoc::RemoveMission( CMission *mission )
{
// If Deleting current mission.
if (mission == m_mission)
{
m_mission = 0;
}
m_missions.erase( std::find( m_missions.begin(),m_missions.end(),mission ) );
CMainFrame *wnd = (CMainFrame*)AfxGetMainWnd();
if (wnd)
wnd->OnMissionUpdate();
}
//////////////////////////////////////////////////////////////////////////
LightingSettings* CCryEditDoc::GetLighting()
{
return GetCurrentMission()->GetLighting();
}
//////////////////////////////////////////////////////////////////////////
void CCryEditDoc::RegisterListener( IDocListener *listener )
{
if (std::find(m_listeners.begin(),m_listeners.end(),listener) == m_listeners.end())
m_listeners.push_back(listener);
}
//////////////////////////////////////////////////////////////////////////
void CCryEditDoc::UnregisterListener( IDocListener *listener )
{
m_listeners.remove(listener);
}
//////////////////////////////////////////////////////////////////////////
void CCryEditDoc::LogLoadTime( int time )
{
// Open log file.
char szExeFileName[_MAX_PATH];
GetModuleFileName( GetModuleHandle(NULL), szExeFileName, sizeof(szExeFileName));
CString exePath = Path::GetPath( szExeFileName );
CString filename = Path::Make( exePath,"LevelLoadTime.log" );
SetFileAttributes( filename,FILE_ATTRIBUTE_ARCHIVE );
FILE *file = fopen( filename,"at" );
if (file)
{
CString level = GetIEditor()->GetGameEngine()->GetLevelName();
CString version = GetIEditor()->GetFileVersion().ToString();
CString text;
time = time/1000;
text.Format( "\n[%s] Level %s loaded in %d seconds",(const char*)version,(const char*)level,time );
CLogFile::WriteLine( text );
fwrite( (const char*)text,text.GetLength(),1,file );
fclose(file);
}
}