yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
room_graphics_content.cc
Go to the documentation of this file.
2#include "util/i18n/tr.h"
3
4#include <algorithm>
5#include <cstdint>
6#include <vector>
7
13#include "imgui/imgui.h"
14
15namespace yaze {
16namespace editor {
17
19 const auto blocks = room.blocks();
20 if (blocks.size() < sheet_previews_.size()) {
22 return;
23 }
24
25 bool needs_refresh =
27 if (!needs_refresh) {
28 for (size_t i = 0; i < preview_block_ids_.size(); ++i) {
29 if (preview_block_ids_[i] != blocks[i]) {
30 needs_refresh = true;
31 break;
32 }
33 }
34 }
35 if (!needs_refresh) {
36 return;
37 }
38
39 std::vector<SDL_Color> palette_colors;
40 if (SDL_Surface* bg_surface = room.bg1_buffer().bitmap().surface()) {
41 if (SDL_Palette* palette = platform::GetSurfacePalette(bg_surface)) {
42 palette_colors.assign(palette->colors,
43 palette->colors + palette->ncolors);
44 }
45 }
46
47 const auto& gfx_buffer = room.get_gfx_buffer();
48 constexpr size_t kSheetBytes = 128 * 32;
49 for (size_t i = 0; i < sheet_previews_.size(); ++i) {
50 preview_block_ids_[i] = blocks[i];
51 const size_t offset = i * kSheetBytes;
52 auto& meta = sheet_preview_metadata_[i];
53 meta = {};
54 meta.block_id = blocks[i];
55 meta.source_offset = offset;
56 if (offset + kSheetBytes > gfx_buffer.size()) {
58 continue;
59 }
60
61 std::vector<uint8_t> sheet_pixels(
62 gfx_buffer.begin() + offset, gfx_buffer.begin() + offset + kSheetBytes);
63 meta.nonzero_pixels = static_cast<int>(
64 std::count_if(sheet_pixels.begin(), sheet_pixels.end(),
65 [](uint8_t value) { return value != 0; }));
66 sheet_previews_[i].Create(128, 32, 8,
67 static_cast<int>(gfx::BitmapFormat::kIndexed),
68 sheet_pixels);
69 if (!palette_colors.empty()) {
70 sheet_previews_[i].SetPalette(palette_colors);
71 }
72 sheet_previews_[i].CreateTexture();
73 meta.width = sheet_previews_[i].width();
74 meta.height = sheet_previews_[i].height();
75 meta.bitmap_active = sheet_previews_[i].is_active();
76 meta.has_surface = sheet_previews_[i].surface() != nullptr;
77 meta.palette_colors = static_cast<int>(palette_colors.size());
78 meta.has_texture = sheet_previews_[i].texture() != nullptr;
79 }
80
81 preview_room_id_ = room.id();
83 palette_dirty_ = false;
84}
85
86void RoomGraphicsContent::Draw(bool* p_open) {
87 (void)p_open;
88 // Resolve the active dungeon editor lazily when this panel is hosted through
89 // the workspace window system instead of the legacy direct constructor.
90 if (current_room_id_ == nullptr || rooms_ == nullptr) {
91 const auto ctx = CurrentDungeonWindowContext();
92 if (ctx) {
93 current_room_id_ = ctx.editor->mutable_current_room_id();
94 rooms_ = &ctx.editor->rooms();
95 renderer_ = ctx.editor->renderer();
96 }
97 }
98
99 if (current_room_id_ == nullptr || rooms_ == nullptr) {
100 ImGui::TextDisabled(tr("No room data available"));
101 return;
102 }
103
104 const int active_room_id = *current_room_id_;
105 if (active_room_id < 0 ||
106 active_room_id >= static_cast<int>(rooms_->size())) {
107 ImGui::TextDisabled(tr("Invalid room ID: %d"), active_room_id);
108 return;
109 }
110
111 auto& room = (*rooms_)[active_room_id];
112 bool needs_render = false;
113 if (room.blocks().empty()) {
114 room.LoadRoomGraphics();
115 needs_render = true;
116 }
117 if (!room.AreObjectsLoaded()) {
118 room.LoadObjects();
119 needs_render = true;
120 }
121 auto& bg1_bitmap = room.bg1_buffer().bitmap();
122 if (needs_render || !bg1_bitmap.is_active() || bg1_bitmap.width() == 0) {
123 room.RenderRoomGraphics();
124 }
125 // Keep room-sheet assignments in sync with the active room header.
126 room.LoadRoomGraphics();
128
129 if (renderer_ != nullptr) {
131 }
132 auto blocks = room.blocks();
133
134 constexpr float kBlockWidth = 128.0f;
135 constexpr float kBlockHeight = 32.0f;
136 constexpr int kBlocksPerRow = 2;
137 constexpr float kPadding = 4.0f;
138
139 const int block_count = static_cast<int>(blocks.size());
140 const int row_count =
141 std::max(1, (block_count + kBlocksPerRow - 1) / kBlocksPerRow);
142 const ImVec2 canvas_size(
143 std::max(ImGui::GetContentRegionAvail().x,
144 kPadding + (kBlockWidth + kPadding) *
145 static_cast<float>(kBlocksPerRow)),
146 kPadding + (kBlockHeight + kPadding) * static_cast<float>(row_count));
147
148 ImGui::Text(tr("Room %03X Graphics Blocks"), active_room_id);
149 ImGui::TextDisabled(tr("Blockset %02X | Spriteset %02X"), room.blockset(),
150 room.spriteset());
151 ImGui::SameLine();
152 ImGui::Checkbox(tr("Source Trace"), &show_source_trace_);
153 ImGui::Separator();
154
155 gui::CanvasFrameOptions frame_opts;
156 frame_opts.canvas_size = canvas_size;
157 frame_opts.draw_grid = false;
158 frame_opts.draw_overlay = false;
159 frame_opts.draw_context_menu = false;
160 frame_opts.render_popups = false;
161
162 auto rt = gui::BeginCanvas(room_gfx_canvas_, frame_opts);
163
164 const float grid_width =
165 kPadding + (kBlockWidth + kPadding) * static_cast<float>(kBlocksPerRow);
166 const float x_offset = std::max(0.0f, (canvas_size.x - grid_width) * 0.5f);
167 ImDrawList* draw_list = ImGui::GetWindowDrawList();
168 for (int i = 0; i < block_count; ++i) {
169 const uint8_t block_id = blocks[static_cast<size_t>(i)];
170 const int row = i / kBlocksPerRow;
171 const int col = i % kBlocksPerRow;
172 const ImVec2 local_pos(x_offset + kPadding + col * (kBlockWidth + kPadding),
173 kPadding + row * (kBlockHeight + kPadding));
174
175 if (i < static_cast<int>(sheet_previews_.size()) &&
176 sheet_previews_[static_cast<size_t>(i)].texture() != 0) {
177 gui::BitmapPreviewOptions preview_opts;
178 preview_opts.dest_pos = local_pos;
179 preview_opts.dest_size = ImVec2(kBlockWidth, kBlockHeight);
180 preview_opts.draw_context_menu = false;
181 preview_opts.draw_grid = false;
182 preview_opts.draw_overlay = false;
183 preview_opts.render_popups = false;
184 preview_opts.ensure_texture = true;
185 gui::DrawBitmapPreview(rt, sheet_previews_[static_cast<size_t>(i)],
186 preview_opts);
187 } else {
188 const ImVec2 zero = room_gfx_canvas_.zero_point();
189 const float scale = room_gfx_canvas_.global_scale();
190 const ImVec2 screen_pos(zero.x + local_pos.x, zero.y + local_pos.y);
191 const ImVec2 screen_end(screen_pos.x + kBlockWidth * scale,
192 screen_pos.y + kBlockHeight * scale);
193 draw_list->AddRect(screen_pos, screen_end,
194 ImGui::GetColorU32(gui::GetOutlineVec4()));
195 draw_list->AddText(ImVec2(screen_pos.x + 6.0f, screen_pos.y + 6.0f),
196 ImGui::GetColorU32(gui::GetTextSecondaryVec4()),
197 block_id == 0 ? "Empty" : "Missing");
198 }
199 }
200
201 gui::EndCanvas(room_gfx_canvas_, rt, frame_opts);
202
203 if (show_source_trace_ &&
204 ImGui::CollapsingHeader(ICON_MD_BUG_REPORT " Source Trace",
205 ImGuiTreeNodeFlags_DefaultOpen)) {
206 ImGui::TextDisabled(tr(
207 "Source: Room::get_gfx_buffer() -> preview bitmap -> queued texture"));
208 ImGui::TextDisabled(tr("Room buffer bytes: %zu"),
209 room.get_gfx_buffer().size());
210 ImGui::Separator();
211 for (int i = 0;
212 i < std::min(block_count,
213 static_cast<int>(sheet_preview_metadata_.size()));
214 ++i) {
215 const auto& meta = sheet_preview_metadata_[static_cast<size_t>(i)];
216 const uintptr_t texture_value = reinterpret_cast<uintptr_t>(
217 sheet_previews_[static_cast<size_t>(i)].texture());
218 ImGui::PushID(i);
219 ImGui::Text(
220 tr("Slot %02d | Block %02X | Buf +0x%04zX | %dx%d | nz=%d | pal=%d | "
221 "active=%d surf=%d tex=%d (0x%zx)"),
222 i, meta.block_id, meta.source_offset, meta.width, meta.height,
223 meta.nonzero_pixels, meta.palette_colors, meta.bitmap_active,
224 meta.has_surface, meta.has_texture, texture_value);
225 ImGui::PopID();
226 }
227 }
228}
229
230} // namespace editor
231} // namespace yaze
std::array< uint8_t, 16 > preview_block_ids_
void RefreshSheetPreviews(const zelda3::Room &room)
void Draw(bool *p_open) override
Draw the panel content.
std::array< gfx::Bitmap, 16 > sheet_previews_
std::array< SheetPreviewMetadata, 16 > sheet_preview_metadata_
void ProcessTextureQueue(IRenderer *renderer)
Definition arena.cc:116
static Arena & Get()
Definition arena.cc:21
Represents a bitmap image optimized for SNES ROM hacking.
Definition bitmap.h:67
auto global_scale() const
Definition canvas.h:397
auto zero_point() const
Definition canvas.h:348
const std::array< uint8_t, 0x10000 > & get_gfx_buffer() const
Definition room.h:970
auto & bg1_buffer()
Definition room.h:975
auto blocks() const
Definition room.h:956
int id() const
Definition room.h:899
#define ICON_MD_BUG_REPORT
Definition icons.h:327
DungeonWindowContext CurrentDungeonWindowContext()
@ kIndexed
Definition bitmap.h:36
void EndCanvas(Canvas &canvas)
void DrawBitmapPreview(const CanvasRuntime &rt, gfx::Bitmap &bitmap, const BitmapPreviewOptions &options)
void BeginCanvas(Canvas &canvas, ImVec2 child_size)
ImVec4 GetTextSecondaryVec4()
ImVec4 GetOutlineVec4()
SDL_Palette * GetSurfacePalette(SDL_Surface *surface)
Get the palette attached to a surface.
Definition sdl_compat.h:392
SDL2/SDL3 compatibility layer.