From f7908dd5e43e9a4f279616e7ed2dbeb4b83a2bb7 Mon Sep 17 00:00:00 2001 From: "r.kuznetsov" Date: Mon, 17 Aug 2015 15:28:24 +0300 Subject: [PATCH] Improved route rendering in drape --- drape_frontend/backend_renderer.cpp | 6 +- drape_frontend/frontend_renderer.cpp | 12 +- drape_frontend/message_subclasses.hpp | 24 +- drape_frontend/route_builder.cpp | 30 +-- drape_frontend/route_builder.hpp | 17 +- drape_frontend/route_renderer.cpp | 312 +++++++++++++++----------- drape_frontend/route_renderer.hpp | 41 +--- drape_frontend/route_shape.cpp | 305 ++++++++++++++++++------- drape_frontend/route_shape.hpp | 57 +++-- map/framework.cpp | 8 +- 10 files changed, 478 insertions(+), 334 deletions(-) diff --git a/drape_frontend/backend_renderer.cpp b/drape_frontend/backend_renderer.cpp index 26e91c37c6..777d268466 100644 --- a/drape_frontend/backend_renderer.cpp +++ b/drape_frontend/backend_renderer.cpp @@ -34,12 +34,10 @@ BackendRenderer::BackendRenderer(Params const & params) MessagePriority::High); }); - m_routeBuilder = make_unique_dp([this](dp::GLState const & state, drape_ptr && bucket, - RouteData const & routeData, dp::GLState const & endOfRouteState, - drape_ptr && endOfRouteBucket) + m_routeBuilder = make_unique_dp([this](drape_ptr && routeData) { m_commutator->PostMessage(ThreadsCommutator::RenderThread, - make_unique_dp(state, move(bucket), routeData, endOfRouteState, move(endOfRouteBucket)), + make_unique_dp(move(routeData)), MessagePriority::Normal); }); diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp index 7548553d42..3be070561d 100755 --- a/drape_frontend/frontend_renderer.cpp +++ b/drape_frontend/frontend_renderer.cpp @@ -302,16 +302,8 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) case Message::FlushRoute: { ref_ptr msg = message; - dp::GLState const & state = msg->GetState(); - drape_ptr bucket = msg->AcceptBuffer(); - m_routeRenderer->AddRouteRenderBucket(state, move(bucket), msg->GetRouteData(), make_ref(m_gpuProgramManager)); - - dp::GLState const & eorState = msg->GetEndOfRouteState(); - drape_ptr eorBucket = msg->AcceptEndOfRouteBuffer(); - if (eorBucket != nullptr) - { - m_routeRenderer->AddEndOfRouteRenderBucket(eorState, move(eorBucket), make_ref(m_gpuProgramManager)); - } + drape_ptr routeData = msg->AcceptRouteData(); + m_routeRenderer->SetRouteData(move(routeData), make_ref(m_gpuProgramManager)); m_myPositionController->ActivateRouting(); break; diff --git a/drape_frontend/message_subclasses.hpp b/drape_frontend/message_subclasses.hpp index 24db400997..02ecdaa237 100644 --- a/drape_frontend/message_subclasses.hpp +++ b/drape_frontend/message_subclasses.hpp @@ -533,31 +533,15 @@ private: class FlushRouteMessage : public Message { public: - FlushRouteMessage(dp::GLState const & state, drape_ptr && buffer, - RouteData const & routeData, dp::GLState const & endOfRouteState, - drape_ptr && endOfRouteBuffer) - : m_state(state) - , m_buffer(move(buffer)) - , m_routeData(routeData) - , m_endOfRouteState(endOfRouteState) - , m_endOfRouteBuffer(move(endOfRouteBuffer)) + FlushRouteMessage(drape_ptr && routeData) + : m_routeData(move(routeData)) {} Type GetType() const override { return Message::FlushRoute; } - - dp::GLState const & GetState() const { return m_state; } - drape_ptr && AcceptBuffer() { return move(m_buffer); } - RouteData const & GetRouteData() const { return m_routeData; } - - dp::GLState const & GetEndOfRouteState() const { return m_endOfRouteState; } - drape_ptr && AcceptEndOfRouteBuffer() { return move(m_endOfRouteBuffer); } + drape_ptr && AcceptRouteData() { return move(m_routeData); } private: - dp::GLState m_state; - drape_ptr m_buffer; - RouteData m_routeData; - dp::GLState m_endOfRouteState; - drape_ptr m_endOfRouteBuffer; + drape_ptr m_routeData; }; class UpdateMapStyleMessage : public Message diff --git a/drape_frontend/route_builder.cpp b/drape_frontend/route_builder.cpp index 34ba4c030f..e98df18f6d 100644 --- a/drape_frontend/route_builder.cpp +++ b/drape_frontend/route_builder.cpp @@ -5,11 +5,8 @@ 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, vector const & turns, @@ -18,29 +15,12 @@ void RouteBuilder::Build(m2::PolylineD const & routePolyline, vector co CommonViewParams params; params.m_depth = 0.0f; - RouteShape shape(routePolyline, params); - m2::RectF textureRect = shape.GetArrowTextureRect(textures); - shape.PrepareGeometry(textures); + drape_ptr routeData = make_unique_dp(); + routeData->m_color = color; + RouteShape(routePolyline, turns, params).Draw(textures, *routeData.get()); - RouteData routeData; - routeData.m_color = color; - routeData.m_arrowTextureRect = textureRect; - routeData.m_joinsBounds = shape.GetJoinsBounds(); - routeData.m_length = shape.GetLength(); - routeData.m_turns = turns; - - dp::GLState eorState = shape.GetEndOfRouteState(); - drape_ptr eorBucket = shape.MoveEndOfRouteRenderBucket(); - - auto flushRoute = [this, &routeData, &eorState, &eorBucket](dp::GLState const & state, - drape_ptr && bucket) - { - if (m_flushRouteFn != nullptr) - m_flushRouteFn(state, move(bucket), routeData, eorState, move(eorBucket)); - }; - - dp::SessionGuard guard(*m_batcher, flushRoute); - shape.Draw(make_ref(m_batcher), textures); + if (m_flushRouteFn != nullptr) + m_flushRouteFn(move(routeData)); } } // namespace df diff --git a/drape_frontend/route_builder.hpp b/drape_frontend/route_builder.hpp index 0bed583408..6a1b105052 100644 --- a/drape_frontend/route_builder.hpp +++ b/drape_frontend/route_builder.hpp @@ -2,34 +2,20 @@ #include "drape_frontend/route_shape.hpp" -#include "drape/batcher.hpp" -#include "drape/glstate.hpp" #include "drape/pointers.hpp" -#include "drape/render_bucket.hpp" #include "drape/texture_manager.hpp" #include "geometry/polyline2d.hpp" #include "std/function.hpp" -#include "std/vector.hpp" namespace df { -struct RouteData -{ - dp::Color m_color; - m2::RectF m_arrowTextureRect; - vector m_joinsBounds; - double m_length; - vector m_turns; -}; - class RouteBuilder { public: - using TFlushRouteFn = function &&, RouteData const &, - dp::GLState const &, drape_ptr &&)>; + using TFlushRouteFn = function &&)>; RouteBuilder(TFlushRouteFn const & flushRouteFn); @@ -38,7 +24,6 @@ public: private: TFlushRouteFn m_flushRouteFn; - drape_ptr m_batcher; }; } // namespace df diff --git a/drape_frontend/route_renderer.cpp b/drape_frontend/route_renderer.cpp index 438c14a661..169532e607 100644 --- a/drape_frontend/route_renderer.cpp +++ b/drape_frontend/route_renderer.cpp @@ -3,6 +3,7 @@ #include "drape/glsl_func.hpp" #include "drape/shader_def.hpp" #include "drape/utils/projection.hpp" +#include "drape/vertex_array_buffer.hpp" #include "indexer/scales.hpp" @@ -14,22 +15,38 @@ namespace df namespace { -float const halfWidthInPixel[] = +double const kArrowHeightFactor = 96.0 / 36.0; +double const kArrowAspect = 400.0 / 192.0; +double const kArrowTailSize = 20.0 / 400.0; +double const kArrowHeadSize = 124.0 / 400.0; + +float const kHalfWidthInPixel[] = { // 1 2 3 4 5 6 7 8 9 10 - 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 2.0f, 2.0f, 2.0f, 2.0f, - //11 12 13 14 15 16 17 18 19 - 2.0f, 2.5f, 3.5f, 5.0f, 7.5f, 10.0f, 14.0f, 18.0f, 36.0f, + 2.0f, 2.0f, 3.0f, 3.0f, 3.0f, 4.0f, 4.0f, 4.0f, 5.0f, 5.0f, + //11 12 13 14 15 16 17 18 19 20 + 6.0f, 6.0f, 7.0f, 7.0f, 7.0f, 7.0f, 8.0f, 10.0f, 24.0f, 36.0f }; -int const arrowAppearingZoomLevel = 14; +uint8_t const kAlphaValue[] = +{ + //1 2 3 4 5 6 7 8 9 10 + 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, + //11 12 13 14 15 16 17 18 19 20 + 204, 204, 204, 204, 190, 180, 170, 160, 140, 120 +}; -int const arrowPartsCount = 3; -double const arrowHeightFactor = 96.0 / 36.0; -double const arrowAspect = 400.0 / 192.0; -double const arrowTailSize = 20.0 / 400.0; -double const arrowHeadSize = 124.0 / 400.0; +int const kArrowAppearingZoomLevel = 14; +enum SegmentStatus +{ + OK = -1, + NoSegment = -2 +}; + +int const kInvalidGroup = -1; + +// Checks for route segments for intersection with the distance [start; end]. int CheckForIntersection(double start, double end, vector const & segments) { for (size_t i = 0; i < segments.size(); i++) @@ -37,43 +54,52 @@ int CheckForIntersection(double start, double end, vector const & if (segments[i].m_isAvailable) continue; - if ((start >= segments[i].m_start && start <= segments[i].m_end) || - (end >= segments[i].m_start && end <= segments[i].m_end) || - (start < segments[i].m_start && end > segments[i].m_end)) + if (start <= segments[i].m_end && end >= segments[i].m_start) return i; } - return -1; + return SegmentStatus::OK; } +// Finds the nearest appropriate route segment to the distance [start; end]. int FindNearestAvailableSegment(double start, double end, vector const & segments) { - double const threshold = 0.8; + double const kThreshold = 0.8; // check if distance intersects unavailable segment int index = CheckForIntersection(start, end, segments); + if (index == SegmentStatus::OK) + return SegmentStatus::OK; // find nearest available segment if necessary - if (index != -1) + double const len = end - start; + for (size_t i = index; i < segments.size(); i++) { - double const len = end - start; - for (int i = index; i < (int)segments.size(); i++) - { - double const factor = (segments[i].m_end - segments[i].m_start) / len; - if (segments[i].m_isAvailable && factor > threshold) - return (int)i; - } + double const factor = (segments[i].m_end - segments[i].m_start) / len; + if (segments[i].m_isAvailable && factor > kThreshold) + return static_cast(i); } + return SegmentStatus::NoSegment; +} - return -1; +void ClipBorders(vector & borders) +{ + auto invalidBorders = [](ArrowBorders const & borders) + { + return borders.m_groupIndex == kInvalidGroup; + }; + borders.erase(remove_if(borders.begin(), borders.end(), invalidBorders), borders.end()); } void MergeAndClipBorders(vector & borders) { + // initial clipping + ClipBorders(borders); + if (borders.empty()) return; // mark groups - for (size_t i = 0; i < borders.size() - 1; i++) + for (size_t i = 0; i + 1 < borders.size(); i++) { if (borders[i].m_endDistance >= borders[i + 1].m_startDistance) borders[i + 1].m_groupIndex = borders[i].m_groupIndex; @@ -92,57 +118,69 @@ void MergeAndClipBorders(vector & borders) } else { - borders[i].m_groupIndex = -1; + borders[i].m_groupIndex = kInvalidGroup; } } borders[lastGroupIndex].m_endDistance = borders.back().m_endDistance; // clip groups - auto const iter = remove_if(borders.begin(), borders.end(), [](ArrowBorders const & borders) - { - return borders.m_groupIndex == -1; - }); - borders.erase(iter, borders.end()); + ClipBorders(borders); +} + +void BuildBuckets(RouteRenderProperty const & renderProperty, ref_ptr mng) +{ + for (drape_ptr const & bucket : renderProperty.m_buckets) + bucket->GetBuffer()->Build(mng->GetProgram(renderProperty.m_state.GetProgramIndex())); } } -RouteGraphics::RouteGraphics(dp::GLState const & state, - drape_ptr && buffer, - dp::Color const & color) - : m_state(state) - , m_buffer(move(buffer)) - , m_color(color) -{} - RouteRenderer::RouteRenderer() : m_distanceFromBegin(0.0) - , m_endOfRouteState(0, dp::GLState::OverlayLayer) {} +void RouteRenderer::InterpolateByZoom(ScreenBase const & screen, float & halfWidth, float & alpha, double & zoom) const +{ + double const zoomLevel = my::clamp(fabs(log(screen.GetScale()) / log(2.0)), 1.0, scales::UPPER_STYLE_SCALE + 1.0); + zoom = trunc(zoomLevel); + int const index = zoom - 1.0; + float const lerpCoef = zoomLevel - zoom; + + if (index < scales::UPPER_STYLE_SCALE) + { + halfWidth = kHalfWidthInPixel[index] + lerpCoef * (kHalfWidthInPixel[index + 1] - kHalfWidthInPixel[index]); + + float const alpha1 = static_cast(kAlphaValue[index]) / numeric_limits::max(); + float const alpha2 = static_cast(kAlphaValue[index + 1]) / numeric_limits::max(); + alpha = alpha1 + lerpCoef * (alpha2 - alpha1); + } + else + { + halfWidth = kHalfWidthInPixel[scales::UPPER_STYLE_SCALE]; + alpha = static_cast(kAlphaValue[scales::UPPER_STYLE_SCALE]) / numeric_limits::max(); + } +} + void RouteRenderer::Render(ScreenBase const & screen, ref_ptr mng, dp::UniformValuesStorage const & commonUniforms) { - // half width calculation + if (!m_routeData) + return; + + // interpolate values by zoom level + double zoom = 0.0; float halfWidth = 0.0; - double const zoomLevel = my::clamp(fabs(log(screen.GetScale()) / log(2.0)), 1.0, scales::UPPER_STYLE_SCALE); - double const truncedZoom = trunc(zoomLevel); - int const index = truncedZoom - 1.0; - float const lerpCoef = zoomLevel - truncedZoom; + float alpha = 0.0; + InterpolateByZoom(screen, halfWidth, alpha, zoom); - if (index < scales::UPPER_STYLE_SCALE - 1) - halfWidth = halfWidthInPixel[index] + lerpCoef * (halfWidthInPixel[index + 1] - halfWidthInPixel[index]); - else - halfWidth = halfWidthInPixel[index]; - - if (!m_routeGraphics.empty()) + // render route { - dp::GLState const & state = m_routeGraphics.front().m_state; + dp::GLState const & state = m_routeData->m_route.m_state; // set up uniforms dp::UniformValuesStorage uniformStorage; - glsl::vec4 color = glsl::ToVec4(m_routeGraphics.front().m_color); - uniformStorage.SetFloatValue("u_color", color.r, color.g, color.b, color.a); + glsl::vec4 color = glsl::ToVec4(m_routeData->m_color); + uniformStorage.SetFloatValue("u_color", color.r, color.g, color.b, alpha); uniformStorage.SetFloatValue("u_halfWidth", halfWidth, halfWidth * screen.GetScale()); uniformStorage.SetFloatValue("u_clipLength", m_distanceFromBegin); @@ -154,57 +192,58 @@ void RouteRenderer::Render(ScreenBase const & screen, ref_ptrRender(); - } + for (drape_ptr const & bucket : m_routeData->m_route.m_buckets) + bucket->Render(screen); + } - // render arrows - if (truncedZoom >= arrowAppearingZoomLevel) - { - // set up shaders and apply common uniforms - ref_ptr prgArrow = mng->GetProgram(gpu::ROUTE_ARROW_PROGRAM); - prgArrow->Bind(); - dp::ApplyState(state, prgArrow); - dp::ApplyUniforms(commonUniforms, prgArrow); + // render arrows + if (zoom >= kArrowAppearingZoomLevel && !m_routeData->m_arrows.empty()) + { + dp::GLState const & state = m_routeData->m_arrows.front()->m_arrow.m_state; - for (RouteGraphics & graphics : m_routeGraphics) - RenderArrow(prgArrow, graphics, halfWidth, screen); - } + // set up shaders and apply common uniforms + dp::UniformValuesStorage uniforms = commonUniforms; + uniforms.SetFloatValue("u_textureRect", m_routeData->m_arrowTextureRect.minX(), + m_routeData->m_arrowTextureRect.minY(), + m_routeData->m_arrowTextureRect.maxX(), + m_routeData->m_arrowTextureRect.maxY()); + + ref_ptr prg = mng->GetProgram(gpu::ROUTE_ARROW_PROGRAM); + prg->Bind(); + dp::ApplyState(state, prg); + dp::ApplyUniforms(uniforms, prg); + + for (drape_ptr & property : m_routeData->m_arrows) + RenderArrow(prg, property, halfWidth, screen); } // render end of route - if (m_endOfRouteBuffer != nullptr) { + dp::GLState const & state = m_routeData->m_endOfRouteSign.m_state; + dp::UniformValuesStorage uniforms = commonUniforms; uniforms.SetFloatValue("u_opacity", 1.0); - ref_ptr eorProgram = mng->GetProgram(m_endOfRouteState.GetProgramIndex()); - eorProgram->Bind(); - dp::ApplyState(m_endOfRouteState, eorProgram); - dp::ApplyUniforms(uniforms, eorProgram); - m_endOfRouteBuffer->Render(); + ref_ptr program = mng->GetProgram(state.GetProgramIndex()); + program->Bind(); + dp::ApplyState(m_routeData->m_endOfRouteSign.m_state, program); + dp::ApplyUniforms(uniforms, program); + for (drape_ptr const & bucket : m_routeData->m_endOfRouteSign.m_buckets) + bucket->Render(screen); } } -void RouteRenderer::RenderArrow(ref_ptr prg, RouteGraphics const & graphics, +void RouteRenderer::RenderArrow(ref_ptr prg, drape_ptr const & property, float halfWidth, ScreenBase const & screen) { - double const arrowHalfWidth = halfWidth * arrowHeightFactor; + double const arrowHalfWidth = halfWidth * kArrowHeightFactor; double const glbArrowHalfWidth = arrowHalfWidth * screen.GetScale(); - double const arrowSize = 0.001; - double const textureWidth = 2.0 * arrowHalfWidth * arrowAspect; + double const textureWidth = 2.0 * arrowHalfWidth * kArrowAspect; dp::UniformValuesStorage uniformStorage; uniformStorage.SetFloatValue("u_halfWidth", arrowHalfWidth, glbArrowHalfWidth); - uniformStorage.SetFloatValue("u_textureRect", m_routeData.m_arrowTextureRect.minX(), - m_routeData.m_arrowTextureRect.minY(), - m_routeData.m_arrowTextureRect.maxX(), - m_routeData.m_arrowTextureRect.maxY()); // calculate arrows - m_arrowBorders.clear(); - CalculateArrowBorders(arrowSize, screen.GetScale(), textureWidth, glbArrowHalfWidth); + CalculateArrowBorders(property, kArrowSize, screen.GetScale(), textureWidth, glbArrowHalfWidth); // split arrow's data by 16-elements buckets array borders; @@ -227,39 +266,30 @@ void RouteRenderer::RenderArrow(ref_ptr prg, RouteGraphics const borders.fill(0.0f); dp::ApplyUniforms(uniformStorage, prg); - graphics.m_buffer->Render(); + for (drape_ptr const & bucket : property->m_arrow.m_buckets) + bucket->Render(screen); } } } -void RouteRenderer::AddRouteRenderBucket(dp::GLState const & state, drape_ptr && bucket, - RouteData const & routeData, ref_ptr mng) +void RouteRenderer::SetRouteData(drape_ptr && routeData, ref_ptr mng) { - m_routeData = routeData; + m_routeData = move(routeData); - m_routeGraphics.push_back(RouteGraphics()); - RouteGraphics & route = m_routeGraphics.back(); + BuildBuckets(m_routeData->m_route, mng); + BuildBuckets(m_routeData->m_endOfRouteSign, mng); + for (drape_ptr const & arrow : m_routeData->m_arrows) + BuildBuckets(arrow->m_arrow, mng); - route.m_state = state; - route.m_color = m_routeData.m_color; - route.m_buffer = bucket->MoveBuffer(); - route.m_buffer->Build(mng->GetProgram(route.m_state.GetProgramIndex())); -} - -void RouteRenderer::AddEndOfRouteRenderBucket(dp::GLState const & state, drape_ptr && bucket, - ref_ptr mng) -{ - m_endOfRouteState = state; - m_endOfRouteBuffer = bucket->MoveBuffer(); - m_endOfRouteBuffer->Build(mng->GetProgram(m_endOfRouteState.GetProgramIndex())); + m_distanceFromBegin = 0.0; } void RouteRenderer::Clear() { - m_routeGraphics.clear(); - m_endOfRouteBuffer.reset(); + m_routeData.reset(); m_arrowBorders.clear(); m_routeSegments.clear(); + m_distanceFromBegin = 0.0; } void RouteRenderer::UpdateDistanceFromBegin(double distanceFromBegin) @@ -267,68 +297,86 @@ void RouteRenderer::UpdateDistanceFromBegin(double distanceFromBegin) m_distanceFromBegin = distanceFromBegin; } -void RouteRenderer::ApplyJoinsBounds(double joinsBoundsScalar, double glbHeadLength) +void RouteRenderer::ApplyJoinsBounds(drape_ptr const & property, double joinsBoundsScalar, + double glbHeadLength, vector & arrowBorders) { m_routeSegments.clear(); - m_routeSegments.reserve(2 * m_routeData.m_joinsBounds.size() + 1); + m_routeSegments.reserve(2 * property->m_joinsBounds.size() + 1); + + double const length = property->m_end - property->m_start; // construct route's segments m_routeSegments.emplace_back(0.0, 0.0, true /* m_isAvailable */); - for (size_t i = 0; i < m_routeData.m_joinsBounds.size(); i++) + for (size_t i = 0; i < property->m_joinsBounds.size(); i++) { - double const start = m_routeData.m_joinsBounds[i].m_offset + - m_routeData.m_joinsBounds[i].m_start * joinsBoundsScalar; - double const end = m_routeData.m_joinsBounds[i].m_offset + - m_routeData.m_joinsBounds[i].m_end * joinsBoundsScalar; + double const start = property->m_joinsBounds[i].m_offset + + property->m_joinsBounds[i].m_start * joinsBoundsScalar; + + double const end = property->m_joinsBounds[i].m_offset + + property->m_joinsBounds[i].m_end * joinsBoundsScalar; m_routeSegments.back().m_end = start; m_routeSegments.emplace_back(start, end, false /* m_isAvailable */); m_routeSegments.emplace_back(end, 0.0, true /* m_isAvailable */); } - m_routeSegments.back().m_end = m_routeData.m_length; + m_routeSegments.back().m_end = length; // shift head of arrow if necessary bool needMerge = false; - for (size_t i = 0; i < m_arrowBorders.size(); i++) + for (size_t i = 0; i < arrowBorders.size(); i++) { - int headIndex = FindNearestAvailableSegment(m_arrowBorders[i].m_endDistance - glbHeadLength, - m_arrowBorders[i].m_endDistance, m_routeSegments); - if (headIndex != -1) + int headIndex = FindNearestAvailableSegment(arrowBorders[i].m_endDistance - glbHeadLength, + arrowBorders[i].m_endDistance, m_routeSegments); + if (headIndex != SegmentStatus::OK) { - m_arrowBorders[i].m_endDistance = min(m_routeData.m_length, m_routeSegments[headIndex].m_start + glbHeadLength); + if (headIndex != SegmentStatus::NoSegment) + { + ASSERT_GREATER_OR_EQUAL(headIndex, 0, ()); + double const restDist = length - m_routeSegments[headIndex].m_start; + if (restDist >= glbHeadLength) + arrowBorders[i].m_endDistance = min(length, m_routeSegments[headIndex].m_start + glbHeadLength); + else + arrowBorders[i].m_groupIndex = kInvalidGroup; + } + else + { + arrowBorders[i].m_groupIndex = kInvalidGroup; + } needMerge = true; } } // merge intersected borders if (needMerge) - MergeAndClipBorders(m_arrowBorders); + MergeAndClipBorders(arrowBorders); } -void RouteRenderer::CalculateArrowBorders(double arrowLength, double scale, double arrowTextureWidth, double joinsBoundsScalar) +void RouteRenderer::CalculateArrowBorders(drape_ptr const & property, double arrowLength, + double scale, double arrowTextureWidth, double joinsBoundsScalar) { - if (m_routeData.m_turns.empty()) - return; + ASSERT(!property->m_turns.empty(), ()); double halfLen = 0.5 * arrowLength; double const glbTextureWidth = arrowTextureWidth * scale; - double const glbTailLength = arrowTailSize * glbTextureWidth; - double const glbHeadLength = arrowHeadSize * glbTextureWidth; + double const glbTailLength = kArrowTailSize * glbTextureWidth; + double const glbHeadLength = kArrowHeadSize * glbTextureWidth; - m_arrowBorders.reserve(m_routeData.m_turns.size() * arrowPartsCount); + int const kArrowPartsCount = 3; + m_arrowBorders.clear(); + m_arrowBorders.reserve(property->m_turns.size() * kArrowPartsCount); double const halfTextureWidth = 0.5 * glbTextureWidth; if (halfLen < halfTextureWidth) halfLen = halfTextureWidth; // initial filling - for (size_t i = 0; i < m_routeData.m_turns.size(); i++) + for (size_t i = 0; i < property->m_turns.size(); i++) { ArrowBorders arrowBorders; arrowBorders.m_groupIndex = (int)i; - arrowBorders.m_startDistance = max(0.0, m_routeData.m_turns[i] - halfLen * 0.8); - arrowBorders.m_endDistance = min(m_routeData.m_length, m_routeData.m_turns[i] + halfLen * 1.2); + arrowBorders.m_startDistance = max(0.0, property->m_turns[i] - halfLen * 0.8); + arrowBorders.m_endDistance = min(property->m_end - property->m_start, property->m_turns[i] + halfLen * 1.2); if (arrowBorders.m_startDistance < m_distanceFromBegin) continue; @@ -340,7 +388,7 @@ void RouteRenderer::CalculateArrowBorders(double arrowLength, double scale, doub MergeAndClipBorders(m_arrowBorders); // apply joins bounds to prevent draw arrow's head on a join - ApplyJoinsBounds(joinsBoundsScalar, glbHeadLength); + ApplyJoinsBounds(property, joinsBoundsScalar, glbHeadLength, m_arrowBorders); // divide to parts of arrow size_t const bordersSize = m_arrowBorders.size(); @@ -351,12 +399,12 @@ void RouteRenderer::CalculateArrowBorders(double arrowLength, double scale, doub m_arrowBorders[i].m_endDistance = startDistance + glbTailLength; m_arrowBorders[i].m_startTexCoord = 0.0; - m_arrowBorders[i].m_endTexCoord = arrowTailSize; + m_arrowBorders[i].m_endTexCoord = kArrowTailSize; ArrowBorders arrowHead; arrowHead.m_startDistance = endDistance - glbHeadLength; arrowHead.m_endDistance = endDistance; - arrowHead.m_startTexCoord = 1.0 - arrowHeadSize; + arrowHead.m_startTexCoord = 1.0 - kArrowHeadSize; arrowHead.m_endTexCoord = 1.0; m_arrowBorders.push_back(arrowHead); diff --git a/drape_frontend/route_renderer.hpp b/drape_frontend/route_renderer.hpp index 51e75d1214..dbbbb9ef11 100644 --- a/drape_frontend/route_renderer.hpp +++ b/drape_frontend/route_renderer.hpp @@ -2,29 +2,14 @@ #include "drape_frontend/route_builder.hpp" -#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" -#include "platform/location.hpp" +#include "geometry/screenbase.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; -}; - struct ArrowBorders { double m_startDistance = 0; @@ -55,29 +40,23 @@ public: void Render(ScreenBase const & screen, ref_ptr mng, dp::UniformValuesStorage const & commonUniforms); - void AddRouteRenderBucket(dp::GLState const & state, drape_ptr && bucket, - RouteData const & routeData, ref_ptr mng); - - void AddEndOfRouteRenderBucket(dp::GLState const & state, drape_ptr && bucket, - ref_ptr mng); + void SetRouteData(drape_ptr && routeData, ref_ptr mng); void Clear(); void UpdateDistanceFromBegin(double distanceFromBegin); private: - void CalculateArrowBorders(double arrowLength, double scale, double arrowTextureWidth, double joinsBoundsScalar); + void CalculateArrowBorders(drape_ptr const & property, double arrowLength, + double scale, double arrowTextureWidth, double joinsBoundsScalar); + void ApplyJoinsBounds(drape_ptr const & property, double joinsBoundsScalar, + double glbHeadLength, vector & arrowBorders); + void RenderArrow(ref_ptr prg, drape_ptr const & property, + float halfWidth, ScreenBase const & screen); + void InterpolateByZoom(ScreenBase const & screen, float & halfWidth, float & alpha, double & zoom) const; - void ApplyJoinsBounds(double joinsBoundsScalar, double glbHeadLength); - - void RenderArrow(ref_ptr prg, RouteGraphics const & graphics, float halfWidth, ScreenBase const & screen); - - vector m_routeGraphics; double m_distanceFromBegin; - RouteData m_routeData; - - dp::GLState m_endOfRouteState; - drape_ptr m_endOfRouteBuffer; + drape_ptr m_routeData; vector m_arrowBorders; vector m_routeSegments; diff --git a/drape_frontend/route_shape.cpp b/drape_frontend/route_shape.cpp index 65217a8d3c..884e15b6bd 100644 --- a/drape_frontend/route_shape.cpp +++ b/drape_frontend/route_shape.cpp @@ -16,50 +16,159 @@ namespace df namespace { - float const LEFT_SIDE = 1.0; - float const CENTER = 0.0; - float const RIGHT_SIDE = -1.0; - void GetArrowTextureRegion(ref_ptr textures, dp::TextureManager::SymbolRegion & region) +float const kLeftSide = 1.0; +float const kCenter = 0.0; +float const kRightSide = -1.0; + +float const kArrowsGeometrySegmentLength = 0.5; + +void GetArrowTextureRegion(ref_ptr textures, dp::TextureManager::SymbolRegion & region) +{ + textures->GetSymbolRegion("route-arrow", region); +} + +void ClipArrowToSegments(vector const & turns, RouteData & routeData) +{ + int const cnt = static_cast(routeData.m_length / kArrowsGeometrySegmentLength) + 1; + routeData.m_arrows.reserve(cnt); + for (int i = 0; i < cnt; ++i) { - textures->GetSymbolRegion("route-arrow", region); + double const start = i * kArrowsGeometrySegmentLength; + double const end = (i + 1) * kArrowsGeometrySegmentLength; + + drape_ptr arrowRenderProperty = make_unique_dp(); + + // looking for corresponding turns + int startTurnIndex = -1; + int endTurnIndex = -1; + for (size_t j = 0; j < turns.size(); ++j) + { + if (turns[j] >= start && turns[j] < end) + { + if (startTurnIndex < 0) + startTurnIndex = j; + + if (startTurnIndex >= 0) + endTurnIndex = j; + + arrowRenderProperty->m_turns.push_back(turns[j]); + } + } + + if (startTurnIndex < 0 || endTurnIndex < 0) + continue; + + // start of arrow segment + if (startTurnIndex != 0) + { + double d = max(0.5 * (turns[startTurnIndex] + turns[startTurnIndex - 1]), + turns[startTurnIndex] - kArrowSize); + arrowRenderProperty->m_start = max(0.0, d); + } + else + { + arrowRenderProperty->m_start = max(0.0, turns[startTurnIndex] - kArrowSize); + } + + // end of arrow segment + if (endTurnIndex + 1 != turns.size()) + { + double d = min(0.5 * (turns[endTurnIndex] + turns[endTurnIndex + 1]), + turns[endTurnIndex] + kArrowSize); + arrowRenderProperty->m_end = min(routeData.m_length, d); + } + else + { + arrowRenderProperty->m_end = min(routeData.m_length, turns[endTurnIndex] + kArrowSize); + } + + // rescale turns + for (size_t j = 0; j < arrowRenderProperty->m_turns.size(); ++j) + arrowRenderProperty->m_turns[j] -= arrowRenderProperty->m_start; + + routeData.m_arrows.push_back(move(arrowRenderProperty)); } } -RouteShape::RouteShape(m2::PolylineD const & polyline, CommonViewParams const & params) - : m_length(0) - , m_params(params) - , m_polyline(polyline) - , m_endOfRouteState(0, dp::GLState::OverlayLayer) -{} - -m2::RectF RouteShape::GetArrowTextureRect(ref_ptr textures) const +vector CalculatePoints(m2::PolylineD const & polyline, double start, double end) { - dp::TextureManager::SymbolRegion region; - GetArrowTextureRegion(textures, region); - return region.GetTexRect(); + vector result; + result.reserve(polyline.GetSize() / 4); + + auto addIfNotExist = [&result](m2::PointD const & pnt) + { + if (result.empty() || result.back() != pnt) + result.push_back(pnt); + }; + + vector const & path = polyline.GetPoints(); + double len = 0; + bool started = false; + for (size_t i = 0; i + 1 < path.size(); i++) + { + double dist = (path[i + 1] - path[i]).Length(); + if (fabs(dist) < 1e-5) + continue; + + double l = len + dist; + if (!started && start >= len && start <= l) + { + double k = (start - len) / dist; + addIfNotExist(path[i] + (path[i + 1] - path[i]) * k); + started = true; + } + if (!started) + { + len = l; + continue; + } + + if (end >= len && end <= l) + { + double k = (end - len) / dist; + addIfNotExist(path[i] + (path[i + 1] - path[i]) * k); + break; + } + else + { + addIfNotExist(path[i + 1]); + } + len = l; + } + return result; } -void RouteShape::PrepareGeometry(ref_ptr textures) +} + +RouteShape::RouteShape(m2::PolylineD const & polyline, vector const & turns, + CommonViewParams const & params) + : m_params(params) + , m_polyline(polyline) + , m_turns(turns) +{} + +void RouteShape::PrepareGeometry(bool isRoute, vector const & path, + TGeometryBuffer & geometry, TGeometryBuffer & joinsGeometry, + vector & joinsBounds, double & outputLength) { - vector const & path = m_polyline.GetPoints(); ASSERT(path.size() > 1, ()); - auto const generateTriangles = [&](glsl::vec3 const & pivot, vector const & normals, - glsl::vec2 const & length, bool isLeft) + auto const generateTriangles = [&joinsGeometry](glsl::vec3 const & pivot, vector const & normals, + glsl::vec2 const & length, bool isLeft) { float const eps = 1e-5; size_t const trianglesCount = normals.size() / 3; - float const side = isLeft ? LEFT_SIDE : RIGHT_SIDE; + float const side = isLeft ? kLeftSide : kRightSide; for (int j = 0; j < trianglesCount; j++) { - glsl::vec3 const len1 = glsl::vec3(length.x, length.y, glsl::length(normals[3 * j]) < eps ? CENTER : side); - glsl::vec3 const len2 = glsl::vec3(length.x, length.y, glsl::length(normals[3 * j + 1]) < eps ? CENTER : side); - glsl::vec3 const len3 = glsl::vec3(length.x, length.y, glsl::length(normals[3 * j + 2]) < eps ? CENTER : side); + glsl::vec3 const len1 = glsl::vec3(length.x, length.y, glsl::length(normals[3 * j]) < eps ? kCenter : side); + glsl::vec3 const len2 = glsl::vec3(length.x, length.y, glsl::length(normals[3 * j + 1]) < eps ? kCenter : side); + glsl::vec3 const len3 = glsl::vec3(length.x, length.y, glsl::length(normals[3 * j + 2]) < eps ? kCenter : side); - m_joinsGeometry.push_back(RV(pivot, normals[3 * j], len1)); - m_joinsGeometry.push_back(RV(pivot, normals[3 * j + 1], len2)); - m_joinsGeometry.push_back(RV(pivot, normals[3 * j + 2], len3)); + joinsGeometry.push_back(RV(pivot, normals[3 * j], len1)); + joinsGeometry.push_back(RV(pivot, normals[3 * j + 1], len2)); + joinsGeometry.push_back(RV(pivot, normals[3 * j + 2], len3)); } }; @@ -91,15 +200,15 @@ void RouteShape::PrepareGeometry(ref_ptr textures) float const projRightStart = -segments[i].m_rightWidthScalar[StartPoint].y; float const projRightEnd = segments[i].m_rightWidthScalar[EndPoint].y; - m_geometry.push_back(RV(startPivot, glsl::vec2(0, 0), glsl::vec3(length, 0, CENTER))); - m_geometry.push_back(RV(startPivot, leftNormalStart, glsl::vec3(length, projLeftStart, LEFT_SIDE))); - m_geometry.push_back(RV(endPivot, glsl::vec2(0, 0), glsl::vec3(endLength, 0, CENTER))); - m_geometry.push_back(RV(endPivot, leftNormalEnd, glsl::vec3(endLength, projLeftEnd, LEFT_SIDE))); + geometry.push_back(RV(startPivot, glsl::vec2(0, 0), glsl::vec3(length, 0, kCenter))); + geometry.push_back(RV(startPivot, leftNormalStart, glsl::vec3(length, projLeftStart, kLeftSide))); + geometry.push_back(RV(endPivot, glsl::vec2(0, 0), glsl::vec3(endLength, 0, kCenter))); + geometry.push_back(RV(endPivot, leftNormalEnd, glsl::vec3(endLength, projLeftEnd, kLeftSide))); - m_geometry.push_back(RV(startPivot, rightNormalStart, glsl::vec3(length, projRightStart, RIGHT_SIDE))); - m_geometry.push_back(RV(startPivot, glsl::vec2(0, 0), glsl::vec3(length, 0, CENTER))); - m_geometry.push_back(RV(endPivot, rightNormalEnd, glsl::vec3(endLength, projRightEnd, RIGHT_SIDE))); - m_geometry.push_back(RV(endPivot, glsl::vec2(0, 0), glsl::vec3(endLength, 0, CENTER))); + geometry.push_back(RV(startPivot, rightNormalStart, glsl::vec3(length, projRightStart, kRightSide))); + geometry.push_back(RV(startPivot, glsl::vec2(0, 0), glsl::vec3(length, 0, kCenter))); + geometry.push_back(RV(endPivot, rightNormalEnd, glsl::vec3(endLength, projRightEnd, kRightSide))); + geometry.push_back(RV(endPivot, glsl::vec2(0, 0), glsl::vec3(endLength, 0, kCenter))); // generate joins if (i < segments.size() - 1) @@ -121,7 +230,7 @@ void RouteShape::PrepareGeometry(ref_ptr textures) } // generate caps - if (i == 0) + if (isRoute && i == 0) { vector normals; normals.reserve(24); @@ -133,7 +242,7 @@ void RouteShape::PrepareGeometry(ref_ptr textures) glsl::vec2(length, 0), true); } - if (i == segments.size() - 1) + if (isRoute && i == segments.size() - 1) { vector normals; normals.reserve(24); @@ -148,32 +257,33 @@ void RouteShape::PrepareGeometry(ref_ptr textures) length = endLength; } - m_length = length; + outputLength = length; // calculate joins bounds - float const eps = 1e-5; - double len = 0; - for (size_t i = 0; i < segments.size() - 1; i++) + if (!isRoute) { - len += glsl::length(segments[i].m_points[EndPoint] - segments[i].m_points[StartPoint]); + float const eps = 1e-5; + double len = 0; + for (size_t i = 0; i < segments.size() - 1; i++) + { + len += glsl::length(segments[i].m_points[EndPoint] - segments[i].m_points[StartPoint]); - RouteJoinBounds bounds; - bounds.m_start = min(segments[i].m_leftWidthScalar[EndPoint].y, - segments[i].m_rightWidthScalar[EndPoint].y); - bounds.m_end = max(-segments[i + 1].m_leftWidthScalar[StartPoint].y, - -segments[i + 1].m_rightWidthScalar[StartPoint].y); + RouteJoinBounds bounds; + bounds.m_start = min(segments[i].m_leftWidthScalar[EndPoint].y, + segments[i].m_rightWidthScalar[EndPoint].y); + bounds.m_end = max(-segments[i + 1].m_leftWidthScalar[StartPoint].y, + -segments[i + 1].m_rightWidthScalar[StartPoint].y); - if (fabs(bounds.m_end - bounds.m_start) < eps) - continue; + if (fabs(bounds.m_end - bounds.m_start) < eps) + continue; - bounds.m_offset = len; - m_joinsBounds.push_back(bounds); + bounds.m_offset = len; + joinsBounds.push_back(bounds); + } } - - CacheEndOfRouteSign(textures); } -void RouteShape::CacheEndOfRouteSign(ref_ptr mng) +void RouteShape::CacheEndOfRouteSign(ref_ptr mng, RouteData & routeData) { dp::TextureManager::SymbolRegion symbol; mng->GetSymbolRegion("route_to", symbol); @@ -196,39 +306,82 @@ void RouteShape::CacheEndOfRouteSign(ref_ptr mng) { dp::Batcher batcher(dp::Batcher::IndexPerQuad, dp::Batcher::VertexPerQuad); - dp::SessionGuard guard(batcher, [this](dp::GLState const & state, drape_ptr && b) + dp::SessionGuard guard(batcher, [&routeData](dp::GLState const & state, drape_ptr && b) { - m_endOfRouteRenderBucket = move(b); - m_endOfRouteState = state; + routeData.m_endOfRouteSign.m_buckets.push_back(move(b)); + routeData.m_endOfRouteSign.m_state = state; }); - dp::AttributeProvider provider(1 /*stream count*/, dp::Batcher::VertexPerQuad); - provider.InitStream(0 /*stream index*/, gpu::SolidTexturingVertex::GetBindingInfo(), make_ref(data)); + dp::AttributeProvider provider(1 /* stream count */, dp::Batcher::VertexPerQuad); + provider.InitStream(0 /* stream index */, gpu::SolidTexturingVertex::GetBindingInfo(), make_ref(data)); dp::IndicesRange indices = batcher.InsertTriangleStrip(state, make_ref(&provider), nullptr); ASSERT(indices.IsValid(), ()); } } -void RouteShape::Draw(ref_ptr batcher, ref_ptr textures) +void RouteShape::Draw(ref_ptr textures, RouteData & routeData) { - ASSERT(!m_geometry.empty(), ()); - - dp::TextureManager::SymbolRegion region; - GetArrowTextureRegion(textures, region); - - dp::GLState state(gpu::ROUTE_PROGRAM, dp::GLState::GeometryLayer); - state.SetColorTexture(region.GetTexture()); - - dp::AttributeProvider provider(1, m_geometry.size()); - provider.InitStream(0, gpu::RouteVertex::GetBindingInfo(), make_ref(m_geometry.data())); - batcher->InsertListOfStrip(state, make_ref(&provider), 4); - - if (!m_joinsGeometry.empty()) + // route geometry { - dp::AttributeProvider joinsProvider(1, m_joinsGeometry.size()); - joinsProvider.InitStream(0, gpu::RouteVertex::GetBindingInfo(), make_ref(m_joinsGeometry.data())); - batcher->InsertTriangleList(state, make_ref(&joinsProvider)); + TGeometryBuffer geometry; + TGeometryBuffer joinsGeometry; + vector bounds; + PrepareGeometry(true /* isRoute */, m_polyline.GetPoints(), geometry, joinsGeometry, bounds, routeData.m_length); + + dp::GLState state = dp::GLState(gpu::ROUTE_PROGRAM, dp::GLState::GeometryLayer); + BatchGeometry(state, geometry, joinsGeometry, routeData.m_route); + } + + // arrows geometry + if (!m_turns.empty()) + { + dp::TextureManager::SymbolRegion region; + GetArrowTextureRegion(textures, region); + routeData.m_arrowTextureRect = region.GetTexRect(); + + dp::GLState state = dp::GLState(gpu::ROUTE_ARROW_PROGRAM, dp::GLState::GeometryLayer); + state.SetColorTexture(region.GetTexture()); + + ClipArrowToSegments(m_turns, routeData); + for (auto & renderProperty : routeData.m_arrows) + { + TGeometryBuffer geometry; + TGeometryBuffer joinsGeometry; + vector points = CalculatePoints(m_polyline, renderProperty->m_start, renderProperty->m_end); + ASSERT_LESS_OR_EQUAL(points.size(), m_polyline.GetSize(), ()); + PrepareGeometry(false /* isRoute */, points, geometry, joinsGeometry, renderProperty->m_joinsBounds, routeData.m_length); + BatchGeometry(state, geometry, joinsGeometry, renderProperty->m_arrow); + } + } + + // end of route sign + CacheEndOfRouteSign(textures, routeData); +} + +void RouteShape::BatchGeometry(dp::GLState const & state, TGeometryBuffer & geometry, + TGeometryBuffer & joinsGeometry, RouteRenderProperty & property) +{ + size_t const verticesCount = geometry.size() + joinsGeometry.size(); + if (verticesCount != 0) + { + dp::Batcher batcher(verticesCount, verticesCount); + dp::SessionGuard guard(batcher, [&property](dp::GLState const & state, drape_ptr && b) + { + property.m_buckets.push_back(move(b)); + property.m_state = state; + }); + + dp::AttributeProvider provider(1 /* stream count */, geometry.size()); + provider.InitStream(0 /* stream index */, gpu::RouteVertex::GetBindingInfo(), make_ref(geometry.data())); + batcher.InsertListOfStrip(state, make_ref(&provider), 4); + + if (!joinsGeometry.empty()) + { + dp::AttributeProvider joinsProvider(1 /* stream count */, joinsGeometry.size()); + joinsProvider.InitStream(0 /* stream index */, gpu::RouteVertex::GetBindingInfo(), make_ref(joinsGeometry.data())); + batcher.InsertTriangleList(state, make_ref(&joinsProvider)); + } } } diff --git a/drape_frontend/route_shape.hpp b/drape_frontend/route_shape.hpp index 2e868aa4da..d8cfe9d325 100644 --- a/drape_frontend/route_shape.hpp +++ b/drape_frontend/route_shape.hpp @@ -6,6 +6,7 @@ #include "drape/glstate.hpp" #include "drape/render_bucket.hpp" #include "drape/utils/vertex_decl.hpp" +#include "drape/pointers.hpp" #include "geometry/polyline2d.hpp" @@ -14,6 +15,8 @@ namespace df { +double const kArrowSize = 0.001; + struct RouteJoinBounds { double m_start = 0; @@ -21,37 +24,53 @@ struct RouteJoinBounds double m_offset = 0; }; +struct RouteRenderProperty +{ + dp::GLState m_state; + vector> m_buckets; + RouteRenderProperty() : m_state(0, dp::GLState::GeometryLayer) {} +}; + +struct ArrowRenderProperty +{ + vector m_joinsBounds; + vector m_turns; + double m_start; + double m_end; + RouteRenderProperty m_arrow; +}; + +struct RouteData +{ + dp::Color m_color; + m2::RectF m_arrowTextureRect; + double m_length; + RouteRenderProperty m_route; + vector> m_arrows; + RouteRenderProperty m_endOfRouteSign; +}; + class RouteShape { public: - RouteShape(m2::PolylineD const & polyline, + RouteShape(m2::PolylineD const & polyline, vector const & turns, CommonViewParams const & params); - - m2::RectF GetArrowTextureRect(ref_ptr textures) const; - vector const & GetJoinsBounds() const { return m_joinsBounds; } - double GetLength() const { return m_length; } - dp::GLState const & GetEndOfRouteState() const { return m_endOfRouteState; } - drape_ptr && MoveEndOfRouteRenderBucket() { return move(m_endOfRouteRenderBucket); } - - void PrepareGeometry(ref_ptr textures); - void Draw(ref_ptr batcher, ref_ptr textures); + void Draw(ref_ptr textures, RouteData & routeData); private: using RV = gpu::RouteVertex; using TGeometryBuffer = buffer_vector; - void CacheEndOfRouteSign(ref_ptr mng); - - TGeometryBuffer m_geometry; - TGeometryBuffer m_joinsGeometry; - vector m_joinsBounds; - double m_length; + void CacheEndOfRouteSign(ref_ptr mng, RouteData & routeData); + void PrepareGeometry(bool isRoute, vector const & path, + TGeometryBuffer & geometry, TGeometryBuffer & joinsGeometry, + vector & joinsBounds, double & outputLength); + void BatchGeometry(dp::GLState const & state, TGeometryBuffer & geometry, + TGeometryBuffer & joinsGeometry, RouteRenderProperty & property); CommonViewParams m_params; m2::PolylineD m_polyline; - - dp::GLState m_endOfRouteState; - drape_ptr m_endOfRouteRenderBucket; + vector m_turns; }; } // namespace df diff --git a/map/framework.cpp b/map/framework.cpp index 97f597c6af..ea2fa35174 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -1874,7 +1874,13 @@ void Framework::InsertRoute(Route const & route) for (size_t i = 0; i < turnsGeom.size(); i++) turns.push_back(turnsGeom[i].m_mercatorDistance); } - m_drapeEngine->AddRoute(route.GetPoly(), turns, dp::Color(110, 180, 240, 160)); + + dp::Color routeColor; + if (m_currentRouterType == RouterType::Pedestrian) + routeColor = dp::Color(5, 105, 175, 204); + else + routeColor = dp::Color(30, 150, 240, 204); + m_drapeEngine->AddRoute(route.GetPoly(), turns, routeColor); } void Framework::CheckLocationForRouting(GpsInfo const & info)