Step-by-step on how to set up your CMake, Qt and OSG in draw-on-demand mode (Part 2)

4 minute read

Problem statement

This tutorial is a continuation of Part 1 where we provided a step-by-step on how to set up Qt with OpenSceneGraph (OSG) in on-demand redraw.

As a result, the previous tutorial provided a Qt-based widget which was able to display a content of an OSG scene. Although we associated the mouse manipulator with the OSG scene which is responsible for camera manipulations, it was not possible to manipulate the camera view because we did not provide any connection between the Qt mouse events and OSG mouse events. And that is what this tutorial focuses on.

How to trigger osgGA::EventQueue from QMouseEvent

At first, we have to include the necessary Qt mouse events header files:

#include <QMouseEvent>
#include <QWheelEvent>

The next step is to define what events of QOpenGLWidget are needed to be redefined. We can find the list of all methods of the widget at the Qt’s manual page. For our case we will only need:

  • mousePressEvent()
  • mouseReleaseEvent()
  • mouseMoveEvent()
  • wheelEvent()
  • event() - inherited from QWidget. It needs to be re-implemented so that to insure re-draw is performed after every user interaction.

event() method

We start from event method which calls an update() function every time there is an event from user:

virtual bool event(QEvent* event)
{
      bool handled = QOpenGLWidget::event(event);
      this->update();
      return handled;
}

Now we can re-define other Qt mouse events. The main idea is to obtain mouse parameters (for example, coordinates or pressed mouse button code) and use them to trigger OSG mouse events.

How to do it? Here we will get a help from getEventQueue() method (we showed how to implement it in Part 1 ) which returns an event queue from the used graphics window. In our case the event queue serves as a collector and adaptor of window events. If we look at the source code of osgGA::EventQueue, we can see what types of events can be triggered in OSG, and also what parameters they take.

mouseButtonPress() event

As an example, let’s take the mouseButtonPress(float x, float y, unsigned int button). In order to trigger a mouse button pressed event, we have to provide mouse coordinates, as well as a button code.

From the EventQueue file on the mouse button press event:

Method for adapting mouse button pressed events, placing this event on the back of the event queue. Button numbering is 1 for left mouse button, 2 for middle, 3 for right.

So, we only have to pass the right button code. To trigger the mouseButtonPress from Qt’s mousePressEvent:

virtual void mousePressEvent(QMouseEvent* event)
  {
      unsigned int button = 0;
      switch (event->button()){
      case Qt::LeftButton:
          button = 1;
          break;
      case Qt::MiddleButton:
          button = 2;
          break;
      case Qt::RightButton:
          button = 3;
          break;
      default:
          break;
      }
      this->getEventQueue()->mouseButtonPress(event->x(), event->y(), button);
  }

mouseReleaseEvent() method

Similarly, we have to re-define the mouse release event:

 
virtual void mouseReleaseEvent(QMouseEvent* event)
  {
      unsigned int button = 0;
      switch (event->button()){
      case Qt::LeftButton:
          button = 1;
          break;
      case Qt::MiddleButton:
          button = 2;
          break;
      case Qt::RightButton:
          button = 3;
          break;
      default:
          break;
      }
      this->getEventQueue()->mouseButtonRelease(event->x(), event->y(), button);
  }

mouseWheelEvent() method

Same manner we can also re-define the mouse wheel event. The only difference between the mouse click events and the scroll event, we have to pass the motion variable of the type osgGA::GUIEVentAdapter::ScrollingMotion, which is anenum type of the file GUIEventAdapter. For the simplest mouse moves, we can define whether the mouse scroll was performed UP or DOWN. The code would look as follows:

virtual void wheelEvent(QWheelEvent* event)
  {
      int delta = event->delta();
      osgGA::GUIEventAdapter::ScrollingMotion motion = delta > 0 ?
                  osgGA::GUIEventAdapter::SCROLL_UP : osgGA::GUIEventAdapter::SCROLL_DOWN;
      this->getEventQueue()->mouseScroll(motion);
  }

After all the event are re-defined, our sample scene (cylinder) can be manipulated by using right and left buttons of the mouse, as well as the wheel. The aforementioned manipulations allow the camera pose change by rotation, pan and zoom.

Conclusion

This tutorial concludes the minimal CMake, Qt and OSG set up when the scene is rendered without a timer, on-demand mode. The second part concentrated mainly on how to use Qt events in order to trigger OSG events, and an example of mouse events (press, release, move) were presented.

Codes

View Code

You can find the code for this tutorial (both parts 1 and 2) on my github repository. Note, the presented code also contains parts of code related to high DPI scaling which can be easily omitted.

Leave a Comment