Added base functionality of gps tracks rendering

This commit is contained in:
r.kuznetsov 2015-11-27 19:02:19 +03:00 committed by Constantin Shalnev
parent 398cd5444f
commit 5a1d3f6a5d
22 changed files with 861 additions and 35 deletions

View file

@ -16,6 +16,7 @@ BUTTON_PROGRAM button_vertex_shader.vsh button_fragment_shader.fsh
BOOKMARK_PROGRAM user_mark.vsh texturing_fragment_shader.fsh
ROUTE_PROGRAM route_vertex_shader.vsh route_fragment_shader.fsh
ROUTE_ARROW_PROGRAM route_vertex_shader.vsh route_arrow_fragment_shader.fsh
TRACK_POINT_PROGRAM trackpoint_vertex_shader.vsh trackpoint_fragment_shader.fsh
DEBUG_RECT_PROGRAM debug_rect_vertex_shader.vsh debug_rect_fragment_shader.fsh
TRANSPARENT_LAYER_PROGRAM transparent_layer_vertex_shader.vsh transparent_layer_fragment_shader.fsh
ARROW_3D_PROGRAM arrow3d_vertex_shader.vsh arrow3d_fragment_shader.fsh

View file

@ -0,0 +1,22 @@
uniform float u_opacity;
uniform float u_radiusShift;
varying vec3 v_radius;
varying vec4 v_color;
const float kAntialiasingScalar = 0.9;
const vec4 kOutlineColor = vec4(1.0, 1.0, 1.0, 1.0);
void main(void)
{
float d = dot(v_radius.xy, v_radius.xy);
float shiftedRadius = v_radius.z - u_radiusShift;
float aaRadius = shiftedRadius * kAntialiasingScalar;
vec4 finalColor = mix(v_color, kOutlineColor, smoothstep(aaRadius * aaRadius, shiftedRadius * shiftedRadius, d));
aaRadius = v_radius.z * kAntialiasingScalar;
float stepValue = smoothstep(aaRadius * aaRadius, v_radius.z * v_radius.z, d);
finalColor.a = finalColor.a * u_opacity * (1.0 - stepValue);
gl_FragColor = finalColor;
}

View file

@ -0,0 +1,21 @@
attribute vec3 a_normal;
attribute vec3 a_position;
attribute vec4 a_color;
uniform mat4 modelView;
uniform mat4 projection;
varying vec3 v_radius;
varying vec4 v_color;
void main(void)
{
vec3 radius = a_normal * a_position.z;
// Here we intentionally decrease precision of 'pos' calculation
// to eliminate jittering effect in process of billboard reconstruction.
lowp vec4 pos = vec4(a_position.xy, 0, 1) * modelView;
highp vec4 shiftedPos = vec4(radius.xy, 0, 0) + pos;
gl_Position = shiftedPos * projection;
v_radius = radius;
v_color = a_color;
}

View file

@ -2,6 +2,7 @@
#include "drape_frontend/backend_renderer.hpp"
#include "drape_frontend/batchers_pool.hpp"
#include "drape_frontend/gps_track_shape.hpp"
#include "drape_frontend/map_shape.hpp"
#include "drape_frontend/message_subclasses.hpp"
#include "drape_frontend/read_manager.hpp"
@ -233,6 +234,17 @@ void BackendRenderer::AcceptMessage(ref_ptr<Message> message)
RecacheMyPosition();
break;
}
case Message::CacheGpsTrackPoints:
{
ref_ptr<CacheGpsTrackPointsMessage> msg = message;
drape_ptr<GpsTrackRenderData> data = make_unique_dp<GpsTrackRenderData>();
data->m_pointsCount = msg->GetPointsCount();
GpsTrackShape::Draw(*data.get());
m_commutator->PostMessage(ThreadsCommutator::RenderThread,
make_unique_dp<FlushGpsTrackPointsMessage>(move(data)),
MessagePriority::Normal);
break;
}
case Message::StopRendering:
{
ProcessStopRenderingMessage();

View file

@ -449,4 +449,18 @@ void DrapeEngine::EnablePerspective(double rotationAngle, double angleFOV)
MessagePriority::Normal);
}
void DrapeEngine::UpdateGpsTrackPoints(vector<df::GpsTrackPoint> && toAdd, vector<uint32_t> && toRemove)
{
m_threadCommutator->PostMessage(ThreadsCommutator::RenderThread,
make_unique_dp<UpdateGpsTrackPointsMessage>(move(toAdd), move(toRemove)),
MessagePriority::Normal);
}
void DrapeEngine::ClearGpsTrackPoints()
{
m_threadCommutator->PostMessage(ThreadsCommutator::RenderThread,
make_unique_dp<ClearGpsTrackPointsMessage>(),
MessagePriority::Normal);
}
} // namespace df

View file

@ -120,6 +120,9 @@ public:
void Allow3dMode(bool allowPerspectiveInNavigation, bool allow3dBuildings, double rotationAngle, double angleFOV);
void EnablePerspective(double rotationAngle, double angleFOV);
void UpdateGpsTrackPoints(vector<df::GpsTrackPoint> && toAdd, vector<uint32_t> && toRemove);
void ClearGpsTrackPoints();
private:
void AddUserEvent(UserEvent const & e);
void ModelViewChanged(ScreenBase const & screen);

View file

