16 const std::vector<uint8_t>& rom_data,
int tile_address,
17 int tile_address_floor, uint8_t floor_graphics) {
18 const int floor_offset =
static_cast<int>(floor_graphics & 0x0F) << 4;
19 const auto table_is_readable = [&](
int address) {
20 return address >= 0 &&
static_cast<size_t>(address + 7) < rom_data.size();
22 if (!table_is_readable(tile_address + floor_offset) ||
23 !table_is_readable(tile_address_floor + floor_offset)) {
27 std::array<TileInfo, 8> tiles;
28 for (
int index = 0; index < 4; ++index) {
29 const int main_address = tile_address + floor_offset + index * 2;
30 const int floor_address = tile_address_floor + floor_offset + index * 2;
31 tiles[index] =
TileInfo(rom_data[main_address], rom_data[main_address + 1]);
33 TileInfo(rom_data[floor_address], rom_data[floor_address + 1]);
39 : width_(width), height_(height) {}
42 const size_t total_tiles =
static_cast<size_t>((
width_ / 8) * (
height_ / 8));
43 if (
buffer_.size() != total_tiles) {
49 const size_t total_pixels =
static_cast<size_t>(
width_ *
height_);
56 const size_t total_pixels =
static_cast<size_t>(
width_ *
height_);
63 const size_t total_pixels =
static_cast<size_t>(
width_ *
height_);
85 if (x_pos < 0 || y_pos < 0) {
90 if (x_pos >= tiles_w || y_pos >= tiles_h) {
94 buffer_[y_pos * tiles_w + x_pos] = value;
100 if (x_pos < 0 || y_pos < 0 || x_pos >= tiles_w || y_pos >= tiles_h) {
103 const size_t index =
static_cast<size_t>(y_pos * tiles_w + x_pos);
148 const uint8_t keep_mask =
static_cast<uint8_t
>(~static_cast<uint8_t>(source));
155 int start_x,
int start_y,
156 int width,
int height) {
160 const uint8_t keep_mask =
static_cast<uint8_t
>(~static_cast<uint8_t>(source));
161 const int end_x = std::min(start_x + width,
width_);
162 const int end_y = std::min(start_y + height,
height_);
163 for (
int y = std::max(start_y, 0); y < end_y; ++y) {
164 for (
int x = std::max(start_x, 0); x < end_x; ++x) {
171 int start_x,
int start_y,
int width,
173 if (width <= 0 || height <= 0) {
177 const uint8_t source_mask =
static_cast<uint8_t
>(source);
178 const int end_x = std::min(start_x + width,
width_);
179 const int end_y = std::min(start_y + height,
height_);
180 for (
int y = std::max(start_y, 0); y < end_y; ++y) {
181 for (
int x = std::max(start_x, 0); x < end_x; ++x) {
213 std::vector<SDL_Color> palette(256);
215 for (
int i = 0; i < 256; i++) {
216 palette[i] = {
static_cast<Uint8
>(i),
static_cast<Uint8
>(i),
217 static_cast<Uint8
>(i), 255};
220 palette[255] = {0, 0, 0, 0};
234 const uint8_t* tiledata,
int indexoffset) {
237 constexpr int kGfxBufferSize = 0x10000;
238 constexpr int kMaxTileRow = 63;
241 int tile_col_idx = tile.
id_ % 16;
242 int tile_row_idx = tile.
id_ / 16;
245 if (tile_row_idx > kMaxTileRow) {
249 int tile_base_x = tile_col_idx * 8;
257 const uint8_t pal = tile.
palette_ & 0x07;
258 const uint8_t palette_offset =
static_cast<uint8_t
>(pal * 16);
264 uint8_t priority = tile.
over_ ? 1 : 0;
267 for (
int py = 0; py < 8; py++) {
270 for (
int px = 0; px < 8; px++) {
275 int src_index = (src_row * 128) + src_col + tile_base_x + tile_base_y;
278 if (src_index < 0 || src_index >= kGfxBufferSize)
281 uint8_t pixel = tiledata[src_index];
286 uint8_t final_color = pixel + palette_offset;
287 int dest_index = indexoffset + (py *
width_) + px;
290 if (dest_index >= 0 && dest_index < max_dest) {
291 canvas[dest_index] = final_color;
318 for (
int yy = 0; yy < tiles_h; yy++) {
319 for (
int xx = 0; xx < tiles_w; xx++) {
320 uint16_t word =
buffer_[xx + yy * tiles_w];
323 if (word == 0xFFFF) {
348 int tile_offset = (yy * 8 *
width_) + (xx * 8);
366 int tile_address,
int tile_address_floor,
367 uint8_t floor_graphics) {
371 LOG_DEBUG(
"[DrawFloor]",
"Creating bitmap: %dx%d, active=%d, width=%d",
375 LOG_DEBUG(
"[DrawFloor]",
"After Create: active=%d, width=%d, height=%d",
379 "Bitmap already exists: active=%d, width=%d, height=%d",
384 rom_data, tile_address, tile_address_floor, floor_graphics);
385 if (!floor_tiles.has_value()) {
386 LOG_DEBUG(
"[DrawFloor]",
"Floor pattern %d is outside the ROM data",
387 static_cast<int>(floor_graphics));
396 std::array<uint16_t, 8> words;
397 std::transform(floor_tiles->begin(), floor_tiles->end(), words.begin(),
398 [](
const TileInfo& tile) { return TileInfoToWord(tile); });
399 for (
int xx = 0; xx < 16; xx++) {
400 for (
int yy = 0; yy < 32; yy++) {
401 for (
int column = 0; column < 4; ++column) {
402 SetTileAt((xx * 4) + column, yy * 2, words[column]);
403 SetTileAt((xx * 4) + column, (yy * 2) + 1, words[column + 4]);
void EnsureBG1RevealMaskAllocated()
void ClearBG1RevealMask()
void DrawTile(const TileInfo &tile_info, uint8_t *canvas, const uint8_t *tiledata, int indexoffset)
void DrawBackground(std::span< uint8_t > gfx16_data)
void SetBG1RevealMaskRect(BG1RevealMaskSource source, int start_x, int start_y, int width, int height)
std::vector< uint8_t > & mutable_bg1_reveal_mask_data()
BackgroundBuffer(int width=512, int height=512)
std::vector< uint8_t > coverage_buffer_
void SetPriorityAt(int x, int y, uint8_t priority)
std::vector< uint8_t > & mutable_priority_data()
std::vector< uint8_t > bg1_reveal_mask_buffer_
uint8_t GetPriorityAt(int x, int y) const
void SetTileAt(int x, int y, uint16_t value)
void EnsureTileBufferAllocated()
void DrawFloor(const std::vector< uint8_t > &rom_data, int tile_address, int tile_address_floor, uint8_t floor_graphics)
std::vector< uint8_t > priority_buffer_
std::vector< uint8_t > & mutable_coverage_data()
void EnsureBitmapInitialized()
void EnsureCoverageBufferAllocated()
void ClearCoverageBuffer()
void ClearBG1RevealMaskRect(BG1RevealMaskSource source, int start_x, int start_y, int width, int height)
uint16_t GetTileAt(int x, int y) const
void EnsurePriorityBufferAllocated()
void ClearPriorityBuffer()
std::vector< uint16_t > buffer_
void Create(int width, int height, int depth, std::span< uint8_t > data)
Create a bitmap with the given dimensions and data.
void SetPalette(const SnesPalette &palette)
Set the palette for the bitmap using SNES palette format.
std::vector< uint8_t > & mutable_data()
SDL_Surface * surface() const
SNES 16-bit tile metadata container.
#define LOG_DEBUG(category, format,...)
Contains classes for handling graphical data.
std::optional< std::array< TileInfo, 8 > > DecodeDungeonFloorTilePattern(const std::vector< uint8_t > &rom_data, int tile_address, int tile_address_floor, uint8_t floor_graphics)
TileInfo WordToTileInfo(uint16_t word)