10#include "imgui/imgui.h"
11#include "imgui_memory_editor.h"
17using ImGui::BeginMenu;
19using ImGui::GetContentRegionAvail;
20using ImGui::GetCursorScreenPos;
22using ImGui::GetMouseDragDelta;
23using ImGui::GetWindowDrawList;
24using ImGui::IsItemActive;
25using ImGui::IsItemHovered;
26using ImGui::IsMouseClicked;
27using ImGui::IsMouseDragging;
29using ImGui::OpenPopupOnItemClick;
30using ImGui::Selectable;
39 ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight;
43 return ImVec2(std::floor(pos.x / scale) * scale,
44 std::floor(pos.y / scale) * scale);
49 const std::function<
void()> &event,
50 int tile_size,
float scale) {
81 ImGui::InvisibleButton(
87 const ImGuiIO &io = GetIO();
88 const bool is_active = IsItemActive();
91 const ImVec2 mouse_pos(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
94 if (
const float mouse_threshold_for_pan =
97 IsMouseDragging(ImGuiMouseButton_Right, mouse_threshold_for_pan)) {
105 const ImGuiIO &io = GetIO();
110 const ImVec2 mouse_pos(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
112 static bool show_bitmap_data =
false;
113 if (show_bitmap_data &&
bitmap_ !=
nullptr) {
114 MemoryEditor mem_edit;
115 mem_edit.DrawWindow(
"Bitmap Data", (
void *)
bitmap_->data(),
bitmap_->size(),
120 if (ImVec2 drag_delta = GetMouseDragDelta(ImGuiMouseButton_Right);
122 OpenPopupOnItemClick(
context_id_.c_str(), ImGuiPopupFlags_MouseButtonRight);
126 if (
MenuItem(
"Reset Position",
nullptr,
false)) {
132 if (BeginMenu(
"Canvas Properties")) {
135 Text(
"Mouse Position: %.0f x %.0f", mouse_pos.x, mouse_pos.y);
139 if (BeginMenu(
"Bitmap Properties")) {
140 Text(
"Size: %.0f x %.0f", scaled_sz.x, scaled_sz.y);
142 Text(
"BitsPerPixel: %d",
bitmap_->surface()->format->BitsPerPixel);
143 Text(
"BytesPerPixel: %d",
bitmap_->surface()->format->BytesPerPixel);
144 MenuItem(
"Data",
nullptr, &show_bitmap_data);
145 if (BeginMenu(
"Format")) {
161 if (BeginMenu(
"Change Palette")) {
162 Text(
"Work in progress");
190 if (BeginMenu(
"View Palette")) {
199 if (BeginMenu(
"Grid Tile Size")) {
220 const ImGuiIO &io = GetIO();
221 const bool is_hovered = IsItemHovered();
225 const ImVec2 mouse_pos(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
226 const auto scaled_size = size * scale;
240 ImVec2 paint_pos = AlignPosToGrid(mouse_pos, scaled_size);
243 ImVec2(paint_pos.x + scaled_size, paint_pos.y + scaled_size);
245 points_.push_back(paint_pos_end);
249 ImVec2(origin.x + paint_pos.x, origin.y + paint_pos.y),
250 ImVec2(origin.x + paint_pos.x + scaled_size,
251 origin.y + paint_pos.y + scaled_size));
254 if (IsMouseClicked(ImGuiMouseButton_Left) &&
255 ImGui::IsMouseDragging(ImGuiMouseButton_Left)) {
266 const ImGuiIO &io = GetIO();
267 const bool is_hovered = IsItemHovered();
270 const ImVec2 mouse_pos(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
282 ImVec2 paint_pos = AlignPosToGrid(mouse_pos, scaled_size);
287 ImVec2(paint_pos.x + scaled_size, paint_pos.y + scaled_size));
298 (ImTextureID)(intptr_t)tilemap.
tile_bitmaps[current_tile].texture(),
299 ImVec2(origin.x + paint_pos.x, origin.y + paint_pos.y),
300 ImVec2(origin.x + paint_pos.x + scaled_size,
301 origin.y + paint_pos.y + scaled_size));
303 if (IsMouseClicked(ImGuiMouseButton_Left) ||
304 ImGui::IsMouseDragging(ImGuiMouseButton_Left)) {
313 const ImGuiIO &io = GetIO();
314 const bool is_hovered = IsItemHovered();
318 const ImVec2 mouse_pos(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
320 static bool is_dragging =
false;
321 static ImVec2 start_drag_pos;
335 ImVec2 paint_pos = AlignPosToGrid(mouse_pos, scaled_tile_size);
344 ImVec2(paint_pos.x + scaled_tile_size, paint_pos.y + scaled_tile_size));
347 ImVec2(origin.x + paint_pos.x + 1, origin.y + paint_pos.y + 1),
348 ImVec2(origin.x + paint_pos.x + scaled_tile_size,
349 origin.y + paint_pos.y + scaled_tile_size),
350 IM_COL32(color.x * 255, color.y * 255, color.z * 255, 255));
352 if (IsMouseClicked(ImGuiMouseButton_Left)) {
354 start_drag_pos = paint_pos;
357 if (is_dragging && ImGui::IsMouseReleased(ImGuiMouseButton_Left)) {
369 int tile_index_x =
static_cast<int>(position.x /
global_scale_) / tile_size;
370 int tile_index_y =
static_cast<int>(position.y /
global_scale_) / tile_size;
372 ImVec2 start_position(tile_index_x * tile_size, tile_index_y * tile_size);
375 for (
int y = 0; y < tile_size; ++y) {
376 for (
int x = 0; x < tile_size; ++x) {
379 (start_position.y + y) * bitmap->
width() + (start_position.x + x);
388 const ImGuiIO &io = GetIO();
389 const bool is_hovered = IsItemHovered();
391 const ImVec2 mouse_pos(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
396 if (is_hovered && IsMouseClicked(ImGuiMouseButton_Left)) {
400 ImVec2 painter_pos = AlignPosToGrid(mouse_pos, size);
402 points_.push_back(painter_pos);
403 points_.push_back(ImVec2(painter_pos.x + size, painter_pos.y + size_y));
407 if (is_hovered && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
415 const ImGuiIO &io = GetIO();
417 const ImVec2 mouse_pos(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
418 static ImVec2 drag_start_pos;
419 const float scaled_size = tile_size * scale;
420 static bool dragging =
false;
421 constexpr int small_map_size = 0x200;
422 int superY = current_map / 8;
423 int superX = current_map % 8;
426 if (IsMouseClicked(ImGuiMouseButton_Right)) {
427 ImVec2 painter_pos = AlignPosToGrid(mouse_pos, scaled_size);
428 int painter_x = painter_pos.x;
429 int painter_y = painter_pos.y;
431 auto tile16_x = (painter_x % small_map_size) / (small_map_size / 0x20);
432 auto tile16_y = (painter_y % small_map_size) / (small_map_size / 0x20);
434 int index_x = superX * 0x20 + tile16_x;
435 int index_y = superY * 0x20 + tile16_y;
441 drag_start_pos = AlignPosToGrid(mouse_pos, scaled_size);
445 ImVec2 drag_end_pos = AlignPosToGrid(mouse_pos, scaled_size);
446 if (ImGui::IsMouseDragging(ImGuiMouseButton_Right)) {
447 auto start = ImVec2(
canvas_p0_.x + drag_start_pos.x,
449 auto end = ImVec2(
canvas_p0_.x + drag_end_pos.x + tile_size,
455 if (dragging && !ImGui::IsMouseDown(ImGuiMouseButton_Right)) {
460 constexpr int tile16_size = 16;
461 int start_x = std::floor(drag_start_pos.x / scaled_size) * tile16_size;
462 int start_y = std::floor(drag_start_pos.y / scaled_size) * tile16_size;
463 int end_x = std::floor(drag_end_pos.x / scaled_size) * tile16_size;
464 int end_y = std::floor(drag_end_pos.y / scaled_size) * tile16_size;
467 if (start_x > end_x) std::swap(start_x, end_x);
468 if (start_y > end_y) std::swap(start_y, end_y);
472 constexpr int tiles_per_local_map = small_map_size / 16;
475 for (
int y = start_y; y <= end_y; y += tile16_size) {
476 for (
int x = start_x; x <= end_x; x += tile16_size) {
478 int local_map_x = x / small_map_size;
479 int local_map_y = y / small_map_size;
482 int tile16_x = (x % small_map_size) / tile16_size;
483 int tile16_y = (y % small_map_size) / tile16_size;
486 int index_x = local_map_x * tiles_per_local_map + tile16_x;
487 int index_y = local_map_y * tiles_per_local_map + tile16_y;
519 (ImTextureID)(intptr_t)bitmap.
texture(),
525 ImVec2(0, 0), ImVec2(1, 1), IM_COL32(255, 255, 255, alpha));
529 ImVec2 src_pos, ImVec2 src_size) {
535 (ImTextureID)(intptr_t)bitmap.
texture(),
537 ImVec2(
canvas_p0_.x + dest_pos.x + dest_size.x,
539 ImVec2(src_pos.x / bitmap.
width(), src_pos.y / bitmap.
height()),
540 ImVec2((src_pos.x + src_size.x) / bitmap.
width(),
541 (src_pos.y + src_size.y) / bitmap.
height()));
546 for (
const auto &[key, value] : gfx_bin) {
547 int offset = 0x40 * (key + 1);
552 draw_list_->AddImage((ImTextureID)(intptr_t)value.texture(),
572 IM_COL32(color.x, color.y, color.z, color.w));
584 int tile_size,
float scale) {
600 static_cast<int>(std::floor(rect_top_left.x / (tile_size * scale)));
602 static_cast<int>(std::floor(rect_top_left.y / (tile_size * scale)));
604 static_cast<int>(std::floor(rect_bottom_right.x / (tile_size * scale)));
606 static_cast<int>(std::floor(rect_bottom_right.y / (tile_size * scale)));
608 if (start_tile_x > end_tile_x) std::swap(start_tile_x, end_tile_x);
609 if (start_tile_y > end_tile_y) std::swap(start_tile_y, end_tile_y);
612 int rect_width = (end_tile_x - start_tile_x) * tile_size;
613 int rect_height = (end_tile_y - start_tile_y) * tile_size;
615 int tiles_per_row = rect_width / tile_size;
616 int tiles_per_col = rect_height / tile_size;
619 for (
int y = 0; y < tiles_per_col + 1; ++y) {
620 for (
int x = 0; x < tiles_per_row + 1; ++x) {
621 int tile_id = group[i];
626 if (tile_id >= 0 && tile_id < tilemap_size) {
628 int tile_pos_x = (x + start_tile_x) * tile_size * scale;
629 int tile_pos_y = (y + start_tile_y) * tile_size * scale;
640 const ImGuiIO &io = GetIO();
642 const ImVec2 mouse_pos(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
643 auto new_start_pos = AlignPosToGrid(mouse_pos, tile_size * scale);
647 ImVec2(new_start_pos.x + rect_width, new_start_pos.y + rect_height));
657 IM_COL32(color.x, color.y, color.z, color.w));
659 ImVec2 outline_origin(origin.x - 1, origin.y - 1);
660 ImVec2 outline_size(size.x + 1, size.y + 1);
674 const uint32_t grid_color = IM_COL32(200, 200, 200, 50);
675 const float grid_thickness = 0.5f;
676 for (
float x = fmodf(
scrolling_.x, grid_step);
681 for (
float y = fmodf(
scrolling_.y, grid_step);
703 for (
float x = fmodf(
scrolling_.x, grid_step);
705 for (
float y = fmodf(
scrolling_.y, grid_step);
709 int tile_id = tile_x + (tile_y * tile_id_offset);
711 if (tile_id >=
labels_[label_id].size()) {
714 std::string label =
labels_[label_id][tile_id];
716 ImVec2(
canvas_p0_.x + x + (grid_step / 2) - tile_id_offset,
717 canvas_p0_.y + y + (grid_step / 2) - tile_id_offset),
730 ImVec2 tile_pos_end(tile_pos.x + grid_step, tile_pos.y + grid_step);
732 draw_list_->AddRectFilled(tile_pos, tile_pos_end,
733 IM_COL32(255, 0, 255, 255));
749 for (
float x = fmodf(
scrolling_.x, grid_step);
751 for (
float y = fmodf(
scrolling_.y, grid_step);
755 int tile_id = tile_x + (tile_y * 16);
756 std::string hex_id = absl::StrFormat(
"%02X", tile_id);
768 for (
float x = fmodf(
scrolling_.x, grid_step);
770 for (
float y = fmodf(
scrolling_.y, grid_step);
774 int tile_id = tile_x + (tile_y * tile_id_offset);
781 ImVec2(
canvas_p0_.x + x + (grid_step / 2) - tile_id_offset,
782 canvas_p0_.y + y + (grid_step / 2) - tile_id_offset),
792 for (
int n = 0; n <
points_.Size; n += 2) {
814 ImDrawList *
draw_list = ImGui::GetWindowDrawList();
816 Text(
"Blue shape is drawn first: appears in back");
817 Text(
"Red shape is drawn after: appears in front");
818 ImVec2 p0 = ImGui::GetCursorScreenPos();
819 draw_list->AddRectFilled(ImVec2(p0.x, p0.y), ImVec2(p0.x + 50, p0.y + 50),
820 IM_COL32(0, 0, 255, 255));
821 draw_list->AddRectFilled(ImVec2(p0.x + 25, p0.y + 25),
822 ImVec2(p0.x + 75, p0.y + 75),
823 IM_COL32(255, 0, 0, 255));
824 ImGui::Dummy(ImVec2(75, 75));
828 Text(
"Blue shape is drawn first, into channel 1: appears in front");
829 Text(
"Red shape is drawn after, into channel 0: appears in back");
830 ImVec2 p1 = ImGui::GetCursorScreenPos();
837 draw_list->AddRectFilled(ImVec2(p1.x, p1.y), ImVec2(p1.x + 50, p1.y + 50),
838 IM_COL32(0, 0, 255, 255));
840 draw_list->AddRectFilled(ImVec2(p1.x + 25, p1.y + 25),
841 ImVec2(p1.x + 75, p1.y + 75),
842 IM_COL32(255, 0, 0, 255));
848 ImGui::Dummy(ImVec2(75, 75));
849 Text(
"After reordering, contents of channel 0 appears below channel 1.");
855 ImGui::BeginChild(canvas.
canvas_id().c_str(), child_size,
true);
868 int num_sheets_to_load,
int canvas_id,
871 if (ImGuiID child_id =
872 ImGui::GetID((ImTextureID)(intptr_t)(intptr_t)canvas_id);
873 ImGui::BeginChild(child_id, ImGui::GetContentRegionAvail(),
true,
874 ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
875 canvas.
DrawBackground(ImVec2(width + 1, num_sheets_to_load * height + 1));
878 for (
const auto &[key, value] : graphics_bin) {
879 int offset = height * (key + 1);
882 top_left_y = canvas.
zero_point().y + height * key;
885 (ImTextureID)(intptr_t)value.texture(),
886 ImVec2(canvas.
zero_point().x + 2, top_left_y),
899 int height,
int tile_size,
bool is_loaded,
900 bool scrollbar,
int canvas_id) {
902 int height,
int tile_size,
bool is_loaded) {
912 if (ImGuiID child_id =
913 ImGui::GetID((ImTextureID)(intptr_t)(intptr_t)canvas_id);
914 ImGui::BeginChild(child_id, ImGui::GetContentRegionAvail(),
true,
915 ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
916 draw_canvas(canvas, bitmap, width, height, tile_size, is_loaded);
920 draw_canvas(canvas, bitmap, width, height, tile_size, is_loaded);
The Renderer class represents the renderer for the Yaze application.
void UpdateBitmap(gfx::Bitmap *bitmap)
void RenderBitmap(gfx::Bitmap *bitmap)
Represents a bitmap image.
const SnesPalette & palette() const
SDL_Texture * texture() const
void WriteColor(int position, const ImVec4 &color)
Write a color to a pixel at the given position.
Represents a canvas for drawing and manipulating graphics.
ImVector< ImVec2 > points_
void DrawBitmap(Bitmap &bitmap, int border_offset, float scale)
void DrawBitmapGroup(std::vector< int > &group, gfx::Tilemap &tilemap, int tile_size, float scale=1.0f)
ImVec2 selected_tile_pos_
void DrawOutlineWithColor(int x, int y, int w, int h, ImVec4 color)
void UpdateInfoGrid(ImVec2 bg_size, float grid_size=64.0f, int label_id=0)
ImVec2 mouse_pos_in_canvas_
bool DrawTilemapPainter(gfx::Tilemap &tilemap, int current_tile)
bool DrawSolidTilePainter(const ImVec4 &color, int size)
bool enable_context_menu_
void DrawLayeredElements()
bool enable_custom_labels_
bool DrawTileSelector(int size, int size_y=0)
void UpdateColorPainter(gfx::Bitmap &bitmap, const ImVec4 &color, const std::function< void()> &event, int tile_size, float scale=1.0f)
void DrawGridLines(float grid_step)
void DrawRect(int x, int y, int w, int h, ImVec4 color)
bool DrawTilePainter(const Bitmap &bitmap, int size, float scale=1.0f)
ImVector< ImVec2 > selected_points_
void DrawTileOnBitmap(int tile_size, gfx::Bitmap *bitmap, ImVec4 color)
void DrawCustomHighlight(float grid_step)
ImVector< ImVector< std::string > > labels_
void DrawText(std::string text, int x, int y)
void DrawSelectRect(int current_map, int tile_size=0x10, float scale=1.0f)
void DrawOutline(int x, int y, int w, int h)
void DrawInfoGrid(float grid_step=64.0f, int tile_id_offset=8, int label_id=0)
bool enable_hex_tile_labels_
void DrawBitmapTable(const BitmapTable &gfx_bin)
void DrawBackground(ImVec2 canvas_size=ImVec2(0, 0))
void DrawGrid(float grid_step=64.0f, int tile_id_offset=8)
std::vector< ImVec2 > selected_tiles_
std::vector< uint8_t > GetTilemapData(Tilemap &tilemap, int tile_id)
std::unordered_map< int, gfx::Bitmap > BitmapTable
void RenderTile(Tilemap &tilemap, int tile_id)
ImVec2 AlignPosToGrid(ImVec2 pos, float scale)
Graphical User Interface (GUI) components for the application.
constexpr uint32_t kWhiteColor
constexpr uint32_t kRectangleColor
void BitmapCanvasPipeline(gui::Canvas &canvas, gfx::Bitmap &bitmap, int width, int height, int tile_size, bool is_loaded, bool scrollbar, int canvas_id)
void EndCanvas(Canvas &canvas)
void BeginCanvas(Canvas &canvas, ImVec2 child_size)
void GraphicsBinCanvasPipeline(int width, int height, int tile_size, int num_sheets_to_load, int canvas_id, bool is_loaded, gfx::BitmapTable &graphics_bin)
constexpr uint32_t kOutlineRect
constexpr uint32_t kBlackColor
constexpr ImGuiButtonFlags kMouseFlags
absl::Status DisplayEditablePalette(gfx::SnesPalette &palette, const std::string &title, bool show_color_picker, int colors_per_row, ImGuiColorEditFlags flags)
absl::flat_hash_map< int, Bitmap > tile_bitmaps