@ -42,6 +42,8 @@ SOURCES += \
engine_context.cpp \
framebuffer.cpp \
frontend_renderer.cpp \
gps_track_renderer.cpp \
gps_track_shape.cpp \
line_shape.cpp \
line_shape_helper.cpp \
map_data_provider.cpp \
@ -126,6 +128,9 @@ HEADERS += \
engine_context.hpp \
framebuffer.hpp \
frontend_renderer.hpp \
gps_track_point.hpp \
gps_track_renderer.hpp \
gps_track_shape.hpp \
intrusive_vector.hpp \
line_shape.hpp \
line_shape_helper.hpp \

View file

@ -47,6 +47,7 @@ FrontendRenderer::FrontendRenderer(Params const & params)
, m_routeRenderer(new RouteRenderer())
, m_framebuffer(new Framebuffer())
, m_transparentLayer(new TransparentLayer())
, m_gpsTrackRenderer(new GpsTrackRenderer(bind(&FrontendRenderer::PrepareGpsTrackPoints, this, _1)))
, m_overlayTree(new dp::OverlayTree())
, m_enablePerspectiveInNavigation(false)
, m_enable3dBuildings(params.m_allow3dBuildings)
@ -523,6 +524,26 @@ void FrontendRenderer::AcceptMessage(ref_ptr<Message> message)
break;
}
case Message::FlushGpsTrackPoints:
{
ref_ptr<FlushGpsTrackPointsMessage> msg = message;
m_gpsTrackRenderer->AddRenderData(make_ref(m_gpuProgramManager), msg->AcceptRenderData());
break;
}
case Message::UpdateGpsTrackPoints:
{
ref_ptr<UpdateGpsTrackPointsMessage> msg = message;
m_gpsTrackRenderer->UpdatePoints(msg->GetPointsToAdd(), msg->GetPointsToRemove());
break;
}
case Message::ClearGpsTrackPoints:
{
m_gpsTrackRenderer->Clear();
break;
}
case Message::Invalidate:
{
// Do nothing here, new frame will be rendered because of this message processing.
@ -718,6 +739,13 @@ FeatureID FrontendRenderer::GetVisiblePOI(m2::RectD const & pixelRect) const
return featureID;
}
void FrontendRenderer::PrepareGpsTrackPoints(size_t pointsCount)
{
m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread,
make_unique_dp<CacheGpsTrackPointsMessage>(pointsCount),
MessagePriority::Normal);
}
void FrontendRenderer::BeginUpdateOverlayTree(ScreenBase const & modelView)
{
if (m_overlayTree->Frame(modelView.isPerspective()))
@ -881,6 +909,9 @@ void FrontendRenderer::RenderScene(ScreenBase const & modelView)
RenderSingleGroup(modelView, make_ref(group));
}
m_gpsTrackRenderer->RenderTrack(modelView, GetCurrentZoomLevel(),
make_ref(m_gpuProgramManager), m_generalUniforms);
GLFunctions::glDisable(gl_const::GLDepthTest);
if (m_selectionShape != nullptr && m_selectionShape->GetSelectedObject() == SelectionShape::OBJECT_USER_MARK)
m_selectionShape->Render(modelView, make_ref(m_gpuProgramManager), m_generalUniforms);
@ -1420,7 +1451,8 @@ void FrontendRenderer::UpdateScene(ScreenBase const & modelView)
TTilesCollection tiles;
ResolveTileKeys(modelView, tiles);
m_overlayTree->ForceUpdate();
m_gpsTrackRenderer->Update();
auto removePredicate = [this](drape_ptr<RenderGroup> const & group)
{
return group->IsOverlay() && group->GetTileKey().m_styleZoomLevel > GetCurrentZoomLevel();

View file

@ -12,6 +12,7 @@
#include "drape_frontend/backend_renderer.hpp"
#include "drape_frontend/base_renderer.hpp"
#include "drape_frontend/gps_track_renderer.hpp"
#include "drape_frontend/my_position_controller.hpp"
#include "drape_frontend/navigator.hpp"
#include "drape_frontend/render_group.hpp"
@ -222,6 +223,8 @@ private:
bool IsPerspective() const;
void PrepareGpsTrackPoints(size_t pointsCount);
private:
drape_ptr<dp::GpuProgramManager> m_gpuProgramManager;
@ -236,6 +239,7 @@ private:
drape_ptr<RouteRenderer> m_routeRenderer;
drape_ptr<Framebuffer> m_framebuffer;
drape_ptr<TransparentLayer> m_transparentLayer;
drape_ptr<GpsTrackRenderer> m_gpsTrackRenderer;
drape_ptr<dp::OverlayTree> m_overlayTree;

View file

@ -0,0 +1,23 @@
#pragma once
#include "geometry/point2d.hpp"
namespace df
{
struct GpsTrackPoint
{
// Timestamp of the point, seconds from 1st Jan 1970
double m_timestamp;
// Point in the Mercator projection
m2::PointD m_point;
// Speed in the point, M/S
double m_speedMPS;
// Unique identifier of the point
uint32_t m_id;
};
} // namespace df

View file

@ -0,0 +1,329 @@
#include "drape_frontend/gps_track_renderer.hpp"
#include "drape_frontend/visual_params.hpp"
#include "drape/glsl_func.hpp"
#include "drape/shader_def.hpp"
#include "drape/vertex_array_buffer.hpp"
#include "indexer/scales.hpp"
#include "base/logging.hpp"
#include "std/algorithm.hpp"
namespace df
{
namespace
{
int const kMinVisibleZoomLevel = 15;
size_t const kAveragePointsCount = 512;
// Radius of circles depending on zoom levels.
float const kRadiusInPixel[] =
{
// 1 2 3 4 5 6 7 8 9 10
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
//11 12 13 14 15 16 17 18 19 20
1.0f, 1.0f, 1.0f, 1.5f, 3.0f, 4.0f, 5.0f, 5.0f, 5.0f, 6.0f
};
double const kMinSpeed = 1.0; // meters per second
double const kAvgSpeed = 2.0; // meters per second
double const kMaxSpeed = 5.0; // meters per second
dp::Color const kMinSpeedColor = dp::Color(255, 0, 0, 255);
dp::Color const kAvgSpeedColor = dp::Color(251, 192, 45, 255);
dp::Color const kMaxSpeedColor = dp::Color(44, 120, 47, 255);
uint8_t const kMinAlpha = 50;
uint8_t const kMaxAlpha = 255;
float const kOutlineRadiusScalar = 0.3f;
bool GpsPointsSortPredicate(GpsTrackPoint const & pt1, GpsTrackPoint const & pt2)
{
return pt1.m_id < pt2.m_id;
}
dp::Color InterpolateColors(dp::Color const & color1, dp::Color const & color2, double t)
{
double const r = color1.GetRed() * (1.0 - t) + color2.GetRed() * t;
double const g = color1.GetGreen() * (1.0 - t) + color2.GetGreen() * t;
double const b = color1.GetBlue() * (1.0 - t) + color2.GetBlue() * t;
double const a = color1.GetAlfa() * (1.0 - t) + color2.GetAlfa() * t;
return dp::Color(r, g, b, a);
}
} // namespace
GpsTrackRenderer::GpsTrackRenderer(TRenderDataRequestFn const & dataRequestFn)
: m_dataRequestFn(dataRequestFn)
, m_needUpdate(false)
, m_waitForRenderData(false)
, m_startSpeed(0.0)
, m_endSpeed(0.0)
, m_startColor(kMaxSpeedColor)
, m_radius(0.0f)
{
ASSERT(m_dataRequestFn != nullptr, ());
m_points.reserve(kAveragePointsCount);
m_handlesCache.reserve(8);
}
float GpsTrackRenderer::CalculateRadius(ScreenBase const & screen) const
{
double const kLog2 = log(2.0);
double const zoomLevel = my::clamp(fabs(log(screen.GetScale()) / kLog2), 1.0, scales::UPPER_STYLE_SCALE + 1.0);
double zoom = trunc(zoomLevel);
int const index = zoom - 1.0;
float const lerpCoef = zoomLevel - zoom;
float radius = 0.0f;
if (index < scales::UPPER_STYLE_SCALE)
radius = kRadiusInPixel[index] + lerpCoef * (kRadiusInPixel[index + 1] - kRadiusInPixel[index]);
else
radius = kRadiusInPixel[scales::UPPER_STYLE_SCALE];
return radius * VisualParams::Instance().GetVisualScale();
}
void GpsTrackRenderer::AddRenderData(ref_ptr<dp::GpuProgramManager> mng,
drape_ptr<GpsTrackRenderData> && renderData)
{
drape_ptr<GpsTrackRenderData> data = move(renderData);
ref_ptr<dp::GpuProgram> program = mng->GetProgram(gpu::TRACK_POINT_PROGRAM);
program->Bind();
data->m_bucket->GetBuffer()->Build(program);
m_renderData.push_back(move(data));
}
void GpsTrackRenderer::UpdatePoints(vector<GpsTrackPoint> const & toAdd, vector<uint32_t> const & toRemove)
{
if (!toRemove.empty())
{
auto removePredicate = [&toRemove](GpsTrackPoint const & pt)
{
return find(toRemove.begin(), toRemove.end(), pt.m_id) != toRemove.end();
};
m_points.erase(remove_if(m_points.begin(), m_points.end(), removePredicate), m_points.end());
}
if (!toAdd.empty())
{
ASSERT(is_sorted(toAdd.begin(), toAdd.end(), GpsPointsSortPredicate), ());
if (!m_points.empty())
ASSERT(GpsPointsSortPredicate(m_points.back(), toAdd.front()), ());
m_points.insert(m_points.end(), toAdd.begin(), toAdd.end());
}
m_needUpdate = true;
}
double GpsTrackRenderer::CalculateTrackLength() const
{
double len = 0.0;
for (size_t i = 0; i + 1 < m_points.size(); i++)
len += (m_points[i + 1].m_point - m_points[i].m_point).Length();
return len;
}
void GpsTrackRenderer::UpdateSpeedsAndColors()
{
m_startSpeed = 0.0;
m_endSpeed = 0.0;
for (size_t i = 0; i < m_points.size(); i++)
{
if (m_points[i].m_speedMPS < m_startSpeed)
m_startSpeed = m_points[i].m_speedMPS;
if (m_points[i].m_speedMPS > m_endSpeed)
m_endSpeed = m_points[i].m_speedMPS;
}
double const delta = m_endSpeed - m_startSpeed;
if (delta <= kMinSpeed)
m_startColor = kMaxSpeedColor;
else if (delta <= kAvgSpeed)
m_startColor = kAvgSpeedColor;
else
m_startColor = kMinSpeedColor;
m_startSpeed = max(m_startSpeed, kMinSpeed);
m_endSpeed = min(m_endSpeed, kMaxSpeed);
double const kBias = 0.01;
if (fabs(m_endSpeed - m_startSpeed) < 1e-5)
m_endSpeed += kBias;
}
size_t GpsTrackRenderer::GetAvailablePointsCount() const
{
size_t pointsCount = 0;
for (size_t i = 0; i < m_renderData.size(); i++)
pointsCount += m_renderData[i]->m_pointsCount;
return pointsCount;
}
double GpsTrackRenderer::PlacePoints(size_t & cacheIndex,
GpsTrackPoint const & start, GpsTrackPoint const & end,
float radius, double diameterMercator,
double offset, double trackLengthMercator,
bool & gap, double & lengthFromStart)
{
if (start.m_point.EqualDxDy(end.m_point, 1e-5))
return offset;
double const kDistanceScalar = 0.65;
m2::PointD const delta = end.m_point - start.m_point;
double const length = delta.Length();
m2::PointD const dir = delta.Normalize();
double pos = offset;
while (pos < length)
{
if (gap)
{
double const dist = pos + diameterMercator * 0.5;
double const td = my::clamp(dist / length, 0.0, 1.0);
double const speed = start.m_speedMPS * (1.0 - td) + end.m_speedMPS * td;
double const ts = my::clamp((speed - m_startSpeed) / (m_endSpeed - m_startSpeed), 0.0, 1.0);
dp::Color color = InterpolateColors(m_startColor, kMaxSpeedColor, ts);
double const ta = my::clamp((lengthFromStart + dist) / trackLengthMercator, 0.0, 1.0);
double const alpha = kMinAlpha * (1.0 - ta) + kMaxAlpha * ta;
color = dp::Color(color.GetRed(), color.GetGreen(), color.GetBlue(), alpha);
m2::PointD const p = start.m_point + dir * dist;
m_handlesCache[cacheIndex].first->SetPoint(m_handlesCache[cacheIndex].second, p, radius, color);
m_handlesCache[cacheIndex].second++;
if (m_handlesCache[cacheIndex].second >= m_handlesCache[cacheIndex].first->GetPointsCount())
cacheIndex++;
ASSERT_LESS(cacheIndex, m_handlesCache.size(), ());
}
gap = !gap;
pos += (diameterMercator * kDistanceScalar);
}
lengthFromStart += length;
return pos - length;
}
void GpsTrackRenderer::RenderTrack(ScreenBase const & screen, int zoomLevel,
ref_ptr<dp::GpuProgramManager> mng,
dp::UniformValuesStorage const & commonUniforms)
{
if (zoomLevel < kMinVisibleZoomLevel)
return;
if (m_needUpdate)
{
// Skip rendering if there is no any point.
if (m_points.empty())
{
m_needUpdate = false;
return;
}
m_radius = CalculateRadius(screen);
float const diameter = 2.0f * m_radius;
float const currentScaleGtoP = 1.0f / screen.GetScale();
double const trackLengthMercator = CalculateTrackLength();
double const trackLengthPixels = trackLengthMercator * currentScaleGtoP;
size_t const pointsCount = static_cast<size_t>(trackLengthPixels / (2 * diameter));
if (pointsCount == 0)
{
m_needUpdate = false;
return;
}
// Check if we have enough points.
size_t const availablePointsCount = GetAvailablePointsCount();
if (pointsCount > availablePointsCount)
{
if (!m_waitForRenderData)
{
size_t const bucketSize = (pointsCount / kAveragePointsCount + 1) * kAveragePointsCount - availablePointsCount;
m_dataRequestFn(bucketSize);
}
m_waitForRenderData = true;
return;
}
else
{
m_waitForRenderData = false;
}
// Update points' positions and colors.
if (!m_waitForRenderData)
{
ASSERT(!m_renderData.empty(), ());
m_handlesCache.clear();
for (size_t i = 0; i < m_renderData.size(); i++)
{
ASSERT_EQUAL(m_renderData[i]->m_bucket->GetOverlayHandlesCount(), 1, ());
GpsTrackHandle * handle = static_cast<GpsTrackHandle*>(m_renderData[i]->m_bucket->GetOverlayHandle(0).get());
handle->Clear();
m_handlesCache.push_back(make_pair(handle, 0));
}
UpdateSpeedsAndColors();
size_t cacheIndex = 0;
double lengthFromStart = 0.0;
if (m_points.size() == 1)
{
m_handlesCache[cacheIndex].first->SetPoint(0, m_points.front().m_point, m_radius, kMaxSpeedColor);
m_handlesCache[cacheIndex].second++;
}
else
{
bool gap = true;
double const diameterMercator = diameter / currentScaleGtoP;
double offset = 0.0;
for (size_t i = 0; i + 1 < m_points.size(); i++)
offset = PlacePoints(cacheIndex, m_points[i], m_points[i + 1], m_radius,
diameterMercator, offset, trackLengthMercator,
gap, lengthFromStart);
}
m_needUpdate = false;
}
}
if (m_handlesCache.empty() || m_handlesCache.front().second == 0)
return;
GLFunctions::glClearDepth();
ASSERT_EQUAL(m_renderData.size(), m_handlesCache.size(), ());
// Render points.
dp::UniformValuesStorage uniforms = commonUniforms;
uniforms.SetFloatValue("u_opacity", 1.0f);
uniforms.SetFloatValue("u_radiusShift", m_radius * kOutlineRadiusScalar);
ref_ptr<dp::GpuProgram> program = mng->GetProgram(gpu::TRACK_POINT_PROGRAM);
program->Bind();
ASSERT_GREATER(m_renderData.size(), 0, ());
dp::ApplyState(m_renderData.front()->m_state, program);
dp::ApplyUniforms(uniforms, program);
for (size_t i = 0; i < m_renderData.size(); i++)
if (m_handlesCache[i].second != 0)
m_renderData[i]->m_bucket->Render(screen);
}
void GpsTrackRenderer::Update()
{
m_needUpdate = true;
}
void GpsTrackRenderer::Clear()
{
m_points.clear();
m_needUpdate = true;
}
} // namespace df

View file

@ -0,0 +1,64 @@
#pragma once
#include "drape_frontend/gps_track_point.hpp"
#include "drape_frontend/gps_track_shape.hpp"
#include "drape/gpu_program_manager.hpp"
#include "drape/pointers.hpp"
#include "drape/uniform_values_storage.hpp"
#include "map/gps_track_container.hpp"
#include "geometry/screenbase.hpp"
#include "geometry/spline.hpp"
#include "std/map.hpp"
#include "std/vector.hpp"
namespace df
{
class GpsTrackRenderer final
{
public:
using TRenderDataRequestFn = function<void(size_t)>;
explicit GpsTrackRenderer(TRenderDataRequestFn const & dataRequestFn);
void AddRenderData(ref_ptr<dp::GpuProgramManager> mng,
drape_ptr<GpsTrackRenderData> && renderData);
void UpdatePoints(vector<GpsTrackPoint> const & toAdd,
vector<uint32_t> const & toRemove);
void RenderTrack(ScreenBase const & screen, int zoomLevel,
ref_ptr<dp::GpuProgramManager> mng,
dp::UniformValuesStorage const & commonUniforms);
void Update();
void Clear();
private:
float CalculateRadius(ScreenBase const & screen) const;
double CalculateTrackLength() const;
void UpdateSpeedsAndColors();
size_t GetAvailablePointsCount() const;
double PlacePoints(size_t & cacheIndex,
GpsTrackPoint const & start, GpsTrackPoint const & end,
float radius, double diameterMercator,
double offset, double trackLengthMercator,
bool & gap, double & lengthFromStart);
TRenderDataRequestFn m_dataRequestFn;
vector<drape_ptr<GpsTrackRenderData>> m_renderData;
vector<GpsTrackPoint> m_points;
bool m_needUpdate;
bool m_waitForRenderData;
vector<pair<GpsTrackHandle*, size_t>> m_handlesCache;
double m_startSpeed;
double m_endSpeed;
dp::Color m_startColor;
float m_radius;
};
} // namespace df

View file

@ -0,0 +1,173 @@
#include "drape_frontend/gps_track_shape.hpp"
#include "drape/attribute_provider.hpp"
#include "drape/batcher.hpp"
#include "drape/glsl_func.hpp"
#include "drape/glsl_types.hpp"
#include "drape/shader_def.hpp"
#include "base/logging.hpp"
namespace df
{
namespace
{
uint32_t const kDynamicStreamID = 0x7F;
struct GpsTrackStaticVertex
{
using TNormal = glsl::vec3;
GpsTrackStaticVertex() = default;
GpsTrackStaticVertex(TNormal const & normal) : m_normal(normal) {}
TNormal m_normal;
};
dp::GLState GetGpsTrackState()
{
dp::GLState state(gpu::TRACK_POINT_PROGRAM, dp::GLState::OverlayLayer);
return state;
}
dp::BindingInfo const & GetGpsTrackStaticBindingInfo()
{
static unique_ptr<dp::BindingInfo> s_info;
if (s_info == nullptr)
{
dp::BindingFiller<GpsTrackStaticVertex> filler(1);
filler.FillDecl<GpsTrackStaticVertex::TNormal>("a_normal");
s_info.reset(new dp::BindingInfo(filler.m_info));
}
return *s_info;
}
dp::BindingInfo const & GetGpsTrackDynamicBindingInfo()
{
static unique_ptr<dp::BindingInfo> s_info;
if (s_info == nullptr)
{
dp::BindingFiller<GpsTrackDynamicVertex> filler(2, kDynamicStreamID);
filler.FillDecl<GpsTrackDynamicVertex::TPosition>("a_position");
filler.FillDecl<GpsTrackDynamicVertex::TColor>("a_color");
s_info.reset(new dp::BindingInfo(filler.m_info));
}
return *s_info;
}
} // namespace
GpsTrackHandle::GpsTrackHandle(size_t pointsCount)
: OverlayHandle(FeatureID(), dp::Anchor::Center, 0)
, m_needUpdate(false)
{
m_buffer.resize(pointsCount * dp::Batcher::VertexPerQuad);
}
void GpsTrackHandle::GetAttributeMutation(ref_ptr<dp::AttributeBufferMutator> mutator,
ScreenBase const & screen) const
{
UNUSED_VALUE(screen);
if (!m_needUpdate)
return;
TOffsetNode const & node = GetOffsetNode(kDynamicStreamID);
ASSERT(node.first.GetElementSize() == sizeof(GpsTrackDynamicVertex), ());
ASSERT(node.second.m_count == m_buffer.size(), ());
uint32_t const byteCount = m_buffer.size() * sizeof(GpsTrackDynamicVertex);
void * buffer = mutator->AllocateMutationBuffer(byteCount);
memcpy(buffer, m_buffer.data(), byteCount);
dp::MutateNode mutateNode;
mutateNode.m_region = node.second;
mutateNode.m_data = make_ref(buffer);
mutator->AddMutation(node.first, mutateNode);
}
bool GpsTrackHandle::Update(ScreenBase const & screen)
{
UNUSED_VALUE(screen);
return true;
}
bool GpsTrackHandle::IndexesRequired() const
{
return false;
}
m2::RectD GpsTrackHandle::GetPixelRect(ScreenBase const & screen) const
{
UNUSED_VALUE(screen);
return m2::RectD();
}
void GpsTrackHandle::GetPixelShape(ScreenBase const & screen, Rects & rects) const
{
UNUSED_VALUE(screen);
}
void GpsTrackHandle::SetPoint(size_t index, m2::PointD const & position,
float radius, dp::Color const & color)
{
size_t bufferIndex = index * dp::Batcher::VertexPerQuad;
ASSERT_GREATER_OR_EQUAL(bufferIndex, 0, ());
ASSERT_LESS(bufferIndex, m_buffer.size(), ());
for (size_t i = 0; i < dp::Batcher::VertexPerQuad; i++)
{
m_buffer[bufferIndex + i].m_position = glsl::vec3(position.x, position.y, radius);
m_buffer[bufferIndex + i].m_color = glsl::ToVec4(color);
}
m_needUpdate = true;
}
void GpsTrackHandle::Clear()
{
memset(m_buffer.data(), 0, m_buffer.size() * sizeof(GpsTrackDynamicVertex));
m_needUpdate = true;
}
size_t GpsTrackHandle::GetPointsCount() const
{
return m_buffer.size() / dp::Batcher::VertexPerQuad;
}
void GpsTrackShape::Draw(GpsTrackRenderData & data)
{
ASSERT_NOT_EQUAL(data.m_pointsCount, 0, ());
size_t const kVerticesInPoint = dp::Batcher::VertexPerQuad;
size_t const kIndicesInPoint = dp::Batcher::IndexPerQuad;
vector<GpsTrackStaticVertex> staticVertexData;
staticVertexData.reserve(data.m_pointsCount * kVerticesInPoint);
for (size_t i = 0; i < data.m_pointsCount; i++)
{
staticVertexData.push_back(GpsTrackStaticVertex(GpsTrackStaticVertex::TNormal(-1.0f, 1.0f, 1.0f)));
staticVertexData.push_back(GpsTrackStaticVertex(GpsTrackStaticVertex::TNormal(-1.0f, -1.0f, 1.0f)));
staticVertexData.push_back(GpsTrackStaticVertex(GpsTrackStaticVertex::TNormal(1.0f, 1.0f, 1.0f)));
staticVertexData.push_back(GpsTrackStaticVertex(GpsTrackStaticVertex::TNormal(1.0f, -1.0f, 1.0f)));
}
vector<GpsTrackDynamicVertex> dynamicVertexData;
dynamicVertexData.resize(data.m_pointsCount * kVerticesInPoint);
dp::Batcher batcher(data.m_pointsCount * kIndicesInPoint, data.m_pointsCount * kVerticesInPoint);
dp::SessionGuard guard(batcher, [&data](dp::GLState const & state, drape_ptr<dp::RenderBucket> && b)
{
data.m_bucket = move(b);
data.m_state = state;
});
drape_ptr<dp::OverlayHandle> handle = make_unique_dp<GpsTrackHandle>(data.m_pointsCount);
dp::AttributeProvider provider(2 /* stream count */, staticVertexData.size());
provider.InitStream(0 /* stream index */, GetGpsTrackStaticBindingInfo(), make_ref(staticVertexData.data()));
provider.InitStream(1 /* stream index */, GetGpsTrackDynamicBindingInfo(), make_ref(dynamicVertexData.data()));
batcher.InsertListOfStrip(GetGpsTrackState(), make_ref(&provider), move(handle), kVerticesInPoint);
}
} // namespace df

View file

@ -0,0 +1,69 @@
#pragma once
#include "drape_frontend/map_shape.hpp"
#include "drape_frontend/shape_view_params.hpp"
#include "drape/glstate.hpp"
#include "drape/render_bucket.hpp"
#include "drape/utils/vertex_decl.hpp"
#include "drape/overlay_handle.hpp"
#include "drape/pointers.hpp"
#include "std/vector.hpp"
namespace df
{
struct GpsTrackRenderData
{
size_t m_pointsCount;
dp::GLState m_state;
drape_ptr<dp::RenderBucket> m_bucket;
GpsTrackRenderData() : m_pointsCount(0), m_state(0, dp::GLState::OverlayLayer) {}
};
struct GpsTrackDynamicVertex
{
using TPosition = glsl::vec3;
using TColor = glsl::vec4;
GpsTrackDynamicVertex() = default;
GpsTrackDynamicVertex(TPosition const & pos, TColor const & color)
: m_position(pos)
, m_color(color)
{}
TPosition m_position;
TColor m_color;
};
class GpsTrackHandle : public dp::OverlayHandle
{
using TBase = dp::OverlayHandle;
public:
GpsTrackHandle(size_t pointsCount);
void GetAttributeMutation(ref_ptr<dp::AttributeBufferMutator> mutator,
ScreenBase const & screen) const override;
bool Update(ScreenBase const & screen) override;
m2::RectD GetPixelRect(ScreenBase const & screen) const override;
void GetPixelShape(ScreenBase const & screen, Rects & rects) const override;
bool IndexesRequired() const override;
void Clear();
void SetPoint(size_t index, m2::PointD const & position, float radius, dp::Color const & color);
size_t GetPointsCount() const;
private:
vector<GpsTrackDynamicVertex> m_buffer;
bool m_needUpdate;
};
class GpsTrackShape
{
public:
static void Draw(GpsTrackRenderData & data);
};
} // namespace df

View file

@ -46,7 +46,11 @@ public:
Invalidate,
Allow3dMode,
Allow3dBuildings,
EnablePerspective
EnablePerspective,
CacheGpsTrackPoints,
FlushGpsTrackPoints,
UpdateGpsTrackPoints,
ClearGpsTrackPoints
};
virtual ~Message() {}

