yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
gfx_tilemap_render_command.cc
Go to the documentation of this file.
2
3#include <array>
4#include <string>
5#include <vector>
6
7#include "absl/flags/declare.h"
8#include "absl/flags/flag.h"
9#include "absl/strings/str_format.h"
11#include "rom/rom.h"
12#include "util/indexed_png.h"
13#include "util/macro.h"
14#include "zelda3/game_data.h"
17
18// `--rom=<path>` is z3ed's global ROM flag (src/cli/flags.cc); cli_main.cc's
19// top-level arg loop consumes it into this flag and strips it from the
20// per-command argv before ArgumentParser ever sees it (so
21// parser.GetString("rom") always comes back empty), even for a command like
22// this one where RequiresRom() is false because the ROM is only needed for
23// some sources. Redeclaring it here (the same pattern cli_main.cc itself
24// uses) reads the same global value other z3ed commands' --rom= uses.
25ABSL_DECLARE_FLAG(std::string, rom);
26
27namespace yaze {
28namespace cli {
29namespace {
30
31constexpr char kDefaultPaletteLabel[] = "Oracle_Menu_Palette";
32
33std::vector<std::array<uint8_t, 4>> ToRgbaPalette(
34 const std::array<gfx::SnesColor, 32>& colors) {
35 std::vector<std::array<uint8_t, 4>> out(32);
36 for (int i = 0; i < 32; ++i) {
37 auto rgb = colors[i].rgb();
38 uint8_t alpha = (i % 4 == 0) ? 0 : 255; // color 0 of each sub-palette
39 out[i] = {static_cast<uint8_t>(rgb.x), static_cast<uint8_t>(rgb.y),
40 static_cast<uint8_t>(rgb.z), alpha};
41 }
42 return out;
43}
44
45absl::StatusOr<Rom> LoadRomArg(const char* why) {
46 std::string rom_path = absl::GetFlag(FLAGS_rom);
47 if (rom_path.empty()) {
48 return absl::InvalidArgumentError(
49 absl::StrFormat("--rom is required (%s)", why));
50 }
51 Rom rom;
52 RETURN_IF_ERROR(rom.LoadFromFile(rom_path));
53 return rom;
54}
55
56} // namespace
57
59 const resources::ArgumentParser& parser) {
60 RETURN_IF_ERROR(parser.RequireArgs({"tilemap", "out"}));
61
62 std::string chr_source = parser.GetString("chr-source").value_or("rom");
63 if (chr_source != "rom" && chr_source != "file") {
64 return absl::InvalidArgumentError("--chr-source must be 'rom' or 'file'");
65 }
66 if (chr_source == "file" && !parser.GetString("chr-file").has_value()) {
67 return absl::InvalidArgumentError("--chr-source file needs --chr-file");
68 }
69
70 std::string palette_source =
71 parser.GetString("palette-source").value_or("symbol");
72 if (palette_source != "symbol" && palette_source != "hud" &&
73 palette_source != "file" && palette_source != "asm") {
74 return absl::InvalidArgumentError(
75 "--palette-source must be 'symbol', 'asm', 'hud' or 'file'");
76 }
77 if (palette_source == "asm" && !parser.GetString("palette-asm").has_value()) {
78 return absl::InvalidArgumentError(
79 "--palette-source asm needs --palette-asm <Menu/menu_palette.asm>");
80 }
81 if (palette_source == "file" &&
82 !parser.GetString("palette-file").has_value()) {
83 return absl::InvalidArgumentError(
84 "--palette-source file needs --palette-file");
85 }
86 if (palette_source == "symbol" && !parser.GetString("symbols").has_value()) {
87 return absl::InvalidArgumentError(
88 "--palette-source symbol needs --symbols <sym file> (and --rom)");
89 }
90 return absl::OkStatus();
91}
92
94 Rom* /*rom*/, const resources::ArgumentParser& parser,
95 resources::OutputFormatter& formatter) {
96 const std::string tilemap_path = *parser.GetString("tilemap");
97 const std::string out_path = *parser.GetString("out");
98
100 RETURN_IF_ERROR(doc.LoadFromFile(tilemap_path));
101
102 // --- CHR source ---
103 const std::string chr_source = parser.GetString("chr-source").value_or("rom");
104 std::vector<uint8_t> chr_sheet;
105 if (chr_source == "file") {
107 *parser.GetString("chr-file")));
108 } else {
109 ASSIGN_OR_RETURN(Rom chr_rom, LoadRomArg("--chr-source rom needs a ROM"));
111 }
112
113 // --- Palette source ---
114 const std::string palette_source =
115 parser.GetString("palette-source").value_or("symbol");
116 std::array<gfx::SnesColor, 32> colors{};
117 std::string palette_label;
118 if (palette_source == "file") {
119 int offset = 2;
120 if (auto off = parser.GetString("palette-file-offset"); off.has_value()) {
121 ASSIGN_OR_RETURN(offset, parser.GetInt("palette-file-offset"));
122 }
124 *parser.GetString("palette-file"),
125 static_cast<size_t>(offset)));
126 } else if (palette_source == "asm") {
127 // Parses Oracle's Menu/menu_palette.asm directly; no ROM or symbol file
128 // needed, and it works when the project ROM is the base ROM (where the
129 // assembled Menu_Palette table reads all zero).
130 palette_label = parser.GetString("palette-label").value_or("Menu_Palette");
131 ASSIGN_OR_RETURN(colors,
133 *parser.GetString("palette-asm"), palette_label));
134 } else if (palette_source == "hud") {
135 ASSIGN_OR_RETURN(Rom pal_rom,
136 LoadRomArg("--palette-source hud needs a ROM"));
137 zelda3::GameData game_data;
138 zelda3::LoadOptions options;
139 options.load_graphics = false;
140 options.load_gfx_groups = false;
141 options.expand_rom = false;
142 options.populate_metadata = false;
143 RETURN_IF_ERROR(zelda3::LoadGameData(pal_rom, game_data, options));
145 } else {
146 palette_label =
147 parser.GetString("palette-label").value_or(kDefaultPaletteLabel);
148 ASSIGN_OR_RETURN(Rom pal_rom,
149 LoadRomArg("--palette-source symbol needs a ROM"));
151 RETURN_IF_ERROR(symbols.LoadSymbolFile(*parser.GetString("symbols"),
154 pal_rom, symbols, palette_label));
155 }
156
157 // --- Render ---
158 auto chr_fn = zelda3::MakeChrPixelFn(chr_sheet);
159 std::vector<uint8_t> indexed = doc.RenderIndexed(chr_fn);
160 std::vector<std::array<uint8_t, 4>> palette = ToRgbaPalette(colors);
161
163 std::vector<uint8_t> png,
165 palette));
167
168 formatter.AddField("tilemap", tilemap_path);
169 formatter.AddField("out", out_path);
170 formatter.AddField("rows", doc.rows());
171 formatter.AddField("cols", doc.cols());
172 formatter.AddField("width", doc.render_width());
173 formatter.AddField("height", doc.render_height());
174 formatter.AddField("chr_source", chr_source);
175 formatter.AddField("palette_source", palette_source);
176 if (palette_source == "asm") {
177 formatter.AddField("palette_asm", *parser.GetString("palette-asm"));
178 }
179 if (!palette_label.empty()) {
180 formatter.AddField("palette_label", palette_label);
181 }
182 return absl::OkStatus();
183}
184
185} // namespace cli
186} // namespace yaze
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
Definition rom.h:49
absl::Status LoadFromFile(const std::string &filename, const LoadOptions &options=LoadOptions::Defaults())
Definition rom.cc:491
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::Status ValidateArgs(const resources::ArgumentParser &parser) override
Validate command arguments.
Utility for parsing common CLI argument patterns.
std::optional< std::string > GetString(const std::string &name) const
Parse a named argument (e.g., –format=json or –format json)
absl::Status RequireArgs(const std::vector< std::string > &required) const
Validate that required arguments are present.
absl::StatusOr< int > GetInt(const std::string &name) const
Parse an integer argument (supports hex with 0x prefix)
Utility for consistent output formatting across commands.
void AddField(const std::string &key, const std::string &value)
Add a key-value pair.
Provider for symbol (label) resolution in disassembly.
absl::Status LoadSymbolFile(const std::string &path, SymbolFormat format=SymbolFormat::kAuto)
Load symbols from a .sym file (various formats)
std::vector< uint8_t > RenderIndexed(const ChrPixelFn &chr) const
absl::Status LoadFromFile(const std::string &path)
ABSL_DECLARE_FLAG(std::string, rom)
#define ASSIGN_OR_RETURN(type_variable_name, expression)
Definition macro.h:62
std::vector< std::array< uint8_t, 4 > > ToRgbaPalette(const std::array< gfx::SnesColor, 32 > &colors)
absl::Status WriteBinaryFile(const std::string &path, const std::vector< uint8_t > &bytes)
absl::StatusOr< std::vector< uint8_t > > EncodeIndexedPng(int width, int height, const std::vector< uint8_t > &indices, const std::vector< std::array< uint8_t, 4 > > &palette)
absl::StatusOr< std::array< gfx::SnesColor, 32 > > ResolveMenuPaletteFromHud(const GameData &game_data)
absl::StatusOr< std::array< gfx::SnesColor, 32 > > ResolveMenuPaletteFromFile(const std::string &path, size_t byte_offset)
absl::StatusOr< std::vector< uint8_t > > ResolveMenuChrFromRom(const Rom &rom)
absl::Status LoadGameData(Rom &rom, GameData &data, const LoadOptions &options)
Loads all Zelda3-specific game data from a generic ROM.
Definition game_data.cc:123
absl::StatusOr< std::vector< uint8_t > > ResolveMenuChrFromFile(const std::string &path)
absl::StatusOr< std::array< gfx::SnesColor, 32 > > ResolveMenuPaletteFromAsm(const std::string &path, const std::string &label)
absl::StatusOr< std::array< gfx::SnesColor, 32 > > ResolveMenuPaletteFromSymbol(const Rom &rom, const emu::debug::SymbolProvider &symbols, const std::string &label)
MenuTilemapDocument::ChrPixelFn MakeChrPixelFn(const std::vector< uint8_t > &sheet_8bpp_indexed)
#define RETURN_IF_ERROR(expr)
Definition snes.cc:22