Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorr.kuznetsov <r.kuznetsov@corp.mail.ru>2015-06-04 17:00:32 +0300
committerr.kuznetsov <r.kuznetsov@corp.mail.ru>2015-11-30 16:08:34 +0300
commitfd8c633f7b3893eb528d5fd53b2fc9751fc515a8 (patch)
tree0b4051f285cc31585e6d4b8629921ffe5beacce5
parent92bd2021230e4e4e815fd6df3020b3dc49b7637d (diff)
Added route tracks rendering
-rw-r--r--drape/shaders/route_fragment_shader.fsh9
-rw-r--r--drape/shaders/route_vertex_shader.vsh24
-rw-r--r--drape/shaders/shader_index.txt1
-rw-r--r--drape/utils/vertex_decl.cpp42
-rw-r--r--drape/utils/vertex_decl.hpp11
-rw-r--r--drape_frontend/backend_renderer.cpp22
-rw-r--r--drape_frontend/backend_renderer.hpp2
-rw-r--r--drape_frontend/drape_engine.cpp19
-rw-r--r--drape_frontend/drape_engine.hpp4
-rwxr-xr-xdrape_frontend/drape_frontend.pro8
-rwxr-xr-xdrape_frontend/frontend_renderer.cpp25
-rwxr-xr-xdrape_frontend/frontend_renderer.hpp10
-rw-r--r--drape_frontend/line_shape.cpp222
-rw-r--r--drape_frontend/line_shape_helper.cpp220
-rw-r--r--drape_frontend/line_shape_helper.hpp57
-rw-r--r--drape_frontend/message.hpp3
-rw-r--r--drape_frontend/message_subclasses.hpp64
-rw-r--r--drape_frontend/route_builder.cpp31
-rw-r--r--drape_frontend/route_builder.hpp31
-rw-r--r--drape_frontend/route_renderer.cpp54
-rw-r--r--drape_frontend/route_renderer.hpp37
-rw-r--r--drape_frontend/route_shape.cpp125
-rw-r--r--drape_frontend/route_shape.hpp24
-rw-r--r--drape_head/testing_engine.cpp18
-rw-r--r--geometry/polyline2d.hpp5
-rw-r--r--map/framework.cpp98
26 files changed, 889 insertions, 277 deletions
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<RouteVertex::TPosition>();
+ 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<RouteVertex::TNormal>();
+ 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<RouteBuilder>([this](dp::GLState const & state,
+ drape_ptr<dp::RenderBucket> && bucket, dp::Color const & color)
+ {
+ m_commutator->PostMessage(ThreadsCommutator::RenderThread,
+ make_unique_dp<FlushRouteMessage>(state, move(bucket), color),
+ MessagePriority::Normal);
+ });
+
StartThread();
}
@@ -93,8 +103,10 @@ void BackendRenderer::AcceptMessage(ref_ptr<Message> message)
break;
}
case Message::GuiRecache:
- RecacheGui(static_cast<ref_ptr<GuiRecacheMessage>>(message)->GetElements());
- break;
+ {
+ RecacheGui(static_cast<ref_ptr<GuiRecacheMessage>>(message)->GetElements());
+ break;
+ }
case Message::TileReadStarted:
{
m_batchersPool->ReserveBatcher(static_cast<ref_ptr<BaseTileMessage>>(message)->GetKey());
@@ -160,6 +172,12 @@ void BackendRenderer::AcceptMessage(ref_ptr<Message> message)
}
break;
}
+ case Message::AddRoute:
+ {
+ ref_ptr<AddRouteMessage> 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<BatchersPool> m_batchersPool;
drape_ptr<ReadManager> m_readManager;
+ drape_ptr<RouteBuilder> 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<GetMyPositionMessage>(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<AddRouteMessage>(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> message)
break;
}
+ case Message::GetMyPosition:
+ {
+ ref_ptr<GetMyPositionMessage> msg = message;
+ msg->SetMyPosition(m_myPositionController->IsModeHasPosition(), m_myPositionController->Position());
+ break;
+ }
+
+ case Message::FlushRoute:
+ {
+ ref_ptr<FlushRouteMessage> msg = message;
+ dp::GLState const & state = msg->GetState();
+ drape_ptr<dp::RenderBucket> 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<gui::LayerRenderer> m_guiRenderer;
drape_ptr<MyPositionController> m_myPositionController;
drape_ptr<SelectionShape> m_selectionShape;
+ drape_ptr<RouteRenderer> m_routeRenderer;
drape_ptr<dp::OverlayTree> 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<glsl::vec2> & 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<int>(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<glsl::vec2> & 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<dp::Batcher> batcher, ref_ptr<dp::TextureManager> t
// constuct segments
vector<LineSegment> 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<m2::PointD> const & path, vector<LineSegment> & 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<glsl::vec2> & 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<int>(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<glsl::vec2> & 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<m2::PointD> const & path, vector<LineSegment> & 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<glsl::vec2> & normals);
+
+void GenerateCapNormals(dp::LineCap capType, glsl::vec2 const & normal1, glsl::vec2 const & normal2,
+ glsl::vec2 const & direction, float halfWidth, bool isStart, vector<glsl::vec2> & 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<dp::RenderBucket> && 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<dp::RenderBucket> && AcceptBuffer() { return move(m_buffer); }
+ dp::Color const & GetColor() const { return m_color; }
+
+private:
+ dp::GLState m_state;
+ drape_ptr<dp::RenderBucket> 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<dp::Batcher>(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<dp::RenderBucket> && 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<void(dp::GLState const &,
+ drape_ptr<dp::RenderBucket> &&,
+ dp::Color const &)>;
+
+ RouteBuilder(TFlushRouteFn const & flushRouteFn);
+
+ void Build(m2::PolylineD const & routePolyline, dp::Color const & color);
+
+private:
+ TFlushRouteFn m_flushRouteFn;
+ drape_ptr<dp::Batcher> 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<dp::VertexArrayBuffer> && buffer,
+ dp::Color const & color)
+ : m_state(state)
+ , m_buffer(move(buffer))
+ , m_color(color)
+{}
+
+void RouteRenderer::Render(int currentZoomLevel, ref_ptr<dp::GpuProgramManager> 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<dp::GpuProgram> 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<dp::RenderBucket> && bucket,
+ dp::Color const & color, ref_ptr<dp::GpuProgramManager> 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<dp::VertexArrayBuffer> && buffer,
+ dp::Color const & color);
+
+ dp::GLState m_state;
+ drape_ptr<dp::VertexArrayBuffer> m_buffer;
+ dp::Color m_color;
+};
+
+class RouteRenderer final
+{
+public:
+ void Render(int currentZoomLevel, ref_ptr<dp::GpuProgramManager> mng,
+ dp::UniformValuesStorage const & commonUniforms);
+
+ void AddRoute(dp::GLState const & state, drape_ptr<dp::RenderBucket> && bucket,
+ dp::Color const & color, ref_ptr<dp::GpuProgramManager> mng);
+
+private:
+ vector<RouteGraphics> 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<gpu::RouteVertex, 128>;
+}
+
+RouteShape::RouteShape(m2::PolylineD const & polyline, CommonViewParams const & params)
+ : m_params(params)
+ , m_polyline(polyline)
+{}
+
+void RouteShape::Draw(ref_ptr<dp::Batcher> batcher) const
+{
+ TGeometryBuffer geometry;
+ TGeometryBuffer joinsGeometry;
+ vector<m2::PointD> const & path = m_polyline.GetPoints();
+ ASSERT(path.size() > 1, ());
+
+ auto const generateTriangles = [&](glsl::vec3 const & pivot, vector<glsl::vec2> 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<LineSegment> 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<glsl::vec2> 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<glsl::vec2> 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<glsl::vec2> 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<dp::Batcher> 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);
@@ -522,6 +525,21 @@ void TestingEngine::DrawImpl()
}
{
+ vector<m2::PointD> 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<m2::PointF> 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) };
AreaViewParams p;
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<Point<T>> const & GetPoints() const
- {
- return m_points;
- }
+ vector<Point<T> > const & GetPoints() const { return m_points; }
friend string DebugPrint(PolylineT<T> 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<State> const & state = GetLocationState();
- //if (!state->IsModeHasPosition())
- //{
- // CallRouteBuilded(IRouter::NoCurrentPosition, vector<storage::TIndex>(),
- // vector<storage::TIndex>());
- // 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<storage::TIndex>());
+ 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<storage::TIndex> absentCountries;
- // vector<storage::TIndex> 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);
- // }
-
- // if (code != IRouter::NeedMoreMaps)
- // RemoveRoute();
- // }
- // CallRouteBuilded(code, absentCountries, absentRoutingIndexes);
- //};
+ m_routingSession.BuildRoute(myPosition, destination,
+ [this] (Route const & route, IRouter::ResultCode code)
+ {
+ ASSERT_THREAD_CHECKER(m_threadChecker, ("BuildRoute_ReadyCallback"));
+ vector<storage::TIndex> absentFiles;
+ vector<storage::TIndex> 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();
+
+ RemoveRoute();
+ }
+ CallRouteBuilded(code, absentFiles);
+ });
+}
- //m_routingSession.BuildRoute(state->Position(), destination,
- // [readyCallback](Route const & route, IRouter::ResultCode code)
- // {
- // GetPlatform().RunOnGuiThread(bind(readyCallback, route, code));
- // },
- // m_progressCallback, timeoutSec);
+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<double> turns;
//if (m_currentRouterType == RouterType::Vehicle)