6#include "absl/strings/str_format.h"
15 constexpr const char* kLabels[] = {
"Unflipped",
"Horizontal",
"Vertical",
16 "Horizontal + vertical"};
18 for (
int orientation = 0; orientation < 4; ++orientation) {
25 label += kLabels[orientation];
35 if (!owner || binding.owner != owner)
36 return absl::FailedPreconditionError(
"Palette address session mismatch");
37 if (binding.colors[0] || target.
palette.
size() != 8 || binding.row < 2 ||
39 (binding.half_offset != 0 && binding.half_offset != 8)) {
40 return absl::FailedPreconditionError(
"Invalid raw palette address mapping");
42 for (
int raw = 1; raw < 8; ++raw) {
43 if (!binding.colors[raw])
44 return absl::FailedPreconditionError(
"Nonzero palette index is unmapped");
47 return color.status();
48 const auto expected = color->rom_color();
49 const auto displayed = target.
palette[raw].rom_color();
50 if (expected.red != displayed.red || expected.green != displayed.green ||
51 expected.blue != displayed.blue) {
52 return absl::FailedPreconditionError(
53 "Displayed palette differs from its writable source; refresh the "
57 return absl::OkStatus();
65 row < 2 ?
"HUD palette addressing is unavailable for this operation."
66 :
"Animated, overridden or unresolved palette source has no "
68 if (!owner || row < 0 || row >= 8 || (half_offset != 0 && half_offset != 8))
71 binding.
owner = owner;
72 binding.
row =
static_cast<uint8_t
>(row);
73 binding.
half_offset =
static_cast<uint8_t
>(half_offset);
74 for (
int raw = 1; raw < 8; ++raw) {
75 binding.
colors[raw] = addresses[row * 16 + half_offset + raw];
93 return absl::FailedPreconditionError(
94 "Graphics source changed; reopen Edit Graphics from the source.");
96 for (
size_t i = 0; i < context.
targets.size(); ++i) {
97 const auto& old = context.
targets[i];
98 const auto& next = refreshed.
targets[i];
99 if (old.sheet_id != next.sheet_id || old.tile_index != next.tile_index ||
100 old.label != next.label ||
101 old.source_orientation_mask != next.source_orientation_mask ||
102 next.palette.size() != 8) {
103 return absl::FailedPreconditionError(
104 "Graphics source changed; reopen Edit Graphics from the source.");
106 if (next.writable_palette) {
113 for (
size_t i = 0; i < context.
targets.size(); ++i) {
114 context.
targets[i].writable_palette =
115 std::move(refreshed.
targets[i].writable_palette);
116 context.
targets[i].palette_address_limitation =
117 std::move(refreshed.
targets[i].palette_address_limitation);
118 context.
targets[i].palette = std::move(refreshed.
targets[i].palette);
121 return absl::OkStatus();
127 if (!owner || room.
game_data() != owner) {
128 return absl::FailedPreconditionError(
"Dungeon graphics session mismatch");
130 auto tiles =
object.GetTiles();
132 return tiles.status();
136 return patterns.status();
137 std::vector<gfx::TileInfo> source_tiles;
142 return parsed.status();
143 source_tiles = std::move(*parsed);
144 tiles = std::span<const gfx::TileInfo>(source_tiles);
147 context.
owner = owner;
149 absl::StrFormat(
"Room %03X / Object %03X / Main %02X", room.
id(),
155 const auto blocks = room.
blocks();
156 std::map<std::pair<uint16_t, uint8_t>,
size_t> target_indices;
157 for (
const auto& tile : *tiles) {
158 if (tile.id_ >= 512 || tile.palette_ >= 8 ||
159 (tile.id_ >= 0x1B0 && tile.id_ < 0x1D0)) {
161 "Animated or unmapped tiles are omitted from pixel editing.";
164 const uint8_t orientation =
165 (tile.horizontal_mirror_ ? 1 : 0) | (tile.vertical_mirror_ ? 2 : 0);
166 const uint8_t orientation_bit = 1 << orientation;
167 const auto [entry, inserted] = target_indices.emplace(
168 std::make_pair(tile.id_, tile.palette_), context.
targets.size());
170 context.
targets[entry->second].source_orientation_mask |= orientation_bit;
173 const int slot = tile.id_ / 64;
174 const int offset = tile.palette_ * 16;
175 if (colors.size() <
static_cast<size_t>(offset + 16)) {
176 return absl::FailedPreconditionError(
"Room palette is not rendered");
179 std::vector<gfx::SnesColor> palette;
180 for (
int index = 0; index < 8; ++index) {
181 const auto& color = colors[offset + (index == 0 ? 0 : half + index)];
182 palette.emplace_back(color.r, color.g, color.b);
185 .sheet_id = blocks[slot],
186 .tile_index =
static_cast<uint16_t
>(tile.id_ % 64),
187 .label = absl::StrFormat(
"Tile %03X / slot %d / sheet %02X / row %d %s",
188 tile.id_, slot, blocks[slot], tile.palette_,
189 half == 8 ?
"right" :
"left"),
191 .source_orientation_mask = orientation_bit,
195 tile.palette_, half);
198 return absl::UnimplementedError(
199 "This object's tiles do not yet have an editable graphics source");
Represents a palette of colors for the Super Nintendo Entertainment System (SNES).
static CustomObjectManager & Get()
absl::StatusOr< std::shared_ptr< const DungeonTilePatterns > > GetTilePatterns()
Direct ROM parser for dungeon objects.
absl::StatusOr< std::vector< gfx::TileInfo > > ParseObject(int16_t object_id)
Parse object data directly from ROM.
const std::vector< SDL_Color > & rendered_palette() const
int BackgroundPaletteOffset(int slot) const
const PaletteAddressMap & rendered_palette_addresses() const
uint8_t resolved_main_blockset() const
Editors are the view controllers for the application.
absl::Status UpdateGraphicsContextPalettes(GraphicsEditContext &context, GraphicsEditContext refreshed)
void ResolveGraphicsPaletteAddressing(GraphicsEditTarget &target, const zelda3::GameData *owner, const zelda3::PaletteAddressMap &addresses, int row, int half_offset)
absl::StatusOr< GraphicsEditContext > MakeDungeonGraphicsEditContext(const zelda3::Room &room, const zelda3::RoomObject &object, const zelda3::GameData *owner)
absl::Status ValidateGraphicsPaletteAddressing(const GraphicsEditTarget &target, const zelda3::GameData *owner)
ResolvedGraphicsContext DescribeDungeonGraphicsContext(const Room &room, const GraphicsContextIdentity &identity)
ObjectLayerSemantics GetEffectiveObjectLayerSemantics(const RoomObject &object)
const char * ObjectRenderRoutingDisplayLabel(const ObjectLayerSemantics &semantics)
bool HasActiveCustomObjectOverride(const RoomObject &object)
absl::StatusOr< gfx::SnesColor > ReadPaletteColor(const GameData &owner, const PaletteColorAddress &address)
std::array< std::optional< PaletteColorAddress >, 128 > PaletteAddressMap
std::string drawing_description
zelda3::ResolvedGraphicsContext resolved
std::vector< GraphicsEditTarget > targets
const zelda3::GameData * owner
std::string SourceOrientationLabel() const
std::optional< GraphicsPaletteAddressing > writable_palette
uint8_t source_orientation_mask
std::string palette_address_limitation
std::array< std::optional< zelda3::PaletteColorAddress >, 8 > colors
const zelda3::GameData * owner