yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
sheet_png_transfer.cc
Go to the documentation of this file.
2
3#include <algorithm>
4#include <memory>
5#include <utility>
6
7#include "absl/strings/str_format.h"
8#include "absl/strings/str_join.h"
14#include "rom/rom.h"
15#include "util/indexed_png.h"
16#include "util/macro.h"
19
20namespace yaze::editor {
21
22namespace {
23
24constexpr size_t kSheetPixels = 128 * 32;
25
26// The Arena's 3bpp sheets are 128x32 with indices 0-7; anything else cannot
27// round-trip through the 3bpp encoder without losing bits.
28absl::Status CheckSheetPixels(uint16_t sheet_id,
29 const std::vector<uint8_t>& indexed_pixels) {
30 if (sheet_id >= zelda3::kGfxSheetCount) {
31 return absl::InvalidArgumentError(
32 absl::StrFormat("Sheet 0x%02X is out of range", sheet_id));
33 }
34 if (zelda3::GetGfxSheetStorageKind(sheet_id) ==
36 return absl::FailedPreconditionError(absl::StrFormat(
37 "Sheet 0x%02X is a 2bpp sheet; PNG import and export cover 3bpp "
38 "sheets only",
39 sheet_id));
40 }
41 if (indexed_pixels.size() != kSheetPixels) {
42 return absl::FailedPreconditionError(absl::StrFormat(
43 "Sheet 0x%02X is not loaded as a 128x32 sheet", sheet_id));
44 }
45 const auto high = std::find_if(indexed_pixels.begin(), indexed_pixels.end(),
46 [](uint8_t index) { return index > 7; });
47 if (high != indexed_pixels.end()) {
48 const size_t at = static_cast<size_t>(high - indexed_pixels.begin());
49 return absl::FailedPreconditionError(absl::StrFormat(
50 "Sheet 0x%02X uses color %d at (%zu, %zu); 3bpp sheets hold colors "
51 "0-7",
52 sheet_id, *high, at % 128, at / 128));
53 }
54 return absl::OkStatus();
55}
56
58 const zelda3::SheetImportResult& result) {
60 preview.sheet_id = sheet_id;
61 preview.indexed_pixels = gfx::SnesTo8bppSheet(result.snes_3bpp, /*bpp=*/3);
62 preview.changed_blocks = result.changed_blocks;
63 preview.changed_tiles = result.changed_tiles;
64 return preview;
65}
66
67} // namespace
68
69absl::StatusOr<std::vector<uint8_t>> ExportSheetPixelsPng(
70 uint16_t sheet_id, const std::vector<uint8_t>& indexed_pixels,
71 const zelda3::SheetPalette& palette) {
72 RETURN_IF_ERROR(CheckSheetPixels(sheet_id, indexed_pixels));
73 const auto snes = gfx::IndexedToSnesSheet(indexed_pixels, /*bpp=*/3);
74 return zelda3::ExportSheetBlocksPng(snes, palette);
75}
76
77absl::StatusOr<SheetPngImportPreview> PreviewSheetPngImport(
78 uint16_t sheet_id, const std::vector<uint8_t>& indexed_pixels,
79 const std::vector<uint8_t>& png_bytes, const zelda3::SheetPalette& palette,
80 int first_block) {
81 RETURN_IF_ERROR(CheckSheetPixels(sheet_id, indexed_pixels));
82 ASSIGN_OR_RETURN(const util::PngImage png, util::DecodePng(png_bytes));
83 const auto snes = gfx::IndexedToSnesSheet(indexed_pixels, /*bpp=*/3);
85 const zelda3::SheetImportResult result,
86 zelda3::ImportSheetBlocksPng(snes, png, first_block, palette));
87 return MakePreview(sheet_id, result);
88}
89
90absl::StatusOr<std::vector<SheetPngImportPreview>> PreviewRoomPngImport(
91 const Rom& rom, const zelda3::RoomBackgroundSet& set,
92 const std::vector<uint8_t>& png_bytes,
93 const zelda3::SheetPalette& palette) {
94 ASSIGN_OR_RETURN(const util::PngImage png, util::DecodePng(png_bytes));
95 ASSIGN_OR_RETURN(const auto imports,
96 zelda3::ImportRoomBackgroundPng(rom, set, png, palette));
97 std::vector<SheetPngImportPreview> previews;
98 previews.reserve(imports.size());
99 for (const zelda3::RoomSheetImport& sheet_import : imports) {
100 previews.push_back(MakePreview(sheet_import.sheet, sheet_import.result));
101 }
102 return previews;
103}
104
105absl::Status ApplySheetPngImport(const SheetPngImportPreview& preview,
106 GraphicsEditorState& state,
107 UndoManager* undo_manager) {
108 const auto* store = ActiveSheetStore(state);
109 if (store == nullptr || !store->HasSheet(preview.sheet_id) ||
110 preview.indexed_pixels.size() != kSheetPixels) {
111 return absl::FailedPreconditionError(absl::StrFormat(
112 "Sheet 0x%02X is not in this ROM's loaded graphics; import it again",
113 preview.sheet_id));
114 }
116 preview.sheet_id, store->Sheet(preview.sheet_id), preview.indexed_pixels);
117 if (diff.empty()) {
118 return absl::OkStatus();
119 }
121 CommitSheetPixels(state, preview.sheet_id, preview.indexed_pixels));
122 if (undo_manager != nullptr) {
123 undo_manager->Push(std::make_unique<GraphicsPixelEditAction>(
124 &state, std::move(diff),
125 absl::StrFormat("Import PNG into sheet 0x%02X", preview.sheet_id)));
126 }
127 return absl::OkStatus();
128}
129
131 if (preview.changed_tiles.empty()) {
132 return absl::StrFormat("Sheet 0x%02X: no change", preview.sheet_id);
133 }
134 return absl::StrFormat(
135 "Sheet 0x%02X: block%s %s (%zu tile%s)", preview.sheet_id,
136 preview.changed_blocks.size() == 1 ? "" : "s",
137 absl::StrJoin(preview.changed_blocks, ", "), preview.changed_tiles.size(),
138 preview.changed_tiles.size() == 1 ? "" : "s");
139}
140
141} // namespace yaze::editor
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
Shared state between GraphicsEditor panel components.
Manages undo/redo stacks for a single editor.
void Push(std::unique_ptr< UndoAction > action)
Locates graphics sheets in the ROM and writes edited sheets back.
One ROM session's graphics sheet pixels, with a revision per sheet.
The Graphics editor's path for sheet pixel writes.
#define ASSIGN_OR_RETURN(type_variable_name, expression)
Definition macro.h:62
SheetPngImportPreview MakePreview(uint16_t sheet_id, const zelda3::SheetImportResult &result)
absl::Status CheckSheetPixels(uint16_t sheet_id, const std::vector< uint8_t > &indexed_pixels)
Editors are the view controllers for the application.
absl::StatusOr< std::vector< uint8_t > > ExportSheetPixelsPng(uint16_t sheet_id, const std::vector< uint8_t > &indexed_pixels, const zelda3::SheetPalette &palette)
zelda3::GraphicsSheetStore * ActiveSheetStore(const GraphicsEditorState &state)
std::string DescribeSheetPngImport(const SheetPngImportPreview &preview)
"Sheet 0x20: blocks 0, 3 (5 tiles)" for the preview list.
absl::Status CommitSheetPixels(GraphicsEditorState &state, uint16_t sheet, absl::Span< const uint8_t > pixels)
absl::StatusOr< std::vector< SheetPngImportPreview > > PreviewRoomPngImport(const Rom &rom, const zelda3::RoomBackgroundSet &set, const std::vector< uint8_t > &png_bytes, const zelda3::SheetPalette &palette)
absl::StatusOr< SheetPngImportPreview > PreviewSheetPngImport(uint16_t sheet_id, const std::vector< uint8_t > &indexed_pixels, const std::vector< uint8_t > &png_bytes, const zelda3::SheetPalette &palette, int first_block)
SheetPixelDiff MakeSheetPixelDiff(uint16_t sheet, absl::Span< const uint8_t > before, absl::Span< const uint8_t > after)
The pixels that differ between two 4096-byte sheets.
absl::Status ApplySheetPngImport(const SheetPngImportPreview &preview, GraphicsEditorState &state, UndoManager *undo_manager)
std::vector< uint8_t > SnesTo8bppSheet(std::span< const uint8_t > sheet, int bpp, int num_sheets)
Definition snes_tile.cc:133
std::vector< uint8_t > IndexedToSnesSheet(std::span< const uint8_t > sheet, int bpp, int num_sheets)
Definition snes_tile.cc:204
absl::StatusOr< PngImage > DecodePng(const std::vector< uint8_t > &bytes)
absl::StatusOr< SheetImportResult > ImportSheetBlocksPng(const std::vector< uint8_t > &snes_3bpp, const util::PngImage &png, int first_block, const SheetPalette &palette)
Places a PNG's 16x16 blocks over a sheet from first_block.
GfxSheetStorageKind GetGfxSheetStorageKind(uint16_t sheet_id)
constexpr size_t kGfxSheetCount
std::array< SheetColor, 8 > SheetPalette
Colors for 3bpp indices 0-7. Index 0 is exported as transparent.
absl::StatusOr< std::vector< uint8_t > > ExportSheetBlocksPng(const std::vector< uint8_t > &snes_3bpp, const SheetPalette &palette, int first_block, int block_count)
absl::StatusOr< std::vector< RoomSheetImport > > ImportRoomBackgroundPng(const Rom &rom, const RoomBackgroundSet &set, const util::PngImage &png, const SheetPalette &palette)
PNG export and import for the Graphics editor.
#define RETURN_IF_ERROR(expr)
Definition snes.cc:22
The pixels one undo step changes in one sheet.
One sheet's pixels after an import, and what changed.
A decoded PNG: palette indices for indexed files, RGBA otherwise.
Definition indexed_png.h:21
std::vector< uint8_t > snes_3bpp
std::vector< int > changed_tiles
std::vector< int > changed_blocks