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