diff --git a/Source/interfac.cpp b/Source/interfac.cpp index a08a9244b..5da1738e3 100644 --- a/Source/interfac.cpp +++ b/Source/interfac.cpp @@ -36,6 +36,10 @@ #include "controls/touch/renderers.h" #endif +#ifdef __DJGPP__ +#define LOAD_ON_MAIN_THREAD +#endif + namespace devilution { namespace { @@ -235,6 +239,64 @@ void DrawCutsceneForeground() RenderPresent(); } +struct { + uint32_t loadStartedAt; + EventHandler prevHandler; + bool skipRendering; + bool done; + uint32_t drawnProgress; + std::array palette; +} ProgressEventHandlerState; + +void InitRendering() +{ + // Blit the background once and then free it. + DrawCutsceneBackground(); + if (RenderDirectlyToOutputSurface && PalSurface != nullptr) { + // Render into all the backbuffers if there are multiple. + const void *initialPixels = PalSurface->pixels; + if (DiabloUiSurface() == PalSurface) + BltFast(nullptr, nullptr); + RenderPresent(); + while (PalSurface->pixels != initialPixels) { + DrawCutsceneBackground(); + if (DiabloUiSurface() == PalSurface) + BltFast(nullptr, nullptr); + RenderPresent(); + } + } + FreeCutsceneBackground(); + + // The loading thread sets `logical_palette`, so we make sure to use + // our own palette for the fade-in. + PaletteFadeIn(8, ProgressEventHandlerState.palette); +} + +void CheckShouldSkipRendering() +{ + if (!ProgressEventHandlerState.skipRendering) return; + const bool shouldSkip = ProgressEventHandlerState.loadStartedAt + *GetOptions().Gameplay.skipLoadingScreenThresholdMs > SDL_GetTicks(); + if (shouldSkip) return; + ProgressEventHandlerState.skipRendering = false; + if (!HeadlessMode) InitRendering(); +} + +bool HandleProgressBarUpdate() +{ + CheckShouldSkipRendering(); + SDL_Event event; + // We use the real `PollEvent` here instead of `FetchMessage` + // to process real events rather than the recorded ones in demo mode. + while (PollEvent(&event) != 0) { + CheckShouldSkipRendering(); + if (event.type != SDL_QUIT) { + HandleMessage(event, SDL_GetModState()); + } + if (ProgressEventHandlerState.done) return false; + } + return true; +} + void DoLoad(interface_mode uMsg) { IncProgress(); @@ -401,6 +463,9 @@ void DoLoad(interface_mode uMsg) LogError("Failed to send WM_ERROR {}", SDL_GetError()); SDL_ClearError(); } +#ifdef LOAD_ON_MAIN_THREAD + HandleProgressBarUpdate(); +#endif return; } @@ -410,48 +475,9 @@ void DoLoad(interface_mode uMsg) LogError("Failed to send WM_DONE {}", SDL_GetError()); SDL_ClearError(); } -} - -struct { - uint32_t loadStartedAt; - EventHandler prevHandler; - bool skipRendering; - bool done; - uint32_t drawnProgress; - std::array palette; -} ProgressEventHandlerState; - -void InitRendering() -{ - // Blit the background once and then free it. - DrawCutsceneBackground(); - if (RenderDirectlyToOutputSurface && PalSurface != nullptr) { - // Render into all the backbuffers if there are multiple. - const void *initialPixels = PalSurface->pixels; - if (DiabloUiSurface() == PalSurface) - BltFast(nullptr, nullptr); - RenderPresent(); - while (PalSurface->pixels != initialPixels) { - DrawCutsceneBackground(); - if (DiabloUiSurface() == PalSurface) - BltFast(nullptr, nullptr); - RenderPresent(); - } - } - FreeCutsceneBackground(); - - // The loading thread sets `logical_palette`, so we make sure to use - // our own palette for the fade-in. - PaletteFadeIn(8, ProgressEventHandlerState.palette); -} - -void CheckShouldSkipRendering() -{ - if (!ProgressEventHandlerState.skipRendering) return; - const bool shouldSkip = ProgressEventHandlerState.loadStartedAt + *GetOptions().Gameplay.skipLoadingScreenThresholdMs > SDL_GetTicks(); - if (shouldSkip) return; - ProgressEventHandlerState.skipRendering = false; - if (!HeadlessMode) InitRendering(); +#ifdef LOAD_ON_MAIN_THREAD + HandleProgressBarUpdate(); +#endif } void ProgressEventHandler(const SDL_Event &event, uint16_t modState) @@ -525,6 +551,9 @@ void ProgressEventHandler(const SDL_Event &event, uint16_t modState) app_fatal("Unknown progress mode"); break; } +#ifdef LOAD_ON_MAIN_THREAD + HandleProgressBarUpdate(); +#endif } } // namespace @@ -578,6 +607,9 @@ void IncProgress(uint32_t steps) LogError("Failed to send WM_PROGRESS {}", SDL_GetError()); SDL_ClearError(); } +#ifdef LOAD_ON_MAIN_THREAD + HandleProgressBarUpdate(); +#endif } } @@ -629,6 +661,11 @@ void ShowProgress(interface_mode uMsg) } // Begin loading +#ifdef LOAD_ON_MAIN_THREAD + const uint32_t start = SDL_GetTicks(); + DoLoad(uMsg); + LogVerbose("Loading finished in {}ms", SDL_GetTicks() - start); +#else static interface_mode loadTarget; loadTarget = uMsg; SdlThread loadThread = SdlThread([]() { @@ -636,28 +673,9 @@ void ShowProgress(interface_mode uMsg) DoLoad(loadTarget); LogVerbose("Load thread finished in {}ms", SDL_GetTicks() - start); }); - - const auto processEvent = [&](const SDL_Event &event) { - CheckShouldSkipRendering(); - if (event.type != SDL_QUIT) { - HandleMessage(event, SDL_GetModState()); - } - if (ProgressEventHandlerState.done) { - loadThread.join(); - return false; - } - return true; - }; - - while (true) { - CheckShouldSkipRendering(); - SDL_Event event; - // We use the real `PollEvent` here instead of `FetchMessage` - // to process real events rather than the recorded ones in demo mode. - while (PollEvent(&event)) { - if (!processEvent(event)) return; - } - } + while (HandleProgressBarUpdate()) { } + loadThread.join(); +#endif } } // namespace devilution