forked from organicmaps/organicmaps
Improvements of arrows rendering
This commit is contained in:
parent
58d2b29b91
commit
e04123350d
10 changed files with 267 additions and 103 deletions
|
@ -36,10 +36,10 @@ BackendRenderer::BackendRenderer(Params const & params)
|
|||
});
|
||||
|
||||
m_routeBuilder = make_unique_dp<RouteBuilder>([this](dp::GLState const & state, drape_ptr<dp::RenderBucket> && bucket,
|
||||
dp::Color const & color, m2::RectF const & arrowTextureRect)
|
||||
RouteData const & routeData)
|
||||
{
|
||||
m_commutator->PostMessage(ThreadsCommutator::RenderThread,
|
||||
make_unique_dp<FlushRouteMessage>(state, move(bucket), color, arrowTextureRect),
|
||||
make_unique_dp<FlushRouteMessage>(state, move(bucket), routeData),
|
||||
MessagePriority::Normal);
|
||||
});
|
||||
|
||||
|
|
|
@ -280,8 +280,7 @@ void FrontendRenderer::AcceptMessage(ref_ptr<Message> message)
|
|||
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->GetColor(), msg->GetArrowTextureRect(),
|
||||
make_ref(m_gpuProgramManager));
|
||||
m_routeRenderer->AddRouteRenderBucket(state, move(bucket), msg->GetRouteData(), make_ref(m_gpuProgramManager));
|
||||
m_myPositionController->ActivateRouting();
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -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<dp::RenderBucket> && 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<dp::RenderBucket> && 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<dp::RenderBucket> m_buffer;
|
||||
dp::Color m_color;
|
||||
m2::RectF m_arrowTextureRect;
|
||||
RouteData m_routeData;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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<dp::RenderBucket> && 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<dp::RenderBucket> && bucket)
|
||||
{
|
||||
if (m_flushRouteFn != nullptr)
|
||||
m_flushRouteFn(state, move(bucket), color, textureRect);
|
||||
m_flushRouteFn(state, move(bucket), routeData);
|
||||
};
|
||||
|
||||
m_batcher->StartSession(flushRoute);
|
||||
|
|
|
@ -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<RouteJoinBounds> m_joinsBounds;
|
||||
double m_length;
|
||||
};
|
||||
|
||||
class RouteBuilder
|
||||
{
|
||||
public:
|
||||
using TFlushRouteFn = function<void(dp::GLState const &, drape_ptr<dp::RenderBucket> &&,
|
||||
dp::Color const &, m2::RectF const &)>;
|
||||
using TFlushRouteFn = function<void(dp::GLState const &, drape_ptr<dp::RenderBucket> &&, RouteData const &)>;
|
||||
|
||||
RouteBuilder(TFlushRouteFn const & flushRouteFn);
|
||||
|
||||
|
|
|
@ -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<RouteSegment> 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_ptr<dp::GpuProgramMana
|
|||
|
||||
graphics.m_buffer->Render();
|
||||
|
||||
// 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> arrowBorders;
|
||||
CalculateArrowBorders(0.001, screen.GetScale(), textureWidth, arrowBorders);
|
||||
CalculateArrowBorders(0.001, screen.GetScale(), textureWidth, arrowHalfWidth * screen.GetScale(), arrowBorders);
|
||||
|
||||
ref_ptr<dp::GpuProgram> 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<float> borders(elementsCount, 0.0);
|
||||
|
@ -111,10 +165,6 @@ void RouteRenderer::Render(ScreenBase const & screen, ref_ptr<dp::GpuProgramMana
|
|||
index = 0;
|
||||
uniformStorage.SetMatrix4x4Value("u_arrowBorders", borders.data());
|
||||
|
||||
ref_ptr<dp::GpuProgram> 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<dp::GpuProgramMana
|
|||
}
|
||||
|
||||
void RouteRenderer::AddRouteRenderBucket(dp::GLState const & state, drape_ptr<dp::RenderBucket> && bucket,
|
||||
dp::Color const & color, m2::RectF const & arrowTextureRect,
|
||||
ref_ptr<dp::GpuProgramManager> mng)
|
||||
RouteData const & routeData, ref_ptr<dp::GpuProgramManager> 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<ArrowBorders> & borders)
|
||||
void RouteRenderer::MergeAndClipBorders(vector<ArrowBorders> & 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<ArrowBorders> & borders)
|
||||
{
|
||||
vector<RouteSegment> 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<ArrowBorders> & 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);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<dp::RenderBucket> && bucket,
|
||||
dp::Color const & color, m2::RectF const & arrowTextureRect,
|
||||
ref_ptr<dp::GpuProgramManager> mng);
|
||||
RouteData const & routeData, ref_ptr<dp::GpuProgramManager> mng);
|
||||
|
||||
void Clear();
|
||||
|
||||
void UpdateDistanceFromBegin(double distanceFromBegin);
|
||||
|
||||
private:
|
||||
void CalculateArrowBorders(double arrowLength, double scale,
|
||||
float arrowTextureWidth, vector<ArrowBorders> & borders);
|
||||
void CalculateArrowBorders(double arrowLength, double scale, double arrowTextureWidth,
|
||||
double joinsBoundsScalar, vector<ArrowBorders> & borders);
|
||||
void MergeAndClipBorders(vector<ArrowBorders> & borders, double scale, double arrowTextureWidth);
|
||||
|
||||
void ApplyJoinsBounds(double arrowTextureWidth, double joinsBoundsScalar, double glbTailLength,
|
||||
double glbHeadLength, double scale, vector<ArrowBorders> & borders);
|
||||
|
||||
vector<RouteGraphics> m_routeGraphics;
|
||||
double m_distanceFromBegin;
|
||||
m2::RectF m_arrowTextureRect;
|
||||
RouteData m_routeData;
|
||||
vector<double> m_turnPoints;
|
||||
};
|
||||
|
||||
|
|
|
@ -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<gpu::RouteVertex, 128>;
|
||||
|
||||
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<dp::TextureManager> textures) const
|
||||
|
@ -43,20 +40,15 @@ m2::RectF RouteShape::GetArrowTextureRect(ref_ptr<dp::TextureManager> textures)
|
|||
return region.GetTexRect();
|
||||
}
|
||||
|
||||
void RouteShape::Draw(ref_ptr<dp::Batcher> batcher, ref_ptr<dp::TextureManager> textures) const
|
||||
void RouteShape::PrepareGeometry()
|
||||
{
|
||||
TGeometryBuffer geometry;
|
||||
TGeometryBuffer joinsGeometry;
|
||||
vector<m2::PointD> const & path = m_polyline.GetPoints();
|
||||
ASSERT(path.size() > 1, ());
|
||||
|
||||
dp::TextureManager::SymbolRegion region;
|
||||
GetArrowTextureRegion(textures, region);
|
||||
|
||||
auto const generateTriangles = [&](glsl::vec3 const & pivot, vector<glsl::vec2> 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<dp::Batcher> batcher, ref_ptr<dp::TextureManager>
|
|||
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<dp::Batcher> batcher, ref_ptr<dp::TextureManager>
|
|||
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<dp::Batcher> batcher, ref_ptr<dp::TextureManager>
|
|||
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<dp::Batcher> batcher, ref_ptr<dp::TextureManager> 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
|
||||
|
|
|
@ -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<dp::TextureManager> textures) const;
|
||||
vector<RouteJoinBounds> const & GetJoinsBounds() const { return m_joinsBounds; }
|
||||
double GetLength() const { return m_length; }
|
||||
|
||||
void Draw(ref_ptr<dp::Batcher> batcher, ref_ptr<dp::TextureManager> textures) const;
|
||||
void PrepareGeometry();
|
||||
void Draw(ref_ptr<dp::Batcher> batcher, ref_ptr<dp::TextureManager> textures);
|
||||
|
||||
private:
|
||||
using RV = gpu::RouteVertex;
|
||||
using TGeometryBuffer = buffer_vector<gpu::RouteVertex, 128>;
|
||||
|
||||
TGeometryBuffer m_geometry;
|
||||
TGeometryBuffer m_joinsGeometry;
|
||||
vector<RouteJoinBounds> m_joinsBounds;
|
||||
double m_length;
|
||||
|
||||
CommonViewParams m_params;
|
||||
m2::PolylineD m_polyline;
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue