@ -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 < SDL_Color , 256 > 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 < SDL_Color , 256 > 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