yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
overworld_entity_renderer.cc
Go to the documentation of this file.
2
3#include <string>
4
5#include "absl/strings/str_format.h"
9#include "core/features.h"
10#include "imgui/imgui.h"
11#include "util/hex.h"
12#include "zelda3/common.h"
14
15namespace yaze {
16namespace editor {
17
18using namespace ImGui;
20
21ImVec4 EntityMarkerColor(const AgentUITheme& theme, EntityType type,
22 bool is_hole) {
23 switch (type) {
24 case EntityType::kEntrance:
25 return is_hole ? theme.hole_color : theme.entrance_color;
26 case EntityType::kExit:
27 return theme.exit_color;
28 case EntityType::kItem:
29 return theme.item_color;
30 case EntityType::kSprite:
31 default:
32 return theme.sprite_color;
33 }
34}
35
36namespace {
37ImVec4 MarkerColor(EntityType type, bool is_hole = false) {
38 return EntityMarkerColor(AgentUI::GetTheme(), type, is_hole);
39}
41 const auto& theme = AgentUI::GetTheme();
42 return ImVec4{theme.status_active.x, theme.status_active.y,
43 theme.status_active.z, 0.5f};
44}
45} // namespace
46
47// =============================================================================
48// Modern CanvasRuntime-based rendering methods (Phase 2)
49// =============================================================================
50
52 int current_world) {
53 // Don't reset hovered_entity_ here - DrawExits resets it (called first)
54 for (auto& each : overworld_->entrances()) {
55 if (each.map_id_ < 0x40 + (current_world * 0x40) &&
56 each.map_id_ >= (current_world * 0x40) && !each.deleted) {
57 gui::DrawRect(rt, each.x_, each.y_, 16, 16,
58 MarkerColor(EntityType::kEntrance, each.is_hole_));
59 if (IsMouseHoveringOverEntity(each, rt)) {
60 hovered_entity_ = &each;
61 }
62 std::string str = util::HexByte(each.entrance_id_);
63 gui::DrawText(rt, str, each.x_, each.y_);
64 }
65 }
66}
67
69 int current_world) {
70 // Reset hover state at the start of entity rendering (DrawExits is called first)
71 hovered_entity_ = nullptr;
72
73 int i = 0;
74 for (auto& each : *overworld_->mutable_exits()) {
75 if (each.map_id_ < 0x40 + (current_world * 0x40) &&
76 each.map_id_ >= (current_world * 0x40) && !each.deleted_) {
77 gui::DrawRect(rt, each.x_, each.y_, 16, 16,
78 MarkerColor(EntityType::kExit));
79 if (IsMouseHoveringOverEntity(each, rt)) {
80 hovered_entity_ = &each;
81 }
82 each.entity_id_ = i;
83 std::string str = util::HexByte(i);
84 gui::DrawText(rt, str, each.x_, each.y_);
85 }
86 i++;
87 }
88}
89
91 int current_world) {
92 for (auto& item : *overworld_->mutable_all_items()) {
93 if (item.room_map_id_ < 0x40 + (current_world * 0x40) &&
94 item.room_map_id_ >= (current_world * 0x40) && !item.deleted) {
95 gui::DrawRect(rt, item.x_, item.y_, 16, 16,
96 MarkerColor(EntityType::kItem));
97 if (IsMouseHoveringOverEntity(item, rt)) {
98 hovered_entity_ = &item;
99 }
100 std::string item_name = "";
101 if (item.id_ < zelda3::kSecretItemNames.size()) {
102 item_name = zelda3::kSecretItemNames[item.id_];
103 } else {
104 item_name = absl::StrFormat("0x%02X", item.id_);
105 }
106 gui::DrawText(rt, item_name, item.x_, item.y_);
107 }
108 }
109}
110
112 int current_world, int game_state) {
113 for (auto& sprite : *overworld_->mutable_sprites(game_state)) {
114 if (!sprite.deleted() && sprite.map_id() < 0x40 + (current_world * 0x40) &&
115 sprite.map_id() >= (current_world * 0x40)) {
116 int sprite_x = sprite.x_;
117 int sprite_y = sprite.y_;
118
119 gui::DrawRect(rt, sprite_x, sprite_y, 16, 16,
120 MarkerColor(EntityType::kSprite));
121 if (IsMouseHoveringOverEntity(sprite, rt)) {
122 hovered_entity_ = &sprite;
123 }
124
125 if (core::FeatureFlags::get().overworld.kDrawOverworldSprites) {
126 if ((*sprite_previews_)[sprite.id()].is_active()) {
127 // For bitmap drawing, we still use the canvas pointer for now
128 // as runtime-based bitmap drawing needs the texture
129 canvas_->DrawBitmap((*sprite_previews_)[sprite.id()], sprite_x,
130 sprite_y, 2.0f);
131 }
132 }
133
134 gui::DrawText(rt, absl::StrFormat("%s", sprite.name()), sprite_x,
135 sprite_y);
136 }
137 }
138}
139
140// =============================================================================
141// Legacy rendering methods (kept for backward compatibility)
142// =============================================================================
143
144void OverworldEntityRenderer::DrawEntrances(ImVec2 canvas_p0, ImVec2 scrolling,
145 int current_world,
146 int current_mode) {
147 // Don't reset hovered_entity_ here - DrawExits resets it (called first)
148 float scale = canvas_->global_scale();
149 int i = 0;
150 for (auto& each : overworld_->entrances()) {
151 if (each.map_id_ < 0x40 + (current_world * 0x40) &&
152 each.map_id_ >= (current_world * 0x40) && !each.deleted) {
153 canvas_->DrawRect(each.x_, each.y_, 16, 16,
154 MarkerColor(EntityType::kEntrance, each.is_hole_));
155 if (IsMouseHoveringOverEntity(each, canvas_p0, scrolling, scale)) {
156 hovered_entity_ = &each;
157 }
158 std::string str = util::HexByte(each.entrance_id_);
159
160 canvas_->DrawText(str, each.x_, each.y_);
161 }
162 i++;
163 }
164}
165
166void OverworldEntityRenderer::DrawExits(ImVec2 canvas_p0, ImVec2 scrolling,
167 int current_world, int current_mode) {
168 // Reset hover state at the start of entity rendering (DrawExits is called
169 // first)
170 hovered_entity_ = nullptr;
171 float scale = canvas_->global_scale();
172
173 int i = 0;
174 for (auto& each : *overworld_->mutable_exits()) {
175 if (each.map_id_ < 0x40 + (current_world * 0x40) &&
176 each.map_id_ >= (current_world * 0x40) && !each.deleted_) {
177 canvas_->DrawRect(each.x_, each.y_, 16, 16,
178 MarkerColor(EntityType::kExit));
179
180 if (IsMouseHoveringOverEntity(each, canvas_p0, scrolling, scale)) {
181 hovered_entity_ = &each;
182 }
183 each.entity_id_ = i;
184
185 std::string str = util::HexByte(i);
186 canvas_->DrawText(str, each.x_, each.y_);
187 }
188 i++;
189 }
190}
191
192void OverworldEntityRenderer::DrawItems(int current_world, int current_mode) {
193 float scale = canvas_->global_scale();
194 int i = 0;
195 for (auto& item : *overworld_->mutable_all_items()) {
196 // Get the item's bitmap and real X and Y positions
197 if (item.room_map_id_ < 0x40 + (current_world * 0x40) &&
198 item.room_map_id_ >= (current_world * 0x40) && !item.deleted) {
199 canvas_->DrawRect(item.x_, item.y_, 16, 16,
200 MarkerColor(EntityType::kItem));
201
203 canvas_->scrolling(), scale)) {
204 hovered_entity_ = &item;
205 }
206
207 std::string item_name = "";
208 if (item.id_ < zelda3::kSecretItemNames.size()) {
209 item_name = zelda3::kSecretItemNames[item.id_];
210 } else {
211 item_name = absl::StrFormat("0x%02X", item.id_);
212 }
213 canvas_->DrawText(item_name, item.x_, item.y_);
214 }
215 i++;
216 }
217}
218
219void OverworldEntityRenderer::DrawSprites(int current_world, int game_state,
220 int current_mode) {
221 float scale = canvas_->global_scale();
222 int i = 0;
223 for (auto& sprite : *overworld_->mutable_sprites(game_state)) {
224 // Filter sprites by current world - only show sprites for the current world
225 if (!sprite.deleted() && sprite.map_id() < 0x40 + (current_world * 0x40) &&
226 sprite.map_id() >= (current_world * 0x40)) {
227 // Sprites are already stored with global coordinates (realX, realY from
228 // ROM loading) So we can use sprite.x_ and sprite.y_ directly
229 int sprite_x = sprite.x_;
230 int sprite_y = sprite.y_;
231
232 // Temporarily update sprite coordinates for entity interaction
233 int original_x = sprite.x_;
234 int original_y = sprite.y_;
235
236 canvas_->DrawRect(sprite_x, sprite_y, 16, 16,
237 MarkerColor(EntityType::kSprite));
239 canvas_->scrolling(), scale)) {
240 hovered_entity_ = &sprite;
241 }
242
244 if ((*sprite_previews_)[sprite.id()].is_active()) {
245 canvas_->DrawBitmap((*sprite_previews_)[sprite.id()], sprite_x,
246 sprite_y, 2.0f);
247 }
248 }
249
250 canvas_->DrawText(absl::StrFormat("%s", sprite.name()), sprite_x,
251 sprite_y);
252
253 // Restore original coordinates
254 sprite.x_ = original_x;
255 sprite.y_ = original_y;
256 }
257 i++;
258 }
259}
260
262 int current_map) {
264 return;
265 }
266
267 const auto& diggable_tiles = overworld_->diggable_tiles();
268 const auto& map_tiles = overworld_->GetMapTiles(current_world);
269
270 // Calculate map bounds based on current_map
271 // Each map is 32x32 tiles (512x512 pixels)
272 // Maps are arranged in an 8x8 grid per world
273 int map_x = (current_map % 8) * 32; // Tile position in world
274 int map_y = (current_map / 8) * 32;
275
276 // Iterate through the 32x32 tiles in this map
277 for (int ty = 0; ty < 32; ++ty) {
278 for (int tx = 0; tx < 32; ++tx) {
279 int world_tx = map_x + tx;
280 int world_ty = map_y + ty;
281
282 // Get the Map16 tile ID at this position
283 // Map tiles are stored [y][x]
284 if (world_ty >= 256 || world_tx >= 256) {
285 continue; // Out of bounds
286 }
287
288 uint16_t tile_id = map_tiles[world_ty][world_tx];
289
290 // Check if this tile is marked as diggable
291 if (diggable_tiles.IsDiggable(tile_id)) {
292 // Calculate pixel position (each tile is 16x16 pixels)
293 int pixel_x = world_tx * 16;
294 int pixel_y = world_ty * 16;
295
296 // Draw a semi-transparent highlight
297 canvas_->DrawRect(pixel_x, pixel_y, 16, 16, GetDiggableTileColor());
298 }
299 }
300 }
301}
302
303} // namespace editor
304} // namespace yaze
static Flags & get()
Definition features.h:119
void DrawDiggableTileHighlights(int current_world, int current_map)
Draw highlights for all diggable tiles on the current map.
void DrawItems(const gui::CanvasRuntime &rt, int current_world)
void DrawExits(const gui::CanvasRuntime &rt, int current_world)
void DrawSprites(const gui::CanvasRuntime &rt, int current_world, int game_state)
void DrawEntrances(const gui::CanvasRuntime &rt, int current_world)
void DrawBitmap(Bitmap &bitmap, int border_offset, float scale)
Definition canvas.cc:1293
auto global_scale() const
Definition canvas.h:413
void DrawRect(int x, int y, int w, int h, ImVec4 color)
Definition canvas.cc:1563
auto zero_point() const
Definition canvas.h:364
auto scrolling() const
Definition canvas.h:366
void DrawText(const std::string &text, int x, int y)
Definition canvas.cc:1568
auto mutable_sprites(int state)
Definition overworld.h:759
const DiggableTiles & diggable_tiles() const
Definition overworld.h:840
const std::vector< OverworldEntrance > & entrances() const
Definition overworld.h:770
OverworldBlockset & GetMapTiles(int world_type)
Definition overworld.h:721
Definition input.cc:30
const AgentUITheme & GetTheme()
ImVec4 EntityMarkerColor(const AgentUITheme &theme, EntityType type, bool is_hole)
EntityType
Type of entity that can be selected in the dungeon editor.
bool IsMouseHoveringOverEntity(const zelda3::GameEntity &entity, ImVec2 canvas_p0, ImVec2 scrolling, float scale)
Check if mouse is hovering over an entity.
Definition entity.cc:30
void DrawRect(const CanvasRuntime &rt, int x, int y, int w, int h, ImVec4 color)
void DrawText(const CanvasRuntime &rt, const std::string &text, int x, int y)
std::string HexByte(uint8_t byte, HexStringParams params)
Definition hex.cc:33
const std::vector< std::string > kSecretItemNames
struct yaze::core::FeatureFlags::Flags::Overworld overworld
Centralized theme colors for Agent UI components.
Definition agent_theme.h:19