/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Data Visualization module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 or (at your option) any later version ** approved by the KDE Free Qt Foundation. The licenses are as published by ** the Free Software Foundation and appearing in the file LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "surfaceobject_p.h" #include "surface3drenderer_p.h" #include QT_BEGIN_NAMESPACE_DATAVISUALIZATION SurfaceObject::SurfaceObject(Surface3DRenderer *renderer) : m_surfaceType(Undefined), m_columns(0), m_rows(0), m_gridIndexCount(0), m_axisCacheX(renderer->m_axisCacheX), m_axisCacheY(renderer->m_axisCacheY), m_axisCacheZ(renderer->m_axisCacheZ), m_renderer(renderer), m_returnTextureBuffer(false), m_dataDimension(0), m_oldDataDimension(-1) { glGenBuffers(1, &m_vertexbuffer); glGenBuffers(1, &m_normalbuffer); glGenBuffers(1, &m_uvbuffer); glGenBuffers(1, &m_elementbuffer); glGenBuffers(1, &m_gridElementbuffer); glGenBuffers(1, &m_uvTextureBuffer); } SurfaceObject::~SurfaceObject() { if (QOpenGLContext::currentContext()) { glDeleteBuffers(1, &m_gridElementbuffer); glDeleteBuffers(1, &m_uvTextureBuffer); } } void SurfaceObject::setUpSmoothData(const QSurfaceDataArray &dataArray, const QRect &space, bool changeGeometry, bool polar, bool flipXZ) { m_columns = space.width(); m_rows = space.height(); int totalSize = m_rows * m_columns; GLfloat uvX = 1.0f / GLfloat(m_columns - 1); GLfloat uvY = 1.0f / GLfloat(m_rows - 1); m_surfaceType = SurfaceSmooth; checkDirections(dataArray); bool indicesDirty = false; if (m_dataDimension != m_oldDataDimension) indicesDirty = true; m_oldDataDimension = m_dataDimension; // Create/populate vertix table if (changeGeometry) m_vertices.resize(totalSize); QVector uvs; if (changeGeometry) uvs.resize(totalSize); int totalIndex = 0; // Init min and max to ridiculous values m_minY = 10000000.0; m_maxY = -10000000.0f; for (int i = 0; i < m_rows; i++) { const QSurfaceDataRow &p = *dataArray.at(i); for (int j = 0; j < m_columns; j++) { getNormalizedVertex(p.at(j), m_vertices[totalIndex], polar, flipXZ); if (changeGeometry) uvs[totalIndex] = QVector2D(GLfloat(j) * uvX, GLfloat(i) * uvY); totalIndex++; } } if (flipXZ) { for (int i = 0; i < m_vertices.size(); i++) { m_vertices[i].setX(-m_vertices.at(i).x()); m_vertices[i].setZ(-m_vertices.at(i).z()); } } // Create normals int rowLimit = m_rows - 1; int colLimit = m_columns - 1; if (changeGeometry) m_normals.resize(totalSize); totalIndex = 0; if ((m_dataDimension == BothAscending) || (m_dataDimension == XDescending)) { for (int row = 0; row < rowLimit; row++) createSmoothNormalBodyLine(totalIndex, row * m_columns); createSmoothNormalUpperLine(totalIndex); } else { // BothDescending || ZDescending createSmoothNormalUpperLine(totalIndex); for (int row = 1; row < m_rows; row++) createSmoothNormalBodyLine(totalIndex, row * m_columns); } // Create indices table if (changeGeometry || indicesDirty) createSmoothIndices(0, 0, colLimit, rowLimit); // Create line element indices if (changeGeometry) createSmoothGridlineIndices(0, 0, colLimit, rowLimit); createBuffers(m_vertices, uvs, m_normals, 0); } void SurfaceObject::createSmoothNormalBodyLine(int &totalIndex, int column) { int colLimit = m_columns - 1; if (m_dataDimension == BothAscending) { int end = colLimit + column; for (int j = column; j < end; j++) { m_normals[totalIndex++] = normal(m_vertices.at(j), m_vertices.at(j + 1), m_vertices.at(j + m_columns)); } m_normals[totalIndex++] = normal(m_vertices.at(end), m_vertices.at(end + m_columns), m_vertices.at(end - 1)); } else if (m_dataDimension == XDescending) { m_normals[totalIndex++] = normal(m_vertices.at(column), m_vertices.at(column + m_columns), m_vertices.at(column + 1)); int end = column + m_columns; for (int j = column + 1; j < end; j++) { m_normals[totalIndex++] = normal(m_vertices.at(j), m_vertices.at(j - 1), m_vertices.at(j + m_columns)); } } else if (m_dataDimension == ZDescending) { int end = colLimit + column; for (int j = column; j < end; j++) { m_normals[totalIndex++] = normal(m_vertices.at(j), m_vertices.at(j + 1), m_vertices.at(j - m_columns)); } m_normals[totalIndex++] = normal(m_vertices.at(end), m_vertices.at(end - m_columns), m_vertices.at(end - 1)); } else { // BothDescending m_normals[totalIndex++] = normal(m_vertices.at(column), m_vertices.at(column - m_columns), m_vertices.at(column + 1)); int end = column + m_columns; for (int j = column + 1; j < end; j++) { m_normals[totalIndex++] = normal(m_vertices.at(j), m_vertices.at(j - 1), m_vertices.at(j - m_columns)); } } } void SurfaceObject::createSmoothNormalUpperLine(int &totalIndex) { if (m_dataDimension == BothAscending) { int lineEnd = m_rows * m_columns - 1; for (int j = (m_rows - 1) * m_columns; j < lineEnd; j++) { m_normals[totalIndex++] = normal(m_vertices.at(j), m_vertices.at(j - m_columns), m_vertices.at(j + 1)); } m_normals[totalIndex++] = normal(m_vertices.at(lineEnd), m_vertices.at(lineEnd - 1), m_vertices.at(lineEnd - m_columns)); } else if (m_dataDimension == XDescending) { int lineStart = (m_rows - 1) * m_columns; int lineEnd = m_rows * m_columns; m_normals[totalIndex++] = normal(m_vertices.at(lineStart), m_vertices.at(lineStart + 1), m_vertices.at(lineStart - m_columns)); for (int j = lineStart + 1; j < lineEnd; j++) { m_normals[totalIndex++] = normal(m_vertices.at(j), m_vertices.at(j - m_columns), m_vertices.at(j - 1)); } } else if (m_dataDimension == ZDescending) { int colLimit = m_columns - 1; for (int j = 0; j < colLimit; j++) { m_normals[totalIndex++] = normal(m_vertices.at(j), m_vertices.at(j + m_columns), m_vertices.at(j + 1)); } m_normals[totalIndex++] = normal(m_vertices.at(colLimit), m_vertices.at(colLimit - 1), m_vertices.at(colLimit + m_columns)); } else { // BothDescending m_normals[totalIndex++] = normal(m_vertices.at(0), m_vertices.at(1), m_vertices.at(m_columns)); for (int j = 1; j < m_columns; j++) { m_normals[totalIndex++] = normal(m_vertices.at(j), m_vertices.at(j + m_columns), m_vertices.at(j - 1)); } } } QVector3D SurfaceObject::createSmoothNormalBodyLineItem(int x, int y) { int p = y * m_columns + x; if (m_dataDimension == BothAscending) { if (x < m_columns - 1) { return normal(m_vertices.at(p), m_vertices.at(p + 1), m_vertices.at(p + m_columns)); } else { return normal(m_vertices.at(p), m_vertices.at(p + m_columns), m_vertices.at(p - 1)); } } else if (m_dataDimension == XDescending) { if (x == 0) { return normal(m_vertices.at(p), m_vertices.at(p + m_columns), m_vertices.at(p + 1)); } else { return normal(m_vertices.at(p), m_vertices.at(p - 1), m_vertices.at(p + m_columns)); } } else if (m_dataDimension == ZDescending) { if (x < m_columns - 1) { return normal(m_vertices.at(p), m_vertices.at(p + 1), m_vertices.at(p - m_columns)); } else { return normal(m_vertices.at(p), m_vertices.at(p - m_columns), m_vertices.at(p - 1)); } } else { // BothDescending if (x == 0) { return normal(m_vertices.at(p), m_vertices.at(p - m_columns), m_vertices.at(p + 1)); } else { return normal(m_vertices.at(p), m_vertices.at(p - 1), m_vertices.at(p - m_columns)); } } } QVector3D SurfaceObject::createSmoothNormalUpperLineItem(int x, int y) { int p = y * m_columns + x; if (m_dataDimension == BothAscending) { if (x < m_columns - 1) { return normal(m_vertices.at(p), m_vertices.at(p - m_columns), m_vertices.at(p + 1)); } else { return normal(m_vertices.at(p), m_vertices.at(p - 1), m_vertices.at(p - m_columns)); } } else if (m_dataDimension == XDescending) { if (x == 0) { return normal(m_vertices.at(p), m_vertices.at(p + 1), m_vertices.at(p - m_columns)); } else { return normal(m_vertices.at(p), m_vertices.at(p - m_columns), m_vertices.at(p - 1)); } } else if (m_dataDimension == ZDescending) { if (x < m_columns - 1) { return normal(m_vertices.at(p), m_vertices.at(p + m_columns), m_vertices.at(p + 1)); } else { return normal(m_vertices.at(p), m_vertices.at(p - 1), m_vertices.at(p + m_columns)); } } else { // BothDescending if (x == 0) { return normal(m_vertices.at(0), m_vertices.at(1), m_vertices.at(m_columns)); } else { return normal(m_vertices.at(p), m_vertices.at(p + m_columns), m_vertices.at(p - 1)); } } } void SurfaceObject::smoothUVs(const QSurfaceDataArray &dataArray, const QSurfaceDataArray &modelArray) { if (dataArray.size() == 0 || modelArray.size() == 0) return; int columns = dataArray.at(0)->size(); int rows = dataArray.size(); float xRangeNormalizer = dataArray.at(0)->at(columns - 1).x() - dataArray.at(0)->at(0).x(); float zRangeNormalizer = dataArray.at(rows - 1)->at(0).z() - dataArray.at(0)->at(0).z(); float xMin = dataArray.at(0)->at(0).x(); float zMin = dataArray.at(0)->at(0).z(); const bool zDescending = m_dataDimension.testFlag(SurfaceObject::ZDescending); const bool xDescending = m_dataDimension.testFlag(SurfaceObject::XDescending); QVector uvs; uvs.resize(m_rows * m_columns); int index = 0; for (int i = 0; i < m_rows; i++) { float y = (modelArray.at(i)->at(0).z() - zMin) / zRangeNormalizer; if (zDescending) y = 1.0f - y; const QSurfaceDataRow &p = *modelArray.at(i); for (int j = 0; j < m_columns; j++) { float x = (p.at(j).x() - xMin) / xRangeNormalizer; if (xDescending) x = 1.0f - x; uvs[index] = QVector2D(x, y); index++; } } if (uvs.size() > 0) { glBindBuffer(GL_ARRAY_BUFFER, m_uvTextureBuffer); glBufferData(GL_ARRAY_BUFFER, uvs.size() * sizeof(QVector2D), &uvs.at(0), GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); m_returnTextureBuffer = true; } } void SurfaceObject::updateSmoothRow(const QSurfaceDataArray &dataArray, int rowIndex, bool polar) { // Update vertices int p = rowIndex * m_columns; const QSurfaceDataRow &dataRow = *dataArray.at(rowIndex); for (int j = 0; j < m_columns; j++) getNormalizedVertex(dataRow.at(j), m_vertices[p++], polar, false); // Create normals bool upwards = (m_dataDimension == BothAscending) || (m_dataDimension == XDescending); int startRow = rowIndex; if ((startRow > 0) && upwards) startRow--; int endRow = rowIndex; if (!upwards && (rowIndex < m_rows - 1)) endRow++; if ((endRow == m_rows - 1) && upwards) endRow--; int totalIndex = startRow * m_columns; if ((startRow == 0) && !upwards) { createSmoothNormalUpperLine(totalIndex); startRow++; } for (int row = startRow; row <= endRow; row++) createSmoothNormalBodyLine(totalIndex, row * m_columns); if ((rowIndex == m_rows - 1) && upwards) createSmoothNormalUpperLine(totalIndex); } void SurfaceObject::updateSmoothItem(const QSurfaceDataArray &dataArray, int row, int column, bool polar) { // Update a vertice getNormalizedVertex(dataArray.at(row)->at(column), m_vertices[row * m_columns + column], polar, false); // Create normals bool upwards = (m_dataDimension == BothAscending) || (m_dataDimension == XDescending); bool rightwards = (m_dataDimension == BothAscending) || (m_dataDimension == ZDescending); int startRow = row; if ((startRow > 0) && upwards) startRow--; int endRow = row; if (!upwards && (row < m_rows - 1)) endRow++; if ((endRow == m_rows - 1) && upwards) endRow--; int startCol = column; if ((startCol > 0) && rightwards) startCol--; int endCol = column; if ((endCol < m_columns - 1) && !rightwards) endCol++; for (int i = startRow; i <= endRow; i++) { for (int j = startCol; j <= endCol; j++) { int p = i * m_columns + j; if ((i == 0) && !upwards) m_normals[p] = createSmoothNormalUpperLineItem(j, i); else if ((i == m_rows - 1) && upwards) m_normals[p] = createSmoothNormalUpperLineItem(j, i); else m_normals[p] = createSmoothNormalBodyLineItem(j, i); } } } void SurfaceObject::createSmoothIndices(int x, int y, int endX, int endY) { if (endX >= m_columns) endX = m_columns - 1; if (endY >= m_rows) endY = m_rows - 1; if (x > endX) x = endX - 1; if (y > endY) y = endY - 1; m_indexCount = 6 * (endX - x) * (endY - y); GLint *indices = new GLint[m_indexCount]; int p = 0; int rowEnd = endY * m_columns; for (int row = y * m_columns; row < rowEnd; row += m_columns) { for (int j = x; j < endX; j++) { if ((m_dataDimension == BothAscending) || (m_dataDimension == BothDescending)) { // Left triangle indices[p++] = row + j + 1; indices[p++] = row + m_columns + j; indices[p++] = row + j; // Right triangle indices[p++] = row + m_columns + j + 1; indices[p++] = row + m_columns + j; indices[p++] = row + j + 1; } else if (m_dataDimension == XDescending) { // Right triangle indices[p++] = row + m_columns + j; indices[p++] = row + m_columns + j + 1; indices[p++] = row + j; // Left triangle indices[p++] = row + j; indices[p++] = row + m_columns + j + 1; indices[p++] = row + j + 1; } else { // Left triangle indices[p++] = row + m_columns + j; indices[p++] = row + m_columns + j + 1; indices[p++] = row + j; // Right triangle indices[p++] = row + j; indices[p++] = row + m_columns + j + 1; indices[p++] = row + j + 1; } } } glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementbuffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_indexCount * sizeof(GLint), indices, GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); delete[] indices; } void SurfaceObject::createSmoothGridlineIndices(int x, int y, int endX, int endY) { if (endX >= m_columns) endX = m_columns - 1; if (endY >= m_rows) endY = m_rows - 1; if (x > endX) x = endX - 1; if (y > endY) y = endY - 1; int nColumns = endX - x + 1; int nRows = endY - y + 1; m_gridIndexCount = 2 * nColumns * (nRows - 1) + 2 * nRows * (nColumns - 1); GLint *gridIndices = new GLint[m_gridIndexCount]; int p = 0; for (int i = y, row = m_columns * y; i <= endY; i++, row += m_columns) { for (int j = x; j < endX; j++) { gridIndices[p++] = row + j; gridIndices[p++] = row + j + 1; } } for (int i = y, row = m_columns * y; i < endY; i++, row += m_columns) { for (int j = x; j <= endX; j++) { gridIndices[p++] = row + j; gridIndices[p++] = row + j + m_columns; } } glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_gridElementbuffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_gridIndexCount * sizeof(GLint), gridIndices, GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); delete[] gridIndices; } void SurfaceObject::setUpData(const QSurfaceDataArray &dataArray, const QRect &space, bool changeGeometry, bool polar, bool flipXZ) { m_columns = space.width(); m_rows = space.height(); int totalSize = m_rows * m_columns * 2; GLfloat uvX = 1.0f / GLfloat(m_columns - 1); GLfloat uvY = 1.0f / GLfloat(m_rows - 1); checkDirections(dataArray); bool indicesDirty = false; if (m_dataDimension != m_oldDataDimension) indicesDirty = true; m_oldDataDimension = m_dataDimension; m_surfaceType = SurfaceFlat; // Create vertix table if (changeGeometry) m_vertices.resize(totalSize); QVector uvs; if (changeGeometry) uvs.resize(totalSize); int totalIndex = 0; int rowLimit = m_rows - 1; int colLimit = m_columns - 1; int doubleColumns = m_columns * 2 - 2; int rowColLimit = rowLimit * doubleColumns; // Init min and max to ridiculous values m_minY = 10000000.0; m_maxY = -10000000.0f; for (int i = 0; i < m_rows; i++) { const QSurfaceDataRow &row = *dataArray.at(i); for (int j = 0; j < m_columns; j++) { getNormalizedVertex(row.at(j), m_vertices[totalIndex], polar, flipXZ); if (changeGeometry) uvs[totalIndex] = QVector2D(GLfloat(j) * uvX, GLfloat(i) * uvY); totalIndex++; if (j > 0 && j < colLimit) { m_vertices[totalIndex] = m_vertices[totalIndex - 1]; if (changeGeometry) uvs[totalIndex] = uvs[totalIndex - 1]; totalIndex++; } } } if (flipXZ) { for (int i = 0; i < m_vertices.size(); i++) { m_vertices[i].setX(-m_vertices.at(i).x()); m_vertices[i].setZ(-m_vertices.at(i).z()); } } // Create normals & indices table GLint *indices = 0; if (changeGeometry || indicesDirty) { int normalCount = 2 * colLimit * rowLimit; m_indexCount = 3 * normalCount; indices = new GLint[m_indexCount]; m_normals.resize(normalCount); } int p = 0; totalIndex = 0; for (int row = 0, upperRow = doubleColumns; row < rowColLimit; row += doubleColumns, upperRow += doubleColumns) { for (int j = 0; j < doubleColumns; j += 2) { createNormals(totalIndex, row, upperRow, j); if (changeGeometry || indicesDirty) { createCoarseIndices(indices, p, row, upperRow, j); } } } // Create grid line element indices if (changeGeometry) createCoarseGridlineIndices(0, 0, colLimit, rowLimit); createBuffers(m_vertices, uvs, m_normals, indices); delete[] indices; } void SurfaceObject::coarseUVs(const QSurfaceDataArray &dataArray, const QSurfaceDataArray &modelArray) { if (dataArray.size() == 0 || modelArray.size() == 0) return; int columns = dataArray.at(0)->size(); int rows = dataArray.size(); float xRangeNormalizer = dataArray.at(0)->at(columns - 1).x() - dataArray.at(0)->at(0).x(); float zRangeNormalizer = dataArray.at(rows - 1)->at(0).z() - dataArray.at(0)->at(0).z(); float xMin = dataArray.at(0)->at(0).x(); float zMin = dataArray.at(0)->at(0).z(); const bool zDescending = m_dataDimension.testFlag(SurfaceObject::ZDescending); const bool xDescending = m_dataDimension.testFlag(SurfaceObject::XDescending); QVector uvs; uvs.resize(m_rows * m_columns * 2); int index = 0; int colLimit = m_columns - 1; for (int i = 0; i < m_rows; i++) { float y = (modelArray.at(i)->at(0).z() - zMin) / zRangeNormalizer; if (zDescending) y = 1.0f - y; const QSurfaceDataRow &p = *modelArray.at(i); for (int j = 0; j < m_columns; j++) { float x = (p.at(j).x() - xMin) / xRangeNormalizer; if (xDescending) x = 1.0f - x; uvs[index] = QVector2D(x, y); index++; if (j > 0 && j < colLimit) { uvs[index] = uvs[index - 1]; index++; } } } if (uvs.size() > 0) { glBindBuffer(GL_ARRAY_BUFFER, m_uvTextureBuffer); glBufferData(GL_ARRAY_BUFFER, uvs.size() * sizeof(QVector2D), &uvs.at(0), GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); m_returnTextureBuffer = true; } } void SurfaceObject::updateCoarseRow(const QSurfaceDataArray &dataArray, int rowIndex, bool polar) { int colLimit = m_columns - 1; int doubleColumns = m_columns * 2 - 2; int p = rowIndex * doubleColumns; const QSurfaceDataRow &dataRow = *dataArray.at(rowIndex); for (int j = 0; j < m_columns; j++) { getNormalizedVertex(dataRow.at(j), m_vertices[p++], polar, false); if (j > 0 && j < colLimit) { m_vertices[p] = m_vertices[p - 1]; p++; } } // Create normals p = rowIndex * doubleColumns; if (p > 0) p -= doubleColumns; int rowLimit = (rowIndex + 1) * doubleColumns; if (rowIndex == m_rows - 1) rowLimit = rowIndex * doubleColumns; //Topmost row, no normals for (int row = p, upperRow = p + doubleColumns; row < rowLimit; row += doubleColumns, upperRow += doubleColumns) { for (int j = 0; j < doubleColumns; j += 2) createNormals(p, row, upperRow, j); } } void SurfaceObject::updateCoarseItem(const QSurfaceDataArray &dataArray, int row, int column, bool polar) { int colLimit = m_columns - 1; int doubleColumns = m_columns * 2 - 2; // Update a vertice int p = row * doubleColumns + column * 2 - (column > 0); getNormalizedVertex(dataArray.at(row)->at(column), m_vertices[p++], polar, false); if (column > 0 && column < colLimit) m_vertices[p] = m_vertices[p - 1]; // Create normals int startRow = row; if (startRow > 0) startRow--; // Change the normal for previous row also int startCol = column; if (startCol > 0) startCol--; if (row == m_rows - 1) row--; if (column == m_columns - 1) column--; for (int i = startRow; i <= row; i++) { for (int j = startCol; j <= column; j++) { p = i * doubleColumns + j * 2; createNormals(p, i * doubleColumns, (i + 1) * doubleColumns, j * 2); } } } void SurfaceObject::createCoarseSubSection(int x, int y, int columns, int rows) { if (columns > m_columns) columns = m_columns; if (rows > m_rows) rows = m_rows; if (x > columns) x = columns - 1; if (y > rows) y = rows - 1; int rowLimit = rows - 1; int doubleColumns = m_columns * 2 - 2; int doubleColumnsLimit = columns * 2 - 2; int rowColLimit = rowLimit * doubleColumns; m_indexCount = 6 * (columns - 1 - x) * (rowLimit - y); int p = 0; GLint *indices = new GLint[m_indexCount]; for (int row = y * doubleColumns, upperRow = (y + 1) * doubleColumns; row < rowColLimit; row += doubleColumns, upperRow += doubleColumns) { for (int j = 2 * x; j < doubleColumnsLimit; j += 2) createCoarseIndices(indices, p, row, upperRow, j); } glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementbuffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_indexCount * sizeof(GLint), indices, GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); delete[] indices; } void SurfaceObject::createCoarseGridlineIndices(int x, int y, int endX, int endY) { if (endX >= m_columns) endX = m_columns - 1; if (endY >= m_rows) endY = m_rows - 1; if (x > endX) x = endX - 1; if (y > endY) y = endY - 1; int nColumns = endX - x + 1; int nRows = endY - y + 1; int doubleEndX = endX * 2; int doubleColumns = m_columns * 2 - 2; int rowColLimit = endY * doubleColumns; m_gridIndexCount = 2 * nColumns * (nRows - 1) + 2 * nRows * (nColumns - 1); GLint *gridIndices = new GLint[m_gridIndexCount]; int p = 0; for (int row = y * doubleColumns; row <= rowColLimit; row += doubleColumns) { for (int j = x * 2; j < doubleEndX; j += 2) { // Horizontal line gridIndices[p++] = row + j; gridIndices[p++] = row + j + 1; if (row < rowColLimit) { // Vertical line gridIndices[p++] = row + j; gridIndices[p++] = row + j + doubleColumns; } } } // The rightmost line separately, since there isn't double vertice for (int i = y * doubleColumns + doubleEndX - 1; i < rowColLimit; i += doubleColumns) { gridIndices[p++] = i; gridIndices[p++] = i + doubleColumns; } glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_gridElementbuffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_gridIndexCount * sizeof(GLint), gridIndices, GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); delete[] gridIndices; } void SurfaceObject::uploadBuffers() { QVector uvs; // Empty dummy createBuffers(m_vertices, uvs, m_normals, 0); } void SurfaceObject::createBuffers(const QVector &vertices, const QVector &uvs, const QVector &normals, const GLint *indices) { // Move to buffers glBindBuffer(GL_ARRAY_BUFFER, m_vertexbuffer); glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(QVector3D), &vertices.at(0), GL_DYNAMIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, m_normalbuffer); glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(QVector3D), &normals.at(0), GL_DYNAMIC_DRAW); if (uvs.size()) { glBindBuffer(GL_ARRAY_BUFFER, m_uvbuffer); glBufferData(GL_ARRAY_BUFFER, uvs.size() * sizeof(QVector2D), &uvs.at(0), GL_STATIC_DRAW); } if (indices) { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementbuffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_indexCount * sizeof(GLint), indices, GL_STATIC_DRAW); } glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0); m_meshDataLoaded = true; } void SurfaceObject::checkDirections(const QSurfaceDataArray &array) { m_dataDimension = BothAscending; if (array.at(0)->at(0).x() > array.at(0)->at(array.at(0)->size() - 1).x()) m_dataDimension |= XDescending; if (m_axisCacheX.reversed()) m_dataDimension ^= XDescending; if (array.at(0)->at(0).z() > array.at(array.size() - 1)->at(0).z()) m_dataDimension |= ZDescending; if (m_axisCacheZ.reversed()) m_dataDimension ^= ZDescending; } void SurfaceObject::getNormalizedVertex(const QSurfaceDataItem &data, QVector3D &vertex, bool polar, bool flipXZ) { float normalizedX; float normalizedZ; if (polar) { // Slice don't use polar, so don't care about flip m_renderer->calculatePolarXZ(data.position(), normalizedX, normalizedZ); } else { if (flipXZ) { normalizedX = m_axisCacheZ.positionAt(data.x()); normalizedZ = m_axisCacheX.positionAt(data.z()); } else { normalizedX = m_axisCacheX.positionAt(data.x()); normalizedZ = m_axisCacheZ.positionAt(data.z()); } } float normalizedY = m_axisCacheY.positionAt(data.y()); m_minY = qMin(normalizedY, m_minY); m_maxY = qMax(normalizedY, m_maxY); vertex.setX(normalizedX); vertex.setY(normalizedY); vertex.setZ(normalizedZ); } GLuint SurfaceObject::gridElementBuf() { if (!m_meshDataLoaded) qFatal("No loaded object"); return m_gridElementbuffer; } GLuint SurfaceObject::uvBuf() { if (!m_meshDataLoaded) qFatal("No loaded object"); if (m_returnTextureBuffer) return m_uvTextureBuffer; else return m_uvbuffer; } GLuint SurfaceObject::gridIndexCount() { return m_gridIndexCount; } QVector3D SurfaceObject::vertexAt(int column, int row) { int pos = 0; if (m_surfaceType == Undefined || !m_vertices.size()) return zeroVector; if (m_surfaceType == SurfaceFlat) pos = row * (m_columns * 2 - 2) + column * 2 - (column > 0); else pos = row * m_columns + column; return m_vertices.at(pos); } void SurfaceObject::clear() { m_gridIndexCount = 0; m_indexCount = 0; m_surfaceType = Undefined; m_vertices.clear(); m_normals.clear(); } void SurfaceObject::createCoarseIndices(GLint *indices, int &p, int row, int upperRow, int j) { if ((m_dataDimension == BothAscending) || (m_dataDimension == BothDescending)) { // 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; } else if (m_dataDimension == XDescending) { indices[p++] = upperRow + j; indices[p++] = upperRow + j + 1; indices[p++] = row + j; indices[p++] = row + j; indices[p++] = upperRow + j + 1; indices[p++] = row + j + 1; } else { // Left triangle indices[p++] = upperRow + j; indices[p++] = upperRow + j + 1; indices[p++] = row + j; // Right triangle indices[p++] = row + j; indices[p++] = upperRow + j + 1; indices[p++] = row + j + 1; } } void SurfaceObject::createNormals(int &p, int row, int upperRow, int j) { if ((m_dataDimension == BothAscending) || (m_dataDimension == BothDescending)) { m_normals[p++] = normal(m_vertices.at(row + j), m_vertices.at(row + j + 1), m_vertices.at(upperRow + j)); m_normals[p++] = normal(m_vertices.at(row + j + 1), m_vertices.at(upperRow + j + 1), m_vertices.at(upperRow + j)); } else if (m_dataDimension == XDescending) { m_normals[p++] = normal(m_vertices.at(row + j), m_vertices.at(upperRow + j), m_vertices.at(upperRow + j + 1)); m_normals[p++] = normal(m_vertices.at(row + j + 1), m_vertices.at(row + j), m_vertices.at(upperRow + j + 1)); } else { m_normals[p++] = normal(m_vertices.at(row + j), m_vertices.at(upperRow + j), m_vertices.at(upperRow + j + 1)); m_normals[p++] = normal(m_vertices.at(row + j + 1), m_vertices.at(row + j), m_vertices.at(upperRow + j + 1)); } } QVector3D SurfaceObject::normal(const QVector3D &a, const QVector3D &b, const QVector3D &c) { QVector3D v1 = b - a; QVector3D v2 = c - a; QVector3D normal = QVector3D::crossProduct(v1, v2); return normal; } QT_END_NAMESPACE_DATAVISUALIZATION