/* Copyright (c) 2002-2012 Croteam Ltd. All rights reserved. */ #include "SeriousSam/StdH.h" #ifdef PLATFORM_WIN32 #include #include #endif // !!! FIXME: rcg01082002 Do something with these. #ifdef PLATFORM_UNIX #include #if !PLATFORM_MACOSX #include #endif #endif #include #include #include #include #define DECL_DLL #include #include "resource.h" #include "SplashScreen.h" #include "MainWindow.h" #include "GLSettings.h" #include "LevelInfo.h" #include "LCDDrawing.h" #include "CmdLine.h" #include "Credits.h" CGame *_pGame = NULL; // application state variables BOOL _bRunning = TRUE; BOOL _bQuitScreen = TRUE; BOOL bMenuActive = FALSE; BOOL bMenuRendering = FALSE; extern BOOL _bDefiningKey; static BOOL _bReconsiderInput = FALSE; PIX _pixDesktopWidth = 0; // desktop width when started (for some tests) static INDEX sam_iMaxFPSActive = 500; static INDEX sam_iMaxFPSInactive = 10; static INDEX sam_bPauseOnMinimize = TRUE; // auto-pause when window has been minimized INDEX sam_bWideScreen = FALSE; FLOAT sam_fPlayerOffset = 0.0f; // display mode settings INDEX sam_bFullScreenActive = TRUE; INDEX sam_iScreenSizeI = 640; // current size of the window INDEX sam_iScreenSizeJ = 480; // current size of the window INDEX sam_iDisplayDepth = 0; // 0==default, 1==16bit, 2==32bit INDEX sam_iDisplayAdapter = 0; INDEX sam_iGfxAPI = 0; // 0==OpenGL INDEX sam_bFirstStarted = TRUE; FLOAT sam_tmDisplayModeReport = 5.0f; INDEX sam_bShowAllLevels = FALSE; INDEX sam_bMentalActivated = FALSE; // network settings CTString sam_strNetworkSettings = ""; // command line CTString sam_strCommandLine = ""; // 0...app started for the first time // 1...all ok // 2...automatic fallback static INDEX _iDisplayModeChangeFlag = 0; static TIME _tmDisplayModeChanged = 100.0f; // when display mode was last changed // rendering preferences for automatic settings INDEX sam_iVideoSetup = 1; // 0==speed, 1==normal, 2==quality, 3==custom // automatic adjustment of audio quality BOOL sam_bAutoAdjustAudio = TRUE; INDEX sam_bAutoPlayDemos = TRUE; static INDEX _bInAutoPlayLoop = TRUE; // menu calling INDEX sam_bMenuSave = FALSE; INDEX sam_bMenuLoad = FALSE; INDEX sam_bMenuControls = FALSE; INDEX sam_bMenuHiScore = FALSE; INDEX sam_bToggleConsole = FALSE; INDEX sam_iStartCredits = FALSE; // for mod re-loading CTFileName _fnmModToLoad = CTString(""); CTString _strModServerJoin = CTString(""); CTString _strURLToVisit = CTString(""); // state variables fo addon execution // 0 - nothing // 1 - start (invoke console) // 2 - console invoked, waiting for one redraw INDEX _iAddonExecState = 0; CTFileName _fnmAddonToExec = CTString(""); // logo textures static CTextureObject _toLogoCT; static CTextureObject _toLogoODI; static CTextureObject _toLogoEAX; CTextureObject *_ptoLogoCT = NULL; CTextureObject *_ptoLogoODI = NULL; CTextureObject *_ptoLogoEAX = NULL; extern CTString sam_strVersion = "1.10"; extern CTString sam_strModName = TRANS("- O P E N S O U R C E -"); #if _SE_DEMO CTString sam_strFirstLevel = "Levels\\KarnakDemo.wld"; #else CTString sam_strFirstLevel = "Levels\\LevelsMP\\1_0_InTheLastEpisode.wld"; #endif CTString sam_strIntroLevel = "Levels\\LevelsMP\\Intro.wld"; CTString sam_strGameName = "serioussamse"; CTString sam_strTechTestLevel = "Levels\\LevelsMP\\TechTest.wld"; CTString sam_strTrainingLevel = "Levels\\KarnakDemo.wld"; ENGINE_API extern INDEX snd_iFormat; // main window canvas CDrawPort *pdp; CDrawPort *pdpNormal; CDrawPort *pdpWideScreen; CViewPort *pvpViewPort; HINSTANCE _hInstance; static void PlayDemo(void* pArgs) { CTString strDemoFilename = *NEXTARGUMENT(CTString*); _gmMenuGameMode = GM_DEMO; CTFileName fnDemo = "demos\\" + strDemoFilename + ".dem"; extern BOOL LSLoadDemo(const CTFileName &fnm); LSLoadDemo(fnDemo); } static void ApplyRenderingPreferences(void) { ApplyGLSettings(TRUE); } void ApplyVideoMode(void) { StartNewMode( (GfxAPIType)sam_iGfxAPI, sam_iDisplayAdapter, sam_iScreenSizeI, sam_iScreenSizeJ, (enum DisplayDepth)sam_iDisplayDepth, sam_bFullScreenActive); } static void BenchMark(void) { _pGfx->Benchmark(pvpViewPort, pdp); } static void QuitGame(void) { _bRunning = FALSE; _bQuitScreen = FALSE; } // check if another app is already running // !!! FIXME: rcg01042002 Actually, I've abstracted this code, but it didn't // !!! FIXME: rcg01042002 really seem to care if there was another copy // !!! FIXME: rcg01042002 running before anyhow. What SHOULD be done is // !!! FIXME: rcg01042002 we should see if the lockfile exists, and if not // !!! FIXME: rcg01042002 create it and write our process ID in it. Then, if // !!! FIXME: rcg01042002 another copy of Serious Sam is run, it sees the // !!! FIXME: rcg01042002 file exists, opens it for reading, gets the process // !!! FIXME: rcg01042002 ID, and sees if that process is still running. If // !!! FIXME: rcg01042002 so, the second copy of the game should abort. // !!! FIXME: rcg01042002 If the process ID isn't running, recreate the file // !!! FIXME: rcg01042002 and THEN give the warning about not shutting down // !!! FIXME: rcg01042002 properly last time. At exit, delete the file. // !!! FIXME: rcg01042002 This is all platform independent except for the // !!! FIXME: rcg01042002 method of determining the current process ID and // !!! FIXME: rcg01042002 determining if a given process ID is still running, // !!! FIXME: rcg01042002 and those are easy abstractions. static CTFileName _fnmLock; static FILE *_hLock = NULL; static void DirectoryLockOn(void) { // create lock filename _fnmLock = _fnmUserDir + "SeriousSam.loc"; // try to open lock file if (_pFileSystem->Exists(_fnmLock)) CPrintF(TRANS("WARNING: SeriousSam didn't shut down properly last time!\n")); _hLock = fopen(_fnmLock, "w"); if (_hLock == NULL) { FatalError(TRANS("Failed to create lockfile %s! (%s)"), (const char *) _fnmLock, strerror(errno)); } } static void DirectoryLockOff(void) { // if lock is open if (_hLock!=NULL) { fclose(_hLock); _hLock == NULL; } unlink(_fnmLock); } void End(void); // automaticaly manage input enable/disable toggling static BOOL _bInputEnabled = FALSE; void UpdateInputEnabledState(void) { // do nothing if window is invalid if( _hwndMain==NULL) return; // input should be enabled if application is active // and no menu is active and no console is active BOOL bShouldBeEnabled = (!IsIconic(_hwndMain) && !bMenuActive && _pGame->gm_csConsoleState==CS_OFF && (_pGame->gm_csComputerState==CS_OFF || _pGame->gm_csComputerState==CS_ONINBACKGROUND)) || _bDefiningKey; // if should be turned off if( (!bShouldBeEnabled && _bInputEnabled) || _bReconsiderInput) { // disable it and remember new state _pInput->DisableInput(); _bInputEnabled = FALSE; } // if should be turned on if( bShouldBeEnabled && !_bInputEnabled) { // enable it and remember new state _pInput->EnableInput(_hwndMain); _bInputEnabled = TRUE; } _bReconsiderInput = FALSE; } // automaticaly manage pause toggling static void UpdatePauseState(void) { BOOL bShouldPause = (_gmRunningGameMode==GM_SINGLE_PLAYER) && (bMenuActive || _pGame->gm_csConsoleState ==CS_ON || _pGame->gm_csConsoleState ==CS_TURNINGON || _pGame->gm_csConsoleState ==CS_TURNINGOFF || _pGame->gm_csComputerState==CS_ON || _pGame->gm_csComputerState==CS_TURNINGON || _pGame->gm_csComputerState==CS_TURNINGOFF); _pNetwork->SetLocalPause(bShouldPause); } // limit current frame rate if neeeded void LimitFrameRate(void) { // measure passed time for each loop static CTimerValue tvLast(-1.0f); CTimerValue tvNow = _pTimer->GetHighPrecisionTimer(); TIME tmCurrentDelta = (tvNow-tvLast).GetSeconds(); // limit maximum frame rate sam_iMaxFPSActive = ClampDn( (INDEX)sam_iMaxFPSActive, 1L); sam_iMaxFPSInactive = ClampDn( (INDEX)sam_iMaxFPSInactive, 1L); INDEX iMaxFPS = sam_iMaxFPSActive; if( IsIconic(_hwndMain)) iMaxFPS = sam_iMaxFPSInactive; if(_pGame->gm_CurrentSplitScreenCfg==CGame::SSC_DEDICATED) { iMaxFPS = ClampDn(iMaxFPS, 60L); // never go very slow if dedicated server } TIME tmWantedDelta = 1.0f / iMaxFPS; if( tmCurrentDeltaSleep( (tmWantedDelta-tmCurrentDelta)*1000.0f); // remember new time tvLast = _pTimer->GetHighPrecisionTimer(); } // load first demo void StartNextDemo(void) { if (!sam_bAutoPlayDemos || !_bInAutoPlayLoop) { _bInAutoPlayLoop = FALSE; return; } // skip if no demos if(_lhAutoDemos.IsEmpty()) { _bInAutoPlayLoop = FALSE; return; } // get first demo level and cycle the list CLevelInfo *pli = LIST_HEAD(_lhAutoDemos, CLevelInfo, li_lnNode); pli->li_lnNode.Remove(); _lhAutoDemos.AddTail(pli->li_lnNode); // if intro if (pli->li_fnLevel==CTFileName(sam_strIntroLevel)) { // start intro _gmRunningGameMode = GM_NONE; _pGame->gm_aiStartLocalPlayers[0] = 0; _pGame->gm_aiStartLocalPlayers[1] = -1; _pGame->gm_aiStartLocalPlayers[2] = -1; _pGame->gm_aiStartLocalPlayers[3] = -1; _pGame->gm_strNetworkProvider = "Local"; _pGame->gm_StartSplitScreenCfg = CGame::SSC_PLAY1; _pShell->SetINDEX("gam_iStartDifficulty", CSessionProperties::GD_NORMAL); _pShell->SetINDEX("gam_iStartMode", CSessionProperties::GM_FLYOVER); CUniversalSessionProperties sp; _pGame->SetSinglePlayerSession(sp); _pGame->gm_bFirstLoading = TRUE; if (_pGame->NewGame( sam_strIntroLevel, sam_strIntroLevel, sp)) { _gmRunningGameMode = GM_INTRO; } // if not intro } else { // start the demo _pGame->gm_StartSplitScreenCfg = CGame::SSC_OBSERVER; _pGame->gm_aiStartLocalPlayers[0] = -1; _pGame->gm_aiStartLocalPlayers[1] = -1; _pGame->gm_aiStartLocalPlayers[2] = -1; _pGame->gm_aiStartLocalPlayers[3] = -1; // play the demo _pGame->gm_strNetworkProvider = "Local"; _gmRunningGameMode = GM_NONE; if( _pGame->StartDemoPlay( pli->li_fnLevel)) { _gmRunningGameMode = GM_DEMO; CON_DiscardLastLineTimes(); } } if (_gmRunningGameMode==GM_NONE) { _bInAutoPlayLoop = FALSE; } } BOOL _bCDPathFound = FALSE; BOOL FileExistsOnHD(const CTString &strFile) { FILE *f = fopen(_fnmApplicationPath+strFile, "rb"); if (f!=NULL) { fclose(f); return TRUE; } else { return FALSE; } } void TrimString(char *str) { int i = strlen(str); if (str[i-1]=='\n' || str[i-1]=='\r') { str[i-1]=0; } } // run web browser and view an url void RunBrowser(const char *strUrl) { #ifdef PLATFORM_WIN32 int iResult = (int)ShellExecuteA( _hwndMain, "OPEN", strUrl, NULL, NULL, SW_SHOWMAXIMIZED); if (iResult<32) { // should report error? NOTHING; } #else STUBBED("Should spawn browser here"); #endif } void LoadAndForceTexture(CTextureObject &to, CTextureObject *&pto, const CTFileName &fnm) { try { to.SetData_t(fnm); CTextureData *ptd = (CTextureData*)to.GetData(); ptd->Force( TEX_CONSTANT); ptd = ptd->td_ptdBaseTexture; if( ptd!=NULL) ptd->Force( TEX_CONSTANT); pto = &to; } catch( char *pchrError) { (void*)pchrError; pto = NULL; } } #if (!defined PLATFORM_WIN32) static char *argv0 = NULL; #endif void InitializeGame(void) { try { #ifdef STATICALLY_LINKED #define fnmExpanded NULL CPrintF(TRANS("Loading game library '%s'...\n"), "(statically linked)"); #else CTFileName fnmDLL; #ifndef NDEBUG fnmDLL = "Bin\\Debug\\Game"+_strModExt+"D.dll"; #else fnmDLL = "Bin\\Game"+_strModExt+".dll"; #endif fnmDLL = CDynamicLoader::ConvertLibNameToPlatform(fnmDLL); CTFileName fnmExpanded; ExpandFilePath(EFP_READ | EFP_NOZIPS,fnmDLL,fnmExpanded); CPrintF(TRANS("Loading game library '%s'...\n"), (const char *)fnmExpanded); #endif const char *err; CDynamicLoader *hGame = CDynamicLoader::GetInstance(fnmExpanded); if ((err = hGame->GetError()) != NULL) { ThrowF_t("%s", err); } CGame* (*GAME_Create)(void) = (CGame* (*)(void))hGame->FindSymbol("GAME_Create"); if ((err = hGame->GetError()) != NULL) { ThrowF_t("%s", err); } _pGame = GAME_Create(); } catch (char *strError) { FatalError("%s", strError); } // init game - this will load persistent symbols _pGame->Initialize(CTString("Data\\SeriousSam.gms")); } BOOL Init( HINSTANCE hInstance, int nCmdShow, CTString strCmdLine) { _hInstance = hInstance; ShowSplashScreen(hInstance); // !!! FIXME: This needs to be done before DetermineDesktopWidth(), but I // !!! FIXME: don't really want this here. #ifdef PLATFORM_UNIX if (SDL_Init(SDL_INIT_VIDEO) == -1) FatalError("SDL_Init(SDL_INIT_VIDEO) failed. Reason: [%s].", SDL_GetError()); #endif // remember desktop width _pixDesktopWidth = DetermineDesktopWidth(); // prepare main window MainWindow_Init(); OpenMainWindowInvisible(); // parse command line before initializing engine ParseCommandLine(strCmdLine); #ifdef PLATFORM_WIN32 char argv0[MAX_PATH]; memset(argv0, '\0', sizeof (argv0)); GetModuleFileName(NULL, argv0, sizeof (argv0) - 1); #endif // initialize engine SE_InitEngine(argv0, sam_strGameName); SE_LoadDefaultFonts(); // now print the output of command line parsing CPrintF("%s", (const char *) cmd_strOutput); // lock the directory DirectoryLockOn(); // load all translation tables InitTranslation(); try { AddTranslationTablesDir_t(CTString("Data\\Translations\\"), CTString("*.txt")); FinishTranslationTable(); } catch (char *strError) { FatalError("%s", strError); } // always disable all warnings when in serious sam _pShell->Execute( "con_bNoWarnings=1;"); // declare shell symbols _pShell->DeclareSymbol("user void PlayDemo(CTString);", (void *) &PlayDemo); _pShell->DeclareSymbol("persistent INDEX sam_bFullScreen;", (void *) &sam_bFullScreenActive); _pShell->DeclareSymbol("persistent INDEX sam_iScreenSizeI;", (void *) &sam_iScreenSizeI); _pShell->DeclareSymbol("persistent INDEX sam_iScreenSizeJ;", (void *) &sam_iScreenSizeJ); _pShell->DeclareSymbol("persistent INDEX sam_iDisplayDepth;", (void *) &sam_iDisplayDepth); _pShell->DeclareSymbol("persistent INDEX sam_iDisplayAdapter;", (void *) &sam_iDisplayAdapter); _pShell->DeclareSymbol("persistent INDEX sam_iGfxAPI;", (void *) &sam_iGfxAPI); _pShell->DeclareSymbol("persistent INDEX sam_bFirstStarted;", (void *) &sam_bFirstStarted); _pShell->DeclareSymbol("persistent INDEX sam_bAutoAdjustAudio;", (void *) &sam_bAutoAdjustAudio); _pShell->DeclareSymbol("persistent user INDEX sam_bWideScreen;", (void *) &sam_bWideScreen); _pShell->DeclareSymbol("persistent user FLOAT sam_fPlayerOffset;", (void *) &sam_fPlayerOffset); _pShell->DeclareSymbol("persistent user INDEX sam_bAutoPlayDemos;", (void *) &sam_bAutoPlayDemos); _pShell->DeclareSymbol("persistent user INDEX sam_iMaxFPSActive;", (void *) &sam_iMaxFPSActive); _pShell->DeclareSymbol("persistent user INDEX sam_iMaxFPSInactive;", (void *) &sam_iMaxFPSInactive); _pShell->DeclareSymbol("persistent user INDEX sam_bPauseOnMinimize;", (void *) &sam_bPauseOnMinimize); _pShell->DeclareSymbol("persistent user FLOAT sam_tmDisplayModeReport;", (void *) &sam_tmDisplayModeReport); _pShell->DeclareSymbol("persistent user CTString sam_strNetworkSettings;", (void *) &sam_strNetworkSettings); _pShell->DeclareSymbol("persistent user CTString sam_strIntroLevel;", (void *) &sam_strIntroLevel); _pShell->DeclareSymbol("persistent user CTString sam_strGameName;", (void *) &sam_strGameName); _pShell->DeclareSymbol("user CTString sam_strVersion;", (void *) &sam_strVersion); _pShell->DeclareSymbol("user CTString sam_strFirstLevel;", (void *) &sam_strFirstLevel); _pShell->DeclareSymbol("user CTString sam_strModName;", (void *) &sam_strModName); _pShell->DeclareSymbol("persistent INDEX sam_bShowAllLevels;", (void *) &sam_bShowAllLevels); _pShell->DeclareSymbol("persistent INDEX sam_bMentalActivated;", (void *) &sam_bMentalActivated); _pShell->DeclareSymbol("user void Quit(void);", (void *) &QuitGame); _pShell->DeclareSymbol("persistent user INDEX sam_iVideoSetup;", (void *) &sam_iVideoSetup); _pShell->DeclareSymbol("user void ApplyRenderingPreferences(void);", (void *) &ApplyRenderingPreferences); _pShell->DeclareSymbol("user void ApplyVideoMode(void);", (void *) &ApplyVideoMode); _pShell->DeclareSymbol("user void Benchmark(void);", (void *) &BenchMark); _pShell->DeclareSymbol("user INDEX sam_bMenuSave;", (void *) &sam_bMenuSave); _pShell->DeclareSymbol("user INDEX sam_bMenuLoad;", (void *) &sam_bMenuLoad); _pShell->DeclareSymbol("user INDEX sam_bMenuControls;", (void *) &sam_bMenuControls); _pShell->DeclareSymbol("user INDEX sam_bMenuHiScore;", (void *) &sam_bMenuHiScore); _pShell->DeclareSymbol("user INDEX sam_bToggleConsole;",(void *) &sam_bToggleConsole); _pShell->DeclareSymbol("INDEX sam_iStartCredits;", (void *) &sam_iStartCredits); InitializeGame(); _pNetwork->md_strGameID = sam_strGameName; _pGame->LCDInit(); if( sam_bFirstStarted) { InfoMessage("%s", TRANS( "SeriousSam is starting for the first time.\n" "If you experience any problems, please consult\n" "ReadMe file for troubleshooting information.")); } // initialize sound library snd_iFormat = Clamp( snd_iFormat, (INDEX)CSoundLibrary::SF_NONE, (INDEX)CSoundLibrary::SF_44100_16); _pSound->SetFormat( (enum CSoundLibrary::SoundFormat)snd_iFormat); if (sam_bAutoAdjustAudio) { _pShell->Execute("include \"Scripts\\Addons\\SFX-AutoAdjust.ini\""); } // execute script given on command line if (cmd_strScript!="") { CPrintF("Command line script: '%s'\n", (const char *) cmd_strScript); CTString strCmd; strCmd.PrintF("include \"%s\"", (const char *) cmd_strScript); _pShell->Execute(strCmd); } // load logo textures LoadAndForceTexture(_toLogoCT, _ptoLogoCT, CTFILENAME("Textures\\Logo\\LogoCT.tex")); LoadAndForceTexture(_toLogoODI, _ptoLogoODI, CTFILENAME("Textures\\Logo\\GodGamesLogo.tex")); LoadAndForceTexture(_toLogoEAX, _ptoLogoEAX, CTFILENAME("Textures\\Logo\\LogoEAX.tex")); // !! NOTE !! Re-enable these to allow mod support. //LoadStringVar(CTString("Data\\Var\\Sam_Version.var"), sam_strVersion); //LoadStringVar(CTString("Data\\Var\\ModName.var"), sam_strModName); CPrintF(TRANS("Serious Sam version: %s\n"), (const char *) sam_strVersion); CPrintF(TRANS("Active mod: %s\n"), (const char *) sam_strModName); InitializeMenus(); // if there is a mod if (_fnmMod!="") { // execute the mod startup script _pShell->Execute(CTString("include \"Scripts\\Mod_startup.ini\";")); } // init gl settings module InitGLSettings(); // init level-info subsystem LoadLevelsList(); LoadDemosList(); // apply application mode StartNewMode( (GfxAPIType)sam_iGfxAPI, sam_iDisplayAdapter, sam_iScreenSizeI, sam_iScreenSizeJ, (enum DisplayDepth)sam_iDisplayDepth, sam_bFullScreenActive); // set default mode reporting if( sam_bFirstStarted) { _iDisplayModeChangeFlag = 0; sam_bFirstStarted = FALSE; } HideSplashScreen(); if (cmd_strPassword!="") { _pShell->SetString("net_strConnectPassword", cmd_strPassword); } #if TECHTESTONLY cmd_strWorld = CTString("Levels\\TechTestElsa.wld"); #endif // if connecting to server from command line if (cmd_strServer!="") { CTString strPort = ""; if (cmd_iPort>0) { _pShell->SetINDEX("net_iPort", cmd_iPort); strPort.PrintF(":%d", cmd_iPort); } CPrintF(TRANS("Command line connection: '%s%s'\n"), (const char *) cmd_strServer, (const char *) strPort); // go to join menu _pGame->gam_strJoinAddress = cmd_strServer; if (cmd_bQuickJoin) { extern void JoinNetworkGame(void); JoinNetworkGame(); } else { StartMenus("join"); } // if starting world from command line } else if (cmd_strWorld!="") { CPrintF(TRANS("Command line world: '%s'\n"), (const char *) cmd_strWorld); // try to start the game with that level try { if (cmd_iGoToMarker>=0) { CPrintF(TRANS("Command line marker: %d\n"), cmd_iGoToMarker); CTString strCommand; strCommand.PrintF("cht_iGoToMarker = %d;", cmd_iGoToMarker); _pShell->Execute(strCommand); } _pGame->gam_strCustomLevel = cmd_strWorld; if (cmd_bServer) { extern void StartNetworkGame(void); StartNetworkGame(); } else { extern void StartSinglePlayerGame(void); StartSinglePlayerGame(); } } catch (char *strError) { CPrintF(TRANS("Cannot start '%s': '%s'\n"), (const char *) cmd_strWorld, strError); } // if no relevant starting at command line } else { StartNextDemo(); } return TRUE; } void End(void) { _pGame->DisableLoadingHook(); // cleanup level-info subsystem ClearLevelsList(); ClearDemosList(); // destroy the main window and its canvas if (pvpViewPort!=NULL) { _pGfx->DestroyWindowCanvas( pvpViewPort); pvpViewPort = NULL; pdpNormal = NULL; } CloseMainWindow(); MainWindow_End(); DestroyMenus(); _pGame->End(); _pGame->LCDEnd(); // unlock the directory DirectoryLockOff(); SE_EndEngine(); } // print display mode info if needed void PrintDisplayModeInfo(void) { // skip if timed out if( _pTimer->GetRealTimeTick() > (_tmDisplayModeChanged+sam_tmDisplayModeReport)) return; // cache some general vars SLONG slDPWidth = pdp->GetWidth(); SLONG slDPHeight = pdp->GetHeight(); if( pdp->IsDualHead()) slDPWidth/=2; CDisplayMode dm; dm.dm_pixSizeI = slDPWidth; dm.dm_pixSizeJ = slDPHeight; // determine proper text scale for statistics display FLOAT fTextScale = (FLOAT)slDPWidth/640.0f; // get resolution CTString strRes; extern CTString _strPreferencesDescription; strRes.PrintF( "%dx%dx%s", slDPWidth, slDPHeight, (const char *) _pGfx->gl_dmCurrentDisplayMode.DepthString()); if( dm.IsDualHead()) strRes += TRANS(" DualMonitor"); if( dm.IsWideScreen()) strRes += TRANS(" WideScreen"); if( _pGfx->gl_eCurrentAPI==GAT_OGL) strRes += " (OpenGL)"; #ifdef PLATFORM_WIN32 else if( _pGfx->gl_eCurrentAPI==GAT_D3D) strRes += " (Direct3D)"; #endif CTString strDescr; strDescr.PrintF("\n%s (%s)\n", (const char *) _strPreferencesDescription, (const char *) RenderingPreferencesDescription(sam_iVideoSetup)); strRes+=strDescr; // tell if application is started for the first time, or failed to set mode if( _iDisplayModeChangeFlag==0) { strRes += TRANS("Display mode set by default!"); } else if( _iDisplayModeChangeFlag==2) { strRes += TRANS("Last mode set failed!"); } // print it all pdp->SetFont( _pfdDisplayFont); pdp->SetTextScaling( fTextScale); pdp->SetTextAspect( 1.0f); pdp->PutText( strRes, slDPWidth*0.05f, slDPHeight*0.85f, _pGame->LCDGetColor(C_GREEN|255, "display mode")); } // do the main game loop and render screen void DoGame(void) { #ifdef SINGLE_THREADED _pTimer->HandleTimerHandlers(); #endif // set flag if not in game if( !_pGame->gm_bGameOn) _gmRunningGameMode = GM_NONE; if( _gmRunningGameMode==GM_DEMO && _pNetwork->IsDemoPlayFinished() ||_gmRunningGameMode==GM_INTRO && _pNetwork->IsGameFinished()) { _pGame->StopGame(); _gmRunningGameMode = GM_NONE; // load next demo StartNextDemo(); if (!_bInAutoPlayLoop) { // start menu StartMenus(); } } // do the main game loop if( _gmRunningGameMode != GM_NONE) { _pGame->GameMainLoop(); // if game is not started } else { // just handle broadcast messages _pNetwork->GameInactive(); } if (sam_iStartCredits>0) { Credits_On(sam_iStartCredits); sam_iStartCredits = 0; } if (sam_iStartCredits<0) { Credits_Off(); sam_iStartCredits = 0; } if( _gmRunningGameMode==GM_NONE) { Credits_Off(); sam_iStartCredits = 0; } // redraw the view if( !IsIconic(_hwndMain) && pdp!=NULL && pdp->Lock()) { if( _gmRunningGameMode!=GM_NONE && !bMenuActive ) { // handle pretouching of textures and shadowmaps pdp->Unlock(); _pGame->GameRedrawView( pdp, (_pGame->gm_csConsoleState!=CS_OFF || bMenuActive)?0:GRV_SHOWEXTRAS); pdp->Lock(); _pGame->ComputerRender(pdp); pdp->Unlock(); CDrawPort dpScroller(pdp, TRUE); dpScroller.Lock(); if (Credits_Render(&dpScroller)==0) { Credits_Off(); } dpScroller.Unlock(); pdp->Lock(); } else { pdp->Fill( _pGame->LCDGetColor(C_dGREEN|CT_OPAQUE, "bcg fill")); } // do menu if( bMenuRendering) { // clear z-buffer pdp->FillZBuffer( ZBUF_BACK); // remember if we should render menus next tick bMenuRendering = DoMenu(pdp); } // print display mode info if needed PrintDisplayModeInfo(); // render console _pGame->ConsoleRender(pdp); // done with all pdp->Unlock(); // clear upper and lower parts of screen if in wide screen mode if( pdp==pdpWideScreen && pdpNormal->Lock()) { const PIX pixWidth = pdpWideScreen->GetWidth(); const PIX pixHeight = (pdpNormal->GetHeight() - pdpWideScreen->GetHeight()) /2; const PIX pixJOfs = pixHeight + pdpWideScreen->GetHeight()-1; pdpNormal->Fill( 0, 0, pixWidth, pixHeight, C_BLACK|CT_OPAQUE); pdpNormal->Fill( 0, pixJOfs, pixWidth, pixHeight, C_BLACK|CT_OPAQUE); pdpNormal->Unlock(); } // show pvpViewPort->SwapBuffers(); } } void TeleportPlayer(int iPosition) { CTString strCommand; strCommand.PrintF( "cht_iGoToMarker = %d;", iPosition); _pShell->Execute(strCommand); } CTextureObject _toStarField; static FLOAT _fLastVolume = 1.0f; void RenderStarfield(CDrawPort *pdp, FLOAT fStrength) { CTextureData *ptd = (CTextureData *)_toStarField.GetData(); // skip if no texture if(ptd==NULL) return; PIX pixSizeI = pdp->GetWidth(); PIX pixSizeJ = pdp->GetHeight(); FLOAT fStretch = pixSizeI/640.0f; fStretch*=FLOAT(ptd->GetPixWidth())/ptd->GetWidth(); PIXaabbox2D boxScreen(PIX2D(0,0), PIX2D(pixSizeI, pixSizeJ)); MEXaabbox2D boxTexture(MEX2D(0, 0), MEX2D(pixSizeI/fStretch, pixSizeJ/fStretch)); pdp->PutTexture(&_toStarField, boxScreen, boxTexture, LerpColor(C_BLACK, C_WHITE, fStrength)|CT_OPAQUE); } FLOAT RenderQuitScreen(CDrawPort *pdp, CViewPort *pvp) { CDrawPort dpQuit(pdp, TRUE); CDrawPort dpWide; dpQuit.MakeWideScreen(&dpWide); // redraw the view if (!dpWide.Lock()) { return 0; } dpWide.Fill(C_BLACK|CT_OPAQUE); RenderStarfield(&dpWide, _fLastVolume); FLOAT fVolume = Credits_Render(&dpWide); _fLastVolume = fVolume; dpWide.Unlock(); pvp->SwapBuffers(); return fVolume; } void QuitScreenLoop(void) { Credits_On(3); CSoundObject soMusic; try { _toStarField.SetData_t(CTFILENAME("Textures\\Background\\Night01\\Stars01.tex")); soMusic.Play_t(CTFILENAME("Music\\Credits.mp3"), SOF_NONGAME|SOF_MUSIC|SOF_LOOP); } catch (char *strError) { CPrintF("%s\n", strError); } // while it is still running FOREVER { FLOAT fVolume = RenderQuitScreen(pdp, pvpViewPort); if (fVolume<=0) { return; } // assure we can listen to non-3d sounds soMusic.SetVolume(fVolume, fVolume); _pSound->UpdateSounds(); // while there are any messages in the message queue MSG msg; while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { // if it is not a keyboard or mouse message if(msg.message==WM_LBUTTONDOWN|| msg.message==WM_RBUTTONDOWN|| msg.message==WM_KEYDOWN) { return; } } //_pTimer->Sleep(5); #ifdef SINGLE_THREADED _pTimer->HandleTimerHandlers(); #endif } } int SubMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { (void)hPrevInstance; if( !Init( hInstance, nCmdShow, lpCmdLine )) return FALSE; // initialy, application is running and active, console and menu are off _bRunning = TRUE; _bQuitScreen = TRUE; _pGame->gm_csConsoleState = CS_OFF; _pGame->gm_csComputerState = CS_OFF; // bMenuActive = FALSE; // bMenuRendering = FALSE; // while it is still running while( _bRunning && _fnmModToLoad=="") { // while there are any messages in the message queue MSG msg; while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE)) { // if it is not a mouse message if( !(msg.message>=WM_MOUSEFIRST && msg.message<=WM_MOUSELAST) ) { // if not system key messages if( !(msg.message==WM_KEYDOWN && msg.wParam==VK_F10 ||msg.message==WM_SYSKEYDOWN)) { // dispatch it TranslateMessage(&msg); DispatchMessage(&msg); } } // system commands (also send by the application itself) #ifdef PLATFORM_WIN32 if( msg.message==WM_SYSCOMMAND) { switch( msg.wParam & ~0x0F) { // if should minimize case SC_MINIMIZE: if( _bWindowChanging) break; _bWindowChanging = TRUE; _bReconsiderInput = TRUE; // if allowed, not already paused and only in single player game mode if( sam_bPauseOnMinimize && !_pNetwork->IsPaused() && _gmRunningGameMode==GM_SINGLE_PLAYER) { // pause game _pNetwork->TogglePause(); } // if in full screen if( sam_bFullScreenActive) { // reset display mode and minimize window _pGfx->ResetDisplayMode(); ShowWindow(_hwndMain, SW_MINIMIZE); // if not in full screen } else { // just minimize the window ShowWindow(_hwndMain, SW_MINIMIZE); } break; // if should restore case SC_RESTORE: if( _bWindowChanging) break; _bWindowChanging = TRUE; _bReconsiderInput = TRUE; // if in full screen if( sam_bFullScreenActive) { ShowWindow(_hwndMain, SW_SHOWNORMAL); // set the display mode once again StartNewMode( (GfxAPIType)sam_iGfxAPI, sam_iDisplayAdapter, sam_iScreenSizeI, sam_iScreenSizeJ, (enum DisplayDepth)sam_iDisplayDepth, sam_bFullScreenActive); // if not in full screen } else { // restore window ShowWindow(_hwndMain, SW_SHOWNORMAL); } break; // if should maximize case SC_MAXIMIZE: if( _bWindowChanging) break; _bWindowChanging = TRUE; _bReconsiderInput = TRUE; // go to full screen StartNewMode( (GfxAPIType)sam_iGfxAPI, sam_iDisplayAdapter, sam_iScreenSizeI, sam_iScreenSizeJ, (enum DisplayDepth)sam_iDisplayDepth, TRUE); ShowWindow( _hwndMain, SW_SHOWNORMAL); break; } } #endif // toggle full-screen on alt-enter if( msg.message==WM_SYSKEYDOWN && msg.wParam==VK_RETURN && !IsIconic(_hwndMain)) { // !!! FIXME: This can be more efficient under Linux with // !!! FIXME: SDL_WM_ToggleFullScreen(), since the GL context is just // !!! FIXME: reused there... --ryan. StartNewMode( (GfxAPIType)sam_iGfxAPI, sam_iDisplayAdapter, sam_iScreenSizeI, sam_iScreenSizeJ, (enum DisplayDepth)sam_iDisplayDepth, !sam_bFullScreenActive); if (_pInput != NULL) // rcg02042003 hack for SDL vs. Win32. _pInput->ClearRelativeMouseMotion(); } // if application should stop if( msg.message==WM_QUIT || msg.message==WM_CLOSE) { // stop running _bRunning = FALSE; _bQuitScreen = FALSE; } #ifdef PLATFORM_WIN32 // if application is deactivated or minimized if( (msg.message==WM_ACTIVATE && (LOWORD(msg.wParam)==WA_INACTIVE || HIWORD(msg.wParam))) || msg.message==WM_CANCELMODE || msg.message==WM_KILLFOCUS || (msg.message==WM_ACTIVATEAPP && !msg.wParam)) { // if application is running and in full screen mode if( !_bWindowChanging && _bRunning) { // minimize if in full screen if( sam_bFullScreenActive) PostMessage(NULL, WM_SYSCOMMAND, SC_MINIMIZE, 0); // just disable input if not in full screen else _pInput->DisableInput(); } } // if application is activated or minimized else if( (msg.message==WM_ACTIVATE && (LOWORD(msg.wParam)==WA_ACTIVE || LOWORD(msg.wParam)==WA_CLICKACTIVE)) || msg.message==WM_SETFOCUS || (msg.message==WM_ACTIVATEAPP && msg.wParam)) { // enable input back again if needed _bReconsiderInput = TRUE; } #endif if (msg.message==WM_KEYDOWN && msg.wParam==VK_ESCAPE && (_gmRunningGameMode==GM_DEMO || _gmRunningGameMode==GM_INTRO)) { _pGame->StopGame(); _gmRunningGameMode=GM_NONE; } if (_pGame->gm_csConsoleState==CS_TALK && msg.message==WM_KEYDOWN && msg.wParam==VK_ESCAPE) { if (_pInput != NULL) // rcg02042003 hack for SDL vs. Win32. _pInput->ClearRelativeMouseMotion(); _pGame->gm_csConsoleState = CS_OFF; msg.message=WM_NULL; } BOOL bMenuForced = (_gmRunningGameMode==GM_NONE && (_pGame->gm_csConsoleState==CS_OFF || _pGame->gm_csConsoleState==CS_TURNINGOFF)); BOOL bMenuToggle = (msg.message==WM_KEYDOWN && msg.wParam==VK_ESCAPE && (_pGame->gm_csComputerState==CS_OFF || _pGame->gm_csComputerState==CS_ONINBACKGROUND)); if( !bMenuActive) { if( bMenuForced || bMenuToggle) { // if console is active if( _pGame->gm_csConsoleState==CS_ON || _pGame->gm_csConsoleState==CS_TURNINGON) { // deactivate it _pGame->gm_csConsoleState = CS_TURNINGOFF; _iAddonExecState = 0; } // delete key down message so menu would not exit because of it msg.message=WM_NULL; // start menu StartMenus(); } } else { if (bMenuForced && bMenuToggle && pgmCurrentMenu->gm_pgmParentMenu == NULL) { // delete key down message so menu would not exit because of it msg.message=WM_NULL; } } // if neither menu nor console is running if (!bMenuActive && (_pGame->gm_csConsoleState==CS_OFF || _pGame->gm_csConsoleState==CS_TURNINGOFF)) { // if current menu is not root if (!IsMenusInRoot()) { // start current menu StartMenus(); } } if (sam_bMenuSave) { sam_bMenuSave = FALSE; StartMenus("save"); } if (sam_bMenuLoad) { sam_bMenuLoad = FALSE; StartMenus("load"); } if (sam_bMenuControls) { sam_bMenuControls = FALSE; StartMenus("controls"); } if (sam_bMenuHiScore) { sam_bMenuHiScore = FALSE; StartMenus("hiscore"); } // interpret console key presses if (_iAddonExecState==0) { if (msg.message==WM_KEYDOWN) { _pGame->ConsoleKeyDown(msg); if (_pGame->gm_csConsoleState!=CS_ON) { _pGame->ComputerKeyDown(msg); } } else if (msg.message==WM_KEYUP) { // special handler for talk (not to invoke return key bind) if( msg.wParam==VK_RETURN && _pGame->gm_csConsoleState==CS_TALK) { if (_pInput != NULL) // rcg02042003 hack for SDL vs. Win32. _pInput->ClearRelativeMouseMotion(); _pGame->gm_csConsoleState = CS_OFF; } } else if (msg.message==WM_CHAR) { _pGame->ConsoleChar(msg); } if (msg.message==WM_LBUTTONDOWN ||msg.message==WM_RBUTTONDOWN ||msg.message==WM_LBUTTONDBLCLK ||msg.message==WM_RBUTTONDBLCLK ||msg.message==WM_LBUTTONUP ||msg.message==WM_RBUTTONUP) { if (_pGame->gm_csConsoleState!=CS_ON) { _pGame->ComputerKeyDown(msg); } } } // if menu is active and no input on if( bMenuActive && !_pInput->IsInputEnabled()) { // pass keyboard/mouse messages to menu if(msg.message==WM_KEYDOWN) { MenuOnKeyDown( msg.wParam); } else if (msg.message==WM_LBUTTONDOWN || msg.message==WM_LBUTTONDBLCLK) { MenuOnKeyDown(VK_LBUTTON); } else if (msg.message==WM_RBUTTONDOWN || msg.message==WM_RBUTTONDBLCLK) { MenuOnKeyDown(VK_RBUTTON); } else if (msg.message==WM_MOUSEMOVE) { MenuOnMouseMove(LOWORD(msg.lParam), HIWORD(msg.lParam)); #ifndef WM_MOUSEWHEEL #define WM_MOUSEWHEEL 0x020A #endif } else if (msg.message==WM_MOUSEWHEEL) { SWORD swDir = SWORD(UWORD(HIWORD(msg.wParam))); if (swDir>0) { MenuOnKeyDown(11); } else if (swDir<0) { MenuOnKeyDown(10); } } else if (msg.message==WM_CHAR) { MenuOnChar(msg); } } // if toggling console BOOL bConsoleKey = sam_bToggleConsole || msg.message==WM_KEYDOWN && // !!! FIXME: rcg11162001 This sucks. #ifdef PLATFORM_UNIX (msg.wParam == SDLK_BACKQUOTE #else (MapVirtualKey(msg.wParam, 0)==41 // scan code for '~' #endif || msg.wParam==VK_F1 || (msg.wParam==VK_ESCAPE && _iAddonExecState==3)); if(bConsoleKey && !_bDefiningKey) { sam_bToggleConsole = FALSE; if( _iAddonExecState==3) _iAddonExecState = 0; // if it is up, or pulling up if( _pGame->gm_csConsoleState==CS_OFF || _pGame->gm_csConsoleState==CS_TURNINGOFF) { // start it moving down and disable menu _pGame->gm_csConsoleState = CS_TURNINGON; // stop all IFeel effects IFeel_StopEffect(NULL); if( bMenuActive) { StopMenus(FALSE); } // if it is down, or dropping down } else if( _pGame->gm_csConsoleState==CS_ON || _pGame->gm_csConsoleState==CS_TURNINGON) { // start it moving up _pGame->gm_csConsoleState = CS_TURNINGOFF; } } if (_pShell->GetINDEX("con_bTalk") && _pGame->gm_csConsoleState==CS_OFF) { _pShell->SetINDEX("con_bTalk", FALSE); _pGame->gm_csConsoleState = CS_TALK; } // if pause pressed if (msg.message==WM_KEYDOWN && msg.wParam==VK_PAUSE) { // toggle pause _pNetwork->TogglePause(); } #ifdef PLATFORM_WIN32 // if command sent from external application if (msg.message==WM_COMMAND) { // if teleport player if (msg.wParam==1001) { // teleport player TeleportPlayer(msg.lParam); // restore PostMessage(NULL, WM_SYSCOMMAND, SC_RESTORE, 0); } } #endif // if demo is playing if (_gmRunningGameMode==GM_DEMO || _gmRunningGameMode==GM_INTRO ) { // check if escape is pressed BOOL bEscape = (msg.message==WM_KEYDOWN && msg.wParam==VK_ESCAPE); // check if console-invoke key is pressed BOOL bTilde = (msg.message==WM_KEYDOWN && (msg.wParam==VK_F1 || // !!! FIXME: ugly. #ifdef PLATFORM_UNIX msg.wParam == SDLK_BACKQUOTE #else MapVirtualKey(msg.wParam, 0)==41 // scan code for '~' #endif )); // check if any key is pressed BOOL bAnyKey = ( (msg.message==WM_KEYDOWN && (msg.wParam==VK_SPACE || msg.wParam==VK_RETURN))|| msg.message==WM_LBUTTONDOWN||msg.message==WM_RBUTTONDOWN); // if escape is pressed if (bEscape) { // stop demo _pGame->StopGame(); _bInAutoPlayLoop = FALSE; _gmRunningGameMode = GM_NONE; // if any other key is pressed except console invoking } else if (bAnyKey && !bTilde) { // if not in menu or in console if (!bMenuActive && !bMenuRendering && _pGame->gm_csConsoleState==CS_OFF) { // skip to next demo _pGame->StopGame(); _gmRunningGameMode = GM_NONE; StartNextDemo(); } } } } // loop while there are messages // when all messages are removed, window has surely changed _bWindowChanging = FALSE; // get real cursor position if( _pGame->gm_csComputerState!=CS_OFF && _pGame->gm_csComputerState!=CS_ONINBACKGROUND) { POINT pt; ::GetCursorPos(&pt); ::ScreenToClient(_hwndMain, &pt); _pGame->ComputerMouseMove(pt.x, pt.y); } // if addon is to be executed if (_iAddonExecState==1) { // print header and start console CPrintF(TRANS("---- Executing addon: '%s'\n"), (const char*)_fnmAddonToExec); sam_bToggleConsole = TRUE; _iAddonExecState = 2; // if addon is ready for execution } else if (_iAddonExecState==2 && _pGame->gm_csConsoleState == CS_ON) { // execute it CTString strCmd; strCmd.PrintF("include \"%s\"", (const char*)_fnmAddonToExec); _pShell->Execute(strCmd); CPrintF(TRANS("Addon done, press Escape to close console\n")); _iAddonExecState = 3; } // automaticaly manage input enable/disable toggling UpdateInputEnabledState(); // automaticaly manage pause toggling UpdatePauseState(); // notify game whether menu is active _pGame->gm_bMenuOn = bMenuActive; // do the main game loop and render screen DoGame(); // limit current frame rate if neeeded LimitFrameRate(); } // end of main application loop _pInput->DisableInput(); _pGame->StopGame(); // invoke quit screen if needed if( _bQuitScreen && _fnmModToLoad=="") QuitScreenLoop(); End(); return TRUE; } void CheckModReload(void) { #ifdef PLATFORM_WIN32 if (_fnmModToLoad!="") { #ifndef NDEBUG CTString strDebug = "Debug\\"; #else CTString strDebug = ""; #endif CTString strCommand = _fnmApplicationPath+"Bin\\"+strDebug+"SeriousSam.exe"; //+mod "+_fnmModToLoad.FileName()+"\""; CTString strMod = _fnmModToLoad.FileName(); const char *argv[7]; argv[0] = strCommand; argv[1] = "+game"; argv[2] = strMod; argv[3] = NULL; if (_strModServerJoin!="") { argv[3] = "+connect"; argv[4] = _strModServerJoin; argv[5] = "+quickjoin"; argv[6] = NULL; } _execv(strCommand, argv); } #else STUBBED("reload ourself?"); #endif } void CheckTeaser(void) { #ifdef PLATFORM_WIN32 CTFileName fnmTeaser = _fnmApplicationPath+CTString("Bin\\AfterSam.exe"); if (fopen(fnmTeaser, "r")!=NULL) { Sleep(500); _execl(fnmTeaser, "\""+fnmTeaser+"\"", NULL); } #else STUBBED("load teaser"); #endif } void CheckBrowser(void) { if (_strURLToVisit!="") { RunBrowser(_strURLToVisit); } } int CommonMainline( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { int iResult; CTSTREAM_BEGIN { iResult = SubMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow); } CTSTREAM_END; CheckModReload(); CheckTeaser(); CheckBrowser(); return iResult; } #ifdef PLATFORM_WIN32 int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { return(CommonMainline(hInstance, hPrevInstance, lpCmdLine, nCmdShow)); } #else // !!! FIXME: rcg01052002 This should really get dumped to the game's // !!! FIXME: rcg01052002 console so it's in the log file, too. #ifdef BETAEXPIRE static inline void check_beta(void) { bool bail = false; setbuf(stderr, NULL); fprintf(stderr, "\n\n\n"); fprintf(stderr, "*********************************************************\n"); fprintf(stderr, "*********************************************************\n"); fprintf(stderr, "*********************************************************\n"); fprintf(stderr, "*********************************************************\n"); fprintf(stderr, "*********************************************************\n"); if ( time(NULL) > (BETAEXPIRE + 30 * 24 * 60 * 60) ) { fprintf(stderr, "Sorry, but this beta of the game has expired, and will no\n" " longer run. This is to prevent tech support on out-of-date\n" " and prerelease versions of the game. Please go to\n" " http://www.croteam.com/ for information on getting a release\n" " version that does not expire.\n"); bail = true; } else { fprintf(stderr, " Warning: This is a beta version of SERIOUS SAM.\n"); } fprintf(stderr, "*********************************************************\n"); fprintf(stderr, "*********************************************************\n"); fprintf(stderr, "*********************************************************\n"); fprintf(stderr, "*********************************************************\n"); fprintf(stderr, "*********************************************************\n"); fprintf(stderr, "\n\n\n"); if (bail) { _exit(0); } } // check_beta #endif // !!! FIXME: rcg01102002 This should really get dumped to the game's // !!! FIXME: rcg01102002 console so it's in the log file, too. #ifdef PROFILING_ENABLED static inline void warn_profiling(void) { setbuf(stderr, NULL); fprintf(stderr, "\n\n\n"); fprintf(stderr, "*********************************************************\n"); fprintf(stderr, "*********************************************************\n"); fprintf(stderr, "*********************************************************\n"); fprintf(stderr, "*********************************************************\n"); fprintf(stderr, "*********************************************************\n"); fprintf(stderr, " Warning: Profiling is enabled in this binary!\n"); fprintf(stderr, " DO NOT SHIP A BINARY WITH THIS ENABLED!\n"); fprintf(stderr, "*********************************************************\n"); fprintf(stderr, "*********************************************************\n"); fprintf(stderr, "*********************************************************\n"); fprintf(stderr, "*********************************************************\n"); fprintf(stderr, "*********************************************************\n"); fprintf(stderr, "\n\n\n"); } // check_beta #endif int main(int argc, char **argv) { #ifdef BETAEXPIRE // !!! FIXME: This is Unix-centric (at least, non-win32) if put in main(). check_beta(); #endif #ifdef PROFILING_ENABLED // !!! FIXME: This is Unix-centric (at least, non-win32) if put in main(). warn_profiling(); #endif argv0 = argv[0]; CTString cmdLine; for (int i = 1; i < argc; i++) { cmdLine += " \""; cmdLine += argv[i]; cmdLine += "\""; } return(CommonMainline(NULL, NULL, (char *) ((const char *) cmdLine), 0)); } #endif // try to start a new display mode BOOL TryToSetDisplayMode( enum GfxAPIType eGfxAPI, INDEX iAdapter, PIX pixSizeI, PIX pixSizeJ, enum DisplayDepth eColorDepth, BOOL bFullScreenMode) { CDisplayMode dmTmp; dmTmp.dm_ddDepth = eColorDepth; CPrintF( TRANS(" Starting display mode: %dx%dx%s (%s)\n"), pixSizeI, pixSizeJ, (const char *) dmTmp.DepthString(), bFullScreenMode ? TRANS("fullscreen") : TRANS("window")); // mark to start ignoring window size/position messages until settled down _bWindowChanging = TRUE; // destroy canvas if existing _pGame->DisableLoadingHook(); if( pvpViewPort!=NULL) { _pGfx->DestroyWindowCanvas( pvpViewPort); pvpViewPort = NULL; pdpNormal = NULL; } // close the application window CloseMainWindow(); // try to set new display mode BOOL bSuccess; if( bFullScreenMode) { #ifdef SE1_D3D if( eGfxAPI==GAT_D3D) OpenMainWindowFullScreen( pixSizeI, pixSizeJ); #endif // SE1_D3D bSuccess = _pGfx->SetDisplayMode( eGfxAPI, iAdapter, pixSizeI, pixSizeJ, eColorDepth); if( bSuccess && eGfxAPI==GAT_OGL) OpenMainWindowFullScreen( pixSizeI, pixSizeJ); } else { #ifdef SE1_D3D if( eGfxAPI==GAT_D3D) OpenMainWindowNormal( pixSizeI, pixSizeJ); #endif // SE1_D3D bSuccess = _pGfx->ResetDisplayMode( eGfxAPI); if( bSuccess && eGfxAPI==GAT_OGL) OpenMainWindowNormal( pixSizeI, pixSizeJ); #ifdef SE1_D3D if( bSuccess && eGfxAPI==GAT_D3D) ResetMainWindowNormal(); #endif // SE1_D3D } // if new mode was set if( bSuccess) { // create canvas ASSERT( pvpViewPort==NULL); ASSERT( pdpNormal==NULL); _pGfx->CreateWindowCanvas( _hwndMain, &pvpViewPort, &pdpNormal); // erase context of both buffers (for the sake of wide-screen) pdp = pdpNormal; if( pdp!=NULL && pdp->Lock()) { pdp->Fill(C_BLACK|CT_OPAQUE); pdp->Unlock(); pvpViewPort->SwapBuffers(); pdp->Lock(); pdp->Fill(C_BLACK|CT_OPAQUE); pdp->Unlock(); pvpViewPort->SwapBuffers(); } // lets try some wide screen screaming :) const PIX pixYBegAdj = pdp->GetHeight() * 21/24; const PIX pixYEndAdj = pdp->GetHeight() * 3/24; const PIX pixXEnd = pdp->GetWidth(); pdpWideScreen = new CDrawPort( pdp, PIXaabbox2D( PIX2D(0,pixYBegAdj), PIX2D(pixXEnd, pixYEndAdj))); pdpWideScreen->dp_fWideAdjustment = 9.0f / 12.0f; if( sam_bWideScreen) pdp = pdpWideScreen; // initial screen fill and swap, just to get context running BOOL bSuccess = FALSE; if( pdp!=NULL && pdp->Lock()) { pdp->Fill(_pGame->LCDGetColor(C_dGREEN|CT_OPAQUE, "bcg fill")); pdp->Unlock(); pvpViewPort->SwapBuffers(); bSuccess = TRUE; } _pGame->EnableLoadingHook(pdp); // if the mode is not working, or is not accelerated if( !bSuccess || !_pGfx->IsCurrentModeAccelerated()) { // report error CPrintF( TRANS("This mode does not support hardware acceleration.\n")); // destroy canvas if existing if( pvpViewPort!=NULL) { _pGame->DisableLoadingHook(); _pGfx->DestroyWindowCanvas( pvpViewPort); pvpViewPort = NULL; pdpNormal = NULL; } // close the application window CloseMainWindow(); // report failure return FALSE; } // remember new settings sam_bFullScreenActive = bFullScreenMode; sam_iScreenSizeI = pixSizeI; sam_iScreenSizeJ = pixSizeJ; sam_iDisplayDepth = eColorDepth; sam_iDisplayAdapter = iAdapter; sam_iGfxAPI = eGfxAPI; // report success return TRUE; } // if couldn't set new mode else { // close the application window CloseMainWindow(); // report failure return FALSE; } } // list of possible display modes for recovery const INDEX aDefaultModes[][3] = { // color, API, adapter { DD_DEFAULT, GAT_OGL, 0}, { DD_16BIT, GAT_OGL, 0}, { DD_16BIT, GAT_OGL, 1}, // 3dfx Voodoo2 #ifdef SE1_D3D { DD_DEFAULT, GAT_D3D, 0}, { DD_16BIT, GAT_D3D, 0}, { DD_16BIT, GAT_D3D, 1}, #endif // SE1_D3D }; const INDEX ctDefaultModes = ARRAYCOUNT(aDefaultModes); // start new display mode void StartNewMode( enum GfxAPIType eGfxAPI, INDEX iAdapter, PIX pixSizeI, PIX pixSizeJ, enum DisplayDepth eColorDepth, BOOL bFullScreenMode) { CPrintF( TRANS("\n* START NEW DISPLAY MODE ...\n")); // try to set the mode BOOL bSuccess = TryToSetDisplayMode( eGfxAPI, iAdapter, pixSizeI, pixSizeJ, eColorDepth, bFullScreenMode); // if failed if( !bSuccess) { // report failure and reset to default resolution _iDisplayModeChangeFlag = 2; // failure CPrintF( TRANS("Requested display mode could not be set!\n")); pixSizeI = 640; pixSizeJ = 480; bFullScreenMode = TRUE; // try to revert to one of recovery modes for( INDEX iMode=0; iModeGetRealTimeTick(); }