#include "ui.hpp" #include "ogl.hpp" #include "sandbox.hpp" #include #include static void AddSand(Sandbox& sb) { for (int y = 80; y <= 90; ++y) { for (int x = 10; x <= 13; ++x) { sb.set_sand(x, y, Tile{ .so = Tile::SAND }); } } } struct ImRect { ImVec2 top_left; ImVec2 bottom_right; }; /// Helpers for displaying and coordinate space tracking of the sandbox image display. struct SandboxDisplay { float tile_size; int sandbox_width = 40; int sandbox_height = 100; ImVec2 size_screenspace; ImVec2 origin; SandboxDisplay(float tile_size, const Sandbox& sb) : tile_size(tile_size) , sandbox_width{ sb.width } , sandbox_height{ sb.height } , size_screenspace(sandbox_width * tile_size, sandbox_height * tile_size) {} ImVec2 tr_sandbox2screen(Pt pt) const { return ImVec2(origin.x + tile_size * pt.x, origin.y - tile_size * pt.y); } // Assuming inclusive-inclusive rectangle ImRect tr_sandbox2screen(Rect r) const { return { ImVec2(origin.x + tile_size * r.bl.x, origin.y - tile_size * (r.tr.y + 1)), ImVec2(origin.x + tile_size * (r.tr.x + 1), origin.y - tile_size * r.bl.y), }; } void show_image(ImTextureID texid) { auto img_topleft = ImGui::GetCursorScreenPos(); ImGui::Image(texid, size_screenspace, ImVec2(0, 1), ImVec2(1, 0)); // bottom-left corner of the sandbox, in screen space origin = img_topleft; origin.y += size_screenspace.y; } }; void ShowEverything() { ImGui::Begin("Options"); static float tile_size = 4.0f; static std::unique_ptr sandbox = std::make_unique(40, 100); static OglImage gl; ImGui::InputFloat("Tile size", &tile_size); { constexpr auto kModify = "Modify sandbox parameters"; static int new_width, new_height; ImGui::Text("size = (%d, %d)", sandbox->width, sandbox->height); if (ImGui::Button("Modify")) { ImGui::OpenPopup(kModify); new_width = sandbox->width; new_height = sandbox->height; } if (ImGui::BeginPopup(kModify)) { ImGui::InputInt("Sandbox width", &new_width); ImGui::InputInt("Sandbox height", &new_height); if (ImGui::Button("Confirm")) { sandbox = std::make_unique(new_width, new_height); ImGui::CloseCurrentPopup(); } ImGui::SameLine(); if (ImGui::Button("Cancel")) { ImGui::CloseCurrentPopup(); } ImGui::EndPopup(); } } static bool running = false; ImGui::Checkbox("Run", &running); static bool show_dirty_rect = true; ImGui::Checkbox("Show dirty rects", &show_dirty_rect); ImGui::Text("ncycle = %d", sandbox->ncycle); ImGui::SameLine(); bool step = ImGui::Button("Step"); if (step || running) { sandbox->simulate_step(); } if (ImGui::Button("Add sand")) { AddSand(*sandbox); } ImGui::End(); ImGui::Begin("Sandbox"); // Update texture to the current state of the the sandbox. // Do this every frame, because it's easier than trying to track when did the sandbox change, which may be caused by: // - Initialization // - Simulation step // - User interaction (painting, save/load, etc.) gl.upload(reinterpret_cast(sandbox->bitmap), sandbox->width, sandbox->height); SandboxDisplay dis(tile_size, *sandbox); dis.show_image(gl.as_imgui()); if (show_dirty_rect) { auto dl = ImGui::GetWindowDrawList(); auto [top_left, bottom_right] = dis.tr_sandbox2screen(sandbox->dirty_writeto); dl->AddRect(top_left, bottom_right, IM_COL32(255, 0, 0, 255)); } ImGui::End(); ImGui::ShowDemoWindow(); }