From 2c26914c9c26e273796397db5fa3e781ff740fc4 Mon Sep 17 00:00:00 2001 From: scawful Date: Sat, 3 Sep 2022 16:49:29 -0500 Subject: [PATCH] build current overworld graphics from 8bpp buffer --- src/app/editor/overworld_editor.cc | 40 ++++--- src/app/rom.cc | 166 ++++++++++++++++++++++++++++- src/app/rom.h | 8 +- src/app/zelda3/overworld.h | 1 + src/app/zelda3/overworld_map.cc | 38 ++----- 5 files changed, 203 insertions(+), 50 deletions(-) diff --git a/src/app/editor/overworld_editor.cc b/src/app/editor/overworld_editor.cc index d0140172..45cbe77f 100644 --- a/src/app/editor/overworld_editor.cc +++ b/src/app/editor/overworld_editor.cc @@ -44,7 +44,7 @@ absl::Status OverworldEditor::Update() { } if (overworld_debug_menu_) { - DrawOverworldDebugMenu(); + RETURN_IF_ERROR(DrawOverworldDebugMenu()) } auto toolset_status = DrawToolset(); @@ -179,8 +179,22 @@ void OverworldEditor::DrawOverworldCanvas() { if (overworld_.isLoaded()) { auto map = overworld_.GetOverworldMap(0); if (map.IsInitialized() && map.IsBuilt()) { - overworld_map_canvas_.DrawBitmap(map.GetBitmap(), 2); + if (map.IsLargeMap()) { + //g.FillRectangle(new SolidBrush(Palettes.overworld_GrassPalettes[0]), new RectangleF(x * 512, y * 512, 1024, 1024)); + // g.DrawImage(ow.allmaps[ow.allmaps[selectedMap].parent].gfxBitmap, new PointF(x * 512, y * 512)); + // g.DrawImage(ow.allmaps[ow.allmaps[selectedMap].parent + 1].gfxBitmap, new PointF((x + 1) * 512, y * 512)); + // g.DrawImage(ow.allmaps[ow.allmaps[selectedMap].parent + 8].gfxBitmap, new PointF((x) * 512, (y+1) * 512)); + // g.DrawImage(ow.allmaps[ow.allmaps[selectedMap].parent + 9].gfxBitmap, new PointF((x + 1) * 512, (y+1) * 512)); + + overworld_map_canvas_.DrawBitmap(map.GetBitmap(), 2); + } else { + // g.FillRectangle(new SolidBrush(Palettes.overworld_GrassPalettes[0]), new RectangleF(x * 512, y * 512, 512, 512)); + //g.DrawImage(ow.allmaps[ow.allmaps[selectedMap].parent].gfxBitmap, new PointF(x * 512, y * 512)); + + overworld_map_canvas_.DrawBitmap(map.GetBitmap(), 2); + } } + } overworld_map_canvas_.DrawGrid(64.f); overworld_map_canvas_.DrawOverlay(); @@ -279,21 +293,17 @@ void OverworldEditor::DrawAreaGraphics() { absl::Status OverworldEditor::DrawOverworldDebugMenu() { ImGui::Begin("Overworld Debug Menu"); + if (ImGui::Button("Load Overworld")) { RETURN_IF_ERROR(overworld_.Load(rom_)) - } - if (ImGui::Button("Current Graphics Bitmap")) { - current_gfx_bmp_.Create(128, 512, 8, overworld_.GetCurrentGraphics().data(), - 32768); + current_gfx_bmp_.Create(128, 512, 64, + overworld_.GetCurrentGraphics().data()); rom_.RenderBitmap(¤t_gfx_bmp_); - } - if (ImGui::Button("Tile16 Blockset Bitmap")) { - tile16_blockset_bmp_.Create( - 512, 16384, 8, overworld_.GetCurrentBlockset().data(), 1048576); + tile16_blockset_bmp_.Create(128, 8192, 128, + overworld_.GetCurrentBlockset().data()); rom_.RenderBitmap(&tile16_blockset_bmp_); - } - if (ImGui::Button("Overworld Map Bitmap")) { - overworld_map_bmp_.Create(1024, 1024, 8, overworld_.GetCurrentBitmapData().data()); + overworld_map_bmp_.Create(512, 512, 8, + overworld_.GetCurrentBitmapData().data()); rom_.RenderBitmap(&overworld_map_bmp_); } @@ -309,8 +319,10 @@ void OverworldEditor::LoadGraphics() { current_palette_[i].w = 1.f; } - PRINT_IF_ERROR(rom_.LoadAllGraphicsData()); + PRINT_IF_ERROR(rom_.LoadAllGraphicsData()) graphics_bin_ = rom_.GetGraphicsBin(); + + PRINT_IF_ERROR(rom_.CreateAllGraphicsData()) } } // namespace editor diff --git a/src/app/rom.cc b/src/app/rom.cc index f4c48bb3..51469bff 100644 --- a/src/app/rom.cc +++ b/src/app/rom.cc @@ -281,7 +281,7 @@ absl::StatusOr> SplitCompressionPiece( default: { return absl::InvalidArgumentError( "SplitCompressionCommand: Invalid Command"); - } break; + } } return new_piece; } @@ -578,6 +578,166 @@ absl::StatusOr ROM::DecompressOverworld(int pos, int size) { return Decompress(pos, size, kNintendoMode1); } +absl::StatusOr ROM::CreateAllGfxDataRaw() { + // 0-112 -> compressed 3bpp bgr -> (decompressed each) 0x600 bytes + // 113-114 -> compressed 2bpp -> (decompressed each) 0x800 bytes + // 115-126 -> uncompressed 3bpp sprites -> (each) 0x600 bytes + // 127-217 -> compressed 3bpp sprites -> (decompressed each) 0x600 bytes + // 218-222 -> compressed 2bpp -> (decompressed each) 0x800 bytes + Bytes buffer(0x54A00); + for (int i = 0; i < 0x54A00; ++i) { + buffer.push_back(0x00); + } + int bufferPos = 0; + Bytes data(0x600); + for (int i = 0; i < 0x600; ++i) { + buffer.push_back(0x00); + } + + for (int i = 0; i < 223; i++) { + bool c = true; + if (i >= 0 && i <= 112) // compressed 3bpp bgr + { + isbpp3[i] = true; + } else if (i >= 113 && i <= 114) // compressed 2bpp + { + isbpp3[i] = false; + } else if (i >= 115 && i <= 126) // uncompressed 3bpp sprites + { + isbpp3[i] = true; + c = false; + } else if (i >= 127 && i <= 217) // compressed 3bpp sprites + { + isbpp3[i] = true; + } else if (i >= 218 && i <= 222) // compressed 2bpp + { + isbpp3[i] = false; + } + + if (c) // if data is compressed decompress it + { + auto offset = GetGraphicsAddress(rom_data_.data(), i); + ASSIGN_OR_RETURN(data, Decompress(offset)) + } else { + data.resize(core::Uncompressed3BPPSize); + auto offset = GetGraphicsAddress(rom_data_.data(), i); + for (int j = 0; j < core::Uncompressed3BPPSize; j++) { + data[j] = rom_data_[j + offset]; + } + } + + for (int j = 0; j < data.size(); j++) { + buffer[j + bufferPos] = data[j]; + } + + bufferPos += data.size(); + } + + return buffer; +} + +absl::Status ROM::CreateAllGraphicsData() { + ASSIGN_OR_RETURN(Bytes data, CreateAllGfxDataRaw()) + Bytes newData(0x6F800); + for (int i = 0; i < 0x6F800; i++) { + newData.push_back(0x00); + } + Bytes mask{0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}; + int sheetPosition = 0; + + // 8x8 tile + // Per Sheet + for (int s = 0; s < 223; s++) { + // Per Tile Line Y + for (int j = 0; j < 4; j++) { + // Per Tile Line X + for (int i = 0; i < 16; i++) { + // Per Pixel Line + for (int y = 0; y < 8; y++) { + if (isbpp3[s]) { + auto lineBits0 = + data[(y * 2) + (i * 24) + (j * 384) + sheetPosition]; + auto lineBits1 = + data[(y * 2) + (i * 24) + (j * 384) + 1 + sheetPosition]; + auto lineBits2 = + data[(y) + (i * 24) + (j * 384) + 16 + sheetPosition]; + + // Per Pixel X + for (int x = 0; x < 4; x++) { + auto pixdata = 0; + auto pixdata2 = 0; + + if ((lineBits0 & mask[(x * 2)]) == mask[(x * 2)]) { + pixdata += 1; + } + if ((lineBits1 & mask[(x * 2)]) == mask[(x * 2)]) { + pixdata += 2; + } + if ((lineBits2 & mask[(x * 2)]) == mask[(x * 2)]) { + pixdata += 4; + } + + if ((lineBits0 & mask[(x * 2) + 1]) == mask[(x * 2) + 1]) { + pixdata2 += 1; + } + if ((lineBits1 & mask[(x * 2) + 1]) == mask[(x * 2) + 1]) { + pixdata2 += 2; + } + if ((lineBits2 & mask[(x * 2) + 1]) == mask[(x * 2) + 1]) { + pixdata2 += 4; + } + + newData[(y * 64) + (x) + (i * 4) + (j * 512) + (s * 2048)] = + ((pixdata << 4) | pixdata2); + } + } else { + auto lineBits0 = + data[(y * 2) + (i * 16) + (j * 256) + sheetPosition]; + auto lineBits1 = + data[(y * 2) + (i * 16) + (j * 256) + 1 + sheetPosition]; + + // Per Pixel X + for (int x = 0; x < 4; x++) { + auto pixdata = 0; + auto pixdata2 = 0; + + if ((lineBits0 & mask[(x * 2)]) == mask[(x * 2)]) { + pixdata += 1; + } + if ((lineBits1 & mask[(x * 2)]) == mask[(x * 2)]) { + pixdata += 2; + } + + if ((lineBits0 & mask[(x * 2) + 1]) == mask[(x * 2) + 1]) { + pixdata2 += 1; + } + if ((lineBits1 & mask[(x * 2) + 1]) == mask[(x * 2) + 1]) { + pixdata2 += 2; + } + + newData[(y * 64) + (x) + (i * 4) + (j * 512) + (s * 2048)] = + ((pixdata << 4) | pixdata2); + } + } + } + } + } + + if (isbpp3[s]) { + sheetPosition += 0x600; + } else { + sheetPosition += 0x800; + } + } + + graphics_buffer_.reserve(0x6F800); + for (int i = 0; i < 0x6F800; i++) { + graphics_buffer_.push_back(newData[i]); + } + + return absl::OkStatus(); +} + // 0-112 -> compressed 3bpp bgr -> (decompressed each) 0x600 chars // 113-114 -> compressed 2bpp -> (decompressed each) 0x800 chars // 115-126 -> uncompressed 3bpp sprites -> (each) 0x600 chars @@ -611,11 +771,11 @@ absl::Status ROM::LoadAllGraphicsData() { graphics_bin_.at(i).CreateTexture(renderer_); for (int j = 0; j < graphics_bin_.at(i).GetSize(); ++j) { - graphics_buffer_.push_back(graphics_bin_.at(i).GetByte(j)); + graphics_8bpp_buffer_.push_back(graphics_bin_.at(i).GetByte(j)); } } else { for (int j = 0; j < 0x1000; ++j) { - graphics_buffer_.push_back(0xFF); + graphics_8bpp_buffer_.push_back(0xFF); } } } diff --git a/src/app/rom.h b/src/app/rom.h index 72557238..128649c0 100644 --- a/src/app/rom.h +++ b/src/app/rom.h @@ -47,7 +47,6 @@ constexpr int kCommandMod = 0x07; constexpr int kExpandedMod = 0xE0; constexpr int kExpandedLengthMod = 0x3FF; constexpr int kNormalLengthMod = 0x1F; - constexpr uchar kGraphicsBitmap[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}; @@ -78,6 +77,10 @@ class ROM { absl::StatusOr DecompressOverworld(int pos, int size); absl::Status LoadAllGraphicsData(); + + absl::StatusOr CreateAllGfxDataRaw(); + absl::Status CreateAllGraphicsData(); + absl::Status LoadFromFile(const absl::string_view& filename); absl::Status LoadFromPointer(uchar* data, size_t length); absl::Status LoadFromBytes(const Bytes& data); @@ -89,6 +92,7 @@ class ROM { auto GetTitle() const { return title; } auto GetGraphicsBin() const { return graphics_bin_; } auto GetGraphicsBuffer() const { return graphics_buffer_; } + auto GetGraphics8BPP() const { return graphics_8bpp_buffer_; } void SetupRenderer(std::shared_ptr renderer) { renderer_ = renderer; } @@ -117,10 +121,12 @@ class ROM { long size_ = 0; uchar title[21] = "ROM Not Loaded"; bool is_loaded_ = false; + bool isbpp3[223]; std::string filename_; Bytes rom_data_; Bytes graphics_buffer_; + Bytes graphics_8bpp_buffer_; std::shared_ptr renderer_; std::unordered_map graphics_bin_; }; diff --git a/src/app/zelda3/overworld.h b/src/app/zelda3/overworld.h index 5b44d25e..84a0c0b6 100644 --- a/src/app/zelda3/overworld.h +++ b/src/app/zelda3/overworld.h @@ -54,6 +54,7 @@ class Overworld { int &ttpos); absl::Status DecompressAllMapTiles(); void FetchLargeMaps(); + void LoadOverworldMap(); int game_state_ = 1; int current_map_ = 0; diff --git a/src/app/zelda3/overworld_map.cc b/src/app/zelda3/overworld_map.cc index f4c51413..b6f16b4d 100644 --- a/src/app/zelda3/overworld_map.cc +++ b/src/app/zelda3/overworld_map.cc @@ -233,26 +233,16 @@ absl::Status OverworldMap::BuildTileset() { current_graphics_sheet_set[i] = sheet; } - all_gfx_ = rom_.GetGraphicsBuffer(); + all_gfx_ = rom_.GetGraphics8BPP(); + current_gfx_.reserve(32768); for (int i = 0; i < 32768; i++) { current_gfx_.push_back(0x00); } - for (int i = 0; i < 16; i++) { - for (int j = 0; j < 2048; j++) { - auto mapByte = all_gfx_[j + (static_graphics_[i] * 2048)]; - switch (i) { - case 0: - case 3: - case 4: - case 5: - mapByte += 0x88; - break; - default: - break; - } - current_gfx_[(i * 2048) + j] = mapByte; + for (int i = 0; i < 32; i++) { + for (int j = 0; j < 4096; j++) { + current_gfx_[(i * 4096) + j] = all_gfx_[j + (static_graphics_[i] * 4096)]; } } return absl::OkStatus(); @@ -271,23 +261,7 @@ absl::Status OverworldMap::BuildTiles16Gfx(int count) { for (auto i = 0; i < count; i++) { // 8x8 tile draw, gfx8 = 4bpp so everyting is /2F for (auto tile = 0; tile < 4; tile++) { - gfx::TileInfo info; - switch (tile) { - case 0: - info = tiles16_[i].tile0_; - break; - case 1: - info = tiles16_[i].tile1_; - break; - case 2: - info = tiles16_[i].tile2_; - break; - case 3: - info = tiles16_[i].tile3_; - break; - default: - return absl::InternalError("Invalid Tile"); - } + gfx::TileInfo info = tiles16_[i].tiles_info[tile]; int offset = offsets[tile]; for (auto y = 0; y < 8; y++) {