yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
snes_palette.cc
Go to the documentation of this file.
3
5
6#include <array>
7#include <cstdint>
8#include <cstdlib>
9#include <cstring>
10#include <limits>
11#include <stdexcept>
12#include <string_view>
13#include <utility>
14#include <vector>
15
16#include "absl/status/status.h"
17#include "absl/status/statusor.h"
18#include "absl/strings/str_format.h"
20#include "imgui/imgui.h"
21#include "rom/snes.h"
22#include "util/macro.h"
24
25namespace yaze::gfx {
26
28 assert((sizeof(data) % 4 == 0) && (sizeof(data) <= 32));
29 for (unsigned i = 0; i < sizeof(data); i += 2) {
30 SnesColor col;
31 col.set_snes(static_cast<uint8_t>(data[i + 1]) << 8);
32 col.set_snes(col.snes() | static_cast<uint8_t>(data[i]));
33 colors_[size_++] = col;
34 }
35}
36
37SnesPalette::SnesPalette(const unsigned char* snes_pal) {
38 assert((sizeof(snes_pal) % 4 == 0) && (sizeof(snes_pal) <= 32));
39 for (unsigned i = 0; i < sizeof(snes_pal); i += 2) {
40 SnesColor col;
41 col.set_snes(snes_pal[i + 1] << (uint16_t)8);
42 col.set_snes(col.snes() | snes_pal[i]);
43 colors_[size_++] = col;
44 }
45}
46
47SnesPalette::SnesPalette(const char* data, size_t length) : size_(0) {
48 for (size_t i = 0; i < length && size_ < kMaxColors; i += 2) {
49 uint16_t color = (static_cast<uint8_t>(data[i + 1]) << 8) |
50 static_cast<uint8_t>(data[i]);
51 colors_[size_++] = SnesColor(color);
52 }
53}
54
55SnesPalette::SnesPalette(const std::vector<uint16_t>& colors) : size_(0) {
56 for (const auto& color : colors) {
57 if (size_ < kMaxColors) {
58 colors_[size_++] = SnesColor(color);
59 }
60 }
61}
62
63SnesPalette::SnesPalette(const std::vector<SnesColor>& colors) : size_(0) {
64 for (const auto& color : colors) {
65 if (size_ < kMaxColors) {
66 colors_[size_++] = color;
67 }
68 }
69}
70
71SnesPalette::SnesPalette(const std::vector<ImVec4>& colors) : size_(0) {
72 for (const auto& color : colors) {
73 if (size_ < kMaxColors) {
74 colors_[size_++] = SnesColor(color);
75 }
76 }
77}
78
83namespace palette_group_internal {
84absl::StatusOr<ResolvedPaletteRecord> ResolvePaletteRecord(
85 std::optional<uint32_t> snes_address, uint64_t color_count,
86 size_t normalized_rom_size) {
87 if (!snes_address.has_value()) {
88 return absl::FailedPreconditionError("Palette record storage is unbound");
89 }
90 if (color_count > std::numeric_limits<uint32_t>::max() / 2u) {
91 return absl::OutOfRangeError("Palette record byte size overflows");
92 }
93 if (color_count != 35 && color_count != 21) {
94 return absl::InvalidArgumentError(
95 "Native palette records require 35 or 21 colors");
96 }
97 const uint32_t address = *snes_address;
98 if (address > 0xFFFFFFu || (address & 0x8000u) == 0) {
99 return absl::InvalidArgumentError("Palette address is not mapped LoROM");
100 }
101 if (((address >> 16) & 0x7Fu) != 0x1Bu) {
102 return absl::FailedPreconditionError(
103 "Palette bank ABI is bound only to bank 1B");
104 }
105 const size_t bytes = static_cast<size_t>(color_count) * 2;
106 if (bytes > 0x10000u - (address & 0xFFFFu)) {
107 return absl::OutOfRangeError("Palette record crosses its native bank");
108 }
109 const uint32_t pc = yaze::SnesToPc(address);
110 if (yaze::PcToSnes(pc) != (address & 0x7FFFFFu)) {
111 return absl::InvalidArgumentError("Palette address does not round trip");
112 }
113 if (pc > normalized_rom_size || bytes > normalized_rom_size - pc) {
114 return absl::OutOfRangeError("Palette record exceeds normalized ROM body");
115 }
117 static_cast<int>(color_count));
118}
119
120absl::StatusOr<uint32_t> ResolvedPaletteRecord::ColorAddress(
121 int color_index) const {
122 if (color_index < 0 || color_index >= color_count_) {
123 return absl::OutOfRangeError(
124 "Palette color selector is outside its record");
125 }
126 return pc_address_ + static_cast<uint32_t>(color_index) * 2u;
127}
128
129absl::StatusOr<std::pair<uint32_t, uint32_t>>
131 const auto address = ColorAddress(color_index);
132 if (!address.ok()) {
133 return address.status();
134 }
135 return std::make_pair(*address, *address + 2u);
136}
137
138namespace {
149} // namespace
150
154
158
160 const auto* metadata = OverworldMetadata(kind);
161 if (!metadata) {
162 return 0;
163 }
164 return metadata->palette_count +
165 (proposed_ ? (kind == OverworldPaletteKind::kMain ? 1 : 2) : 0);
166}
167
168absl::StatusOr<ResolvedPaletteRecord> OverworldPaletteLayout::Resolve(
169 OverworldPaletteKind kind, int selector, size_t normalized_rom_size) const {
170 const auto* metadata = OverworldMetadata(kind);
171 if (!metadata) {
172 return absl::InvalidArgumentError("Unknown overworld palette kind");
173 }
174 if (selector < 0 || selector >= RecordCount(kind)) {
175 return absl::OutOfRangeError(
176 "Palette record selector is outside its layout");
177 }
178 if (selector >= metadata->palette_count) {
179 return ResolvePaletteRecord(std::nullopt, metadata->colors_per_palette,
180 normalized_rom_size);
181 }
182 const uint64_t pc =
183 metadata->base_address +
184 static_cast<uint64_t>(selector) * metadata->colors_per_palette * 2u;
185 if (pc > std::numeric_limits<uint32_t>::max()) {
186 return absl::OutOfRangeError("Palette record address overflows");
187 }
188 return ResolvePaletteRecord(yaze::PcToSnes(static_cast<uint32_t>(pc)),
189 metadata->colors_per_palette,
190 normalized_rom_size);
191}
192
195 const std::vector<uint8_t>& normalized_rom_data, PaletteGroup& group) {
196 const int count = layout.RecordCount(kind);
197 if (count <= 0) {
198 return absl::InvalidArgumentError("Unknown overworld palette kind");
199 }
200 std::vector<ResolvedPaletteRecord> records;
201 records.reserve(count);
202 for (int selector = 0; selector < count; ++selector) {
203 auto record = layout.Resolve(kind, selector, normalized_rom_data.size());
204 if (!record.ok()) {
205 return record.status();
206 }
207 records.push_back(*record);
208 }
209 // Complete preflight before appending any colors or changing group state.
210 for (const auto& record : records) {
212 record.pc_address(), record.color_count(), normalized_rom_data.data()));
213 }
214 return absl::OkStatus();
215}
216
217absl::Status LoadOverworldMainPalettes(const std::vector<uint8_t>& rom_data,
218 gfx::PaletteGroupMap& palette_groups) {
221 palette_groups.overworld_main);
222}
223
225 const std::vector<uint8_t>& rom_data,
226 gfx::PaletteGroupMap& palette_groups) {
229 palette_groups.overworld_aux);
230}
231
233 const std::vector<uint8_t>& rom_data,
234 gfx::PaletteGroupMap& palette_groups) {
235 auto data = rom_data.data();
236 size_t rom_size = rom_data.size();
237 for (int i = 0; i < 14; i++) {
238 int offset = kOverworldPaletteAnimated + (i * (7 * 2));
239 int num_colors = 7;
240 if (offset < 0 || offset + (num_colors * 2) > static_cast<int>(rom_size)) {
241 return absl::OutOfRangeError(absl::StrFormat(
242 "Overworld animated palette %d out of bounds: offset %d, size %zu", i,
243 offset, rom_size));
244 }
245 palette_groups.overworld_animated.AddPalette(
246 gfx::ReadPaletteFromRom(offset, num_colors, data));
247 }
248 return absl::OkStatus();
249}
250
251absl::Status LoadHUDPalettes(const std::vector<uint8_t>& rom_data,
252 gfx::PaletteGroupMap& palette_groups) {
253 auto data = rom_data.data();
254 size_t rom_size = rom_data.size();
255 for (int i = 0; i < 2; i++) {
256 int offset = kHudPalettes + (i * 64);
257 int num_colors = 32;
258 if (offset < 0 || offset + (num_colors * 2) > static_cast<int>(rom_size)) {
259 return absl::OutOfRangeError(
260 absl::StrFormat("HUD palette %d out of bounds: offset %d, size %zu",
261 i, offset, rom_size));
262 }
263 palette_groups.hud.AddPalette(
264 gfx::ReadPaletteFromRom(offset, num_colors, data));
265 }
266 return absl::OkStatus();
267}
268
269absl::Status LoadGlobalSpritePalettes(const std::vector<uint8_t>& rom_data,
270 gfx::PaletteGroupMap& palette_groups) {
271 auto data = rom_data.data();
272 size_t rom_size = rom_data.size();
273
274 // Check first palette
275 int offset1 = kGlobalSpritesLW;
276 int num_colors1 = 60;
277 if (offset1 < 0 || offset1 + (num_colors1 * 2) > static_cast<int>(rom_size)) {
278 return absl::OutOfRangeError(absl::StrFormat(
279 "Global sprite LW palette out of bounds: offset %d, size %zu", offset1,
280 rom_size));
281 }
282 palette_groups.global_sprites.AddPalette(
283 gfx::ReadPaletteFromRom(offset1, num_colors1, data));
284
285 // Check second palette
286 int offset2 = kGlobalSpritePalettesDW;
287 int num_colors2 = 60;
288 if (offset2 < 0 || offset2 + (num_colors2 * 2) > static_cast<int>(rom_size)) {
289 return absl::OutOfRangeError(absl::StrFormat(
290 "Global sprite DW palette out of bounds: offset %d, size %zu", offset2,
291 rom_size));
292 }
293 palette_groups.global_sprites.AddPalette(
294 gfx::ReadPaletteFromRom(offset2, num_colors2, data));
295 return absl::OkStatus();
296}
297
298absl::Status LoadArmorPalettes(const std::vector<uint8_t>& rom_data,
299 gfx::PaletteGroupMap& palette_groups) {
300 auto data = rom_data.data();
301 size_t rom_size = rom_data.size();
302 for (int i = 0; i < 5; i++) {
303 int offset = kArmorPalettes + (i * 30);
304 int num_colors = 15;
305 if (offset < 0 || offset + (num_colors * 2) > static_cast<int>(rom_size)) {
306 return absl::OutOfRangeError(
307 absl::StrFormat("Armor palette %d out of bounds: offset %d, size %zu",
308 i, offset, rom_size));
309 }
310 palette_groups.armors.AddPalette(
311 gfx::ReadPaletteFromRom(offset, num_colors, data));
312 }
313 return absl::OkStatus();
314}
315
316absl::Status LoadSwordPalettes(const std::vector<uint8_t>& rom_data,
317 gfx::PaletteGroupMap& palette_groups) {
318 auto data = rom_data.data();
319 size_t rom_size = rom_data.size();
320 for (int i = 0; i < 4; i++) {
321 int offset = kSwordPalettes + (i * 6);
322 int num_colors = 3;
323 if (offset < 0 || offset + (num_colors * 2) > static_cast<int>(rom_size)) {
324 return absl::OutOfRangeError(
325 absl::StrFormat("Sword palette %d out of bounds: offset %d, size %zu",
326 i, offset, rom_size));
327 }
328 palette_groups.swords.AddPalette(
329 gfx::ReadPaletteFromRom(offset, num_colors, data));
330 }
331 return absl::OkStatus();
332}
333
334absl::Status LoadShieldPalettes(const std::vector<uint8_t>& rom_data,
335 gfx::PaletteGroupMap& palette_groups) {
336 auto data = rom_data.data();
337 size_t rom_size = rom_data.size();
338 for (int i = 0; i < 3; i++) {
339 int offset = kShieldPalettes + (i * 8);
340 int num_colors = 4;
341 if (offset < 0 || offset + (num_colors * 2) > static_cast<int>(rom_size)) {
342 return absl::OutOfRangeError(absl::StrFormat(
343 "Shield palette %d out of bounds: offset %d, size %zu", i, offset,
344 rom_size));
345 }
346 palette_groups.shields.AddPalette(
347 gfx::ReadPaletteFromRom(offset, num_colors, data));
348 }
349 return absl::OkStatus();
350}
351
352absl::Status LoadSpriteAux1Palettes(const std::vector<uint8_t>& rom_data,
353 gfx::PaletteGroupMap& palette_groups) {
354 auto data = rom_data.data();
355 size_t rom_size = rom_data.size();
356 for (int i = 0; i < 12; i++) {
357 int offset = kSpritesPalettesAux1 + (i * 14);
358 int num_colors = 7;
359 if (offset < 0 || offset + (num_colors * 2) > static_cast<int>(rom_size)) {
360 return absl::OutOfRangeError(absl::StrFormat(
361 "Sprite aux1 palette %d out of bounds: offset %d, size %zu", i,
362 offset, rom_size));
363 }
364 palette_groups.sprites_aux1.AddPalette(
365 gfx::ReadPaletteFromRom(offset, num_colors, data));
366 }
367 return absl::OkStatus();
368}
369
370absl::Status LoadSpriteAux2Palettes(const std::vector<uint8_t>& rom_data,
371 gfx::PaletteGroupMap& palette_groups) {
372 auto data = rom_data.data();
373 size_t rom_size = rom_data.size();
374 for (int i = 0; i < 11; i++) {
375 int offset = kSpritesPalettesAux2 + (i * 14);
376 int num_colors = 7;
377 if (offset < 0 || offset + (num_colors * 2) > static_cast<int>(rom_size)) {
378 return absl::OutOfRangeError(absl::StrFormat(
379 "Sprite aux2 palette %d out of bounds: offset %d, size %zu", i,
380 offset, rom_size));
381 }
382 palette_groups.sprites_aux2.AddPalette(
383 gfx::ReadPaletteFromRom(offset, num_colors, data));
384 }
385 return absl::OkStatus();
386}
387
388absl::Status LoadSpriteAux3Palettes(const std::vector<uint8_t>& rom_data,
389 gfx::PaletteGroupMap& palette_groups) {
390 auto data = rom_data.data();
391 size_t rom_size = rom_data.size();
392 for (int i = 0; i < 24; i++) {
393 int offset = kSpritesPalettesAux3 + (i * 14);
394 int num_colors = 7;
395 if (offset < 0 || offset + (num_colors * 2) > static_cast<int>(rom_size)) {
396 return absl::OutOfRangeError(absl::StrFormat(
397 "Sprite aux3 palette %d out of bounds: offset %d, size %zu", i,
398 offset, rom_size));
399 }
400 palette_groups.sprites_aux3.AddPalette(
401 gfx::ReadPaletteFromRom(offset, num_colors, data));
402 }
403 return absl::OkStatus();
404}
405
406absl::Status LoadDungeonMainPalettes(const std::vector<uint8_t>& rom_data,
407 gfx::PaletteGroupMap& palette_groups) {
408 auto data = rom_data.data();
409 size_t rom_size = rom_data.size();
410 for (int i = 0; i < 20; i++) {
411 int offset = kDungeonMainPalettes + (i * 180);
412 int num_colors = 90;
413 if (offset < 0 || offset + (num_colors * 2) > static_cast<int>(rom_size)) {
414 return absl::OutOfRangeError(absl::StrFormat(
415 "Dungeon main palette %d out of bounds: offset %d, size %zu", i,
416 offset, rom_size));
417 }
418 palette_groups.dungeon_main.AddPalette(
419 gfx::ReadPaletteFromRom(offset, num_colors, data));
420 }
421 return absl::OkStatus();
422}
423
424absl::Status LoadGrassColors(const std::vector<uint8_t>& rom_data,
425 gfx::PaletteGroupMap& palette_groups) {
426 size_t rom_size = rom_data.size();
427
428 // Each color is 2 bytes
429 if (kHardcodedGrassLW < 0 ||
430 kHardcodedGrassLW + 2 > static_cast<int>(rom_size)) {
431 return absl::OutOfRangeError(
432 absl::StrFormat("Grass LW color out of bounds: offset %d, size %zu",
433 kHardcodedGrassLW, rom_size));
434 }
435 palette_groups.grass.AddColor(
436 gfx::ReadColorFromRom(kHardcodedGrassLW, rom_data.data()));
437
438 if (kHardcodedGrassDW < 0 ||
439 kHardcodedGrassDW + 2 > static_cast<int>(rom_size)) {
440 return absl::OutOfRangeError(
441 absl::StrFormat("Grass DW color out of bounds: offset %d, size %zu",
442 kHardcodedGrassDW, rom_size));
443 }
444 palette_groups.grass.AddColor(
445 gfx::ReadColorFromRom(kHardcodedGrassDW, rom_data.data()));
446
447 if (kHardcodedGrassSpecial < 0 ||
448 kHardcodedGrassSpecial + 2 > static_cast<int>(rom_size)) {
449 return absl::OutOfRangeError(absl::StrFormat(
450 "Grass special color out of bounds: offset %d, size %zu",
451 kHardcodedGrassSpecial, rom_size));
452 }
453 palette_groups.grass.AddColor(
455 return absl::OkStatus();
456}
457
458absl::Status Load3DObjectPalettes(const std::vector<uint8_t>& rom_data,
459 gfx::PaletteGroupMap& palette_groups) {
460 auto data = rom_data.data();
461 size_t rom_size = rom_data.size();
462
463 int offset1 = kTriforcePalette;
464 int num_colors1 = 8;
465 if (offset1 < 0 || offset1 + (num_colors1 * 2) > static_cast<int>(rom_size)) {
466 return absl::OutOfRangeError(
467 absl::StrFormat("Triforce palette out of bounds: offset %d, size %zu",
468 offset1, rom_size));
469 }
470 palette_groups.object_3d.AddPalette(
471 gfx::ReadPaletteFromRom(offset1, num_colors1, data));
472
473 int offset2 = kCrystalPalette;
474 int num_colors2 = 8;
475 if (offset2 < 0 || offset2 + (num_colors2 * 2) > static_cast<int>(rom_size)) {
476 return absl::OutOfRangeError(
477 absl::StrFormat("Crystal palette out of bounds: offset %d, size %zu",
478 offset2, rom_size));
479 }
480 palette_groups.object_3d.AddPalette(
481 gfx::ReadPaletteFromRom(offset2, num_colors2, data));
482 return absl::OkStatus();
483}
484
486 const std::vector<uint8_t>& rom_data,
487 gfx::PaletteGroupMap& palette_groups) {
488 auto data = rom_data.data();
489 size_t rom_size = rom_data.size();
490 for (int i = 0; i < 2; i++) {
491 int offset = kOverworldMiniMapPalettes + (i * 256);
492 int num_colors = 128;
493 if (offset < 0 || offset + (num_colors * 2) > static_cast<int>(rom_size)) {
494 return absl::OutOfRangeError(absl::StrFormat(
495 "Overworld minimap palette %d out of bounds: offset %d, size %zu", i,
496 offset, rom_size));
497 }
498 palette_groups.overworld_mini_map.AddPalette(
499 gfx::ReadPaletteFromRom(offset, num_colors, data));
500 }
501 return absl::OkStatus();
502}
503} // namespace palette_group_internal
504
505constexpr std::array<std::pair<absl::string_view, uint32_t>, 15>
507 {"ow_main", kOverworldPaletteMain},
508 {"ow_aux", kOverworldPaletteAux},
509 {"ow_animated", kOverworldPaletteAnimated},
510 {"hud", kHudPalettes},
511 {"global_sprites", kGlobalSpritesLW},
512 {"armors", kArmorPalettes},
513 {"swords", kSwordPalettes},
514 {"shields", kShieldPalettes},
515 {"sprites_aux1", kSpritesPalettesAux1},
516 {"sprites_aux2", kSpritesPalettesAux2},
517 {"sprites_aux3", kSpritesPalettesAux3},
518 {"dungeon_main", kDungeonMainPalettes},
519 {"grass", kHardcodedGrassLW},
520 {"3d_object", kTriforcePalette},
521 {"ow_mini_map", kOverworldMiniMapPalettes},
522 }};
523
524constexpr std::array<std::pair<absl::string_view, uint32_t>, 15>
526 {"ow_main", 35},
527 {"ow_aux", 21},
528 {"ow_animated", 7},
529 {"hud", 32},
530 {"global_sprites", 60},
531 {"armors", 15},
532 {"swords", 3},
533 {"shields", 4},
534 {"sprites_aux1", 7},
535 {"sprites_aux2", 7},
536 {"sprites_aux3", 7},
537 {"dungeon_main", 90},
538 {"grass", 1},
539 {"3d_object", 8},
540 {"ow_mini_map", 128},
541 }};
542
543template <size_t N>
545 absl::string_view group_name,
546 const std::array<std::pair<absl::string_view, uint32_t>, N>& table) {
547 for (const auto& [name, value] : table) {
548 if (name == group_name) {
549 return value;
550 }
551 }
552 throw std::out_of_range(
553 absl::StrFormat("Unknown palette group: %s", group_name));
554}
555
556uint32_t GetPaletteAddress(const std::string& group_name, size_t palette_index,
557 size_t color_index) {
558 // Retrieve the base address and palette width for the palette group.
559 const uint32_t base_address =
561 const uint32_t colors_per_palette =
563
564 // Calculate the address for thes specified color in the ROM
565 uint32_t address = base_address + (palette_index * colors_per_palette * 2) +
566 (color_index * 2);
567
568 return address;
569}
570
597SnesPalette ReadPaletteFromRom(int offset, int num_colors, const uint8_t* rom) {
598 int color_offset = 0;
599 std::vector<gfx::SnesColor> colors(num_colors);
600
601 while (color_offset < num_colors) {
602 // Bounds check before accessing ROM data
603 // Each color is 2 bytes, so we need at least offset + 1 bytes available
604 // Note: We can't check full bounds here without ROM size, but we can at least
605 // validate the immediate access. Full bounds should be checked by caller.
606
607 // Read SNES 15-bit color (little endian)
608 uint16_t snes_color_word = (uint16_t)((rom[offset + 1]) << 8) | rom[offset];
609
610 // Extract RGB components (5-bit each) and expand to 8-bit (0-255)
611 snes_color new_color;
612 new_color.red = (snes_color_word & 0x1F) * 8; // Bits 0-4
613 new_color.green = ((snes_color_word >> 5) & 0x1F) * 8; // Bits 5-9
614 new_color.blue = ((snes_color_word >> 10) & 0x1F) * 8; // Bits 10-14
615
616 // Create SnesColor by converting RGB back to SNES format
617 // (This ensures all internal representations are consistent)
618 colors[color_offset].set_snes(ConvertRgbToSnes(new_color));
619
620 // DO NOT mark as transparent - preserve actual ROM color data!
621 // Transparency is handled at render time, not in the data
622
623 color_offset++;
624 offset += 2; // SNES colors are 2 bytes each
625 }
626
627 return gfx::SnesPalette(colors);
628}
629
630std::array<float, 4> ToFloatArray(const SnesColor& color) {
631 std::array<float, 4> colorArray;
632 colorArray[0] = color.rgb().x / 255.0f;
633 colorArray[1] = color.rgb().y / 255.0f;
634 colorArray[2] = color.rgb().z / 255.0f;
635 colorArray[3] = color.rgb().w;
636 return colorArray;
637}
638
639absl::StatusOr<PaletteGroup> CreatePaletteGroupFromColFile(
640 std::vector<SnesColor>& palette_rows) {
641 PaletteGroup palette_group;
642 for (int i = 0; i < palette_rows.size(); i += 8) {
643 SnesPalette palette;
644 for (int j = 0; j < 8; j++) {
645 palette.AddColor(palette_rows[i + j]);
646 }
647 palette_group.AddPalette(palette);
648 }
649 return palette_group;
650}
651
667absl::StatusOr<PaletteGroup> CreatePaletteGroupFromLargePalette(
668 SnesPalette& palette, int num_colors) {
669 PaletteGroup palette_group;
670 for (int i = 0; i < palette.size(); i += num_colors) {
671 SnesPalette new_palette;
672 if (i + num_colors <= palette.size()) {
673 for (int j = 0; j < num_colors; j++) {
674 auto color = palette[i + j];
675 // DO NOT mark as transparent - preserve actual color data!
676 // Transparency is handled at render time, not in the data
677 new_palette.AddColor(color);
678 }
679 }
680 palette_group.AddPalette(new_palette);
681 }
682 return palette_group;
683}
684
685using namespace palette_group_internal;
686
687// TODO: Refactor LoadAllPalettes to use group names, move to zelda3 namespace
688absl::Status LoadAllPalettes(const std::vector<uint8_t>& rom_data,
689 PaletteGroupMap& groups) {
693 RETURN_IF_ERROR(LoadHUDPalettes(rom_data, groups))
695 RETURN_IF_ERROR(LoadArmorPalettes(rom_data, groups))
696 RETURN_IF_ERROR(LoadSwordPalettes(rom_data, groups))
697 RETURN_IF_ERROR(LoadShieldPalettes(rom_data, groups))
698 RETURN_IF_ERROR(LoadSpriteAux1Palettes(rom_data, groups))
699 RETURN_IF_ERROR(LoadSpriteAux2Palettes(rom_data, groups))
700 RETURN_IF_ERROR(LoadSpriteAux3Palettes(rom_data, groups))
702 RETURN_IF_ERROR(LoadGrassColors(rom_data, groups))
703 RETURN_IF_ERROR(Load3DObjectPalettes(rom_data, groups))
705 return absl::OkStatus();
706}
707
708std::unordered_map<uint8_t, gfx::Paletteset> GfxContext::palettesets_;
709
710} // namespace yaze::gfx
static std::unordered_map< uint8_t, gfx::Paletteset > palettesets_
SNES Color container.
Definition snes_color.h:110
constexpr ImVec4 rgb() const
Get RGB values (WARNING: stored as 0-255 in ImVec4)
Definition snes_color.h:183
void set_snes(uint16_t val)
Set color from SNES 15-bit format.
constexpr uint16_t snes() const
Get SNES 15-bit color.
Definition snes_color.h:193
Represents a palette of colors for the Super Nintendo Entertainment System (SNES).
void AddColor(const SnesColor &color)
static constexpr size_t kMaxColors
absl::StatusOr< ResolvedPaletteRecord > Resolve(OverworldPaletteKind kind, int selector, size_t normalized_rom_size) const
absl::StatusOr< std::pair< uint32_t, uint32_t > > ColorWriteRange(int color_index) const
absl::StatusOr< uint32_t > ColorAddress(int color_index) const
const zelda3::PaletteGroupMetadata * OverworldMetadata(OverworldPaletteKind kind)
absl::Status LoadOverworldPaletteRecords(OverworldPaletteKind kind, const OverworldPaletteLayout &layout, const std::vector< uint8_t > &normalized_rom_data, PaletteGroup &group)
absl::StatusOr< ResolvedPaletteRecord > ResolvePaletteRecord(std::optional< uint32_t > snes_address, uint64_t color_count, size_t normalized_rom_size)
absl::Status LoadDungeonMainPalettes(const std::vector< uint8_t > &rom_data, gfx::PaletteGroupMap &palette_groups)
absl::Status LoadOverworldMiniMapPalettes(const std::vector< uint8_t > &rom_data, gfx::PaletteGroupMap &palette_groups)
absl::Status LoadSpriteAux2Palettes(const std::vector< uint8_t > &rom_data, gfx::PaletteGroupMap &palette_groups)
absl::Status LoadOverworldMainPalettes(const std::vector< uint8_t > &rom_data, gfx::PaletteGroupMap &palette_groups)
absl::Status LoadSpriteAux1Palettes(const std::vector< uint8_t > &rom_data, gfx::PaletteGroupMap &palette_groups)
absl::Status LoadGlobalSpritePalettes(const std::vector< uint8_t > &rom_data, gfx::PaletteGroupMap &palette_groups)
absl::Status LoadOverworldAnimatedPalettes(const std::vector< uint8_t > &rom_data, gfx::PaletteGroupMap &palette_groups)
absl::Status LoadArmorPalettes(const std::vector< uint8_t > &rom_data, gfx::PaletteGroupMap &palette_groups)
absl::Status LoadGrassColors(const std::vector< uint8_t > &rom_data, gfx::PaletteGroupMap &palette_groups)
absl::Status LoadSpriteAux3Palettes(const std::vector< uint8_t > &rom_data, gfx::PaletteGroupMap &palette_groups)
absl::Status LoadHUDPalettes(const std::vector< uint8_t > &rom_data, gfx::PaletteGroupMap &palette_groups)
absl::Status LoadShieldPalettes(const std::vector< uint8_t > &rom_data, gfx::PaletteGroupMap &palette_groups)
absl::Status LoadOverworldAuxiliaryPalettes(const std::vector< uint8_t > &rom_data, gfx::PaletteGroupMap &palette_groups)
absl::Status Load3DObjectPalettes(const std::vector< uint8_t > &rom_data, gfx::PaletteGroupMap &palette_groups)
absl::Status LoadSwordPalettes(const std::vector< uint8_t > &rom_data, gfx::PaletteGroupMap &palette_groups)
Contains classes for handling graphical data.
constexpr int kHardcodedGrassSpecial
constexpr int kHudPalettes
constexpr int kOverworldPaletteAux
SnesPalette ReadPaletteFromRom(int offset, int num_colors, const uint8_t *rom)
Read a palette from ROM data.
uint32_t LookupPaletteGroupValue(absl::string_view group_name, const std::array< std::pair< absl::string_view, uint32_t >, N > &table)
absl::StatusOr< PaletteGroup > CreatePaletteGroupFromLargePalette(SnesPalette &palette, int num_colors)
Create a PaletteGroup by dividing a large palette into sub-palettes.
constexpr int kHardcodedGrassLW
constexpr int kArmorPalettes
constexpr std::array< std::pair< absl::string_view, uint32_t >, 15 > kPaletteGroupAddressMap
constexpr int kCrystalPalette
uint16_t ConvertRgbToSnes(const snes_color &color)
Convert RGB (0-255) to SNES 15-bit color.
Definition snes_color.cc:26
constexpr int kShieldPalettes
constexpr int kSpritesPalettesAux2
constexpr int kOverworldPaletteAnimated
SnesColor ReadColorFromRom(int offset, const uint8_t *rom)
Definition snes_color.cc:41
constexpr int kOverworldMiniMapPalettes
constexpr int kOverworldPaletteMain
constexpr int kSwordPalettes
constexpr int kHardcodedGrassDW
constexpr int kGlobalSpritesLW
constexpr int kSpritesPalettesAux1
constexpr std::array< std::pair< absl::string_view, uint32_t >, 15 > kPaletteGroupColorCounts
std::array< float, 4 > ToFloatArray(const SnesColor &color)
constexpr int kGlobalSpritePalettesDW
constexpr int kSpritesPalettesAux3
constexpr int kDungeonMainPalettes
uint32_t GetPaletteAddress(const std::string &group_name, size_t palette_index, size_t color_index)
constexpr int kTriforcePalette
absl::Status LoadAllPalettes(const std::vector< uint8_t > &rom_data, PaletteGroupMap &groups)
Loads all the palettes for the game.
absl::StatusOr< PaletteGroup > CreatePaletteGroupFromColFile(std::vector< SnesColor > &palette_rows)
constexpr PaletteGroupMetadata kOverworldMain
constexpr PaletteGroupMetadata kOverworldAux
uint32_t PcToSnes(uint32_t addr)
Definition snes.h:17
uint32_t SnesToPc(uint32_t addr) noexcept
Definition snes.h:8
SDL2/SDL3 compatibility layer.
#define RETURN_IF_ERROR(expr)
Definition snes.cc:22
SNES color in 15-bit RGB format (BGR555)
uint16_t green
uint16_t red
uint16_t blue
Represents a mapping of palette groups.
Represents a group of palettes.
void AddColor(SnesColor color)
void AddPalette(SnesPalette pal)