4 XCSoar Glide Computer - http://www.xcsoar.org/
5 Copyright (C) 2000-2013 The XCSoar Project
6 A detailed list of copyright holders can be found in the file "AUTHORS".
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #include "Terrain/TerrainRenderer.hpp"
25 #include "Terrain/RasterTerrain.hpp"
26 #include "Screen/Ramp.hpp"
27 #include "Projection/WindowProjection.hpp"
28 #include "Util/Macros.hpp"
31 #include "Screen/OpenGL/Texture.hpp"
32 #include "Screen/OpenGL/Scope.hpp"
33 #include "Screen/OpenGL/Compatibility.hpp"
38 static constexpr ColorRamp terrain_colors
[][NUM_COLOR_RAMP_LEVELS
] = {
40 {0, 0x70, 0xc0, 0xa7},
41 {250, 0xca, 0xe7, 0xb9},
42 {500, 0xf4, 0xea, 0xaf},
43 {750, 0xdc, 0xb2, 0x82},
44 {1000, 0xca, 0x8e, 0x72},
45 {1250, 0xde, 0xc8, 0xbd},
46 {1500, 0xe3, 0xe4, 0xe9},
47 {1750, 0xdb, 0xd9, 0xef},
48 {2000, 0xce, 0xcd, 0xf5},
49 {2250, 0xc2, 0xc1, 0xfa},
50 {2500, 0xb7, 0xb9, 0xff},
51 {5000, 0xb7, 0xb9, 0xff},
52 {6000, 0xb7, 0xb9, 0xff}
55 {0, 0x70, 0xc0, 0xa7},
56 {500, 0xca, 0xe7, 0xb9},
57 {1000, 0xf4, 0xea, 0xaf},
58 {1500, 0xdc, 0xb2, 0x82},
59 {2000, 0xca, 0x8e, 0x72},
60 {2500, 0xde, 0xc8, 0xbd},
61 {3000, 0xe3, 0xe4, 0xe9},
62 {3500, 0xdb, 0xd9, 0xef},
63 {4000, 0xce, 0xcd, 0xf5},
64 {4500, 0xc2, 0xc1, 0xfa},
65 {5000, 0xb7, 0xb9, 0xff},
66 {6000, 0xb7, 0xb9, 0xff},
67 {7000, 0xb7, 0xb9, 0xff}
69 { // Imhof Type 7, geomteric 1.35 9
75 {1222, 255, 219, 173},
76 {1650, 254, 170, 136},
77 {2227, 253, 107, 100},
78 {3007, 255, 255, 255},
79 {5000, 255, 255, 255},
80 {6000, 255, 255, 255},
81 {7000, 255, 255, 255},
84 { // Imhof Type 4, geomteric 1.5 8
90 {1336, 221, 199, 175},
91 {2004, 215, 170, 148},
92 {3007, 255, 255, 255},
93 {4000, 255, 255, 255},
94 {5000, 255, 255, 255},
95 {6000, 255, 255, 255},
96 {7000, 255, 255, 255},
99 { // Imhof Type 12, geomteric 1.5 8
101 {399, 219, 239, 212},
102 {558, 254, 253, 230},
103 {782, 254, 247, 211},
104 {1094, 254, 237, 202},
105 {1532, 254, 226, 207},
106 {2145, 254, 209, 204},
107 {3004, 255, 255, 255},
108 {4000, 255, 255, 255},
109 {5000, 255, 255, 255},
110 {6000, 255, 255, 255},
111 {7000, 255, 255, 255},
112 {8000, 255, 255, 255}
114 { // Imhof Atlas der Schweiz
117 {496, 117, 148, 153},
118 {670, 155, 178, 140},
119 {905, 192, 190, 139},
120 {1222, 215, 199, 137},
121 {1650, 229, 203, 171},
122 {2227, 246, 206, 171},
123 {3007, 252, 246, 244},
124 {5001, 252, 246, 244},
125 {7000, 252, 246, 244},
126 {8000, 252, 246, 244},
127 {9000, 252, 246, 244}
131 {199, 180, 205, 181},
132 {200, 225, 233, 192},
133 {499, 225, 233, 192},
134 {500, 255, 249, 196},
135 {999, 255, 249, 196},
136 {1000, 255, 219, 173},
137 {1499, 255, 219, 173},
138 {1500, 254, 170, 136},
139 {1999, 254, 170, 136},
140 {2000, 253, 107, 100},
141 {2499, 253, 107, 100},
142 {2500, 255, 255, 255}
146 {100, 220, 220, 220},
147 {200, 220, 220, 220},
148 {300, 220, 220, 220},
149 {500, 220, 220, 220},
150 {700, 220, 220, 220},
151 {1000, 220, 220, 220},
152 {1250, 220, 220, 220},
153 {1500, 220, 220, 220},
154 {1750, 220, 220, 220},
155 {2000, 220, 220, 220},
156 {2250, 220, 220, 220},
157 {2500, 220, 220, 220}
161 {100, 255, 255, 255},
162 {200, 255, 255, 255},
163 {300, 255, 255, 255},
164 {500, 255, 255, 255},
165 {700, 255, 255, 255},
166 {1000, 255, 255, 255},
167 {1250, 255, 255, 255},
168 {1500, 255, 255, 255},
169 {1750, 255, 255, 255},
170 {2000, 255, 255, 255},
171 {2250, 255, 255, 255},
172 {2500, 255, 255, 255}
176 * "Gaudy". Imitates SeeYouMobile's default ramp.
179 {0, 0x00, 0x80, 0x00},
180 {1000, 0xff, 0xff, 0x00},
181 {1500, 0xc0, 0x20, 0x00},
182 {2800, 0xff, 0xff, 0xff},
183 {3000, 0xff, 0xff, 0xff},
184 {3100, 0xff, 0xff, 0xff},
185 {3200, 0xff, 0xff, 0xff},
186 {3300, 0xff, 0xff, 0xff},
187 {3400, 0xff, 0xff, 0xff},
188 {3500, 0xff, 0xff, 0xff},
189 {3600, 0xff, 0xff, 0xff},
190 {3700, 0xff, 0xff, 0xff},
191 {3800, 0xff, 0xff, 0xff},
195 {150, 251, 227, 162},
196 {305, 235, 195, 132},
197 {610, 220, 162, 100},
199 {1500, 205, 118, 48},
200 {2000, 202, 142, 114},
201 {2500, 222, 200, 189},
202 {3000, 227, 228, 233},
203 {3500, 219, 217, 239},
204 {4000, 206, 205, 245},
205 {4500, 194, 193, 255},
206 {5000, 183, 185, 255},
211 {150, 226, 234, 179},
212 {305, 209, 219, 128},
213 {610, 236, 214, 176},
214 {915, 234, 193, 145},
215 {1525, 231, 188, 126},
216 {2440, 218, 170, 115},
217 {3050, 204, 129, 68},
218 {3500, 255, 255, 255},
219 {4000, 255, 255, 255},
220 {5500, 255, 255, 255},
221 {6000, 255, 255, 255},
223 { // Italian Avioportolano VFR Charts
227 {149, 245, 242, 237},
228 {150, 235, 242, 204},
229 {304, 235, 242, 204},
230 {305, 212, 222, 140},
231 {609, 212, 222, 140},
232 {610, 242, 227, 199},
233 {915, 237, 204, 163},
234 {1525, 229, 194, 138},
235 {2440, 217, 181, 130},
236 {3050, 208, 134, 69},
238 { // German DFS VFR Chart
240 {150, 243, 243, 243},
241 {305, 227, 227, 227},
242 {610, 206, 206, 206},
243 {915, 208, 208, 208},
244 {1525, 193, 193, 193},
245 {3050, 126, 126, 126},
246 {4500, 255, 255, 255},
247 {5000, 255, 255, 255},
248 {6500, 255, 255, 255},
249 {7000, 255, 255, 255},
250 {8500, 255, 255, 255},
251 {9000, 255, 255, 255}
253 { // French SIA VFR Chart
255 {305, 250, 249, 227},
256 {610, 251, 250, 201},
257 {915, 253, 235, 165},
258 {1525, 250, 210, 147},
259 {2440, 249, 178, 126},
260 {3050, 217, 236, 240},
261 {4500, 255, 255, 255},
262 {5000, 255, 255, 255},
263 {6500, 255, 255, 255},
264 {7000, 255, 255, 255},
265 {8500, 255, 255, 255},
266 {9000, 255, 255, 255}
269 static_assert(ARRAY_SIZE(terrain_colors
) == TerrainRendererSettings::NUM_RAMPS
,
272 // map scale is approximately 2 points on the grid
273 // therefore, want one to one mapping if mapscale is 0.5
274 // there are approx 30 pixels in mapscale
275 // 240/QUANTISATION_PIXELS resolution = 6 pixels per terrain
276 // (mapscale/30) km/pixels
278 // (0.25*30/mapscale) pixels/terrain
279 // mapscale/(0.25*30)
280 // mapscale/7.5 terrain units/pixel
282 // this is for TerrainInfo.StepSize = 0.0025;
283 TerrainRenderer::TerrainRenderer(const RasterTerrain
*_terrain
)
285 last_sun_azimuth(Angle::Zero()),
286 last_color_ramp(NULL
)
288 assert(terrain
!= NULL
);
289 settings
.SetDefaults();
293 TerrainRenderer::CopyTo(Canvas
&canvas
, unsigned width
, unsigned height
) const
295 raster_renderer
.GetImage().StretchTo(raster_renderer
.GetWidth(),
296 raster_renderer
.GetHeight(), canvas
,
301 TerrainRenderer::SetSettings(const TerrainRendererSettings
&_settings
)
303 if (settings
== _settings
)
306 settings
= _settings
;
309 raster_renderer
.Invalidate();
311 compare_projection
.Clear();
317 * Checks if the size difference of any dimension is more than a
318 * factor of two. This is used to check whether the terrain has to be
319 * redrawn after zooming in.
322 IsLargeSizeDifference(const GeoBounds
&a
, const GeoBounds
&b
)
327 return a
.GetWidth().Native() > Double(b
.GetWidth().Native()) ||
328 a
.GetHeight().Native() > Double(b
.GetHeight().Native());
333 TerrainRenderer::Generate(const WindowProjection
&map_projection
,
334 const Angle sunazimuth
)
337 const GeoBounds
&old_bounds
= raster_renderer
.GetBounds();
338 const GeoBounds
&new_bounds
= map_projection
.GetScreenBounds();
339 assert(new_bounds
.IsValid());
341 if (old_bounds
.IsValid() && old_bounds
.IsInside(new_bounds
) &&
342 !IsLargeSizeDifference(old_bounds
, new_bounds
) &&
343 terrain_serial
== terrain
->GetSerial() &&
344 sunazimuth
.CompareRoughly(last_sun_azimuth
) &&
345 !raster_renderer
.UpdateQuantisation())
346 /* no change since previous frame */
350 if (compare_projection
.Compare(map_projection
) &&
351 terrain_serial
== terrain
->GetSerial() &&
352 sunazimuth
.CompareRoughly(last_sun_azimuth
))
353 /* no change since previous frame */
356 compare_projection
= CompareProjection(map_projection
);
359 terrain_serial
= terrain
->GetSerial();
361 last_sun_azimuth
= sunazimuth
;
363 const bool do_water
= true;
364 const unsigned height_scale
= 4;
365 const int interp_levels
= 2;
366 const bool is_terrain
= true;
367 const bool do_shading
= is_terrain
&&
368 settings
.slope_shading
!= SlopeShading::OFF
;
370 const ColorRamp
*const color_ramp
= &terrain_colors
[settings
.ramp
][0];
371 if (color_ramp
!= last_color_ramp
) {
372 raster_renderer
.ColorTable(color_ramp
, do_water
,
373 height_scale
, interp_levels
);
374 last_color_ramp
= color_ramp
;
378 RasterTerrain::Lease
map(*terrain
);
379 raster_renderer
.ScanMap(map
, map_projection
);
382 raster_renderer
.GenerateImage(do_shading
, height_scale
,
383 settings
.contrast
, settings
.brightness
,
388 * Draws the terrain to the given canvas
389 * @param canvas The drawing canvas
390 * @param map_projection The Projection
391 * @param sunazimuth Azimuth of the sun (for terrain shading)
394 TerrainRenderer::Draw(Canvas
&canvas
,
395 const WindowProjection
&map_projection
) const
398 const GeoBounds
&bounds
= raster_renderer
.GetBounds();
399 assert(bounds
.IsValid());
401 const RasterPoint vertices
[] = {
402 map_projection
.GeoToScreen(bounds
.GetNorthWest()),
403 map_projection
.GeoToScreen(bounds
.GetNorthEast()),
404 map_projection
.GeoToScreen(bounds
.GetSouthWest()),
405 map_projection
.GeoToScreen(bounds
.GetSouthEast()),
408 glVertexPointer(2, GL_VALUE
, 0, vertices
);
410 const GLTexture
&texture
= raster_renderer
.BindAndGetTexture();
411 const PixelSize allocated
= texture
.GetAllocatedSize();
413 const int src_x
= 0, src_y
= 0, src_width
= raster_renderer
.GetWidth(),
414 src_height
= raster_renderer
.GetHeight();
416 GLfloat x0
= (GLfloat
)src_x
/ allocated
.cx
;
417 GLfloat y0
= (GLfloat
)src_y
/ allocated
.cy
;
418 GLfloat x1
= (GLfloat
)(src_x
+ src_width
) / allocated
.cx
;
419 GLfloat y1
= (GLfloat
)(src_y
+ src_height
) / allocated
.cy
;
421 const GLfloat coord
[] = {
428 OpenGL::glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
430 GLEnable
scope(GL_TEXTURE_2D
);
431 glEnableClientState(GL_TEXTURE_COORD_ARRAY
);
432 glTexCoordPointer(2, GL_FLOAT
, 0, coord
);
433 glDrawArrays(GL_TRIANGLE_STRIP
, 0, 4);
434 glDisableClientState(GL_TEXTURE_COORD_ARRAY
);
436 CopyTo(canvas
, map_projection
.GetScreenWidth(),
437 map_projection
.GetScreenHeight());