1
0
Fork 0

scenery: Move flightgears paging back into the application.

This way of scenery paging is really application code.
Now that the simgear stg loader is seperated from the paging
code, this appication specific paging can reside here.
May be at some time also use the spt stuff here.
This commit is contained in:
Mathias Froehlich 2012-03-15 20:56:37 +01:00
parent 44c716bb03
commit 1ddb658a70
9 changed files with 647 additions and 9 deletions

View file

@ -27,7 +27,6 @@
#include <simgear/scene/material/matlib.hxx>
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
#include <simgear/scene/tgdb/userdata.hxx>
#include <simgear/scene/tgdb/TileEntry.hxx>
#include <simgear/scene/model/ModelRegistry.hxx>
#include <simgear/scene/model/modellib.hxx>

View file

@ -4,6 +4,8 @@ set(SOURCES
SceneryPager.cxx
redout.cxx
scenery.cxx
tilecache.cxx
tileentry.cxx
tilemgr.cxx
)
@ -11,8 +13,9 @@ set(HEADERS
SceneryPager.hxx
redout.hxx
scenery.hxx
tilecache.hxx
tileentry.hxx
tilemgr.hxx
)
flightgear_component(Scenery "${SOURCES}" "${HEADERS}")

218
src/Scenery/tilecache.cxx Normal file
View file

@ -0,0 +1,218 @@
// TileCache.cxx -- routines to handle scenery tile caching
//
// Written by Curtis Olson, started December 2000.
//
// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <simgear/bucket/newbucket.hxx>
#include <simgear/debug/logstream.hxx>
#include <simgear/misc/sg_path.hxx>
#include "tileentry.hxx"
#include "tilecache.hxx"
TileCache::TileCache( void ) :
max_cache_size(100), current_time(0.0)
{
tile_cache.clear();
}
TileCache::~TileCache( void ) {
clear_cache();
}
// Free a tile cache entry
void TileCache::entry_free( long tile_index ) {
SG_LOG( SG_TERRAIN, SG_DEBUG, "FREEING CACHE ENTRY = " << tile_index );
TileEntry *tile = tile_cache[tile_index];
tile->removeFromSceneGraph();
tile_cache.erase( tile_index );
delete tile;
}
// Initialize the tile cache subsystem
void TileCache::init( void ) {
SG_LOG( SG_TERRAIN, SG_INFO, "Initializing the tile cache." );
SG_LOG( SG_TERRAIN, SG_INFO, " max cache size = "
<< max_cache_size );
SG_LOG( SG_TERRAIN, SG_INFO, " current cache size = "
<< tile_cache.size() );
clear_cache();
SG_LOG( SG_TERRAIN, SG_INFO, " done with init()" );
}
// Search for the specified "bucket" in the cache
bool TileCache::exists( const SGBucket& b ) const {
long tile_index = b.gen_index();
const_tile_map_iterator it = tile_cache.find( tile_index );
return ( it != tile_cache.end() );
}
// Return the index of a tile to be dropped from the cache, return -1 if
// nothing available to be removed.
long TileCache::get_drop_tile() {
long min_index = -1;
double min_time = DBL_MAX;
float priority = FLT_MAX;
tile_map_iterator current = tile_cache.begin();
tile_map_iterator end = tile_cache.end();
for ( ; current != end; ++current ) {
long index = current->first;
TileEntry *e = current->second;
if (( !e->is_current_view() )&&
( e->is_expired(current_time) ))
{
if (e->is_expired(current_time - 1.0)&&
!e->is_loaded())
{
/* Immediately drop "empty" tiles which are no longer used/requested, and were last requested > 1 second ago...
* Allow a 1 second timeout since an empty tiles may just be loaded...
*/
SG_LOG( SG_TERRAIN, SG_DEBUG, " dropping an unused and empty tile");
break;
}
if (( e->get_time_expired() < min_time )||
(( e->get_time_expired() == min_time)&&
( priority > e->get_priority())))
{
// drop oldest tile with lowest priority
min_time = e->get_time_expired();
priority = e->get_priority();
min_index = index;
}
}
}
SG_LOG( SG_TERRAIN, SG_DEBUG, " index = " << min_index );
SG_LOG( SG_TERRAIN, SG_DEBUG, " min_time = " << min_time );
return min_index;
}
// Clear all flags indicating tiles belonging to the current view
void TileCache::clear_current_view()
{
tile_map_iterator current = tile_cache.begin();
tile_map_iterator end = tile_cache.end();
for ( ; current != end; ++current ) {
TileEntry *e = current->second;
if (e->is_current_view())
{
// update expiry time for tiles belonging to most recent position
e->update_time_expired( current_time );
e->set_current_view( false );
}
}
}
// Clear a cache entry, note that the cache only holds pointers
// and this does not free the object which is pointed to.
void TileCache::clear_entry( long tile_index ) {
tile_cache.erase( tile_index );
}
// Clear all completely loaded tiles (ignores partially loaded tiles)
void TileCache::clear_cache() {
std::vector<long> indexList;
tile_map_iterator current = tile_cache.begin();
tile_map_iterator end = tile_cache.end();
for ( ; current != end; ++current ) {
long index = current->first;
SG_LOG( SG_TERRAIN, SG_DEBUG, "clearing " << index );
TileEntry *e = current->second;
if ( e->is_loaded() ) {
e->tile_bucket.make_bad();
// entry_free modifies tile_cache, so store index and call entry_free() later;
indexList.push_back( index);
}
}
for (unsigned int it = 0; it < indexList.size(); it++) {
entry_free( indexList[ it]);
}
}
/**
* Create a new tile and schedule it for loading.
*/
bool TileCache::insert_tile( TileEntry *e ) {
// register tile in the cache
long tile_index = e->get_tile_bucket().gen_index();
tile_cache[tile_index] = e;
e->update_time_expired(current_time);
return true;
}
/**
* Reloads a tile when it's already in memory.
*/
void TileCache::refresh_tile(long tile_index)
{
const_tile_map_iterator it = tile_cache.find( tile_index );
if ( it == tile_cache.end() )
return;
SG_LOG( SG_TERRAIN, SG_DEBUG, "REFRESHING CACHE ENTRY = " << tile_index );
if (it->second)
it->second->refresh();
}
// update tile's priority and expiry time according to current request
void TileCache::request_tile(TileEntry* t,float priority,bool current_view,double request_time)
{
if ((!current_view)&&(request_time<=0.0))
return;
// update priority when higher - or old request has expired
if ((t->is_expired(current_time))||
(priority > t->get_priority()))
{
t->set_priority( priority );
}
if (current_view)
{
t->update_time_expired( current_time );
t->set_current_view( true );
}
else
{
t->update_time_expired( current_time+request_time );
}
}

