1// Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
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 "segmentsvisitor_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/geometryrenderer_p.h>
11#include <Qt3DRender/private/geometryrenderermanager_p.h>
12#include <Qt3DRender/private/geometry_p.h>
13#include <Qt3DRender/private/attribute_p.h>
14#include <Qt3DRender/private/buffer_p.h>
15#include <Qt3DRender/private/trianglesvisitor_p.h>
16#include <Qt3DRender/private/visitorutils_p.h>
17
18QT_BEGIN_NAMESPACE
19
20namespace Qt3DRender {
21
22namespace Render {
23
24namespace {
25
26bool isSegmentBased(Qt3DRender::QGeometryRenderer::PrimitiveType type) noexcept
27{
28 switch (type) {
29 case Qt3DRender::QGeometryRenderer::Lines:
30 case Qt3DRender::QGeometryRenderer::LineStrip:
31 case Qt3DRender::QGeometryRenderer::LineLoop:
32 case Qt3DRender::QGeometryRenderer::LinesAdjacency:
33 case Qt3DRender::QGeometryRenderer::LineStripAdjacency:
34 return true;
35 default:
36 return false;
37 }
38}
39
40// indices, vertices are already offset
41template<typename Index, typename Vertex>
42void traverseSegmentsIndexed(Index *indices,
43 Vertex *vertices,
44 const BufferInfo &indexInfo,
45 const BufferInfo &vertexInfo,
46 SegmentsVisitor *visitor)
47{
48 uint i = 0;
49 const uint verticesStride = vertexInfo.byteStride / sizeof(Vertex);
50 const uint maxVerticesDataSize = qMin(a: vertexInfo.dataSize, b: 3U);
51
52 uint ndx[2];
53 Vector3D abc[2];
54 while (i < indexInfo.count) {
55 for (uint u = 0; u < 2; ++u) {
56 ndx[u] = indices[i + u];
57 const uint idx = ndx[u] * verticesStride;
58 for (uint j = 0; j < maxVerticesDataSize; ++j) {
59 abc[u][j] = vertices[idx + j];
60 }
61 }
62 visitor->visit(andx: ndx[0], a: abc[0], bndx: ndx[1], b: abc[1]);
63 i += 2;
64 }
65}
66
67// vertices are already offset
68template<typename Vertex>
69void traverseSegments(Vertex *vertices,
70 const BufferInfo &vertexInfo,
71 SegmentsVisitor *visitor)
72{
73 uint i = 0;
74
75 const uint verticesStride = vertexInfo.byteStride / sizeof(Vertex);
76 const uint maxVerticesDataSize = qMin(a: vertexInfo.dataSize, b: 3U);
77
78 uint ndx[2];
79 Vector3D abc[2];
80 while (i < vertexInfo.count) {
81 for (uint u = 0; u < 2; ++u) {
82 ndx[u] = (i + u);
83 const uint idx = ndx[u] * verticesStride;
84 for (uint j = 0; j < maxVerticesDataSize; ++j)
85 abc[u][j] = vertices[idx + j];
86 }
87 visitor->visit(andx: ndx[0], a: abc[0], bndx: ndx[1], b: abc[1]);
88 i += 2;
89 }
90}
91
92// indices, vertices are already offset
93template<typename Index, typename Vertex>
94void traverseSegmentStripIndexed(Index *indices,
95 Vertex *vertices,
96 const BufferInfo &indexInfo,
97 const BufferInfo &vertexInfo,
98 SegmentsVisitor *visitor,
99 bool loop)
100{
101 uint i = 0;
102 uint stripStartIndex = 0;
103
104 const uint verticesStride = vertexInfo.byteStride / sizeof(Vertex);
105 const uint maxVerticesDataSize = qMin(a: vertexInfo.dataSize, b: 3U);
106
107 uint ndx[2];
108 Vector3D abc[2];
109 while (i < indexInfo.count) {
110 if (indexInfo.restartEnabled && indexInfo.restartIndexValue == static_cast<int>(indices[i])) {
111 ++i;
112 continue;
113 }
114 stripStartIndex = i;
115 ndx[0] = indices[stripStartIndex];
116 uint idx = ndx[0] * verticesStride;
117 for (uint j = 0; j < maxVerticesDataSize; ++j)
118 abc[0][j] = vertices[idx + j];
119 ++i;
120 while (i < indexInfo.count && (!indexInfo.restartEnabled || indexInfo.restartIndexValue != static_cast<int>(indices[i]))) {
121 ndx[1] = indices[i];
122 if (ndx[0] != ndx[1]) {
123 idx = ndx[1] * verticesStride;
124 for (uint j = 0; j < maxVerticesDataSize; ++j)
125 abc[1][j] = vertices[idx + j];
126 visitor->visit(andx: ndx[0], a: abc[0], bndx: ndx[1], b: abc[1]);
127 }
128 ++i;
129 ndx[0] = ndx[1];
130 abc[0] = abc[1];
131 }
132 if (loop) {
133 ndx[1] = indices[stripStartIndex];
134 if (ndx[0] != ndx[1]) {
135 idx = ndx[1] * verticesStride;
136 for (uint j = 0; j < maxVerticesDataSize; ++j)
137 abc[1][j] = vertices[idx + j];
138 visitor->visit(andx: ndx[0], a: abc[0], bndx: ndx[1], b: abc[1]);
139 }
140 }
141 }
142}
143
144// vertices are already offset
145template<typename Vertex>
146void traverseSegmentStrip(Vertex *vertices,
147 const BufferInfo &vertexInfo,
148 SegmentsVisitor *visitor,
149 bool loop)
150{
151 uint i = 0;
152
153 const uint verticesStride = vertexInfo.byteStride / sizeof(Vertex);
154 const uint maxVerticesDataSize = qMin(a: vertexInfo.dataSize, b: 3U);
155
156 uint ndx[2];
157 Vector3D abc[2];
158 ndx[0] = i;
159 uint idx = ndx[0] * verticesStride;
160 for (uint j = 0; j < maxVerticesDataSize; ++j)
161 abc[0][j] = vertices[idx + j];
162 while (i < vertexInfo.count - 1) {
163 ndx[1] = (i + 1);
164 idx = ndx[1] * verticesStride;
165 for (uint j = 0; j < maxVerticesDataSize; ++j)
166 abc[1][j] = vertices[idx + j];
167 visitor->visit(andx: ndx[0], a: abc[0], bndx: ndx[1], b: abc[1]);
168 ++i;
169 ndx[0] = ndx[1];
170 abc[0] = abc[1];
171 }
172 if (loop) {
173 ndx[1] = 0;
174 idx = ndx[1] * verticesStride;
175 for (uint j = 0; j < maxVerticesDataSize; ++j)
176 abc[1][j] = vertices[idx + j];
177 visitor->visit(andx: ndx[0], a: abc[0], bndx: ndx[1], b: abc[1]);
178 }
179}
180
181// indices, vertices are already offset
182template<typename Index, typename Vertex>
183void traverseSegmentAdjacencyIndexed(Index *indices,
184 Vertex *vertices,
185 const BufferInfo &indexInfo,
186 const BufferInfo &vertexInfo,
187 SegmentsVisitor *visitor)
188{
189 uint i = 1;
190 uint n = indexInfo.count - 1;
191 const uint verticesStride = vertexInfo.byteStride / sizeof(Vertex);
192 const uint maxVerticesDataSize = qMin(a: vertexInfo.dataSize, b: 3U);
193
194 uint ndx[2];
195 Vector3D abc[2];
196 while (i < n) {
197 for (uint u = 0; u < 2; ++u) {
198 ndx[u] = indices[i + u];
199 const uint idx = ndx[u] * verticesStride;
200 for (uint j = 0; j < maxVerticesDataSize; ++j) {
201 abc[u][j] = vertices[idx + j];
202 }
203 }
204 visitor->visit(andx: ndx[0], a: abc[0], bndx: ndx[1], b: abc[1]);
205 i += 2;
206 }
207}
208
209// vertices are already offset
210template<typename Vertex>
211void traverseSegmentAdjacency(Vertex *vertices,
212 const BufferInfo &vertexInfo,
213 SegmentsVisitor *visitor)
214{
215 uint i = 1;
216 uint n = vertexInfo.count - 1;
217
218 const uint verticesStride = vertexInfo.byteStride / sizeof(Vertex);
219 const uint maxVerticesDataSize = qMin(a: vertexInfo.dataSize, b: 3U);
220
221 uint ndx[2];
222 Vector3D abc[2];
223 while (i < n) {
224 for (uint u = 0; u < 2; ++u) {
225 ndx[u] = (i + u);
226 const uint idx = ndx[u] * verticesStride;
227 for (uint j = 0; j < maxVerticesDataSize; ++j)
228 abc[u][j] = vertices[idx + j];
229 }
230 visitor->visit(andx: ndx[0], a: abc[0], bndx: ndx[1], b: abc[1]);
231 i += 2;
232 }
233}
234
235template<typename Index, typename Visitor>
236struct IndexedVertexExecutor
237{
238 template<typename Vertex>
239 void operator ()(const BufferInfo &vertexInfo, Vertex * vertices)
240 {
241 switch (m_primitiveType) {
242 case Qt3DRender::QGeometryRenderer::Lines:
243 traverseSegmentsIndexed(m_indices, vertices, m_indexBufferInfo, vertexInfo, m_visitor);
244 return;
245 case Qt3DRender::QGeometryRenderer::LineStrip:
246 traverseSegmentStripIndexed(m_indices, vertices, m_indexBufferInfo, vertexInfo, m_visitor, false);
247 return;
248 case Qt3DRender::QGeometryRenderer::LineLoop:
249 traverseSegmentStripIndexed(m_indices, vertices, m_indexBufferInfo, vertexInfo, m_visitor, true);
250 return;
251 case Qt3DRender::QGeometryRenderer::LinesAdjacency:
252 traverseSegmentAdjacencyIndexed(m_indices, vertices, m_indexBufferInfo, vertexInfo, m_visitor);
253 return;
254 case Qt3DRender::QGeometryRenderer::LineStripAdjacency: // fall through
255 default:
256 Q_UNREACHABLE();
257 return;
258 }
259 }
260
261 BufferInfo m_indexBufferInfo;
262 Index *m_indices;
263 Qt3DRender::QGeometryRenderer::PrimitiveType m_primitiveType;
264 Visitor* m_visitor;
265};
266
267template<typename Visitor>
268struct IndexExecutor
269{
270 template<typename Index>
271 void operator ()( const BufferInfo &indexInfo, Index *indices)
272 {
273 IndexedVertexExecutor<Index, Visitor> exec;
274 exec.m_primitiveType = m_primitiveType;
275 exec.m_indices = indices;
276 exec.m_indexBufferInfo = indexInfo;
277 exec.m_visitor = m_visitor;
278 Qt3DRender::Render::Visitor::processBuffer(m_vertexBufferInfo, exec);
279 }
280
281 BufferInfo m_vertexBufferInfo;
282 Qt3DRender::QGeometryRenderer::PrimitiveType m_primitiveType;
283 Visitor* m_visitor;
284};
285
286template<typename Visitor>
287struct VertexExecutor
288{
289 template<typename Vertex>
290 void operator ()(const BufferInfo &vertexInfo, Vertex *vertices)
291 {
292 switch (m_primitiveType) {
293 case Qt3DRender::QGeometryRenderer::Lines:
294 traverseSegments(vertices, vertexInfo, m_visitor);
295 return;
296 case Qt3DRender::QGeometryRenderer::LineStrip:
297 traverseSegmentStrip(vertices, vertexInfo, m_visitor, false);
298 return;
299 case Qt3DRender::QGeometryRenderer::LineLoop:
300 traverseSegmentStrip(vertices, vertexInfo, m_visitor, true);
301 return;
302 case Qt3DRender::QGeometryRenderer::LinesAdjacency:
303 traverseSegmentAdjacency(vertices, vertexInfo, m_visitor);
304 return;
305 case Qt3DRender::QGeometryRenderer::LineStripAdjacency: // fall through
306 default:
307 Q_UNREACHABLE();
308 return;
309 }
310 }
311
312 Qt3DRender::QGeometryRenderer::PrimitiveType m_primitiveType;
313 Visitor* m_visitor;
314};
315
316} // anonymous
317
318
319SegmentsVisitor::~SegmentsVisitor()
320{
321
322}
323
324void SegmentsVisitor::apply(const Qt3DCore::QEntity *entity)
325{
326 GeometryRenderer *renderer = m_manager->geometryRendererManager()->lookupResource(id: entity->id());
327 apply(renderer, id: entity->id());
328}
329
330void SegmentsVisitor::apply(const GeometryRenderer *renderer, const Qt3DCore::QNodeId id)
331{
332 m_nodeId = id;
333 if (renderer && renderer->instanceCount() == 1 && isSegmentBased(type: renderer->primitiveType())) {
334 Visitor::visitPrimitives<GeometryRenderer, VertexExecutor<SegmentsVisitor>,
335 IndexExecutor<SegmentsVisitor>, SegmentsVisitor>(manager: m_manager, renderer, visitor: this);
336 }
337}
338
339void SegmentsVisitor::apply(const PickingProxy *proxy, const Qt3DCore::QNodeId id)
340{
341 m_nodeId = id;
342 if (proxy && proxy->instanceCount() == 1 && isSegmentBased(type: static_cast<Qt3DRender::QGeometryRenderer::PrimitiveType>(proxy->primitiveType()))) {
343 Visitor::visitPrimitives<PickingProxy, VertexExecutor<SegmentsVisitor>,
344 IndexExecutor<SegmentsVisitor>, SegmentsVisitor>(manager: m_manager, renderer: proxy, visitor: this);
345 }
346}
347
348} // namespace Render
349
350} // namespace Qt3DRender
351
352QT_END_NAMESPACE
353

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