]> git.mxchange.org Git - flightgear.git/blobdiff - src/Scenery/newcache.cxx
Fix a bug in tile manager updating when switching from one view to the next.
[flightgear.git] / src / Scenery / newcache.cxx
index b83d3a3aabbbe718abd9c1f6839b3b4952937573..0ba6176f8acb61f26feb6301caa41976fcd7d3ae 100644 (file)
 #  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>
@@ -51,7 +44,7 @@ SG_USING_NAMESPACE(std);
 
 // Constructor
 FGNewCache::FGNewCache( void ) :
-    max_cache_size(50)
+    max_cache_size(100)
 {
     tile_cache.clear();
 }
@@ -88,7 +81,7 @@ void FGNewCache::init( void ) {
     SG_LOG( SG_TERRAIN, SG_INFO, "  current cache size = " 
            << tile_cache.size() );
 
-#if 0 // don't clear the cache right now
+#if 0 // don't clear the cache
     clear_cache();
 #endif
 
@@ -105,36 +98,161 @@ bool FGNewCache::exists( const SGBucket& b ) const {
 }
 
 
-// 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() );
+// Ensure at least one entry is free in the cache
+bool 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 );
 
-    // clear out a distant entry in the cache if needed.
-    make_space();
+    if ( (int)tile_cache.size() < max_cache_size ) {
+       // space in the cache, return
+       return true;
+    }
 
-    // create the entry
-    FGTileEntry *e = new FGTileEntry( b );
+    while ( (int)tile_cache.size() >= max_cache_size ) {
+       sgdVec3 abs_view_pos;
+       float dist;
+        double timestamp = 0.0;
+       int max_index = -1;
+        double min_time = 2419200000.0f;  // one month should be enough
+        double max_time = 0;
 
-    // register it in the cache
-    long tile_index = b.gen_index();
-    tile_cache[tile_index] = e;
+       // 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) ) {
+
+                timestamp = e->get_timestamp();
+                if ( timestamp < min_time ) {
+                    max_index = index;
+                    min_time = timestamp;
+                }
+                if ( timestamp > max_time ) {
+                    max_time = timestamp;
+                }
+
+           } else {
+                SG_LOG( SG_TERRAIN, SG_DEBUG, "loaded = " << e->is_loaded()
+                        << " pending models = " << e->get_pending_models()
+                        << " time stamp = " << e->get_timestamp() );
+            }
+       }
 
-    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" );
+       // If we made it this far, then there were no open cache entries.
+       // We will instead free the oldest cache entry and return true
+        
+        SG_LOG( SG_TERRAIN, SG_DEBUG, "    min_time = " << min_time );
+        SG_LOG( SG_TERRAIN, SG_DEBUG, "    index = " << max_index );
+        SG_LOG( SG_TERRAIN, SG_DEBUG, "    max_time = " << max_time );
+       if ( max_index >= 0 ) {
+           entry_free( max_index );
+           return true;
+       } else {
+           SG_LOG( SG_TERRAIN, SG_ALERT, "WHOOPS!!! can't make_space(), tile "
+                    "cache is full, but no entries available for removal." );
+           return false;
+       }
     }
-    
-    // Load the appropriate data file
-    e->load( tile_path, true );
+
+    SG_LOG( SG_TERRAIN, SG_ALERT, "WHOOPS!!! Hit an unhandled condition in  "
+            "FGNewCache::make_space()." );
+    return false;
 }
 #endif
 
 
