Improved route rendering in drape

This commit is contained in:
r.kuznetsov 2015-08-17 15:28:24 +03:00
parent 7e05661e00
commit f7908dd5e4
10 changed files with 478 additions and 334 deletions

View file

@ -34,12 +34,10 @@ BackendRenderer::BackendRenderer(Params const & params)
MessagePriority::High);
});
m_routeBuilder = make_unique_dp<RouteBuilder>([this](dp::GLState const & state, drape_ptr<dp::RenderBucket> && bucket,
RouteData const & routeData, dp::GLState const & endOfRouteState,
drape_ptr<dp::RenderBucket> && endOfRouteBucket)
m_routeBuilder = make_unique_dp<RouteBuilder>([this](drape_ptr<RouteData> && routeData)
{
m_commutator->PostMessage(ThreadsCommutator::RenderThread,
make_unique_dp<FlushRouteMessage>(state, move(bucket), routeData, endOfRouteState, move(endOfRouteBucket)),
make_unique_dp<FlushRouteMessage>(move(routeData)),
MessagePriority::Normal);
});

View file

@ -302,16 +302,8 @@ void FrontendRenderer::AcceptMessage(ref_ptr<Message> message)
case Message::FlushRoute:
{
ref_ptr<FlushRouteMessage> msg = message;
dp::GLState const & state = msg->GetState();
drape_ptr<dp::RenderBucket> bucket = msg->AcceptBuffer();
m_routeRenderer->AddRouteRenderBucket(state, move(bucket), msg->GetRouteData(), make_ref(m_gpuProgramManager));
dp::GLState const & eorState = msg->GetEndOfRouteState();
drape_ptr<dp::RenderBucket> eorBucket = msg->AcceptEndOfRouteBuffer();
if (eorBucket != nullptr)
{
m_routeRenderer->AddEndOfRouteRenderBucket(eorState, move(eorBucket), make_ref(m_gpuProgramManager));
}
drape_ptr<RouteData> routeData = msg->AcceptRouteData();
m_routeRenderer->SetRouteData(move(routeData), make_ref(m_gpuProgramManager));
m_myPositionController->ActivateRouting();
break;

View file

@ -533,31 +533,15 @@ private:
class FlushRouteMessage : public Message
{
public:
FlushRouteMessage(dp::GLState const & state, drape_ptr<dp::RenderBucket> && buffer,
RouteData const & routeData, dp::GLState const & endOfRouteState,
drape_ptr<dp::RenderBucket> && endOfRouteBuffer)
: m_state(state)
, m_buffer(move(buffer))
, m_routeData(routeData)
, m_endOfRouteState(endOfRouteState)
, m_endOfRouteBuffer(move(endOfRouteBuffer))
FlushRouteMessage(drape_ptr<RouteData> && routeData)
: m_routeData(move(routeData))
{}
Type GetType() const override { return Message::FlushRoute; }
dp::GLState const & GetState() const { return m_state; }
drape_ptr<dp::RenderBucket> && AcceptBuffer() { return move(m_buffer); }
RouteData const & GetRouteData() const { return m_routeData; }
dp::GLState const & GetEndOfRouteState() const { return m_endOfRouteState; }
drape_ptr<dp::RenderBucket> && AcceptEndOfRouteBuffer() { return move(m_endOfRouteBuffer); }
drape_ptr<RouteData> && AcceptRouteData() { return move(m_routeData); }
private:
dp::GLState m_state;
drape_ptr<dp::RenderBucket> m_buffer;
RouteData m_routeData;
dp::GLState m_endOfRouteState;
drape_ptr<dp::RenderBucket> m_endOfRouteBuffer;
drape_ptr<RouteData> m_routeData;
};
class UpdateMapStyleMessage : public Message

View file

@ -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<dp::Batcher>(ESTIMATE_BUFFER_SIZE, ESTIMATE_BUFFER_SIZE))
{}
void RouteBuilder::Build(m2::PolylineD const & routePolyline, vector<double> const & turns,
@ -18,29 +15,12 @@ void RouteBuilder::Build(m2::PolylineD const & routePolyline, vector<double> co
CommonViewParams params;
params.m_depth = 0.0f;
RouteShape shape(routePolyline, params);
m2::RectF textureRect = shape.GetArrowTextureRect(textures);
shape.PrepareGeometry(textures);
drape_ptr<RouteData> routeData = make_unique_dp<RouteData>();
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<dp::RenderBucket> eorBucket = shape.MoveEndOfRouteRenderBucket();
auto flushRoute = [this, &routeData, &eorState, &eorBucket](dp::GLState const & state,
drape_ptr<dp::RenderBucket> && 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

View file

@ -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<RouteJoinBounds> m_joinsBounds;
double m_length;
vector<double> m_turns;
};
class RouteBuilder
{
public:
using TFlushRouteFn = function<void(dp::GLState const &, drape_ptr<dp::RenderBucket> &&, RouteData const &,
dp::GLState const &, drape_ptr<dp::RenderBucket> &&)>;
using TFlushRouteFn = function<void(drape_ptr<RouteData> &&)>;
RouteBuilder(TFlushRouteFn const & flushRouteFn);
@ -38,7 +24,6 @@ public:
private:
TFlushRouteFn m_flushRouteFn;
drape_ptr<dp::Batcher> m_batcher;
};
} // namespace df

View file

@ -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<RouteSegment> const & segments)
{
for (size_t i = 0; i < segments.size(); i++)
@ -37,43 +54,52 @@ int CheckForIntersection(double start, double end, vector<RouteSegment> 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<RouteSegment> 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<int>(i);
}
return SegmentStatus::NoSegment;
}
return -1;
void ClipBorders(vector<ArrowBorders> & 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<ArrowBorders> & 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<ArrowBorders> & 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<dp::GpuProgramManager> mng)
{
for (drape_ptr<dp::RenderBucket> const & bucket : renderProperty.m_buckets)
bucket->GetBuffer()->Build(mng->GetProgram(renderProperty.m_state.GetProgramIndex()));
}
}
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)
{}
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<float>(kAlphaValue[index]) / numeric_limits<uint8_t>::max();
float const alpha2 = static_cast<float>(kAlphaValue[index + 1]) / numeric_limits<uint8_t>::max();
alpha = alpha1 + lerpCoef * (alpha2 - alpha1);
}
else
{
halfWidth = kHalfWidthInPixel[scales::UPPER_STYLE_SCALE];
alpha = static_cast<float>(kAlphaValue[scales::UPPER_STYLE_SCALE]) / numeric_limits<uint8_t>::max();
}
}
void RouteRenderer::Render(ScreenBase const & screen, ref_ptr<dp::GpuProgramManager> 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_ptr<dp::GpuProgramMana
dp::ApplyUniforms(uniformStorage, prg);
// render routes
for (RouteGraphics & graphics : m_routeGraphics)
{
ASSERT(graphics.m_state == state, ());
graphics.m_buffer->Render();
}
for (drape_ptr<dp::RenderBucket> 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<dp::GpuProgram> 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<dp::GpuProgram> prg = mng->GetProgram(gpu::ROUTE_ARROW_PROGRAM);
prg->Bind();
dp::ApplyState(state, prg);
dp::ApplyUniforms(uniforms, prg);
for (drape_ptr<ArrowRenderProperty> & 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<dp::GpuProgram> eorProgram = mng->GetProgram(m_endOfRouteState.GetProgramIndex());
eorProgram->Bind();
dp::ApplyState(m_endOfRouteState, eorProgram);
dp::ApplyUniforms(uniforms, eorProgram);
m_endOfRouteBuffer->Render();
ref_ptr<dp::GpuProgram> program = mng->GetProgram(state.GetProgramIndex());
program->Bind();
dp::ApplyState(m_routeData->m_endOfRouteSign.m_state, program);
dp::ApplyUniforms(uniforms, program);
for (drape_ptr<dp::RenderBucket> const & bucket : m_routeData->m_endOfRouteSign.m_buckets)
bucket->Render(screen);
}
}
void RouteRenderer::RenderArrow(ref_ptr<dp::GpuProgram> prg, RouteGraphics const & graphics,
void RouteRenderer::RenderArrow(ref_ptr<dp::GpuProgram> prg, drape_ptr<ArrowRenderProperty> 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<float, 16> borders;
@ -227,39 +266,30 @@ void RouteRenderer::RenderArrow(ref_ptr<dp::GpuProgram> prg, RouteGraphics const
borders.fill(0.0f);
dp::ApplyUniforms(uniformStorage, prg);
graphics.m_buffer->Render();
for (drape_ptr<dp::RenderBucket> const & bucket : property->m_arrow.m_buckets)
bucket->Render(screen);
}
}
}
void RouteRenderer::AddRouteRenderBucket(dp::GLState const & state, drape_ptr<dp::RenderBucket> && bucket,
RouteData const & routeData, ref_ptr<dp::GpuProgramManager> mng)
void RouteRenderer::SetRouteData(drape_ptr<RouteData> && routeData, ref_ptr<dp::GpuProgramManager> 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<ArrowRenderProperty> 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<dp::RenderBucket> && bucket,
ref_ptr<dp::GpuProgramManager> 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<ArrowRenderProperty> const & property, double joinsBoundsScalar,
double glbHeadLength, vector<ArrowBorders> & 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<ArrowRenderProperty> 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);

View file

@ -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<dp::VertexArrayBuffer> && buffer,
dp::Color const & color);
dp::GLState m_state;
drape_ptr<dp::VertexArrayBuffer> m_buffer;
dp::Color m_color;
};
struct ArrowBorders
{
double m_startDistance = 0;
@ -55,29 +40,23 @@ public:
void Render(ScreenBase const & screen, ref_ptr<dp::GpuProgramManager> mng,
dp::UniformValuesStorage const & commonUniforms);
void AddRouteRenderBucket(dp::GLState const & state, drape_ptr<dp::RenderBucket> && bucket,
RouteData const & routeData, ref_ptr<dp::GpuProgramManager> mng);
void AddEndOfRouteRenderBucket(dp::GLState const & state, drape_ptr<dp::RenderBucket> && bucket,
ref_ptr<dp::GpuProgramManager> mng);
void SetRouteData(drape_ptr<RouteData> && routeData, ref_ptr<dp::GpuProgramManager> mng);
void Clear();
void UpdateDistanceFromBegin(double distanceFromBegin);
private:
void CalculateArrowBorders(double arrowLength, double scale, double arrowTextureWidth, double joinsBoundsScalar);
void CalculateArrowBorders(drape_ptr<ArrowRenderProperty> const & property, double arrowLength,
double scale, double arrowTextureWidth, double joinsBoundsScalar);
void ApplyJoinsBounds(drape_ptr<ArrowRenderProperty> const & property, double joinsBoundsScalar,
double glbHeadLength, vector<ArrowBorders> & arrowBorders);
void RenderArrow(ref_ptr<dp::GpuProgram> prg, drape_ptr<ArrowRenderProperty> 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<dp::GpuProgram> prg, RouteGraphics const & graphics, float halfWidth, ScreenBase const & screen);
vector<RouteGraphics> m_routeGraphics;
double m_distanceFromBegin;
RouteData m_routeData;
dp::GLState m_endOfRouteState;
drape_ptr<dp::VertexArrayBuffer> m_endOfRouteBuffer;
drape_ptr<RouteData> m_routeData;
vector<ArrowBorders> m_arrowBorders;
vector<RouteSegment> m_routeSegments;

View file

@ -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<dp::TextureManager> 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<dp::TextureManager> textures, dp::TextureManager::SymbolRegion & region)
{
textures->GetSymbolRegion("route-arrow", region);
}
void ClipArrowToSegments(vector<double> const & turns, RouteData & routeData)
{
int const cnt = static_cast<int>(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> arrowRenderProperty = make_unique_dp<ArrowRenderProperty>();
// 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<dp::TextureManager> textures) const
vector<m2::PointD> CalculatePoints(m2::PolylineD const & polyline, double start, double end)
{
dp::TextureManager::SymbolRegion region;
GetArrowTextureRegion(textures, region);
return region.GetTexRect();
vector<m2::PointD> result;
result.reserve(polyline.GetSize() / 4);
auto addIfNotExist = [&result](m2::PointD const & pnt)
{
if (result.empty() || result.back() != pnt)
result.push_back(pnt);
};
vector<m2::PointD> 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<dp::TextureManager> textures)
}
RouteShape::RouteShape(m2::PolylineD const & polyline, vector<double> const & turns,
CommonViewParams const & params)
: m_params(params)
, m_polyline(polyline)
, m_turns(turns)
{}
void RouteShape::PrepareGeometry(bool isRoute, vector<m2::PointD> const & path,
TGeometryBuffer & geometry, TGeometryBuffer & joinsGeometry,
vector<RouteJoinBounds> & joinsBounds, double & outputLength)
{
vector<m2::PointD> const & path = m_polyline.GetPoints();
ASSERT(path.size() > 1, ());
auto const generateTriangles = [&](glsl::vec3 const & pivot, vector<glsl::vec2> const & normals,
glsl::vec2 const & length, bool isLeft)
auto const generateTriangles = [&joinsGeometry](glsl::vec3 const & pivot, vector<glsl::vec2> 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<dp::TextureManager> 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<dp::TextureManager> textures)
}
// generate caps
if (i == 0)
if (isRoute && i == 0)
{
vector<glsl::vec2> normals;
normals.reserve(24);
@ -133,7 +242,7 @@ void RouteShape::PrepareGeometry(ref_ptr<dp::TextureManager> textures)
glsl::vec2(length, 0), true);
}
if (i == segments.size() - 1)
if (isRoute && i == segments.size() - 1)
{
vector<glsl::vec2> normals;
normals.reserve(24);
@ -148,32 +257,33 @@ void RouteShape::PrepareGeometry(ref_ptr<dp::TextureManager> 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<dp::TextureManager> mng)
void RouteShape::CacheEndOfRouteSign(ref_ptr<dp::TextureManager> mng, RouteData & routeData)
{
dp::TextureManager::SymbolRegion symbol;
mng->GetSymbolRegion("route_to", symbol);
@ -196,39 +306,82 @@ void RouteShape::CacheEndOfRouteSign(ref_ptr<dp::TextureManager> mng)
{
dp::Batcher batcher(dp::Batcher::IndexPerQuad, dp::Batcher::VertexPerQuad);
dp::SessionGuard guard(batcher, [this](dp::GLState const & state, drape_ptr<dp::RenderBucket> && b)
dp::SessionGuard guard(batcher, [&routeData](dp::GLState const & state, drape_ptr<dp::RenderBucket> && 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<dp::Batcher> batcher, ref_ptr<dp::TextureManager> textures)
void RouteShape::Draw(ref_ptr<dp::TextureManager> 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<RouteJoinBounds> 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<m2::PointD> 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<dp::RenderBucket> && 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));
}
}
}

View file

@ -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<drape_ptr<dp::RenderBucket>> m_buckets;
RouteRenderProperty() : m_state(0, dp::GLState::GeometryLayer) {}
};
struct ArrowRenderProperty
{
vector<RouteJoinBounds> m_joinsBounds;
vector<double> 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<drape_ptr<ArrowRenderProperty>> m_arrows;
RouteRenderProperty m_endOfRouteSign;
};
class RouteShape
{
public:
RouteShape(m2::PolylineD const & polyline,
RouteShape(m2::PolylineD const & polyline, vector<double> const & turns,
CommonViewParams const & params);
m2::RectF GetArrowTextureRect(ref_ptr<dp::TextureManager> textures) const;
vector<RouteJoinBounds> const & GetJoinsBounds() const { return m_joinsBounds; }
double GetLength() const { return m_length; }
dp::GLState const & GetEndOfRouteState() const { return m_endOfRouteState; }
drape_ptr<dp::RenderBucket> && MoveEndOfRouteRenderBucket() { return move(m_endOfRouteRenderBucket); }
void PrepareGeometry(ref_ptr<dp::TextureManager> textures);
void Draw(ref_ptr<dp::Batcher> batcher, ref_ptr<dp::TextureManager> textures);
void Draw(ref_ptr<dp::TextureManager> textures, RouteData & routeData);
private:
using RV = gpu::RouteVertex;
using TGeometryBuffer = buffer_vector<gpu::RouteVertex, 128>;
void CacheEndOfRouteSign(ref_ptr<dp::TextureManager> mng);
TGeometryBuffer m_geometry;
TGeometryBuffer m_joinsGeometry;
vector<RouteJoinBounds> m_joinsBounds;
double m_length;
void CacheEndOfRouteSign(ref_ptr<dp::TextureManager> mng, RouteData & routeData);
void PrepareGeometry(bool isRoute, vector<m2::PointD> const & path,
TGeometryBuffer & geometry, TGeometryBuffer & joinsGeometry,
vector<RouteJoinBounds> & 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<dp::RenderBucket> m_endOfRouteRenderBucket;
vector<double> m_turns;
};
} // namespace df

View file

@ -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)