Skip to content

Commit

Permalink
manage camera events queue
Browse files Browse the repository at this point in the history
fixes impossibility of wasd + freelook in linux
fixes jagged focused orbiting
  • Loading branch information
Garux committed Nov 7, 2022
1 parent 4010e94 commit f7a33dd
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 17 deletions.
46 changes: 46 additions & 0 deletions libs/gtkutil/cursor.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,26 @@ class DeferredMotion
}
};

class DeferredMotion2
{
QMouseEvent m_mouseMoveEvent;
const std::function<void( const QMouseEvent& )> m_func;
public:
template<class Functor>
DeferredMotion2( Functor func ) :
m_mouseMoveEvent( QEvent::MouseMove, QPointF(), Qt::MouseButton::NoButton, Qt::MouseButtons(), Qt::KeyboardModifiers() ),
m_func( func )
{
}
void motion( const QMouseEvent *event ){
m_mouseMoveEvent = *event;
}
void invoke(){
m_func( m_mouseMoveEvent );
}
typedef MemberCaller<DeferredMotion2, &DeferredMotion2::invoke> InvokeCaller;
};

class DeferredMotionDelta
{
QMouseEvent m_mouseMoveEvent;
Expand Down Expand Up @@ -79,6 +99,32 @@ class DeferredMotionDelta
}
};

class DeferredMotionDelta2
{
QMouseEvent m_mouseMoveEvent;
std::function<void( int, int, const QMouseEvent& )> m_func;
int m_delta_x = 0;
int m_delta_y = 0;
public:
template<class Functor>
DeferredMotionDelta2( Functor func ) :
m_mouseMoveEvent( QEvent::MouseMove, QPointF(), Qt::MouseButton::NoButton, Qt::MouseButtons(), Qt::KeyboardModifiers() ),
m_func( func )
{
}
void motion_delta( int x, int y, const QMouseEvent *event ){
m_delta_x += x;
m_delta_y += y;
m_mouseMoveEvent = *event;
}
void invoke(){
m_func( m_delta_x, m_delta_y, m_mouseMoveEvent );
m_delta_x = 0;
m_delta_y = 0;
}
typedef MemberCaller<DeferredMotionDelta2, &DeferredMotionDelta2::invoke> InvokeCaller;
};



class FreezePointer : public QObject
Expand Down
100 changes: 83 additions & 17 deletions radiant/camwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,81 @@

#include <QOpenGLWidget>

#include <QApplication>

// https://stackoverflow.com/questions/42566421/how-to-queue-lambda-function-into-qts-event-loop/42566867#42566867
template <typename Fun> void postCall( QObject * obj, Fun && fun ) {
// qDebug() << __FUNCTION__;
struct Event : public QEvent {
using F = typename std::decay<Fun>::type;
F fun;
Event( F && fun ) : QEvent( QEvent::None ), fun( std::move( fun ) ) {}
Event( const F & fun ) : QEvent( QEvent::None ), fun( fun ) {}
~Event() { fun(); }
};
QCoreApplication::postEvent(
obj->thread() ? obj : qApp, new Event( std::forward<Fun>( fun ) ) );
}

class IdleDraw2 : public QObject
{
Callback m_redraw;
std::vector<Callback> m_funcs;
Callback m_loopFunc;
bool m_running{};
bool m_queued{};
bool m_redrawDo{};

void invoke(){
if( !m_running ){
m_running = true;
for( auto& f : m_funcs )
f();
m_funcs.clear();
m_loopFunc();
if( m_redrawDo )
m_redraw();
}
else
globalWarningStream() << "invoke() during m_running\n";

m_running = false;
m_queued = false;
m_redrawDo = false;

doLoop();
}
public:
IdleDraw2( const Callback& redrawCallback ) : m_redraw( redrawCallback ){}
void queueDraw( const Callback& func, bool redrawDo ){
if( !m_running ){
if( std::find( m_funcs.cbegin(), m_funcs.cend(), func ) == m_funcs.cend() ){
m_funcs.push_back( func );
// globalOutputStream() << m_funcs.size() << " m_funcs.size()\n";
}
m_redrawDo |= redrawDo;
if( !m_queued ){
m_queued = true;
postCall( this, [this](){ invoke(); } );
}
}
else
globalWarningStream() << "queueDraw() during m_running\n";
}
void startLoop( const Callback& func ){
m_loopFunc = func;
doLoop();
}
void doLoop(){
if( m_loopFunc != Callback() )
queueDraw( Callback(), true );
}
void breakLoop(){
m_loopFunc = {};
}
};


Signal0 g_cameraMoved_callbacks;

