Refactor ROM handling and remove SharedRom singleton for improved architecture

- Eliminated the SharedRom class to enhance modularity and reduce global state management.
- Updated various classes to directly manage ROM instances, improving clarity and encapsulation.
- Added new functions for loading messages and colors from ROM, enhancing functionality.
- Refactored Canvas and Editor classes to utilize direct ROM references, streamlining interactions.
- Improved documentation and comments for better code understanding and maintainability.
This commit is contained in:
scawful
2025-08-03 17:52:02 -04:00
parent a9a9cc888b
commit fdda77c172
17 changed files with 256 additions and 236 deletions

View File

@@ -9,7 +9,6 @@ The goal of yaze is to build a cross platform editor for the Legend of Zelda: A
- **yaze**: Desktop application for Windows/macOS/Linux
- **z3ed**: Command Line Interface
- **yaze_c**: C Library
- **yaze_py**: Python Module
- **yaze_test**: Unit test executable
- **yaze_ios**: iOS application
@@ -23,7 +22,6 @@ The goal of yaze is to build a cross platform editor for the Legend of Zelda: A
- **app**: Contains the GUI editor `yaze`
- **app/emu**: Contains a standalone Snes emulator application `yaze_emu`
- **cli**: Contains the command line interface `z3ed`
- **cli/python**: Contains the Python module `yaze_py`
- **ios**: Contains the iOS application `yaze_ios`
- **lib**: Contains the dependencies as git submodules
- **test**: Contains testing interface `yaze_test`
@@ -37,11 +35,10 @@ See [build-instructions.md](docs/build-instructions.md) for more information.
- **ImGui**: GUI library
- **Abseil**: C++ library
- **libpng**: Image library
- **Boost**: Python library
## Flow of Control
- app/yaze.cc
- app/main.cc
- Initializes `absl::FailureSignalHandler` for stack tracing.
- Runs the `core::Controller` loop.
- app/core/controller.cc
@@ -75,8 +72,6 @@ See [build-instructions.md](docs/build-instructions.md) for more information.
The Rom class provides methods to manipulate and access data from a ROM.
Currently implemented as a singleton with SharedRom which is not great but has helped with development velocity. Potential room for improvement is to refactor the editors to take the ROM as a parameter.
## Bitmap
- app/gfx/bitmap.cc

View File

@@ -35,8 +35,6 @@ struct yaze_project {
const char* name;
const char* filepath;
const char* rom_filename;
const char* code_folder;
const char* labels_filename;
};
yaze_project yaze_load_project(const char* filename);
@@ -93,14 +91,61 @@ typedef struct snes_tile32 {
uint16_t t3;
} snes_tile32;
/**
* @brief Get a color from a palette set.
*
* @details This function gets a color from a palette set and returns it as a
* snes_color object.
*
* @param rom The ROM to get the color from.
* @param palette_set The palette set to get the color from.
* @param palette The palette to get the color from.
* @param color The color to get from the palette.
* @return The color from the palette set.
*/
snes_color yaze_get_color_from_paletteset(const zelda3_rom* rom,
int palette_set, int palette,
int color);
/**
* @brief Load the overworld from the ROM.
*
* @param rom The ROM to load the overworld from.
* @return The status of the operation. If the operation is successful, the
* overworld object will be populated with the overworld from the ROM.
*/
zelda3_overworld* yaze_load_overworld(const zelda3_rom* rom);
/**
* @brief Load all rooms from the ROM.
*
* @details This function loads all rooms from the ROM and returns them as an
* array of rooms.
*
* @param rom The ROM to load rooms from.
* @return The status of the operation. If the operation is successful, the
* rooms array will be populated with the rooms from the ROM.
*/
zelda3_dungeon_room* yaze_load_all_rooms(const zelda3_rom* rom);
/**
* @brief Load all messages from the ROM.
*
* @details This function loads all messages from the ROM and returns them as an
* array of messages.
*
* @param rom The ROM to load messages from.
* @param messages Pointer to an array of messages.
* @return The status of the operation. If the operation is successful, the
* messages array will be populated with the messages from the ROM.
*/
yaze_status yaze_load_messages(zelda3_rom* rom, zelda3_message** messages);
/**
* @brief Function pointer to initialize the extension.
*
* @param context The editor context.
*/
typedef void (*yaze_initialize_func)(yaze_editor_context* context);
typedef void (*yaze_cleanup_func)(void);

View File

