yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
tile16_renderer.cc
Go to the documentation of this file.
2
3#include <algorithm>
4
7
8namespace yaze::zelda3 {
9
10namespace {
11
12constexpr int kTile8Size = 8;
13constexpr int kTile16Size = 16;
14constexpr int kTile16PixelCount = 256;
15
16} // namespace
17
18std::vector<uint8_t> RenderTile16PixelsFromMetadata(
19 const gfx::Tile16& tile_data,
20 const std::vector<Tile8PixelData>& tile8_pixels) {
21 std::vector<uint8_t> tile16_pixels(kTile16PixelCount, 0);
22
23 for (int quadrant = 0; quadrant < 4; ++quadrant) {
24 const gfx::TileInfo& tile_info = Tile16QuadrantInfo(tile_data, quadrant);
25 const int quadrant_x = quadrant % 2;
26 const int quadrant_y = quadrant / 2;
27 const int tile8_id = tile_info.id_;
28
29 if (tile8_id < 0 || tile8_id >= static_cast<int>(tile8_pixels.size())) {
30 continue;
31 }
32
33 const Tile8PixelData& source_tile8 = tile8_pixels[tile8_id];
34
35 const bool x_flip = tile_info.horizontal_mirror_;
36 const bool y_flip = tile_info.vertical_mirror_;
37 const uint8_t palette_index =
38 static_cast<uint8_t>(tile_info.palette_ & 0x07);
39
40 for (int ty = 0; ty < kTile8Size; ++ty) {
41 for (int tx = 0; tx < kTile8Size; ++tx) {
42 const int src_x = x_flip ? (kTile8Size - 1 - tx) : tx;
43 const int src_y = y_flip ? (kTile8Size - 1 - ty) : ty;
44 const int src_index = src_y * kTile8Size + src_x;
45
46 const int dst_x = (quadrant_x * kTile8Size) + tx;
47 const int dst_y = (quadrant_y * kTile8Size) + ty;
48 const int dst_index = dst_y * kTile16Size + dst_x;
49
50 if (src_index < 0 ||
51 src_index >= static_cast<int>(source_tile8.size()) ||
52 dst_index < 0 || dst_index >= kTile16PixelCount) {
53 continue;
54 }
55
56 const uint8_t pixel = source_tile8[static_cast<size_t>(src_index)];
57 tile16_pixels[dst_index] = (pixel & 0x0F) + (palette_index * 0x10);
58 }
59 }
60 }
61
62 return tile16_pixels;
63}
64
65std::vector<uint8_t> RenderTile16PixelsFromMetadata(
66 const gfx::Tile16& tile_data,
67 const std::vector<gfx::Bitmap>& tile8_bitmaps) {
68 std::vector<uint8_t> tile16_pixels(kTile16PixelCount, 0);
69
70 for (int quadrant = 0; quadrant < 4; ++quadrant) {
71 const gfx::TileInfo& tile_info = Tile16QuadrantInfo(tile_data, quadrant);
72 const int quadrant_x = quadrant % 2;
73 const int quadrant_y = quadrant / 2;
74 const int tile8_id = tile_info.id_;
75
76 if (tile8_id < 0 || tile8_id >= static_cast<int>(tile8_bitmaps.size())) {
77 continue;
78 }
79
80 const gfx::Bitmap& source_tile8 = tile8_bitmaps[tile8_id];
81 if (!source_tile8.is_active() || source_tile8.data() == nullptr) {
82 continue;
83 }
84
85 const bool x_flip = tile_info.horizontal_mirror_;
86 const bool y_flip = tile_info.vertical_mirror_;
87 const uint8_t palette_index =
88 static_cast<uint8_t>(tile_info.palette_ & 0x07);
89
90 for (int ty = 0; ty < kTile8Size; ++ty) {
91 for (int tx = 0; tx < kTile8Size; ++tx) {
92 const int src_x = x_flip ? (kTile8Size - 1 - tx) : tx;
93 const int src_y = y_flip ? (kTile8Size - 1 - ty) : ty;
94 const int src_index = src_y * kTile8Size + src_x;
95
96 const int dst_x = (quadrant_x * kTile8Size) + tx;
97 const int dst_y = (quadrant_y * kTile8Size) + ty;
98 const int dst_index = dst_y * kTile16Size + dst_x;
99
100 if (src_index < 0 ||
101 src_index >= static_cast<int>(source_tile8.size()) ||
102 dst_index < 0 || dst_index >= kTile16PixelCount) {
103 continue;
104 }
105
106 const uint8_t pixel = source_tile8.data()[src_index];
107 tile16_pixels[dst_index] = (pixel & 0x0F) + (palette_index * 0x10);
108 }
109 }
110 }
111
112 return tile16_pixels;
113}
114
116 const gfx::Tile16& tile_data,
117 const std::vector<Tile8PixelData>& tile8_pixels,
118 gfx::Bitmap* output_bitmap) {
119 if (!output_bitmap) {
120 return absl::InvalidArgumentError("Output bitmap pointer is null");
121 }
122 if (tile8_pixels.empty()) {
123 return absl::FailedPreconditionError("Tile8 bitmap source is empty");
124 }
125
126 const auto pixels = RenderTile16PixelsFromMetadata(tile_data, tile8_pixels);
127 output_bitmap->Create(kTile16Size, kTile16Size, 8, pixels);
128 return absl::OkStatus();
129}
130
132 const gfx::Tile16& tile_data, const std::vector<gfx::Bitmap>& tile8_bitmaps,
133 gfx::Bitmap* output_bitmap) {
134 if (!output_bitmap) {
135 return absl::InvalidArgumentError("Output bitmap pointer is null");
136 }
137 if (tile8_bitmaps.empty()) {
138 return absl::FailedPreconditionError("Tile8 bitmap source is empty");
139 }
140
141 const auto pixels = RenderTile16PixelsFromMetadata(tile_data, tile8_bitmaps);
142 output_bitmap->Create(kTile16Size, kTile16Size, 8, pixels);
143 return absl::OkStatus();
144}
145
146int ComputeTile16Count(const gfx::Tilemap* tile16_blockset) {
147 if (!tile16_blockset || !tile16_blockset->atlas.is_active()) {
149 }
150
151 const int tiles_per_row =
152 std::max(1, tile16_blockset->atlas.width() / kTile16Size);
153 const int rows = std::max(1, tile16_blockset->atlas.height() / kTile16Size);
154 const int computed = tiles_per_row * rows;
155 return std::clamp(computed, 1, kNumTile16Individual);
156}
157
159 const gfx::Bitmap& source_bitmap) {
160 if (!destination || !destination->is_active() || !source_bitmap.is_active()) {
161 return;
162 }
163
164 const int tiles_per_row = std::max(1, destination->width() / kTile16Size);
165 const int tile_x = (tile_id % tiles_per_row) * kTile16Size;
166 const int tile_y = (tile_id / tiles_per_row) * kTile16Size;
167
168 for (int ty = 0; ty < kTile16Size; ++ty) {
169 for (int tx = 0; tx < kTile16Size; ++tx) {
170 const int src_index = ty * kTile16Size + tx;
171 const int dst_index =
172 (tile_y + ty) * destination->width() + (tile_x + tx);
173 if (src_index < static_cast<int>(source_bitmap.size()) &&
174 dst_index < static_cast<int>(destination->size())) {
175 destination->WriteToPixel(dst_index, source_bitmap.data()[src_index]);
176 }
177 }
178 }
179}
180
181} // namespace yaze::zelda3
Represents a bitmap image optimized for SNES ROM hacking.
Definition bitmap.h:67
const uint8_t * data() const
Definition bitmap.h:377
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:201
auto size() const
Definition bitmap.h:376
bool is_active() const
Definition bitmap.h:384
int height() const
Definition bitmap.h:374
int width() const
Definition bitmap.h:373
Tile composition of four 8x8 tiles.
Definition snes_tile.h:142
SNES 16-bit tile metadata container.
Definition snes_tile.h:52
Zelda 3 specific classes and functions.
absl::Status RenderTile16BitmapFromMetadata(const gfx::Tile16 &tile_data, const std::vector< Tile8PixelData > &tile8_pixels, gfx::Bitmap *output_bitmap)
constexpr int kNumTile16Individual
Definition overworld.h:239
int ComputeTile16Count(const gfx::Tilemap *tile16_blockset)
std::vector< uint8_t > RenderTile16PixelsFromMetadata(const gfx::Tile16 &tile_data, const std::vector< Tile8PixelData > &tile8_pixels)
const gfx::TileInfo & Tile16QuadrantInfo(const gfx::Tile16 &tile, int quadrant)
void BlitTile16BitmapToAtlas(gfx::Bitmap *destination, int tile_id, const gfx::Bitmap &source_bitmap)
std::array< uint8_t, 64 > Tile8PixelData
Room transition destination.
Definition zelda.h:448
Tilemap structure for SNES tile-based graphics management.
Definition tilemap.h:118
Bitmap atlas
Master bitmap containing all tiles.
Definition tilemap.h:119