How to make a QGLWidget a real time game loop?



  • I am trying to make my runtime window a real time window,
    I know that many demos use a timer to send and updates message to a WGLWdiget like this
    @m_animationTimer.setSingleShot(false);
    connect(&m_animationTimer, SIGNAL(timeout()), this, SLOT(OnIdle()));
    m_animationTimer.start(2);@

    However the timer method has few short comings:
    First the granularity is too course (milliseconds instead of microsecond).
    Second it requires lots of management when you want to stop for example to do some other actions.
    the timer keeps sending even to the update in the middle of other operations, and you end up with flags and other stuff
    just to control the logic.

    Usually other GUIs have an event that is called when the system have no more Event in the event Queue. So to set a Real time Update all the client application need to do is to trap the Idle Event and from there send the Update to the Gl window.
    This automatically controls the event queue to never overflow and the also the update stop each time
    any other message is send to the system.
    I am assuming that QT also have to have and Idle Event that is call when no more message are pendim, but I cannot find it.
    Can someone tell me how to do this, please?



  • What I am doing is that I am setting my Own Even Handle
    @class newtonDemosEventFilter: public QObject
    {
    Q_OBJECT
    protected:
    bool eventFilter(QObject *obj, QEvent *ev);
    };

    bool newtonDemosEventFilter::eventFilter(QObject *obj, QEvent *ev)
    {
    // I want to know what code is the one for want the application is Idle so thar I can send one even to update my WGLWidget
    if (ev->type() == QEvent::What_is_the_Idle_Evene?) {
    // what event to send to force a WGLWidget update?
    }

    return QObject::eventFilter(obj, ev);
    }

    int main(int argc, char *argv[])
    {
    // Enable run-time memory check for debug builds.
    #ifdef _MSC_VER
    _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
    #endif

    // Set the memory allocation function before creation the newton world
    // this is the only function that can be called before the creation of the newton world.
    // it should be called once, and the the call is optional
    NewtonSetMemorySystem (newtonDemos::PhysicsAlloc, newtonDemos::PhysicsFree);

    QApplication aplication(argc, argv);
    newtonDemosEventFilter filter;

    newtonDemos demos;
    demos.show();

    aplication.installEventFilter(&filter);
    return aplication.exec();
    }@
    But I am stoked find the idle event.


  • Moderators

    I really do not understand what you want to do. Why would you want to paint whenever the event loop is empty?

    I do understand a "paint after each event" or "paint x frames per second", but why would you want to paint whenever the event queue is empty?

    PS: How is 'render whenever the event queue happens to be empty' realtime?



  • Whent you are making an application like a video Game or a performace measuring tool, you need the application to update as fast as it can. That is why you draw after all events are processed.
    It is a very standrad operation in all operating system and all GUIs I know.

    A timer is a very, very bad Idea.





  • I see that class QAbstractEventDispatcher seems to have what I look for,
    but hwo do I use that class
    I do not see a single example using a class like tha in the demos.

    I tryed this
    @//class newtonDemosEventFilter: public QObject
    class newtonDemosEventFilter: public QAbstractEventDispatcher
    {
    Q_OBJECT
    protected:
    bool eventFilter(QObject *obj, QEvent *ev);
    };@

    but all I get is a bunch of errors.



  • for what I can see thsi si too low level, It is asking me to impelmnet all thsi funtions

    bq. 1> due to following members:
    1> 'bool QAbstractEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags)' : is abstract
    1> c:\newton-dynamics_new\packages\thirdparty\qt\4.7.1\include\qtcore../../src/corelib/kernel/qabstracteventdispatcher.h(71) : see declaration of 'QAbstractEventDispatcher::processEvents'
    1> 'bool QAbstractEventDispatcher::hasPendingEvents(void)' : is abstract
    1> c:\newton-dynamics_new\packages\thirdparty\qt\4.7.1\include\qtcore../../src/corelib/kernel/qabstracteventdispatcher.h(72) : see declaration of 'QAbstractEventDispatcher::hasPendingEvents'
    1> 'void QAbstractEventDispatcher::registerSocketNotifier(QSocketNotifier *)' : is abstract
    1> c:\newton-dynamics_new\packages\thirdparty\qt\4.7.1\include\qtcore../../src/corelib/kernel/qabstracteventdispatcher.h(74) : see declaration of 'QAbstractEventDispatcher::registerSocketNotifier'
    1> 'void QAbstractEventDispatcher::unregisterSocketNotifier(QSocketNotifier *)' : is abstract
    1> c:\newton-dynamics_new\packages\thirdparty\qt\4.7.1\include\qtcore../../src/corelib/kernel/qabstracteventdispatcher.h(75) : see declaration of 'QAbstractEventDispatcher::unregisterSocketNotifier'
    1> 'void QAbstractEventDispatcher::registerTimer(int,int,QObject *)' : is abstract
    1> c:\newton-dynamics_new\packages\thirdparty\qt\4.7.1\include\qtcore../../src/corelib/kernel/qabstracteventdispatcher.h(78) : see declaration of 'QAbstractEventDispatcher::registerTimer'
    1> 'bool QAbstractEventDispatcher::unregisterTimer(int)' : is abstract
    1> c:\newton-dynamics_new\packages\thirdparty\qt\4.7.1\include\qtcore../../src/corelib/kernel/qabstracteventdispatcher.h(79) : see declaration of 'QAbstractEventDispatcher::unregisterTimer'
    1> 'bool QAbstractEventDispatcher::unregisterTimers(QObject *)' : is abstract
    1> c:\newton-dynamics_new\packages\thirdparty\qt\4.7.1\include\qtcore../../src/corelib/kernel/qabstracteventdispatcher.h(80) : see declaration of 'QAbstractEventDispatcher::unregisterTimers'
    1> 'QList<T> QAbstractEventDispatcher::registeredTimers(QObject *) const' : is abstract
    1> with

    I am lost here, this is so eassy to do in Windows and WxWidget,
    there has to be a way to do this eassy in Qt.
    so far everything else has being very eassy.



  • From Qt's documentation:
    A QTimer with a timeout interval of 0 will time out as soon as all the events in the window system's event queue have been processed.



  • @
    connect(QAbstractEventDispatcher::instance(), SIGNAL(aboutToBlock()),
    this, SLOT(onAboutToBlock()));
    @



  • I saw that but when I do this

    @m_animationTimer.setSingleShot(false);
    connect(&m_animationTimer, SIGNAL(timeout()), this, SLOT(OnIdle()));
    m_animationTimer.start(0);@
    [quote author="kkrzewniak" date="1297960472"]From Qt's documentation: A QTimer with a timeout interval of 0 will time out as soon as all the events in the window system's event queue have been processed.[/quote]
    I saw that but this is what I was explaining above, the timer send events asynchronously even when other event are being proccesed, not when the queue is empty.
    This is importnat because this application is running a sevral threads on teh background.
    if for example I go to the menu and a Load a different scene, the render should stops,
    but is does not so the mommnet I click I get all kind of rasing conditions.
    I suppose I can fix that but tha was not nessesary before.

    when I set it to this
    @ m_animationTimer.setSingleShot(false);
    connect(&m_animationTimer, SIGNAL(timeout()), this, SLOT(OnIdle()));
    m_animationTimer.start(0);
    @

    It update as fast as it can, but still have the problem that if you click on en menu for example the timer still update send even and it should stops, because there are other events with higher priority.
    Basically I need the updates if and only if when the system has nothing else to do.

    To Bradley I see it is a signal, I read the explanation of that signal and it is no clear to me by I will experiment with that,
    I see that there are other signals as well.



  • [quote author="Bradley" date="1297960977"]@ connect(QAbstractEventDispatcher::instance(), SIGNAL(aboutToBlock()), this, SLOT(onAboutToBlock())); @[/quote]

    That does part of what I want but still not exacty, because it does update as fas as it can
    however it still send the same sinal when I click on the menu.
    I need tha teh signal to be the lowest possible priority of all signals.

    Maybe I did it wrong, I implemenetd like this

    @connect(QAbstractEventDispatcher::instance(), SIGNAL(aboutToBlock()), this, SLOT(OnIdle()));

    ...

    void newtonDemos::OnIdle()
    {
    m_canvas->update();
    }@

    is that how is supposet to be?



  • You are probably causing a cycle. The update() call will probably post an UpdateRequest event, and after it is processed (and any other events), the aboutToBlock signal will be sent again, which will cause another update() call.



  • so I though somethomg liek this shopuld do it, but it does not

    @void newtonDemos::OnIdle()
    {
    static bool updateCanvas;
    if (updateCanvas) {
    updateCanvas = true;
    m_canvas->update();
    updateCanvas = false;
    }
    }@

    what does "a funtion that coul block" means?
    bq. This signal is emitted after the event loop returns from a function that could block.



  • For what I can see the only way I can do this is by having a bool that is toggled on each action/slot,
    and that does not sound like an elegant or atractive solution.

    I can not beleive this is not a trivial operation in Qt.
    This is the default behavior in window



  • I can upload the two application to my server and post a link to it maybe some one can
    take a look and tell me how to do what I want.
    the window and the QT.



  • Well I could not find a clean way to do it, but it does no matter, I can acomplishe the same in diffrnet way
    I end up doing this

    @void newtonDemos::OnIdle()
    {
    if (m_doVisualUpdates) {
    m_canvas->update();
    }
    }@

    and I set m_doVisualUpdates on and off on eh relvane Menu actions.
    It is still better than using a timer, and I also learned a lot about trapping events wih Qt.
    Thank every one for the help.



  • Hello I am here again with the same problem but this time in different OS.

    If you remember you told me that adding this action will make my display to refresh perpetually as fast as the system can

    In my init window I added this
    @// create the render window
    m_canvas = new DemoEntityManager (this, glFormat);
    setCentralWidget(m_canvas);

    connect(QAbstractEventDispatcher::instance(), SIGNAL(aboutToBlock()), this, SLOT(OnIdle())); @

    The idle function is this

    @void newtonDemos::OnIdle()
    {
    if (m_doVisualUpdates) {
    m_canvas->update();
    }
    }@

    m_doVisualUpdates is set to true.
    This works beatifully on all windows systems and all Linux 32 and 64 system a tested,
    But on the Mac it fails to call OnIdle.
    OnIdle is only called once and after that only whne some event happens, like moving the mouce or touching a key.

    Is there something different on the Mac that does not refresh like is does on other OS?
    If so how do I make a Game loop on a Mac running OS X?


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.