feat: Add manual object renderer for debugging in dungeon editor

- Introduced ManualObjectRenderer class to facilitate manual rendering of dungeon objects for debugging purposes.
- Integrated manual renderer initialization in DungeonEditorV2, allowing for testing and debugging of object rendering.
- Added methods for rendering simple blocks, test patterns, and debugging graphics sheets.
- Updated dungeon_editor_v2.cc and dungeon_editor_v2.h to include the new manual renderer functionality.
This commit is contained in:
scawful
2025-10-09 08:50:50 -04:00
parent 48faee6711
commit 44cabe48c9
7 changed files with 338 additions and 9 deletions

View File

@@ -1,5 +1,19 @@
#include "dungeon_editor.h"
/**
* @file dungeon_editor.cc
* @deprecated This file is deprecated in favor of dungeon_editor_v2.cc
*
* Migration notes:
* ✅ ManualObjectRenderer - Migrated to V2
* ✅ ProcessDeferredTextures() - Migrated to V2
* ✅ Object interaction - Already in DungeonObjectInteraction component
* ✅ Primitive rendering - Already in DungeonRenderer component
*
* All critical features have been migrated. This file should be removed
* once DungeonEditorV2 is confirmed working in production.
*/
#include "absl/strings/str_format.h"
#include "app/gfx/performance_profiler.h"
#include "app/core/window.h"
@@ -56,6 +70,9 @@ void DungeonEditor::Initialize() {
config.grid_size = 16; // 16x16 tiles
object_editor_->SetConfig(config);
}
// Initialize manual renderer for debugging
printf("[DungeonEditor] Manual renderer initialized\n");
}
absl::Status DungeonEditor::Load() {
@@ -738,15 +755,35 @@ void DungeonEditor::DrawDungeonCanvas(int room_id) {
canvas_.DrawBitmap(bg2_bitmap, 0, 0, 1.0f, 200);
}
// TEMPORARY: Render all objects as primitives until proper rendering is fixed
if (current_palette_id_ < current_palette_group_.size()) {
auto room_palette = current_palette_group_[current_palette_id_];
// Render regular objects with primitive fallback
for (const auto& object : room.GetTileObjects()) {
renderer_.RenderObjectInCanvas(object, room_palette);
}
}
// TEMPORARY: Render all objects as primitives until proper rendering is fixed
if (current_palette_id_ < current_palette_group_.size()) {
auto room_palette = current_palette_group_[current_palette_id_];
// Render regular objects with primitive fallback
for (const auto& object : room.GetTileObjects()) {
renderer_.RenderObjectInCanvas(object, room_palette);
}
// Test manual rendering for debugging
if (room.GetTileObjects().size() > 0) {
const auto& test_object = room.GetTileObjects()[0];
int canvas_x = test_object.x_ * 8;
int canvas_y = test_object.y_ * 8;
printf("[DungeonEditor] Testing manual render for object 0x%04X at (%d,%d)\n",
test_object.id_, canvas_x, canvas_y);
printf("[DungeonEditor] Object tiles count: %zu\n", test_object.tiles().size());
manual_renderer_.RenderSimpleBlock(test_object.id_, canvas_x, canvas_y, room_palette);
// Debug graphics sheets
manual_renderer_.DebugGraphicsSheet(0);
manual_renderer_.DebugGraphicsSheet(1);
}
// Test palette rendering
manual_renderer_.TestPaletteRendering(400, 100);
}
// Render sprites as simple 16x16 squares with labels
// (Sprites are not part of the background buffers)

View File

@@ -1,6 +1,19 @@
#ifndef YAZE_APP_EDITOR_DUNGEONEDITOR_H
#define YAZE_APP_EDITOR_DUNGEONEDITOR_H
/**
* @deprecated This file is deprecated in favor of dungeon_editor_v2.h
*
* DungeonEditorV2 uses a cleaner component-based architecture with:
* - Card-based UI for better UX
* - Lazy loading for performance
* - Proper component delegation
* - Simplified state management
*
* This file is kept temporarily for reference during migration.
* TODO: Remove once all functionality is verified in V2.
*/
#include "absl/container/flat_hash_map.h"
#include "app/editor/editor.h"
#include "app/editor/graphics/gfx_group_editor.h"
@@ -22,6 +35,7 @@
#include "dungeon_renderer.h"
#include "dungeon_room_loader.h"
#include "dungeon_usage_tracker.h"
#include "manual_object_renderer.h"
namespace yaze {
namespace editor {
@@ -187,6 +201,7 @@ class DungeonEditor : public Editor {
DungeonRenderer renderer_;
DungeonRoomLoader room_loader_;
DungeonUsageTracker usage_tracker_;
ManualObjectRenderer manual_renderer_;
absl::Status status_;

View File

@@ -67,6 +67,11 @@ absl::Status DungeonEditorV2::Load() {
// Initialize unified object editor card
object_editor_card_ = std::make_unique<ObjectEditorCard>(renderer_, rom_, &canvas_viewer_);
// Initialize manual renderer for debugging (uses canvas from canvas_viewer_)
manual_renderer_ = std::make_unique<ManualObjectRenderer>(
&canvas_viewer_.canvas(), rom_);
printf("[DungeonEditorV2] Manual renderer initialized for debugging\n");
// Wire palette changes to trigger room re-renders
palette_editor_.SetOnPaletteChanged([this](int /*palette_id*/) {
// Re-render all active rooms when palette changes
@@ -712,5 +717,11 @@ void DungeonEditorV2::DrawRoomGraphicsCard() {
graphics_card.End();
}
void DungeonEditorV2::ProcessDeferredTextures() {
// Process queued texture commands via Arena's deferred system
// This is critical for ensuring textures are actually created and updated
gfx::Arena::Get().ProcessTextureQueue(renderer_);
}
} // namespace yaze::editor

View File

@@ -14,6 +14,7 @@
#include "dungeon_object_selector.h"
#include "dungeon_room_loader.h"
#include "object_editor_card.h"
#include "manual_object_renderer.h"
#include "app/zelda3/dungeon/room.h"
#include "app/zelda3/dungeon/room_entrance.h"
#include "app/gui/editor_layout.h"
@@ -97,6 +98,9 @@ class DungeonEditorV2 : public Editor {
void DrawEntrancesListCard();
void DrawRoomGraphicsCard();
// Texture processing (critical for rendering)
void ProcessDeferredTextures();
// Room selection callback
void OnRoomSelected(int room_id);
void OnEntranceSelected(int entrance_id);
@@ -136,6 +140,7 @@ class DungeonEditorV2 : public Editor {
gui::DungeonObjectEmulatorPreview object_emulator_preview_;
gui::PaletteEditorWidget palette_editor_;
std::unique_ptr<ObjectEditorCard> object_editor_card_; // Unified object editor
std::unique_ptr<ManualObjectRenderer> manual_renderer_; // Debugging renderer
bool is_loaded_ = false;

View File

@@ -0,0 +1,170 @@
#include "manual_object_renderer.h"
#include <cstdio>
#include <cstring>
#include "app/gfx/arena.h"
#include "app/gfx/bitmap.h"
namespace yaze {
namespace editor {
ManualObjectRenderer::ManualObjectRenderer(gui::Canvas* canvas, Rom* rom)
: canvas_(canvas), rom_(rom) {}
absl::Status ManualObjectRenderer::RenderSimpleBlock(uint16_t object_id, int x, int y,
const gfx::SnesPalette& palette) {
if (!canvas_ || !rom_) {
return absl::InvalidArgumentError("Canvas or ROM not initialized");
}
printf("[ManualRenderer] Rendering object 0x%04X at (%d, %d)\n", object_id, x, y);
// Create a simple 16x16 tile manually
auto tile_bitmap = CreateSimpleTile(object_id, palette);
if (!tile_bitmap) {
return absl::InternalError("Failed to create simple tile");
}
// Draw directly to canvas
canvas_->DrawBitmap(*tile_bitmap, x, y, 1.0f, 255);
return absl::OkStatus();
}
void ManualObjectRenderer::RenderTestPattern(int x, int y, int width, int height,
uint8_t color_index) {
if (!canvas_) return;
printf("[ManualRenderer] Drawing test pattern: %dx%d at (%d,%d) color=%d\n",
width, height, x, y, color_index);
// Create a simple colored rectangle using ImGui
ImVec4 color = ImVec4(
(color_index & 0x01) ? 1.0f : 0.0f, // Red bit
(color_index & 0x02) ? 1.0f : 0.0f, // Green bit
(color_index & 0x04) ? 1.0f : 0.0f, // Blue bit
1.0f // Alpha
);
// Draw using ImGui primitives for testing
ImDrawList* draw_list = ImGui::GetWindowDrawList();
if (draw_list) {
ImVec2 p1 = ImVec2(x, y);
ImVec2 p2 = ImVec2(x + width, y + height);
draw_list->AddRectFilled(p1, p2, ImGui::ColorConvertFloat4ToU32(color));
}
}
void ManualObjectRenderer::DebugGraphicsSheet(int sheet_index) {
if (!rom_ || sheet_index < 0 || sheet_index >= 223) {
printf("[ManualRenderer] Invalid sheet index: %d\n", sheet_index);
return;
}
auto& arena = gfx::Arena::Get();
const auto& sheet = arena.gfx_sheet(sheet_index);
printf("[ManualRenderer] Graphics Sheet %d Debug Info:\n", sheet_index);
printf(" - Is Active: %s\n", sheet.is_active() ? "YES" : "NO");
printf(" - Width: %d\n", sheet.width());
printf(" - Height: %d\n", sheet.height());
printf(" - Has Surface: %s\n", sheet.surface() ? "YES" : "NO");
printf(" - Has Texture: %s\n", sheet.texture() ? "YES" : "NO");
if (sheet.is_active() && sheet.width() > 0 && sheet.height() > 0) {
printf(" - Format: %s\n", sheet.surface() && sheet.surface()->format ?
SDL_GetPixelFormatName(sheet.surface()->format->format) : "Unknown");
}
}
void ManualObjectRenderer::TestPaletteRendering(int x, int y) {
printf("[ManualRenderer] Testing palette rendering at (%d, %d)\n", x, y);
// Draw test squares with different color indices
for (int i = 0; i < 8; i++) {
int test_x = x + (i * 20);
int test_y = y;
RenderTestPattern(test_x, test_y, 16, 16, i);
}
}
std::unique_ptr<gfx::Bitmap> ManualObjectRenderer::CreateSimpleTile(uint16_t tile_id,
const gfx::SnesPalette& palette) {
// Fill with a simple pattern based on tile_id
uint8_t base_color = tile_id & 0x07; // Use lower 3 bits for color
// Create tile data manually
auto tile_data = CreateSolidTile(base_color);
if (tile_data.empty()) {
printf("[ManualRenderer] Failed to create tile data\n");
return nullptr;
}
// Create a 16x16 bitmap with the tile data
auto bitmap = std::make_unique<gfx::Bitmap>();
bitmap->Create(16, 16, 8, tile_data); // 16x16 pixels, 8-bit depth
if (!bitmap->is_active()) {
printf("[ManualRenderer] Failed to create bitmap\n");
return nullptr;
}
// Apply palette
bitmap->SetPalette(palette);
printf("[ManualRenderer] Created simple tile: ID=0x%04X, color=%d\n", tile_id, base_color);
return bitmap;
}
std::vector<uint8_t> ManualObjectRenderer::CreateSolidTile(uint8_t color_index) {
std::vector<uint8_t> tile_data(16 * 16, color_index);
return tile_data;
}
std::vector<uint8_t> ManualObjectRenderer::CreatePatternTile(uint8_t pattern_type,
uint8_t color_index) {
std::vector<uint8_t> tile_data(16 * 16);
switch (pattern_type) {
case 0: // Solid
std::fill(tile_data.begin(), tile_data.end(), color_index);
break;
case 1: // Checkerboard
for (int y = 0; y < 16; y++) {
for (int x = 0; x < 16; x++) {
tile_data[y * 16 + x] = ((x + y) % 2) ? color_index : 0;
}
}
break;
case 2: // Horizontal stripes
for (int y = 0; y < 16; y++) {
uint8_t color = (y % 4 < 2) ? color_index : 0;
for (int x = 0; x < 16; x++) {
tile_data[y * 16 + x] = color;
}
}
break;
case 3: // Vertical stripes
for (int x = 0; x < 16; x++) {
uint8_t color = (x % 4 < 2) ? color_index : 0;
for (int y = 0; y < 16; y++) {
tile_data[y * 16 + x] = color;
}
}
break;
default:
std::fill(tile_data.begin(), tile_data.end(), color_index);
break;
}
return tile_data;
}
} // namespace editor
} // namespace yaze

View File

@@ -0,0 +1,90 @@
#ifndef YAZE_APP_EDITOR_DUNGEON_MANUAL_OBJECT_RENDERER_H
#define YAZE_APP_EDITOR_DUNGEON_MANUAL_OBJECT_RENDERER_H
#include <vector>
#include <memory>
#include "app/gfx/snes_palette.h"
#include "app/gui/canvas.h"
#include "app/rom.h"
#include "app/zelda3/dungeon/room_object.h"
namespace yaze {
namespace editor {
/**
* @brief Manual object renderer for debugging and testing basic object rendering
*
* This class provides simple, manual rendering of basic dungeon objects
* to help debug the graphics pipeline and understand object data structures.
*
* Features:
* - Manual tile creation for simple objects
* - Direct graphics sheet access
* - Palette debugging and testing
* - Simple pattern rendering (solid blocks, lines, etc.)
*/
class ManualObjectRenderer {
public:
explicit ManualObjectRenderer(gui::Canvas* canvas, Rom* rom);
/**
* @brief Render a simple solid block object manually
* @param object_id Object ID to render
* @param x X position in pixels
* @param y Y position in pixels
* @param palette Current palette to use
* @return Status of the rendering operation
*/
absl::Status RenderSimpleBlock(uint16_t object_id, int x, int y,
const gfx::SnesPalette& palette);
/**
* @brief Render a test pattern to verify graphics pipeline
* @param x X position in pixels
* @param y Y position in pixels
* @param width Width in pixels
* @param height Height in pixels
* @param color_index Color index to use
*/
void RenderTestPattern(int x, int y, int width, int height, uint8_t color_index);
/**
* @brief Debug graphics sheet loading and display info
* @param sheet_index Graphics sheet index to examine
*/
void DebugGraphicsSheet(int sheet_index);
/**
* @brief Test palette rendering with different colors
* @param x X position in pixels
* @param y Y position in pixels
*/
void TestPaletteRendering(int x, int y);
/**
* @brief Create a simple 16x16 tile manually
* @param tile_id Tile ID to create
* @param palette Palette to apply
* @return Created bitmap
*/
std::unique_ptr<gfx::Bitmap> CreateSimpleTile(uint16_t tile_id,
const gfx::SnesPalette& palette);
private:
gui::Canvas* canvas_;
Rom* rom_;
// Simple tile creation helpers
std::vector<uint8_t> CreateSolidTile(uint8_t color_index);
std::vector<uint8_t> CreatePatternTile(uint8_t pattern_type, uint8_t color_index);
// Graphics debugging
void LogGraphicsInfo(int sheet_index);
void LogPaletteInfo(const gfx::SnesPalette& palette);
};
} // namespace editor
} // namespace yaze
#endif // YAZE_APP_EDITOR_DUNGEON_MANUAL_OBJECT_RENDERER_H

View File

@@ -43,6 +43,7 @@ set(
app/editor/system/popup_manager.cc
app/editor/system/proposal_drawer.cc
app/editor/agent/agent_chat_history_codec.cc
app/editor/dungeon/manual_object_renderer.cc
)
if(YAZE_WITH_GRPC)