6#include "imgui/imgui.h"
16 ImVec2 drag_start_pos = ImVec2(-1, -1);
17 bool is_dragging =
false;
31 return ImVec2(std::floor(pos.x / grid_step) * grid_step,
32 std::floor(pos.y / grid_step) * grid_step);
36 const ImGuiIO& imgui_io = ImGui::GetIO();
39 return ImVec2(imgui_io.MousePos.x - origin.x, imgui_io.MousePos.y - origin.y);
43 const ImGuiIO& imgui_io = ImGui::GetIO();
44 return imgui_io.MousePos.x >= geometry.
canvas_p0.x &&
45 imgui_io.MousePos.x <= geometry.
canvas_p1.x &&
46 imgui_io.MousePos.y >= geometry.
canvas_p0.y &&
47 imgui_io.MousePos.y <= geometry.
canvas_p1.y;
52 const float scaled_size = tile_size * global_scale;
53 return ImVec2(std::floor(canvas_pos.x / scaled_size),
54 std::floor(canvas_pos.y / scaled_size));
62 int current_map,
float tile_size,
63 ImDrawList* draw_list,
64 ImGuiMouseButton mouse_button) {
73 const float scaled_size =
75 constexpr int kSmallMapSize = 0x200;
80 if (current_map < 0x40) {
82 super_y = current_map / 8;
83 super_x = current_map % 8;
84 }
else if (current_map < 0x80) {
86 super_y = (current_map - 0x40) / 8;
87 super_x = (current_map - 0x40) % 8;
90 super_y = (current_map - 0x80) / 8;
91 super_x = (current_map - 0x80) % 8;
95 if (ImGui::IsMouseClicked(mouse_button)) {
100 ImVec2 painter_pos =
AlignToGrid(mouse_pos, scaled_size);
101 int painter_x =
static_cast<int>(painter_pos.x);
102 int painter_y =
static_cast<int>(painter_pos.y);
104 auto tile16_x = (painter_x % kSmallMapSize) / (kSmallMapSize / 0x20);
105 auto tile16_y = (painter_y % kSmallMapSize) / (kSmallMapSize / 0x20);
107 int index_x = super_x * 0x20 + tile16_x;
108 int index_y = super_y * 0x20 + tile16_y;
110 event.start_pos = painter_pos;
111 event.selected_tiles.push_back(
112 ImVec2(
static_cast<float>(index_x),
static_cast<float>(index_y)));
116 ImVec2 drag_end_pos =
AlignToGrid(mouse_pos, scaled_size);
117 if (ImGui::IsMouseDragging(mouse_button) && draw_list) {
119 event.is_active =
true;
121 event.end_pos = drag_end_pos;
127 auto end = ImVec2(geometry.
canvas_p0.x + drag_end_pos.x + tile_size,
128 geometry.
canvas_p0.y + drag_end_pos.y + tile_size);
129 draw_list->AddRect(start, end, IM_COL32(255, 255, 255, 255));
133 if (g_select_rect_state.
is_dragging && !ImGui::IsMouseDown(mouse_button)) {
135 event.is_complete =
true;
136 event.is_active =
false;
138 event.end_pos = drag_end_pos;
141 constexpr int kTile16Size = 16;
142 int start_x =
static_cast<int>(std::floor(
145 int start_y =
static_cast<int>(std::floor(
148 int end_x =
static_cast<int>(std::floor(drag_end_pos.x / scaled_size)) *
150 int end_y =
static_cast<int>(std::floor(drag_end_pos.y / scaled_size)) *
154 std::swap(start_x, end_x);
156 std::swap(start_y, end_y);
158 constexpr int kTilesPerLocalMap = kSmallMapSize / 16;
160 for (
int tile_y = start_y; tile_y <= end_y; tile_y += kTile16Size) {
161 for (
int tile_x = start_x; tile_x <= end_x; tile_x += kTile16Size) {
162 int local_map_x = tile_x / kSmallMapSize;
163 int local_map_y = tile_y / kSmallMapSize;
165 int tile16_x = (tile_x % kSmallMapSize) / kTile16Size;
166 int tile16_y = (tile_y % kSmallMapSize) / kTile16Size;
168 int index_x = local_map_x * kTilesPerLocalMap + tile16_x;
169 int index_y = local_map_y * kTilesPerLocalMap + tile16_y;
171 event.selected_tiles.emplace_back(
static_cast<float>(index_x),
172 static_cast<float>(index_y));
181 int current_map,
float tile_size,
182 ImGuiMouseButton mouse_button) {
185 if (!
IsMouseInCanvas(geometry) || !ImGui::IsMouseClicked(mouse_button)) {
190 const float scaled_size =
192 constexpr int kSmallMapSize = 0x200;
197 if (current_map < 0x40) {
198 super_y = current_map / 8;
199 super_x = current_map % 8;
200 }
else if (current_map < 0x80) {
201 super_y = (current_map - 0x40) / 8;
202 super_x = (current_map - 0x40) % 8;
204 super_y = (current_map - 0x80) / 8;
205 super_x = (current_map - 0x80) % 8;
208 ImVec2 painter_pos =
AlignToGrid(mouse_pos, scaled_size);
209 int painter_x =
static_cast<int>(painter_pos.x);
210 int painter_y =
static_cast<int>(painter_pos.y);
212 auto tile16_x = (painter_x % kSmallMapSize) / (kSmallMapSize / 0x20);
213 auto tile16_y = (painter_y % kSmallMapSize) / (kSmallMapSize / 0x20);
215 int index_x = super_x * 0x20 + tile16_x;
216 int index_y = super_y * 0x20 + tile16_y;
218 event.tile_position =
219 ImVec2(
static_cast<float>(index_x),
static_cast<float>(index_y));
220 event.is_valid =
true;
230 float tile_size, ImGuiMouseButton mouse_button) {
239 const float scaled_size =
242 ImVec2 paint_pos =
AlignToGrid(mouse_pos, scaled_size);
243 event.position = mouse_pos;
244 event.grid_position = paint_pos;
247 if (ImGui::IsMouseClicked(mouse_button)) {
248 event.is_complete =
true;
249 event.is_drag =
false;
250 }
else if (ImGui::IsMouseDragging(mouse_button)) {
251 event.is_complete =
true;
252 event.is_drag =
true;
261 ImDrawList* draw_list,
262 ImGuiMouseButton mouse_button) {
270 const float scaled_size =
274 ImVec2 paint_pos =
AlignToGrid(mouse_pos, scaled_size);
275 event.position = mouse_pos;
276 event.grid_position = paint_pos;
279 ImVec2(paint_pos.x + scaled_size, paint_pos.y + scaled_size);
286 reinterpret_cast<ImTextureID
>(bitmap.
texture()),
287 ImVec2(origin.x + paint_pos.x, origin.y + paint_pos.y),
288 ImVec2(origin.x + paint_pos_end.x, origin.y + paint_pos_end.y));
292 if (ImGui::IsMouseClicked(mouse_button) &&
293 ImGui::IsMouseDragging(mouse_button)) {
294 event.is_complete =
true;
295 event.is_drag =
true;
303 ImDrawList* draw_list,
304 ImGuiMouseButton mouse_button) {
313 const float scaled_size =
316 ImVec2 paint_pos =
AlignToGrid(mouse_pos, scaled_size);
317 event.position = mouse_pos;
318 event.grid_position = paint_pos;
329 if (ImGui::IsMouseDown(mouse_button)) {
330 event.is_complete =
true;
331 event.is_drag = ImGui::IsMouseDragging(mouse_button);
349 const float scaled_size =
352 event.position = mouse_pos;
353 event.grid_position =
AlignToGrid(mouse_pos, scaled_size);
354 event.is_valid =
true;
360 float tile_size, ImDrawList* draw_list, ImU32 color) {
361 if (!hover.
is_valid || !draw_list) {
365 const float scaled_size =
370 ImVec2 preview_start = ImVec2(origin.x + hover.
grid_position.x,
373 ImVec2(preview_start.x + scaled_size, preview_start.y + scaled_size);
375 draw_list->AddRectFilled(preview_start, preview_end, color);
384 ImVec2 entity_position) {
387 event.position = entity_position;
Free functions for canvas interaction handling.
Represents a bitmap image optimized for SNES ROM hacking.
TextureHandle texture() const
thread_local SelectRectState g_select_rect_state
void RenderHoverPreview(const CanvasGeometry &geometry, const HoverEvent &hover, float tile_size, ImDrawList *draw_list, ImU32 color)
Render hover preview overlay.
TilePaintEvent HandleTilePaintWithPreview(const CanvasGeometry &geometry, const gfx::Bitmap &bitmap, float tile_size, ImDrawList *draw_list, ImGuiMouseButton mouse_button)
Handle tile painter with bitmap preview.
TileSelectionEvent HandleTileSelection(const CanvasGeometry &geometry, int current_map, float tile_size, ImGuiMouseButton mouse_button)
Handle single tile selection (right-click)
ImVec2 CanvasToTileGrid(ImVec2 canvas_pos, float tile_size, float global_scale)
Calculate tile grid indices from canvas position.
TilePaintEvent HandleTilePaint(const CanvasGeometry &geometry, int tile_id, float tile_size, ImGuiMouseButton mouse_button)
Handle tile painting interaction.
ImVec2 GetMouseInCanvasSpace(const CanvasGeometry &geometry)
Get mouse position in canvas space.
ImVec2 AlignToGrid(ImVec2 pos, float grid_step)
Align position to grid.
HoverEvent HandleHover(const CanvasGeometry &geometry, float tile_size)
Update hover state for canvas.
RectSelectionEvent HandleRectangleSelection(const CanvasGeometry &geometry, int current_map, float tile_size, ImDrawList *draw_list, ImGuiMouseButton mouse_button)
Handle rectangle selection interaction.
TilePaintEvent HandleTilemapPaint(const CanvasGeometry &geometry, const gfx::Tilemap &tilemap, int current_tile, ImDrawList *draw_list, ImGuiMouseButton mouse_button)
Handle tilemap painting interaction.
EntityInteractionEvent HandleEntityInteraction(const CanvasGeometry &geometry, int entity_id, ImVec2 entity_position)
Handle entity interaction (hover, click, drag)
bool IsMouseInCanvas(const CanvasGeometry &geometry)
Check if mouse is in canvas bounds.
Tilemap structure for SNES tile-based graphics management.
Bitmap atlas
Master bitmap containing all tiles.
Canvas geometry calculated per-frame.
Event payload for entity interactions.
int entity_id
Entity being interacted with.
Event payload for hover preview.
bool is_valid
True if hovering over canvas.
ImVec2 grid_position
Grid-aligned hover position.
Event payload for rectangle selection operations.
int current_map
Map ID for coordinate calculation.
Event payload for tile painting operations.
int tile_id
Tile ID being painted (-1 if none)
Event payload for single tile selection.