summaryrefslogtreecommitdiffstats
path: root/src/datavis3d/utils
diff options
context:
space:
mode:
Diffstat (limited to 'src/datavis3d/utils')
-rw-r--r--src/datavis3d/utils/camerahelper.cpp103
-rw-r--r--src/datavis3d/utils/camerahelper_p.h31
-rw-r--r--src/datavis3d/utils/meshloader.cpp107
-rw-r--r--src/datavis3d/utils/meshloader_p.h23
-rw-r--r--src/datavis3d/utils/utils.pri7
-rw-r--r--src/datavis3d/utils/vertexindexer.cpp137
-rw-r--r--src/datavis3d/utils/vertexindexer_p.h60
7 files changed, 468 insertions, 0 deletions
diff --git a/src/datavis3d/utils/camerahelper.cpp b/src/datavis3d/utils/camerahelper.cpp
new file mode 100644
index 00000000..be71d127
--- /dev/null
+++ b/src/datavis3d/utils/camerahelper.cpp
@@ -0,0 +1,103 @@
+#include "camerahelper_p.h"
+
+#include <QMatrix4x4>
+#include <QVector3D>
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+// Initial camera position
+QVector3D m_position = QVector3D(0, 0.25, 3);
+QVector3D m_target = QVector3D(0, 0, 0);
+QVector3D m_up = QVector3D(0, 1, 0);
+
+QPoint m_previousMousePos(0, 0);
+
+float m_xRotation = 0;
+float m_yRotation = 0;
+float m_defaultXRotation = 0;
+float m_defaultYRotation = 0;
+
+float m_pi = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679f;
+float m_rotationSpeed = 100;
+
+// FUNCTIONS
+void CameraHelper::setRotationSpeed(int speed)
+{
+ // increase for faster rotation
+ m_rotationSpeed = speed;
+}
+
+void CameraHelper::setCameraRotation(QPointF rotation)
+{
+ m_xRotation = rotation.x();
+ m_defaultXRotation = m_xRotation;
+ m_yRotation = rotation.y();
+ m_defaultYRotation = m_yRotation;
+}
+
+void CameraHelper::setDefaultCameraOrientation(QVector3D defaultPosition
+ , QVector3D defaultTarget
+ , QVector3D defaultUp)
+{
+ m_position = defaultPosition;
+ m_target = defaultTarget;
+ m_up = defaultUp;
+}
+
+QMatrix4x4 CameraHelper::calculateViewMatrix(QPoint mousePos, int zoom, int screenWidth, int screenHeight)
+{
+ QMatrix4x4 viewMatrix;
+
+ // Calculate mouse movement since last frame
+ float mouseMoveX = float(m_previousMousePos.x() - mousePos.x())
+ / (screenWidth / m_rotationSpeed);
+ float mouseMoveY = float(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 (fabs(m_xRotation) >= 360)
+ m_xRotation = 0;
+ if (m_yRotation >= 90) {
+ m_yRotation = 90;
+ }
+ else if (m_yRotation <= 0) {
+ m_yRotation = 0;
+ }
+
+ // Apply to view matrix
+ viewMatrix.lookAt(
+ m_position // Camera is here
+ , m_target // and looks here
+ , m_up // Head is up (set to 0,-1,0 to look upside-down)
+ );
+ // Apply rotations
+ // Handle x and z rotation when y -angle is other than 0
+ viewMatrix.rotate(m_xRotation, 0, cos(m_yRotation*m_pi/180), sin(m_yRotation*m_pi/180));
+ // y rotation is always "clean"
+ viewMatrix.rotate(m_yRotation, 1.0f, 0, 0);
+ // handle zoom by scaling
+ viewMatrix.scale((float)zoom / 100.0f);
+ //qDebug() << m_xRotation << m_yRotation;
+
+ //qDebug() << "sin(m_yRotation)" << sin(m_yRotation*m_pi/180);
+ //qDebug() << "asin(m_yRotation)" << asin(m_yRotation*m_pi/180);
+ //qDebug() << "cos(m_yRotation)" << cos(m_yRotation*m_pi/180);
+ //qDebug() << "tan(m_yRotation)" << tan(m_yRotation*m_pi/180);
+
+ m_previousMousePos = mousePos;
+ return viewMatrix;
+}
+
+void CameraHelper::updateMousePos(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;
+ }
+}
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
diff --git a/src/datavis3d/utils/camerahelper_p.h b/src/datavis3d/utils/camerahelper_p.h
new file mode 100644
index 00000000..340eb982
--- /dev/null
+++ b/src/datavis3d/utils/camerahelper_p.h
@@ -0,0 +1,31 @@
+#ifndef CAMERAPOSITIONER_P_H
+#define CAMERAPOSITIONER_P_H
+
+#include "qdatavis3dglobal.h"
+
+class QMatrix4x4;
+class QVector3D;
+class QPoint;
+class QPointF;
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+class CameraHelper
+{
+public:
+ // How fast camera rotates when mouse is dragged. Default is 100.
+ static void setRotationSpeed(int speed);
+ // Set camera rotation in degrees
+ static void setCameraRotation(QPointF rotation);
+ // Set default camera orientation. Position's x and y should be 0.
+ static void setDefaultCameraOrientation(QVector3D defaultPosition
+ , QVector3D defaultTarget
+ , QVector3D defaultUp);
+ static QMatrix4x4 calculateViewMatrix(QPoint mousePos, int zoom
+ , int screenWidth, int screenHeight);
+ static void updateMousePos(QPoint mousePos);
+};
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
+
+#endif
diff --git a/src/datavis3d/utils/meshloader.cpp b/src/datavis3d/utils/meshloader.cpp
new file mode 100644
index 00000000..b94c5a46
--- /dev/null
+++ b/src/datavis3d/utils/meshloader.cpp
@@ -0,0 +1,107 @@
+#include "meshloader_p.h"
+
+#include <QFile>
+#include <QStringList>
+#include <QVector>
+#include <QVector2D>
+#include <QVector3D>
+
+#include <QDebug>
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+QString slashTag = QStringLiteral("/");
+
+bool MeshLoader::loadOBJ(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;
+}
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
diff --git a/src/datavis3d/utils/meshloader_p.h b/src/datavis3d/utils/meshloader_p.h
new file mode 100644
index 00000000..4507ceb7
--- /dev/null
+++ b/src/datavis3d/utils/meshloader_p.h
@@ -0,0 +1,23 @@
+#ifndef MESHLOADER_P_H
+#define MESHLOADER_P_H
+
+#include "qdatavis3dglobal.h"
+
+class QVector2D;
+class QVector3D;
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+class MeshLoader
+{
+public:
+ static bool loadOBJ(QString path,
+ QVector<QVector3D> &out_vertices,
+ QVector<QVector2D> &out_uvs,
+ QVector<QVector3D> &out_normals);
+ // TODO: add loaders for other formats?
+};
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
+
+#endif
diff --git a/src/datavis3d/utils/utils.pri b/src/datavis3d/utils/utils.pri
new file mode 100644
index 00000000..c62340d1
--- /dev/null
+++ b/src/datavis3d/utils/utils.pri
@@ -0,0 +1,7 @@
+HEADERS += $$PWD/meshloader_p.h \
+ $$PWD/vertexindexer_p.h \
+ $$PWD/camerahelper_p.h
+
+SOURCES += $$PWD/meshloader.cpp \
+ $$PWD/vertexindexer.cpp \
+ $$PWD/camerahelper.cpp
diff --git a/src/datavis3d/utils/vertexindexer.cpp b/src/datavis3d/utils/vertexindexer.cpp
new file mode 100644
index 00000000..c54cbf8a
--- /dev/null
+++ b/src/datavis3d/utils/vertexindexer.cpp
@@ -0,0 +1,137 @@
+#include "vertexindexer_p.h"
+
+#include <string.h> // for memcmp
+
+#include <QDebug>
+
+QTCOMMERCIALDATAVIS3D_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 fabs(v1 - v2) < 0.01f;
+}
+
+// Searches through all already-exported vertices
+// for a similar one.
+// Similar = same position + same UVs + same normal
+bool VertexIndexer::getSimilarVertexIndex(QVector3D &in_vertex
+ , QVector2D &in_uv
+ , 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(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(QVector<QVector3D> &in_vertices
+ , QVector<QVector2D> &in_uvs
+ , 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) { // A similar vertex is already in the VBO, use it instead !
+ out_indices.append(index);
+ }
+ else { // If not, it needs to be added in the output data.
+ 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(QVector<QVector3D> &in_vertices
+ , QVector<QVector2D> &in_uvs
+ , QVector<QVector3D> &in_normals
+ , QVector<QVector3D> &in_tangents
+ , 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) { // A similar vertex is already in the VBO, use it instead !
+ out_indices.append(index);
+
+ // Average the tangents and the bitangents
+ out_tangents[index] += in_tangents[i];
+ out_bitangents[index] += in_bitangents[i];
+ }
+ else { // If not, it needs to be added in the output data.
+ 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;
+}
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
diff --git a/src/datavis3d/utils/vertexindexer_p.h b/src/datavis3d/utils/vertexindexer_p.h
new file mode 100644
index 00000000..f784756e
--- /dev/null
+++ b/src/datavis3d/utils/vertexindexer_p.h
@@ -0,0 +1,60 @@
+#ifndef VERTEXINDEXER_P_H
+#define VERTEXINDEXER_P_H
+
+#include "qdatavis3dglobal.h"
+
+#include <QVector>
+#include <QVector2D>
+#include <QVector3D>
+
+QTCOMMERCIALDATAVIS3D_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(QVector<QVector3D> &in_vertices
+ , QVector<QVector2D> &in_uvs
+ , 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(QVector<QVector3D> &in_vertices
+ , QVector<QVector2D> &in_uvs
+ , QVector<QVector3D> &in_normals
+ , QVector<QVector3D> &in_tangents
+ , 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(QVector3D &in_vertex
+ , QVector2D &in_uv
+ , QVector3D &in_normal
+ , QVector<QVector3D> &out_vertices
+ , QVector<QVector2D> &out_uvs
+ , QVector<QVector3D> &out_normals
+ , unsigned short &result);
+ static bool getSimilarVertexIndex_fast(PackedVertex &packed
+ , QMap<PackedVertex, unsigned short> &VertexToOutIndex
+ , unsigned short &result);
+};
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
+
+#endif