diff --git a/android/app/src/main/java/app/organicmaps/Map.java b/android/app/src/main/java/app/organicmaps/Map.java index 8a13a57208..65b8abfffb 100644 --- a/android/app/src/main/java/app/organicmaps/Map.java +++ b/android/app/src/main/java/app/organicmaps/Map.java @@ -35,6 +35,7 @@ public final class Map public static final int WIDGET_COMPASS = 0x02; public static final int WIDGET_COPYRIGHT = 0x04; public static final int WIDGET_SCALE_FPS_LABEL = 0x08; + public static final int WIDGET_SPEED_LIMIT = 0x10; // Should correspond to dp::Anchor from drape_global.hpp public static final int ANCHOR_CENTER = 0x00; @@ -328,11 +329,13 @@ public final class Map if (mDisplayType == DisplayType.Device) { nativeSetupWidget(WIDGET_SCALE_FPS_LABEL, UiUtils.dimen(context, R.dimen.margin_base), UiUtils.dimen(context, R.dimen.margin_base) * 2, ANCHOR_LEFT_TOP); + nativeSetupWidget(WIDGET_SPEED_LIMIT, mWidth / 2, mHeight / 2, ANCHOR_CENTER); updateCompassOffset(context, mCurrentCompassOffsetX, mCurrentCompassOffsetY, false); } else { nativeSetupWidget(WIDGET_SCALE_FPS_LABEL, UiUtils.dimen(context, R.dimen.margin_base), mHeight - UiUtils.dimen(context, R.dimen.margin_base) * 5, ANCHOR_LEFT_TOP); + nativeSetupWidget(WIDGET_SPEED_LIMIT, mWidth / 2, mHeight / 2, ANCHOR_CENTER); updateCompassOffset(context, mWidth, mCurrentCompassOffsetY, true); } } diff --git a/drape/color.cpp b/drape/color.cpp index c8258daa03..231d7c2943 100644 --- a/drape/color.cpp +++ b/drape/color.cpp @@ -23,11 +23,6 @@ Color::Color(uint32_t rgba) : m_rgba(rgba) {} -Color::Color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) -{ - m_rgba = red << 24 | green << 16 | blue << 8 | alpha; -} - uint8_t Color::GetRed() const { return EXTRACT_BYTE(m_rgba, 3); diff --git a/drape/color.hpp b/drape/color.hpp index b46edacc14..0b96881775 100644 --- a/drape/color.hpp +++ b/drape/color.hpp @@ -12,7 +12,10 @@ struct Color { Color(); explicit Color(uint32_t rgba); - Color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha); + constexpr Color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) + : m_rgba(red << 24 | green << 16 | blue << 8 | alpha) + { + } uint8_t GetRed() const; uint8_t GetGreen() const; @@ -37,13 +40,13 @@ struct Color void PremultiplyAlpha(float opacity); - static Color Black() { return Color(0, 0, 0, 255); } - static Color White() { return Color(255, 255, 255, 255); } - static Color Red() { return Color(255, 0, 0, 255); } - static Color Blue() { return Color(0, 0, 255, 255); } - static Color Green() { return Color(0, 255, 0, 255); } - static Color Yellow() { return Color(255, 255, 0, 255); } - static Color Transparent() { return Color(0, 0, 0, 0); } + static constexpr Color Black() { return Color(0, 0, 0, 255); } + static constexpr Color White() { return Color(255, 255, 255, 255); } + static constexpr Color Red() { return Color(255, 0, 0, 255); } + static constexpr Color Blue() { return Color(0, 0, 255, 255); } + static constexpr Color Green() { return Color(0, 255, 0, 255); } + static constexpr Color Yellow() { return Color(255, 255, 0, 255); } + static constexpr Color Transparent() { return Color(0, 0, 0, 0); } private: uint32_t m_rgba; diff --git a/drape_frontend/CMakeLists.txt b/drape_frontend/CMakeLists.txt index 472346ab74..dde4763f12 100644 --- a/drape_frontend/CMakeLists.txt +++ b/drape_frontend/CMakeLists.txt @@ -77,6 +77,8 @@ set(SRC gps_track_point.hpp gps_track_renderer.cpp gps_track_renderer.hpp + gui/elements/circle.cpp + gui/elements/circle.hpp gui/choose_position_mark.cpp gui/choose_position_mark.hpp gui/compass.cpp @@ -100,6 +102,10 @@ set(SRC gui/shape.hpp gui/skin.cpp gui/skin.hpp + gui/speed_limit.cpp + gui/speed_limit.hpp + gui/speed_limit_helper.hpp + gui/speed_limit_helper.cpp kinetic_scroller.cpp kinetic_scroller.hpp line_shape.cpp diff --git a/drape_frontend/drape_engine.cpp b/drape_frontend/drape_engine.cpp index 448f7441e7..c4b8deb6b0 100644 --- a/drape_frontend/drape_engine.cpp +++ b/drape_frontend/drape_engine.cpp @@ -497,6 +497,11 @@ void DrapeEngine::SetGpsInfo(location::GpsInfo const & info, bool isNavigable, MessagePriority::Normal); } +void DrapeEngine::SetSpeedLimitInfo(double speedLimitMps) const +{ + gui::DrapeGui::Instance().GetSpeedLimitHelper().SetSpeedLimit(speedLimitMps); +} + void DrapeEngine::SwitchMyPositionNextMode() { using Mode = ChangeMyPositionModeMessage::EChangeType; diff --git a/drape_frontend/drape_engine.hpp b/drape_frontend/drape_engine.hpp index 92017e4310..42d485089b 100644 --- a/drape_frontend/drape_engine.hpp +++ b/drape_frontend/drape_engine.hpp @@ -156,6 +156,7 @@ public: void SetCompassInfo(location::CompassInfo const & info); void SetGpsInfo(location::GpsInfo const & info, bool isNavigable, location::RouteMatchingInfo const & routeInfo); + void SetSpeedLimitInfo(double speedLimitMps) const; void SwitchMyPositionNextMode(); void LoseLocation(); void StopLocationFollow(); diff --git a/drape_frontend/gui/drape_gui.cpp b/drape_frontend/gui/drape_gui.cpp index f087eb29ca..76089eff8d 100644 --- a/drape_frontend/gui/drape_gui.cpp +++ b/drape_frontend/gui/drape_gui.cpp @@ -13,6 +13,7 @@ df::ColorConstant const kGuiTextColor = "GuiText"; struct DrapeGui::Impl { RulerHelper m_rulerHelper; + SpeedLimitHelper m_speedLimitHelper; }; DrapeGui::DrapeGui() @@ -33,6 +34,11 @@ RulerHelper & DrapeGui::GetRulerHelper() return Instance().GetRulerHelperImpl(); } +SpeedLimitHelper & DrapeGui::GetSpeedLimitHelper() +{ + return Instance().GetSpeedLimitHelperImpl(); +} + dp::FontDecl DrapeGui::GetGuiTextFont() { return {df::GetColorConstant(kGuiTextColor), 14}; @@ -62,6 +68,12 @@ RulerHelper & DrapeGui::GetRulerHelperImpl() return m_impl->m_rulerHelper; } +SpeedLimitHelper & DrapeGui::GetSpeedLimitHelperImpl() +{ + ASSERT(m_impl != nullptr, ()); + return m_impl->m_speedLimitHelper; +} + void DrapeGui::ConnectOnCompassTappedHandler(Shape::TTapHandler const & handler) { m_onCompassTappedHandler = handler; diff --git a/drape_frontend/gui/drape_gui.hpp b/drape_frontend/gui/drape_gui.hpp index 0da8c0e992..e1edefbe99 100644 --- a/drape_frontend/gui/drape_gui.hpp +++ b/drape_frontend/gui/drape_gui.hpp @@ -3,6 +3,7 @@ #include "drape_frontend/gui/compass.hpp" #include "drape_frontend/gui/scale_fps_helper.hpp" #include "drape_frontend/gui/skin.hpp" +#include "drape_frontend/gui/speed_limit_helper.hpp" #include "storage/storage_defines.hpp" @@ -23,6 +24,7 @@ class DrapeGui public: static DrapeGui & Instance(); static RulerHelper & GetRulerHelper(); + static SpeedLimitHelper & GetSpeedLimitHelper(); static dp::FontDecl GetGuiTextFont(); @@ -45,6 +47,7 @@ public: private: DrapeGui(); RulerHelper & GetRulerHelperImpl(); + SpeedLimitHelper & GetSpeedLimitHelperImpl(); struct Impl; std::unique_ptr m_impl; diff --git a/drape_frontend/gui/elements/circle.cpp b/drape_frontend/gui/elements/circle.cpp new file mode 100644 index 0000000000..8a8e216396 --- /dev/null +++ b/drape_frontend/gui/elements/circle.cpp @@ -0,0 +1,107 @@ +#include "circle.hpp" + +namespace +{ +struct CircleVertex +{ + CircleVertex() = default; + + CircleVertex(glsl::vec2 position, glsl::vec3 color, glsl::vec3 outlineColor, float radius, float outlineWidthRatio) + : m_position(position) + , m_color(color) + , m_outlineColor(outlineColor) + , m_radius(radius) + , m_outlineWidthRatio(outlineWidthRatio) + { + } + + static dp::BindingInfo GetBindingInfo() + { + dp::BindingFiller filler(5); + filler.FillDecl("a_position"); + filler.FillDecl("a_color"); + filler.FillDecl("a_outlineColor"); + filler.FillDecl("a_radius"); + filler.FillDecl("a_outlineWidthRatio"); + return filler.m_info; + } + + glsl::vec2 m_position{}; + glsl::vec3 m_color{}; + glsl::vec3 m_outlineColor{}; + float m_radius{}; + float m_outlineWidthRatio{}; +}; + +using CircleVertexData = buffer_vector; + +CircleVertexData createCircleVertexData(glsl::vec3 color, glsl::vec3 outlineColor, float radius, + float outlineWidthRatio) +{ + CircleVertexData data; + data.emplace_back(glsl::vec2(-1.0, 1.0), color, outlineColor, radius, outlineWidthRatio); + data.emplace_back(glsl::vec2(-1.0, -1.0), color, outlineColor, radius, outlineWidthRatio); + data.emplace_back(glsl::vec2(1.0, 1.0), color, outlineColor, radius, outlineWidthRatio); + data.emplace_back(glsl::vec2(1.0, -1.0), color, outlineColor, radius, outlineWidthRatio); + return data; +} +} // namespace + +namespace gui::elements +{ +CircleHandle::CircleHandle(uint32_t id, dp::Anchor anchor, const m2::PointF & pivot, const m2::PointF & size) + : Handle(id, anchor, pivot, size) +{ + SetIsVisible(true); +} + +void Circle::SetHandleId(uint32_t handleId) { m_handleId = handleId; } + +void Circle::SetPosition(const Position & position) { m_position = position; } + +void Circle::SetRadius(float radius) { m_radius = radius; } + +void Circle::SetOutlineWidthRatio(float widthRatio) { m_outlineWidthRatio = widthRatio; } + +void Circle::SetColor(dp::Color const & color) { m_color = color; } + +void Circle::SetOutlineColor(dp::Color const & color) { m_outlineColor = color; } + +void Circle::SetHandleCreator(HandleCreator handleCreator) +{ + m_handleCreator = std::move(handleCreator); +} + +void Circle::Draw(ref_ptr context, ShapeControl & control) const +{ + Validate(); + + float const radiusInPixels = m_radius * df::VisualParams::Instance().GetVisualScale(); + CircleVertexData data = + createCircleVertexData(glsl::ToVec3(m_color), glsl::ToVec3(m_outlineColor), radiusInPixels, m_outlineWidthRatio); + + auto state = df::CreateRenderState(gpu::Program::GuiCircle, df::DepthLayer::GuiLayer); + state.SetDepthTestEnabled(false); + + dp::AttributeProvider provider(1, 4); + provider.InitStream(0, CircleVertex::GetBindingInfo(), make_ref(data.data())); + drape_ptr handle = m_handleCreator( + m_handleId, m_position.m_anchor, m_position.m_pixelPivot, m2::PointF{radiusInPixels * 2, radiusInPixels * 2}); + + dp::Batcher batcher(dp::Batcher::IndexPerQuad, dp::Batcher::VertexPerQuad); + batcher.SetBatcherHash(static_cast(df::BatcherBucket::Default)); + dp::SessionGuard guard(context, batcher, std::bind(&ShapeControl::AddShape, &control, _1, _2)); + batcher.InsertTriangleStrip(context, state, make_ref(&provider), std::move(handle)); +} + +void Circle::Validate() const +{ + ASSERT_NOT_EQUAL(m_handleId, 0, ("Handle id must be set.")); + ASSERT_EQUAL(m_position.m_anchor, dp::Center, ("Only dp::Center is supported for Circle.")); + ASSERT_NOT_EQUAL(m_radius, 0.0f, ("Radius must be set.")); + ASSERT_GREATER_OR_EQUAL(m_outlineWidthRatio, 0.0f, ("Outline width ratio must be in the range [0.0, 1.0].")); + ASSERT_LESS_OR_EQUAL(m_outlineWidthRatio, 1.0f, ("Outline width ratio must be in the range [0.0, 1.0].")); + ASSERT_NOT_EQUAL(m_color, dp::Color::Transparent(), ("Color must be set.")); + ASSERT(m_handleCreator, ("HandleCreator must be set.")); +} +} // namespace gui::elements diff --git a/drape_frontend/gui/elements/circle.hpp b/drape_frontend/gui/elements/circle.hpp new file mode 100644 index 0000000000..582d2f919e --- /dev/null +++ b/drape_frontend/gui/elements/circle.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include "drape_frontend/gui/shape.hpp" + +namespace gui::elements +{ +class CircleHandle : public Handle +{ +public: + CircleHandle(uint32_t id, dp::Anchor anchor, m2::PointF const & pivot, m2::PointF const & size); +}; + +class Circle +{ +public: + using HandleCreator = + std::function(uint32_t, dp::Anchor, m2::PointF const &, m2::PointF const &)>; + + Circle() = default; + + void SetHandleId(uint32_t handleId); + void SetPosition(Position const & position); + void SetRadius(float radius); + void SetOutlineWidthRatio(float widthRatio); + void SetColor(dp::Color const & color); + void SetOutlineColor(dp::Color const & color); + void SetHandleCreator(HandleCreator handleCreator); + + void Draw(ref_ptr context, ShapeControl & control) const; + +private: + void Validate() const; + + uint32_t m_handleId = 0; + Position m_position{}; + float m_radius = 0.0f; + float m_outlineWidthRatio = 0.0f; + dp::Color m_color = dp::Color::Transparent(); + dp::Color m_outlineColor = dp::Color::Transparent(); + HandleCreator m_handleCreator; +}; +} // namespace gui::elements diff --git a/drape_frontend/gui/gui_text.cpp b/drape_frontend/gui/gui_text.cpp index 99c29ded9e..fd4dfb9727 100644 --- a/drape_frontend/gui/gui_text.cpp +++ b/drape_frontend/gui/gui_text.cpp @@ -348,9 +348,25 @@ void MutableLabel::Precache(PrecacheParams const & params, PrecacheResult & resu glsl::vec2 colorTex = glsl::ToVec2(color.GetTexRect().Center()); glsl::vec2 outlineTex = glsl::ToVec2(outlineColor.GetTexRect().Center()); + uint32_t maxGlyphWidth = 0; + uint32_t maxGlyphHeight = 0; + for (const auto & node : m_alphabet) + { + dp::TextureManager::GlyphRegion const & reg = node.second; + m2::PointU pixelSize(reg.GetPixelSize()); + maxGlyphWidth = std::max(maxGlyphWidth, pixelSize.x); + maxGlyphHeight = std::max(maxGlyphHeight, pixelSize.y); + } + + float offsetWidth = 0; + if (params.m_anchor == dp::Center) + { + offsetWidth -= maxGlyphWidth / (1.5f * vparams.GetVisualScale()); + } + auto const vertexCount = static_cast(m_maxLength) * 4; result.m_buffer.resize(vertexCount, - StaticVertex(glsl::vec3(0.0, 0.0, 0.0), colorTex, outlineTex)); + StaticVertex(glsl::vec3(offsetWidth, 0.0, 0.0), colorTex, outlineTex)); float depth = 0.0f; for (size_t i = 0; i < vertexCount; i += 4) @@ -362,16 +378,6 @@ void MutableLabel::Precache(PrecacheParams const & params, PrecacheResult & resu depth += 10.0f; } - uint32_t maxGlyphWidth = 0; - uint32_t maxGlyphHeight = 0; - for (const auto & node : m_alphabet) - { - dp::TextureManager::GlyphRegion const & reg = node.second; - m2::PointU pixelSize(reg.GetPixelSize()); - maxGlyphWidth = std::max(maxGlyphWidth, pixelSize.x); - maxGlyphHeight = std::max(maxGlyphHeight, pixelSize.y); - } - result.m_maxPixelSize = m2::PointF(m_maxLength * maxGlyphWidth, maxGlyphHeight); } @@ -556,6 +562,7 @@ m2::PointF MutableLabelDrawer::Draw(ref_ptr context, Params drape_ptr handle = params.m_handleCreator(params.m_anchor, params.m_pivot); MutableLabel::PrecacheParams preCacheP; + preCacheP.m_anchor = params.m_anchor; preCacheP.m_alphabet = params.m_alphabet; preCacheP.m_font = params.m_font; preCacheP.m_maxLength = params.m_maxLength; diff --git a/drape_frontend/gui/gui_text.hpp b/drape_frontend/gui/gui_text.hpp index c01b34de8d..929619acc3 100644 --- a/drape_frontend/gui/gui_text.hpp +++ b/drape_frontend/gui/gui_text.hpp @@ -95,6 +95,7 @@ public: struct PrecacheParams { + dp::Anchor m_anchor; std::string m_alphabet; size_t m_maxLength; dp::FontDecl m_font; diff --git a/drape_frontend/gui/layer_render.cpp b/drape_frontend/gui/layer_render.cpp index d179a59051..cea060b12a 100644 --- a/drape_frontend/gui/layer_render.cpp +++ b/drape_frontend/gui/layer_render.cpp @@ -7,6 +7,7 @@ #include "drape_frontend/gui/layer_render.hpp" #include "drape_frontend/gui/ruler.hpp" #include "drape_frontend/gui/ruler_helper.hpp" +#include "drape_frontend/gui/speed_limit.hpp" #include "drape_frontend/visual_params.hpp" @@ -206,6 +207,7 @@ drape_ptr LayerCacher::RecacheWidgets(ref_ptr renderer = make_unique_dp(); @@ -397,4 +399,14 @@ m2::PointF LayerCacher::CacheScaleFpsLabel(ref_ptr context, renderer->AddShapeRenderer(WIDGET_SCALE_FPS_LABEL, std::move(scaleRenderer)); return size; } + +m2::PointF LayerCacher::CacheSpeedLimit(ref_ptr context, + Position const & position, ref_ptr renderer, + ref_ptr textures) +{ + drape_ptr shape = SpeedLimit(position).Draw(context, textures); + renderer->AddShapeRenderer(WIDGET_SPEED_LIMIT, std::move(shape)); + + return {}; +} } // namespace gui diff --git a/drape_frontend/gui/layer_render.hpp b/drape_frontend/gui/layer_render.hpp index 6195eb300b..d313abc222 100644 --- a/drape_frontend/gui/layer_render.hpp +++ b/drape_frontend/gui/layer_render.hpp @@ -80,5 +80,7 @@ private: ref_ptr textures); m2::PointF CacheWatermark(ref_ptr context, Position const & position, ref_ptr renderer, ref_ptr textures); + m2::PointF CacheSpeedLimit(ref_ptr context, Position const & position, + ref_ptr renderer, ref_ptr textures); }; } // namespace gui diff --git a/drape_frontend/gui/skin.hpp b/drape_frontend/gui/skin.hpp index 400f25dad5..e91d0530d7 100644 --- a/drape_frontend/gui/skin.hpp +++ b/drape_frontend/gui/skin.hpp @@ -19,6 +19,7 @@ enum EWidget WIDGET_COMPASS = 0x2, WIDGET_COPYRIGHT = 0x4, WIDGET_SCALE_FPS_LABEL = 0x8, + WIDGET_SPEED_LIMIT = 0x10, // The following widgets are controlled by the engine. Don't use them in platform code. WIDGET_CHOOSE_POSITION_MARK = 0x8000, #ifdef RENDER_DEBUG_INFO_LABELS @@ -31,6 +32,8 @@ enum EGuiHandle GuiHandleScaleLabel, GuiHandleCopyright, GuiHandleCompass, + GuiHandleSpeedSign, + GuiHandleSpeedSignLabel, GuiHandleRuler, GuiHandleRulerLabel, GuiHandleChoosePositionMark, diff --git a/drape_frontend/gui/speed_limit.cpp b/drape_frontend/gui/speed_limit.cpp new file mode 100644 index 0000000000..2d1024a438 --- /dev/null +++ b/drape_frontend/gui/speed_limit.cpp @@ -0,0 +1,102 @@ +#include "drape_frontend/gui/speed_limit.hpp" + +#include "drape_frontend/animation/show_hide_animation.hpp" +#include "drape_frontend/gui/drape_gui.hpp" + +#include "shaders/programs.hpp" + +#include "drape/glsl_func.hpp" +#include "drape/glsl_types.hpp" + +#include +#include + +using namespace std::placeholders; + +namespace gui +{ +namespace +{ +class TextHandle : public MutableLabelHandle +{ + using TBase = MutableLabelHandle; + +public: + TextHandle(uint32_t id, m2::PointF const & pivot, ref_ptr textures) + : TBase(id, dp::Center, pivot) + { + SetTextureManager(textures); + } + +private: + bool Update(ScreenBase const & screen) override + { + SpeedLimitHelper const & helper = DrapeGui::Instance().GetSpeedLimitHelper(); + SetIsVisible(helper.IsSpeedLimitAvailable()); + if (IsVisible()) + { + SetContent(helper.GetSpeedLimit()); + } + + return TBase::Update(screen); + } +}; + +class BackgroundHandle : public elements::CircleHandle +{ +public: + using CircleHandle::CircleHandle; + + bool Update(const ScreenBase & screen) override + { + SpeedLimitHelper const & helper = DrapeGui::Instance().GetSpeedLimitHelper(); + SetIsVisible(helper.IsSpeedLimitAvailable()); + return CircleHandle::Update(screen); + } +}; +} // namespace + +SpeedLimit::SpeedLimit(const Position & position) : Shape(position) +{ + m_background.SetHandleId(EGuiHandle::GuiHandleSpeedSign); + m_background.SetPosition(position); + m_background.SetRadius(Config::kBackgroundRadius); + m_background.SetOutlineWidthRatio(Config::kBackgroundOutlineWidthRatio); + m_background.SetColor(Config::kBackgroundColor); + m_background.SetOutlineColor(Config::kBackgroundOutlineColor); + m_background.SetHandleCreator( + [](uint32_t id, dp::Anchor anchor, m2::PointF const & pivot, m2::PointF const & size) + { return make_unique_dp(id, anchor, pivot, size); }); +} + +drape_ptr SpeedLimit::Draw(ref_ptr context, ref_ptr tex) const +{ + ShapeControl control; + m_background.Draw(context, control); + DrawText(context, control, tex); + + drape_ptr renderer = make_unique_dp(); + renderer->AddShapeControl(std::move(control)); + return renderer; +} + +void SpeedLimit::DrawText(ref_ptr context, ShapeControl & control, + ref_ptr tex) const +{ + ASSERT_EQUAL(m_position.m_anchor, dp::Center, ()); + + MutableLabelDrawer::Params params; + params.m_anchor = m_position.m_anchor; + params.m_alphabet = "0123456789"; + params.m_maxLength = 3; + params.m_font = DrapeGui::GetGuiTextFont(); + params.m_font.m_color = Config::kTextColor; + params.m_font.m_outlineColor = Config::kTextColor; + params.m_font.m_size *= df::VisualParams::Instance().GetVisualScale() * 0.8f; + params.m_pivot = m_position.m_pixelPivot; + params.m_handleCreator = [tex](dp::Anchor anchor, m2::PointF const & pivot) + { return make_unique_dp(EGuiHandle::GuiHandleSpeedSignLabel, pivot, tex); }; + + MutableLabelDrawer::Draw(context, params, tex, std::bind(&ShapeControl::AddShape, &control, _1, _2)); +} +} // namespace gui diff --git a/drape_frontend/gui/speed_limit.hpp b/drape_frontend/gui/speed_limit.hpp new file mode 100644 index 0000000000..9f510477e6 --- /dev/null +++ b/drape_frontend/gui/speed_limit.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include "drape_frontend/gui/elements/circle.hpp" +#include "drape_frontend/gui/shape.hpp" + +namespace gui +{ +class SpeedLimit : public Shape +{ + struct Config + { + static constexpr float kBackgroundRadius = 40.0f; + static constexpr float kBackgroundOutlineWidthRatio = 0.2f; + static constexpr dp::Color kBackgroundColor = dp::Color::White(); + static constexpr dp::Color kBackgroundOutlineColor = dp::Color::Red(); + static constexpr dp::Color kTextColor = dp::Color::Black(); + }; + +public: + explicit SpeedLimit(gui::Position const & position); + + drape_ptr Draw(ref_ptr context, ref_ptr tex) const; + +private: + void DrawText(ref_ptr context, ShapeControl & control, ref_ptr tex) const; + + elements::Circle m_background; +}; +} // namespace gui diff --git a/drape_frontend/gui/speed_limit_helper.cpp b/drape_frontend/gui/speed_limit_helper.cpp new file mode 100644 index 0000000000..3473a67a1c --- /dev/null +++ b/drape_frontend/gui/speed_limit_helper.cpp @@ -0,0 +1,18 @@ +#pragma once + +#include "speed_limit_helper.hpp" + +#include "platform/measurement_utils.hpp" + +namespace gui +{ +void SpeedLimitHelper::SetSpeedLimit(double speedLimitMps) { m_speedLimitMps = speedLimitMps; } + +bool SpeedLimitHelper::IsSpeedLimitAvailable() const { return true; } + +std::string SpeedLimitHelper::GetSpeedLimit() const +{ + return "120"; + return measurement_utils::FormatSpeedNumeric(m_speedLimitMps, measurement_utils::GetMeasurementUnits()); +} +} // namespace gui diff --git a/drape_frontend/gui/speed_limit_helper.hpp b/drape_frontend/gui/speed_limit_helper.hpp new file mode 100644 index 0000000000..dbc23bcea3 --- /dev/null +++ b/drape_frontend/gui/speed_limit_helper.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include + +namespace gui +{ +class SpeedLimitHelper +{ +public: + void SetSpeedLimit(double speedLimitMps); + + bool IsSpeedLimitAvailable() const; + std::string GetSpeedLimit() const; + +private: + double m_speedLimitMps; +}; +} // namespace gui diff --git a/map/routing_manager.cpp b/map/routing_manager.cpp index 832cd6c204..3cffc2c96c 100644 --- a/map/routing_manager.cpp +++ b/map/routing_manager.cpp @@ -563,6 +563,7 @@ void RoutingManager::RemoveRoute(bool deactivateFollowing) // Remove all subroutes. m_drapeEngine.SafeCall(&df::DrapeEngine::RemoveSubroute, dp::DrapeID(), true /* deactivateFollowing */); + m_drapeEngine.SafeCall(&df::DrapeEngine::SetSpeedLimitInfo, -1.f); } else { @@ -796,6 +797,12 @@ void RoutingManager::CloseRouting(bool removeRoutePoints) } } +void RoutingManager::GetRouteFollowingInfo(routing::FollowingInfo & info) +{ + m_routingSession.GetRouteFollowingInfo(info); + m_drapeEngine.SafeCall(&df::DrapeEngine::SetSpeedLimitInfo, info.m_speedLimitMps); +} + void RoutingManager::SetLastUsedRouter(RouterType type) { settings::Set(kRouterTypeKey, ToString(type)); diff --git a/map/routing_manager.hpp b/map/routing_manager.hpp index 2b42c5781d..36888f06cc 100644 --- a/map/routing_manager.hpp +++ b/map/routing_manager.hpp @@ -169,10 +169,7 @@ public: } void FollowRoute(); void CloseRouting(bool removeRoutePoints); - void GetRouteFollowingInfo(routing::FollowingInfo & info) const - { - m_routingSession.GetRouteFollowingInfo(info); - } + void GetRouteFollowingInfo(routing::FollowingInfo & info); TransitRouteInfo GetTransitRouteInfo() const; diff --git a/qt/qt_common/map_widget.cpp b/qt/qt_common/map_widget.cpp index bfb95e01a1..2abb9a8bc1 100644 --- a/qt/qt_common/map_widget.cpp +++ b/qt/qt_common/map_widget.cpp @@ -104,6 +104,7 @@ void MapWidget::CreateEngine() [&p](gui::EWidget widget, gui::Position const & pos) { p.m_widgetsInitInfo[widget] = pos; }); p.m_widgetsInitInfo[gui::WIDGET_SCALE_FPS_LABEL] = gui::Position(dp::LeftTop); + p.m_widgetsInitInfo[gui::WIDGET_SPEED_LIMIT] = gui::Position(m2::PointF(100, 100), dp::Center); m_framework.CreateDrapeEngine(make_ref(m_contextFactory), std::move(p)); m_framework.SetViewportListener(std::bind(&MapWidget::OnViewportChanged, this, std::placeholders::_1)); diff --git a/shaders/CMakeLists.txt b/shaders/CMakeLists.txt index a1bc905b2e..1c5144402b 100644 --- a/shaders/CMakeLists.txt +++ b/shaders/CMakeLists.txt @@ -24,6 +24,8 @@ set(shader_files GL/dashed_line.vsh.glsl GL/debug_rect.fsh.glsl GL/debug_rect.vsh.glsl + GL/gui_circle.fsh.glsl + GL/gui_circle.vsh.glsl GL/hatching_area.fsh.glsl GL/hatching_area.vsh.glsl GL/line.fsh.glsl diff --git a/shaders/GL/gui_circle.fsh.glsl b/shaders/GL/gui_circle.fsh.glsl new file mode 100644 index 0000000000..1442204dd8 --- /dev/null +++ b/shaders/GL/gui_circle.fsh.glsl @@ -0,0 +1,26 @@ +in vec2 v_position; +in vec3 v_color; +in vec3 v_outlineColor; +in float v_outlineWidthRatio; + +void main() +{ + float R = 1.0; + float R2 = R - v_outlineWidthRatio; + float dist = sqrt(dot(v_position, v_position)); + if (dist >= R) + { + gl_FragColor.w = 0.0; + } + else if (dist <= R2) + { + gl_FragColor = vec4(v_color, 255.0); + } + else + { + float sm = smoothstep(R, R-0.01, dist); + float sm2 = smoothstep(R2, R2+0.01, dist); + float alpha = sm*sm2; + gl_FragColor = vec4(v_outlineColor, alpha); + } +} diff --git a/shaders/GL/gui_circle.vsh.glsl b/shaders/GL/gui_circle.vsh.glsl new file mode 100644 index 0000000000..b8fa44d796 --- /dev/null +++ b/shaders/GL/gui_circle.vsh.glsl @@ -0,0 +1,27 @@ +in vec2 a_position; +in vec3 a_color; +in vec3 a_outlineColor; +in float a_radius; +in float a_outlineWidthRatio; + +uniform mat4 u_modelView; +uniform mat4 u_projection; + +out vec2 v_position; +out vec3 v_color; +out vec3 v_outlineColor; +out float v_outlineWidthRatio; + +void main() +{ + v_position = a_position; + v_color = a_color; + v_outlineColor = a_outlineColor; + v_outlineWidthRatio = a_outlineWidthRatio; + + gl_Position = vec4(a_position * a_radius, 0, 1) * u_modelView * u_projection; +#ifdef VULKAN + gl_Position.y = -gl_Position.y; + gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5; +#endif +} diff --git a/shaders/GL/shader_index.txt b/shaders/GL/shader_index.txt index a3cb58d8fb..2fd1f65e53 100644 --- a/shaders/GL/shader_index.txt +++ b/shaders/GL/shader_index.txt @@ -19,6 +19,7 @@ DashedLine dashed_line.vsh.glsl dashed_line.fsh.glsl PathSymbol path_symbol.vsh.glsl texturing.fsh.glsl HatchingArea hatching_area.vsh.glsl hatching_area.fsh.glsl TexturingGui texturing_gui.vsh.glsl texturing.fsh.glsl +GuiCircle gui_circle.vsh.glsl gui_circle.fsh.glsl Ruler ruler.vsh.glsl texturing.fsh.glsl Accuracy position_accuracy3d.vsh.glsl texturing.fsh.glsl MyPosition my_position.vsh.glsl texturing.fsh.glsl diff --git a/shaders/program_params.hpp b/shaders/program_params.hpp index 2e65567832..200b9c072b 100644 --- a/shaders/program_params.hpp +++ b/shaders/program_params.hpp @@ -163,6 +163,7 @@ struct GuiProgramParams Program::TextStaticOutlinedGui, Program::TextOutlinedGui, Program::TexturingGui, + Program::GuiCircle, Program::Ruler) } ALIGNMENT; diff --git a/shaders/programs.hpp b/shaders/programs.hpp index f9b9ce9c2a..96e6d4c98b 100644 --- a/shaders/programs.hpp +++ b/shaders/programs.hpp @@ -30,6 +30,7 @@ enum class Program PathSymbol, HatchingArea, TexturingGui, + GuiCircle, Ruler, Accuracy, MyPosition, @@ -94,6 +95,7 @@ inline std::string DebugPrint(Program p) case Program::PathSymbol: return "PathSymbol"; case Program::HatchingArea: return "HatchingArea"; case Program::TexturingGui: return "TexturingGui"; + case Program::GuiCircle: return "GuiCircle"; case Program::Ruler: return "Ruler"; case Program::Accuracy: return "Accuracy"; case Program::MyPosition: return "MyPosition";