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

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