134
src/Scenery/tilecache.hxx Normal file
View file

@ -0,0 +1,134 @@
// TileCache.hxx -- routines to handle scenery tile caching
//
// Written by Curtis Olson, started December 2000.
//
// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifndef _TILECACHE_HXX
#define _TILECACHE_HXX
#include <map>
#include <simgear/bucket/newbucket.hxx>
#include "tileentry.hxx"
using std::map;
// A class to store and manage a pile of tiles
class TileCache {
public:
typedef map < long, TileEntry * > tile_map;
typedef tile_map::iterator tile_map_iterator;
typedef tile_map::const_iterator const_tile_map_iterator;
private:
// cache storage space
tile_map tile_cache;
// maximum cache size
int max_cache_size;
// pointers to allow an external linear traversal of cache entries
tile_map_iterator current;
double current_time;
// Free a tile cache entry
void entry_free( long cache_index );
public:
tile_map_iterator begin() { return tile_cache.begin(); }
tile_map_iterator end() { return tile_cache.end(); }
const_tile_map_iterator begin() const { return tile_cache.begin(); }
const_tile_map_iterator end() const { return tile_cache.end(); }
// Constructor
TileCache();
// Destructor
~TileCache();
// Initialize the tile cache subsystem
void init( void );
// Check if the specified "bucket" exists in the cache
bool exists( const SGBucket& b ) const;
// Return the index of a tile to be dropped from the cache, return -1 if
// nothing available to be removed.
long get_drop_tile();
// Clear all flags indicating tiles belonging to the current view
void clear_current_view();
// Clear a cache entry, note that the cache only holds pointers
// and this does not free the object which is pointed to.
void clear_entry( long cache_entry );
// Refresh/reload a tile when it's already in memory.
void refresh_tile(long tile_index);
// Clear all completely loaded tiles (ignores partially loaded tiles)
void clear_cache();
// Return a pointer to the specified tile cache entry
inline TileEntry *get_tile( const long tile_index ) const {
const_tile_map_iterator it = tile_cache.find( tile_index );
if ( it != tile_cache.end() ) {
return it->second;
} else {
return NULL;
}
}
// Return a pointer to the specified tile cache entry
inline TileEntry *get_tile( const SGBucket& b ) const {
return get_tile( b.gen_index() );
}
// Return the cache size
inline size_t get_size() const { return tile_cache.size(); }
// External linear traversal of cache
inline void reset_traversal() { current = tile_cache.begin(); }
inline bool at_end() { return current == tile_cache.end(); }
inline TileEntry *get_current() const {
// cout << "index = " << current->first << endl;
return current->second;
}
inline void next() { ++current; }
inline int get_max_cache_size() const { return max_cache_size; }
inline void set_max_cache_size( int m ) { max_cache_size = m; }
/**
* Create a new tile and enqueue it for loading.
* @param b
* @return success/failure
*/
bool insert_tile( TileEntry* e );
void set_current_time(double val) { current_time = val; }
double get_current_time() const { return current_time; }
// update tile's priority and expiry time according to current request
void request_tile(TileEntry* t,float priority,bool current_view,double requesttime);
};
#endif // _TILECACHE_HXX

