mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-12 06:32:09 +00:00
ifcviewer: add Shift+F fly-mode camera
WASD strafe, Q/E down/up, mouse-look (cursor hidden + recentered), Shift to sprint, scrollwheel scales speed, click or Esc returns to orbit. Exiting drops back to the same viewpoint because rotation re-pins camera_target_ to keep camera_eye_ stationary. Movement integrates wall-clock dt inside render() and the next frame self-schedules via requestUpdate() while any key is held. A QTimer would fight Qt's event loop during long swapBuffers blocks and produce "camera pauses one frame" stalls; render-driven integration keeps movement phase-locked to vsync and absorbs slow frames in a single catch-up step. IFC_FPS_HITCH_MS=<n> logs frames slower than n ms while in fly mode. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -26,6 +26,7 @@
|
||||
#include <QElapsedTimer>
|
||||
#include <QMatrix4x4>
|
||||
#include <QVector3D>
|
||||
#include <QSet>
|
||||
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
@@ -192,6 +193,7 @@ protected:
|
||||
void exposeEvent(QExposeEvent* event) override;
|
||||
void resizeEvent(QResizeEvent* event) override;
|
||||
void keyPressEvent(QKeyEvent* event) override;
|
||||
void keyReleaseEvent(QKeyEvent* event) override;
|
||||
bool event(QEvent* event) override;
|
||||
|
||||
private:
|
||||
@@ -273,6 +275,24 @@ private:
|
||||
void handleMouseMove(QMouseEvent* event);
|
||||
void handleWheel(QWheelEvent* event);
|
||||
|
||||
// FPS/fly mode. Toggled with Shift+F; exits on any mouse click or Esc.
|
||||
// While active, WASD translates the camera in view-space, Q/E moves
|
||||
// world-down/up, mouse rotates the view (cursor hidden + recentered each
|
||||
// move), Shift accelerates, and the wheel scales the base move speed
|
||||
// instead of zooming. The underlying orbit state is preserved: movement
|
||||
// translates camera_target_ and rotation re-pins it so camera_eye_ stays
|
||||
// put, so exiting drops the user back into orbit at the same viewpoint.
|
||||
//
|
||||
// Movement is integrated inside render() using wall-clock dt and the
|
||||
// next frame is requestUpdate()'d while any movement key is held — that
|
||||
// way one long frame only produces a single catch-up step instead of
|
||||
// also missing a QTimer tick.
|
||||
enum class CameraMode { Orbit, Fps };
|
||||
void enterFpsMode();
|
||||
void exitFpsMode();
|
||||
void fpsIntegrate(); // called from render()
|
||||
void recenterFpsCursor();
|
||||
|
||||
QOpenGLContext* context_ = nullptr;
|
||||
QOpenGLFunctions_4_5_Core* gl_ = nullptr;
|
||||
bool gl_initialized_ = false;
|
||||
@@ -383,6 +403,16 @@ private:
|
||||
Qt::MouseButton active_button_ = Qt::NoButton;
|
||||
QPoint last_mouse_pos_;
|
||||
|
||||
// FPS/fly mode state. fps_keys_held_ tracks WASD/QE/Shift between
|
||||
// press+release; fps_last_tick_ gates dt inside render().
|
||||
// fps_ignore_next_mouse_move_ swallows the synthetic MouseMove that
|
||||
// QCursor::setPos() generates after we recenter.
|
||||
CameraMode camera_mode_ = CameraMode::Orbit;
|
||||
QSet<int> fps_keys_held_;
|
||||
float fps_move_speed_ = 5.0f; // m/s at speed=1
|
||||
QElapsedTimer fps_last_tick_;
|
||||
bool fps_ignore_next_mouse_move_ = false;
|
||||
|
||||
// Selection
|
||||
uint32_t selected_object_id_ = 0;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user