1#ifndef YAZE_APP_EDITOR_SPRITE_SPRITE_AUTHORING_H_
2#define YAZE_APP_EDITOR_SPRITE_SPRITE_AUTHORING_H_
8#include "absl/status/statusor.h"
22 for (
size_t i = 0; i < 8; ++i) {
25 int index = row.index;
26 if (row.group ==
"auto") {
29 }
else if (row.group ==
"global_sprites")
31 else if (row.group ==
"sprites_aux1")
33 else if (row.group ==
"sprites_aux2")
35 else if (row.group ==
"sprites_aux3")
37 if (!group || index < 0 ||
static_cast<size_t>(index) >= group->
size())
38 return absl::OutOfRangeError(
39 "Sprite palette binding unavailable in loaded ROM");
46 const std::string& adapter) {
47 if (adapter ==
"literal_v1")
48 return absl::OkStatus();
49 if (adapter !=
"oracle_maple_v1")
50 return absl::InvalidArgumentError(
"Unsupported draw adapter");
52 for (
const auto& tile : frame.Tiles)
53 if (tile.x != 128 || !tile.size)
54 return absl::FailedPreconditionError(
55 "Maple's current driver requires X offset 0 and 16x16 tiles");
56 return absl::OkStatus();
74 for (
auto it = layout.
tiles.rbegin(); it != layout.
tiles.rend(); ++it) {
75 const auto& tile = *it;
77 tile.flip_x, tile.flip_y, tile.tile_id,
78 tile.palette, tile.size_16x16, 3);
85 if (frames.size() >=
kMaxFrames || copy_from < -1 ||
86 copy_from >=
static_cast<int>(frames.size()))
90 frames.push_back(std::move(frame));
96 if (frames.size() <= 1 || index < 0 ||
97 index >=
static_cast<int>(frames.size()))
99 frames.erase(frames.begin() + index);
100 const int last = std::min(255,
static_cast<int>(frames.size()) - 1);
102 auto remap = [=](
int endpoint) {
103 return std::clamp(endpoint - (endpoint > index ? 1 : 0), 0, last);
105 animation.frame_start = remap(animation.frame_start);
106 animation.frame_end =
107 std::max<int>(animation.frame_start, remap(animation.frame_end));
117 return absl::InvalidArgumentError(
"Draw export needs 1 to 256 frames");
118 std::ostringstream starts, counts, xs, ys, chars, properties, sizes;
120 for (
size_t i = 0; i < sprite.
editor.
Frames.size(); ++i) {
122 if (frame.Tiles.empty() || total + frame.Tiles.size() > 128)
123 return absl::InvalidArgumentError(
124 "Draw export needs nonempty frames and at most 128 total tiles (word "
131 counts << frame.Tiles.size() - 1;
132 for (
const auto& tile : frame.Tiles) {
133 if (tile.id > 511 || tile.palette > 7 || tile.priority > 3 || tile.z != 0)
134 return absl::InvalidArgumentError(
135 "Draw export requires tile 0..511, palette 0..7, priority 0..3 and "
146 chars << (tile.id & 255);
147 properties << ((tile.mirror_y ? 128 : 0) | (tile.mirror_x ? 64 : 0) |
148 (tile.priority << 4) | (tile.palette << 1) |
150 sizes << (tile.size ? 2 : 0);
154 "; Yaze draw-table candidate. Review driver, bank and OAM "
156 ".start_index\n db " + starts.str() +
"\n.nbr_of_tiles\n db " +
157 counts.str() +
"\n.x_offsets\n dw " + xs.str() +
158 "\n.y_offsets\n dw " + ys.str() +
"\n.chr\n db " + chars.str() +
159 "\n.properties\n db " + properties.str() +
"\n.sizes\n db " +
166 size_t frame_count,
float delta,
int& frame,
168 if (!frame_count || !std::isfinite(delta) || delta < 0)
170 const int last = std::min<size_t>(255, frame_count - 1);
171 const int start = std::min<int>(animation.
frame_start, last);
172 const int end = std::clamp<int>(animation.
frame_end, start, last);
173 const int before = frame;
174 frame = std::clamp(frame, start, end);
175 const double duration = std::max<int>(1, animation.
frame_speed) / 60.0;
176 const double elapsed =
178 (std::isfinite(remainder) && remainder > 0 ? double(remainder) : 0.0);
179 const double steps = std::floor(elapsed / duration);
180 const int length = end - start + 1;
182 (frame - start +
static_cast<int>(std::fmod(steps, length))) % length;
183 remainder =
static_cast<float>(std::fmod(elapsed, duration));
184 return frame != before;
absl::StatusOr< std::string > ExportDrawTables(const zsprite::ZSprite &sprite)
int OffsetX(const zsprite::OamTile &tile)
absl::Status ValidateDrawAdapter(const zsprite::ZSprite &sprite, const std::string &adapter)
bool Advance(const zsprite::AnimationGroup &animation, size_t frame_count, float delta, int &frame, float &remainder)
absl::StatusOr< gfx::PaletteGroup > BindPaletteRows(const project::SpriteAssetBinding &binding, const gfx::PaletteGroup &defaults, const gfx::PaletteGroup &global, const gfx::PaletteGroup &aux1, const gfx::PaletteGroup &aux2, const gfx::PaletteGroup &aux3)
int OffsetY(const zsprite::OamTile &tile)
constexpr size_t kMaxFrames
bool AppendFrame(zsprite::ZSprite &sprite, int copy_from=-1)
zsprite::Frame CopyVanillaLayout(const zelda3::SpriteOamLayout &layout)
bool DeleteFrame(zsprite::ZSprite &sprite, int index)
std::vector< OamTile > Tiles
std::vector< Frame > Frames
std::vector< AnimationGroup > animations
Represents a group of palettes.
auto palette(int i) const
void AddPalette(SnesPalette pal)
std::array< SpritePaletteBinding, 8 > palette_rows
Complete OAM layout for a vanilla sprite.
std::vector< SpriteOamEntry > tiles