137
src/Scenery/tileentry.cxx Normal file
View file

@ -0,0 +1,137 @@
// tileentry.cxx -- routines to handle a scenery tile
//
// Written by Curtis Olson, started May 1998.
//
// Copyright (C) 1998 - 2001 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <simgear/compiler.h>
#include <string>
#include <sstream>
#include <istream>
#include <osg/LOD>
#include <simgear/bucket/newbucket.hxx>
#include <simgear/debug/logstream.hxx>
#include "tileentry.hxx"
using std::string;
// Constructor
TileEntry::TileEntry ( const SGBucket& b )
: tile_bucket( b ),
tileFileName(b.gen_index_str()),
_node( new osg::LOD ),
_priority(-FLT_MAX),
_current_view(false),
_time_expired(-1.0)
{
tileFileName += ".stg";
_node->setName(tileFileName);
// Give a default LOD range so that traversals that traverse
// active children (like the groundcache lookup) will work before
// tile manager has had a chance to update this node.
_node->setRange(0, 0.0, 10000.0);
}
TileEntry::TileEntry( const TileEntry& t )
: tile_bucket( t.tile_bucket ),
tileFileName(t.tileFileName),
_node( new osg::LOD ),
_priority(t._priority),
_current_view(t._current_view),
_time_expired(t._time_expired)
{
_node->setName(tileFileName);
// Give a default LOD range so that traversals that traverse
// active children (like the groundcache lookup) will work before
// tile manager has had a chance to update this node.
_node->setRange(0, 0.0, 10000.0);
}
// Destructor
TileEntry::~TileEntry ()
{
}
// Update the ssg transform node for this tile so it can be
// properly drawn relative to our (0,0,0) point
void TileEntry::prep_ssg_node(float vis) {
if (!is_loaded())
return;
// visibility can change from frame to frame so we update the
// range selector cutoff's each time.
float bounding_radius = _node->getChild(0)->getBound().radius();
_node->setRange( 0, 0, vis + bounding_radius );
}
void
TileEntry::addToSceneGraph(osg::Group *terrain_branch)
{
terrain_branch->addChild( _node.get() );
SG_LOG( SG_TERRAIN, SG_DEBUG,
"connected a tile into scene graph. _node = "
<< _node.get() );
SG_LOG( SG_TERRAIN, SG_DEBUG, "num parents now = "
<< _node->getNumParents() );
}
void
TileEntry::removeFromSceneGraph()
{
SG_LOG( SG_TERRAIN, SG_DEBUG, "disconnecting TileEntry nodes" );
if (! is_loaded()) {
SG_LOG( SG_TERRAIN, SG_DEBUG, "removing a not-fully loaded tile!" );
} else {
SG_LOG( SG_TERRAIN, SG_DEBUG, "removing a fully loaded tile! _node = " << _node.get() );
}
// find the nodes branch parent
if ( _node->getNumParents() > 0 ) {
// find the first parent (should only be one)
osg::Group *parent = _node->getParent( 0 ) ;
if( parent ) {
parent->removeChild( _node.get() );
}
}
}
void
TileEntry::refresh()
{
osg::Group *parent = NULL;
// find the nodes branch parent
if ( _node->getNumParents() > 0 ) {
// find the first parent (should only be one)
parent = _node->getParent( 0 ) ;
if( parent ) {
parent->removeChild( _node.get() );
}
}
_node = new osg::LOD;
if (parent)
parent->addChild(_node.get());
}

150
src/Scenery/tileentry.hxx Normal file
View file

