Changeset View
Changeset View
Standalone View
Standalone View
source/main.cpp
Show First 20 Lines • Show All 120 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; | __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; | ||||
__declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 0x00000001; | __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 0x00000001; | ||||
} | } | ||||
#endif | #endif | ||||
#include <chrono> | #include <chrono> | ||||
using namespace std::literals; | |||||
extern CStrW g_UniqueLogPostfix; | extern CStrW g_UniqueLogPostfix; | ||||
// Determines the lifetime of the mainloop | // Determines the lifetime of the mainloop | ||||
enum ShutdownType | enum ShutdownType | ||||
{ | { | ||||
// The application shall continue the main loop. | // The application shall continue the main loop. | ||||
None, | None, | ||||
Show All 12 Lines | |||||
// to avoid redundant and/or recursive resizing, we save the new | // to avoid redundant and/or recursive resizing, we save the new | ||||
// size after VIDEORESIZE messages and only update the video mode | // size after VIDEORESIZE messages and only update the video mode | ||||
// once per frame. | // once per frame. | ||||
// these values are the latest resize message, and reset to 0 once we've | // these values are the latest resize message, and reset to 0 once we've | ||||
// updated the video mode | // updated the video mode | ||||
static int g_ResizedW; | static int g_ResizedW; | ||||
static int g_ResizedH; | static int g_ResizedH; | ||||
static std::chrono::high_resolution_clock::time_point lastFrameTime; | |||||
bool IsQuitRequested() | bool IsQuitRequested() | ||||
{ | { | ||||
return g_Shutdown == ShutdownType::Quit; | return g_Shutdown == ShutdownType::Quit; | ||||
} | } | ||||
void QuitEngine() | void QuitEngine() | ||||
{ | { | ||||
g_Shutdown = ShutdownType::Quit; | g_Shutdown = ShutdownType::Quit; | ||||
} | } | ||||
void RestartEngine() | void RestartEngine() | ||||
{ | { | ||||
g_Shutdown = ShutdownType::Restart; | g_Shutdown = ShutdownType::Restart; | ||||
} | } | ||||
void StartAtlas() | void StartAtlas() | ||||
{ | { | ||||
g_Shutdown = ShutdownType::RestartAsAtlas; | g_Shutdown = ShutdownType::RestartAsAtlas; | ||||
} | } | ||||
namespace | |||||
{ | |||||
// main app message handler | // main app message handler | ||||
static InReaction MainInputHandler(const SDL_Event_* ev) | InReaction MainInputHandler(const SDL_Event_* ev) | ||||
{ | { | ||||
switch(ev->ev.type) | switch(ev->ev.type) | ||||
{ | { | ||||
case SDL_WINDOWEVENT: | case SDL_WINDOWEVENT: | ||||
switch(ev->ev.window.event) | switch(ev->ev.window.event) | ||||
{ | { | ||||
case SDL_WINDOWEVENT_RESIZED: | case SDL_WINDOWEVENT_RESIZED: | ||||
g_ResizedW = ev->ev.window.data1; | g_ResizedW = ev->ev.window.data1; | ||||
▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | case SDL_HOTKEYPRESS: | ||||
break; | break; | ||||
} | } | ||||
return IN_PASS; | return IN_PASS; | ||||
} | } | ||||
// dispatch all pending events to the various receivers. | // dispatch all pending events to the various receivers. | ||||
static void PumpEvents() | void PumpEvents() | ||||
{ | { | ||||
ScriptRequest rq(g_GUI->GetScriptInterface()); | ScriptRequest rq(g_GUI->GetScriptInterface()); | ||||
PROFILE3("dispatch events"); | PROFILE3("dispatch events"); | ||||
SDL_Event_ ev; | SDL_Event_ ev; | ||||
while (in_poll_event(&ev)) | while (in_poll_event(&ev)) | ||||
{ | { | ||||
Show All 10 Lines | void PumpEvents() | ||||
g_TouchInput.Frame(); | g_TouchInput.Frame(); | ||||
} | } | ||||
/** | /** | ||||
* Optionally throttle the render frequency in order to | * Optionally throttle the render frequency in order to | ||||
* prevent 100% workload of the currently used CPU core. | * prevent 100% workload of the currently used CPU core. | ||||
*/ | */ | ||||
inline static void LimitFPS() | void LimitFPS(const std::chrono::steady_clock::time_point& frameStart) | ||||
{ | { | ||||
if (g_VideoMode.IsVSyncEnabled()) | if (g_VideoMode.IsVSyncEnabled()) | ||||
return; | return; | ||||
double fpsLimit = 0.0; | double fpsLimit = 0.0; | ||||
CFG_GET_VAL(g_Game && g_Game->IsGameStarted() ? "adaptivefps.session" : "adaptivefps.menu", fpsLimit); | CFG_GET_VAL(g_Game && g_Game->IsGameStarted() ? "adaptivefps.session" : "adaptivefps.menu", fpsLimit); | ||||
// Keep in sync with options.json | // Keep in sync with options.json | ||||
if (fpsLimit < 20.0 || fpsLimit >= 360.0) | if (fpsLimit < 20.0 || fpsLimit >= 360.0) | ||||
return; | return; | ||||
double wait = 1000.0 / fpsLimit - | const auto earliestFrameStop = frameStart + 1.0s / fpsLimit; | ||||
std::chrono::duration_cast<std::chrono::microseconds>( | |||||
std::chrono::high_resolution_clock::now() - lastFrameTime).count() / 1000.0; | |||||
if (wait > 0.0) | std::this_thread::sleep_until(earliestFrameStop); | ||||
SDL_Delay(wait); | |||||
lastFrameTime = std::chrono::high_resolution_clock::now(); | |||||
} | } | ||||
static int ProgressiveLoad() | int ProgressiveLoad() | ||||
{ | { | ||||
PROFILE3("progressive load"); | PROFILE3("progressive load"); | ||||
wchar_t description[100]; | wchar_t description[100]; | ||||
int progress_percent; | int progress_percent; | ||||
try | try | ||||
{ | { | ||||
Status ret = LDR_ProgressiveLoad(10e-3, description, ARRAY_SIZE(description), &progress_percent); | Status ret = LDR_ProgressiveLoad(10e-3, description, ARRAY_SIZE(description), &progress_percent); | ||||
Show All 28 Lines | catch (PSERROR_Game_World_MapLoadFailed& e) | ||||
// (delete game data, switch GUI page, show error, etc.) | // (delete game data, switch GUI page, show error, etc.) | ||||
CancelLoad(CStr(e.what()).FromUTF8()); | CancelLoad(CStr(e.what()).FromUTF8()); | ||||
} | } | ||||
g_GUI->DisplayLoadProgress(progress_percent, description); | g_GUI->DisplayLoadProgress(progress_percent, description); | ||||
return 0; | return 0; | ||||
} | } | ||||
void RendererIncrementalLoad() | |||||
static void RendererIncrementalLoad() | |||||
{ | { | ||||
PROFILE3("renderer incremental load"); | PROFILE3("renderer incremental load"); | ||||
const double maxTime = 0.1f; | const double maxTime = 0.1f; | ||||
double startTime = timer_Time(); | double startTime = timer_Time(); | ||||
bool more; | bool more; | ||||
do { | do { | ||||
more = g_Renderer.GetTextureManager().MakeProgress(); | more = g_Renderer.GetTextureManager().MakeProgress(); | ||||
} | } | ||||
while (more && timer_Time() - startTime < maxTime); | while (more && timer_Time() - startTime < maxTime); | ||||
} | } | ||||
static void Frame(RL::Interface* rlInterface) | void Frame(RL::Interface* rlInterface) | ||||
{ | { | ||||
const std::chrono::steady_clock::time_point chronoTime{std::chrono::steady_clock::now()}; | |||||
vladislavbelov: It implicitly means that there is no work outside `Frame`. It'd be good to somehow guarantee… | |||||
g_Profiler2.RecordFrameStart(); | g_Profiler2.RecordFrameStart(); | ||||
PROFILE2("frame"); | PROFILE2("frame"); | ||||
g_Profiler2.IncrementFrameNumber(); | g_Profiler2.IncrementFrameNumber(); | ||||
PROFILE2_ATTR("%d", g_Profiler2.GetFrameNumber()); | PROFILE2_ATTR("%d", g_Profiler2.GetFrameNumber()); | ||||
// get elapsed time | // get elapsed time | ||||
const double time = timer_Time(); | const double time = timer_Time(); | ||||
g_frequencyFilter->Update(time); | g_frequencyFilter->Update(time); | ||||
▲ Show 20 Lines • Show All 73 Lines • ▼ Show 20 Lines | #endif | ||||
if (g_SoundManager) | if (g_SoundManager) | ||||
g_SoundManager->IdleTask(); | g_SoundManager->IdleTask(); | ||||
g_Renderer.RenderFrame(true); | g_Renderer.RenderFrame(true); | ||||
g_Profiler.Frame(); | g_Profiler.Frame(); | ||||
LimitFPS(); | LimitFPS(chronoTime); | ||||
} | } | ||||
static void NonVisualFrame() | void NonVisualFrame() | ||||
{ | { | ||||
g_Profiler2.RecordFrameStart(); | g_Profiler2.RecordFrameStart(); | ||||
PROFILE2("frame"); | PROFILE2("frame"); | ||||
g_Profiler2.IncrementFrameNumber(); | g_Profiler2.IncrementFrameNumber(); | ||||
PROFILE2_ATTR("%d", g_Profiler2.GetFrameNumber()); | PROFILE2_ATTR("%d", g_Profiler2.GetFrameNumber()); | ||||
if (g_NetClient) | if (g_NetClient) | ||||
g_NetClient->Poll(); | g_NetClient->Poll(); | ||||
static u32 turn = 0; | static u32 turn = 0; | ||||
if (g_Game && g_Game->IsGameStarted() && g_Game->GetTurnManager()) | if (g_Game && g_Game->IsGameStarted() && g_Game->GetTurnManager()) | ||||
if (g_Game->GetTurnManager()->Update(DEFAULT_TURN_LENGTH, 1)) | if (g_Game->GetTurnManager()->Update(DEFAULT_TURN_LENGTH, 1)) | ||||
debug_printf("Turn %u (%u)...\n", turn++, DEFAULT_TURN_LENGTH); | debug_printf("Turn %u (%u)...\n", turn++, DEFAULT_TURN_LENGTH); | ||||
g_Profiler.Frame(); | g_Profiler.Frame(); | ||||
if (g_Game->IsGameFinished()) | if (g_Game->IsGameFinished()) | ||||
QuitEngine(); | QuitEngine(); | ||||
} | } | ||||
static void MainControllerInit() | void MainControllerInit() | ||||
{ | { | ||||
// add additional input handlers only needed by this controller: | // add additional input handlers only needed by this controller: | ||||
// must be registered after gui_handler. Should mayhap even be last. | // must be registered after gui_handler. Should mayhap even be last. | ||||
in_add_handler(MainInputHandler); | in_add_handler(MainInputHandler); | ||||
} | } | ||||
static void MainControllerShutdown() | void MainControllerShutdown() | ||||
{ | { | ||||
in_reset_handlers(); | in_reset_handlers(); | ||||
} | } | ||||
static std::optional<RL::Interface> CreateRLInterface(const CmdLineArgs& args) | std::optional<RL::Interface> CreateRLInterface(const CmdLineArgs& args) | ||||
{ | { | ||||
if (!args.Has("rl-interface")) | if (!args.Has("rl-interface")) | ||||
return std::nullopt; | return std::nullopt; | ||||
std::string server_address; | std::string server_address; | ||||
CFG_GET_VAL("rlinterface.address", server_address); | CFG_GET_VAL("rlinterface.address", server_address); | ||||
if (!args.Get("rl-interface").empty()) | if (!args.Get("rl-interface").empty()) | ||||
server_address = args.Get("rl-interface"); | server_address = args.Get("rl-interface"); | ||||
debug_printf("RL interface listening on %s\n", server_address.c_str()); | debug_printf("RL interface listening on %s\n", server_address.c_str()); | ||||
return std::make_optional<RL::Interface>(server_address.c_str()); | return std::make_optional<RL::Interface>(server_address.c_str()); | ||||
} | } | ||||
// moved into a helper function to ensure args is destroyed before | // moved into a helper function to ensure args is destroyed before | ||||
// exit(), which may result in a memory leak. | // exit(), which may result in a memory leak. | ||||
static void RunGameOrAtlas(const PS::span<const char* const> argv) | void RunGameOrAtlas(const PS::span<const char* const> argv) | ||||
{ | { | ||||
const CmdLineArgs args(argv); | const CmdLineArgs args(argv); | ||||
g_CmdLineArgs = args; | g_CmdLineArgs = args; | ||||
if (args.Has("version")) | if (args.Has("version")) | ||||
{ | { | ||||
debug_printf("Pyrogenesis %s\n", engine_version); | debug_printf("Pyrogenesis %s\n", engine_version); | ||||
▲ Show 20 Lines • Show All 203 Lines • ▼ Show 20 Lines | |||||
#else | #else | ||||
if (g_Shutdown == ShutdownType::RestartAsAtlas) | if (g_Shutdown == ShutdownType::RestartAsAtlas) | ||||
ATLAS_RunIfOnCmdLine(args, true); | ATLAS_RunIfOnCmdLine(args, true); | ||||
#endif | #endif | ||||
Threading::TaskManager::Instance().ClearQueue(); | Threading::TaskManager::Instance().ClearQueue(); | ||||
CXeromyces::Terminate(); | CXeromyces::Terminate(); | ||||
} | } | ||||
} // anonymous namespace | |||||
#if OS_ANDROID | #if OS_ANDROID | ||||
// In Android we compile the engine as a shared library, not an executable, | // In Android we compile the engine as a shared library, not an executable, | ||||
// so rename main() to a different symbol that the wrapper library can load | // so rename main() to a different symbol that the wrapper library can load | ||||
#undef main | #undef main | ||||
#define main pyrogenesis_main | #define main pyrogenesis_main | ||||
extern "C" __attribute__((visibility ("default"))) int main(int argc, char* argv[]); | extern "C" __attribute__((visibility ("default"))) int main(int argc, char* argv[]); | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 42 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator
It implicitly means that there is no work outside Frame. It'd be good to somehow guarantee that, at least by a comment.