diff --git a/drape/shaders/route_fragment_shader.fsh b/drape/shaders/route_fragment_shader.fsh new file mode 100644 index 0000000000..c2db173581 --- /dev/null +++ b/drape/shaders/route_fragment_shader.fsh @@ -0,0 +1,9 @@ +uniform vec4 u_color; + +void main(void) +{ + if (u_color.a < 0.1) + discard; + + gl_FragColor = u_color; +} diff --git a/drape/shaders/route_vertex_shader.vsh b/drape/shaders/route_vertex_shader.vsh new file mode 100644 index 0000000000..d075be76e8 --- /dev/null +++ b/drape/shaders/route_vertex_shader.vsh @@ -0,0 +1,24 @@ +attribute vec3 a_position; +attribute vec2 a_normal; + +uniform mat4 modelView; +uniform mat4 projection; + +uniform float u_halfWidth; + +void main(void) +{ + float halfWidth = length(a_normal); + vec2 transformedAxisPos = (vec4(a_position.xy, 0.0, 1.0) * modelView).xy; + if (u_halfWidth != 0.0 && halfWidth != 0.0) + { + vec2 norm = a_normal * u_halfWidth; + float actualHalfWidth = length(norm); + + vec4 glbShiftPos = vec4(a_position.xy + norm, 0.0, 1.0); + vec2 shiftPos = (glbShiftPos * modelView).xy; + transformedAxisPos = transformedAxisPos + normalize(shiftPos - transformedAxisPos) * actualHalfWidth; + } + + gl_Position = vec4(transformedAxisPos, a_position.z, 1.0) * projection; +} diff --git a/drape/shaders/shader_index.txt b/drape/shaders/shader_index.txt index 7adb7b7b14..e54a4c4b45 100644 --- a/drape/shaders/shader_index.txt +++ b/drape/shaders/shader_index.txt @@ -7,3 +7,4 @@ ACCURACY_PROGRAM position_accuracy_shader.vsh texturing_fragment_shader.fsh MY_POSITION_PROGRAM my_position_shader.vsh texturing_fragment_shader.fsh BUTTON_PROGRAM button_vertex_shader.vsh button_fragment_shader.fsh BOOKMARK_PROGRAM user_mark.vsh texturing_fragment_shader.fsh +ROUTE_PROGRAM route_vertex_shader.vsh route_fragment_shader.fsh diff --git a/drape/utils/vertex_decl.cpp b/drape/utils/vertex_decl.cpp index 99e29ac77a..d701afb2f2 100644 --- a/drape/utils/vertex_decl.cpp +++ b/drape/utils/vertex_decl.cpp @@ -12,6 +12,7 @@ enum VertexType TextStatic, TextDynamic, Line, + Route, TypeCount }; @@ -146,13 +147,37 @@ dp::BindingInfo LineBindingInit() return info; } +dp::BindingInfo RouteBindingInit() +{ + STATIC_ASSERT(sizeof(RouteVertex) == sizeof(RouteVertex::TPosition) + + sizeof(RouteVertex::TNormal)); + dp::BindingInfo info(2); + + dp::BindingDecl & posDecl = info.GetBindingDecl(0); + posDecl.m_attributeName = "a_position"; + posDecl.m_componentCount = glsl::GetComponentCount(); + posDecl.m_componentType = gl_const::GLFloatType; + posDecl.m_offset = 0; + posDecl.m_stride = sizeof(RouteVertex); + + dp::BindingDecl & normalDecl = info.GetBindingDecl(1); + normalDecl.m_attributeName = "a_normal"; + normalDecl.m_componentCount = glsl::GetComponentCount(); + normalDecl.m_componentType = gl_const::GLFloatType; + normalDecl.m_offset = posDecl.m_offset + sizeof(RouteVertex::TPosition); + normalDecl.m_stride = posDecl.m_stride; + + return info; +} + BindingNode g_bindingNodes[TypeCount]; TInitFunction g_initFunctions[TypeCount] = { &SolidTexturingBindingInit, &TextStaticBindingInit, &TextDynamicBindingInit, - &LineBindingInit + &LineBindingInit, + &RouteBindingInit }; dp::BindingInfo const & GetBinding(VertexType type) @@ -253,5 +278,20 @@ dp::BindingInfo const & LineVertex::GetBindingInfo() return GetBinding(Line); } +RouteVertex::RouteVertex() + : m_position(0.0, 0.0, 0.0) + , m_normal(0.0, 0.0) +{} + +RouteVertex::RouteVertex(TPosition const & position, TNormal const & normal) + : m_position(position) + , m_normal(normal) +{} + +dp::BindingInfo const & RouteVertex::GetBindingInfo() +{ + return GetBinding(Route); +} + } //namespace gpu diff --git a/drape/utils/vertex_decl.hpp b/drape/utils/vertex_decl.hpp index 046476c548..c779d05a31 100644 --- a/drape/utils/vertex_decl.hpp +++ b/drape/utils/vertex_decl.hpp @@ -73,4 +73,15 @@ struct LineVertex : BaseVertex static dp::BindingInfo const & GetBindingInfo(); }; +struct RouteVertex : BaseVertex +{ + RouteVertex(); + RouteVertex(TPosition const & position, TNormal const & normal); + + TPosition m_position; + TNormal m_normal; + + static dp::BindingInfo const & GetBindingInfo(); +}; + } // namespace gpu diff --git a/drape_frontend/backend_renderer.cpp b/drape_frontend/backend_renderer.cpp index 41c0b3e659..1ba432f01b 100644 --- a/drape_frontend/backend_renderer.cpp +++ b/drape_frontend/backend_renderer.cpp @@ -1,8 +1,10 @@ #include "drape_frontend/backend_renderer.hpp" + #include "drape_frontend/batchers_pool.hpp" #include "drape_frontend/map_shape.hpp" #include "drape_frontend/message_subclasses.hpp" #include "drape_frontend/read_manager.hpp" +#include "drape_frontend/route_builder.hpp" #include "drape_frontend/user_mark_shapes.hpp" #include "drape_frontend/visual_params.hpp" @@ -35,6 +37,14 @@ BackendRenderer::BackendRenderer(Params const & params) MessagePriority::High); }); + m_routeBuilder = make_unique_dp([this](dp::GLState const & state, + drape_ptr && bucket, dp::Color const & color) + { + m_commutator->PostMessage(ThreadsCommutator::RenderThread, + make_unique_dp(state, move(bucket), color), + MessagePriority::Normal); + }); + StartThread(); } @@ -93,8 +103,10 @@ void BackendRenderer::AcceptMessage(ref_ptr message) break; } case Message::GuiRecache: - RecacheGui(static_cast>(message)->GetElements()); - break; + { + RecacheGui(static_cast>(message)->GetElements()); + break; + } case Message::TileReadStarted: { m_batchersPool->ReserveBatcher(static_cast>(message)->GetKey()); @@ -160,6 +172,12 @@ void BackendRenderer::AcceptMessage(ref_ptr message) } break; } + case Message::AddRoute: + { + ref_ptr msg = message; + m_routeBuilder->Build(msg->GetRoutePolyline(), msg->GetColor()); + break; + } case Message::StopRendering: { ProcessStopRenderingMessage(); diff --git a/drape_frontend/backend_renderer.hpp b/drape_frontend/backend_renderer.hpp index 8425246cd5..eb34d21826 100644 --- a/drape_frontend/backend_renderer.hpp +++ b/drape_frontend/backend_renderer.hpp @@ -21,6 +21,7 @@ namespace df class Message; class BatchersPool; class ReadManager; +class RouteBuilder; class BackendRenderer : public BaseRenderer { @@ -51,6 +52,7 @@ private: MapDataProvider m_model; drape_ptr m_batchersPool; drape_ptr m_readManager; + drape_ptr m_routeBuilder; gui::LayerCacher m_guiCacher; ///////////////////////////////////////// diff --git a/drape_frontend/drape_engine.cpp b/drape_frontend/drape_engine.cpp index abe7a9f681..1e7309337c 100644 --- a/drape_frontend/drape_engine.cpp +++ b/drape_frontend/drape_engine.cpp @@ -297,4 +297,23 @@ void DrapeEngine::DeselectObject() MessagePriority::High); } +bool DrapeEngine::GetMyPosition(m2::PointD & myPosition) +{ + bool hasPosition = false; + BaseBlockingMessage::Blocker blocker; + m_threadCommutator->PostMessage(ThreadsCommutator::RenderThread, + make_unique_dp(blocker, hasPosition, myPosition), + MessagePriority::High); + + blocker.Wait(); + return hasPosition; +} + +void DrapeEngine::AddRoute(m2::PolylineD const & routePolyline, dp::Color const & color) +{ + m_threadCommutator->PostMessage(ThreadsCommutator::ResourceUploadThread, + make_unique_dp(routePolyline, color), + MessagePriority::Normal); +} + } // namespace df diff --git a/drape_frontend/drape_engine.hpp b/drape_frontend/drape_engine.hpp index 5f5a7e0869..84a232883d 100644 --- a/drape_frontend/drape_engine.hpp +++ b/drape_frontend/drape_engine.hpp @@ -10,6 +10,7 @@ #include "platform/location.hpp" +#include "geometry/polyline2d.hpp" #include "geometry/screenbase.hpp" #include "base/strings_bundle.hpp" @@ -92,6 +93,9 @@ public: FeatureID GetVisiblePOI(m2::PointD const & glbPoint); void SelectObject(SelectionShape::ESelectedObject obj, m2::PointD const & pt); void DeselectObject(); + bool GetMyPosition(m2::PointD & myPosition); + + void AddRoute(m2::PolylineD const & routePolyline, dp::Color const & color); private: void AddUserEvent(UserEvent const & e); diff --git a/drape_frontend/drape_frontend.pro b/drape_frontend/drape_frontend.pro index 9f3b38c3a1..15a5c779d6 100755 --- a/drape_frontend/drape_frontend.pro +++ b/drape_frontend/drape_frontend.pro @@ -25,6 +25,7 @@ SOURCES += \ engine_context.cpp \ frontend_renderer.cpp \ line_shape.cpp \ + line_shape_helper.cpp \ map_data_provider.cpp \ memory_feature_index.cpp \ message_acceptor.cpp \ @@ -39,6 +40,9 @@ SOURCES += \ read_mwm_task.cpp \ render_group.cpp \ render_node.cpp \ + route_builder.cpp \ + route_renderer.cpp \ + route_shape.cpp \ rule_drawer.cpp \ selection_shape.cpp \ stylist.cpp \ @@ -75,6 +79,7 @@ HEADERS += \ frontend_renderer.hpp \ intrusive_vector.hpp \ line_shape.hpp \ + line_shape_helper.hpp \ map_data_provider.hpp \ map_shape.hpp \ memory_feature_index.hpp \ @@ -92,6 +97,9 @@ HEADERS += \ read_mwm_task.hpp \ render_group.hpp \ render_node.hpp \ + route_builder.hpp \ + route_renderer.hpp \ + route_shape.hpp \ rule_drawer.hpp \ selection_shape.hpp \ shape_view_params.hpp \ diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp index a0c066af50..b63d68611e 100755 --- a/drape_frontend/frontend_renderer.cpp +++ b/drape_frontend/frontend_renderer.cpp @@ -49,6 +49,7 @@ FrontendRenderer::FrontendRenderer(Params const & params) , m_tapEventInfoFn(params.m_tapEventFn) , m_userPositionChangedFn(params.m_positionChangedFn) , m_tileTree(new TileTree()) + , m_routeRenderer(new RouteRenderer()) { #ifdef DRAW_INFO m_tpf = 0,0; @@ -263,6 +264,22 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) break; } + case Message::GetMyPosition: + { + ref_ptr msg = message; + msg->SetMyPosition(m_myPositionController->IsModeHasPosition(), m_myPositionController->Position()); + break; + } + + case Message::FlushRoute: + { + ref_ptr msg = message; + dp::GLState const & state = msg->GetState(); + drape_ptr bucket = msg->AcceptBuffer(); + m_routeRenderer->AddRoute(state, move(bucket), msg->GetColor(), make_ref(m_gpuProgramManager)); + break; + } + default: ASSERT(false, ()); } @@ -467,9 +484,9 @@ void FrontendRenderer::RenderScene(ScreenBase const & modelView) SelectionShape::ESelectedObject selectedObject = m_selectionShape->GetSelectedObject(); if (selectedObject == SelectionShape::OBJECT_MY_POSITION) { - ASSERT(m_myPositionController->IsModeHasPosition(), ()); - m_selectionShape->SetPosition(m_myPositionController->Position()); - m_selectionShape->Render(modelView, make_ref(m_gpuProgramManager), m_generalUniforms); + GLFunctions::glClearDepth(); + m_myPositionController->Render(modelView, make_ref(m_gpuProgramManager), m_generalUniforms); + m_routeRenderer->Render(GetCurrentZoomLevel(), make_ref(m_gpuProgramManager), m_generalUniforms); } else if (selectedObject == SelectionShape::OBJECT_POI) m_selectionShape->Render(modelView, make_ref(m_gpuProgramManager), m_generalUniforms); @@ -496,6 +513,7 @@ void FrontendRenderer::RenderScene(ScreenBase const & modelView) } GLFunctions::glClearDepth(); + if (m_guiRenderer != nullptr) m_guiRenderer->Render(make_ref(m_gpuProgramManager), modelView); @@ -746,6 +764,7 @@ void FrontendRenderer::ReleaseResources() m_guiRenderer.reset(); m_myPositionController.reset(); m_selectionShape.release(); + m_routeRenderer.reset(); m_gpuProgramManager.reset(); } diff --git a/drape_frontend/frontend_renderer.hpp b/drape_frontend/frontend_renderer.hpp index 9f2a98dd6c..085beb7768 100755 --- a/drape_frontend/frontend_renderer.hpp +++ b/drape_frontend/frontend_renderer.hpp @@ -8,15 +8,16 @@ #include "std/numeric.hpp" #endif +#include "drape_frontend/backend_renderer.hpp" #include "drape_frontend/base_renderer.hpp" +#include "drape_frontend/my_position_controller.hpp" +#include "drape_frontend/navigator.hpp" +#include "drape_frontend/render_group.hpp" +#include "drape_frontend/route_renderer.hpp" #include "drape_frontend/threads_commutator.hpp" #include "drape_frontend/tile_info.hpp" #include "drape_frontend/tile_tree.hpp" -#include "drape_frontend/backend_renderer.hpp" -#include "drape_frontend/render_group.hpp" -#include "drape_frontend/navigator.hpp" #include "drape_frontend/user_event_stream.hpp" -#include "drape_frontend/my_position_controller.hpp" #include "drape_gui/layer_render.hpp" @@ -195,6 +196,7 @@ private: drape_ptr m_guiRenderer; drape_ptr m_myPositionController; drape_ptr m_selectionShape; + drape_ptr m_routeRenderer; drape_ptr m_overlayTree; diff --git a/drape_frontend/line_shape.cpp b/drape_frontend/line_shape.cpp index 1dfab2ced7..aefb8e4777 100644 --- a/drape_frontend/line_shape.cpp +++ b/drape_frontend/line_shape.cpp @@ -1,5 +1,7 @@ #include "drape_frontend/line_shape.hpp" +#include "drape_frontend/line_shape_helper.hpp" + #include "drape/utils/vertex_decl.hpp" #include "drape/glsl_types.hpp" #include "drape/glsl_func.hpp" @@ -65,193 +67,6 @@ namespace bool m_isSolid = true; }; - enum EPointType - { - StartPoint = 0, - EndPoint = 1, - PointsCount = 2 - }; - - enum ENormalType - { - StartNormal = 0, - EndNormal = 1, - BaseNormal = 2 - }; - - struct LineSegment - { - glsl::vec2 m_points[PointsCount]; - glsl::vec2 m_tangent; - glsl::vec2 m_leftBaseNormal; - glsl::vec2 m_leftNormals[PointsCount]; - glsl::vec2 m_rightBaseNormal; - glsl::vec2 m_rightNormals[PointsCount]; - glsl::vec2 m_leftWidthScalar[PointsCount]; - glsl::vec2 m_rightWidthScalar[PointsCount]; - bool m_hasLeftJoin[PointsCount]; - - LineSegment() - { - m_leftWidthScalar[StartPoint] = m_leftWidthScalar[EndPoint] = glsl::vec2(1.0f, 0.0f); - m_rightWidthScalar[StartPoint] = m_rightWidthScalar[EndPoint] = glsl::vec2(1.0f, 0.0f); - m_hasLeftJoin[StartPoint] = m_hasLeftJoin[EndPoint] = true; - } - }; - - void UpdateNormalBetweenSegments(LineSegment * segment1, LineSegment * segment2) - { - ASSERT(segment1 != nullptr && segment2 != nullptr, ()); - - float const dotProduct = glsl::dot(segment1->m_leftNormals[EndPoint], - segment2->m_leftNormals[StartPoint]); - float const absDotProduct = fabs(dotProduct); - float const eps = 1e-5; - - if (fabs(absDotProduct - 1.0f) < eps) - { - // change nothing - return; - } - - float const crossProduct = glsl::cross(glsl::vec3(segment1->m_tangent, 0), - glsl::vec3(segment2->m_tangent, 0)).z; - if (crossProduct < 0) - { - segment1->m_hasLeftJoin[EndPoint] = true; - segment2->m_hasLeftJoin[StartPoint] = true; - - // change right-side normals - glsl::vec2 averageNormal = glsl::normalize(segment1->m_rightNormals[EndPoint] + - segment2->m_rightNormals[StartPoint]); - segment1->m_rightNormals[EndPoint] = averageNormal; - segment2->m_rightNormals[StartPoint] = averageNormal; - - float const cosAngle = glsl::dot(segment1->m_tangent, averageNormal); - segment1->m_rightWidthScalar[EndPoint].x = 1.0f / sqrt(1.0f - cosAngle * cosAngle); - segment1->m_rightWidthScalar[EndPoint].y = segment1->m_rightWidthScalar[EndPoint].x * cosAngle; - segment2->m_rightWidthScalar[StartPoint] = segment1->m_rightWidthScalar[EndPoint]; - } - else - { - segment1->m_hasLeftJoin[EndPoint] = false; - segment2->m_hasLeftJoin[StartPoint] = false; - - // change left-side normals - glsl::vec2 averageNormal = glsl::normalize(segment1->m_leftNormals[EndPoint] + - segment2->m_leftNormals[StartPoint]); - segment1->m_leftNormals[EndPoint] = averageNormal; - segment2->m_leftNormals[StartPoint] = averageNormal; - - float const cosAngle = glsl::dot(segment1->m_tangent, averageNormal); - segment1->m_leftWidthScalar[EndPoint].x = 1.0f / sqrt(1.0f - cosAngle * cosAngle); - segment1->m_leftWidthScalar[EndPoint].y = segment1->m_leftWidthScalar[EndPoint].x * cosAngle; - segment2->m_leftWidthScalar[StartPoint] = segment1->m_leftWidthScalar[EndPoint]; - } - } - - void UpdateNormals(LineSegment * segment, LineSegment * prevSegment, LineSegment * nextSegment) - { - ASSERT(segment != nullptr, ()); - - if (prevSegment != nullptr) - UpdateNormalBetweenSegments(prevSegment, segment); - - if (nextSegment != nullptr) - UpdateNormalBetweenSegments(segment, nextSegment); - } - - void GenerateJoinNormals(dp::LineJoin joinType, glsl::vec2 const & normal1, glsl::vec2 const & normal2, - float halfWidth, bool isLeft, float widthScalar, vector & normals) - { - if (joinType == dp::LineJoin::BevelJoin) - { - glsl::vec2 const n1 = halfWidth * normal1; - glsl::vec2 const n2 = halfWidth * normal2; - - normals.push_back(glsl::vec2(0.0f, 0.0f)); - normals.push_back(isLeft ? n1 : n2); - normals.push_back(isLeft ? n2 : n1); - } - else if (joinType == dp::LineJoin::MiterJoin) - { - glsl::vec2 averageNormal = halfWidth * widthScalar * glsl::normalize(normal1 + normal2); - - glsl::vec2 const n1 = halfWidth * normal1; - glsl::vec2 const n2 = halfWidth * normal2; - - normals.push_back(glsl::vec2(0.0f, 0.0f)); - normals.push_back(isLeft ? n1 : averageNormal); - normals.push_back(isLeft ? averageNormal : n1); - - normals.push_back(glsl::vec2(0.0f, 0.0f)); - normals.push_back(isLeft ? averageNormal : n2); - normals.push_back(isLeft ? n2 : averageNormal); - } - else - { - double const segmentAngle = math::pi / 8.0; - double const fullAngle = acos(glsl::dot(normal1, normal2)); - int segmentsCount = static_cast(fullAngle / segmentAngle); - if (segmentsCount == 0) - segmentsCount = 1; - - double const angle = fullAngle / segmentsCount * (isLeft ? -1.0 : 1.0); - glsl::vec2 const normalizedNormal = glsl::normalize(normal1); - m2::PointD const startNormal(normalizedNormal.x, normalizedNormal.y); - - for (int i = 0; i < segmentsCount; i++) - { - m2::PointD n1 = m2::Rotate(startNormal, i * angle) * halfWidth; - m2::PointD n2 = m2::Rotate(startNormal, (i + 1) * angle) * halfWidth; - - normals.push_back(glsl::vec2(0.0f, 0.0f)); - normals.push_back(isLeft ? glsl::vec2(n1.x, n1.y) : glsl::vec2(n2.x, n2.y)); - normals.push_back(isLeft ? glsl::vec2(n2.x, n2.y) : glsl::vec2(n1.x, n1.y)); - } - } - } - - void GenerateCapNormals(dp::LineCap capType, glsl::vec2 const & normal1, glsl::vec2 const & normal2, - glsl::vec2 const & direction, float halfWidth, bool isStart, vector & normals) - { - if (capType == dp::ButtCap) - return; - - if (capType == dp::SquareCap) - { - glsl::vec2 const n1 = halfWidth * normal1; - glsl::vec2 const n2 = halfWidth * normal2; - glsl::vec2 const n3 = halfWidth * (normal1 + direction); - glsl::vec2 const n4 = halfWidth * (normal2 + direction); - - normals.push_back(n2); - normals.push_back(isStart ? n4 : n1); - normals.push_back(isStart ? n1 : n4); - - normals.push_back(n1); - normals.push_back(isStart ? n4 : n3); - normals.push_back(isStart ? n3 : n4); - } - else - { - int const segmentsCount = 8; - double const segmentSize = math::pi / segmentsCount * (isStart ? -1.0 : 1.0); - glsl::vec2 const normalizedNormal = glsl::normalize(normal2); - m2::PointD const startNormal(normalizedNormal.x, normalizedNormal.y); - - for (int i = 0; i < segmentsCount; i++) - { - m2::PointD n1 = m2::Rotate(startNormal, i * segmentSize) * halfWidth; - m2::PointD n2 = m2::Rotate(startNormal, (i + 1) * segmentSize) * halfWidth; - - normals.push_back(glsl::vec2(0.0f, 0.0f)); - normals.push_back(isStart ? glsl::vec2(n1.x, n1.y) : glsl::vec2(n2.x, n2.y)); - normals.push_back(isStart ? glsl::vec2(n2.x, n2.y) : glsl::vec2(n1.x, n1.y)); - } - } - } - float GetProjectionLength(glsl::vec2 const & newPoint, glsl::vec2 const & startPoint, glsl::vec2 const & endPoint) { @@ -261,25 +76,6 @@ namespace float const proj = glsl::dot(v1, v2) / squareLen; return sqrt(squareLen) * my::clamp(proj, 0.0f, 1.0f); } - - void CalculateTangentAndNormals(glsl::vec2 const & pt0, glsl::vec2 const & pt1, - glsl::vec2 & tangent, glsl::vec2 & leftNormal, - glsl::vec2 & rightNormal) - { - tangent = glsl::normalize(pt1 - pt0); - leftNormal = glsl::vec2(-tangent.y, tangent.x); - rightNormal = -leftNormal; - } - - glsl::vec2 GetNormal(LineSegment const & segment, bool isLeft, ENormalType normalType) - { - if (normalType == BaseNormal) - return isLeft ? segment.m_leftBaseNormal : segment.m_rightBaseNormal; - - int const index = (normalType == StartNormal) ? StartPoint : EndPoint; - return isLeft ? segment.m_leftWidthScalar[index].x * segment.m_leftNormals[index]: - segment.m_rightWidthScalar[index].x * segment.m_rightNormals[index]; - } } LineShape::LineShape(m2::SharedSpline const & spline, @@ -339,19 +135,7 @@ void LineShape::Draw(ref_ptr batcher, ref_ptr t // constuct segments vector segments; segments.reserve(path.size() - 1); - for (size_t i = 1; i < path.size(); ++i) - { - LineSegment segment; - segment.m_points[StartPoint] = glsl::ToVec2(path[i - 1]); - segment.m_points[EndPoint] = glsl::ToVec2(path[i]); - CalculateTangentAndNormals(segment.m_points[StartPoint], segment.m_points[EndPoint], segment.m_tangent, - segment.m_leftBaseNormal, segment.m_rightBaseNormal); - - segment.m_leftNormals[StartPoint] = segment.m_leftNormals[EndPoint] = segment.m_leftBaseNormal; - segment.m_rightNormals[StartPoint] = segment.m_rightNormals[EndPoint] = segment.m_rightBaseNormal; - - segments.push_back(segment); - } + ConstructLineSegments(path, segments); // build geometry for (size_t i = 0; i < segments.size(); i++) diff --git a/drape_frontend/line_shape_helper.cpp b/drape_frontend/line_shape_helper.cpp new file mode 100644 index 0000000000..b60e47b7da --- /dev/null +++ b/drape_frontend/line_shape_helper.cpp @@ -0,0 +1,220 @@ +#include "drape_frontend/line_shape_helper.hpp" + +#include "drape/glsl_func.hpp" + +#include "base/assert.hpp" + +namespace df +{ + +namespace +{ + +void UpdateNormalBetweenSegments(LineSegment * segment1, LineSegment * segment2) +{ + ASSERT(segment1 != nullptr && segment2 != nullptr, ()); + + float const dotProduct = glsl::dot(segment1->m_leftNormals[EndPoint], + segment2->m_leftNormals[StartPoint]); + float const absDotProduct = fabs(dotProduct); + float const eps = 1e-5; + + if (fabs(absDotProduct - 1.0f) < eps) + { + // change nothing + return; + } + + float const crossProduct = glsl::cross(glsl::vec3(segment1->m_tangent, 0), + glsl::vec3(segment2->m_tangent, 0)).z; + if (crossProduct < 0) + { + segment1->m_hasLeftJoin[EndPoint] = true; + segment2->m_hasLeftJoin[StartPoint] = true; + + // change right-side normals + glsl::vec2 averageNormal = glsl::normalize(segment1->m_rightNormals[EndPoint] + + segment2->m_rightNormals[StartPoint]); + segment1->m_rightNormals[EndPoint] = averageNormal; + segment2->m_rightNormals[StartPoint] = averageNormal; + + float const cosAngle = glsl::dot(segment1->m_tangent, averageNormal); + segment1->m_rightWidthScalar[EndPoint].x = 1.0f / sqrt(1.0f - cosAngle * cosAngle); + segment1->m_rightWidthScalar[EndPoint].y = segment1->m_rightWidthScalar[EndPoint].x * cosAngle; + segment2->m_rightWidthScalar[StartPoint] = segment1->m_rightWidthScalar[EndPoint]; + } + else + { + segment1->m_hasLeftJoin[EndPoint] = false; + segment2->m_hasLeftJoin[StartPoint] = false; + + // change left-side normals + glsl::vec2 averageNormal = glsl::normalize(segment1->m_leftNormals[EndPoint] + + segment2->m_leftNormals[StartPoint]); + segment1->m_leftNormals[EndPoint] = averageNormal; + segment2->m_leftNormals[StartPoint] = averageNormal; + + float const cosAngle = glsl::dot(segment1->m_tangent, averageNormal); + segment1->m_leftWidthScalar[EndPoint].x = 1.0f / sqrt(1.0f - cosAngle * cosAngle); + segment1->m_leftWidthScalar[EndPoint].y = segment1->m_leftWidthScalar[EndPoint].x * cosAngle; + segment2->m_leftWidthScalar[StartPoint] = segment1->m_leftWidthScalar[EndPoint]; + } +} + +void CalculateTangentAndNormals(glsl::vec2 const & pt0, glsl::vec2 const & pt1, + glsl::vec2 & tangent, glsl::vec2 & leftNormal, + glsl::vec2 & rightNormal) +{ + tangent = glsl::normalize(pt1 - pt0); + leftNormal = glsl::vec2(-tangent.y, tangent.x); + rightNormal = -leftNormal; +} + +} + +void ConstructLineSegments(vector const & path, vector & segments) +{ + ASSERT(path.size() > 1, ()); + + float const eps = 1e-5; + + m2::PointD prevPoint = path[0]; + for (size_t i = 1; i < path.size(); ++i) + { + // filter the same points + if (prevPoint.EqualDxDy(path[i], eps)) + continue; + + LineSegment segment; + + segment.m_points[StartPoint] = glsl::ToVec2(prevPoint); + segment.m_points[EndPoint] = glsl::ToVec2(path[i]); + CalculateTangentAndNormals(segment.m_points[StartPoint], segment.m_points[EndPoint], segment.m_tangent, + segment.m_leftBaseNormal, segment.m_rightBaseNormal); + + segment.m_leftNormals[StartPoint] = segment.m_leftNormals[EndPoint] = segment.m_leftBaseNormal; + segment.m_rightNormals[StartPoint] = segment.m_rightNormals[EndPoint] = segment.m_rightBaseNormal; + + prevPoint = path[i]; + + segments.push_back(segment); + } +} + +void UpdateNormals(LineSegment * segment, LineSegment * prevSegment, LineSegment * nextSegment) +{ + ASSERT(segment != nullptr, ()); + + if (prevSegment != nullptr) + UpdateNormalBetweenSegments(prevSegment, segment); + + if (nextSegment != nullptr) + UpdateNormalBetweenSegments(segment, nextSegment); +} + +void GenerateJoinNormals(dp::LineJoin joinType, glsl::vec2 const & normal1, glsl::vec2 const & normal2, + float halfWidth, bool isLeft, float widthScalar, vector & normals) +{ + float const eps = 1e-5; + if (fabs(glsl::dot(normal1, normal2) - 1.0f) < eps) + return; + + if (joinType == dp::LineJoin::BevelJoin) + { + glsl::vec2 const n1 = halfWidth * normal1; + glsl::vec2 const n2 = halfWidth * normal2; + + normals.push_back(glsl::vec2(0.0f, 0.0f)); + normals.push_back(isLeft ? n1 : n2); + normals.push_back(isLeft ? n2 : n1); + } + else if (joinType == dp::LineJoin::MiterJoin) + { + glsl::vec2 averageNormal = halfWidth * widthScalar * glsl::normalize(normal1 + normal2); + + glsl::vec2 const n1 = halfWidth * normal1; + glsl::vec2 const n2 = halfWidth * normal2; + + normals.push_back(glsl::vec2(0.0f, 0.0f)); + normals.push_back(isLeft ? n1 : averageNormal); + normals.push_back(isLeft ? averageNormal : n1); + + normals.push_back(glsl::vec2(0.0f, 0.0f)); + normals.push_back(isLeft ? averageNormal : n2); + normals.push_back(isLeft ? n2 : averageNormal); + } + else + { + double const segmentAngle = math::pi / 8.0; + double const fullAngle = acos(glsl::dot(normal1, normal2)); + int segmentsCount = static_cast(fullAngle / segmentAngle); + if (segmentsCount == 0) + segmentsCount = 1; + + double const angle = fullAngle / segmentsCount * (isLeft ? -1.0 : 1.0); + glsl::vec2 const normalizedNormal = glsl::normalize(normal1); + m2::PointD const startNormal(normalizedNormal.x, normalizedNormal.y); + + for (int i = 0; i < segmentsCount; i++) + { + m2::PointD n1 = m2::Rotate(startNormal, i * angle) * halfWidth; + m2::PointD n2 = m2::Rotate(startNormal, (i + 1) * angle) * halfWidth; + + normals.push_back(glsl::vec2(0.0f, 0.0f)); + normals.push_back(isLeft ? glsl::vec2(n1.x, n1.y) : glsl::vec2(n2.x, n2.y)); + normals.push_back(isLeft ? glsl::vec2(n2.x, n2.y) : glsl::vec2(n1.x, n1.y)); + } + } +} + +void GenerateCapNormals(dp::LineCap capType, glsl::vec2 const & normal1, glsl::vec2 const & normal2, + glsl::vec2 const & direction, float halfWidth, bool isStart, vector & normals) +{ + if (capType == dp::ButtCap) + return; + + if (capType == dp::SquareCap) + { + glsl::vec2 const n1 = halfWidth * normal1; + glsl::vec2 const n2 = halfWidth * normal2; + glsl::vec2 const n3 = halfWidth * (normal1 + direction); + glsl::vec2 const n4 = halfWidth * (normal2 + direction); + + normals.push_back(n2); + normals.push_back(isStart ? n4 : n1); + normals.push_back(isStart ? n1 : n4); + + normals.push_back(n1); + normals.push_back(isStart ? n4 : n3); + normals.push_back(isStart ? n3 : n4); + } + else + { + int const segmentsCount = 8; + double const segmentSize = math::pi / segmentsCount * (isStart ? -1.0 : 1.0); + glsl::vec2 const normalizedNormal = glsl::normalize(normal2); + m2::PointD const startNormal(normalizedNormal.x, normalizedNormal.y); + + for (int i = 0; i < segmentsCount; i++) + { + m2::PointD n1 = m2::Rotate(startNormal, i * segmentSize) * halfWidth; + m2::PointD n2 = m2::Rotate(startNormal, (i + 1) * segmentSize) * halfWidth; + + normals.push_back(glsl::vec2(0.0f, 0.0f)); + normals.push_back(isStart ? glsl::vec2(n1.x, n1.y) : glsl::vec2(n2.x, n2.y)); + normals.push_back(isStart ? glsl::vec2(n2.x, n2.y) : glsl::vec2(n1.x, n1.y)); + } + } +} + +glsl::vec2 GetNormal(LineSegment const & segment, bool isLeft, ENormalType normalType) +{ + if (normalType == BaseNormal) + return isLeft ? segment.m_leftBaseNormal : segment.m_rightBaseNormal; + + int const index = (normalType == StartNormal) ? StartPoint : EndPoint; + return isLeft ? segment.m_leftWidthScalar[index].x * segment.m_leftNormals[index]: + segment.m_rightWidthScalar[index].x * segment.m_rightNormals[index]; +} + +} // namespace df diff --git a/drape_frontend/line_shape_helper.hpp b/drape_frontend/line_shape_helper.hpp new file mode 100644 index 0000000000..5fe92bf6e5 --- /dev/null +++ b/drape_frontend/line_shape_helper.hpp @@ -0,0 +1,57 @@ +#pragma once + +#include "drape/drape_global.hpp" +#include "drape/glsl_types.hpp" + +#include "std/vector.hpp" + +namespace df +{ + +enum EPointType +{ + StartPoint = 0, + EndPoint = 1, + PointsCount = 2 +}; + +enum ENormalType +{ + StartNormal = 0, + EndNormal = 1, + BaseNormal = 2 +}; + +struct LineSegment +{ + glsl::vec2 m_points[PointsCount]; + glsl::vec2 m_tangent; + glsl::vec2 m_leftBaseNormal; + glsl::vec2 m_leftNormals[PointsCount]; + glsl::vec2 m_rightBaseNormal; + glsl::vec2 m_rightNormals[PointsCount]; + glsl::vec2 m_leftWidthScalar[PointsCount]; + glsl::vec2 m_rightWidthScalar[PointsCount]; + bool m_hasLeftJoin[PointsCount]; + + LineSegment() + { + m_leftWidthScalar[StartPoint] = m_leftWidthScalar[EndPoint] = glsl::vec2(1.0f, 0.0f); + m_rightWidthScalar[StartPoint] = m_rightWidthScalar[EndPoint] = glsl::vec2(1.0f, 0.0f); + m_hasLeftJoin[StartPoint] = m_hasLeftJoin[EndPoint] = true; + } +}; + +void ConstructLineSegments(vector const & path, vector & segments); + +void UpdateNormals(LineSegment * segment, LineSegment * prevSegment, LineSegment * nextSegment); + +void GenerateJoinNormals(dp::LineJoin joinType, glsl::vec2 const & normal1, glsl::vec2 const & normal2, + float halfWidth, bool isLeft, float widthScalar, vector & normals); + +void GenerateCapNormals(dp::LineCap capType, glsl::vec2 const & normal1, glsl::vec2 const & normal2, + glsl::vec2 const & direction, float halfWidth, bool isStart, vector & normals); + +glsl::vec2 GetNormal(LineSegment const & segment, bool isLeft, ENormalType normalType); + +} // namespace df diff --git a/drape_frontend/message.hpp b/drape_frontend/message.hpp index 95d7bb1236..96cd928145 100644 --- a/drape_frontend/message.hpp +++ b/drape_frontend/message.hpp @@ -31,6 +31,9 @@ public: GpsInfo, FindVisiblePOI, SelectObject + GetMyPosition, + AddRoute, + FlushRoute }; virtual ~Message() {} diff --git a/drape_frontend/message_subclasses.hpp b/drape_frontend/message_subclasses.hpp index 313ae6df17..52cd7676d6 100644 --- a/drape_frontend/message_subclasses.hpp +++ b/drape_frontend/message_subclasses.hpp @@ -7,6 +7,7 @@ #include "drape_frontend/tile_utils.hpp" #include "drape_frontend/user_marks_provider.hpp" +#include "geometry/polyline2d.hpp" #include "geometry/rect2d.hpp" #include "geometry/screenbase.hpp" @@ -445,4 +446,67 @@ private: bool m_isDismiss; }; +class GetMyPositionMessage : public BaseBlockingMessage +{ +public: + GetMyPositionMessage(Blocker & blocker, bool & hasPosition, m2::PointD & myPosition) + : BaseBlockingMessage(blocker) + , m_myPosition(myPosition) + , m_hasPosition(hasPosition) + {} + + Type GetType() const override { return GetMyPosition; } + + void SetMyPosition(bool hasPosition, m2::PointD const & myPosition) + { + m_hasPosition = hasPosition; + m_myPosition = myPosition; + } + +private: + m2::PointD & m_myPosition; + bool & m_hasPosition; +}; + +class AddRouteMessage : public Message +{ +public: + AddRouteMessage(m2::PolylineD const & routePolyline, dp::Color const & color) + : m_routePolyline(routePolyline) + , m_color(color) + {} + + Type GetType() const override { return Message::AddRoute; } + + m2::PolylineD const & GetRoutePolyline() { return m_routePolyline; } + dp::Color const & GetColor() const { return m_color; } + +private: + m2::PolylineD m_routePolyline; + dp::Color m_color; +}; + +class FlushRouteMessage : public Message +{ +public: + FlushRouteMessage(dp::GLState const & state, drape_ptr && buffer, + dp::Color const & color) + : m_state(state) + , m_buffer(move(buffer)) + , m_color(color) + {} + + Type GetType() const override { return Message::FlushRoute; } + + dp::GLState const & GetState() const { return m_state; } + drape_ptr && AcceptBuffer() { return move(m_buffer); } + dp::Color const & GetColor() const { return m_color; } + +private: + dp::GLState m_state; + drape_ptr m_buffer; + dp::Color m_color; +}; + + } // namespace df diff --git a/drape_frontend/route_builder.cpp b/drape_frontend/route_builder.cpp new file mode 100644 index 0000000000..5fb4be4d19 --- /dev/null +++ b/drape_frontend/route_builder.cpp @@ -0,0 +1,31 @@ +#include "drape_frontend/route_builder.hpp" + +#include "drape_frontend/route_shape.hpp" + +namespace df +{ + +const int ESTIMATE_BUFFER_SIZE = 4000; + +RouteBuilder::RouteBuilder(RouteBuilder::TFlushRouteFn const & flushRouteFn) + : m_flushRouteFn(flushRouteFn) + , m_batcher(make_unique_dp(ESTIMATE_BUFFER_SIZE, ESTIMATE_BUFFER_SIZE)) +{} + +void RouteBuilder::Build(m2::PolylineD const & routePolyline, dp::Color const & color) +{ + CommonViewParams params; + params.m_depth = 0.0f; + + auto flushRoute = [this, &color](dp::GLState const & state, drape_ptr && bucket) + { + if (m_flushRouteFn != nullptr) + m_flushRouteFn(state, move(bucket), color); + }; + + m_batcher->StartSession(flushRoute); + RouteShape(routePolyline, params).Draw(make_ref(m_batcher)); + m_batcher->EndSession(); +} + +} // namespace df diff --git a/drape_frontend/route_builder.hpp b/drape_frontend/route_builder.hpp new file mode 100644 index 0000000000..79a1f4335c --- /dev/null +++ b/drape_frontend/route_builder.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include "drape/batcher.hpp" +#include "drape/glstate.hpp" +#include "drape/pointers.hpp" +#include "drape/render_bucket.hpp" + +#include "geometry/polyline2d.hpp" + +#include "std/function.hpp" + +namespace df +{ + +class RouteBuilder +{ +public: + using TFlushRouteFn = function &&, + dp::Color const &)>; + + RouteBuilder(TFlushRouteFn const & flushRouteFn); + + void Build(m2::PolylineD const & routePolyline, dp::Color const & color); + +private: + TFlushRouteFn m_flushRouteFn; + drape_ptr m_batcher; +}; + +} // namespace df diff --git a/drape_frontend/route_renderer.cpp b/drape_frontend/route_renderer.cpp new file mode 100644 index 0000000000..4de442045d --- /dev/null +++ b/drape_frontend/route_renderer.cpp @@ -0,0 +1,54 @@ +#include "drape_frontend/route_renderer.hpp" + +#include "drape/glsl_func.hpp" +#include "drape/utils/projection.hpp" + +#include "base/logging.hpp" + +namespace df +{ + +RouteGraphics::RouteGraphics(dp::GLState const & state, + drape_ptr && buffer, + dp::Color const & color) + : m_state(state) + , m_buffer(move(buffer)) + , m_color(color) +{} + +void RouteRenderer::Render(int currentZoomLevel, ref_ptr mng, + dp::UniformValuesStorage const & commonUniforms) +{ + // TODO(@kuznetsov): calculate pixel width by zoom level + float halfWidth = 30.0f; + + for (RouteGraphics & route : m_routes) + { + dp::UniformValuesStorage uniformStorage; + glsl::vec4 color = glsl::ToVec4(route.m_color); + uniformStorage.SetFloatValue("u_color", color.r, color.g, color.b, color.a); + uniformStorage.SetFloatValue("u_halfWidth", halfWidth); + + ref_ptr prg = mng->GetProgram(route.m_state.GetProgramIndex()); + prg->Bind(); + dp::ApplyState(route.m_state, prg); + dp::ApplyUniforms(commonUniforms, prg); + dp::ApplyUniforms(uniformStorage, prg); + + route.m_buffer->Render(); + } +} + +void RouteRenderer::AddRoute(dp::GLState const & state, drape_ptr && bucket, + dp::Color const & color, ref_ptr mng) +{ + m_routes.push_back(RouteGraphics()); + RouteGraphics & route = m_routes.back(); + + route.m_state = state; + route.m_color = color; + route.m_buffer = bucket->MoveBuffer(); + route.m_buffer->Build(mng->GetProgram(route.m_state.GetProgramIndex())); +} + +} // namespace df diff --git a/drape_frontend/route_renderer.hpp b/drape_frontend/route_renderer.hpp new file mode 100644 index 0000000000..1bd21dd7e0 --- /dev/null +++ b/drape_frontend/route_renderer.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include "drape/batcher.hpp" +#include "drape/glsl_types.hpp" +#include "drape/glstate.hpp" +#include "drape/gpu_program_manager.hpp" +#include "drape/pointers.hpp" +#include "drape/vertex_array_buffer.hpp" + +namespace df +{ + +struct RouteGraphics +{ + RouteGraphics() : m_state(0, dp::GLState::GeometryLayer) {} + RouteGraphics(dp::GLState const & state, drape_ptr && buffer, + dp::Color const & color); + + dp::GLState m_state; + drape_ptr m_buffer; + dp::Color m_color; +}; + +class RouteRenderer final +{ +public: + void Render(int currentZoomLevel, ref_ptr mng, + dp::UniformValuesStorage const & commonUniforms); + + void AddRoute(dp::GLState const & state, drape_ptr && bucket, + dp::Color const & color, ref_ptr mng); + +private: + vector m_routes; +}; + +} // namespace df diff --git a/drape_frontend/route_shape.cpp b/drape_frontend/route_shape.cpp new file mode 100644 index 0000000000..8968f407d0 --- /dev/null +++ b/drape_frontend/route_shape.cpp @@ -0,0 +1,125 @@ +#include "drape_frontend/route_shape.hpp" + +#include "drape_frontend/line_shape_helper.hpp" + +#include "drape/utils/vertex_decl.hpp" +#include "drape/glsl_types.hpp" +#include "drape/glsl_func.hpp" +#include "drape/shader_def.hpp" +#include "drape/attribute_provider.hpp" +#include "drape/glstate.hpp" +#include "drape/batcher.hpp" + +#include "base/logging.hpp" + +namespace df +{ + +namespace +{ + using RV = gpu::RouteVertex; + using TGeometryBuffer = buffer_vector; +} + +RouteShape::RouteShape(m2::PolylineD const & polyline, CommonViewParams const & params) + : m_params(params) + , m_polyline(polyline) +{} + +void RouteShape::Draw(ref_ptr batcher) const +{ + TGeometryBuffer geometry; + TGeometryBuffer joinsGeometry; + vector const & path = m_polyline.GetPoints(); + ASSERT(path.size() > 1, ()); + + auto const generateTriangles = [&](glsl::vec3 const & pivot, vector const & normals) + { + size_t const trianglesCount = normals.size() / 3; + for (int j = 0; j < trianglesCount; j++) + { + joinsGeometry.push_back(RV(pivot, normals[3 * j])); + joinsGeometry.push_back(RV(pivot, normals[3 * j + 1])); + joinsGeometry.push_back(RV(pivot, normals[3 * j + 2])); + } + }; + + // constuct segments + vector segments; + segments.reserve(path.size() - 1); + ConstructLineSegments(path, segments); + + // build geometry + for (size_t i = 0; i < segments.size(); i++) + { + UpdateNormals(&segments[i], (i > 0) ? &segments[i - 1] : nullptr, + (i < segments.size() - 1) ? &segments[i + 1] : nullptr); + + // generate main geometry + glsl::vec3 const startPivot = glsl::vec3(segments[i].m_points[StartPoint], m_params.m_depth); + glsl::vec3 const endPivot = glsl::vec3(segments[i].m_points[EndPoint], m_params.m_depth); + + geometry.push_back(RV(startPivot, glsl::vec2(0, 0))); + geometry.push_back(RV(startPivot, GetNormal(segments[i], true /* isLeft */, StartNormal))); + geometry.push_back(RV(endPivot, glsl::vec2(0, 0))); + geometry.push_back(RV(endPivot, GetNormal(segments[i], true /* isLeft */, EndNormal))); + + geometry.push_back(RV(startPivot, GetNormal(segments[i], false /* isLeft */, StartNormal))); + geometry.push_back(RV(startPivot, glsl::vec2(0, 0))); + geometry.push_back(RV(endPivot, GetNormal(segments[i], false /* isLeft */, EndNormal))); + geometry.push_back(RV(endPivot, glsl::vec2(0, 0))); + + // generate joins + if (i < segments.size() - 1) + { + glsl::vec2 n1 = segments[i].m_hasLeftJoin[EndPoint] ? segments[i].m_leftNormals[EndPoint] : + segments[i].m_rightNormals[EndPoint]; + glsl::vec2 n2 = segments[i + 1].m_hasLeftJoin[StartPoint] ? segments[i + 1].m_leftNormals[StartPoint] : + segments[i + 1].m_rightNormals[StartPoint]; + + float widthScalar = segments[i].m_hasLeftJoin[EndPoint] ? segments[i].m_rightWidthScalar[EndPoint].x : + segments[i].m_leftWidthScalar[EndPoint].x; + + vector normals; + normals.reserve(24); + GenerateJoinNormals(dp::RoundJoin, n1, n2, 1.0f, segments[i].m_hasLeftJoin[EndPoint], widthScalar, normals); + + generateTriangles(glsl::vec3(segments[i].m_points[EndPoint], m_params.m_depth), normals); + } + + // generate caps + if (i == 0) + { + vector normals; + normals.reserve(24); + GenerateCapNormals(dp::RoundCap, segments[i].m_leftNormals[StartPoint], + segments[i].m_rightNormals[StartPoint], -segments[i].m_tangent, + 1.0f, true /* isStart */, normals); + + generateTriangles(glsl::vec3(segments[i].m_points[StartPoint], m_params.m_depth), normals); + } + + if (i == segments.size() - 1) + { + vector normals; + normals.reserve(24); + GenerateCapNormals(dp::RoundCap, segments[i].m_leftNormals[EndPoint], + segments[i].m_rightNormals[EndPoint], segments[i].m_tangent, + 1.0f, false /* isStart */, normals); + + generateTriangles(glsl::vec3(segments[i].m_points[EndPoint], m_params.m_depth), normals); + } + } + + dp::GLState state(gpu::ROUTE_PROGRAM, dp::GLState::GeometryLayer); + + dp::AttributeProvider provider(1, geometry.size()); + provider.InitStream(0, gpu::RouteVertex::GetBindingInfo(), make_ref(geometry.data())); + batcher->InsertListOfStrip(state, make_ref(&provider), 4); + + dp::AttributeProvider joinsProvider(1, joinsGeometry.size()); + joinsProvider.InitStream(0, gpu::RouteVertex::GetBindingInfo(), make_ref(joinsGeometry.data())); + batcher->InsertTriangleList(state, make_ref(&joinsProvider)); +} + +} // namespace df diff --git a/drape_frontend/route_shape.hpp b/drape_frontend/route_shape.hpp new file mode 100644 index 0000000000..ec0632d615 --- /dev/null +++ b/drape_frontend/route_shape.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "drape_frontend/map_shape.hpp" +#include "drape_frontend/shape_view_params.hpp" + +#include "geometry/polyline2d.hpp" + +namespace df +{ + +class RouteShape +{ +public: + RouteShape(m2::PolylineD const & polyline, + CommonViewParams const & params); + + void Draw(ref_ptr batcher) const; + +private: + CommonViewParams m_params; + m2::PolylineD m_polyline; +}; + +} // namespace df diff --git a/drape_head/testing_engine.cpp b/drape_head/testing_engine.cpp index bce3b7d30d..1816c45bb0 100644 --- a/drape_head/testing_engine.cpp +++ b/drape_head/testing_engine.cpp @@ -8,6 +8,7 @@ #include "drape_frontend/text_shape.hpp" #include "drape_frontend/path_text_shape.hpp" #include "drape_frontend/path_symbol_shape.hpp" +#include "drape_frontend/route_shape.hpp" #include "drape_frontend/area_shape.hpp" #include "drape_frontend/circle_shape.hpp" #include "drape_frontend/poi_symbol_shape.hpp" @@ -444,6 +445,8 @@ void TestingEngine::timerEvent(QTimerEvent * e) void TestingEngine::DrawImpl() { m_generalUniforms.SetFloatValue("u_opacity", 1.0f); + m_generalUniforms.SetFloatValue("u_color", 0.0f, 0.0f, 1.0f, 0.7f); + m_generalUniforms.SetFloatValue("u_halfWidth", 5.0f); dp::Batcher::TFlushFn flushFn = bind(&df::TestingEngine::OnFlushData, this, _1, _2); m_batcher->StartSession(flushFn); @@ -521,6 +524,21 @@ void TestingEngine::DrawImpl() LineShape(spl1, lvp).Draw(make_ref(m_batcher), make_ref(m_textures)); } + { + vector path1; + path1.push_back(m2::PointD(80.277071f, 37.9271164f)); + path1.push_back(m2::PointD(80.277071f, 35.9271164f)); + path1.push_back(m2::PointD(86.277071f, 35.9271164f)); + path1.push_back(m2::PointD(86.277071f, 30.9271164f)); + path1.push_back(m2::PointD(88.277071f, 32.9271164f)); + path1.push_back(m2::PointD(89.277071f, 39.9271164f)); + m2::PolylineD pln(path1); + + CommonViewParams rvp; + rvp.m_depth = 95.0f; + RouteShape(pln, rvp).Draw(make_ref(m_batcher)); + } + { vector trg{ m2::PointD(110.0f, 30.0f), m2::PointD(112.0f, 30.0f), m2::PointD(112.0f, 28.0f), m2::PointD(110.0f, 30.0f), m2::PointD(112.0f, 28.0f), m2::PointD(110.0f, 28.0f) }; diff --git a/geometry/polyline2d.hpp b/geometry/polyline2d.hpp index 6a56b17073..d10c1cccf5 100644 --- a/geometry/polyline2d.hpp +++ b/geometry/polyline2d.hpp @@ -89,10 +89,7 @@ public: return m_points[idx]; } - vector> const & GetPoints() const - { - return m_points; - } + vector > const & GetPoints() const { return m_points; } friend string DebugPrint(PolylineT const & p) { diff --git a/map/framework.cpp b/map/framework.cpp index 281ab3c295..4d466aebad 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -1807,56 +1807,60 @@ void Framework::UpdateSavedDataVersion() void Framework::BuildRoute(m2::PointD const & start, m2::PointD const & finish, uint32_t timeoutSec) { - //ASSERT_THREAD_CHECKER(m_threadChecker, ("BuildRoute")); + ASSERT_THREAD_CHECKER(m_threadChecker, ("BuildRoute")); + ASSERT(m_drapeEngine != nullptr, ()); - //shared_ptr const & state = GetLocationState(); - //if (!state->IsModeHasPosition()) - //{ - // CallRouteBuilded(IRouter::NoCurrentPosition, vector(), - // vector()); - // return; - //} + m2::PointD myPosition(MercatorBounds::LonToX(37.537866403232542), MercatorBounds::LatToY(55.796739740505075)); - //if (IsRoutingActive()) - // CloseRouting(); + /*m2::PointD myPosition; + bool const hasPosition = m_drapeEngine->GetMyPosition(myPosition); + if (!hasPosition) + { + CallRouteBuilded(IRouter::NoCurrentPosition, vector()); + return; + }*/ - //SetLastUsedRouter(m_currentRouterType); + if (IsRoutingActive()) + CloseRouting(); - //auto readyCallback = [this](Route const & route, IRouter::ResultCode code) - //{ - // ASSERT_THREAD_CHECKER(m_threadChecker, ("BuildRoute_ReadyCallback")); + SetLastUsedRouter(m_currentRouterType); - // vector absentCountries; - // vector absentRoutingIndexes; - // if (code == IRouter::NoError) - // { - // InsertRoute(route); - // GetLocationState()->RouteBuilded(); - // ShowRectExVisibleScale(route.GetPoly().GetLimitRect()); - // } - // else - // { - // for (string const & name : route.GetAbsentCountries()) - // { - // storage::TIndex fileIndex = m_storage.FindIndexByFile(name); - // if (m_storage.GetLatestLocalFile(fileIndex) && code != IRouter::FileTooOld) - // absentRoutingIndexes.push_back(fileIndex); - // else - // absentCountries.push_back(fileIndex); - // } + m_routingSession.BuildRoute(myPosition, destination, + [this] (Route const & route, IRouter::ResultCode code) + { + ASSERT_THREAD_CHECKER(m_threadChecker, ("BuildRoute_ReadyCallback")); + vector absentFiles; + vector absentRoutingIndexes; + if (code == IRouter::NoError) + { + InsertRoute(route); + m_drapeEngine->SetModelViewRect(route.GetPoly().GetLimitRect(), true, -1, true); + } + else + { + for (string const & name : route.GetAbsentCountries()) + { + storage::TIndex fileIndex = m_storage.FindIndexByFile(name); + if (m_storage.GetLatestLocalFile(fileIndex)) + absentRoutingIndexes.push_back(fileIndex); + else + absentCountries.push_back(fileIndex); + } - // if (code != IRouter::NeedMoreMaps) - // RemoveRoute(); - // } - // CallRouteBuilded(code, absentCountries, absentRoutingIndexes); - //}; + if (code != IRouter::NeedMoreMaps) + RemoveRoute(); - //m_routingSession.BuildRoute(state->Position(), destination, - // [readyCallback](Route const & route, IRouter::ResultCode code) - // { - // GetPlatform().RunOnGuiThread(bind(readyCallback, route, code)); - // }, - // m_progressCallback, timeoutSec); + RemoveRoute(); + } + CallRouteBuilded(code, absentFiles); + }); +} + +void Framework::FollowRoute() +{ + /// Устанавливает начальный зум - высчитывание ректа ->DE + ///@TODO UVR + //GetLocationState()->StartRouteFollow(); } void Framework::SetRouter(RouterType type) @@ -1950,6 +1954,12 @@ void Framework::InsertRoute(Route const & route) return; } + ASSERT(m_drapeEngine != nullptr, ()); + m_drapeEngine->AddRoute(route.GetPoly(), dp::Color(110, 180, 240, 200)); + + //float const visScale = df::VisualParams::Instance().GetVisualScale(); + + //RouteTrack track(route.GetPoly()); // @TODO UVR //vector turns; //if (m_currentRouterType == RouterType::Vehicle)