]> git.mxchange.org Git - flightgear.git/blob - src/Scenery/tilecache.cxx
67ef6deecd15b1392168f384fc5fa5dfa9102537
[flightgear.git] / src / Scenery / tilecache.cxx
1 // tilecache.cxx -- routines to handle scenery tile caching
2 //
3 // Written by Curtis Olson, started January 1998.
4 //
5 // Copyright (C) 1997  Curtis L. Olson  - curt@infoplane.com
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 <XGL/xgl.h>
34
35 #include <Debug/logstream.hxx>
36 #include <Airports/genapt.hxx>
37 #include <Bucket/newbucket.hxx>
38 #include <Main/options.hxx>
39 #include <Main/views.hxx>
40 #include <Misc/fgpath.hxx>
41 #include <Objects/obj.hxx>
42
43 #include "tilecache.hxx"
44 #include "tileentry.hxx"
45
46
47 // the tile cache
48 FGTileCache global_tile_cache;
49
50
51 // Constructor
52 FGTileCache::FGTileCache( void ) {
53     tile_cache.clear();
54 }
55
56
57 // Initialize the tile cache subsystem
58 void
59 FGTileCache::init( void )
60 {
61     int i;
62
63     FG_LOG( FG_TERRAIN, FG_INFO, "Initializing the tile cache." );
64
65     // expand cache if needed.  For best results ... i.e. to avoid
66     // tile load problems and blank areas: 
67     // 
68     //   target_cache_size >= (current.options.tile_diameter + 1) ** 2 
69     // 
70     int side = current_options.get_tile_diameter() + 2;
71     int target_cache_size = (side*side);
72     FG_LOG( FG_TERRAIN, FG_DEBUG, "  target cache size = " 
73             << target_cache_size );
74     FG_LOG( FG_TERRAIN, FG_DEBUG, "  current cache size = " 
75             << tile_cache.size() );
76     FGTileEntry e;
77     FG_LOG( FG_TERRAIN, FG_DEBUG, "  size of tile = " 
78             << sizeof( e ) );
79     if ( target_cache_size > (int)tile_cache.size() ) {
80         // FGTileEntry e;
81         e.mark_unused();
82         int expansion_amt = target_cache_size - (int)tile_cache.size();
83         for ( i = 0; i < expansion_amt; ++i ) {
84             tile_cache.push_back( e );
85             FG_LOG( FG_TERRAIN, FG_DEBUG, "  expanding cache size = " 
86                     << tile_cache.size() );
87         }
88     }
89     FG_LOG( FG_TERRAIN, FG_DEBUG, "  done expanding cache, size = " 
90             << tile_cache.size() );
91
92     for ( i = 0; i < (int)tile_cache.size(); i++ ) {
93         if ( !tile_cache[i].is_unused() ) {
94             entry_free(i);
95         }
96         tile_cache[i].mark_unused();
97         tile_cache[i].tile_bucket.make_bad();
98     }
99     FG_LOG( FG_TERRAIN, FG_DEBUG, "  done with init()"  );
100 }
101
102
103 // Search for the specified "bucket" in the cache
104 int
105 FGTileCache::exists( const FGBucket& p )
106 {
107     int i;
108
109     for ( i = 0; i < (int)tile_cache.size(); i++ ) {
110         if ( tile_cache[i].tile_bucket == p ) {
111             FG_LOG( FG_TERRAIN, FG_DEBUG, 
112                     "TILE EXISTS in cache ... index = " << i );
113             return( i );
114         }
115     }
116     
117     return( -1 );
118 }
119
120
121 // Fill in a tile cache entry with real data for the specified bucket
122 void
123 FGTileCache::fill_in( int index, const FGBucket& p )
124 {
125     // Load the appropriate data file and build tile fragment list
126     FGPath tile_path( current_options.get_fg_root() );
127     tile_path.append( "Scenery" );
128     tile_path.append( p.gen_base_path() );
129     tile_path.append( p.gen_index_str() );
130
131     tile_cache[index].mark_loaded();
132     tile_cache[index].tile_bucket = p;
133     fgObjLoad( tile_path.str(), &tile_cache[index] );
134 //     tile_cache[ index ].ObjLoad( tile_path, p );
135
136     // cout << " ncount before = " << tile_cache[index].ncount << "\n";
137     // cout << " fragments before = " << tile_cache[index].fragment_list.size()
138     //      << "\n";
139
140     string apt_path = tile_path.str();
141     apt_path += ".apt";
142     fgAptGenerate( apt_path, &tile_cache[index] );
143
144     // cout << " ncount after = " << tile_cache[index].ncount << "\n";
145     // cout << " fragments after = " << tile_cache[index].fragment_list.size()
146     //      << "\n";
147 }
148
149
150 // Free a tile cache entry
151 void
152 FGTileCache::entry_free( int index )
153 {
154     tile_cache[index].release_fragments();
155 }
156
157
158 // Return index of next available slot in tile cache
159 int
160 FGTileCache::next_avail( void )
161 {
162     Point3D delta, abs_view_pos;
163     int i;
164     float max, med, min, tmp;
165     float dist, max_dist;
166     int max_index;
167     
168     max_dist = 0.0;
169     max_index = -1;
170
171     for ( i = 0; i < (int)tile_cache.size(); i++ ) {
172         // only look at freeing NON-scheduled (i.e. ready to load
173         // cache entries.  This assumes that the cache is always big
174         // enough for our tile radius!
175
176         if ( tile_cache[i].is_unused() ) {
177             // favor unused cache slots
178             return(i);
179         } else if ( tile_cache[i].is_loaded() ) {
180             // calculate approximate distance from view point
181             abs_view_pos = current_view.get_abs_view_pos();
182
183             FG_LOG( FG_TERRAIN, FG_DEBUG,
184                     "DIST Abs view pos = " << abs_view_pos );
185             FG_LOG( FG_TERRAIN, FG_DEBUG,
186                     "    ref point = " << tile_cache[i].center );
187
188             delta.setx( fabs(tile_cache[i].center.x() - abs_view_pos.x() ) );
189             delta.sety( fabs(tile_cache[i].center.y() - abs_view_pos.y() ) );
190             delta.setz( fabs(tile_cache[i].center.z() - abs_view_pos.z() ) );
191
192             max = delta.x(); med = delta.y(); min = delta.z();
193             if ( max < med ) {
194                 tmp = max; max = med; med = tmp;
195             }
196             if ( max < min ) {
197                 tmp = max; max = min; min = tmp;
198             }
199             dist = max + (med + min) / 4;
200
201             FG_LOG( FG_TERRAIN, FG_DEBUG, "    distance = " << dist );
202
203             if ( dist > max_dist ) {
204                 max_dist = dist;
205                 max_index = i;
206             }
207         }
208     }
209
210     // If we made it this far, then there were no open cache entries.
211     // We will instead free the furthest cache entry and return it's
212     // index.
213     
214     entry_free( max_index );
215     return( max_index );
216 }
217
218
219 // Destructor
220 FGTileCache::~FGTileCache( void ) {
221 }
222
223