1 /****************************************************************************
2 **
3 ** Copyright (C) 2018 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtLocation module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL3$
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 http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free
28 ** Software Foundation and appearing in the file LICENSE.GPL included in
29 ** the packaging of this file. Please review the following information to
30 ** ensure the GNU General Public License version 2.0 requirements will be
31 ** met: http://www.gnu.org/licenses/gpl-2.0.html.
32 **
33 ** $QT_END_LICENSE$
34 **
35 ****************************************************************************/
36
37 #include "qgeomapobjectqsgsupport_p.h"
38 #include <QtLocation/private/qgeomap_p_p.h>
39
40 QT_BEGIN_NAMESPACE
41
findMapObject(QGeoMapObject * o,const QList<MapObject> & list)42 static int findMapObject(QGeoMapObject *o, const QList<MapObject> &list)
43 {
44 for (int i = 0; i < list.size(); ++i)
45 {
46 if (list.at(i).object.data() == o)
47 return i;
48 }
49 return -1;
50 }
51
createMapObjectImplementation(QGeoMapObject * obj,QGeoMapPrivate * d)52 bool QGeoMapObjectQSGSupport::createMapObjectImplementation(QGeoMapObject *obj, QGeoMapPrivate *d)
53 {
54 QExplicitlySharedDataPointer<QGeoMapObjectPrivate> pimpl =
55 QExplicitlySharedDataPointer<QGeoMapObjectPrivate>(d->createMapObjectImplementation(obj));
56 if (pimpl.constData()) {
57 bool res = obj->setImplementation(pimpl);
58 if (res)
59 emit m_map->sgNodeChanged();
60 return res;
61 }
62 return false;
63 }
64
createMapObjectImplementationPrivate(QGeoMapObject * obj)65 QGeoMapObjectPrivate *QGeoMapObjectQSGSupport::createMapObjectImplementationPrivate(QGeoMapObject *obj)
66 {
67 QGeoMapObjectPrivate *res = nullptr;
68
69 {
70 QQSGMapObject *sgo = nullptr;
71 switch (obj->type()) {
72 case QGeoMapObject::PolylineType: {
73 QMapPolylineObjectPrivate &oldImpl = static_cast<QMapPolylineObjectPrivate &>(*obj->implementation());
74 QMapPolylineObjectPrivateQSG *pimpl =
75 new QMapPolylineObjectPrivateQSG(oldImpl);
76 sgo = pimpl;
77 res = pimpl;
78 break;
79 }
80 case QGeoMapObject::PolygonType: {
81 QMapPolygonObjectPrivate &oldImpl = static_cast<QMapPolygonObjectPrivate &>(*obj->implementation());
82 QMapPolygonObjectPrivateQSG *pimpl =
83 new QMapPolygonObjectPrivateQSG(oldImpl);
84 sgo = pimpl;
85 res = pimpl;
86 break;
87 }
88 case QGeoMapObject::CircleType: {
89 QMapCircleObjectPrivate &oldImpl = static_cast<QMapCircleObjectPrivate &>(*obj->implementation());
90 QMapCircleObjectPrivateQSG *pimpl =
91 new QMapCircleObjectPrivateQSG(oldImpl);
92 sgo = pimpl;
93 res = pimpl;
94 break;
95 }
96 case QGeoMapObject::RouteType: {
97 QMapRouteObjectPrivate &oldImpl = static_cast<QMapRouteObjectPrivate &>(*obj->implementation());
98 QMapRouteObjectPrivateQSG *pimpl =
99 new QMapRouteObjectPrivateQSG(oldImpl);
100 sgo = pimpl;
101 res = pimpl;
102 break;
103 }
104 case QGeoMapObject::IconType: {
105 QMapIconObjectPrivate &oldImpl = static_cast<QMapIconObjectPrivate &>(*obj->implementation());
106 QMapIconObjectPrivateQSG *pimpl =
107 new QMapIconObjectPrivateQSG(oldImpl);
108 sgo = pimpl;
109 res = pimpl;
110 break;
111 }
112 default:
113 // Use the following warning only for debugging purposes.
114 // qWarning() << "QGeoMapObjectQSGSupport::createMapObjectImplementationPrivate: not instantiating pimpl for unsupported object type " << obj->type();
115 break;
116 }
117
118 if (res) {
119 QPointer<QGeoMapObject> p(obj);
120 MapObject mo(p, sgo);
121 m_pendingMapObjects << mo;
122 }
123 }
124 return res;
125 }
126
mapObjects() const127 QList<QGeoMapObject *> QGeoMapObjectQSGSupport::mapObjects() const
128 {
129 QList<QGeoMapObject *> res;
130 for (int i = 0; i < m_mapObjects.size(); ++i) {
131 res.append(m_mapObjects.at(i).object.data());
132 }
133 return res;
134 }
135
removeMapObject(QGeoMapObject * obj)136 void QGeoMapObjectQSGSupport::removeMapObject(QGeoMapObject *obj)
137 {
138 int idx = findMapObject(obj, m_mapObjects);
139 if (idx >= 0) {
140 const MapObject &mo = m_mapObjects.takeAt(idx);
141 obj->disconnect(m_map);
142 m_removedMapObjects << mo;
143 emit m_map->sgNodeChanged();
144 } else {
145 idx = findMapObject(obj, m_pendingMapObjects);
146 if (idx >= 0) {
147 m_pendingMapObjects.removeAt(idx);
148 obj->disconnect(m_map);
149 } else {
150 // obj not here.
151 }
152 }
153 }
154
155 // called in the render thread
updateMapObjects(QSGNode * root,QQuickWindow * window)156 void QGeoMapObjectQSGSupport::updateMapObjects(QSGNode *root, QQuickWindow *window)
157 {
158 if (!root)
159 return;
160
161 if (m_mapObjectsRootNode && !m_mapObjectsRootNode->parent())
162 root->appendChildNode(m_mapObjectsRootNode.get());
163
164 if (!m_mapObjectsRootNode) {
165 m_mapObjectsRootNode = std::make_unique<QDeclarativePolygonMapItemPrivateOpenGL::RootNode>();
166 root->appendChildNode(m_mapObjectsRootNode.get());
167 m_mapObjectsRootNode->setFlag(QSGNode::OwnedByParent, false);
168 }
169
170 m_mapObjectsRootNode->removeAllChildNodes();
171 for (int i = 0; i < m_removedMapObjects.size(); ++i) {
172 MapObject mo = m_removedMapObjects[i];
173 if (mo.qsgNode) {
174 delete mo.qsgNode;
175 mo.qsgNode = nullptr;
176 // mo.sgObject is now invalid as it is destroyed right after appending
177 // mo to m_removedMapObjects
178 }
179 }
180 m_removedMapObjects.clear();
181
182 for (int i = 0; i < m_mapObjects.size(); ++i) {
183 // already added as node
184 if (Q_UNLIKELY(!m_mapObjects.at(i).object)) {
185 qWarning() << "unexpected NULL pointer in m_mapObjects at "<<i;
186 continue;
187 }
188
189 MapObject &mo = m_mapObjects[i];
190 QQSGMapObject *sgo = mo.sgObject;
191 QSGNode *oldNode = mo.qsgNode;
192 mo.qsgNode = sgo->updateMapObjectNode(oldNode, &mo.visibleNode, m_mapObjectsRootNode.get(), window);
193 if (Q_UNLIKELY(!mo.qsgNode)) {
194 qWarning() << "updateMapObjectNode for "<<mo.object->type() << " returned NULL";
195 } else if (mo.visibleNode && (mo.visibleNode->visible() != mo.object->visible())) {
196 mo.visibleNode->setVisible(mo.object->visible());
197 mo.qsgNode->markDirty(QSGNode::DirtySubtreeBlocked);
198 }
199 }
200
201 QList<int> toRemove;
202 for (int i = 0; i < m_pendingMapObjects.size(); ++i) {
203 // already added as node
204 MapObject &mo = m_pendingMapObjects[i];
205 QQSGMapObject *sgo = mo.sgObject;
206 QSGNode *oldNode = mo.qsgNode;
207 sgo->updateGeometry(); // or subtree will be blocked
208 mo.qsgNode = sgo->updateMapObjectNode(oldNode, &mo.visibleNode, m_mapObjectsRootNode.get(), window);
209 if (mo.qsgNode) {
210 if (mo.visibleNode && (mo.visibleNode->visible() != mo.object->visible())) {
211 mo.visibleNode->setVisible(mo.object->visible());
212 mo.qsgNode->markDirty(QSGNode::DirtySubtreeBlocked);
213 }
214 m_mapObjects << mo;
215 toRemove.push_front(i);
216 QObject::connect(mo.object, SIGNAL(visibleChanged()), m_map, SIGNAL(sgNodeChanged()));
217 } else {
218 // leave it to be processed, don't spit warnings
219 }
220 }
221
222 for (int i: qAsConst(toRemove))
223 m_pendingMapObjects.removeAt(i);
224 m_mapObjectsRootNode->setSubtreeBlocked(false);
225 }
226
227 // called in GUI thread
updateObjectsGeometry()228 void QGeoMapObjectQSGSupport::updateObjectsGeometry()
229 {
230 for (int i = 0; i < m_mapObjects.size(); ++i) {
231 // already added as node
232 if (Q_UNLIKELY(!m_mapObjects.at(i).object)) {
233 qWarning() << "unexpected NULL pointer in m_mapObjects at "<<i;
234 continue;
235 }
236
237 QQSGMapObject *sgo = m_mapObjects.at(i).sgObject;
238 sgo->updateGeometry();
239 }
240 emit m_map->sgNodeChanged();
241 }
242
243 QT_END_NAMESPACE
244