]> git.mxchange.org Git - flightgear.git/blob - src/Scenery/newcache.cxx
Make FGViewer::update() a pure virtual because FGViewer is a base class
[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 <Scenery/scenery.hxx>  // for scenery.center
43
44 #include "newcache.hxx"
45 #include "tileentry.hxx"
46
47
48 SG_USING_NAMESPACE(std);
49
50
51 // Constructor
52 FGNewCache::FGNewCache( void ) :
53     max_cache_size(50)
54 {
55     tile_cache.clear();
56 }
57
58
59 // Destructor
60 FGNewCache::~FGNewCache( void ) {
61 }
62
63
64 // Free a tile cache entry
65 void FGNewCache::entry_free( long cache_index ) {
66     SG_LOG( SG_TERRAIN, SG_DEBUG, "FREEING CACHE ENTRY = " << cache_index );
67     FGTileEntry *tile = tile_cache[cache_index];
68     tile->disconnect_ssg_nodes();
69
70 #ifdef WISH_PLIB_WAS_THREADED // but it isn't
71     tile->sched_removal();
72 #else
73     tile->free_tile();
74     delete tile;
75 #endif
76
77     tile_cache.erase( cache_index );
78 }
79
80
81 // Initialize the tile cache subsystem
82 void FGNewCache::init( void ) {
83     SG_LOG( SG_TERRAIN, SG_INFO, "Initializing the tile cache." );
84
85     SG_LOG( SG_TERRAIN, SG_INFO, "  max cache size = " 
86             << max_cache_size );
87     SG_LOG( SG_TERRAIN, SG_INFO, "  current cache size = " 
88             << tile_cache.size() );
89
90 #if 0 // don't clear the cache right now
91     clear_cache();
92 #endif
93
94     SG_LOG( SG_TERRAIN, SG_INFO, "  done with init()"  );
95 }
96
97
98 // Search for the specified "bucket" in the cache
99 bool FGNewCache::exists( const SGBucket& b ) const {
100     long tile_index = b.gen_index();
101     const_tile_map_iterator it = tile_cache.find( tile_index );
102
103     return ( it != tile_cache.end() );
104 }
105
106
107 // depricated for threading
108 #if 0
109 // Fill in a tile cache entry with real data for the specified bucket
110 void FGNewCache::fill_in( const SGBucket& b ) {
111     SG_LOG( SG_TERRAIN, SG_DEBUG, "FILL IN CACHE ENTRY = " << b.gen_index() );
112
113     // clear out a distant entry in the cache if needed.
114     make_space();
115
116     // create the entry
117     FGTileEntry *e = new FGTileEntry( b );
118
119     // register it in the cache
120     long tile_index = b.gen_index();
121     tile_cache[tile_index] = e;
122
123     SGPath tile_path;
124     if ( globals->get_fg_scenery() != (string)"" ) {
125         tile_path.set( globals->get_fg_scenery() );
126     } else {
127         tile_path.set( globals->get_fg_root() );
128         tile_path.append( "Scenery" );
129     }
130     
131     // Load the appropriate data file
132     e->load( tile_path, true );
133 }
134 #endif
135
136
137 // Ensure at least one entry is free in the cache
138 void FGNewCache::make_space() {
139     SG_LOG( SG_TERRAIN, SG_DEBUG, "Make space in cache" );
140     SG_LOG( SG_TERRAIN, SG_DEBUG, "cache entries = " << tile_cache.size() );
141     SG_LOG( SG_TERRAIN, SG_DEBUG, "max size = " << max_cache_size );
142
143     if ( (int)tile_cache.size() < max_cache_size ) {
144         // space in the cache, return
145         return;
146     }
147
148     while ( (int)tile_cache.size() >= max_cache_size ) {
149         sgdVec3 abs_view_pos;
150         float dist;
151         float max_dist = 0.0;
152         int max_index = -1;
153
154         // we need to free the furthest entry
155         tile_map_iterator current = tile_cache.begin();
156         tile_map_iterator end = tile_cache.end();
157     
158         for ( ; current != end; ++current ) {
159             long index = current->first;
160             FGTileEntry *e = current->second;
161
162             if ( e->is_loaded() && e->get_pending_models() == 0 ) {
163                 // calculate approximate distance from view point
164                 sgdCopyVec3( abs_view_pos,
165                              globals->get_current_view()->get_abs_view_pos() );
166
167                 SG_LOG( SG_TERRAIN, SG_DEBUG, "DIST Abs view pos = " 
168                         << abs_view_pos[0] << ","
169                         << abs_view_pos[1] << ","
170                         << abs_view_pos[2] );
171                 SG_LOG( SG_TERRAIN, SG_DEBUG,
172                         "    ref point = " << e->center );
173
174                 sgdVec3 center;
175                 sgdSetVec3( center,
176                             e->center.x(), e->center.y(), e->center.z() );
177                 dist = sgdDistanceVec3( center, abs_view_pos );
178
179                 SG_LOG( SG_TERRAIN, SG_DEBUG, "    distance = " << dist );
180
181                 if ( dist > max_dist ) {
182                     max_dist = dist;
183                     max_index = index;
184                 }
185             }
186         }
187
188         // If we made it this far, then there were no open cache entries.
189         // We will instead free the furthest cache entry and return it's
190         // index.
191
192         if ( max_index >= 0 ) {
193             SG_LOG( SG_TERRAIN, SG_DEBUG, "    max_dist = " << max_dist );
194             SG_LOG( SG_TERRAIN, SG_DEBUG, "    index = " << max_index );
195             entry_free( max_index );
196         } else {
197             SG_LOG( SG_TERRAIN, SG_ALERT, "WHOOPS!!! Dying in make_space()"
198                     "tile cache is full, but no entries available to removal.");
199             exit( -1 );
200         }
201     }
202 }
203
204
205 // Clear all completely loaded tiles (ignores partially loaded tiles)
206 void FGNewCache::clear_cache() {
207     // This is a hack that should really get cleaned up at some point
208     extern ssgBranch *terrain;
209
210     tile_map_iterator current = tile_cache.begin();
211     tile_map_iterator end = tile_cache.end();
212     
213     for ( ; current != end; ++current ) {
214         long index = current->first;
215         SG_LOG( SG_TERRAIN, SG_DEBUG, "clearing " << index );
216         FGTileEntry *e = current->second;
217         if ( e->is_loaded() && e->get_pending_models() == 0 ) {
218             e->tile_bucket.make_bad();
219             entry_free(index);
220         }
221     }
222
223     // and ... just in case we missed something ... 
224     terrain->removeAllKids();
225 }
226
227
228 /**
229  * Create a new tile and schedule it for loading.
230  */
231 void
232 FGNewCache::insert_tile( FGTileEntry *e )
233 {
234     // clear out a distant entry in the cache if needed.
235     make_space();
236
237     // register it in the cache
238     long tile_index = e->get_tile_bucket().gen_index();
239     tile_cache[tile_index] = e;
240
241 }