@@ -86,7 +86,7 @@ const static zelda3_version_pointers zelda3_jp_pointers = {
typedef struct zelda3_rom {
const char* filename;
const uint8_t* data;
uint8_t* data;
size_t size;
void* impl; // yaze::Rom*
} zelda3_rom;
@@ -95,6 +95,19 @@ zelda3_rom* yaze_load_rom(const char* filename);
void yaze_unload_rom(zelda3_rom* rom);
void yaze_save_rom(zelda3_rom* rom, const char* filename);
/**
* @brief Primitive of a message.
*
*/
typedef struct zelda3_message {
uint8_t id;
uint8_t address;
uint8_t *raw_string;
uint8_t *contents_parsed;
uint8_t *data;
uint8_t *data_parsed;
} zelda3_message;
/**
* @brief Primitive of an overworld map.
*/

View File

@@ -206,15 +206,16 @@
}
- (void)openFileAction:(id)sender {
if (!yaze::SharedRom::shared_rom_
->LoadFromFile(yaze::core::FileDialogWrapper::ShowOpenFileDialog())
.ok()) {
NSAlert *alert = [[NSAlert alloc] init];
[alert setMessageText:@"Error"];
[alert setInformativeText:@"Failed to load file."];
[alert addButtonWithTitle:@"OK"];
[alert runModal];
}
// TODO: Re-implmenent this without the SharedRom singleton
// if (!yaze::SharedRom::shared_rom_
// ->LoadFromFile(yaze::core::FileDialogWrapper::ShowOpenFileDialog())
// .ok()) {
// NSAlert *alert = [[NSAlert alloc] init];
// [alert setMessageText:@"Error"];
// [alert setInformativeText:@"Failed to load file."];
// [alert addButtonWithTitle:@"OK"];
// [alert runModal];
// }
}
- (void)cutAction:(id)sender {
@@ -238,12 +239,12 @@ extern "C" void yaze_initialize_cococa() {
extern "C" int yaze_run_cocoa_app_delegate(const char *filename) {
yaze_initialize_cococa();
yaze::core::Controller controller;
EXIT_IF_ERROR(controller.OnEntry(filename));
while (controller.IsActive()) {
auto controller = std::make_unique<yaze::core::Controller>();
EXIT_IF_ERROR(controller->OnEntry(filename));
while (controller->IsActive()) {
@autoreleasepool {
controller.OnInput();
if (auto status = controller.OnLoad(); !status.ok()) {
controller->OnInput();
if (auto status = controller->OnLoad(); !status.ok()) {
NSAlert *alert = [[NSAlert alloc] init];
[alert setMessageText:@"Error"];
[alert setInformativeText:[NSString stringWithUTF8String:status.message().data()]];
@@ -251,10 +252,10 @@ extern "C" int yaze_run_cocoa_app_delegate(const char *filename) {
[alert runModal];
break;
}
controller.DoRender();
controller->DoRender();
}
}
controller.OnExit();
controller->OnExit();
return EXIT_SUCCESS;
}

View File

@@ -13,7 +13,7 @@ namespace editor {
* @class GfxGroupEditor
* @brief Manage graphics group configurations in a Rom.
*/
class GfxGroupEditor : public SharedRom {
class GfxGroupEditor {
public:
absl::Status Update();
@@ -27,6 +27,8 @@ class GfxGroupEditor : public SharedRom {
void SetSelectedSpriteset(uint8_t spriteset) {
selected_spriteset_ = spriteset;
}
void set_rom(Rom* rom) { rom_ = rom; }
Rom* rom() const { return rom_; }
private:
uint8_t selected_blockset_ = 0;
@@ -39,6 +41,7 @@ class GfxGroupEditor : public SharedRom {
gui::Canvas spriteset_canvas_;
gfx::SnesPalette palette_;
Rom* rom_ = nullptr;
};
} // namespace editor

View File

@@ -586,7 +586,9 @@ absl::Status OverworldEditor::CheckForCurrentMap() {
}
const int current_highlighted_map = current_map_;
current_parent_ = overworld_.overworld_map(current_map_)->parent();
if (!current_map_lock_) {
current_parent_ = overworld_.overworld_map(current_map_)->parent();
}
if (overworld_.overworld_map(current_map_)->is_large_map() ||
overworld_.overworld_map(current_map_)->large_index() != 0) {
@@ -613,6 +615,11 @@ absl::Status OverworldEditor::CheckForCurrentMap() {
maps_bmp_[current_map_].set_modified(false);
}
// If double clicked, toggle the current map
if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Right)) {
current_map_lock_ = !current_map_lock_;
}
return absl::OkStatus();
}

View File

@@ -31,7 +31,8 @@ constexpr ImVec2 kBlocksetCanvasSize(0x100 + 1, 0x4000 + 1);
constexpr ImVec2 kGraphicsBinCanvasSize(0x100 + 1, kNumSheetsToLoad * 0x40 + 1);
constexpr ImGuiTableFlags kOWMapFlags =
ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable;
ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable |
ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingStretchProp;
constexpr ImGuiTableFlags kToolsetTableFlags = ImGuiTableFlags_SizingFixedFit;
constexpr ImGuiTableFlags kOWEditFlags =
ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable |
@@ -75,6 +76,7 @@ class OverworldEditor : public Editor, public gfx::GfxContext {
public:
explicit OverworldEditor(Rom* rom) : rom_(rom) {
type_ = EditorType::kOverworld;
gfx_group_editor_.set_rom(rom);
}
void Initialize() override;
@@ -212,12 +214,13 @@ class OverworldEditor : public Editor, public gfx::GfxContext {
bool overworld_canvas_fullscreen_ = false;
bool middle_mouse_dragging_ = false;
bool is_dragging_entity_ = false;
bool current_map_lock_ = false;
gfx::Tilemap tile16_blockset_;
Rom* rom_;
Tile16Editor tile16_editor_{&tile16_blockset_};
Tile16Editor tile16_editor_{rom_, &tile16_blockset_};
GfxGroupEditor gfx_group_editor_;
PaletteEditor palette_editor_;

View File

@@ -245,7 +245,7 @@ absl::Status Tile16Editor::DrawToCurrentTile16(ImVec2 click_position) {
}
absl::Status Tile16Editor::UpdateTile16Edit() {
auto ow_main_pal_group = rom()->palette_group().overworld_main;
static const auto ow_main_pal_group = rom()->palette_group().overworld_main;
// Create a more organized layout with tabs
if (BeginTabBar("Tile16EditorTabs")) {

View File

@@ -22,9 +22,10 @@ namespace editor {
/**
* @brief Popup window to edit Tile16 data
*/
class Tile16Editor : public gfx::GfxContext, public SharedRom {
class Tile16Editor : public gfx::GfxContext {
public:
Tile16Editor(gfx::Tilemap *tile16_blockset) : tile16_blockset_(tile16_blockset) {}
Tile16Editor(Rom *rom, gfx::Tilemap *tile16_blockset)
: rom_(rom), tile16_blockset_(tile16_blockset) {}
absl::Status Initialize(const gfx::Bitmap &tile16_blockset_bmp,
const gfx::Bitmap &current_gfx_bmp,
std::array<uint8_t, 0x200> &all_tiles_types);
@@ -52,7 +53,11 @@ class Tile16Editor : public gfx::GfxContext, public SharedRom {
absl::Status LoadTile16FromScratchSpace(int slot);
absl::Status ClearScratchSpace(int slot);
void set_rom(Rom *rom) { rom_ = rom; }
Rom *rom() const { return rom_; }
private:
Rom *rom_ = nullptr;
bool map_blockset_loaded_ = false;
bool transfer_started_ = false;
bool transfer_blockset_loaded_ = false;

View File

@@ -4,7 +4,7 @@
#include <vector>
#include "app/core/platform/file_dialog.h"
#include "app/core/platform/renderer.h"
#include "app/core/window.h"
#include "app/emu/cpu/internal/opcodes.h"
#include "app/gui/icons.h"
#include "app/gui/input.h"

View File

@@ -250,7 +250,7 @@ struct BackgroundLayer {
bool enabled; // Whether the background layer is enabled
};
class Ppu : public SharedRom {
class Ppu {
public:
// Initializes the PPU with the necessary resources and dependencies
Ppu(Memory& memory) : memory_(memory) {}

View File

@@ -2,7 +2,7 @@
#include <vector>
#include "app/core/platform/renderer.h"
#include "app/core/window.h"
#include "app/gfx/bitmap.h"
#include "app/gfx/snes_tile.h"

View File

@@ -6,14 +6,11 @@
#include "app/core/window.h"
#include "app/gfx/bitmap.h"
#include "app/gui/color.h"
#include "app/gui/input.h"
#include "app/gui/style.h"
#include "app/rom.h"
#include "imgui/imgui.h"
#include "imgui_memory_editor.h"
namespace yaze {
namespace gui {
namespace yaze::gui {
using core::Renderer;
@@ -43,8 +40,8 @@ constexpr ImGuiButtonFlags kMouseFlags =
namespace {
ImVec2 AlignPosToGrid(ImVec2 pos, float scale) {
return ImVec2(std::floor((double)pos.x / scale) * scale,
std::floor((double)pos.y / scale) * scale);
return ImVec2(std::floor(pos.x / scale) * scale,
std::floor(pos.y / scale) * scale);
}
} // namespace
@@ -62,15 +59,14 @@ void Canvas::UpdateColorPainter(gfx::Bitmap &bitmap, const ImVec4 &color,
DrawOverlay();
}
void Canvas::UpdateInfoGrid(ImVec2 bg_size, int tile_size, float scale,
float grid_size, int label_id) {
void Canvas::UpdateInfoGrid(ImVec2 bg_size, float grid_size, int label_id) {
enable_custom_labels_ = true;
DrawBackground(bg_size);
DrawInfoGrid(grid_size, 8, label_id);
DrawOverlay();
}
void Canvas::DrawBackground(ImVec2 canvas_size, bool can_drag) {
void Canvas::DrawBackground(ImVec2 canvas_size) {
draw_list_ = GetWindowDrawList();
canvas_p0_ = GetCursorScreenPos();
if (!custom_canvas_size_) canvas_sz_ = GetContentRegionAvail();
@@ -145,59 +141,59 @@ void Canvas::DrawContextMenu() {
Text("Pitch: %d", bitmap_->surface()->pitch);
Text("BitsPerPixel: %d", bitmap_->surface()->format->BitsPerPixel);
Text("BytesPerPixel: %d", bitmap_->surface()->format->BytesPerPixel);
EndMenu();
}
if (BeginMenu("Bitmap Format")) {
if (MenuItem("Indexed")) {
bitmap_->Reformat(gfx::BitmapFormat::kIndexed);
Renderer::Get().UpdateBitmap(bitmap_);
}
if (MenuItem("4BPP")) {
bitmap_->Reformat(gfx::BitmapFormat::k4bpp);
Renderer::Get().UpdateBitmap(bitmap_);
}
if (MenuItem("8BPP")) {
bitmap_->Reformat(gfx::BitmapFormat::k8bpp);
Renderer::Get().UpdateBitmap(bitmap_);
}
EndMenu();
}
if (BeginMenu("View Palette")) {
DisplayEditablePalette(*bitmap_->mutable_palette(), "Palette", true, 8);
EndMenu();
}
if (BeginMenu("Bitmap Palette")) {
if (rom()->is_loaded()) {
gui::TextWithSeparators("ROM Palette");
ImGui::SetNextItemWidth(100.f);
ImGui::Combo("Palette Group", (int *)&edit_palette_group_name_index_,
gfx::kPaletteGroupAddressesKeys,
IM_ARRAYSIZE(gfx::kPaletteGroupAddressesKeys));
ImGui::SetNextItemWidth(100.f);
gui::InputHexWord("Palette Group Index", &edit_palette_index_);
auto palette_group = rom()->mutable_palette_group()->get_group(
gfx::kPaletteGroupAddressesKeys[edit_palette_group_name_index_]);
auto palette = palette_group->mutable_palette(edit_palette_index_);
if (ImGui::BeginChild("Palette", ImVec2(0, 300), true)) {
gui::SelectablePalettePipeline(edit_palette_sub_index_,
refresh_graphics_, *palette);
if (refresh_graphics_) {
bitmap_->SetPaletteWithTransparent(*palette,
edit_palette_sub_index_);
Renderer::Get().UpdateBitmap(bitmap_);
refresh_graphics_ = false;
}
ImGui::EndChild();
MenuItem("Data", nullptr, &show_bitmap_data);
if (BeginMenu("Format")) {
if (MenuItem("Indexed")) {
bitmap_->Reformat(gfx::BitmapFormat::kIndexed);
Renderer::Get().UpdateBitmap(bitmap_);
}
if (MenuItem("4BPP")) {
bitmap_->Reformat(gfx::BitmapFormat::k4bpp);
Renderer::Get().UpdateBitmap(bitmap_);
}
if (MenuItem("8BPP")) {
bitmap_->Reformat(gfx::BitmapFormat::k8bpp);
Renderer::Get().UpdateBitmap(bitmap_);
}
EndMenu();
}
if (BeginMenu("Change Palette")) {
Text("Work in progress");
// TODO: Get ROM data for change palette
// gui::TextWithSeparators("ROM Palette");
// ImGui::SetNextItemWidth(100.f);
// ImGui::Combo("Palette Group", (int *)&edit_palette_group_name_index_,
// gfx::kPaletteGroupAddressesKeys,
// IM_ARRAYSIZE(gfx::kPaletteGroupAddressesKeys));
// ImGui::SetNextItemWidth(100.f);
// gui::InputHexWord("Palette Group Index", &edit_palette_index_);
// auto palette_group = rom()->mutable_palette_group()->get_group(
// gfx::kPaletteGroupAddressesKeys[edit_palette_group_name_index_]);
// auto palette = palette_group->mutable_palette(edit_palette_index_);
// if (ImGui::BeginChild("Palette", ImVec2(0, 300), true)) {
// gui::SelectablePalettePipeline(edit_palette_sub_index_,
// refresh_graphics_, *palette);
// if (refresh_graphics_) {
// bitmap_->SetPaletteWithTransparent(*palette,
// edit_palette_sub_index_);
// Renderer::Get().UpdateBitmap(bitmap_);
// refresh_graphics_ = false;
// }
// ImGui::EndChild();
// }
EndMenu();
}
if (BeginMenu("View Palette")) {
DisplayEditablePalette(*bitmap_->mutable_palette(), "Palette", true,
8);
EndMenu();
}
EndMenu();
}
MenuItem("Bitmap Data", nullptr, &show_bitmap_data);
}
ImGui::Separator();
if (BeginMenu("Grid Tile Size")) {
@@ -255,12 +251,8 @@ bool Canvas::DrawTilePainter(const Bitmap &bitmap, int size, float scale) {
origin.y + paint_pos.y + scaled_size));
}
if (IsMouseClicked(ImGuiMouseButton_Left)) {
// Draw the currently selected tile on the overworld here
// Save the coordinates of the selected tile.
drawn_tile_pos_ = paint_pos;
return true;
} else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) {
if (IsMouseClicked(ImGuiMouseButton_Left) &&
ImGui::IsMouseDragging(ImGuiMouseButton_Left)) {
// Draw the currently selected tile on the overworld here
// Save the coordinates of the selected tile.
drawn_tile_pos_ = paint_pos;
@@ -308,10 +300,8 @@ bool Canvas::DrawTilemapPainter(gfx::Tilemap &tilemap, int current_tile) {
ImVec2(origin.x + paint_pos.x + scaled_size,
origin.y + paint_pos.y + scaled_size));
if (IsMouseClicked(ImGuiMouseButton_Left)) {
drawn_tile_pos_ = paint_pos;
return true;
} else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) {
if (IsMouseClicked(ImGuiMouseButton_Left) ||
ImGui::IsMouseDragging(ImGuiMouseButton_Left)) {
drawn_tile_pos_ = paint_pos;
return true;
}
@@ -407,9 +397,7 @@ bool Canvas::DrawTileSelector(int size, int size_y) {
if (!points_.empty()) {
points_.clear();
}
ImVec2 painter_pos;
painter_pos.x = std::floor((double)mouse_pos.x / size) * size;
painter_pos.y = std::floor((double)mouse_pos.y / size) * size;
ImVec2 painter_pos = AlignPosToGrid(mouse_pos, size);
points_.push_back(painter_pos);
points_.push_back(ImVec2(painter_pos.x + size, painter_pos.y + size_y));
@@ -464,50 +452,48 @@ void Canvas::DrawSelectRect(int current_map, int tile_size, float scale) {
dragging = true;
}
if (dragging) {
if (dragging && !ImGui::IsMouseDown(ImGuiMouseButton_Right)) {
// Release dragging mode
if (!ImGui::IsMouseDown(ImGuiMouseButton_Right)) {
dragging = false;
dragging = false;
// Calculate the bounds of the rectangle in terms of 16x16 tile indices
constexpr int tile16_size = 16;
int start_x = std::floor(drag_start_pos.x / scaled_size) * tile16_size;
int start_y = std::floor(drag_start_pos.y / scaled_size) * tile16_size;
int end_x = std::floor(drag_end_pos.x / scaled_size) * tile16_size;
int end_y = std::floor(drag_end_pos.y / scaled_size) * tile16_size;
// Calculate the bounds of the rectangle in terms of 16x16 tile indices
constexpr int tile16_size = 16;
int start_x = std::floor(drag_start_pos.x / scaled_size) * tile16_size;
int start_y = std::floor(drag_start_pos.y / scaled_size) * tile16_size;
int end_x = std::floor(drag_end_pos.x / scaled_size) * tile16_size;
int end_y = std::floor(drag_end_pos.y / scaled_size) * tile16_size;
// Swap the start and end positions if they are in the wrong order
if (start_x > end_x) std::swap(start_x, end_x);
if (start_y > end_y) std::swap(start_y, end_y);
// Swap the start and end positions if they are in the wrong order
if (start_x > end_x) std::swap(start_x, end_x);
if (start_y > end_y) std::swap(start_y, end_y);
selected_tiles_.clear();
// Number of tiles per local map (since each tile is 16x16)
constexpr int tiles_per_local_map = small_map_size / 16;
selected_tiles_.clear();
// Number of tiles per local map (since each tile is 16x16)
constexpr int tiles_per_local_map = small_map_size / 16;
// Loop through the tiles in the rectangle and store their positions
for (int y = start_y; y <= end_y; y += tile16_size) {
for (int x = start_x; x <= end_x; x += tile16_size) {
// Determine which local map (512x512) the tile is in
int local_map_x = x / small_map_size;
int local_map_y = y / small_map_size;
// Loop through the tiles in the rectangle and store their positions
for (int y = start_y; y <= end_y; y += tile16_size) {
for (int x = start_x; x <= end_x; x += tile16_size) {
// Determine which local map (512x512) the tile is in
int local_map_x = x / small_map_size;
int local_map_y = y / small_map_size;
// Calculate the tile's position within its local map
int tile16_x = (x % small_map_size) / tile16_size;
int tile16_y = (y % small_map_size) / tile16_size;
// Calculate the tile's position within its local map
int tile16_x = (x % small_map_size) / tile16_size;
int tile16_y = (y % small_map_size) / tile16_size;
// Calculate the index within the overall map structure
int index_x = local_map_x * tiles_per_local_map + tile16_x;
int index_y = local_map_y * tiles_per_local_map + tile16_y;
// Calculate the index within the overall map structure
int index_x = local_map_x * tiles_per_local_map + tile16_x;
int index_y = local_map_y * tiles_per_local_map + tile16_y;
selected_tiles_.push_back(ImVec2(index_x, index_y));
}
selected_tiles_.push_back(ImVec2(index_x, index_y));
}
// Clear and add the calculated rectangle points
selected_points_.clear();
selected_points_.push_back(drag_start_pos);
selected_points_.push_back(drag_end_pos);
select_rect_active_ = true;
}
// Clear and add the calculated rectangle points
selected_points_.clear();
selected_points_.push_back(drag_start_pos);
selected_points_.push_back(drag_end_pos);
select_rect_active_ = true;
}
}
@@ -709,25 +695,27 @@ void Canvas::DrawInfoGrid(float grid_step, int tile_id_offset, int label_id) {
DrawGridLines(grid_step);
DrawCustomHighlight(grid_step);
if (enable_custom_labels_) {
// Draw the contents of labels on the grid
for (float x = fmodf(scrolling_.x, grid_step);
x < canvas_sz_.x * global_scale_; x += grid_step) {
for (float y = fmodf(scrolling_.y, grid_step);
y < canvas_sz_.y * global_scale_; y += grid_step) {
int tile_x = (x - scrolling_.x) / grid_step;
int tile_y = (y - scrolling_.y) / grid_step;
int tile_id = tile_x + (tile_y * tile_id_offset);
if (!enable_custom_labels_) {
return;
}
if (tile_id >= labels_[label_id].size()) {
break;
}
std::string label = labels_[label_id][tile_id];
draw_list_->AddText(
ImVec2(canvas_p0_.x + x + (grid_step / 2) - tile_id_offset,
canvas_p0_.y + y + (grid_step / 2) - tile_id_offset),
kWhiteColor, label.data());
// Draw the contents of labels on the grid
for (float x = fmodf(scrolling_.x, grid_step);
x < canvas_sz_.x * global_scale_; x += grid_step) {
for (float y = fmodf(scrolling_.y, grid_step);
y < canvas_sz_.y * global_scale_; y += grid_step) {
int tile_x = (x - scrolling_.x) / grid_step;
int tile_y = (y - scrolling_.y) / grid_step;
int tile_id = tile_x + (tile_y * tile_id_offset);
if (tile_id >= labels_[label_id].size()) {
break;
}
std::string label = labels_[label_id][tile_id];
draw_list_->AddText(
ImVec2(canvas_p0_.x + x + (grid_step / 2) - tile_id_offset,
canvas_p0_.y + y + (grid_step / 2) - tile_id_offset),
kWhiteColor, label.data());
}
}
}
@@ -773,25 +761,26 @@ void Canvas::DrawGrid(float grid_step, int tile_id_offset) {
}
}
if (enable_custom_labels_) {
// Draw the contents of labels on the grid
for (float x = fmodf(scrolling_.x, grid_step);
x < canvas_sz_.x * global_scale_; x += grid_step) {
for (float y = fmodf(scrolling_.y, grid_step);
y < canvas_sz_.y * global_scale_; y += grid_step) {
int tile_x = (x - scrolling_.x) / grid_step;
int tile_y = (y - scrolling_.y) / grid_step;
int tile_id = tile_x + (tile_y * tile_id_offset);
if (!enable_custom_labels_) {
return;
}
// Draw the contents of labels on the grid
for (float x = fmodf(scrolling_.x, grid_step);
x < canvas_sz_.x * global_scale_; x += grid_step) {
for (float y = fmodf(scrolling_.y, grid_step);
y < canvas_sz_.y * global_scale_; y += grid_step) {
int tile_x = (x - scrolling_.x) / grid_step;
int tile_y = (y - scrolling_.y) / grid_step;
int tile_id = tile_x + (tile_y * tile_id_offset);
if (tile_id >= labels_[current_labels_].size()) {
break;
}
std::string label = labels_[current_labels_][tile_id];
draw_list_->AddText(
ImVec2(canvas_p0_.x + x + (grid_step / 2) - tile_id_offset,
canvas_p0_.y + y + (grid_step / 2) - tile_id_offset),
kWhiteColor, label.data());
if (tile_id >= labels_[current_labels_].size()) {
break;
}
std::string label = labels_[current_labels_][tile_id];
draw_list_->AddText(
ImVec2(canvas_p0_.x + x + (grid_step / 2) - tile_id_offset,
canvas_p0_.y + y + (grid_step / 2) - tile_id_offset),
kWhiteColor, label.data());
}
}
}
@@ -909,8 +898,8 @@ void GraphicsBinCanvasPipeline(int width, int height, int tile_size,
void BitmapCanvasPipeline(gui::Canvas &canvas, gfx::Bitmap &bitmap, int width,
int height, int tile_size, bool is_loaded,
bool scrollbar, int canvas_id) {
auto draw_canvas = [](gui::Canvas &canvas, gfx::Bitmap &bitmap, int width,
int height, int tile_size, bool is_loaded) {
auto draw_canvas = [&](gui::Canvas &canvas, gfx::Bitmap &bitmap, int width,
int height, int tile_size, bool is_loaded) {
canvas.DrawBackground(ImVec2(width + 1, height + 1));
canvas.DrawContextMenu();
canvas.DrawBitmap(bitmap, 2, is_loaded);
@@ -932,5 +921,4 @@ void BitmapCanvasPipeline(gui::Canvas &canvas, gfx::Bitmap &bitmap, int width,
}
}
} // namespace gui
} // namespace yaze
} // namespace yaze::gui

View File

@@ -34,28 +34,28 @@ enum class CanvasGridSize { k8x8, k16x16, k32x32, k64x64 };
* on a canvas. It supports features such as bitmap drawing, context menu
* handling, tile painting, custom grid, and more.
*/
class Canvas : public SharedRom {
class Canvas {
public:
Canvas() = default;
explicit Canvas(const std::string &id) : canvas_id_(id) {
context_id_ = id + "Context";
}
explicit Canvas(const std::string &id, ImVec2 canvas_size)
: canvas_id_(id), custom_canvas_size_(true), canvas_sz_(canvas_size) {
: custom_canvas_size_(true), canvas_sz_(canvas_size), canvas_id_(id) {
context_id_ = id + "Context";
}
explicit Canvas(const std::string &id, ImVec2 canvas_size,
CanvasGridSize grid_size)
: canvas_id_(id), custom_canvas_size_(true), canvas_sz_(canvas_size) {
: custom_canvas_size_(true), canvas_sz_(canvas_size), canvas_id_(id) {
context_id_ = id + "Context";
SetCanvasGridSize(grid_size);
}
explicit Canvas(const std::string &id, ImVec2 canvas_size,
CanvasGridSize grid_size, float global_scale)
: canvas_id_(id),
custom_canvas_size_(true),
: custom_canvas_size_(true),
global_scale_(global_scale),
canvas_sz_(canvas_size),
global_scale_(global_scale) {
canvas_id_(id) {
context_id_ = id + "Context";
SetCanvasGridSize(grid_size);
}
@@ -81,12 +81,12 @@ class Canvas : public SharedRom {
const std::function<void()> &event, int tile_size,
float scale = 1.0f);
void UpdateInfoGrid(ImVec2 bg_size, int tile_size, float scale = 1.0f,
float grid_size = 64.0f, int label_id = 0);
void UpdateInfoGrid(ImVec2 bg_size, float grid_size = 64.0f,
int label_id = 0);
// Background for the Canvas represents region without any content drawn to
// it, but can be controlled by the user.
void DrawBackground(ImVec2 canvas_size = ImVec2(0, 0), bool drag = false);
void DrawBackground(ImVec2 canvas_size = ImVec2(0, 0));
// Context Menu refers to what happens when the right mouse button is pressed
// This routine also handles the scrolling for the canvas.
@@ -111,8 +111,8 @@ class Canvas : public SharedRom {
// Draws the contents of the Bitmap image to the Canvas
void DrawBitmap(Bitmap &bitmap, int border_offset, float scale);
void DrawBitmap(Bitmap &bitmap, int x_offset, int y_offset, float scale = 1.0f,
int alpha = 255);
void DrawBitmap(Bitmap &bitmap, int x_offset, int y_offset,
float scale = 1.0f, int alpha = 255);
void DrawBitmap(Bitmap &bitmap, ImVec2 dest_pos, ImVec2 dest_size,
ImVec2 src_pos, ImVec2 src_size);
void DrawBitmapTable(const BitmapTable &gfx_bin);
@@ -206,6 +206,9 @@ class Canvas : public SharedRom {
auto hover_mouse_pos() const { return mouse_pos_in_canvas_; }
void set_rom(Rom *rom) { rom_ = rom; }
Rom *rom() const { return rom_; }
private:
bool draggable_ = false;
bool is_hovered_ = false;
@@ -228,6 +231,7 @@ class Canvas : public SharedRom {
uint64_t edit_palette_sub_index_ = 0;
Bitmap *bitmap_ = nullptr;
Rom *rom_ = nullptr;
ImDrawList *draw_list_ = nullptr;

View File

@@ -649,6 +649,4 @@ absl::Status Rom::WriteColor(uint32_t address, const gfx::SnesColor &color) {
return WriteShort(address, bgr);
}
std::shared_ptr<Rom> SharedRom::shared_rom_ = nullptr;
} // namespace yaze

View File

@@ -272,40 +272,6 @@ absl::StatusOr<std::array<gfx::Bitmap, kNumLinkSheets>> LoadLinkGraphics(
absl::StatusOr<gfx::Bitmap> LoadFontGraphics(const Rom& rom);
/**
* @brief A class to hold a shared pointer to a Rom object.
*/
class SharedRom {
public:
SharedRom() = default;
virtual ~SharedRom() = default;
std::shared_ptr<Rom> shared_rom() {
if (!shared_rom_) {
shared_rom_ = std::make_shared<Rom>();
}
return shared_rom_;
}
auto rom() {
if (!shared_rom_) {
shared_rom_ = std::make_shared<Rom>();
}
Rom* rom = shared_rom_.get();
return rom;
}
static void set_rom(Rom* rom) {
if (!shared_rom_) {
shared_rom_ = std::make_shared<Rom>();
}
shared_rom_ = std::shared_ptr<Rom>(rom);
}
// private:
static std::shared_ptr<Rom> shared_rom_;
};
} // namespace yaze
#endif

View File

@@ -77,14 +77,6 @@
// Enable native IME.
SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");
if (!_controller->CreateWindow().ok()) {
printf("Error creating window: %s\n", SDL_GetError());
abort();
}
if (!_controller->CreateRenderer().ok()) {
printf("Error creating renderer: %s\n", SDL_GetError());
abort();
}
ImGui_ImplSDL2_InitForSDLRenderer(_controller->window(),
yaze::core::Renderer::Get().renderer());
@@ -93,7 +85,6 @@
if (!LoadPackageFonts().ok()) {
abort();
}
_controller->Initialize("");
_controller->set_active(true);
_hoverGestureRecognizer =
@@ -357,9 +348,10 @@
rom_data.resize(size);
std::copy(bytes, bytes + size, rom_data.begin());
PRINT_IF_ERROR(yaze::SharedRom::shared_rom_->LoadFromData(rom_data));
// TODO: Re-implmenent this without the SharedRom singleton
// PRINT_IF_ERROR(yaze::SharedRom::shared_rom_->LoadFromData(rom_data));
std::string filename = std::string([selectedFileURL.path UTF8String]);
yaze::SharedRom::shared_rom_->set_filename(filename);
// yaze::SharedRom::shared_rom_->set_filename(filename);
[selectedFileURL stopAccessingSecurityScopedResource];
} else {