diff options
author | Mika Salmela <mika.salmela@digia.com> | 2013-11-26 15:48:51 +0200 |
---|---|---|
committer | Mika Salmela <mika.salmela@digia.com> | 2013-11-27 11:30:44 +0200 |
commit | de3661089cb85701d7444bbf517711783df3aa49 (patch) | |
tree | e833426f16198da680101c9720c00ab4bcd2a678 /src/datavisualization | |
parent | 7c942cc0f497fe7e61ce6a10fce45771c0858e09 (diff) |
Better proxy API for surface
Part 1, row change. More is on the way.
Change-Id: I4e152a5160275f2d629e7793d4d40b85082a2fc2
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@digia.com>
Diffstat (limited to 'src/datavisualization')
-rw-r--r-- | src/datavisualization/data/qbardataproxy.cpp | 2 | ||||
-rw-r--r-- | src/datavisualization/data/qsurface3dseries.cpp | 2 | ||||
-rw-r--r-- | src/datavisualization/data/qsurfacedataproxy.cpp | 54 | ||||
-rw-r--r-- | src/datavisualization/data/qsurfacedataproxy.h | 4 | ||||
-rw-r--r-- | src/datavisualization/data/qsurfacedataproxy_p.h | 3 | ||||
-rw-r--r-- | src/datavisualization/engine/surface3dcontroller.cpp | 28 | ||||
-rw-r--r-- | src/datavisualization/engine/surface3dcontroller_p.h | 7 | ||||
-rw-r--r-- | src/datavisualization/engine/surface3drenderer.cpp | 42 | ||||
-rw-r--r-- | src/datavisualization/engine/surface3drenderer_p.h | 1 | ||||
-rw-r--r-- | src/datavisualization/utils/surfaceobject.cpp | 361 | ||||
-rw-r--r-- | src/datavisualization/utils/surfaceobject_p.h | 10 |
11 files changed, 442 insertions, 72 deletions
diff --git a/src/datavisualization/data/qbardataproxy.cpp b/src/datavisualization/data/qbardataproxy.cpp index 88c08556..2529eeac 100644 --- a/src/datavisualization/data/qbardataproxy.cpp +++ b/src/datavisualization/data/qbardataproxy.cpp @@ -159,7 +159,7 @@ void QBarDataProxy::resetArray(QBarDataArray *newArray, const QStringList &rowLa } /*! - * Changes existing rows by replacing a row at \a rowIndex with \a row. The \a row can be + * Changes existing rows by replacing a row at \a rowIndex with a new \a row. The \a row can be * the same as the existing row already stored at the \a rowIndex. * Existing row labels are not affected. */ diff --git a/src/datavisualization/data/qsurface3dseries.cpp b/src/datavisualization/data/qsurface3dseries.cpp index d71962c3..2e850b03 100644 --- a/src/datavisualization/data/qsurface3dseries.cpp +++ b/src/datavisualization/data/qsurface3dseries.cpp @@ -242,6 +242,8 @@ void QSurface3DSeriesPrivate::connectControllerAndProxy(Abstract3DController *ne QObject::connect(surfaceDataProxy, &QSurfaceDataProxy::arrayReset, controller, &Surface3DController::handleArrayReset); + QObject::connect(surfaceDataProxy, &QSurfaceDataProxy::rowsChanged, controller, + &Surface3DController::handleRowsChanged); QObject::connect(q_ptr, &QAbstract3DSeries::visibilityChanged, controller, &Abstract3DController::handleSeriesVisibilityChanged); diff --git a/src/datavisualization/data/qsurfacedataproxy.cpp b/src/datavisualization/data/qsurfacedataproxy.cpp index b55fea97..aba2e288 100644 --- a/src/datavisualization/data/qsurfacedataproxy.cpp +++ b/src/datavisualization/data/qsurfacedataproxy.cpp @@ -36,6 +36,11 @@ QT_DATAVISUALIZATION_BEGIN_NAMESPACE * * All rows must have the same number of items. * + * QSurfaceDataProxy takes ownership of all QSurfaceDataRows passed to it, whether directly or + * in a QSurfaceDataArray container. + * If you use QSurfaceDataRow pointers to directly modify data after adding the array to the proxy, + * you must also emit proper signal to make the graph update. + * * When determining what rows and columns are visible, the first item in each row and the first item in * each column determine if the whole row or column is visible, even if other items in the row or column * individually have different X- or Z-coordinates. @@ -130,6 +135,29 @@ void QSurfaceDataProxy::resetArray(QSurfaceDataArray *newArray) } /*! + * Changes existing row by replacing a row at \a rowIndex with a new \a row. The \a row can be + * the same as the existing row already stored at the \a rowIndex. The new \a row must have + * the same number of columns as the row it is replacing. + */ +void QSurfaceDataProxy::setRow(int rowIndex, QSurfaceDataRow *row) +{ + dptr()->setRow(rowIndex, row); + emit rowsChanged(rowIndex, 1); +} + +/*! + * Changes existing rows by replacing a rows starting at \a rowIndex with \a rows. + * The rows in the \a rows array can be the same as the existing rows already + * stored at the \a rowIndex. The new rows must have the same number of columns + * as the rows they are replacing. + */ +void QSurfaceDataProxy::setRows(int rowIndex, const QSurfaceDataArray &rows) +{ + dptr()->setRows(rowIndex, rows); + emit rowsChanged(rowIndex, rows.size()); +} + +/*! * \return pointer to the data array. */ const QSurfaceDataArray *QSurfaceDataProxy::array() const @@ -219,6 +247,32 @@ void QSurfaceDataProxyPrivate::resetArray(QSurfaceDataArray *newArray) } } +void QSurfaceDataProxyPrivate::setRow(int rowIndex, QSurfaceDataRow *row) +{ + Q_ASSERT(rowIndex >= 0 && rowIndex < m_dataArray->size()); + Q_ASSERT(m_dataArray->at(rowIndex)->size() == row->size()); + + if (row != m_dataArray->at(rowIndex)) { + clearRow(rowIndex); + (*m_dataArray)[rowIndex] = row; + } +} + +void QSurfaceDataProxyPrivate::setRows(int rowIndex, const QSurfaceDataArray &rows) +{ + QSurfaceDataArray &dataArray = *m_dataArray; + Q_ASSERT(rowIndex >= 0 && (rowIndex + rows.size()) <= dataArray.size()); + Q_ASSERT(m_dataArray->at(rowIndex)->size() == rows.at(0)->size()); + + for (int i = 0; i < rows.size(); i++) { + if (rows.at(i) != dataArray.at(rowIndex)) { + clearRow(rowIndex); + dataArray[rowIndex] = rows.at(i); + } + rowIndex++; + } +} + QSurfaceDataProxy *QSurfaceDataProxyPrivate::qptr() { return static_cast<QSurfaceDataProxy *>(q_ptr); diff --git a/src/datavisualization/data/qsurfacedataproxy.h b/src/datavisualization/data/qsurfacedataproxy.h index ed594963..d8808ded 100644 --- a/src/datavisualization/data/qsurfacedataproxy.h +++ b/src/datavisualization/data/qsurfacedataproxy.h @@ -50,8 +50,12 @@ public: void resetArray(QSurfaceDataArray *newArray); + void setRow(int rowIndex, QSurfaceDataRow *row); + void setRows(int rowIndex, const QSurfaceDataArray &rows); + signals: void arrayReset(); + void rowsChanged(int startIndex, int count); void seriesChanged(QSurface3DSeries *series); protected: diff --git a/src/datavisualization/data/qsurfacedataproxy_p.h b/src/datavisualization/data/qsurfacedataproxy_p.h index 066df629..38d92be1 100644 --- a/src/datavisualization/data/qsurfacedataproxy_p.h +++ b/src/datavisualization/data/qsurfacedataproxy_p.h @@ -44,7 +44,8 @@ public: virtual ~QSurfaceDataProxyPrivate(); void resetArray(QSurfaceDataArray *newArray); - + void setRow(int rowIndex, QSurfaceDataRow *row); + void setRows(int rowIndex, const QSurfaceDataArray &rows); void limitValues(QVector3D &minValues, QVector3D &maxValues) const; virtual void setSeries(QAbstract3DSeries *series); diff --git a/src/datavisualization/engine/surface3dcontroller.cpp b/src/datavisualization/engine/surface3dcontroller.cpp index 54614576..5b603a62 100644 --- a/src/datavisualization/engine/surface3dcontroller.cpp +++ b/src/datavisualization/engine/surface3dcontroller.cpp @@ -38,7 +38,9 @@ Surface3DController::Surface3DController(QRect rect) m_isSurfaceEnabled(true), m_isSurfaceGridEnabled(true), m_selectedPoint(invalidSelectionPosition()), - m_selectedSeries(0) + m_selectedSeries(0), + m_rowsChangeStartId(0), + m_rowsChangeCount(0) { // Setting a null axis creates a new default axis according to orientation and graph type. // Note: these cannot be set in the Abstract3DController constructor, as they will call virtual @@ -97,10 +99,16 @@ void Surface3DController::synchDataToRenderer() emit smoothSurfaceEnabledChanged(m_isSmoothSurfaceEnabled); } + if (m_changeTracker.rowsChanged) { + m_renderer->updateRows(m_rowsChangeStartId, m_rowsChangeCount); + m_changeTracker.rowsChanged = false; + } + if (m_changeTracker.selectedPointChanged) { m_renderer->updateSelectedPoint(m_selectedPoint, m_selectedSeries); m_changeTracker.selectedPointChanged = false; } + } void Surface3DController::handleAxisAutoAdjustRangeChangedInOrientation(Q3DAbstractAxis::AxisOrientation orientation, bool autoAdjust) @@ -339,6 +347,22 @@ void Surface3DController::handlePointClicked(const QPoint &position, QSurface3DS // TODO: Also hover needed? (QTRD-2131) } +void Surface3DController::handleRowsChanged(int startIndex, int count) +{ + QSurfaceDataProxy *sender = static_cast<QSurfaceDataProxy *>(QObject::sender()); + if (static_cast<QSurface3DSeries *>(m_seriesList.at(0)) == sender->series()) { + // Change is for the visible series, put the change to queue + m_rowsChangeStartId = startIndex; + m_rowsChangeCount = count; + m_changeTracker.rowsChanged = true; + + adjustValueAxisRange(); + // Clear selection unless still valid + setSelectedPoint(m_selectedPoint, m_selectedSeries); + emitNeedRender(); + } +} + void Surface3DController::handleRequestSmoothSurface(bool enable) { setSmoothSurface(enable); @@ -352,7 +376,7 @@ void Surface3DController::adjustValueAxisRange() QVector3D maxLimits; QSurface3DSeries *series = static_cast<QSurface3DSeries *>(m_seriesList.at(0)); static_cast<QSurfaceDataProxy *>(series->dataProxy())->dptrc()->limitValues(minLimits, - maxLimits); + maxLimits); Q3DValueAxis *valueAxis = static_cast<Q3DValueAxis *>(m_axisX); if (valueAxis && valueAxis->isAutoAdjustRange()) { if (minLimits.x() != maxLimits.x()) diff --git a/src/datavisualization/engine/surface3dcontroller_p.h b/src/datavisualization/engine/surface3dcontroller_p.h index 7a0b7f0e..aec520cf 100644 --- a/src/datavisualization/engine/surface3dcontroller_p.h +++ b/src/datavisualization/engine/surface3dcontroller_p.h @@ -44,12 +44,14 @@ struct Surface3DChangeBitField { bool smoothStatusChanged : 1; bool surfaceGridChanged : 1; bool selectedPointChanged : 1; + bool rowsChanged : 1; Surface3DChangeBitField() : gradientColorChanged(true), smoothStatusChanged(true), surfaceGridChanged(true), - selectedPointChanged(true) + selectedPointChanged(true), + rowsChanged(true) { } }; @@ -68,6 +70,8 @@ private: QPoint m_selectedPoint; QSurface3DSeries *m_selectedSeries; // Points to the series for which the point is selected in // single series selection cases. + int m_rowsChangeStartId; + int m_rowsChangeCount; public: explicit Surface3DController(QRect rect); @@ -102,6 +106,7 @@ public: public slots: void handleArrayReset(); + void handleRowsChanged(int startIndex, int count); // Renderer callback handlers void handlePointClicked(const QPoint &position, QSurface3DSeries *series); diff --git a/src/datavisualization/engine/surface3drenderer.cpp b/src/datavisualization/engine/surface3drenderer.cpp index 2298aef4..28ade504 100644 --- a/src/datavisualization/engine/surface3drenderer.cpp +++ b/src/datavisualization/engine/surface3drenderer.cpp @@ -270,6 +270,48 @@ void Surface3DRenderer::updateData() updateSelectedPoint(m_selectedPoint, m_selectedSeries); } +void Surface3DRenderer::updateRows(int startIndex, int count) +{ + // TODO: Properly support non-straight rows and columns (QTRD-2643) + if (startIndex > m_sampleSpace.height()) { + // No changes on visible area + return; + } + + // Surface only supports single series for now, so we are only interested in the first series + const QSurfaceDataArray *array = 0; + if (m_visibleSeriesList.size()) { + QSurface3DSeries *firstSeries = static_cast<QSurface3DSeries *>(m_visibleSeriesList.at(0).series()); + if (m_cachedSurfaceGridOn || m_cachedSurfaceVisible) { + QSurfaceDataProxy *dataProxy = firstSeries->dataProxy(); + if (dataProxy) + array = dataProxy->array(); + } + } + + if (array && array->size() >= 2 && array->at(0)->size() >= 2 && + m_sampleSpace.width() >= 2 && m_sampleSpace.height() >= 2) { + int endRow = startIndex + count; + if (endRow > m_sampleSpace.height()) + endRow = m_sampleSpace.height(); + + for (int i = startIndex; i < endRow; i++) { + for (int j = 0; j < m_sampleSpace.width(); j++) + (*(m_dataArray.at(i)))[j] = array->at(i + m_sampleSpace.y())->at(j + m_sampleSpace.x()); + } + + if (m_cachedSmoothSurface) { + m_surfaceObj->updateSmoothRows(m_dataArray, startIndex, endRow, m_heightNormalizer, + m_axisCacheY.min()); + } else { + m_surfaceObj->updateCoarseRows(m_dataArray, startIndex, endRow, m_heightNormalizer, + m_axisCacheY.min()); + } + } + + updateSelectedPoint(m_selectedPoint, m_selectedSeries); +} + void Surface3DRenderer::updateSliceDataModel(const QPoint &point) { int column = point.y(); diff --git a/src/datavisualization/engine/surface3drenderer_p.h b/src/datavisualization/engine/surface3drenderer_p.h index ab656194..9803f59d 100644 --- a/src/datavisualization/engine/surface3drenderer_p.h +++ b/src/datavisualization/engine/surface3drenderer_p.h @@ -134,6 +134,7 @@ public: ~Surface3DRenderer(); void updateData(); + void updateRows(int startIndex, int count); void updateScene(Q3DScene *scene); bool updateSmoothStatus(bool enable); void updateSurfaceGridStatus(bool enable); diff --git a/src/datavisualization/utils/surfaceobject.cpp b/src/datavisualization/utils/surfaceobject.cpp index c4d8532e..81945900 100644 --- a/src/datavisualization/utils/surfaceobject.cpp +++ b/src/datavisualization/utils/surfaceobject.cpp @@ -105,58 +105,164 @@ void SurfaceObject::setUpSmoothData(const QSurfaceDataArray &dataArray, const QR m_vertices.at(j - m_columns), m_vertices.at(j + 1)); } - int p = m_rows * colLimit; - m_normals[totalIndex++] = normal(m_vertices.at(p), - m_vertices.at(p - 1), - m_vertices.at(p - m_columns - 1)); + m_normals[totalIndex++] = normal(m_vertices.at(totalLimit), + m_vertices.at(totalLimit - 1), + m_vertices.at(totalLimit - m_columns)); // Create indices table - GLint *indices = 0; - if (changeGeometry) { - m_indexCount = 6 * colLimit * rowLimit; - indices = new GLint[m_indexCount]; - p = 0; - for (int row = 0; row < rowLimit * m_columns; row += m_columns) { - for (int j = 0; j < colLimit; j++) { - // Left triangle - indices[p++] = row + j + 1; - indices[p++] = row + m_columns + j; - indices[p++] = row + j; + if (changeGeometry) + createSmoothIndices(0, 0, colLimit, rowLimit); - // Right triangle - indices[p++] = row + m_columns + j + 1; - indices[p++] = row + m_columns + j; - indices[p++] = row + j + 1; - } + // Create line element indices + if (changeGeometry) + createSmoothGridlineIndices(0, 0, colLimit, rowLimit); + + createBuffers(m_vertices, uvs, m_normals, 0, changeGeometry); +} + +void SurfaceObject::updateSmoothRows(const QSurfaceDataArray &dataArray, int startRow, + int endRow, GLfloat yRange, GLfloat yMin) +{ + GLfloat xMin = dataArray.at(0)->at(0).x(); + GLfloat zMin = dataArray.at(0)->at(0).z(); + GLfloat xNormalizer = (dataArray.at(0)->last().x() - xMin) / 2.0f; + GLfloat yNormalizer = yRange / 2.0f; + GLfloat zNormalizer = (dataArray.last()->at(0).z() - zMin) / -2.0f; + + // Update vertices + int totalIndex = startRow * m_columns; + for (int i = startRow; i < endRow; i++) { + const QSurfaceDataRow &p = *dataArray.at(i); + for (int j = 0; j < m_columns; j++) { + const QSurfaceDataItem &data = p.at(j); + float normalizedX = ((data.x() - xMin) / xNormalizer); + float normalizedY = ((data.y() - yMin) / yNormalizer); + float normalizedZ = ((data.z() - zMin) / zNormalizer); + m_vertices[totalIndex++] = QVector3D(normalizedX - 1.0f, normalizedY - 1.0f, normalizedZ + 1.0f); } } - // Create line element indices - GLint *gridIndices = 0; - if (changeGeometry) { - m_gridIndexCount = 2 * m_columns * rowLimit + 2 * m_rows * colLimit; - gridIndices = new GLint[m_gridIndexCount]; - p = 0; - for (int i = 0, row = 0; i < m_rows; i++, row += m_columns) { + // Create normals + int colLimit = m_columns - 1; + int rowColLimit = endRow * m_columns; + if (endRow == m_rows) + rowColLimit = (endRow - 1) * m_columns; + int totalLimit = endRow * m_columns - 1; + + totalIndex = startRow * m_columns; + if (startRow > 0) { + // Change the normals for the previous row also + totalIndex -= m_columns; + } + if (totalIndex < (m_rows - 1) * m_columns) { + for (int row = totalIndex; row < rowColLimit; row += m_columns) { for (int j = 0; j < colLimit; j++) { - gridIndices[p++] = row + j; - gridIndices[p++] = row + j + 1; + // One right and one up + m_normals[totalIndex++] = normal(m_vertices.at(row + j), + m_vertices.at(row + j + 1), + m_vertices.at(row + m_columns + j)); } + int p = row + colLimit; + // One up and one left + m_normals[totalIndex++] = normal(m_vertices.at(p), + m_vertices.at(p + m_columns), + m_vertices.at(p - 1)); } - for (int i = 0, row = 0; i < rowLimit; i++, row += m_columns) { - for (int j = 0; j < m_columns; j++) { - gridIndices[p++] = row + j; - gridIndices[p++] = row + j + m_columns; - } + } + if (endRow == m_rows) { + // Top most line, nothing above, must have different handling. + // Take from one down and one right. Read till second-to-last + for (int j = rowColLimit; j < totalLimit; j++) { + m_normals[totalIndex++] = normal(m_vertices.at(j), + m_vertices.at(j - m_columns), + m_vertices.at(j + 1)); + } + + // Top left corner. Take from one left and one down + m_normals[totalIndex++] = normal(m_vertices.at(totalLimit), + m_vertices.at(totalLimit - 1), + m_vertices.at(totalLimit - m_columns)); + } + + QVector<QVector2D> uvs; // Empty dummy + createBuffers(m_vertices, uvs, m_normals, 0, false); +} + +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++) { + // 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; } } - createBuffers(m_vertices, uvs, m_normals, indices, gridIndices, changeGeometry); + 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; - delete[] gridIndices; } +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, GLfloat yRange, GLfloat yMin, bool changeGeometry) @@ -250,38 +356,164 @@ void SurfaceObject::setUpData(const QSurfaceDataArray &dataArray, const QRect &s } // Create grid line element indices - GLint *gridIndices = 0; - if (changeGeometry) { - m_gridIndexCount = 2 * m_columns * rowLimit + 2 * m_rows * colLimit; - gridIndices = new GLint[m_gridIndexCount]; - p = 0; - int fullRowLimit = m_rows * doubleColumns; - for (int row = 0; row < fullRowLimit; row += doubleColumns) { - for (int j = 0; j < doubleColumns; j += 2) { - gridIndices[p++] = row + j; - gridIndices[p++] = row + j + 1; + if (changeGeometry) + createCoarseGridlineIndices(0, 0, colLimit, rowLimit); + + createBuffers(m_vertices, uvs, m_normals, indices, changeGeometry); + + delete[] indices; +} - if (row < rowColLimit) { - gridIndices[p++] = row + j; - gridIndices[p++] = row + j + doubleColumns; - } +void SurfaceObject::updateCoarseRows(const QSurfaceDataArray &dataArray, int startRow, + int endRow, GLfloat yRange, GLfloat yMin) +{ + GLfloat xMin = dataArray.at(0)->at(0).x(); + GLfloat zMin = dataArray.at(0)->at(0).z(); + GLfloat xNormalizer = (dataArray.at(0)->last().x() - xMin) / 2.0f; + GLfloat yNormalizer = yRange / 2.0f; + GLfloat zNormalizer = (dataArray.last()->at(0).z() - zMin) / -2.0f; + + int colLimit = m_columns - 1; + int doubleColumns = m_columns * 2 - 2; + int totalIndex = startRow * doubleColumns; + + for (int i = startRow; i < endRow; i++) { + const QSurfaceDataRow &row = *dataArray.at(i); + for (int j = 0; j < m_columns; j++) { + const QSurfaceDataItem &data = row.at(j); + float normalizedX = ((data.x() - xMin) / xNormalizer); + float normalizedY = ((data.y() - yMin) / yNormalizer); + float normalizedZ = ((data.z() - zMin) / zNormalizer); + m_vertices[totalIndex++] = QVector3D(normalizedX - 1.0f, normalizedY - 1.0f, normalizedZ + 1.0f); + + if (j > 0 && j < colLimit) { + m_vertices[totalIndex] = m_vertices[totalIndex - 1]; + totalIndex++; } } - for (int i = doubleColumns - 1; i < rowColLimit; i += doubleColumns) { - gridIndices[p++] = i; - gridIndices[p++] = i + doubleColumns; + } + + // Create normals + if (startRow > 0) + startRow--; + totalIndex = startRow * doubleColumns; + int rowColLimit = startRow * doubleColumns; + for (int row = totalIndex, upperRow = totalIndex + doubleColumns; + row <= rowColLimit; + row += doubleColumns, upperRow += doubleColumns) { + for (int j = 0; j < doubleColumns; j += 2) { + // Normal for the left triangle + m_normals[totalIndex++] = normal(m_vertices.at(row + j), + m_vertices.at(row + j + 1), + m_vertices.at(upperRow + j)); + + // Normal for the right triangle + m_normals[totalIndex++] = normal(m_vertices.at(row + j + 1), + m_vertices.at(upperRow + j + 1), + m_vertices.at(upperRow + j)); + } + } + + QVector<QVector2D> uvs; // Empty dummy + createBuffers(m_vertices, uvs, m_normals, 0, false); +} + +void SurfaceObject::createCoarseIndices(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) { + // 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; } } - createBuffers(m_vertices, uvs, m_normals, indices, gridIndices, changeGeometry); + 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::createBuffers(const QVector<QVector3D> &vertices, const QVector<QVector2D> &uvs, const QVector<QVector3D> &normals, const GLint *indices, - const GLint *gridIndices, bool changeGeometry) + bool changeGeometry) { // Move to buffers glBindBuffer(GL_ARRAY_BUFFER, m_vertexbuffer); @@ -293,18 +525,15 @@ void SurfaceObject::createBuffers(const QVector<QVector3D> &vertices, const QVec &normals.at(0), GL_DYNAMIC_DRAW); if (changeGeometry) { - if (uvs.size()) { - glBindBuffer(GL_ARRAY_BUFFER, m_uvbuffer); - glBufferData(GL_ARRAY_BUFFER, uvs.size() * sizeof(QVector2D), - &uvs.at(0), GL_STATIC_DRAW); + 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, m_elementbuffer); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_indexCount * sizeof(GLint), - indices, GL_STATIC_DRAW); - - 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); } diff --git a/src/datavisualization/utils/surfaceobject_p.h b/src/datavisualization/utils/surfaceobject_p.h index 4f30f7c0..895fd3eb 100644 --- a/src/datavisualization/utils/surfaceobject_p.h +++ b/src/datavisualization/utils/surfaceobject_p.h @@ -48,6 +48,14 @@ public: GLfloat yMin, bool changeGeometry); void setUpSmoothData(const QSurfaceDataArray &dataArray, const QRect &space, GLfloat yRange, GLfloat yMin, bool changeGeometry); + void updateCoarseRows(const QSurfaceDataArray &dataArray, int startRow, + int endRow, GLfloat yRange, GLfloat yMin); + void updateSmoothRows(const QSurfaceDataArray &dataArray, int startRow, + int endRow, GLfloat yRange, GLfloat yMin); + void createSmoothIndices(int x, int y, int endX, int endY); + void createCoarseIndices(int x, int y, int columns, int rows); + void createSmoothGridlineIndices(int x, int y, int endX, int endY); + void createCoarseGridlineIndices(int x, int y, int endX, int endY); GLuint gridElementBuf(); GLuint gridIndexCount(); QVector3D vertexAt(int column, int row); @@ -56,7 +64,7 @@ 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); + bool changeGeometry); private: enum SurfaceType { |