diff --git a/Source/DiabloUI/progress.cpp b/Source/DiabloUI/progress.cpp index 7d5d07d63..51a01302d 100644 --- a/Source/DiabloUI/progress.cpp +++ b/Source/DiabloUI/progress.cpp @@ -1,3 +1,5 @@ +#include + #include "DiabloUI/art_draw.h" #include "DiabloUI/button.h" #include "DiabloUI/diabloui.h" @@ -27,11 +29,15 @@ void DialogActionCancel() endMenu = true; } -void ProgressLoad() +void ProgressLoadBackground() { LoadBackgroundArt("ui_art\\black.pcx"); ArtPopupSm = LoadPcxAsset("ui_art\\spopup.pcx"); ArtProgBG = LoadPcxAsset("ui_art\\prog_bg.pcx"); +} + +void ProgressLoadForeground() +{ ProgFil = LoadPcxAsset("ui_art\\prog_fil.pcx"); const Point uiPosition = GetUIRectangle().position; @@ -39,25 +45,40 @@ void ProgressLoad() vecProgress.push_back(std::make_unique(_("Cancel"), &DialogActionCancel, rect3)); } -void ProgressFree() +void ProgressFreeBackground() { ArtBackground = std::nullopt; ArtPopupSm = std::nullopt; ArtProgBG = std::nullopt; +} + +void ProgressFreeForeground() +{ + vecProgress.clear(); ProgFil = std::nullopt; } -void ProgressRender(BYTE progress) +Point GetPosition() +{ + return { GetCenterOffset(280), GetCenterOffset(144, gnScreenHeight) }; +} + +void ProgressRenderBackground() { SDL_FillRect(DiabloUiSurface(), nullptr, 0x000000); const Surface &out = Surface(DiabloUiSurface()); RenderPcxSprite(out, PcxSpriteSheet { *ArtBackground }.sprite(0), { 0, 0 }); - Point position = { GetCenterOffset(280), GetCenterOffset(144, gnScreenHeight) }; - + const Point position = GetPosition(); RenderPcxSprite(out, PcxSprite { *ArtPopupSm }, position); RenderPcxSprite(out, PcxSprite { *ArtProgBG }, { GetCenterOffset(227), position.y + 52 }); +} + +void ProgressRenderForeground(int progress) +{ + const Surface &out = Surface(DiabloUiSurface()); + const Point position = GetPosition(); if (progress != 0) { const int x = GetCenterOffset(227); const int w = 227 * progress / 100; @@ -71,16 +92,29 @@ void ProgressRender(BYTE progress) bool UiProgressDialog(int (*fnfunc)()) { - ProgressLoad(); SetFadeLevel(256); + // Blit the background once and then free it. + ProgressLoadBackground(); + ProgressRenderBackground(); + if (RenderDirectlyToOutputSurface && IsDoubleBuffered()) { + // Blit twice for triple buffering. + for (unsigned i = 0; i < 2; ++i) { + UiFadeIn(); + ProgressRenderBackground(); + } + } + ProgressFreeBackground(); + + ProgressLoadForeground(); + endMenu = false; int progress = 0; SDL_Event event; while (!endMenu && progress < 100) { progress = fnfunc(); - ProgressRender(progress); + ProgressRenderForeground(progress); UiRenderItems(vecProgress); DrawMouse(); UiFadeIn(); @@ -113,7 +147,7 @@ bool UiProgressDialog(int (*fnfunc)()) UiHandleEvents(&event); } } - ProgressFree(); + ProgressFreeForeground(); return progress == 100; } diff --git a/Source/interfac.cpp b/Source/interfac.cpp index 2c98b9c81..d084057ff 100644 --- a/Source/interfac.cpp +++ b/Source/interfac.cpp @@ -6,6 +6,8 @@ #include +#include + #include "control.h" #include "dx.h" #include "engine.h" @@ -40,12 +42,6 @@ const int BarPos[3][2] = { { 53, 37 }, { 53, 421 }, { 53, 37 } }; std::optional ArtCutsceneWidescreen; -void FreeInterface() -{ - sgpBackCel = std::nullopt; - ArtCutsceneWidescreen = std::nullopt; -} - Cutscenes PickCutscene(interface_mode uMsg) { switch (uMsg) { @@ -97,7 +93,7 @@ Cutscenes PickCutscene(interface_mode uMsg) } } -void InitCutscene(interface_mode uMsg) +void LoadCutsceneBackground(interface_mode uMsg) { const char *celPath; const char *palPath; @@ -170,7 +166,13 @@ void InitCutscene(interface_mode uMsg) sgdwProgress = 0; } -void DrawCutscene() +void FreeCutsceneBackground() +{ + sgpBackCel = std::nullopt; + ArtCutsceneWidescreen = std::nullopt; +} + +void DrawCutsceneBackground() { const Rectangle &uiRectangle = GetUIRectangle(); const Surface &out = GlobalBackBuffer(); @@ -179,7 +181,12 @@ void DrawCutscene() RenderPcxSprite(out, sprite, { uiRectangle.position.x - (sprite.width() - uiRectangle.size.width) / 2, uiRectangle.position.y }); } CelDrawTo(out, { uiRectangle.position.x, 480 - 1 + uiRectangle.position.y }, *sgpBackCel, 0); +} +void DrawCutsceneForeground() +{ + const Rectangle &uiRectangle = GetUIRectangle(); + const Surface &out = GlobalBackBuffer(); constexpr int ProgressHeight = 22; SDL_Rect rect = MakeSdlRect( out.region.x + BarPos[progress_id][0] + uiRectangle.position.x, @@ -188,7 +195,8 @@ void DrawCutscene() ProgressHeight); SDL_FillRect(out.surface, &rect, BarColor[progress_id]); - BltFast(&rect, &rect); + if (DiabloUiSurface() == PalSurface) + BltFast(&rect, &rect); RenderPresent(); } @@ -212,8 +220,7 @@ bool IncProgress() sgdwProgress += 23; if (sgdwProgress > 534) sgdwProgress = 534; - if (sgpBackCel) - DrawCutscene(); + DrawCutsceneForeground(); return sgdwProgress >= 534; } @@ -230,9 +237,21 @@ void ShowProgress(interface_mode uMsg) interface_msg_pump(); ClearScreenBuffer(); scrollrt_draw_game_screen(); - InitCutscene(uMsg); BlackPalette(); - DrawCutscene(); + + // Blit the background once and then free it. + LoadCutsceneBackground(uMsg); + DrawCutsceneBackground(); + if (RenderDirectlyToOutputSurface && IsDoubleBuffered()) { + // Blit twice for triple buffering. + for (unsigned i = 0; i < 2; ++i) { + if (DiabloUiSurface() == PalSurface) + BltFast(nullptr, nullptr); + RenderPresent(); + DrawCutsceneBackground(); + } + } + FreeCutsceneBackground(); if (IsHardwareCursor()) SetHardwareCursorVisible(false); @@ -390,7 +409,6 @@ void ShowProgress(interface_mode uMsg) assert(ghMainWnd); PaletteFadeOut(8); - FreeInterface(); saveProc = SetWindowProc(saveProc); assert(saveProc == DisableInputWndProc); diff --git a/Source/utils/display.cpp b/Source/utils/display.cpp index bdc87e730..1420d0dfd 100644 --- a/Source/utils/display.cpp +++ b/Source/utils/display.cpp @@ -473,6 +473,15 @@ SDL_Surface *GetOutputSurface() #endif } +bool IsDoubleBuffered() +{ +#ifdef USE_SDL1 + return (GetOutputSurface()->flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF; +#else + return true; +#endif +} + bool OutputRequiresScaling() { #ifdef USE_SDL1 diff --git a/Source/utils/display.h b/Source/utils/display.h index 857cdb1ac..eb8b52acb 100644 --- a/Source/utils/display.h +++ b/Source/utils/display.h @@ -40,6 +40,8 @@ bool IsFullScreen(); // SDL2, upscale: Renderer texture surface. SDL_Surface *GetOutputSurface(); +bool IsDoubleBuffered(); + // Whether the output surface requires software scaling. // Always returns false on SDL2. bool OutputRequiresScaling();