Skip to content

Commit 7753120

Browse files
authored
Merge pull request #6576 from lrineau/QGLViewer-fix_picking_with_HiDPI_screen-GF
Fix 3D demo with HiDPI screen
2 parents e6f6120 + b32619f commit 7753120

File tree

9 files changed

+61
-41
lines changed

9 files changed

+61
-41
lines changed

GraphicsView/include/CGAL/Qt/camera.h

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <CGAL/Qt/quaternion.h>
1919
#include <CGAL/export/Qt.h>
2020
#include <QOpenGLFunctions_2_1>
21+
#include <QOpenGLFunctions>
2122

2223
namespace CGAL{
2324
class QGLViewer;
@@ -199,6 +200,7 @@ public Q_SLOTS:
199200
CGAL::QGLViewer's window dimensions when the Camera is attached to a CGAL::QGLViewer. See
200201
also QOpenGLWidget::height() */
201202
int screenHeight() const { return screenHeight_; }
203+
qreal devicePixelRatio() const { return devicePixelRatio_; }
202204
void getViewport(GLint viewport[4]) const;
203205
qreal pixelGLRatio(const Vec &position) const;
204206

@@ -279,7 +281,7 @@ public Q_SLOTS:
279281
setScreenWidthAndHeight(int(100.0 * aspect), 100);
280282
}
281283

282-
void setScreenWidthAndHeight(int width, int height);
284+
void setScreenWidthAndHeight(int width, int height, qreal devicePixelRatio = 1.0);
283285
/*! Sets the zNearCoefficient() value. */
284286
void setZNearCoefficient(qreal coef) {
285287
zNearCoef_ = coef;
@@ -444,6 +446,7 @@ private Q_SLOTS:
444446

445447
// C a m e r a p a r a m e t e r s
446448
int screenWidth_, screenHeight_; // size of the window, in pixels
449+
qreal devicePixelRatio_;
447450
qreal fieldOfView_; // in radians
448451
Vec sceneCenter_;
449452
qreal sceneRadius_; // OpenGL units
@@ -467,6 +470,36 @@ private Q_SLOTS:
467470
KeyFrameInterpolator *interpolationKfi_;
468471
};
469472

473+
inline void read_pixel(const QPoint &pixel, QOpenGLFunctions *p,
474+
const Camera *camera, GLenum format, GLenum type,
475+
GLvoid *pixel_data) {
476+
const auto pixel_ratio = camera->devicePixelRatio();
477+
p->glReadPixels(pixel.x() * pixel_ratio,
478+
(camera->screenHeight() - pixel.y()) * pixel_ratio - 1, 1, 1,
479+
format, type, pixel_data);
480+
}
481+
482+
inline auto read_pixel_as_float_rgb(const QPoint &pixel, QOpenGLFunctions *p,
483+
const Camera *camera) {
484+
std::array<float, 3> res;
485+
read_pixel(pixel, p, camera, GL_RGB, GL_FLOAT, res.data());
486+
return res;
487+
}
488+
489+
inline auto read_pixel_as_ubyte_rgba(const QPoint &pixel, QOpenGLFunctions *p,
490+
const Camera *camera) {
491+
std::array<GLubyte, 4> res;
492+
read_pixel(pixel, p, camera, GL_RGBA, GL_UNSIGNED_BYTE, res.data());
493+
return res;
494+
}
495+
496+
inline float read_depth_under_pixel(const QPoint &pixel, QOpenGLFunctions *p,
497+
const Camera *camera) {
498+
float depth = 2.0f;
499+
read_pixel(pixel, p, camera, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
500+
return depth;
501+
}
502+
470503
} // namespace qglviewer
471504
} //CGAL
472505
#endif // QGLVIEWER_CAMERA_H

