This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/Tools/LevelEdit/LevelEditDoc.cpp

1071 lines
26 KiB
C++
Raw Permalink Normal View History

/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// LevelEditDoc.cpp : implementation of the CLevelEditDoc class
//
#include "stdafx.h"
#include "leveledit.h"
#include "leveleditdoc.h"
#include "utils.h"
#include "physcoltest.h"
#include "gridcull.h"
#include "aabtreecull.h"
#include "light.h"
#include "ffactory.h"
#include "leveleditview.h"
#include "filemgr.h"
#include "profilesection.h"
#include "editorphys.h"
#include "sceneeditor.h"
#include "nodemgr.h"
#include "node.h"
#include "cameramgr.h"
#include "regkeys.h"
#include "editorassetmgr.h"
#include "_assetmgr.h"
#include "rcfile.h"
#include "editorini.h"
#include "updateassetsdialog.h"
#include "filelocations.h"
#include "ww3d.h"
#include "editorsaveload.h"
#include "presetslibform.h"
#include "rawfile.h"
#include "progressui.h"
#include "verchk.h"
#include "overlappage.h"
#include "stringsmgr.h"
#include "dazzle.h"
#include "texture.h"
#include "conversationpage.h"
#include "conversationeditormgr.h"
#include "dx8renderer.h"
#include "presetmgr.h"
#include "combatchunkid.h"
#include "combat.h"
#include "backgroundmgr.h"
#include "weathermgr.h"
#include "gameobjmanager.h"
#include "scripts.h"
#include "soundenvironment.h"
#include "soldier.h"
#include "editorbuild.h"
#include "export.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// Constants
/////////////////////////////////////////////////////////////////////////////
const Vector3 DEF_BACK_COLOR (0.2F, 0.4F, 0.6F);
const Vector3 DEF_AMBIENT_COLOR (0.3F, 0.3F, 0.3F);
/////////////////////////////////////////////////////////////////////////////
// Static member initialization
/////////////////////////////////////////////////////////////////////////////
bool CLevelEditDoc::IsBatchExportMode = false;
/////////////////////////////////////////////////////////////////////////////
// CLevelEditDoc
IMPLEMENT_DYNCREATE(CLevelEditDoc, CDocument)
BEGIN_MESSAGE_MAP(CLevelEditDoc, CDocument)
//{{AFX_MSG_MAP(CLevelEditDoc)
ON_COMMAND(ID_FILE_SAVE, OnFileSave)
ON_COMMAND(ID_FILE_SAVE_AS, OnFileSaveAs)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CLevelEditDoc construction/destruction
////////////////////////////////////////////////////////////
//
// CLevelEditDoc
//
CLevelEditDoc::CLevelEditDoc (void)
: m_pScene (NULL),
m_bPerformanceSampling (false),
m_DisplayPathWeb (false),
m_DisplayFullPaths (false),
m_CoordSystem (COORD_WORLD),
m_AxisRestriction (RESTRICT_NONE),
m_ModeModifiers (0),
m_bSnapPointsActive (true),
m_bNeedRepartition (false),
m_DebugScriptsMode (false)
{
// Allocate new managers
m_pFileMgr = new FileMgrClass;
//
// Read the settings from the registry
//
m_DebugScriptsMode = (theApp.GetProfileInt (CONFIG_KEY, "ScriptDebugMode", 0) == 1);
return;
}
////////////////////////////////////////////////////////////
//
// ~CLevelEditDoc
//
CLevelEditDoc::~CLevelEditDoc (void)
{
// Used to ensure all dynamically allocated data is freed
CleanupResources ();
return ;
}
///////////////////////////////////////////////////////////////
//
// Set_Debug_Script_Mode
//
///////////////////////////////////////////////////////////////
void
CLevelEditDoc::Set_Debug_Script_Mode (bool onoff)
{
m_DebugScriptsMode = onoff;
theApp.WriteProfileInt (CONFIG_KEY, "ScriptDebugMode", m_DebugScriptsMode);
return ;
}
///////////////////////////////////////////////////////////////
//
// Initialize_VSS
//
bool
CLevelEditDoc::Initialize_VSS (void)
{
bool retval = false;
ASSERT (m_pFileMgr != NULL);
#ifdef PUBLIC_EDITOR_VER
m_pFileMgr->Initialize_VSS ("");
retval = true;
#else
// Get the default VSS database to open
CString database_path = theApp.GetProfileString (CONFIG_KEY,
VSSDB_VALUE,
DEF_VSS_DB);
// Look up the user's Source Safe logon name
TCHAR user_name[256] = { 0 };
bool blogon_success = false;
if (::GetEnvironmentVariable ("SSUSER", user_name, sizeof (user_name)) == 0) {
// Let the user know they need to setup this variable
::Message_Box (NULL,
IDS_NOVSSUSER_MSG,
IDS_NOVSS_TITLE,
MB_ICONERROR | MB_OK | MB_SETFOREGROUND | MB_TOPMOST);
} else {
// Attempt to log onto the database using the correct username
blogon_success = m_pFileMgr->Initialize_VSS (database_path, user_name);
}
// Were we successful in logging on with the username?
if (blogon_success == false) {
// Attempt to logon with read-only access
blogon_success = m_pFileMgr->Initialize_VSS (database_path);
if (!blogon_success) {
// If we were unsuccessful, let the user know
::Message_Box (NULL,
IDS_NOVSS_MSG,
IDS_NOVSS_TITLE,
MB_ICONERROR | MB_OK | MB_SETFOREGROUND | MB_TOPMOST);
}
// Ensure or is VSS interface read-only
m_pFileMgr->Set_Read_Only_VSS (true);
}
if (m_pFileMgr->Is_VSS_Read_Only ()) {
// Let the user know they are in read-only mode
::Message_Box (NULL,
IDS_VSS_READONLY_MSG,
IDS_NOVSS_TITLE,
MB_ICONEXCLAMATION | MB_OK | MB_SETFOREGROUND | MB_TOPMOST);
}
// If at some point we were successful, then cache the database
// path in the registry and return success
if (blogon_success) {
theApp.WriteProfileString (CONFIG_KEY, VSSDB_VALUE, database_path);
retval = true;
}
#endif //PUBLIC_EDITOR_VER
// Return the true/false result code
return retval;
}
///////////////////////////////////////////////////////////////
//
// Change_Base_Path
//
bool
CLevelEditDoc::Change_Base_Path (void)
{
// Assume failure
bool retval = false;
// Ask the user to pick a base path
CString base_path;
if (::Browse_For_Folder (base_path,
NULL,
NULL,
"Please select a location to keep your models. A subdir named Assets will be created automatically.")) {
// Concat the Assets subdir onto the path
if (base_path[::lstrlen (base_path)-1] != '\\') {
base_path += "\\";
}
base_path += "Assets";
// Let the file manager know what the new base path is
m_pFileMgr->Set_Base_Path (base_path);
retval = true;
}
// Return the true/false result code
return retval;
}
///////////////////////////////////////////////////////////////
//
// Update_Core_Files
//
///////////////////////////////////////////////////////////////
void
CLevelEditDoc::Update_Core_Files (void)
{
// Ensure that VSS is initialized
if (Initialize_VSS ()) {
// Do we already have a base path?
if (::lstrlen (m_pFileMgr->Get_Base_Path ()) == 0) {
// Ask the user for a base path
if (!Change_Base_Path ()) {
// Pick a path for the user
CString path = ::Get_Startup_Directory ().Left (3);
path += DEF_ASSET_PATH;
m_pFileMgr->Set_Base_Path (path);
}
}
//
// Add some search paths to the file factory
//
EditorFileFactoryClass::Add_Search_Path (m_pFileMgr->Make_Full_Path (SHATTER_DIR));
EditorFileFactoryClass::Add_Search_Path (m_pFileMgr->Make_Full_Path (WEATHER_DIR));
EditorFileFactoryClass::Add_Search_Path (m_pFileMgr->Make_Full_Path (SKY_DIR));
EditorFileFactoryClass::Add_Search_Path (m_pFileMgr->Make_Full_Path ("always\\sound\\weather"));
EditorFileFactoryClass::Add_Search_Path (m_pFileMgr->Make_Full_Path ("always\\effects"));
ProgressUIMgrClass::Set_Status_Text ("Updating core asset files...");
#ifdef PUBLIC_EDITOR_VER
Update_Assets_For_Mod_Tree ();
#else
//
// Make sure we have the latest versions of the core files
//
m_pFileMgr->Update_File (PRESETS_PATH);
if (::Is_Silent_Mode () == false) {
m_pFileMgr->Update_File (ALWAYS_INI_PATH);
m_pFileMgr->Update_File (SERIAL_INI_PATH);
m_pFileMgr->Update_File (UPDATE_INI_PATH);
m_pFileMgr->Get_Subproject (ALWAYS_INI_DIR);
m_pFileMgr->Update_File (HUMAN_SKEL_PATH);
m_pFileMgr->Update_File (SKY_DIR);
m_pFileMgr->Update_File (WEATHER_DIR);
m_pFileMgr->Update_File (SHATTER_DIR);
m_pFileMgr->Build_Global_Include_List ();
if (m_DebugScriptsMode == false) {
m_pFileMgr->Update_File (SCRIPTS_PATH);
}
//
// Ensure the asset tree is updated
//
Update_Asset_Tree ();
}
#endif //PUBLIC_EDITOR_VER
//
// Update the strings database
//
StringsMgrClass::Create_Database_If_Necessary ();
StringsMgrClass::Load_Translation_Database ();
}
return ;
}
///////////////////////////////////////////////////////////////
//
// Update_Assets_For_Mod_Tree
//
///////////////////////////////////////////////////////////////
void
CLevelEditDoc::Update_Assets_For_Mod_Tree (void)
{
//
// Get all INI files to the always\INI directory
//
CString full_ini_path = ::Get_File_Mgr ()->Make_Full_Path (ALWAYS_INI_DIR);
m_pFileMgr->Update_All_Files (full_ini_path, "*.ini");
//
// Make sure to get the human skeleton
//
m_pFileMgr->Update_File ("presets\\objects.ddb");
//
// Make sure to get the human skeleton
//
m_pFileMgr->Update_File (HUMAN_SKEL_PATH);
return ;
}
///////////////////////////////////////////////////////////////
//
// Update_Asset_Tree
//
///////////////////////////////////////////////////////////////
void
CLevelEditDoc::Update_Asset_Tree (void)
{
// Get a pointer to the INI file from the asset manager
CString path = ::Get_File_Mgr ()->Make_Full_Path (UPDATE_INI_PATH);
EditorINIClass *pini = _pThe3DAssetManager->Get_INI (path);
// Were we successful in getting a pointer to the INI file?
ASSERT (pini != NULL);
if (pini != NULL) {
// Determine what the last time we updated was and when the
// last time the database was modified
int update_id = theApp.GetProfileInt (CONFIG_KEY, LAST_UPDATE_VALUE, 0);
int curr_update_id = pini->Get_Int ("General", "ID");
// Do we need to update?
if (update_id < curr_update_id) {
// Get the comments from the file
TCHAR comments[512];
pini->Get_TextBlock ("Comments", comments, sizeof (comments));
for (LPSTR newline = ::strchr (comments, '|');
newline != NULL;
newline = ::strchr (newline, '|'))
{
newline[0] = '\r';
newline[1] = '\n';
}
//
// Build a list of directories that we need to update...
//
STRING_LIST directory_list;
bool update_all = false;
for (int index = update_id + 1; index <= curr_update_id; index ++) {
//
// Get the directory associated with this update-id
//
CString number_string;
number_string.Format ("%d", index);
StringClass filename;
pini->Get_String (filename, "Details", number_string);
//
// If we couldn't get the directory, then update all files
//
if (filename.Get_Length () > 0) {
directory_list.Add (::Get_File_Mgr ()->Make_Full_Path (filename));
} else {
update_all = true;
}
}
//
// Show a dialog to the user that will ask them
// if they want to update now.
//
//if (::Is_Silent_Mode () == false) {
UpdateAssetsDialogClass dialog (CString (comments), directory_list, update_all, NULL);
if (dialog.DoModal () == IDOK) {
// Remember that we've updated ourselves
theApp.WriteProfileInt (CONFIG_KEY, LAST_UPDATE_VALUE, curr_update_id);
}
//}
}
// Free the INI object
SAFE_DELETE (pini);
}
return ;
}
///////////////////////////////////////////////////////////////
//
// CleanupResources
//
void
CLevelEditDoc::CleanupResources (void)
{
//
// Release our hold on the scene
//
MEMBER_RELEASE (m_pScene);
SAFE_DELETE (m_pFileMgr);
return ;
}
////////////////////////////////////////////////////////////
//
// OnNewDocument
//
BOOL
CLevelEditDoc::OnNewDocument (void)
{
// Allow the base class to process this message
if (!CDocument::OnNewDocument())
return FALSE;
//
// Keep the view from refreshing
//
::Get_Main_View ()->Allow_Repaint (false);
//
// Instantiate a new scene
//
MEMBER_RELEASE (m_pScene);
m_pScene = new SceneEditorClass;
m_pScene->Set_Ambient_Light (DEF_AMBIENT_COLOR);
m_pScene->Update_Lighting ();
m_pScene->Enable_Collision_Detection (0, 0);
m_pScene->Set_Sun_Light_Orientation (0, DEG_TO_RADF (50));
m_pScene->Update_Lighting();
// Reset sound environment, background and weather systems.
CombatManager::Get_Sound_Environment()->Reset();
BackgroundMgrClass::Reset();
WeatherMgrClass::Reset();
//
// Reset the scene, camera, and file manager
//
m_pFileMgr->Initialize ();
::Get_Main_View ()->Reset_View ();
::Get_Scene_Editor ()->Re_Partition_Dynamic_Culling_System ();
SetModifiedFlag (false);
//
// Force free the assets...
//
WW3DAssetManager::Get_Instance ()->Free_Assets ();
TheDX8MeshRenderer.Invalidate ();
Preload_Human_Data ();
Preload_Tool_Assets ();
//
// Reset the overlap-sphere page
//
OverlapPageClass *form = ::Get_Overlap_Form ();
if (form != NULL) {
form->Reset_Tree ();
}
//
// Reset the conversation page
//
ConversationPageClass *conversation_form = ::Get_Conversation_Form ();
if (conversation_form != NULL) {
conversation_form->Reload_Data ();
}
// Allow a refresh
::Get_Main_View ()->Allow_Repaint (true);
::Refresh_Main_View ();
return true;
}
////////////////////////////////////////////////////////////
//
// Serialize
//
////////////////////////////////////////////////////////////
void
CLevelEditDoc::Serialize (CArchive& ar)
{
SetModifiedFlag (FALSE);
return ;
}
/////////////////////////////////////////////////////////////////////////////
// CLevelEditDoc diagnostics
#ifdef _DEBUG
void CLevelEditDoc::AssertValid() const
{
CDocument::AssertValid();
}
void CLevelEditDoc::Dump(CDumpContext& dc) const
{
CDocument::Dump(dc);
}
#endif //_DEBUG
///////////////////////////////////////////////////////////////
//
// Do_Version_Check
//
////////////////////////////////////////////////////////////
bool
CLevelEditDoc::Do_Version_Check (void)
{
bool retval = true;
#ifndef PUBLIC_EDITOR_VER
//
// Check the version of the level editor that is out on the network
// against the version we are running. We don't want people making modifications
// with and older version
//
if (Check_Editor_Version () == false) {
if (Message_Box (NULL, IDS_VERSION_ERROR_MSG, IDS_VERSION_ERROR_TITLE, MB_ICONEXCLAMATION | MB_OKCANCEL | MB_SETFOREGROUND | MB_SYSTEMMODAL) == IDCANCEL) {
//
// Just for kicks, exit the process pretty violently
//
ExitProcess (1);
retval = false;
}
m_pFileMgr->Set_Read_Only_VSS (true);
}
#endif //PUBLIC_EDITOR_VER
return retval;
}
///////////////////////////////////////////////////////////////
//
// Preload_Assets
//
////////////////////////////////////////////////////////////
void
CLevelEditDoc::Preload_Assets (void)
{
Preload_Human_Data ();
Preload_Tool_Assets ();
//
// Initialize the dazzle system
//
CString dazzle_ini_path = ::Get_File_Mgr ()->Make_Full_Path (DAZZLE_INI_PATH);
FileClass * dazzle_ini_file = _TheFileFactory->Get_File (dazzle_ini_path);
if (dazzle_ini_file) {
INIClass dazzle_ini (*dazzle_ini_file);
DazzleRenderObjClass::Init_From_INI (&dazzle_ini);
_TheFileFactory->Return_File (dazzle_ini_file);
}
return ;
}
///////////////////////////////////////////////////////////////
//
// Preload_Tool_Assets
//
////////////////////////////////////////////////////////////
void
CLevelEditDoc::Preload_Tool_Assets (void)
{
//
// Load the tool-art textures into the asset manager
//
_pThe3DAssetManager->Load_Resource_Texture ("METER.TGA");
_pThe3DAssetManager->Load_Resource_Texture ("TA_CEMENT.TGA");
_pThe3DAssetManager->Load_Resource_Texture ("TA_FRONT.TGA");
_pThe3DAssetManager->Load_Resource_Texture ("TA_DUMMY.TGA");
//
// Load the tool-art models into the asset manager
//
ResourceFileClass way_start (NULL, "WayStart.w3d");
ResourceFileClass way_mid (NULL, "WayMid.w3d");
ResourceFileClass way_end (NULL, "WayStop.w3d");
ResourceFileClass way_r (NULL, "Way_R.w3d");
ResourceFileClass way_g (NULL, "Way_G.w3d");
ResourceFileClass way_b (NULL, "Way_B.w3d");
ResourceFileClass point_light (NULL, "PointLight.w3d");
ResourceFileClass speaker1 (NULL, "Speaker.w3d");
ResourceFileClass speaker2 (NULL, "Speaker2.w3d");
ResourceFileClass body_box (NULL, "BODYBOX.W3D");
ResourceFileClass camera_model (NULL, "CAMERA.W3D");
ResourceFileClass grid_model (NULL, "GRID.W3D");
ResourceFileClass trans_box_model (NULL, "TRANSBOX.W3D");
ResourceFileClass dummy_model (NULL, "DUMMY.W3D");
ResourceFileClass cover_spot_model (NULL, "COVERSPOT.W3D");
ResourceFileClass building_model (NULL, "BUILDINGICON.W3D");
ResourceFileClass carmarker_model (NULL, "CARMARKER.W3D");
WW3DAssetManager::Get_Instance()->Load_3D_Assets (way_start);
WW3DAssetManager::Get_Instance()->Load_3D_Assets (way_mid);
WW3DAssetManager::Get_Instance()->Load_3D_Assets (way_end);
WW3DAssetManager::Get_Instance()->Load_3D_Assets (way_r);
WW3DAssetManager::Get_Instance()->Load_3D_Assets (way_g);
WW3DAssetManager::Get_Instance()->Load_3D_Assets (way_b);
WW3DAssetManager::Get_Instance()->Load_3D_Assets (point_light);
WW3DAssetManager::Get_Instance()->Load_3D_Assets (speaker1);
WW3DAssetManager::Get_Instance()->Load_3D_Assets (speaker2);
WW3DAssetManager::Get_Instance()->Load_3D_Assets (body_box);
WW3DAssetManager::Get_Instance()->Load_3D_Assets (camera_model);
WW3DAssetManager::Get_Instance()->Load_3D_Assets (grid_model);
WW3DAssetManager::Get_Instance()->Load_3D_Assets (trans_box_model);
WW3DAssetManager::Get_Instance()->Load_3D_Assets (dummy_model);
WW3DAssetManager::Get_Instance()->Load_3D_Assets (cover_spot_model);
WW3DAssetManager::Get_Instance()->Load_3D_Assets (building_model);
WW3DAssetManager::Get_Instance()->Load_3D_Assets (carmarker_model);
//
// Build a list of all the textures in the sky and weather directories
//
/*CString path1 = ::Get_File_Mgr()->Make_Full_Path (SKY_DIR);
CString path2 = ::Get_File_Mgr()->Make_Full_Path (WEATHER_DIR);
DynamicVectorClass<CString> file_list;
::Get_File_Mgr ()->Find_Files (path1, "*.tga", file_list, false);
::Get_File_Mgr ()->Find_Files (path2, "*.tga", file_list, false);
//
// Preload all of these textures
//
for (int index = 0; index < file_list.Count (); index ++) {
CString &filename = file_list[index];
TextureClass *texture = WW3DAssetManager::Get_Instance()->Get_Texture (filename);
REF_PTR_RELEASE (texture);
}*/
return ;
}
///////////////////////////////////////////////////////////////
//
// Preload_Human_Data
//
////////////////////////////////////////////////////////////
void
CLevelEditDoc::Preload_Human_Data (void)
{
//
// Make sure the human skeletons are loaded
//
_pThe3DAssetManager->Load_3D_Assets (HUMAN_SKEL_PATH);
//
// Force load the commando model
//
PresetClass *preset = PresetMgrClass::Find_Typed_Preset (CLASSID_GAME_OBJECT_DEF_SOLDIER, "Commando");
if (preset != NULL) {
preset->Load_All_Assets ();
SoldierGameObj *soldier = (SoldierGameObj *)preset->Get_Definition ()->Create ();
if (soldier != NULL) {
soldier->Set_Delete_Pending ();
}
}
return ;
}
///////////////////////////////////////////////////////////////
//
// Init_Scene
//
////////////////////////////////////////////////////////////
void
CLevelEditDoc::Init_Scene (void)
{
if (m_pScene == NULL) {
// Ensure we have the latest core files
Update_Core_Files ();
//
// Add the texture cache to the search path
//
EditorFileFactoryClass::Add_Search_Path (::Get_File_Mgr ()->Get_Texture_Cache_Path ());
//
// Load the global conversations
//
ConversationEditorMgrClass::Get_Latest_Version ();
ConversationEditorMgrClass::Load_Global_Database ();
//
// Make sure we are using the right version of the editor
//
Do_Version_Check ();
//
// Make sure certain *required* assets are loaded into memory...
//
Preload_Assets ();
//
// Instantiate a new scene
//
m_pScene = new SceneEditorClass;
m_pScene->Set_Ambient_Light (DEF_AMBIENT_COLOR);
m_pScene->Update_Lighting ();
m_pScene->Enable_Collision_Detection (0, 0);
}
return ;
}
///////////////////////////////////////////////////////////////
//
// Get_Coord_System_Transform
//
///////////////////////////////////////////////////////////////
Matrix3D
CLevelEditDoc::Get_Coord_System_Transform (NodeClass *node)
{
Matrix3D matrix (1);
// What coordinate system are we working in?
switch (m_CoordSystem) {
case CLevelEditDoc::COORD_WORLD:
matrix = Matrix3D (1);
break;
case CLevelEditDoc::COORD_OBJECT:
matrix = node->Get_Transform ();
break;
case CLevelEditDoc::COORD_VIEW:
matrix = ::Get_Camera_Mgr ()->Get_Camera()->Get_Transform ();
break;
}
// Return the matrix
return matrix;
}
///////////////////////////////////////////////////////////////
//
// OnOpenDocument
//
///////////////////////////////////////////////////////////////
BOOL
CLevelEditDoc::OnOpenDocument (LPCTSTR path)
{
::Get_Main_View ()->Allow_Repaint (false);
DWORD start_time = ::GetTickCount ();
//
// Start a new document
//
OnNewDocument ();
//
// Load the level
//
EditorSaveLoadClass::Load_Level (path);
SetModifiedFlag (false);
//
// Reload the conversation page
//
ConversationPageClass *conversation_form = ::Get_Conversation_Form ();
if (conversation_form != NULL) {
conversation_form->Reload_Data ();
}
//
// Load the level load time
//
CString load_time_message;
load_time_message.Format ("Level load took %d seconds\r\n", int((::GetTickCount () - start_time) / 1000));
::Output_Message (load_time_message);
::Get_Main_View ()->Allow_Repaint (true);
return TRUE;
}
///////////////////////////////////////////////////////////////
//
// Set_Current_Path
//
///////////////////////////////////////////////////////////////
void
CLevelEditDoc::Set_Current_Path (const char *path)
{
m_strPathName = path;
return ;
}
///////////////////////////////////////////////////////////////
//
// OnSaveDocument
//
///////////////////////////////////////////////////////////////
BOOL
CLevelEditDoc::OnSaveDocument (LPCTSTR path)
{
theApp.WriteProfileString (CONFIG_KEY,
LAST_SAVE_DIR_VALUE,
::Strip_Filename_From_Path (path));
// Peform the save operation
EditorSaveLoadClass::Save_Level (path);
return TRUE;
}
///////////////////////////////////////////////////////////////
//
// Repartition_If_Necessary
//
///////////////////////////////////////////////////////////////
void
CLevelEditDoc::Repartition_If_Necessary (void)
{
if (m_bNeedRepartition) {
// (gth) can't re-partition the object culling systems
// or we'll lose hierarchical vis...
m_pScene->Re_Partition_Static_Lights ();
m_pScene->Re_Partition_Audio_System ();
m_bNeedRepartition = false;
}
return ;
}
///////////////////////////////////////////////////////////////
//
// PreCloseFrame
//
///////////////////////////////////////////////////////////////
void
CLevelEditDoc::PreCloseFrame (CFrameWnd *pFrame)
{
//
// Cleanup any dangling embedded objects
//
PresetMgrClass::Free_All_Embedded_Nodes ();
NetworkObjectMgrClass::Delete_Pending ();
GameObjObserverManager::Delete_Pending ();
ScriptManager::Destroy_Pending ();
return ;
}
//////////////////////////////////////////////////////////////////////////
//
// OnFileSave
//
//////////////////////////////////////////////////////////////////////////
void
CLevelEditDoc::OnFileSave (void)
{
#ifdef PUBLIC_EDITOR_VER
if (m_strPathName.IsEmpty () || ::GetFileAttributes (m_strPathName) == 0xFFFFFFFF) {
//
// Pick a new path and save to it
//
CString full_path;
if (Pick_Save_Path (full_path)) {
Save_Level_File (full_path);
}
} else {
//
// Save to this path
//
Save_Level_File (m_strPathName);
}
#else
CDocument::OnFileSave ();
#endif //PUBLIC_EDITOR_VER
return ;
}
//////////////////////////////////////////////////////////////////////////
//
// OnFileSaveAs
//
//////////////////////////////////////////////////////////////////////////
void
CLevelEditDoc::OnFileSaveAs (void)
{
#ifdef PUBLIC_EDITOR_VER
//
// Pick a new path and save to it
//
CString full_path;
if (Pick_Save_Path (full_path)) {
Save_Level_File (full_path);
}
#else
CDocument::OnFileSaveAs ();
#endif //PUBLIC_EDITOR_VER
return ;
}
//////////////////////////////////////////////////////////////////////////
//
// Pick_Save_Path
//
//////////////////////////////////////////////////////////////////////////
bool
CLevelEditDoc::Pick_Save_Path (CString &save_path)
{
bool retval = false;
//
// Determine which directory we should save to
//
CString full_path = ::Get_File_Mgr ()->Make_Full_Path (LEVELS_ASSET_DIR);
_pThe3DAssetManager->Set_Current_Directory (full_path);
//
// Make a default filename from the name of the document
//
CString default_name = GetTitle ();
if (default_name.GetLength () > 0) {
//default_name += ".lvl";
}
CFileDialog dialog ( FALSE,
".lvl",
default_name,
OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_EXPLORER,
"Level Editor Files (*.lvl)|*.lvl||",
::AfxGetMainWnd ());
//
// Set the path, so it opens in the correct directory
//
dialog.m_ofn.lpstrInitialDir = full_path;
//
// Ask the user where they want to save this level
//
if (dialog.DoModal () == IDOK) {
//
// Return the path to the caller
//
retval = true;
save_path = dialog.GetPathName ();
}
return retval;
}
//////////////////////////////////////////////////////////////////////////
//
// Save_Level_File
//
//////////////////////////////////////////////////////////////////////////
void
CLevelEditDoc::Save_Level_File (const char *full_path)
{
//
// Reset the title and change the document name
//
SetPathName (full_path);
//
// Save in level editor format
//
OnSaveDocument (full_path);
//
// Save in game format
//
ExporterClass exporter;
exporter.Export_Level_Only (full_path);
return ;
}