]> git.mxchange.org Git - flightgear.git/blob - src/Scenery/newcache.cxx
Make tile_mgr->prep_ssg_nodes() use an FGLocation object.
[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(100)
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 #if 0
109 // Ensure at least one entry is free in the cache
110 bool FGNewCache::make_space() {
111     SG_LOG( SG_TERRAIN, SG_DEBUG, "Make space in cache" );
112     SG_LOG( SG_TERRAIN, SG_DEBUG, "cache entries = " << tile_cache.size() );
113     SG_LOG( SG_TERRAIN, SG_DEBUG, "max size = " << max_cache_size );
114
115     if ( (int)tile_cache.size() < max_cache_size ) {
116         // space in the cache, return
117         return true;
118     }
119
120     while ( (int)tile_cache.size() >= max_cache_size ) {
121         sgdVec3 abs_view_pos;
122         float dist;
123         double timestamp = 0.0;
124         int max_index = -1;
125         double min_time = 2419200000.0f;  // one month should be enough
126         double max_time = 0;
127
128         // we need to free the furthest entry
129         tile_map_iterator current = tile_cache.begin();
130         tile_map_iterator end = tile_cache.end();
131     
132         for ( ; current != end; ++current ) {
133             long index = current->first;
134             FGTileEntry *e = current->second;
135             if ( e->is_loaded() && (e->get_pending_models() == 0) ) {
136
137                 timestamp = e->get_timestamp();
138                 if ( timestamp < min_time ) {
139                     max_index = index;
140                     min_time = timestamp;
141                 }
142                 if ( timestamp > max_time ) {
143                     max_time = timestamp;
144                 }
145
146             } else {
147                 SG_LOG( SG_TERRAIN, SG_DEBUG, "loaded = " << e->is_loaded()
148                         << " pending models = " << e->get_pending_models()
149                         << " time stamp = " << e->get_timestamp() );
150             }
151         }
152
153         // If we made it this far, then there were no open cache entries.
154         // We will instead free the oldest cache entry and return true
155         
156         SG_LOG( SG_TERRAIN, SG_DEBUG, "    min_time = " << min_time );
157         SG_LOG( SG_TERRAIN, SG_DEBUG, "    index = " << max_index );
158         SG_LOG( SG_TERRAIN, SG_DEBUG, "    max_time = " << max_time );
159         if ( max_index >= 0 ) {
160             entry_free( max_index );
161             return true;
162         } else {
163             SG_LOG( SG_TERRAIN, SG_ALERT, "WHOOPS!!! can't make_space(), tile "
164                     "cache is full, but no entries available for removal." );
165             return false;
166         }
167     }
168
169     SG_LOG( SG_TERRAIN, SG_ALERT, "WHOOPS!!! Hit an unhandled condition in  "
170             "FGNewCache::make_space()." );
171     return false;
172 }
173 #endif
174
175
176 // Return the index of the oldest tile in the cache, return -1 if
177 // nothing available to be removed.
178 long FGNewCache::get_oldest_tile() {
179     // we need to free the furthest entry
180     long min_index = -1;
181     double timestamp = 0.0;
182     double min_time = 2419200000.0f; // one month should be enough
183     double max_time = 0;
184
185     tile_map_iterator current = tile_cache.begin();
186     tile_map_iterator end = tile_cache.end();
187     
188     for ( ; current != end; ++current ) {
189         long index = current->first;
190         FGTileEntry *e = current->second;
191         if ( e->is_loaded() && (e->get_pending_models() == 0) ) {
192             
193             timestamp = e->get_timestamp();
194             if ( timestamp < min_time ) {
195                 min_index = index;
196                 min_time = timestamp;
197             }
198             if ( timestamp > max_time ) {
199                 max_time = timestamp;
200             }
201
202         } else {
203             SG_LOG( SG_TERRAIN, SG_DEBUG, "loaded = " << e->is_loaded()
204                     << " pending models = " << e->get_pending_models()
205                     << " time stamp = " << e->get_timestamp() );
206         }
207     }
208
209     SG_LOG( SG_TERRAIN, SG_DEBUG, "    min_time = " << min_time );
210     SG_LOG( SG_TERRAIN, SG_DEBUG, "    index = " << min_index );
211     SG_LOG( SG_TERRAIN, SG_DEBUG, "    max_time = " << max_time );
212
213     return min_index;
214 }
215
216
217 // Clear a cache entry, note that the cache only holds pointers
218 // and this does not free the object which is pointed to.
219 void FGNewCache::clear_entry( long cache_index ) {
220     tile_cache.erase( cache_index );
221 }
222
223
224 // Clear all completely loaded tiles (ignores partially loaded tiles)
225 void FGNewCache::clear_cache() {
226
227     tile_map_iterator current = tile_cache.begin();
228     tile_map_iterator end = tile_cache.end();
229     
230     for ( ; current != end; ++current ) {
231         long index = current->first;
232         SG_LOG( SG_TERRAIN, SG_DEBUG, "clearing " << index );
233         FGTileEntry *e = current->second;
234         if ( e->is_loaded() && (e->get_pending_models() == 0) ) {
235             e->tile_bucket.make_bad();
236             entry_free(index);
237         }
238     }
239
240     // and ... just in case we missed something ... 
241     globals->get_scenery()->get_terrain_branch()->removeAllKids();
242 }
243
244
245 /**
246  * Create a new tile and schedule it for loading.
247  */
248 bool FGNewCache::insert_tile( FGTileEntry *e ) {
249     // set time of insertion for tracking age of tiles...
250     e->set_timestamp(globals->get_sim_time_sec());
251
252     // register it in the cache
253     long tile_index = e->get_tile_bucket().gen_index();
254     tile_cache[tile_index] = e;
255
256     return true;
257 }
258
259
260 // Note this is the old version of FGNewCache::make_space(), currently disabled
261 // It uses distance from a center point to determine tiles to be discarded...
262 #if 0
263 // Ensure at least one entry is free in the cache
264 bool FGNewCache::make_space() {
265     SG_LOG( SG_TERRAIN, SG_DEBUG, "Make space in cache" );
266     SG_LOG( SG_TERRAIN, SG_DEBUG, "cache entries = " << tile_cache.size() );
267     SG_LOG( SG_TERRAIN, SG_DEBUG, "max size = " << max_cache_size );
268
269     if ( (int)tile_cache.size() < max_cache_size ) {
270         // space in the cache, return
271         return true;
272     }
273
274     while ( (int)tile_cache.size() >= max_cache_size ) {
275         sgdVec3 abs_view_pos;
276         float dist;
277         float max_dist = 0.0;
278         int max_index = -1;
279
280         // we need to free the furthest entry
281         tile_map_iterator current = tile_cache.begin();
282         tile_map_iterator end = tile_cache.end();
283     
284         for ( ; current != end; ++current ) {
285             long index = current->first;
286             FGTileEntry *e = current->second;
287
288             if ( e->is_loaded() && (e->get_pending_models() == 0) ) {
289                 // calculate approximate distance from view point
290                 sgdCopyVec3( abs_view_pos,
291                              globals->get_current_view()->get_absolute_view_pos() );
292
293                 SG_LOG( SG_TERRAIN, SG_DEBUG, "DIST Abs view pos = " 
294                         << abs_view_pos[0] << ","
295                         << abs_view_pos[1] << ","
296                         << abs_view_pos[2] );
297                 SG_LOG( SG_TERRAIN, SG_DEBUG,
298                         "    ref point = " << e->center );
299
300                 sgdVec3 center;
301                 sgdSetVec3( center,
302                             e->center.x(), e->center.y(), e->center.z() );
303                 dist = sgdDistanceVec3( center, abs_view_pos );
304
305                 SG_LOG( SG_TERRAIN, SG_DEBUG, "    distance = " << dist );
306
307                 if ( dist > max_dist ) {
308                     max_dist = dist;
309                     max_index = index;
310                 }
311             } else {
312                 SG_LOG( SG_TERRAIN, SG_INFO, "loaded = " << e->is_loaded()
313                         << " pending models = " << e->get_pending_models() );
314             }
315         }
316
317         // If we made it this far, then there were no open cache entries.
318         // We will instead free the furthest cache entry and return true
319         
320         SG_LOG( SG_TERRAIN, SG_INFO, "    max_dist = " << max_dist );
321         SG_LOG( SG_TERRAIN, SG_INFO, "    index = " << max_index );
322         if ( max_index >= 0 ) {
323             entry_free( max_index );
324             return true;
325         } else {
326             SG_LOG( SG_TERRAIN, SG_ALERT, "WHOOPS!!! can't make_space(), tile "
327                     "cache is full, but no entries available for removal." );
328             return false;
329         }
330     }
331
332     SG_LOG( SG_TERRAIN, SG_ALERT, "WHOOPS!!! Hit an unhandled condition in  "
333             "FGNewCache::make_space()." );
334     return false;
335 }
336 #endif
337
338