#include "munga.h" #pragma hdrstop #include "appmgr.h" HWND ghWnd = 0; // per-frame observer slot (see RunMissions); the game layer registers // the single-player local-console marshal here void (*gPerFrameHook)() = NULL; // an in-process console owns the launch (hosted network races) Logical gConsoleMarshalsLaunch = False; // losing the console mid-mission ends it (lobby-member races) Logical gConsoleLossEndsMission = False; ApplicationManager* ApplicationManager::CurrentAppManager = NULL; ApplicationManager::ApplicationManager(HINSTANCE hInstance, HWND hWnd, Scalar frame_rate) : Node(ApplicationManagerClassID), runningApplications(this) { frameRate = frame_rate; frameDuration = 1.0f/frameRate; mHInstance = hInstance; ghWnd = hWnd; ApplicationManager::CurrentAppManager = this; Check_Fpu(); } ApplicationManager::~ApplicationManager() { } void ApplicationManager::StartApplication(Application *new_app) { Check(this); Check(new_app); runningApplications.Add(new_app); application = new_app; new_app->Initialize(); } // //############################################################################# // RunMissions //############################################################################# // void ApplicationManager::RunMissions() { Check(this); int backgroundTasksRun = 0; int foregroundTasksRun = 0; Time beginFrameTimestamp, lastFrameTimestamp; MSG msg; SChainIteratorOf current_application(runningApplications); SChainOf endedApplications(NULL); SChainIteratorOf endingApplication(endedApplications); Start_Of_Frame: backgroundTasksRun = 0; foregroundTasksRun = 0; beginFrameTimestamp = Now(); current_application.First(); lastFrameTimestamp = Now(); Time end_of_frame = Now(); end_of_frame += frameDuration; #if defined(LAB_ONLY) int bad_count = 0; #endif // //---------------------------------- // Run all relevant foreground loops //---------------------------------- // Time startForeground = Now(); while ((application = current_application.ReadAndNext()) != NULL) { Check(application); foregroundTasksRun++; //------------------------------------------------------------------ // Give the per-frame observer a slice while 'application' is live // (the loop condition NULLs the global on exit). The single-player // local-console marshal hangs off this; NULL when unregistered. //------------------------------------------------------------------ if (gPerFrameHook != NULL) { (*gPerFrameHook)(); } if (!application->ExecuteForeground(end_of_frame, frameDuration)) { if (!application->Shutdown(current_application.GetSize())) { endedApplications.Add(application); if (current_application.GetCurrent() == NULL) { current_application.Last(); } else { current_application.Previous(); } current_application.Remove(); } } } Time endForeground = Now(); // //----------------------------------------------------------------------- // Check the Windows message queue for messages to be processed //----------------------------------------------------------------------- // //InvalidateRect(ghWnd, NULL, false); if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) { endingApplication.First(); while (application = endingApplication.ReadAndNext()) { application->Terminate(); delete application; } return; } TranslateMessage(&msg); DispatchMessage(&msg); } // //----------------------------------------------------------------------- // Run all relevant background loops until it is time for the next frame. // If no applications remain, exit the whole loop //----------------------------------------------------------------------- // current_application.First(); application = current_application.GetCurrent(); if (!application) { endingApplication.First(); while (application = endingApplication.ReadAndNext()) { application->Terminate(); delete application; } return; } do { while (application->GetNetworkManager()->RoutePacket()) ; current_application.Next(); application = current_application.GetCurrent(); } while (application); current_application.First(); application = current_application.GetCurrent(); if (!application) { endingApplication.First(); while (application = endingApplication.ReadAndNext()) { application->Terminate(); delete application; } return; } // //------------------------------------------------------------------ // Give each application a chance to do at least one background task //------------------------------------------------------------------ // Time startBackground = Now(); Background_Loop: do { Check(application); application->ExecuteBackgroundTask(); backgroundTasksRun++; // // Move to the next application // current_application.Next(); application = current_application.GetCurrent(); } while (application); // //--------------------------------------------------------------------- // If time remains before the next frame is due, do another pass on the // background tasks //--------------------------------------------------------------------- // Time t2 = Now(); Time lateTime = Now(); lateTime += 15L; current_application.First(); application = current_application.GetCurrent(); if (t2 < end_of_frame) { #if defined(LAB_ONLY) if (end_of_frame - t2 > 0.1f) { DEBUG_STREAM << t2 << ',' << end_of_frame << endl << std::flush; if (++bad_count == 1000) { Fail("End-of-frame cannot be correctly calculated!"); } } #endif goto Background_Loop; } Time endBackground = Now(); //char str[256]; //Scalar lastFrameLength = Now() - beginFrameTimestamp; //sprintf(str, "RPL4 - %.2f FPS", 1.0f / lastFrameLength); //SetWindowTextA(ghWnd, str); goto Start_Of_Frame; }