Getting round: the wheel closes in on what's under the mouse (an object, the ground; the sky: on that way), the whole camera with it, so far from everything it no longer creeps at a spot in the air; arrow keys move along the ground, Page Up / Down up and down (a flat view: closer, further), Shift faster; fry_hold and fry_wheel to try them; crash dumps and a.out out of the repository and ignored

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Nexoniarz 2026-10-21 09:19:13 +02:00
commit de749dba11
13 changed files with 54 additions and 4 deletions

4
.gitignore vendored
View file

@ -4,3 +4,7 @@ build/
__pycache__/
*.fry~
dist/
# crash dumps and stray test programs
core.[0-9]*
a.out

View file

@ -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.

0
a.out
View file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -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_);

View file

@ -1463,6 +1463,7 @@ private:
int left = 0;
std::vector<double> ms;
} bench_;
std::vector<std::pair<ImGuiKey, int>> holding_; // (fry_hold: keys held down for that many more frames)
void benchStep();
void benchEnd(std::chrono::steady_clock::time_point began);

View file

@ -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"}});

View file

@ -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<glm::vec3> 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();
}