diff --git a/Source/debug.h b/Source/debug.h index 2d226a8c9..c619fdc1e 100644 --- a/Source/debug.h +++ b/Source/debug.h @@ -10,7 +10,6 @@ #include "engine.h" #include "engine/cel_sprite.hpp" #include "miniwin/miniwin.h" -#include "utils/stdcompat/optional.hpp" #include "utils/stdcompat/string_view.hpp" namespace devilution { diff --git a/Source/engine/animationinfo.cpp b/Source/engine/animationinfo.cpp index fb3ab8a82..28f97af57 100644 --- a/Source/engine/animationinfo.cpp +++ b/Source/engine/animationinfo.cpp @@ -74,7 +74,7 @@ float AnimationInfo::GetAnimationProgress() const return animationFraction; } -void AnimationInfo::SetNewAnimation(std::optional celSprite, int8_t numberOfFrames, int8_t ticksPerFrame, AnimationDistributionFlags flags /*= AnimationDistributionFlags::None*/, int8_t numSkippedFrames /*= 0*/, int8_t distributeFramesBeforeFrame /*= 0*/, float previewShownGameTickFragments /*= 0.F*/) +void AnimationInfo::SetNewAnimation(OptionalCelSprite celSprite, int8_t numberOfFrames, int8_t ticksPerFrame, AnimationDistributionFlags flags /*= AnimationDistributionFlags::None*/, int8_t numSkippedFrames /*= 0*/, int8_t distributeFramesBeforeFrame /*= 0*/, float previewShownGameTickFragments /*= 0.F*/) { if ((flags & AnimationDistributionFlags::RepeatedAction) == AnimationDistributionFlags::RepeatedAction && distributeFramesBeforeFrame != 0 && NumberOfFrames == numberOfFrames && CurrentFrame + 1 >= distributeFramesBeforeFrame && CurrentFrame != NumberOfFrames - 1) { // We showed the same Animation (for example a melee attack) before but truncated the Animation. @@ -167,7 +167,7 @@ void AnimationInfo::SetNewAnimation(std::optional celSprite, int8_t n } } -void AnimationInfo::ChangeAnimationData(std::optional celSprite, int8_t numberOfFrames, int8_t ticksPerFrame) +void AnimationInfo::ChangeAnimationData(OptionalCelSprite celSprite, int8_t numberOfFrames, int8_t ticksPerFrame) { if (numberOfFrames != NumberOfFrames || ticksPerFrame != TicksPerFrame) { // Ensure that the CurrentFrame is still valid and that we disable ADL cause the calculcated values (for example TickModifier) could be wrong diff --git a/Source/engine/animationinfo.h b/Source/engine/animationinfo.h index b64cd8c56..d06fac1a2 100644 --- a/Source/engine/animationinfo.h +++ b/Source/engine/animationinfo.h @@ -9,7 +9,6 @@ #include #include "engine/cel_sprite.hpp" -#include "utils/stdcompat/optional.hpp" namespace devilution { @@ -40,7 +39,7 @@ public: /** * @brief Animation sprite */ - std::optional celSprite; + OptionalCelSprite celSprite; /** * @brief How many game ticks are needed to advance one Animation Frame */ @@ -83,7 +82,7 @@ public: * @param distributeFramesBeforeFrame Distribute the numSkippedFrames only before this frame * @param previewShownGameTickFragments Defines how long (in game ticks fraction) the preview animation was shown */ - void SetNewAnimation(std::optional celSprite, int8_t numberOfFrames, int8_t ticksPerFrame, AnimationDistributionFlags flags = AnimationDistributionFlags::None, int8_t numSkippedFrames = 0, int8_t distributeFramesBeforeFrame = 0, float previewShownGameTickFragments = 0.F); + void SetNewAnimation(OptionalCelSprite celSprite, int8_t numberOfFrames, int8_t ticksPerFrame, AnimationDistributionFlags flags = AnimationDistributionFlags::None, int8_t numSkippedFrames = 0, int8_t distributeFramesBeforeFrame = 0, float previewShownGameTickFragments = 0.F); /** * @brief Changes the Animation Data on-the-fly. This is needed if a animation is currently in progress and the player changes his gear. @@ -91,7 +90,7 @@ public: * @param numberOfFrames Number of Frames in Animation * @param ticksPerFrame How many game ticks are needed to advance one Animation Frame */ - void ChangeAnimationData(std::optional celSprite, int8_t numberOfFrames, int8_t ticksPerFrame); + void ChangeAnimationData(OptionalCelSprite celSprite, int8_t numberOfFrames, int8_t ticksPerFrame); /** * @brief Process the Animation for a game tick (for example advances the frame) diff --git a/Source/engine/cel_sprite.hpp b/Source/engine/cel_sprite.hpp index 2161a16d5..0d3983898 100644 --- a/Source/engine/cel_sprite.hpp +++ b/Source/engine/cel_sprite.hpp @@ -3,12 +3,15 @@ #include #include +#include "appfat.h" #include "utils/pointer_value_union.hpp" #include "utils/stdcompat/cstddef.hpp" +#include "utils/stdcompat/optional.hpp" namespace devilution { class OwnedCelSprite; +class OptionalCelSprite; /** * Stores a CEL or CL2 sprite and its width(s). @@ -61,8 +64,82 @@ public: } private: + // for OptionalCelSprite + CelSprite() + : data_ptr_(nullptr) + , width_(nullptr) + { + } + const byte *data_ptr_; PointerOrValue width_; + + friend class OptionalCelSprite; +}; + +/** + * @brief Equivalent to `std::optional` but smaller. + */ +class OptionalCelSprite { +public: + OptionalCelSprite() = default; + + OptionalCelSprite(CelSprite sprite) + : sprite_(sprite) + { + } + + explicit OptionalCelSprite(const OwnedCelSprite &owned); + + OptionalCelSprite(std::nullopt_t) + : OptionalCelSprite() + { + } + + template + CelSprite &emplace(Args &&...args) + { + sprite_ = CelSprite(std::forward(args)...); + return sprite_; + } + + OptionalCelSprite &operator=(CelSprite sprite) + { + sprite_ = sprite; + return *this; + } + + OptionalCelSprite &operator=(std::nullopt_t) + { + sprite_ = {}; + return *this; + } + + CelSprite operator*() const + { + assert(sprite_.data_ptr_ != nullptr); + return sprite_; + } + + CelSprite *operator->() + { + assert(sprite_.data_ptr_ != nullptr); + return &sprite_; + } + + const CelSprite *operator->() const + { + assert(sprite_.data_ptr_ != nullptr); + return &sprite_; + } + + operator bool() const + { + return sprite_.data_ptr_ != nullptr; + } + +private: + CelSprite sprite_; }; /** @@ -103,6 +180,11 @@ inline CelSprite::CelSprite(const OwnedCelSprite &owned) { } +inline OptionalCelSprite::OptionalCelSprite(const OwnedCelSprite &owned) +{ + sprite_ = CelSprite { owned }; +} + struct CelSpriteWithFrameHeight { CelSprite sprite; unsigned frameHeight; diff --git a/Source/engine/render/scrollrt.cpp b/Source/engine/render/scrollrt.cpp index 96d5c9aa2..51c2387bf 100644 --- a/Source/engine/render/scrollrt.cpp +++ b/Source/engine/render/scrollrt.cpp @@ -509,7 +509,7 @@ void DrawPlayer(const Surface &out, const Player &player, Point tilePosition, Po return; } - std::optional sprite = player.AnimInfo.celSprite; + OptionalCelSprite sprite = player.AnimInfo.celSprite; int nCel = player.AnimInfo.GetFrameToUseForRendering(); if (player.previewCelSprite) { @@ -713,7 +713,7 @@ void DrawItem(const Surface &out, Point tilePosition, Point targetBufferPosition if (item._iPostDraw == pre) return; - std::optional cel = item.AnimInfo.celSprite; + OptionalCelSprite cel = item.AnimInfo.celSprite; if (!cel) { Log("Draw Item \"{}\" 1: NULL CelSprite", item._iIName); return; diff --git a/Source/items.cpp b/Source/items.cpp index f61cf019b..41767b8b2 100644 --- a/Source/items.cpp +++ b/Source/items.cpp @@ -4582,7 +4582,7 @@ void Item::setNewAnimation(bool showAnimation) { int8_t it = ItemCAnimTbl[_iCurs]; int8_t numberOfFrames = ItemAnimLs[it]; - auto celSprite = itemanims[it] ? std::optional { *itemanims[it] } : std::nullopt; + auto celSprite = itemanims[it] ? OptionalCelSprite { *itemanims[it] } : std::nullopt; if (_iCurs != ICURS_MAGIC_ROCK) AnimInfo.SetNewAnimation(celSprite, numberOfFrames, 1, AnimationDistributionFlags::ProcessAnimationPending, 0, numberOfFrames); else diff --git a/Source/monster.h b/Source/monster.h index 748b9866c..8e9e520da 100644 --- a/Source/monster.h +++ b/Source/monster.h @@ -20,7 +20,6 @@ #include "monstdat.h" #include "spelldat.h" #include "textdat.h" -#include "utils/stdcompat/optional.hpp" namespace devilution { @@ -133,7 +132,7 @@ enum class LeaderRelation : uint8_t { }; struct AnimStruct { - [[nodiscard]] std::optional getCelSpritesForDirection(Direction direction) const + [[nodiscard]] OptionalCelSprite getCelSpritesForDirection(Direction direction) const { const byte *spriteData = celSpritesForDirections[static_cast(direction)]; if (spriteData == nullptr) diff --git a/Source/panels/charpanel.hpp b/Source/panels/charpanel.hpp index 7cb1fb8e2..a0525a885 100644 --- a/Source/panels/charpanel.hpp +++ b/Source/panels/charpanel.hpp @@ -2,7 +2,6 @@ #include "engine/cel_sprite.hpp" #include "engine/surface.hpp" -#include "utils/stdcompat/optional.hpp" namespace devilution { diff --git a/Source/panels/info_box.hpp b/Source/panels/info_box.hpp index b93e77ee2..ba69d4229 100644 --- a/Source/panels/info_box.hpp +++ b/Source/panels/info_box.hpp @@ -1,7 +1,6 @@ #pragma once #include "engine/cel_sprite.hpp" -#include "utils/stdcompat/optional.hpp" namespace devilution { diff --git a/Source/player.cpp b/Source/player.cpp index fa6eecd9b..f71b0706a 100644 --- a/Source/player.cpp +++ b/Source/player.cpp @@ -368,7 +368,7 @@ void StartWalk(int pnum, Displacement vel, Direction dir, bool pmWillBeCalled) StartWalkAnimation(player, dir, pmWillBeCalled); } -void SetPlayerGPtrs(const char *path, std::unique_ptr &data, std::array, 8> &anim, int width) +void SetPlayerGPtrs(const char *path, std::unique_ptr &data, std::array &anim, int width) { data = nullptr; data = LoadFileInMem(path); @@ -2188,7 +2188,7 @@ void Player::UpdatePreviewCelSprite(_cmd_id cmdId, Point point, uint16_t wParam1 return; LoadPlrGFX(*this, *graphic); - std::optional celSprites = AnimationData[static_cast(*graphic)].GetCelSpritesForDirection(dir); + OptionalCelSprite celSprites = AnimationData[static_cast(*graphic)].GetCelSpritesForDirection(dir); if (celSprites && previewCelSprite != celSprites) { previewCelSprite = celSprites; progressToNextGameTickWhenPreviewWasSet = gfProgressToNextGameTick; @@ -2343,7 +2343,7 @@ void NewPlrAnim(Player &player, player_graphic graphic, Direction dir, int8_t nu { LoadPlrGFX(player, graphic); - std::optional celSprite = player.AnimationData[static_cast(graphic)].GetCelSpritesForDirection(dir); + OptionalCelSprite celSprite = player.AnimationData[static_cast(graphic)].GetCelSpritesForDirection(dir); float previewShownGameTickFragments = 0.F; if (celSprite == player.previewCelSprite && !player.IsWalking()) diff --git a/Source/player.h b/Source/player.h index 6fe0ef23a..20ce8a7b0 100644 --- a/Source/player.h +++ b/Source/player.h @@ -196,14 +196,14 @@ struct PlayerAnimationData { /** * @brief CelSprites for the different directions */ - std::array, 8> CelSpritesForDirections; + std::array CelSpritesForDirections; /** * @brief Raw Data (binary) of the CL2 file. * Is referenced from CelSprite in celSpritesForDirections */ std::unique_ptr RawData; - [[nodiscard]] std::optional GetCelSpritesForDirection(Direction direction) const + [[nodiscard]] OptionalCelSprite GetCelSpritesForDirection(Direction direction) const { return CelSpritesForDirections[static_cast(direction)]; } @@ -234,7 +234,7 @@ struct Player { /** * @brief Contains a optional preview CelSprite that is displayed until the current command is handled by the game logic */ - std::optional previewCelSprite; + OptionalCelSprite previewCelSprite; /** * @brief Contains the progress to next game tick when previewCelSprite was set */ diff --git a/Source/quests.h b/Source/quests.h index 90a453609..fa3c8f55c 100644 --- a/Source/quests.h +++ b/Source/quests.h @@ -16,7 +16,6 @@ #include "panels/info_box.hpp" #include "textdat.h" #include "utils/attributes.h" -#include "utils/stdcompat/optional.hpp" namespace devilution { diff --git a/Source/utils/stdcompat/optional.hpp b/Source/utils/stdcompat/optional.hpp index ad6c5404a..90af7a275 100644 --- a/Source/utils/stdcompat/optional.hpp +++ b/Source/utils/stdcompat/optional.hpp @@ -7,6 +7,7 @@ #include // IWYU pragma: export #define optional experimental::optional #define nullopt experimental::nullopt +#define nullopt_t experimental::nullopt_t #else #error "Missing support for or " #endif