Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
view3d.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
8#include "view3d.h"
9
10#include <QKeyEvent>
11#include <QGLFunctions>
12#include <QApplication>
13#include <QGridLayout>
14
15#define SELECTION_BUFSIZE 512
16
17#ifndef GL_TEXTURE_MAX_ANISOTROPY_EXT
18# define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
19#endif
20
21/*******************************************************************************
22** QView3DWidget
23*/
24
25class QView3DWidget : public QGLWidget
26{
27 Q_OBJECT
28public:
29 QView3DWidget(QWidget *parent);
30 virtual void initializeGL();
31 void resizeGL(int w, int h) override;
32 virtual void paintGL();
33 void clear();
34
35 void addTexture(QWidget *w, const QPixmap &pm);
36
37 void beginAddingWidgets(QWidget *form);
38 void addWidget(int depth, QWidget *w);
39 void endAddingWidgets();
40
41 QWidget *widgetAt(const QPoint &pos);
42
43signals:
44 void updateForm();
45
46protected:
47 void mousePressEvent(QMouseEvent *);
48 void mouseReleaseEvent(QMouseEvent *);
49 void mouseMoveEvent(QMouseEvent *);
50 void wheelEvent(QWheelEvent *);
51 void keyReleaseEvent(QKeyEvent *);
52
53 void contextMenuEvent(QContextMenuEvent *);
54
55private:
56 QWidget *m_form;
57 QPoint m_old_pos;
58 bool m_layer_coloring;
59 bool m_use_mipmaps;
60 GLuint m_form_list_id;
61
62 typedef QMap<QWidget*, GLuint> TextureMap;
63 TextureMap m_texture_map;
64
65 typedef QMap<GLuint, QWidget*> WidgetNameMap;
66 GLuint m_next_widget_name;
67 WidgetNameMap m_widget_name_map;
68};
69
70QView3DWidget::QView3DWidget(QWidget *parent)
71 : QGLWidget(parent)
72 , m_layer_coloring(true)
73 , m_form_list_id(0)
74 , m_next_widget_name(0)
75{
76 setFocusPolicy(Qt::StrongFocus);
77}
78
79static int nearestSize(int v)
80{
81 int n = 0, last = 0;
82 for (int s = 0; s < 32; ++s) {
83 if (((v>>s) & 1) == 1) {
84 ++n;
85 last = s;
86 }
87 }
88 if (n > 1)
89 return 1 << (last+1);
90 return 1 << last;
91}
92
93// static int pm_cnt = 0;
94
95void QView3DWidget::addTexture(QWidget *w, const QPixmap &pm)
96{
97 int tx_w = nearestSize(pm.width());
98 int tx_h = nearestSize(pm.height());
99
100 QPixmap tmp(tx_w, tx_h);
101 tmp.fill(QColor(0,0,0));
102 QPainter p(&tmp);
103 p.drawPixmap(0, tx_h - pm.height(), pm);
104 p.end();
105 QImage tex = tmp.toImage();
106
107// QString file_name = QString("pixmapDump%1.png").arg(pm_cnt++);
108// qDebug() << "grabWidget():" << file_name << tex.save(file_name, "PNG");
109
110 tex = QGLWidget::convertToGLFormat(tex);
111
112 GLuint tx_id;
113 glGenTextures(1, &tx_id);
114 glBindTexture(GL_TEXTURE_2D, tx_id);
115 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
116 if (m_use_mipmaps) {
117 //glHint(GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST);
118 //glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
119 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
120 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 16.f);
121 } else {
122 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
123 }
124 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, tex.width(), tex.height(), 0, GL_RGBA,
125 GL_UNSIGNED_BYTE, tex.bits());
126 m_texture_map[w] = tx_id;
127}
128
129void QView3DWidget::addWidget(int depth, QWidget *widget)
130{
131 const auto it = m_texture_map.find(widget);
132 Q_ASSERT(it != m_texture_map.end());
133
134 makeCurrent();
135
136 int w = m_form->size().width();
137 int h = m_form->size().height();
138 int max = qMax(w, h);
139 QRect r = widget->rect();
140 QPoint pos = widget->mapToGlobal(QPoint(0, 0));
141 r.moveTopLeft(m_form->mapFromGlobal(pos));
142
143 float s = r.width()/float(nearestSize(r.width()));
144 float t = r.height()/float(nearestSize(r.height()));
145
146 if (m_layer_coloring)
147 glColor4f(1.0 - depth/10.0, 1.0 - depth/10.0, 1.0, 1.0 - depth/20.0);
148 else
149 glColor4f(1.0, 1.0, 1.0, 1.0);
150
151 glBindTexture(GL_TEXTURE_2D, *it);
152 glBegin(GL_QUADS);
153 glLoadName(m_next_widget_name);
154 glTexCoord2f(0.0, 0.0); glVertex3f(r.left() - w/2, r.bottom() - h/2, depth*max/8);
155 glTexCoord2f(s, 0.0); glVertex3f(r.right() - w/2, r.bottom()- h/2, depth*max/8);
156 glTexCoord2f(s, t); glVertex3f(r.right() - w/2, r.top() - h/2, depth*max/8);
157 glTexCoord2f(0.0, t); glVertex3f(r.left() - w/2, r.top() - h/2, depth*max/8);
158 glEnd();
159
160 m_widget_name_map[m_next_widget_name++] = widget;
161}
162
163void QView3DWidget::clear()
164{
165 makeCurrent();
166 glDeleteLists(m_form_list_id, 1);
167 for (auto it = m_texture_map.begin(), end = m_texture_map.end(); it != end; ++it)
168 glDeleteTextures(1, &(it.value()));
169 m_texture_map.clear();
170 m_widget_name_map.clear();
171 m_next_widget_name = 0;
172}
173
174void QView3DWidget::beginAddingWidgets(QWidget *form)
175{
176 makeCurrent();
177 m_form = form;
178 m_form_list_id = glGenLists(1);
179 glNewList(m_form_list_id, GL_COMPILE);
180 glInitNames();
181 glPushName(-1);
182 m_next_widget_name = 0;
183}
184
185void QView3DWidget::endAddingWidgets()
186{
187 makeCurrent();
188 glEndList();
189}
190
191void QView3DWidget::initializeGL()
192{
193 glMatrixMode(GL_MODELVIEW);
194 glLoadIdentity();
195
196 qglClearColor(palette().color(QPalette::Window).darker());
197 glColor3f (1.0, 1.0, 1.0);
198 glEnable(GL_DEPTH_TEST);
199 glDepthFunc(GL_LEQUAL);
200
201 glShadeModel(GL_FLAT);
202 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
203 QString extensions(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)));
204 m_use_mipmaps = false;// extensions.contains("GL_SGIS_generate_mipmap");
205}
206
207void QView3DWidget::resizeGL(int width, int height)
208{
209 glViewport(0, 0, width, height);
210 glMatrixMode(GL_PROJECTION);
211 glLoadIdentity();
212 glOrtho(-width/2, width/2, height/2, -height/2, -999999, 999999);
213}
214
215void QView3DWidget::paintGL()
216{
217 glColor4f(1.0, 1.0, 1.0, 1.0);
218 glEnable(GL_TEXTURE_2D);
219 glEnable(GL_BLEND);
220 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
221 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
222 glCallList(m_form_list_id);
223
224 glPushAttrib(GL_ENABLE_BIT);
225 glDisable(GL_DEPTH_TEST);
226 glDisable(GL_LIGHTING);
227 glDisable(GL_TEXTURE_2D);
228 glMatrixMode(GL_MODELVIEW);
229 glPushMatrix();
230 glLoadIdentity();
231 glTranslatef(-width()/2, -height()/2, 0.0);
232
233 QFontMetrics fm(font());
234 glColor4f(0.4, 0.4, 0.4, 0.7);
235 glRecti(0, height() - fm.lineSpacing()*2.5, width(), height());
236
237 glColor3f(1.0, 1.0, 1.0);
238 renderText(10, height() - fm.lineSpacing()*1.5,
239 "Press and hold left/right mouse button = tilt the view.");
240 renderText(10, height() - fm.lineSpacing()*0.5,
241 "Mouse wheel = zoom. 't' = toggle layer coloring. 'r' = reset transform.");
242 glPopMatrix();
243 glPopAttrib();
244}
245
246QWidget *QView3DWidget::widgetAt(const QPoint & /* pos */)
247{
248 makeCurrent();
249 GLuint selectBuf[SELECTION_BUFSIZE];
250 glSelectBuffer(SELECTION_BUFSIZE, selectBuf);
251 glRenderMode (GL_SELECT);
252
253 glMatrixMode(GL_PROJECTION);
254 glPushMatrix();
255 glLoadIdentity();
256
257 glCallList(m_form_list_id);
258 return 0;
259}
260
261void QView3DWidget::keyReleaseEvent(QKeyEvent *e)
262{
263 if (e->key() == Qt::Key_T) {
264 m_layer_coloring = !m_layer_coloring;
265 emit updateForm();
266 } else if (e->key() == Qt::Key_R) {
267 makeCurrent();
268 glMatrixMode(GL_MODELVIEW);
269 glLoadIdentity();
270 }
271
272 updateGL();
273}
274
275void QView3DWidget::mousePressEvent(QMouseEvent *e)
276{
277 m_old_pos = e->pos();
278}
279
280void QView3DWidget::mouseReleaseEvent(QMouseEvent *e)
281{
282 m_old_pos = e->pos();
283}
284
285void QView3DWidget::mouseMoveEvent(QMouseEvent *e)
286{
287 if (e->buttons() & (Qt::LeftButton | Qt::RightButton)) {
288 GLfloat rx = (GLfloat) (e->x() - m_old_pos.x()) / width();
289 GLfloat ry = (GLfloat) (e->y() - m_old_pos.y()) / height();
290
291 makeCurrent();
292 glMatrixMode(GL_MODELVIEW);
293 if (e->buttons() & Qt::LeftButton) {
294 // Left button down - rotate around X and Y axes
295 glRotatef(-180*ry, 1, 0, 0);
296 glRotatef(180*rx, 0, 1, 0);
297 } else if (e->buttons() & Qt::RightButton) {
298 // Right button down - rotate around X and Z axes
299 glRotatef(-180*ry, 1, 0, 0);
300 glRotatef(-180*rx, 0, 0, 1);
301 }
302 updateGL();
303 m_old_pos = e->pos();
304 } else {
305
306 }
307}
308
309void QView3DWidget::wheelEvent(QWheelEvent *e)
310{
311 makeCurrent();
312 glMatrixMode(GL_MODELVIEW);
313 if (e->delta() < 0)
314 glScalef(0.9, 0.9, 0.9);
315 else
316 glScalef(1.1, 1.1, 1.1);
317 updateGL();
318}
319
320void QView3DWidget::contextMenuEvent(QContextMenuEvent *e)
321{
322 e->accept();
323}
324
325/*******************************************************************************
326** Misc tools
327*/
328
330{
331public:
332 virtual void operator () (int depth, QWidget *widget) const = 0;
333};
334
335static bool skipWidget(QDesignerFormEditorInterface *core, QWidget *widget)
336{
337 QDesignerMetaDataBaseItemInterface *item = core->metaDataBase()->item(widget);
338 if (item == 0)
339 return true;
340 QString name = widget->metaObject()->className();
341 if (name == "QLayoutWidget")
342 return true;
343
344 return false;
345}
346
347static void walkWidgetTree(QDesignerFormEditorInterface *core, int depth, QWidget *widget, const WalkWidgetTreeFunction &func)
348{
349 if (widget == 0)
350 return;
351 if (!widget->isVisible())
352 return;
353
354 if (!skipWidget(core, widget))
355 func(depth++, widget);
356
357 const QObjectList child_obj_list = widget->children();
358 for (QObject *child_obj : child_obj_list) {
359 QWidget *child = qobject_cast<QWidget*>(child_obj);
360 if (child != 0)
361 walkWidgetTree(core, depth, child, func);
362 }
363}
364
365static void grabWidget_helper(QWidget *widget, QPixmap &res, QPixmap &buf,
366 const QRect &r, const QPoint &offset, QDesignerFormEditorInterface *core)
367{
368 buf.fill(widget, r.topLeft());
369 QPainter::setRedirected(widget, &buf, r.topLeft());
370 QPaintEvent e(r & widget->rect());
371 QApplication::sendEvent(widget, &e);
372 QPainter::restoreRedirected(widget);
373 {
374 QPainter pt(&res);
375 pt.drawPixmap(offset.x(), offset.y(), buf, 0, 0, r.width(), r.height());
376 }
377
378 for (auto *o : widget->children()) {
379 QWidget *child = qobject_cast<QWidget*>(o);
380 if (child == 0 || child->isWindow())
381 continue;
382 if (child->isHidden() || !child->geometry().intersects(r))
383 continue;
384 if (core->metaDataBase()->item(child) != 0)
385 continue;
386 QRect cr = r & child->geometry();
387 cr.translate(-child->pos());
388 grabWidget_helper(child, res, buf, cr, offset + child->pos(), core);
389 }
390}
391
392static QPixmap grabWidget(QWidget * widget, QDesignerFormEditorInterface *core)
393{
394 if (!widget)
395 return QPixmap();
396
397 QRect r = widget->rect();
398 QSize s = widget->size();
399
400 QPixmap res(s), buf(s);
401
402 grabWidget_helper(widget, res, buf, r, QPoint(), core);
403
404 return res;
405}
406
407/*******************************************************************************
408** QView3D
409*/
410
412{
413public:
414 inline AddTexture(QDesignerFormEditorInterface *core, QView3DWidget *w)
415 : m_core(core), m_3d_widget(w) {}
416 inline virtual void operator ()(int, QWidget *w) const
417 { m_3d_widget->addTexture(w, ::grabWidget(w, m_core)); }
418 QDesignerFormEditorInterface *m_core;
419 QView3DWidget *m_3d_widget;
420};
421
423{
424public:
425 inline AddWidget(QView3DWidget *w) : m_3d_widget(w) {}
426 inline virtual void operator ()(int depth, QWidget *w) const
427 { m_3d_widget->addWidget(depth, w); }
428 QView3DWidget *m_3d_widget;
429};
430
431QView3D::QView3D(QDesignerFormWindowInterface *form_window, QWidget *parent)
432 : QWidget(parent)
433{
434 m_form_window = form_window;
435 m_3d_widget = new QView3DWidget(this);
436 connect(m_3d_widget, SIGNAL(updateForm()), this, SLOT(updateForm()));
437
438 QGridLayout *layout = new QGridLayout(this);
439 layout->setContentsMargins(QMargins());
440 layout->addWidget(m_3d_widget, 0, 0, 1, 1);
441
442 updateForm();
443}
444
445void QView3D::updateForm()
446{
447 QWidget *w = m_form_window->mainContainer();
448 if (w == 0)
449 return;
450
451 m_3d_widget->clear();
452
453 walkWidgetTree(m_form_window->core(), 0, w, AddTexture(m_form_window->core(), m_3d_widget));
454 m_3d_widget->beginAddingWidgets(w);
455 walkWidgetTree(m_form_window->core(), 0, w, AddWidget(m_3d_widget));
456 m_3d_widget->endAddingWidgets();
457}
458
459#include "view3d.moc"
QView3DWidget * m_3d_widget
Definition view3d.cpp:419
virtual void operator()(int, QWidget *w) const
Definition view3d.cpp:416
QDesignerFormEditorInterface * m_core
Definition view3d.cpp:418
AddTexture(QDesignerFormEditorInterface *core, QView3DWidget *w)
Definition view3d.cpp:414
virtual void operator()(int depth, QWidget *w) const
Definition view3d.cpp:426
AddWidget(QView3DWidget *w)
Definition view3d.cpp:425
QView3DWidget * m_3d_widget
Definition view3d.cpp:428
The QDesignerMetaDataBaseItemInterface class provides an interface to individual items in \QD's meta ...
friend class QWidget
Definition qpainter.h:432
virtual void operator()(int depth, QWidget *widget) const =0
#define GL_TEXTURE_MAX_ANISOTROPY_EXT
static void grabWidget_helper(QWidget *widget, QPixmap &res, QPixmap &buf, const QRect &r, const QPoint &offset, QDesignerFormEditorInterface *core)
Definition view3d.cpp:365
#define SELECTION_BUFSIZE
Definition view3d.cpp:15
static int nearestSize(int v)
Definition view3d.cpp:79
static bool skipWidget(QDesignerFormEditorInterface *core, QWidget *widget)
Definition view3d.cpp:335
static QPixmap grabWidget(QWidget *widget, QDesignerFormEditorInterface *core)
Definition view3d.cpp:392
static void walkWidgetTree(QDesignerFormEditorInterface *core, int depth, QWidget *widget, const WalkWidgetTreeFunction &func)
Definition view3d.cpp:347