From e04123350dabdf197889e1bcfab9703f59da2844 Mon Sep 17 00:00:00 2001 From: "r.kuznetsov" Date: Mon, 15 Jun 2015 17:21:05 +0300 Subject: [PATCH] Improvements of arrows rendering --- drape_frontend/backend_renderer.cpp | 4 +- drape_frontend/frontend_renderer.cpp | 3 +- drape_frontend/message_subclasses.hpp | 12 +- drape_frontend/route_builder.cpp | 11 +- drape_frontend/route_builder.hpp | 14 +- drape_frontend/route_renderer.cpp | 205 +++++++++++++++++++------- drape_frontend/route_renderer.hpp | 15 +- drape_frontend/route_shape.cpp | 79 ++++++---- drape_frontend/route_shape.hpp | 23 ++- drape_head/testing_engine.cpp | 4 +- 10 files changed, 267 insertions(+), 103 deletions(-) diff --git a/drape_frontend/backend_renderer.cpp b/drape_frontend/backend_renderer.cpp index b40d83f61d..346dc33529 100644 --- a/drape_frontend/backend_renderer.cpp +++ b/drape_frontend/backend_renderer.cpp @@ -36,10 +36,10 @@ BackendRenderer::BackendRenderer(Params const & params) }); m_routeBuilder = make_unique_dp([this](dp::GLState const & state, drape_ptr && bucket, - dp::Color const & color, m2::RectF const & arrowTextureRect) + RouteData const & routeData) { m_commutator->PostMessage(ThreadsCommutator::RenderThread, - make_unique_dp(state, move(bucket), color, arrowTextureRect), + make_unique_dp(state, move(bucket), routeData), MessagePriority::Normal); }); diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp index e20779fcfc..e9e2b4aeb5 100755 --- a/drape_frontend/frontend_renderer.cpp +++ b/drape_frontend/frontend_renderer.cpp @@ -280,8 +280,7 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) ref_ptr msg = message; dp::GLState const & state = msg->GetState(); drape_ptr bucket = msg->AcceptBuffer(); - m_routeRenderer->AddRouteRenderBucket(state, move(bucket), msg->GetColor(), msg->GetArrowTextureRect(), - make_ref(m_gpuProgramManager)); + m_routeRenderer->AddRouteRenderBucket(state, move(bucket), msg->GetRouteData(), make_ref(m_gpuProgramManager)); m_myPositionController->ActivateRouting(); break; } diff --git a/drape_frontend/message_subclasses.hpp b/drape_frontend/message_subclasses.hpp index a38482a69d..27206aed0b 100644 --- a/drape_frontend/message_subclasses.hpp +++ b/drape_frontend/message_subclasses.hpp @@ -4,6 +4,7 @@ #include "drape_frontend/gui/layer_render.hpp" #include "drape_frontend/gui/skin.hpp" +#include "drape_frontend/route_builder.hpp" #include "drape_frontend/my_position.hpp" #include "drape_frontend/selection_shape.hpp" #include "drape_frontend/message.hpp" @@ -530,25 +531,22 @@ class FlushRouteMessage : public Message { public: FlushRouteMessage(dp::GLState const & state, drape_ptr && buffer, - dp::Color const & color, m2::RectF const & arrowTextureRect) + RouteData const & routeData) : m_state(state) , m_buffer(move(buffer)) - , m_color(color) - , m_arrowTextureRect(arrowTextureRect) + , m_routeData(routeData) {} Type GetType() const override { return Message::FlushRoute; } dp::GLState const & GetState() const { return m_state; } drape_ptr && AcceptBuffer() { return move(m_buffer); } - dp::Color const & GetColor() const { return m_color; } - m2::RectF const & GetArrowTextureRect() const { return m_arrowTextureRect; } + RouteData const & GetRouteData() const { return m_routeData; } private: dp::GLState m_state; drape_ptr m_buffer; - dp::Color m_color; - m2::RectF m_arrowTextureRect; + RouteData m_routeData; }; diff --git a/drape_frontend/route_builder.cpp b/drape_frontend/route_builder.cpp index e3e4c88e85..2f5029d996 100644 --- a/drape_frontend/route_builder.cpp +++ b/drape_frontend/route_builder.cpp @@ -19,11 +19,18 @@ void RouteBuilder::Build(m2::PolylineD const & routePolyline, dp::Color const & RouteShape shape(routePolyline, params); m2::RectF textureRect = shape.GetArrowTextureRect(textures); + shape.PrepareGeometry(); - auto flushRoute = [this, &color, &textureRect](dp::GLState const & state, drape_ptr && bucket) + RouteData routeData; + routeData.m_color = color; + routeData.m_arrowTextureRect = textureRect; + routeData.m_joinsBounds = shape.GetJoinsBounds(); + routeData.m_length = shape.GetLength(); + + auto flushRoute = [this, &routeData](dp::GLState const & state, drape_ptr && bucket) { if (m_flushRouteFn != nullptr) - m_flushRouteFn(state, move(bucket), color, textureRect); + m_flushRouteFn(state, move(bucket), routeData); }; m_batcher->StartSession(flushRoute); diff --git a/drape_frontend/route_builder.hpp b/drape_frontend/route_builder.hpp index 7ef4c345fe..c2ed30cca9 100644 --- a/drape_frontend/route_builder.hpp +++ b/drape_frontend/route_builder.hpp @@ -1,5 +1,7 @@ #pragma once +#include "drape_frontend/route_shape.hpp" + #include "drape/batcher.hpp" #include "drape/glstate.hpp" #include "drape/pointers.hpp" @@ -9,15 +11,23 @@ #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; +}; + class RouteBuilder { public: - using TFlushRouteFn = function &&, - dp::Color const &, m2::RectF const &)>; + using TFlushRouteFn = function &&, RouteData const &)>; RouteBuilder(TFlushRouteFn const & flushRouteFn); diff --git a/drape_frontend/route_renderer.cpp b/drape_frontend/route_renderer.cpp index a80090fa52..a7eb2e81a0 100644 --- a/drape_frontend/route_renderer.cpp +++ b/drape_frontend/route_renderer.cpp @@ -25,8 +25,57 @@ float const halfWidthInPixel[] = int const arrowPartsCount = 3; double const arrowHeightFactor = 96.0 / 36.0; double const arrowAspect = 400.0 / 192.0; -double const arrowTailSize = 32.0 / 400.0; -double const arrowHeadSize = 144.0 / 400.0; +double const arrowTailSize = 20.0 / 400.0; +double const arrowHeadSize = 124.0 / 400.0; + +struct RouteSegment +{ + double m_start = 0; + double m_end = 0; + bool m_isAvailable = false; + + RouteSegment(double start, double end, bool isAvailable) + : m_start(start) + , m_end(end) + , m_isAvailable(isAvailable) + {} +}; + +int FindNearestAvailableSegment(bool isTail, double start, double end, vector const & segments) +{ + // check if distance is inside unavailable segment + int startIndex = -1; + int endIndex = -1; + for (size_t i = 0; i < segments.size(); i++) + { + if (!segments[i].m_isAvailable && start >= segments[i].m_start && start <= segments[i].m_end) + startIndex = i; + + if (!segments[i].m_isAvailable && end >= segments[i].m_start && end <= segments[i].m_end) + endIndex = i; + } + + // find nearest available segment if necessary + int index = max(startIndex, endIndex); + if (index != -1) + { + double const len = end - start; + if (isTail) + { + for (int i = index; i >= 0; i--) + if (segments[i].m_isAvailable && len <= (segments[i].m_end - segments[i].m_start)) + return (int)i; + } + else + { + for (int i = index; i < (int)segments.size(); i++) + if (segments[i].m_isAvailable && len <= (segments[i].m_end - segments[i].m_start)) + return (int)i; + } + } + + return -1; +} } @@ -73,18 +122,23 @@ void RouteRenderer::Render(ScreenBase const & screen, ref_ptrRender(); - // TEST + // arrows rendering double arrowHalfWidth = halfWidth * arrowHeightFactor; uniformStorage.SetFloatValue("u_halfWidth", arrowHalfWidth, arrowHalfWidth * screen.GetScale()); - uniformStorage.SetFloatValue("u_textureRect", m_arrowTextureRect.minX(), m_arrowTextureRect.minY(), - m_arrowTextureRect.maxX(), m_arrowTextureRect.maxY()); + uniformStorage.SetFloatValue("u_textureRect", m_routeData.m_arrowTextureRect.minX(), + m_routeData.m_arrowTextureRect.minY(), + m_routeData.m_arrowTextureRect.maxX(), + m_routeData.m_arrowTextureRect.maxY()); - - - m_turnPoints = { 0.0091, 0.0102 }; - float const textureWidth = 2.0 * arrowHalfWidth * arrowAspect; + m_turnPoints = { 0.0091, 0.0109 }; + double const textureWidth = 2.0 * arrowHalfWidth * arrowAspect; vector arrowBorders; - CalculateArrowBorders(0.001, screen.GetScale(), textureWidth, arrowBorders); + CalculateArrowBorders(0.001, screen.GetScale(), textureWidth, arrowHalfWidth * screen.GetScale(), arrowBorders); + + ref_ptr prgArrow = mng->GetProgram(gpu::ROUTE_ARROW_PROGRAM); + prgArrow->Bind(); + dp::ApplyState(graphics.m_state, prgArrow); + dp::ApplyUniforms(commonUniforms, prgArrow); size_t const elementsCount = 16; vector borders(elementsCount, 0.0); @@ -111,10 +165,6 @@ void RouteRenderer::Render(ScreenBase const & screen, ref_ptr prgArrow = mng->GetProgram(gpu::ROUTE_ARROW_PROGRAM); - prgArrow->Bind(); - dp::ApplyState(graphics.m_state, prgArrow); - dp::ApplyUniforms(commonUniforms, prgArrow); dp::ApplyUniforms(uniformStorage, prgArrow); graphics.m_buffer->Render(); } @@ -123,18 +173,17 @@ void RouteRenderer::Render(ScreenBase const & screen, ref_ptr && bucket, - dp::Color const & color, m2::RectF const & arrowTextureRect, - ref_ptr mng) + RouteData const & routeData, ref_ptr mng) { + m_routeData = routeData; + m_routeGraphics.push_back(RouteGraphics()); RouteGraphics & route = m_routeGraphics.back(); route.m_state = state; - route.m_color = color; + route.m_color = m_routeData.m_color; route.m_buffer = bucket->MoveBuffer(); route.m_buffer->Build(mng->GetProgram(route.m_state.GetProgramIndex())); - - m_arrowTextureRect = arrowTextureRect; } void RouteRenderer::Clear() @@ -147,26 +196,11 @@ void RouteRenderer::UpdateDistanceFromBegin(double distanceFromBegin) m_distanceFromBegin = distanceFromBegin; } -void RouteRenderer::CalculateArrowBorders(double arrowLength, double scale, - float arrowTextureWidth, vector & borders) +void RouteRenderer::MergeAndClipBorders(vector & borders, double scale, double arrowTextureWidth) { - if (m_turnPoints.empty()) + if (borders.empty()) return; - double const halfLen = 0.5 * arrowLength; - - borders.reserve(m_turnPoints.size() * arrowPartsCount); - - // initial filling - for (size_t i = 0; i < m_turnPoints.size(); i++) - { - ArrowBorders arrowBorders; - arrowBorders.m_groupIndex = (int)i; - arrowBorders.m_startDistance = m_turnPoints[i] - halfLen; - arrowBorders.m_endDistance = m_turnPoints[i] + halfLen; - borders.push_back(arrowBorders); - } - // mark groups for (size_t i = 0; i < borders.size() - 1; i++) { @@ -203,22 +237,99 @@ void RouteRenderer::CalculateArrowBorders(double arrowLength, double scale, return distanceInPixels < (arrowHeadSize + arrowTailSize) * arrowTextureWidth; }); borders.erase(iter, borders.end()); +} + +void RouteRenderer::ApplyJoinsBounds(double arrowTextureWidth, double joinsBoundsScalar, double glbTailLength, + double glbHeadLength, double scale, vector & borders) +{ + vector segments; + segments.reserve(2 * m_routeData.m_joinsBounds.size() + 1); + + // construct route's segments + segments.emplace_back(0.0, 0.0, true /* m_isAvailable */); + for (size_t i = 0; i < m_routeData.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; + + segments.back().m_end = start; + segments.emplace_back(start, end, false /* m_isAvailable */); + + segments.emplace_back(end, 0.0, true /* m_isAvailable */); + } + segments.back().m_end = m_routeData.m_length; + + // shift tail and head of arrow if necessary + bool needMerge = false; + for (size_t i = 0; i < borders.size(); i++) + { + int tailIndex = FindNearestAvailableSegment(true /* isTail */, borders[i].m_startDistance, + borders[i].m_startDistance + glbTailLength, segments); + if (tailIndex != -1) + { + borders[i].m_startDistance = segments[tailIndex].m_end - glbTailLength; + needMerge = true; + } + + int headIndex = FindNearestAvailableSegment(false /* isTail */, borders[i].m_endDistance - glbHeadLength, + borders[i].m_endDistance, segments); + if (headIndex != -1) + { + borders[i].m_endDistance = segments[headIndex].m_start + glbHeadLength; + needMerge = true; + } + } + + // merge intersected borders + if (needMerge) + MergeAndClipBorders(borders, scale, arrowTextureWidth); +} + +void RouteRenderer::CalculateArrowBorders(double arrowLength, double scale, double arrowTextureWidth, + double joinsBoundsScalar, vector & borders) +{ + if (m_turnPoints.empty()) + return; + + double const halfLen = 0.5 * arrowLength; + double const glbTextureWidth = arrowTextureWidth * scale; + double const glbTailLength = arrowTailSize * glbTextureWidth; + double const glbHeadLength = arrowHeadSize * glbTextureWidth; + + borders.reserve(m_turnPoints.size() * arrowPartsCount); + + // initial filling + for (size_t i = 0; i < m_turnPoints.size(); i++) + { + ArrowBorders arrowBorders; + arrowBorders.m_groupIndex = (int)i; + arrowBorders.m_startDistance = m_turnPoints[i] - halfLen; + arrowBorders.m_endDistance = m_turnPoints[i] + halfLen; + borders.push_back(arrowBorders); + } + + // merge intersected borders and clip them + MergeAndClipBorders(borders, scale, arrowTextureWidth); + + // apply joins bounds to prevent draw arrow's head and tail on a join + ApplyJoinsBounds(arrowTextureWidth, joinsBoundsScalar, glbTailLength, + glbHeadLength, scale, borders); // divide to parts of arrow size_t const bordersSize = borders.size(); - - double const glbTextureWidth = arrowTextureWidth * scale; for (size_t i = 0; i < bordersSize; i++) { float const startDistance = borders[i].m_startDistance; float const endDistance = borders[i].m_endDistance; - borders[i].m_endDistance = startDistance + arrowTailSize * glbTextureWidth; + borders[i].m_endDistance = startDistance + glbTailLength; borders[i].m_startTexCoord = 0.0; borders[i].m_endTexCoord = arrowTailSize; ArrowBorders arrowHead; - arrowHead.m_startDistance = endDistance - arrowHeadSize * glbTextureWidth; + arrowHead.m_startDistance = endDistance - glbHeadLength; arrowHead.m_endDistance = endDistance; arrowHead.m_startTexCoord = 1.0 - arrowHeadSize; arrowHead.m_endTexCoord = 1.0; @@ -230,20 +341,6 @@ void RouteRenderer::CalculateArrowBorders(double arrowLength, double scale, arrowBody.m_startTexCoord = borders[i].m_endTexCoord; arrowBody.m_endTexCoord = arrowHead.m_startTexCoord; borders.push_back(arrowBody); - - /*for (int j = 1; j <= arrowPartsCount; j++) - { - ArrowBorders arrowBorders; - arrowBorders.m_startDistance = startDistance + arrowTextureParts[j - 1] * len; - arrowBorders.m_endDistance = startDistance + arrowTextureParts[j] * len; - arrowBorders.m_startTexCoord = arrowTextureParts[j - 1]; - arrowBorders.m_endTexCoord = arrowTextureParts[j]; - - if (j == 1) - borders[i] = arrowBorders; - else - borders.push_back(arrowBorders); - }*/ } } diff --git a/drape_frontend/route_renderer.hpp b/drape_frontend/route_renderer.hpp index 2967681d9e..00d6a5c150 100644 --- a/drape_frontend/route_renderer.hpp +++ b/drape_frontend/route_renderer.hpp @@ -1,5 +1,7 @@ #pragma once +#include "drape_frontend/route_builder.hpp" + #include "drape/batcher.hpp" #include "drape/glsl_types.hpp" #include "drape/glstate.hpp" @@ -41,20 +43,23 @@ public: dp::UniformValuesStorage const & commonUniforms); void AddRouteRenderBucket(dp::GLState const & state, drape_ptr && bucket, - dp::Color const & color, m2::RectF const & arrowTextureRect, - ref_ptr mng); + RouteData const & routeData, ref_ptr mng); void Clear(); void UpdateDistanceFromBegin(double distanceFromBegin); private: - void CalculateArrowBorders(double arrowLength, double scale, - float arrowTextureWidth, vector & borders); + void CalculateArrowBorders(double arrowLength, double scale, double arrowTextureWidth, + double joinsBoundsScalar, vector & borders); + void MergeAndClipBorders(vector & borders, double scale, double arrowTextureWidth); + + void ApplyJoinsBounds(double arrowTextureWidth, double joinsBoundsScalar, double glbTailLength, + double glbHeadLength, double scale, vector & borders); vector m_routeGraphics; double m_distanceFromBegin; - m2::RectF m_arrowTextureRect; + RouteData m_routeData; vector m_turnPoints; }; diff --git a/drape_frontend/route_shape.cpp b/drape_frontend/route_shape.cpp index 0c3e1a0213..cfafef03d4 100644 --- a/drape_frontend/route_shape.cpp +++ b/drape_frontend/route_shape.cpp @@ -9,7 +9,6 @@ #include "drape/glstate.hpp" #include "drape/shader_def.hpp" #include "drape/texture_manager.hpp" -#include "drape/utils/vertex_decl.hpp" #include "base/logging.hpp" @@ -18,9 +17,6 @@ namespace df namespace { - using RV = gpu::RouteVertex; - using TGeometryBuffer = buffer_vector; - float const LEFT_SIDE = 1.0; float const CENTER = 0.0; float const RIGHT_SIDE = -1.0; @@ -34,6 +30,7 @@ namespace RouteShape::RouteShape(m2::PolylineD const & polyline, CommonViewParams const & params) : m_params(params) , m_polyline(polyline) + , m_length(0) {} m2::RectF RouteShape::GetArrowTextureRect(ref_ptr textures) const @@ -43,20 +40,15 @@ m2::RectF RouteShape::GetArrowTextureRect(ref_ptr textures) return region.GetTexRect(); } -void RouteShape::Draw(ref_ptr batcher, ref_ptr textures) const +void RouteShape::PrepareGeometry() { - TGeometryBuffer geometry; - TGeometryBuffer joinsGeometry; vector const & path = m_polyline.GetPoints(); ASSERT(path.size() > 1, ()); - dp::TextureManager::SymbolRegion region; - GetArrowTextureRegion(textures, region); - auto const generateTriangles = [&](glsl::vec3 const & pivot, vector const & normals, glsl::vec2 const & length, bool isLeft) { - const float eps = 1e-5; + float const eps = 1e-5; size_t const trianglesCount = normals.size() / 3; float const side = isLeft ? LEFT_SIDE : RIGHT_SIDE; for (int j = 0; j < trianglesCount; j++) @@ -65,9 +57,9 @@ void RouteShape::Draw(ref_ptr batcher, ref_ptr 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); - 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)); + 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)); } }; @@ -99,15 +91,15 @@ void RouteShape::Draw(ref_ptr batcher, ref_ptr float const projRightStart = -segments[i].m_rightWidthScalar[StartPoint].y; float const projRightEnd = segments[i].m_rightWidthScalar[EndPoint].y; - geometry.push_back(RV(startPivot, glsl::vec2(0, 0), glsl::vec3(length, 0, CENTER))); - geometry.push_back(RV(startPivot, leftNormalStart, glsl::vec3(length, projLeftStart, LEFT_SIDE))); - geometry.push_back(RV(endPivot, glsl::vec2(0, 0), glsl::vec3(endLength, 0, CENTER))); - geometry.push_back(RV(endPivot, leftNormalEnd, glsl::vec3(endLength, projLeftEnd, LEFT_SIDE))); + 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, rightNormalStart, glsl::vec3(length, projRightStart, RIGHT_SIDE))); - geometry.push_back(RV(startPivot, glsl::vec2(0, 0), glsl::vec3(length, 0, CENTER))); - geometry.push_back(RV(endPivot, rightNormalEnd, glsl::vec3(endLength, projRightEnd, RIGHT_SIDE))); - geometry.push_back(RV(endPivot, glsl::vec2(0, 0), glsl::vec3(endLength, 0, CENTER))); + 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))); // generate joins if (i < segments.size() - 1) @@ -156,16 +148,49 @@ void RouteShape::Draw(ref_ptr batcher, ref_ptr length = endLength; } + m_length = length; + + // calculate joins bounds + 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); + + if (fabs(bounds.m_end - bounds.m_start) < eps) + continue; + + bounds.m_offset = len; + m_joinsBounds.push_back(bounds); + } +} + +void RouteShape::Draw(ref_ptr batcher, ref_ptr textures) +{ + 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, geometry.size()); - provider.InitStream(0, gpu::RouteVertex::GetBindingInfo(), make_ref(geometry.data())); + 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); - dp::AttributeProvider joinsProvider(1, joinsGeometry.size()); - joinsProvider.InitStream(0, gpu::RouteVertex::GetBindingInfo(), make_ref(joinsGeometry.data())); - batcher->InsertTriangleList(state, make_ref(&joinsProvider)); + if (!m_joinsGeometry.empty()) + { + dp::AttributeProvider joinsProvider(1, m_joinsGeometry.size()); + joinsProvider.InitStream(0, gpu::RouteVertex::GetBindingInfo(), make_ref(m_joinsGeometry.data())); + batcher->InsertTriangleList(state, make_ref(&joinsProvider)); + } } } // namespace df diff --git a/drape_frontend/route_shape.hpp b/drape_frontend/route_shape.hpp index 1c8a9f0a36..7c5f803fd4 100644 --- a/drape_frontend/route_shape.hpp +++ b/drape_frontend/route_shape.hpp @@ -3,11 +3,22 @@ #include "drape_frontend/map_shape.hpp" #include "drape_frontend/shape_view_params.hpp" +#include "drape/utils/vertex_decl.hpp" + #include "geometry/polyline2d.hpp" +#include "std/vector.hpp" + namespace df { +struct RouteJoinBounds +{ + double m_start = 0; + double m_end = 0; + double m_offset = 0; +}; + class RouteShape { public: @@ -15,10 +26,20 @@ public: CommonViewParams const & params); m2::RectF GetArrowTextureRect(ref_ptr textures) const; + vector const & GetJoinsBounds() const { return m_joinsBounds; } + double GetLength() const { return m_length; } - void Draw(ref_ptr batcher, ref_ptr textures) const; + void PrepareGeometry(); + void Draw(ref_ptr batcher, ref_ptr textures); private: + using RV = gpu::RouteVertex; + using TGeometryBuffer = buffer_vector; + + TGeometryBuffer m_geometry; + TGeometryBuffer m_joinsGeometry; + vector m_joinsBounds; + double m_length; CommonViewParams m_params; m2::PolylineD m_polyline; diff --git a/drape_head/testing_engine.cpp b/drape_head/testing_engine.cpp index 9eef22fac4..e6303b5632 100644 --- a/drape_head/testing_engine.cpp +++ b/drape_head/testing_engine.cpp @@ -525,7 +525,9 @@ void TestingEngine::DrawImpl() CommonViewParams rvp; rvp.m_depth = 95.0f; - RouteShape(pln, rvp).Draw(make_ref(m_batcher), make_ref(m_textures)); + RouteShape shape(pln, rvp); + shape.PrepareGeometry(); + shape.Draw(make_ref(m_batcher), make_ref(m_textures)); } {