]> git.mxchange.org Git - flightgear.git/blob - src/Scenery/newcache.cxx
Irix MipsPro patches and fixes.
[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 <simgear/xgl/xgl.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 #include "tilemgr.hxx"          // temp, need to delete later
47
48 SG_USING_NAMESPACE(std);
49
50
51 // the tile cache
52 FGNewCache global_tile_cache;
53
54
55 // Constructor
56 FGNewCache::FGNewCache( void ) {
57     tile_cache.clear();
58 }
59
60
61 // Destructor
62 FGNewCache::~FGNewCache( void ) {
63 }
64
65
66 // Free a tile cache entry
67 void FGNewCache::entry_free( long cache_index ) {
68     SG_LOG( SG_TERRAIN, SG_DEBUG, "FREEING CACHE ENTRY = " << cache_index );
69     FGTileEntry *e = tile_cache[cache_index];
70     e->free_tile();
71     delete( e );
72     tile_cache.erase( cache_index );
73 }
74
75
76 // Initialize the tile cache subsystem
77 void FGNewCache::init( void ) {
78     // This is a hack that should really get cleaned up at some point
79     extern ssgBranch *terrain;
80
81     SG_LOG( SG_TERRAIN, SG_INFO, "Initializing the tile cache." );
82
83     // expand cache if needed.  For best results ... i.e. to avoid
84     // tile load problems and blank areas: 
85     max_cache_size = 50;        // a random number to start with
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     tile_map_iterator current = tile_cache.begin();
92     tile_map_iterator end = tile_cache.end();
93     
94     for ( ; current != end; ++current ) {
95         long index = current->first;
96         SG_LOG( SG_TERRAIN, SG_DEBUG, "clearing " << index );
97         FGTileEntry *e = current->second;
98         e->tile_bucket.make_bad();
99         entry_free(index);
100     }
101
102     // and ... just in case we missed something ... 
103     terrain->removeAllKids();
104
105     SG_LOG( SG_TERRAIN, SG_INFO, "  done with init()"  );
106 }
107
108
109 // Search for the specified "bucket" in the cache
110 bool FGNewCache::exists( const SGBucket& b ) {
111     long tile_index = b.gen_index();
112     tile_map_iterator it = tile_cache.find( tile_index );
113
114     return ( it != tile_cache.end() );
115 }
116
117
118 // Fill in a tile cache entry with real data for the specified bucket
119 void FGNewCache::fill_in( const SGBucket& b ) {
120     SG_LOG( SG_TERRAIN, SG_DEBUG, "FILL IN CACHE ENTRY = " << b.gen_index() );
121
122     // clear out a distant entry in the cache if needed.
123     make_space();
124
125     // create the entry
126     FGTileEntry *e = new FGTileEntry( b );
127
128     // register it in the cache
129     long tile_index = b.gen_index();
130     tile_cache[tile_index] = e;
131
132     SGPath tile_path;
133     if ( globals->get_fg_scenery() != (string)"" ) {
134         tile_path.set( globals->get_fg_scenery() );
135     } else {
136         tile_path.set( globals->get_fg_root() );
137         tile_path.append( "Scenery" );
138     }
139     
140     // Load the appropriate data file
141     e->load( tile_path, true );
142 }
143
144
145 // Ensure at least one entry is free in the cache
146 void FGNewCache::make_space() {
147     SG_LOG( SG_TERRAIN, SG_DEBUG, "Make space in cache" );
148
149     
150     SG_LOG( SG_TERRAIN, SG_DEBUG, "cache entries = " << tile_cache.size() );
151     SG_LOG( SG_TERRAIN, SG_DEBUG, "max size = " << max_cache_size );
152
153     if ( (int)tile_cache.size() < max_cache_size ) {
154         // space in the cache, return
155         return;
156     }
157
158     while ( (int)tile_cache.size() >= max_cache_size ) {
159         sgdVec3 abs_view_pos;
160         float dist;
161         float max_dist = 0.0;
162         int max_index = -1;
163
164         // we need to free the furthest entry
165         tile_map_iterator current = tile_cache.begin();
166         tile_map_iterator end = tile_cache.end();
167     
168         for ( ; current != end; ++current ) {
169             long index = current->first;
170             FGTileEntry *e = current->second;
171
172             // calculate approximate distance from view point
173             sgdCopyVec3( abs_view_pos,
174                          globals->get_current_view()->get_abs_view_pos() );
175
176             SG_LOG( SG_TERRAIN, SG_DEBUG, "DIST Abs view pos = " 
177                     << abs_view_pos[0] << ","
178                     << abs_view_pos[1] << ","
179                     << abs_view_pos[2] );
180             SG_LOG( SG_TERRAIN, SG_DEBUG,
181                     "    ref point = " << e->center );
182
183             sgdVec3 center;
184             sgdSetVec3( center, e->center.x(), e->center.y(), e->center.z() );
185             dist = sgdDistanceVec3( center, abs_view_pos );
186
187             SG_LOG( SG_TERRAIN, SG_DEBUG, "    distance = " << dist );
188
189             if ( dist > max_dist ) {
190                 max_dist = dist;
191                 max_index = index;
192             }
193         }
194
195         // If we made it this far, then there were no open cache entries.
196         // We will instead free the furthest cache entry and return it's
197         // index.
198
199         if ( max_index >= 0 ) {
200             SG_LOG( SG_TERRAIN, SG_DEBUG, "    max_dist = " << max_dist );
201             SG_LOG( SG_TERRAIN, SG_DEBUG, "    index = " << max_index );
202             entry_free( max_index );
203         } else {
204             SG_LOG( SG_TERRAIN, SG_ALERT, "WHOOPS!!! Dying in next_avail()" );
205             exit( -1 );
206         }
207     }
208 }