You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
344 lines
6.5 KiB
344 lines
6.5 KiB
#pragma once |
|
|
|
#include <memory> |
|
#include <utility> |
|
|
|
#include "appfat.h" |
|
#include "engine/cel_header.hpp" |
|
#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). |
|
* Does not own the data. |
|
*/ |
|
class CelSprite { |
|
public: |
|
CelSprite(const byte *data, uint16_t width) |
|
: data_ptr_(data) |
|
, width_(width) |
|
{ |
|
} |
|
|
|
CelSprite(const byte *data, const uint16_t *widths) |
|
: data_ptr_(data) |
|
, width_(widths) |
|
{ |
|
} |
|
|
|
CelSprite(const byte *data, PointerOrValue<uint16_t> widths) |
|
: data_ptr_(data) |
|
, width_(widths) |
|
{ |
|
} |
|
|
|
explicit CelSprite(const OwnedCelSprite &owned); |
|
|
|
CelSprite(const CelSprite &) = default; |
|
CelSprite(CelSprite &&) noexcept = default; |
|
CelSprite &operator=(const CelSprite &) = default; |
|
CelSprite &operator=(CelSprite &&) noexcept = default; |
|
|
|
[[nodiscard]] const byte *Data() const |
|
{ |
|
return data_ptr_; |
|
} |
|
|
|
[[nodiscard]] uint16_t Width(std::size_t frame = 0) const |
|
{ |
|
return width_.HoldsPointer() ? width_.AsPointer()[frame] : width_.AsValue(); |
|
} |
|
|
|
[[nodiscard]] PointerOrValue<uint16_t> widthOrWidths() const |
|
{ |
|
return width_; |
|
} |
|
|
|
[[nodiscard]] bool operator==(CelSprite other) const |
|
{ |
|
return data_ptr_ == other.data_ptr_; |
|
} |
|
[[nodiscard]] bool operator!=(CelSprite other) const |
|
{ |
|
return data_ptr_ != other.data_ptr_; |
|
} |
|
|
|
private: |
|
// for OptionalCelSprite |
|
CelSprite() |
|
: data_ptr_(nullptr) |
|
, width_(nullptr) |
|
{ |
|
} |
|
|
|
const byte *data_ptr_; |
|
PointerOrValue<uint16_t> width_; |
|
|
|
friend class OptionalCelSprite; |
|
}; |
|
|
|
/** |
|
* @brief Equivalent to `std::optional<CelSprite>` but smaller. |
|
*/ |
|
class OptionalCelSprite { |
|
public: |
|
OptionalCelSprite() = default; |
|
|
|
OptionalCelSprite(CelSprite sprite) |
|
: sprite_(sprite) |
|
{ |
|
} |
|
|
|
explicit OptionalCelSprite(const OwnedCelSprite &owned); |
|
|
|
OptionalCelSprite(std::nullopt_t) |
|
: OptionalCelSprite() |
|
{ |
|
} |
|
|
|
template <typename... Args> |
|
CelSprite &emplace(Args &&...args) |
|
{ |
|
sprite_ = CelSprite(std::forward<Args>(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_; |
|
}; |
|
|
|
class OptionalOwnedCelSprite; |
|
|
|
/** |
|
* Stores a CEL or CL2 sprite and its width(s). |
|
* Owns the data. |
|
*/ |
|
class OwnedCelSprite { |
|
public: |
|
OwnedCelSprite(std::unique_ptr<byte[]> data, uint16_t width) |
|
: data_(std::move(data)) |
|
, width_(width) |
|
{ |
|
} |
|
|
|
OwnedCelSprite(std::unique_ptr<byte[]> data, const uint16_t *widths) |
|
: data_(std::move(data)) |
|
, width_(widths) |
|
{ |
|
} |
|
|
|
OwnedCelSprite(std::unique_ptr<byte[]> data, PointerOrValue<uint16_t> widths) |
|
: data_(std::move(data)) |
|
, width_(widths) |
|
{ |
|
} |
|
|
|
OwnedCelSprite(OwnedCelSprite &&) noexcept = default; |
|
OwnedCelSprite &operator=(OwnedCelSprite &&) noexcept = default; |
|
|
|
[[nodiscard]] byte *MutableData() |
|
{ |
|
return data_.get(); |
|
} |
|
|
|
std::unique_ptr<byte[]> data() && |
|
{ |
|
return std::move(data_); |
|
} |
|
|
|
private: |
|
// for OptionalOwnedCelSprite. |
|
OwnedCelSprite() |
|
: data_(nullptr) |
|
, width_(nullptr) |
|
{ |
|
} |
|
|
|
std::unique_ptr<byte[]> data_; |
|
PointerOrValue<uint16_t> width_; |
|
|
|
friend class CelSprite; |
|
friend class OptionalOwnedCelSprite; |
|
}; |
|
|
|
/** |
|
* @brief Equivalent to `std::optional<OwnedCelSprite>` but smaller. |
|
*/ |
|
class OptionalOwnedCelSprite { |
|
public: |
|
OptionalOwnedCelSprite() = default; |
|
|
|
OptionalOwnedCelSprite(OwnedCelSprite &&sprite) |
|
: sprite_(std::move(sprite)) |
|
{ |
|
} |
|
|
|
OptionalOwnedCelSprite(std::nullopt_t) |
|
: OptionalOwnedCelSprite() |
|
{ |
|
} |
|
|
|
template <typename... Args> |
|
OwnedCelSprite &emplace(Args &&...args) |
|
{ |
|
sprite_ = OwnedCelSprite(std::forward<Args>(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) |
|
: CelSprite(owned.data_.get(), owned.width_) |
|
{ |
|
} |
|
|
|
inline OptionalCelSprite::OptionalCelSprite(const OwnedCelSprite &owned) |
|
{ |
|
sprite_ = CelSprite { owned }; |
|
} |
|
|
|
struct CelSpriteWithFrameHeight { |
|
CelSprite sprite; |
|
unsigned frameHeight; |
|
}; |
|
|
|
struct CelFrameWithHeight { |
|
CelSprite sprite; |
|
uint16_t frameHeight; |
|
uint16_t frame; |
|
|
|
[[nodiscard]] uint16_t width() const |
|
{ |
|
return sprite.Width(frame); |
|
} |
|
[[nodiscard]] uint16_t height() const |
|
{ |
|
return frameHeight; |
|
} |
|
}; |
|
|
|
struct OwnedCelSpriteWithFrameHeight { |
|
OwnedCelSprite ownedSprite; |
|
uint16_t frameHeight; |
|
|
|
[[nodiscard]] CelFrameWithHeight sprite() const |
|
{ |
|
return { CelSprite { ownedSprite }, frameHeight, 0 }; |
|
} |
|
}; |
|
|
|
struct CelSpriteSheetWithFrameHeight { |
|
CelSprite sheet; |
|
uint16_t frameHeight; |
|
|
|
[[nodiscard]] unsigned numFrames() const |
|
{ |
|
return LoadLE32(sheet.Data()); |
|
} |
|
|
|
[[nodiscard]] CelFrameWithHeight sprite(uint16_t frame) const |
|
{ |
|
return { CelSprite { sheet }, frameHeight, frame }; |
|
} |
|
}; |
|
|
|
struct OwnedCelSpriteSheetWithFrameHeight { |
|
OwnedCelSprite ownedSprite; |
|
uint16_t frameHeight; |
|
|
|
[[nodiscard]] CelSpriteSheetWithFrameHeight sheet() const |
|
{ |
|
return CelSpriteSheetWithFrameHeight { CelSprite { ownedSprite }, frameHeight }; |
|
} |
|
|
|
[[nodiscard]] CelFrameWithHeight sprite(uint16_t frame) const |
|
{ |
|
return CelFrameWithHeight { CelSprite { ownedSprite }, frameHeight, frame }; |
|
} |
|
}; |
|
|
|
} // namespace devilution
|
|
|