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 | |
54 | QT_BEGIN_NAMESPACE |
55 | |
56 | namespace Qt3DRender { |
57 | |
58 | namespace Render { |
59 | |
60 | namespace { |
61 | |
62 | bool 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 |
77 | template<typename Index, typename Vertex> |
78 | void 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 |
104 | template<typename Vertex> |
105 | void 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 |
129 | template<typename Index, typename Vertex> |
130 | void 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 |
181 | template<typename Vertex> |
182 | void 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 |
218 | template<typename Index, typename Vertex> |
219 | void 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 |
246 | template<typename Vertex> |
247 | void 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 | |
271 | template<typename Index, typename Visitor> |
272 | struct 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 | |
303 | template<typename Visitor> |
304 | struct 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 | |
322 | template<typename Visitor> |
323 | struct 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 | |
355 | SegmentsVisitor::~SegmentsVisitor() |
356 | { |
357 | |
358 | } |
359 | |
360 | void 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 | |
366 | void 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 | |
379 | QT_END_NAMESPACE |
380 | |