1// Copyright (C) 2015 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 "geometryrenderer_p.h"
5#include <Qt3DRender/private/geometryrenderermanager_p.h>
6#include <Qt3DRender/private/qboundingvolume_p.h>
7#include <Qt3DRender/private/qgeometryrenderer_p.h>
8#include <Qt3DRender/private/qmesh_p.h>
9#include <Qt3DCore/private/qnode_p.h>
10#include <Qt3DCore/private/qservicelocator_p.h>
11#include <QtCore/qcoreapplication.h>
12
13#include <memory>
14
15QT_BEGIN_NAMESPACE
16
17using namespace Qt3DCore;
18
19namespace Qt3DRender {
20namespace Render {
21
22GeometryRenderer::GeometryRenderer()
23 : BackendNode(ReadWrite)
24 , m_instanceCount(0)
25 , m_vertexCount(0)
26 , m_indexOffset(0)
27 , m_firstInstance(0)
28 , m_firstVertex(0)
29 , m_indexBufferByteOffset(0)
30 , m_restartIndexValue(-1)
31 , m_verticesPerPatch(0)
32 , m_primitiveRestartEnabled(false)
33 , m_primitiveType(QGeometryRenderer::Triangles)
34 , m_dirty(false)
35 , m_hasView(false)
36 , m_manager(nullptr)
37 , m_sortIndex(-1.f)
38{
39}
40
41GeometryRenderer::~GeometryRenderer()
42{
43}
44
45void GeometryRenderer::cleanup()
46{
47 BackendNode::setEnabled(false);
48 m_instanceCount = 0;
49 m_vertexCount = 0;
50 m_indexOffset = 0;
51 m_firstInstance = 0;
52 m_firstVertex = 0;
53 m_indexBufferByteOffset = 0;
54 m_restartIndexValue = -1;
55 m_verticesPerPatch = 0;
56 m_primitiveRestartEnabled = false;
57 m_primitiveType = QGeometryRenderer::Triangles;
58 m_geometryId = Qt3DCore::QNodeId();
59 m_hasView = m_dirty = false;
60 m_geometryFactory.reset();
61 m_sortIndex = -1.f;
62}
63
64void GeometryRenderer::setManager(GeometryRendererManager *manager)
65{
66 m_manager = manager;
67}
68
69void GeometryRenderer::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
70{
71 BackendNode::syncFromFrontEnd(frontEnd, firstTime);
72 const QGeometryRenderer *node = qobject_cast<const QGeometryRenderer *>(object: frontEnd);
73 if (!node)
74 return;
75 const Qt3DCore::QGeometryView *view = node->view();
76
77 auto propertyUpdater = [this](const auto *node) {
78 m_dirty |= m_instanceCount != node->instanceCount();
79 m_instanceCount = node->instanceCount();
80 m_dirty |= m_vertexCount != node->vertexCount();
81 m_vertexCount = node->vertexCount();
82 m_dirty |= m_indexOffset != node->indexOffset();
83 m_indexOffset = node->indexOffset();
84 m_dirty |= m_firstInstance != node->firstInstance();
85 m_firstInstance = node->firstInstance();
86 m_dirty |= m_firstVertex != node->firstVertex();
87 m_firstVertex = node->firstVertex();
88 m_dirty |= m_indexBufferByteOffset != node->indexBufferByteOffset();
89 m_indexBufferByteOffset = node->indexBufferByteOffset();
90 m_dirty |= m_restartIndexValue != node->restartIndexValue();
91 m_restartIndexValue = node->restartIndexValue();
92 m_dirty |= m_verticesPerPatch != node->verticesPerPatch();
93 m_verticesPerPatch = node->verticesPerPatch();
94 m_dirty |= m_primitiveRestartEnabled != node->primitiveRestartEnabled();
95 m_primitiveRestartEnabled = node->primitiveRestartEnabled();
96 m_dirty |= m_primitiveType != static_cast<QGeometryRenderer::PrimitiveType>(node->primitiveType());
97 m_primitiveType = static_cast<QGeometryRenderer::PrimitiveType>(node->primitiveType());
98 m_dirty |= (node->geometry() && m_geometryId != node->geometry()->id()) || (!node->geometry() && !m_geometryId.isNull());
99 m_geometryId = node->geometry() ? node->geometry()->id() : Qt3DCore::QNodeId();
100 };
101
102 if (view) {
103 m_dirty |= !m_hasView;
104 m_hasView = true;
105 propertyUpdater(view);
106 } else {
107 m_dirty |= m_hasView;
108 m_hasView = false;
109 propertyUpdater(node);
110
111 const QGeometryRendererPrivate *dnode = static_cast<const QGeometryRendererPrivate *>(QNodePrivate::get(q: frontEnd));
112 QGeometryFactoryPtr newFunctor = dnode->m_geometryFactory;
113 const bool functorDirty = ((m_geometryFactory && !newFunctor)
114 || (!m_geometryFactory && newFunctor)
115 || (m_geometryFactory && newFunctor && !(*newFunctor == *m_geometryFactory)));
116 if (functorDirty) {
117 m_dirty = true;
118 m_geometryFactory = newFunctor;
119 if (m_geometryFactory && m_manager != nullptr) {
120 m_manager->addDirtyGeometryRenderer(bufferId: peerId());
121
122 const bool isQMeshFunctor = m_geometryFactory->id() == Qt3DCore::functorTypeId<MeshLoaderFunctor>();
123 if (isQMeshFunctor) {
124 const QMesh *meshNode = static_cast<const QMesh *>(node);
125 QMeshPrivate *dmeshNode = QMeshPrivate::get(q: const_cast<QMesh *>(meshNode));
126 dmeshNode->setStatus(QMesh::Loading);
127 }
128 }
129 }
130 }
131
132 m_sortIndex = node->sortIndex();
133
134 markDirty(changes: AbstractRenderer::GeometryDirty);
135}
136
137GeometryFunctorResult GeometryRenderer::executeFunctor()
138{
139 Q_ASSERT(m_geometryFactory);
140
141 // What kind of functor are we dealing with?
142 const bool isQMeshFunctor = m_geometryFactory->id() == Qt3DCore::functorTypeId<MeshLoaderFunctor>();
143
144 if (isQMeshFunctor) {
145 QSharedPointer<MeshLoaderFunctor> meshLoader = qSharedPointerCast<MeshLoaderFunctor>(src: m_geometryFactory);
146
147 // Set the aspect engine to allow remote downloads
148 if (meshLoader->nodeManagers() == nullptr)
149 meshLoader->setNodeManagers(m_renderer->nodeManagers());
150
151 if (meshLoader->downloaderService() == nullptr) {
152 Qt3DCore::QServiceLocator *services = m_renderer->services();
153 meshLoader->setDownloaderService(services->service<Qt3DCore::QDownloadHelperService>(serviceType: Qt3DCore::QServiceLocator::DownloadHelperService));
154 }
155 }
156
157 // Load geometry
158 QGeometry *geometry = (*m_geometryFactory)();
159 QMesh::Status meshLoaderStatus = QMesh::None;
160
161 // If the geometry is null, then we were either unable to load it (Error)
162 // or the mesh is located at a remote url and needs to be downloaded first (Loading)
163 if (geometry != nullptr) {
164 // Move the QGeometry object to the main thread and notify the
165 // corresponding QGeometryRenderer
166 const auto appThread = QCoreApplication::instance()->thread();
167 geometry->moveToThread(thread: appThread);
168 }
169
170 // Send Status
171 if (isQMeshFunctor) {
172 QSharedPointer<MeshLoaderFunctor> meshLoader = qSharedPointerCast<MeshLoaderFunctor>(src: m_geometryFactory);
173 meshLoaderStatus = meshLoader->status();
174 }
175
176 return { .geometry: geometry, .status: meshLoaderStatus };
177}
178
179void GeometryRenderer::unsetDirty()
180{
181 m_dirty = false;
182}
183
184GeometryRendererFunctor::GeometryRendererFunctor(AbstractRenderer *renderer, GeometryRendererManager *manager)
185 : m_manager(manager)
186 , m_renderer(renderer)
187{
188}
189
190Qt3DCore::QBackendNode *GeometryRendererFunctor::create(Qt3DCore::QNodeId id) const
191{
192 GeometryRenderer *geometryRenderer = m_manager->getOrCreateResource(id);
193 geometryRenderer->setManager(m_manager);
194 geometryRenderer->setRenderer(m_renderer);
195 return geometryRenderer;
196}
197
198Qt3DCore::QBackendNode *GeometryRendererFunctor::get(Qt3DCore::QNodeId id) const
199{
200 return m_manager->lookupResource(id);
201}
202
203void GeometryRendererFunctor::destroy(Qt3DCore::QNodeId id) const
204{
205 m_manager->releaseResource(id);
206}
207
208} // namespace Render
209} // namespace Qt3DRender
210
211QT_END_NAMESPACE
212

source code of qt3d/src/render/geometry/geometryrenderer.cpp