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 | 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 |
182 | template<typename Index, typename Vertex> |
183 | void 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 |
210 | template<typename Vertex> |
211 | void 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 | |
235 | template<typename Index, typename Visitor> |
236 | struct 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 | |
267 | template<typename Visitor> |
268 | struct 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 | |
286 | template<typename Visitor> |
287 | struct 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 | |
319 | SegmentsVisitor::~SegmentsVisitor() |
320 | { |
321 | |
322 | } |
323 | |
324 | void 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 | |
330 | void 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 | |
339 | void 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 | |
352 | QT_END_NAMESPACE |
353 | |