1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the Qt Data Visualization module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:GPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 or (at your option) any later version
20 ** approved by the KDE Free Qt Foundation. The licenses are as published by
21 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
22 ** included in the packaging of this file. Please review the following
23 ** information to ensure the GNU General Public License requirements will
24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 **
26 ** $QT_END_LICENSE$
27 **
28 ****************************************************************************/
29 
30 #include "selectionpointer_p.h"
31 #include "shaderhelper_p.h"
32 #include "objecthelper_p.h"
33 #include "texturehelper_p.h"
34 #include "q3dcamera_p.h"
35 #include "utils_p.h"
36 
37 QT_BEGIN_NAMESPACE_DATAVISUALIZATION
38 
39 const GLfloat sliceUnits = 2.5;
40 
SelectionPointer(Drawer * drawer)41 SelectionPointer::SelectionPointer(Drawer *drawer)
42     : QObject(0),
43       m_labelShader(0),
44       m_pointShader(0),
45       m_labelObj(0),
46       m_pointObj(0),
47       m_textureHelper(0),
48       m_cachedTheme(drawer->theme()),
49       m_labelBackground(false),
50       m_drawer(drawer),
51       m_cachedScene(0)
52 {
53     initializeOpenGL();
54 
55     QObject::connect(m_drawer, &Drawer::drawerChanged,
56                      this, &SelectionPointer::handleDrawerChange);
57 }
58 
~SelectionPointer()59 SelectionPointer::~SelectionPointer()
60 {
61     delete m_labelShader;
62     delete m_pointShader;
63     delete m_textureHelper;
64 }
65 
initializeOpenGL()66 void SelectionPointer::initializeOpenGL()
67 {
68     initializeOpenGLFunctions();
69 
70     m_textureHelper = new TextureHelper();
71     m_drawer->initializeOpenGL();
72 
73     initShaders();
74 }
75 
updateScene(Q3DScene * scene)76 void SelectionPointer::updateScene(Q3DScene *scene)
77 {
78     m_cachedScene = scene;
79 }
80 
renderSelectionPointer(GLuint defaultFboHandle,bool useOrtho)81 void SelectionPointer::renderSelectionPointer(GLuint defaultFboHandle, bool useOrtho)
82 {
83     Q_UNUSED(defaultFboHandle)
84 
85     glViewport(m_mainViewPort.x(), m_mainViewPort.y(),
86                m_mainViewPort.width(), m_mainViewPort.height());
87 
88     Q3DCamera *camera = m_cachedScene->activeCamera();
89 
90     QMatrix4x4 itModelMatrix;
91 
92     // Get view matrix
93     QMatrix4x4 viewMatrix;
94     QMatrix4x4 projectionMatrix;
95     GLfloat viewPortRatio = (GLfloat)m_mainViewPort.width() / (GLfloat)m_mainViewPort.height();
96     if (m_cachedIsSlicingActivated) {
97         GLfloat sliceUnitsScaled = sliceUnits / m_autoScaleAdjustment;
98         viewMatrix.lookAt(QVector3D(0.0f, 0.0f, 1.0f), zeroVector, upVector);
99         projectionMatrix.ortho(-sliceUnitsScaled * viewPortRatio, sliceUnitsScaled * viewPortRatio,
100                                -sliceUnitsScaled, sliceUnitsScaled,
101                                -1.0f, 4.0f);
102     } else if (useOrtho) {
103         viewMatrix = camera->d_ptr->viewMatrix();
104         GLfloat orthoRatio = 2.0f;
105         projectionMatrix.ortho(-viewPortRatio * orthoRatio, viewPortRatio * orthoRatio,
106                                -orthoRatio, orthoRatio,
107                                0.0f, 100.0f);
108     } else {
109         viewMatrix = camera->d_ptr->viewMatrix();
110         projectionMatrix.perspective(45.0f, viewPortRatio, 0.1f, 100.0f);
111     }
112 
113     QMatrix4x4 modelMatrix;
114     QMatrix4x4 MVPMatrix;
115 
116     // Position the pointer ball
117     modelMatrix.translate(m_position);
118 
119     if (!m_rotation.isIdentity()) {
120         modelMatrix.rotate(m_rotation);
121         itModelMatrix.rotate(m_rotation);
122     }
123 
124     // Scale the point with fixed values (at this point)
125     QVector3D scaleVector(0.05f, 0.05f, 0.05f);
126     modelMatrix.scale(scaleVector);
127     itModelMatrix.scale(scaleVector);
128 
129     MVPMatrix = projectionMatrix * viewMatrix * modelMatrix;
130 
131     QVector3D lightPos =  m_cachedScene->activeLight()->position();
132 
133     //
134     // Draw the point
135     //
136     m_pointShader->bind();
137     m_pointShader->setUniformValue(m_pointShader->lightP(), lightPos);
138     m_pointShader->setUniformValue(m_pointShader->view(), viewMatrix);
139     m_pointShader->setUniformValue(m_pointShader->model(), modelMatrix);
140     m_pointShader->setUniformValue(m_pointShader->nModel(), itModelMatrix.inverted().transposed());
141     m_pointShader->setUniformValue(m_pointShader->color(), m_highlightColor);
142     m_pointShader->setUniformValue(m_pointShader->MVP(), MVPMatrix);
143     m_pointShader->setUniformValue(m_pointShader->ambientS(),
144                                    m_cachedTheme->ambientLightStrength());
145     m_pointShader->setUniformValue(m_pointShader->lightS(), m_cachedTheme->lightStrength() * 2.0f);
146     m_pointShader->setUniformValue(m_pointShader->lightColor(),
147                                    Utils::vectorFromColor(m_cachedTheme->lightColor()));
148 
149     m_drawer->drawObject(m_pointShader, m_pointObj);
150 }
151 
renderSelectionLabel(GLuint defaultFboHandle,bool useOrtho)152 void SelectionPointer::renderSelectionLabel(GLuint defaultFboHandle, bool useOrtho)
153 {
154     Q_UNUSED(defaultFboHandle)
155 
156     glViewport(m_mainViewPort.x(), m_mainViewPort.y(),
157                m_mainViewPort.width(), m_mainViewPort.height());
158 
159     Q3DCamera *camera = m_cachedScene->activeCamera();
160 
161     // Get view matrix
162     QMatrix4x4 viewMatrix;
163     QMatrix4x4 modelMatrixLabel;
164     QMatrix4x4 projectionMatrix;
165     GLfloat viewPortRatio = (GLfloat)m_mainViewPort.width() / (GLfloat)m_mainViewPort.height();
166     if (m_cachedIsSlicingActivated) {
167         GLfloat sliceUnitsScaled = sliceUnits / m_autoScaleAdjustment;
168         viewMatrix.lookAt(QVector3D(0.0f, 0.0f, 1.0f), zeroVector, upVector);
169         projectionMatrix.ortho(-sliceUnitsScaled * viewPortRatio, sliceUnitsScaled * viewPortRatio,
170                                -sliceUnitsScaled, sliceUnitsScaled,
171                                -1.0f, 4.0f);
172     } else if (useOrtho) {
173         viewMatrix = camera->d_ptr->viewMatrix();
174         GLfloat orthoRatio = 2.0f;
175         projectionMatrix.ortho(-viewPortRatio * orthoRatio, viewPortRatio * orthoRatio,
176                                -orthoRatio, orthoRatio,
177                                0.0f, 100.0f);
178     } else {
179         viewMatrix = camera->d_ptr->viewMatrix();
180         projectionMatrix.perspective(45.0f, viewPortRatio, 0.1f, 100.0f);
181     }
182 
183     QSize textureSize = m_labelItem.size();
184 
185     // Calculate scale factor to get uniform font size
186     GLfloat scaledFontSize = 0.05f + m_drawer->font().pointSizeF() / 500.0f;
187     GLfloat scaleFactor = scaledFontSize / (GLfloat)textureSize.height();
188 
189     // Position label
190     QVector3D labelAlign(0.0f, 1.0f * scaledFontSize + 0.05f, 0.0f);
191     modelMatrixLabel.translate(m_position + labelAlign);
192 
193     // Position the label towards the camera
194     float camRotationsX = camera->xRotation();
195     float camRotationsY = camera->yRotation();
196     if (!m_cachedIsSlicingActivated) {
197         modelMatrixLabel.rotate(-camRotationsX, 0.0f, 1.0f, 0.0f);
198         modelMatrixLabel.rotate(-camRotationsY, 1.0f, 0.0f, 0.0f);
199     }
200 
201     // Scale label based on text size
202     modelMatrixLabel.scale(QVector3D((GLfloat)textureSize.width() * scaleFactor,
203                                      scaledFontSize,
204                                      0.0f));
205 
206     // Make label to be always on top
207     glDisable(GL_DEPTH_TEST);
208 
209     // Make label transparent
210     glEnable(GL_BLEND);
211     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
212 
213     m_labelShader->bind();
214 
215     QMatrix4x4 MVPMatrix;
216 
217     // Set shader bindings
218     MVPMatrix = projectionMatrix * viewMatrix * modelMatrixLabel;
219     m_labelShader->setUniformValue(m_labelShader->MVP(), MVPMatrix);
220 
221     // Draw the object
222     m_drawer->drawObject(m_labelShader, m_labelObj, m_labelItem.textureId());
223 
224     // Release shader
225     glUseProgram(0);
226 
227     // Disable transparency
228     glDisable(GL_BLEND);
229 
230     // Depth test back to normal
231     glEnable(GL_DEPTH_TEST);
232 }
233 
setPosition(const QVector3D & position)234 void SelectionPointer::setPosition(const QVector3D &position)
235 {
236     m_position = position;
237 }
238 
updateSliceData(bool sliceActivated,GLfloat autoScaleAdjustment)239 void SelectionPointer::updateSliceData(bool sliceActivated, GLfloat autoScaleAdjustment)
240 {
241     m_cachedIsSlicingActivated = sliceActivated;
242     m_autoScaleAdjustment = autoScaleAdjustment;
243 }
244 
setHighlightColor(const QVector4D & colorVector)245 void SelectionPointer::setHighlightColor(const QVector4D &colorVector)
246 {
247     m_highlightColor = colorVector;
248 }
249 
setRotation(const QQuaternion & rotation)250 void SelectionPointer::setRotation(const QQuaternion &rotation)
251 {
252     m_rotation = rotation;
253 }
254 
setLabel(const QString & label,bool themeChange)255 void SelectionPointer::setLabel(const QString &label, bool themeChange)
256 {
257     if (themeChange || m_label != label) {
258         m_label = label;
259         m_drawer->generateLabelItem(m_labelItem, m_label);
260     }
261 }
262 
setPointerObject(ObjectHelper * object)263 void SelectionPointer::setPointerObject(ObjectHelper *object)
264 {
265     m_pointObj = object;
266 }
267 
setLabelObject(ObjectHelper * object)268 void SelectionPointer::setLabelObject(ObjectHelper *object)
269 {
270     m_labelObj = object;
271 }
272 
handleDrawerChange()273 void SelectionPointer::handleDrawerChange()
274 {
275     m_cachedTheme = m_drawer->theme();
276     setLabel(m_label, true);
277 }
278 
updateBoundingRect(const QRect & rect)279 void SelectionPointer::updateBoundingRect(const QRect &rect)
280 {
281     m_mainViewPort = rect;
282 }
283 
initShaders()284 void SelectionPointer::initShaders()
285 {
286     // The shader for printing the text label
287     if (m_labelShader)
288         delete m_labelShader;
289     m_labelShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexLabel"),
290                                      QStringLiteral(":/shaders/fragmentLabel"));
291     m_labelShader->initialize();
292 
293     // The shader for the small point ball
294     if (m_pointShader)
295         delete m_pointShader;
296 
297     if (Utils::isOpenGLES()) {
298         m_pointShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertex"),
299                                          QStringLiteral(":/shaders/fragmentES2"));
300     } else {
301         m_pointShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertex"),
302                                          QStringLiteral(":/shaders/fragment"));
303     }
304 
305     m_pointShader->initialize();
306 }
307 
308 QT_END_NAMESPACE_DATAVISUALIZATION
309