Quarter updates to handle Qt devicePixelRatio properly

146 views
Skip to first unread message

Randall O'Reilly

unread,
Jul 6, 2016, 7:22:14 PM7/6/16
to coin3d-...@googlegroups.com
Here’s some more patches to update Quarter to handle recent changes in Qt. This time, to deal with the devicePixelRatio issues — each “logical” pixel can correspond to 2 physical pixels for high DPI displays (e.g., Mac retina displays). The viewport and event coordinates need to take this conversion factor into account.

These diffs are against a previous less robust way of dealing with this issue, so they are not going to work directly against a pure Quarter source but the relevant new code is all there..

I have pushed these into our svn repository:
https://grey.colorado.edu/emergent/index.php/Coin3d

Cheers,
- Randy

Index: include/Quarter/QuarterWidget.h
===================================================================
--- include/Quarter/QuarterWidget.h (revision 32)
+++ include/Quarter/QuarterWidget.h (working copy)
@@ -74,6 +74,7 @@
Q_PROPERTY(TransparencyType transparencyType READ transparencyType WRITE setTransparencyType)
Q_PROPERTY(RenderMode renderMode READ renderMode WRITE setRenderMode)
Q_PROPERTY(StereoMode stereoMode READ stereoMode WRITE setStereoMode)
+ Q_PROPERTY(qreal devicePixelRatio READ devicePixelRatio NOTIFY devicePixelRatioChanged)

Q_ENUMS(TransparencyType)
Q_ENUMS(RenderMode)
@@ -127,6 +128,8 @@
void setBackgroundColor(const QColor & color);
QColor backgroundColor(void) const;

+ qreal devicePixelRatio(void) const;
+
void resetNavigationModeFile(void);
void setNavigationModeFile(const QUrl & url = QUrl(DEFAULT_NAVIGATIONFILE));
const QUrl & navigationModeFile(void) const;
@@ -187,11 +190,15 @@
void setStereoMode(StereoMode mode);
void setTransparencyType(TransparencyType type);

+signals:
+ void devicePixelRatioChanged(qreal dev_pixel_ratio);
+
protected:
virtual void resizeGL(int width, int height);
virtual void initializeGL(void);
virtual void paintGL(void);
virtual void actualRedraw(void);
+ virtual bool updateDevicePixelRatio(void);

private:
void constructor(const QT_GL_WIDGET * sharewidget);
Index: include/Quarter/devices/InputDevice.h
===================================================================
--- include/Quarter/devices/InputDevice.h (revision 32)
+++ include/Quarter/devices/InputDevice.h (working copy)
@@ -32,9 +32,11 @@

