Porytiles
Loading...
Searching...
No Matches
animation.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm>
4#include <optional>
5#include <ranges>
6#include <set>
7#include <string>
8#include <vector>
9
15
16namespace porytiles {
17
18namespace anim {
19
20constexpr std::string g_tileset_anims_prefix = "gTilesetAnims_";
21constexpr std::string s_tileset_anims_prefix = "sTilesetAnims_";
22constexpr std::string porytiles_managed_prefix = "PorytilesManaged_";
23
24[[nodiscard]] inline std::string message_header(
25 const TextFormatter &format,
26 const std::string &anim_name,
27 const std::string &frame_name,
28 std::size_t internal_tile_index,
29 std::size_t subtile_row,
30 std::size_t subtile_col)
31{
32 return format.format(
33 "{} '{}' | frame '{}' | subtile {} | pixel {},{}",
34 FormatParam{"anim"},
35 FormatParam{anim_name},
36 FormatParam{frame_name},
37 FormatParam{std::to_string(internal_tile_index)},
38 FormatParam{std::to_string(subtile_row)},
39 FormatParam{std::to_string(subtile_col)});
40}
41
42[[nodiscard]] inline std::string message_header(
43 const TextFormatter &format,
44 const std::string &anim_name,
45 const std::string &frame_name,
46 std::size_t internal_tile_index)
47{
48 return format.format(
49 "{} '{}' | frame '{}' | subtile {}",
50 FormatParam{"anim"},
51 FormatParam{anim_name},
52 FormatParam{frame_name},
53 FormatParam{std::to_string(internal_tile_index)});
54}
55
56} // namespace anim
57
77template <SupportsTransparency PixelType>
78class Animation {
79 public:
80 Animation() = default;
81
82 explicit Animation(std::string name) : name_{std::move(name)} {}
83
84 Animation(std::string name, AnimParams params) : name_{std::move(name)}, params_{std::move(params)} {}
85
86 [[nodiscard]] const std::string &name() const
87 {
88 return name_;
89 }
90
91 [[nodiscard]] const AnimParams &params() const
92 {
93 return params_;
94 }
95
97 {
98 params_ = std::move(params);
99 }
100
106 [[nodiscard]] bool has_key_frame() const
107 {
108 return key_frame_.has_value();
109 }
110
121 [[nodiscard]] const AnimFrame<PixelType> &key_frame() const
122 {
123 if (!key_frame_.has_value()) {
124 panic("key_frame() called on Animation with no key frame set");
125 }
126 return *key_frame_;
127 }
128
130 {
131 key_frame_ = std::move(key_frame);
132 }
133
134 [[nodiscard]] const std::map<std::string, AnimFrame<PixelType>> &frames() const
135 {
136 return frames_;
137 }
138
139 [[nodiscard]] std::map<std::string, AnimFrame<PixelType>> &frames()
140 {
141 return frames_;
142 }
143
144 [[nodiscard]] std::vector<AnimFrame<PixelType>> frames_values() const
145 {
146 return frames_ | std::views::values | std::ranges::to<std::vector>();
147 }
148
154 [[nodiscard]] bool has_frames() const
155 {
156 return !frames_.empty();
157 }
158
164 [[nodiscard]] std::size_t frame_count() const
165 {
166 return frames_.size();
167 }
168
169 bool has_frame(const std::string &frame_name)
170 {
171 return frames_.contains(frame_name);
172 }
173
181 [[nodiscard]] const AnimFrame<PixelType> &frame_for_name(const std::string &frame_name) const
182 {
183 if (!frames_.contains(frame_name)) {
184 panic("anim '" + name_ + "' has no such frame '" + frame_name + "'");
185 }
186 return frames_.at(frame_name);
187 }
188
195 void put_frame(const std::string &name, AnimFrame<PixelType> frame)
196 {
197 frames_.emplace(name, std::move(frame));
198 }
199
220 [[nodiscard]] AnimFrame<PixelType> composite_frame(const PixelType &extrinsic_transparency) const
221 requires requires(const PixelType &p) { p.is_transparent(p); }
222 {
223 /*
224 * Note: this method currently only supports extrinsic transparency (Rgba32). If a future caller needs the same
225 * logic for IndexPixel (intrinsic transparency), this would need to be extended — but no caller exists today,
226 * so the function is constrained via the requires-clause to the Rgba32 case.
227 */
228
229 // Determine tile count from key frame or first regular frame
230 std::size_t tile_count = 0;
231 if (has_key_frame()) {
232 tile_count = key_frame().tile_count();
233 }
234 else if (has_frames()) {
235 tile_count = frames_.begin()->second.tile_count();
236 }
237 else {
238 panic("composite_frame() called on Animation with no key frame and no frames");
239 }
240
241 AnimFrame<PixelType> composite{"composite"};
242
243 for (std::size_t tile_idx = 0; tile_idx < tile_count; ++tile_idx) {
244 std::set<PixelType> all_colors;
245
246 // Collect from key frame (if present)
247 if (has_key_frame()) {
248 auto key_colors = key_frame().tile_at(tile_idx).unique_nontransparent_colors(extrinsic_transparency);
249 all_colors.merge(key_colors);
250 }
251
252 // Collect from regular frames
253 for (const auto &[name, frame] : frames_) {
254 auto colors = frame.tile_at(tile_idx).unique_nontransparent_colors(extrinsic_transparency);
255 all_colors.merge(colors);
256 }
257
258 // Create composite tile with all colors packed arbitrarily, first pixel is guaranteed extrinsic_transparent
259 PixelTile<PixelType> composite_tile{extrinsic_transparency};
260 std::size_t pix_idx = 1;
261 for (const auto &color : all_colors) {
262 if (pix_idx >= tile::size_pix) {
263 panic("pix_idx exceeded tile size in pixels");
264 }
265 composite_tile.set(pix_idx++, color);
266 }
267
268 if (composite_tile.unique_nontransparent_colors(extrinsic_transparency).size() >= pal::max_size) {
269 panic("composite tile had >= 16 colors");
270 }
271
272 composite.add_tile(std::move(composite_tile));
273 }
274
275 return composite;
276 }
277
278 private:
279 std::string name_;
280 AnimParams params_;
281 std::optional<AnimFrame<PixelType>> key_frame_;
282 std::map<std::string, AnimFrame<PixelType>> frames_;
283};
284
285} // namespace porytiles
Represents a single frame of an animation, containing tiles and a frame name.
Configuration parameters for a single tileset animation.
A complete tileset animation with name, configuration, and frame data.
Definition animation.hpp:78
const AnimParams & params() const
Definition animation.hpp:91
AnimFrame< PixelType > composite_frame(const PixelType &extrinsic_transparency) const
Returns the "composite" frame for this animation.
Animation(std::string name)
Definition animation.hpp:82
const AnimFrame< PixelType > & frame_for_name(const std::string &frame_name) const
Returns the frame with the specified name.
void params(AnimParams params)
Definition animation.hpp:96
bool has_frames() const
Checks if this animation has any frames.
const std::string & name() const
Definition animation.hpp:86
void key_frame(AnimFrame< PixelType > key_frame)
bool has_key_frame() const
Checks if this animation has a key frame set.
Animation(std::string name, AnimParams params)
Definition animation.hpp:84
const AnimFrame< PixelType > & key_frame() const
Returns the key frame of this animation.
void put_frame(const std::string &name, AnimFrame< PixelType > frame)
Adds a frame to this Animation frame map.
std::map< std::string, AnimFrame< PixelType > > & frames()
bool has_frame(const std::string &frame_name)
std::vector< AnimFrame< PixelType > > frames_values() const
const std::map< std::string, AnimFrame< PixelType > > & frames() const
std::size_t frame_count() const
Returns the number of frames in this animation.
A text parameter with associated styling for formatted output.
Abstract base class for applying text styling with context-aware formatting.
virtual std::string format(const std::string &format_str, const std::vector< FormatParam > &params) const
Formats a string with styled parameters using fmtlib syntax.
constexpr std::string porytiles_managed_prefix
Definition animation.hpp:22
constexpr std::string g_tileset_anims_prefix
Definition animation.hpp:20
constexpr std::string s_tileset_anims_prefix
Definition animation.hpp:21
std::string message_header(const TextFormatter &format, const std::string &anim_name, const std::string &frame_name, std::size_t internal_tile_index, std::size_t subtile_row, std::size_t subtile_col)
Definition animation.hpp:24
constexpr std::size_t max_size
Definition palette.hpp:19
constexpr std::size_t size_pix
void panic(const StringViewSourceLoc &s)
Unconditionally terminates the program with a panic message.
Definition panic.cpp:43