From 67e1e7ea0cb2adcb8b5be30e503ed0b9f790d373 Mon Sep 17 00:00:00 2001 From: Justin Scofield Date: Sun, 17 Jul 2022 18:09:12 -0400 Subject: [PATCH] Expand all graphics retrieval with bitmap and vram --- src/CMakeLists.txt | 2 +- src/app/editor/overworld_editor.cc | 109 +++--------------- src/app/editor/overworld_editor.h | 8 +- .../gfx/{psuedo_vram.cc => pseudo_vram.cc} | 2 +- src/app/gfx/{psuedo_vram.h => pseudo_vram.h} | 18 +-- src/app/rom.cc | 4 + src/app/rom.h | 15 ++- src/app/zelda3/overworld.h | 2 +- src/app/zelda3/overworld_map.cc | 4 +- src/gui/canvas.cc | 102 +++++++++++++++- src/gui/canvas.h | 13 +++ test/CMakeLists.txt | 1 + 12 files changed, 165 insertions(+), 115 deletions(-) rename src/app/gfx/{psuedo_vram.cc => pseudo_vram.cc} (74%) rename src/app/gfx/{psuedo_vram.h => pseudo_vram.h} (63%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5c9a9d5e..b9718324 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -49,7 +49,7 @@ add_executable( app/core/constants.cc app/core/controller.cc app/gfx/bitmap.cc - app/gfx/psuedo_vram.cc + app/gfx/pseudo_vram.cc app/gfx/snes_tile.cc app/gfx/snes_palette.cc app/zelda3/overworld.cc diff --git a/src/app/editor/overworld_editor.cc b/src/app/editor/overworld_editor.cc index b3c725fe..18aaffbe 100644 --- a/src/app/editor/overworld_editor.cc +++ b/src/app/editor/overworld_editor.cc @@ -192,90 +192,7 @@ void OverworldEditor::DrawOverworldMapSettings() { void OverworldEditor::DrawOverworldCanvas() { DrawOverworldMapSettings(); ImGui::Separator(); - static ImVector points; - static ImVec2 scrolling(0.0f, 0.0f); - static bool opt_enable_context_menu = true; - static bool adding_line = false; - ImVec2 canvas_p0 = ImGui::GetCursorScreenPos(); - ImVec2 canvas_sz = ImGui::GetContentRegionAvail(); - auto canvas_p1 = ImVec2(canvas_p0.x + canvas_sz.x, canvas_p0.y + canvas_sz.y); - - // Draw border and background color - const ImGuiIO &io = ImGui::GetIO(); - ImDrawList *draw_list = ImGui::GetWindowDrawList(); - draw_list->AddRectFilled(canvas_p0, canvas_p1, IM_COL32(32, 32, 32, 255)); - draw_list->AddRect(canvas_p0, canvas_p1, IM_COL32(255, 255, 255, 255)); - - // This will catch our interactions - ImGui::InvisibleButton( - "canvas", canvas_sz, - ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight); - const bool is_hovered = ImGui::IsItemHovered(); // Hovered - const bool is_active = ImGui::IsItemActive(); // Held - const ImVec2 origin(canvas_p0.x + scrolling.x, - canvas_p0.y + scrolling.y); // Lock scrolled origin - const ImVec2 mouse_pos_in_canvas(io.MousePos.x - origin.x, - io.MousePos.y - origin.y); - - // Add first and second point - if (is_hovered && !adding_line && - ImGui::IsMouseClicked(ImGuiMouseButton_Left)) { - points.push_back(mouse_pos_in_canvas); - points.push_back(mouse_pos_in_canvas); - adding_line = true; - } - if (adding_line) { - points.back() = mouse_pos_in_canvas; - if (!ImGui::IsMouseDown(ImGuiMouseButton_Left)) adding_line = false; - } - - // Pan (we use a zero mouse threshold when there's no context menu) - const float mouse_threshold_for_pan = opt_enable_context_menu ? -1.0f : 0.0f; - if (is_active && - ImGui::IsMouseDragging(ImGuiMouseButton_Right, mouse_threshold_for_pan)) { - scrolling.x += io.MouseDelta.x; - scrolling.y += io.MouseDelta.y; - } - - // Context menu (under default mouse threshold) - ImVec2 drag_delta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Right); - if (opt_enable_context_menu && drag_delta.x == 0.0f && drag_delta.y == 0.0f) - ImGui::OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight); - if (ImGui::BeginPopup("context")) { - if (adding_line) points.resize(points.size() - 2); - adding_line = false; - if (ImGui::MenuItem("Remove one", nullptr, false, points.Size > 0)) { - points.resize(points.size() - 2); - } - if (ImGui::MenuItem("Remove all", nullptr, false, points.Size > 0)) { - points.clear(); - } - ImGui::EndPopup(); - } - - // Draw grid + all lines in the canvas - draw_list->PushClipRect(canvas_p0, canvas_p1, true); - if (opt_enable_grid) { - const float GRID_STEP = 64.0f; - for (float x = fmodf(scrolling.x, GRID_STEP); x < canvas_sz.x; - x += GRID_STEP) - draw_list->AddLine(ImVec2(canvas_p0.x + x, canvas_p0.y), - ImVec2(canvas_p0.x + x, canvas_p1.y), - IM_COL32(200, 200, 200, 40)); - for (float y = fmodf(scrolling.y, GRID_STEP); y < canvas_sz.y; - y += GRID_STEP) - draw_list->AddLine(ImVec2(canvas_p0.x, canvas_p0.y + y), - ImVec2(canvas_p1.x, canvas_p0.y + y), - IM_COL32(200, 200, 200, 40)); - } - - for (int n = 0; n < points.Size; n += 2) - draw_list->AddLine( - ImVec2(origin.x + points[n].x, origin.y + points[n].y), - ImVec2(origin.x + points[n + 1].x, origin.y + points[n + 1].y), - IM_COL32(255, 255, 0, 255), 2.0f); - - draw_list->PopClipRect(); + overworld_map_canvas_.Update(); } void OverworldEditor::DrawTileSelector() { @@ -300,7 +217,10 @@ void OverworldEditor::DrawTileSelector() { ImGui::EndChild(); ImGui::EndTabItem(); } - + if (ImGui::BeginTabItem("VRAM")) { + DrawPseudoVRAM(); + ImGui::EndTabItem(); + } ImGui::EndTabBar(); } } @@ -392,13 +312,14 @@ void OverworldEditor::DrawTile8Selector() const { } if (all_gfx_loaded_) { - for (const auto &[key, value] : all_texture_sheet_) { + for (const auto &[key, value] : graphics_bin_) { int offset = 64 * (key + 1); int top_left_y = canvas_p0.y + 2; if (key >= 1) { top_left_y = canvas_p0.y + 64 * key; } - draw_list->AddImage((void *)value, ImVec2(canvas_p0.x + 2, top_left_y), + draw_list->AddImage((void *)value.GetTexture(), + ImVec2(canvas_p0.x + 2, top_left_y), ImVec2(canvas_p0.x + 256, canvas_p0.y + offset)); } } @@ -422,12 +343,20 @@ void OverworldEditor::DrawTile8Selector() const { draw_list->PopClipRect(); } -void OverworldEditor::LoadGraphics() { - for (int i = 0; i < kNumSheetsToLoad; i++) { - all_texture_sheet_[i] = rom_.DrawGraphicsSheet(i); +void OverworldEditor::DrawPseudoVRAM() { + if (!vram_loaded_ && rom_.isLoaded()) { + for (int tileset_index = 0; tileset_index < 16; tileset_index++) { + rom_.GetVRAM().GetTileset(tileset_index); + } + pseudo_vram_canvas_.Update(); } } +void OverworldEditor::LoadGraphics() { + rom_.DrawAllGraphicsData(); + graphics_bin_ = rom_.GetGraphicsBin(); +} + } // namespace editor } // namespace app } // namespace yaze \ No newline at end of file diff --git a/src/app/editor/overworld_editor.h b/src/app/editor/overworld_editor.h index e000c889..c91db920 100644 --- a/src/app/editor/overworld_editor.h +++ b/src/app/editor/overworld_editor.h @@ -10,6 +10,7 @@ #include "app/gfx/snes_palette.h" #include "app/gfx/snes_tile.h" #include "app/zelda3/overworld.h" +#include "gui/canvas.h" #include "gui/icons.h" namespace yaze { @@ -30,6 +31,7 @@ class OverworldEditor { void DrawTileSelector(); void DrawTile16Selector() const; void DrawTile8Selector() const; + void DrawPseudoVRAM(); void LoadBlockset(); void LoadGraphics(); @@ -38,6 +40,8 @@ class OverworldEditor { zelda3::Overworld overworld_; gfx::SNESPalette palette_; + gui::Canvas overworld_map_canvas_; + gui::Canvas pseudo_vram_canvas_; // pointer size 1048576 gfx::Bitmap tile16_blockset_bmp_; @@ -51,6 +55,7 @@ class OverworldEditor { gfx::Bitmap mapblockset16Bitmap; std::unordered_map all_texture_sheet_; + std::unordered_map graphics_bin_; int current_world_ = 0; char map_gfx_[3] = ""; @@ -64,10 +69,11 @@ class OverworldEditor { bool opt_enable_grid = true; bool all_gfx_loaded_ = false; bool map_blockset_loaded_ = false; + bool vram_loaded_ = false; constexpr static int kByteSize = 3; constexpr static int kMessageIdSize = 5; - constexpr static int kNumSheetsToLoad = 100; + constexpr static int kNumSheetsToLoad = 223; constexpr static int kTile8DisplayHeight = 64; constexpr static float kInputFieldSize = 30.f; diff --git a/src/app/gfx/psuedo_vram.cc b/src/app/gfx/pseudo_vram.cc similarity index 74% rename from src/app/gfx/psuedo_vram.cc rename to src/app/gfx/pseudo_vram.cc index f9435e41..bd73d1d8 100644 --- a/src/app/gfx/psuedo_vram.cc +++ b/src/app/gfx/pseudo_vram.cc @@ -1,4 +1,4 @@ -#include "psuedo_vram.h" +#include "pseudo_vram.h" namespace yaze { namespace app { diff --git a/src/app/gfx/psuedo_vram.h b/src/app/gfx/pseudo_vram.h similarity index 63% rename from src/app/gfx/psuedo_vram.h rename to src/app/gfx/pseudo_vram.h index daefea18..d36abfd4 100644 --- a/src/app/gfx/psuedo_vram.h +++ b/src/app/gfx/pseudo_vram.h @@ -1,5 +1,5 @@ -#ifndef YAZE_APP_GFX_PSUEDO_VRAM_H -#define YAZE_APP_GFX_PSUEDO_VRAM_H +#ifndef YAZE_APP_GFX_PSEUDO_VRAM_H +#define YAZE_APP_GFX_PSEUDO_VRAM_H #include @@ -21,22 +21,24 @@ namespace gfx { // Palette: 256 entries; 15-Bit color (BGR555) for a total of 32,768 colors. // Resolution: between 256x224 and 512x448. -class psuedo_vram { +class pseudo_vram { public: - void ChangeGraphicsSet(const std::vector& graphics_set); + void ChangeGraphicsTileset(const std::vector& graphics_set); void ChangeGraphicsPalette(const SNESPalette& graphics_pal); - void ChangeSpriteSet(const std::vector& sprite_set); + void ChangeSpriteTileset(const std::vector& sprite_set); void ChangeSpritePalette(const SNESPalette& sprite_pal); + auto GetTileset(int index) const { return m_vram.at(index); } + private: - std::unordered_map m_vram; + std::unordered_map m_vram; static const uint32_t REAL_VRAM_SIZE = 0x8000; }; std::vector CreateGraphicsSet( - int id, const std::unordered_map& all_graphics); + int id, const std::unordered_map& all_graphics); std::vector CreateSpriteSet( - int id, const std::unordered_map& all_graphics); + int id, const std::unordered_map& all_graphics); } // namespace gfx } // namespace app diff --git a/src/app/rom.cc b/src/app/rom.cc index 3c06d78d..f7ae2510 100644 --- a/src/app/rom.cc +++ b/src/app/rom.cc @@ -239,6 +239,10 @@ void ROM::DrawAllGraphicsData() { data = Decompress(gfx_addr, core::constants::UncompressedSheetSize); } + gfx::Bitmap tilesheet_bmp(128, 32, 8, SNES3bppTo8bppSheet(data)); + tilesheet_bmp.CreateTexture(sdl_renderer_); + graphics_bin_[i] = tilesheet_bmp; + for (int j = 0; j < sizeof(data); j++) { buffer[j + buffer_pos] = data[j]; } diff --git a/src/app/rom.h b/src/app/rom.h index 81f5cb25..1078cfe7 100644 --- a/src/app/rom.h +++ b/src/app/rom.h @@ -15,6 +15,7 @@ #include "app/core/common.h" #include "app/core/constants.h" +#include "app/gfx/pseudo_vram.h" #include "app/gfx/snes_tile.h" namespace yaze { @@ -28,7 +29,7 @@ class ROM { void Close(); void SetupRenderer(std::shared_ptr renderer); void LoadFromFile(const std::string& path); - void LoadFromPointer(uchar *data); + void LoadFromPointer(uchar* data); uchar* DecompressGraphics(int pos, int size); uchar* DecompressOverworld(int pos, int size); @@ -43,25 +44,27 @@ class ROM { gfx::SNESPalette ExtractPalette(uint addr, int bpp); uchar* data() { return current_rom_; } - auto Renderer() { return sdl_renderer_; } const uchar* getTitle() const { return title; } long getSize() const { return size_; } bool isLoaded() const { return is_loaded_; } + auto Renderer() { return sdl_renderer_; } + auto GetGraphicsBin() const { return graphics_bin_; } + auto GetVRAM() const { return pseudo_vram_; } private: - bool is_loaded_ = false; int num_sheets_ = 0; long size_ = 0; uchar* current_rom_; uchar title[21] = "ROM Not Loaded"; - enum rom_type type_ = LoROM; + bool is_loaded_ = false; bool isbpp3[core::constants::NumberOfSheets]; + enum rom_type type_ = LoROM; - std::shared_ptr rom_ptr_; + gfx::pseudo_vram pseudo_vram_; std::vector decompressed_graphic_sheets_; std::vector converted_graphic_sheets_; - std::vector surfaces_; std::shared_ptr sdl_renderer_; + std::unordered_map graphics_bin_; }; } // namespace app diff --git a/src/app/zelda3/overworld.h b/src/app/zelda3/overworld.h index fc7ea42b..7d0e1ff3 100644 --- a/src/app/zelda3/overworld.h +++ b/src/app/zelda3/overworld.h @@ -9,7 +9,7 @@ #include "app/core/constants.h" #include "app/gfx/bitmap.h" -#include "app/gfx/psuedo_vram.h" +#include "app/gfx/pseudo_vram.h" #include "app/gfx/snes_tile.h" #include "app/rom.h" #include "app/zelda3/overworld_map.h" diff --git a/src/app/zelda3/overworld_map.cc b/src/app/zelda3/overworld_map.cc index d89dcab7..832ac869 100644 --- a/src/app/zelda3/overworld_map.cc +++ b/src/app/zelda3/overworld_map.cc @@ -188,7 +188,7 @@ void OverworldMap::CopyTile8bpp16(int x, int y, int tile, uchar* destbmpPtr, void OverworldMap::CopyTile8bpp16From8(int xP, int yP, int tileID, uchar* destbmpPtr, uchar* sourcebmpPtr) { auto gfx16Data = destbmpPtr; - // TODO: PSUEDO VRAM + // TODO: PSEUDO VRAM auto gfx8Data = currentOWgfx16Ptr_; int offsets[] = {0, 8, 4096, 4104}; @@ -342,7 +342,7 @@ void OverworldMap::BuildTileset(int gameState) { staticgfx[7] = 91; } - // TODO: PSUEDO VRAM DATA HERE + // TODO: PSEUDO VRAM DATA HERE uchar* currentmapgfx8Data = currentOWgfx16Ptr_; // TODO: PUT GRAPHICS DATA HERE uchar const* allgfxData = allGfx16Ptr_; diff --git a/src/gui/canvas.cc b/src/gui/canvas.cc index c503ec48..df08d816 100644 --- a/src/gui/canvas.cc +++ b/src/gui/canvas.cc @@ -10,8 +10,10 @@ namespace gui { void Canvas::Update() { ImVec2 canvas_p0 = ImGui::GetCursorScreenPos(); - ImVec2 canvas_sz = ImGui::GetContentRegionAvail(); - auto canvas_p1 = ImVec2(canvas_p0.x + canvas_sz.x, canvas_p0.y + canvas_sz.y); + if (!custom_canvas_size_) canvas_sz_ = ImGui::GetContentRegionAvail(); + + auto canvas_p1 = + ImVec2(canvas_p0.x + canvas_sz_.x, canvas_p0.y + canvas_sz_.y); // Draw border and background color const ImGuiIO &io = ImGui::GetIO(); @@ -21,7 +23,7 @@ void Canvas::Update() { // This will catch our interactions ImGui::InvisibleButton( - "canvas", canvas_sz, + "canvas", canvas_sz_, ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight); const bool is_hovered = ImGui::IsItemHovered(); // Hovered const bool is_active = ImGui::IsItemActive(); // Held @@ -67,12 +69,12 @@ void Canvas::Update() { draw_list->PushClipRect(canvas_p0, canvas_p1, true); if (enable_grid_) { const float GRID_STEP = 64.0f; - for (float x = fmodf(scrolling_.x, GRID_STEP); x < canvas_sz.x; + for (float x = fmodf(scrolling_.x, GRID_STEP); x < canvas_sz_.x; x += GRID_STEP) draw_list->AddLine(ImVec2(canvas_p0.x + x, canvas_p0.y), ImVec2(canvas_p0.x + x, canvas_p1.y), IM_COL32(200, 200, 200, 40)); - for (float y = fmodf(scrolling_.y, GRID_STEP); y < canvas_sz.y; + for (float y = fmodf(scrolling_.y, GRID_STEP); y < canvas_sz_.y; y += GRID_STEP) draw_list->AddLine(ImVec2(canvas_p0.x, canvas_p0.y + y), ImVec2(canvas_p1.x, canvas_p0.y + y), @@ -89,5 +91,95 @@ void Canvas::Update() { draw_list->PopClipRect(); } +void Canvas::DrawBackground() { + canvas_p0_ = ImGui::GetCursorScreenPos(); + if (!custom_canvas_size_) canvas_sz_ = ImGui::GetContentRegionAvail(); + + canvas_p1_ = ImVec2(canvas_p0_.x + canvas_sz_.x, canvas_p0_.y + canvas_sz_.y); + + // Draw border and background color + draw_list_ = ImGui::GetWindowDrawList(); + draw_list_->AddRectFilled(canvas_p0_, canvas_p1_, IM_COL32(32, 32, 32, 255)); + draw_list_->AddRect(canvas_p0_, canvas_p1_, IM_COL32(255, 255, 255, 255)); +} + +void Canvas::UpdateContext() { + // This will catch our interactions + const ImGuiIO &io = ImGui::GetIO(); + ImGui::InvisibleButton( + "canvas", canvas_sz_, + ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight); + const bool is_hovered = ImGui::IsItemHovered(); // Hovered + const bool is_active = ImGui::IsItemActive(); // Held + const ImVec2 origin(canvas_p0_.x + scrolling_.x, + canvas_p0_.y + scrolling_.y); // Lock scrolled origin + const ImVec2 mouse_pos_in_canvas(io.MousePos.x - origin.x, + io.MousePos.y - origin.y); + + // Add first and second point + if (is_hovered && !dragging_select_ && + ImGui::IsMouseClicked(ImGuiMouseButton_Left)) { + points_.push_back(mouse_pos_in_canvas); + points_.push_back(mouse_pos_in_canvas); + dragging_select_ = true; + } + if (dragging_select_) { + points_.back() = mouse_pos_in_canvas; + if (!ImGui::IsMouseDown(ImGuiMouseButton_Left)) dragging_select_ = false; + } + + // Pan (we use a zero mouse threshold when there's no context menu) + const float mouse_threshold_for_pan = enable_context_menu_ ? -1.0f : 0.0f; + if (is_active && + ImGui::IsMouseDragging(ImGuiMouseButton_Right, mouse_threshold_for_pan)) { + scrolling_.x += io.MouseDelta.x; + scrolling_.y += io.MouseDelta.y; + } + + // Context menu (under default mouse threshold) + ImVec2 drag_delta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Right); + if (enable_context_menu_ && drag_delta.x == 0.0f && drag_delta.y == 0.0f) + ImGui::OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight); + if (ImGui::BeginPopup("context")) { + if (dragging_select_) points_.resize(points_.size() - 2); + dragging_select_ = false; + if (ImGui::MenuItem("Remove all", nullptr, false, points_.Size > 0)) { + points_.clear(); + } + ImGui::EndPopup(); + } +} + +void Canvas::DrawGrid() { + // Draw grid + all lines in the canvas + draw_list_->PushClipRect(canvas_p0_, canvas_p1_, true); + if (enable_grid_) { + const float GRID_STEP = 64.0f; + for (float x = fmodf(scrolling_.x, GRID_STEP); x < canvas_sz_.x; + x += GRID_STEP) + draw_list_->AddLine(ImVec2(canvas_p0_.x + x, canvas_p0_.y), + ImVec2(canvas_p0_.x + x, canvas_p1_.y), + IM_COL32(200, 200, 200, 40)); + for (float y = fmodf(scrolling_.y, GRID_STEP); y < canvas_sz_.y; + y += GRID_STEP) + draw_list_->AddLine(ImVec2(canvas_p0_.x, canvas_p0_.y + y), + ImVec2(canvas_p1_.x, canvas_p0_.y + y), + IM_COL32(200, 200, 200, 40)); + } +} + +void Canvas::DrawOverlay() { + const ImVec2 origin(canvas_p0_.x + scrolling_.x, + canvas_p0_.y + scrolling_.y); // Lock scrolled origin + for (int n = 0; n < points_.Size; n += 2) { + draw_list_->AddRect( + ImVec2(origin.x + points_[n].x, origin.y + points_[n].y), + ImVec2(origin.x + points_[n + 1].x, origin.y + points_[n + 1].y), + IM_COL32(255, 255, 255, 255), 1.0f); + } + + draw_list_->PopClipRect(); +} + } // namespace gui } // namespace yaze \ No newline at end of file diff --git a/src/gui/canvas.h b/src/gui/canvas.h index 4b5bddf8..729af14b 100644 --- a/src/gui/canvas.h +++ b/src/gui/canvas.h @@ -4,6 +4,7 @@ #include #include +#include #include namespace yaze { @@ -11,18 +12,30 @@ namespace gui { class Canvas { public: Canvas() = default; + Canvas(ImVec2 canvas_size) + : canvas_sz_(canvas_size), custom_canvas_size_(true) {} void Update(); + void DrawBackground(); + void UpdateContext(); + void DrawGrid(); + void DrawOverlay(); // last + private: bool enable_grid_ = true; bool enable_context_menu_ = true; bool dragging_select_ = false; + bool custom_canvas_size_ = false; std::string title_; + ImDrawList* draw_list_; ImVector points_; ImVec2 scrolling_; + ImVec2 canvas_sz_; + ImVec2 canvas_p0_; + ImVec2 canvas_p1_; }; } // namespace gui } // namespace yaze diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 954ec9a5..35ffbff0 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -19,6 +19,7 @@ add_executable( yaze_test.cc rom_test.cc ../src/app/rom.cc + ../src/app/gfx/bitmap.cc ../src/app/gfx/snes_tile.cc ../src/app/gfx/snes_palette.cc ../src/app/core/common.cc