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 | |
18 | QT_BEGIN_NAMESPACE |
19 | |
20 | namespace Qt3DRender { |
21 | |
22 | namespace Render { |
23 | |
24 | namespace { |
25 | |
26 | bool 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 |
41 | template<typename Index, typename Vertex> |
42 | void 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 |
68 | template<typename Vertex> |
69 | void 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 |
93 | template<typename Index, typename Vertex> |
94 | void 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 |
145 | template<typename Vertex> |
146 | void traverseSegmentStrip(Vertex *vertices, |
147 | const BufferInfo &vertexInfo, |
148 | SegmentsVisitor *visitor, |
149 | bool loop) |
150 | { |
151 | uint i = 0; |
152 | |
153 | if (vertexInfo.count < 1) |
154 | return; |
155 | |
156 | const uint verticesStride = vertexInfo.byteStride / sizeof(Vertex); |
157 | const uint maxVerticesDataSize = qMin(a: vertexInfo.dataSize, b: 3U); |
158 | |
159 | uint ndx[2]; |
160 | Vector3D abc[2]; |
161 | ndx[0] = i; |
162 | uint idx = ndx[0] * verticesStride; |
163 | for (uint j = 0; j < maxVerticesDataSize; ++j) |
164 | abc[0][j] = vertices[idx + j]; |
165 | while (i < vertexInfo.count - 1) { |
166 | ndx[1] = (i + 1); |
167 | idx = ndx[1] * verticesStride; |
168 | for (uint j = 0; j < maxVerticesDataSize; ++j) |
169 | abc[1][j] = vertices[idx + j]; |
170 | visitor->visit(andx: ndx[0], a: abc[0], bndx: ndx[1], b: abc[1]); |
171 | ++i; |
172 | ndx[0] = ndx[1]; |
173 | abc[0] = abc[1]; |
174 | } |
175 | if (loop) { |
176 | ndx[1] = 0; |
177 | idx = ndx[1] * verticesStride; |
178 | for (uint j = 0; j < maxVerticesDataSize; ++j) |
179 | abc[1][j] = vertices[idx + j]; |
180 | visitor->visit(andx: ndx[0], a: abc[0], bndx: ndx[1], b: abc[1]); |
181 | } |
182 | } |
183 | |
184 | // indices, vertices are already offset |
185 | template<typename Index, typename Vertex> |
186 | void traverseSegmentAdjacencyIndexed(Index *indices, |
187 | Vertex *vertices, |
188 | const BufferInfo &indexInfo, |
189 | const BufferInfo &vertexInfo, |
190 | SegmentsVisitor *visitor) |
191 | { |
192 | uint i = 1; |
193 | uint n = indexInfo.count - 1; |
194 | const uint verticesStride = vertexInfo.byteStride / sizeof(Vertex); |
195 | const uint maxVerticesDataSize = qMin(a: vertexInfo.dataSize, b: 3U); |
196 | |
197 | uint ndx[2]; |
198 | Vector3D abc[2]; |
199 | while (i < n) { |
200 | for (uint u = 0; u < 2; ++u) { |
201 | ndx[u] = indices[i + u]; |
202 | const uint idx = ndx[u] * verticesStride; |
203 | for (uint j = 0; j < maxVerticesDataSize; ++j) { |
204 | abc[u][j] = vertices[idx + j]; |
205 | } |
206 | } |
207 | visitor->visit(andx: ndx[0], a: abc[0], bndx: ndx[1], b: abc[1]); |
208 | i += 2; |
209 | } |
210 | } |
211 | |
212 | // vertices are already offset |
213 | template<typename Vertex> |
214 | void traverseSegmentAdjacency(Vertex *vertices, |
215 | const BufferInfo &vertexInfo, |
216 | SegmentsVisitor *visitor) |
217 | { |
218 | uint i = 1; |
219 | uint n = vertexInfo.count - 1; |
220 | |
221 | const uint verticesStride = vertexInfo.byteStride / sizeof(Vertex); |
222 | const uint maxVerticesDataSize = qMin(a: vertexInfo.dataSize, b: 3U); |
223 | |
224 | uint ndx[2]; |
225 | Vector3D abc[2]; |
226 | while (i < n) { |
227 | for (uint u = 0; u < 2; ++u) { |
228 | ndx[u] = (i + u); |
229 | const uint idx = ndx[u] * verticesStride; |
230 | for (uint j = 0; j < maxVerticesDataSize; ++j) |
231 | abc[u][j] = vertices[idx + j]; |
232 | } |
233 | visitor->visit(andx: ndx[0], a: abc[0], bndx: ndx[1], b: abc[1]); |
234 | i += 2; |
235 | } |
236 | } |
237 | |
238 | template<typename Index, typename Visitor> |
239 | struct IndexedVertexExecutor |
240 | { |
241 | template<typename Vertex> |
242 | void operator ()(const BufferInfo &vertexInfo, Vertex * vertices) |
243 | { |
244 | switch (m_primitiveType) { |
245 | case Qt3DRender::QGeometryRenderer::Lines: |
246 | traverseSegmentsIndexed(m_indices, vertices, m_indexBufferInfo, vertexInfo, m_visitor); |
247 | return; |
248 | case Qt3DRender::QGeometryRenderer::LineStrip: |
249 | traverseSegmentStripIndexed(m_indices, vertices, m_indexBufferInfo, vertexInfo, m_visitor, false); |
250 | return; |
251 | case Qt3DRender::QGeometryRenderer::LineLoop: |
252 | traverseSegmentStripIndexed(m_indices, vertices, m_indexBufferInfo, vertexInfo, m_visitor, true); |
253 | return; |
254 | case Qt3DRender::QGeometryRenderer::LinesAdjacency: |
255 | traverseSegmentAdjacencyIndexed(m_indices, vertices, m_indexBufferInfo, vertexInfo, m_visitor); |
256 | return; |
257 | case Qt3DRender::QGeometryRenderer::LineStripAdjacency: // fall through |
258 | default: |
259 | Q_UNREACHABLE(); |
260 | return; |
261 | } |
262 | } |
263 | |
264 | BufferInfo m_indexBufferInfo; |
265 | Index *m_indices; |
266 | Qt3DRender::QGeometryRenderer::PrimitiveType m_primitiveType; |
267 | Visitor* m_visitor; |
268 | }; |
269 | |
270 | template<typename Visitor> |
271 | struct IndexExecutor |
272 | { |
273 | template<typename Index> |
274 | void operator ()( const BufferInfo &indexInfo, Index *indices) |
275 | { |
276 | IndexedVertexExecutor<Index, Visitor> exec; |
277 | exec.m_primitiveType = m_primitiveType; |
278 | exec.m_indices = indices; |
279 | exec.m_indexBufferInfo = indexInfo; |
280 | exec.m_visitor = m_visitor; |
281 | Qt3DRender::Render::Visitor::processBuffer(m_vertexBufferInfo, exec); |
282 | } |
283 | |
284 | BufferInfo m_vertexBufferInfo; |
285 | Qt3DRender::QGeometryRenderer::PrimitiveType m_primitiveType; |
286 | Visitor* m_visitor; |
287 | }; |
288 | |
289 | template<typename Visitor> |
290 | struct VertexExecutor |
291 | { |
292 | template<typename Vertex> |
293 | void operator ()(const BufferInfo &vertexInfo, Vertex *vertices) |
294 | { |
295 | switch (m_primitiveType) { |
296 | case Qt3DRender::QGeometryRenderer::Lines: |
297 | traverseSegments(vertices, vertexInfo, m_visitor); |
298 | return; |
299 | case Qt3DRender::QGeometryRenderer::LineStrip: |
300 | traverseSegmentStrip(vertices, vertexInfo, m_visitor, false); |
301 | return; |
302 | case Qt3DRender::QGeometryRenderer::LineLoop: |
303 | traverseSegmentStrip(vertices, vertexInfo, m_visitor, true); |
304 | return; |
305 | case Qt3DRender::QGeometryRenderer::LinesAdjacency: |
306 | traverseSegmentAdjacency(vertices, vertexInfo, m_visitor); |
307 | return; |
308 | case Qt3DRender::QGeometryRenderer::LineStripAdjacency: // fall through |
309 | default: |
310 | Q_UNREACHABLE(); |
311 | return; |
312 | } |
313 | } |
314 | |
315 | Qt3DRender::QGeometryRenderer::PrimitiveType m_primitiveType; |
316 | Visitor* m_visitor; |
317 | }; |
318 | |
319 | } // anonymous |
320 | |
321 | |
322 | SegmentsVisitor::~SegmentsVisitor() |
323 | { |
324 | |
325 | } |
326 | |
327 | void SegmentsVisitor::apply(const Qt3DCore::QEntity *entity) |
328 | { |
329 | GeometryRenderer *renderer = m_manager->geometryRendererManager()->lookupResource(id: entity->id()); |
330 | apply(renderer, id: entity->id()); |
331 | } |
332 | |
333 | void SegmentsVisitor::apply(const GeometryRenderer *renderer, const Qt3DCore::QNodeId id) |
334 | { |
335 | m_nodeId = id; |
336 | if (renderer && renderer->instanceCount() == 1 && isSegmentBased(type: renderer->primitiveType())) { |
337 | Visitor::visitPrimitives<GeometryRenderer, VertexExecutor<SegmentsVisitor>, |
338 | IndexExecutor<SegmentsVisitor>, SegmentsVisitor>(manager: m_manager, renderer, visitor: this); |
339 | } |
340 | } |
341 | |
342 | void SegmentsVisitor::apply(const PickingProxy *proxy, const Qt3DCore::QNodeId id) |
343 | { |
344 | m_nodeId = id; |
345 | if (proxy && proxy->instanceCount() == 1 && isSegmentBased(type: static_cast<Qt3DRender::QGeometryRenderer::PrimitiveType>(proxy->primitiveType()))) { |
346 | Visitor::visitPrimitives<PickingProxy, VertexExecutor<SegmentsVisitor>, |
347 | IndexExecutor<SegmentsVisitor>, SegmentsVisitor>(manager: m_manager, renderer: proxy, visitor: this); |
348 | } |
349 | } |
350 | |
351 | } // namespace Render |
352 | |
353 | } // namespace Qt3DRender |
354 | |
355 | QT_END_NAMESPACE |
356 | |