1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt Data Visualization module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 or (at your option) any later version
20** approved by the KDE Free Qt Foundation. The licenses are as published by
21** the Free Software Foundation and appearing in the file LICENSE.GPL3
22** included in the packaging of this file. Please review the following
23** information to ensure the GNU General Public License requirements will
24** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25**
26** $QT_END_LICENSE$
27**
28****************************************************************************/
29
30#include "surfaceobject_p.h"
31#include "surface3drenderer_p.h"
32
33#include <QtGui/QVector2D>
34
35QT_BEGIN_NAMESPACE_DATAVISUALIZATION
36
37SurfaceObject::SurfaceObject(Surface3DRenderer *renderer)
38 : m_axisCacheX(renderer->m_axisCacheX),
39 m_axisCacheY(renderer->m_axisCacheY),
40 m_axisCacheZ(renderer->m_axisCacheZ),
41 m_renderer(renderer)
42{
43 glGenBuffers(n: 1, buffers: &m_vertexbuffer);
44 glGenBuffers(n: 1, buffers: &m_normalbuffer);
45 glGenBuffers(n: 1, buffers: &m_uvbuffer);
46 glGenBuffers(n: 1, buffers: &m_elementbuffer);
47 glGenBuffers(n: 1, buffers: &m_gridElementbuffer);
48 glGenBuffers(n: 1, buffers: &m_uvTextureBuffer);
49}
50
51SurfaceObject::~SurfaceObject()
52{
53 if (QOpenGLContext::currentContext()) {
54 glDeleteBuffers(n: 1, buffers: &m_gridElementbuffer);
55 glDeleteBuffers(n: 1, buffers: &m_uvTextureBuffer);
56 }
57}
58
59void SurfaceObject::setUpSmoothData(const QSurfaceDataArray &dataArray, const QRect &space,
60 bool changeGeometry, bool polar, bool flipXZ)
61{
62 m_columns = space.width();
63 m_rows = space.height();
64 int totalSize = m_rows * m_columns;
65 GLfloat uvX = 1.0f / GLfloat(m_columns - 1);
66 GLfloat uvY = 1.0f / GLfloat(m_rows - 1);
67
68 m_surfaceType = SurfaceSmooth;
69
70 checkDirections(array: dataArray);
71 bool indicesDirty = false;
72 if (m_dataDimension != m_oldDataDimension)
73 indicesDirty = true;
74 m_oldDataDimension = m_dataDimension;
75
76 // Create/populate vertix table
77 if (changeGeometry)
78 m_vertices.resize(asize: totalSize);
79
80 QVector<QVector2D> uvs;
81 if (changeGeometry)
82 uvs.resize(asize: totalSize);
83 int totalIndex = 0;
84
85 // Init min and max to ridiculous values
86 m_minY = 10000000.0;
87 m_maxY = -10000000.0f;
88
89 for (int i = 0; i < m_rows; i++) {
90 const QSurfaceDataRow &p = *dataArray.at(i);
91 for (int j = 0; j < m_columns; j++) {
92 getNormalizedVertex(data: p.at(i: j), vertex&: m_vertices[totalIndex], polar, flipXZ);
93 if (changeGeometry)
94 uvs[totalIndex] = QVector2D(GLfloat(j) * uvX, GLfloat(i) * uvY);
95 totalIndex++;
96 }
97 }
98
99 if (flipXZ) {
100 for (int i = 0; i < m_vertices.size(); i++) {
101 m_vertices[i].setX(-m_vertices.at(i).x());
102 m_vertices[i].setZ(-m_vertices.at(i).z());
103 }
104 }
105
106 // Create normals
107 int rowLimit = m_rows - 1;
108 int colLimit = m_columns - 1;
109 if (changeGeometry)
110 m_normals.resize(asize: totalSize);
111
112 totalIndex = 0;
113
114 if ((m_dataDimension == BothAscending) || (m_dataDimension == XDescending)) {
115 for (int row = 0; row < rowLimit; row++)
116 createSmoothNormalBodyLine(totalIndex, column: row * m_columns);
117 createSmoothNormalUpperLine(totalIndex);
118 } else { // BothDescending || ZDescending
119 createSmoothNormalUpperLine(totalIndex);
120 for (int row = 1; row < m_rows; row++)
121 createSmoothNormalBodyLine(totalIndex, column: row * m_columns);
122 }
123
124 // Create indices table
125 if (changeGeometry || indicesDirty)
126 createSmoothIndices(x: 0, y: 0, endX: colLimit, endY: rowLimit);
127
128 // Create line element indices
129 if (changeGeometry)
130 createSmoothGridlineIndices(x: 0, y: 0, endX: colLimit, endY: rowLimit);
131
132 createBuffers(vertices: m_vertices, uvs, normals: m_normals, indices: 0);
133}
134
135void SurfaceObject::createSmoothNormalBodyLine(int &totalIndex, int column)
136{
137 int colLimit = m_columns - 1;
138
139 if (m_dataDimension == BothAscending) {
140 int end = colLimit + column;
141 for (int j = column; j < end; j++) {
142 m_normals[totalIndex++] = normal(a: m_vertices.at(i: j),
143 b: m_vertices.at(i: j + 1),
144 c: m_vertices.at(i: j + m_columns));
145 }
146 m_normals[totalIndex++] = normal(a: m_vertices.at(i: end),
147 b: m_vertices.at(i: end + m_columns),
148 c: m_vertices.at(i: end - 1));
149 } else if (m_dataDimension == XDescending) {
150 m_normals[totalIndex++] = normal(a: m_vertices.at(i: column),
151 b: m_vertices.at(i: column + m_columns),
152 c: m_vertices.at(i: column + 1));
153 int end = column + m_columns;
154 for (int j = column + 1; j < end; j++) {
155 m_normals[totalIndex++] = normal(a: m_vertices.at(i: j),
156 b: m_vertices.at(i: j - 1),
157 c: m_vertices.at(i: j + m_columns));
158 }
159 } else if (m_dataDimension == ZDescending) {
160 int end = colLimit + column;
161 for (int j = column; j < end; j++) {
162 m_normals[totalIndex++] = normal(a: m_vertices.at(i: j),
163 b: m_vertices.at(i: j + 1),
164 c: m_vertices.at(i: j - m_columns));
165 }
166 m_normals[totalIndex++] = normal(a: m_vertices.at(i: end),
167 b: m_vertices.at(i: end - m_columns),
168 c: m_vertices.at(i: end - 1));
169 } else { // BothDescending
170 m_normals[totalIndex++] = normal(a: m_vertices.at(i: column),
171 b: m_vertices.at(i: column - m_columns),
172 c: m_vertices.at(i: column + 1));
173 int end = column + m_columns;
174 for (int j = column + 1; j < end; j++) {
175 m_normals[totalIndex++] = normal(a: m_vertices.at(i: j),
176 b: m_vertices.at(i: j - 1),
177 c: m_vertices.at(i: j - m_columns));
178 }
179 }
180}
181
182void SurfaceObject::createSmoothNormalUpperLine(int &totalIndex)
183{
184 if (m_dataDimension == BothAscending) {
185 int lineEnd = m_rows * m_columns - 1;
186 for (int j = (m_rows - 1) * m_columns; j < lineEnd; j++) {
187 m_normals[totalIndex++] = normal(a: m_vertices.at(i: j),
188 b: m_vertices.at(i: j - m_columns),
189 c: m_vertices.at(i: j + 1));
190 }
191 m_normals[totalIndex++] = normal(a: m_vertices.at(i: lineEnd),
192 b: m_vertices.at(i: lineEnd - 1),
193 c: m_vertices.at(i: lineEnd - m_columns));
194 } else if (m_dataDimension == XDescending) {
195 int lineStart = (m_rows - 1) * m_columns;
196 int lineEnd = m_rows * m_columns;
197 m_normals[totalIndex++] = normal(a: m_vertices.at(i: lineStart),
198 b: m_vertices.at(i: lineStart + 1),
199 c: m_vertices.at(i: lineStart - m_columns));
200 for (int j = lineStart + 1; j < lineEnd; j++) {
201 m_normals[totalIndex++] = normal(a: m_vertices.at(i: j),
202 b: m_vertices.at(i: j - m_columns),
203 c: m_vertices.at(i: j - 1));
204 }
205 } else if (m_dataDimension == ZDescending) {
206 int colLimit = m_columns - 1;
207 for (int j = 0; j < colLimit; j++) {
208 m_normals[totalIndex++] = normal(a: m_vertices.at(i: j),
209 b: m_vertices.at(i: j + m_columns),
210 c: m_vertices.at(i: j + 1));
211 }
212 m_normals[totalIndex++] = normal(a: m_vertices.at(i: colLimit),
213 b: m_vertices.at(i: colLimit - 1),
214 c: m_vertices.at(i: colLimit + m_columns));
215 } else { // BothDescending
216 m_normals[totalIndex++] = normal(a: m_vertices.at(i: 0),
217 b: m_vertices.at(i: 1),
218 c: m_vertices.at(i: m_columns));
219 for (int j = 1; j < m_columns; j++) {
220 m_normals[totalIndex++] = normal(a: m_vertices.at(i: j),
221 b: m_vertices.at(i: j + m_columns),
222 c: m_vertices.at(i: j - 1));
223 }
224 }
225}
226
227QVector3D SurfaceObject::createSmoothNormalBodyLineItem(int x, int y)
228{
229 int p = y * m_columns + x;
230 if (m_dataDimension == BothAscending) {
231 if (x < m_columns - 1) {
232 return normal(a: m_vertices.at(i: p), b: m_vertices.at(i: p + 1),
233 c: m_vertices.at(i: p + m_columns));
234 } else {
235 return normal(a: m_vertices.at(i: p), b: m_vertices.at(i: p + m_columns),
236 c: m_vertices.at(i: p - 1));
237 }
238 } else if (m_dataDimension == XDescending) {
239 if (x == 0) {
240 return normal(a: m_vertices.at(i: p), b: m_vertices.at(i: p + m_columns),
241 c: m_vertices.at(i: p + 1));
242 } else {
243 return normal(a: m_vertices.at(i: p), b: m_vertices.at(i: p - 1),
244 c: m_vertices.at(i: p + m_columns));
245 }
246 } else if (m_dataDimension == ZDescending) {
247 if (x < m_columns - 1) {
248 return normal(a: m_vertices.at(i: p), b: m_vertices.at(i: p + 1),
249 c: m_vertices.at(i: p - m_columns));
250 } else {
251 return normal(a: m_vertices.at(i: p), b: m_vertices.at(i: p - m_columns),
252 c: m_vertices.at(i: p - 1));
253 }
254 } else { // BothDescending
255 if (x == 0) {
256 return normal(a: m_vertices.at(i: p), b: m_vertices.at(i: p - m_columns),
257 c: m_vertices.at(i: p + 1));
258 } else {
259 return normal(a: m_vertices.at(i: p), b: m_vertices.at(i: p - 1),
260 c: m_vertices.at(i: p - m_columns));
261 }
262 }
263}
264
265QVector3D SurfaceObject::createSmoothNormalUpperLineItem(int x, int y)
266{
267 int p = y * m_columns + x;
268 if (m_dataDimension == BothAscending) {
269 if (x < m_columns - 1) {
270 return normal(a: m_vertices.at(i: p), b: m_vertices.at(i: p - m_columns),
271 c: m_vertices.at(i: p + 1));
272 } else {
273 return normal(a: m_vertices.at(i: p), b: m_vertices.at(i: p - 1),
274 c: m_vertices.at(i: p - m_columns));
275 }
276 } else if (m_dataDimension == XDescending) {
277 if (x == 0) {
278 return normal(a: m_vertices.at(i: p), b: m_vertices.at(i: p + 1),
279 c: m_vertices.at(i: p - m_columns));
280 } else {
281 return normal(a: m_vertices.at(i: p), b: m_vertices.at(i: p - m_columns),
282 c: m_vertices.at(i: p - 1));
283 }
284 } else if (m_dataDimension == ZDescending) {
285 if (x < m_columns - 1) {
286 return normal(a: m_vertices.at(i: p), b: m_vertices.at(i: p + m_columns),
287 c: m_vertices.at(i: p + 1));
288 } else {
289 return normal(a: m_vertices.at(i: p), b: m_vertices.at(i: p - 1),
290 c: m_vertices.at(i: p + m_columns));
291 }
292 } else { // BothDescending
293 if (x == 0) {
294 return normal(a: m_vertices.at(i: 0), b: m_vertices.at(i: 1),
295 c: m_vertices.at(i: m_columns));
296 } else {
297 return normal(a: m_vertices.at(i: p), b: m_vertices.at(i: p + m_columns),
298 c: m_vertices.at(i: p - 1));
299 }
300 }
301}
302
303void SurfaceObject::smoothUVs(const QSurfaceDataArray &dataArray,
304 const QSurfaceDataArray &modelArray)
305{
306 if (dataArray.size() == 0 || modelArray.size() == 0)
307 return;
308
309 int columns = dataArray.at(i: 0)->size();
310 int rows = dataArray.size();
311 float xRangeNormalizer = dataArray.at(i: 0)->at(i: columns - 1).x() - dataArray.at(i: 0)->at(i: 0).x();
312 float zRangeNormalizer = dataArray.at(i: rows - 1)->at(i: 0).z() - dataArray.at(i: 0)->at(i: 0).z();
313 float xMin = dataArray.at(i: 0)->at(i: 0).x();
314 float zMin = dataArray.at(i: 0)->at(i: 0).z();
315 const bool zDescending = m_dataDimension.testFlag(flag: SurfaceObject::ZDescending);
316 const bool xDescending = m_dataDimension.testFlag(flag: SurfaceObject::XDescending);
317
318 QVector<QVector2D> uvs;
319 uvs.resize(asize: m_rows * m_columns);
320 int index = 0;
321 for (int i = 0; i < m_rows; i++) {
322 float y = (modelArray.at(i)->at(i: 0).z() - zMin) / zRangeNormalizer;
323 if (zDescending)
324 y = 1.0f - y;
325 const QSurfaceDataRow &p = *modelArray.at(i);
326 for (int j = 0; j < m_columns; j++) {
327 float x = (p.at(i: j).x() - xMin) / xRangeNormalizer;
328 if (xDescending)
329 x = 1.0f - x;
330 uvs[index] = QVector2D(x, y);
331 index++;
332 }
333 }
334
335 if (uvs.size() > 0) {
336 glBindBuffer(GL_ARRAY_BUFFER, buffer: m_uvTextureBuffer);
337 glBufferData(GL_ARRAY_BUFFER, size: uvs.size() * sizeof(QVector2D),
338 data: &uvs.at(i: 0), GL_STATIC_DRAW);
339 glBindBuffer(GL_ARRAY_BUFFER, buffer: 0);
340
341 m_returnTextureBuffer = true;
342 }
343}
344
345void SurfaceObject::updateSmoothRow(const QSurfaceDataArray &dataArray, int rowIndex, bool polar)
346{
347 // Update vertices
348 int p = rowIndex * m_columns;
349 const QSurfaceDataRow &dataRow = *dataArray.at(i: rowIndex);
350
351 for (int j = 0; j < m_columns; j++)
352 getNormalizedVertex(data: dataRow.at(i: j), vertex&: m_vertices[p++], polar, flipXZ: false);
353
354 // Create normals
355 bool upwards = (m_dataDimension == BothAscending) || (m_dataDimension == XDescending);
356 int startRow = rowIndex;
357 if ((startRow > 0) && upwards)
358 startRow--;
359 int endRow = rowIndex;
360 if (!upwards && (rowIndex < m_rows - 1))
361 endRow++;
362 if ((endRow == m_rows - 1) && upwards)
363 endRow--;
364 int totalIndex = startRow * m_columns;
365
366 if ((startRow == 0) && !upwards) {
367 createSmoothNormalUpperLine(totalIndex);
368 startRow++;
369 }
370
371 for (int row = startRow; row <= endRow; row++)
372 createSmoothNormalBodyLine(totalIndex, column: row * m_columns);
373
374 if ((rowIndex == m_rows - 1) && upwards)
375 createSmoothNormalUpperLine(totalIndex);
376}
377
378void SurfaceObject::updateSmoothItem(const QSurfaceDataArray &dataArray, int row, int column,
379 bool polar)
380{
381 // Update a vertice
382 getNormalizedVertex(data: dataArray.at(i: row)->at(i: column),
383 vertex&: m_vertices[row * m_columns + column], polar, flipXZ: false);
384
385 // Create normals
386 bool upwards = (m_dataDimension == BothAscending) || (m_dataDimension == XDescending);
387 bool rightwards = (m_dataDimension == BothAscending) || (m_dataDimension == ZDescending);
388 int startRow = row;
389 if ((startRow > 0) && upwards)
390 startRow--;
391 int endRow = row;
392 if (!upwards && (row < m_rows - 1))
393 endRow++;
394 if ((endRow == m_rows - 1) && upwards)
395 endRow--;
396 int startCol = column;
397 if ((startCol > 0) && rightwards)
398 startCol--;
399 int endCol = column;
400 if ((endCol < m_columns - 1) && !rightwards)
401 endCol++;
402
403 for (int i = startRow; i <= endRow; i++) {
404 for (int j = startCol; j <= endCol; j++) {
405 int p = i * m_columns + j;
406 if ((i == 0) && !upwards)
407 m_normals[p] = createSmoothNormalUpperLineItem(x: j, y: i);
408 else if ((i == m_rows - 1) && upwards)
409 m_normals[p] = createSmoothNormalUpperLineItem(x: j, y: i);
410 else
411 m_normals[p] = createSmoothNormalBodyLineItem(x: j, y: i);
412 }
413 }
414}
415
416
417void SurfaceObject::createSmoothIndices(int x, int y, int endX, int endY)
418{
419 if (endX >= m_columns)
420 endX = m_columns - 1;
421 if (endY >= m_rows)
422 endY = m_rows - 1;
423 if (x > endX)
424 x = endX - 1;
425 if (y > endY)
426 y = endY - 1;
427
428 m_indexCount = 6 * (endX - x) * (endY - y);
429 GLint *indices = new GLint[m_indexCount];
430 int p = 0;
431 int rowEnd = endY * m_columns;
432 for (int row = y * m_columns; row < rowEnd; row += m_columns) {
433 for (int j = x; j < endX; j++) {
434 if ((m_dataDimension == BothAscending) || (m_dataDimension == BothDescending)) {
435 // Left triangle
436 indices[p++] = row + j + 1;
437 indices[p++] = row + m_columns + j;
438 indices[p++] = row + j;
439
440 // Right triangle
441 indices[p++] = row + m_columns + j + 1;
442 indices[p++] = row + m_columns + j;
443 indices[p++] = row + j + 1;
444 } else if (m_dataDimension == XDescending) {
445 // Right triangle
446 indices[p++] = row + m_columns + j;
447 indices[p++] = row + m_columns + j + 1;
448 indices[p++] = row + j;
449
450 // Left triangle
451 indices[p++] = row + j;
452 indices[p++] = row + m_columns + j + 1;
453 indices[p++] = row + j + 1;
454 } else {
455 // Left triangle
456 indices[p++] = row + m_columns + j;
457 indices[p++] = row + m_columns + j + 1;
458 indices[p++] = row + j;
459
460 // Right triangle
461 indices[p++] = row + j;
462 indices[p++] = row + m_columns + j + 1;
463 indices[p++] = row + j + 1;
464
465 }
466 }
467 }
468
469 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer: m_elementbuffer);
470 glBufferData(GL_ELEMENT_ARRAY_BUFFER, size: m_indexCount * sizeof(GLint),
471 data: indices, GL_STATIC_DRAW);
472
473 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer: 0);
474
475 delete[] indices;
476}
477
478void SurfaceObject::createSmoothGridlineIndices(int x, int y, int endX, int endY)
479{
480 if (endX >= m_columns)
481 endX = m_columns - 1;
482 if (endY >= m_rows)
483 endY = m_rows - 1;
484 if (x > endX)
485 x = endX - 1;
486 if (y > endY)
487 y = endY - 1;
488
489 int nColumns = endX - x + 1;
490 int nRows = endY - y + 1;
491 m_gridIndexCount = 2 * nColumns * (nRows - 1) + 2 * nRows * (nColumns - 1);
492 GLint *gridIndices = new GLint[m_gridIndexCount];
493 int p = 0;
494 for (int i = y, row = m_columns * y; i <= endY; i++, row += m_columns) {
495 for (int j = x; j < endX; j++) {
496 gridIndices[p++] = row + j;
497 gridIndices[p++] = row + j + 1;
498 }
499 }
500 for (int i = y, row = m_columns * y; i < endY; i++, row += m_columns) {
501 for (int j = x; j <= endX; j++) {
502 gridIndices[p++] = row + j;
503 gridIndices[p++] = row + j + m_columns;
504 }
505 }
506
507 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer: m_gridElementbuffer);
508 glBufferData(GL_ELEMENT_ARRAY_BUFFER, size: m_gridIndexCount * sizeof(GLint),
509 data: gridIndices, GL_STATIC_DRAW);
510
511 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer: 0);
512
513 delete[] gridIndices;
514}
515
516void SurfaceObject::setUpData(const QSurfaceDataArray &dataArray, const QRect &space,
517 bool changeGeometry, bool polar, bool flipXZ)
518{
519 m_columns = space.width();
520 m_rows = space.height();
521 int totalSize = m_rows * m_columns * 2;
522 GLfloat uvX = 1.0f / GLfloat(m_columns - 1);
523 GLfloat uvY = 1.0f / GLfloat(m_rows - 1);
524
525 checkDirections(array: dataArray);
526 bool indicesDirty = false;
527 if (m_dataDimension != m_oldDataDimension)
528 indicesDirty = true;
529 m_oldDataDimension = m_dataDimension;
530
531 m_surfaceType = SurfaceFlat;
532
533 // Create vertix table
534 if (changeGeometry)
535 m_vertices.resize(asize: totalSize);
536
537 QVector<QVector2D> uvs;
538 if (changeGeometry)
539 uvs.resize(asize: totalSize);
540
541 int totalIndex = 0;
542 int rowLimit = m_rows - 1;
543 int colLimit = m_columns - 1;
544 int doubleColumns = m_columns * 2 - 2;
545 int rowColLimit = rowLimit * doubleColumns;
546
547 // Init min and max to ridiculous values
548 m_minY = 10000000.0;
549 m_maxY = -10000000.0f;
550
551 for (int i = 0; i < m_rows; i++) {
552 const QSurfaceDataRow &row = *dataArray.at(i);
553 for (int j = 0; j < m_columns; j++) {
554 getNormalizedVertex(data: row.at(i: j), vertex&: m_vertices[totalIndex], polar, flipXZ);
555 if (changeGeometry)
556 uvs[totalIndex] = QVector2D(GLfloat(j) * uvX, GLfloat(i) * uvY);
557
558 totalIndex++;
559
560 if (j > 0 && j < colLimit) {
561 m_vertices[totalIndex] = m_vertices[totalIndex - 1];
562 if (changeGeometry)
563 uvs[totalIndex] = uvs[totalIndex - 1];
564 totalIndex++;
565 }
566 }
567 }
568
569 if (flipXZ) {
570 for (int i = 0; i < m_vertices.size(); i++) {
571 m_vertices[i].setX(-m_vertices.at(i).x());
572 m_vertices[i].setZ(-m_vertices.at(i).z());
573 }
574 }
575
576 // Create normals & indices table
577 GLint *indices = 0;
578 if (changeGeometry || indicesDirty) {
579 int normalCount = 2 * colLimit * rowLimit;
580 m_indexCount = 3 * normalCount;
581 indices = new GLint[m_indexCount];
582 m_normals.resize(asize: normalCount);
583 }
584
585 int p = 0;
586 totalIndex = 0;
587 for (int row = 0, upperRow = doubleColumns;
588 row < rowColLimit;
589 row += doubleColumns, upperRow += doubleColumns) {
590 for (int j = 0; j < doubleColumns; j += 2) {
591 createNormals(p&: totalIndex, row, upperRow, j);
592
593 if (changeGeometry || indicesDirty) {
594 createCoarseIndices(indices, p, row, upperRow, j);
595 }
596 }
597 }
598
599 // Create grid line element indices
600 if (changeGeometry)
601 createCoarseGridlineIndices(x: 0, y: 0, endX: colLimit, endY: rowLimit);
602
603 createBuffers(vertices: m_vertices, uvs, normals: m_normals, indices);
604
605 delete[] indices;
606}
607
608void SurfaceObject::coarseUVs(const QSurfaceDataArray &dataArray,
609 const QSurfaceDataArray &modelArray)
610{
611 if (dataArray.size() == 0 || modelArray.size() == 0)
612 return;
613
614 int columns = dataArray.at(i: 0)->size();
615 int rows = dataArray.size();
616 float xRangeNormalizer = dataArray.at(i: 0)->at(i: columns - 1).x() - dataArray.at(i: 0)->at(i: 0).x();
617 float zRangeNormalizer = dataArray.at(i: rows - 1)->at(i: 0).z() - dataArray.at(i: 0)->at(i: 0).z();
618 float xMin = dataArray.at(i: 0)->at(i: 0).x();
619 float zMin = dataArray.at(i: 0)->at(i: 0).z();
620 const bool zDescending = m_dataDimension.testFlag(flag: SurfaceObject::ZDescending);
621 const bool xDescending = m_dataDimension.testFlag(flag: SurfaceObject::XDescending);
622
623 QVector<QVector2D> uvs;
624 uvs.resize(asize: m_rows * m_columns * 2);
625 int index = 0;
626 int colLimit = m_columns - 1;
627 for (int i = 0; i < m_rows; i++) {
628 float y = (modelArray.at(i)->at(i: 0).z() - zMin) / zRangeNormalizer;
629 if (zDescending)
630 y = 1.0f - y;
631 const QSurfaceDataRow &p = *modelArray.at(i);
632 for (int j = 0; j < m_columns; j++) {
633 float x = (p.at(i: j).x() - xMin) / xRangeNormalizer;
634 if (xDescending)
635 x = 1.0f - x;
636 uvs[index] = QVector2D(x, y);
637 index++;
638 if (j > 0 && j < colLimit) {
639 uvs[index] = uvs[index - 1];
640 index++;
641 }
642 }
643 }
644
645 if (uvs.size() > 0) {
646 glBindBuffer(GL_ARRAY_BUFFER, buffer: m_uvTextureBuffer);
647 glBufferData(GL_ARRAY_BUFFER, size: uvs.size() * sizeof(QVector2D),
648 data: &uvs.at(i: 0), GL_STATIC_DRAW);
649 glBindBuffer(GL_ARRAY_BUFFER, buffer: 0);
650
651 m_returnTextureBuffer = true;
652 }
653}
654
655void SurfaceObject::updateCoarseRow(const QSurfaceDataArray &dataArray, int rowIndex, bool polar)
656{
657 int colLimit = m_columns - 1;
658 int doubleColumns = m_columns * 2 - 2;
659
660 int p = rowIndex * doubleColumns;
661 const QSurfaceDataRow &dataRow = *dataArray.at(i: rowIndex);
662
663 for (int j = 0; j < m_columns; j++) {
664 getNormalizedVertex(data: dataRow.at(i: j), vertex&: m_vertices[p++], polar, flipXZ: false);
665 if (j > 0 && j < colLimit) {
666 m_vertices[p] = m_vertices[p - 1];
667 p++;
668 }
669 }
670
671 // Create normals
672 p = rowIndex * doubleColumns;
673 if (p > 0)
674 p -= doubleColumns;
675 int rowLimit = (rowIndex + 1) * doubleColumns;
676 if (rowIndex == m_rows - 1)
677 rowLimit = rowIndex * doubleColumns; //Topmost row, no normals
678 for (int row = p, upperRow = p + doubleColumns;
679 row < rowLimit;
680 row += doubleColumns, upperRow += doubleColumns) {
681 for (int j = 0; j < doubleColumns; j += 2)
682 createNormals(p, row, upperRow, j);
683 }
684}
685
686void SurfaceObject::updateCoarseItem(const QSurfaceDataArray &dataArray, int row, int column,
687 bool polar)
688{
689 int colLimit = m_columns - 1;
690 int doubleColumns = m_columns * 2 - 2;
691
692 // Update a vertice
693 int p = row * doubleColumns + column * 2 - (column > 0);
694 getNormalizedVertex(data: dataArray.at(i: row)->at(i: column), vertex&: m_vertices[p++], polar, flipXZ: false);
695
696 if (column > 0 && column < colLimit)
697 m_vertices[p] = m_vertices[p - 1];
698
699 // Create normals
700 int startRow = row;
701 if (startRow > 0)
702 startRow--; // Change the normal for previous row also
703 int startCol = column;
704 if (startCol > 0)
705 startCol--;
706 if (row == m_rows - 1)
707 row--;
708 if (column == m_columns - 1)
709 column--;
710
711 for (int i = startRow; i <= row; i++) {
712 for (int j = startCol; j <= column; j++) {
713 p = i * doubleColumns + j * 2;
714 createNormals(p, row: i * doubleColumns, upperRow: (i + 1) * doubleColumns, j: j * 2);
715 }
716 }
717}
718
719void SurfaceObject::createCoarseSubSection(int x, int y, int columns, int rows)
720{
721 if (columns > m_columns)
722 columns = m_columns;
723 if (rows > m_rows)
724 rows = m_rows;
725 if (x > columns)
726 x = columns - 1;
727 if (y > rows)
728 y = rows - 1;
729
730 int rowLimit = rows - 1;
731 int doubleColumns = m_columns * 2 - 2;
732 int doubleColumnsLimit = columns * 2 - 2;
733 int rowColLimit = rowLimit * doubleColumns;
734 m_indexCount = 6 * (columns - 1 - x) * (rowLimit - y);
735
736 int p = 0;
737 GLint *indices = new GLint[m_indexCount];
738 for (int row = y * doubleColumns, upperRow = (y + 1) * doubleColumns;
739 row < rowColLimit;
740 row += doubleColumns, upperRow += doubleColumns) {
741 for (int j = 2 * x; j < doubleColumnsLimit; j += 2)
742 createCoarseIndices(indices, p, row, upperRow, j);
743 }
744
745 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer: m_elementbuffer);
746 glBufferData(GL_ELEMENT_ARRAY_BUFFER, size: m_indexCount * sizeof(GLint),
747 data: indices, GL_STATIC_DRAW);
748
749 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer: 0);
750
751 delete[] indices;
752}
753
754void SurfaceObject::createCoarseGridlineIndices(int x, int y, int endX, int endY)
755{
756 if (endX >= m_columns)
757 endX = m_columns - 1;
758 if (endY >= m_rows)
759 endY = m_rows - 1;
760 if (x > endX)
761 x = endX - 1;
762 if (y > endY)
763 y = endY - 1;
764
765 int nColumns = endX - x + 1;
766 int nRows = endY - y + 1;
767 int doubleEndX = endX * 2;
768 int doubleColumns = m_columns * 2 - 2;
769 int rowColLimit = endY * doubleColumns;
770
771 m_gridIndexCount = 2 * nColumns * (nRows - 1) + 2 * nRows * (nColumns - 1);
772 GLint *gridIndices = new GLint[m_gridIndexCount];
773 int p = 0;
774
775 for (int row = y * doubleColumns; row <= rowColLimit; row += doubleColumns) {
776 for (int j = x * 2; j < doubleEndX; j += 2) {
777 // Horizontal line
778 gridIndices[p++] = row + j;
779 gridIndices[p++] = row + j + 1;
780
781 if (row < rowColLimit) {
782 // Vertical line
783 gridIndices[p++] = row + j;
784 gridIndices[p++] = row + j + doubleColumns;
785 }
786 }
787 }
788 // The rightmost line separately, since there isn't double vertice
789 for (int i = y * doubleColumns + doubleEndX - 1; i < rowColLimit; i += doubleColumns) {
790 gridIndices[p++] = i;
791 gridIndices[p++] = i + doubleColumns;
792 }
793
794 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer: m_gridElementbuffer);
795 glBufferData(GL_ELEMENT_ARRAY_BUFFER, size: m_gridIndexCount * sizeof(GLint),
796 data: gridIndices, GL_STATIC_DRAW);
797
798 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer: 0);
799
800 delete[] gridIndices;
801}
802
803void SurfaceObject::uploadBuffers()
804{
805 QVector<QVector2D> uvs; // Empty dummy
806 createBuffers(vertices: m_vertices, uvs, normals: m_normals, indices: 0);
807}
808
809void SurfaceObject::createBuffers(const QVector<QVector3D> &vertices, const QVector<QVector2D> &uvs,
810 const QVector<QVector3D> &normals, const GLint *indices)
811{
812 // Move to buffers
813 glBindBuffer(GL_ARRAY_BUFFER, buffer: m_vertexbuffer);
814 glBufferData(GL_ARRAY_BUFFER, size: vertices.size() * sizeof(QVector3D),
815 data: &vertices.at(i: 0), GL_DYNAMIC_DRAW);
816
817 glBindBuffer(GL_ARRAY_BUFFER, buffer: m_normalbuffer);
818 glBufferData(GL_ARRAY_BUFFER, size: normals.size() * sizeof(QVector3D),
819 data: &normals.at(i: 0), GL_DYNAMIC_DRAW);
820
821 if (uvs.size()) {
822 glBindBuffer(GL_ARRAY_BUFFER, buffer: m_uvbuffer);
823 glBufferData(GL_ARRAY_BUFFER, size: uvs.size() * sizeof(QVector2D),
824 data: &uvs.at(i: 0), GL_STATIC_DRAW);
825 }
826
827 if (indices) {
828 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer: m_elementbuffer);
829 glBufferData(GL_ELEMENT_ARRAY_BUFFER, size: m_indexCount * sizeof(GLint),
830 data: indices, GL_STATIC_DRAW);
831 }
832
833 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer: 0);
834 glBindBuffer(GL_ARRAY_BUFFER, buffer: 0);
835
836 m_meshDataLoaded = true;
837}
838
839void SurfaceObject::checkDirections(const QSurfaceDataArray &array)
840{
841 m_dataDimension = BothAscending;
842
843 if (array.at(i: 0)->at(i: 0).x() > array.at(i: 0)->at(i: array.at(i: 0)->size() - 1).x())
844 m_dataDimension |= XDescending;
845 if (m_axisCacheX.reversed())
846 m_dataDimension ^= XDescending;
847
848 if (array.at(i: 0)->at(i: 0).z() > array.at(i: array.size() - 1)->at(i: 0).z())
849 m_dataDimension |= ZDescending;
850 if (m_axisCacheZ.reversed())
851 m_dataDimension ^= ZDescending;
852}
853
854void SurfaceObject::getNormalizedVertex(const QSurfaceDataItem &data, QVector3D &vertex,
855 bool polar, bool flipXZ)
856{
857 float normalizedX;
858 float normalizedZ;
859 if (polar) {
860 // Slice don't use polar, so don't care about flip
861 m_renderer->calculatePolarXZ(dataPos: data.position(), x&: normalizedX, z&: normalizedZ);
862 } else {
863 if (flipXZ) {
864 normalizedX = m_axisCacheZ.positionAt(value: data.x());
865 normalizedZ = m_axisCacheX.positionAt(value: data.z());
866 } else {
867 normalizedX = m_axisCacheX.positionAt(value: data.x());
868 normalizedZ = m_axisCacheZ.positionAt(value: data.z());
869 }
870 }
871 float normalizedY = m_axisCacheY.positionAt(value: data.y());
872 m_minY = qMin(a: normalizedY, b: m_minY);
873 m_maxY = qMax(a: normalizedY, b: m_maxY);
874 vertex.setX(normalizedX);
875 vertex.setY(normalizedY);
876 vertex.setZ(normalizedZ);
877}
878
879GLuint SurfaceObject::gridElementBuf()
880{
881 if (!m_meshDataLoaded)
882 qFatal(msg: "No loaded object");
883 return m_gridElementbuffer;
884}
885
886GLuint SurfaceObject::uvBuf()
887{
888 if (!m_meshDataLoaded)
889 qFatal(msg: "No loaded object");
890
891 if (m_returnTextureBuffer)
892 return m_uvTextureBuffer;
893 else
894 return m_uvbuffer;
895}
896
897GLuint SurfaceObject::gridIndexCount()
898{
899 return m_gridIndexCount;
900}
901
902QVector3D SurfaceObject::vertexAt(int column, int row)
903{
904 int pos = 0;
905 if (m_surfaceType == Undefined || !m_vertices.size())
906 return zeroVector;
907
908 if (m_surfaceType == SurfaceFlat)
909 pos = row * (m_columns * 2 - 2) + column * 2 - (column > 0);
910 else
911 pos = row * m_columns + column;
912 return m_vertices.at(i: pos);
913}
914
915void SurfaceObject::clear()
916{
917 m_gridIndexCount = 0;
918 m_indexCount = 0;
919 m_surfaceType = Undefined;
920 m_vertices.clear();
921 m_normals.clear();
922}
923
924void SurfaceObject::createCoarseIndices(GLint *indices, int &p, int row, int upperRow, int j)
925{
926 if ((m_dataDimension == BothAscending) || (m_dataDimension == BothDescending)) {
927 // Left triangle
928 indices[p++] = row + j + 1;
929 indices[p++] = upperRow + j;
930 indices[p++] = row + j;
931
932 // Right triangle
933 indices[p++] = upperRow + j + 1;
934 indices[p++] = upperRow + j;
935 indices[p++] = row + j + 1;
936 } else if (m_dataDimension == XDescending) {
937 indices[p++] = upperRow + j;
938 indices[p++] = upperRow + j + 1;
939 indices[p++] = row + j;
940
941 indices[p++] = row + j;
942 indices[p++] = upperRow + j + 1;
943 indices[p++] = row + j + 1;
944 } else {
945 // Left triangle
946 indices[p++] = upperRow + j;
947 indices[p++] = upperRow + j + 1;
948 indices[p++] = row + j;
949
950 // Right triangle
951 indices[p++] = row + j;
952 indices[p++] = upperRow + j + 1;
953 indices[p++] = row + j + 1;
954 }
955}
956
957void SurfaceObject::createNormals(int &p, int row, int upperRow, int j)
958{
959 if ((m_dataDimension == BothAscending) || (m_dataDimension == BothDescending)) {
960 m_normals[p++] = normal(a: m_vertices.at(i: row + j),
961 b: m_vertices.at(i: row + j + 1),
962 c: m_vertices.at(i: upperRow + j));
963
964 m_normals[p++] = normal(a: m_vertices.at(i: row + j + 1),
965 b: m_vertices.at(i: upperRow + j + 1),
966 c: m_vertices.at(i: upperRow + j));
967 } else if (m_dataDimension == XDescending) {
968 m_normals[p++] = normal(a: m_vertices.at(i: row + j),
969 b: m_vertices.at(i: upperRow + j),
970 c: m_vertices.at(i: upperRow + j + 1));
971
972 m_normals[p++] = normal(a: m_vertices.at(i: row + j + 1),
973 b: m_vertices.at(i: row + j),
974 c: m_vertices.at(i: upperRow + j + 1));
975 } else {
976 m_normals[p++] = normal(a: m_vertices.at(i: row + j),
977 b: m_vertices.at(i: upperRow + j),
978 c: m_vertices.at(i: upperRow + j + 1));
979
980 m_normals[p++] = normal(a: m_vertices.at(i: row + j + 1),
981 b: m_vertices.at(i: row + j),
982 c: m_vertices.at(i: upperRow + j + 1));
983 }
984}
985
986QVector3D SurfaceObject::normal(const QVector3D &a, const QVector3D &b, const QVector3D &c)
987{
988 QVector3D v1 = b - a;
989 QVector3D v2 = c - a;
990 QVector3D normal = QVector3D::crossProduct(v1, v2);
991
992 return normal;
993}
994
995QT_END_NAMESPACE_DATAVISUALIZATION
996

source code of qtdatavis3d/src/datavisualization/utils/surfaceobject.cpp