Revision control
++ // Copyright (C) 2016 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
++
++ #include "selectionpointer_p.h"
++ #include "shaderhelper_p.h"
++ #include "objecthelper_p.h"
++ #include "texturehelper_p.h"
++ #include "q3dcamera_p.h"
++ #include "utils_p.h"
++
++ QT_BEGIN_NAMESPACE
++
++ const GLfloat spSliceUnits = 2.5;
++
++ SelectionPointer::SelectionPointer(Drawer *drawer)
++ : QObject(0),
++ m_labelShader(0),
++ m_pointShader(0),
++ m_labelObj(0),
++ m_pointObj(0),
++ m_textureHelper(0),
++ m_cachedTheme(drawer->theme()),
++ m_labelBackground(false),
++ m_drawer(drawer),
++ m_cachedScene(0)
++ {
++ initializeOpenGL();
++
++ QObject::connect(m_drawer, &Drawer::drawerChanged,
++ this, &SelectionPointer::handleDrawerChange);
++ }
++
++ SelectionPointer::~SelectionPointer()
++ {
++ delete m_labelShader;
++ delete m_pointShader;
++ delete m_textureHelper;
++ }
++
++ void SelectionPointer::initializeOpenGL()
++ {
++ initializeOpenGLFunctions();
++
++ m_textureHelper = new TextureHelper();
++ m_drawer->initializeOpenGL();
++
++ initShaders();
++ }
++
++ void SelectionPointer::updateScene(Q3DScene *scene)
++ {
++ m_cachedScene = scene;
++ }
++
++ void SelectionPointer::renderSelectionPointer(GLuint defaultFboHandle, bool useOrtho)
++ {
++ Q_UNUSED(defaultFboHandle);
++
++ glViewport(m_mainViewPort.x(), m_mainViewPort.y(),
++ m_mainViewPort.width(), m_mainViewPort.height());
++
++ Q3DCamera *camera = m_cachedScene->activeCamera();
++
++ QMatrix4x4 itModelMatrix;
++
++ // Get view matrix
++ QMatrix4x4 viewMatrix;
++ QMatrix4x4 projectionMatrix;
++ GLfloat viewPortRatio = (GLfloat)m_mainViewPort.width() / (GLfloat)m_mainViewPort.height();
++ if (m_cachedIsSlicingActivated) {
++ GLfloat sliceUnitsScaled = spSliceUnits / m_autoScaleAdjustment;
++ viewMatrix.lookAt(QVector3D(0.0f, 0.0f, 1.0f), zeroVector, upVector);
++ projectionMatrix.ortho(-sliceUnitsScaled * viewPortRatio, sliceUnitsScaled * viewPortRatio,
++ -sliceUnitsScaled, sliceUnitsScaled,
++ -1.0f, 4.0f);
++ } else if (useOrtho) {
++ viewMatrix = camera->d_ptr->viewMatrix();
++ GLfloat orthoRatio = 2.0f;
++ projectionMatrix.ortho(-viewPortRatio * orthoRatio, viewPortRatio * orthoRatio,
++ -orthoRatio, orthoRatio,
++ 0.0f, 100.0f);
++ } else {
++ viewMatrix = camera->d_ptr->viewMatrix();
++ projectionMatrix.perspective(45.0f, viewPortRatio, 0.1f, 100.0f);
++ }
++
++ QMatrix4x4 modelMatrix;
++ QMatrix4x4 MVPMatrix;
++
++ // Position the pointer ball
++ modelMatrix.translate(m_position);
++
++ if (!m_rotation.isIdentity()) {
++ modelMatrix.rotate(m_rotation);
++ itModelMatrix.rotate(m_rotation);
++ }
++
++ // Scale the point with fixed values (at this point)
++ QVector3D scaleVector(0.05f, 0.05f, 0.05f);
++ modelMatrix.scale(scaleVector);
++ itModelMatrix.scale(scaleVector);
++
++ MVPMatrix = projectionMatrix * viewMatrix * modelMatrix;
++
++ QVector3D lightPos = m_cachedScene->activeLight()->position();
++
++ //
++ // Draw the point
++ //
++ m_pointShader->bind();
++ m_pointShader->setUniformValue(m_pointShader->lightP(), lightPos);
++ m_pointShader->setUniformValue(m_pointShader->view(), viewMatrix);
++ m_pointShader->setUniformValue(m_pointShader->model(), modelMatrix);
++ m_pointShader->setUniformValue(m_pointShader->nModel(), itModelMatrix.inverted().transposed());
++ m_pointShader->setUniformValue(m_pointShader->color(), m_highlightColor);
++ m_pointShader->setUniformValue(m_pointShader->MVP(), MVPMatrix);
++ m_pointShader->setUniformValue(m_pointShader->ambientS(),
++ m_cachedTheme->ambientLightStrength());
++ m_pointShader->setUniformValue(m_pointShader->lightS(), m_cachedTheme->lightStrength() * 2.0f);
++ m_pointShader->setUniformValue(m_pointShader->lightColor(),
++ Utils::vectorFromColor(m_cachedTheme->lightColor()));
++
++ m_drawer->drawObject(m_pointShader, m_pointObj);
++ }
++
++ void SelectionPointer::renderSelectionLabel(GLuint defaultFboHandle, bool useOrtho)
++ {
++ Q_UNUSED(defaultFboHandle);
++
++ glViewport(m_mainViewPort.x(), m_mainViewPort.y(),
++ m_mainViewPort.width(), m_mainViewPort.height());
++
++ Q3DCamera *camera = m_cachedScene->activeCamera();
++
++ // Get view matrix
++ QMatrix4x4 viewMatrix;
++ QMatrix4x4 modelMatrixLabel;
++ QMatrix4x4 projectionMatrix;
++ GLfloat viewPortRatio = (GLfloat)m_mainViewPort.width() / (GLfloat)m_mainViewPort.height();
++ if (m_cachedIsSlicingActivated) {
++ GLfloat sliceUnitsScaled = spSliceUnits / m_autoScaleAdjustment;
++ viewMatrix.lookAt(QVector3D(0.0f, 0.0f, 1.0f), zeroVector, upVector);
++ projectionMatrix.ortho(-sliceUnitsScaled * viewPortRatio, sliceUnitsScaled * viewPortRatio,
++ -sliceUnitsScaled, sliceUnitsScaled,
++ -1.0f, 4.0f);
++ } else if (useOrtho) {
++ viewMatrix = camera->d_ptr->viewMatrix();
++ GLfloat orthoRatio = 2.0f;
++ projectionMatrix.ortho(-viewPortRatio * orthoRatio, viewPortRatio * orthoRatio,
++ -orthoRatio, orthoRatio,
++ 0.0f, 100.0f);
++ } else {
++ viewMatrix = camera->d_ptr->viewMatrix();
++ projectionMatrix.perspective(45.0f, viewPortRatio, 0.1f, 100.0f);
++ }
++
++ QSize textureSize = m_labelItem.size();
++
++ // Calculate scale factor to get uniform font size
++ GLfloat scaledFontSize = 0.05f + m_drawer->font().pointSizeF() / 500.0f;
++ GLfloat scaleFactor = scaledFontSize / (GLfloat)textureSize.height();
++
++ // Position label
++ QVector3D labelAlign(0.0f, 1.0f * scaledFontSize + 0.05f, 0.0f);
++ modelMatrixLabel.translate(m_position + labelAlign);
++
++ // Position the label towards the camera
++ float camRotationsX = camera->xRotation();
++ float camRotationsY = camera->yRotation();
++ if (!m_cachedIsSlicingActivated) {
++ modelMatrixLabel.rotate(-camRotationsX, 0.0f, 1.0f, 0.0f);
++ modelMatrixLabel.rotate(-camRotationsY, 1.0f, 0.0f, 0.0f);
++ }
++
++ // Scale label based on text size
++ modelMatrixLabel.scale(QVector3D((GLfloat)textureSize.width() * scaleFactor,
++ scaledFontSize,
++ 0.0f));
++
++ // Make label to be always on top
++ glDisable(GL_DEPTH_TEST);
++
++ // Make label transparent
++ glEnable(GL_BLEND);
++ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
++
++ m_labelShader->bind();
++
++ QMatrix4x4 MVPMatrix;
++
++ // Set shader bindings
++ MVPMatrix = projectionMatrix * viewMatrix * modelMatrixLabel;
++ m_labelShader->setUniformValue(m_labelShader->MVP(), MVPMatrix);
++
++ // Draw the object
++ m_drawer->drawObject(m_labelShader, m_labelObj, m_labelItem.textureId());
++
++ // Release shader
++ glUseProgram(0);
++
++ // Disable transparency
++ glDisable(GL_BLEND);
++
++ // Depth test back to normal
++ glEnable(GL_DEPTH_TEST);
++ }
++
++ void SelectionPointer::setPosition(const QVector3D &position)
++ {
++ m_position = position;
++ }
++
++ void SelectionPointer::updateSliceData(bool sliceActivated, GLfloat autoScaleAdjustment)
++ {
++ m_cachedIsSlicingActivated = sliceActivated;
++ m_autoScaleAdjustment = autoScaleAdjustment;
++ }
++
++ void SelectionPointer::setHighlightColor(const QVector4D &colorVector)
++ {
++ m_highlightColor = colorVector;
++ }
++
++ void SelectionPointer::setRotation(const QQuaternion &rotation)
++ {
++ m_rotation = rotation;
++ }
++
++ void SelectionPointer::setLabel(const QString &label, bool themeChange)
++ {
++ if (themeChange || m_label != label) {
++ m_label = label;
++ m_drawer->generateLabelItem(m_labelItem, m_label);
++ }
++ }
++
++ void SelectionPointer::setPointerObject(ObjectHelper *object)
++ {
++ m_pointObj = object;
++ }
++
++ void SelectionPointer::setLabelObject(ObjectHelper *object)
++ {
++ m_labelObj = object;
++ }
++
++ void SelectionPointer::handleDrawerChange()
++ {
++ m_cachedTheme = m_drawer->theme();
++ setLabel(m_label, true);
++ }
++
++ void SelectionPointer::updateBoundingRect(const QRect &rect)
++ {
++ m_mainViewPort = rect;
++ }
++
++ void SelectionPointer::initShaders()
++ {
++ // The shader for printing the text label
++ if (m_labelShader)
++ delete m_labelShader;
++ m_labelShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexLabel"),
++ QStringLiteral(":/shaders/fragmentLabel"));
++ m_labelShader->initialize();
++
++ // The shader for the small point ball
++ if (m_pointShader)
++ delete m_pointShader;
++
++ if (Utils::isOpenGLES()) {
++ m_pointShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertex"),
++ QStringLiteral(":/shaders/fragmentES2"));
++ } else {
++ m_pointShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertex"),
++ QStringLiteral(":/shaders/fragment"));
++ }
++
++ m_pointShader->initialize();
++ }
++
++ QT_END_NAMESPACE