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
|
||||
{
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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 ){
|
||||
|
|
@ -135,8 +210,6 @@ struct camera_t
|
|||
{
|
||||
int width, height;
|
||||
|
||||
bool timing;
|
||||
|
||||
Vector3 origin;
|
||||
Vector3 angles;
|
||||
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
@ -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 ),
|
||||
|
|
@ -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 ){
|
||||
}
|
||||
};
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
@ -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 */
|
||||
|
|
@ -454,14 +520,12 @@ 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;
|
||||
}
|
||||
|
|
@ -469,7 +533,7 @@ void Camera_setMovementFlags( camera_t& camera, unsigned int 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;
|
||||
}
|
||||
|
|
@ -657,6 +721,7 @@ public:
|
|||
|
||||
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 ){
|
||||
|
|
@ -896,7 +961,7 @@ public:
|
|||
rect_t m_XORRect;
|
||||
|
||||
DeferredDraw m_deferredDraw;
|
||||
DeferredMotion m_deferred_motion;
|
||||
DeferredMotion2 m_deferred_motion;
|
||||
|
||||
Timer m_render_time;
|
||||
|
||||
|
|
@ -1578,6 +1643,7 @@ protected:
|
|||
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{
|
||||
;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user