manage camera events queue
fixes impossibility of wasd + freelook in linux fixes jagged focused orbiting
This commit is contained in:
parent
4010e94bec
commit
f7a33dd4d3
|
|
@ -48,6 +48,26 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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
|
class DeferredMotionDelta
|
||||||
{
|
{
|
||||||
QMouseEvent m_mouseMoveEvent;
|
QMouseEvent m_mouseMoveEvent;
|
||||||
|
|
@ -79,6 +99,32 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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
|
class FreezePointer : public QObject
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,81 @@
|
||||||
|
|
||||||
#include <QOpenGLWidget>
|
#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;
|
Signal0 g_cameraMoved_callbacks;
|
||||||
|
|
||||||
void AddCameraMovedCallback( const SignalHandler& handler ){
|
void AddCameraMovedCallback( const SignalHandler& handler ){
|
||||||
|
|
@ -135,8 +210,6 @@ struct camera_t
|
||||||
{
|
{
|
||||||
int width, height;
|
int width, height;
|
||||||
|
|
||||||
bool timing;
|
|
||||||
|
|
||||||
Vector3 origin;
|
Vector3 origin;
|
||||||
Vector3 angles;
|
Vector3 angles;
|
||||||
|
|
||||||
|
|
@ -159,17 +232,17 @@ struct camera_t
|
||||||
|
|
||||||
unsigned int movementflags; // movement flags
|
unsigned int movementflags; // movement flags
|
||||||
Timer m_keycontrol_timer;
|
Timer m_keycontrol_timer;
|
||||||
QTimer m_keycontrol_caller;
|
|
||||||
float m_keymove_speed_current;
|
float m_keymove_speed_current;
|
||||||
|
|
||||||
|
|
||||||
static float fieldOfView;
|
static float fieldOfView;
|
||||||
static const float near_z;
|
static const float near_z;
|
||||||
|
|
||||||
DeferredMotionDelta m_mouseMove;
|
DeferredMotionDelta2 m_mouseMove;
|
||||||
|
|
||||||
View* m_view;
|
View* m_view;
|
||||||
Callback m_update;
|
Callback m_update;
|
||||||
|
IdleDraw2 m_idleDraw;
|
||||||
|
|
||||||
Callback1<const MotionDeltaValues&> m_update_motion_freemove;
|
Callback1<const MotionDeltaValues&> m_update_motion_freemove;
|
||||||
|
|
||||||
|
|
@ -178,7 +251,6 @@ struct camera_t
|
||||||
camera_t( View* view, const Callback& update, const Callback1<const MotionDeltaValues&>& update_motion_freemove ) :
|
camera_t( View* view, const Callback& update, const Callback1<const MotionDeltaValues&>& update_motion_freemove ) :
|
||||||
width( 0 ),
|
width( 0 ),
|
||||||
height( 0 ),
|
height( 0 ),
|
||||||
timing( false ),
|
|
||||||
origin( 0, 0, 0 ),
|
origin( 0, 0, 0 ),
|
||||||
angles( 0, 0, 0 ),
|
angles( 0, 0, 0 ),
|
||||||
color( 0, 0, 0 ),
|
color( 0, 0, 0 ),
|
||||||
|
|
@ -187,6 +259,7 @@ struct camera_t
|
||||||
m_mouseMove( [this]( int x, int y, const QMouseEvent& event ){ Camera_mouseMove( *this, x, y, event ); } ),
|
m_mouseMove( [this]( int x, int y, const QMouseEvent& event ){ Camera_mouseMove( *this, x, y, event ); } ),
|
||||||
m_view( view ),
|
m_view( view ),
|
||||||
m_update( update ),
|
m_update( update ),
|
||||||
|
m_idleDraw( update ),
|
||||||
m_update_motion_freemove( update_motion_freemove ){
|
m_update_motion_freemove( update_motion_freemove ){
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -364,7 +437,6 @@ void Camera_mouseMove( camera_t& camera, int x, int y, const QMouseEvent& event
|
||||||
//globalOutputStream() << "mousemove... ";
|
//globalOutputStream() << "mousemove... ";
|
||||||
Camera_FreeMove( camera, -x, -y );
|
Camera_FreeMove( camera, -x, -y );
|
||||||
camera.m_update_motion_freemove( MotionDeltaValues( x, y, event ) );
|
camera.m_update_motion_freemove( MotionDeltaValues( x, y, event ) );
|
||||||
camera.m_update();
|
|
||||||
CameraMovedNotify();
|
CameraMovedNotify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -440,12 +512,6 @@ void Cam_KeyControl( camera_t& camera, float dtime ){
|
||||||
}
|
}
|
||||||
|
|
||||||
void Camera_keyMove( camera_t& camera ){
|
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... ";
|
//globalOutputStream() << "keymove... ";
|
||||||
float time_seconds = camera.m_keycontrol_timer.elapsed_sec();
|
float time_seconds = camera.m_keycontrol_timer.elapsed_sec();
|
||||||
if( time_seconds == 0 ) /* some reasonable move at the very start */
|
if( time_seconds == 0 ) /* some reasonable move at the very start */
|
||||||
|
|
@ -454,14 +520,12 @@ void Camera_keyMove( camera_t& camera ){
|
||||||
|
|
||||||
Cam_KeyControl( camera, time_seconds );
|
Cam_KeyControl( camera, time_seconds );
|
||||||
|
|
||||||
camera.m_update();
|
|
||||||
CameraMovedNotify();
|
CameraMovedNotify();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Camera_setMovementFlags( camera_t& camera, unsigned int mask ){
|
void Camera_setMovementFlags( camera_t& camera, unsigned int mask ){
|
||||||
if ( ( ~camera.movementflags & mask ) != 0 && camera.movementflags == 0 ) {
|
if ( ( ~camera.movementflags & mask ) != 0 && camera.movementflags == 0 ) {
|
||||||
camera.m_keycontrol_caller.callOnTimeout( [&camera](){ Camera_keyMove( camera ); } );
|
camera.m_idleDraw.startLoop( ReferenceCaller<camera_t, Camera_keyMove>( camera ) );
|
||||||
camera.m_keycontrol_caller.start( 4 ); // with 0 consumes entire thread by spamming calls 🤷♀️
|
|
||||||
camera.m_keycontrol_timer.start();
|
camera.m_keycontrol_timer.start();
|
||||||
camera.m_keymove_speed_current = 0;
|
camera.m_keymove_speed_current = 0;
|
||||||
}
|
}
|
||||||
|
|
@ -469,7 +533,7 @@ void Camera_setMovementFlags( camera_t& camera, unsigned int mask ){
|
||||||
}
|
}
|
||||||
void Camera_clearMovementFlags( camera_t& camera, unsigned int mask ){
|
void Camera_clearMovementFlags( camera_t& camera, unsigned int mask ){
|
||||||
if ( ( camera.movementflags & ~mask ) == 0 && camera.movementflags != 0 ) {
|
if ( ( camera.movementflags & ~mask ) == 0 && camera.movementflags != 0 ) {
|
||||||
camera.m_keycontrol_caller.stop();
|
camera.m_idleDraw.breakLoop();
|
||||||
}
|
}
|
||||||
camera.movementflags &= ~mask;
|
camera.movementflags &= ~mask;
|
||||||
}
|
}
|
||||||
|
|
@ -657,6 +721,7 @@ public:
|
||||||
|
|
||||||
static void Camera_motionDelta( int x, int y, const QMouseEvent *event, camera_t& cam ){
|
static void Camera_motionDelta( int x, int y, const QMouseEvent *event, camera_t& cam ){
|
||||||
cam.m_mouseMove.motion_delta( x, y, event );
|
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 );
|
cam.m_orbit = ( event->modifiers() & Qt::KeyboardModifier::AltModifier ) && ( event->buttons() & Qt::MouseButton::RightButton );
|
||||||
if( cam.m_orbit ){
|
if( cam.m_orbit ){
|
||||||
|
|
@ -896,7 +961,7 @@ public:
|
||||||
rect_t m_XORRect;
|
rect_t m_XORRect;
|
||||||
|
|
||||||
DeferredDraw m_deferredDraw;
|
DeferredDraw m_deferredDraw;
|
||||||
DeferredMotion m_deferred_motion;
|
DeferredMotion2 m_deferred_motion;
|
||||||
|
|
||||||
Timer m_render_time;
|
Timer m_render_time;
|
||||||
|
|
||||||
|
|
@ -1578,6 +1643,7 @@ protected:
|
||||||
void mouseMoveEvent( QMouseEvent *event ) override {
|
void mouseMoveEvent( QMouseEvent *event ) override {
|
||||||
if( !m_camwnd.m_bFreeMove ){
|
if( !m_camwnd.m_bFreeMove ){
|
||||||
m_camwnd.m_deferred_motion.motion( event );
|
m_camwnd.m_deferred_motion.motion( event );
|
||||||
|
m_camwnd.getCamera().m_idleDraw.queueDraw( DeferredMotion2::InvokeCaller( m_camwnd.m_deferred_motion ), false );
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
;
|
;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user