mirror of
https://github.com/electronicarts/CnC_Renegade.git
synced 2026-02-04 07:53:58 -05:00
Initial commit of Command & Conquer Renegade source code.
This commit is contained in:
627
Code/Tools/LevelEdit/LevelEdit.cpp
Normal file
627
Code/Tools/LevelEdit/LevelEdit.cpp
Normal file
@@ -0,0 +1,627 @@
|
||||
/*
|
||||
** 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/>.
|
||||
*/
|
||||
|
||||
// LevelEdit.cpp : Defines the class behaviors for the application.
|
||||
//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "leveledit.h"
|
||||
|
||||
#include "mainfrm.h"
|
||||
#include "leveleditdoc.h"
|
||||
#include "leveleditview.h"
|
||||
#include "assetmgr.h"
|
||||
#include "ww3d.h"
|
||||
#include "wwdebug.h"
|
||||
#include "utils.h"
|
||||
#include "editorassetmgr.h"
|
||||
#include "_assetmgr.h"
|
||||
#include "wwphystrig.h"
|
||||
#include "regkeys.h"
|
||||
#include "_wwaudio.h"
|
||||
#include "win.h"
|
||||
#include "sceneeditor.h"
|
||||
#include "editorsaveload.h"
|
||||
#include "generatingvisdialog.h"
|
||||
#include "splash.h"
|
||||
#include "ffactory.h"
|
||||
#include "wwsaveload.h"
|
||||
#include "wwmath.h"
|
||||
#include "wwphys.h"
|
||||
#include "translatedb.h"
|
||||
#include "presetmgr.h"
|
||||
#include "phys.h"
|
||||
#include "utils.h"
|
||||
#include "colorutils.h"
|
||||
#include "assetpackagemgr.h"
|
||||
#include "editorbuild.h"
|
||||
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define new DEBUG_NEW
|
||||
#undef THIS_FILE
|
||||
static char THIS_FILE[] = __FILE__;
|
||||
#endif
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Local prototypes
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
void Register_Light_Icon (void);
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// CLevelEditApp
|
||||
|
||||
BEGIN_MESSAGE_MAP(CLevelEditApp, CWinApp)
|
||||
//{{AFX_MSG_MAP(CLevelEditApp)
|
||||
ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
|
||||
ON_COMMAND(ID_FILE_OPEN, OnFileOpen)
|
||||
//}}AFX_MSG_MAP
|
||||
// Standard file based document commands
|
||||
ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
|
||||
ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// CLevelEditApp construction
|
||||
|
||||
CLevelEditApp::CLevelEditApp()
|
||||
{
|
||||
// TODO: add construction code here,
|
||||
// Place all significant initialization in InitInstance
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// The one and only CLevelEditApp object
|
||||
|
||||
CLevelEditApp theApp;
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// fnMessage_Print_Func
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
void
|
||||
fnMessage_Print_Func (DebugType /*type*/, const char *message)
|
||||
{
|
||||
::OutputDebugString (message);
|
||||
::Output_Message (message);
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// fnAssert_Print_Func
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
void
|
||||
fnAssert_Print_Func (const char *message)
|
||||
{
|
||||
::Output_Message (message);
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// fnTrigger_Func
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
bool
|
||||
fnTrigger_Func (int trigger_num)
|
||||
{
|
||||
// Assume not triggered
|
||||
bool retval = false;
|
||||
|
||||
// Are we checking for inverted 'vis'?
|
||||
if (trigger_num == WWPHYS_TRIGGER_INVERT_VIS) {
|
||||
retval = bool(::GetKeyState (VK_F9) < 0);
|
||||
}
|
||||
|
||||
// Return the true/false result code
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
bool File_Exists (LPCSTR filename)
|
||||
{
|
||||
WIN32_FIND_DATA find_info;
|
||||
HANDLE file_handle = ::FindFirstFile (filename, &find_info);
|
||||
|
||||
if (file_handle != INVALID_HANDLE_VALUE) {
|
||||
::FindClose (file_handle);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// InitInstance
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
BOOL
|
||||
CLevelEditApp::InitInstance (void)
|
||||
{
|
||||
//
|
||||
// Get the installation directory of this application
|
||||
//
|
||||
TCHAR install_path[MAX_PATH] = { 0 };
|
||||
::GetModuleFileName (::AfxGetInstanceHandle (), install_path, sizeof (install_path));
|
||||
if (install_path[::lstrlen(install_path)-1] == '\\') {
|
||||
install_path[::lstrlen(install_path)-1] = 0;
|
||||
}
|
||||
|
||||
_pThe3DAssetManager = new EditorAssetMgrClass;
|
||||
|
||||
//
|
||||
// Let the user select which asset package they wish to work with
|
||||
//
|
||||
AssetPackageMgrClass::Initialize ();
|
||||
AssetPackageMgrClass::Show_Package_Selection_UI ();
|
||||
|
||||
//
|
||||
// Display the splash screen
|
||||
//
|
||||
SplashClass splash_screen;
|
||||
splash_screen.Show (true);
|
||||
|
||||
//
|
||||
// Initialize the libraries
|
||||
//
|
||||
WWMath::Init ();
|
||||
WWPhys::Init ();
|
||||
WWSaveLoad::Init ();
|
||||
TranslateDBClass::Initialize ();
|
||||
|
||||
// Standard initialization
|
||||
// If you are not using these features and wish to reduce the size
|
||||
// of your final executable, you should remove from the following
|
||||
// the specific initialization routines you do not need.
|
||||
|
||||
#ifdef _AFXDLL
|
||||
Enable3dControls(); // Call this when using MFC in a shared DLL
|
||||
#else
|
||||
Enable3dControlsStatic(); // Call this when linking to MFC statically
|
||||
#endif
|
||||
|
||||
RegisterColorPicker (::AfxGetInstanceHandle ());
|
||||
RegisterColorBar (::AfxGetInstanceHandle ());
|
||||
|
||||
// Change the registry key under which our settings are stored.
|
||||
// You should modify this string to be something appropriate
|
||||
// such as the name of your company or organization.
|
||||
SetRegistryKey(_T("Westwood Studios"));
|
||||
|
||||
//
|
||||
// Handle the command line
|
||||
//
|
||||
LPCTSTR cmd_line = ::strstr (m_lpCmdLine, "-j=");
|
||||
if (cmd_line != NULL) {
|
||||
cmd_line += 3;
|
||||
|
||||
Set_Silent_Mode (true);
|
||||
}
|
||||
|
||||
|
||||
LoadStdProfileSettings(9); // Load standard INI file options (including MRU)
|
||||
|
||||
::WWDebug_Install_Message_Handler (fnMessage_Print_Func);
|
||||
::WWDebug_Install_Assert_Handler (fnAssert_Print_Func);
|
||||
::WWDebug_Install_Trigger_Handler (fnTrigger_Func);
|
||||
|
||||
//
|
||||
// Disable the 3DFX logo
|
||||
//
|
||||
_putenv ("FX_GLIDE_NO_SPLASH=1");
|
||||
|
||||
// Register the application's document templates. Document templates
|
||||
// serve as the connection between documents, frame windows and views.
|
||||
|
||||
#ifdef PUBLIC_EDITOR_VER
|
||||
|
||||
CSingleDocTemplate* pDocTemplate;
|
||||
pDocTemplate = new CSingleDocTemplate(
|
||||
IDR_MAINFRAME2,
|
||||
RUNTIME_CLASS(CLevelEditDoc),
|
||||
RUNTIME_CLASS(CMainFrame), // main SDI frame window
|
||||
RUNTIME_CLASS(CLevelEditView));
|
||||
AddDocTemplate(pDocTemplate);
|
||||
|
||||
#else
|
||||
|
||||
CSingleDocTemplate* pDocTemplate;
|
||||
pDocTemplate = new CSingleDocTemplate(
|
||||
IDR_MAINFRAME,
|
||||
RUNTIME_CLASS(CLevelEditDoc),
|
||||
RUNTIME_CLASS(CMainFrame), // main SDI frame window
|
||||
RUNTIME_CLASS(CLevelEditView));
|
||||
AddDocTemplate(pDocTemplate);
|
||||
|
||||
#endif //PUBLIC_EDITOR_VER
|
||||
|
||||
// Enable DDE Execute open
|
||||
EnableShellOpen();
|
||||
RegisterShellFileTypes(TRUE);
|
||||
|
||||
// Parse command line for standard shell commands, DDE, file open
|
||||
CCommandLineInfo cmdInfo;
|
||||
ParseCommandLine(cmdInfo);
|
||||
|
||||
// Dispatch commands specified on the command line
|
||||
if (!ProcessShellCommand(cmdInfo))
|
||||
return FALSE;
|
||||
|
||||
// The one and only window has been initialized, so show and update it.
|
||||
m_pMainWnd->ShowWindow(SW_SHOW);
|
||||
m_pMainWnd->UpdateWindow();
|
||||
|
||||
// Enable drag/drop open
|
||||
m_pMainWnd->DragAcceptFiles();
|
||||
|
||||
ProgramInstance = m_hInstance;
|
||||
MainWindow = m_pMainWnd->m_hWnd;
|
||||
PresetMgrClass::Initialize ();
|
||||
|
||||
//
|
||||
// Update the installation key in the registry
|
||||
//
|
||||
const char *INSTALL_KEY = "Software\\Westwood Studios\\LevelEdit\\Install";
|
||||
const char *INSTALL_VALUE = "Exe";
|
||||
HKEY reg_key = NULL;
|
||||
if (::RegCreateKeyEx ( HKEY_CURRENT_USER,
|
||||
INSTALL_KEY,
|
||||
0L,
|
||||
NULL,
|
||||
0L,
|
||||
KEY_ALL_ACCESS,
|
||||
NULL,
|
||||
®_key,
|
||||
NULL) == ERROR_SUCCESS)
|
||||
{
|
||||
::RegSetValueEx ( reg_key,
|
||||
INSTALL_VALUE,
|
||||
0L,
|
||||
REG_SZ,
|
||||
(BYTE *)install_path,
|
||||
::lstrlen (install_path) + 1);
|
||||
::RegCloseKey (reg_key);
|
||||
}
|
||||
|
||||
//
|
||||
// Register an icon with the light file
|
||||
//
|
||||
Register_Light_Icon ();
|
||||
|
||||
//
|
||||
// Handle the command line
|
||||
//
|
||||
if (cmd_line != NULL) {
|
||||
::Perform_Job (cmd_line, true);
|
||||
Set_Modified (false);
|
||||
m_pMainWnd->PostMessage (WM_CLOSE);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// CAboutDlg dialog used for App About
|
||||
|
||||
class CAboutDlg : public CDialog
|
||||
{
|
||||
public:
|
||||
CAboutDlg();
|
||||
|
||||
// Dialog Data
|
||||
//{{AFX_DATA(CAboutDlg)
|
||||
enum { IDD = IDD_ABOUTBOX };
|
||||
//}}AFX_DATA
|
||||
|
||||
// ClassWizard generated virtual function overrides
|
||||
//{{AFX_VIRTUAL(CAboutDlg)
|
||||
public:
|
||||
protected:
|
||||
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
|
||||
//}}AFX_VIRTUAL
|
||||
|
||||
// Implementation
|
||||
protected:
|
||||
//{{AFX_MSG(CAboutDlg)
|
||||
// No message handlers
|
||||
//}}AFX_MSG
|
||||
DECLARE_MESSAGE_MAP()
|
||||
};
|
||||
|
||||
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
|
||||
{
|
||||
//{{AFX_DATA_INIT(CAboutDlg)
|
||||
//}}AFX_DATA_INIT
|
||||
}
|
||||
|
||||
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
|
||||
{
|
||||
CDialog::DoDataExchange(pDX);
|
||||
//{{AFX_DATA_MAP(CAboutDlg)
|
||||
//}}AFX_DATA_MAP
|
||||
}
|
||||
|
||||
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
|
||||
//{{AFX_MSG_MAP(CAboutDlg)
|
||||
// No message handlers
|
||||
//}}AFX_MSG_MAP
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
// App command to run the dialog
|
||||
void CLevelEditApp::OnAppAbout()
|
||||
{
|
||||
CAboutDlg aboutDlg;
|
||||
aboutDlg.DoModal();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// CLevelEditApp commands
|
||||
|
||||
/*
|
||||
**
|
||||
*/
|
||||
void Debug_Refs(void)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
TRACE("Detecting Active Refs...\r\n");
|
||||
//ODS("At time %s", cMiscUtil::Get_Text_Time());
|
||||
RefCountNodeClass * first = RefCountClass::ActiveRefList.First();
|
||||
RefCountNodeClass * node = first;
|
||||
while (node->Is_Valid())
|
||||
{
|
||||
RefCountClass * obj = node->Get();
|
||||
ActiveRefStruct * ref = &(obj->ActiveRefInfo);
|
||||
|
||||
bool display = true;
|
||||
int count = 0;
|
||||
RefCountNodeClass * search = first;
|
||||
while (search->Is_Valid()) {
|
||||
|
||||
if (search == node) { // if this is not the first one
|
||||
if (count != 0) {
|
||||
display = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RefCountClass * search_obj = search->Get();
|
||||
ActiveRefStruct * search_ref = &(search_obj->ActiveRefInfo);
|
||||
|
||||
if ( ref->File && search_ref->File &&
|
||||
!strcmp(search_ref->File, ref->File) &&
|
||||
(search_ref->Line == ref->Line) ) {
|
||||
count++;
|
||||
} else if ( (ref->File == NULL) && (search_ref->File == NULL) ) {
|
||||
count++;
|
||||
}
|
||||
|
||||
search = search->Next();
|
||||
}
|
||||
|
||||
if ( display ) {
|
||||
TRACE ( "%d Active Ref: %s %d %p\n", count, ref->File,ref->Line,obj);
|
||||
|
||||
static int num_printed = 0;
|
||||
if (++num_printed > 20) {
|
||||
TRACE( "And Many More......\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
node = node->Next();
|
||||
}
|
||||
TRACE("Done.\r\n");
|
||||
//ODS("At time %s", cMiscUtil::Get_Text_Time());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ExitInstance
|
||||
//
|
||||
int
|
||||
CLevelEditApp::ExitInstance (void)
|
||||
{
|
||||
// Remove the debug handlers we installed earlier
|
||||
::WWDebug_Install_Message_Handler (NULL);
|
||||
::WWDebug_Install_Assert_Handler (NULL);
|
||||
::WWDebug_Install_Trigger_Handler (NULL);
|
||||
|
||||
//
|
||||
// Free the audio manager
|
||||
//
|
||||
SAFE_DELETE (_pTheAudioManager);
|
||||
|
||||
//
|
||||
// Shutdown the libraries
|
||||
//
|
||||
WWMath::Shutdown ();
|
||||
WWPhys::Shutdown ();
|
||||
WWSaveLoad::Shutdown ();
|
||||
TranslateDBClass::Shutdown ();
|
||||
PresetMgrClass::Shutdown ();
|
||||
|
||||
//
|
||||
// Check for active refs
|
||||
//
|
||||
Debug_Refs ();
|
||||
|
||||
// Allow the base class to process this message
|
||||
return CWinApp::ExitInstance();
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// OnFileOpen
|
||||
//
|
||||
void
|
||||
CLevelEditApp::OnFileOpen (void)
|
||||
{
|
||||
CFileDialog dialog (TRUE,
|
||||
".lvl",
|
||||
NULL,
|
||||
OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_EXPLORER,
|
||||
"Level Files|*.lvl||",
|
||||
::AfxGetMainWnd ());
|
||||
|
||||
//
|
||||
// Setup the initial directory
|
||||
//
|
||||
CString full_path = theApp.GetProfileString (CONFIG_KEY, LAST_SAVE_DIR_VALUE);
|
||||
if (full_path.GetLength () != 0) {
|
||||
dialog.m_ofn.lpstrInitialDir = full_path;
|
||||
}
|
||||
|
||||
//
|
||||
// Let the user pick a file
|
||||
//
|
||||
if (dialog.DoModal () == IDOK) {
|
||||
OpenDocumentFile (dialog.GetPathName ());
|
||||
}
|
||||
|
||||
// Determine which directory we should use as a default for the open
|
||||
/*CString full_path = theApp.GetProfileString (CONFIG_KEY, LAST_SAVE_DIR_VALUE);
|
||||
if (full_path.GetLength () != 0) {
|
||||
::SetCurrentDirectory (full_path);
|
||||
::Get_Current_Document ()->Set_Current_Path (full_path);
|
||||
}
|
||||
|
||||
// Allow the base class to process this message
|
||||
CWinApp::OnFileOpen ();*/
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Register_Light_Icon
|
||||
//
|
||||
/////////////////////////////////////////////////////////////
|
||||
void
|
||||
Register_Light_Icon (void)
|
||||
{
|
||||
DWORD disp = 0;
|
||||
HKEY reg_key = NULL;
|
||||
|
||||
const char *LIGHT_ICON_APP_NAME = "W3D Light";
|
||||
const char *LIGHT_ICON_KEY = "W3D Light\\DefaultIcon";
|
||||
|
||||
//
|
||||
// Open the file extension association registry key
|
||||
//
|
||||
if (::RegCreateKeyEx ( HKEY_CLASSES_ROOT,
|
||||
".wlt",
|
||||
0,
|
||||
NULL,
|
||||
REG_OPTION_NON_VOLATILE,
|
||||
KEY_ALL_ACCESS,
|
||||
NULL,
|
||||
®_key,
|
||||
&disp) == ERROR_SUCCESS)
|
||||
{
|
||||
//
|
||||
// Write the name of the application under this extension's default value
|
||||
//
|
||||
::RegSetValueEx (reg_key, NULL, 0, REG_SZ, (const BYTE *)LIGHT_ICON_APP_NAME, ::lstrlen (LIGHT_ICON_APP_NAME) + 1);
|
||||
::RegCloseKey (reg_key);
|
||||
|
||||
//
|
||||
// Open the application key
|
||||
//
|
||||
if (::RegCreateKeyEx ( HKEY_CLASSES_ROOT,
|
||||
LIGHT_ICON_KEY,
|
||||
0,
|
||||
NULL,
|
||||
REG_OPTION_NON_VOLATILE,
|
||||
KEY_ALL_ACCESS,
|
||||
NULL,
|
||||
®_key,
|
||||
&disp) == ERROR_SUCCESS)
|
||||
{
|
||||
//
|
||||
// Build a string representing the path to the level editor and
|
||||
// the icon's index.
|
||||
//
|
||||
TCHAR path[MAX_PATH] = { 0 };
|
||||
::GetModuleFileName (NULL, path, MAX_PATH);
|
||||
|
||||
CString icon_path;
|
||||
icon_path.Format ("%s,-%d", path, IDI_LIGHT);
|
||||
|
||||
//
|
||||
// Write the icon's location under this key
|
||||
//
|
||||
::RegSetValueEx (reg_key, NULL, 0, REG_SZ, (const BYTE *)(LPCTSTR)icon_path, ::lstrlen (icon_path) + 1);
|
||||
::RegCloseKey (reg_key);
|
||||
}
|
||||
}
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PreTranslateMessage
|
||||
//
|
||||
// This is a hack to ensure that translator keys are
|
||||
// processed even if we are in one of the sidebar windows.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////
|
||||
BOOL
|
||||
CLevelEditApp::PreTranslateMessage (MSG *pMsg)
|
||||
{
|
||||
BOOL retval = false;
|
||||
|
||||
//
|
||||
// Is this window registered for global translation?
|
||||
//
|
||||
if (pMsg->hwnd != NULL && ::GetProp (pMsg->hwnd, "TRANS_ACCS") == (HANDLE)1) {
|
||||
|
||||
//
|
||||
// Translate the accelerator
|
||||
//
|
||||
CMainFrame *main_wnd = (CMainFrame *)::AfxGetMainWnd ();
|
||||
if (main_wnd != NULL) {
|
||||
HACCEL accel_table = main_wnd->GetDefaultAccelerator ();
|
||||
if (::TranslateAccelerator (main_wnd->m_hWnd, accel_table, pMsg)) {
|
||||
retval = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (retval == false) {
|
||||
retval = CWinApp::PreTranslateMessage (pMsg);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user