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

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