namespace SIM { namespace Coin3D { namespace Quarter {

+class QuarterWidget;
+
class QUARTER_DLL_API InputDevice {
public:
- InputDevice(void);
+ InputDevice(QuarterWidget* quarter);
virtual ~InputDevice() {}

/*!
@@ -50,6 +52,7 @@
protected:
SbVec2s mousepos;
SbVec2s windowsize;
+ QuarterWidget* quarter;
};

}}} // namespace
Index: include/Quarter/devices/Keyboard.h
===================================================================
--- include/Quarter/devices/Keyboard.h (revision 32)
+++ include/Quarter/devices/Keyboard.h (working copy)
@@ -33,7 +33,7 @@

class QUARTER_DLL_API Keyboard : public InputDevice {
public:
- Keyboard(void);
+ Keyboard(QuarterWidget* quarter);
virtual ~Keyboard();

virtual const SoEvent * translateEvent(QEvent * event);
Index: include/Quarter/devices/Mouse.h
===================================================================
--- include/Quarter/devices/Mouse.h (revision 32)
+++ include/Quarter/devices/Mouse.h (working copy)
@@ -28,12 +28,13 @@

class QEvent;
class SoEvent;
+class QuarterWidget;

namespace SIM { namespace Coin3D { namespace Quarter {

class QUARTER_DLL_API Mouse : public InputDevice {
public:
- Mouse(void);
+ Mouse(QuarterWidget* quarter);
virtual ~Mouse();

virtual const SoEvent * translateEvent(QEvent * event);
Index: include/Quarter/devices/SpaceNavigatorDevice.h
===================================================================
--- include/Quarter/devices/SpaceNavigatorDevice.h (revision 32)
+++ include/Quarter/devices/SpaceNavigatorDevice.h (working copy)
@@ -33,7 +33,7 @@

class QUARTER_DLL_API SpaceNavigatorDevice : public InputDevice {
public:
- SpaceNavigatorDevice(void);
+ SpaceNavigatorDevice(QuarterWidget* quarter);
virtual ~SpaceNavigatorDevice();
virtual const SoEvent * translateEvent(QEvent * event);

Index: src/Quarter/EventFilter.cpp
===================================================================
--- src/Quarter/EventFilter.cpp (revision 32)
+++ src/Quarter/EventFilter.cpp (working copy)
@@ -67,9 +67,7 @@

SbVec2s mousepos(event->pos().x(), this->windowsize[1] - event->pos().y() - 1);
// the following corrects for high-dpi displays (e.g., mac retina)
-#if (QT_VERSION >= 0x050000)
- mousepos *= ((QGuiApplication*)QGuiApplication::instance())->devicePixelRatio();
-#endif
+ mousepos *= quarterwidget->devicePixelRatio();
foreach(InputDevice * device, this->devices) {
device->setMousePosition(mousepos);
}
@@ -88,17 +86,19 @@
{
PRIVATE(this) = new EventFilterP;

- PRIVATE(this)->quarterwidget = dynamic_cast<QuarterWidget *>(parent);
+ QuarterWidget* quarter = dynamic_cast<QuarterWidget *>(parent);
+
+ PRIVATE(this)->quarterwidget = quarter;
assert(PRIVATE(this)->quarterwidget);

PRIVATE(this)->windowsize = SbVec2s(PRIVATE(this)->quarterwidget->width(),
PRIVATE(this)->quarterwidget->height());

- PRIVATE(this)->devices += new Mouse;
- PRIVATE(this)->devices += new Keyboard;
+ PRIVATE(this)->devices += new Mouse(quarter);
+ PRIVATE(this)->devices += new Keyboard(quarter);

#ifdef HAVE_SPACENAV_LIB
- PRIVATE(this)->devices += new SpaceNavigatorDevice;
+ PRIVATE(this)->devices += new SpaceNavigatorDevice(quarter);
#endif // HAVE_SPACENAV_LIB

}
Index: src/Quarter/InputDevice.cpp
===================================================================
--- src/Quarter/InputDevice.cpp (revision 32)
+++ src/Quarter/InputDevice.cpp (working copy)
@@ -23,6 +23,7 @@
#include <Quarter/devices/InputDevice.h>
#include <QInputEvent>
#include <Inventor/events/SoEvents.h>
+#include <Quarter/QuarterWidget.h>

using namespace SIM::Coin3D::Quarter;

@@ -34,7 +35,8 @@
devices.
*/

-InputDevice::InputDevice(void)
+InputDevice::InputDevice(QuarterWidget* quart) :
+ quarter(quart)
{
this->mousepos = SbVec2s(0, 0);
}
Index: src/Quarter/Keyboard.cpp
===================================================================
--- src/Quarter/Keyboard.cpp (revision 32)
+++ src/Quarter/Keyboard.cpp (working copy)
@@ -41,7 +41,8 @@

#define PRIVATE(obj) obj->pimpl

-Keyboard::Keyboard(void)
+Keyboard::Keyboard(QuarterWidget* quart) :
+ InputDevice(quart)
{
PRIVATE(this) = new KeyboardP(this);
}
Index: src/Quarter/Mouse.cpp
===================================================================
--- src/Quarter/Mouse.cpp (revision 32)
+++ src/Quarter/Mouse.cpp (working copy)
@@ -32,6 +32,8 @@
#include <QEvent>
#include <QSize>
#include <QWheelEvent>
+#include <Quarter/QuarterWidget.h>
+
#if (QT_VERSION >= 0x050000)
#include <QGuiApplication>
#endif
@@ -74,7 +76,8 @@
#define PRIVATE(obj) obj->pimpl
#define PUBLIC(obj) obj->publ

-Mouse::Mouse(void)
+Mouse::Mouse(QuarterWidget* quart) :
+ InputDevice(quart)
{
PRIVATE(this) = new MouseP(this);
}
@@ -125,9 +128,7 @@
assert(this->windowsize[1] != -1);
SbVec2s pos(event->pos().x(), this->windowsize[1] - event->pos().y() - 1);
// the following corrects for high-dpi displays (e.g., mac retina)
-#if (QT_VERSION >= 0x050000)
- pos *= ((QGuiApplication*)QGuiApplication::instance())->devicePixelRatio();
-#endif
+ pos *= publ->quarter->devicePixelRatio();
this->location2->setPosition(pos);
this->mousebutton->setPosition(pos);
return this->location2;
@@ -139,9 +140,7 @@
PUBLIC(this)->setModifiers(this->mousebutton, event);
SbVec2s pos(event->pos().x(), PUBLIC(this)->windowsize[1] - event->pos().y() - 1);
// the following corrects for high-dpi displays (e.g., mac retina)
-#if (QT_VERSION >= 0x050000)
- pos *= ((QGuiApplication*)QGuiApplication::instance())->devicePixelRatio();
-#endif
+ pos *= publ->quarter->devicePixelRatio();
this->location2->setPosition(pos);
this->mousebutton->setPosition(pos);

@@ -164,9 +163,7 @@
PUBLIC(this)->setModifiers(this->mousebutton, event);
SbVec2s pos(event->pos().x(), PUBLIC(this)->windowsize[1] - event->pos().y() - 1);
// the following corrects for high-dpi displays (e.g., mac retina)
-#if (QT_VERSION >= 0x050000)
- pos *= ((QGuiApplication*)QGuiApplication::instance())->devicePixelRatio();
-#endif
+ pos *= publ->quarter->devicePixelRatio();
this->location2->setPosition(pos);
this->mousebutton->setPosition(pos);

Index: src/Quarter/QuarterWidget.cpp
===================================================================
--- src/Quarter/QuarterWidget.cpp (revision 32)
+++ src/Quarter/QuarterWidget.cpp (working copy)
@@ -456,6 +456,23 @@
}

/*!
+ \property QuarterWidget::devicePixelRatio
+
+ \copydetails QuarterWidget::devicePixelRatio
+*/
+
+/*!
+ The ratio between logical and physical pixel sizes -- obtained from the window that
+the widget is located within, and updated whenver any change occurs, emitting a devicePixelRatioChanged signal. Only available for version Qt 5.6 and above (will be 1.0 for all previous versions)
+ */
+
+qreal
+QuarterWidget::devicePixelRatio(void) const
+{
+ return PRIVATE(this)->device_pixel_ratio;
+}
+
+/*!
Sets the Inventor scenegraph to be rendered
*/
void
@@ -657,6 +674,31 @@
this->getSoRenderManager()->reinitialize();
}

+
+bool
+QuarterWidget::updateDevicePixelRatio(void) {
+#ifdef QT_OPEN_GL_WIDGET
+ qreal dev_pix_ratio = 1.0;
+ QWidget* winwidg = window();
+ QWindow* win = NULL;
+ if(winwidg) {
+ win = winwidg->windowHandle();
+ }
+ if(win) {
+ dev_pix_ratio = win->devicePixelRatio();
+ }
+ else {
+ dev_pix_ratio = ((QGuiApplication*)QGuiApplication::instance())->devicePixelRatio();
+ }
+ if(PRIVATE(this)->device_pixel_ratio != dev_pix_ratio) {
+ PRIVATE(this)->device_pixel_ratio = dev_pix_ratio;
+ emit devicePixelRatioChanged(dev_pix_ratio);
+ return true;
+ }
+#endif
+ return false;
+}
+
/*!
Overridden from QGLWidget to resize the Coin scenegraph
*/
@@ -664,17 +706,12 @@
QuarterWidget::resizeGL(int width, int height)
{
#ifdef QT_OPEN_GL_WIDGET
- float dev_pix_ratio = 1.0f;
- QWindow* win = windowHandle();
- if(win) {
- dev_pix_ratio = win->devicePixelRatio();
- }
- else {
- dev_pix_ratio = ((QGuiApplication*)QGuiApplication::instance())->devicePixelRatio();
- }
+ updateDevicePixelRatio();
+ qreal dev_pix_ratio = devicePixelRatio();
width = (int)(dev_pix_ratio * width);
height = (int)(dev_pix_ratio * height);
#endif
+
SbViewportRegion vp(width, height);
PRIVATE(this)->sorendermanager->setViewportRegion(vp);
PRIVATE(this)->soeventmanager->setViewportRegion(vp);
@@ -686,6 +723,17 @@
void
QuarterWidget::paintGL(void)
{
+#ifdef QT_OPEN_GL_WIDGET
+ if(updateDevicePixelRatio()) {
+ qreal dev_pix_ratio = devicePixelRatio();
+ int width = (int)(dev_pix_ratio * this->width());
+ int height = (int)(dev_pix_ratio * this->height());
+ SbViewportRegion vp(width, height);
+ PRIVATE(this)->sorendermanager->setViewportRegion(vp);
+ PRIVATE(this)->soeventmanager->setViewportRegion(vp);
+ }
+#endif
+
assert(this->isValid() && "No valid GL context found!");
// We might have to process the delay queue here since we don't know
// if paintGL() is called from Qt, and we might have some sensors
Index: src/Quarter/QuarterWidgetP.cpp
===================================================================
--- src/Quarter/QuarterWidgetP.cpp (revision 32)
+++ src/Quarter/QuarterWidgetP.cpp (working copy)
@@ -72,6 +72,7 @@
interactionmodeenabled(false),
clearzbuffer(true),
clearwindow(true),
+ device_pixel_ratio(1.0),
addactions(true)
{
this->cachecontext = findCacheContext(masterptr, sharewidget);
Index: src/Quarter/QuarterWidgetP.h
===================================================================
--- src/Quarter/QuarterWidgetP.h (revision 32)
+++ src/Quarter/QuarterWidgetP.h (working copy)
@@ -90,6 +90,7 @@
bool processdelayqueue;
QUrl navigationModeFile;
SoScXMLStateMachine * currentStateMachine;
+ qreal device_pixel_ratio;

static void rendercb(void * userdata, SoRenderManager *);
static void prerendercb(void * userdata, SoRenderManager * manager);
Index: src/Quarter/SpaceNavigatorDevice.cpp
===================================================================
--- src/Quarter/SpaceNavigatorDevice.cpp (revision 32)
+++ src/Quarter/SpaceNavigatorDevice.cpp (working copy)
@@ -72,7 +72,8 @@
#define PRIVATE(obj) obj->pimpl
using namespace SIM::Coin3D::Quarter;

-SpaceNavigatorDevice::SpaceNavigatorDevice()
+SpaceNavigatorDevice::SpaceNavigatorDevice(QuarterWidget* quart) :
+ InputDevice(quart)
{
PRIVATE(this) = new SpaceNavigatorDeviceP(this);

Doug Epps

unread,
Aug 27, 2019, 1:12:49 PM8/27/19
to coin3d-discuss

I just built Coin and Quarter on Beta of macOS Catalina.

And it seems the dpi is possibly being double-handled ?  my windows all only show the lower-left quadrant of what they should see.
The mouse coords seem to be mapped correctly though (e.g. Seek does the right thing, and orbiting makes sense).


Un-clear if it's a Qt5 thing, or a OSX thing or a Quarter thing.

Anyone else tried on MacOS ?

Doug Epps

unread,
Aug 28, 2019, 12:36:55 AM8/28/19
to coin3d-discuss
FYI, I get the right thing (I think) by forcing 
QuarterWidget::resizeGL(int width, int height)

to use 1.0 instead of devicePixelRatio() for dev_pix_ratio 
(which it uses to calculate width/height.

Not sure if Qt is now doing something different, or OSX.

Bastiaan

unread,
Aug 30, 2019, 7:48:18 AM8/30/19
to coin3d-discuss

Bastiaan

unread,
Sep 16, 2019, 3:04:11 AM9/16/19
to coin3d-discuss


On Friday, August 30, 2019 at 1:48:18 PM UTC+2, Bastiaan wrote:


On a side note: On the Qt side things still have not settled: https://lists.qt-project.org/pipermail/development/2019-September/037434.html 

Charles Martin

unread,
Apr 16, 2020, 9:29:03 PM4/16/20
to coin3d-discuss
I’m also seeing this on MacOS Catalina. Has it been resolved? If not, Brian could you share your patches?

Thanks,
Charlie

Charles Martin

unread,
Apr 16, 2020, 9:30:36 PM4/16/20
to coin3d-discuss
Opps, I meant could Doug share his patches?

Charlie

On Wednesday, July 6, 2016 at 5:22:14 PM UTC-6, Randall O'Reilly wrote:
Reply all
Reply to author
Forward
0 new messages