diff --git a/Source/DiabloUI/credits.cpp b/Source/DiabloUI/credits.cpp index 2980dd286..d906939c8 100644 --- a/Source/DiabloUI/credits.cpp +++ b/Source/DiabloUI/credits.cpp @@ -10,6 +10,8 @@ #include "control.h" #include "controls/input.h" #include "controls/menu_controls.h" +#include "engine/load_pcx.hpp" +#include "engine/render/pcx_render.hpp" #include "engine/render/text_render.hpp" #include "hwcursor.hpp" #include "utils/display.h" @@ -63,8 +65,8 @@ public: ~CreditsRenderer() { - ArtBackgroundWidescreen.Unload(); - ArtBackground.Unload(); + ArtBackgroundWidescreen = std::nullopt; + ArtBackground = std::nullopt; } void Render(); @@ -95,8 +97,9 @@ void CreditsRenderer::Render() SDL_FillRect(DiabloUiSurface(), nullptr, 0x000000); const Point uiPosition = GetUIRectangle().position; - DrawArt(uiPosition - Displacement { 320, 0 }, &ArtBackgroundWidescreen); - DrawArt(uiPosition, &ArtBackground); + if (ArtBackgroundWidescreen) + RenderPcxSprite(Surface(DiabloUiSurface()), PcxSprite { *ArtBackgroundWidescreen }, uiPosition - Displacement { 320, 0 }); + RenderPcxSprite(Surface(DiabloUiSurface()), PcxSpriteSheet { *ArtBackground }.sprite(0), uiPosition); const std::size_t linesBegin = std::max(offsetY / LINE_H, 0); const std::size_t linesEnd = std::min(linesBegin + MAX_VISIBLE_LINES, linesToRender.size()); @@ -167,7 +170,7 @@ bool TextDialog(char const *const *text, std::size_t textLines) bool UiCreditsDialog() { - LoadArt("ui_art\\creditsw.pcx", &ArtBackgroundWidescreen); + ArtBackgroundWidescreen = LoadPcxAsset("ui_art\\creditsw.pcx"); LoadBackgroundArt("ui_art\\credits.pcx"); return TextDialog(CreditLines, CreditLinesSize); @@ -176,10 +179,10 @@ bool UiCreditsDialog() bool UiSupportDialog() { if (gbIsHellfire) { - LoadArt("ui_art\\supportw.pcx", &ArtBackgroundWidescreen); + ArtBackgroundWidescreen = LoadPcxAsset("ui_art\\supportw.pcx"); LoadBackgroundArt("ui_art\\support.pcx"); } else { - LoadArt("ui_art\\creditsw.pcx", &ArtBackgroundWidescreen); + ArtBackgroundWidescreen = LoadPcxAsset("ui_art\\creditsw.pcx"); LoadBackgroundArt("ui_art\\credits.pcx"); } diff --git a/Source/DiabloUI/diabloui.cpp b/Source/DiabloUI/diabloui.cpp index 708e701fb..5f5275508 100644 --- a/Source/DiabloUI/diabloui.cpp +++ b/Source/DiabloUI/diabloui.cpp @@ -19,8 +19,11 @@ #include "discord/discord.h" #include "dx.h" #include "engine/cel_sprite.hpp" +#include "engine/load_pcx.hpp" #include "engine/load_pcx_as_cel.hpp" +#include "engine/pcx_sprite.hpp" #include "engine/render/cel_render.hpp" +#include "engine/render/pcx_render.hpp" #include "hwcursor.hpp" #include "palette.h" #include "utils/display.h" @@ -51,8 +54,8 @@ namespace devilution { std::array, 3> ArtLogos; std::array, 3> ArtFocus; -Art ArtBackgroundWidescreen; -Art ArtBackground; +std::optional ArtBackgroundWidescreen; +std::optional ArtBackground; Art ArtCursor; Art ArtHero; @@ -672,8 +675,8 @@ Sint16 GetCenterOffset(Sint16 w, Sint16 bw) void LoadBackgroundArt(const char *pszFile, int frames) { SDL_Color pPal[256]; - LoadArt(pszFile, &ArtBackground, frames, pPal); - if (ArtBackground.surface == nullptr) + ArtBackground = LoadPcxSpriteSheetAsset(pszFile, static_cast(frames), pPal); + if (!ArtBackground) return; LoadPalInMem(pPal); @@ -697,13 +700,13 @@ void LoadBackgroundArt(const char *pszFile, int frames) void UiAddBackground(std::vector> *vecDialog) { int uiPositionY = GetUIRectangle().position.y; - if (ArtBackgroundWidescreen.surface != nullptr) { + if (ArtBackgroundWidescreen) { SDL_Rect rectw = { 0, uiPositionY, 0, 0 }; - vecDialog->push_back(std::make_unique(&ArtBackgroundWidescreen, rectw, UiFlags::AlignCenter)); + vecDialog->push_back(std::make_unique(PcxSprite { *ArtBackgroundWidescreen }, rectw, UiFlags::AlignCenter)); } SDL_Rect rect = { 0, uiPositionY, 0, 0 }; - vecDialog->push_back(std::make_unique(&ArtBackground, rect, UiFlags::AlignCenter)); + vecDialog->push_back(std::make_unique(PcxSpriteSheet { *ArtBackground }.sprite(0), rect, UiFlags::AlignCenter)); } void UiAddLogo(std::vector> *vecDialog, int size, int y) @@ -840,6 +843,26 @@ void Render(const UiImageCel *uiImage) } } +void Render(const UiImagePcx *uiImage) +{ + PcxSprite sprite = uiImage->GetSprite(); + int x = uiImage->m_rect.x; + if (uiImage->IsCentered()) { + x += GetCenterOffset(sprite.width(), uiImage->m_rect.w); + } + RenderPcxSprite(Surface(DiabloUiSurface()), sprite, { x, uiImage->m_rect.y }); +} + +void Render(const UiImageAnimatedPcx *uiImage) +{ + PcxSprite sprite = uiImage->GetSprite(GetAnimationFrame(uiImage->NumFrames())); + int x = uiImage->m_rect.x; + if (uiImage->IsCentered()) { + x += GetCenterOffset(sprite.width(), uiImage->m_rect.w); + } + RenderPcxSprite(Surface(DiabloUiSurface()), sprite, { x, uiImage->m_rect.y }); +} + void Render(const UiArtTextButton *uiButton) { Rectangle rect { { uiButton->m_rect.x, uiButton->m_rect.y }, { uiButton->m_rect.w, uiButton->m_rect.h } }; @@ -925,6 +948,12 @@ void RenderItem(UiItemBase *item) case UiType::ImageCel: Render(static_cast(item)); break; + case UiType::ImagePcx: + Render(static_cast(item)); + break; + case UiType::ImageAnimatedPcx: + Render(static_cast(item)); + break; case UiType::ArtTextButton: Render(static_cast(item)); break; diff --git a/Source/DiabloUI/diabloui.h b/Source/DiabloUI/diabloui.h index 317254b02..eaa4260b8 100644 --- a/Source/DiabloUI/diabloui.h +++ b/Source/DiabloUI/diabloui.h @@ -8,6 +8,7 @@ #include "DiabloUI/art.h" #include "DiabloUI/ui_item.h" #include "engine/cel_sprite.hpp" +#include "engine/pcx_sprite.hpp" #include "player.h" #include "utils/display.h" @@ -69,8 +70,8 @@ struct _uiheroinfo { extern std::array, 3> ArtLogos; extern std::array, 3> ArtFocus; -extern Art ArtBackground; -extern Art ArtBackgroundWidescreen; +extern std::optional ArtBackgroundWidescreen; +extern std::optional ArtBackground; extern Art ArtCursor; extern Art ArtHero; diff --git a/Source/DiabloUI/dialogs.cpp b/Source/DiabloUI/dialogs.cpp index 9b39b0fbc..9017c2620 100644 --- a/Source/DiabloUI/dialogs.cpp +++ b/Source/DiabloUI/dialogs.cpp @@ -163,9 +163,9 @@ void LoadFallbackPalette() void Init(string_view caption, string_view text, bool error, bool renderBehind) { if (!renderBehind) { - ArtBackground.Unload(); + ArtBackground = std::nullopt; LoadBackgroundArt("ui_art\\black.pcx"); - if (ArtBackground.surface == nullptr) { + if (!ArtBackground) { LoadFallbackPalette(); if (SDL_ShowCursor(SDL_ENABLE) <= -1) Log("{}", SDL_GetError()); @@ -215,7 +215,7 @@ void Deinit() dialogArt.Unload(); UnloadSmlButtonArt(); vecOkDialog.clear(); - ArtBackground.Unload(); + ArtBackground = std::nullopt; } void DialogLoop(const std::vector> &items, const std::vector> &renderBehind) @@ -249,7 +249,7 @@ void DialogLoop(const std::vector> &items, const std UiRenderItems(renderBehind); } UiRenderItems(items); - if (ArtBackground.surface != nullptr) { + if (ArtBackground) { DrawMouse(); } UiFadeIn(); diff --git a/Source/DiabloUI/mainmenu.cpp b/Source/DiabloUI/mainmenu.cpp index d9149757a..f762409a8 100644 --- a/Source/DiabloUI/mainmenu.cpp +++ b/Source/DiabloUI/mainmenu.cpp @@ -2,6 +2,7 @@ #include "DiabloUI/diabloui.h" #include "DiabloUI/selok.h" #include "control.h" +#include "engine/load_pcx.hpp" #include "utils/language.h" namespace devilution { @@ -46,7 +47,7 @@ void MainmenuLoad(const char *name, void (*fnSound)(const char *file)) if (!gbIsSpawn || gbIsHellfire) { if (gbIsHellfire) - LoadArt("ui_art\\mainmenuw.pcx", &ArtBackgroundWidescreen); + ArtBackgroundWidescreen = LoadPcxAsset("ui_art\\mainmenuw.pcx"); LoadBackgroundArt("ui_art\\mainmenu.pcx"); } else { LoadBackgroundArt("ui_art\\swmmenu.pcx"); @@ -76,8 +77,8 @@ void MainmenuLoad(const char *name, void (*fnSound)(const char *file)) void MainmenuFree() { - ArtBackgroundWidescreen.Unload(); - ArtBackground.Unload(); + ArtBackgroundWidescreen = std::nullopt; + ArtBackground = std::nullopt; vecMainMenuDialog.clear(); diff --git a/Source/DiabloUI/progress.cpp b/Source/DiabloUI/progress.cpp index ba726f450..537a4e7ce 100644 --- a/Source/DiabloUI/progress.cpp +++ b/Source/DiabloUI/progress.cpp @@ -5,6 +5,9 @@ #include "controls/input.h" #include "controls/menu_controls.h" #include "dx.h" +#include "engine/load_pcx.hpp" +#include "engine/pcx_sprite.hpp" +#include "engine/render/pcx_render.hpp" #include "hwcursor.hpp" #include "palette.h" #include "utils/display.h" @@ -13,10 +16,9 @@ namespace devilution { namespace { Art dialogArt; -Art progressArt; -Art ArtPopupSm; -Art ArtProgBG; -Art ProgFil; +std::optional ArtPopupSm; +std::optional ArtProgBG; +std::optional ProgFil; std::vector> vecProgress; bool endMenu; @@ -28,9 +30,9 @@ void DialogActionCancel() void ProgressLoad() { LoadBackgroundArt("ui_art\\black.pcx"); - LoadArt("ui_art\\spopup.pcx", &ArtPopupSm); - LoadArt("ui_art\\prog_bg.pcx", &ArtProgBG); - LoadArt("ui_art\\prog_fil.pcx", &ProgFil); + ArtPopupSm = LoadPcxAsset("ui_art\\spopup.pcx"); + ArtProgBG = LoadPcxAsset("ui_art\\prog_bg.pcx"); + ProgFil = LoadPcxAsset("ui_art\\prog_fil.pcx"); LoadSmlButtonArt(); const Point uiPosition = GetUIRectangle().position; @@ -40,24 +42,28 @@ void ProgressLoad() void ProgressFree() { - ArtBackground.Unload(); - ArtPopupSm.Unload(); - ArtProgBG.Unload(); - ProgFil.Unload(); + ArtBackground = std::nullopt; + ArtPopupSm = std::nullopt; + ArtProgBG = std::nullopt; + ProgFil = std::nullopt; UnloadSmlButtonArt(); } void ProgressRender(BYTE progress) { SDL_FillRect(DiabloUiSurface(), nullptr, 0x000000); - DrawArt({ 0, 0 }, &ArtBackground); + + const Surface &out = Surface(DiabloUiSurface()); + RenderPcxSprite(out, PcxSpriteSheet { *ArtBackground }.sprite(0), { 0, 0 }); Point position = { GetCenterOffset(280), GetCenterOffset(144, gnScreenHeight) }; - DrawArt(position, &ArtPopupSm, 0, 280, 140); - DrawArt({ GetCenterOffset(227), position.y + 52 }, &ArtProgBG, 0, 227); + RenderPcxSprite(out, PcxSprite { *ArtPopupSm }, position); + RenderPcxSprite(out, PcxSprite { *ArtProgBG }, { GetCenterOffset(227), position.y + 52 }); if (progress != 0) { - DrawArt({ GetCenterOffset(227), position.y + 52 }, &ProgFil, 0, 227 * progress / 100); + const int x = GetCenterOffset(227); + const int w = 227 * progress / 100; + RenderPcxSprite(out.subregion(x, 0, w, out.h()), PcxSprite { *ProgFil }, { 0, position.y + 52 }); } DrawArt({ GetCenterOffset(110), position.y + 99 }, &SmlButton, 2, 110); } diff --git a/Source/DiabloUI/selconn.cpp b/Source/DiabloUI/selconn.cpp index 276093e24..60f3c0197 100644 --- a/Source/DiabloUI/selconn.cpp +++ b/Source/DiabloUI/selconn.cpp @@ -89,7 +89,7 @@ void SelconnLoad() void SelconnFree() { - ArtBackground.Unload(); + ArtBackground = std::nullopt; vecConnItems.clear(); diff --git a/Source/DiabloUI/selgame.cpp b/Source/DiabloUI/selgame.cpp index cff86a688..7e382d8d3 100644 --- a/Source/DiabloUI/selgame.cpp +++ b/Source/DiabloUI/selgame.cpp @@ -60,7 +60,7 @@ void selgame_Init() void selgame_Free() { - ArtBackground.Unload(); + ArtBackground = std::nullopt; UnloadScrollBar(); selgame_FreeVectors(); } diff --git a/Source/DiabloUI/selhero.cpp b/Source/DiabloUI/selhero.cpp index 4b54a510e..8a809c692 100644 --- a/Source/DiabloUI/selhero.cpp +++ b/Source/DiabloUI/selhero.cpp @@ -66,7 +66,7 @@ void SelheroUiFocusNavigationYesNo() void SelheroFree() { - ArtBackground.Unload(); + ArtBackground = std::nullopt; vecSelHeroDialog.clear(); @@ -229,7 +229,7 @@ void SelheroClassSelectorSelect(int value) { auto hClass = static_cast(vecSelHeroDlgItems[value]->m_value); if (gbIsSpawn && (hClass == HeroClass::Rogue || hClass == HeroClass::Sorcerer || (hClass == HeroClass::Bard && !hfbard_mpq))) { - ArtBackground.Unload(); + ArtBackground = std::nullopt; UiSelOkDialog(nullptr, _("The Rogue and Sorcerer are only available in the full retail version of Diablo. Visit https://www.gog.com/game/diablo to purchase.").c_str(), false); LoadBackgroundArt("ui_art\\selhero.pcx"); SelheroListSelect(selhero_SaveCount); @@ -275,7 +275,7 @@ void SelheroNameSelect(int /*value*/) { // only check names in multiplayer, we don't care about them in single if (selhero_isMultiPlayer && !UiValidPlayerName(selhero_heroInfo.name)) { - ArtBackground.Unload(); + ArtBackground = std::nullopt; UiSelOkDialog(title, _("Invalid name. A name cannot contain spaces, reserved characters, or reserved words.\n").c_str(), false); LoadBackgroundArt("ui_art\\selhero.pcx"); } else { diff --git a/Source/DiabloUI/selok.cpp b/Source/DiabloUI/selok.cpp index 364a52282..cf3becc1c 100644 --- a/Source/DiabloUI/selok.cpp +++ b/Source/DiabloUI/selok.cpp @@ -23,7 +23,7 @@ std::vector> vecSelOkDialog; void selok_Free() { - ArtBackground.Unload(); + ArtBackground = std::nullopt; vecSelOkDialogItems.clear(); diff --git a/Source/DiabloUI/selstart.cpp b/Source/DiabloUI/selstart.cpp index 3cb94cb7a..d28f1a97e 100644 --- a/Source/DiabloUI/selstart.cpp +++ b/Source/DiabloUI/selstart.cpp @@ -1,65 +1,65 @@ -#include "selstart.h" - -#include "DiabloUI/diabloui.h" -#include "control.h" -#include "options.h" -#include "utils/language.h" - -namespace devilution { -namespace { - -bool endMenu; - -std::vector> vecDialogItems; -std::vector> vecDialog; - -Art artLogo; - -void ItemSelected(int value) -{ - auto option = static_cast(vecDialogItems[value]->m_value); - sgOptions.StartUp.gameMode.SetValue(option); - SaveOptions(); - endMenu = true; -} - -void EscPressed() -{ - endMenu = true; -} - -} // namespace - -void UiSelStartUpGameOption() -{ - LoadArt("ui_art\\mainmenuw.pcx", &ArtBackgroundWidescreen); - LoadBackgroundArt("ui_art\\mainmenu.pcx"); - LoadMaskedArt("ui_art\\hf_logo2.pcx", &artLogo, 16); - UiAddBackground(&vecDialog); - - const Point uiPosition = GetUIRectangle().position; - - SDL_Rect rect = { 0, (Sint16)(uiPosition.y), 0, 0 }; - vecDialog.push_back(std::make_unique(&artLogo, rect, UiFlags::AlignCenter, /*bAnimated=*/true)); - - vecDialogItems.push_back(std::make_unique(_("Enter Hellfire"), static_cast(StartUpGameMode::Hellfire))); - vecDialogItems.push_back(std::make_unique(_("Switch to Diablo"), static_cast(StartUpGameMode::Diablo))); - vecDialog.push_back(std::make_unique(vecDialogItems, vecDialogItems.size(), uiPosition.x + 64, (uiPosition.y + 240), 510, 43, UiFlags::AlignCenter | UiFlags::FontSize42 | UiFlags::ColorUiGold, 5)); - - UiInitList(nullptr, ItemSelected, EscPressed, vecDialog, true); - - endMenu = false; - while (!endMenu) { - UiClearScreen(); - UiRenderItems(vecDialog); - UiPollAndRender(); - } - - artLogo.Unload(); - ArtBackground.Unload(); - ArtBackgroundWidescreen.Unload(); - vecDialogItems.clear(); - vecDialog.clear(); -} - -} // namespace devilution +#include "selstart.h" + +#include "DiabloUI/diabloui.h" +#include "control.h" +#include "engine/load_pcx.hpp" +#include "options.h" +#include "utils/language.h" + +namespace devilution { +namespace { + +bool endMenu; + +std::vector> vecDialogItems; +std::vector> vecDialog; + +Art artLogo; + +void ItemSelected(int value) +{ + auto option = static_cast(vecDialogItems[value]->m_value); + sgOptions.StartUp.gameMode.SetValue(option); + SaveOptions(); + endMenu = true; +} + +void EscPressed() +{ + endMenu = true; +} + +} // namespace + +void UiSelStartUpGameOption() +{ + ArtBackgroundWidescreen = LoadPcxAsset("ui_art\\mainmenuw.pcx"); + LoadBackgroundArt("ui_art\\mainmenu.pcx"); + LoadMaskedArt("ui_art\\hf_logo2.pcx", &artLogo, 16); + UiAddBackground(&vecDialog); + + const Point uiPosition = GetUIRectangle().position; + SDL_Rect rect = { 0, (Sint16)(uiPosition.y), 0, 0 }; + vecDialog.push_back(std::make_unique(&artLogo, rect, UiFlags::AlignCenter, /*bAnimated=*/true)); + + vecDialogItems.push_back(std::make_unique(_("Enter Hellfire"), static_cast(StartUpGameMode::Hellfire))); + vecDialogItems.push_back(std::make_unique(_("Switch to Diablo"), static_cast(StartUpGameMode::Diablo))); + vecDialog.push_back(std::make_unique(vecDialogItems, vecDialogItems.size(), uiPosition.x + 64, uiPosition.y + 240, 510, 43, UiFlags::AlignCenter | UiFlags::FontSize42 | UiFlags::ColorUiGold, 5)); + + UiInitList(nullptr, ItemSelected, EscPressed, vecDialog, true); + + endMenu = false; + while (!endMenu) { + UiClearScreen(); + UiRenderItems(vecDialog); + UiPollAndRender(); + } + + artLogo.Unload(); + ArtBackground = std::nullopt; + ArtBackgroundWidescreen = std::nullopt; + vecDialogItems.clear(); + vecDialog.clear(); +} + +} // namespace devilution diff --git a/Source/DiabloUI/selyesno.cpp b/Source/DiabloUI/selyesno.cpp index d458ff2f8..0b33c7562 100644 --- a/Source/DiabloUI/selyesno.cpp +++ b/Source/DiabloUI/selyesno.cpp @@ -19,7 +19,7 @@ std::vector> vecSelYesNoDialog; void SelyesnoFree() { - ArtBackground.Unload(); + ArtBackground = std::nullopt; vecSelYesNoDialogItems.clear(); diff --git a/Source/DiabloUI/settingsmenu.cpp b/Source/DiabloUI/settingsmenu.cpp index f17a698ef..ac42578ea 100644 --- a/Source/DiabloUI/settingsmenu.cpp +++ b/Source/DiabloUI/settingsmenu.cpp @@ -73,8 +73,8 @@ void CleanUpSettingsUI() vecDialog.clear(); vecOptions.clear(); - ArtBackground.Unload(); - ArtBackgroundWidescreen.Unload(); + ArtBackground = std::nullopt; + ArtBackgroundWidescreen = std::nullopt; UnloadScrollBar(); } diff --git a/Source/DiabloUI/title.cpp b/Source/DiabloUI/title.cpp index eab711f85..41e683883 100644 --- a/Source/DiabloUI/title.cpp +++ b/Source/DiabloUI/title.cpp @@ -3,6 +3,7 @@ #include "controls/input.h" #include "controls/menu_controls.h" #include "discord/discord.h" +#include "engine/load_pcx.hpp" #include "engine/load_pcx_as_cel.hpp" #include "utils/language.h" @@ -14,10 +15,8 @@ std::vector> vecTitleScreen; void TitleLoad() { if (gbIsHellfire) { - // This is a 2.4 MiB PCX file without transparency (4.6 MiB as an SDL surface). LoadBackgroundArt("ui_art\\hf_logo1.pcx", 16); - - LoadArt("ui_art\\hf_titlew.pcx", &ArtBackgroundWidescreen); + ArtBackgroundWidescreen = LoadPcxAsset("ui_art\\hf_titlew.pcx"); } else { LoadBackgroundArt("ui_art\\title.pcx"); ArtLogos[LOGO_BIG] = LoadPcxAssetAsCel("ui_art\\logo.pcx", /*numFrames=*/15, /*generateFrameHeaders=*/false, /*transparentColorIndex=*/250); @@ -26,8 +25,8 @@ void TitleLoad() void TitleFree() { - ArtBackground.Unload(); - ArtBackgroundWidescreen.Unload(); + ArtBackground = std::nullopt; + ArtBackgroundWidescreen = std::nullopt; ArtLogos[LOGO_BIG] = std::nullopt; vecTitleScreen.clear(); @@ -41,8 +40,9 @@ void UiTitleDialog() const Point uiPosition = GetUIRectangle().position; if (gbIsHellfire) { SDL_Rect rect = { 0, uiPosition.y, 0, 0 }; - vecTitleScreen.push_back(std::make_unique(&ArtBackgroundWidescreen, rect, UiFlags::AlignCenter, /*bAnimated=*/true)); - vecTitleScreen.push_back(std::make_unique(&ArtBackground, rect, UiFlags::AlignCenter, /*bAnimated=*/true)); + if (ArtBackgroundWidescreen) + vecTitleScreen.push_back(std::make_unique(PcxSprite { *ArtBackgroundWidescreen }, rect, UiFlags::AlignCenter)); + vecTitleScreen.push_back(std::make_unique(PcxSpriteSheet { *ArtBackground }, rect, UiFlags::AlignCenter)); } else { UiAddBackground(&vecTitleScreen); UiAddLogo(&vecTitleScreen, LOGO_BIG, 182); diff --git a/Source/DiabloUI/ui_item.h b/Source/DiabloUI/ui_item.h index ccdb248b4..6748b75ad 100644 --- a/Source/DiabloUI/ui_item.h +++ b/Source/DiabloUI/ui_item.h @@ -8,6 +8,7 @@ #include "DiabloUI/art.h" #include "DiabloUI/ui_flags.hpp" #include "engine/cel_sprite.hpp" +#include "engine/pcx_sprite.hpp" #include "engine/render/text_render.hpp" #include "utils/enum_traits.h" #include "utils/stubs.h" @@ -20,6 +21,8 @@ enum class UiType { ArtTextButton, Image, ImageCel, + ImagePcx, + ImageAnimatedPcx, Button, List, Scrollbar, @@ -173,6 +176,57 @@ private: int frame_; }; +//============================================================================= +class UiImagePcx : public UiItemBase { +public: + UiImagePcx(PcxSprite sprite, SDL_Rect rect, UiFlags flags = UiFlags::None) + : UiItemBase(UiType::ImagePcx, rect, flags) + , sprite_(sprite) + { + } + + [[nodiscard]] bool IsCentered() const + { + return HasAnyOf(GetFlags(), UiFlags::AlignCenter); + } + + [[nodiscard]] PcxSprite GetSprite() const + { + return sprite_; + } + +private: + PcxSprite sprite_; +}; + +//============================================================================= +class UiImageAnimatedPcx : public UiItemBase { +public: + UiImageAnimatedPcx(PcxSpriteSheet sheet, SDL_Rect rect, UiFlags flags = UiFlags::None) + : UiItemBase(UiType::ImageAnimatedPcx, rect, flags) + , sheet_(sheet) + { + } + + [[nodiscard]] bool IsCentered() const + { + return HasAnyOf(GetFlags(), UiFlags::AlignCenter); + } + + [[nodiscard]] PcxSprite GetSprite(uint16_t frame) const + { + return sheet_.sprite(frame); + } + + [[nodiscard]] uint16_t NumFrames() const + { + return sheet_.numFrames(); + } + +private: + PcxSpriteSheet sheet_; +}; + //============================================================================= class UiArtText : public UiItemBase {