summaryrefslogtreecommitdiffstats
path: root/src/datavisualization
diff options
context:
space:
mode:
authorMika Salmela <mika.salmela@digia.com>2013-11-26 15:48:51 +0200
committerMika Salmela <mika.salmela@digia.com>2013-11-27 11:30:44 +0200
commitde3661089cb85701d7444bbf517711783df3aa49 (patch)
treee833426f16198da680101c9720c00ab4bcd2a678 /src/datavisualization
parent7c942cc0f497fe7e61ce6a10fce45771c0858e09 (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.cpp2
-rw-r--r--src/datavisualization/data/qsurface3dseries.cpp2
-rw-r--r--src/datavisualization/data/qsurfacedataproxy.cpp54
-rw-r--r--src/datavisualization/data/qsurfacedataproxy.h4
-rw-r--r--src/datavisualization/data/qsurfacedataproxy_p.h3
-rw-r--r--src/datavisualization/engine/surface3dcontroller.cpp28
-rw-r--r--src/datavisualization/engine/surface3dcontroller_p.h7
-rw-r--r--src/datavisualization/engine/surface3drenderer.cpp42
-rw-r--r--src/datavisualization/engine/surface3drenderer_p.h1
-rw-r--r--src/datavisualization/utils/surfaceobject.cpp361
-rw-r--r--src/datavisualization/utils/surfaceobject_p.h10
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 {