summaryrefslogtreecommitdiffstats
path: root/src/datavisualization/utils
diff options
context:
space:
mode:
authorTomi Korpipää <tomi.korpipaa@digia.com>2013-09-10 11:42:13 +0300
committerTomi Korpipää <tomi.korpipaa@digia.com>2013-09-10 12:04:24 +0300
commita28cdb72a4ea768a898ca07f0df0fa3c17c073a8 (patch)
tree0bafdcfa99fc783e9f5204539a8242bf6128d795 /src/datavisualization/utils
parentf3e38983d77c72f3121c33a149a58fdf9c64158c (diff)
Module renamed
Task-number: QTRD-2224 Change-Id: Iec18b6121809300b11d85445281d3c626c434f35 Reviewed-by: Miikka Heikkinen <miikka.heikkinen@digia.com>
Diffstat (limited to 'src/datavisualization/utils')
-rw-r--r--src/datavisualization/utils/abstractobjecthelper.cpp81
-rw-r--r--src/datavisualization/utils/abstractobjecthelper_p.h65
-rw-r--r--src/datavisualization/utils/camerahelper.cpp286
-rw-r--r--src/datavisualization/utils/camerahelper_p.h90
-rw-r--r--src/datavisualization/utils/meshloader.cpp125
-rw-r--r--src/datavisualization/utils/meshloader_p.h51
-rw-r--r--src/datavisualization/utils/objecthelper.cpp101
-rw-r--r--src/datavisualization/utils/objecthelper_p.h54
-rw-r--r--src/datavisualization/utils/shaderhelper.cpp229
-rw-r--r--src/datavisualization/utils/shaderhelper_p.h110
-rw-r--r--src/datavisualization/utils/surfaceobject.cpp348
-rw-r--r--src/datavisualization/utils/surfaceobject_p.h67
-rw-r--r--src/datavisualization/utils/texturehelper.cpp394
-rw-r--r--src/datavisualization/utils/texturehelper_p.h71
-rw-r--r--src/datavisualization/utils/utils.cpp303
-rw-r--r--src/datavisualization/utils/utils.pri19
-rw-r--r--src/datavisualization/utils/utils_p.h76
-rw-r--r--src/datavisualization/utils/vertexindexer.cpp153
-rw-r--r--src/datavisualization/utils/vertexindexer_p.h88
19 files changed, 2711 insertions, 0 deletions
diff --git a/src/datavisualization/utils/abstractobjecthelper.cpp b/src/datavisualization/utils/abstractobjecthelper.cpp
new file mode 100644
index 00000000..d47f2fe6
--- /dev/null
+++ b/src/datavisualization/utils/abstractobjecthelper.cpp
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#include "abstractobjecthelper_p.h"
+
+#include <QDebug>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+AbstractObjectHelper::AbstractObjectHelper()
+ : m_vertexbuffer(0),
+ m_normalbuffer(0),
+ m_uvbuffer(0),
+ m_elementbuffer(0),
+ m_indexCount(0),
+ m_meshDataLoaded(false)
+{
+}
+
+AbstractObjectHelper::~AbstractObjectHelper()
+{
+ glDeleteBuffers(1, &m_vertexbuffer);
+ glDeleteBuffers(1, &m_uvbuffer);
+ glDeleteBuffers(1, &m_normalbuffer);
+ glDeleteBuffers(1, &m_elementbuffer);
+}
+
+GLuint AbstractObjectHelper::vertexBuf()
+{
+ if (!m_meshDataLoaded)
+ qFatal("No loaded object");
+ return m_vertexbuffer;
+}
+
+GLuint AbstractObjectHelper::normalBuf()
+{
+ if (!m_meshDataLoaded)
+ qFatal("No loaded object");
+ return m_normalbuffer;
+}
+
+GLuint AbstractObjectHelper::uvBuf()
+{
+ if (!m_meshDataLoaded)
+ qFatal("No loaded object");
+ return m_uvbuffer;
+}
+
+GLuint AbstractObjectHelper::elementBuf()
+{
+ if (!m_meshDataLoaded)
+ qFatal("No loaded object");
+ return m_elementbuffer;
+}
+
+GLuint AbstractObjectHelper::indexCount()
+{
+ return m_indexCount;
+}
+
+GLuint AbstractObjectHelper::indicesType()
+{
+ return m_indicesType;
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/utils/abstractobjecthelper_p.h b/src/datavisualization/utils/abstractobjecthelper_p.h
new file mode 100644
index 00000000..a6de6941
--- /dev/null
+++ b/src/datavisualization/utils/abstractobjecthelper_p.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtDataVisualization API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef ABSTRACTOBJECTHELPER_H
+#define ABSTRACTOBJECTHELPER_H
+
+#include "datavisualizationglobal_p.h"
+#include <QOpenGLFunctions>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class AbstractObjectHelper: protected QOpenGLFunctions
+{
+protected:
+ AbstractObjectHelper();
+public:
+ ~AbstractObjectHelper();
+
+ GLuint vertexBuf();
+ GLuint normalBuf();
+ GLuint uvBuf();
+ GLuint elementBuf();
+ GLuint indexCount();
+ GLuint indicesType();
+
+public:
+ GLuint m_vertexbuffer;
+ GLuint m_normalbuffer;
+ GLuint m_uvbuffer;
+ GLuint m_elementbuffer;
+
+ GLuint m_indexCount;
+ GLboolean m_meshDataLoaded;
+
+ GLuint m_indicesType;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif // ABSTRACTOBJECTHELPER_H
diff --git a/src/datavisualization/utils/camerahelper.cpp b/src/datavisualization/utils/camerahelper.cpp
new file mode 100644
index 00000000..01de3f80
--- /dev/null
+++ b/src/datavisualization/utils/camerahelper.cpp
@@ -0,0 +1,286 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#include "camerahelper_p.h"
+
+#include <qmath.h>
+#include <QMatrix4x4>
+#include <QVector3D>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+CameraHelper::CameraHelper(QObject *parent) :
+ QObject(parent),
+ m_position(0, 0.25, 3),
+ m_target(0, 0, 0),
+ m_up(0, 1, 0),
+ m_previousMousePos(0,0),
+ m_xRotation(0),
+ m_yRotation(0),
+ m_defaultXRotation(0),
+ m_defaultYRotation(0),
+ m_rotationSpeed(100)
+{
+}
+
+CameraHelper::~CameraHelper()
+{
+}
+
+
+// FUNCTIONS
+void CameraHelper::setRotationSpeed(int speed)
+{
+ // increase for faster rotation
+ m_rotationSpeed = speed;
+}
+
+void CameraHelper::setCameraRotation(const QPointF &rotation)
+{
+ m_xRotation = rotation.x();
+ m_defaultXRotation = m_xRotation;
+ m_yRotation = rotation.y();
+ m_defaultYRotation = m_yRotation;
+}
+
+void CameraHelper::setDefaultCameraOrientation(const QVector3D &defaultPosition,
+ const QVector3D &defaultTarget,
+ const QVector3D &defaultUp)
+{
+ m_position = defaultPosition;
+ m_target = defaultTarget;
+ m_up = defaultUp;
+}
+
+QMatrix4x4 CameraHelper::calculateViewMatrix(const QPoint &mousePos, int zoom,
+ int screenWidth, int screenHeight, bool showUnder)
+{
+ QMatrix4x4 viewMatrix;
+ GLfloat lowerLimit = 0.0f;
+
+ if (showUnder)
+ lowerLimit = -90.0f;
+
+ // Calculate mouse movement since last frame
+ GLfloat mouseMoveX = GLfloat(m_previousMousePos.x() - mousePos.x())
+ / (screenWidth / m_rotationSpeed);
+ GLfloat mouseMoveY = GLfloat(m_previousMousePos.y() - mousePos.y())
+ / (screenHeight / m_rotationSpeed);
+ // Apply to rotations
+ m_xRotation -= mouseMoveX;
+ m_yRotation -= mouseMoveY;
+ // Reset at 360 in x and limit to 0...90 in y
+ if (qAbs(m_xRotation) >= 360.0f)
+ m_xRotation = 0.0f;
+ if (m_yRotation >= 90.0f)
+ m_yRotation = 90.0f;
+ else if (m_yRotation <= lowerLimit)
+ m_yRotation = lowerLimit;
+
+ // Apply to view matrix
+ viewMatrix.lookAt(m_position, m_target, m_up);
+ // Compensate for translation (if m_target is off origin)
+ viewMatrix.translate(m_target.x(), m_target.y(), m_target.z());
+ // Apply rotations
+ // Handle x and z rotation when y -angle is other than 0
+ viewMatrix.rotate(m_xRotation, 0, qCos(qDegreesToRadians(m_yRotation)),
+ qSin(qDegreesToRadians(m_yRotation)));
+ // y rotation is always "clean"
+ viewMatrix.rotate(m_yRotation, 1.0f, 0.0f, 0.0f);
+ // handle zoom by scaling
+ viewMatrix.scale((GLfloat)zoom / 100.0f);
+ // Compensate for translation (if m_target is off origin)
+ viewMatrix.translate(-m_target.x(), -m_target.y(), -m_target.z());
+ //qDebug() << m_xRotation << m_yRotation;
+
+ m_previousMousePos = mousePos;
+ return viewMatrix;
+}
+
+QVector3D CameraHelper::calculateLightPosition(const QVector3D &lightPosition,
+ GLfloat fixedRotation, GLfloat distanceModifier)
+{
+ // Move light with camera
+ QVector3D newLightPosition;
+ GLfloat radiusFactor = lightPosition.z() * (1.5f + distanceModifier); // for making sure light is outside the scene at its lowest point
+ GLfloat xAngle;
+ GLfloat yAngle;
+ if (!fixedRotation) {
+ xAngle = qDegreesToRadians(m_xRotation);
+ yAngle = qDegreesToRadians(m_yRotation);
+ } else {
+ xAngle = qDegreesToRadians(fixedRotation);
+ yAngle = 0;
+ }
+ GLfloat radius = (radiusFactor + lightPosition.y()); // set radius to match the highest height of the light
+ GLfloat zPos = radius * qCos(xAngle) * qCos(yAngle);
+ GLfloat xPos = radius * qSin(xAngle) * qCos(yAngle);
+ GLfloat yPos = (radiusFactor + lightPosition.y()) * qSin(yAngle);
+ // Keep light in the set position in relation to camera
+ newLightPosition = QVector3D(-xPos + lightPosition.x(),
+ yPos + lightPosition.y(),
+ zPos + lightPosition.z());
+ //qDebug() << newLightPosition << xAngle << yAngle << fixedRotation;
+ return newLightPosition;
+}
+
+void CameraHelper::updateMousePos(const QPoint &mousePos)
+{
+ m_previousMousePos = mousePos;
+ // if mouse position is set to (0, 0), reset rotations
+ if (QPoint(0, 0) == mousePos) {
+ m_xRotation = m_defaultXRotation;
+ m_yRotation = m_defaultYRotation;
+ }
+}
+
+QPointF CameraHelper::getCameraRotations()
+{
+ QPointF rotations(m_xRotation, m_yRotation);
+ return rotations;
+}
+
+void CameraHelper::setCameraPreset(QDataVis::CameraPreset preset)
+{
+ switch (preset) {
+ case QDataVis::PresetFrontLow: {
+ qDebug("PresetFrontLow");
+ CameraHelper::setCameraRotation(QPointF(0.0f, 0.0f));
+ break;
+ }
+ case QDataVis::PresetFront: {
+ qDebug("PresetFront");
+ CameraHelper::setCameraRotation(QPointF(0.0f, 22.5f));
+ break;
+ }
+ case QDataVis::PresetFrontHigh: {
+ qDebug("PresetFrontHigh");
+ CameraHelper::setCameraRotation(QPointF(0.0f, 45.0f));
+ break;
+ }
+ case QDataVis::PresetLeftLow: {
+ qDebug("PresetLeftLow");
+ CameraHelper::setCameraRotation(QPointF(90.0f, 0.0f));
+ break;
+ }
+ case QDataVis::PresetLeft: {
+ qDebug("PresetLeft");
+ CameraHelper::setCameraRotation(QPointF(90.0f, 22.5f));
+ break;
+ }
+ case QDataVis::PresetLeftHigh: {
+ qDebug("PresetLeftHigh");
+ CameraHelper::setCameraRotation(QPointF(90.0f, 45.0f));
+ break;
+ }
+ case QDataVis::PresetRightLow: {
+ qDebug("PresetRightLow");
+ CameraHelper::setCameraRotation(QPointF(-90.0f, 0.0f));
+ break;
+ }
+ case QDataVis::PresetRight: {
+ qDebug("PresetRight");
+ CameraHelper::setCameraRotation(QPointF(-90.0f, 22.5f));
+ break;
+ }
+ case QDataVis::PresetRightHigh: {
+ qDebug("PresetRightHigh");
+ CameraHelper::setCameraRotation(QPointF(-90.0f, 45.0f));
+ break;
+ }
+ case QDataVis::PresetBehindLow: {
+ qDebug("PresetBehindLow");
+ CameraHelper::setCameraRotation(QPointF(180.0f, 0.0f));
+ break;
+ }
+ case QDataVis::PresetBehind: {
+ qDebug("PresetBehind");
+ CameraHelper::setCameraRotation(QPointF(180.0f, 22.5f));
+ break;
+ }
+ case QDataVis::PresetBehindHigh: {
+ qDebug("PresetBehindHigh");
+ CameraHelper::setCameraRotation(QPointF(180.0f, 45.0f));
+ break;
+ }
+ case QDataVis::PresetIsometricLeft: {
+ qDebug("PresetIsometricLeft");
+ CameraHelper::setCameraRotation(QPointF(45.0f, 22.5f));
+ break;
+ }
+ case QDataVis::PresetIsometricLeftHigh: {
+ qDebug("PresetIsometricLeftHigh");
+ CameraHelper::setCameraRotation(QPointF(45.0f, 45.0f));
+ break;
+ }
+ case QDataVis::PresetIsometricRight: {
+ qDebug("PresetIsometricRight");
+ CameraHelper::setCameraRotation(QPointF(-45.0f, 22.5f));
+ break;
+ }
+ case QDataVis::PresetIsometricRightHigh: {
+ qDebug("PresetIsometricRightHigh");
+ CameraHelper::setCameraRotation(QPointF(-45.0f, 45.0f));
+ break;
+ }
+ case QDataVis::PresetDirectlyAbove: {
+ qDebug("PresetDirectlyAbove");
+ CameraHelper::setCameraRotation(QPointF(0.0f, 90.0f));
+ break;
+ }
+ case QDataVis::PresetDirectlyAboveCW45: {
+ qDebug("PresetDirectlyAboveCW45");
+ CameraHelper::setCameraRotation(QPointF(-45.0f, 90.0f));
+ break;
+ }
+ case QDataVis::PresetDirectlyAboveCCW45: {
+ qDebug("PresetDirectlyAboveCCW45");
+ CameraHelper::setCameraRotation(QPointF(45.0f, 90.0f));
+ break;
+ }
+ case QDataVis::PresetFrontBelow: {
+ qDebug("PresetFrontBelow");
+ CameraHelper::setCameraRotation(QPointF(0.0f, -45.0f));
+ break;
+ }
+ case QDataVis::PresetLeftBelow: {
+ qDebug("PresetLeftBelow");
+ CameraHelper::setCameraRotation(QPointF(90.0f, -45.0f));
+ break;
+ }
+ case QDataVis::PresetRightBelow: {
+ qDebug("PresetRightBelow");
+ CameraHelper::setCameraRotation(QPointF(-90.0f, -45.0f));
+ break;
+ }
+ case QDataVis::PresetBehindBelow: {
+ qDebug("PresetBehindBelow");
+ CameraHelper::setCameraRotation(QPointF(180.0f, -45.0f));
+ break;
+ }
+ case QDataVis::PresetDirectlyBelow: {
+ qDebug("PresetDirectlyBelow");
+ CameraHelper::setCameraRotation(QPointF(0.0f, -90.0f));
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/utils/camerahelper_p.h b/src/datavisualization/utils/camerahelper_p.h
new file mode 100644
index 00000000..1ef4d257
--- /dev/null
+++ b/src/datavisualization/utils/camerahelper_p.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtDataVisualization API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef CAMERAPOSITIONER_P_H
+#define CAMERAPOSITIONER_P_H
+
+#include "datavisualizationglobal_p.h"
+#include "q3dbars.h"
+#include <QObject>
+
+class QMatrix4x4;
+class QVector3D;
+class QPoint;
+class QPointF;
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class CameraHelper : public QObject
+{
+ Q_OBJECT
+
+private:
+ QVector3D m_position;
+ QVector3D m_target;
+ QVector3D m_up;
+
+ QPoint m_previousMousePos;
+
+ GLfloat m_xRotation;
+ GLfloat m_yRotation;
+ GLfloat m_defaultXRotation;
+ GLfloat m_defaultYRotation;
+
+ GLfloat m_rotationSpeed;
+
+public:
+ explicit CameraHelper(QObject *parent = 0);
+ ~CameraHelper();
+
+ // How fast camera rotates when mouse is dragged. Default is 100.
+ void setRotationSpeed(int speed);
+ // Set camera rotation in degrees
+ void setCameraRotation(const QPointF &rotation);
+ // Get camera rotations
+ QPointF getCameraRotations();
+ // Set default camera orientation. Position's x and y should be 0.
+ void setDefaultCameraOrientation(const QVector3D &defaultPosition,
+ const QVector3D &defaultTarget,
+ const QVector3D &defaultUp);
+ // Calculate view matrix based on rotation and zoom
+ QMatrix4x4 calculateViewMatrix(const QPoint &mousePos, int zoom,
+ int screenWidth, int screenHeight,
+ bool showUnder = false);
+ // Calcluate light position based on rotation. Call after calling calculateViewMatrix to get
+ // up-to-date position
+ QVector3D calculateLightPosition(const QVector3D &lightPosition,
+ GLfloat fixedRotation = 0.0f,
+ GLfloat distanceModifier = 0.0f);
+ void updateMousePos(const QPoint &mousePos);
+ void setCameraPreset(QDataVis::CameraPreset preset);
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/utils/meshloader.cpp b/src/datavisualization/utils/meshloader.cpp
new file mode 100644
index 00000000..119cde3a
--- /dev/null
+++ b/src/datavisualization/utils/meshloader.cpp
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#include "meshloader_p.h"
+
+#include <QFile>
+#include <QStringList>
+#include <QVector>
+#include <QVector2D>
+#include <QVector3D>
+
+#include <QDebug>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+QString slashTag = QStringLiteral("/");
+
+bool MeshLoader::loadOBJ(const QString &path,
+ QVector<QVector3D> &out_vertices,
+ QVector<QVector2D> &out_uvs,
+ QVector<QVector3D> &out_normals)
+{
+ //qDebug() << "Loading OBJ file" << path;
+
+ QVector<unsigned int> vertexIndices, uvIndices, normalIndices;
+ QVector<QVector3D> temp_vertices;
+ QVector<QVector2D> temp_uvs;
+ QVector<QVector3D> temp_normals;
+
+ QFile file(path);
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ qWarning("Cannot open the file");
+ return false;
+ }
+
+ QTextStream textIn(&file);
+ while (!textIn.atEnd()) {
+ QString line = textIn.readLine();
+ QStringList lineContents = line.split(QStringLiteral(" "));
+ if (!lineContents.at(0).compare(QStringLiteral("v"))) {
+ QVector3D vertex;
+ vertex.setX(lineContents.at(1).toFloat());
+ vertex.setY(lineContents.at(2).toFloat());
+ vertex.setZ(lineContents.at(3).toFloat());
+ temp_vertices.append(vertex);
+ }
+ else if (!lineContents.at(0).compare(QStringLiteral("vt"))) {
+ QVector2D uv;
+ uv.setX(lineContents.at(1).toFloat());
+ uv.setY(lineContents.at(2).toFloat()); // invert this if using DDS textures
+ temp_uvs.append(uv);
+ }
+ else if (!lineContents.at(0).compare(QStringLiteral("vn"))) {
+ QVector3D normal;
+ normal.setX(lineContents.at(1).toFloat());
+ normal.setY(lineContents.at(2).toFloat());
+ normal.setZ(lineContents.at(3).toFloat());
+ temp_normals.append(normal);
+ }
+ else if (!lineContents.at(0).compare(QStringLiteral("f"))) {
+ unsigned int vertexIndex[3], uvIndex[3], normalIndex[3];
+ QStringList set1 = lineContents.at(1).split(slashTag);
+ QStringList set2 = lineContents.at(2).split(slashTag);
+ QStringList set3 = lineContents.at(3).split(slashTag);
+ vertexIndex[0] = set1.at(0).toUInt();
+ vertexIndex[1] = set2.at(0).toUInt();
+ vertexIndex[2] = set3.at(0).toUInt();
+ uvIndex[0] = set1.at(1).toUInt();
+ uvIndex[1] = set2.at(1).toUInt();
+ uvIndex[2] = set3.at(1).toUInt();
+ normalIndex[0] = set1.at(2).toUInt();
+ normalIndex[1] = set2.at(2).toUInt();
+ normalIndex[2] = set3.at(2).toUInt();
+ vertexIndices.append(vertexIndex[0]);
+ vertexIndices.append(vertexIndex[1]);
+ vertexIndices.append(vertexIndex[2]);
+ uvIndices.append(uvIndex[0]);
+ uvIndices.append(uvIndex[1]);
+ uvIndices.append(uvIndex[2]);
+ normalIndices.append(normalIndex[0]);
+ normalIndices.append(normalIndex[1]);
+ normalIndices.append(normalIndex[2]);
+ }
+ else {
+ //qWarning("Line did not contain usable data");
+ }
+ }
+
+ // For each vertex of each triangle
+ for (int i = 0; i < vertexIndices.size(); i++) {
+ // Get the indices of its attributes
+ unsigned int vertexIndex = vertexIndices[i];
+ unsigned int uvIndex = uvIndices[i];
+ unsigned int normalIndex = normalIndices[i];
+
+ // Get the attributes thanks to the index
+ QVector3D vertex = temp_vertices[vertexIndex - 1];
+ QVector2D uv = temp_uvs[uvIndex - 1];
+ QVector3D normal = temp_normals[normalIndex - 1];
+
+ // Put the attributes in buffers
+ out_vertices.append(vertex);
+ out_uvs.append(uv);
+ out_normals.append(normal);
+ }
+
+ return true;
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/utils/meshloader_p.h b/src/datavisualization/utils/meshloader_p.h
new file mode 100644
index 00000000..48551fff
--- /dev/null
+++ b/src/datavisualization/utils/meshloader_p.h
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtDataVisualization API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef MESHLOADER_P_H
+#define MESHLOADER_P_H
+
+#include "datavisualizationglobal_p.h"
+
+class QVector2D;
+class QVector3D;
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class MeshLoader
+{
+ public:
+ static bool loadOBJ(const QString &path,
+ QVector<QVector3D> &out_vertices,
+ QVector<QVector2D> &out_uvs,
+ QVector<QVector3D> &out_normals);
+ // TODO: add loaders for other formats?
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/utils/objecthelper.cpp b/src/datavisualization/utils/objecthelper.cpp
new file mode 100644
index 00000000..9660c215
--- /dev/null
+++ b/src/datavisualization/utils/objecthelper.cpp
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#include "meshloader_p.h"
+#include "vertexindexer_p.h"
+#include "objecthelper_p.h"
+#include "abstractobjecthelper_p.h"
+
+#include <QDebug>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+ObjectHelper::ObjectHelper(const QString &objectFile)
+ : m_objectFile(objectFile)
+{
+ m_indicesType = GL_UNSIGNED_SHORT;
+}
+
+ObjectHelper::~ObjectHelper()
+{
+}
+
+void ObjectHelper::setObjectFile(const QString &objectFile)
+{
+ m_objectFile = objectFile;
+}
+
+void ObjectHelper::load()
+{
+ initializeOpenGLFunctions();
+ if (m_meshDataLoaded) {
+ // Delete old data
+ glDeleteBuffers(1, &m_vertexbuffer);
+ glDeleteBuffers(1, &m_uvbuffer);
+ glDeleteBuffers(1, &m_normalbuffer);
+ glDeleteBuffers(1, &m_elementbuffer);
+ }
+ QVector<QVector3D> vertices;
+ QVector<QVector2D> uvs;
+ QVector<QVector3D> normals;
+ bool loadOk = MeshLoader::loadOBJ(m_objectFile, vertices, uvs, normals);
+ if (!loadOk)
+ qFatal("loading failed");
+
+ //qDebug() << "vertex count" << vertices.size();;
+
+ // Index vertices
+ QVector<unsigned short> indices;
+ QVector<QVector3D> indexed_vertices;
+ QVector<QVector2D> indexed_uvs;
+ QVector<QVector3D> indexed_normals;
+ VertexIndexer::indexVBO(vertices, uvs, normals, indices, indexed_vertices, indexed_uvs,
+ indexed_normals);
+
+ m_indexCount = indices.size();
+ //qDebug() << "index count" << m_indexCount;
+
+ glGenBuffers(1, &m_vertexbuffer);
+ glBindBuffer(GL_ARRAY_BUFFER, m_vertexbuffer);
+ glBufferData(GL_ARRAY_BUFFER, indexed_vertices.size() * sizeof(QVector3D),
+ &indexed_vertices.at(0),
+ GL_STATIC_DRAW);
+
+ glGenBuffers(1, &m_normalbuffer);
+ glBindBuffer(GL_ARRAY_BUFFER, m_normalbuffer);
+ glBufferData(GL_ARRAY_BUFFER, indexed_normals.size() * sizeof(QVector3D),
+ &indexed_normals.at(0),
+ GL_STATIC_DRAW);
+
+ glGenBuffers(1, &m_uvbuffer);
+ glBindBuffer(GL_ARRAY_BUFFER, m_uvbuffer);
+ glBufferData(GL_ARRAY_BUFFER, indexed_uvs.size() * sizeof(QVector2D),
+ &indexed_uvs.at(0), GL_STATIC_DRAW);
+
+ glGenBuffers(1, &m_elementbuffer);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementbuffer);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned short),
+ &indices.at(0), GL_STATIC_DRAW);
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ m_meshDataLoaded = true;
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/utils/objecthelper_p.h b/src/datavisualization/utils/objecthelper_p.h
new file mode 100644
index 00000000..9d643fdd
--- /dev/null
+++ b/src/datavisualization/utils/objecthelper_p.h
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtDataVisualization API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef OBJECTHELPER_P_H
+#define OBJECTHELPER_P_H
+
+#include "datavisualizationglobal_p.h"
+#include "abstractobjecthelper_p.h"
+#include <QOpenGLFunctions>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class ObjectHelper : public AbstractObjectHelper
+{
+public:
+ ObjectHelper(const QString &objectFile = QString());
+ ~ObjectHelper();
+
+ void setObjectFile(const QString &objectFile);
+
+ void load();
+
+private:
+ QString m_objectFile;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/utils/shaderhelper.cpp b/src/datavisualization/utils/shaderhelper.cpp
new file mode 100644
index 00000000..508bc90a
--- /dev/null
+++ b/src/datavisualization/utils/shaderhelper.cpp
@@ -0,0 +1,229 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#include "shaderhelper_p.h"
+
+#include <QOpenGLShader>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+ShaderHelper::ShaderHelper(QObject *parent,
+ const QString &vertexShader,
+ const QString &fragmentShader,
+ const QString &texture,
+ const QString &depthTexture)
+ : m_caller(parent),
+ m_program(0),
+ m_vertexShaderFile(vertexShader),
+ m_fragmentShaderFile(fragmentShader),
+ m_textureFile(texture),
+ m_depthTextureFile(depthTexture)
+{
+}
+
+ShaderHelper::~ShaderHelper()
+{
+ delete m_program;
+}
+
+void ShaderHelper::setShaders(const QString &vertexShader,
+ const QString &fragmentShader)
+{
+ m_vertexShaderFile = vertexShader;
+ m_fragmentShaderFile = fragmentShader;
+}
+
+void ShaderHelper::setTextures(const QString &texture,
+ const QString &depthTexture)
+{
+ m_textureFile = texture;
+ m_depthTextureFile = depthTexture;
+}
+
+void ShaderHelper::initialize()
+{
+ if (m_program)
+ delete m_program;
+ m_program = new QOpenGLShaderProgram(m_caller);
+ if (!m_program->addShaderFromSourceFile(QOpenGLShader::Vertex, m_vertexShaderFile))
+ qFatal("Compiling Vertex shader failed");
+ if (!m_program->addShaderFromSourceFile(QOpenGLShader::Fragment, m_fragmentShaderFile))
+ qFatal("Compiling Fragment shader failed");
+ m_program->link();
+
+ m_positionAttr = m_program->attributeLocation("vertexPosition_mdl");
+ m_normalAttr = m_program->attributeLocation("vertexNormal_mdl");
+ m_uvAttr = m_program->attributeLocation("vertexUV");
+
+ m_mvpMatrixUniform = m_program->uniformLocation("MVP");
+ m_viewMatrixUniform = m_program->uniformLocation("V");
+ m_modelMatrixUniform = m_program->uniformLocation("M");
+ m_invTransModelMatrixUniform = m_program->uniformLocation("itM");
+ m_depthMatrixUniform = m_program->uniformLocation("depthMVP");
+ m_lightPositionUniform = m_program->uniformLocation("lightPosition_wrld");
+ m_lightStrengthUniform = m_program->uniformLocation("lightStrength");
+ m_ambientStrengthUniform = m_program->uniformLocation("ambientStrength");
+ m_shadowQualityUniform = m_program->uniformLocation("shadowQuality");
+ m_colorUniform = m_program->uniformLocation("color_mdl");
+ m_textureUniform = m_program->uniformLocation("textureSampler");
+ m_shadowUniform = m_program->uniformLocation("shadowMap");
+
+ m_initialized = true;
+}
+
+void ShaderHelper::bind()
+{
+ m_program->bind();
+}
+
+void ShaderHelper::release()
+{
+ m_program->release();
+}
+
+void ShaderHelper::setUniformValue(GLuint uniform, const QVector3D &value)
+{
+ m_program->setUniformValue(uniform, value);
+}
+
+void ShaderHelper::setUniformValue(GLuint uniform, const QVector4D &value)
+{
+ m_program->setUniformValue(uniform, value);
+}
+
+void ShaderHelper::setUniformValue(GLuint uniform, const QMatrix4x4 &value)
+{
+ m_program->setUniformValue(uniform, value);
+}
+
+void ShaderHelper::setUniformValue(GLuint uniform, GLfloat value)
+{
+ m_program->setUniformValue(uniform, value);
+}
+
+void ShaderHelper::setUniformValue(GLuint uniform, GLint value)
+{
+ m_program->setUniformValue(uniform, value);
+}
+
+GLuint ShaderHelper::MVP()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_mvpMatrixUniform;
+}
+
+GLuint ShaderHelper::view()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_viewMatrixUniform;
+}
+
+GLuint ShaderHelper::model()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_modelMatrixUniform;
+}
+
+GLuint ShaderHelper::nModel()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_invTransModelMatrixUniform;
+}
+
+GLuint ShaderHelper::depth()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_depthMatrixUniform;
+}
+
+GLuint ShaderHelper::lightP()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_lightPositionUniform;
+}
+
+GLuint ShaderHelper::lightS()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_lightStrengthUniform;
+}
+
+GLuint ShaderHelper::ambientS()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_ambientStrengthUniform;
+}
+
+GLuint ShaderHelper::shadowQ()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_shadowQualityUniform;
+}
+
+GLuint ShaderHelper::color()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_colorUniform;
+}
+
+GLuint ShaderHelper::texture()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_textureUniform;
+}
+
+GLuint ShaderHelper::shadow()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_shadowUniform;
+}
+
+GLuint ShaderHelper::posAtt()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_positionAttr;
+}
+
+GLuint ShaderHelper::uvAtt()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_uvAttr;
+}
+
+GLuint ShaderHelper::normalAtt()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_normalAttr;
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/utils/shaderhelper_p.h b/src/datavisualization/utils/shaderhelper_p.h
new file mode 100644
index 00000000..72a7b256
--- /dev/null
+++ b/src/datavisualization/utils/shaderhelper_p.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtDataVisualization API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef SHADERHELPER_P_H
+#define SHADERHELPER_P_H
+
+#include "datavisualizationglobal_p.h"
+#include <QOpenGLFunctions>
+
+class QOpenGLShaderProgram;
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class ShaderHelper
+{
+ public:
+ ShaderHelper(QObject *parent,
+ const QString &vertexShader = QString(),
+ const QString &fragmentShader = QString(),
+ const QString &texture = QString(),
+ const QString &depthTexture = QString());
+ ~ShaderHelper();
+
+ void setShaders(const QString &vertexShader, const QString &fragmentShader);
+ void setTextures(const QString &texture, const QString &depthTexture);
+
+ void initialize();
+ void bind();
+ void release();
+ void setUniformValue(GLuint uniform, const QVector3D &value);
+ void setUniformValue(GLuint uniform, const QVector4D &value);
+ void setUniformValue(GLuint uniform, const QMatrix4x4 &value);
+ void setUniformValue(GLuint uniform, GLfloat value);
+ void setUniformValue(GLuint uniform, GLint value);
+
+ GLuint MVP();
+ GLuint view();
+ GLuint model();
+ GLuint nModel();
+ GLuint depth();
+ GLuint lightP();
+ GLuint lightS();
+ GLuint ambientS();
+ GLuint shadowQ();
+ GLuint color();
+ GLuint texture();
+ GLuint shadow();
+
+ GLuint posAtt();
+ GLuint uvAtt();
+ GLuint normalAtt();
+
+ private:
+ QObject *m_caller;
+ QOpenGLShaderProgram *m_program;
+
+ QString m_vertexShaderFile;
+ QString m_fragmentShaderFile;
+
+ QString m_textureFile;
+ QString m_depthTextureFile;
+
+ GLuint m_positionAttr;
+ GLuint m_uvAttr;
+ GLuint m_normalAttr;
+
+ GLuint m_colorUniform;
+ GLuint m_viewMatrixUniform;
+ GLuint m_modelMatrixUniform;
+ GLuint m_invTransModelMatrixUniform;
+ GLuint m_depthMatrixUniform;
+ GLuint m_mvpMatrixUniform;
+ GLuint m_lightPositionUniform;
+ GLuint m_lightStrengthUniform;
+ GLuint m_ambientStrengthUniform;
+ GLuint m_shadowQualityUniform;
+ GLuint m_textureUniform;
+ GLuint m_shadowUniform;
+
+ GLboolean m_initialized;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/utils/surfaceobject.cpp b/src/datavisualization/utils/surfaceobject.cpp
new file mode 100644
index 00000000..a0ed292a
--- /dev/null
+++ b/src/datavisualization/utils/surfaceobject.cpp
@@ -0,0 +1,348 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#include "surfaceobject_p.h"
+#include "abstractobjecthelper_p.h"
+
+#include <QVector3D>
+#include <QVector2D>
+
+#include <QDebug>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+SurfaceObject::SurfaceObject()
+{
+ m_indicesType = GL_UNSIGNED_INT;
+}
+
+SurfaceObject::~SurfaceObject()
+{
+}
+
+void SurfaceObject::setUpSmoothData(const QSurfaceDataArray &dataArray, QRect space, GLfloat yRange, bool changeGeometry)
+{
+ int columns = space.width();
+ int rows = space.height();
+ GLfloat width = (GLfloat(columns) - 1.0f) / 2.0f;
+ GLfloat depth = (GLfloat(rows) - 1.0f) / -2.0f;
+ GLfloat height = yRange / 2.0f;
+
+ // Create vertice table
+ QVector<QVector3D> vertices;
+ QVector<QVector2D> uvs;
+ float uvX = 1.0 / float(columns - 1);
+ float uvY = 1.0 / float(rows - 1);
+ int row = 0;
+ for (float i = 0.0f; i < float(rows); i += 1.0, row += columns) {
+ for (float j = 0; j < columns; j++) {
+ vertices.append(QVector3D(j / width - 1.0f,
+ dataArray.at(int(i))->at(int(j)) / height - 1.0f,
+ i / depth + 1.0f));
+ uvs.append(QVector2D(j * uvX, i * uvY));
+ }
+ }
+
+ // Create normals
+ QVector<QVector3D> normals;
+ for (int row = 0; row < (rows - 1) * columns; row += columns) {
+ for (int j = 0; j < columns - 1; j++) {
+ normals.append(normal(vertices.at(row + j),
+ vertices.at(row + j + 1),
+ vertices.at(row + columns + j)));
+ }
+ int p = row + columns - 1;
+ normals.append(normal(vertices.at(p),
+ vertices.at(p + columns),
+ vertices.at(p - 1)));
+ }
+ for (int j = (rows - 1) * columns ; j < rows * columns - 1; j++) {
+ normals.append(normal(vertices.at(j),
+ vertices.at(j - columns),
+ vertices.at(j + 1)));
+ }
+ int p = rows * columns - 1;
+ normals.append(normal(vertices.at(p),
+ vertices.at(p - 1),
+ vertices.at(p - columns - 1)));
+
+ // Create indices table
+ GLint *indices = 0;
+ if (changeGeometry) {
+ m_indexCount = 6 * (columns - 1) * (rows - 1);
+ indices = new GLint[m_indexCount];
+ p = 0;
+ for (int row = 0; row < (rows - 1) * columns; row += columns) {
+ for (int j = 0; j < columns - 1; j++) {
+ // Left triangle
+ indices[p++] = row + j + 1;
+ indices[p++] = row + columns + j;
+ indices[p++] = row + j;
+
+ // Right triangle
+ indices[p++] = row + columns + j + 1;
+ indices[p++] = row + columns + j;
+ indices[p++] = row + j + 1;
+ }
+ }
+ }
+
+ // Create line element indices
+ GLint *gridIndices = 0;
+ if (changeGeometry) {
+ m_gridIndexCount = 2 * columns * (rows - 1) + 2 * rows * (columns - 1);
+ gridIndices = new GLint[m_gridIndexCount];
+ p = 0;
+ for (int i = 0, row = 0; i < rows; i++, row += columns) {
+ for (int j = 0; j < columns - 1; j++) {
+ gridIndices[p++] = row + j;
+ gridIndices[p++] = row + j + 1;
+ }
+ }
+ for (int i = 0, row = 0; i < rows - 1; i++, row += columns) {
+ for (int j = 0; j < columns; j++) {
+ gridIndices[p++] = row + j;
+ gridIndices[p++] = row + j + columns;
+ }
+ }
+ }
+
+ createBuffers(vertices, uvs, normals, indices, gridIndices, changeGeometry);
+
+ delete[] indices;
+ delete[] gridIndices;
+}
+
+
+void SurfaceObject::setUpData(const QSurfaceDataArray &dataArray, QRect space, GLfloat yRange, bool changeGeometry)
+{
+ int columns = space.width();
+ int rows = space.height();
+ GLfloat width = (GLfloat(columns) - 1.0f) / 2.0f;
+ GLfloat depth = (GLfloat(rows) - 1.0f) / -2.0f;
+ GLfloat height = yRange / 2.0f;
+ float uvX = 1.0 / float(columns - 1);
+ float uvY = 1.0 / float(rows - 1);
+
+ // Create vertice table
+ QVector<QVector3D> vertices;
+ QVector<QVector2D> uvs;
+ int row = 0;
+ for (float i = 0.0f; i < float(rows); i += 1.0f, row += columns) {
+ for (float j = 0.0f; j < float(columns); j += 1.0f) {
+ vertices.append(QVector3D(j / width - 1.0f,
+ dataArray.at(int(i))->at(int(j)) / height - 1.0f,
+ i / depth + 1.0f));
+ uvs.append(QVector2D(j * uvX, i * uvY));
+ if (j > 0 && j < columns - 1) {
+ vertices.append(vertices.last());
+ uvs.append(uvs.last());
+ }
+ }
+ }
+
+ // Create normals & indices table
+ QVector<QVector3D> normals;
+ int doubleColumns = columns * 2 - 2;
+
+ GLint *indices = 0;
+ int p = 0;
+ if (changeGeometry) {
+ m_indexCount = 6 * (columns - 1) * (rows - 1);
+ indices = new GLint[m_indexCount];
+ }
+
+ for (int row = 0, upperRow = doubleColumns;
+ row < (rows - 1) * doubleColumns;
+ row += doubleColumns, upperRow += doubleColumns) {
+ for (int j = 0; j < doubleColumns; j += 2) {
+ // Normal for the left triangle
+ normals.append(normal(vertices.at(row + j),
+ vertices.at(row + j + 1),
+ vertices.at(upperRow + j)));
+
+ // Normal for the right triangle
+ normals.append(normal(vertices.at(row + j + 1),
+ vertices.at(upperRow + j + 1),
+ vertices.at(upperRow + j)));
+
+ if (changeGeometry) {
+ // Left triangle
+ indices[p++] = row + j + 1;
+ indices[p++] = upperRow + j;
+ indices[p++] = row + j;
+
+ // Right triangle
+ indices[p++] = upperRow + j + 1;
+ indices[p++] = upperRow + j;
+ indices[p++] = row + j + 1;
+ }
+ }
+ }
+
+ // Create grid line element indices
+ m_gridIndexCount = 2 * columns * (rows - 1) + 2 * rows * (columns - 1);
+ GLint *gridIndices = new GLint[m_gridIndexCount];
+ p = 0;
+ int rowLimit = (rows - 1) * doubleColumns;
+ for (int row = 0; row < rows * doubleColumns; row += doubleColumns) {
+ for (int j = 0; j < doubleColumns; j += 2) {
+ gridIndices[p++] = row + j;
+ gridIndices[p++] = row + j + 1;
+
+ if (row < rowLimit) {
+ gridIndices[p++] = row + j;
+ gridIndices[p++] = row + j + doubleColumns;
+ }
+ }
+ }
+ for (int i = doubleColumns - 1; i < rowLimit; i += doubleColumns) {
+ gridIndices[p++] = i;
+ gridIndices[p++] = i + doubleColumns;
+ }
+
+ createBuffers(vertices, uvs, normals, indices, gridIndices, changeGeometry);
+
+ delete[] indices;
+ delete[] gridIndices;
+}
+
+void SurfaceObject::createBuffers(const QVector<QVector3D> &vertices, const QVector<QVector2D> &uvs,
+ const QVector<QVector3D> &normals, const GLint *indices,
+ const GLint *gridIndices, bool changeGeometry)
+{
+ initializeOpenGLFunctions();
+ if (m_meshDataLoaded) {
+ // Delete old data
+ glDeleteBuffers(1, &m_vertexbuffer);
+ glDeleteBuffers(1, &m_normalbuffer);
+ if (changeGeometry) {
+ glDeleteBuffers(1, &m_uvbuffer);
+ glDeleteBuffers(1, &m_elementbuffer);
+ glDeleteBuffers(1, &m_gridElementbuffer);
+ }
+ }
+
+ // Move to buffers
+ glGenBuffers(1, &m_vertexbuffer);
+ glBindBuffer(GL_ARRAY_BUFFER, m_vertexbuffer);
+ glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(QVector3D),
+ &vertices.at(0), GL_STATIC_DRAW);
+
+ glGenBuffers(1, &m_normalbuffer);
+ glBindBuffer(GL_ARRAY_BUFFER, m_normalbuffer);
+ glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(QVector3D),
+ &normals.at(0), GL_STATIC_DRAW);
+
+ if (changeGeometry) {
+ glGenBuffers(1, &m_uvbuffer);
+ glBindBuffer(GL_ARRAY_BUFFER, m_uvbuffer);
+ glBufferData(GL_ARRAY_BUFFER, uvs.size() * sizeof(QVector2D),
+ &uvs.at(0), GL_STATIC_DRAW);
+
+ glGenBuffers(1, &m_elementbuffer);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementbuffer);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_indexCount * sizeof(GLint),
+ indices, GL_STATIC_DRAW);
+
+ glGenBuffers(1, &m_gridElementbuffer);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_gridElementbuffer);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_gridIndexCount * sizeof(GLint),
+ gridIndices, GL_STATIC_DRAW);
+ }
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ // We're done. Set the flag ON
+ m_meshDataLoaded = true;
+}
+
+GLuint SurfaceObject::gridElementBuf()
+{
+ if (!m_meshDataLoaded)
+ qFatal("No loaded object");
+ return m_gridElementbuffer;
+}
+
+GLuint SurfaceObject::gridIndexCount()
+{
+ return m_gridIndexCount;
+}
+
+QVector3D SurfaceObject::normal(const QVector3D &a, const QVector3D &b, const QVector3D &c)
+{
+ QVector3D v1 = b - a;
+ QVector3D v2 = c - a;
+ return QVector3D::crossProduct(v1, v2);
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+
+
+// For rainy days
+
+// QVector3D vertices[] = {
+// QVector3D(-0.5f, 0.0f, 0.1f),
+// QVector3D(0.5f, 0.0f, 0.1f),
+// QVector3D(0.0f, 1.0f, -0.5f)
+// };
+
+// QVector3D normals[] = {
+// QVector3D(0.5, 0.0, 1.0),
+// QVector3D(0.5, 0.0, 1.0),
+// QVector3D(0.5, 0.0, 1.0)
+// };
+
+// vertices.append(QVector3D(-1.0f, 0.0f, 0.1f));
+// vertices.append(QVector3D(0.0f, 0.0f, 0.1f));
+// vertices.append(QVector3D(0.0f, 0.5f, -0.5f));
+
+// normals.append(QVector3D(0.5, 0.0, 1.0));
+// normals.append(QVector3D(0.5, 0.0, 1.0));
+// normals.append(QVector3D(0.5, 0.0, 1.0));
+
+//GLushort indices[] = {0, 1, 2, 1, 3, 2};
+//GLushort indices[] = {1, 3, 2};
+
+//qDebug() << indices[p + 0] << ", " << indices[p + 1] << ", " << indices[p + 2];
+//qDebug() << indices[p + 3] << ", " << indices[p + 4] << ", " << indices[p + 5];
+
+//qDebug() << "(" << float(j) / width << ", 0.0, " << float(i) / depth * -1.0f << ")";
+
+//normals.append(QVector3D(1,0,0));
+//normals.append(QVector3D(0,1,0));
+//normals.append(QVector3D(0,0,1));
+//normals.append(QVector3D(1,0,1));
+
+//normals.append(QVector3D(1,0,0));
+//normals.append(QVector3D(0,1,0));
+//normals.append(QVector3D(0,0,1));
+//normals.append(QVector3D(1,0,1));
+
+//normals.append(QVector3D(1,0,0));
+//normals.append(QVector3D(0,1,0));
+//normals.append(QVector3D(0,0,1));
+//normals.append(QVector3D(1,0,1));
+
+
+//qDebug() << "Left normal from (" << row + j << ", " << row + j + 1 << ", " << row + doubleColumns + j << ")";
+
+//qDebug() << "right normal from (" << row + j +1 << ", " << row + doubleColumns + j + 1 << ", " << row + doubleColumns + j << ")";
+
diff --git a/src/datavisualization/utils/surfaceobject_p.h b/src/datavisualization/utils/surfaceobject_p.h
new file mode 100644
index 00000000..e9057f88
--- /dev/null
+++ b/src/datavisualization/utils/surfaceobject_p.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtDataVisualization API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef SURFACEOBJECT_P_H
+#define SURFACEOBJECT_P_H
+
+#include "datavisualizationglobal_p.h"
+#include "abstractobjecthelper_p.h"
+#include "qsurfacedataproxy.h"
+
+#include <QOpenGLFunctions>
+#include <QRect>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class SurfaceObject : public AbstractObjectHelper
+{
+public:
+ SurfaceObject();
+ ~SurfaceObject();
+
+ void setUpData(const QSurfaceDataArray &dataArray, QRect space, GLfloat yRange, bool changeGeometry);
+ void setUpSmoothData(const QSurfaceDataArray &dataArray, QRect space, GLfloat yRange, bool changeGeometry);
+ GLuint gridElementBuf();
+ GLuint gridIndexCount();
+
+private:
+ QVector3D normal(const QVector3D &a, const QVector3D &b, const QVector3D &c);
+ void createBuffers(const QVector<QVector3D> &vertices, const QVector<QVector2D> &uvs,
+ const QVector<QVector3D> &normals, const GLint *indices,
+ const GLint *gridIndices, bool changeGeometry);
+
+private:
+ int m_dataWidth;
+ int m_dataDepth;
+ GLfloat m_yRange;
+ GLuint m_gridElementbuffer;
+ GLuint m_gridIndexCount;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+#endif // SURFACEOBJECT_P_H
diff --git a/src/datavisualization/utils/texturehelper.cpp b/src/datavisualization/utils/texturehelper.cpp
new file mode 100644
index 00000000..4c7d71a5
--- /dev/null
+++ b/src/datavisualization/utils/texturehelper.cpp
@@ -0,0 +1,394 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#include "texturehelper_p.h"
+#include "utils_p.h"
+
+#include <QImage>
+
+#include <QDebug>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+TextureHelper::TextureHelper()
+{
+ initializeOpenGLFunctions();
+}
+
+TextureHelper::~TextureHelper()
+{
+}
+
+GLuint TextureHelper::create2DTexture(const QImage &image, bool useTrilinearFiltering, bool convert)
+{
+ if (image.isNull())
+ return 0;
+
+ QImage texImage;
+
+#if defined(Q_OS_ANDROID)
+ GLuint temp;
+ //qDebug() << "old size" << image.size();
+ GLuint imageWidth = Utils::getNearestPowerOfTwo(image.width(), temp);
+ //qDebug() << "new width" << imageWidth << "padding" << temp;
+ GLuint imageHeight = Utils::getNearestPowerOfTwo(image.height(), temp);
+ //qDebug() << "new height" << imageHeight << "padding" << temp;
+ texImage = image.scaled(imageWidth, imageHeight, Qt::IgnoreAspectRatio,
+ Qt::SmoothTransformation);
+ //qDebug() << "new size" << texImage.size();
+#else
+ texImage = image;
+#endif
+
+ GLuint textureId;
+ glGenTextures(1, &textureId);
+ glBindTexture(GL_TEXTURE_2D, textureId);
+ if (convert) {
+ QImage glTexture = convertToGLFormat(texImage);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glTexture.width(), glTexture.height(),
+ 0, GL_RGBA, GL_UNSIGNED_BYTE, glTexture.bits());
+ } else {
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texImage.width(), texImage.height(),
+ 0, GL_RGBA, GL_UNSIGNED_BYTE, texImage.bits());
+ }
+ if (useTrilinearFiltering) {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glGenerateMipmap(GL_TEXTURE_2D);
+ } else {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ }
+ glBindTexture(GL_TEXTURE_2D, 0);
+ return textureId;
+}
+
+GLuint TextureHelper::create2DTexture(const uchar *image, int width, int height)
+{
+ GLuint textureId;
+ glGenTextures(1, &textureId);
+ glBindTexture(GL_TEXTURE_2D, textureId);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height,
+ 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ return textureId;
+}
+
+GLuint TextureHelper::createCubeMapTexture(const QImage &image, bool useTrilinearFiltering)
+{
+ if (image.isNull())
+ return 0;
+
+ GLuint textureId;
+ glGenTextures(1, &textureId);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, textureId);
+ QImage glTexture = convertToGLFormat(image);
+ glTexImage2D(GL_TEXTURE_CUBE_MAP, 0, GL_RGBA, glTexture.width(), glTexture.height(),
+ 0, GL_RGBA, GL_UNSIGNED_BYTE, glTexture.bits());
+ if (useTrilinearFiltering) {
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
+ } else {
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ }
+ glBindTexture(GL_TEXTURE_2D, 0);
+ return textureId;
+}
+
+GLuint TextureHelper::createSelectionBuffer(const QSize &size, GLuint &texture,
+ GLuint &depthTexture)
+{
+ GLuint framebuffer;
+
+ // Create frame buffer
+ glGenFramebuffers(1, &framebuffer);
+ glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
+
+ // Create texture for the selection buffer
+ glGenTextures(1, &texture);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+//#if !defined(QT_OPENGL_ES_2)
+// glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0, GL_RGB,
+// GL_UNSIGNED_BYTE, NULL);
+//#else
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size.width(), size.height(), 0, GL_RGB,
+ GL_UNSIGNED_BYTE, NULL);
+//#endif
+
+ // Create texture object for the depth buffer
+ glGenTextures(1, &depthTexture);
+ glBindTexture(GL_TEXTURE_2D, depthTexture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, size.width(), size.height(),
+ 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ // Attach texture to color attachment
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
+ // Attach texture to depth attachment
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTexture, 0);
+
+ // Verify that the frame buffer is complete
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ qCritical() << "Frame buffer creation failed" << status;
+ return 0;
+ }
+
+ // Restore the default framebuffer
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ return framebuffer;
+}
+
+GLuint TextureHelper::createSelectionTexture(const QSize &size, GLuint &frameBuffer,
+ GLuint &depthBuffer)
+{
+ GLuint textureid;
+
+ // Create texture for the selection buffer
+ glGenTextures(1, &textureid);
+ glBindTexture(GL_TEXTURE_2D, textureid);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+#if !defined(QT_OPENGL_ES_2)
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, NULL);
+#else
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size.width(), size.height(), 0, GL_RGB,
+ GL_UNSIGNED_BYTE, NULL);
+#endif
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ // Create render buffer
+ if (!depthBuffer)
+ glGenRenderbuffers(1, &depthBuffer);
+ glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
+#if !defined(QT_OPENGL_ES_2)
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, size.width(), size.height());
+#else
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, size.width(), size.height());
+#endif
+ glBindRenderbuffer(GL_RENDERBUFFER, 0);
+
+ // Create frame buffer
+ if (!frameBuffer)
+ glGenFramebuffers(1, &frameBuffer);
+ glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
+
+ // Attach texture to color attachment
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureid, 0);
+ // Attach renderbuffer to depth attachment
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer);
+
+ // Verify that the frame buffer is complete
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ qCritical() << "Frame buffer creation failed" << status;
+ return 0;
+ }
+
+ // Restore the default framebuffer
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ return textureid;
+}
+
+#if !defined(QT_OPENGL_ES_2)
+GLuint TextureHelper::createDepthTexture(const QSize &size, GLuint &frameBuffer, GLuint textureSize)
+{
+ GLuint depthtextureid;
+
+ // Create depth texture for the shadow mapping
+ glGenTextures(1, &depthtextureid);
+ glBindTexture(GL_TEXTURE_2D, depthtextureid);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, size.width() * textureSize,
+ size.height() * textureSize, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ // Create frame buffer
+ if (!frameBuffer)
+ glGenFramebuffers(1, &frameBuffer);
+ glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
+
+ // Attach texture to depth attachment
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthtextureid, 0);
+
+ glDrawBuffer(GL_NONE);
+ glReadBuffer(GL_NONE);
+
+ // Verify that the frame buffer is complete
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ qCritical() << "Frame buffer creation failed" << status;
+ return 0;
+ }
+
+ // Restore the default framebuffer
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ return depthtextureid;
+}
+#endif
+
+void TextureHelper::deleteTexture(const GLuint *texture)
+{
+ glDeleteTextures(1, texture);
+}
+
+QImage TextureHelper::convertToGLFormat(const QImage &srcImage)
+{
+ QImage res(srcImage.size(), QImage::Format_ARGB32);
+ convertToGLFormatHelper(res, srcImage.convertToFormat(QImage::Format_ARGB32), GL_RGBA);
+ return res;
+}
+
+void TextureHelper::convertToGLFormatHelper(QImage &dstImage, const QImage &srcImage,
+ GLenum texture_format)
+{
+ Q_ASSERT(dstImage.depth() == 32);
+ Q_ASSERT(srcImage.depth() == 32);
+
+ if (dstImage.size() != srcImage.size()) {
+ int target_width = dstImage.width();
+ int target_height = dstImage.height();
+ qreal sx = target_width / qreal(srcImage.width());
+ qreal sy = target_height / qreal(srcImage.height());
+
+ quint32 *dest = (quint32 *) dstImage.scanLine(0); // NB! avoid detach here
+ uchar *srcPixels = (uchar *) srcImage.scanLine(srcImage.height() - 1);
+ int sbpl = srcImage.bytesPerLine();
+ int dbpl = dstImage.bytesPerLine();
+
+ int ix = int(0x00010000 / sx);
+ int iy = int(0x00010000 / sy);
+
+ quint32 basex = int(0.5 * ix);
+ quint32 srcy = int(0.5 * iy);
+
+ // scale, swizzle and mirror in one loop
+ while (target_height--) {
+ const uint *src = (const quint32 *) (srcPixels - (srcy >> 16) * sbpl);
+ int srcx = basex;
+ for (int x=0; x<target_width; ++x) {
+ dest[x] = qt_gl_convertToGLFormatHelper(src[srcx >> 16], texture_format);
+ srcx += ix;
+ }
+ dest = (quint32 *)(((uchar *) dest) + dbpl);
+ srcy += iy;
+ }
+ } else {
+ const int width = srcImage.width();
+ const int height = srcImage.height();
+ const uint *p = (const uint*) srcImage.scanLine(srcImage.height() - 1);
+ uint *q = (uint*) dstImage.scanLine(0);
+
+#if !defined(QT_OPENGL_ES_2)
+ if (texture_format == GL_BGRA) {
+#else
+ if (texture_format == GL_BGRA8_EXT) {
+#endif
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
+ // mirror + swizzle
+ for (int i=0; i < height; ++i) {
+ const uint *end = p + width;
+ while (p < end) {
+ *q = ((*p << 24) & 0xff000000)
+ | ((*p >> 24) & 0x000000ff)
+ | ((*p << 8) & 0x00ff0000)
+ | ((*p >> 8) & 0x0000ff00);
+ p++;
+ q++;
+ }
+ p -= 2 * width;
+ }
+ } else {
+ const uint bytesPerLine = srcImage.bytesPerLine();
+ for (int i=0; i < height; ++i) {
+ memcpy(q, p, bytesPerLine);
+ q += width;
+ p -= width;
+ }
+ }
+ } else {
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
+ for (int i=0; i < height; ++i) {
+ const uint *end = p + width;
+ while (p < end) {
+ *q = (*p << 8) | ((*p >> 24) & 0xff);
+ p++;
+ q++;
+ }
+ p -= 2 * width;
+ }
+ } else {
+ for (int i=0; i < height; ++i) {
+ const uint *end = p + width;
+ while (p < end) {
+ *q = ((*p << 16) & 0xff0000) | ((*p >> 16) & 0xff) | (*p & 0xff00ff00);
+ p++;
+ q++;
+ }
+ p -= 2 * width;
+ }
+ }
+ }
+ }
+}
+
+QRgb TextureHelper::qt_gl_convertToGLFormatHelper(QRgb src_pixel, GLenum texture_format)
+{
+#if !defined(QT_OPENGL_ES_2)
+ if (texture_format == GL_BGRA) {
+#else
+ if (texture_format == GL_BGRA8_EXT) {
+#endif
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
+ return ((src_pixel << 24) & 0xff000000)
+ | ((src_pixel >> 24) & 0x000000ff)
+ | ((src_pixel << 8) & 0x00ff0000)
+ | ((src_pixel >> 8) & 0x0000ff00);
+ } else {
+ return src_pixel;
+ }
+ } else { // GL_RGBA
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
+ return (src_pixel << 8) | ((src_pixel >> 24) & 0xff);
+ } else {
+ return ((src_pixel << 16) & 0xff0000)
+ | ((src_pixel >> 16) & 0xff)
+ | (src_pixel & 0xff00ff00);
+ }
+ }
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/utils/texturehelper_p.h b/src/datavisualization/utils/texturehelper_p.h
new file mode 100644
index 00000000..e5f54d00
--- /dev/null
+++ b/src/datavisualization/utils/texturehelper_p.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtDataVisualization API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef TEXTUREHELPER_P_H
+#define TEXTUREHELPER_P_H
+
+#include "datavisualizationglobal_p.h"
+#include <QOpenGLFunctions>
+#include <QRgb>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class TextureHelper : protected QOpenGLFunctions
+{
+ public:
+ TextureHelper();
+ ~TextureHelper();
+
+ // Ownership of created texture is transferred to caller
+ GLuint create2DTexture(const QImage &image, bool useTrilinearFiltering = false,
+ bool convert = true);
+ GLuint create2DTexture(const uchar *image, int width, int height);
+ GLuint createCubeMapTexture(const QImage &image, bool useTrilinearFiltering = false);
+ // Returns selection framebuffer and inserts generated texture id to texture parameters
+ GLuint createSelectionBuffer(const QSize &size, GLuint &texture, GLuint &depthTexture);
+ // Returns selection texture and inserts generated framebuffers to framebuffer parameters
+ GLuint createSelectionTexture(const QSize &size, GLuint &frameBuffer, GLuint &depthBuffer);
+#if !defined(QT_OPENGL_ES_2)
+ // Returns depth texture and inserts generated framebuffer to parameter
+ GLuint createDepthTexture(const QSize &size, GLuint &frameBuffer, GLuint textureSize = 1);
+#endif
+ void deleteTexture(const GLuint *texture);
+
+ private:
+ QImage convertToGLFormat(const QImage &srcImage);
+ void convertToGLFormatHelper(QImage &dstImage, const QImage &srcImage, GLenum texture_format);
+ QRgb qt_gl_convertToGLFormatHelper(QRgb src_pixel, GLenum texture_format);
+
+ friend class Bars3DRenderer;
+ friend class Surface3DRenderer;
+ friend class Scatter3DRenderer;
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/utils/utils.cpp b/src/datavisualization/utils/utils.cpp
new file mode 100644
index 00000000..8771c88a
--- /dev/null
+++ b/src/datavisualization/utils/utils.cpp
@@ -0,0 +1,303 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#include "utils_p.h"
+
+#include <QVector3D>
+#include <QColor>
+#include <QPainter>
+#include <QPoint>
+#include <QImage>
+#include <QRegExp>
+#include <qmath.h>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+#define NUM_IN_POWER(y, x) for (;y<x;y<<=1)
+#define MIN_POWER 32
+
+GLuint Utils::getNearestPowerOfTwo(GLuint value, GLuint &padding)
+{
+ GLuint powOfTwoValue = MIN_POWER;
+ NUM_IN_POWER(powOfTwoValue, value);
+ padding = powOfTwoValue - value;
+ return powOfTwoValue;
+}
+
+QVector3D Utils::vectorFromColor(const QColor &color)
+{
+ return QVector3D(color.redF(), color.greenF(), color.blueF());
+}
+
+void Utils::printText(QPainter *painter, const QString &text, const QSize &position,
+ bool absoluteCoords, qreal rotation, qreal scale)
+{
+ painter->save();
+ painter->setCompositionMode(QPainter::CompositionMode_Source);
+ painter->setPen(Qt::black); // TODO: Use black, as nothing works
+ QFont bgrFont = QFont(QStringLiteral("Arial"), 17);
+ QFont valueFont = QFont(QStringLiteral("Arial"), 11);
+ valueFont.setBold(true);
+ painter->setFont(bgrFont);
+ QFontMetrics valueFM(valueFont);
+ QFontMetrics bgrFM(bgrFont);
+ int valueStrLen = valueFM.width(text);
+ int bgrStrLen = 0;
+ int bgrHeight = valueFM.height() + 8;
+ QString bgrStr = QString();
+ do {
+ bgrStr.append(QStringLiteral("I"));
+ bgrStrLen = bgrFM.width(bgrStr);
+ } while (bgrStrLen <= (valueStrLen + 8));
+#if 0
+ // Hack solution, as drawRect doesn't work
+ painter->drawText(position.width() - (bgrStrLen / 2),
+ position.height() - bgrHeight,
+ bgrStrLen, bgrHeight,
+ Qt::AlignCenter | Qt::AlignVCenter,
+ bgrStr);
+ //painter->setPen(d_ptr->m_textColor);
+ painter->setPen(Qt::lightGray); // TODO: Use lightGray, as nothing works
+ painter->setFont(valueFont);
+ painter->drawText(position.width() - (valueStrLen / 2),
+ position.height() - bgrHeight,
+ valueStrLen, bgrHeight,
+ Qt::AlignCenter | Qt::AlignVCenter,
+ text);
+#else
+ //qDebug() << painter->window() << painter->viewport();
+ painter->scale(scale, scale);
+ if (absoluteCoords) {
+ // This assumes absolute screen coordinates
+ painter->translate(position.width() - (((float)bgrStrLen / 2.0f)
+ * qCos(qDegreesToRadians(rotation)))
+ + (((float)bgrHeight / 2.0f) * qSin(qDegreesToRadians(rotation))),
+ position.height()
+ - ((((float)bgrHeight / 2.0f) * qCos(qDegreesToRadians(rotation)))
+ + (((float)bgrStrLen / 2.0f) * qSin(qDegreesToRadians(rotation)))));
+ } else {
+ // This calculates y as a distance from screen bottom
+ painter->translate(position.width() - (((float)bgrStrLen / 2.0f)
+ * qCos(qDegreesToRadians(rotation)))
+ + (((float)bgrHeight / 2.0f) * qSin(qDegreesToRadians(rotation))),
+ painter->window().height() - position.height()
+ - ((((float)bgrHeight / 2.0f) * qCos(qDegreesToRadians(rotation)))
+ + (((float)bgrStrLen / 2.0f) * qSin(qDegreesToRadians(rotation)))));
+ }
+ //qDebug() << painter->window().height() - position.height()
+ // - ((((float)bgrHeight / 2.0f) * qCos(qDegreesToRadians(rotation)))
+ // + (((float)bgrStrLen / 2.0f) * qSin(qDegreesToRadians(rotation))));
+ painter->rotate(rotation);
+ painter->drawText(0, 0,
+ bgrStrLen, bgrHeight,
+ Qt::AlignCenter | Qt::AlignVCenter,
+ bgrStr);
+ painter->setPen(Qt::lightGray); // TODO: Use lightGray, as nothing works
+ painter->setFont(valueFont);
+ painter->drawText(6, 0,
+ valueStrLen, bgrHeight,
+ Qt::AlignCenter | Qt::AlignVCenter,
+ text);
+ painter->resetTransform();
+#endif
+ painter->restore();
+}
+
+QImage Utils::printTextToImage(const QFont &font, const QString &text, const QColor &bgrColor,
+ const QColor &txtColor, QDataVis::LabelTransparency transparency,
+ int maxLabelWidth)
+{
+ GLuint paddingWidth = 15;
+ GLuint paddingHeight = 15;
+ // Calculate text dimensions
+ QFont valueFont = font;
+ valueFont.setPointSize(50);
+ QFontMetrics valueFM(valueFont);
+ int valueStrWidth = valueFM.width(text);
+ if (maxLabelWidth && QDataVis::TransparencyNoBackground != transparency)
+ valueStrWidth = maxLabelWidth;
+ int valueStrHeight = valueFM.height();
+ QSize labelSize;
+
+#if defined(Q_OS_ANDROID)
+ // Android can't handle textures with dimensions not in power of 2. Resize labels accordingly.
+ // Add some padding before converting to power of two to avoid too tight fit
+ GLuint prePadding = 5;
+ // Android needs to use this always because of the power of 2 -issue.
+ valueStrWidth = maxLabelWidth;
+ labelSize = QSize(valueStrWidth + prePadding, valueStrHeight + prePadding);
+ //qDebug() << "label size before padding" << labelSize;
+ labelSize.setWidth(getNearestPowerOfTwo(labelSize.width(), paddingWidth));
+ labelSize.setHeight(getNearestPowerOfTwo(labelSize.height(), paddingHeight));
+ //qDebug() << "label size after padding" << labelSize << paddingWidth << paddingHeight;
+#else
+ if (QDataVis::TransparencyNoBackground == transparency)
+ labelSize = QSize(valueStrWidth, valueStrHeight);
+ else
+ labelSize = QSize(valueStrWidth + paddingWidth * 2, valueStrHeight + paddingHeight * 2);
+#endif
+
+ // Create image
+ QImage image = QImage(labelSize, QImage::Format_ARGB32);
+ image.fill(Qt::transparent);
+
+ // Init painter
+ QPainter painter(&image);
+ // Paint text
+ painter.setRenderHint(QPainter::Antialiasing, true);
+ painter.setCompositionMode(QPainter::CompositionMode_Source);
+ switch (transparency) {
+ case QDataVis::TransparencyNoBackground: {
+ painter.setFont(valueFont);
+ painter.setPen(txtColor);
+#if defined(Q_OS_ANDROID)
+ painter.drawText((labelSize.width() - valueStrWidth) / 2.0f,
+ (labelSize.height() - valueStrHeight) / 2.0f,
+ valueStrWidth, valueStrHeight,
+ Qt::AlignCenter | Qt::AlignVCenter,
+ text);
+#else
+ painter.drawText(0, 0,
+ valueStrWidth, valueStrHeight,
+ Qt::AlignCenter | Qt::AlignVCenter,
+ text);
+#endif
+ break;
+ }
+ case QDataVis::TransparencyFromTheme: {
+ painter.setBrush(QBrush(bgrColor));
+ painter.setPen(bgrColor);
+ painter.drawRoundedRect(0, 0, labelSize.width(), labelSize.height(), 10.0, 10.0f);
+ painter.setFont(valueFont);
+ painter.setPen(txtColor);
+ painter.drawText((labelSize.width() - valueStrWidth) / 2.0f,
+ (labelSize.height() - valueStrHeight) / 2.0f,
+ valueStrWidth, valueStrHeight,
+ Qt::AlignCenter | Qt::AlignVCenter,
+ text);
+ break;
+ }
+ case QDataVis::TransparencyNone: {
+ painter.setBrush(QBrush(bgrColor));
+ painter.setPen(bgrColor);
+ painter.drawRect(0, 0, labelSize.width(), labelSize.height());
+ painter.setFont(valueFont);
+ painter.setPen(txtColor);
+ painter.drawText((labelSize.width() - valueStrWidth) / 2.0f,
+ (labelSize.height() - valueStrHeight) / 2.0f,
+ valueStrWidth, valueStrHeight,
+ Qt::AlignCenter | Qt::AlignVCenter,
+ text);
+ break;
+ }
+ }
+ return image;
+}
+
+QVector3D Utils::getSelection(QPoint mousepos, int height)
+{
+ QVector3D selectedColor;
+
+ //#if defined(QT_OPENGL_ES_2)
+ // This is the only one that works with ANGLE (ES 2.0)
+ // Item count will be limited to 256*256*256
+ GLubyte pixel[4];
+ glReadPixels(mousepos.x(), height - mousepos.y(), 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
+ (void *)pixel);
+
+ //qDebug() << "rgba" << pixel[0] << pixel[1] << pixel[2] << pixel[3] << "mousepos:" << mousepos << "height:" << height;
+
+ //#else
+ // These work with desktop OpenGL
+ // They offer a lot higher possible object count and a possibility to use object ids
+ //GLuint pixel[3];
+ //glReadPixels(mousepos.x(), height - mousepos.y(), 1, 1,
+ // GL_RGB, GL_UNSIGNED_INT, (void *)pixel);
+ //qDebug() << "rgba" << pixel[0] << pixel[1] << pixel[2];// << pixel[3];
+
+ //GLfloat pixel3[3];
+ //glReadPixels(mousepos.x(), height - mousepos.y(), 1, 1,
+ // GL_RGB, GL_FLOAT, (void *)pixel3);
+ //qDebug() << "rgba" << pixel3[0] << pixel3[1] << pixel3[2];// << pixel[3];
+ //#endif
+ selectedColor = QVector3D(pixel[0], pixel[1], pixel[2]);
+ //qDebug() << selectedColor;
+
+ return selectedColor;
+}
+
+Utils::ParamType Utils::mapFormatCharToParamType(const QChar &formatChar)
+{
+ ParamType retVal = ParamTypeUnknown;
+ if (formatChar == QLatin1Char('d')
+ || formatChar == QLatin1Char('i')
+ || formatChar == QLatin1Char('c')) {
+ retVal = ParamTypeInt;
+ } else if (formatChar == QLatin1Char('u')
+ || formatChar == QLatin1Char('o')
+ || formatChar == QLatin1Char('x')
+ || formatChar == QLatin1Char('X')) {
+ retVal = ParamTypeUInt;
+ } else if (formatChar == QLatin1Char('f')
+ || formatChar == QLatin1Char('F')
+ || formatChar == QLatin1Char('e')
+ || formatChar == QLatin1Char('E')
+ || formatChar == QLatin1Char('g')
+ || formatChar == QLatin1Char('G')) {
+ retVal = ParamTypeReal;
+ }
+
+ return retVal;
+}
+
+Utils::ParamType Utils::findFormatParamType(const QString &format)
+{
+ static QRegExp formatMatcher(QStringLiteral("%[\\-\\+#\\s\\d\\.lhjztL]*([dicuoxfegXFEG])"));
+
+ if (formatMatcher.indexIn(format, 0) != -1) {
+ QString capStr = formatMatcher.cap(1);
+ if (capStr.isEmpty())
+ return ParamTypeUnknown;
+ else
+ return mapFormatCharToParamType(capStr.at(0));
+ }
+
+ return ParamTypeUnknown;
+}
+
+QString Utils::formatLabel(const QByteArray &format, ParamType paramType, qreal value)
+{
+ switch (paramType) {
+ case ParamTypeInt:
+ return QString().sprintf(format, (qint64)value);
+ case ParamTypeUInt:
+ return QString().sprintf(format, (quint64)value);
+ case ParamTypeReal:
+ return QString().sprintf(format, value);
+ default:
+ return QString::fromUtf8(format); // To detect errors
+ }
+}
+
+QString Utils::defaultLabelFormat()
+{
+ static const QString defaultFormat(QStringLiteral("%.2f"));
+ return defaultFormat;
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/utils/utils.pri b/src/datavisualization/utils/utils.pri
new file mode 100644
index 00000000..cef5ebf0
--- /dev/null
+++ b/src/datavisualization/utils/utils.pri
@@ -0,0 +1,19 @@
+HEADERS += $$PWD/meshloader_p.h \
+ $$PWD/vertexindexer_p.h \
+ $$PWD/camerahelper_p.h \
+ $$PWD/shaderhelper_p.h \
+ $$PWD/objecthelper_p.h \
+ $$PWD/texturehelper_p.h \
+ $$PWD/utils_p.h \
+ $$PWD/abstractobjecthelper_p.h \
+ $$PWD/surfaceobject_p.h
+
+SOURCES += $$PWD/meshloader.cpp \
+ $$PWD/vertexindexer.cpp \
+ $$PWD/camerahelper.cpp \
+ $$PWD/shaderhelper.cpp \
+ $$PWD/objecthelper.cpp \
+ $$PWD/texturehelper.cpp \
+ $$PWD/utils.cpp \
+ $$PWD/abstractobjecthelper.cpp \
+ $$PWD/surfaceobject.cpp
diff --git a/src/datavisualization/utils/utils_p.h b/src/datavisualization/utils/utils_p.h
new file mode 100644
index 00000000..4cbd8f35
--- /dev/null
+++ b/src/datavisualization/utils/utils_p.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtDataVisualization API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef UTILS_P_H
+#define UTILS_P_H
+
+#include "datavisualizationglobal_p.h"
+#include "q3dbars.h"
+
+class QVector3D;
+class QColor;
+class QPainter;
+class QString;
+class QPoint;
+class QImage;
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class Utils
+{
+public:
+ enum ParamType {
+ ParamTypeUnknown = 0,
+ ParamTypeInt,
+ ParamTypeUInt,
+ ParamTypeReal
+ };
+
+ static GLuint getNearestPowerOfTwo(GLuint value, GLuint &padding);
+ static QVector3D vectorFromColor(const QColor &color);
+ static void printText(QPainter *painter, const QString &text, const QSize &position,
+ bool absoluteCoords = true, qreal rotation = 0, qreal scale = 1.0f);
+ static QImage printTextToImage(const QFont &font,
+ const QString &text,
+ const QColor &bgrColor,
+ const QColor &txtColor,
+ QDataVis::LabelTransparency transparency,
+ int maxLabelWidth = 0);
+ static QVector3D getSelection(QPoint mousepos, int height);
+
+ static ParamType findFormatParamType(const QString &format);
+ static QString formatLabel(const QByteArray &format, ParamType paramType, qreal value);
+ static QString defaultLabelFormat();
+
+private:
+ static ParamType mapFormatCharToParamType(const QChar &formatChar);
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif
diff --git a/src/datavisualization/utils/vertexindexer.cpp b/src/datavisualization/utils/vertexindexer.cpp
new file mode 100644
index 00000000..63b9faaf
--- /dev/null
+++ b/src/datavisualization/utils/vertexindexer.cpp
@@ -0,0 +1,153 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#include "vertexindexer_p.h"
+
+#include <string.h> // for memcmp
+#include <qmath.h>
+
+#include <QDebug>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+int unique_vertices = 0;
+
+// Returns true if v1 can be considered equal to v2
+bool VertexIndexer::is_near(float v1, float v2)
+{
+ return qAbs(v1 - v2) < 0.01f;
+}
+
+// Searches through all already-exported vertices
+// for a similar one.
+// Similar = same position + same UVs + same normal
+bool VertexIndexer::getSimilarVertexIndex(const QVector3D &in_vertex,
+ const QVector2D &in_uv,
+ const QVector3D &in_normal,
+ QVector<QVector3D> &out_vertices,
+ QVector<QVector2D> &out_uvs,
+ QVector<QVector3D> &out_normals,
+ unsigned short &result)
+{
+ // Lame linear search
+ for (int i = 0; i < out_vertices.size(); i++) {
+ if (is_near(in_vertex.x() , out_vertices[i].x())
+ && is_near(in_vertex.y() , out_vertices[i].y())
+ && is_near(in_vertex.z() , out_vertices[i].z())
+ && is_near(in_uv.x() , out_uvs [i].x())
+ && is_near(in_uv.y() , out_uvs [i].y())
+ && is_near(in_normal.x() , out_normals [i].x())
+ && is_near(in_normal.y() , out_normals [i].y())
+ && is_near(in_normal.z() , out_normals [i].z())) {
+ result = i;
+ return true;
+ }
+ }
+ // No other vertex could be used instead.
+ // Looks like we'll have to add it to the VBO.
+ return false;
+}
+
+bool VertexIndexer::getSimilarVertexIndex_fast(const PackedVertex &packed,
+ QMap<PackedVertex, unsigned short> &VertexToOutIndex,
+ unsigned short &result)
+{
+ QMap<PackedVertex, unsigned short>::iterator it = VertexToOutIndex.find(packed);
+ if (it == VertexToOutIndex.end()) {
+ return false;
+ } else {
+ result = it.value();
+ return true;
+ }
+}
+
+void VertexIndexer::indexVBO(const QVector<QVector3D> &in_vertices,
+ const QVector<QVector2D> &in_uvs,
+ const QVector<QVector3D> &in_normals,
+ QVector<unsigned short> &out_indices,
+ QVector<QVector3D> &out_vertices,
+ QVector<QVector2D> &out_uvs,
+ QVector<QVector3D> &out_normals)
+{
+ unique_vertices = 0;
+ QMap<PackedVertex, unsigned short> VertexToOutIndex;
+
+ // For each input vertex
+ for (int i = 0; i < in_vertices.size(); i++) {
+ PackedVertex packed = {in_vertices[i], in_uvs[i], in_normals[i]};
+
+ // Try to find a similar vertex in out_XXXX
+ unsigned short index;
+ bool found = getSimilarVertexIndex_fast(packed, VertexToOutIndex, index);
+
+ if (found) {
+ out_indices.append(index);
+ } else {
+ unique_vertices++;
+ out_vertices.append(in_vertices[i]);
+ out_uvs.append(in_uvs[i]);
+ out_normals.append(in_normals[i]);
+ unsigned short newindex = (unsigned short)out_vertices.size() - 1;
+ out_indices.append(newindex);
+ VertexToOutIndex[packed] = newindex;
+ }
+ }
+ //qDebug() << "unique vertices" << unique_vertices;
+}
+
+void VertexIndexer::indexVBO_TBN(const QVector<QVector3D> &in_vertices,
+ const QVector<QVector2D> &in_uvs,
+ const QVector<QVector3D> &in_normals,
+ const QVector<QVector3D> &in_tangents,
+ const QVector<QVector3D> &in_bitangents,
+ QVector<unsigned short> &out_indices,
+ QVector<QVector3D> &out_vertices,
+ QVector<QVector2D> &out_uvs,
+ QVector<QVector3D> &out_normals,
+ QVector<QVector3D> &out_tangents,
+ QVector<QVector3D> &out_bitangents)
+{
+ unique_vertices = 0;
+ // For each input vertex
+ for (int i = 0; i < in_vertices.size(); i++) {
+
+ // Try to find a similar vertex in out_XXXX
+ unsigned short index;
+ bool found = getSimilarVertexIndex(in_vertices[i], in_uvs[i], in_normals[i],
+ out_vertices, out_uvs, out_normals, index);
+
+ if (found) {
+ out_indices.append(index);
+
+ // Average the tangents and the bitangents
+ out_tangents[index] += in_tangents[i];
+ out_bitangents[index] += in_bitangents[i];
+ } else {
+ unique_vertices++;
+ out_vertices.append(in_vertices[i]);
+ out_uvs.append(in_uvs[i]);
+ out_normals.append(in_normals[i]);
+ out_tangents.append(in_tangents[i]);
+ out_bitangents.append(in_bitangents[i]);
+ out_indices.append((unsigned short)out_vertices.size() - 1);
+ }
+ }
+ //qDebug() << "unique vertices" << unique_vertices;
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/utils/vertexindexer_p.h b/src/datavisualization/utils/vertexindexer_p.h
new file mode 100644
index 00000000..0cf1857b
--- /dev/null
+++ b/src/datavisualization/utils/vertexindexer_p.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtDataVisualization API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef VERTEXINDEXER_P_H
+#define VERTEXINDEXER_P_H
+
+#include "datavisualizationglobal_p.h"
+
+#include <QVector>
+#include <QVector2D>
+#include <QVector3D>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+class VertexIndexer
+{
+ public:
+ struct PackedVertex {
+ QVector3D position;
+ QVector2D uv;
+ QVector3D normal;
+ bool operator<(const PackedVertex that) const {
+ return memcmp((void*)this, (void*)&that, sizeof(PackedVertex)) > 0;
+ }
+ };
+
+ static void indexVBO(const QVector<QVector3D> &in_vertices,
+ const QVector<QVector2D> &in_uvs,
+ const QVector<QVector3D> &in_normals,
+ QVector<unsigned short> &out_indices,
+ QVector<QVector3D> &out_vertices,
+ QVector<QVector2D> &out_uvs,
+ QVector<QVector3D> &out_normals);
+
+ static void indexVBO_TBN(const QVector<QVector3D> &in_vertices,
+ const QVector<QVector2D> &in_uvs,
+ const QVector<QVector3D> &in_normals,
+ const QVector<QVector3D> &in_tangents,
+ const QVector<QVector3D> &in_bitangents,
+ QVector<unsigned short> &out_indices,
+ QVector<QVector3D> &out_vertices,
+ QVector<QVector2D> &out_uvs,
+ QVector<QVector3D> &out_normals,
+ QVector<QVector3D> &out_tangents,
+ QVector<QVector3D> &out_bitangents);
+
+ private:
+ static bool is_near(float v1, float v2);
+ static bool getSimilarVertexIndex(const QVector3D &in_vertex,
+ const QVector2D &in_uv,
+ const QVector3D &in_normal,
+ QVector<QVector3D> &out_vertices,
+ QVector<QVector2D> &out_uvs,
+ QVector<QVector3D> &out_normals,
+ unsigned short &result);
+ static bool getSimilarVertexIndex_fast(const PackedVertex &packed,
+ QMap<PackedVertex, unsigned short> &VertexToOutIndex,
+ unsigned short &result);
+};
+
+QT_DATAVISUALIZATION_END_NAMESPACE
+
+#endif