GraphicsView/include/CGAL/Qt/camera_impl.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,11 @@ frustrum coherence.
160160
If your Camera is used without a CGAL::QGLViewer (offscreen rendering, shadow maps),
161161
use setAspectRatio() instead to define the projection matrix. */
162162
CGAL_INLINE_FUNCTION
163-
void Camera::setScreenWidthAndHeight(int width, int height) {
163+
void Camera::setScreenWidthAndHeight(int width, int height, qreal devicePixelRatio) {
164164
// Prevent negative and zero dimensions that would cause divisions by zero.
165165
screenWidth_ = width > 0 ? width : 1;
166166
screenHeight_ = height > 0 ? height : 1;
167+
devicePixelRatio_ = devicePixelRatio;
167168
projectionMatrixIsUpToDate_ = false;
168169
}
169170

@@ -884,8 +885,7 @@ Vec Camera::pointUnderPixel(const QPoint &pixel, bool &found) const {
884885
// Qt uses upper corner for its origin while GL uses the lower corner.
885886
if(auto p = dynamic_cast<QOpenGLFunctions*>(parent()))
886887
{
887-
p->glReadPixels(pixel.x(), screenHeight() - 1 - pixel.y(), 1, 1,
888-
GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
888+
depth = read_depth_under_pixel(pixel, p, this);
889889
}
890890
found = depth < 1.0;
891891
Vec point(pixel.x(), pixel.y(), depth);

GraphicsView/include/CGAL/Qt/qglviewer_impl.h

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -807,7 +807,7 @@ void CGAL::QGLViewer::setCamera(qglviewer::Camera *const camera) {
807807

808808
camera->setSceneRadius(sceneRadius());
809809
camera->setSceneCenter(sceneCenter());
810-
camera->setScreenWidthAndHeight(width(), height());
810+
camera->setScreenWidthAndHeight(width(), height(), devicePixelRatio());
811811

812812
// Disconnect current camera from this viewer.
813813
disconnect(this->camera()->frame(), SIGNAL(manipulated()), this,
@@ -1147,7 +1147,9 @@ void CGAL::QGLViewer::beginSelection(const QPoint &point)
11471147
{
11481148
makeCurrent();
11491149
glEnable(GL_SCISSOR_TEST);
1150-
glScissor(point.x(), camera()->screenHeight()-1-point.y(), 1, 1);
1150+
glScissor(point.x() * devicePixelRatio(),
1151+
(camera()->screenHeight() - point.y()) * devicePixelRatio() - 1, 1,
1152+
1);
11511153
}
11521154

11531155
/*! This method is called by select() after scene elements were drawn by
@@ -2369,7 +2371,7 @@ CGAL_INLINE_FUNCTION
23692371
void CGAL::QGLViewer::resizeGL(int width, int height) {
23702372
QOpenGLWidget::resizeGL(width, height);
23712373
glViewport(0, 0, GLint(width), GLint(height));
2372-
camera()->setScreenWidthAndHeight(this->width(), this->height());
2374+
camera()->setScreenWidthAndHeight(this->width(), this->height(), this->devicePixelRatio());
23732375
}
23742376

23752377
//////////////////////////////////////////////////////////////////////////
@@ -3187,10 +3189,11 @@ void CGAL::QGLViewer::drawVisualHints() {
31873189
mvpMatrix.ortho(-1,1,-1,1,-1,1);
31883190
size=30*devicePixelRatio();
31893191
rendering_program.setUniformValue("mvp_matrix", mvpMatrix);
3190-
glViewport(GLint((camera()->projectedCoordinatesOf(camera()->pivotPoint()).x-size/2)*devicePixelRatio()),
3191-
GLint((height() - camera()->projectedCoordinatesOf(camera()->pivotPoint()).y-size/2)*devicePixelRatio()), size, size);
3192-
glScissor (GLint((camera()->projectedCoordinatesOf(camera()->pivotPoint()).x-size/2)*devicePixelRatio()),
3193-
GLint((height() - camera()->projectedCoordinatesOf(camera()->pivotPoint()).y-size/2)*devicePixelRatio()), size, size);
3192+
const auto point_2d = camera()->projectedCoordinatesOf(camera()->pivotPoint());
3193+
glViewport(GLint(point_2d.x*devicePixelRatio()-size/2),
3194+
GLint((height() - point_2d.y)*devicePixelRatio()-size/2), size, size);
3195+
glScissor (GLint(point_2d.x*devicePixelRatio()-size/2),
3196+
GLint((height() - point_2d.y)*devicePixelRatio()-size/2), size, size);
31943197
rendering_program.setUniformValue("color", QColor(::Qt::black));
31953198
glDisable(GL_DEPTH_TEST);
31963199
glDrawArrays(GL_LINES, 0, static_cast<GLsizei>(4));

Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Io_image_plugin.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -116,11 +116,7 @@ public Q_SLOTS:
116116
boost::optional<DoubleConverter> fc;
117117
Viewer_interface* viewer;
118118
void getPixel(const QPoint& e) {
119-
float data[3];
120-
int vp[4];
121-
viewer->glGetIntegerv(GL_VIEWPORT, vp);
122-
viewer->glReadPixels(e.x(), vp[3] - e.y(), 1, 1, GL_RGB, GL_FLOAT, data);
123-
119+
const auto data = read_pixel_as_float_rgb(e, viewer, viewer->camera());
124120
if(fc) {
125121
Q_EMIT x(QString::number((*fc)(data[0]), 'f', 6 ));
126122
} else if(ic) {

Polyhedron/demo/Polyhedron/Plugins/PCA/Scene_edit_box_item.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,11 +1049,7 @@ void Scene_edit_box_item_priv::picking(int& type, int& id, Viewer_interface *vie
10491049
viewer->setBackgroundColor(::Qt::white);
10501050
draw_picking(viewer);
10511051

1052-
int rowLength = deviceWidth * 4; // data asked in RGBA,so 4 bytes.
1053-
const static int dataLength = rowLength * deviceHeight;
1054-
GLubyte* buffer = new GLubyte[dataLength];
1055-
// Qt uses upper corner for its origin while GL uses the lower corner.
1056-
viewer->glReadPixels(picked_pixel.x(), deviceHeight-1-picked_pixel.y(), 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
1052+
const auto buffer = read_pixel_as_ubyte_rgba(picked_pixel, viewer, viewer->camera());
10571053
//decode ID and pick (don't forget the case nothing is picked
10581054
if(!(buffer[0]==buffer[1] && buffer[1]==buffer[2]))
10591055
{
@@ -1080,7 +1076,6 @@ void Scene_edit_box_item_priv::picking(int& type, int& id, Viewer_interface *vie
10801076
}
10811077
}
10821078
}
1083-
delete[] buffer;
10841079
viewer->setBackgroundColor(bgColor);
10851080
fbo->release();
10861081
delete fbo;

Polyhedron/demo/Polyhedron/Scene.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -563,9 +563,8 @@ void Scene::renderScene(const QList<Scene_interface::Item_id> &items,
563563
if(with_names) {
564564

565565
// read depth buffer at pick location;
566-
float depth = 1.0;
567-
viewer->glReadPixels(picked_pixel.x(),viewer->camera()->screenHeight()-1-picked_pixel.y(),1,1,GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
568-
if (depth != 1.0)
566+
float depth = read_depth_under_pixel(picked_pixel, viewer, viewer->camera());
567+
if (depth < 2.0)
569568
{
570569
//add object to list of picked objects;
571570
picked_item_IDs[depth] = index;
@@ -634,7 +633,7 @@ void Scene::renderWireScene(const QList<Scene_interface::Item_id> &items,
634633

635634
// read depth buffer at pick location;
636635
float depth = 1.0;
637-
viewer->glReadPixels(picked_pixel.x(),viewer->camera()->screenHeight()-1-picked_pixel.y(),1,1,GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
636+
depth = read_depth_under_pixel(picked_pixel, viewer, viewer->camera());
638637
if (depth != 1.0)
639638
{
640639
//add object to list of picked objects;
@@ -676,7 +675,7 @@ void Scene::renderPointScene(const QList<Scene_interface::Item_id> &items,
676675
if(item.renderingMode() == Points && with_names) {
677676
// read depth buffer at pick location;
678677
float depth = 1.0;
679-
viewer->glReadPixels(picked_pixel.x(),viewer->camera()->screenHeight()-1-picked_pixel.y(),1,1,GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
678+
depth = read_depth_under_pixel(picked_pixel, viewer, viewer->camera());
680679
if (depth != 1.0)
681680
{
682681
//add object to list of picked objects;

Polyhedron/demo/Polyhedron/Scene_group_item.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ void Scene_group_item::renderChildren(Viewer_interface *viewer,
211211
if(with_names) {
212212
// read depth buffer at pick location;
213213
float depth = 1.0;
214-
viewer->glReadPixels(picked_pixel.x(),viewer->camera()->screenHeight()-1-picked_pixel.y(),1,1,GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
214+
depth = read_depth_under_pixel(picked_pixel, viewer, viewer->camera());
215215
if (depth != 1.0)
216216
{
217217
//add object to list of picked objects;

Polyhedron/demo/Polyhedron/Scene_spheres_item.cpp

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -187,8 +187,6 @@ void Scene_spheres_item::draw(Viewer_interface *viewer) const
187187
setBuffersFilled(true);
188188
setBuffersInit(viewer, true);
189189
}
190-
int deviceWidth = viewer->camera()->screenWidth();
191-
int deviceHeight = viewer->camera()->screenHeight();
192190
if(d->has_plane)
193191
{
194192
QVector4D cp = cgal_plane_to_vector4d(d->plane);
@@ -207,12 +205,8 @@ void Scene_spheres_item::draw(Viewer_interface *viewer) const
207205
}
208206
if(d->pickable && (d->spheres.size() > 1 && viewer->inDrawWithNames()))
209207
{
210-
int rowLength = deviceWidth * 4; // data asked in RGBA,so 4 bytes.
211-
const static int dataLength = rowLength * deviceHeight;
212-
GLubyte* buffer = new GLubyte[dataLength];
213-
// Qt uses upper corner for its origin while GL uses the lower corner.
214208
QPoint picking_target = viewer->mapFromGlobal(QCursor::pos());
215-
viewer->glReadPixels(picking_target.x(), deviceHeight-1-picking_target.y(), 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
209+
const auto buffer = read_pixel_as_ubyte_rgba(picking_target, viewer, viewer->camera());
216210
int ID = (buffer[0] + buffer[1] * 256 +buffer[2] * 256*256) ;
217211
if(buffer[0]*buffer[1]*buffer[2] < 255*255*255)
218212
{

Triangulation_3/demo/Triangulation_3/Viewer.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1696,9 +1696,9 @@ void Viewer::drawWithNames()
16961696
rendering_program.release();
16971697

16981698
//read depth and store in map
1699-
GLfloat depth = 1.0f;
1700-
glReadPixels(picking_pos.x(),camera()->screenHeight()-1-picking_pos.y(),1,1,GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
1701-
if (depth != 1.0)
1699+
GLfloat depth = 2.0f;
1700+
depth = read_depth_under_pixel(picking_pos, this, this->camera());
1701+
if (depth < 2.0f)
17021702
{
17031703
picked_IDs[depth] = i;
17041704
}
@@ -1740,9 +1740,9 @@ void Viewer::drawWithNames()
17401740
rendering_program.release();
17411741

17421742
//read depth and store in map
1743-
GLfloat depth = 1.0f;
1744-
glReadPixels(picking_pos.x(),camera()->screenHeight()-1-picking_pos.y(),1,1,GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
1745-
if (depth != 1.0)
1743+
GLfloat depth = 2.0f;
1744+
depth = read_depth_under_pixel(picking_pos, this, this->camera());
1745+
if (depth < 2.0f)
17461746
{
17471747
picked_IDs[depth] = -1;
17481748
}

0 commit comments

Comments
 (0)