@ -0,0 +1,150 @@
// tileentry.hxx -- routines to handle an individual scenery tile
//
// Written by Curtis Olson, started May 1998.
//
// Copyright (C) 1998 - 2001 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifndef _TILEENTRY_HXX
#define _TILEENTRY_HXX
#ifndef __cplusplus
# error This library requires C++
#endif
#include <simgear/compiler.h>
#include <vector>
#include <string>
#include <simgear/bucket/newbucket.hxx>
#include <simgear/misc/sg_path.hxx>
#include <osg/ref_ptr>
#include <osgDB/ReaderWriter>
#include <osg/Group>
#include <osg/LOD>
/**
* A class to encapsulate everything we need to know about a scenery tile.
*/
class TileEntry {
public:
// this tile's official location in the world
SGBucket tile_bucket;
std::string tileFileName;
private:
// pointer to ssg range selector for this tile
osg::ref_ptr<osg::LOD> _node;
// Reference to DatabaseRequest object set and used by the
// osgDB::DatabasePager.
osg::ref_ptr<osg::Referenced> _databaseRequest;
/**
* This value is used by the tile scheduler/loader to load tiles
* in a useful sequence. The priority is set to reflect the tiles
* distance from the center, so all tiles are loaded in an innermost
* to outermost sequence.
*/
float _priority;
/** Flag indicating if tile belongs to current view. */
bool _current_view;
/** Time when tile expires. */
double _time_expired;
public:
// Constructor
TileEntry( const SGBucket& b );
TileEntry( const TileEntry& t );
// Destructor
~TileEntry();
// Update the ssg transform node for this tile so it can be
// properly drawn relative to our (0,0,0) point
void prep_ssg_node(float vis);
/**
* Transition to OSG database pager
*/
static osg::Node* loadTileByFileName(const std::string& index_str,
const osgDB::Options*);
/**
* Return true if the tile entry is loaded, otherwise return false
* indicating that the loading thread is still working on this.
*/
inline bool is_loaded() const
{
return _node->getNumChildren() > 0;
}
/**
* Return the "bucket" for this tile
*/
inline const SGBucket& get_tile_bucket() const { return tile_bucket; }
/**
* Add terrain mesh and ground lighting to scene graph.
*/
void addToSceneGraph( osg::Group *terrain_branch);
/**
* disconnect terrain mesh and ground lighting nodes from scene
* graph for this tile.
*/
void removeFromSceneGraph();
/**
* Refresh a tile, reload the node from disk.
*/
void refresh();
/**
* return the scenegraph node for the terrain
*/
osg::LOD *getNode() const { return _node.get(); }
inline double get_time_expired() const { return _time_expired; }
inline void update_time_expired( double time_expired ) { if (_time_expired<time_expired) _time_expired = time_expired; }
inline void set_priority(float priority) { _priority=priority; }
inline float get_priority() const { return _priority; }
inline void set_current_view(bool current_view) { _current_view = current_view; }
inline bool is_current_view() const { return _current_view; }
/**
* Return true if the tile entry is still needed, otherwise return false
* indicating that the tile is no longer in active use.
*/
inline bool is_expired(double current_time) const { return (_current_view) ? false : (current_time > _time_expired); }
// Get the ref_ptr to the DatabaseRequest object, in order to pass
// this to the pager.
osg::ref_ptr<osg::Referenced>& getDatabaseRequest()
{
return _databaseRequest;
}
};
#endif // _TILEENTRY_HXX

View file

@ -49,8 +49,6 @@
#include "tilemgr.hxx"
using flightgear::SceneryPager;
using simgear::TileEntry;
using simgear::TileCache;
FGTileMgr::FGTileMgr():

View file

@ -28,8 +28,8 @@
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/bucket/newbucket.hxx>
#include <simgear/scene/tgdb/TileEntry.hxx>
#include <simgear/scene/tgdb/TileCache.hxx>
#include "tileentry.hxx"
#include "tilecache.hxx"
namespace osg
{
@ -78,7 +78,7 @@ private:
/**
* tile cache
*/
simgear::TileCache tile_cache;
TileCache tile_cache;
simgear::SGTerraSync* _terra_sync;
// Update the various queues maintained by the tilemagr (private

View file

@ -44,7 +44,6 @@
#include <simgear/scene/util/OsgMath.hxx>
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
#include <simgear/scene/tgdb/userdata.hxx>
#include <simgear/scene/tgdb/TileEntry.hxx>
#include <simgear/scene/model/ModelRegistry.hxx>
#include <simgear/scene/model/modellib.hxx>