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

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