yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
overworld_graphics_preview.h
Go to the documentation of this file.
1#ifndef YAZE_CORE_OVERWORLD_GRAPHICS_PREVIEW_H_
2#define YAZE_CORE_OVERWORLD_GRAPHICS_PREVIEW_H_
3
4#include <filesystem>
5#include <fstream>
6#include <string>
7
8#include "absl/status/status.h"
9#include "absl/status/statusor.h"
10#include "nlohmann/json.hpp"
12
13namespace yaze::core {
14
15// Explicit project-owned, read-only rendering configuration. Assets resolve
16// relative to this file, never by ROM filename or a global area exception.
17inline absl::StatusOr<zelda3::OverworldGraphicsPreview>
18LoadOverworldGraphicsPreview(const std::string& filename) {
20 if (filename.empty())
21 return result;
22 std::ifstream input(filename);
23 if (!input)
24 return absl::NotFoundError("Cannot open graphics preview: " + filename);
25 try {
26 const auto document = nlohmann::json::parse(input);
27 if (document.at("schema_version").get<int>() != 1 ||
28 !document.at("areas").is_array()) {
29 return absl::InvalidArgumentError("Unsupported graphics preview schema");
30 }
31 for (const auto& area : document.at("areas")) {
32 const int parent = area.at("parent_map").get<int>();
33 if (parent < 0 || parent >= 160 || result.contains(parent)) {
34 return absl::InvalidArgumentError(
35 "Invalid or duplicate graphics preview parent_map");
36 }
37 const int base = area.at("bg_character_base_word").get<int>();
38 auto& tiles = result[parent];
39 if (!area.at("transfers").is_array() || area.at("transfers").empty()) {
40 return absl::InvalidArgumentError("Graphics preview needs transfers");
41 }
42 for (const auto& transfer : area.at("transfers")) {
43 if (transfer.at("format").get<std::string>() != "snes4bpp") {
44 return absl::InvalidArgumentError(
45 "Graphics preview format must be snes4bpp");
46 }
47 const int count = transfer.at("byte_count").get<int>();
48 if (count <= 0 || count > 0x8000 || count % 32 != 0) {
49 return absl::InvalidArgumentError(
50 "Invalid graphics preview byte_count");
51 }
52 const auto path = std::filesystem::path(filename).parent_path() /
53 transfer.at("path").get<std::string>();
54 std::error_code ec;
55 const auto size = std::filesystem::file_size(path, ec);
56 if (ec)
57 return absl::NotFoundError("Missing graphics preview asset: " +
58 path.string());
59 if (size != static_cast<size_t>(count)) {
60 return absl::InvalidArgumentError(
61 "Graphics preview asset has wrong byte count: " + path.string());
62 }
63 std::vector<uint8_t> bytes(count);
64 std::ifstream asset(path, std::ios::binary);
65 if (!asset.read(reinterpret_cast<char*>(bytes.data()), count)) {
66 return absl::DataLossError("Cannot read graphics preview asset: " +
67 path.string());
68 }
70 bytes, transfer.at("vram_word_address").get<int>(), base);
71 if (!decoded.ok())
72 return decoded.status();
73 for (const auto& [id, pixels] : *decoded) {
74 if (!tiles.emplace(id, pixels).second) {
75 return absl::InvalidArgumentError(
76 "Overlapping graphics preview transfers");
77 }
78 }
79 }
80 }
81 } catch (const nlohmann::json::exception& e) {
82 return absl::InvalidArgumentError(
83 std::string("Invalid graphics preview: ") + e.what());
84 }
85 return result;
86}
87
88} // namespace yaze::core
89#endif
absl::StatusOr< zelda3::OverworldGraphicsPreview > LoadOverworldGraphicsPreview(const std::string &filename)
absl::StatusOr< AreaGraphicsPreview > DecodeGraphicsPreviewTransfer(std::span< const uint8_t > bytes, int destination_word, int bg_base_word)
std::map< int, AreaGraphicsPreview > OverworldGraphicsPreview