138 lines
5.0 KiB
C++
138 lines
5.0 KiB
C++
#include "app/gfx/background_buffer.h"
|
|
|
|
#include <algorithm>
|
|
#include <cstdint>
|
|
#include <vector>
|
|
|
|
#include "app/gfx/bitmap.h"
|
|
#include "app/gfx/snes_tile.h"
|
|
|
|
namespace yaze::gfx {
|
|
|
|
BackgroundBuffer::BackgroundBuffer(int width, int height)
|
|
: width_(width), height_(height) {
|
|
// Initialize buffer with size for SNES layers
|
|
const int total_tiles = (width / 8) * (height / 8);
|
|
buffer_.resize(total_tiles, 0);
|
|
}
|
|
|
|
void BackgroundBuffer::SetTileAt(int x, int y, uint16_t value) {
|
|
if (x < 0 || y < 0) return;
|
|
int tiles_w = width_ / 8;
|
|
int tiles_h = height_ / 8;
|
|
if (x >= tiles_w || y >= tiles_h) return;
|
|
buffer_[y * tiles_w + x] = value;
|
|
}
|
|
|
|
uint16_t BackgroundBuffer::GetTileAt(int x, int y) const {
|
|
int tiles_w = width_ / 8;
|
|
int tiles_h = height_ / 8;
|
|
if (x < 0 || y < 0 || x >= tiles_w || y >= tiles_h) return 0;
|
|
return buffer_[y * tiles_w + x];
|
|
}
|
|
|
|
void BackgroundBuffer::ClearBuffer() { std::ranges::fill(buffer_, 0); }
|
|
|
|
void BackgroundBuffer::DrawTile(const TileInfo& tile, uint8_t* canvas,
|
|
const uint8_t* tiledata, int indexoffset) {
|
|
int tx = (tile.id_ / 16 * 512) + ((tile.id_ & 0xF) * 4);
|
|
|
|
// Clamp palette to 0-5 (90 colors / 16 = 5.625, so max palette is 5)
|
|
// Palettes 6-7 would require colors 96-127, which don't exist in dungeon palettes
|
|
uint8_t clamped_palette = tile.palette_ & 0x07; // Get palette 0-7
|
|
if (clamped_palette > 5) {
|
|
clamped_palette = clamped_palette % 6; // Wrap palette 6->0, 7->1
|
|
}
|
|
|
|
uint8_t palnibble = (uint8_t)(clamped_palette << 4);
|
|
uint8_t r = tile.horizontal_mirror_ ? 1 : 0;
|
|
|
|
for (int yl = 0; yl < 512; yl += 64) {
|
|
int my = indexoffset + (tile.vertical_mirror_ ? 448 - yl : yl);
|
|
|
|
for (int xl = 0; xl < 4; xl++) {
|
|
int mx = 2 * (tile.horizontal_mirror_ ? 3 - xl : xl);
|
|
|
|
uint8_t pixel = tiledata[tx + yl + xl];
|
|
|
|
int index = mx + my;
|
|
canvas[index + r ^ 1] = (uint8_t)((pixel & 0x0F) | palnibble);
|
|
canvas[index + r] = (uint8_t)((pixel >> 4) | palnibble);
|
|
}
|
|
}
|
|
}
|
|
|
|
void BackgroundBuffer::DrawBackground(std::span<uint8_t> gfx16_data) {
|
|
// Initialize bitmap
|
|
bitmap_.Create(width_, height_, 8, std::vector<uint8_t>(width_ * height_, 0));
|
|
int tiles_w = width_ / 8;
|
|
int tiles_h = height_ / 8;
|
|
if ((int)buffer_.size() < tiles_w * tiles_h) {
|
|
buffer_.resize(tiles_w * tiles_h);
|
|
}
|
|
|
|
// For each tile on the tile buffer
|
|
for (int yy = 0; yy < tiles_h; yy++) {
|
|
for (int xx = 0; xx < tiles_w; xx++) {
|
|
uint16_t word = buffer_[xx + yy * tiles_w];
|
|
// Prevent draw if tile == 0xFFFF since it's 0 indexed
|
|
if (word == 0xFFFF) continue;
|
|
auto tile = gfx::WordToTileInfo(word);
|
|
DrawTile(tile, bitmap_.mutable_data().data(), gfx16_data.data(),
|
|
(yy * 512) + (xx * 8));
|
|
}
|
|
}
|
|
}
|
|
|
|
void BackgroundBuffer::DrawFloor(const std::vector<uint8_t>& rom_data,
|
|
int tile_address, int tile_address_floor,
|
|
uint8_t floor_graphics) {
|
|
auto f = (uint8_t)(floor_graphics << 4);
|
|
|
|
// Create floor tiles from ROM data
|
|
gfx::TileInfo floorTile1(rom_data[tile_address + f],
|
|
rom_data[tile_address + f + 1]);
|
|
gfx::TileInfo floorTile2(rom_data[tile_address + f + 2],
|
|
rom_data[tile_address + f + 3]);
|
|
gfx::TileInfo floorTile3(rom_data[tile_address + f + 4],
|
|
rom_data[tile_address + f + 5]);
|
|
gfx::TileInfo floorTile4(rom_data[tile_address + f + 6],
|
|
rom_data[tile_address + f + 7]);
|
|
|
|
gfx::TileInfo floorTile5(rom_data[tile_address_floor + f],
|
|
rom_data[tile_address_floor + f + 1]);
|
|
gfx::TileInfo floorTile6(rom_data[tile_address_floor + f + 2],
|
|
rom_data[tile_address_floor + f + 3]);
|
|
gfx::TileInfo floorTile7(rom_data[tile_address_floor + f + 4],
|
|
rom_data[tile_address_floor + f + 5]);
|
|
gfx::TileInfo floorTile8(rom_data[tile_address_floor + f + 6],
|
|
rom_data[tile_address_floor + f + 7]);
|
|
|
|
// Draw the floor tiles in a pattern
|
|
// Convert TileInfo to 16-bit words with palette information
|
|
uint16_t word1 = gfx::TileInfoToWord(floorTile1);
|
|
uint16_t word2 = gfx::TileInfoToWord(floorTile2);
|
|
uint16_t word3 = gfx::TileInfoToWord(floorTile3);
|
|
uint16_t word4 = gfx::TileInfoToWord(floorTile4);
|
|
uint16_t word5 = gfx::TileInfoToWord(floorTile5);
|
|
uint16_t word6 = gfx::TileInfoToWord(floorTile6);
|
|
uint16_t word7 = gfx::TileInfoToWord(floorTile7);
|
|
uint16_t word8 = gfx::TileInfoToWord(floorTile8);
|
|
|
|
for (int xx = 0; xx < 16; xx++) {
|
|
for (int yy = 0; yy < 32; yy++) {
|
|
SetTileAt((xx * 4), (yy * 2), word1);
|
|
SetTileAt((xx * 4) + 1, (yy * 2), word2);
|
|
SetTileAt((xx * 4) + 2, (yy * 2), word3);
|
|
SetTileAt((xx * 4) + 3, (yy * 2), word4);
|
|
|
|
SetTileAt((xx * 4), (yy * 2) + 1, word5);
|
|
SetTileAt((xx * 4) + 1, (yy * 2) + 1, word6);
|
|
SetTileAt((xx * 4) + 2, (yy * 2) + 1, word7);
|
|
SetTileAt((xx * 4) + 3, (yy * 2) + 1, word8);
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace yaze::gfx
|