views:

483

answers:

3

I am currently playing with QT trying to set up a small particle system. Therein I've subclassed the GLWidget and hacked away at it. Everything was going well until I made some unknown change and now the widget only repaints when I move the mouse (it should be doing it all the time due to the QTimer I have firing). Relevant code:

OpenGLWidget.h

class OpenGLWidget :  public QGLWidget  {

   Q_OBJECT

public:
   OpenGLWidget(QWidget * parent = 0);
   ~OpenGLWidget();

public slots:
   void toggleEmitter();

protected:
   void initializeGL();
   void paintGL();
   void resizeGL(int width, int height);
   QSize minimumSizeHint() const;
   QSize sizeHint() const;
   void mousePressEvent(QMouseEvent *event);
   void mouseMoveEvent(QMouseEvent *event);

protected slots:
   void timeOut();

private:

   void testFunc(Particle & p, unsigned int t);

   QTime time;
   QTimer timer;

   Emitter emitter;

Relevant code from the .cpp

// in the constructor
time.start();
connect(&timer, SIGNAL(timeout()), this, SLOT(timeOut()));
timer.start(0);

void OpenGLWidget::initializeGL()  {
   GLuint tex = 0;

   qglClearColor(bgColor);
   glEnable(GL_DEPTH_TEST);   
   glClearDepth(1.0f);
    glDepthFunc(GL_LEQUAL);
   glShadeModel(GL_SMOOTH); 

   glDisable(GL_CULL_FACE);
   glEnable(GL_TEXTURE_2D); 
   glEnable( GL_BLEND );
   glBlendFunc( GL_SRC_ALPHA, GL_ONE); // _MINUS_SRC_ALPHA );

   glPointSize(3.0f);

   tex = bindTexture(QPixmap(QString("testparticle2.png")), GL_TEXTURE_2D);
   emitter = Emitter(Vector(0, 0, 0.0f), tex, 50, fastdelegate::FastDelegate2<Particle &, unsigned int>(this, &OpenGLWidget::testFunc));
}

void OpenGLWidget::paintGL()  {
   makeCurrent();
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

   mainCam.SetView();

   glRotatef(xRot, 1, 0, 0);
   glRotatef(yRot, 0, 1, 0);

   emitter.Process(time.elapsed());

   totalTime += time.elapsed();
   time.restart();

}

void OpenGLWidget::resizeGL(int width, int height)  {
   contextWidth = width;
   contextHeight = height;

   glViewport(0, 0, width, height);

   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   gluPerspective(55.0f, width / (float) height, 0.01f, 100.0f);

   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();

}

void OpenGLWidget::timeOut()  {
   updateGL();
}

void OpenGLWidget::mousePressEvent(QMouseEvent *event)  {
    lastX = event->pos().x();
    lastY = event->pos().y();
}

void OpenGLWidget::mouseMoveEvent(QMouseEvent *event)  {
    int dx = event->x() - lastX;
    int dy = event->y() - lastY;

    if (event->buttons() & Qt::LeftButton) {
        xRot += 3 * dy;
        yRot += 3 * dx;
    } else if (event->buttons() & Qt::RightButton) {
        xRot += 3 * dy;
        yRot += 3 * dx;
    }

    lastX = event->pos().x();
    lastY = event->pos().y();

}
+1  A: 

considering that updateGL() calls glDraw() which calls paintGL(), you'd think the timer should be calling the same functionality as your mousemove event.

Are you sure the timer is actually ticking?

BTW, there is no need to call makeCurrent() in paintGL().

edit: after the extra information was added:

QTimer says:

"As a special case, a QTimer with timeout 0 times out as soon as all the events in the window system's event queue have been processed."

so, if you want it to go as fast as possible (though 10ms is probably the minimum on Windows and most x386-based systems), then start your timer with a value of 1 instead of 0. I assume that this is the problem, that its only ticking when it has finished reading off messages from the queue.

gbjbaanb
makeCurrent was there for debugging purposes. It turns out the timer is ticking but the time step is not updating correctly except when the mouse is being moved.
Ron Warholic
Try a non-zero time step? 1/60th of a second is ~17 msec.
jblocksom
A: 

A time step of 20ms gives me reasonably smooth motion, however at lower time steps the motion becomes choppy to the point of halting unless the mouse is in motion. I'd much prefer to keep a time step of zero (which should process as fast as possible). Any other ideas?

Ron Warholic
+1  A: 

A QTimer with 0 second time out only fires when the event loop gets the control. I suspect this is not the case. However, when you move the mouse, the event loop processes some events (again) and then delivers the pending timer event(s). Maybe you need to invoke processEvents() in your update loop to make sure that the pending timer event from QTimer gets processed.

Ariya Hidayat