/* Copyright (c) 2002-2012 Croteam Ltd. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ // WorldEditor.cpp : Defines the class behaviors for the application. // #include "stdafx.h" #include "WorldEditor.h" #include "DlgTipOfTheDay.h" #include #include #include #include #include #ifdef _DEBUG #undef new #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif UINT _uiMessengerMsg=-1; UINT _uiMessengerForcePopup=-1; extern FLOAT _fFlyModeSpeedMultiplier = 1.0f; FLOAT _fLastMipBrushingOptionUsed = -10000.0f; extern INDEX wed_iMaxFPSActive = 500; extern FLOAT wed_fFrontClipDistance = 0.5f; extern struct GameGUI_interface *_pGameGUI = NULL; extern INDEX wed_bUseGenericTextureReplacement = FALSE; CTFileName fnmPersistentSymbols = CTString("Scripts\\PersistentSymbols.ini"); // Macros used for ini i/o operations #define INI_PRIMITIVE_READ( strname, default_val) \ strcpy( strIni, CStringA(theApp.GetProfileString( L"World editor prefs", CString(strPrimitiveType+" "+ strname ), CString( default_val )))) #define INI_PRIMITIVE_WRITE( strname) \ theApp.WriteProfileString( L"World editor prefs", CString(strPrimitiveType+" "+strname), CString(strIni)) #define INI_READ( strname, default_val) \ strcpy( strIni, CStringA(theApp.GetProfileString( L"World editor prefs", CString( strname ), CString(default_val)))) #define GET_FLAG( var) \ if( strcmp( strIni, "YES") == 0) var = TRUE; \ else var = FALSE; #define GET_COLOR( var) \ sscanf( strIni, "0X%08x", &var); #define GET_INDEX( var) \ sscanf( strIni, "%d", &var); #define GET_FLOAT( var) \ sscanf( strIni, "%f", &var); #define GET_STRING( var) \ var = CTString( strIni); #define SET_FLAG( var) \ if( var) strcpy( strIni, "YES"); \ else strcpy( strIni, "NO"); #define SET_COLOR( var) \ sprintf( strIni, "0x%08x", var); \ _strupr( strIni); #define SET_INDEX( var) \ sprintf( strIni, "%d", var); \ _strupr( strIni); #define SET_FLOAT( var) \ sprintf( strIni, "%f", var); \ _strupr( strIni); #define SET_STRING( var) \ sprintf( strIni, "%s", var); #define INI_WRITE( strname) \ theApp.WriteProfileString( L"World editor prefs", CString( strname ), CString(strIni)) void InitializeGame(void) { try { #ifndef NDEBUG #define GAMEDLL _fnmApplicationExe.FileDir()+"GameGUI"+_strModExt+"D.dll" #else #define GAMEDLL _fnmApplicationExe.FileDir()+"GameGUI"+_strModExt+".dll" #endif CTFileName fnmExpanded; ExpandFilePath(EFP_READ, CTString(GAMEDLL), fnmExpanded); HMODULE hGame = LoadLibraryA(fnmExpanded); if (hGame==NULL) { ThrowF_t("%s", GetWindowsError(GetLastError())); } GameGUI_interface* (*GAMEGUI_Create)(void) = (GameGUI_interface* (*)(void))GetProcAddress(hGame, "GAMEGUI_Create"); if (GAMEGUI_Create==NULL) { ThrowF_t("%s", GetWindowsError(GetLastError())); } _pGameGUI = GAMEGUI_Create(); } catch (char *strError) { FatalError("%s", strError); } _pGameGUI->Initialize(CTString("Data\\WorldEditor.gms")); } ///////////////////////////////////////////////////////////////////////////// // CWorldEditorApp BEGIN_MESSAGE_MAP(CWorldEditorApp, CWinApp) //{{AFX_MSG_MAP(CWorldEditorApp) ON_COMMAND(ID_APP_ABOUT, OnAppAbout) ON_COMMAND(ID_FILE_PREFERENCES, OnFilePreferences) ON_COMMAND(ID_FILE_OPEN, OnFileOpen) ON_COMMAND(ID_IMPORT_3D_OBJECT, OnImport3DObject) ON_COMMAND(ID_DECADIC_GRID, OnDecadicGrid) ON_UPDATE_COMMAND_UI(ID_DECADIC_GRID, OnUpdateDecadicGrid) ON_COMMAND(ID_CONVERT_WORLDS, OnConvertWorlds) ON_COMMAND(ID_SET_AS_DEFAULT, OnSetAsDefault) ON_COMMAND(ID_HELP_SHOWTIPOFTHEDAY, OnHelpShowTipOfTheDay) //}}AFX_MSG_MAP // Standard file based document commands ON_COMMAND(ID_FILE_NEW, OnFileNew) ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CWorldEditorApp construction void SetRenderingPrefs( CViewPrefs vp) { // store current shadows on/off state CWorldRenderPrefs::ShadowsType sht=_wrpWorldRenderPrefs.GetShadowsType(); _wrpWorldRenderPrefs = vp.m_wrpWorldRenderPrefs; _mrpModelRenderPrefs = vp.m_mrpModelRenderPrefs; _wrpWorldRenderPrefs.SetSelectedEntityModel( theApp.m_pEntityMarkerModelObject); _wrpWorldRenderPrefs.SetSelectedPortalModel( theApp.m_pPortalMarkerModelObject); _wrpWorldRenderPrefs.SetEmptyBrushModel( theApp.m_pEmptyBrushModelObject); // restore current shadows on/off state _wrpWorldRenderPrefs.SetShadowsType( sht); } void WED_ApplyChildSettings(INDEX iChildCfg) { CChildConfiguration &cc = theApp.m_ccChildConfigurations[ iChildCfg]; // find perspective view for( INDEX iView=0; iViewGetDocument(); } // otherwise else { return NULL; } } } CWorldEditorView* CWorldEditorApp::GetActiveView(void) { CWorldEditorView *res; CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd()); res = DYNAMIC_DOWNCAST(CWorldEditorView, pMainFrame->GetActiveFrame()->GetActiveView()); return res; } ///////////////////////////////////////////////////////////////////////////// // The one and only CWorldEditorApp object CWorldEditorApp theApp; ///////////////////////////////////////////////////////////////////////////// // CWorldEditorApp initialization BOOL CWorldEditorApp::InitInstance() { _CrtSetBreakAlloc(55); BOOL bResult; CTSTREAM_BEGIN { bResult = SubInitInstance(); } CTSTREAM_END; return bResult; } static CTString _strCmd; static CString _strCmdW; static CTString cmd_strOutput; static CTString cmd_strMod; // get first next word or quoted string static CTString GetNextParam(void) { // strip leading spaces/tabs _strCmd.TrimSpacesLeft(); // if nothing left if (_strCmd=="") { // no word to return return ""; } // if the first char is quote if (_strCmd[0]=='"') { // find first next quote const char *pchClosingQuote = strchr(_strCmd+1, '"'); // if not found if (pchClosingQuote==NULL) { // error in command line cmd_strOutput+=CTString(0, TRANS("Command line error!\n")); // finish parsing _strCmd = ""; return ""; } INDEX iQuote = pchClosingQuote-_strCmd; // get the quoted string CTString strWord; CTString strRest; _strCmd.Split(iQuote, strWord, strRest); // remove the quotes strWord.DeleteChar(0); strRest.DeleteChar(0); // get the word _strCmd = strRest; return strWord; // if the first char is not quote } else { // find first next space INDEX iSpace; INDEX ctChars = strlen(_strCmd); for(iSpace=0; iSpaceLoadFrame(IDR_MAINFRAME)) return FALSE; m_pMainWnd = pMainFrame; // set main window for engine SE_UpdateWindowHandle( m_pMainWnd->m_hWnd); // Enable drag/drop open m_pMainWnd->DragAcceptFiles(); // Enable DDE Execute open EnableShellOpen(); RegisterShellFileTypes(TRUE); // Parse command line for standard shell commands, DDE, file open CCommandLineInfo cmdInfo; ParseCommandLine(cmdInfo); // add console variables extern INDEX wed_bSaveTestGameFirstTime; _pShell->DeclareSymbol("user INDEX wed_bSaveTestGameFirstTime;", &wed_bSaveTestGameFirstTime); _pShell->DeclareSymbol("persistent user INDEX wed_iMaxFPSActive;", &wed_iMaxFPSActive); _pShell->DeclareSymbol("persistent user FLOAT wed_fFrontClipDistance;", &wed_fFrontClipDistance); _pShell->DeclareSymbol("persistent user INDEX wed_bUseGenericTextureReplacement;", &wed_bUseGenericTextureReplacement); // functions that are used to change rendering preferences while testing game _pShell->DeclareSymbol("user void WED_ApplyChildSettings0(void);", &WED_ApplyChildSettings0); _pShell->DeclareSymbol("user void WED_ApplyChildSettings1(void);", &WED_ApplyChildSettings1); _pShell->DeclareSymbol("user void WED_ApplyChildSettings2(void);", &WED_ApplyChildSettings2); _pShell->DeclareSymbol("user void WED_ApplyChildSettings3(void);", &WED_ApplyChildSettings3); _pShell->DeclareSymbol("user void WED_ApplyChildSettings4(void);", &WED_ApplyChildSettings4); _pShell->DeclareSymbol("user void WED_ApplyChildSettings5(void);", &WED_ApplyChildSettings5); _pShell->DeclareSymbol("user void WED_ApplyChildSettings6(void);", &WED_ApplyChildSettings6); _pShell->DeclareSymbol("user void WED_ApplyChildSettings7(void);", &WED_ApplyChildSettings7); _pShell->DeclareSymbol("user void WED_ApplyChildSettings8(void);", &WED_ApplyChildSettings8); _pShell->DeclareSymbol("user void WED_ApplyChildSettings9(void);", &WED_ApplyChildSettings9); _pShell->DeclareSymbol("user void WED_ApplyRenderingSettings0(void);", &WED_ApplyRenderingSettings0); _pShell->DeclareSymbol("user void WED_ApplyRenderingSettings1(void);", &WED_ApplyRenderingSettings1); _pShell->DeclareSymbol("user void WED_ApplyRenderingSettings2(void);", &WED_ApplyRenderingSettings2); _pShell->DeclareSymbol("user void WED_ApplyRenderingSettings3(void);", &WED_ApplyRenderingSettings3); _pShell->DeclareSymbol("user void WED_ApplyRenderingSettings4(void);", &WED_ApplyRenderingSettings4); _pShell->DeclareSymbol("user void WED_ApplyRenderingSettings5(void);", &WED_ApplyRenderingSettings5); _pShell->DeclareSymbol("user void WED_ApplyRenderingSettings6(void);", &WED_ApplyRenderingSettings6); _pShell->DeclareSymbol("user void WED_ApplyRenderingSettings7(void);", &WED_ApplyRenderingSettings7); _pShell->DeclareSymbol("user void WED_ApplyRenderingSettings8(void);", &WED_ApplyRenderingSettings8); _pShell->DeclareSymbol("user void WED_ApplyRenderingSettings9(void);", &WED_ApplyRenderingSettings9); _pShell->DeclareSymbol("user void WED_FindEmptyBrush(void);", &WED_FindEmptyBrushes); // load persistent symbols _pShell->Execute(CTString("include \""+fnmPersistentSymbols+"\";")); // prepare full screen mode _EngineGUI.GetFullScreenModeFromRegistry( "Display modes", m_dmFullScreen, m_gatFullScreen); _EngineGUI.SetFullScreenModeToRegistry( "Display modes", m_dmFullScreen, m_gatFullScreen); m_iApi=GAT_OGL; m_iApi=AfxGetApp()->GetProfileInt(L"Display modes", L"SED Gfx API", GAT_OGL); // (re)set default display mode _pGfx->ResetDisplayMode((enum GfxAPIType) m_iApi); // initialize game itself (GameShell interface) and load settings InitializeGame(); // load startup script _pShell->Execute( "include \"Scripts\\WorldEditor_startup.ini\""); // read all data from ini file ReadFromIniFileOnInit(); ReadDefaultPolygonValues(); // load primitives history buffer CTString strPrimitives("Data\\PrimitivesHistory.pri"); if (FileExists(strPrimitives)) { CTFileStream strmFile; try { strmFile.Open_t(strPrimitives); INDEX ctHistory; strmFile >> ctHistory; for( INDEX iPrim=0; iPrimpihb_vfpPrimitive.Read_t( strmFile); m_lhPrimitiveHistory.AddTail( ppihbMember->pihb_lnNode); } } catch( char *strError) { WarningMessage( strError); } } m_bDecadicGrid = !m_Preferences.ap_BinaryGrid; // don't start new document automatically cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing; // create temporary directory to contain undo files CreateDirectoryA( _fnmApplicationPath + "Temp\\", NULL); // try to try { // load error texture DECLARE_CTFILENAME( fnErrorTexture, "Textures\\Editor\\Error.tex"); m_ptdError = _pTextureStock->Obtain_t( fnErrorTexture); // load error texture DECLARE_CTFILENAME( fnViewIcons, "Models\\Editor\\ViewIcons.tex"); m_pViewIconsTD = _pTextureStock->Obtain_t( fnViewIcons); // load icon tray texture DECLARE_CTFILENAME( fnIconTrayTexture, "Textures\\Editor\\IconsTray.tex"); m_ptdIconsTray = _pTextureStock->Obtain_t( fnIconTrayTexture); } catch( char *err_str) { AfxMessageBox( CString(err_str)); return FALSE; } m_ptoError = new CTextureObject; m_ptoError->SetData( m_ptdError); // assign system font m_pfntSystem = _pfdDisplayFont; try { // load entity selection marker model DECLARE_CTFILENAME( fnEntityMarker, "Models\\Editor\\EntityMarker.mdl"); m_pEntityMarkerModelData = _pModelStock->Obtain_t( fnEntityMarker); m_pEntityMarkerModelObject = new CModelObject; m_pEntityMarkerModelObject->SetData(m_pEntityMarkerModelData); m_pEntityMarkerModelObject->SetAnim( 0); // load entity selection marker model's texture DECLARE_CTFILENAME( fnEntityMarkerTex, "Models\\Editor\\EntityMarker.tex"); m_ptdEntityMarkerTexture = _pTextureStock->Obtain_t( fnEntityMarkerTex); m_pEntityMarkerModelObject->mo_toTexture.SetData( m_ptdEntityMarkerTexture); // load portal selection marker model DECLARE_CTFILENAME( fnPortalMarker, "Models\\Editor\\PortalMarker.mdl"); m_pPortalMarkerModelData = _pModelStock->Obtain_t( fnPortalMarker); m_pPortalMarkerModelObject = new CModelObject; m_pPortalMarkerModelObject->SetData(m_pPortalMarkerModelData); m_pPortalMarkerModelObject->SetAnim( 0); // load portal selection marker model's texture DECLARE_CTFILENAME( fnPortalMarkerTex, "Models\\Editor\\PortalMarker.tex"); m_ptdPortalMarkerTexture = _pTextureStock->Obtain_t( fnPortalMarkerTex); m_pPortalMarkerModelObject->mo_toTexture.SetData( m_ptdPortalMarkerTexture); // load empty brush model DECLARE_CTFILENAME( fnEmptyBrush, "Models\\Editor\\EmptyBrush.mdl"); m_pEmptyBrushModelData = _pModelStock->Obtain_t( fnEmptyBrush); m_pEmptyBrushModelObject = new CModelObject; m_pEmptyBrushModelObject->SetData(m_pEmptyBrushModelData); m_pEmptyBrushModelObject->SetAnim( 0); // load empty brush model's texture DECLARE_CTFILENAME( fnEmptyBrushTex, "Models\\Editor\\EmptyBrush.tex"); m_ptdEmptyBrushTexture = _pTextureStock->Obtain_t( fnEmptyBrushTex); m_pEmptyBrushModelObject->mo_toTexture.SetData( m_ptdEmptyBrushTexture); // load range sphere DECLARE_CTFILENAME( fnRangeSphere, "Models\\Editor\\RangeSphere.mdl"); m_pRangeSphereModelData = _pModelStock->Obtain_t( fnRangeSphere); m_pRangeSphereModelObject = new CModelObject; m_pRangeSphereModelObject->SetData(m_pRangeSphereModelData); m_pRangeSphereModelObject->SetAnim( 0); // load range sphere model's texture DECLARE_CTFILENAME( fnRangeSphereTex, "Models\\Editor\\RangeSphere.tex"); m_ptdRangeSphereTexture = _pTextureStock->Obtain_t( fnRangeSphereTex); m_pRangeSphereModelObject->mo_toTexture.SetData( m_ptdRangeSphereTexture); // load angle 3d model DECLARE_CTFILENAME( fnAngle3D, "Models\\Editor\\AngleVector.mdl"); m_pAngle3DModelData = _pModelStock->Obtain_t( fnAngle3D); m_pAngle3DModelObject = new CModelObject; m_pAngle3DModelObject->SetData(m_pAngle3DModelData); m_pAngle3DModelObject->SetAnim( 0); // load angle 3d model's texture DECLARE_CTFILENAME( fnAngle3DTex, "Models\\Editor\\Vector.tex"); m_ptdAngle3DTexture = _pTextureStock->Obtain_t( fnAngle3DTex); m_pAngle3DModelObject->mo_toTexture.SetData( m_ptdAngle3DTexture); // load bounding box DECLARE_CTFILENAME( fnBoundingBox, "Models\\Editor\\BoundingBox.mdl"); m_pBoundingBoxModelData = _pModelStock->Obtain_t( fnBoundingBox); m_pBoundingBoxModelObject = new CModelObject; m_pBoundingBoxModelObject->SetData(m_pBoundingBoxModelData); m_pBoundingBoxModelObject->SetAnim( 0); // load bounding box model's texture DECLARE_CTFILENAME( fnBoundingBoxTex, "Models\\Editor\\BoundingBox.tex"); m_ptdBoundingBoxTexture = _pTextureStock->Obtain_t( fnBoundingBoxTex); m_pBoundingBoxModelObject->mo_toTexture.SetData( m_ptdBoundingBoxTexture); } catch (char *error) { FatalError("Cannot load one of entity selection model components: %s", error); return FALSE; } // initialize browsing window's view port CBrowseWindow *pBrowseWindow = &pMainFrame->m_Browser.m_BrowseWindow; _pGfx->CreateWindowCanvas( pMainFrame->m_Browser.m_BrowseWindow.m_hWnd, &pBrowseWindow->m_pViewPort, &pBrowseWindow->m_pDrawPort); pMainFrame->m_Browser.OpenSelectedDirectory(); // assure that terrain brushes exist GenerateNonExistingTerrainEditBrushes(); // Dispatch commands specified on the command line if (!ProcessShellCommand(cmdInfo)) return FALSE; // The main window has been initialized, so show and update it. pMainFrame->ShowWindow(SW_SHOWMAXIMIZED); pMainFrame->UpdateWindow(); // show tip of the day if (m_bShowTipOfTheDay) { OnHelpShowTipOfTheDay(); } // if we should automatically call preferences dialog (because WED is first time started) if( m_bFirstTimeStarted) OnFilePreferences(); CTString strCmdLine=CTString(CStringA(m_lpCmdLine)); if(strCmdLine[0]=='\"' && strCmdLine[strCmdLine.Length()-1]=='\"') { strCmdLine.DeleteChar(0); strCmdLine.DeleteChar(strCmdLine.Length()-1); } if (strCmdLine != "" && !strCmdLine.RemovePrefix("/dde")) { // Open a file passed as the first command line parameter. OpenDocumentFile(m_lpCmdLine); } 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) 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 CWorldEditorApp::OnAppAbout() { CAboutDlg aboutDlg; aboutDlg.DoModal(); } ///////////////////////////////////////////////////////////////////////////// // CWorldEditorApp commands BOOL CWorldEditorApp::SaveAllModified() { CMainFrame* pMainFrame = (CMainFrame *) m_pMainWnd; if( (pMainFrame != NULL) && (pMainFrame->m_Browser.m_bVirtualTreeChanged) ) { switch(::MessageBoxA( pMainFrame->m_hWnd, "Virtual tree changed but not saved. Do You want to save it?", "Warning !", MB_YESNOCANCEL | MB_ICONWARNING | MB_DEFBUTTON1 | MB_TASKMODAL | MB_TOPMOST) ) { case IDYES: { pMainFrame->m_Browser.SaveVirtualTree(pMainFrame->m_fnLastVirtualTree, &pMainFrame->m_Browser.m_VirtualTree); break; } case IDCANCEL: { return FALSE; } } } return CWinApp::SaveAllModified(); } void CWorldEditorApp::ReadFromIniFileOnInit(void) { char strIni[ 256]; // read data that can be saved multiple times to ini file ReadFromIniFile(); // obtain texture for primitive CString strTexture = GetProfileString( L"World editor prefs", L"Default primitive texture", L"Textures\\Editor\\Default.tex"); // if exists in ini file if( strTexture != L"") { theApp.SetNewActiveTexture( _fnmApplicationPath + CTString(CStringA(strTexture))); } INI_READ( "Paint power", "1.0"); GET_FLOAT( m_fPaintPower); INI_READ( "Smooth power", "1.0"); GET_FLOAT( m_fSmoothPower); INI_READ( "Current filter", "1"); GET_INDEX( m_iFilter); INI_READ( "Posterize step", "2.0"); GET_FLOAT( m_fPosterizeStep); INI_READ( "Terrain generation method", "0"); GET_INDEX( m_iTerrainGenerationMethod); INI_READ( "Subdivade and displace itterations", "2"); GET_INDEX( m_iRNDSubdivideAndDisplaceItterations); INI_READ( "Noise altitude", "1.0"); GET_FLOAT( m_fNoiseAltitude); INI_READ( "Distribution noise texture", CTFILENAME("Textures\\Editor\\RandomNoise.tex")); GET_STRING( m_fnDistributionNoiseTexture); INI_READ( "Continous noise texture", CTFILENAME("Textures\\Editor\\RandomNoise.tex")); GET_STRING( m_fnContinousNoiseTexture); INI_READ( "FBM Octaves", "4"); GET_INDEX( m_iFBMOctaves); INI_READ( "FBM High frequency step", "1.0"); GET_FLOAT( m_fFBMHighFrequencyStep); INI_READ( "FBM Step factor", "2.0"); GET_FLOAT( m_fFBMStepFactor); INI_READ( "FBM Max amplitude", "64.0"); GET_FLOAT( m_fFBMMaxAmplitude); INI_READ( "FBM Amplitude decreaser", "0.5"); GET_FLOAT( m_fFBMfAmplitudeDecreaser); INI_READ( "FBM Add negative values", "NO"); GET_FLAG( m_bFBMAddNegativeValues); INI_READ( "FBM Random offset", "NO"); GET_FLAG( m_bFBMRandomOffset); m_bShowTipOfTheDay = GetProfileInt(L"World editor", L"Show Tip of the Day", TRUE); m_iCurrentTipOfTheDay = GetProfileInt(L"World editor", L"Current Tip of the Day", 0); _fFlyModeSpeedMultiplier=m_Preferences.ap_fDefaultFlyModeSpeed; } void CWorldEditorApp::ReadFromIniFile() { // if loading of world and model's rendering preferences file fails if( !LoadRenderingPreferences()) { CViewPrefs tempVP; // for all view's rendering preferences for( INDEX i=0; i< VIEW_PREFERENCES_CT; i++) { // clear possibly wrong loaded values m_vpViewPrefs[ i] = tempVP; // set default values m_vpViewPrefs[ i].SetDefaultValues(); } // BUFFER 0: -default view // BUFFER 1: -no REM m_vpViewPrefs[ 1].m_wrpWorldRenderPrefs.SetEditorModelsOn( FALSE); m_vpViewPrefs[ 1].m_wrpWorldRenderPrefs.SetFieldBrushesOn( FALSE); m_vpViewPrefs[ 1].m_wrpWorldRenderPrefs.SetLensFlaresType( CWorldRenderPrefs::LFT_REFLECTIONS_AND_GLARE); // BUFFER 2: -polygon color, edges ink, no REM m_vpViewPrefs[ 2].m_wrpWorldRenderPrefs.SetPolygonsFillType( CWorldRenderPrefs::FT_POLYGONCOLOR); m_vpViewPrefs[ 2].m_wrpWorldRenderPrefs.SetEdgesFillType( CWorldRenderPrefs::FT_INKCOLOR); m_vpViewPrefs[ 2].m_wrpWorldRenderPrefs.SetEditorModelsOn( FALSE); m_vpViewPrefs[ 2].m_wrpWorldRenderPrefs.SetFieldBrushesOn( FALSE); m_vpViewPrefs[ 2].m_wrpWorldRenderPrefs.SetLensFlaresType( CWorldRenderPrefs::LFT_REFLECTIONS_AND_GLARE); // BUFFER 3: -wire frame (lines in color of polygons) m_vpViewPrefs[ 3].m_wrpWorldRenderPrefs.SetPolygonsFillType( CWorldRenderPrefs::FT_NONE); m_vpViewPrefs[ 3].m_wrpWorldRenderPrefs.SetEditorModelsOn( FALSE); m_vpViewPrefs[ 3].m_wrpWorldRenderPrefs.SetFieldBrushesOn( FALSE); m_vpViewPrefs[ 3].m_mrpModelRenderPrefs.BBoxAllShow( TRUE); // BUFFER 4: -polygons show sector color, no REM m_vpViewPrefs[ 4].m_wrpWorldRenderPrefs.SetEdgesFillType( CWorldRenderPrefs::FT_INKCOLOR); m_vpViewPrefs[ 4].m_wrpWorldRenderPrefs.SetPolygonsFillType( CWorldRenderPrefs::FT_SECTORCOLOR); m_vpViewPrefs[ 4].m_wrpWorldRenderPrefs.SetEditorModelsOn( FALSE); m_vpViewPrefs[ 4].m_wrpWorldRenderPrefs.SetFieldBrushesOn( FALSE); // BUFFER 5: -polygons in gray color, no REM m_vpViewPrefs[ 5].m_wrpWorldRenderPrefs.SetEdgesFillType( CWorldRenderPrefs::FT_NONE); m_vpViewPrefs[ 5].m_wrpWorldRenderPrefs.SetPolygonsFillType( CWorldRenderPrefs::FT_INKCOLOR); m_vpViewPrefs[ 5].m_wrpWorldRenderPrefs.SetEditorModelsOn( FALSE); m_vpViewPrefs[ 5].m_wrpWorldRenderPrefs.SetFieldBrushesOn( FALSE); m_vpViewPrefs[ 5].m_wrpWorldRenderPrefs.SetPolygonsInkColor( C_GRAY); // BUFFER 6: -polygons color, no REM m_vpViewPrefs[ 6].m_wrpWorldRenderPrefs.SetPolygonsFillType( CWorldRenderPrefs::FT_POLYGONCOLOR); m_vpViewPrefs[ 6].m_wrpWorldRenderPrefs.SetEdgesFillType( CWorldRenderPrefs::FT_NONE); m_vpViewPrefs[ 6].m_wrpWorldRenderPrefs.SetEditorModelsOn( FALSE); m_vpViewPrefs[ 6].m_wrpWorldRenderPrefs.SetFieldBrushesOn( FALSE); // BUFFER 7: -polygons in white color m_vpViewPrefs[ 7].m_wrpWorldRenderPrefs.SetPolygonsFillType( CWorldRenderPrefs::FT_INKCOLOR); m_vpViewPrefs[ 7].m_wrpWorldRenderPrefs.SetEdgesFillType( CWorldRenderPrefs::FT_INKCOLOR); m_vpViewPrefs[ 7].m_wrpWorldRenderPrefs.SetPolygonsInkColor( C_WHITE); // BUFFER 8: -polygons use texture, edges ink m_vpViewPrefs[ 8].m_wrpWorldRenderPrefs.SetPolygonsFillType( CWorldRenderPrefs::FT_TEXTURE); m_vpViewPrefs[ 8].m_wrpWorldRenderPrefs.SetEdgesFillType( CWorldRenderPrefs::FT_INKCOLOR); // BUFFER 9: -game view with background texture m_vpViewPrefs[ VIEW_PREFERENCES_CT-1].m_wrpWorldRenderPrefs.SetPolygonsFillType( CWorldRenderPrefs::FT_TEXTURE); m_vpViewPrefs[ VIEW_PREFERENCES_CT-1].m_wrpWorldRenderPrefs.SetEdgesFillType( CWorldRenderPrefs::FT_NONE); m_vpViewPrefs[ VIEW_PREFERENCES_CT-1].m_wrpWorldRenderPrefs.SetEditorModelsOn( FALSE); m_vpViewPrefs[ VIEW_PREFERENCES_CT-1].m_wrpWorldRenderPrefs.SetFieldBrushesOn( FALSE); m_vpViewPrefs[ VIEW_PREFERENCES_CT-1].m_wrpWorldRenderPrefs.SetLensFlaresType( CWorldRenderPrefs::LFT_REFLECTIONS_AND_GLARE); m_vpViewPrefs[ VIEW_PREFERENCES_CT-1].m_wrpWorldRenderPrefs.SetBackgroundTextureOn( TRUE); m_vpViewPrefs[ VIEW_PREFERENCES_CT-1].m_wrpWorldRenderPrefs.SetFogOn( TRUE); m_vpViewPrefs[ VIEW_PREFERENCES_CT-1].m_wrpWorldRenderPrefs.SetHazeOn( TRUE); m_vpViewPrefs[ VIEW_PREFERENCES_CT-1].m_wrpWorldRenderPrefs.SetMirrorsOn( TRUE); } // if loading of child configuration file fails if( !LoadChildConfigurations()) { // for all child configurations for( INDEX i=0; i> iPrimitiveType; vfp_ptPrimitiveType = (enum PrimitiveType) iPrimitiveType; INDEX ctBaseVtx; strmFile >> ctBaseVtx; vfp_avVerticesOnBaseOfPrimitive.Clear(); vfp_avVerticesOnBaseOfPrimitive.New( ctBaseVtx); for( INDEX iBaseVtx=0; iBaseVtx> vfp_avVerticesOnBaseOfPrimitive[iBaseVtx]; } strmFile >> vfp_plPrimitive; INDEX iTriangularisationType; strmFile >> iTriangularisationType; vfp_ttTriangularisationType = (enum TriangularisationType) iTriangularisationType; strmFile >> vfp_bClosed; strmFile >> vfp_bDummy; INDEX iCSGOperation; strmFile >> iCSGOperation; vfp_csgtCSGOperation = (enum CSGType) iCSGOperation; strmFile >> vfp_bAutoCreateMipBrushes; strmFile >> vfp_colSectorsColor; strmFile >> vfp_colPolygonsColor; strmFile >> vfp_fXMin; strmFile >> vfp_fXMax; strmFile >> vfp_fYMin; strmFile >> vfp_fYMax; strmFile >> vfp_fZMin; strmFile >> vfp_fZMax; strmFile >> vfp_fShearX; strmFile >> vfp_fShearZ; strmFile >> vfp_fStretchX; strmFile >> vfp_fStretchY; strmFile >> vfp_bLinearStaircases; strmFile >> vfp_bOuter; strmFile >> vfp_iSlicesIn360; strmFile >> vfp_iNoOfSlices; strmFile >> vfp_fRadius; strmFile >> vfp_iMeridians; strmFile >> vfp_iParalels; strmFile >> vfp_iSlicesPerWidth; strmFile >> vfp_iSlicesPerHeight; strmFile >> vfp_iTopShape; strmFile >> vfp_iBottomShape; strmFile >> vfp_fAmplitude; strmFile >> vfp_fnDisplacement; if( cidVersion == CChunkID(VALUES_FOR_PRIMITIVE_VERSION3)) { strmFile >> vfp_fMipStart; strmFile >> vfp_fMipStep; } } void CWorldEditorApp::WriteToIniFileOnEnd(void) { char strIni[ 256]; // write data that can be saved multiple times to ini file WriteToIniFile(); if( theApp.m_ptdActiveTexture != NULL) { CTFileName fnTextureForPrimitive( theApp.m_ptdActiveTexture->GetName()); fnTextureForPrimitive.SetAbsolutePath(); strcpy( strIni, fnTextureForPrimitive); WriteProfileString( L"World editor prefs", L"Default primitive texture", CString(strIni)); } SET_FLOAT( m_fPaintPower); INI_WRITE( "Paint power"); SET_FLOAT( m_fSmoothPower); INI_WRITE( "Smooth power"); SET_INDEX( m_iFilter); INI_WRITE( "Current filter"); SET_FLOAT( m_fPosterizeStep); INI_WRITE( "Posterize step"); SET_INDEX( m_iTerrainGenerationMethod); INI_WRITE( "Terrain generation method"); SET_INDEX( m_iRNDSubdivideAndDisplaceItterations); INI_WRITE( "Subdivade and displace itterations"); SET_FLOAT( m_fNoiseAltitude); INI_WRITE( "Noise altitude"); SET_STRING( m_fnDistributionNoiseTexture); INI_WRITE( "Distribution noise texture"); SET_STRING( m_fnContinousNoiseTexture); INI_WRITE( "Continous noise texture"); SET_INDEX( m_iFBMOctaves); INI_WRITE( "FBM Octaves"); SET_FLOAT( m_fFBMHighFrequencyStep); INI_WRITE( "FBM High frequency step"); SET_FLOAT( m_fFBMStepFactor); INI_WRITE( "FBM Step factor"); SET_FLOAT( m_fFBMMaxAmplitude); INI_WRITE( "FBM Max amplitude"); SET_FLOAT( m_fFBMfAmplitudeDecreaser); INI_WRITE( "FBM Amplitude decreaser"); SET_FLAG( m_bFBMAddNegativeValues); INI_WRITE( "FBM Add negative values"); SET_FLAG( m_bFBMRandomOffset); INI_WRITE( "FBM Random offset"); WriteProfileInt(L"World editor", L"Show Tip of the Day", m_bShowTipOfTheDay); WriteProfileInt(L"World editor", L"Current Tip of the Day", m_iCurrentTipOfTheDay); WriteProfileInt(L"Display modes", L"SED Gfx API", m_iApi); } void CWorldEditorApp::WriteToIniFile() { // write values for preferences m_Preferences.WriteToIniFile(); // write to INI file last values used for primitive m_vfpPreLast.WriteToIniFile("PreLast"); m_vfpLast.WriteToIniFile("Last"); m_vfpCurrent.WriteToIniFile("Current"); // write to INI last values for each type of primitive m_vfpConus.WriteToIniFile("Conus"); m_vfpTorus.WriteToIniFile("Torus"); m_vfpStaircases.WriteToIniFile("Staircases"); m_vfpSphere.WriteToIniFile("Sphere"); m_vfpTerrain.WriteToIniFile("Terrain"); // save world and model rendering preferences SaveRenderingPreferences(); // save child configurations SaveChildConfigurations(); } // World editor ini write function for preferences void CAppPrefs::WriteToIniFile() { char strIni[ 256]; SET_FLAG( ap_CopyExistingWindowPrefs); INI_WRITE( "Copy existing window preferences"); SET_FLAG( ap_AutoMaximizeWindow); INI_WRITE( "Auto maximize window"); SET_FLAG( ap_SetDefaultColors); INI_WRITE( "Set default colors"); SET_FLAG( ap_AutomaticInfo); INI_WRITE( "Automatic info"); SET_FLAG( ap_UpdateAllways); INI_WRITE( "Update allways"); SET_FLAG( ap_BinaryGrid); INI_WRITE( "Binary grid"); SET_FLAG( ap_bSaveUndoForDelete); INI_WRITE( "Save undo for delete"); SET_FLAG( ap_bAutoColorize); INI_WRITE( "Auto colorize primitives"); SET_FLAG( ap_bShowAllOnOpen); INI_WRITE( "Show all on open"); SET_FLAG( ap_bHideShadowsOnOpen); INI_WRITE( "Hide shadows on open"); SET_FLAG( ap_bAutoUpdateDisplaceMap); INI_WRITE( "Auto update displace map"); SET_INDEX( ap_iUndoLevels); INI_WRITE( "Undo levels"); SET_INDEX( ap_iStartupWindowSetup); INI_WRITE( "Startup window setup"); SET_COLOR( ap_DefaultInkColor); INI_WRITE( "Ink color"); SET_COLOR( ap_DefaultPaperColor); INI_WRITE( "Paper color"); SET_COLOR( ap_DefaultSelectionColor); INI_WRITE( "Current selection color"); SET_COLOR( ap_DefaultGridColor); INI_WRITE( "Current grid color"); SET_STRING( ap_strSourceSafeProject); INI_WRITE( "Source safe project"); SET_FLOAT( ap_fDefaultFlyModeSpeed); INI_WRITE( "Default fly mode speed"); SET_INDEX( ap_iTerrainSelectionVisible); INI_WRITE( "Terrain selection visible"); SET_INDEX( ap_iTerrainSelectionHidden); INI_WRITE( "Terrain selection hidden"); SET_INDEX( ap_iMemoryForTerrainUndo); INI_WRITE( "Memory for terrain undo"); SET_FLAG( ap_bAutoUpdateTerrainDistribution); INI_WRITE( "Auto generate distribution"); } BOOL CWorldEditorApp::LoadRenderingPreferences() { CTFileName fnRenderingPrefs = CTString("Data\\WEDRenderingPrefs.bin"); // if rendering preferences file does not exist if (!FileExists(fnRenderingPrefs)) { // just reset to defaults without a note return FALSE; } // load world and model rendering preferences CTFileStream strmFile; try { // open binary file to read rendering preferences strmFile.Open_t( fnRenderingPrefs); // read file ID strmFile.ExpectID_t( CChunkID( "RPRF")); // rendering preferences // check version number if( !(CChunkID( VIEW_PREFERENCES_VER) == strmFile.GetID_t()) ) { throw( "Invalid version of rendering preferences, switching to defaults."); } // read view rendering preferences strmFile.Read_t( &m_vpViewPrefs, sizeof( m_vpViewPrefs)); for(INDEX i=0; iSetDefaultValues(); // read child configurations array strmFile.Read_t( &m_ccChildConfigurations, sizeof( m_ccChildConfigurations)); // read end of file ID strmFile.ExpectID_t( CChunkID( "CCED")); // end of child configurations ID } catch( char *err_str) { char achrMessage[ 256]; sprintf( achrMessage, "%s\nSplit window configurations will be switched to defaults.", err_str); AfxMessageBox( CString(achrMessage)); ClearInvalidConfigPointers(); return FALSE; } ClearInvalidConfigPointers(); return TRUE; } void CWorldEditorApp::SaveChildConfigurations(void) { ClearInvalidConfigPointers(); // save child configurations CTFileStream strmFile; try { CTFileName fnChildConfigurations = CTString("Data\\WEDChildConfigurations.bin"); // create binary file to receive child configurations strmFile.Create_t( fnChildConfigurations, CTStream::CM_BINARY); // write file ID strmFile.WriteID_t( CChunkID( "CCFG")); // child configurations // write version number strmFile.WriteID_t( CChunkID( CHILD_CONFIGURATION_VER)); // write child configurations array strmFile.Write_t( &m_ccChildConfigurations, sizeof( m_ccChildConfigurations)); // write end of file ID strmFile.WriteID_t( CChunkID( "CCED")); // end of child configurations ID } catch( char *err_str) { AfxMessageBox( CString(err_str)); } } // clear possibly invalid pointers in view configurations void CWorldEditorApp::ClearInvalidConfigPointers(void) { for(INDEX i=0; iEnd(); // delete clipboard file RemoveFile( CTString("Temp\\ClipboardWorld.wld")); WriteToIniFileOnEnd(); WriteDefaultPolygonValues(); // release entity marker texture if( m_ptdEntityMarkerTexture != NULL) { _pTextureStock->Release( m_ptdEntityMarkerTexture); m_ptdEntityMarkerTexture = NULL; } // and entity marker model data if( m_pEntityMarkerModelData != NULL) { _pModelStock->Release( m_pEntityMarkerModelData); delete m_pEntityMarkerModelObject; m_pEntityMarkerModelObject = NULL; } // release portal marker texture if( m_ptdPortalMarkerTexture != NULL) { _pTextureStock->Release( m_ptdPortalMarkerTexture); m_ptdPortalMarkerTexture = NULL; } // and portal marker model data if( m_pPortalMarkerModelData != NULL) { _pModelStock->Release( m_pPortalMarkerModelData); delete m_pPortalMarkerModelObject; m_pPortalMarkerModelObject = NULL; } // release empty brush texture if( m_ptdEmptyBrushTexture != NULL) { _pTextureStock->Release( m_ptdEmptyBrushTexture); m_ptdEmptyBrushTexture = NULL; } // and empty brush model data if( m_pEmptyBrushModelData != NULL) { _pModelStock->Release( m_pEmptyBrushModelData); delete m_pEmptyBrushModelObject; m_pEmptyBrushModelObject = NULL; } // release range sphere texture if( m_ptdRangeSphereTexture != NULL) { _pTextureStock->Release( m_ptdRangeSphereTexture); m_ptdRangeSphereTexture = NULL; } // and range sphere model data if( m_pRangeSphereModelData != NULL) { _pModelStock->Release( m_pRangeSphereModelData); delete m_pRangeSphereModelObject; m_pRangeSphereModelObject = NULL; } // release angle3d texture if( m_ptdAngle3DTexture != NULL) { _pTextureStock->Release( m_ptdAngle3DTexture); m_ptdAngle3DTexture = NULL; } // and angle3d model data if( m_pAngle3DModelData != NULL) { _pModelStock->Release( m_pAngle3DModelData); delete m_pAngle3DModelObject; m_pAngle3DModelObject = NULL; } // release bounding box texture if( m_ptdBoundingBoxTexture != NULL) { _pTextureStock->Release( m_ptdBoundingBoxTexture); m_ptdBoundingBoxTexture = NULL; } // and range bounding box model data if( m_pBoundingBoxModelData != NULL) { _pModelStock->Release( m_pBoundingBoxModelData); delete m_pBoundingBoxModelObject; m_pBoundingBoxModelObject = NULL; } // release error texture object if( m_ptoError != NULL) { delete m_ptoError; } // release error texture if( m_ptdError != NULL) { _pTextureStock->Release( m_ptdError); } // release icons tray texture if( m_ptdIconsTray != NULL) { _pTextureStock->Release( m_ptdIconsTray); } // release orientation icons if( m_pViewIconsTD != NULL) { _pTextureStock->Release( m_pViewIconsTD); } // release default primitive texture if( m_ptdActiveTexture != NULL) { _pTextureStock->Release( m_ptdActiveTexture); } /* FORDELETELIST( CDisplayMode, dm_Node, m_AvailableModes, litDM) { delete &litDM.Current(); } */ FORDELETELIST( CPrimitiveInHistoryBuffer, pihb_lnNode, theApp.m_lhPrimitiveHistory, itPrim) { delete &itPrim.Current(); } delete m_pbpoClipboardPolygon; // end entire engine SE_EndEngine(); int iResult = CWinApp::ExitInstance(); return iResult; } void CWorldEditorApp::OnFilePreferences() { CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd()); CDlgPreferences dlg; dlg.m_dmFullScreen = m_dmFullScreen; dlg.m_gatFullScreen = m_gatFullScreen; if( dlg.DoModal() == IDOK) { // remember new full screen mode m_dmFullScreen = dlg.m_dmFullScreen; m_gatFullScreen = dlg.m_gatFullScreen; } } BOOL CWorldEditorApp::OnIdle(LONG lCount) { // if game is on if( _pInput->IsInputEnabled()) { ASSERT(FALSE); //!!!!! return FALSE; } // if game is on, everithing else is off (don't execute this) else if( !(lCount&0xF)) { POSITION pos = m_pDocTemplate->GetFirstDocPosition(); while (pos!=NULL) { CWorldEditorDoc *pdocCurrent = (CWorldEditorDoc *)m_pDocTemplate->GetNextDoc(pos); pdocCurrent->OnIdle(); } // remember the world pointer of current document CWorldEditorView *pvCurrent = GetActiveView(); if (pvCurrent!=NULL) { CWorldEditorDoc *pdocCurrent = pvCurrent->GetDocument(); if (pdocCurrent!=NULL) { _pShell->SetCurrentWorld(&pdocCurrent->m_woWorld); } } ((CMainFrame *)m_pMainWnd)->OnIdle( lCount); } BOOL bLMB = (GetKeyState( VK_LBUTTON)&0x8000) != 0; BOOL bRMB = (GetKeyState( VK_RBUTTON)&0x8000) != 0; BOOL bResult=CWinApp::OnIdle(lCount); return bResult||bLMB||bRMB; } // force all documents to repaint thir views void CWorldEditorApp::RefreshAllDocuments( void) { POSITION pos = m_pDocTemplate->GetFirstDocPosition(); while (pos!=NULL) { CWorldEditorDoc *pdocCurrent = (CWorldEditorDoc *)m_pDocTemplate->GetNextDoc(pos); pdocCurrent->UpdateAllViews( NULL); } } // sets new active texture for primitive's default material void CWorldEditorApp::SetNewActiveTexture( CTFileName fnFullTexName) { CMainFrame *pMainFrame = (CMainFrame *)m_pMainWnd; // to hold new texture CTextureData *pdtNewTexture = NULL; // to hold short texture name CTFileName fnTexName = fnFullTexName; // try to try { // obtain the new texture fnTexName.RemoveApplicationPath_t(); pdtNewTexture = _pTextureStock->Obtain_t( fnTexName); } // if failed catch( char *err_str) { pdtNewTexture = _pTextureStock->Obtain_t( CTFILENAME("Textures\\Editor\\Default.tex") ); (void)err_str; // report error //AfxMessageBox( CString(err_str)); //return; } ASSERT(pdtNewTexture != NULL); // if there is old texture if (m_ptdActiveTexture!=NULL) { // release it _pTextureStock->Release(m_ptdActiveTexture); } // remember the new texture m_ptdActiveTexture = pdtNewTexture; // if info frame exists, update it if( pMainFrame->m_pInfoFrame != NULL) { CInfoSheet *pSheet = pMainFrame->m_pInfoFrame->m_pInfoSheet; // redraw info frame pMainFrame->m_pInfoFrame->Invalidate(FALSE); // info's page is pg global if( (pSheet->GetActivePage() == &pSheet->m_PgGlobal) ) { // update texture description pMainFrame->m_pInfoFrame->m_pInfoSheet->m_PgGlobal.UpdateData( FALSE); } // get active view CWorldEditorView *pWorldEditorView = theApp.GetActiveView(); // get active document CWorldEditorDoc* pDoc = theApp.GetActiveDocument(); // if view and second layer exist (CSG is on), and primitive mode is on if( (pWorldEditorView != NULL) && (pDoc->m_pwoSecondLayer != NULL) && (pDoc->m_bPrimitiveMode) ) { // apply texture change for CSG primitive pSheet->m_PgPrimitive.ApplySCGChange(); } } } // opens directory wich contains given item void CWorldEditorApp::FindItemInBrowser( CTFileName fnItemFileName) { CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd()); pMainFrame->m_Browser.SelectItemDirectory( fnItemFileName); } void CWorldEditorApp::TexturizeSelection(void) { // get active document CWorldEditorDoc* pDoc = theApp.GetActiveDocument(); // if it exists if( pDoc != NULL) { // try to apply new texture to current selection try { // if polygon mode if( (pDoc->m_iMode == POLYGON_MODE) && (m_ptdActiveTexture != NULL) ) { // get name from serial object CTFileName fnTextureName = m_ptdActiveTexture->GetName(); pDoc->PasteTextureOverSelection_t( fnTextureName); } } // if failed catch( char *err_str) { // report error AfxMessageBox( CString(err_str)); return; } } } void CWorldEditorApp::OnFileOpen() { // call file requester for opening documents CDynamicArray afnOpenedWorlds; _EngineGUI.FileRequester( "Choose worlds to open", FILTER_WLD FILTER_ALL FILTER_END, "Open world directory", "Worlds\\", "", &afnOpenedWorlds); FOREACHINDYNAMICARRAY( afnOpenedWorlds, CTFileName, itWorld) { // try to load document m_pDocTemplate->OpenDocumentFile( CString(_fnmApplicationPath+itWorld.Current())); } } void CWorldEditorApp::OnConvertWorlds() { _pShell->Execute( CTString("con_bNoWarnings=1;")); // call file requester for list containing worlds to convert CTFileName fnFileList = _EngineGUI.FileRequester( "Choose list file for conversion", FILTER_LST FILTER_TXT FILTER_ALL FILTER_END, "List files directory", ""); if( fnFileList == "") return; INDEX ctLines = 0; char achrLine[256]; CTFileStream fsFileList; // count lines in list file try { fsFileList.Open_t( fnFileList); while( !fsFileList.AtEOF()) { fsFileList.GetLine_t( achrLine, 256); // increase counter only for lines that are not blank if( achrLine != "") ctLines++; } fsFileList.Close(); } // if the list file can't be opened catch(char *strError) { _pShell->Execute( CTString("con_bNoWarnings=0;")); WarningMessage( "Error reading list file: %s", strError); return; } // process list file CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd()); CDlgProgress dlgProgressDialog( pMainFrame, TRUE); dlgProgressDialog.Create( IDD_PROGRESS_DIALOG); // create progress dialog dlgProgressDialog.SetWindowText( L"Convert files"); dlgProgressDialog.ShowWindow( SW_SHOW); // show progress window dlgProgressDialog.CenterWindow(); // center window dlgProgressDialog.m_ctrlProgres.SetRange( 0, (short)ctLines); // set progress range // prepare error file CTFileStream fsErrorFile; CTFileName fnErrorFile = fnFileList.NoExt() + ".err"; // reopen list file fsFileList.Open_t( fnFileList); INDEX iCurrent = 0; BOOL bConvertError = FALSE; CTString strReport; CTFileName fnmFile, fnmExt, fnmFileFull; // loop thru lines while( !fsFileList.AtEOF()) { try { if( dlgProgressDialog.m_bCancelPressed) break; // read one line from list file fsFileList.GetLine_t( achrLine, 256); // ignore blank lines if( achrLine == "") continue; // set message and progress position char achrProgressMessage[256]; sprintf( achrProgressMessage, "Converting files ... (%d / %d)", iCurrent+1, ctLines); dlgProgressDialog.SetProgressMessageAndPosition( achrProgressMessage, iCurrent+1); // convert needed type of object fnmFile = CTString( achrLine); fnmFileFull = _fnmApplicationPath+fnmFile; fnmExt = fnmFile.FileExt(); struct _stat FileStat; struct _utimbuf FileTime; // convert world? if( fnmExt == ".wld") { // load the world CWorld woWorld; woWorld.Load_t(fnmFile); // reinitialize all entities woWorld.ReinitializeEntities(); // flush stale caches _pShell->Execute("FreeUnusedStock();"); // show all sectors and entities woWorld.ShowAllSectors(); woWorld.ShowAllEntities(); // recalculate shadows on all brush polygons in the world woWorld.DiscardAllShadows(); woWorld.CalculateDirectionalShadows(); woWorld.CalculateNonDirectionalShadows(); // get original file date if( _stat( fnmFileFull, &FileStat)) throw "Error getting file date."; // save world in new format woWorld.Save_t(fnmFile); _pShell->Execute( CTString( "bReinitializeShadowLayers=0;")); woWorld.Clear(); // revert to original file date FileTime.actime = FileStat.st_atime; FileTime.modtime = FileStat.st_mtime; if( _utime( fnmFileFull, &FileTime)) throw "Error setting file date."; } // convert texture? else if( fnmExt == ".tex" || fnmExt == ".tbn") { // convert textures (but keep the file date) CTextureData tdTex; tdTex.Load_t( fnmFile); // if old texture has been loaded if( tdTex.td_ulFlags & TEX_WASOLD) { // cannost convert mangled textures if( tdTex.td_ptegEffect==NULL && tdTex.IsModified()) throw( TRANS("Cannot write texture that has modified frames.")); // get original file date if( _stat( fnmFileFull, &FileStat)) throw "Error getting file date."; // save texture in new format tdTex.Save_t( fnmFile); // revert to original file date FileTime.actime = FileStat.st_atime; FileTime.modtime = FileStat.st_mtime; if( _utime( fnmFileFull, &FileTime)) throw "Error setting file date."; } } // convert WHAT? else if( fnmFile=="") { continue; } else { ThrowF_t( "Unsupported file format: %s", (CTString&)fnmExt); } } // if file can't be opened catch( char *strError) { try { // on first error if( !bConvertError) { // (re)create error file fsErrorFile.Create_t( fnErrorFile); bConvertError = TRUE; } // report error to file strReport.PrintF( "File: %s\nHad error: %s\n", (CTString)fnmFile, strError); fsErrorFile.PutString_t( strReport); fsErrorFile.PutLine_t( "-----------------------------------------------"); } // here should be no errors, catch( char *strError) { // otherwise ... (void) strError; WarningMessage( "Fatal error occured while working with error file!"); break; } } // advance to next line iCurrent++; } fsFileList.Close(); dlgProgressDialog.DestroyWindow(); // destroy progress dialog _pShell->Execute( CTString("con_bNoWarnings=0;")); // report error situation (if any) if( bConvertError) { fsErrorFile.PutLine_t( "DONE."); fsErrorFile.Close(); WarningMessage( "There were some errors in conversion. They are listed in file:\n %s", fnErrorFile); } } CEntity *CWorldEditorApp::CreateWorldBaseEntity(CWorld &woWorld, BOOL bZoning, CPlacement3D plWorld/*=CPlacement3D(FLOAT3D(0,0,0),ANGLE3D(0,0,0))*/) { CEntity *penwb; // try to try { // create world base entity penwb = woWorld.CreateEntity_t(plWorld, CTFILENAME("Classes\\WorldBase.ecl")); } // catch and catch( char *err_str) { // report errors AfxMessageBox( CString(err_str)); return NULL; } // prepare the entity penwb->Initialize(); if( bZoning) { EFirstWorldBase eFirstWorldBase; penwb->SendEvent( eFirstWorldBase); CEntity::HandleSentEvents(); } return penwb; } BOOL CWorldEditorApp::Add3DObject(CWorldEditorDoc *pDoc, CEntity *penwb, CTFileName fnFile, BOOL bAdd) { CObject3D o3d; // temporary world CWorld woWorld; CEntity *penwb2=CreateWorldBaseEntity(woWorld, FALSE); if( penwb2==NULL) { return FALSE; } // try to try { // load 3D object FLOATmatrix3D mStretch; mStretch.Diagonal(1.0f); if (fnFile.FileExt()==".obj") { // Maya Obj has different orientation mStretch.Diagonal(FLOAT3D(-1.0f, 1.0f, -1.0f)); } o3d.LoadAny3DFormat_t( fnFile, mStretch); FOREACHINDYNAMICARRAY(o3d.ob_aoscSectors, CObjectSector, itosc) { // for each material in object3D FOREACHINDYNAMICARRAY(itosc->osc_aomtMaterials, CObjectMaterial, itom) { if( !FileExists(itom->omt_Name)) { itom->omt_Name = "Textures\\Editor\\Default.tex"; } } } // create world base's brush from object 3D CBrush3D *pbr = penwb2->GetBrush(); pbr->FromObject3D_t( o3d); pbr->CalculateBoundingBoxes(); CPlacement3D plDummy; plDummy.pl_PositionVector = FLOAT3D(0.0f,0.0f,0.0f); plDummy.pl_OrientationAngle = ANGLE3D(0,0,0); // if should apply CSG add if(bAdd) { penwb->en_pwoWorld->CSGAdd(*penwb, woWorld, *penwb2, plDummy); } // if should perform join layers else { // copy entities penwb->en_pwoWorld->CopyEntities( woWorld, woWorld.wo_cenEntities, pDoc->m_selEntitySelection, plDummy); } } // catch and catch( char *err_str) { // report errors AfxMessageBox( CString(err_str)); return FALSE; } return TRUE; } /* * Import 3d object(s), create new document */ void CWorldEditorApp::OnImport3DObject() { // try to load document CWorldEditorDoc *pDoc = (CWorldEditorDoc *) m_pDocTemplate->CreateNewDocument(); // create the World entity CEntity *pwb=CreateWorldBaseEntity(pDoc->m_woWorld, TRUE); if( pwb==NULL) { delete pDoc; return; } // create 3d objects INDEX ctImported=Insert3DObjects(pDoc); if( ctImported==0) { delete pDoc; return; } // finish creating document if (pDoc == NULL) { TRACE0("CDocTemplate::CreateNewDocument returned NULL.\n"); AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC); return; } ASSERT_VALID(pDoc); BOOL bAutoDelete = pDoc->m_bAutoDelete; pDoc->m_bAutoDelete = FALSE; // don't destroy if something goes wrong CFrameWnd* pFrame = m_pDocTemplate->CreateNewFrame(pDoc, NULL); pDoc->m_bAutoDelete = bAutoDelete; if (pFrame == NULL) { AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC); delete pDoc; // explicit delete on error return; } ASSERT_VALID(pFrame); pDoc->SetModifiedFlag(); // set document name and don't add it into MRU //pDoc->SetPathName( _fnmApplicationPath+"Worlds\\"+"Untitled.wld", FALSE); //pDoc->SetTitle( fn3D.FileName() + ".wld"); m_pDocTemplate->InitialUpdateFrame(pFrame, pDoc, TRUE); pDoc->SetModifiedFlag( TRUE); } INDEX CWorldEditorApp::Insert3DObjects(CWorldEditorDoc *pDoc) { INDEX ctInserted=0; CDynamicArray afnFiles; CTFileName fn3D = _EngineGUI.FileRequester( "Import 3D object series", FILTER_3DOBJ FILTER_LWO FILTER_OBJ FILTER_3DS FILTER_ALL FILTER_END, "Import 3D object directory", "", "", &afnFiles); if( afnFiles.Count() == 0) return 0; // get first file (when strings are sorted) CTString strMin="a"; ((char *)(const char *) strMin)[0]=char(255); CTFileName *pfn=NULL; {FOREACHINDYNAMICARRAY(afnFiles, CTFileName, itfn) { CTString str=itfn->FileName(); if( strcmp(str, strMin)<0) { strMin=str; pfn=&*itfn; } }} ASSERT(pfn!=NULL); if(pfn==NULL) return ctInserted; // create main World entity CEntity *pwb=CreateWorldBaseEntity(pDoc->m_woWorld, TRUE); if( pwb==NULL) { return 0; } // add first 3D file as zoning base if( !Add3DObject(pDoc, pwb, *pfn, TRUE)) { return 0; } ctInserted++; // remove added file from dynamic container afnFiles.Delete(pfn); // add other files {FOREACHINDYNAMICARRAY(afnFiles, CTFileName, itfn) { CTString &str=*itfn; CTString strName=itfn->FileName(); if( ((char *)(const char *)strName)[strlen(strName)-1] == 'E') { // join layers Add3DObject(pDoc, pwb, *itfn, FALSE); } else { // CSG add Add3DObject(pDoc, pwb, *itfn, TRUE); } ctInserted++; }} return ctInserted; } CWorldEditorDoc* CWorldEditorApp::GetLastActivatedDocument(void) { return m_pLastActivatedDocument; } void CWorldEditorApp::ActivateDocument(CWorldEditorDoc *pDocToActivate) { // remember document to be activated as last activated m_pLastActivatedDocument = pDocToActivate; } CWorldEditorDoc *CWorldEditorApp::GetDocument() { // obtain current view ptr CWorldEditorView *pWorldEditorView = GetActiveView(); // if view does not exist, return if( pWorldEditorView == NULL) { return NULL; } // obtain document ptr CWorldEditorDoc *pDoc = pWorldEditorView->GetDocument(); // return it return pDoc; } void CWorldEditorApp::OnFileNew() { CWinApp::OnFileNew(); // obtain new document ptr CWorldEditorDoc *pDoc = GetDocument(); CTFileName fnDefaultBcg = CTString(CStringA(theApp.GetProfileString( L"World editor prefs", L"Default background picture", CString("Textures\\Editor\\Default.tex")))); try { //!!!! pDoc->m_woWorld.SetBackgroundTexture_t( fnDefaultBcg); } catch( char *strError) { (void) strError; } try { //!!!! pDoc->m_woWorld.SetBackgroundTexture_t( CTString("Textures\\Editor\\Default.tex")); } catch( char *strError) { AfxMessageBox( CString(strError)); } char chrColor[ 16]; COLOR colBackground; // obtain background color form INI file strcpy( chrColor, CStringA(theApp.GetProfileString( L"World editor prefs", L"Default background color", L"0XFF000000"))); sscanf( chrColor, "0X%08x", &colBackground); // set background color to color button pDoc->m_woWorld.SetBackgroundColor( colBackground); pDoc->m_woWorld.SetDescription( "No mission description"); pDoc->SetModifiedFlag( TRUE); CString strOpenPath; strOpenPath = CStringA(theApp.GetProfileString(L"World editor", L"Open directory", L"")); // set default document's name and don't set it into MRU pDoc->SetPathName( strOpenPath + "Untitled.wld", FALSE); pDoc->SetTitle( L"Untitled.wld"); } int CWorldEditorApp::Run() { int iResult; CTSTREAM_BEGIN { iResult=CWinApp::Run(); } CTSTREAM_END; return iResult; } BOOL CWorldEditorApp::PreTranslateMessage(MSG* pMsg) { return CWinApp::PreTranslateMessage(pMsg); } CTString CWorldEditorApp::GetNameForVirtualTreeNode( CVirtualTreeNode *pvtnNode) { ASSERT( pvtnNode != NULL); // start from selected directory CVirtualTreeNode *pvtnCurrentDir = pvtnNode; // reset curently opened virtual directory name CTString strResult = ""; // compile full path name while( pvtnCurrentDir->vnt_pvtnParent != NULL) { strResult = pvtnCurrentDir->vtn_strName+"\\"+ strResult; pvtnCurrentDir = pvtnCurrentDir->vnt_pvtnParent; } // if given is root directory if( strResult == "") { strResult = ""; } return strResult; } void CWorldEditorApp::OnDecadicGrid() { m_bDecadicGrid = !m_bDecadicGrid; // refresh all documents RefreshAllDocuments(); } void CWorldEditorApp::OnUpdateDecadicGrid(CCmdUI* pCmdUI) { pCmdUI->SetCheck( m_bDecadicGrid); } void CCustomToolTip::ManualOn( PIX pixManualX, PIX pixManualY, TTCFunction_type *pCallBack, void *pThis) { CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd()); cct_pCallback = pCallBack; cct_pThis = pThis; if( pMainFrame->m_pwndToolTip != NULL) { ManualOff(); } pMainFrame->ManualToolTipOn( pixManualX, pixManualY); } void CCustomToolTip::ManualOff( void) { CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd()); pMainFrame->m_pwndToolTip->ManualOff(); pMainFrame->m_pwndToolTip = NULL; } void CCustomToolTip::ManualUpdate(void) { CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd()); pMainFrame->ManualToolTipUpdate(); } void CCustomToolTip::MouseMoveNotify( HWND hwndCaller, ULONG ulTime, TTCFunction_type *pCallBack, void *pThis) { cct_hwndCaller = hwndCaller; cct_pCallback = pCallBack; cct_pThis = pThis; CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd()); pMainFrame->KillTimer( 0); pMainFrame->SetTimer( 0, ulTime, NULL); } void CWorldEditorApp::OnSetAsDefault() { CWorldEditorDoc *pDoc = GetDocument(); ASSERT( pDoc->m_selPolygonSelection.Count() == 1); pDoc->m_selPolygonSelection.Lock(); m_pbpoPolygonWithDeafultValues->CopyPropertiesWithoutTexture( pDoc->m_selPolygonSelection[0]); pDoc->m_selPolygonSelection.Unlock(); } void CWorldEditorApp::ReadDefaultPolygonValues() { char strIni[ 256]; INI_READ( "Default polygon flags", "0"); GET_INDEX( m_pbpoPolygonWithDeafultValues->bpo_ulFlags); INI_READ( "Default polygon shadow color", "0XFFFFFFFF"); GET_COLOR( m_pbpoPolygonWithDeafultValues->bpo_colShadow); INI_READ( "Default polygon surface", "0"); GET_INDEX( m_pbpoPolygonWithDeafultValues->bpo_bppProperties.bpp_ubSurfaceType); INI_READ( "Default polygon illumination", "0"); GET_INDEX( m_pbpoPolygonWithDeafultValues->bpo_bppProperties.bpp_ubIlluminationType); INI_READ( "Default polygon blend", "1"); GET_INDEX( m_pbpoPolygonWithDeafultValues->bpo_bppProperties.bpp_ubShadowBlend); INI_READ( "Default polygon mirror", "0"); GET_INDEX( m_pbpoPolygonWithDeafultValues->bpo_bppProperties.bpp_ubMirrorType); INI_READ( "Default polygon cluster size", "2"); GET_INDEX( m_pbpoPolygonWithDeafultValues->bpo_bppProperties.bpp_sbShadowClusterSize); } void CWorldEditorApp::WriteDefaultPolygonValues() { char strIni[ 256]; SET_INDEX( m_pbpoPolygonWithDeafultValues->bpo_ulFlags); INI_WRITE( "Default polygon flags"); SET_COLOR( m_pbpoPolygonWithDeafultValues->bpo_colShadow); INI_WRITE( "Default polygon shadow color"); SET_INDEX( m_pbpoPolygonWithDeafultValues->bpo_bppProperties.bpp_ubSurfaceType); INI_WRITE( "Default polygon surface"); SET_INDEX( m_pbpoPolygonWithDeafultValues->bpo_bppProperties.bpp_ubIlluminationType); INI_WRITE( "Default polygon illumination"); SET_INDEX( m_pbpoPolygonWithDeafultValues->bpo_bppProperties.bpp_ubShadowBlend); INI_WRITE( "Default polygon blend"); SET_INDEX( m_pbpoPolygonWithDeafultValues->bpo_bppProperties.bpp_ubMirrorType); INI_WRITE( "Default polygon mirror"); SET_INDEX( m_pbpoPolygonWithDeafultValues->bpo_bppProperties.bpp_sbShadowClusterSize); INI_WRITE( "Default polygon cluster size"); } void CWorldEditorApp::OnHelpShowTipOfTheDay() { CDlgTipOfTheDay dlgTips; dlgTips.DoModal(); m_bShowTipOfTheDay = dlgTips.m_bShowTipsAtStartup; } void FindEmptyBrushes( void) { // remember the world pointer of current document CWorldEditorView *pvCurrent = theApp.GetActiveView(); if (pvCurrent!=NULL) { CWorldEditorDoc *pDoc = pvCurrent->GetDocument(); if (pDoc!=NULL) { // for each entity in the world FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten) { FLOAT3D vPos = iten->GetPlacement().pl_PositionVector; // if it is brush entity if (iten->en_RenderType == CEntity::RT_BRUSH) { INDEX iMip = 0; // for each mip in its brush FOREACHINLIST(CBrushMip, bm_lnInBrush, iten->en_pbrBrush->br_lhBrushMips, itbm) { if( itbm->bm_abscSectors.Count() == 0) { CPrintF("Found brush named %s, without sectors in mip %d at coordinates: (%g, %g, %g)\n", iten->GetName(), iMip, vPos(1), vPos(2), vPos(3)); } iMip++; } } } } } } void CWorldEditorApp::WinHelp(DWORD dwData, UINT nCmd) { // TODO: Add your specialized code here and/or call the base class if (nCmd == HELP_CONTEXT) { DisplayHelp(CTFILENAME("Help\\SeriousEditorContext.hlk"), HH_HELP_CONTEXT, dwData); } else { CWinApp::WinHelp(dwData, nCmd); } } void CWorldEditorApp::DisplayHelp(const CTFileName &fnHlk, UINT uCommand, DWORD dwData) { CTString strHelpPath; BOOL bHlkFound = TRUE; try { strHelpPath.Load_t(fnHlk.NoExt()+".hlk"); } catch(char *strError) { (void) strError; if (fnHlk.FileExt()==".ecl") { WarningMessage("No help available for class: %s", fnHlk.FileName()); } bHlkFound = FALSE; } // extract prefix CTString strHelpFormatID = strHelpPath; strHelpFormatID.OnlyFirstLine(); strHelpPath.RemovePrefix(strHelpFormatID); strHelpPath.DeleteChar(0); strHelpPath.OnlyFirstLine(); if( bHlkFound) { if( strHelpFormatID=="HTM" || strHelpFormatID=="HTML" || strHelpFormatID=="TXT") { // obtain iexplore path CTString strKey = "HKEY_CLASSES_ROOT\\.htm\\"; CTString strString; REG_GetString(strKey, strString); strKey = "HKEY_CLASSES_ROOT\\"+strString+"\\shell\\open\\command\\"; REG_GetString(strKey, strString); // now extract file path between two " char aExePath[PATH_MAX]; sscanf( strString, "\"%1024[^\"]\"", aExePath); CTString strCommand = "\""+CTString(aExePath)+"\""; CTString strInputParam = "\""+_fnmApplicationPath+strHelpPath+"\""; const char *argv[4]; argv[0] = strCommand; argv[1] = strInputParam; argv[2] = NULL; _spawnvp(_P_NOWAIT, aExePath, argv); return; } else if( strHelpFormatID=="CHM") { HtmlHelp(dwData); //HtmlHelp(NULL, // _fnmApplicationPath+strHelpPath, uCommand, dwData); return; } else { WarningMessage("Expected TXT, HTM, HTML, or CHM help format indentifier."); } } HtmlHelp(dwData); //HtmlHelp(NULL, // _fnmApplicationPath+"Help\\ToolsHelp.chm::/SeriousEditor/Overview.htm", uCommand, dwData); } CEntity *GetTerrainEntity(void) { CTerrain *ptTerrain=GetTerrain(); if(ptTerrain!=NULL) { return ptTerrain->tr_penEntity; } return NULL; } CTerrain *GetTerrain(void) { CWorldEditorDoc* pDoc = theApp.GetActiveDocument(); if(pDoc==NULL) return NULL; return pDoc->m_ptrSelectedTerrain; } CTerrainLayer *GetLayer(INDEX iLayer) { CTerrain *ptTerrain=GetTerrain(); if(ptTerrain==NULL) return NULL; if(!(ptTerrain->tr_atlLayers.Count()>0) || iLayer>=ptTerrain->tr_atlLayers.Count()) return NULL; return &ptTerrain->tr_atlLayers[iLayer]; } CTerrainLayer *GetLayer(void) { CTerrain *ptTerrain=GetTerrain(); if(ptTerrain==NULL) return NULL; if(!(ptTerrain->tr_atlLayers.Count()>0)) return NULL; if(ptTerrain->tr_iSelectedLayer>=ptTerrain->tr_atlLayers.Count()) { ptTerrain->tr_iSelectedLayer=0; } return &ptTerrain->tr_atlLayers[ptTerrain->tr_iSelectedLayer]; } INDEX GetLayerIndex(void) { CTerrain *ptTerrain=GetTerrain(); if(ptTerrain==NULL) return 0; if(ptTerrain->tr_atlLayers.Count()<=0 || ptTerrain->tr_iSelectedLayer>=ptTerrain->tr_atlLayers.Count()) { ptTerrain->tr_iSelectedLayer=0; } return ptTerrain->tr_iSelectedLayer; } void SelectLayer(INDEX iLayer) { CTerrain *ptrTerrain=GetTerrain(); if(ptrTerrain==NULL) return; if(ptrTerrain->tr_atlLayers.Count()<=iLayer || iLayer<0) { ptrTerrain->tr_iSelectedLayer=0; } else { ptrTerrain->tr_iSelectedLayer=iLayer; } }