1// Copyright (C) 2015 Paul Lemire paul.lemire350@gmail.com
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "trianglesvisitor_p.h"
5#include <Qt3DCore/qentity.h>
6#include <Qt3DRender/qgeometryrenderer.h>
7#include <Qt3DRender/private/managers_p.h>
8#include <Qt3DRender/private/nodemanagers_p.h>
9#include <Qt3DRender/private/buffermanager_p.h>
10#include <Qt3DRender/private/pickingproxy_p.h>
11#include <Qt3DRender/private/geometryrenderer_p.h>
12#include <Qt3DRender/private/geometryrenderermanager_p.h>
13#include <Qt3DRender/private/geometry_p.h>
14#include <Qt3DRender/private/attribute_p.h>
15#include <Qt3DRender/private/buffer_p.h>
16#include <Qt3DRender/private/visitorutils_p.h>
17#include <Qt3DRender/private/bufferutils_p.h>
18
19QT_BEGIN_NAMESPACE
20
21using namespace Qt3DCore;
22
23namespace Qt3DRender {
24
25namespace Render {
26
27namespace {
28
29bool isTriangleBased(Qt3DRender::QGeometryRenderer::PrimitiveType type) noexcept
30{
31 switch (type) {
32 case Qt3DRender::QGeometryRenderer::Triangles:
33 case Qt3DRender::QGeometryRenderer::TriangleStrip:
34 case Qt3DRender::QGeometryRenderer::TriangleFan:
35 case Qt3DRender::QGeometryRenderer::TrianglesAdjacency:
36 case Qt3DRender::QGeometryRenderer::TriangleStripAdjacency:
37 return true;
38 default:
39 return false;
40 }
41}
42
43// TO DO: Add methods for triangle strip adjacency
44// What about primitive restart ?
45
46// indices, vertices are already offset
47template<typename index, typename vertex>
48void traverseTrianglesIndexed(index *indices,
49 vertex *vertices,
50 const BufferInfo &indexInfo,
51 const BufferInfo &vertexInfo,
52 TrianglesVisitor* visitor)
53{
54 uint i = 0;
55 const uint maxVerticesDataSize = qMin(a: vertexInfo.dataSize, b: 3U);
56 const uint verticesStride = vertexInfo.byteStride ? vertexInfo.byteStride / sizeof(vertex) : maxVerticesDataSize;
57
58 uint ndx[3];
59 Vector3D abc[3];
60 while (i < indexInfo.count) {
61 for (uint u = 0; u < 3; ++u) {
62 ndx[u] = indices[i + u];
63 uint idx = ndx[u] * verticesStride;
64 for (uint j = 0; j < maxVerticesDataSize; ++j) {
65 abc[u][j] = vertices[idx + j];
66 }
67 }
68 visitor->visit(andx: ndx[2], a: abc[2], bndx: ndx[1], b: abc[1], cndx: ndx[0], c: abc[0]);
69 i += 3;
70 }
71}
72
73// vertices are already offset
74template<typename vertex>
75void traverseTriangles(vertex *vertices,
76 const BufferInfo &vertexInfo,
77 TrianglesVisitor* visitor)
78{
79 uint i = 0;
80
81 const uint maxVerticesDataSize = qMin(a: vertexInfo.dataSize, b: 3U);
82 const uint verticesStride = vertexInfo.byteStride ? vertexInfo.byteStride / sizeof(vertex) : maxVerticesDataSize;
83
84 uint ndx[3];
85 Vector3D abc[3];
86 while (i < vertexInfo.count) {
87 for (uint u = 0; u < 3; ++u) {
88 ndx[u] = (i + u);
89 uint idx = ndx[u] * verticesStride;
90 for (uint j = 0; j < maxVerticesDataSize; ++j) {
91 abc[u][j] = vertices[idx + j];
92 }
93 }
94 visitor->visit(andx: ndx[2], a: abc[2], bndx: ndx[1], b: abc[1], cndx: ndx[0], c: abc[0]);
95 i += 3;
96 }
97}
98
99static inline bool checkDegenerate(const uint ndx[3], const uint idx, const uint u)
100{
101 for (uint j = 0; j < u; ++j) {
102 if (idx == ndx[j])
103 return true;
104 }
105 return false;
106}
107
108// indices, vertices are already offset
109template<typename index, typename vertex>
110void traverseTriangleStripIndexed(index *indices,
111 vertex *vertices,
112 const BufferInfo &indexInfo,
113 const BufferInfo &vertexInfo,
114 TrianglesVisitor* visitor)
115{
116 uint i = 0;
117 const uint maxVerticesDataSize = qMin(a: vertexInfo.dataSize, b: 3U);
118 const uint verticesStride = vertexInfo.byteStride ? vertexInfo.byteStride / sizeof(vertex) : maxVerticesDataSize;
119
120 uint ndx[3];
121 Vector3D abc[3];
122 while (i < indexInfo.count - 2) {
123 if (indexInfo.restartEnabled && indexInfo.restartIndexValue == static_cast<int>(indices[i + 2])) {
124 i += 3;
125 continue;
126 }
127 bool degenerate = false;
128 for (uint u = 0; u < 3; ++u) {
129 ndx[u] = indices[i + u];
130 if (checkDegenerate(ndx, idx: ndx[u], u)) {
131 degenerate = true;
132 break;
133 }
134 uint idx = ndx[u] * verticesStride;
135 for (uint j = 0; j < maxVerticesDataSize; ++j)
136 abc[u][j] = vertices[idx + j];
137 }
138 if (!degenerate)
139 visitor->visit(andx: ndx[2], a: abc[2], bndx: ndx[1], b: abc[1], cndx: ndx[0], c: abc[0]);
140 ++i;
141 }
142}
143
144// vertices are already offset
145template<typename vertex>
146void traverseTriangleStrip(vertex *vertices,
147 const BufferInfo &vertexInfo,
148 TrianglesVisitor* visitor)
149{
150 uint i = 0;
151
152 const uint maxVerticesDataSize = qMin(a: vertexInfo.dataSize, b: 3U);
153 const uint verticesStride = vertexInfo.byteStride ? vertexInfo.byteStride / sizeof(vertex) : maxVerticesDataSize;
154
155 uint ndx[3];
156 Vector3D abc[3];
157 while (i < vertexInfo.count - 2) {
158 for (uint u = 0; u < 3; ++u) {
159 ndx[u] = (i + u);
160 uint idx = ndx[u] * verticesStride;
161 for (uint j = 0; j < maxVerticesDataSize; ++j) {
162 abc[u][j] = vertices[idx + j];
163 }
164 }
165 visitor->visit(andx: ndx[2], a: abc[2], bndx: ndx[1], b: abc[1], cndx: ndx[0], c: abc[0]);
166 ++i;
167 }
168}
169
170// indices, vertices are already offset
171template<typename index, typename vertex>
172void traverseTriangleFanIndexed(index *indices,
173 vertex *vertices,
174 const BufferInfo &indexInfo,
175 const BufferInfo &vertexInfo,
176 TrianglesVisitor* visitor)
177{
178 const uint maxVerticesDataSize = qMin(a: vertexInfo.dataSize, b: 3U);
179 const uint verticesStride = vertexInfo.byteStride ? vertexInfo.byteStride / sizeof(vertex) : maxVerticesDataSize;
180
181 uint ndx[3];
182 Vector3D abc[3];
183
184 for (uint j = 0; j < maxVerticesDataSize; ++j) {
185 abc[0][j] = vertices[static_cast<int>(indices[0]) * verticesStride + j];
186 }
187 ndx[0] = indices[0];
188 uint i = 1;
189 while (i < indexInfo.count - 1) {
190 if (indexInfo.restartEnabled && indexInfo.restartIndexValue == static_cast<int>(indices[i + 1])) {
191 ndx[0] = indices[i + 2];
192 i += 3;
193 continue;
194 }
195 for (uint u = 0; u < 2; ++u) {
196 ndx[u + 1] = indices[i + u];
197 uint idx = ndx[u + 1] * verticesStride;
198 for (uint j = 0; j < maxVerticesDataSize; ++j) {
199 abc[u + 1][j] = vertices[idx + j];
200 }
201 }
202 visitor->visit(andx: ndx[2], a: abc[2], bndx: ndx[1], b: abc[1], cndx: ndx[0], c: abc[0]);
203 ++i;
204 }
205}
206
207// vertices are already offset
208template<typename vertex>
209void traverseTriangleFan(vertex *vertices,
210 const BufferInfo &vertexInfo,
211 TrianglesVisitor* visitor)
212{
213 const uint maxVerticesDataSize = qMin(a: vertexInfo.dataSize, b: 3U);
214 const uint verticesStride = vertexInfo.byteStride ? vertexInfo.byteStride / sizeof(vertex) : maxVerticesDataSize;
215
216 uint ndx[3];
217 Vector3D abc[3];
218
219 for (uint j = 0; j < maxVerticesDataSize; ++j) {
220 abc[0][j] = vertices[j];
221 }
222 ndx[0] = 0;
223
224 uint i = 1;
225 while (i < vertexInfo.count - 1) {
226 for (uint u = 0; u < 2; ++u) {
227 ndx[u + 1] = (i + u);
228 uint idx = ndx[u + 1] * verticesStride;
229 for (uint j = 0; j < maxVerticesDataSize; ++j) {
230 abc[u + 1][j] = vertices[idx + j];
231 }
232 }
233 visitor->visit(andx: ndx[2], a: abc[2], bndx: ndx[1], b: abc[1], cndx: ndx[0], c: abc[0]);
234 i += 1;
235 }
236}
237
238// indices, vertices are already offset
239template<typename index, typename vertex>
240void traverseTriangleAdjacencyIndexed(index *indices,
241 vertex *vertices,
242 const BufferInfo &indexInfo,
243 const BufferInfo &vertexInfo,
244 TrianglesVisitor* visitor)
245{
246 uint i = 0;
247 const uint maxVerticesDataSize = qMin(a: vertexInfo.dataSize, b: 3U);
248 const uint verticesStride = vertexInfo.byteStride ? vertexInfo.byteStride / sizeof(vertex) : maxVerticesDataSize;
249
250 uint ndx[3];
251 Vector3D abc[3];
252 while (i < indexInfo.count) {
253 for (uint u = 0; u < 6; u += 2) {
254 ndx[u / 2] = indices[i + u];
255 uint idx = ndx[u / 2] * verticesStride;
256 for (uint j = 0; j < maxVerticesDataSize; ++j) {
257 abc[u / 2][j] = vertices[idx + j];
258 }
259 }
260 visitor->visit(andx: ndx[2], a: abc[2], bndx: ndx[1], b: abc[1], cndx: ndx[0], c: abc[0]);
261 i += 6;
262 }
263}
264
265// vertices are already offset
266template<typename Vertex>
267void traverseTriangleAdjacency(Vertex *vertices,
268 const BufferInfo &vertexInfo,
269 TrianglesVisitor* visitor)
270{
271 uint i = 0;
272
273 const uint maxVerticesDataSize = qMin(a: vertexInfo.dataSize, b: 3U);
274 const uint verticesStride = vertexInfo.byteStride ? vertexInfo.byteStride / sizeof(Vertex) : maxVerticesDataSize;
275
276 uint ndx[3];
277 Vector3D abc[3];
278 while (i < vertexInfo.count) {
279 for (uint u = 0; u < 6; u += 2) {
280 ndx[u / 2] = (i + u);
281 uint idx = ndx[u / 2] * verticesStride;
282 for (uint j = 0; j < maxVerticesDataSize; ++j) {
283 abc[u / 2][j] = vertices[idx + j];
284 }
285 }
286 visitor->visit(andx: ndx[2], a: abc[2], bndx: ndx[1], b: abc[1], cndx: ndx[0], c: abc[0]);
287 i += 6;
288 }
289}
290
291template<typename Coordinate>
292Vector4D readCoordinate(const BufferInfo &info, Coordinate *coordinates, uint index)
293{
294 const uint stride = info.byteStride ? info.byteStride / sizeof(Coordinate) : info.dataSize;
295 Vector4D ret(0, 0, 0, 1.0f);
296 coordinates += stride * index;
297 for (uint e = 0; e < info.dataSize; ++e)
298 ret[e] = coordinates[e];
299 return ret;
300}
301
302
303template <QAttribute::VertexBaseType> struct EnumToType;
304template <> struct EnumToType<QAttribute::Byte> { typedef const char type; };
305template <> struct EnumToType<QAttribute::UnsignedByte> { typedef const uchar type; };
306template <> struct EnumToType<QAttribute::Short> { typedef const short type; };
307template <> struct EnumToType<QAttribute::UnsignedShort> { typedef const ushort type; };
308template <> struct EnumToType<QAttribute::Int> { typedef const int type; };
309template <> struct EnumToType<QAttribute::UnsignedInt> { typedef const uint type; };
310template <> struct EnumToType<QAttribute::Float> { typedef const float type; };
311template <> struct EnumToType<QAttribute::Double> { typedef const double type; };
312
313template<QAttribute::VertexBaseType v>
314typename EnumToType<v>::type *castToType(const QByteArray &u, uint byteOffset)
315{
316 return reinterpret_cast< typename EnumToType<v>::type *>(u.constData() + byteOffset);
317}
318
319Vector4D readBuffer(const BufferInfo &info, uint index)
320{
321 switch (info.type) {
322 case QAttribute::Byte:
323 return readCoordinate(info, coordinates: BufferTypeInfo::castToType<QAttribute::Byte>(u: info.data, byteOffset: info.byteOffset), index);
324 case QAttribute::UnsignedByte:
325 return readCoordinate(info, coordinates: BufferTypeInfo::castToType<QAttribute::UnsignedByte>(u: info.data, byteOffset: info.byteOffset), index);
326 case QAttribute::Short:
327 return readCoordinate(info, coordinates: BufferTypeInfo::castToType<QAttribute::Short>(u: info.data, byteOffset: info.byteOffset), index);
328 case QAttribute::UnsignedShort:
329 return readCoordinate(info, coordinates: BufferTypeInfo::castToType<QAttribute::UnsignedShort>(u: info.data, byteOffset: info.byteOffset), index);
330 case QAttribute::Int:
331 return readCoordinate(info, coordinates: BufferTypeInfo::castToType<QAttribute::Int>(u: info.data, byteOffset: info.byteOffset), index);
332 case QAttribute::UnsignedInt:
333 return readCoordinate(info, coordinates: BufferTypeInfo::castToType<QAttribute::UnsignedInt>(u: info.data, byteOffset: info.byteOffset), index);
334 case QAttribute::Float:
335 return readCoordinate(info, coordinates: BufferTypeInfo::castToType<QAttribute::Float>(u: info.data, byteOffset: info.byteOffset), index);
336 case QAttribute::Double:
337 return readCoordinate(info, coordinates: BufferTypeInfo::castToType<QAttribute::Double>(u: info.data, byteOffset: info.byteOffset), index);
338 default:
339 break;
340 }
341 return Vector4D();
342}
343
344template<typename Index, typename Visitor>
345struct IndexedVertexExecutor
346{
347 template<typename Vertex>
348 void operator ()(const BufferInfo &vertexInfo, Vertex * vertices)
349 {
350 switch (m_primitiveType) {
351 case Qt3DRender::QGeometryRenderer::Triangles:
352 traverseTrianglesIndexed(m_indices, vertices, m_indexBufferInfo, vertexInfo, m_visitor);
353 return;
354 case Qt3DRender::QGeometryRenderer::TriangleStrip:
355 traverseTriangleStripIndexed(m_indices, vertices, m_indexBufferInfo, vertexInfo, m_visitor);
356 return;
357 case Qt3DRender::QGeometryRenderer::TriangleFan:
358 traverseTriangleFanIndexed(m_indices, vertices, m_indexBufferInfo, vertexInfo, m_visitor);
359 return;
360 case Qt3DRender::QGeometryRenderer::TrianglesAdjacency:
361 traverseTriangleAdjacencyIndexed(m_indices, vertices, m_indexBufferInfo, vertexInfo, m_visitor);
362 return;
363 case Qt3DRender::QGeometryRenderer::TriangleStripAdjacency: // fall through
364 default:
365 return;
366 }
367 }
368
369 BufferInfo m_indexBufferInfo;
370 Index *m_indices;
371 Qt3DRender::QGeometryRenderer::PrimitiveType m_primitiveType;
372 Visitor* m_visitor;
373};
374
375template<typename Visitor>
376struct IndexExecutor
377{
378 template<typename Index>
379 void operator ()( const BufferInfo &indexInfo, Index *indices)
380 {
381 IndexedVertexExecutor<Index, Visitor> exec;
382 exec.m_primitiveType = m_primitiveType;
383 exec.m_indices = indices;
384 exec.m_indexBufferInfo = indexInfo;
385 exec.m_visitor = m_visitor;
386 Qt3DRender::Render::Visitor::processBuffer(m_vertexBufferInfo, exec);
387 }
388
389 BufferInfo m_vertexBufferInfo;
390 Qt3DRender::QGeometryRenderer::PrimitiveType m_primitiveType;
391 Visitor* m_visitor;
392};
393
394template<typename Visitor>
395struct VertexExecutor
396{
397 template<typename Vertex>
398 void operator ()(const BufferInfo &vertexInfo, Vertex *vertices)
399 {
400 switch (m_primitiveType) {
401 case Qt3DRender::QGeometryRenderer::Triangles:
402 traverseTriangles(vertices, vertexInfo, m_visitor);
403 return;
404 case Qt3DRender::QGeometryRenderer::TriangleStrip:
405 traverseTriangleStrip(vertices, vertexInfo, m_visitor);
406 return;
407 case Qt3DRender::QGeometryRenderer::TriangleFan:
408 traverseTriangleFan(vertices, vertexInfo, m_visitor);
409 return;
410 case Qt3DRender::QGeometryRenderer::TrianglesAdjacency:
411 traverseTriangleAdjacency(vertices, vertexInfo, m_visitor);
412 return;
413 case Qt3DRender::QGeometryRenderer::TriangleStripAdjacency: // fall through
414 default:
415 return;
416 }
417 }
418
419 Qt3DRender::QGeometryRenderer::PrimitiveType m_primitiveType;
420 Visitor* m_visitor;
421};
422
423} // anonymous
424
425
426TrianglesVisitor::~TrianglesVisitor()
427{
428
429}
430
431void TrianglesVisitor::apply(const Qt3DCore::QEntity *entity)
432{
433 GeometryRenderer *renderer = m_manager->geometryRendererManager()->lookupResource(id: entity->id());
434 apply(renderer, id: entity->id());
435}
436
437void TrianglesVisitor::apply(const GeometryRenderer *renderer, const Qt3DCore::QNodeId id)
438{
439 m_nodeId = id;
440 if (renderer && renderer->instanceCount() == 1 && isTriangleBased(type: renderer->primitiveType())) {
441 Visitor::visitPrimitives<GeometryRenderer, VertexExecutor<TrianglesVisitor>,
442 IndexExecutor<TrianglesVisitor>, TrianglesVisitor>(manager: m_manager, renderer, visitor: this);
443 }
444}
445
446void TrianglesVisitor::apply(const PickingProxy *proxy, const QNodeId id)
447{
448 m_nodeId = id;
449 if (proxy && proxy->instanceCount() == 1 && isTriangleBased(type: static_cast<Qt3DRender::QGeometryRenderer::PrimitiveType>(proxy->primitiveType()))) {
450 Visitor::visitPrimitives<PickingProxy, VertexExecutor<TrianglesVisitor>,
451 IndexExecutor<TrianglesVisitor>, TrianglesVisitor>(manager: m_manager, renderer: proxy, visitor: this);
452 }
453}
454
455bool CoordinateReader::setGeometry(const GeometryRenderer *renderer, const QString &attributeName)
456{
457 if (renderer == nullptr || renderer->instanceCount() != 1
458 || !isTriangleBased(type: renderer->primitiveType())) {
459 return false;
460 }
461
462 Geometry *geom = m_manager->lookupResource<Geometry, GeometryManager>(id: renderer->geometryId());
463
464 if (!geom)
465 return false;
466
467 Attribute *attribute = nullptr;
468
469 const auto attrIds = geom->attributes();
470 for (const Qt3DCore::QNodeId &attrId : attrIds) {
471 attribute = m_manager->lookupResource<Attribute, AttributeManager>(id: attrId);
472 if (attribute){
473 if (attribute->name() == attributeName
474 || (attributeName == QStringLiteral("default")
475 && attribute->name() == QAttribute::defaultTextureCoordinateAttributeName())) {
476 break;
477 }
478 }
479 attribute = nullptr;
480 }
481
482 if (!attribute)
483 return false;
484
485 m_attribute = attribute;
486 m_buffer = m_manager->lookupResource<Buffer, BufferManager>(id: attribute->bufferId());
487
488 m_bufferInfo.data = m_buffer->data();
489 m_bufferInfo.type = m_attribute->vertexBaseType();
490 m_bufferInfo.byteOffset = m_attribute->byteOffset();
491 m_bufferInfo.byteStride = m_attribute->byteStride();
492 m_bufferInfo.dataSize = m_attribute->vertexSize();
493 m_bufferInfo.count = m_attribute->count();
494 return true;
495}
496
497Vector4D CoordinateReader::getCoordinate(uint vertexIndex)
498{
499 return readBuffer(info: m_bufferInfo, index: vertexIndex);
500}
501
502} // namespace Render
503
504} // namespace Qt3DRender
505
506QT_END_NAMESPACE
507

source code of qt3d/src/render/backend/trianglesvisitor.cpp