yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
game_data.cc
Go to the documentation of this file.
1#include "zelda3/game_data.h"
2
3#include "absl/strings/str_format.h"
5#include "core/rom_settings.h"
6#include "util/log.h"
7#include "util/macro.h"
9
10#include <algorithm>
11
12#ifdef __EMSCRIPTEN__
14#endif
15
16namespace yaze {
17namespace zelda3 {
18
19namespace {
20
21constexpr uint32_t kUncompressedSheetSize = 0x0800;
22// constexpr uint32_t kTile16Ptr = 0x78000;
23
24// Helper to get address from bytes
25uint32_t AddressFromBytes(uint8_t bank, uint8_t high, uint8_t low) {
26 return (bank << 16) | (high << 8) | low;
27}
28
29// Helper to convert SNES to PC address
30uint32_t SnesToPc(uint32_t snes_addr) {
31 return (snes_addr & 0x7FFF) | ((snes_addr & 0x7F0000) >> 1);
32}
33
35 size_t offset = 0;
36 int length = 0;
37 bool valid = false;
38};
39
41 const int palette_size = static_cast<int>(palette.size());
42 if (palette_size <= 0) {
43 return {};
44 }
45
46 const bool has_explicit_transparent =
47 palette_size >= 16 && (palette_size % 16 == 0);
48 PaletteSlice slice;
49 slice.offset = has_explicit_transparent ? 1 : 0;
50 slice.length = has_explicit_transparent ? 15 : std::min(palette_size, 15);
51 slice.valid =
52 slice.length > 0 &&
53 (slice.offset + static_cast<size_t>(slice.length) <= palette.size());
54
55 if (!slice.valid) {
56 slice.offset = 0;
57 slice.length = std::min(palette_size, 15);
58 slice.valid =
59 slice.length > 0 &&
60 (slice.offset + static_cast<size_t>(slice.length) <= palette.size());
61 }
62
63 return slice;
64}
65
66void ApplyDefaultPalette(gfx::Bitmap& bitmap, const gfx::SnesPalette& palette) {
67 auto slice = GetDefaultPaletteSlice(palette);
68 if (!slice.valid) {
69 return;
70 }
71 bitmap.SetPaletteWithTransparent(palette, slice.offset, slice.length);
72}
73
74// Helper to convert PC to SNES address
75// uint32_t PcToSnes(uint32_t pc_addr) {
76// return ((pc_addr & 0x7FFF) | 0x8000) | ((pc_addr & 0x3F8000) << 1);
77// }
78
79// ============================================================================
80// Graphics Address Resolution
81// ============================================================================
82
108} // namespace
109
112uint32_t GetGraphicsAddress(const uint8_t* data, uint8_t addr, uint32_t ptr1,
113 uint32_t ptr2, uint32_t ptr3, size_t rom_size) {
114 if (ptr1 > UINT32_MAX - addr || ptr1 + addr >= rom_size ||
115 ptr2 > UINT32_MAX - addr || ptr2 + addr >= rom_size ||
116 ptr3 > UINT32_MAX - addr || ptr3 + addr >= rom_size) {
117 return static_cast<uint32_t>(rom_size);
118 }
119 return SnesToPc(AddressFromBytes(data[ptr1 + addr], data[ptr2 + addr],
120 data[ptr3 + addr]));
121}
122
123absl::Status LoadGameData(Rom& rom, GameData& data,
124 const LoadOptions& options) {
125 data.Clear();
126 data.set_rom(&rom);
127
128 if (options.populate_metadata) {
129 RETURN_IF_ERROR(LoadMetadata(rom, data));
130 }
131
132 if (options.load_palettes) {
133 RETURN_IF_ERROR(LoadPalettes(rom, data));
134 }
135
136 if (options.load_gfx_groups) {
137 RETURN_IF_ERROR(LoadGfxGroups(rom, data));
138 }
139
140 if (options.load_graphics) {
141 RETURN_IF_ERROR(LoadGraphics(rom, data));
142 }
143
144 if (options.expand_rom) {
145 if (rom.size() < 1048576 * 2) {
146 rom.Expand(1048576 * 2);
147 }
148 }
149
151
153
154 return absl::OkStatus();
155}
156
157absl::Status SaveGameData(Rom& rom, GameData& data) {
158 if (core::FeatureFlags::get().kSaveAllPalettes) {
159 // TODO: Implement SaveAllPalettes logic using Rom::WriteColor
160 // This was previously in Rom::SaveAllPalettes
161 return data.palette_groups.for_each(
162 [&](gfx::PaletteGroup& group) -> absl::Status {
163 for (size_t i = 0; i < group.size(); ++i) {
164 auto* palette = group.mutable_palette(i);
165 for (size_t j = 0; j < palette->size(); ++j) {
166 gfx::SnesColor color = (*palette)[j];
167 if (color.is_modified()) {
168 RETURN_IF_ERROR(rom.WriteColor(
169 gfx::GetPaletteAddress(group.name(), i, j), color));
170 color.set_modified(false);
171 }
172 }
173 }
174 return absl::OkStatus();
175 });
176 }
177
179 RETURN_IF_ERROR(SaveGfxGroups(rom, data));
180 }
181
182 // Graphics sheets are saved by GraphicsEditor::Save via WriteGfxSheet.
183 return absl::OkStatus();
184}
185
186absl::Status LoadMetadata(const Rom& rom, GameData& data) {
187 constexpr uint32_t kTitleStringOffset = 0x7FC0;
188 constexpr uint32_t kTitleStringLength = 20;
189
190 if (rom.size() < kTitleStringOffset + kTitleStringLength) {
191 return absl::OutOfRangeError("ROM too small for metadata");
192 }
193
194 // Check version byte at offset + 0x19 (0x7FD9)
195 if (kTitleStringOffset + 0x19 < rom.size()) {
196 // Access directly via data() since ReadByte is non-const
197 uint8_t version_byte = rom.data()[kTitleStringOffset + 0x19];
198 data.version =
199 (version_byte == 0) ? zelda3_version::JP : zelda3_version::US;
200 }
201
202 auto title_bytes = rom.ReadByteVector(kTitleStringOffset, kTitleStringLength);
203 if (title_bytes.ok()) {
204 data.title.assign(title_bytes->begin(), title_bytes->end());
205 }
206
207 return absl::OkStatus();
208}
209
210absl::Status LoadPalettes(const Rom& rom, GameData& data) {
211 // Create a vector from rom data for palette loading
212 const std::vector<uint8_t>& rom_vec = rom.vector();
213 return gfx::LoadAllPalettes(rom_vec, data.palette_groups);
214}
215
216absl::Status LoadGfxGroups(Rom& rom, GameData& data) {
217 data.gfx_groups_loaded = false;
218 data.gfx_main_group_address = 0;
219 if (kVersionConstantsMap.find(data.version) == kVersionConstantsMap.end()) {
220 return absl::FailedPreconditionError("Unsupported ROM version");
221 }
222
223 auto version_constants = kVersionConstantsMap.at(data.version);
224
225 // Load Main Blocksets
226 ASSIGN_OR_RETURN(auto main_ptr, rom.ReadWord(kGfxGroupsPointer));
227 const uint32_t main_pc = SnesToPc(main_ptr);
228 for (uint32_t i = 0; i < kNumMainBlocksets; i++) {
229 for (int j = 0; j < 8; j++) {
231 rom.ReadByte(main_pc + (i * 8) + j));
232 }
233 }
234
235 // Load Room Blocksets
236 for (uint32_t i = 0; i < kNumRoomBlocksets; i++) {
237 for (int j = 0; j < 4; j++) {
239 rom.ReadByte(kEntranceGfxGroup + (i * 4) + j));
240 }
241 }
242
243 // Load Sprite Blocksets
244 for (uint32_t i = 0; i < kNumSpritesets; i++) {
245 for (int j = 0; j < 4; j++) {
247 data.spriteset_ids[i][j],
248 rom.ReadByte(version_constants.kSpriteBlocksetPointer + (i * 4) + j));
249 }
250 }
251
252 // Load Palette Sets
253 for (uint32_t i = 0; i < kNumPalettesets; i++) {
254 for (int j = 0; j < 4; j++) {
256 data.paletteset_ids[i][j],
257 rom.ReadByte(version_constants.kDungeonPalettesGroups + (i * 4) + j));
258 }
259 }
260
261 data.gfx_main_group_address = main_pc;
262 data.gfx_groups_loaded = true;
263 return absl::OkStatus();
264}
265
266namespace {
267
269 uint32_t main = 0;
270 uint32_t room = 0;
271 uint32_t sprite = 0;
272 uint32_t palette = 0;
273};
274
275absl::StatusOr<GfxGroupTableAddresses> ResolveGfxGroupTables(
276 const Rom& rom, const GameData& data) {
277 const auto version = kVersionConstantsMap.find(data.version);
278 if (version == kVersionConstantsMap.end() ||
279 version->second.kSpriteBlocksetPointer == 0) {
280 return absl::FailedPreconditionError(
281 "Gfx group tables are unknown for this ROM version");
282 }
283 if (kGfxGroupsPointer + 1 >= rom.size()) {
284 return absl::OutOfRangeError("Main blockset pointer is past the ROM end");
285 }
287 tables.main = SnesToPc(rom.data()[kGfxGroupsPointer] |
288 (rom.data()[kGfxGroupsPointer + 1] << 8));
289 tables.room = kEntranceGfxGroup;
290 tables.sprite = version->second.kSpriteBlocksetPointer;
291 tables.palette = version->second.kDungeonPalettesGroups;
292 const std::pair<uint32_t, size_t> extents[] = {
293 {tables.main, kNumMainBlocksets * 8},
294 {tables.room, kNumRoomBlocksets * 4},
295 {tables.sprite, kNumSpritesets * 4},
296 {tables.palette, kNumPalettesets * 4}};
297 for (const auto& [pc, size] : extents) {
298 if (static_cast<size_t>(pc) + size > rom.size()) {
299 return absl::OutOfRangeError(
300 absl::StrFormat("Gfx group table at 0x%06X is past the ROM end", pc));
301 }
302 }
303 return tables;
304}
305
306// Calls visit(pc, wanted, flag) for every byte of the four tables.
307template <typename Visit>
309 const GameData& data, Visit visit) {
310 for (uint32_t i = 0; i < kNumMainBlocksets; ++i) {
311 for (int j = 0; j < 8; ++j) {
312 visit(tables.main + i * 8 + j, data.main_blockset_ids[i][j], 0);
313 }
314 }
315 for (uint32_t i = 0; i < kNumRoomBlocksets; ++i) {
316 for (int j = 0; j < 4; ++j) {
317 visit(tables.room + i * 4 + j, data.room_blockset_ids[i][j], 1);
318 }
319 }
320 for (uint32_t i = 0; i < kNumSpritesets; ++i) {
321 for (int j = 0; j < 4; ++j) {
322 visit(tables.sprite + i * 4 + j, data.spriteset_ids[i][j], 2);
323 }
324 }
325 for (uint32_t i = 0; i < kNumPalettesets; ++i) {
326 for (int j = 0; j < 4; ++j) {
327 visit(tables.palette + i * 4 + j, data.paletteset_ids[i][j], 3);
328 }
329 }
330}
331
332} // namespace
333
334absl::StatusOr<GfxGroupDiff> DiffGfxGroups(const Rom& rom,
335 const GameData& data) {
336 ASSIGN_OR_RETURN(const auto tables, ResolveGfxGroupTables(rom, data));
337 GfxGroupDiff diff;
338 ForEachGfxGroupByte(tables, data,
339 [&](uint32_t pc, uint8_t wanted, int table) {
340 if (rom.data()[pc] == wanted) {
341 return;
342 }
343 ++diff.changed_bytes;
344 switch (table) {
345 case 0:
346 diff.main_blocksets = true;
347 break;
348 case 1:
349 diff.room_blocksets = true;
350 break;
351 case 2:
352 diff.spritesets = true;
353 break;
354 default:
355 diff.palettesets = true;
356 break;
357 }
358 });
359 return diff;
360}
361
362absl::Status SaveGfxGroups(Rom& rom, const GameData& data) {
363 ASSIGN_OR_RETURN(const auto tables, ResolveGfxGroupTables(rom, data));
364 absl::Status status;
365 ForEachGfxGroupByte(tables, data, [&](uint32_t pc, uint8_t wanted, int) {
366 if (status.ok() && rom.data()[pc] != wanted) {
367 status = rom.WriteByte(static_cast<int>(pc), wanted);
368 }
369 });
370 RETURN_IF_ERROR(status);
371
372 ASSIGN_OR_RETURN(const auto readback, DiffGfxGroups(rom, data));
373 if (readback.any()) {
374 return absl::DataLossError(absl::StrFormat(
375 "Gfx group read-back differs in %d byte(s)", readback.changed_bytes));
376 }
377 return absl::OkStatus();
378}
379
380// ============================================================================
381// Main Graphics Loading
382// ============================================================================
383
414 std::vector<uint8_t> data;
415 bool is_compressed = false;
417 bool is_bpp3 = false; // true if 3BPP, false if skipped/2BPP
418 uint32_t pc_offset = 0;
419};
420
421SheetLoadResult LoadSheetRaw(const Rom& rom, uint32_t i, uint32_t ptr1,
422 uint32_t ptr2, uint32_t ptr3) {
423 SheetLoadResult result;
424 result.data.assign(zelda3::kUncompressedSheetSize, 0); // Default empty
425
426 // Uncompressed 3BPP (115-126)
427 if (i >= 115 && i <= 126) {
428 result.is_compressed = false;
429 result.pc_offset =
430 GetGraphicsAddress(rom.data(), i, ptr1, ptr2, ptr3, rom.size());
431
432 auto read_res =
434 if (read_res.ok()) {
435 result.data = *read_res;
436 result.decompression_succeeded = true;
437 result.is_bpp3 = true;
438 } else {
439 result.decompression_succeeded = false;
440 }
441 }
442 // 2BPP (113-114, 218+) - Skipped in main loop
443 else if (i == 113 || i == 114 || i >= 218) {
444 result.is_compressed = true;
445 result.is_bpp3 = false;
446 }
447 // Compressed 3BPP (Standard)
448 else {
449 result.is_compressed = true;
450 result.pc_offset =
451 GetGraphicsAddress(rom.data(), i, ptr1, ptr2, ptr3, rom.size());
452
453 if (result.pc_offset < rom.size()) {
454 auto decomp_res = gfx::lc_lz2::DecompressV2(rom.data(), result.pc_offset,
455 0x800, 1, rom.size());
456 if (decomp_res.ok()) {
457 result.data = *decomp_res;
458 result.decompression_succeeded = true;
459 result.is_bpp3 = true;
460 } else {
461 result.decompression_succeeded = false;
462 }
463 }
464 }
465 return result;
466}
467
468void ProcessSheetBitmap(GameData& data, uint32_t i,
469 const SheetLoadResult& result) {
470 if (result.is_bpp3) {
471 auto converted_sheet = gfx::SnesTo8bppSheet(result.data, 3);
472 if (converted_sheet.size() != 4096)
473 converted_sheet.resize(4096, 0);
474
475 data.raw_gfx_sheets[i] = converted_sheet;
477 gfx::kTilesheetDepth, converted_sheet);
478
479 // Apply default palettes
480 if (!data.palette_groups.empty()) {
481 gfx::SnesPalette default_palette;
482 if (i < 113 && data.palette_groups.dungeon_main.size() > 0) {
483 default_palette = data.palette_groups.dungeon_main[0];
484 } else if (i < 128 && data.palette_groups.sprites_aux1.size() > 0) {
485 default_palette = data.palette_groups.sprites_aux1[0];
486 } else if (data.palette_groups.hud.size() > 0) {
487 default_palette = data.palette_groups.hud.palette(0);
488 }
489
490 if (!default_palette.empty()) {
491 ApplyDefaultPalette(data.gfx_bitmaps[i], default_palette);
492 } else {
493 // Fallback to grayscale if no palette found
494 std::vector<gfx::SnesColor> grayscale;
495 for (int color_idx = 0; color_idx < 16; ++color_idx) {
496 float val = color_idx / 15.0f;
497 grayscale.emplace_back(ImVec4(val, val, val, 1.0f));
498 }
499 if (!grayscale.empty()) {
500 grayscale[0].set_transparent(true);
501 }
502 data.gfx_bitmaps[i].SetPalette(gfx::SnesPalette(grayscale));
503 }
504 } else {
505 // Fallback to grayscale if no palette groups loaded
506 std::vector<gfx::SnesColor> grayscale;
507 for (int color_idx = 0; color_idx < 16; ++color_idx) {
508 float val = color_idx / 15.0f;
509 grayscale.emplace_back(ImVec4(val, val, val, 1.0f));
510 }
511 if (!grayscale.empty()) {
512 grayscale[0].set_transparent(true);
513 }
514 data.gfx_bitmaps[i].SetPalette(gfx::SnesPalette(grayscale));
515 }
516
517 data.graphics_buffer.insert(
518 data.graphics_buffer.end(), data.gfx_bitmaps[i].data(),
519 data.gfx_bitmaps[i].data() + data.gfx_bitmaps[i].size());
520 } else {
521 // Placeholder - Fill with 0 (transparent) instead of 0xFF (white)
522 std::vector<uint8_t> placeholder(4096, 0);
523 data.raw_gfx_sheets[i] = placeholder;
525 gfx::kTilesheetDepth, placeholder);
526 data.graphics_buffer.resize(data.graphics_buffer.size() + 4096, 0);
527 }
528}
529
530absl::Status LoadGraphics(Rom& rom, GameData& data) {
531 if (kVersionConstantsMap.find(data.version) == kVersionConstantsMap.end()) {
532 return absl::FailedPreconditionError(
533 "Unsupported ROM version for graphics");
534 }
535 auto version_constants = kVersionConstantsMap.at(data.version);
536 const uint32_t gfx_ptr1 = core::RomSettings::Get().GetAddressOr(
538 version_constants.kOverworldGfxPtr1);
539 const uint32_t gfx_ptr2 = core::RomSettings::Get().GetAddressOr(
541 version_constants.kOverworldGfxPtr2);
542 const uint32_t gfx_ptr3 = core::RomSettings::Get().GetAddressOr(
544 version_constants.kOverworldGfxPtr3);
545
546 data.sheet_store.Clear();
547
548#ifdef __EMSCRIPTEN__
549 auto loading_handle =
550 app::platform::WasmLoadingManager::BeginLoading("Loading Graphics");
551#endif
552
553 // Initialize Diagnostics
554 auto& diag = data.diagnostics;
555 diag.rom_size = rom.size();
556 diag.ptr1_loc = gfx_ptr1;
557 diag.ptr2_loc = gfx_ptr2;
558 diag.ptr3_loc = gfx_ptr3;
559
560 LOG_INFO("Graphics", "Loading %d graphics sheets...", kNumGfxSheets);
561
562 for (uint32_t i = 0; i < kNumGfxSheets; i++) {
563#ifdef __EMSCRIPTEN__
564 app::platform::WasmLoadingManager::UpdateProgress(
565 loading_handle, static_cast<float>(i) / kNumGfxSheets);
566#endif
567
568 // Inside LoadGraphics loop:
569 auto result = LoadSheetRaw(rom, i, gfx_ptr1, gfx_ptr2, gfx_ptr3);
570
571 // Update Diagnostics
572 auto& sd = diag.sheets[i];
573 sd.index = i;
574 sd.is_compressed = result.is_compressed;
575 sd.pc_offset = result.pc_offset;
576 sd.decompression_succeeded = result.decompression_succeeded;
577 sd.actual_decomp_size = result.data.size();
578 if (!result.data.empty()) {
579 size_t count = std::min<size_t>(result.data.size(), 8);
580 sd.first_bytes.assign(result.data.begin(), result.data.begin() + count);
581 }
582 if (result.is_compressed && !result.is_bpp3) {
583 sd.decomp_size_param = 0x800; // Expected for LC-LZ2
584 }
585
586 ProcessSheetBitmap(data, i, result);
587
588 if (i % 50 == 0 || i == kNumGfxSheets - 1) {
589 LOG_DEBUG("Graphics", "Sheet %d: offset=0x%06X, size=%zu, %s", i,
590 result.pc_offset, result.data.size(),
591 result.decompression_succeeded ? "OK" : "FAILED");
592 }
593 }
594
595 // The sheets were appended through the graphics_buffer alias.
597 diag.Analyze();
598 LOG_INFO("Graphics", "Graphics loading complete. Sheets processed: %d",
600
601#ifdef __EMSCRIPTEN__
602 app::platform::WasmLoadingManager::EndLoading(loading_handle);
603#endif
604
605 return absl::OkStatus();
606}
607
608// ============================================================================
609// Link Graphics Loading
610// ============================================================================
611
612absl::StatusOr<std::array<gfx::Bitmap, kNumLinkSheets>> LoadLinkGraphics(
613 const Rom& rom) {
614 std::array<gfx::Bitmap, kNumLinkSheets> link_graphics;
615 for (uint32_t i = 0; i < kNumLinkSheets; i++) {
616 auto link_sheet_data_result =
617 rom.ReadByteVector(/*offset=*/kLinkGfxOffset + (i * kLinkGfxLength),
618 /*length=*/kLinkGfxLength);
619 if (!link_sheet_data_result.ok()) {
620 return link_sheet_data_result.status();
621 }
622 auto link_sheet_8bpp =
623 gfx::SnesTo8bppSheet(*link_sheet_data_result, /*bpp=*/4);
624 if (link_sheet_8bpp.size() != 4096)
625 link_sheet_8bpp.resize(4096, 0);
626
627 link_graphics[i].Create(gfx::kTilesheetWidth, gfx::kTilesheetHeight,
628 gfx::kTilesheetDepth, link_sheet_8bpp);
629 // Palette is applied by the caller since GameData may not be available here
630 }
631 return link_graphics;
632}
633
634// ============================================================================
635// 2BPP Graphics Loading
636// ============================================================================
637
638absl::StatusOr<std::vector<uint8_t>> Load2BppGraphics(const Rom& rom) {
639 std::vector<uint8_t> sheet;
640 const uint8_t sheets[] = {0x71, 0x72, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE};
641
642 // Get version constants - default to US if we don't know
643 auto version_constants = kVersionConstantsMap.at(zelda3_version::US);
644 const uint32_t gfx_ptr1 = core::RomSettings::Get().GetAddressOr(
646 version_constants.kOverworldGfxPtr1);
647 const uint32_t gfx_ptr2 = core::RomSettings::Get().GetAddressOr(
649 version_constants.kOverworldGfxPtr2);
650 const uint32_t gfx_ptr3 = core::RomSettings::Get().GetAddressOr(
652 version_constants.kOverworldGfxPtr3);
653
654 for (const auto& sheet_id : sheets) {
655 auto offset = GetGraphicsAddress(rom.data(), sheet_id, gfx_ptr1, gfx_ptr2,
656 gfx_ptr3, rom.size());
657
658 if (offset >= rom.size()) {
659 return absl::OutOfRangeError(absl::StrFormat(
660 "2BPP graphics sheet %u offset %u exceeds ROM size %zu", sheet_id,
661 offset, rom.size()));
662 }
663
664 // Decompress using LC-LZ2 algorithm with 0x800 byte output buffer.
665 auto decomp_result =
666 gfx::lc_lz2::DecompressV2(rom.data(), offset, 0x800, 1, rom.size());
667 if (!decomp_result.ok()) {
668 return decomp_result.status();
669 }
670 auto converted_sheet = gfx::SnesTo8bppSheet(*decomp_result, 2);
671 for (const auto& each_pixel : converted_sheet) {
672 sheet.push_back(each_pixel);
673 }
674 }
675 return sheet;
676}
677
678// ============================================================================
679// Font Graphics Loading
680// ============================================================================
681
682absl::StatusOr<gfx::Bitmap> LoadFontGraphics(const Rom& rom) {
683 // Font sprites are located at 0x70000, 2BPP format
684 constexpr uint32_t kFontDataSize = 0x4000; // 16KB of font data
685
686 auto font_data_result =
687 rom.ReadByteVector(kFontSpriteLocation, kFontDataSize);
688 if (!font_data_result.ok()) {
689 return font_data_result.status();
690 }
691
692 // Convert from 2BPP SNES format to 8BPP
693 auto font_8bpp = gfx::SnesTo8bppSheet(*font_data_result, /*bpp=*/2);
694
695 gfx::Bitmap font_bitmap;
697 gfx::kTilesheetDepth, font_8bpp);
698
699 return font_bitmap;
700}
701
702// ============================================================================
703// Graphics Saving
704// ============================================================================
705
707 [[maybe_unused]] Rom& rom,
708 [[maybe_unused]] const std::array<gfx::Bitmap, kNumGfxSheets>& sheets) {
709 // Rewriting every sheet is never what an edit needs. Edited sheets are
710 // written one at a time by WriteGfxSheet (zelda3/gfx_sheet_storage.h),
711 // which GraphicsEditor::Save uses. Fail loudly instead of reporting a save.
712 return absl::UnimplementedError(
713 "SaveAllGraphicsData is not implemented; write edited sheets with "
714 "zelda3::WriteGfxSheet");
715}
716
717} // namespace zelda3
718} // 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::StatusOr< std::vector< uint8_t > > ReadByteVector(uint32_t offset, uint32_t length) const
Definition rom.cc:808
absl::StatusOr< uint8_t > ReadByte(int offset) const
Definition rom.cc:785
const auto & vector() const
Definition rom.h:205
void Expand(int size)
Definition rom.h:92
absl::StatusOr< uint16_t > ReadWord(int offset) const
Definition rom.cc:793
auto data() const
Definition rom.h:201
auto size() const
Definition rom.h:200
static Flags & get()
Definition features.h:119
static RomSettings & Get()
uint32_t GetAddressOr(const std::string &key, uint32_t default_value) const
Represents a bitmap image optimized for SNES ROM hacking.
Definition bitmap.h:70
void Create(int width, int height, int depth, std::span< uint8_t > data)
Create a bitmap with the given dimensions and data.
Definition bitmap.cc:198
void SetPaletteWithTransparent(const SnesPalette &palette, size_t index, int length=7)
Set the palette with a transparent color.
Definition bitmap.cc:524
SNES Color container.
Definition snes_color.h:110
constexpr bool is_modified() const
Definition snes_color.h:195
Represents a palette of colors for the Super Nintendo Entertainment System (SNES).
void MarkAllSheetsChanged()
Call after the loader refills the buffer: bumps every revision.
void Clear()
Empties the buffer and bumps every revision.
static absl::Status LoadFromRom(Rom *rom, PitDamageTable *out)
int main(int argc, char **argv)
Definition emu.cc:43
#define LOG_DEBUG(category, format,...)
Definition log.h:133
#define LOG_INFO(category, format,...)
Definition log.h:136
#define ASSIGN_OR_RETURN(type_variable_name, expression)
Definition macro.h:62
constexpr char kOverworldGfxPtr3[]
constexpr char kOverworldGfxPtr1[]
constexpr char kOverworldGfxPtr2[]
absl::StatusOr< std::vector< uint8_t > > DecompressV2(const uint8_t *data, int offset, int size, int mode, size_t rom_size)
Decompresses a buffer of data using the LC_LZ2 algorithm.
constexpr int kTilesheetHeight
Definition snes_tile.h:17
constexpr int kTilesheetWidth
Definition snes_tile.h:16
constexpr int kTilesheetDepth
Definition snes_tile.h:18
std::vector< uint8_t > SnesTo8bppSheet(std::span< const uint8_t > sheet, int bpp, int num_sheets)
Definition snes_tile.cc:133
absl::Status LoadAllPalettes(const std::vector< uint8_t > &rom_data, PaletteGroupMap &groups)
Loads all the palettes for the game.
void ApplyDefaultPalette(gfx::Bitmap &bitmap, const gfx::SnesPalette &palette)
Definition game_data.cc:66
void ForEachGfxGroupByte(const GfxGroupTableAddresses &tables, const GameData &data, Visit visit)
Definition game_data.cc:308
absl::StatusOr< GfxGroupTableAddresses > ResolveGfxGroupTables(const Rom &rom, const GameData &data)
Definition game_data.cc:275
PaletteSlice GetDefaultPaletteSlice(const gfx::SnesPalette &palette)
Definition game_data.cc:40
absl::Status SaveGfxGroups(Rom &rom, const GameData &data)
Definition game_data.cc:362
absl::StatusOr< std::vector< uint8_t > > Load2BppGraphics(const Rom &rom)
Loads 2BPP graphics sheets from ROM.
Definition game_data.cc:638
constexpr uint16_t kLinkGfxLength
Definition game_data.h:52
constexpr uint32_t kFontSpriteLocation
Definition game_data.h:55
absl::StatusOr< std::array< gfx::Bitmap, kNumLinkSheets > > LoadLinkGraphics(const Rom &rom)
Loads Link's graphics sheets from ROM.
Definition game_data.cc:612
absl::StatusOr< gfx::Bitmap > LoadFontGraphics(const Rom &rom)
Loads font graphics from ROM.
Definition game_data.cc:682
constexpr uint32_t kNumRoomBlocksets
Definition game_data.h:33
constexpr uint32_t kUncompressedSheetSize
Definition game_data.h:58
absl::StatusOr< GfxGroupDiff > DiffGfxGroups(const Rom &rom, const GameData &data)
Definition game_data.cc:334
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::Status LoadMetadata(const Rom &rom, GameData &data)
Definition game_data.cc:186
constexpr uint32_t kNumPalettesets
Definition game_data.h:35
absl::Status SaveAllGraphicsData(Rom &rom, const std::array< gfx::Bitmap, kNumGfxSheets > &sheets)
Not implemented; always returns UnimplementedError.
Definition game_data.cc:706
std::vector< RoomDefaultEntrance > ComputeRoomDefaultEntrances(Rom &rom)
constexpr uint32_t kLinkGfxOffset
Definition game_data.h:51
constexpr uint32_t kNumMainBlocksets
Definition game_data.h:32
constexpr uint32_t kNumGfxSheets
Definition game_data.h:28
constexpr uint32_t kEntranceGfxGroup
Definition game_data.h:38
void ProcessSheetBitmap(GameData &data, uint32_t i, const SheetLoadResult &result)
Definition game_data.cc:468
constexpr uint32_t kNumSpritesets
Definition game_data.h:34
constexpr uint32_t kNumLinkSheets
Definition game_data.h:29
absl::Status LoadPalettes(const Rom &rom, GameData &data)
Definition game_data.cc:210
absl::Status SaveGameData(Rom &rom, GameData &data)
Saves modified game data back to the ROM.
Definition game_data.cc:157
absl::Status LoadGraphics(Rom &rom, GameData &data)
Definition game_data.cc:530
uint32_t GetGraphicsAddress(const uint8_t *data, uint8_t addr, uint32_t ptr1, uint32_t ptr2, uint32_t ptr3, size_t rom_size)
Gets the graphics address for a sheet index.
Definition game_data.cc:112
absl::Status LoadGfxGroups(Rom &rom, GameData &data)
Definition game_data.cc:216
constexpr int kGfxGroupsPointer
SheetLoadResult LoadSheetRaw(const Rom &rom, uint32_t i, uint32_t ptr1, uint32_t ptr2, uint32_t ptr3)
Definition game_data.cc:421
int AddressFromBytes(uint8_t bank, uint8_t high, uint8_t low) noexcept
Definition snes.h:39
uint32_t SnesToPc(uint32_t addr) noexcept
Definition snes.h:8
#define RETURN_IF_ERROR(expr)
Definition snes.cc:22
absl::Status for_each(Func &&func)
Represents a group of palettes.
auto palette(int i) const
std::vector< RoomDefaultEntrance > room_default_entrances
Definition game_data.h:118
std::array< std::array< uint8_t, 4 >, kNumSpritesets > spriteset_ids
Definition game_data.h:99
void set_rom(Rom *rom)
Definition game_data.h:81
std::array< std::array< uint8_t, 4 >, kNumRoomBlocksets > room_blockset_ids
Definition game_data.h:98
std::array< std::array< uint8_t, 4 >, kNumPalettesets > paletteset_ids
Definition game_data.h:108
gfx::PaletteGroupMap palette_groups
Definition game_data.h:95
GraphicsLoadDiagnostics diagnostics
Definition game_data.h:111
zelda3_version version
Definition game_data.h:84
PitDamageTable pit_damage_table
Definition game_data.h:114
std::array< gfx::Bitmap, kNumGfxSheets > gfx_bitmaps
Definition game_data.h:90
std::array< std::array< uint8_t, 8 >, kNumMainBlocksets > main_blockset_ids
Definition game_data.h:97
uint32_t gfx_main_group_address
Definition game_data.h:102
std::array< std::vector< uint8_t >, kNumGfxSheets > raw_gfx_sheets
Definition game_data.h:89
Which gfx group tables in data differ from the bytes in rom.
Definition game_data.h:166
std::vector< uint8_t > & graphics_buffer
Legacy name for sheet_store.mutable_pixels().
std::vector< uint8_t > data
Definition game_data.cc:414