+// Return the index of the oldest tile in the cache, return -1 if
+// nothing available to be removed.
+long FGNewCache::get_oldest_tile() {
+    // we need to free the furthest entry
+    long min_index = -1;
+    double timestamp = 0.0;
+    double min_time = 2419200000.0f; // one month should be enough
+    double max_time = 0;
+
+    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) ) {
+            
+            timestamp = e->get_timestamp();
+            if ( timestamp < min_time ) {
+                min_index = index;
+                min_time = timestamp;
+            }
+            if ( timestamp > max_time ) {
+                max_time = timestamp;
+            }
+
+        } else {
+            SG_LOG( SG_TERRAIN, SG_DEBUG, "loaded = " << e->is_loaded()
+                    << " pending models = " << e->get_pending_models()
+                    << " time stamp = " << e->get_timestamp() );
+        }
+    }
+
+    SG_LOG( SG_TERRAIN, SG_DEBUG, "    min_time = " << min_time );
+    SG_LOG( SG_TERRAIN, SG_DEBUG, "    index = " << min_index );
+    SG_LOG( SG_TERRAIN, SG_DEBUG, "    max_time = " << max_time );
+
+    return min_index;
+}
+
+
+// Clear a cache entry, note that the cache only holds pointers
+// and this does not free the object which is pointed to.
+void FGNewCache::clear_entry( long cache_index ) {
+    tile_cache.erase( cache_index );
+}
+
+
+// Clear all completely loaded tiles (ignores partially loaded tiles)
+void FGNewCache::clear_cache() {
+
+    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;
+        if ( e->is_loaded() && (e->get_pending_models() == 0) ) {
+            e->tile_bucket.make_bad();
+            entry_free(index);
+        }
+    }
+
+    // and ... just in case we missed something ... 
+    globals->get_scenery()->get_terrain_branch()->removeAllKids();
+}
+
+
+/**
+ * Create a new tile and schedule it for loading.
+ */
+bool FGNewCache::insert_tile( FGTileEntry *e ) {
+    // set time of insertion for tracking age of tiles...
+    e->set_timestamp(globals->get_sim_time_sec());
+
+    // register it in the cache
+    long tile_index = e->get_tile_bucket().gen_index();
+    tile_cache[tile_index] = e;
+
+    return true;
+}
+
+
+// Note this is the old version of FGNewCache::make_space(), currently disabled
+// It uses distance from a center point to determine tiles to be discarded...
+#if 0
 // Ensure at least one entry is free in the cache
 bool FGNewCache::make_space() {
     SG_LOG( SG_TERRAIN, SG_DEBUG, "Make space in cache" );
@@ -160,10 +278,10 @@ bool FGNewCache::make_space() {
            long index = current->first;
            FGTileEntry *e = current->second;
 
-           if ( e->is_loaded() && e->get_pending_models() == 0 ) {
+           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() );
+                            globals->get_current_view()->get_absolute_view_pos() );
 
                SG_LOG( SG_TERRAIN, SG_DEBUG, "DIST Abs view pos = " 
                        << abs_view_pos[0] << ","
@@ -183,63 +301,31 @@ bool FGNewCache::make_space() {
                    max_dist = dist;
                    max_index = index;
                }
-           }
+           } else {
+                SG_LOG( SG_TERRAIN, SG_INFO, "loaded = " << e->is_loaded()
+                        << " pending models = " << e->get_pending_models() );
+            }
        }
 
        // If we made it this far, then there were no open cache entries.
        // We will instead free the furthest cache entry and return true
-
+        
+        SG_LOG( SG_TERRAIN, SG_INFO, "    max_dist = " << max_dist );
+        SG_LOG( SG_TERRAIN, SG_INFO, "    index = " << max_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 );
            return true;
        } else {
            SG_LOG( SG_TERRAIN, SG_ALERT, "WHOOPS!!! can't make_space(), tile "
-                    "cache is full, but no entries available to removal." );
+                    "cache is full, but no entries available for removal." );
            return false;
        }
     }
-}
-
-
-// Clear all completely loaded tiles (ignores partially loaded tiles)
-void FGNewCache::clear_cache() {
-    // This is a hack that should really get cleaned up at some point
-    extern ssgBranch *terrain;
-
-    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;
-        if ( e->is_loaded() && e->get_pending_models() == 0 ) {
-            e->tile_bucket.make_bad();
-            entry_free(index);
-        }
-    }
 
-    // and ... just in case we missed something ... 
-    terrain->removeAllKids();
+    SG_LOG( SG_TERRAIN, SG_ALERT, "WHOOPS!!! Hit an unhandled condition in  "
+            "FGNewCache::make_space()." );
+    return false;
 }
+#endif
 
 
-/**
- * Create a new tile and schedule it for loading.
- */
-bool FGNewCache::insert_tile( FGTileEntry *e ) {
-    // clear out a distant entry in the cache if needed.
-    if ( make_space() ) {
-      // register it in the cache
-      long tile_index = e->get_tile_bucket().gen_index();
-      tile_cache[tile_index] = e;
-
-      return true;
-    } else {
-      // failed to find cache space
-
-      return false;
-    }
-}