yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
coordinate_mapper.cc
Go to the documentation of this file.
2
3#include <algorithm>
4#include <cmath>
5
7
8namespace yaze {
9namespace gui {
10
12 float screen_y) const {
13 ScreenToTileResult result;
14 result.screen_x = screen_x;
15 result.screen_y = screen_y;
16
17 // Step 1: Check if within canvas bounds
18 result.in_canvas_bounds = IsInCanvasBounds(screen_x, screen_y);
19
20 // Step 2: Convert to canvas-relative coordinates
21 result.canvas_x = screen_x - geometry_.canvas_p0.x;
22 result.canvas_y = screen_y - geometry_.canvas_p0.y;
23
24 // Step 3: Apply inverse scale (for zoomed canvases)
25 ImVec2 scaled = ApplyInverseScale(result.canvas_x, result.canvas_y);
26 result.scaled_x = scaled.x;
27 result.scaled_y = scaled.y;
28
29 // Step 4: Apply scroll offset to get content position
30 ImVec2 content = ApplyScrollOffset(result.scaled_x, result.scaled_y);
31 result.content_x = content.x;
32 result.content_y = content.y;
33
34 // Step 5: Get tile information
35 if (result.in_canvas_bounds && result.content_x >= 0 && result.content_y >= 0) {
36 result.tile_info = CanvasToTile(result.content_x, result.content_y);
38 }
39
40 return result;
41}
42
44 float canvas_y) const {
45 TileHitInfo info;
46
47 // Snap to tile grid
48 auto [tile_x, tile_y] = SnapToTileGrid(canvas_x, canvas_y);
49
50 // Validate tile coordinates
51 if (!IsValidTileCoord(tile_x, tile_y)) {
52 info.is_valid = false;
53 return info;
54 }
55
56 info.map_x = tile_x;
57 info.map_y = tile_y;
58 info.is_valid = true;
59
60 // Calculate tile IDs
61 info.tile_id = GetTileId(canvas_x, canvas_y);
62
63 if (config_.use_tile16) {
64 info.tile16_index = GetTile16Index(canvas_x, canvas_y);
65 }
66
67 // Calculate tile origin in canvas space
68 info.tile_origin_px = ImVec2(tile_x * config_.tile_size,
69 tile_y * config_.tile_size);
71
72 // Calculate local map ID (for overworld)
73 if (config_.local_map_size > 0) {
74 info.local_map_id = CalculateLocalMapId(canvas_x, canvas_y);
75 }
76
77 // Calculate ROM offset
80 } else {
82 }
83
84 return info;
85}
86
87ImVec2 CoordinateMapper::TileToCanvas(int tile_x, int tile_y) const {
88 float x = tile_x * config_.tile_size - geometry_.scrolling.x;
89 float y = tile_y * config_.tile_size - geometry_.scrolling.y;
90 return ImVec2(x * scale_, y * scale_);
91}
92
93ImVec2 CoordinateMapper::TileToScreen(int tile_x, int tile_y) const {
94 ImVec2 canvas_pos = TileToCanvas(tile_x, tile_y);
95 return ImVec2(geometry_.canvas_p0.x + canvas_pos.x,
96 geometry_.canvas_p0.y + canvas_pos.y);
97}
98
99int CoordinateMapper::GetTileId(float canvas_x, float canvas_y) const {
100 if (config_.tile_size <= 0 || config_.tiles_per_row <= 0) {
101 return -1;
102 }
103
104 int tile_x = static_cast<int>(canvas_x / config_.tile_size);
105 int tile_y = static_cast<int>(canvas_y / config_.tile_size);
106
107 if (!IsValidTileCoord(tile_x, tile_y)) {
108 return -1;
109 }
110
111 return tile_y * config_.tiles_per_row + tile_x;
112}
113
114int CoordinateMapper::GetTile16Index(float canvas_x, float canvas_y) const {
115 // Tile16 uses 16x16 tiles regardless of the base tile size
116 const float tile16_size = 16.0f;
117 int tile16_per_row = config_.tiles_per_row;
118
119 if (config_.tile_size == 8.0f) {
120 // If using 8x8 tiles, tile16 has half the tiles per row
121 tile16_per_row = config_.tiles_per_row / 2;
122 }
123
124 int tile_x = static_cast<int>(canvas_x / tile16_size);
125 int tile_y = static_cast<int>(canvas_y / tile16_size);
126
127 if (tile_x < 0 || tile_y < 0 || tile_x >= tile16_per_row) {
128 return -1;
129 }
130
131 return tile_y * tile16_per_row + tile_x;
132}
133
134bool CoordinateMapper::IsInCanvasBounds(float screen_x, float screen_y) const {
135 return screen_x >= geometry_.canvas_p0.x &&
136 screen_x < geometry_.canvas_p1.x &&
137 screen_y >= geometry_.canvas_p0.y &&
138 screen_y < geometry_.canvas_p1.y;
139}
140
141bool CoordinateMapper::IsValidTileCoord(int tile_x, int tile_y) const {
142 return tile_x >= 0 && tile_y >= 0 &&
143 tile_x < config_.tiles_per_row &&
144 tile_y < config_.tiles_per_col;
145}
146
148 uint32_t base_offset) const {
149 if (tile_id < 0) {
150 return 0;
151 }
152
153 // Default calculation: assumes contiguous tile data
154 // Each tile16 is 8 bytes (4 tile references)
155 // Each tile8 in 4BPP is 32 bytes
156 if (config_.use_tile16) {
157 return base_offset + (tile_id * 8);
158 } else {
159 return base_offset + (tile_id * 32);
160 }
161}
162
164 float content_y) const {
165 if (config_.local_map_size <= 0) {
166 return -1;
167 }
168
169 int local_x = static_cast<int>(content_x / config_.local_map_size);
170 int local_y = static_cast<int>(content_y / config_.local_map_size);
171
172 // Standard overworld layout: 8 maps wide
173 const int maps_per_row = 8;
174 return local_y * maps_per_row + local_x;
175}
176
177std::vector<ScreenToTileResult> CoordinateMapper::ScreenToTileBatch(
178 const std::vector<std::pair<float, float>>& positions) const {
179 std::vector<ScreenToTileResult> results;
180 results.reserve(positions.size());
181
182 for (const auto& [x, y] : positions) {
183 results.push_back(ScreenToTile(x, y));
184 }
185
186 return results;
187}
188
190 float canvas_y) const {
191 return ImVec2(canvas_x - geometry_.scrolling.x,
192 canvas_y - geometry_.scrolling.y);
193}
194
195ImVec2 CoordinateMapper::ApplyInverseScale(float x, float y) const {
196 if (scale_ <= 0.0f) {
197 return ImVec2(x, y);
198 }
199 return ImVec2(x / scale_, y / scale_);
200}
201
202std::pair<int, int> CoordinateMapper::SnapToTileGrid(float x, float y) const {
203 if (config_.tile_size <= 0) {
204 return {-1, -1};
205 }
206
207 int tile_x = static_cast<int>(std::floor(x / config_.tile_size));
208 int tile_y = static_cast<int>(std::floor(y / config_.tile_size));
209 return {tile_x, tile_y};
210}
211
212// --- Free Functions ---
213
215 float screen_x, float screen_y,
216 float tile_size) {
217 TileHitInfo info;
218
219 // Check bounds
220 if (screen_x < runtime.canvas_p0.x || screen_x >= runtime.canvas_p0.x + runtime.canvas_sz.x ||
221 screen_y < runtime.canvas_p0.y || screen_y >= runtime.canvas_p0.y + runtime.canvas_sz.y) {
222 info.is_valid = false;
223 return info;
224 }
225
226 // Convert to canvas-relative coordinates
227 float canvas_x = screen_x - runtime.canvas_p0.x;
228 float canvas_y = screen_y - runtime.canvas_p0.y;
229
230 // Apply inverse scale
231 float scale = runtime.scale > 0 ? runtime.scale : 1.0f;
232 float scaled_x = canvas_x / scale;
233 float scaled_y = canvas_y / scale;
234
235 // Apply scroll offset
236 float content_x = scaled_x - runtime.scrolling.x;
237 float content_y = scaled_y - runtime.scrolling.y;
238
239 // Calculate tile coordinates
240 if (content_x < 0 || content_y < 0 || tile_size <= 0) {
241 info.is_valid = false;
242 return info;
243 }
244
245 int tile_x = static_cast<int>(content_x / tile_size);
246 int tile_y = static_cast<int>(content_y / tile_size);
247
248 // Calculate tile ID (assuming 32 tiles per row as default)
249 int tiles_per_row = static_cast<int>(runtime.canvas_sz.x / (tile_size * scale));
250 if (tiles_per_row <= 0) tiles_per_row = 32;
251
252 info.map_x = tile_x;
253 info.map_y = tile_y;
254 info.tile_id = tile_y * tiles_per_row + tile_x;
255 info.tile_origin_px = ImVec2(tile_x * tile_size, tile_y * tile_size);
256 info.tile_size_px = ImVec2(tile_size, tile_size);
257 info.is_valid = true;
258
259 return info;
260}
261
262int CalculateTileIndex(float local_x, float local_y,
263 float tile_size, int tiles_per_row) {
264 if (tile_size <= 0 || tiles_per_row <= 0) {
265 return -1;
266 }
267
268 int tile_x = static_cast<int>(local_x / tile_size);
269 int tile_y = static_cast<int>(local_y / tile_size);
270
271 if (tile_x < 0 || tile_y < 0 || tile_x >= tiles_per_row) {
272 return -1;
273 }
274
275 return tile_y * tiles_per_row + tile_x;
276}
277
278ImVec4 GetTileBounds(int tile_x, int tile_y, float tile_size, float scale) {
279 float x = tile_x * tile_size * scale;
280 float y = tile_y * tile_size * scale;
281 float w = tile_size * scale;
282 float h = tile_size * scale;
283 return ImVec4(x, y, x + w, y + h);
284}
285
286} // namespace gui
287} // namespace yaze
bool IsInCanvasBounds(float screen_x, float screen_y) const
Check if screen coordinates are within canvas bounds.
int GetTileId(float canvas_x, float canvas_y) const
Get tile ID from canvas position.
std::pair< int, int > SnapToTileGrid(float x, float y) const
ImVec2 TileToScreen(int tile_x, int tile_y) const
Convert tile coordinates to screen position.
ImVec2 ApplyInverseScale(float x, float y) const
ScreenToTileResult ScreenToTile(float screen_x, float screen_y) const
Convert screen coordinates to tile information.
std::vector< ScreenToTileResult > ScreenToTileBatch(const std::vector< std::pair< float, float > > &positions) const
Convert multiple screen positions to tile info.
TileHitInfo CanvasToTile(float canvas_x, float canvas_y) const
Convert canvas-relative coordinates to tile information.
int GetTile16Index(float canvas_x, float canvas_y) const
Get tile16 index from canvas position.
ImVec2 ApplyScrollOffset(float canvas_x, float canvas_y) const
int CalculateLocalMapId(float content_x, float content_y) const
Calculate local map ID from content coordinates.
CoordinateMapperConfig config_
bool IsValidTileCoord(int tile_x, int tile_y) const
Check if tile coordinates are valid.
RomOffsetCalculator rom_offset_calculator_
uint32_t CalculateRomOffset(int tile_id, uint32_t base_offset=0) const
Calculate ROM offset for a given tile ID.
ImVec2 TileToCanvas(int tile_x, int tile_y) const
Convert tile coordinates to canvas position.
int CalculateTileIndex(float local_x, float local_y, float tile_size, int tiles_per_row)
Calculate tile index from local position and grid settings.
ImVec4 GetTileBounds(int tile_x, int tile_y, float tile_size, float scale)
Get tile bounds in canvas space.
TileHitInfo ScreenToTileQuick(const CanvasRuntime &runtime, float screen_x, float screen_y, float tile_size)
Quick screen-to-tile lookup using canvas runtime state.
bool use_tile16
Use 16x16 tile indexing.
int tiles_per_col
Number of tiles per column.
int local_map_size
Size of local map in pixels (512 for OW)
int tiles_per_row
Number of tiles per row in the map.
float tile_size
Size of tiles in pixels (8 or 16)
Screen coordinate mapping result.
float scaled_x
X after applying inverse scale.
TileHitInfo tile_info
Full tile information.
float scaled_y
Y after applying inverse scale.
float canvas_x
X position relative to canvas origin.
float canvas_y
Y position relative to canvas origin.
float content_y
Y in content space (with scroll)
float screen_x
Original screen X coordinate.
float screen_y
Original screen Y coordinate.
bool in_canvas_bounds
Whether point is within canvas.
float content_x
X in content space (with scroll)
Information about a tile at a specific screen location.
bool is_valid
Whether the hit is valid.
ImVec2 tile_origin_px
Top-left of tile in canvas space (pixels)
uint32_t rom_offset
ROM offset for tile data.
std::string canvas_id
ID of the canvas that was hit.
int tile_id
8x8 tile ID (-1 if invalid)
int map_y
Tile Y coordinate in map space.
int tile16_index
16x16 tile index (-1 if invalid)
int local_map_id
Local map ID (for overworld)
int map_x
Tile X coordinate in map space.
ImVec2 tile_size_px
Size of the tile in pixels.