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 "MapWindow.hpp"
25 #include "Look/MapLook.hpp"
26 #include "Geo/GeoClip.hpp"
27 #include "Screen/Icon.hpp"
28 #include "Task/ProtectedRoutePlanner.hpp"
31 #include "Screen/OpenGL/Triangulate.hpp"
35 #include "Util/StaticArray.hpp"
37 typedef std::vector
<RasterPoint
> RasterPointVector
;
41 * The number of points of the associated ReachFan. The first
42 * ProjectedFan starts of ProjectedFans::points[0], followed by the
43 * second one at ProjectedFans::points[reach_fan0.size], etc.
47 ProjectedFan() = default;
49 ProjectedFan(unsigned n
):size(n
) {
53 void DrawFill(const RasterPoint
*points
, unsigned start
) const {
54 /* triangulate the polygon */
55 AllocatedArray
<GLushort
> triangle_buffer
;
57 unsigned idx_count
= PolygonToTriangles(points
+ start
, size
,
62 /* add offset to all vertex indices */
63 for (unsigned i
= 0; i
< idx_count
; ++i
)
64 triangle_buffer
[i
] += start
;
66 glDrawElements(GL_TRIANGLES
, idx_count
, GL_UNSIGNED_SHORT
,
67 triangle_buffer
.begin());
70 void DrawOutline(unsigned start
) const {
71 glDrawArrays(GL_LINE_LOOP
, start
, size
);
74 void DrawFill(Canvas
&canvas
, const RasterPoint
*points
) const {
75 canvas
.DrawPolygon(&points
[0], size
);
78 void DrawOutline(Canvas
&canvas
, const RasterPoint
*points
) const {
79 canvas
.DrawPolygon(&points
[0], size
);
84 struct ProjectedFans
{
85 typedef StaticArray
<ProjectedFan
, FlatTriangleFanTree::REACH_MAX_FANS
> ProjectedFanVector
;
87 ProjectedFanVector fans
;
90 * All points of all ProjectedFan objects. The first one starts of
91 * points[0], followed by the second one at points[fans[0].size],
94 RasterPointVector points
;
105 /* try to guess the total number of vertices */
106 points
.reserve(FlatTriangleFanTree::REACH_MAX_FANS
* ROUTEPOLAR_POINTS
/ 10);
117 ProjectedFanVector::size_type
size() const {
121 ProjectedFan
&Append(unsigned n
) {
123 assert(remaining
== 0);
127 points
.reserve(points
.size() + n
);
129 fans
.push_back(ProjectedFan(n
));
133 void Append(const RasterPoint
&pt
) {
135 assert(remaining
> 0);
139 points
.push_back(pt
);
144 glVertexPointer(2, GL_VALUE
, 0, &points
[0]);
148 void DrawFill(Canvas
&canvas
) const {
149 assert(remaining
== 0);
153 const RasterPoint
*points
= &this->points
[0];
154 for (auto i
= fans
.begin(), end
= fans
.end(); i
!= end
; ++i
) {
155 i
->DrawFill(points
, start
);
159 const RasterPoint
*points
= &this->points
[0];
160 for (auto i
= fans
.begin(), end
= fans
.end(); i
!= end
; ++i
) {
161 i
->DrawFill(canvas
, points
);
167 void DrawOutline(Canvas
&canvas
) const {
168 assert(remaining
== 0);
172 for (auto i
= fans
.begin(), end
= fans
.end(); i
!= end
; ++i
) {
173 i
->DrawOutline(start
);
177 const RasterPoint
*points
= &this->points
[0];
178 for (auto i
= fans
.begin(), end
= fans
.end(); i
!= end
; ++i
) {
179 i
->DrawOutline(canvas
, points
);
186 typedef StaticArray
<ProjectedFan
, FlatTriangleFanTree::REACH_MAX_FANS
> ProjectedFanVector
;
188 class TriangleCompound
: public TriangleFanVisitor
{
189 /** Temporary container for TriangleFan processing */
190 StaticArray
<GeoPoint
, ROUTEPOLAR_POINTS
+2> g
;
191 /** Temporary container for TriangleFan clipping */
192 GeoPoint clipped
[(ROUTEPOLAR_POINTS
+2) * 3];
193 /** Projection to use for GeoPoint -> RasterPoint conversion */
194 const MapWindowProjection
&proj
;
195 /** GeoClip instance used for TriangleFan clipping */
199 /** STL-Container of rasterized polygons */
202 TriangleCompound(const MapWindowProjection
& _proj
)
204 clip(_proj
.GetScreenBounds().Scale(fixed(1.1)))
208 virtual void StartFan() {
209 // Clear the GeoPointVector for the next TriangleFan
213 virtual void AddPoint(const GeoPoint
& p
) {
214 // Add a new GeoPoint to the current TriangleFan
224 // remove unnecessary inclusion of origin if next and last points are identical
226 const size_t gsize
= g
.size();
227 if (gsize
> 2 && g
[gsize
- 1] == g
[1])
230 if (gsize
< start
+ 3)
233 // Perform clipping on the GeoPointVector (Result: clipped)
234 unsigned size
= clip
.ClipPolygon(clipped
, g
.raw() + start
, gsize
- start
);
235 // With less than three points we can't draw a polygon
239 // Work directly on the RasterPoints in the fans vector
242 // Convert GeoPoints to RasterPoints
243 for (unsigned i
= 0; i
< size
; ++i
)
244 fans
.Append(proj
.GeoToScreen(clipped
[i
]));
249 * Draw the final glide groundline (and shading) to the buffer
250 * and copy the transparent buffer to the canvas
251 * @param canvas The drawing canvas
252 * @param rc The area to draw in
253 * @param buffer The drawing buffer
256 MapWindow::DrawTerrainAbove(Canvas
&canvas
)
258 // Don't draw at all if
261 // .. feature disabled
262 // .. feature inaccessible
263 if (!Basic().location_available
264 || !Calculated().flight
.flying
265 || GetComputerSettings().features
.final_glide_terrain
== FeaturesSettings::FinalGlideTerrain::OFF
266 || route_planner
== NULL
)
269 // Create a visitor for the Reach code
270 TriangleCompound
visitor(render_projection
);
272 // Fill the TriangleCompound with all TriangleFans in range
273 route_planner
->AcceptInRange(render_projection
.GetScreenBounds(), visitor
);
275 // Exit early if not fans found
276 if (visitor
.fans
.empty())
279 // @todo: update this rendering
281 // Don't draw shade if
282 // .. shade feature disabled
283 // .. pan mode activated
284 if (GetComputerSettings().features
.final_glide_terrain
== FeaturesSettings::FinalGlideTerrain::SHADE
&&
289 visitor
.fans
.Prepare();
291 glEnable(GL_STENCIL_TEST
);
292 glClear(GL_STENCIL_BUFFER_BIT
);
294 glColorMask(GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_FALSE
);
296 glStencilFunc(GL_ALWAYS
, 1, 1);
297 glStencilOp(GL_KEEP
, GL_KEEP
, GL_REPLACE
);
300 visitor
.fans
.DrawFill(canvas
);
302 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
303 glStencilFunc(GL_NOTEQUAL
, 1, 1);
304 glStencilOp(GL_KEEP
, GL_KEEP
, GL_KEEP
);
307 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
309 canvas
.Clear(Color(255, 255, 255, 77));
312 glDisable(GL_STENCIL_TEST
);
314 #elif defined(USE_GDI)
316 // Get a buffer for drawing a mask
317 Canvas
&buffer
= buffer_canvas
;
319 // Set the pattern colors
320 buffer
.SetBackgroundOpaque();
321 buffer
.SetBackgroundColor(COLOR_WHITE
);
322 buffer
.SetTextColor(Color(0xd0, 0xd0, 0xd0));
324 // Paint the whole buffer canvas with a pattern brush (small dots)
325 buffer
.Clear(look
.above_terrain_brush
);
327 // Select the TerrainLine pen
328 buffer
.SelectHollowBrush();
329 buffer
.Select(look
.reach_pen_thick
);
330 buffer
.SetBackgroundColor(Color(0xf0, 0xf0, 0xf0));
332 // Draw the TerrainLine polygons
333 visitor
.fans
.DrawOutline(buffer
);
335 // Select a white brush (will later be transparent)
336 buffer
.SelectNullPen();
337 buffer
.SelectWhiteBrush();
339 // Draw the TerrainLine polygons to remove the
340 // brush pattern from the polygon areas
341 visitor
.fans
.DrawFill(buffer
);
343 // Copy everything non-white to the buffer
344 canvas
.CopyTransparentWhite(buffer
);
346 /* skip the separate terrain line step below, because we have done
354 if (visitor
.fans
.size() == 1) {
355 /* only one fan: we can draw a simple polygon */
358 visitor
.fans
.Prepare();
359 look
.reach_pen
.Bind();
361 // Select the TerrainLine pen
362 canvas
.SelectHollowBrush();
363 canvas
.Select(look
.reach_pen
);
364 canvas
.SetBackgroundOpaque();
365 canvas
.SetBackgroundColor(COLOR_WHITE
);
367 // drop out extraneous line from origin
370 // Draw the TerrainLine polygon
372 visitor
.fans
.DrawOutline(canvas
);
375 look
.reach_pen
.Unbind();
378 /* more than one fan (turning reach enabled): we have to use a
379 stencil to draw the outline, because the fans may overlap */
382 visitor
.fans
.Prepare();
384 glEnable(GL_STENCIL_TEST
);
385 glClear(GL_STENCIL_BUFFER_BIT
);
387 glColorMask(GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_FALSE
);
389 glStencilFunc(GL_ALWAYS
, 1, 1);
390 glStencilOp(GL_KEEP
, GL_KEEP
, GL_REPLACE
);
393 visitor
.fans
.DrawFill(canvas
);
395 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
396 glStencilFunc(GL_NOTEQUAL
, 1, 1);
397 glStencilOp(GL_KEEP
, GL_KEEP
, GL_KEEP
);
399 look
.reach_pen_thick
.Bind();
400 visitor
.fans
.DrawOutline(canvas
);
401 look
.reach_pen_thick
.Unbind();
403 glDisable(GL_STENCIL_TEST
);
405 #elif defined(USE_GDI)
407 // Get a buffer for drawing a mask
408 Canvas
&buffer
= buffer_canvas
;
410 // Paint the whole buffer canvas white ( = transparent)
413 // Select the TerrainLine pen
414 buffer
.SelectHollowBrush();
415 buffer
.Select(look
.reach_pen_thick
);
416 buffer
.SetBackgroundOpaque();
417 buffer
.SetBackgroundColor(Color(0xf0, 0xf0, 0xf0));
419 // Draw the TerrainLine polygons
420 visitor
.fans
.DrawOutline(buffer
);
422 // Select a white brush (will later be transparent)
423 buffer
.SelectNullPen();
424 buffer
.SelectWhiteBrush();
426 // Draw the TerrainLine polygons again to remove
427 // the lines connecting all the polygons
429 // This removes half of the TerrainLine line width !!
430 visitor
.fans
.DrawFill(buffer
);
432 // Copy everything non-white to the buffer
433 canvas
.CopyTransparentWhite(buffer
);
441 MapWindow::DrawGlideThroughTerrain(Canvas
&canvas
) const
443 if (!Calculated().flight
.flying
||
444 !Calculated().terrain_warning
||
445 Calculated().terrain_warning_location
.Distance(Basic().location
) < fixed(500.0))
449 if (render_projection
.GeoToScreenIfVisible(Calculated().terrain_warning_location
,
451 look
.terrain_warning_icon
.Draw(canvas
, sc
.x
, sc
.y
);