Expand all graphics retrieval with bitmap and vram

This commit is contained in:
Justin Scofield
2022-07-17 18:09:12 -04:00
parent 5a62497110
commit 67e1e7ea0c
12 changed files with 165 additions and 115 deletions

View File

@@ -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

View File

@@ -192,90 +192,7 @@ void OverworldEditor::DrawOverworldMapSettings() {
void OverworldEditor::DrawOverworldCanvas() {
DrawOverworldMapSettings();
ImGui::Separator();
static ImVector<ImVec2> 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

View File

@@ -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<unsigned int, SDL_Texture *> all_texture_sheet_;
std::unordered_map<unsigned int, gfx::Bitmap> 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;

View File

@@ -1,4 +1,4 @@
#include "psuedo_vram.h"
#include "pseudo_vram.h"
namespace yaze {
namespace app {

View File

@@ -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 <SDL2/SDL.h>
@@ -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<Bitmap>& graphics_set);
void ChangeGraphicsTileset(const std::vector<Bitmap>& graphics_set);
void ChangeGraphicsPalette(const SNESPalette& graphics_pal);
void ChangeSpriteSet(const std::vector<Bitmap>& sprite_set);
void ChangeSpriteTileset(const std::vector<Bitmap>& sprite_set);
void ChangeSpritePalette(const SNESPalette& sprite_pal);
auto GetTileset(int index) const { return m_vram.at(index); }
private:
std::unordered_map<uint32_t, Bitmap> m_vram;
std::unordered_map<int, Bitmap> m_vram;
static const uint32_t REAL_VRAM_SIZE = 0x8000;
};
std::vector<Bitmap> CreateGraphicsSet(
int id, const std::unordered_map<uint32_t, Bitmap>& all_graphics);
int id, const std::unordered_map<int, Bitmap>& all_graphics);
std::vector<Bitmap> CreateSpriteSet(
int id, const std::unordered_map<uint32_t, Bitmap>& all_graphics);
int id, const std::unordered_map<int, Bitmap>& all_graphics);
} // namespace gfx
} // namespace app

View File

@@ -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];
}

View File

@@ -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<SDL_Renderer> 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<uchar> rom_ptr_;
gfx::pseudo_vram pseudo_vram_;
std::vector<uchar*> decompressed_graphic_sheets_;
std::vector<uchar*> converted_graphic_sheets_;
std::vector<SDL_Surface> surfaces_;
std::shared_ptr<SDL_Renderer> sdl_renderer_;
std::unordered_map<unsigned int, gfx::Bitmap> graphics_bin_;
};
} // namespace app

View File

@@ -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"

View File

@@ -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_;

View File

@@ -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

View File

@@ -4,6 +4,7 @@
#include <imgui/imgui.h>
#include <cmath>
#include <memory>
#include <string>
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<ImVec2> points_;
ImVec2 scrolling_;
ImVec2 canvas_sz_;
ImVec2 canvas_p0_;
ImVec2 canvas_p1_;
};
} // namespace gui
} // namespace yaze