refactor: Introduce OverworldEntityRenderer for Enhanced Entity Visualization

- Added OverworldEntityRenderer class to separate entity rendering logic from OverworldEditor, improving maintainability and testability.
- Updated OverworldEditor to utilize the new entity renderer, removing legacy drawing functions for entrances, exits, items, and sprites.
- Enhanced initialization and drawing methods to streamline entity visualization and interaction within the editor.
- Updated CMake configuration to include the new renderer files, ensuring proper integration into the build system.
This commit is contained in:
scawful
2025-10-05 18:20:12 -04:00
parent a86f3708df
commit 9835eb2ab1
5 changed files with 377 additions and 241 deletions

View File

@@ -35,6 +35,7 @@ set(
app/editor/overworld/map_properties.cc
app/editor/graphics/gfx_group_editor.cc
app/editor/overworld/entity.cc
app/editor/overworld/overworld_entity_renderer.cc
app/editor/system/settings_editor.cc
app/editor/system/command_manager.cc
app/editor/system/extension_manager.cc

View File

@@ -16,7 +16,6 @@
#include "app/core/asar_wrapper.h"
#include "app/core/features.h"
#include "app/core/window.h"
#include "app/editor/overworld/entity.h"
#include "app/editor/overworld/map_properties.h"
#include "app/editor/overworld/tile16_editor.h"
#include "app/gfx/arena.h"
@@ -62,6 +61,10 @@ void OverworldEditor::Initialize() {
overworld_manager_ =
std::make_unique<OverworldEditorManager>(&overworld_, rom_, this);
// Initialize OverworldEntityRenderer for entity visualization
entity_renderer_ = std::make_unique<OverworldEntityRenderer>(
&overworld_, &ow_map_canvas_, &sprite_previews_);
// Setup overworld canvas context menu
SetupOverworldCanvasContextMenu();
@@ -1100,10 +1103,24 @@ void OverworldEditor::DrawOverworldCanvas() {
if (overworld_.is_loaded()) {
DrawOverworldMaps();
DrawOverworldExits(ow_map_canvas_.zero_point(), ow_map_canvas_.scrolling());
DrawOverworldEntrances(ow_map_canvas_.zero_point(), ow_map_canvas_.scrolling());
DrawOverworldItems();
DrawOverworldSprites();
// Update entity renderer state
entity_renderer_->set_current_map(current_map_);
// Draw all entities using the entity renderer
int mode_int = static_cast<int>(current_mode);
entity_renderer_->DrawExits(ow_map_canvas_.zero_point(), ow_map_canvas_.scrolling(),
current_world_, mode_int);
entity_renderer_->DrawEntrances(ow_map_canvas_.zero_point(), ow_map_canvas_.scrolling(),
current_world_, mode_int);
entity_renderer_->DrawItems(current_world_, mode_int);
entity_renderer_->DrawSprites(current_world_, game_state_, mode_int);
// Check if entity renderer wants to jump to a tab (e.g., double-clicked entrance/exit)
if (entity_renderer_->jump_to_tab() != -1) {
jump_to_tab_ = entity_renderer_->jump_to_tab();
entity_renderer_->reset_jump_to_tab();
}
// Draw overlay preview if enabled
if (show_overlay_preview_) {
@@ -1243,237 +1260,8 @@ absl::Status OverworldEditor::DrawAreaGraphics() {
}
// DrawTileSelector() removed - replaced by individual card system in Update()
void OverworldEditor::DrawOverworldEntrances(ImVec2 canvas_p0, ImVec2 scrolling) {
int i = 0;
for (auto& each : overworld_.entrances()) {
if (each.map_id_ < 0x40 + (current_world_ * 0x40) &&
each.map_id_ >= (current_world_ * 0x40) && !each.deleted) {
// Use theme-aware color with proper transparency
ImVec4 entrance_color = gui::GetEntranceColor();
if (each.is_hole_) {
// Holes are more opaque for visibility
entrance_color.w = 0.78f; // 200/255 alpha
}
ow_map_canvas_.DrawRect(each.x_, each.y_, 16, 16, entrance_color);
std::string str = util::HexByte(each.entrance_id_);
if (current_mode == EditingMode::ENTRANCES) {
HandleEntityDragging(&each, canvas_p0, scrolling, is_dragging_entity_,
dragged_entity_, current_entity_);
if (IsMouseHoveringOverEntity(each, canvas_p0, scrolling) &&
ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
jump_to_tab_ = each.entrance_id_;
}
if (IsMouseHoveringOverEntity(each, canvas_p0, scrolling) &&
ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
current_entrance_id_ = i;
current_entrance_ = each;
}
}
ow_map_canvas_.DrawText(str, each.x_, each.y_);
}
i++;
}
if (DrawEntranceInserterPopup()) {
// Get the deleted entrance ID and insert it at the mouse position
auto deleted_entrance_id = overworld_.deleted_entrances().back();
overworld_.deleted_entrances().pop_back();
auto& entrance = overworld_.entrances()[deleted_entrance_id];
entrance.map_id_ = current_map_;
entrance.entrance_id_ = deleted_entrance_id;
entrance.x_ = ow_map_canvas_.hover_mouse_pos().x;
entrance.y_ = ow_map_canvas_.hover_mouse_pos().y;
entrance.deleted = false;
}
if (current_mode == EditingMode::ENTRANCES) {
const auto is_hovering =
IsMouseHoveringOverEntity(current_entrance_, canvas_p0, scrolling);
if (!is_hovering && ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
ImGui::OpenPopup("Entrance Inserter");
} else {
if (DrawOverworldEntrancePopup(
overworld_.entrances()[current_entrance_id_])) {
overworld_.entrances()[current_entrance_id_] = current_entrance_;
}
if (overworld_.entrances()[current_entrance_id_].deleted) {
overworld_.mutable_deleted_entrances()->emplace_back(
current_entrance_id_);
}
}
}
}
void OverworldEditor::DrawOverworldExits(ImVec2 canvas_p0, ImVec2 scrolling) {
int i = 0;
for (auto& each : *overworld_.mutable_exits()) {
if (each.map_id_ < 0x40 + (current_world_ * 0x40) &&
each.map_id_ >= (current_world_ * 0x40) && !each.deleted_) {
ow_map_canvas_.DrawRect(each.x_, each.y_, 16, 16,
gui::GetExitColor());
if (current_mode == EditingMode::EXITS) {
each.entity_id_ = i;
HandleEntityDragging(&each, ow_map_canvas_.zero_point(),
ow_map_canvas_.scrolling(), is_dragging_entity_,
dragged_entity_, current_entity_, true);
if (IsMouseHoveringOverEntity(each, canvas_p0, scrolling) &&
ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
jump_to_tab_ = each.room_id_;
}
if (IsMouseHoveringOverEntity(each, canvas_p0, scrolling) &&
ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
current_exit_id_ = i;
current_exit_ = each;
current_entity_ = &each;
current_entity_->entity_id_ = i;
ImGui::OpenPopup("Exit editor");
}
}
std::string str = util::HexByte(i);
ow_map_canvas_.DrawText(str, each.x_, each.y_);
}
i++;
}
DrawExitInserterPopup();
if (current_mode == EditingMode::EXITS) {
const auto hovering = IsMouseHoveringOverEntity(
overworld_.mutable_exits()->at(current_exit_id_),
ow_map_canvas_.zero_point(), ow_map_canvas_.scrolling());
if (!hovering && ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
ImGui::OpenPopup("Exit Inserter");
} else {
if (DrawExitEditorPopup(
overworld_.mutable_exits()->at(current_exit_id_))) {
overworld_.mutable_exits()->at(current_exit_id_) = current_exit_;
}
}
}
}
void OverworldEditor::DrawOverworldItems() {
int i = 0;
for (auto& item : *overworld_.mutable_all_items()) {
// Get the item's bitmap and real X and Y positions
if (item.room_map_id_ < 0x40 + (current_world_ * 0x40) &&
item.room_map_id_ >= (current_world_ * 0x40) && !item.deleted) {
ow_map_canvas_.DrawRect(item.x_, item.y_, 16, 16, gui::GetItemColor());
if (current_mode == EditingMode::ITEMS) {
// Check if this item is being clicked and dragged
HandleEntityDragging(&item, ow_map_canvas_.zero_point(),
ow_map_canvas_.scrolling(), is_dragging_entity_,
dragged_entity_, current_entity_);
const auto hovering = IsMouseHoveringOverEntity(
item, ow_map_canvas_.zero_point(), ow_map_canvas_.scrolling());
if (hovering && ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
current_item_id_ = i;
current_item_ = item;
current_entity_ = &item;
}
}
std::string item_name = "";
if (item.id_ < zelda3::kSecretItemNames.size()) {
item_name = zelda3::kSecretItemNames[item.id_];
} else {
item_name = absl::StrFormat("0x%02X", item.id_);
}
ow_map_canvas_.DrawText(item_name, item.x_, item.y_);
}
i++;
}
DrawItemInsertPopup();
if (current_mode == EditingMode::ITEMS) {
const auto hovering = IsMouseHoveringOverEntity(
overworld_.mutable_all_items()->at(current_item_id_),
ow_map_canvas_.zero_point(), ow_map_canvas_.scrolling());
if (!hovering && ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
ImGui::OpenPopup("Item Inserter");
} else {
if (DrawItemEditorPopup(
overworld_.mutable_all_items()->at(current_item_id_))) {
overworld_.mutable_all_items()->at(current_item_id_) = current_item_;
}
}
}
}
void OverworldEditor::DrawOverworldSprites() {
int i = 0;
for (auto& sprite : *overworld_.mutable_sprites(game_state_)) {
// Filter sprites by current world - only show sprites for the current world
if (!sprite.deleted() && sprite.map_id() < 0x40 + (current_world_ * 0x40) &&
sprite.map_id() >= (current_world_ * 0x40)) {
// Sprites are already stored with global coordinates (realX, realY from
// ROM loading) So we can use sprite.x_ and sprite.y_ directly
int sprite_x = sprite.x_;
int sprite_y = sprite.y_;
// Temporarily update sprite coordinates for entity interaction
int original_x = sprite.x_;
int original_y = sprite.y_;
ow_map_canvas_.DrawRect(sprite_x, sprite_y, kTile16Size, kTile16Size,
gui::GetSpriteColor());
if (current_mode == EditingMode::SPRITES) {
HandleEntityDragging(&sprite, ow_map_canvas_.zero_point(),
ow_map_canvas_.scrolling(), is_dragging_entity_,
dragged_entity_, current_entity_);
if (IsMouseHoveringOverEntity(sprite, ow_map_canvas_.zero_point(),
ow_map_canvas_.scrolling()) &&
ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
current_sprite_id_ = i;
current_sprite_ = sprite;
}
}
if (core::FeatureFlags::get().overworld.kDrawOverworldSprites) {
if (sprite_previews_[sprite.id()].is_active()) {
ow_map_canvas_.DrawBitmap(sprite_previews_[sprite.id()], sprite_x,
sprite_y, 2.0f);
}
}
ow_map_canvas_.DrawText(absl::StrFormat("%s", sprite.name()), sprite_x,
sprite_y);
// Restore original coordinates
sprite.x_ = original_x;
sprite.y_ = original_y;
}
i++;
}
DrawSpriteInserterPopup();
if (current_mode == EditingMode::SPRITES) {
const auto hovering = IsMouseHoveringOverEntity(
overworld_.mutable_sprites(game_state_)->at(current_sprite_id_),
ow_map_canvas_.zero_point(), ow_map_canvas_.scrolling());
if (!hovering && ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
ImGui::OpenPopup("Sprite Inserter");
} else {
if (DrawSpriteEditorPopup(overworld_.mutable_sprites(game_state_)
->at(current_sprite_id_))) {
overworld_.mutable_sprites(game_state_)->at(current_sprite_id_) =
current_sprite_;
}
}
}
}
// DrawOverworldEntrances(), DrawOverworldExits(), DrawOverworldItems(), DrawOverworldSprites()
// removed - moved to OverworldEntityRenderer
absl::Status OverworldEditor::Save() {
if (core::FeatureFlags::get().overworld.kSaveOverworldMaps) {

View File

@@ -7,6 +7,7 @@
#include "app/editor/graphics/palette_editor.h"
#include "app/editor/overworld/tile16_editor.h"
#include "app/editor/overworld/map_properties.h"
#include "app/editor/overworld/overworld_entity_renderer.h"
#include "app/gfx/bitmap.h"
#include "app/gfx/snes_palette.h"
#include "app/gfx/tilemap.h"
@@ -123,11 +124,6 @@ class OverworldEditor : public Editor, public gfx::GfxContext {
void RefreshMapProperties();
absl::Status RefreshTile16Blockset();
void DrawOverworldEntrances(ImVec2 canvas_p, ImVec2 scrolling);
void DrawOverworldExits(ImVec2 zero, ImVec2 scrolling);
void DrawOverworldItems();
void DrawOverworldSprites();
void DrawOverworldMaps();
void DrawOverworldEdits();
void RenderUpdatedMapBitmap(const ImVec2& click_position,
@@ -276,6 +272,7 @@ class OverworldEditor : public Editor, public gfx::GfxContext {
// Map properties system for UI organization
std::unique_ptr<MapPropertiesSystem> map_properties_system_;
std::unique_ptr<OverworldEditorManager> overworld_manager_;
std::unique_ptr<OverworldEntityRenderer> entity_renderer_;
// Scratch space for large layouts
// Scratch space canvas for tile16 drawing (like a mini overworld)

View File

@@ -0,0 +1,260 @@
#include "overworld_entity_renderer.h"
#include "absl/strings/str_format.h"
#include "app/core/features.h"
#include "app/editor/overworld/entity.h"
#include "app/gui/canvas.h"
#include "app/zelda3/common.h"
#include "util/hex.h"
#include "imgui/imgui.h"
namespace yaze {
namespace editor {
using namespace ImGui;
// Entity colors - these could be theme-dependent in the future
namespace {
ImVec4 GetEntranceColor() { return ImVec4(0.0f, 1.0f, 0.0f, 0.5f); } // Green
ImVec4 GetExitColor() { return ImVec4(1.0f, 0.0f, 0.0f, 0.5f); } // Red
ImVec4 GetItemColor() { return ImVec4(1.0f, 1.0f, 0.0f, 0.5f); } // Yellow
ImVec4 GetSpriteColor() { return ImVec4(1.0f, 0.5f, 0.0f, 0.5f); } // Orange
} // namespace
void OverworldEntityRenderer::DrawEntrances(ImVec2 canvas_p0, ImVec2 scrolling,
int current_world,
int current_mode) {
int i = 0;
for (auto& each : overworld_->entrances()) {
if (each.map_id_ < 0x40 + (current_world * 0x40) &&
each.map_id_ >= (current_world * 0x40) && !each.deleted) {
// Use theme-aware color with proper transparency
ImVec4 entrance_color = GetEntranceColor();
if (each.is_hole_) {
// Holes are more opaque for visibility
entrance_color.w = 0.78f; // 200/255 alpha
}
canvas_->DrawRect(each.x_, each.y_, 16, 16, entrance_color);
std::string str = util::HexByte(each.entrance_id_);
if (current_mode == 1) { // EditingMode::ENTRANCES
HandleEntityDragging(&each, canvas_p0, scrolling, is_dragging_entity_,
dragged_entity_, current_entity_);
if (IsMouseHoveringOverEntity(each, canvas_p0, scrolling) &&
ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
jump_to_tab_ = each.entrance_id_;
}
if (IsMouseHoveringOverEntity(each, canvas_p0, scrolling) &&
ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
current_entrance_id_ = i;
current_entrance_ = each;
}
}
canvas_->DrawText(str, each.x_, each.y_);
}
i++;
}
if (DrawEntranceInserterPopup()) {
// Get the deleted entrance ID and insert it at the mouse position
auto deleted_entrance_id = overworld_->deleted_entrances().back();
overworld_->deleted_entrances().pop_back();
auto& entrance = overworld_->entrances()[deleted_entrance_id];
entrance.map_id_ = current_map_;
entrance.entrance_id_ = deleted_entrance_id;
entrance.x_ = canvas_->hover_mouse_pos().x;
entrance.y_ = canvas_->hover_mouse_pos().y;
entrance.deleted = false;
}
if (current_mode == 1) { // EditingMode::ENTRANCES
const auto is_hovering =
IsMouseHoveringOverEntity(current_entrance_, canvas_p0, scrolling);
if (!is_hovering && ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
ImGui::OpenPopup("Entrance Inserter");
} else {
if (DrawOverworldEntrancePopup(
overworld_->entrances()[current_entrance_id_])) {
overworld_->entrances()[current_entrance_id_] = current_entrance_;
}
if (overworld_->entrances()[current_entrance_id_].deleted) {
overworld_->mutable_deleted_entrances()->emplace_back(
current_entrance_id_);
}
}
}
}
void OverworldEntityRenderer::DrawExits(ImVec2 canvas_p0, ImVec2 scrolling,
int current_world,
int current_mode) {
int i = 0;
for (auto& each : *overworld_->mutable_exits()) {
if (each.map_id_ < 0x40 + (current_world * 0x40) &&
each.map_id_ >= (current_world * 0x40) && !each.deleted_) {
canvas_->DrawRect(each.x_, each.y_, 16, 16, GetExitColor());
if (current_mode == 2) { // EditingMode::EXITS
each.entity_id_ = i;
HandleEntityDragging(&each, canvas_->zero_point(),
canvas_->scrolling(), is_dragging_entity_,
dragged_entity_, current_entity_, true);
if (IsMouseHoveringOverEntity(each, canvas_p0, scrolling) &&
ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
jump_to_tab_ = each.room_id_;
}
if (IsMouseHoveringOverEntity(each, canvas_p0, scrolling) &&
ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
current_exit_id_ = i;
current_exit_ = each;
current_entity_ = &each;
current_entity_->entity_id_ = i;
ImGui::OpenPopup("Exit editor");
}
}
std::string str = util::HexByte(i);
canvas_->DrawText(str, each.x_, each.y_);
}
i++;
}
DrawExitInserterPopup();
if (current_mode == 2) { // EditingMode::EXITS
const auto hovering = IsMouseHoveringOverEntity(
overworld_->mutable_exits()->at(current_exit_id_),
canvas_->zero_point(), canvas_->scrolling());
if (!hovering && ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
ImGui::OpenPopup("Exit Inserter");
} else {
if (DrawExitEditorPopup(
overworld_->mutable_exits()->at(current_exit_id_))) {
overworld_->mutable_exits()->at(current_exit_id_) = current_exit_;
}
}
}
}
void OverworldEntityRenderer::DrawItems(int current_world, int current_mode) {
int i = 0;
for (auto& item : *overworld_->mutable_all_items()) {
// Get the item's bitmap and real X and Y positions
if (item.room_map_id_ < 0x40 + (current_world * 0x40) &&
item.room_map_id_ >= (current_world * 0x40) && !item.deleted) {
canvas_->DrawRect(item.x_, item.y_, 16, 16, GetItemColor());
if (current_mode == 3) { // EditingMode::ITEMS
// Check if this item is being clicked and dragged
HandleEntityDragging(&item, canvas_->zero_point(),
canvas_->scrolling(), is_dragging_entity_,
dragged_entity_, current_entity_);
const auto hovering = IsMouseHoveringOverEntity(
item, canvas_->zero_point(), canvas_->scrolling());
if (hovering && ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
current_item_id_ = i;
current_item_ = item;
current_entity_ = &item;
}
}
std::string item_name = "";
if (item.id_ < zelda3::kSecretItemNames.size()) {
item_name = zelda3::kSecretItemNames[item.id_];
} else {
item_name = absl::StrFormat("0x%02X", item.id_);
}
canvas_->DrawText(item_name, item.x_, item.y_);
}
i++;
}
DrawItemInsertPopup();
if (current_mode == 3) { // EditingMode::ITEMS
const auto hovering = IsMouseHoveringOverEntity(
overworld_->mutable_all_items()->at(current_item_id_),
canvas_->zero_point(), canvas_->scrolling());
if (!hovering && ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
ImGui::OpenPopup("Item Inserter");
} else {
if (DrawItemEditorPopup(
overworld_->mutable_all_items()->at(current_item_id_))) {
overworld_->mutable_all_items()->at(current_item_id_) = current_item_;
}
}
}
}
void OverworldEntityRenderer::DrawSprites(int current_world, int game_state,
int current_mode) {
int i = 0;
for (auto& sprite : *overworld_->mutable_sprites(game_state)) {
// Filter sprites by current world - only show sprites for the current world
if (!sprite.deleted() && sprite.map_id() < 0x40 + (current_world * 0x40) &&
sprite.map_id() >= (current_world * 0x40)) {
// Sprites are already stored with global coordinates (realX, realY from
// ROM loading) So we can use sprite.x_ and sprite.y_ directly
int sprite_x = sprite.x_;
int sprite_y = sprite.y_;
// Temporarily update sprite coordinates for entity interaction
int original_x = sprite.x_;
int original_y = sprite.y_;
canvas_->DrawRect(sprite_x, sprite_y, 16, 16, GetSpriteColor());
if (current_mode == 4) { // EditingMode::SPRITES
HandleEntityDragging(&sprite, canvas_->zero_point(),
canvas_->scrolling(), is_dragging_entity_,
dragged_entity_, current_entity_);
if (IsMouseHoveringOverEntity(sprite, canvas_->zero_point(),
canvas_->scrolling()) &&
ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
current_sprite_id_ = i;
current_sprite_ = sprite;
}
}
if (core::FeatureFlags::get().overworld.kDrawOverworldSprites) {
if ((*sprite_previews_)[sprite.id()].is_active()) {
canvas_->DrawBitmap((*sprite_previews_)[sprite.id()], sprite_x,
sprite_y, 2.0f);
}
}
canvas_->DrawText(absl::StrFormat("%s", sprite.name()), sprite_x,
sprite_y);
// Restore original coordinates
sprite.x_ = original_x;
sprite.y_ = original_y;
}
i++;
}
DrawSpriteInserterPopup();
if (current_mode == 4) { // EditingMode::SPRITES
const auto hovering = IsMouseHoveringOverEntity(
overworld_->mutable_sprites(game_state)->at(current_sprite_id_),
canvas_->zero_point(), canvas_->scrolling());
if (!hovering && ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
ImGui::OpenPopup("Sprite Inserter");
} else {
if (DrawSpriteEditorPopup(overworld_->mutable_sprites(game_state)
->at(current_sprite_id_))) {
overworld_->mutable_sprites(game_state)->at(current_sprite_id_) =
current_sprite_;
}
}
}
}
} // namespace editor
} // namespace yaze

View File

@@ -0,0 +1,90 @@
#ifndef YAZE_APP_EDITOR_OVERWORLD_OVERWORLD_ENTITY_RENDERER_H
#define YAZE_APP_EDITOR_OVERWORLD_OVERWORLD_ENTITY_RENDERER_H
#include <vector>
#include "app/gfx/bitmap.h"
#include "app/gui/canvas.h"
#include "app/zelda3/overworld/overworld.h"
#include "app/zelda3/overworld/overworld_entrance.h"
#include "app/zelda3/overworld/overworld_exit.h"
#include "app/zelda3/overworld/overworld_item.h"
#include "app/zelda3/sprite/sprite.h"
#include "imgui/imgui.h"
namespace yaze {
namespace editor {
class OverworldEditor; // Forward declaration
/**
* @class OverworldEntityRenderer
* @brief Handles visualization of all overworld entities (entrances, exits, items, sprites)
*
* This class separates entity rendering logic from the main OverworldEditor,
* making it easier to maintain and test entity visualization independently.
*/
class OverworldEntityRenderer {
public:
OverworldEntityRenderer(zelda3::Overworld* overworld, gui::Canvas* canvas,
std::vector<gfx::Bitmap>* sprite_previews)
: overworld_(overworld), canvas_(canvas),
sprite_previews_(sprite_previews) {}
// Main rendering methods
void DrawEntrances(ImVec2 canvas_p0, ImVec2 scrolling, int current_world,
int current_mode);
void DrawExits(ImVec2 canvas_p0, ImVec2 scrolling, int current_world,
int current_mode);
void DrawItems(int current_world, int current_mode);
void DrawSprites(int current_world, int game_state, int current_mode);
// State accessors
int current_entrance_id() const { return current_entrance_id_; }
int current_exit_id() const { return current_exit_id_; }
int current_item_id() const { return current_item_id_; }
int current_sprite_id() const { return current_sprite_id_; }
int jump_to_tab() const { return jump_to_tab_; }
zelda3::OverworldEntrance& current_entrance() { return current_entrance_; }
zelda3::OverworldExit& current_exit() { return current_exit_; }
zelda3::OverworldItem& current_item() { return current_item_; }
zelda3::Sprite& current_sprite() { return current_sprite_; }
void set_current_map(int map) { current_map_ = map; }
void set_is_dragging_entity(bool value) { is_dragging_entity_ = value; }
void set_dragged_entity(zelda3::GameEntity* entity) { dragged_entity_ = entity; }
void set_current_entity(zelda3::GameEntity* entity) { current_entity_ = entity; }
void reset_jump_to_tab() { jump_to_tab_ = -1; }
private:
zelda3::Overworld* overworld_;
gui::Canvas* canvas_;
std::vector<gfx::Bitmap>* sprite_previews_;
// Current entity selections
int current_entrance_id_ = 0;
int current_exit_id_ = 0;
int current_item_id_ = 0;
int current_sprite_id_ = 0;
int current_map_ = 0;
int jump_to_tab_ = -1;
// Entity interaction state
bool is_dragging_entity_ = false;
zelda3::GameEntity* dragged_entity_ = nullptr;
zelda3::GameEntity* current_entity_ = nullptr;
// Current entity instances for editing
zelda3::OverworldEntrance current_entrance_;
zelda3::OverworldExit current_exit_;
zelda3::OverworldItem current_item_;
zelda3::Sprite current_sprite_;
};
} // namespace editor
} // namespace yaze
#endif // YAZE_APP_EDITOR_OVERWORLD_OVERWORLD_ENTITY_RENDERER_H