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