View file

@ -4,6 +4,8 @@
#include "drape_frontend/gui/layer_render.hpp"
#include "drape_frontend/gui/skin.hpp"
#include "drape_frontend/gps_track_point.hpp"
#include "drape_frontend/gps_track_shape.hpp"
#include "drape_frontend/route_builder.hpp"
#include "drape_frontend/my_position.hpp"
#include "drape_frontend/selection_shape.hpp"
@ -708,4 +710,53 @@ private:
double const m_angleFOV;
};
class CacheGpsTrackPointsMessage : public Message
{
public:
CacheGpsTrackPointsMessage(size_t pointsCount) : m_pointsCount(pointsCount) {}
Type GetType() const override { return Message::CacheGpsTrackPoints; }
size_t GetPointsCount() const { return m_pointsCount; }
private:
size_t m_pointsCount;
};
class FlushGpsTrackPointsMessage : public Message
{
public:
FlushGpsTrackPointsMessage(drape_ptr<GpsTrackRenderData> && renderData)
: m_renderData(move(renderData))
{}
Type GetType() const override { return Message::FlushGpsTrackPoints; }
drape_ptr<GpsTrackRenderData> && AcceptRenderData() { return move(m_renderData); }
private:
drape_ptr<GpsTrackRenderData> m_renderData;
};
class UpdateGpsTrackPointsMessage : public Message
{
public:
UpdateGpsTrackPointsMessage(vector<GpsTrackPoint> && toAdd, vector<uint32_t> && toRemove)
: m_pointsToAdd(move(toAdd))
, m_pointsToRemove(move(toRemove))
{}
Type GetType() const override { return Message::UpdateGpsTrackPoints; }
vector<GpsTrackPoint> const & GetPointsToAdd() { return m_pointsToAdd; }
vector<uint32_t> const & GetPointsToRemove() { return m_pointsToRemove; }
private:
vector<GpsTrackPoint> m_pointsToAdd;
vector<uint32_t> m_pointsToRemove;
};
class ClearGpsTrackPointsMessage : public Message
{
public:
ClearGpsTrackPointsMessage(){}
Type GetType() const override { return Message::ClearGpsTrackPoints; }
};
} // namespace df

