/* ** 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 . */ // 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; }