Revision control
++ // Copyright (C) 2016 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
++
++ #include "surfaceobject_p.h"
++ #include "surface3drenderer_p.h"
++
++ #include <QtGui/QVector2D>
++
++ QT_BEGIN_NAMESPACE
++
++ SurfaceObject::SurfaceObject(Surface3DRenderer *renderer)
++ : m_axisCacheX(renderer->m_axisCacheX),
++ m_axisCacheY(renderer->m_axisCacheY),
++ m_axisCacheZ(renderer->m_axisCacheZ),
++ m_renderer(renderer)
++ {
++ 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);
++
++ QList<QVector2D> 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);
++
++ QList<QVector2D> 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);
++
++ QList<QVector2D> 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);
++
++ QList<QVector2D> 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()
++ {
++ QList<QVector2D> uvs; // Empty dummy
++ createBuffers(m_vertices, uvs, m_normals, 0);
++ }
++
++ void SurfaceObject::createBuffers(const QList<QVector3D> &vertices, const QList<QVector2D> &uvs,
++ const QList<QVector3D> &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);
++ if (!qIsNaN(normalizedY) && !qIsInf(normalizedY))
++ 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