/**************************************************************************** ** ** 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 #include #include 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 vertices; QVector 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 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 vertices; QVector 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 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 &vertices, const QVector &uvs, const QVector &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 << ")";