void MapOverlayBitmap::Draw(Canvas &canvas, const WindowProjection &projection) noexcept { if (!simple_bounds.Overlaps(projection.GetScreenBounds())) /* not visible, outside of screen area */ return; const RasterPoint vertices[] = { projection.GeoToScreen(bounds.top_left), projection.GeoToScreen(bounds.top_right), projection.GeoToScreen(bounds.bottom_left), projection.GeoToScreen(bounds.bottom_right), }; const ScopeVertexPointer vp(vertices); GLTexture &texture = *bitmap.GetNative(); texture.Bind(); const PixelSize allocated = texture.GetAllocatedSize(); const unsigned src_x = 0, src_y = 0; const unsigned src_width = texture.GetWidth(); const unsigned src_height = texture.GetHeight(); GLfloat x0 = (GLfloat)src_x / allocated.cx; GLfloat y0 = (GLfloat)src_y / allocated.cy; GLfloat x1 = (GLfloat)(src_x + src_width) / allocated.cx; GLfloat y1 = (GLfloat)(src_y + src_height) / allocated.cy; if (bitmap.IsFlipped()) { y0 = 1 - y0; y1 = 1 - y1; } const Point2D<GLfloat> coord[] = { {x0, y0}, {x1, y0}, {x0, y1}, {x1, y1}, }; const ScopeTextureConstantAlpha blend(alpha); #ifdef USE_GLSL OpenGL::texture_shader->Use(); glEnableVertexAttribArray(OpenGL::Attribute::TEXCOORD); glVertexAttribPointer(OpenGL::Attribute::TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, coord); #else const GLEnable<GL_TEXTURE_2D> scope; glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(2, GL_FLOAT, 0, coord); #endif glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); #ifdef USE_GLSL glDisableVertexAttribArray(OpenGL::Attribute::TEXCOORD); OpenGL::solid_shader->Use(); #else glDisableClientState(GL_TEXTURE_COORD_ARRAY); #endif }
void TopographyFileRenderer::UpdateVisibleShapes(const WindowProjection &projection) { if (file.GetSerial() == visible_serial && visible_bounds.IsInside(projection.GetScreenBounds()) && projection.GetScreenBounds().Scale(fixed_two).IsInside(visible_bounds)) /* cache is clean */ return; visible_serial = file.GetSerial(); visible_bounds = projection.GetScreenBounds().Scale(fixed(1.2)); visible_shapes.clear(); visible_labels.clear(); for (auto it = file.begin(), end = file.end(); it != end; ++it) { const XShape &shape = *it; if (!visible_bounds.Overlaps(shape.get_bounds())) continue; if (shape.get_type() != MS_SHAPE_NULL) visible_shapes.push_back(&shape); if (shape.get_label() != NULL) visible_labels.push_back(&shape); } }
bool TopographyFile::Update(const WindowProjection &map_projection) { if (IsEmpty()) return false; if (map_projection.GetMapScale() > scale_threshold) /* not visible, don't update cache now */ return false; const GeoBounds screenRect = map_projection.GetScreenBounds(); if (cache_bounds.IsValid() && cache_bounds.IsInside(screenRect)) /* the cache is still fresh */ return false; cache_bounds = map_projection.GetScreenBounds().Scale(fixed(2)); rectObj deg_bounds = ConvertRect(cache_bounds); // Test which shapes are inside the given bounds and save the // status to file.status msShapefileWhichShapes(&file, dir, deg_bounds, 0); // If not a single shape is inside the bounds if (!file.status) { // ... clear the whole buffer ClearCache(); return false; } // Iterate through the shapefile entries const ShapeList **current = &first; auto it = shapes.begin(); for (int i = 0; i < file.numshapes; ++i, ++it) { if (!msGetBit(file.status, i)) { // If the shape is outside the bounds // delete the shape from the cache delete it->shape; it->shape = NULL; } else { // is inside the bounds if (it->shape == NULL) // shape isn't cached yet -> cache the shape it->shape = new XShape(&file, i, label_field); // update list pointer *current = it; current = &it->next; } } // end of list marker *current = NULL; ++serial; return true; }
void MapOverlayBitmap::Draw(Canvas &canvas, const WindowProjection &projection) noexcept { if (!simple_bounds.Overlaps(projection.GetScreenBounds())) /* not visible, outside of screen area */ return; auto clipped = Clip(bounds, projection.GetScreenBounds()); if (clipped.empty()) return; GLTexture &texture = *bitmap.GetNative(); const PixelSize allocated = texture.GetAllocatedSize(); const double x_factor = double(texture.GetWidth()) / allocated.cx; const double y_factor = double(texture.GetHeight()) / allocated.cy; Point2D<GLfloat> coord[16]; BulkPixelPoint vertices[16]; const ScopeVertexPointer vp(vertices); texture.Bind(); const ScopeTextureConstantAlpha blend(use_bitmap_alpha, alpha); glEnableVertexAttribArray(OpenGL::Attribute::TEXCOORD); glVertexAttribPointer(OpenGL::Attribute::TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, coord); for (const auto &polygon : clipped) { const auto &ring = polygon.outer(); size_t n = ring.size(); if (ring.front() == ring.back()) --n; for (size_t i = 0; i < n; ++i) { const auto v = GeoFrom2D(ring[i]); auto p = MapInQuadrilateral(bounds, v); coord[i].x = p.x * x_factor; coord[i].y = p.y * y_factor; if (bitmap.IsFlipped()) coord[i].y = 1 - coord[i].y; vertices[i] = projection.GeoToScreen(v); } glDrawArrays(GL_TRIANGLE_FAN, 0, n); } glDisableVertexAttribArray(OpenGL::Attribute::TEXCOORD); }
void TopographyThread::Trigger(const WindowProjection &_projection) { assert(_projection.IsValid()); const GeoBounds new_bounds = _projection.GetScreenBounds(); if (last_bounds.IsValid() && last_bounds.IsInside(new_bounds)) { /* still inside cache bounds - now check if we crossed a scale threshold for at least one file, which would mean we have to update a file which was not updated for the current cache bounds */ if (scale_threshold < 0 || _projection.GetMapScale() >= scale_threshold) /* the cache is still fresh */ return; } last_bounds = new_bounds.Scale(1.1); scale_threshold = store.GetNextScaleThreshold(_projection.GetMapScale()); { const ScopeLock protect(mutex); next_projection = _projection; StandbyThread::Trigger(); } }
bool RaspRenderer::Generate(const WindowProjection &projection, const TerrainRendererSettings &settings) { const auto &style = LookupWeatherTerrainStyle(cache.GetMapName()); const bool do_water = style.do_water; const unsigned height_scale = style.height_scale; const int interp_levels = 5; const ColorRamp *color_ramp = style.color_ramp; const RasterMap *map = cache.GetMap(); if (map == nullptr) return false; if (!map->GetBounds().Overlaps(projection.GetScreenBounds())) /* not visible */ return false; if (color_ramp != last_color_ramp) { raster_renderer.PrepareColorTable(color_ramp, do_water, height_scale, interp_levels); last_color_ramp = color_ramp; } raster_renderer.ScanMap(*map, projection); raster_renderer.GenerateImage(false, height_scale, settings.contrast, settings.brightness, Angle::Zero(), false); return true; }
void TerrainRenderer::Generate(const WindowProjection &map_projection, const Angle sunazimuth) { #ifdef ENABLE_OPENGL const GeoBounds &old_bounds = raster_renderer.GetBounds(); const GeoBounds &new_bounds = map_projection.GetScreenBounds(); assert(new_bounds.IsValid()); if (old_bounds.IsValid() && old_bounds.IsInside(new_bounds) && !IsLargeSizeDifference(old_bounds, new_bounds) && terrain_serial == terrain->GetSerial() && sunazimuth.CompareRoughly(last_sun_azimuth) && !raster_renderer.UpdateQuantisation()) /* no change since previous frame */ return; #else if (compare_projection.Compare(map_projection) && terrain_serial == terrain->GetSerial() && sunazimuth.CompareRoughly(last_sun_azimuth)) /* no change since previous frame */ return; compare_projection = CompareProjection(map_projection); #endif terrain_serial = terrain->GetSerial(); last_sun_azimuth = sunazimuth; const bool do_water = true; const unsigned height_scale = 4; const int interp_levels = 2; const bool is_terrain = true; const bool do_shading = is_terrain && settings.slope_shading != SlopeShading::OFF; const bool do_contour = is_terrain && settings.contours != Contours::OFF; const ColorRamp *const color_ramp = &terrain_colors[settings.ramp][0]; if (color_ramp != last_color_ramp) { raster_renderer.ColorTable(color_ramp, do_water, height_scale, interp_levels); last_color_ramp = color_ramp; } { RasterTerrain::Lease map(*terrain); raster_renderer.ScanMap(map, map_projection); } raster_renderer.GenerateImage(do_shading, height_scale, settings.contrast, settings.brightness, sunazimuth, do_contour); }
AirspaceFillRenderer(Canvas &_canvas, const WindowProjection &_projection, const AirspaceLook &_look, const AirspaceWarningCopy &_warnings, const AirspaceRendererSettings &_settings) :MapCanvas(_canvas, _projection, _projection.GetScreenBounds().Scale(fixed(1.1))), look(_look), warning_manager(_warnings), settings(_settings) { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); }
AirspaceOutlineRenderer(Canvas &_canvas, const WindowProjection &_projection, const AirspaceLook &_airspace_look, bool _black) :MapCanvas(_canvas, _projection, _projection.GetScreenBounds().Scale(fixed(1.1))), airspace_look(_airspace_look), black(_black) { if (black) canvas.SelectBlackPen(); canvas.SelectHollowBrush(); }
AirspaceOutlineRenderer(Canvas &_canvas, const WindowProjection &_projection, const AirspaceLook &_look, const AirspaceRendererSettings &_settings) :MapCanvas(_canvas, _projection, _projection.GetScreenBounds().Scale(fixed(1.1))), look(_look), settings(_settings) { if (settings.black_outline) canvas.SelectBlackPen(); canvas.SelectHollowBrush(); }
StencilMapCanvas::StencilMapCanvas(Canvas &_buffer, Canvas &_stencil, const WindowProjection &_proj, const AirspaceRendererSettings &_settings) :clip(_proj.GetScreenBounds().Scale(fixed(1.1))), buffer(_buffer), stencil(_stencil), proj(_proj), buffer_drawn(false), use_stencil(false), settings(_settings) { }
AirspaceVisitorRenderer(Canvas &_canvas, const WindowProjection &_projection, const AirspaceLook &_look, const AirspaceWarningCopy &_warnings, const AirspaceRendererSettings &_settings) :MapCanvas(_canvas, _projection, _projection.GetScreenBounds().Scale(fixed(1.1))), look(_look), warning_manager(_warnings), settings(_settings) { glStencilMask(0xff); glClear(GL_STENCIL_BUFFER_BIT); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); }
MapDrawHelper::MapDrawHelper(Canvas &_canvas, Canvas &_buffer, Canvas &_stencil, const WindowProjection &_proj, const AirspaceRendererSettings &_settings) :clip(_proj.GetScreenBounds().Scale(fixed(1.1))), m_canvas(_canvas), m_buffer(_buffer), m_stencil(_stencil), m_proj(_proj), m_buffer_drawn(false), m_use_stencil(false), settings(_settings) { }
void RasterRenderer::ScanMap(const RasterMap &map, const WindowProjection &projection) { // Coordinates of the MapWindow center unsigned x = projection.GetScreenWidth() / 2; unsigned y = projection.GetScreenHeight() / 2; // GeoPoint corresponding to the MapWindow center GeoPoint center = projection.ScreenToGeo(x, y); // GeoPoint "next to" Gmid (depends on terrain resolution) GeoPoint neighbor = projection.ScreenToGeo(x + quantisation_pixels, y + quantisation_pixels); // Geographical edge length of pixel in the MapWindow center in meters pixel_size = M_SQRT1_2 * center.DistanceS(neighbor); // set resolution if (pixel_size < 3000) { // Data point size of the (terrain) map in meters multiplied by 256 auto map_pixel_size = map.PixelDistance(center, 1); // How many screen pixels does one data point stretch? auto q = map_pixel_size / pixel_size; /* round down to reduce slope shading artefacts (caused by RasterBuffer interpolation) */ quantisation_effective = std::max(1, (int)q); /* disable slope shading when zoomed in very near (not enough terrain resolution to make a useful slope calculation) */ if (quantisation_effective > 25) quantisation_effective = 0; } else /* disable slope shading when zoomed out very far (too tiny) */ quantisation_effective = 0; #ifdef ENABLE_OPENGL bounds = projection.GetScreenBounds().Scale(1.5); bounds.IntersectWith(map.GetBounds()); height_matrix.Fill(map, bounds, projection.GetScreenWidth() / quantisation_pixels, projection.GetScreenHeight() / quantisation_pixels, true); last_quantisation_pixels = quantisation_pixels; #else height_matrix.Fill(map, projection, quantisation_pixels, true); #endif }
void RasterRenderer::ScanMap(const RasterMap &map, const WindowProjection &projection) { // Coordinates of the MapWindow center unsigned x = projection.GetScreenWidth() / 2; unsigned y = projection.GetScreenHeight() / 2; // GeoPoint corresponding to the MapWindow center GeoPoint Gmid = projection.ScreenToGeo(x, y); // GeoPoint "next to" Gmid (depends on terrain resolution) GeoPoint Gneighbor = projection.ScreenToGeo(x + quantisation_pixels, y + quantisation_pixels); // Geographical edge length of pixel in the MapWindow center in meters pixel_size = fixed_sqrt_half * Gmid.Distance(Gneighbor); // set resolution if (pixel_size < fixed(3000)) { /* round down to reduce slope shading artefacts (caused by RasterBuffer interpolation) */ fixed map_pixel_size = map.PixelDistance(Gmid, 1); fixed q = map_pixel_size / pixel_size; quantisation_effective = std::max(1, (int)q); if (quantisation_effective > 25) /* disable slope shading when zoomed in very near (not enough terrain resolution to make a useful slope calculation) */ quantisation_effective = 0; } else /* disable slope shading when zoomed out very far (too tiny) */ quantisation_effective = 0; #ifdef ENABLE_OPENGL bounds = projection.GetScreenBounds().Scale(fixed(1.5)); height_matrix.Fill(map, bounds, projection.GetScreenWidth() / quantisation_pixels, projection.GetScreenHeight() / quantisation_pixels, true); last_quantisation_pixels = quantisation_pixels; #else height_matrix.Fill(map, projection, quantisation_pixels, true); #endif }
static void PaintTask(Canvas &canvas, const WindowProjection &projection, const OrderedTask &task, const GeoPoint &location, const MapSettings &settings_map, const TaskLook &task_look, const AirspaceLook &airspace_look, const RasterTerrain *terrain) { BackgroundRenderer background; background.SetTerrain(terrain); background.Draw(canvas, projection, settings_map.terrain); OZRenderer ozv(task_look, airspace_look, settings_map.airspace); RenderTaskPoint tpv(canvas, projection, task_look, task.GetTaskProjection(), ozv, false, RenderTaskPoint::NONE, location); TaskRenderer dv(tpv, projection.GetScreenBounds()); dv.Draw(task); }
static void PaintTask(Canvas &canvas, const WindowProjection &projection, const OrderedTask &task, const GeoPoint &location, const SETTINGS_MAP &settings_map, const TaskLook &task_look, const AirspaceLook &airspace_look, const RasterTerrain *terrain) { BackgroundDrawHelper background; background.set_terrain(terrain); background.Draw(canvas, projection, settings_map.terrain); RenderObservationZone ozv(task_look, airspace_look); RenderTaskPoint tpv(canvas, NULL, projection, settings_map, task_look, task.get_task_projection(), ozv, false, false, location); RenderTask dv(tpv, projection.GetScreenBounds()); dv.Visit(task); }
static void PaintTask(Canvas &canvas, const WindowProjection &projection, const OrderedTask &task, const GeoPoint &location, const MapSettings &settings_map, const TaskLook &task_look, const AirspaceLook &airspace_look, const RasterTerrain *terrain, const Airspaces *airspaces) { BackgroundRenderer background; background.SetTerrain(terrain); background.Draw(canvas, projection, settings_map.terrain); if (airspaces != NULL) { AirspaceRenderer airspace_renderer(airspace_look); airspace_renderer.SetAirspaces(airspaces); #ifndef ENABLE_OPENGL BufferCanvas buffer_canvas, stencil_canvas; buffer_canvas.set(canvas); stencil_canvas.set(canvas); #endif airspace_renderer.Draw(canvas, #ifndef ENABLE_OPENGL buffer_canvas, stencil_canvas, #endif projection, settings_map.airspace); } #ifdef ENABLE_OPENGL /* desaturate the map background, to focus on the task */ canvas.FadeToWhite(0xc0); #endif OZRenderer ozv(task_look, airspace_look, settings_map.airspace); RenderTaskPoint tpv(canvas, projection, task_look, task.GetTaskProjection(), ozv, false, RenderTaskPoint::NONE, location); TaskRenderer dv(tpv, projection.GetScreenBounds()); dv.Draw(task); }
void RenderFAISector(Canvas &canvas, const WindowProjection &projection, const GeoPoint &pt1, const GeoPoint &pt2, bool reverse, const FAITriangleSettings &settings) { GeoPoint geo_points[FAI_TRIANGLE_SECTOR_MAX]; GeoPoint *geo_end = GenerateFAITriangleArea(geo_points, pt1, pt2, reverse, settings); GeoPoint clipped[FAI_TRIANGLE_SECTOR_MAX * 3], *clipped_end = clipped + GeoClip(projection.GetScreenBounds().Scale(fixed(1.1))) .ClipPolygon(clipped, geo_points, geo_end - geo_points); RasterPoint points[FAI_TRIANGLE_SECTOR_MAX], *p = points; for (GeoPoint *geo_i = clipped; geo_i != clipped_end;) *p++ = projection.GeoToScreen(*geo_i++); canvas.DrawPolygon(points, p - points); }
RenderTaskPoint::RenderTaskPoint(Canvas &_canvas, const WindowProjection &_projection, const TaskLook &_task_look, const TaskProjection &_task_projection, OZRenderer &_ozv, bool _draw_bearing, TargetVisibility _target_visibility, const GeoPoint &_location) :canvas(_canvas), m_proj(_projection), map_canvas(_canvas, _projection, _projection.GetScreenBounds().Scale(fixed(1.1))), task_look(_task_look), task_projection(_task_projection), draw_bearing(_draw_bearing), target_visibility(_target_visibility), index(0), ozv(_ozv), active_index(0), location(_location), mode_optional_start(false) { }
void TrailRenderer::Draw(Canvas &canvas, const TraceComputer &trace_computer, const WindowProjection &projection, unsigned min_time, bool enable_traildrift, const RasterPoint pos, const NMEAInfo &basic, const DerivedInfo &calculated, const TrailSettings &settings) { if (settings.length == TrailSettings::Length::OFF) return; if (!LoadTrace(trace_computer, min_time, projection)) return; if (!calculated.wind_available) enable_traildrift = false; GeoPoint traildrift; if (enable_traildrift) { GeoPoint tp1 = FindLatitudeLongitude(basic.location, calculated.wind.bearing, calculated.wind.norm); traildrift = basic.location - tp1; } auto minmax = GetMinMax(settings.type, trace); auto value_min = minmax.first; auto value_max = minmax.second; bool scaled_trail = settings.scaling_enabled && projection.GetMapScale() <= 6000; const GeoBounds bounds = projection.GetScreenBounds().Scale(4); RasterPoint last_point = RasterPoint(0, 0); bool last_valid = false; for (auto it = trace.begin(), end = trace.end(); it != end; ++it) { const GeoPoint gp = enable_traildrift ? it->GetLocation().Parametric(traildrift, it->CalculateDrift(basic.time)) : it->GetLocation(); if (!bounds.IsInside(gp)) { /* the point is outside of the MapWindow; don't paint it */ last_valid = false; continue; } RasterPoint pt = projection.GeoToScreen(gp); if (last_valid) { if (settings.type == TrailSettings::Type::ALTITUDE) { unsigned index = GetAltitudeColorIndex(it->GetAltitude(), value_min, value_max); canvas.Select(look.trail_pens[index]); canvas.DrawLinePiece(last_point, pt); } else { unsigned color_index = GetSnailColorIndex(it->GetVario(), value_min, value_max); if (it->GetVario() < 0 && (settings.type == TrailSettings::Type::VARIO_1_DOTS || settings.type == TrailSettings::Type::VARIO_2_DOTS || settings.type == TrailSettings::Type::VARIO_DOTS_AND_LINES)) { canvas.SelectNullPen(); canvas.Select(look.trail_brushes[color_index]); canvas.DrawCircle((pt.x + last_point.x) / 2, (pt.y + last_point.y) / 2, look.trail_widths[color_index]); } else { // positive vario case if (settings.type == TrailSettings::Type::VARIO_DOTS_AND_LINES) { canvas.Select(look.trail_brushes[color_index]); canvas.Select(look.trail_pens[color_index]); //fixed-width pen canvas.DrawCircle((pt.x + last_point.x) / 2, (pt.y + last_point.y) / 2, look.trail_widths[color_index]); } else if (scaled_trail) // width scaled to vario canvas.Select(look.scaled_trail_pens[color_index]); else // fixed-width pen canvas.Select(look.trail_pens[color_index]); canvas.DrawLinePiece(last_point, pt); } } } last_point = pt; last_valid = true; } if (last_valid) canvas.DrawLine(last_point, pos); }
void TrailRenderer::Draw(Canvas &canvas, const TraceComputer &trace_computer, const WindowProjection &projection, unsigned min_time, bool enable_traildrift, const RasterPoint pos, const NMEAInfo &basic, const DerivedInfo &calculated, const MapSettings &settings) { if (settings.trail_length == TRAIL_OFF) return; if (!LoadTrace(trace_computer, min_time, projection)) return; if (!calculated.wind_available) enable_traildrift = false; GeoPoint traildrift; if (enable_traildrift) { GeoPoint tp1 = FindLatitudeLongitude(basic.location, calculated.wind.bearing, calculated.wind.norm); traildrift = basic.location - tp1; } fixed value_max, value_min; if (settings.snail_type == stAltitude) { value_max = fixed(1000); value_min = fixed(500); for (auto it = trace.begin(); it != trace.end(); ++it) { value_max = max(it->GetAltitude(), value_max); value_min = min(it->GetAltitude(), value_min); } } else { value_max = fixed(0.75); value_min = fixed(-2.0); for (auto it = trace.begin(); it != trace.end(); ++it) { value_max = max(it->GetVario(), value_max); value_min = min(it->GetVario(), value_min); } value_max = min(fixed(7.5), value_max); value_min = max(fixed(-5.0), value_min); } bool scaled_trail = settings.snail_scaling_enabled && projection.GetMapScale() <= fixed_int_constant(6000); const GeoBounds bounds = projection.GetScreenBounds().Scale(fixed_four); RasterPoint last_point; bool last_valid = false; for (auto it = trace.begin(), end = trace.end(); it != end; ++it) { const GeoPoint gp = enable_traildrift ? it->get_location().Parametric(traildrift, it->CalculateDrift(basic.time)) : it->get_location(); if (!bounds.IsInside(gp)) { /* the point is outside of the MapWindow; don't paint it */ last_valid = false; continue; } RasterPoint pt = projection.GeoToScreen(gp); if (last_valid) { if (settings.snail_type == stAltitude) { unsigned index((it->GetAltitude() - value_min) / (value_max - value_min) * (TrailLook::NUMSNAILCOLORS - 1)); index = max(0u, min(TrailLook::NUMSNAILCOLORS - 1, index)); canvas.Select(look.hpSnail[index]); } else { const fixed colour_vario = negative(it->GetVario()) ? - it->GetVario() / value_min : it->GetVario() / value_max ; if (!scaled_trail) canvas.Select(look.hpSnail[GetSnailColorIndex(colour_vario)]); else canvas.Select(look.hpSnailVario[GetSnailColorIndex(colour_vario)]); } canvas.line_piece(last_point, pt); } last_point = pt; last_valid = true; } canvas.line(last_point, pos); }
void TopographyFileRenderer::Paint(Canvas &canvas, const WindowProjection &projection) { if (file.IsEmpty()) return; fixed map_scale = projection.GetMapScale(); if (!file.IsVisible(map_scale)) return; UpdateVisibleShapes(projection); if (visible_shapes.empty()) return; // TODO code: only draw inside screen! // this will save time with rendering pixmaps especially // we already do an outer visibility test, but may need a test // in screen coords #ifdef ENABLE_OPENGL pen.Set(); brush.Set(); #else shape_renderer.Configure(&pen, &brush); #endif // get drawing info #ifdef ENABLE_OPENGL const unsigned level = file.GetThinningLevel(map_scale); const unsigned min_distance = file.GetMinimumPointDistance(level) / Layout::Scale(1); #ifndef HAVE_GLES float opengl_matrix[16]; glGetFloatv(GL_MODELVIEW_MATRIX, opengl_matrix); #endif glPushMatrix(); fixed angle = projection.GetScreenAngle().Degrees(); fixed scale = projection.GetScale(); const RasterPoint &screen_origin = projection.GetScreenOrigin(); #ifdef HAVE_GLES #ifdef FIXED_MATH GLfixed fixed_angle = angle.as_glfixed(); GLfixed fixed_scale = scale.as_glfixed_scale(); #else GLfixed fixed_angle = angle * (1<<16); GLfixed fixed_scale = scale * (1LL<<32); #endif glTranslatex((int)screen_origin.x << 16, (int)screen_origin.y << 16, 0); glRotatex(fixed_angle, 0, 0, -(1<<16)); glScalex(fixed_scale, fixed_scale, 1<<16); #else glTranslatef(screen_origin.x, screen_origin.y, 0.); glRotatef((GLfloat)angle, 0., 0., -1.); glScalef((GLfloat)scale, (GLfloat)scale, 1.); #endif #else // !ENABLE_OPENGL const GeoClip clip(projection.GetScreenBounds().Scale(fixed(1.1))); AllocatedArray<GeoPoint> geo_points; int iskip = file.GetSkipSteps(map_scale); #endif for (auto it = visible_shapes.begin(), end = visible_shapes.end(); it != end; ++it) { const XShape &shape = **it; if (!projection.GetScreenBounds().Overlaps(shape.get_bounds())) continue; #ifdef ENABLE_OPENGL const ShapePoint *points = shape.get_points(); const ShapePoint translation = shape.shape_translation(projection.GetGeoLocation()); glPushMatrix(); #ifdef HAVE_GLES glTranslatex(translation.x, translation.y, 0); #else glTranslatef(translation.x, translation.y, 0.); #endif #else // !ENABLE_OPENGL const unsigned short *lines = shape.get_lines(); const unsigned short *end_lines = lines + shape.get_number_of_lines(); const GeoPoint *points = shape.get_points(); #endif switch (shape.get_type()) { case MS_SHAPE_NULL: break; case MS_SHAPE_POINT: #ifdef ENABLE_OPENGL #ifdef HAVE_GLES PaintPoint(canvas, projection, shape, NULL); #else PaintPoint(canvas, projection, shape, opengl_matrix); #endif #else // !ENABLE_OPENGL PaintPoint(canvas, projection, lines, end_lines, points); #endif break; case MS_SHAPE_LINE: { #ifdef ENABLE_OPENGL #ifdef HAVE_GLES glVertexPointer(2, GL_FIXED, 0, &points[0].x); #else glVertexPointer(2, GL_INT, 0, &points[0].x); #endif const GLushort *indices, *count; if (level == 0 || (indices = shape.get_indices(level, min_distance, count)) == NULL) { count = shape.get_lines(); const GLushort *end_count = count + shape.get_number_of_lines(); for (int offset = 0; count < end_count; offset += *count++) glDrawArrays(GL_LINE_STRIP, offset, *count); } else { const GLushort *end_count = count + shape.get_number_of_lines(); for (; count < end_count; indices += *count++) glDrawElements(GL_LINE_STRIP, *count, GL_UNSIGNED_SHORT, indices); } #else // !ENABLE_OPENGL for (; lines < end_lines; ++lines) { unsigned msize = *lines; shape_renderer.Begin(msize); const GeoPoint *end = points + msize - 1; for (; points < end; ++points) shape_renderer.AddPointIfDistant(projection.GeoToScreen(*points)); // make sure we always draw the last point shape_renderer.AddPoint(projection.GeoToScreen(*points)); shape_renderer.FinishPolyline(canvas); } #endif } break; case MS_SHAPE_POLYGON: #ifdef ENABLE_OPENGL { const GLushort *index_count; const GLushort *triangles = shape.get_indices(level, min_distance, index_count); #ifdef HAVE_GLES glVertexPointer(2, GL_FIXED, 0, &points[0].x); #else glVertexPointer(2, GL_INT, 0, &points[0].x); #endif glDrawElements(GL_TRIANGLE_STRIP, *index_count, GL_UNSIGNED_SHORT, triangles); } #else // !ENABLE_OPENGL for (; lines < end_lines; ++lines) { unsigned msize = *lines / iskip; /* copy all polygon points into the geo_points array and clip them, to avoid integer overflows (as RasterPoint may store only 16 bit integers on some platforms) */ geo_points.GrowDiscard(msize * 3); for (unsigned i = 0; i < msize; ++i) geo_points[i] = points[i * iskip]; msize = clip.ClipPolygon(geo_points.begin(), geo_points.begin(), msize); if (msize < 3) continue; shape_renderer.Begin(msize); for (unsigned i = 0; i < msize; ++i) { GeoPoint g = geo_points[i]; shape_renderer.AddPointIfDistant(projection.GeoToScreen(g)); } shape_renderer.FinishPolygon(canvas); } #endif break; } #ifdef ENABLE_OPENGL glPopMatrix(); #endif } #ifdef ENABLE_OPENGL glPopMatrix(); #else shape_renderer.Commit(); #endif }
void TrailRenderer::Draw(Canvas &canvas, const TraceComputer &trace_computer, const WindowProjection &projection, unsigned min_time, bool enable_traildrift, const RasterPoint pos, const NMEAInfo &basic, const DerivedInfo &calculated, const TrailSettings &settings) { if (settings.length == TrailSettings::Length::OFF) return; if (!LoadTrace(trace_computer, min_time, projection)) return; if (!calculated.wind_available) enable_traildrift = false; GeoPoint traildrift; if (enable_traildrift) { GeoPoint tp1 = FindLatitudeLongitude(basic.location, calculated.wind.bearing, calculated.wind.norm); traildrift = basic.location - tp1; } fixed value_max, value_min; GetMinMax(value_min, value_max, settings.type, trace); bool scaled_trail = settings.scaling_enabled && projection.GetMapScale() <= fixed_int_constant(6000); const GeoBounds bounds = projection.GetScreenBounds().Scale(fixed_four); RasterPoint last_point; bool last_valid = false; for (auto it = trace.begin(), end = trace.end(); it != end; ++it) { const GeoPoint gp = enable_traildrift ? it->GetLocation().Parametric(traildrift, it->CalculateDrift(basic.time)) : it->GetLocation(); if (!bounds.IsInside(gp)) { /* the point is outside of the MapWindow; don't paint it */ last_valid = false; continue; } RasterPoint pt = projection.GeoToScreen(gp); if (last_valid) { if (settings.type == TrailSettings::Type::ALTITUDE) { unsigned index((it->GetAltitude() - value_min) / (value_max - value_min) * (TrailLook::NUMSNAILCOLORS - 1)); index = max(0u, min(TrailLook::NUMSNAILCOLORS - 1, index)); canvas.Select(look.trail_pens[index]); canvas.DrawLinePiece(last_point, pt); } else { const fixed colour_vario = negative(it->GetVario()) ? - it->GetVario() / value_min : it->GetVario() / value_max ; unsigned color_index = GetSnailColorIndex(colour_vario); if (negative(it->GetVario()) && (settings.type == TrailSettings::Type::VARIO_1_DOTS || settings.type == TrailSettings::Type::VARIO_2_DOTS)) { canvas.SelectNullPen(); canvas.Select(look.trail_brushes[color_index]); canvas.DrawCircle((pt.x + last_point.x) / 2, (pt.y + last_point.y) / 2, look.trail_widths[color_index]); } else { if (!scaled_trail) canvas.Select(look.trail_pens[color_index]); else canvas.Select(look.scaled_trail_pens[color_index]); canvas.DrawLinePiece(last_point, pt); } } } last_point = pt; last_valid = true; } if (last_valid) canvas.DrawLine(last_point, pos); }
bool TopographyFile::Update(const WindowProjection &map_projection) { if (IsEmpty()) return false; if (map_projection.GetMapScale() > scale_threshold) /* not visible, don't update cache now */ return false; const GeoBounds screenRect = map_projection.GetScreenBounds(); if (cache_bounds.IsValid() && cache_bounds.IsInside(screenRect)) /* the cache is still fresh */ return false; cache_bounds = screenRect.Scale(2); rectObj deg_bounds = ConvertRect(cache_bounds); // Test which shapes are inside the given bounds and save the // status to file.status switch (msShapefileWhichShapes(&file, dir, deg_bounds, 0)) { case MS_FAILURE: ClearCache(); return false; case MS_DONE: /* screen is outside of map bounds */ return false; case MS_SUCCESS: break; } assert(file.status != nullptr); // Iterate through the shapefile entries const ShapeList **current = &first; auto it = shapes.begin(); for (int i = 0; i < file.numshapes; ++i, ++it) { if (!msGetBit(file.status, i)) { // If the shape is outside the bounds // delete the shape from the cache if (it->shape != nullptr) { assert(*current == it); /* remove from linked list (protected) */ { const ScopeLock lock(mutex); *current = it->next; ++serial; } /* now it's unreachable, and we can delete the XShape without holding a lock */ delete it->shape; it->shape = nullptr; } } else { // is inside the bounds if (it->shape == nullptr) { assert(*current != it); // shape isn't cached yet -> cache the shape it->shape = LoadShape(&file, center, i, label_field); it->next = *current; /* insert into linked list (protected) */ { const ScopeLock lock(mutex); *current = it; ++serial; } } current = &it->next; } } // end of list marker assert(*current == nullptr); return true; }
void PaintTask(Canvas &canvas, const WindowProjection &projection, const OrderedTask &task, const GeoPoint &location, const MapSettings &settings_map, const TaskLook &task_look, const AirspaceLook &airspace_look, const RasterTerrain *terrain, const Airspaces *airspaces, bool fai_sectors, int highlight_index) { BackgroundRenderer background; background.SetTerrain(terrain); background.Draw(canvas, projection, settings_map.terrain); if (airspaces != NULL) { AirspaceRenderer airspace_renderer(airspace_look); airspace_renderer.SetAirspaces(airspaces); #ifndef ENABLE_OPENGL BufferCanvas stencil_canvas; stencil_canvas.Create(canvas); #endif airspace_renderer.Draw(canvas, #ifndef ENABLE_OPENGL stencil_canvas, #endif projection, settings_map.airspace); } #ifdef ENABLE_OPENGL /* desaturate the map background, to focus on the task */ canvas.FadeToWhite(0xc0); #endif if (fai_sectors && IsFAITriangleApplicable(task)) { static constexpr Color fill_color = COLOR_YELLOW; #if defined(ENABLE_OPENGL) || defined(USE_MEMORY_CANVAS) #ifdef ENABLE_OPENGL const ScopeAlphaBlend alpha_blend; #endif canvas.Select(Brush(fill_color.WithAlpha(40))); canvas.Select(Pen(1, COLOR_BLACK.WithAlpha(80))); RenderFAISectors(canvas, projection, task); #else BufferCanvas buffer_canvas; buffer_canvas.Create(canvas); buffer_canvas.ClearWhite(); #ifdef HAVE_HATCHED_BRUSH buffer_canvas.Select(airspace_look.brushes[3]); buffer_canvas.SetTextColor(fill_color); buffer_canvas.SetBackgroundColor(COLOR_WHITE); #else buffer_canvas.Select(Brush(fill_color)); #endif buffer_canvas.SelectNullPen(); RenderFAISectors(buffer_canvas, projection, task); canvas.CopyAnd(buffer_canvas); canvas.SelectHollowBrush(); canvas.SelectBlackPen(); RenderFAISectors(canvas, projection, task); #endif } OZRenderer ozv(task_look, airspace_look, settings_map.airspace); TaskPointRenderer tpv(canvas, projection, task_look, task.GetTaskProjection(), ozv, false, TaskPointRenderer::NONE, location); TaskRenderer dv(tpv, projection.GetScreenBounds()); dv.Draw(task); // highlight a task point if (highlight_index >= 0 && highlight_index < (int) task.TaskSize()) { /* TODO: clumsy way of highlighting. maybe it should be done by * painting the task point with a different pen and brush, * e.g. red, 4px wide */ auto pt = projection.GeoToScreen(task.GetPoint(highlight_index). GetLocation()); canvas.Select(task_look.highlight_pen); canvas.DrawLine(pt.x - 7, pt.y - 7, pt.x + 7, pt.y + 7); canvas.DrawLine(pt.x + 7, pt.y - 7, pt.x - 7, pt.y + 7); } }
bool TopographyFile::Update(const WindowProjection &map_projection) { if (IsEmpty()) return false; if (map_projection.GetMapScale() > scale_threshold) /* not visible, don't update cache now */ return false; const GeoBounds screenRect = map_projection.GetScreenBounds(); if (cache_bounds.inside(screenRect)) /* the cache is still fresh */ return false; cache_bounds = map_projection.GetScreenBounds().scale(fixed_two); rectObj deg_bounds = ConvertRect(cache_bounds); // Test which shapes are inside the given bounds and save the // status to file.status msShapefileWhichShapes(&file, dir, deg_bounds, 0); // If not a single shape is inside the bounds if (!file.status) { // ... clear the whole buffer ClearCache(); return false; } // Iterate through the shapefile entries for (int i = 0; i < file.numshapes; i++) { if (!msGetBit(file.status, i)) { // If the shape is outside the bounds // delete the shape from the cache delete shapes[i].shape; shapes[i].shape = NULL; } else if (shapes[i].shape == NULL) { // If the shape is inside the bounds and if the // shape isn't cached yet -> cache the shape shapes[i].shape = new XShape(&file, i, label_field); } } ShapeList::NotNull not_null; XShapePointerArray::iterator end = shapes.end(), it = shapes.begin(); it = std::find_if(it, end, not_null); if (it != shapes.end()) { ShapeList *current = &*it; first = current; while (true) { ++it; it = std::find_if(it, end, not_null); if (it == end) { current->next = NULL; break; } ShapeList *next = &*it; current->next = next; current = next; } } else first = NULL; return true; }
void TopographyFileRenderer::PaintLabels(Canvas &canvas, const WindowProjection &projection, LabelBlock &label_block) { if (file.IsEmpty()) return; fixed map_scale = projection.GetMapScale(); if (!file.IsVisible(map_scale) || !file.IsLabelVisible(map_scale)) return; UpdateVisibleShapes(projection); if (visible_labels.empty()) return; // TODO code: only draw inside screen! // this will save time with rendering pixmaps especially // we already do an outer visibility test, but may need a test // in screen coords canvas.Select(file.IsLabelImportant(map_scale) ? Fonts::map_label_important : Fonts::map_label); canvas.SetTextColor(Color(0x20, 0x20, 0x20)); canvas.SetBackgroundTransparent(); // get drawing info int iskip = file.GetSkipSteps(map_scale); #ifdef ENABLE_OPENGL Matrix2D m1; m1.Translate(projection.GetScreenOrigin()); m1.Rotate(projection.GetScreenAngle()); m1.Scale(projection.GetScale()); #endif // Iterate over all shapes in the file for (auto it = visible_labels.begin(), end = visible_labels.end(); it != end; ++it) { const XShape &shape = **it; if (!projection.GetScreenBounds().Overlaps(shape.get_bounds())) continue; // Skip shapes without a label const TCHAR *label = shape.get_label(); if (label == NULL) continue; const unsigned short *lines = shape.get_lines(); const unsigned short *end_lines = lines + shape.get_number_of_lines(); #ifdef ENABLE_OPENGL const ShapePoint *points = shape.get_points(); Matrix2D m2(m1); m2.Translatex(shape.shape_translation(projection.GetGeoLocation())); #else const GeoPoint *points = shape.get_points(); #endif for (; lines < end_lines; ++lines) { int minx = canvas.get_width(); int miny = canvas.get_height(); #ifdef ENABLE_OPENGL const ShapePoint *end = points + *lines; #else const GeoPoint *end = points + *lines; #endif for (; points < end; points += iskip) { #ifdef ENABLE_OPENGL RasterPoint pt = m2.Apply(*points); #else RasterPoint pt = projection.GeoToScreen(*points); #endif if (pt.x <= minx) { minx = pt.x; miny = pt.y; } } points = end; minx += 2; miny += 2; PixelSize tsize = canvas.CalcTextSize(label); PixelRect brect; brect.left = minx; brect.right = brect.left + tsize.cx; brect.top = miny; brect.bottom = brect.top + tsize.cy; if (!label_block.check(brect)) continue; canvas.text(minx, miny, label); } } }