diff options
author | Tomi Korpipää <tomi.korpipaa@digia.com> | 2013-09-10 11:42:13 +0300 |
---|---|---|
committer | Tomi Korpipää <tomi.korpipaa@digia.com> | 2013-09-10 12:04:24 +0300 |
commit | a28cdb72a4ea768a898ca07f0df0fa3c17c073a8 (patch) | |
tree | 0bafdcfa99fc783e9f5204539a8242bf6128d795 /src/datavisualization/utils | |
parent | f3e38983d77c72f3121c33a149a58fdf9c64158c (diff) |
Module renamed
Task-number: QTRD-2224
Change-Id: Iec18b6121809300b11d85445281d3c626c434f35
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@digia.com>
Diffstat (limited to 'src/datavisualization/utils')
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 |