diff --git a/Source/control.cpp b/Source/control.cpp index e9d74bfb7..2a100394e 100644 --- a/Source/control.cpp +++ b/Source/control.cpp @@ -85,7 +85,7 @@ Rectangle MainPanel; Rectangle LeftPanel; Rectangle RightPanel; std::optional pBtmBuff; -std::optional pGBoxBuff; +OptionalOwnedCelSprite pGBoxBuff; const Rectangle &GetMainPanel() { @@ -135,10 +135,10 @@ namespace { std::optional pLifeBuff; std::optional pManaBuff; -std::optional talkButtons; -std::optional pDurIcons; -std::optional multiButtons; -std::optional pPanelButtons; +OptionalOwnedCelSprite talkButtons; +OptionalOwnedCelSprite pDurIcons; +OptionalOwnedCelSprite multiButtons; +OptionalOwnedCelSprite pPanelButtons; bool PanelButtons[8]; int PanelButtonIndex; diff --git a/Source/control.h b/Source/control.h index 5db22a168..478b22c19 100644 --- a/Source/control.h +++ b/Source/control.h @@ -52,7 +52,7 @@ const Rectangle &GetRightPanel(); bool IsLeftPanelOpen(); bool IsRightPanelOpen(); extern std::optional pBtmBuff; -extern std::optional pGBoxBuff; +extern OptionalOwnedCelSprite pGBoxBuff; extern SDL_Rect PanBtnPos[8]; void CalculatePanelAreas(); diff --git a/Source/controls/modifier_hints.cpp b/Source/controls/modifier_hints.cpp index 0e6eda2f6..3eabfd93f 100644 --- a/Source/controls/modifier_hints.cpp +++ b/Source/controls/modifier_hints.cpp @@ -16,7 +16,7 @@ namespace devilution { -extern std::optional pSBkIconCels; +extern OptionalOwnedCelSprite pSBkIconCels; namespace { diff --git a/Source/cursor.cpp b/Source/cursor.cpp index b5fdb17ed..ea1ac9b3d 100644 --- a/Source/cursor.cpp +++ b/Source/cursor.cpp @@ -31,8 +31,8 @@ namespace devilution { namespace { /** Cursor images CEL */ -std::optional pCursCels; -std::optional pCursCels2; +OptionalOwnedCelSprite pCursCels; +OptionalOwnedCelSprite pCursCels2; /** Maps from objcurs.cel frame number to frame width. */ const uint16_t InvItemWidth1[] = { diff --git a/Source/debug.cpp b/Source/debug.cpp index 63a935a31..cfbb0d94e 100644 --- a/Source/debug.cpp +++ b/Source/debug.cpp @@ -35,7 +35,7 @@ namespace devilution { std::string TestMapPath; -std::optional pSquareCel; +OptionalOwnedCelSprite pSquareCel; bool DebugToggle = false; bool DebugGodMode = false; bool DebugVision = false; diff --git a/Source/debug.h b/Source/debug.h index c619fdc1e..6d77f6ba7 100644 --- a/Source/debug.h +++ b/Source/debug.h @@ -15,7 +15,7 @@ namespace devilution { extern std::string TestMapPath; -extern std::optional pSquareCel; +extern OptionalOwnedCelSprite pSquareCel; extern bool DebugToggle; extern bool DebugGodMode; extern bool DebugVision; diff --git a/Source/doom.cpp b/Source/doom.cpp index ab8522473..ab35298ce 100644 --- a/Source/doom.cpp +++ b/Source/doom.cpp @@ -14,7 +14,7 @@ namespace devilution { namespace { -std::optional DoomCel; +OptionalOwnedCelSprite DoomCel; } // namespace bool DoomFlag; diff --git a/Source/engine/cel_sprite.hpp b/Source/engine/cel_sprite.hpp index 0d3983898..793cb8d92 100644 --- a/Source/engine/cel_sprite.hpp +++ b/Source/engine/cel_sprite.hpp @@ -142,6 +142,8 @@ private: CelSprite sprite_; }; +class OptionalOwnedCelSprite; + /** * Stores a CEL or CL2 sprite and its width(s). * Owns the data. @@ -169,10 +171,87 @@ public: } private: + // for OptionalOwnedCelSprite. + OwnedCelSprite() + : data_(nullptr) + , width_(nullptr) + { + } + std::unique_ptr data_; PointerOrValue width_; friend class CelSprite; + friend class OptionalOwnedCelSprite; +}; + +/** + * @brief Equivalent to `std::optional` but smaller. + */ +class OptionalOwnedCelSprite { +public: + OptionalOwnedCelSprite() = default; + + OptionalOwnedCelSprite(OwnedCelSprite &&sprite) + : sprite_(std::move(sprite)) + { + } + + OptionalOwnedCelSprite(std::nullopt_t) + : OptionalOwnedCelSprite() + { + } + + template + OwnedCelSprite &emplace(Args &&...args) + { + sprite_ = OwnedCelSprite(std::forward(args)...); + return sprite_; + } + + OptionalOwnedCelSprite &operator=(OwnedCelSprite &&sprite) + { + sprite_ = std::move(sprite); + return *this; + } + + OptionalOwnedCelSprite &operator=(std::nullopt_t) + { + sprite_ = {}; + return *this; + } + + OwnedCelSprite &operator*() + { + assert(sprite_.data_ != nullptr); + return sprite_; + } + + const OwnedCelSprite &operator*() const + { + assert(sprite_.data_ != nullptr); + return sprite_; + } + + OwnedCelSprite *operator->() + { + assert(sprite_.data_ != nullptr); + return &sprite_; + } + + const OwnedCelSprite *operator->() const + { + assert(sprite_.data_ != nullptr); + return &sprite_; + } + + operator bool() const + { + return sprite_.data_ != nullptr; + } + +private: + OwnedCelSprite sprite_; }; inline CelSprite::CelSprite(const OwnedCelSprite &owned) diff --git a/Source/engine/render/text_render.cpp b/Source/engine/render/text_render.cpp index 33a6c8fca..129b4ba87 100644 --- a/Source/engine/render/text_render.cpp +++ b/Source/engine/render/text_render.cpp @@ -31,7 +31,7 @@ namespace devilution { -std::optional pSPentSpn2Cels; +OptionalOwnedCelSprite pSPentSpn2Cels; namespace { diff --git a/Source/engine/render/text_render.hpp b/Source/engine/render/text_render.hpp index 3d5e98354..ca1f15bf9 100644 --- a/Source/engine/render/text_render.hpp +++ b/Source/engine/render/text_render.hpp @@ -123,7 +123,7 @@ private: * * Also used in the stores and the quest log. */ -extern std::optional pSPentSpn2Cels; +extern OptionalOwnedCelSprite pSPentSpn2Cels; void LoadSmallSelectionSpinner(); diff --git a/Source/gmenu.cpp b/Source/gmenu.cpp index 22336a8f9..d2c11cf22 100644 --- a/Source/gmenu.cpp +++ b/Source/gmenu.cpp @@ -24,10 +24,10 @@ namespace devilution { namespace { -std::optional optbar_cel; -std::optional PentSpin_cel; -std::optional option_cel; -std::optional sgpLogo; +OptionalOwnedCelSprite optbar_cel; +OptionalOwnedCelSprite PentSpin_cel; +OptionalOwnedCelSprite option_cel; +OptionalOwnedCelSprite sgpLogo; bool mouseNavigation; TMenuItem *sgpCurrItem; int LogoAnim_tick; diff --git a/Source/interfac.cpp b/Source/interfac.cpp index 8393e3210..62faf1607 100644 --- a/Source/interfac.cpp +++ b/Source/interfac.cpp @@ -30,7 +30,7 @@ namespace devilution { namespace { -std::optional sgpBackCel; +OptionalOwnedCelSprite sgpBackCel; bool IsProgress; uint32_t sgdwProgress; diff --git a/Source/inv.cpp b/Source/inv.cpp index 458c0e5ac..518cee2bf 100644 --- a/Source/inv.cpp +++ b/Source/inv.cpp @@ -137,7 +137,7 @@ const Point InvRect[] = { namespace { -std::optional pInvCels; +OptionalOwnedCelSprite pInvCels; /** * @brief Adds an item to a player's InvGrid array diff --git a/Source/items.cpp b/Source/items.cpp index 41767b8b2..b7993bc51 100644 --- a/Source/items.cpp +++ b/Source/items.cpp @@ -131,7 +131,7 @@ _sfx_id ItemInvSnds[] = { namespace { -std::optional itemanims[ITEMTYPES]; +OptionalOwnedCelSprite itemanims[ITEMTYPES]; enum class PlayerArmorGraphic : uint8_t { // clang-format off diff --git a/Source/levels/gendung.cpp b/Source/levels/gendung.cpp index e2df47488..14e3a7fdb 100644 --- a/Source/levels/gendung.cpp +++ b/Source/levels/gendung.cpp @@ -21,7 +21,7 @@ Bitset2d Protected; Rectangle SetPieceRoom; Rectangle SetPiece; std::unique_ptr pSetPiece; -std::optional pSpecialCels; +OptionalOwnedCelSprite pSpecialCels; std::unique_ptr pMegaTiles; std::unique_ptr pDungeonCels; std::array SOLData; diff --git a/Source/levels/gendung.h b/Source/levels/gendung.h index f7ebadbac..2a219454f 100644 --- a/Source/levels/gendung.h +++ b/Source/levels/gendung.h @@ -148,7 +148,7 @@ extern Rectangle SetPieceRoom; extern Rectangle SetPiece; /** Contains the contents of the single player quest DUN file. */ extern std::unique_ptr pSetPiece; -extern std::optional pSpecialCels; +extern OptionalOwnedCelSprite pSpecialCels; /** Specifies the tile definitions of the active dungeon type; (e.g. levels/l1data/l1.til). */ extern DVL_API_FOR_TEST std::unique_ptr pMegaTiles; extern std::unique_ptr pDungeonCels; diff --git a/Source/minitext.cpp b/Source/minitext.cpp index 64849d80c..edb539645 100644 --- a/Source/minitext.cpp +++ b/Source/minitext.cpp @@ -30,7 +30,7 @@ int qtextSpd; /** Start time of scrolling */ Uint32 ScrollStart; /** Graphics for the window border */ -std::optional pTextBoxCels; +OptionalOwnedCelSprite pTextBoxCels; /** Pixels for a line of text and the empty space under it. */ const int LineHeight = 38; diff --git a/Source/panels/charpanel.cpp b/Source/panels/charpanel.cpp index c4276382d..3f10f3e38 100644 --- a/Source/panels/charpanel.cpp +++ b/Source/panels/charpanel.cpp @@ -17,7 +17,7 @@ namespace devilution { -std::optional pChrButtons; +OptionalOwnedCelSprite pChrButtons; /** Map of hero class names */ const char *const ClassStrTbl[] = { diff --git a/Source/panels/charpanel.hpp b/Source/panels/charpanel.hpp index a0525a885..551fbf7e1 100644 --- a/Source/panels/charpanel.hpp +++ b/Source/panels/charpanel.hpp @@ -5,7 +5,7 @@ namespace devilution { -extern std::optional pChrButtons; +extern OptionalOwnedCelSprite pChrButtons; extern const char *const ClassStrTbl[]; void DrawChr(const Surface &); diff --git a/Source/panels/info_box.cpp b/Source/panels/info_box.cpp index 192bd49b7..14a6c6929 100644 --- a/Source/panels/info_box.cpp +++ b/Source/panels/info_box.cpp @@ -4,8 +4,8 @@ namespace devilution { -std::optional pSTextBoxCels; -std::optional pSTextSlidCels; +OptionalOwnedCelSprite pSTextBoxCels; +OptionalOwnedCelSprite pSTextSlidCels; void InitInfoBoxGfx() { diff --git a/Source/panels/info_box.hpp b/Source/panels/info_box.hpp index ba69d4229..c436495b4 100644 --- a/Source/panels/info_box.hpp +++ b/Source/panels/info_box.hpp @@ -9,14 +9,14 @@ namespace devilution { * * Used in stores, the quest log, the help window, and the unique item info window. */ -extern std::optional pSTextBoxCels; +extern OptionalOwnedCelSprite pSTextBoxCels; /** * @brief Info box scrollbar graphics. * * Used in stores and `DrawDiabloMsg`. */ -extern std::optional pSTextSlidCels; +extern OptionalOwnedCelSprite pSTextSlidCels; void InitInfoBoxGfx(); void FreeInfoBoxGfx(); diff --git a/Source/panels/spell_book.cpp b/Source/panels/spell_book.cpp index 3166cecfa..438994595 100644 --- a/Source/panels/spell_book.cpp +++ b/Source/panels/spell_book.cpp @@ -21,12 +21,12 @@ namespace devilution { -std::optional pSBkIconCels; +OptionalOwnedCelSprite pSBkIconCels; namespace { -std::optional pSBkBtnCel; -std::optional pSpellBkCel; +OptionalOwnedCelSprite pSBkBtnCel; +OptionalOwnedCelSprite pSpellBkCel; /** Maps from spellbook page number and position to spell_id. */ spell_id SpellPages[6][7] = { diff --git a/Source/panels/spell_icons.cpp b/Source/panels/spell_icons.cpp index e79a85b02..cbcaa26f0 100644 --- a/Source/panels/spell_icons.cpp +++ b/Source/panels/spell_icons.cpp @@ -9,7 +9,7 @@ namespace devilution { namespace { -std::optional pSpellCels; +OptionalOwnedCelSprite pSpellCels; uint8_t SplTransTbl[256]; } // namespace diff --git a/Source/quests.cpp b/Source/quests.cpp index f32549a13..80b383b93 100644 --- a/Source/quests.cpp +++ b/Source/quests.cpp @@ -30,7 +30,7 @@ namespace devilution { bool QuestLogIsOpen; -std::optional pQLogCel; +OptionalOwnedCelSprite pQLogCel; /** Contains the quests of the current game. */ Quest Quests[MAXQUESTS]; Point ReturnLvlPosition; diff --git a/Source/quests.h b/Source/quests.h index fa3c8f55c..a48adada7 100644 --- a/Source/quests.h +++ b/Source/quests.h @@ -73,7 +73,7 @@ struct QuestData { }; extern bool QuestLogIsOpen; -extern std::optional pQLogCel; +extern OptionalOwnedCelSprite pQLogCel; extern DVL_API_FOR_TEST Quest Quests[MAXQUESTS]; extern Point ReturnLvlPosition; extern dungeon_type ReturnLevelType;