1 /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2  *
3  * This library is open source and may be redistributed and/or modified under
4  * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5  * (at your option) any later version.  The full license is in LICENSE file
6  * included with this distribution, and on the openscenegraph.org website.
7  *
8  * This library is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * OpenSceneGraph Public License for more details.
12 */
13 
14 #include <osgTerrain/TerrainTile>
15 #include <osgTerrain/Terrain>
16 #include <osgTerrain/GeometryTechnique>
17 
18 #include <osg/ClusterCullingCallback>
19 
20 #include <osgDB/ReadFile>
21 
22 
23 using namespace osg;
24 using namespace osgTerrain;
25 
26 /////////////////////////////////////////////////////////////////////////////////
27 //
28 // TileID
29 //
TileID()30 TileID::TileID():
31     level(-1),
32     x(-1),
33     y(-1)
34 {
35 }
36 
TileID(int in_level,int in_x,int in_y)37 TileID::TileID(int in_level, int in_x, int in_y):
38     level(in_level),
39     x(in_x),
40     y(in_y)
41 {
42 }
43 
44 /////////////////////////////////////////////////////////////////////////////////
45 //
46 // TerrainTile
47 //
setTileLoadedCallback(TerrainTile::TileLoadedCallback * lc)48 void TerrainTile::setTileLoadedCallback(TerrainTile::TileLoadedCallback* lc)
49 {
50     getTileLoadedCallback() = lc;
51 }
52 
getTileLoadedCallback()53 osg::ref_ptr<TerrainTile::TileLoadedCallback>& TerrainTile::getTileLoadedCallback()
54 {
55     static osg::ref_ptr<TileLoadedCallback> s_TileLoadedCallback;
56     return s_TileLoadedCallback;
57 }
58 
TerrainTile()59 TerrainTile::TerrainTile():
60     _terrain(0),
61     _dirtyMask(NOT_DIRTY),
62     _hasBeenTraversal(false),
63     _requiresNormals(true),
64     _treatBoundariesToValidDataAsDefaultValue(false),
65     _blendingPolicy(INHERIT)
66 {
67     setThreadSafeRefUnref(true);
68 }
69 
TerrainTile(const TerrainTile & terrain,const osg::CopyOp & copyop)70 TerrainTile::TerrainTile(const TerrainTile& terrain,const osg::CopyOp& copyop):
71     Group(terrain,copyop),
72     _terrain(0),
73     _dirtyMask(NOT_DIRTY),
74     _hasBeenTraversal(false),
75     _elevationLayer(terrain._elevationLayer),
76     _colorLayers(terrain._colorLayers),
77     _requiresNormals(terrain._requiresNormals),
78     _treatBoundariesToValidDataAsDefaultValue(terrain._treatBoundariesToValidDataAsDefaultValue),
79     _blendingPolicy(terrain._blendingPolicy)
80 {
81     if (terrain.getTerrainTechnique())
82     {
83         setTerrainTechnique(dynamic_cast<TerrainTechnique*>(terrain.getTerrainTechnique()->clone(osg::CopyOp::SHALLOW_COPY)));
84     }
85 }
86 
~TerrainTile()87 TerrainTile::~TerrainTile()
88 {
89     if (_terrainTechnique.valid())
90     {
91         _terrainTechnique->setTerrainTile(0);
92     }
93 
94     if (_terrain) setTerrain(0);
95 }
96 
setTerrain(Terrain * ts)97 void TerrainTile::setTerrain(Terrain* ts)
98 {
99     if (_terrain == ts) return;
100 
101     if (_terrain) _terrain->unregisterTerrainTile(this);
102 
103     _terrain = ts;
104 
105     if (_terrain) _terrain->registerTerrainTile(this);
106 }
107 
setTileID(const TileID & tileID)108 void TerrainTile::setTileID(const TileID& tileID)
109 {
110     if (_tileID == tileID) return;
111 
112     if (_terrain) _terrain->unregisterTerrainTile(this);
113 
114     _tileID = tileID;
115 
116     if (_terrain) _terrain->registerTerrainTile(this);
117 }
118 
119 
traverse(osg::NodeVisitor & nv)120 void TerrainTile::traverse(osg::NodeVisitor& nv)
121 {
122     if (!_hasBeenTraversal)
123     {
124         if (!_terrain)
125         {
126             osg::NodePath& nodePath = nv.getNodePath();
127             if (!nodePath.empty())
128             {
129                 for(osg::NodePath::reverse_iterator itr = nodePath.rbegin();
130                     itr != nodePath.rend() && !_terrain;
131                     ++itr)
132                 {
133                     osgTerrain::Terrain* ts = dynamic_cast<Terrain*>(*itr);
134                     if (ts)
135                     {
136                         OSG_INFO<<"Assigning terrain system "<<ts<<std::endl;
137                         setTerrain(ts);
138                     }
139                 }
140             }
141         }
142 
143         init(getDirtyMask(), false);
144 
145         _hasBeenTraversal = true;
146     }
147 
148     if (nv.getVisitorType()==osg::NodeVisitor::CULL_VISITOR)
149     {
150         osg::ClusterCullingCallback* ccc = dynamic_cast<osg::ClusterCullingCallback*>(getCullCallback());
151         if (ccc)
152         {
153             if (ccc->cull(&nv,0,static_cast<State *>(0))) return;
154         }
155     }
156 
157     if (_terrainTechnique.valid())
158     {
159         _terrainTechnique->traverse(nv);
160     }
161     else
162     {
163         osg::Group::traverse(nv);
164     }
165 }
166 
init(int dirtyMask,bool assumeMultiThreaded)167 void TerrainTile::init(int dirtyMask, bool assumeMultiThreaded)
168 {
169     if (!_terrainTechnique)
170     {
171         if (_terrain && _terrain->getTerrainTechniquePrototype())
172         {
173             osg::ref_ptr<osg::Object> object = _terrain->getTerrainTechniquePrototype()->clone(osg::CopyOp::DEEP_COPY_ALL);
174             setTerrainTechnique(dynamic_cast<TerrainTechnique*>(object.get()));
175         }
176         else
177         {
178             setTerrainTechnique(new GeometryTechnique);
179         }
180     }
181 
182     if (_terrainTechnique.valid())
183     {
184         _terrainTechnique->init(dirtyMask|getDirtyMask(), assumeMultiThreaded);
185     }
186 }
187 
setTerrainTechnique(TerrainTechnique * terrainTechnique)188 void TerrainTile::setTerrainTechnique(TerrainTechnique* terrainTechnique)
189 {
190     if (_terrainTechnique == terrainTechnique) return;
191 
192     if (_terrainTechnique.valid())
193     {
194         _terrainTechnique->setTerrainTile(0);
195     }
196 
197     _terrainTechnique = terrainTechnique;
198 
199     if (_terrainTechnique.valid())
200     {
201         _terrainTechnique->setTerrainTile(this);
202 
203         setDirtyMask(ALL_DIRTY);
204     }
205 }
206 
setDirtyMask(int dirtyMask)207 void TerrainTile::setDirtyMask(int dirtyMask)
208 {
209     if (_dirtyMask==dirtyMask) return;
210 
211     int dirtyDelta = (_dirtyMask==NOT_DIRTY) ? 0 : -1;
212 
213     _dirtyMask = dirtyMask;
214 
215     if (_dirtyMask!=NOT_DIRTY) dirtyDelta += 1;
216 
217     // setNumChildrenRequeingUpdateTraversal() isn't thread safe so should avoid using it.
218     if (dirtyDelta>0)
219     {
220         setNumChildrenRequiringUpdateTraversal(getNumChildrenRequiringUpdateTraversal()+1);
221     }
222     else if (dirtyDelta<0 && getNumChildrenRequiringUpdateTraversal()>0)
223     {
224         setNumChildrenRequiringUpdateTraversal(getNumChildrenRequiringUpdateTraversal()-1);
225     }
226 }
227 
228 
229 
setElevationLayer(Layer * layer)230 void TerrainTile::setElevationLayer(Layer* layer)
231 {
232     _elevationLayer = layer;
233 }
234 
setColorLayer(unsigned int i,Layer * layer)235 void TerrainTile::setColorLayer(unsigned int i, Layer* layer)
236 {
237     if (_colorLayers.size() <= i) _colorLayers.resize(i+1);
238 
239     _colorLayers[i] = layer;
240 }
241 
computeBound() const242 osg::BoundingSphere TerrainTile::computeBound() const
243 {
244     osg::BoundingSphere bs;
245 
246     if (_elevationLayer.valid())
247     {
248         bs.expandBy(_elevationLayer->computeBound(true));
249     }
250     else
251     {
252         for(Layers::const_iterator itr = _colorLayers.begin();
253             itr != _colorLayers.end();
254             ++itr)
255         {
256             if (itr->valid()) bs.expandBy((*itr)->computeBound(false));
257         }
258     }
259 
260     return bs;
261 }
262 
263 
264 /////////////////////////////////////////////////////////////////////////////////
265 //
266 // WhiteListTileLoadedCallback
267 //
WhiteListTileLoadedCallback()268 WhiteListTileLoadedCallback::WhiteListTileLoadedCallback()
269 {
270     _minumumNumberOfLayers = 0;
271     _replaceSwitchLayer = false;
272     _allowAll = false;
273 }
274 
~WhiteListTileLoadedCallback()275 WhiteListTileLoadedCallback::~WhiteListTileLoadedCallback()
276 {
277 }
278 
layerAcceptable(const std::string & setname) const279 bool WhiteListTileLoadedCallback::layerAcceptable(const std::string& setname) const
280 {
281     if (_allowAll) return true;
282 
283     if (setname.empty()) return true;
284 
285     return _setWhiteList.count(setname)!=0;
286 }
287 
readImageLayer(osgTerrain::ImageLayer * imageLayer,const osgDB::ReaderWriter::Options * options) const288 bool WhiteListTileLoadedCallback::readImageLayer(osgTerrain::ImageLayer* imageLayer, const osgDB::ReaderWriter::Options* options) const
289 {
290    if (!imageLayer->getImage() &&
291         !imageLayer->getFileName().empty())
292     {
293         if (layerAcceptable(imageLayer->getSetName()))
294         {
295             osg::ref_ptr<osg::Image> image = osgDB::readRefImageFile(imageLayer->getFileName(), options);
296             imageLayer->setImage(image.get());
297         }
298     }
299     return imageLayer->getImage()!=0;
300 }
301 
deferExternalLayerLoading() const302 bool WhiteListTileLoadedCallback::deferExternalLayerLoading() const
303 {
304     return true;
305 }
306 
loaded(osgTerrain::TerrainTile * tile,const osgDB::ReaderWriter::Options * options) const307 void WhiteListTileLoadedCallback::loaded(osgTerrain::TerrainTile* tile, const osgDB::ReaderWriter::Options* options) const
308 {
309 
310     // read any external layers
311     for(unsigned int i=0; i<tile->getNumColorLayers(); ++i)
312     {
313         osgTerrain::Layer* layer = tile->getColorLayer(i);
314         osgTerrain::ImageLayer* color_imageLayer = dynamic_cast<osgTerrain::ImageLayer*>(layer);
315         if (color_imageLayer)
316         {
317             readImageLayer(color_imageLayer, options);
318             continue;
319         }
320 
321         osgTerrain::SwitchLayer* switchLayer = dynamic_cast<osgTerrain::SwitchLayer*>(layer);
322         if (switchLayer)
323         {
324             for(unsigned int si=0; si<switchLayer->getNumLayers(); ++si)
325             {
326                 osgTerrain::ImageLayer* imageLayer = dynamic_cast<osgTerrain::ImageLayer*>(switchLayer->getLayer(si));
327                 if (imageLayer)
328                 {
329                     if (readImageLayer(imageLayer, options))
330                     {
331                         // replace SwitchLayer by
332                         if (_replaceSwitchLayer) tile->setColorLayer(i, imageLayer);
333                         else if (switchLayer->getActiveLayer()<0) switchLayer->setActiveLayer(si);
334 
335                         continue;
336                     }
337                 }
338             }
339             continue;
340         }
341 
342         osgTerrain::CompositeLayer* compositeLayer = dynamic_cast<osgTerrain::CompositeLayer*>(layer);
343         if (compositeLayer)
344         {
345             for(unsigned int ci=0; ci<compositeLayer->getNumLayers(); ++ci)
346             {
347                 osgTerrain::ImageLayer* imageLayer = dynamic_cast<osgTerrain::ImageLayer*>(compositeLayer->getLayer(ci));
348                 if (imageLayer)
349                 {
350                     readImageLayer(imageLayer, options);
351                 }
352             }
353             continue;
354         }
355     }
356 
357     // assign colour layers over missing layers
358     osgTerrain::Layer* validLayer = 0;
359     for(unsigned int i=0; i<tile->getNumColorLayers(); ++i)
360     {
361         osgTerrain::Layer* layer = tile->getColorLayer(i);
362         osgTerrain::ImageLayer* color_imageLayer = dynamic_cast<osgTerrain::ImageLayer*>(layer);
363         if (color_imageLayer)
364         {
365             if (color_imageLayer->getImage()!=0)
366             {
367                 validLayer = color_imageLayer;
368             }
369             continue;
370         }
371 
372         osgTerrain::SwitchLayer* switchLayer = dynamic_cast<osgTerrain::SwitchLayer*>(layer);
373         if (switchLayer)
374         {
375             for(unsigned int si=0; si<switchLayer->getNumLayers(); ++si)
376             {
377                 osgTerrain::ImageLayer* imageLayer = dynamic_cast<osgTerrain::ImageLayer*>(switchLayer->getLayer(si));
378                 if (imageLayer && imageLayer->getImage()!=0)
379                 {
380                     validLayer = imageLayer;
381                 }
382             }
383             continue;
384         }
385 
386         osgTerrain::CompositeLayer* compositeLayer = dynamic_cast<osgTerrain::CompositeLayer*>(layer);
387         if (compositeLayer)
388         {
389             for(unsigned int ci=0; ci<compositeLayer->getNumLayers(); ++ci)
390             {
391                 osgTerrain::ImageLayer* imageLayer = dynamic_cast<osgTerrain::ImageLayer*>(switchLayer->getLayer(ci));
392                 if (imageLayer && imageLayer->getImage()!=0)
393                 {
394                     validLayer = imageLayer;
395                 }
396             }
397             continue;
398         }
399     }
400 
401     if (validLayer)
402     {
403         // fill in any missing layers
404         for(unsigned int i=0; i<tile->getNumColorLayers(); ++i)
405         {
406             osgTerrain::Layer* layer = tile->getColorLayer(i);
407             osgTerrain::ImageLayer* color_imageLayer = dynamic_cast<osgTerrain::ImageLayer*>(layer);
408             if (color_imageLayer)
409             {
410                 if (color_imageLayer->getImage()==0)
411                 {
412                     tile->setColorLayer(i, validLayer);
413                     break;
414                 }
415                 continue;
416             }
417 
418             osgTerrain::SwitchLayer* switchLayer = dynamic_cast<osgTerrain::SwitchLayer*>(layer);
419             if (switchLayer)
420             {
421                 for(unsigned int si=0; si<switchLayer->getNumLayers(); ++si)
422                 {
423                     osgTerrain::ImageLayer* imageLayer = dynamic_cast<osgTerrain::ImageLayer*>(switchLayer->getLayer(si));
424                     if (imageLayer && imageLayer->getImage()==0)
425                     {
426                         if (_replaceSwitchLayer) tile->setColorLayer(i, imageLayer);
427                         else
428                         {
429                             switchLayer->setLayer(si, validLayer);
430                             if (switchLayer->getActiveLayer()<0) switchLayer->setActiveLayer(si);
431                         }
432                         break;
433                     }
434                 }
435                 if (switchLayer->getNumLayers()==0)
436                 {
437                     if (_replaceSwitchLayer) tile->setColorLayer(i, validLayer);
438                     else
439                     {
440                         switchLayer->setLayer(0, validLayer);
441                         switchLayer->setActiveLayer(0);
442                     }
443                 }
444             }
445 
446             osgTerrain::CompositeLayer* compositeLayer = dynamic_cast<osgTerrain::CompositeLayer*>(layer);
447             if (compositeLayer)
448             {
449                 for(unsigned int ci=0; ci<compositeLayer->getNumLayers(); ++ci)
450                 {
451                     osgTerrain::ImageLayer* imageLayer = dynamic_cast<osgTerrain::ImageLayer*>(switchLayer->getLayer(ci));
452                     if (imageLayer && imageLayer->getImage()==0)
453                     {
454                         tile->setColorLayer(i, validLayer);
455                         break;
456                     }
457                 }
458                 continue;
459             }
460         }
461 
462         if (_minumumNumberOfLayers>tile->getNumColorLayers())
463         {
464             for(unsigned int i=tile->getNumColorLayers(); i<_minumumNumberOfLayers; ++i)
465             {
466                 tile->setColorLayer(i, validLayer);
467             }
468         }
469 
470     }
471 }
472 
releaseGLObjects(osg::State * state) const473 void TerrainTile::releaseGLObjects(osg::State* state) const
474 {
475     Group::releaseGLObjects(state);
476 
477     if (_terrainTechnique.valid())
478     {
479         _terrainTechnique->releaseGLObjects( state );
480     }
481 }
482 
483