android/GlueIOIOPort: fix spurious errors after IOIO baud rate change
[xcsoar.git] / src / Terrain / TerrainRenderer.cpp
blob14f6c59b0464d2ad5737a32ddadc8ca226e57d6c
1 /*
2 Copyright_License {
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"
30 #ifdef ENABLE_OPENGL
31 #include "Screen/OpenGL/Texture.hpp"
32 #include "Screen/OpenGL/Scope.hpp"
33 #include "Screen/OpenGL/Compatibility.hpp"
34 #endif
36 #include <assert.h>
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
70 {0, 153, 178, 169},
71 {368, 180, 205, 181},
72 {496, 225, 233, 192},
73 {670, 255, 249, 196},
74 {905, 255, 249, 196},
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},
82 {8000, 255, 255, 255}
84 { // Imhof Type 4, geomteric 1.5 8
85 {0, 175, 224, 203},
86 {264, 211, 237, 211},
87 {396, 254, 254, 234},
88 {594, 252, 243, 210},
89 {891, 237, 221, 195},
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},
97 {8000, 255, 255, 255}
99 { // Imhof Type 12, geomteric 1.5 8
100 {0, 165, 220, 201},
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
115 {0, 47, 101, 147},
116 {368, 58, 129, 152},
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}
129 { // ICAO
130 {0, 180, 205, 181},
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}
144 { // Grey
145 {0, 220, 220, 220},
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}
159 { // White
160 {0, 255, 255, 255},
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},
193 { // Sandstone
194 {0, 255, 255, 255},
195 {150, 251, 227, 162},
196 {305, 235, 195, 132},
197 {610, 220, 162, 100},
198 {915, 209, 131, 69},
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},
208 { // Pastel
209 {0, 255, 255, 255},
210 {75, 240, 238, 235},
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
224 {0, 255, 255, 255},
225 {74, 255, 255, 255},
226 {75, 245, 242, 237},
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
239 {0, 255, 255, 255},
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
254 {0, 255, 255, 255},
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,
270 "mismatched size");
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
277 // 0.250 km/terrain
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)
284 :terrain(_terrain),
285 last_sun_azimuth(Angle::Zero()),
286 last_color_ramp(NULL)
288 assert(terrain != NULL);
289 settings.SetDefaults();
292 void
293 TerrainRenderer::CopyTo(Canvas &canvas, unsigned width, unsigned height) const
295 raster_renderer.GetImage().StretchTo(raster_renderer.GetWidth(),
296 raster_renderer.GetHeight(), canvas,
297 width, height);
300 void
301 TerrainRenderer::SetSettings(const TerrainRendererSettings &_settings)
303 if (settings == _settings)
304 return;
306 settings = _settings;
308 #ifdef ENABLE_OPENGL
309 raster_renderer.Invalidate();
310 #else
311 compare_projection.Clear();
312 #endif
315 #ifdef ENABLE_OPENGL
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.
321 static bool
322 IsLargeSizeDifference(const GeoBounds &a, const GeoBounds &b)
324 assert(a.IsValid());
325 assert(b.IsValid());
327 return a.GetWidth().Native() > Double(b.GetWidth().Native()) ||
328 a.GetHeight().Native() > Double(b.GetHeight().Native());
330 #endif
332 void
333 TerrainRenderer::Generate(const WindowProjection &map_projection,
334 const Angle sunazimuth)
336 #ifdef ENABLE_OPENGL
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 */
347 return;
349 #else
350 if (compare_projection.Compare(map_projection) &&
351 terrain_serial == terrain->GetSerial() &&
352 sunazimuth.CompareRoughly(last_sun_azimuth))
353 /* no change since previous frame */
354 return;
356 compare_projection = CompareProjection(map_projection);
357 #endif
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,
384 sunazimuth);
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)
393 void
394 TerrainRenderer::Draw(Canvas &canvas,
395 const WindowProjection &map_projection) const
397 #ifdef ENABLE_OPENGL
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[] = {
422 x0, y0,
423 x1, y0,
424 x0, y1,
425 x1, y1,
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);
435 #else
436 CopyTo(canvas, map_projection.GetScreenWidth(),
437 map_projection.GetScreenHeight());
438 #endif