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), ICON_MD_CONTENT_PASTE
46 " Overworld selection active! Click in scratch space to stamp.");
47 } else {
48 Text("Left-click to paint with current tile.");
49 Text("Right-click to select tiles.");
50 }
51
52 // Initialize scratch bitmap if needed
54 int bitmap_width = scratch_space_.width * 16;
55 int bitmap_height = scratch_space_.height * 16;
56 std::vector<uint8_t> empty_data(bitmap_width * bitmap_height, 0);
57 scratch_space_.scratch_bitmap.Create(bitmap_width, bitmap_height, 8,
58 empty_data);
59 if (all_gfx_loaded_) {
65 }
66 }
67
68 // Draw the scratch space canvas using modern BeginCanvas/EndCanvas pattern
70 ImGui::BeginGroup();
71
72 ImVec2 scratch_content_size(scratch_space_.width * 16 + 4,
73 scratch_space_.height * 16 + 4);
74
75 // Configure canvas frame options
76 gui::CanvasFrameOptions frame_opts;
77 frame_opts.canvas_size = scratch_content_size;
78 frame_opts.draw_grid = true;
79 frame_opts.grid_step = 32.0f; // Tile16 grid (32px = 2x tile scale)
80 frame_opts.draw_context_menu = false; // No context menu for scratch
81 frame_opts.draw_overlay = true;
82 frame_opts.render_popups = false;
83 frame_opts.use_child_window = false;
84
85 gui::BeginChildWithScrollbar("##ScratchSpaceScrollRegion",
86 scratch_content_size);
87
88 auto canvas_rt = gui::BeginCanvas(scratch_canvas_, frame_opts);
90
93 }
94
97 }
98
99 // Handle Interactions using runtime hover state
100 if (canvas_rt.hovered) {
102 !ow_map_canvas_.selected_tiles().empty()) {
103 if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
105 }
106 } else if (current_mode == EditingMode::DRAW_TILE ||
107 ImGui::IsMouseDown(ImGuiMouseButton_Left)) {
109 }
110 }
111
112 gui::EndCanvas(scratch_canvas_, canvas_rt, frame_opts);
113 EndChild();
114 ImGui::EndGroup();
115
116 return absl::OkStatus();
117}
118
120 auto mouse_position = scratch_canvas_.drawn_tile_position();
121 int grid_size = 32;
122
123 int tile_x = static_cast<int>(mouse_position.x) / grid_size;
124 int tile_y = static_cast<int>(mouse_position.y) / grid_size;
125
126 int max_width = scratch_space_.width > 0 ? scratch_space_.width : 20;
127 int max_height = scratch_space_.height > 0 ? scratch_space_.height : 30;
128
129 if (tile_x >= 0 && tile_x < max_width && tile_y >= 0 && tile_y < max_height) {
130 if (tile_x < 32 && tile_y < 32) {
131 scratch_space_.tile_data[tile_x][tile_y] = current_tile16_;
132 }
133
135
136 if (!scratch_space_.in_use) {
137 scratch_space_.in_use = true;
138 scratch_space_.name = "Modified Layout";
139 }
140 }
141}
142
144 auto mouse_position = scratch_canvas_.drawn_tile_position();
145
146 int start_tile_x = static_cast<int>(mouse_position.x) / 32;
147 int start_tile_y = static_cast<int>(mouse_position.y) / 32;
148
151 return;
152 }
153
156 int pattern_height = dependencies_.shared_clipboard->overworld_height;
157
158 if (tile_ids.empty())
159 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())
197 return;
198
199 const int grid_size = 32;
200 int scratch_bitmap_width = scratch_space_.scratch_bitmap.width();
201 int scratch_bitmap_height = scratch_space_.scratch_bitmap.height();
202
203 for (int y = 0; y < 16; ++y) {
204 for (int x = 0; x < 16; ++x) {
205 int src_index = y * 16 + x;
206
207 int dst_x = tile_x * grid_size + x + x;
208 int dst_y = tile_y * grid_size + y + y;
209
210 if (dst_x >= 0 && dst_x < scratch_bitmap_width && dst_y >= 0 &&
211 dst_y < scratch_bitmap_height &&
212 src_index < static_cast<int>(tile_data.size())) {
213 for (int py = 0; py < 2 && (dst_y + py) < scratch_bitmap_height; ++py) {
214 for (int px = 0; px < 2 && (dst_x + px) < scratch_bitmap_width;
215 ++px) {
216 int dst_index = (dst_y + py) * scratch_bitmap_width + (dst_x + px);
218 tile_data[src_index]);
219 }
220 }
221 }
222 }
223 }
224
228 scratch_space_.in_use = true;
229}
230
232 gfx::ScopedTimer timer("overworld_save_selection_to_scratch");
233
235 !ow_map_canvas_.selected_tiles().empty()) {
236 const auto& selected_points = ow_map_canvas_.selected_points();
237 if (selected_points.size() >= 2) {
238 // selected_points are now stored in world coordinates
239 const auto start = selected_points[0];
240 const auto end = selected_points[1];
241
242 int selection_width =
243 std::abs(static_cast<int>((end.x - start.x) / 16)) + 1;
244 int selection_height =
245 std::abs(static_cast<int>((end.y - start.y) / 16)) + 1;
246
247 scratch_space_.width = std::max(1, std::min(selection_width, 32));
248 scratch_space_.height = std::max(1, std::min(selection_height, 32));
249 scratch_space_.in_use = true;
250 scratch_space_.name = absl::StrFormat(
251 "Selection %dx%d", scratch_space_.width, scratch_space_.height);
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:35
static Arena & Get()
Definition arena.cc:20
void WriteToPixel(int position, uint8_t value)
Write a value to a pixel at the given position.
Definition bitmap.cc:581
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:201
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:384
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.
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