yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
canvas_runtime_draw.cc
Go to the documentation of this file.
2
3#include <algorithm>
4#include <cmath>
5
11#include "imgui/imgui.h"
12
13namespace yaze::gui {
14
15namespace {
17 CanvasGeometry geom;
18 geom.canvas_p0 = rt.canvas_p0;
19 geom.canvas_sz = rt.canvas_sz;
20 geom.scrolling = rt.scrolling;
21 geom.scaled_size =
22 ImVec2(rt.canvas_sz.x * rt.scale, rt.canvas_sz.y * rt.scale);
23 geom.canvas_p1 = ImVec2(geom.canvas_p0.x + geom.canvas_sz.x,
24 geom.canvas_p0.y + geom.canvas_sz.y);
25 return geom;
26}
27
28ImVec2 AlignPosToGridHelper(ImVec2 pos, float scale) {
29 return ImVec2(std::floor(pos.x / scale) * scale,
30 std::floor(pos.y / scale) * scale);
31}
32} // namespace
33
34void DrawBitmap(const CanvasRuntime& rt, gfx::Bitmap& bitmap, int border_offset,
35 float scale) {
36 if (!rt.draw_list)
37 return;
38 CanvasGeometry geom = GetGeometryFromRuntime(rt);
39 RenderBitmapOnCanvas(rt.draw_list, geom, bitmap, border_offset, scale);
40}
41
42void DrawBitmap(const CanvasRuntime& rt, gfx::Bitmap& bitmap, int x_offset,
43 int y_offset, float scale, int alpha) {
44 if (!rt.draw_list)
45 return;
46 CanvasGeometry geom = GetGeometryFromRuntime(rt);
47 RenderBitmapOnCanvas(rt.draw_list, geom, bitmap, x_offset, y_offset, scale,
48 alpha);
49}
50
51void DrawBitmap(const CanvasRuntime& rt, gfx::Bitmap& bitmap, ImVec2 dest_pos,
52 ImVec2 dest_size, ImVec2 src_pos, ImVec2 src_size) {
53 if (!rt.draw_list)
54 return;
55 CanvasGeometry geom = GetGeometryFromRuntime(rt);
56 RenderBitmapOnCanvas(rt.draw_list, geom, bitmap, dest_pos, dest_size, src_pos,
57 src_size);
58}
59
60void DrawBitmap(const CanvasRuntime& rt, gfx::Bitmap& bitmap,
61 const BitmapDrawOpts& opts) {
62 if (!rt.draw_list)
63 return;
64
65 if (opts.ensure_texture && !bitmap.texture() && bitmap.surface()) {
68 }
69
70 if (opts.dest_size.x > 0 && opts.dest_size.y > 0) {
71 ImVec2 src_size = opts.src_size;
72 if (src_size.x <= 0 || src_size.y <= 0) {
73 src_size = ImVec2(static_cast<float>(bitmap.width()),
74 static_cast<float>(bitmap.height()));
75 }
76 DrawBitmap(rt, bitmap, opts.dest_pos, opts.dest_size, opts.src_pos,
77 src_size);
78 } else {
79 DrawBitmap(rt, bitmap, static_cast<int>(opts.dest_pos.x),
80 static_cast<int>(opts.dest_pos.y), opts.scale, opts.alpha);
81 }
82}
83
85 const BitmapPreviewOptions& options) {
86 if (options.ensure_texture && !bitmap.texture() && bitmap.surface()) {
89 }
90
91 if (options.dest_size.x > 0 && options.dest_size.y > 0) {
92 ImVec2 src_size = options.src_size;
93 if (src_size.x <= 0 || src_size.y <= 0) {
94 src_size = ImVec2(bitmap.width(), bitmap.height());
95 }
96 DrawBitmap(rt, bitmap, options.dest_pos, options.dest_size, options.src_pos,
97 src_size);
98 } else {
99 DrawBitmap(rt, bitmap, static_cast<int>(options.dest_pos.x),
100 static_cast<int>(options.dest_pos.y), options.scale,
101 options.alpha);
102 }
103}
104
106 const PreviewPanelOpts& opts) {
107 if (!rt.draw_list)
108 return false;
109
110 if (opts.ensure_texture && !bmp.texture() && bmp.surface()) {
113 }
114
115 if (opts.dest_size.x > 0 && opts.dest_size.y > 0) {
116 DrawBitmap(rt, bmp, opts.dest_pos, opts.dest_size, ImVec2(0, 0),
117 ImVec2(static_cast<float>(bmp.width()),
118 static_cast<float>(bmp.height())));
119 } else {
120 DrawBitmap(rt, bmp, static_cast<int>(opts.dest_pos.x),
121 static_cast<int>(opts.dest_pos.y), 1.0f, 255);
122 }
123 return true;
124}
125
126void DrawRect(const CanvasRuntime& rt, int x, int y, int w, int h,
127 ImVec4 color) {
128 if (!rt.draw_list)
129 return;
131 h, color, rt.scale);
132}
133
134void DrawText(const CanvasRuntime& rt, const std::string& text, int x, int y) {
135 if (!rt.draw_list)
136 return;
138 y, rt.scale);
139}
140
141void DrawOutline(const CanvasRuntime& rt, int x, int y, int w, int h,
142 ImU32 color) {
143 if (!rt.draw_list)
144 return;
146 w, h, color);
147}
148
150 int current_tile, ImVec2* out_drawn_pos) {
151 if (!rt.draw_list)
152 return false;
153
154 const ImGuiIO& io = ImGui::GetIO();
155 const ImVec2 origin(rt.canvas_p0.x + rt.scrolling.x,
156 rt.canvas_p0.y + rt.scrolling.y);
157 const ImVec2 mouse_pos(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
158
159 if (!tilemap.atlas.is_active() || tilemap.tile_size.x <= 0) {
160 return false;
161 }
162
163 const float scaled_size = tilemap.tile_size.x * rt.scale;
164
165 if (!rt.hovered) {
166 return false;
167 }
168
169 ImVec2 paint_pos = AlignPosToGridHelper(mouse_pos, scaled_size);
170
171 if (tilemap.atlas.is_active() && tilemap.atlas.texture()) {
172 int tiles_per_row = tilemap.atlas.width() / tilemap.tile_size.x;
173 if (tiles_per_row > 0) {
174 int tile_x = (current_tile % tiles_per_row) * tilemap.tile_size.x;
175 int tile_y = (current_tile / tiles_per_row) * tilemap.tile_size.y;
176
177 if (tile_x >= 0 && tile_x < tilemap.atlas.width() && tile_y >= 0 &&
178 tile_y < tilemap.atlas.height()) {
179 ImVec2 uv0 =
180 ImVec2(static_cast<float>(tile_x) / tilemap.atlas.width(),
181 static_cast<float>(tile_y) / tilemap.atlas.height());
182 ImVec2 uv1 = ImVec2(static_cast<float>(tile_x + tilemap.tile_size.x) /
183 tilemap.atlas.width(),
184 static_cast<float>(tile_y + tilemap.tile_size.y) /
185 tilemap.atlas.height());
186
187 rt.draw_list->AddImage(
188 (ImTextureID)(intptr_t)tilemap.atlas.texture(),
189 ImVec2(origin.x + paint_pos.x, origin.y + paint_pos.y),
190 ImVec2(origin.x + paint_pos.x + scaled_size,
191 origin.y + paint_pos.y + scaled_size),
192 uv0, uv1);
193 }
194 }
195 }
196
197 if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) ||
198 ImGui::IsMouseDragging(ImGuiMouseButton_Left)) {
199 if (out_drawn_pos)
200 *out_drawn_pos = paint_pos;
201 return true;
202 }
203
204 return false;
205}
206
207bool DrawTileSelector(const CanvasRuntime& rt, int size, int size_y,
208 ImVec2* out_selected_pos) {
209 const ImGuiIO& io = ImGui::GetIO();
210 const ImVec2 origin(rt.canvas_p0.x + rt.scrolling.x,
211 rt.canvas_p0.y + rt.scrolling.y);
212 const ImVec2 mouse_pos(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
213
214 if (size_y == 0) {
215 size_y = size;
216 }
217
218 if (rt.hovered && ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
219 ImVec2 painter_pos =
220 AlignPosToGridHelper(mouse_pos, static_cast<float>(size));
221 if (out_selected_pos)
222 *out_selected_pos = painter_pos;
223 }
224
225 if (rt.hovered && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
226 return true;
227 }
228
229 return false;
230}
231
232void DrawSelectRect(const CanvasRuntime& rt, int current_map, int tile_size,
233 float scale, CanvasSelection& selection) {
234 if (!rt.draw_list)
235 return;
236
237 const ImGuiIO& io = ImGui::GetIO();
238 const ImVec2 origin(rt.canvas_p0.x + rt.scrolling.x,
239 rt.canvas_p0.y + rt.scrolling.y);
240 const ImVec2 mouse_pos(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
241 static ImVec2 drag_start_pos;
242 const float scaled_size = tile_size * scale;
243 static bool dragging = false;
244 constexpr int small_map_size = 0x200;
245 constexpr uint32_t kWhite = IM_COL32(255, 255, 255, 255);
246
247 if (!rt.hovered) {
248 return;
249 }
250
251 int superY, superX;
252 if (current_map < 0x40) {
253 superY = current_map / 8;
254 superX = current_map % 8;
255 } else if (current_map < 0x80) {
256 superY = (current_map - 0x40) / 8;
257 superX = (current_map - 0x40) % 8;
258 } else {
259 superY = (current_map - 0x80) / 8;
260 superX = (current_map - 0x80) % 8;
261 }
262
263 if (ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
264 ImVec2 painter_pos = AlignPosToGridHelper(mouse_pos, scaled_size);
265 int world_x = static_cast<int>(painter_pos.x / scale);
266 int world_y = static_cast<int>(painter_pos.y / scale);
267
268 auto tile16_x = (world_x % small_map_size) / (small_map_size / 0x20);
269 auto tile16_y = (world_y % small_map_size) / (small_map_size / 0x20);
270
271 int index_x = superX * 0x20 + tile16_x;
272 int index_y = superY * 0x20 + tile16_y;
273 selection.selected_tile_pos =
274 ImVec2(static_cast<float>(index_x), static_cast<float>(index_y));
275 selection.selected_points.clear();
276 selection.select_rect_active = false;
277
278 drag_start_pos = AlignPosToGridHelper(mouse_pos, scaled_size);
279 }
280
281 ImVec2 drag_end_pos = AlignPosToGridHelper(mouse_pos, scaled_size);
282 if (ImGui::IsMouseDragging(ImGuiMouseButton_Right)) {
283 auto start =
284 ImVec2(origin.x + drag_start_pos.x, origin.y + drag_start_pos.y);
285 auto end = ImVec2(origin.x + drag_end_pos.x + scaled_size,
286 origin.y + drag_end_pos.y + scaled_size);
287 rt.draw_list->AddRect(start, end, kWhite);
288 dragging = true;
289 }
290
291 if (dragging && !ImGui::IsMouseDown(ImGuiMouseButton_Right)) {
292 dragging = false;
293
294 constexpr int tile16_size = 16;
295 int start_x = static_cast<int>(std::floor(drag_start_pos.x / scaled_size)) *
296 tile16_size;
297 int start_y = static_cast<int>(std::floor(drag_start_pos.y / scaled_size)) *
298 tile16_size;
299 int end_x = static_cast<int>(std::floor(drag_end_pos.x / scaled_size)) *
300 tile16_size;
301 int end_y = static_cast<int>(std::floor(drag_end_pos.y / scaled_size)) *
302 tile16_size;
303
304 if (start_x > end_x)
305 std::swap(start_x, end_x);
306 if (start_y > end_y)
307 std::swap(start_y, end_y);
308
309 selection.selected_tiles.clear();
310 selection.selected_tiles.reserve(
311 static_cast<size_t>(((end_x - start_x) / tile16_size + 1) *
312 ((end_y - start_y) / tile16_size + 1)));
313
314 constexpr int tiles_per_local_map = small_map_size / 16;
315
316 for (int y = start_y; y <= end_y; y += tile16_size) {
317 for (int x = start_x; x <= end_x; x += tile16_size) {
318 int local_map_x = (x / small_map_size) % 8;
319 int local_map_y = (y / small_map_size) % 8;
320 int tile16_x = (x % small_map_size) / tile16_size;
321 int tile16_y = (y % small_map_size) / tile16_size;
322 int index_x = local_map_x * tiles_per_local_map + tile16_x;
323 int index_y = local_map_y * tiles_per_local_map + tile16_y;
324 selection.selected_tiles.emplace_back(static_cast<float>(index_x),
325 static_cast<float>(index_y));
326 }
327 }
328
329 selection.selected_points.clear();
330 selection.selected_points.push_back(
331 ImVec2(drag_start_pos.x / scale, drag_start_pos.y / scale));
332 selection.selected_points.push_back(
333 ImVec2(drag_end_pos.x / scale, drag_end_pos.y / scale));
334 selection.select_rect_active = true;
335 }
336}
337
338} // namespace yaze::gui
void QueueTextureCommand(TextureCommandType type, Bitmap *bitmap)
Definition arena.cc:36
static Arena & Get()
Definition arena.cc:21
Represents a bitmap image optimized for SNES ROM hacking.
Definition bitmap.h:67
TextureHandle texture() const
Definition bitmap.h:401
bool is_active() const
Definition bitmap.h:405
int height() const
Definition bitmap.h:395
int width() const
Definition bitmap.h:394
SDL_Surface * surface() const
Definition bitmap.h:400
void DrawCanvasRect(ImDrawList *draw_list, ImVec2 canvas_p0, ImVec2 scrolling, int x, int y, int w, int h, ImVec4 color, float global_scale)
void DrawCanvasOutline(ImDrawList *draw_list, ImVec2 canvas_p0, ImVec2 scrolling, int x, int y, int w, int h, uint32_t color)
void DrawCanvasText(ImDrawList *draw_list, ImVec2 canvas_p0, ImVec2 scrolling, const std::string &text, int x, int y, float global_scale)
CanvasGeometry GetGeometryFromRuntime(const CanvasRuntime &rt)
Graphical User Interface (GUI) components for the application.
void DrawBitmapPreview(const CanvasRuntime &rt, gfx::Bitmap &bitmap, const BitmapPreviewOptions &options)
bool DrawTileSelector(const CanvasRuntime &rt, int size, int size_y, ImVec2 *out_selected_pos)
bool DrawTilemapPainter(const CanvasRuntime &rt, gfx::Tilemap &tilemap, int current_tile, ImVec2 *out_drawn_pos)
void DrawRect(const CanvasRuntime &rt, int x, int y, int w, int h, ImVec4 color)
void DrawBitmap(const CanvasRuntime &rt, gfx::Bitmap &bitmap, int border_offset=2, float scale=1.0f)
void DrawOutline(const CanvasRuntime &rt, int x, int y, int w, int h, ImU32 color=IM_COL32(255, 255, 255, 200))
void DrawText(const CanvasRuntime &rt, const std::string &text, int x, int y)
void RenderBitmapOnCanvas(ImDrawList *draw_list, const CanvasGeometry &geometry, gfx::Bitmap &bitmap, int, float scale)
Render bitmap on canvas (border offset variant)
void DrawSelectRect(const CanvasRuntime &rt, int current_map, int tile_size, float scale, CanvasSelection &selection)
bool RenderPreviewPanel(const CanvasRuntime &rt, gfx::Bitmap &bmp, const PreviewPanelOpts &opts)
int y
Y coordinate or height.
Definition tilemap.h:21
int x
X coordinate or width.
Definition tilemap.h:20
Tilemap structure for SNES tile-based graphics management.
Definition tilemap.h:118
Pair tile_size
Size of individual tiles (8x8 or 16x16)
Definition tilemap.h:123
Bitmap atlas
Master bitmap containing all tiles.
Definition tilemap.h:119
Canvas geometry calculated per-frame.
Selection state for canvas interactions.
std::vector< ImVec2 > selected_tiles
std::vector< ImVec2 > selected_points