8#include <unordered_map>
11#include "absl/status/status.h"
12#include "absl/strings/str_format.h"
32#include "imgui/imgui.h"
33#include "imgui_memory_editor.h"
45 Text(
"Scratch Space Slot:");
46 for (
int i = 0; i < 4; i++) {
51 PushStyleColor(ImGuiCol_Button, ImVec4(0.4f, 0.7f, 0.4f, 1.0f));
52 if (Button(std::to_string(i + 1).c_str(), ImVec2(25, 25))) {
60 if (Button(
"Save Selection")) {
68 if (Button(
"Clear")) {
74 Text(
"Selection Transfer:");
82 HOVER_HINT(
"Copy current overworld selection to this scratch slot");
90 std::vector<int> scratch_tile_ids;
92 int tile_x =
static_cast<int>(tile_pos.x) / 32;
93 int tile_y =
static_cast<int>(tile_pos.y) / 32;
94 if (tile_x >= 0 && tile_x < 32 && tile_y >= 0 && tile_y < 32) {
95 scratch_tile_ids.push_back(
102 std::abs(
static_cast<int>((points[1].x - points[0].x) / 32)) + 1;
104 std::abs(
static_cast<int>((points[1].y - points[0].y) / 32)) + 1;
106 std::move(scratch_tile_ids);
113 HOVER_HINT(
"Copy scratch selection to clipboard for pasting in overworld");
118 " Pattern ready! Use Shift+Click to stamp, or paste in overworld");
126 "Select tiles from Tile16 tab or make selections in overworld, then draw "
131 if (!current_slot.scratch_bitmap.is_active()) {
133 int bitmap_width = current_slot.width * 16;
134 int bitmap_height = current_slot.height * 16;
135 std::vector<uint8_t> empty_data(bitmap_width * bitmap_height, 0);
136 current_slot.scratch_bitmap.Create(bitmap_width, bitmap_height, 8,
140 current_slot.scratch_bitmap.SetPalette(
palette_);
152 ImVec2 scratch_content_size(current_slot.width * 16 + 4,
153 current_slot.height * 16 + 4);
155 scratch_content_size);
163 if (current_slot.scratch_bitmap.is_active()) {
178 return absl::OkStatus();
191 int tile_x =
static_cast<int>(mouse_position.x) / grid_size;
192 int tile_y =
static_cast<int>(mouse_position.y) / grid_size;
196 int max_width = current_slot.width > 0 ? current_slot.width : 20;
197 int max_height = current_slot.height > 0 ? current_slot.height : 30;
200 if (tile_x >= 0 && tile_x < max_width && tile_y >= 0 && tile_y < max_height) {
202 if (tile_x < 32 && tile_y < 32) {
210 if (!current_slot.in_use) {
211 current_slot.in_use =
true;
223 int start_tile_x =
static_cast<int>(mouse_position.x) / 32;
224 int start_tile_y =
static_cast<int>(mouse_position.y) / 32;
232 const auto& tile_ids =
237 if (tile_ids.empty())
241 int max_width = current_slot.width > 0 ? current_slot.width : 20;
242 int max_height = current_slot.height > 0 ? current_slot.height : 30;
246 for (
int py = 0; py < pattern_height && (start_tile_y + py) < max_height;
248 for (
int px = 0; px < pattern_width && (start_tile_x + px) < max_width;
250 if (idx <
static_cast<int>(tile_ids.size())) {
251 int tile_id = tile_ids[idx];
252 int scratch_x = start_tile_x + px;
253 int scratch_y = start_tile_y + py;
256 if (scratch_x >= 0 && scratch_x < 32 && scratch_y >= 0 &&
258 current_slot.tile_data[scratch_x][scratch_y] = tile_id;
267 current_slot.in_use =
true;
268 if (current_slot.name ==
"Empty") {
270 absl::StrFormat(
"Pattern %dx%d", pattern_width, pattern_height);
275 int tile_id,
int slot) {
284 if (tile_data.empty())
290 const int grid_size = 32;
291 int scratch_bitmap_width = scratch_slot.scratch_bitmap.width();
292 int scratch_bitmap_height = scratch_slot.scratch_bitmap.height();
295 for (
int y = 0; y < 16; ++y) {
296 for (
int x = 0; x < 16; ++x) {
297 int src_index = y * 16 + x;
300 int dst_x = tile_x * grid_size + x + x;
301 int dst_y = tile_y * grid_size + y + y;
304 if (dst_x >= 0 && dst_x < scratch_bitmap_width && dst_y >= 0 &&
305 dst_y < scratch_bitmap_height &&
306 src_index <
static_cast<int>(tile_data.size())) {
309 for (
int py = 0; py < 2 && (dst_y + py) < scratch_bitmap_height; ++py) {
310 for (
int px = 0; px < 2 && (dst_x + px) < scratch_bitmap_width;
312 int dst_index = (dst_y + py) * scratch_bitmap_width + (dst_x + px);
313 scratch_slot.scratch_bitmap.WriteToPixel(dst_index,
314 tile_data[src_index]);
321 scratch_slot.scratch_bitmap.set_modified(
true);
325 scratch_slot.in_use =
true;
331 if (slot < 0 || slot >= 4) {
332 return absl::InvalidArgumentError(
"Invalid scratch slot");
339 if (selected_points.size() >= 2) {
340 const auto start = selected_points[0];
341 const auto end = selected_points[1];
344 int selection_width =
345 std::abs(
static_cast<int>((end.x - start.x) / 16)) + 1;
346 int selection_height =
347 std::abs(
static_cast<int>((end.y - start.y) / 16)) + 1;
350 scratch_spaces_[slot].width = std::max(1, std::min(selection_width, 32));
352 std::max(1, std::min(selection_height, 32));
361 std::vector<uint8_t> empty_data(bitmap_width * bitmap_height, 0);
362 scratch_spaces_[slot].scratch_bitmap.Create(bitmap_width, bitmap_height,
389 if (x < 32 && y < 32) {
408 return absl::OkStatus();
412 if (slot < 0 || slot >= 4) {
413 return absl::InvalidArgumentError(
"Invalid scratch slot");
417 return absl::FailedPreconditionError(
"Scratch slot is empty");
421 util::logf(
"Loading scratch slot %d: %s", slot,
424 return absl::OkStatus();
428 if (slot < 0 || slot >= 4) {
429 return absl::InvalidArgumentError(
"Invalid scratch slot");
438 std::fill(data.begin(), data.end(), 0);
445 return absl::OkStatus();
EditorDependencies dependencies_
bool map_blockset_loaded_
absl::Status DrawScratchSpace()
std::array< ScratchSpaceSlot, 4 > scratch_spaces_
absl::Status ClearScratchSpace(int slot)
gfx::Tilemap tile16_blockset_
gui::Canvas ow_map_canvas_
void DrawScratchSpacePattern()
gui::Canvas scratch_canvas_
absl::Status SaveCurrentSelectionToScratch(int slot)
void DrawScratchSpaceEdits()
absl::Status LoadScratchToSelection(int slot)
zelda3::Overworld overworld_
void UpdateScratchBitmapTile(int tile_x, int tile_y, int tile_id, int slot=-1)
int current_scratch_slot_
gfx::SnesPalette palette_
void QueueTextureCommand(TextureCommandType type, Bitmap *bitmap)
RAII timer for automatic timing management.
void DrawBitmap(Bitmap &bitmap, int border_offset, float scale)
auto global_scale() const
auto select_rect_active() const
auto selected_tiles() const
auto drawn_tile_position() const
bool DrawTileSelector(int size, int size_y=0)
void SetContextMenuEnabled(bool enabled)
void DrawBackground(ImVec2 canvas_size=ImVec2(0, 0))
void DrawGrid(float grid_step=64.0f, int tile_id_offset=8)
auto selected_points() const
auto current_area_palette() const
void set_current_world(int world)
int GetTileFromPosition(ImVec2 position) const
void set_current_map(int i)
#define ICON_MD_CONTENT_PASTE
#define RETURN_IF_ERROR(expression)
#define HOVER_HINT(string)
Editors are the view controllers for the application.
std::vector< uint8_t > GetTilemapData(Tilemap &tilemap, int tile_id)
void BeginChildWithScrollbar(const char *str_id)
void logf(const absl::FormatSpec< Args... > &format, Args &&... args)
bool has_overworld_tile16
std::vector< int > overworld_tile16_ids
SharedClipboard * shared_clipboard