void AddCameraMovedCallback( const SignalHandler& handler ){
Expand Down Expand Up @@ -135,8 +210,6 @@ struct camera_t
{
int width, height;

bool timing;

Vector3 origin;
Vector3 angles;

Expand All @@ -159,17 +232,17 @@ struct camera_t

unsigned int movementflags; // movement flags
Timer m_keycontrol_timer;
QTimer m_keycontrol_caller;
float m_keymove_speed_current;


static float fieldOfView;
static const float near_z;

DeferredMotionDelta m_mouseMove;
DeferredMotionDelta2 m_mouseMove;

View* m_view;
Callback m_update;
IdleDraw2 m_idleDraw;

Callback1<const MotionDeltaValues&> m_update_motion_freemove;

Expand All @@ -178,7 +251,6 @@ struct camera_t
camera_t( View* view, const Callback& update, const Callback1<const MotionDeltaValues&>& update_motion_freemove ) :
width( 0 ),
height( 0 ),
timing( false ),
origin( 0, 0, 0 ),
angles( 0, 0, 0 ),
color( 0, 0, 0 ),
Expand All @@ -187,6 +259,7 @@ struct camera_t
m_mouseMove( [this]( int x, int y, const QMouseEvent& event ){ Camera_mouseMove( *this, x, y, event ); } ),
m_view( view ),
m_update( update ),
m_idleDraw( update ),
m_update_motion_freemove( update_motion_freemove ){
}
};
Expand Down Expand Up @@ -364,7 +437,6 @@ void Camera_mouseMove( camera_t& camera, int x, int y, const QMouseEvent& event
//globalOutputStream() << "mousemove... ";
Camera_FreeMove( camera, -x, -y );
camera.m_update_motion_freemove( MotionDeltaValues( x, y, event ) );
camera.m_update();
CameraMovedNotify();
}

Expand Down Expand Up @@ -440,12 +512,6 @@ void Cam_KeyControl( camera_t& camera, float dtime ){
}

void Camera_keyMove( camera_t& camera ){
// globalOutputStream() << camera.m_keycontrol_timer.elapsed_sec() << '\n';
if( camera.m_keycontrol_timer.elapsed_msec() == 0 ) // a lot of zeros happen = torn, slow, inconsistent motion 🤔
return;

camera.m_mouseMove.flush();

//globalOutputStream() << "keymove... ";
float time_seconds = camera.m_keycontrol_timer.elapsed_sec();
if( time_seconds == 0 ) /* some reasonable move at the very start */
Expand All @@ -454,22 +520,20 @@ void Camera_keyMove( camera_t& camera ){

Cam_KeyControl( camera, time_seconds );

camera.m_update();
CameraMovedNotify();
}

void Camera_setMovementFlags( camera_t& camera, unsigned int mask ){
if ( ( ~camera.movementflags & mask ) != 0 && camera.movementflags == 0 ) {
camera.m_keycontrol_caller.callOnTimeout( [&camera](){ Camera_keyMove( camera ); } );
camera.m_keycontrol_caller.start( 4 ); // with 0 consumes entire thread by spamming calls 🤷‍♀️
camera.m_idleDraw.startLoop( ReferenceCaller<camera_t, Camera_keyMove>( camera ) );
camera.m_keycontrol_timer.start();
camera.m_keymove_speed_current = 0;
}
camera.movementflags |= mask;
}
void Camera_clearMovementFlags( camera_t& camera, unsigned int mask ){
if ( ( camera.movementflags & ~mask ) == 0 && camera.movementflags != 0 ) {
camera.m_keycontrol_caller.stop();
camera.m_idleDraw.breakLoop();
}
camera.movementflags &= ~mask;
}
Expand Down Expand Up @@ -657,6 +721,7 @@ class RadiantCameraView : public CameraView

static void Camera_motionDelta( int x, int y, const QMouseEvent *event, camera_t& cam ){
cam.m_mouseMove.motion_delta( x, y, event );
cam.m_idleDraw.queueDraw( DeferredMotionDelta2::InvokeCaller( cam.m_mouseMove ), true );

cam.m_orbit = ( event->modifiers() & Qt::KeyboardModifier::AltModifier ) && ( event->buttons() & Qt::MouseButton::RightButton );
if( cam.m_orbit ){
Expand Down Expand Up @@ -896,7 +961,7 @@ class CamWnd
rect_t m_XORRect;

DeferredDraw m_deferredDraw;
DeferredMotion m_deferred_motion;
DeferredMotion2 m_deferred_motion;

Timer m_render_time;

Expand Down Expand Up @@ -1578,6 +1643,7 @@ class CamGLWidget : public QOpenGLWidget
void mouseMoveEvent( QMouseEvent *event ) override {
if( !m_camwnd.m_bFreeMove ){
m_camwnd.m_deferred_motion.motion( event );
m_camwnd.getCamera().m_idleDraw.queueDraw( DeferredMotion2::InvokeCaller( m_camwnd.m_deferred_motion ), false );
}
else{
;
Expand Down

0 comments on commit f7a33dd

Please sign in to comment.