1
0
Fork 0
flightgear/src/Scenery/newcache.cxx
curt 2afcbb4bc8 We can't remove ssg branches in the threaded tile page because if we happen
to have attached an ssg loaded object to this branch, then plib will remove
it and all it's states (and textures) which will call opengl api commands
which will crash the program if run from a separate thread from the main render
thread.
2001-05-20 06:49:06 +00:00

231 lines
6.1 KiB
C++

// newcache.cxx -- routines to handle scenery tile caching
//
// Written by Curtis Olson, started December 2000.
//
// Copyright (C) 2000 Curtis L. Olson - curt@flightgear.org
//
// 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef HAVE_WINDOWS_H
# include <windows.h>
#endif
#include <GL/glut.h>
#include <GL/gl.h>
#include <plib/ssg.h> // plib include
#include <simgear/bucket/newbucket.hxx>
#include <simgear/debug/logstream.hxx>
#include <simgear/misc/sg_path.hxx>
#include <Main/globals.hxx>
#include <Scenery/scenery.hxx> // for scenery.center
#include "newcache.hxx"
#include "tileentry.hxx"
SG_USING_NAMESPACE(std);
// Constructor
FGNewCache::FGNewCache( void ) {
tile_cache.clear();
}
// Destructor
FGNewCache::~FGNewCache( void ) {
}
// Free a tile cache entry
void FGNewCache::entry_free( long cache_index ) {
SG_LOG( SG_TERRAIN, SG_DEBUG, "FREEING CACHE ENTRY = " << cache_index );
FGTileEntry *tile = tile_cache[cache_index];
tile->disconnect_ssg_nodes();
#ifdef WISH_PLIB_WAS_THREADED
tile->sched_removal();
#else // plib isn't threaded so we always go here
tile->free_tile();
delete tile;
#endif
tile_cache.erase( cache_index );
}
// Initialize the tile cache subsystem
void FGNewCache::init( void ) {
// This is a hack that should really get cleaned up at some point
extern ssgBranch *terrain;
SG_LOG( SG_TERRAIN, SG_INFO, "Initializing the tile cache." );
// expand cache if needed. For best results ... i.e. to avoid
// tile load problems and blank areas:
max_cache_size = 50; // a random number to start with
SG_LOG( SG_TERRAIN, SG_INFO, " max cache size = "
<< max_cache_size );
SG_LOG( SG_TERRAIN, SG_INFO, " current cache size = "
<< tile_cache.size() );
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 );
FGTileEntry *e = current->second;
e->tile_bucket.make_bad();
entry_free(index);
}
// and ... just in case we missed something ...
terrain->removeAllKids();
SG_LOG( SG_TERRAIN, SG_INFO, " done with init()" );
}
// Search for the specified "bucket" in the cache
bool FGNewCache::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() );
}
// depricated for threading
#if 0
// Fill in a tile cache entry with real data for the specified bucket
void FGNewCache::fill_in( const SGBucket& b ) {
SG_LOG( SG_TERRAIN, SG_DEBUG, "FILL IN CACHE ENTRY = " << b.gen_index() );
// clear out a distant entry in the cache if needed.
make_space();
// create the entry
FGTileEntry *e = new FGTileEntry( b );
// register it in the cache
long tile_index = b.gen_index();
tile_cache[tile_index] = e;
SGPath tile_path;
if ( globals->get_fg_scenery() != (string)"" ) {
tile_path.set( globals->get_fg_scenery() );
} else {
tile_path.set( globals->get_fg_root() );
tile_path.append( "Scenery" );
}
// Load the appropriate data file
e->load( tile_path, true );
}
#endif
// Ensure at least one entry is free in the cache
void FGNewCache::make_space() {
SG_LOG( SG_TERRAIN, SG_DEBUG, "Make space in cache" );
SG_LOG( SG_TERRAIN, SG_DEBUG, "cache entries = " << tile_cache.size() );
SG_LOG( SG_TERRAIN, SG_DEBUG, "max size = " << max_cache_size );
if ( (int)tile_cache.size() < max_cache_size ) {
// space in the cache, return
return;
}
while ( (int)tile_cache.size() >= max_cache_size ) {
sgdVec3 abs_view_pos;
float dist;
float max_dist = 0.0;
int max_index = -1;
// we need to free the furthest entry
tile_map_iterator current = tile_cache.begin();
tile_map_iterator end = tile_cache.end();
for ( ; current != end; ++current ) {
long index = current->first;
FGTileEntry *e = current->second;
if ( e->is_loaded() && e->get_pending_models() == 0 ) {
// calculate approximate distance from view point
sgdCopyVec3( abs_view_pos,
globals->get_current_view()->get_abs_view_pos() );
SG_LOG( SG_TERRAIN, SG_DEBUG, "DIST Abs view pos = "
<< abs_view_pos[0] << ","
<< abs_view_pos[1] << ","
<< abs_view_pos[2] );
SG_LOG( SG_TERRAIN, SG_DEBUG,
" ref point = " << e->center );
sgdVec3 center;
sgdSetVec3( center,
e->center.x(), e->center.y(), e->center.z() );
dist = sgdDistanceVec3( center, abs_view_pos );
SG_LOG( SG_TERRAIN, SG_DEBUG, " distance = " << dist );
if ( dist > max_dist ) {
max_dist = dist;
max_index = index;
}
}
}
// If we made it this far, then there were no open cache entries.
// We will instead free the furthest cache entry and return it's
// index.
if ( max_index >= 0 ) {
SG_LOG( SG_TERRAIN, SG_DEBUG, " max_dist = " << max_dist );
SG_LOG( SG_TERRAIN, SG_DEBUG, " index = " << max_index );
entry_free( max_index );
} else {
SG_LOG( SG_TERRAIN, SG_ALERT, "WHOOPS!!! Dying in next_avail()" );
exit( -1 );
}
}
}
/**
* Create a new tile and schedule it for loading.
*/
void
FGNewCache::insert_tile( FGTileEntry *e )
{
// clear out a distant entry in the cache if needed.
make_space();
// register it in the cache
long tile_index = e->get_tile_bucket().gen_index();
tile_cache[tile_index] = e;
}