View file

@ -878,6 +878,12 @@ void Framework::UpdateCountryInfo(storage::TIndex const & countryIndex, bool isC
m_drapeEngine->SetCountryInfo(countryInfo, isCurrentCountry);
}
void Framework::OnUpdateGpsTrackPoints(vector<df::GpsTrackPoint> && toAdd, vector<uint32_t> && toRemove)
{
if (m_drapeEngine != nullptr)
m_drapeEngine->UpdateGpsTrackPoints(move(toAdd), move(toRemove));
}
void Framework::MemoryWarning()
{
LOG(LINFO, ("MemoryWarning"));

View file

@ -11,6 +11,7 @@
#include "drape_frontend/gui/skin.hpp"
#include "drape_frontend/drape_engine.hpp"
#include "drape_frontend/gps_track_point.hpp"
#include "drape_frontend/user_event_stream.hpp"
#include "drape_frontend/watch/frame_image.hpp"
@ -340,6 +341,8 @@ private:
void OnUpdateCountryIndex(storage::TIndex const & currentIndex, m2::PointF const & pt);
void UpdateCountryInfo(storage::TIndex const & countryIndex, bool isCurrentCountry);
void OnUpdateGpsTrackPoints(vector<df::GpsTrackPoint> && toAdd, vector<uint32_t> && toRemove);
public:
using TSearchRequest = search::QuerySaver::TSearchRequest;

View file

@ -29,7 +29,7 @@ void GpsTrackContainer::SetDuration(hours duration)
RemoveOldPoints(removed);
if (m_callback && !removed.empty())
m_callback(vector<GpsTrackPoint>(), move(removed));
m_callback(vector<df::GpsTrackPoint>(), move(removed));
}
void GpsTrackContainer::SetMaxSize(size_t maxSize)
@ -42,7 +42,7 @@ void GpsTrackContainer::SetMaxSize(size_t maxSize)
RemoveOldPoints(removed);
if (m_callback && !removed.empty())
m_callback(vector<GpsTrackPoint>(), move(removed));
m_callback(vector<df::GpsTrackPoint>(), move(removed));
}
void GpsTrackContainer::SetCallback(TGpsTrackDiffCallback callback, bool sendAll)
@ -54,7 +54,7 @@ void GpsTrackContainer::SetCallback(TGpsTrackDiffCallback callback, bool sendAll
if (!m_callback || !sendAll || m_points.empty())
return;
vector<GpsTrackPoint> added;
vector<df::GpsTrackPoint> added;
CopyPoints(added);
m_callback(move(added), vector<uint32_t>());
@ -72,7 +72,7 @@ uint32_t GpsTrackContainer::AddPoint(m2::PointD const & point, double speedMPS,
return kInvalidId;
}
GpsTrackPoint gtp;
df::GpsTrackPoint gtp;
gtp.m_timestamp = timestamp;
gtp.m_point = point;
gtp.m_speedMPS = speedMPS;
@ -80,7 +80,7 @@ uint32_t GpsTrackContainer::AddPoint(m2::PointD const & point, double speedMPS,
m_points.push_back(gtp);
vector<GpsTrackPoint> added;
vector<df::GpsTrackPoint> added;
added.emplace_back(gtp);
vector<uint32_t> removed;
@ -92,7 +92,7 @@ uint32_t GpsTrackContainer::AddPoint(m2::PointD const & point, double speedMPS,
return gtp.m_id;
}
void GpsTrackContainer::GetPoints(vector<GpsTrackPoint> & points) const
void GpsTrackContainer::GetPoints(vector<df::GpsTrackPoint> & points) const
{
lock_guard<mutex> lg(m_guard);
@ -110,11 +110,14 @@ void GpsTrackContainer::RemoveOldPoints(vector<uint32_t> & removedIds)
if (m_points.front().m_timestamp < lowerBorder)
{
GpsTrackPoint pt;
df::GpsTrackPoint pt;
pt.m_timestamp = lowerBorder;
auto const itr = lower_bound(m_points.begin(), m_points.end(), pt,
[](GpsTrackPoint const & a, GpsTrackPoint const & b)->bool{ return a.m_timestamp < b.m_timestamp; });
[](df::GpsTrackPoint const & a, df::GpsTrackPoint const & b) -> bool
{
return a.m_timestamp < b.m_timestamp;
});
if (itr != m_points.begin())
{
@ -138,11 +141,11 @@ void GpsTrackContainer::RemoveOldPoints(vector<uint32_t> & removedIds)
}
}
void GpsTrackContainer::CopyPoints(vector<GpsTrackPoint> & points) const
void GpsTrackContainer::CopyPoints(vector<df::GpsTrackPoint> & points) const
{
// Must be called under m_guard lock
vector<GpsTrackPoint> tmp;
vector<df::GpsTrackPoint> tmp;
tmp.reserve(m_points.size());
copy(m_points.begin(), m_points.end(), back_inserter(tmp));
points.swap(tmp);

View file

@ -1,29 +1,15 @@
#pragma once
#include "drape_frontend/gps_track_point.hpp"
#include "std/chrono.hpp"
#include "std/deque.hpp"
#include "std/function.hpp"
#include "std/mutex.hpp"
#include "geometry/point2d.hpp"
class GpsTrackContainer
{
public:
struct GpsTrackPoint
{
// Timestamp of the point, seconds from 1st Jan 1970
double m_timestamp;
// Point in the Mercator projection
m2::PointD m_point;
// Speed in the point, M/S
double m_speedMPS;
// Unique identifier of the point
uint32_t m_id;
};
static uint32_t constexpr kInvalidId = numeric_limits<uint32_t>::max();
@ -31,7 +17,7 @@ public:
/// @param toAdd - collection of points to add.
/// @param toRemove - collection of point indices to remove.
/// @note Calling of a GpsTrackContainer's function from the callback causes deadlock.
using TGpsTrackDiffCallback = std::function<void(vector<GpsTrackPoint> && toAdd, vector<uint32_t> && toRemove)>;
using TGpsTrackDiffCallback = std::function<void(vector<df::GpsTrackPoint> && toAdd, vector<uint32_t> && toRemove)>;
GpsTrackContainer();
@ -64,11 +50,11 @@ public:
/// Returns points snapshot from the container.
/// @param points - output for collection of points.
void GetPoints(vector<GpsTrackPoint> & points) const;
void GetPoints(vector<df::GpsTrackPoint> & points) const;
private:
void RemoveOldPoints(vector<uint32_t> & removedIds);
void CopyPoints(vector<GpsTrackPoint> & points) const;
void CopyPoints(vector<df::GpsTrackPoint> & points) const;
mutable mutex m_guard;
@ -82,7 +68,7 @@ private:
// Collection of points, by nature is asc. sorted by m_timestamp.
// Max size of m_points is adjusted by m_trackDuration and m_maxSize.
deque<GpsTrackPoint> m_points;
deque<df::GpsTrackPoint> m_points;
// Simple counter which is used to generate point unique ids.
uint32_t m_counter;

View file

@ -12,12 +12,12 @@ uint32_t constexpr kSecondsPerHour = 60 * 60;
struct GpsTrackContainerCallback
{
public:
void OnChange(vector<GpsTrackContainer::GpsTrackPoint> && toAdd, vector<uint32_t> && toRemove)
void OnChange(vector<df::GpsTrackPoint> && toAdd, vector<uint32_t> && toRemove)
{
m_toAdd.insert(m_toAdd.end(), toAdd.begin(), toAdd.end());
m_toRemove.insert(m_toRemove.end(), toRemove.begin(), toRemove.end());
}
vector<GpsTrackContainer::GpsTrackPoint> m_toAdd;
vector<df::GpsTrackPoint> m_toAdd;
vector<uint32_t> m_toRemove;
};
@ -76,7 +76,7 @@ UNIT_TEST(GpsTrackContainer_Test)
// and test there is only id25 point in the track
vector<GpsTrackContainer::GpsTrackPoint> points;
vector<df::GpsTrackPoint> points;
gpstrack.GetPoints(points);
TEST_EQUAL(1, points.size(), ());

View file

@ -13,6 +13,7 @@ using std::fill;
using std::find;
using std::find_if;
using std::find_first_of;
using std::is_sorted;
using std::lexicographical_compare;
using std::lower_bound;
using std::max;