]> git.mxchange.org Git - flightgear.git/blob - src/Scenery/newcache.cxx
Small tweaks to initialization sequence and logic so we can default to
[flightgear.git] / src / Scenery / newcache.cxx
1 // newcache.cxx -- routines to handle scenery tile caching
2 //
3 // Written by Curtis Olson, started December 2000.
4 //
5 // Copyright (C) 2000  Curtis L. Olson  - curt@flightgear.org
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 //
21 // $Id$
22
23
24 #ifdef HAVE_CONFIG_H
25 #  include <config.h>
26 #endif
27
28 #ifdef HAVE_WINDOWS_H
29 #  include <windows.h>
30 #endif
31
32 #include <GL/glut.h>
33 #include <GL/gl.h>
34
35 #include <plib/ssg.h>           // plib include
36
37 #include <simgear/bucket/newbucket.hxx>
38 #include <simgear/debug/logstream.hxx>
39 #include <simgear/misc/sg_path.hxx>
40
41 #include <Main/globals.hxx>
42 #include <Main/viewer.hxx>
43 #include <Scenery/scenery.hxx>  // for scenery.center
44
45 #include "newcache.hxx"
46 #include "tileentry.hxx"
47
48
49 SG_USING_NAMESPACE(std);
50
51
52 // Constructor
53 FGNewCache::FGNewCache( void ) :
54     max_cache_size(50)
55 {
56     tile_cache.clear();
57 }
58
59
60 // Destructor
61 FGNewCache::~FGNewCache( void ) {
62 }
63
64
65 // Free a tile cache entry
66 void FGNewCache::entry_free( long cache_index ) {
67     SG_LOG( SG_TERRAIN, SG_DEBUG, "FREEING CACHE ENTRY = " << cache_index );
68     FGTileEntry *tile = tile_cache[cache_index];
69     tile->disconnect_ssg_nodes();
70
71 #ifdef WISH_PLIB_WAS_THREADED // but it isn't
72     tile->sched_removal();
73 #else
74     tile->free_tile();
75     delete tile;
76 #endif
77
78     tile_cache.erase( cache_index );
79 }
80
81
82 // Initialize the tile cache subsystem
83 void FGNewCache::init( void ) {
84     SG_LOG( SG_TERRAIN, SG_INFO, "Initializing the tile cache." );
85
86     SG_LOG( SG_TERRAIN, SG_INFO, "  max cache size = " 
87             << max_cache_size );
88     SG_LOG( SG_TERRAIN, SG_INFO, "  current cache size = " 
89             << tile_cache.size() );
90
91 #if 0 // don't clear the cache
92     clear_cache();
93 #endif
94
95     SG_LOG( SG_TERRAIN, SG_INFO, "  done with init()"  );
96 }
97
98
99 // Search for the specified "bucket" in the cache
100 bool FGNewCache::exists( const SGBucket& b ) const {
101     long tile_index = b.gen_index();
102     const_tile_map_iterator it = tile_cache.find( tile_index );
103
104     return ( it != tile_cache.end() );
105 }
106
107
108 // Ensure at least one entry is free in the cache
109 bool FGNewCache::make_space() {
110     SG_LOG( SG_TERRAIN, SG_DEBUG, "Make space in cache" );
111     SG_LOG( SG_TERRAIN, SG_DEBUG, "cache entries = " << tile_cache.size() );
112     SG_LOG( SG_TERRAIN, SG_DEBUG, "max size = " << max_cache_size );
113
114     if ( (int)tile_cache.size() < max_cache_size ) {
115         // space in the cache, return
116         return true;
117     }
118
119     while ( (int)tile_cache.size() >= max_cache_size ) {
120         sgdVec3 abs_view_pos;
121         float dist;
122         float max_dist = 0.0;
123         int max_index = -1;
124
125         // we need to free the furthest entry
126         tile_map_iterator current = tile_cache.begin();
127         tile_map_iterator end = tile_cache.end();
128     
129         for ( ; current != end; ++current ) {
130             long index = current->first;
131             FGTileEntry *e = current->second;
132
133             if ( e->is_loaded() && (e->get_pending_models() == 0) ) {
134                 // calculate approximate distance from view point
135                 sgdCopyVec3( abs_view_pos,
136                              globals->get_current_view()->get_abs_view_pos() );
137
138                 SG_LOG( SG_TERRAIN, SG_DEBUG, "DIST Abs view pos = " 
139                         << abs_view_pos[0] << ","
140                         << abs_view_pos[1] << ","
141                         << abs_view_pos[2] );
142                 SG_LOG( SG_TERRAIN, SG_DEBUG,
143                         "    ref point = " << e->center );
144
145                 sgdVec3 center;
146                 sgdSetVec3( center,
147                             e->center.x(), e->center.y(), e->center.z() );
148                 dist = sgdDistanceVec3( center, abs_view_pos );
149
150                 SG_LOG( SG_TERRAIN, SG_DEBUG, "    distance = " << dist );
151
152                 if ( dist > max_dist ) {
153                     max_dist = dist;
154                     max_index = index;
155                 }
156             } else {
157                 SG_LOG( SG_TERRAIN, SG_INFO, "loaded = " << e->is_loaded()
158                         << " pending models = " << e->get_pending_models() );
159             }
160         }
161
162         // If we made it this far, then there were no open cache entries.
163         // We will instead free the furthest cache entry and return true
164         
165         SG_LOG( SG_TERRAIN, SG_INFO, "    max_dist = " << max_dist );
166         SG_LOG( SG_TERRAIN, SG_INFO, "    index = " << max_index );
167         if ( max_index >= 0 ) {
168             entry_free( max_index );
169             return true;
170         } else {
171             SG_LOG( SG_TERRAIN, SG_ALERT, "WHOOPS!!! can't make_space(), tile "
172                     "cache is full, but no entries available for removal." );
173             return false;
174         }
175     }
176 }
177
178
179 // Clear all completely loaded tiles (ignores partially loaded tiles)
180 void FGNewCache::clear_cache() {
181     // This is a hack that should really get cleaned up at some point
182     extern ssgBranch *terrain;
183
184     tile_map_iterator current = tile_cache.begin();
185     tile_map_iterator end = tile_cache.end();
186     
187     for ( ; current != end; ++current ) {
188         long index = current->first;
189         SG_LOG( SG_TERRAIN, SG_DEBUG, "clearing " << index );
190         FGTileEntry *e = current->second;
191         if ( e->is_loaded() && (e->get_pending_models() == 0) ) {
192             e->tile_bucket.make_bad();
193             entry_free(index);
194         }
195     }
196
197     // and ... just in case we missed something ... 
198     terrain->removeAllKids();
199 }
200
201
202 /**
203  * Create a new tile and schedule it for loading.
204  */
205 bool FGNewCache::insert_tile( FGTileEntry *e ) {
206     // clear out a distant entry in the cache if needed.
207     if ( make_space() ) {
208         // register it in the cache
209         long tile_index = e->get_tile_bucket().gen_index();
210         tile_cache[tile_index] = e;
211
212         return true;
213     } else {
214         // failed to find cache space
215
216         return false;
217     }
218 }