yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
scratch_space.cc
Go to the documentation of this file.
1#include <algorithm>
2#include <cmath>
3#include <vector>
4
5#include "absl/status/status.h"
6#include "absl/strings/str_format.h"
13#include "app/gui/core/icons.h"
14#include "app/gui/core/style.h"
15#include "imgui/imgui.h"
16#include "util/log.h"
17#include "util/macro.h"
19
20namespace yaze::editor {
21
22using namespace ImGui;
23
24// =============================================================================
25// Scratch Space - Unified Single Workspace
26// =============================================================================
27
29 // Header with clear button
30 Text(ICON_MD_BRUSH " Scratch Workspace");
31 SameLine();
32 if (Button("Clear")) {
34 }
35 HOVER_HINT("Clear scratch workspace");
36
37 // Status info
38 Text("%s (%dx%d)", scratch_space_.name.c_str(), scratch_space_.width,
40
41 // Interaction hints
43 !ow_map_canvas_.selected_tiles().empty()) {
44 TextColored(
45 ImVec4(0.4f, 1.0f, 0.4f, 1.0f),
47 " Overworld selection active! Click in scratch space to stamp.");
48 } else {
49 Text("Left-click to paint with current tile.");
50 Text("Right-click to select tiles.");
51 }
52
53 // Initialize scratch bitmap if needed
55 int bitmap_width = scratch_space_.width * 16;
56 int bitmap_height = scratch_space_.height * 16;
57 std::vector<uint8_t> empty_data(bitmap_width * bitmap_height, 0);
58 scratch_space_.scratch_bitmap.Create(bitmap_width, bitmap_height, 8,
59 empty_data);
60 if (all_gfx_loaded_) {
66 }
67 }
68
69 // Draw the scratch space canvas using modern BeginCanvas/EndCanvas pattern
71 ImGui::BeginGroup();
72
73 ImVec2 scratch_content_size(scratch_space_.width * 16 + 4,
74 scratch_space_.height * 16 + 4);
75
76 // Configure canvas frame options
77 gui::CanvasFrameOptions frame_opts;
78 frame_opts.canvas_size = scratch_content_size;
79 frame_opts.draw_grid = true;
80 frame_opts.grid_step = 32.0f; // Tile16 grid (32px = 2x tile scale)
81 frame_opts.draw_context_menu = false; // No context menu for scratch
82 frame_opts.draw_overlay = true;
83 frame_opts.render_popups = false;
84 frame_opts.use_child_window = false;
85
86 gui::BeginChildWithScrollbar("##ScratchSpaceScrollRegion",
87 scratch_content_size);
88
89 auto canvas_rt = gui::BeginCanvas(scratch_canvas_, frame_opts);
91
94 }
95
98 }
99
100 // Handle Interactions using runtime hover state
101 if (canvas_rt.hovered) {
103 !ow_map_canvas_.selected_tiles().empty()) {
104 if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
106 }
107 } else if (current_mode == EditingMode::DRAW_TILE ||
108 ImGui::IsMouseDown(ImGuiMouseButton_Left)) {
110 }
111 }
112
113 gui::EndCanvas(scratch_canvas_, canvas_rt, frame_opts);
114 EndChild();
115 ImGui::EndGroup();
116
117 return absl::OkStatus();
118}
119
121 auto mouse_position = scratch_canvas_.drawn_tile_position();
122 int grid_size = 32;
123
124 int tile_x = static_cast<int>(mouse_position.x) / grid_size;
125 int tile_y = static_cast<int>(mouse_position.y) / grid_size;
126
127 int max_width = scratch_space_.width > 0 ? scratch_space_.width : 20;
128 int max_height = scratch_space_.height > 0 ? scratch_space_.height : 30;
129
130 if (tile_x >= 0 && tile_x < max_width && tile_y >= 0 && tile_y < max_height) {
131 if (tile_x < 32 && tile_y < 32) {
132 scratch_space_.tile_data[tile_x][tile_y] = current_tile16_;
133 }
134
136
137 if (!scratch_space_.in_use) {
138 scratch_space_.in_use = true;
139 scratch_space_.name = "Modified Layout";
140 }
141 }
142}
143
145 auto mouse_position = scratch_canvas_.drawn_tile_position();
146
147 int start_tile_x = static_cast<int>(mouse_position.x) / 32;
148 int start_tile_y = static_cast<int>(mouse_position.y) / 32;
149
152 return;
153 }
154
157 int pattern_height = dependencies_.shared_clipboard->overworld_height;
158
159 if (tile_ids.empty()) return;
160
161 int max_width = scratch_space_.width > 0 ? scratch_space_.width : 20;
162 int max_height = scratch_space_.height > 0 ? scratch_space_.height : 30;
163
164 int idx = 0;
165 for (int py = 0; py < pattern_height && (start_tile_y + py) < max_height;
166 ++py) {
167 for (int px = 0; px < pattern_width && (start_tile_x + px) < max_width;
168 ++px) {
169 if (idx < static_cast<int>(tile_ids.size())) {
170 int tile_id = tile_ids[idx];
171 int scratch_x = start_tile_x + px;
172 int scratch_y = start_tile_y + py;
173
174 if (scratch_x >= 0 && scratch_x < 32 && scratch_y >= 0 &&
175 scratch_y < 32) {
176 scratch_space_.tile_data[scratch_x][scratch_y] = tile_id;
177 UpdateScratchBitmapTile(scratch_x, scratch_y, tile_id);
178 }
179 idx++;
180 }
181 }
182 }
183
184 scratch_space_.in_use = true;
185 if (scratch_space_.name == "Scratch Space") {
187 absl::StrFormat("Pattern %dx%d", pattern_width, pattern_height);
188 }
189}
190
192 int tile_id) {
193 gfx::ScopedTimer timer("overworld_update_scratch_tile");
194
195 auto tile_data = gfx::GetTilemapData(tile16_blockset_, tile_id);
196 if (tile_data.empty()) return;
197
198 const int grid_size = 32;
199 int scratch_bitmap_width = scratch_space_.scratch_bitmap.width();
200 int scratch_bitmap_height = scratch_space_.scratch_bitmap.height();
201
202 for (int y = 0; y < 16; ++y) {
203 for (int x = 0; x < 16; ++x) {
204 int src_index = y * 16 + x;
205
206 int dst_x = tile_x * grid_size + x + x;
207 int dst_y = tile_y * grid_size + y + y;
208
209 if (dst_x >= 0 && dst_x < scratch_bitmap_width && dst_y >= 0 &&
210 dst_y < scratch_bitmap_height &&
211 src_index < static_cast<int>(tile_data.size())) {
212 for (int py = 0; py < 2 && (dst_y + py) < scratch_bitmap_height; ++py) {
213 for (int px = 0; px < 2 && (dst_x + px) < scratch_bitmap_width;
214 ++px) {
215 int dst_index = (dst_y + py) * scratch_bitmap_width + (dst_x + px);
217 tile_data[src_index]);
218 }
219 }
220 }
221 }
222 }
223
227 scratch_space_.in_use = true;
228}
229
231 gfx::ScopedTimer timer("overworld_save_selection_to_scratch");
232
234 !ow_map_canvas_.selected_tiles().empty()) {
235 const auto& selected_points = ow_map_canvas_.selected_points();
236 if (selected_points.size() >= 2) {
237 // selected_points are now stored in world coordinates
238 const auto start = selected_points[0];
239 const auto end = selected_points[1];
240
241 int selection_width =
242 std::abs(static_cast<int>((end.x - start.x) / 16)) + 1;
243 int selection_height =
244 std::abs(static_cast<int>((end.y - start.y) / 16)) + 1;
245
246 scratch_space_.width = std::max(1, std::min(selection_width, 32));
247 scratch_space_.height = std::max(1, std::min(selection_height, 32));
248 scratch_space_.in_use = true;
249 scratch_space_.name = absl::StrFormat("Selection %dx%d",
252
253 int bitmap_width = scratch_space_.width * 16;
254 int bitmap_height = scratch_space_.height * 16;
255 std::vector<uint8_t> empty_data(bitmap_width * bitmap_height, 0);
256 scratch_space_.scratch_bitmap.Create(bitmap_width, bitmap_height, 8,
257 empty_data);
258 if (all_gfx_loaded_) {
264 }
265
268
269 int idx = 0;
270 for (int y = 0;
272 idx < static_cast<int>(ow_map_canvas_.selected_tiles().size());
273 ++y) {
274 for (int x = 0;
275 x < scratch_space_.width &&
276 idx < static_cast<int>(ow_map_canvas_.selected_tiles().size());
277 ++x) {
278 if (idx < static_cast<int>(ow_map_canvas_.selected_tiles().size())) {
279 int tile_id = overworld_.GetTileFromPosition(
281 if (x < 32 && y < 32) {
282 scratch_space_.tile_data[x][y] = tile_id;
283 }
284 UpdateScratchBitmapTile(x, y, tile_id);
285 idx++;
286 }
287 }
288 }
289 }
290 } else {
293 scratch_space_.name = absl::StrFormat("Map %d Area", current_map_);
294 scratch_space_.in_use = true;
295 }
296
297 return absl::OkStatus();
298}
299
301 if (!scratch_space_.in_use) {
302 return absl::FailedPreconditionError("Scratch space is empty");
303 }
304
305 util::logf("Loading scratch space: %s", scratch_space_.name.c_str());
306
307 return absl::OkStatus();
308}
309
311 scratch_space_.in_use = false;
312 scratch_space_.name = "Scratch Space";
313
314 // Clear tile data
315 for (auto& row : scratch_space_.tile_data) {
316 row.fill(0);
317 }
318
319 // Clear the bitmap
322 std::fill(data.begin(), data.end(), 0);
326 }
327
328 return absl::OkStatus();
329}
330
331} // namespace yaze::editor
EditorDependencies dependencies_
Definition editor.h:237
void UpdateScratchBitmapTile(int tile_x, int tile_y, int tile_id)
absl::Status SaveCurrentSelectionToScratch()
void QueueTextureCommand(TextureCommandType type, Bitmap *bitmap)
Definition arena.cc:34
static Arena & Get()
Definition arena.cc:19
void WriteToPixel(int position, uint8_t value)
Write a value to a pixel at the given position.
Definition bitmap.cc:579
void Create(int width, int height, int depth, std::span< uint8_t > data)
Create a bitmap with the given dimensions and data.
Definition bitmap.cc:199
bool is_active() const
Definition bitmap.h:384
void set_modified(bool modified)
Definition bitmap.h:388
int height() const
Definition bitmap.h:374
void SetPalette(const SnesPalette &palette)
Set the palette for the bitmap using SNES palette format.
Definition bitmap.cc:382
int width() const
Definition bitmap.h:373
std::vector< uint8_t > & mutable_data()
Definition bitmap.h:378
RAII timer for automatic timing management.
void DrawBitmap(Bitmap &bitmap, int border_offset, float scale)
Definition canvas.cc:1075
auto select_rect_active() const
Definition canvas.h:490
auto selected_tiles() const
Definition canvas.h:491
auto drawn_tile_position() const
Definition canvas.h:450
bool DrawTileSelector(int size, int size_y=0)
Definition canvas.cc:1011
auto selected_points() const
Definition canvas.h:556
auto current_area_palette() const
Definition overworld.h:512
void set_current_world(int world)
Definition overworld.h:535
int GetTileFromPosition(ImVec2 position) const
Definition overworld.h:449
void set_current_map(int i)
Definition overworld.h:534
#define ICON_MD_BRUSH
Definition icons.h:325
#define ICON_MD_CONTENT_PASTE
Definition icons.h:467
#define HOVER_HINT(string)
Definition macro.h:24
Definition input.cc:22
Editors are the view controllers for the application.
Definition agent_chat.cc:23
std::vector< uint8_t > GetTilemapData(Tilemap &tilemap, int tile_id)
Definition tilemap.cc:270
void EndCanvas(Canvas &canvas)
Definition canvas.cc:1509
void BeginPadding(int i)
Definition style.cc:274
void BeginCanvas(Canvas &canvas, ImVec2 child_size)
Definition canvas.cc:1486
void EndPadding()
Definition style.cc:278
void BeginChildWithScrollbar(const char *str_id)
Definition style.cc:290
void logf(const absl::FormatSpec< Args... > &format, Args &&... args)
Definition log.h:115
#define RETURN_IF_ERROR(expr)
Definition snes.cc:22
SharedClipboard * shared_clipboard
Definition editor.h:132
std::array< std::array< int, 32 >, 32 > tile_data
std::optional< float > grid_step
Definition canvas.h:70