6#include "imgui/imgui.h"
16 ImVec2 drag_start_pos = ImVec2(-1, -1);
17 bool is_dragging =
false;
30 return ImVec2(std::floor(pos.x / grid_step) * grid_step,
31 std::floor(pos.y / grid_step) * grid_step);
35 const ImGuiIO& imgui_io = ImGui::GetIO();
38 return ImVec2(imgui_io.MousePos.x - origin.x, imgui_io.MousePos.y - origin.y);
42 const ImGuiIO& imgui_io = ImGui::GetIO();
43 return imgui_io.MousePos.x >= geometry.
canvas_p0.x &&
44 imgui_io.MousePos.x <= geometry.
canvas_p1.x &&
45 imgui_io.MousePos.y >= geometry.
canvas_p0.y &&
46 imgui_io.MousePos.y <= geometry.
canvas_p1.y;
51 const float scaled_size = tile_size * global_scale;
52 return ImVec2(std::floor(canvas_pos.x / scaled_size),
53 std::floor(canvas_pos.y / scaled_size));
61 int current_map,
float tile_size,
62 ImDrawList* draw_list,
63 ImGuiMouseButton mouse_button) {
72 const float scaled_size =
74 constexpr int kSmallMapSize = 0x200;
79 if (current_map < 0x40) {
81 super_y = current_map / 8;
82 super_x = current_map % 8;
83 }
else if (current_map < 0x80) {
85 super_y = (current_map - 0x40) / 8;
86 super_x = (current_map - 0x40) % 8;
89 super_y = (current_map - 0x80) / 8;
90 super_x = (current_map - 0x80) % 8;
94 if (ImGui::IsMouseClicked(mouse_button)) {
99 ImVec2 painter_pos =
AlignToGrid(mouse_pos, scaled_size);
100 int painter_x =
static_cast<int>(painter_pos.x);
101 int painter_y =
static_cast<int>(painter_pos.y);
103 auto tile16_x = (painter_x % kSmallMapSize) / (kSmallMapSize / 0x20);
104 auto tile16_y = (painter_y % kSmallMapSize) / (kSmallMapSize / 0x20);
106 int index_x = super_x * 0x20 + tile16_x;
107 int index_y = super_y * 0x20 + tile16_y;
109 event.start_pos = painter_pos;
110 event.selected_tiles.push_back(
111 ImVec2(
static_cast<float>(index_x),
static_cast<float>(index_y)));
115 ImVec2 drag_end_pos =
AlignToGrid(mouse_pos, scaled_size);
116 if (ImGui::IsMouseDragging(mouse_button) && draw_list) {
118 event.is_active =
true;
120 event.end_pos = drag_end_pos;
126 auto end = ImVec2(geometry.
canvas_p0.x + drag_end_pos.x + tile_size,
127 geometry.
canvas_p0.y + drag_end_pos.y + tile_size);
128 draw_list->AddRect(start, end, IM_COL32(255, 255, 255, 255));
132 if (g_select_rect_state.
is_dragging && !ImGui::IsMouseDown(mouse_button)) {
134 event.is_complete =
true;
135 event.is_active =
false;
137 event.end_pos = drag_end_pos;
140 constexpr int kTile16Size = 16;
141 int start_x =
static_cast<int>(std::floor(
144 int start_y =
static_cast<int>(std::floor(
147 int end_x =
static_cast<int>(std::floor(drag_end_pos.x / scaled_size)) *
149 int end_y =
static_cast<int>(std::floor(drag_end_pos.y / scaled_size)) *
153 std::swap(start_x, end_x);
155 std::swap(start_y, end_y);
157 constexpr int kTilesPerLocalMap = kSmallMapSize / 16;
159 for (
int tile_y = start_y; tile_y <= end_y; tile_y += kTile16Size) {
160 for (
int tile_x = start_x; tile_x <= end_x; tile_x += kTile16Size) {
161 int local_map_x = tile_x / kSmallMapSize;
162 int local_map_y = tile_y / kSmallMapSize;
164 int tile16_x = (tile_x % kSmallMapSize) / kTile16Size;
165 int tile16_y = (tile_y % kSmallMapSize) / kTile16Size;
167 int index_x = local_map_x * kTilesPerLocalMap + tile16_x;
168 int index_y = local_map_y * kTilesPerLocalMap + tile16_y;
170 event.selected_tiles.emplace_back(
static_cast<float>(index_x),
171 static_cast<float>(index_y));
180 int current_map,
float tile_size,
181 ImGuiMouseButton mouse_button) {
184 if (!
IsMouseInCanvas(geometry) || !ImGui::IsMouseClicked(mouse_button)) {
189 const float scaled_size =
191 constexpr int kSmallMapSize = 0x200;
196 if (current_map < 0x40) {
197 super_y = current_map / 8;
198 super_x = current_map % 8;
199 }
else if (current_map < 0x80) {
200 super_y = (current_map - 0x40) / 8;
201 super_x = (current_map - 0x40) % 8;
203 super_y = (current_map - 0x80) / 8;
204 super_x = (current_map - 0x80) % 8;
207 ImVec2 painter_pos =
AlignToGrid(mouse_pos, scaled_size);
208 int painter_x =
static_cast<int>(painter_pos.x);
209 int painter_y =
static_cast<int>(painter_pos.y);
211 auto tile16_x = (painter_x % kSmallMapSize) / (kSmallMapSize / 0x20);
212 auto tile16_y = (painter_y % kSmallMapSize) / (kSmallMapSize / 0x20);
214 int index_x = super_x * 0x20 + tile16_x;
215 int index_y = super_y * 0x20 + tile16_y;
217 event.tile_position =
218 ImVec2(
static_cast<float>(index_x),
static_cast<float>(index_y));
219 event.is_valid =
true;
229 float tile_size, ImGuiMouseButton mouse_button) {
238 const float scaled_size =
241 ImVec2 paint_pos =
AlignToGrid(mouse_pos, scaled_size);
242 event.position = mouse_pos;
243 event.grid_position = paint_pos;
246 if (ImGui::IsMouseClicked(mouse_button)) {
247 event.is_complete =
true;
248 event.is_drag =
false;
249 }
else if (ImGui::IsMouseDragging(mouse_button)) {
250 event.is_complete =
true;
251 event.is_drag =
true;
260 ImDrawList* draw_list,
261 ImGuiMouseButton mouse_button) {
269 const float scaled_size =
273 ImVec2 paint_pos =
AlignToGrid(mouse_pos, scaled_size);
274 event.position = mouse_pos;
275 event.grid_position = paint_pos;
278 ImVec2(paint_pos.x + scaled_size, paint_pos.y + scaled_size);
285 reinterpret_cast<ImTextureID
>(bitmap.
texture()),
286 ImVec2(origin.x + paint_pos.x, origin.y + paint_pos.y),
287 ImVec2(origin.x + paint_pos_end.x, origin.y + paint_pos_end.y));
291 if (ImGui::IsMouseClicked(mouse_button) &&
292 ImGui::IsMouseDragging(mouse_button)) {
293 event.is_complete =
true;
294 event.is_drag =
true;
302 ImDrawList* draw_list,
303 ImGuiMouseButton mouse_button) {
312 const float scaled_size =
315 ImVec2 paint_pos =
AlignToGrid(mouse_pos, scaled_size);
316 event.position = mouse_pos;
317 event.grid_position = paint_pos;
323 if (ImGui::IsMouseDown(mouse_button)) {
324 event.is_complete =
true;
325 event.is_drag = ImGui::IsMouseDragging(mouse_button);
343 const float scaled_size =
346 event.position = mouse_pos;
347 event.grid_position =
AlignToGrid(mouse_pos, scaled_size);
348 event.is_valid =
true;
354 float tile_size, ImDrawList* draw_list, ImU32 color) {
355 if (!hover.
is_valid || !draw_list) {
359 const float scaled_size =
364 ImVec2 preview_start = ImVec2(origin.x + hover.
grid_position.x,
367 ImVec2(preview_start.x + scaled_size, preview_start.y + scaled_size);
369 draw_list->AddRectFilled(preview_start, preview_end, color);
378 ImVec2 entity_position) {
381 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.
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.