diff --git a/.gitignore b/.gitignore index a1ee074..ca88d80 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,7 @@ build/ __pycache__/ *.fry~ dist/ + +# crash dumps and stray test programs +core.[0-9]* +a.out diff --git a/README.md b/README.md index eb16ad6..b50ee1d 100644 --- a/README.md +++ b/README.md @@ -102,6 +102,8 @@ Five tabs along the top: **Model**, **Paint**, **Layout**, **Render**, **Print** - **Layout tab**: move, turn and size the flat frames of the surface yourself; the paint follows. **Seeing it** +- **Getting round**: right drag orbits, middle drag pans, the wheel goes towards what's under the + mouse; the **arrow keys** move you along the ground (Page Up / Down: up and down, Shift: faster). - **Solid** view for modelling, **Rendered** with a real sky, sun and soft shadows (Z). Wireframe (Shift+Z), X-ray (Alt+Z). The Render tab: the sun, sky, ground, brightness, shadows, glow; F12 saves a picture of just the view. diff --git a/a.out b/a.out deleted file mode 100755 index e69de29..0000000 diff --git a/core.35446 b/core.35446 deleted file mode 100644 index f679297..0000000 Binary files a/core.35446 and /dev/null differ diff --git a/core.35463 b/core.35463 deleted file mode 100644 index 9f663b1..0000000 Binary files a/core.35463 and /dev/null differ diff --git a/core.35933 b/core.35933 deleted file mode 100644 index 7b0c47c..0000000 Binary files a/core.35933 and /dev/null differ diff --git a/core.35947 b/core.35947 deleted file mode 100644 index 0acfa6a..0000000 Binary files a/core.35947 and /dev/null differ diff --git a/core.36411 b/core.36411 deleted file mode 100644 index e815dfa..0000000 Binary files a/core.36411 and /dev/null differ diff --git a/core.36564 b/core.36564 deleted file mode 100644 index f450b61..0000000 Binary files a/core.36564 and /dev/null differ diff --git a/src/app.cpp b/src/app.cpp index f9d1757..5a2d433 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -262,6 +262,21 @@ auto App::init() -> void { if (a.size() < 3) return self->say("fry_bench orbit|smooth|angle|round frames"); self->bench_ = {a[1], std::max(1, std::stoi(a[2])), {}}; }, "Fry3DX: fry_bench orbit|smooth|angle|round frames: time that many frames while the camera turns or the picked object's setting is dragged"); + static keel::Cmd hold("fry_hold", [](const keel::Args& a) { // a key held down for some frames, as if pressed (for trying keys out) + if (a.size() < 3) return self->say("fry_hold key frames (UpArrow, PageUp, LeftShift...)"); + for (int k = ImGuiKey_NamedKey_BEGIN; k < ImGuiKey_NamedKey_END; ++k) + if (a[1] == ImGui::GetKeyName(ImGuiKey(k))) { + ImGui::GetIO().AddKeyEvent(ImGuiKey(k), true); + return self->holding_.push_back({ImGuiKey(k), std::stoi(a[2])}); + } + self->say("fry_hold: no key called " + a[1]); + }, "Fry3DX: fry_hold key frames: hold a key down (UpArrow, PageUp...)"); + static keel::Cmd wheel("fry_wheel", [](const keel::Args& a) { // the wheel turned at x y (0..1 of the view) + if (a.size() < 4) return; + ImGuiIO& io = ImGui::GetIO(); + io.AddMousePosEvent(self->viewMin_.x + (self->viewMax_.x - self->viewMin_.x) * std::stof(a[1]), self->viewMin_.y + (self->viewMax_.y - self->viewMin_.y) * std::stof(a[2])); + io.AddMouseWheelEvent(0, std::stof(a[3])); + }, "Fry3DX: fry_wheel x y notches: the mouse wheel at that point of the view"); static keel::Cmd capture("fry_capture", [](const keel::Args& a) { if (a.size() > 1) self->savePicture(a[1]); }, "Fry3DX: save a picture of the view"); static keel::Cmd layout("fry_layout", [](const keel::Args& a) { Object* o = self->find(self->active_); @@ -460,6 +475,9 @@ auto App::onEscape() -> void { // (fry_bench) Each frame: the change being timed. auto App::benchStep() -> void { + for (auto& [k, left] : holding_) + if (--left <= 0) ImGui::GetIO().AddKeyEvent(k, false); + std::erase_if(holding_, [](const auto& h) { return h.second <= 0; }); if (bench_.left <= 0) return; const int i = int(bench_.ms.size()); Object* o = find(active_); diff --git a/src/app.h b/src/app.h index f101d67..de7eada 100644 --- a/src/app.h +++ b/src/app.h @@ -1463,6 +1463,7 @@ private: int left = 0; std::vector ms; } bench_; + std::vector> holding_; // (fry_hold: keys held down for that many more frames) void benchStep(); void benchEnd(std::chrono::steady_clock::time_point began); diff --git a/src/app_scripts.cpp b/src/app_scripts.cpp index f3a7f8e..c3d1a70 100644 --- a/src/app_scripts.cpp +++ b/src/app_scripts.cpp @@ -446,7 +446,8 @@ auto App::helpWindow() -> void { rows("Finding things", {{"F3 or Ctrl+Space", "Search for any command by name and run it"}, {"Space (held)", "The tools round the mouse: point at one, let go"}, {"Shift+Space (held)", "The views round the mouse"}}); myKeysTable(); - rows("Looking around", {{"Right drag", "Orbit round what you look at"}, {"Middle drag / Shift+Right drag", "Pan"}, {"Wheel", "Zoom (towards the mouse)"}, + rows("Looking around", {{"Right drag", "Orbit round what you look at"}, {"Middle drag / Shift+Right drag", "Pan"}, {"Wheel", "Zoom (towards what's under the mouse)"}, + {"Arrow keys", "Move round (Page Up / Down: up and down; Shift: faster)"}, {"Orbit / Pan / Zoom buttons", "Drag them (touchpads)"}, {"F", "Frame the selection"}, {"Home", "Frame everything"}, {"Numpad 1 / 3 / 7", "Front / side / top (Shift: the opposite)"}, {"Numpad 5", "Flat view / 3D"}, {"Z / Shift+Z", "Solid or Rendered / Wireframe"}, {"Alt+Z", "X-ray: see and pick through"}}); diff --git a/src/app_view.cpp b/src/app_view.cpp index b5f2aa3..d1257f4 100644 --- a/src/app_view.cpp +++ b/src/app_view.cpp @@ -194,11 +194,35 @@ auto App::updateCamera(ImGuiIO& io) -> void { findSoft(); message_ = std::format("Soft selection reaches {:.3f} m (wheel)", softReach_), messageAt_ = now(); } else if (inView && io.MouseWheel != 0) { - // Towards what's under the mouse: the target slides that way a little. + // Towards what's under the mouse: an object, else the ground, else the plane the target's + // on. The whole camera closes in on that point (it stays under the mouse), so far from + // everything you still get somewhere instead of creeping at a spot in the air. const float k = std::pow(0.85f, io.MouseWheel); const Ray ray = mouseRay(io.MousePos); - if (auto p = hitPlane(ray, target_, -viewDir())) target_ += (*p - target_) * (1.0f - k); - dist_ = std::clamp(dist_ * k, 0.01f, 5000.0f); + std::optional at; + if (const Hit h = pickObject(ray); h.object) at = ray.origin + ray.dir * h.t; + else if (auto g = hitPlane(ray, glm::vec3(0.0f), glm::vec3(0, 0, 1)); g && glm::distance(*g, eye_) < dist_ * 40.0f) at = g; + if (!at && k < 1.0f) target_ += ray.dir * dist_ * (1.0f - k); // (nothing there: the sky; on that way) + else { + if (!at) at = hitPlane(ray, target_, -viewDir()); + const float to = std::clamp(dist_ * k, 0.01f, 5000.0f); + if (at) target_ = *at + (target_ - *at) * (to / dist_); + dist_ = to; + } + } + // Arrow keys: forward, back and sideways along the ground (in a flat view: the way they + // point on the screen), Page Up / Down: up and down; Shift: faster. As fast as the view is big. + if (!io.WantTextInput && !search_.open && !ImGui::IsAnyItemActive() && !io.KeyCtrl && !io.KeyAlt) { + const float x = float(ImGui::IsKeyDown(ImGuiKey_RightArrow)) - float(ImGui::IsKeyDown(ImGuiKey_LeftArrow)); + const float y = float(ImGui::IsKeyDown(ImGuiKey_UpArrow)) - float(ImGui::IsKeyDown(ImGuiKey_DownArrow)); + const float z = float(ImGui::IsKeyDown(ImGuiKey_PageUp)) - float(ImGui::IsKeyDown(ImGuiKey_PageDown)); + if (x != 0 || y != 0 || z != 0) { + const glm::vec3 f = viewDir(), right = glm::normalize(glm::cross(f, std::abs(f.z) > 0.99f ? glm::vec3(std::cos(glm::radians(yaw_)), std::sin(glm::radians(yaw_)), 0) : glm::vec3(0, 0, 1))); + const glm::vec3 ahead = view_ == View::Perspective ? glm::normalize(glm::cross(glm::vec3(0, 0, 1), right)) : glm::cross(right, f); + const float dt = std::min(io.DeltaTime, 0.1f), speed = dist_ * (io.KeyShift ? 2.5f : 0.8f) * dt; + target_ += (right * x + ahead * y + (view_ == View::Perspective ? glm::vec3(0, 0, z) : glm::vec3(0.0f))) * speed; + if (view_ != View::Perspective && z != 0) dist_ = std::clamp(dist_ * std::pow(io.KeyShift ? 0.1f : 0.4f, z * dt), 0.01f, 5000.0f); // (flat: closer or further) + } } settleView(); }