namespace housekeeping continued again
This commit is contained in:
296
src/app/rom.cc
Normal file
296
src/app/rom.cc
Normal file
@@ -0,0 +1,296 @@
|
||||
#include "rom.h"
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
#include "Core/constants.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace Data {
|
||||
|
||||
ROM::~ROM() {
|
||||
if (loaded) {
|
||||
delete[] current_rom_;
|
||||
for (auto &each : decompressed_graphic_sheets_) {
|
||||
free(each);
|
||||
}
|
||||
for (auto &each : converted_graphic_sheets_) {
|
||||
free(each);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ROM::SetupRenderer(std::shared_ptr<SDL_Renderer> renderer) {
|
||||
sdl_renderer_ = renderer;
|
||||
}
|
||||
|
||||
// TODO: check if the rom has a header on load
|
||||
void ROM::LoadFromFile(const std::string &path) {
|
||||
size_ = std::filesystem::file_size(path.c_str());
|
||||
std::ifstream file(path.c_str(), std::ios::binary);
|
||||
if (!file.is_open()) {
|
||||
std::cout << "Error: Could not open ROM file " << path << std::endl;
|
||||
return;
|
||||
}
|
||||
current_rom_ = new unsigned char[size_];
|
||||
for (unsigned int i = 0; i < size_; i++) {
|
||||
char byte_read_ = ' ';
|
||||
file.read(&byte_read_, sizeof(char));
|
||||
current_rom_[i] = byte_read_;
|
||||
}
|
||||
file.close();
|
||||
memcpy(title, current_rom_ + 32704, 21);
|
||||
version_ = current_rom_[27];
|
||||
loaded = true;
|
||||
}
|
||||
|
||||
std::vector<tile8> ROM::ExtractTiles(gfx::TilePreset &preset) {
|
||||
std::cout << "Extracting tiles..." << std::endl;
|
||||
uint filePos = 0;
|
||||
uint size_out = 0;
|
||||
uint size = preset.length_;
|
||||
int tilePos = preset.pc_tiles_location_;
|
||||
std::vector<tile8> rawTiles;
|
||||
filePos = GetRomPosition(tilePos, preset.SNESTilesLocation);
|
||||
std::cout << "ROM Position: " << filePos << " from "
|
||||
<< preset.SNESTilesLocation << std::endl;
|
||||
|
||||
// decompress the gfx
|
||||
auto data = (char *)malloc(sizeof(char) * size);
|
||||
memcpy(data, (current_rom_ + filePos), size);
|
||||
data = alttp_decompress_gfx(data, 0, size, &size_out, &compressed_size_);
|
||||
std::cout << "size: " << size << std::endl;
|
||||
std::cout << "lastCompressedSize: " << compressed_size_ << std::endl;
|
||||
if (data == nullptr) {
|
||||
std::cout << alttp_decompression_error << std::endl;
|
||||
return rawTiles;
|
||||
}
|
||||
|
||||
// unpack the tiles based on their depth
|
||||
unsigned tileCpt = 0;
|
||||
std::cout << "Unpacking tiles..." << std::endl;
|
||||
for (unsigned int tilePos = 0; tilePos < size;
|
||||
tilePos += preset.bits_per_pixel_ * 8) {
|
||||
tile8 newTile = unpack_bpp_tile(data, tilePos, preset.bits_per_pixel_);
|
||||
newTile.id = tileCpt;
|
||||
rawTiles.push_back(newTile);
|
||||
tileCpt++;
|
||||
}
|
||||
std::cout << "Done unpacking tiles" << std::endl;
|
||||
free(data);
|
||||
std::cout << "Done extracting tiles." << std::endl;
|
||||
return rawTiles;
|
||||
}
|
||||
|
||||
gfx::SNESPalette ROM::ExtractPalette(gfx::TilePreset &preset) {
|
||||
uint filePos =
|
||||
GetRomPosition(preset.pc_palette_location_, preset.SNESPaletteLocation);
|
||||
std::cout << "Palette pos : " << filePos << std::endl; // TODO: make this hex
|
||||
uint palette_size = pow(2, preset.bits_per_pixel_); // - 1;
|
||||
|
||||
auto palette_data = std::make_unique<unsigned char[]>(palette_size * 2);
|
||||
memcpy(palette_data.get(), current_rom_ + filePos, palette_size * 2);
|
||||
|
||||
// char *ab = (char *)malloc(sizeof(char) * (palette_size * 2));
|
||||
// memcpy(ab, current_rom_ + filePos, palette_size * 2);
|
||||
|
||||
for (int i = 0; i < palette_size; i++) {
|
||||
std::cout << palette_data[i];
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
const unsigned char *data = palette_data.get();
|
||||
gfx::SNESPalette pal(data);
|
||||
if (preset.no_zero_color_) {
|
||||
gfx::SNESColor col;
|
||||
|
||||
col.setRgb(ImVec4(153, 153, 153, 255));
|
||||
pal.colors.push_back(col);
|
||||
pal.colors.erase(pal.colors.begin(),
|
||||
pal.colors.begin() + pal.colors.size() - 1);
|
||||
}
|
||||
return pal;
|
||||
}
|
||||
|
||||
uint32_t ROM::GetRomPosition(int direct_addr, uint snes_addr) const {
|
||||
unsigned int filePos = -1;
|
||||
std::cout << "directAddr:" << direct_addr << std::endl;
|
||||
if (direct_addr == -1) {
|
||||
filePos = rommapping_snes_to_pc(snes_addr, type_, has_header_);
|
||||
} else {
|
||||
filePos = direct_addr;
|
||||
if (has_header_) filePos += 0x200;
|
||||
}
|
||||
std::cout << "filePos:" << filePos << std::endl;
|
||||
return filePos;
|
||||
}
|
||||
|
||||
char *ROM::Decompress(int pos, int size, bool reversed) {
|
||||
char *buffer = new char[size];
|
||||
decompressed_graphic_sheets_.push_back(buffer);
|
||||
for (int i = 0; i < size; i++) {
|
||||
buffer[i] = 0;
|
||||
}
|
||||
unsigned int bufferPos = 0;
|
||||
unsigned char cmd = 0;
|
||||
unsigned int length = 0;
|
||||
|
||||
uchar databyte = current_rom_[pos];
|
||||
while (true) {
|
||||
databyte = (unsigned char)current_rom_[pos];
|
||||
if (databyte == 0xFF) // End of decompression
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if ((databyte & 0xE0) == 0xE0) // Expanded Command
|
||||
{
|
||||
cmd = (unsigned char)((databyte >> 2) & 0x07);
|
||||
length =
|
||||
(unsigned short)(((current_rom_[pos] << 8) | current_rom_[pos + 1]) &
|
||||
0x3FF);
|
||||
pos += 2; // Advance 2 bytes in ROM
|
||||
} else // Normal Command
|
||||
{
|
||||
cmd = (unsigned char)((databyte >> 5) & 0x07);
|
||||
length = (unsigned char)(databyte & 0x1F);
|
||||
pos += 1; // Advance 1 byte in ROM
|
||||
}
|
||||
length += 1; // Every commands are at least 1 size even if 00
|
||||
switch (cmd) {
|
||||
case 00: // Direct Copy (Could be replaced with a MEMCPY)
|
||||
for (int i = 0; i < length; i++) {
|
||||
buffer[bufferPos++] = (unsigned char)current_rom_[pos++];
|
||||
}
|
||||
// Do not advance in the ROM
|
||||
break;
|
||||
case 01: // Byte Fill
|
||||
for (int i = 0; i < length; i++) {
|
||||
buffer[bufferPos++] = (unsigned char)current_rom_[pos];
|
||||
}
|
||||
pos += 1; // Advance 1 byte in the ROM
|
||||
break;
|
||||
case 02: // Word Fill
|
||||
for (int i = 0; i < length; i += 2) {
|
||||
buffer[bufferPos++] = (unsigned char)current_rom_[pos];
|
||||
buffer[bufferPos++] = (unsigned char)current_rom_[pos + 1];
|
||||
}
|
||||
pos += 2; // Advance 2 byte in the ROM
|
||||
break;
|
||||
case 03: // Increasing Fill
|
||||
{
|
||||
unsigned char incByte = (unsigned char)current_rom_[pos];
|
||||
for (int i = 0; i < (unsigned int)length; i++) {
|
||||
buffer[bufferPos++] = (unsigned char)incByte++;
|
||||
}
|
||||
pos += 1; // Advance 1 byte in the ROM
|
||||
} break;
|
||||
case 04: // Repeat (Reversed byte order for maps)
|
||||
{
|
||||
unsigned short s1 = ((current_rom_[pos + 1] & 0xFF) << 8);
|
||||
unsigned short s2 = ((current_rom_[pos] & 0xFF));
|
||||
unsigned short Addr = (unsigned short)(s1 | s2);
|
||||
for (int i = 0; i < length; i++) {
|
||||
buffer[bufferPos] = (unsigned char)buffer[Addr + i];
|
||||
bufferPos++;
|
||||
}
|
||||
pos += 2; // Advance 2 bytes in the ROM
|
||||
} break;
|
||||
}
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
uchar *ROM::SNES3bppTo8bppSheet(uchar *buffer_in,
|
||||
int sheet_id) // 128x32
|
||||
{
|
||||
// 8bpp sheet out
|
||||
const uchar bitmask[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
|
||||
uchar *sheet_buffer_out = (uchar *)malloc(0x1000);
|
||||
converted_graphic_sheets_.push_back(sheet_buffer_out);
|
||||
int xx = 0; // positions where we are at on the sheet
|
||||
int yy = 0;
|
||||
int pos = 0;
|
||||
int ypos = 0;
|
||||
|
||||
if (sheet_id != 0) {
|
||||
yy = sheet_id;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 64; i++) // for each tiles //16 per lines
|
||||
{
|
||||
for (int y = 0; y < 8; y++) // for each lines
|
||||
{
|
||||
//[0] + [1] + [16]
|
||||
for (int x = 0; x < 8; x++) {
|
||||
unsigned char b1 =
|
||||
(unsigned char)((buffer_in[(y * 2) + (24 * pos)] & (bitmask[x])));
|
||||
unsigned char b2 =
|
||||
(unsigned char)(buffer_in[((y * 2) + (24 * pos)) + 1] &
|
||||
(bitmask[x]));
|
||||
unsigned char b3 =
|
||||
(unsigned char)(buffer_in[(16 + y) + (24 * pos)] & (bitmask[x]));
|
||||
unsigned char b = 0;
|
||||
if (b1 != 0) {
|
||||
b |= 1;
|
||||
};
|
||||
if (b2 != 0) {
|
||||
b |= 2;
|
||||
};
|
||||
if (b3 != 0) {
|
||||
b |= 4;
|
||||
};
|
||||
sheet_buffer_out[x + (xx) + (y * 128) + (yy * 1024)] = b;
|
||||
}
|
||||
}
|
||||
pos++;
|
||||
ypos++;
|
||||
xx += 8;
|
||||
if (ypos >= 16) {
|
||||
yy++;
|
||||
xx = 0;
|
||||
ypos = 0;
|
||||
}
|
||||
}
|
||||
return sheet_buffer_out;
|
||||
}
|
||||
|
||||
SDL_Texture *ROM::DrawgfxSheet(int offset) {
|
||||
SDL_Surface *surface =
|
||||
SDL_CreateRGBSurfaceWithFormat(0, 128, 32, 8, SDL_PIXELFORMAT_INDEX8);
|
||||
std::cout << "Drawing surface #" << offset << std::endl;
|
||||
uchar *sheet_buffer = nullptr;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
surface->format->palette->colors[i].r = i * 31;
|
||||
surface->format->palette->colors[i].g = i * 31;
|
||||
surface->format->palette->colors[i].b = i * 31;
|
||||
}
|
||||
|
||||
unsigned int snesAddr = 0;
|
||||
unsigned int pcAddr = 0;
|
||||
snesAddr = (unsigned int)((((uchar)(current_rom_[0x4F80 + offset]) << 16) |
|
||||
((uchar)(current_rom_[0x505F + offset]) << 8) |
|
||||
((uchar)(current_rom_[0x513E + offset]))));
|
||||
pcAddr = SnesToPc(snesAddr);
|
||||
std::cout << "Decompressing..." << std::endl;
|
||||
char *decomp = Decompress(pcAddr);
|
||||
std::cout << "Converting to 8bpp sheet..." << std::endl;
|
||||
sheet_buffer = SNES3bppTo8bppSheet((uchar *)decomp);
|
||||
std::cout << "Assigning pixel data..." << std::endl;
|
||||
surface->pixels = sheet_buffer;
|
||||
std::cout << "Creating texture from surface..." << std::endl;
|
||||
SDL_Texture *sheet_texture = nullptr;
|
||||
sheet_texture = SDL_CreateTextureFromSurface(sdl_renderer_.get(), surface);
|
||||
if (sheet_texture == nullptr) {
|
||||
std::cout << "Error: " << SDL_GetError() << std::endl;
|
||||
}
|
||||
return sheet_texture;
|
||||
}
|
||||
|
||||
int AddressFromBytes(uchar addr1, uchar addr2, uchar addr3) {
|
||||
return (addr1 << 16) | (addr2 << 8) | addr3;
|
||||
}
|
||||
|
||||
} // namespace Data
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
Reference in New Issue
Block a user