Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorr.kuznetsov <r.kuznetsov@corp.mail.ru>2016-08-16 14:28:05 +0300
committerr.kuznetsov <r.kuznetsov@corp.mail.ru>2016-10-05 13:52:06 +0300
commit6dc03b1114362f2f06244422c88a1d159d827f5b (patch)
tree92a829f91254b87fb0e56204ccf7a49138f834d0
parentea20412b1da6b31a2a69181ccecb2d7b9006b6a2 (diff)
Added traffic renderer
-rw-r--r--data/resources-6plus_clear/traffic-arrow.pngbin0 -> 508 bytes
-rw-r--r--data/resources-6plus_dark/traffic-arrow.pngbin0 -> 508 bytes
-rw-r--r--data/resources-6plus_legacy/traffic-arrow.pngbin0 -> 508 bytes
-rw-r--r--data/resources-hdpi_clear/traffic-arrow.pngbin0 -> 508 bytes
-rw-r--r--data/resources-hdpi_dark/traffic-arrow.pngbin0 -> 508 bytes
-rw-r--r--data/resources-hdpi_legacy/traffic-arrow.pngbin0 -> 508 bytes
-rw-r--r--data/resources-ldpi_clear/traffic-arrow.pngbin0 -> 508 bytes
-rw-r--r--data/resources-ldpi_dark/traffic-arrow.pngbin0 -> 508 bytes
-rw-r--r--data/resources-ldpi_legacy/traffic-arrow.pngbin0 -> 508 bytes
-rw-r--r--data/resources-mdpi_clear/traffic-arrow.pngbin0 -> 508 bytes
-rw-r--r--data/resources-mdpi_dark/traffic-arrow.pngbin0 -> 508 bytes
-rw-r--r--data/resources-mdpi_legacy/traffic-arrow.pngbin0 -> 508 bytes
-rw-r--r--data/resources-xhdpi_clear/traffic-arrow.pngbin0 -> 508 bytes
-rw-r--r--data/resources-xhdpi_dark/traffic-arrow.pngbin0 -> 508 bytes
-rw-r--r--data/resources-xhdpi_legacy/traffic-arrow.pngbin0 -> 508 bytes
-rw-r--r--data/resources-xxhdpi_clear/traffic-arrow.pngbin0 -> 508 bytes
-rw-r--r--data/resources-xxhdpi_dark/traffic-arrow.pngbin0 -> 508 bytes
-rw-r--r--data/resources-xxhdpi_legacy/traffic-arrow.pngbin0 -> 508 bytes
-rw-r--r--drape/drape.pro2
-rw-r--r--drape/drape_common.pri2
-rw-r--r--drape/shaders/shader_index.txt1
-rw-r--r--drape/shaders/traffic_fragment_shader.fsh19
-rw-r--r--drape/shaders/traffic_vertex_shader.vsh42
-rw-r--r--drape/static_texture.cpp120
-rw-r--r--drape/static_texture.hpp34
-rw-r--r--drape/texture.hpp2
-rw-r--r--drape/texture_manager.cpp15
-rw-r--r--drape/texture_manager.hpp3
-rw-r--r--drape_frontend/backend_renderer.cpp37
-rw-r--r--drape_frontend/backend_renderer.hpp2
-rw-r--r--drape_frontend/color_constants.cpp6
-rw-r--r--drape_frontend/color_constants.hpp3
-rw-r--r--drape_frontend/drape_engine.cpp14
-rw-r--r--drape_frontend/drape_engine.hpp4
-rwxr-xr-xdrape_frontend/drape_frontend.pro4
-rwxr-xr-xdrape_frontend/frontend_renderer.cpp31
-rwxr-xr-xdrape_frontend/frontend_renderer.hpp2
-rw-r--r--drape_frontend/gps_track_shape.cpp2
-rw-r--r--drape_frontend/gps_track_shape.hpp2
-rw-r--r--drape_frontend/line_shape_helper.cpp4
-rw-r--r--drape_frontend/line_shape_helper.hpp3
-rw-r--r--drape_frontend/message.hpp6
-rw-r--r--drape_frontend/message_subclasses.hpp57
-rw-r--r--drape_frontend/traffic_generator.cpp362
-rw-r--r--drape_frontend/traffic_generator.hpp136
-rw-r--r--drape_frontend/traffic_renderer.cpp145
-rw-r--r--drape_frontend/traffic_renderer.hpp45
47 files changed, 1094 insertions, 11 deletions
diff --git a/data/resources-6plus_clear/traffic-arrow.png b/data/resources-6plus_clear/traffic-arrow.png
new file mode 100644
index 0000000000..ff4e41a01a
--- /dev/null
+++ b/data/resources-6plus_clear/traffic-arrow.png
Binary files differ
diff --git a/data/resources-6plus_dark/traffic-arrow.png b/data/resources-6plus_dark/traffic-arrow.png
new file mode 100644
index 0000000000..ff4e41a01a
--- /dev/null
+++ b/data/resources-6plus_dark/traffic-arrow.png
Binary files differ
diff --git a/data/resources-6plus_legacy/traffic-arrow.png b/data/resources-6plus_legacy/traffic-arrow.png
new file mode 100644
index 0000000000..ff4e41a01a
--- /dev/null
+++ b/data/resources-6plus_legacy/traffic-arrow.png
Binary files differ
diff --git a/data/resources-hdpi_clear/traffic-arrow.png b/data/resources-hdpi_clear/traffic-arrow.png
new file mode 100644
index 0000000000..ff4e41a01a
--- /dev/null
+++ b/data/resources-hdpi_clear/traffic-arrow.png
Binary files differ
diff --git a/data/resources-hdpi_dark/traffic-arrow.png b/data/resources-hdpi_dark/traffic-arrow.png
new file mode 100644
index 0000000000..ff4e41a01a
--- /dev/null
+++ b/data/resources-hdpi_dark/traffic-arrow.png
Binary files differ
diff --git a/data/resources-hdpi_legacy/traffic-arrow.png b/data/resources-hdpi_legacy/traffic-arrow.png
new file mode 100644
index 0000000000..ff4e41a01a
--- /dev/null
+++ b/data/resources-hdpi_legacy/traffic-arrow.png
Binary files differ
diff --git a/data/resources-ldpi_clear/traffic-arrow.png b/data/resources-ldpi_clear/traffic-arrow.png
new file mode 100644
index 0000000000..ff4e41a01a
--- /dev/null
+++ b/data/resources-ldpi_clear/traffic-arrow.png
Binary files differ
diff --git a/data/resources-ldpi_dark/traffic-arrow.png b/data/resources-ldpi_dark/traffic-arrow.png
new file mode 100644
index 0000000000..ff4e41a01a
--- /dev/null
+++ b/data/resources-ldpi_dark/traffic-arrow.png
Binary files differ
diff --git a/data/resources-ldpi_legacy/traffic-arrow.png b/data/resources-ldpi_legacy/traffic-arrow.png
new file mode 100644
index 0000000000..ff4e41a01a
--- /dev/null
+++ b/data/resources-ldpi_legacy/traffic-arrow.png
Binary files differ
diff --git a/data/resources-mdpi_clear/traffic-arrow.png b/data/resources-mdpi_clear/traffic-arrow.png
new file mode 100644
index 0000000000..ff4e41a01a
--- /dev/null
+++ b/data/resources-mdpi_clear/traffic-arrow.png
Binary files differ
diff --git a/data/resources-mdpi_dark/traffic-arrow.png b/data/resources-mdpi_dark/traffic-arrow.png
new file mode 100644
index 0000000000..ff4e41a01a
--- /dev/null
+++ b/data/resources-mdpi_dark/traffic-arrow.png
Binary files differ
diff --git a/data/resources-mdpi_legacy/traffic-arrow.png b/data/resources-mdpi_legacy/traffic-arrow.png
new file mode 100644
index 0000000000..ff4e41a01a
--- /dev/null
+++ b/data/resources-mdpi_legacy/traffic-arrow.png
Binary files differ
diff --git a/data/resources-xhdpi_clear/traffic-arrow.png b/data/resources-xhdpi_clear/traffic-arrow.png
new file mode 100644
index 0000000000..ff4e41a01a
--- /dev/null
+++ b/data/resources-xhdpi_clear/traffic-arrow.png
Binary files differ
diff --git a/data/resources-xhdpi_dark/traffic-arrow.png b/data/resources-xhdpi_dark/traffic-arrow.png
new file mode 100644
index 0000000000..ff4e41a01a
--- /dev/null
+++ b/data/resources-xhdpi_dark/traffic-arrow.png
Binary files differ
diff --git a/data/resources-xhdpi_legacy/traffic-arrow.png b/data/resources-xhdpi_legacy/traffic-arrow.png
new file mode 100644
index 0000000000..ff4e41a01a
--- /dev/null
+++ b/data/resources-xhdpi_legacy/traffic-arrow.png
Binary files differ
diff --git a/data/resources-xxhdpi_clear/traffic-arrow.png b/data/resources-xxhdpi_clear/traffic-arrow.png
new file mode 100644
index 0000000000..ff4e41a01a
--- /dev/null
+++ b/data/resources-xxhdpi_clear/traffic-arrow.png
Binary files differ
diff --git a/data/resources-xxhdpi_dark/traffic-arrow.png b/data/resources-xxhdpi_dark/traffic-arrow.png
new file mode 100644
index 0000000000..ff4e41a01a
--- /dev/null
+++ b/data/resources-xxhdpi_dark/traffic-arrow.png
Binary files differ
diff --git a/data/resources-xxhdpi_legacy/traffic-arrow.png b/data/resources-xxhdpi_legacy/traffic-arrow.png
new file mode 100644
index 0000000000..ff4e41a01a
--- /dev/null
+++ b/data/resources-xxhdpi_legacy/traffic-arrow.png
Binary files differ
diff --git a/drape/drape.pro b/drape/drape.pro
index 0253766c1f..e13cad0f68 100644
--- a/drape/drape.pro
+++ b/drape/drape.pro
@@ -54,6 +54,8 @@ OTHER_FILES += \
shaders/texturing_vertex_shader.vsh \
shaders/trackpoint_vertex_shader.vsh \
shaders/trackpoint_fragment_shader.fsh \
+ shaders/traffic_fragment_shader.fsh \
+ shaders/traffic_vertex_shader.vsh \
shaders/transparent_layer_fragment_shader.fsh \
shaders/transparent_layer_vertex_shader.vsh \
shaders/user_mark.vsh \
diff --git a/drape/drape_common.pri b/drape/drape_common.pri
index f8cc8fa8ff..132d156d30 100644
--- a/drape/drape_common.pri
+++ b/drape/drape_common.pri
@@ -36,6 +36,7 @@ SOURCES += \
$$DRAPE_DIR/render_bucket.cpp \
$$DRAPE_DIR/shader.cpp \
$$DRAPE_DIR/shader_def.cpp \
+ $$DRAPE_DIR/static_texture.cpp \
$$DRAPE_DIR/stipple_pen_resource.cpp \
$$DRAPE_DIR/support_manager.cpp \
$$DRAPE_DIR/symbols_texture.cpp \
@@ -93,6 +94,7 @@ HEADERS += \
$$DRAPE_DIR/render_bucket.hpp \
$$DRAPE_DIR/shader.hpp \
$$DRAPE_DIR/shader_def.hpp \
+ $$DRAPE_DIR/static_texture.hpp \
$$DRAPE_DIR/stipple_pen_resource.hpp \
$$DRAPE_DIR/support_manager.hpp \
$$DRAPE_DIR/symbols_texture.hpp \
diff --git a/drape/shaders/shader_index.txt b/drape/shaders/shader_index.txt
index 62b1ad476e..73fc39a3ce 100644
--- a/drape/shaders/shader_index.txt
+++ b/drape/shaders/shader_index.txt
@@ -29,3 +29,4 @@ MASKED_TEXTURING_BILLBOARD_PROGRAM masked_texturing_billboard_vertex_shader.vsh
TEXT_OUTLINED_BILLBOARD_PROGRAM text_outlined_billboard_vertex_shader.vsh text_fragment_shader.fsh
TEXT_BILLBOARD_PROGRAM text_billboard_vertex_shader.vsh text_fragment_shader.fsh
BOOKMARK_BILLBOARD_PROGRAM user_mark_billboard.vsh texturing_fragment_shader.fsh
+TRAFFIC_PROGRAM traffic_vertex_shader.vsh traffic_fragment_shader.fsh
diff --git a/drape/shaders/traffic_fragment_shader.fsh b/drape/shaders/traffic_fragment_shader.fsh
new file mode 100644
index 0000000000..287ea0b076
--- /dev/null
+++ b/drape/shaders/traffic_fragment_shader.fsh
@@ -0,0 +1,19 @@
+varying vec2 v_colorTexCoord;
+varying vec2 v_maskTexCoord;
+varying float v_halfLength;
+
+uniform sampler2D u_colorTex;
+uniform sampler2D u_maskTex;
+uniform float u_opacity;
+
+const float kAntialiasingThreshold = 0.92;
+
+void main(void)
+{
+ vec4 color = texture2D(u_colorTex, v_colorTexCoord);
+ vec4 mask = texture2D(u_maskTex, v_maskTexCoord);
+ color.a = color.a * u_opacity * (1.0 - smoothstep(kAntialiasingThreshold, 1.0, abs(v_halfLength)));
+ color.rgb = mix(color.rgb, mask.rgb, mask.a);
+
+ gl_FragColor = color;
+}
diff --git a/drape/shaders/traffic_vertex_shader.vsh b/drape/shaders/traffic_vertex_shader.vsh
new file mode 100644
index 0000000000..e1c735b39c
--- /dev/null
+++ b/drape/shaders/traffic_vertex_shader.vsh
@@ -0,0 +1,42 @@
+attribute vec3 a_position;
+attribute vec4 a_normal;
+attribute vec2 a_colorTexCoord;
+
+uniform mat4 modelView;
+uniform mat4 projection;
+uniform mat4 pivotTransform;
+
+uniform vec4 u_trafficParams;
+
+varying vec2 v_colorTexCoord;
+varying vec2 v_maskTexCoord;
+varying float v_halfLength;
+
+const float kShapeCoordScalar = 1000.0;
+
+void main(void)
+{
+ vec2 normal = a_normal.xy;
+ float halfWidth = length(normal);
+ vec2 transformedAxisPos = (vec4(a_position.xy, 0.0, 1.0) * modelView).xy;
+ if (halfWidth != 0.0)
+ {
+ vec2 norm = normal * u_trafficParams.x;
+ if (a_normal.z < 0.0) norm = normal * u_trafficParams.y;
+ halfWidth = length(norm);
+
+ vec4 glbShiftPos = vec4(a_position.xy + norm, 0.0, 1.0);
+ vec2 shiftPos = (glbShiftPos * modelView).xy;
+ transformedAxisPos = transformedAxisPos + normalize(shiftPos - transformedAxisPos) * halfWidth;
+ }
+
+ float uOffset = length(vec4(kShapeCoordScalar, 0, 0, 0) * modelView) * a_normal.w;
+ v_colorTexCoord = a_colorTexCoord;
+ v_maskTexCoord = vec2(uOffset * u_trafficParams.z, 0.5 * a_normal.z + 0.5) * u_trafficParams.w;
+ v_halfLength = a_normal.z;
+ vec4 pos = vec4(transformedAxisPos, a_position.z, 1.0) * projection;
+ float w = pos.w;
+ pos.xyw = (pivotTransform * vec4(pos.xy, 0.0, w)).xyw;
+ pos.z *= pos.w / w;
+ gl_Position = pos;
+}
diff --git a/drape/static_texture.cpp b/drape/static_texture.cpp
new file mode 100644
index 0000000000..782cbf7649
--- /dev/null
+++ b/drape/static_texture.cpp
@@ -0,0 +1,120 @@
+#include "drape/static_texture.hpp"
+#include "3party/stb_image/stb_image.h"
+
+#include "indexer/map_style_reader.hpp"
+
+#include "platform/platform.hpp"
+
+#include "coding/reader.hpp"
+#include "coding/parse_xml.hpp"
+
+#include "base/string_utils.hpp"
+
+namespace dp
+{
+
+namespace
+{
+
+using TLoadingCompletion = function<void(unsigned char *, uint32_t, uint32_t)>;
+using TLoadingFailure = function<void(string const &)>;
+
+void LoadData(string const & textureName, string const & skinPathName,
+ TLoadingCompletion const & completionHandler,
+ TLoadingFailure const & failureHandler)
+{
+ ASSERT(completionHandler != nullptr, ());
+ ASSERT(failureHandler != nullptr, ());
+
+ vector<unsigned char> rawData;
+ try
+ {
+ ReaderPtr<Reader> reader = GetStyleReader().GetResourceReader(textureName + ".png", skinPathName);
+ size_t const size = reader.Size();
+ rawData.resize(size);
+ reader.Read(0, &rawData[0], size);
+ }
+ catch (RootException & e)
+ {
+ failureHandler(e.what());
+ return;
+ }
+
+ int w, h, bpp;
+ unsigned char * data = stbi_png_load_from_memory(&rawData[0], rawData.size(), &w, &h, &bpp, 0);
+ ASSERT_EQUAL(bpp, 4, ("Incorrect texture format"));
+ completionHandler(data, w, h);
+
+ stbi_image_free(data);
+}
+
+class StaticResourceInfo : public Texture::ResourceInfo
+{
+public:
+ StaticResourceInfo() : Texture::ResourceInfo(m2::RectF(0.0f, 0.0f, 1.0f, 1.0f)) {}
+ virtual ~StaticResourceInfo(){}
+
+ Texture::ResourceType GetType() const override { return Texture::Static; }
+};
+
+} // namespace
+
+StaticTexture::StaticTexture(string const & textureName, string const & skinPathName,
+ ref_ptr<HWTextureAllocator> allocator)
+ : m_textureName(textureName)
+ , m_info(make_unique_dp<StaticResourceInfo>())
+{
+ Load(skinPathName, allocator);
+}
+
+void StaticTexture::Load(string const & skinPathName, ref_ptr<HWTextureAllocator> allocator)
+{
+ auto completionHandler = [this, &allocator](unsigned char * data, uint32_t width, uint32_t height)
+ {
+ Texture::Params p;
+ p.m_allocator = allocator;
+ p.m_format = dp::RGBA8;
+ p.m_width = width;
+ p.m_height = height;
+ p.m_wrapSMode = gl_const::GLRepeate;
+ p.m_wrapTMode = gl_const::GLRepeate;
+
+ Create(p, make_ref(data));
+ };
+
+ auto failureHandler = [this](string const & reason)
+ {
+ LOG(LERROR, (reason));
+ Fail();
+ };
+
+ LoadData(m_textureName, skinPathName, completionHandler, failureHandler);
+}
+
+void StaticTexture::Invalidate(string const & skinPathName, ref_ptr<HWTextureAllocator> allocator)
+{
+ Destroy();
+ Load(skinPathName, allocator);
+}
+
+ref_ptr<Texture::ResourceInfo> StaticTexture::FindResource(Texture::Key const & key, bool & newResource)
+{
+ newResource = false;
+ if (key.GetType() != Texture::Static)
+ return nullptr;
+ return make_ref(m_info);
+}
+
+void StaticTexture::Fail()
+{
+ int32_t alfaTexture = 0;
+ Texture::Params p;
+ p.m_allocator = GetDefaultAllocator();
+ p.m_format = dp::RGBA8;
+ p.m_width = 1;
+ p.m_height = 1;
+
+ Create(p, make_ref(&alfaTexture));
+}
+
+} // namespace dp
diff --git a/drape/static_texture.hpp b/drape/static_texture.hpp
new file mode 100644
index 0000000000..9385faf917
--- /dev/null
+++ b/drape/static_texture.hpp
@@ -0,0 +1,34 @@
+#pragma once
+
+#include "drape/texture.hpp"
+
+#include "std/string.hpp"
+
+namespace dp
+{
+
+class StaticTexture : public Texture
+{
+public:
+ class StaticKey : public Key
+ {
+ public:
+ ResourceType GetType() const override { return ResourceType::Static; }
+ };
+
+ StaticTexture(string const & textureName, string const & skinPathName,
+ ref_ptr<HWTextureAllocator> allocator);
+
+ ref_ptr<ResourceInfo> FindResource(Key const & key, bool & newResource) override;
+
+ void Invalidate(string const & skinPathName, ref_ptr<HWTextureAllocator> allocator);
+
+private:
+ void Fail();
+ void Load(string const & skinPathName, ref_ptr<HWTextureAllocator> allocator);
+
+ string m_textureName;
+ drape_ptr<Texture::ResourceInfo> m_info;
+};
+
+} // namespace dp
diff --git a/drape/texture.hpp b/drape/texture.hpp
index 83d9e26c1f..b102f94598 100644
--- a/drape/texture.hpp
+++ b/drape/texture.hpp
@@ -22,7 +22,7 @@ public:
Glyph,
StipplePen,
Color,
- UniformValue
+ Static
};
class Key
diff --git a/drape/texture_manager.cpp b/drape/texture_manager.cpp
index 9fd92dd856..e1cfb9948f 100644
--- a/drape/texture_manager.cpp
+++ b/drape/texture_manager.cpp
@@ -1,6 +1,7 @@
#include "drape/texture_manager.hpp"
#include "drape/symbols_texture.hpp"
#include "drape/font_texture.hpp"
+#include "drape/static_texture.hpp"
#include "drape/stipple_pen_resource.hpp"
#include "drape/texture_of_colors.hpp"
#include "drape/glfunctions.hpp"
@@ -210,6 +211,8 @@ void TextureManager::Release()
m_stipplePenTexture.reset();
m_colorTexture.reset();
+ m_trafficArrowTexture.reset();
+
m_glyphTextures.clear();
m_glyphManager.reset();
@@ -379,6 +382,9 @@ void TextureManager::Init(Params const & params)
m_symbolTexture = make_unique_dp<SymbolsTexture>(params.m_resPostfix, make_ref(m_textureAllocator));
+ m_trafficArrowTexture = make_unique_dp<StaticTexture>("traffic-arrow", params.m_resPostfix,
+ make_ref(m_textureAllocator));
+
// initialize patterns
buffer_vector<buffer_vector<uint8_t, 8>, 64> patterns;
double const visualScale = params.m_visualScale;
@@ -450,6 +456,10 @@ void TextureManager::Invalidate(string const & resPostfix)
ASSERT(m_symbolTexture != nullptr, ());
ref_ptr<SymbolsTexture> symbolsTexture = make_ref(m_symbolTexture);
symbolsTexture->Invalidate(resPostfix, make_ref(m_textureAllocator));
+
+ ASSERT(m_trafficArrowTexture != nullptr, ());
+ ref_ptr<StaticTexture> staticTexture = make_ref(m_trafficArrowTexture);
+ staticTexture->Invalidate(resPostfix, make_ref(m_textureAllocator));
}
void TextureManager::GetSymbolRegion(string const & symbolName, SymbolRegion & region)
@@ -507,6 +517,11 @@ ref_ptr<Texture> TextureManager::GetSymbolsTexture() const
return make_ref(m_symbolTexture);
}
+ref_ptr<Texture> TextureManager::GetTrafficArrowTexture() const
+{
+ return make_ref(m_trafficArrowTexture);
+}
+
constexpr size_t TextureManager::GetInvalidGlyphGroup()
{
return kInvalidGlyphGroup;
diff --git a/drape/texture_manager.hpp b/drape/texture_manager.hpp
index f25a9bbb5d..f820e6729f 100644
--- a/drape/texture_manager.hpp
+++ b/drape/texture_manager.hpp
@@ -102,6 +102,7 @@ public:
bool AreGlyphsReady(strings::UniString const & str) const;
ref_ptr<Texture> GetSymbolsTexture() const;
+ ref_ptr<Texture> GetTrafficArrowTexture() const;
private:
struct GlyphGroup
@@ -239,6 +240,8 @@ private:
drape_ptr<Texture> m_colorTexture;
list<drape_ptr<Texture>> m_glyphTextures;
+ drape_ptr<Texture> m_trafficArrowTexture;
+
drape_ptr<GlyphManager> m_glyphManager;
drape_ptr<HWTextureAllocator> m_textureAllocator;
diff --git a/drape_frontend/backend_renderer.cpp b/drape_frontend/backend_renderer.cpp
index ce46e5a973..c7b7eea718 100644
--- a/drape_frontend/backend_renderer.cpp
+++ b/drape_frontend/backend_renderer.cpp
@@ -27,6 +27,7 @@ BackendRenderer::BackendRenderer(Params const & params)
: BaseRenderer(ThreadsCommutator::ResourceUploadThread, params)
, m_model(params.m_model)
, m_readManager(make_unique_dp<ReadManager>(params.m_commutator, m_model, params.m_allow3dBuildings))
+ , m_trafficGenerator(make_unique_dp<TrafficGenerator>())
, m_requestedTiles(params.m_requestedTiles)
, m_updateCurrentCountryFn(params.m_updateCurrentCountryFn)
{
@@ -329,6 +330,42 @@ void BackendRenderer::AcceptMessage(ref_ptr<Message> message)
break;
}
+ case Message::AddTrafficSegments:
+ {
+ ref_ptr<AddTrafficSegmentsMessage> msg = message;
+ for (auto const & segment : msg->GetSegments())
+ m_trafficGenerator->AddSegment(segment.first, segment.second);
+ break;
+ }
+ case Message::UpdateTraffic:
+ {
+ ref_ptr<UpdateTrafficMessage> msg = message;
+ auto segments = m_trafficGenerator->GetSegmentsToUpdate(msg->GetSegmentsData());
+ if (!segments.empty())
+ {
+ m_commutator->PostMessage(ThreadsCommutator::RenderThread,
+ make_unique_dp<UpdateTrafficMessage>(segments),
+ MessagePriority::Normal);
+ }
+
+ if (segments.size() < msg->GetSegmentsData().size())
+ {
+ vector<TrafficRenderData> data;
+ m_trafficGenerator->GetTrafficGeom(m_texMng, msg->GetSegmentsData(), data);
+ m_commutator->PostMessage(ThreadsCommutator::RenderThread,
+ make_unique_dp<FlushTrafficDataMessage>(move(data)),
+ MessagePriority::Normal);
+
+ if (m_trafficGenerator->IsColorsCacheRefreshed())
+ {
+ auto texCoords = m_trafficGenerator->ProcessCacheRefreshing();
+ m_commutator->PostMessage(ThreadsCommutator::RenderThread,
+ make_unique_dp<SetTrafficTexCoordsMessage>(move(texCoords)),
+ MessagePriority::Normal);
+ }
+ }
+ break;
+ }
default:
ASSERT(false, ());
break;
diff --git a/drape_frontend/backend_renderer.hpp b/drape_frontend/backend_renderer.hpp
index ca34b14e4a..39ee36a9ac 100644
--- a/drape_frontend/backend_renderer.hpp
+++ b/drape_frontend/backend_renderer.hpp
@@ -6,6 +6,7 @@
#include "drape_frontend/map_data_provider.hpp"
#include "drape_frontend/overlay_batcher.hpp"
#include "drape_frontend/requested_tiles.hpp"
+#include "drape_frontend/traffic_generator.hpp"
#include "drape_frontend/viewport.hpp"
#include "drape/pointers.hpp"
@@ -94,6 +95,7 @@ private:
drape_ptr<BatchersPool> m_batchersPool;
drape_ptr<ReadManager> m_readManager;
drape_ptr<RouteBuilder> m_routeBuilder;
+ drape_ptr<TrafficGenerator> m_trafficGenerator;
gui::LayerCacher m_guiCacher;
ref_ptr<RequestedTiles> m_requestedTiles;
diff --git a/drape_frontend/color_constants.cpp b/drape_frontend/color_constants.cpp
index e743bba1c1..4d64b1bd0b 100644
--- a/drape_frontend/color_constants.cpp
+++ b/drape_frontend/color_constants.cpp
@@ -24,6 +24,9 @@ unordered_map<int, unordered_map<int, dp::Color>> kColorConstants =
{ TrackCarSpeed, dp::Color(21, 121, 244, 255) },
{ TrackPlaneSpeed, dp::Color(10, 196, 255, 255) },
{ TrackUnknownDistance, dp::Color(97, 97, 97, 255) },
+ { TrafficNormal, dp::Color(60, 170, 60, 255) },
+ { TrafficSlow, dp::Color(255, 219, 88, 255) },
+ { TrafficVerySlow, dp::Color(227, 38, 54, 255) },
}
},
{ MapStyleDark,
@@ -40,6 +43,9 @@ unordered_map<int, unordered_map<int, dp::Color>> kColorConstants =
{ TrackCarSpeed, dp::Color(255, 202, 40, 255) },
{ TrackPlaneSpeed, dp::Color(255, 245, 160, 255) },
{ TrackUnknownDistance, dp::Color(150, 150, 150, 255) },
+ { TrafficNormal, dp::Color(60, 170, 60, 255) },
+ { TrafficSlow, dp::Color(255, 219, 88, 255) },
+ { TrafficVerySlow, dp::Color(227, 38, 54, 255) },
}
},
};
diff --git a/drape_frontend/color_constants.hpp b/drape_frontend/color_constants.hpp
index ff79ecc4ce..214ddc76f2 100644
--- a/drape_frontend/color_constants.hpp
+++ b/drape_frontend/color_constants.hpp
@@ -21,6 +21,9 @@ enum ColorConstant
TrackCarSpeed,
TrackPlaneSpeed,
TrackUnknownDistance,
+ TrafficNormal,
+ TrafficSlow,
+ TrafficVerySlow
};
dp::Color GetColorConstant(MapStyle style, ColorConstant constant);
diff --git a/drape_frontend/drape_engine.cpp b/drape_frontend/drape_engine.cpp
index 4dd722cf65..7944158951 100644
--- a/drape_frontend/drape_engine.cpp
+++ b/drape_frontend/drape_engine.cpp
@@ -524,4 +524,18 @@ void DrapeEngine::RequestSymbolsSize(vector<string> const & symbols,
MessagePriority::Normal);
}
+void DrapeEngine::AddTrafficSegments(vector<pair<uint64_t, m2::PolylineD>> const & segments)
+{
+ m_threadCommutator->PostMessage(ThreadsCommutator::ResourceUploadThread,
+ make_unique_dp<AddTrafficSegmentsMessage>(segments),
+ MessagePriority::Normal);
+}
+
+void DrapeEngine::UpdateTraffic(vector<TrafficSegmentData> const & segmentsData)
+{
+ m_threadCommutator->PostMessage(ThreadsCommutator::ResourceUploadThread,
+ make_unique_dp<UpdateTrafficMessage>(segmentsData),
+ MessagePriority::Normal);
+}
+
} // namespace df
diff --git a/drape_frontend/drape_engine.hpp b/drape_frontend/drape_engine.hpp
index c908b64dec..6c8b9a2b0b 100644
--- a/drape_frontend/drape_engine.hpp
+++ b/drape_frontend/drape_engine.hpp
@@ -5,6 +5,7 @@
#include "drape_frontend/frontend_renderer.hpp"
#include "drape_frontend/route_shape.hpp"
#include "drape_frontend/selection_shape.hpp"
+#include "drape_frontend/traffic_generator.hpp"
#include "drape_frontend/threads_commutator.hpp"
#include "drape/pointers.hpp"
@@ -161,6 +162,9 @@ public:
void RequestSymbolsSize(vector<string> const & symbols,
TRequestSymbolsSizeCallback const & callback);
+ void AddTrafficSegments(vector<pair<uint64_t, m2::PolylineD>> const & segments);
+ void UpdateTraffic(vector<TrafficSegmentData> const & segmentsData);
+
private:
void AddUserEvent(drape_ptr<UserEvent> && e);
void ModelViewChanged(ScreenBase const & screen);
diff --git a/drape_frontend/drape_frontend.pro b/drape_frontend/drape_frontend.pro
index 514f82d1ab..c0d2a44d91 100755
--- a/drape_frontend/drape_frontend.pro
+++ b/drape_frontend/drape_frontend.pro
@@ -85,6 +85,8 @@ SOURCES += \
tile_info.cpp \
tile_key.cpp \
tile_utils.cpp \
+ traffic_generator.cpp \
+ traffic_renderer.cpp \
transparent_layer.cpp \
user_event_stream.cpp \
user_mark_shapes.cpp \
@@ -185,6 +187,8 @@ HEADERS += \
tile_info.hpp \
tile_key.hpp \
tile_utils.hpp \
+ traffic_generator.hpp \
+ traffic_renderer.hpp \
transparent_layer.hpp \
user_event_stream.hpp \
user_mark_shapes.hpp \
diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp
index 5c94bf82a3..70189c96d0 100755
--- a/drape_frontend/frontend_renderer.cpp
+++ b/drape_frontend/frontend_renderer.cpp
@@ -114,6 +114,7 @@ FrontendRenderer::FrontendRenderer(Params const & params)
: BaseRenderer(ThreadsCommutator::RenderThread, params)
, m_gpuProgramManager(new dp::GpuProgramManager())
, m_routeRenderer(new RouteRenderer())
+ , m_trafficRenderer(new TrafficRenderer())
, m_framebuffer(new Framebuffer())
, m_transparentLayer(new TransparentLayer())
, m_gpsTrackRenderer(new GpsTrackRenderer(bind(&FrontendRenderer::PrepareGpsTrackPoints, this, _1)))
@@ -737,6 +738,27 @@ void FrontendRenderer::AcceptMessage(ref_ptr<Message> message)
break;
}
+ case Message::UpdateTraffic:
+ {
+ ref_ptr<UpdateTrafficMessage> msg = message;
+ m_trafficRenderer->UpdateTraffic(msg->GetSegmentsData());
+ break;
+ }
+
+ case Message::SetTrafficTexCoords:
+ {
+ ref_ptr<SetTrafficTexCoordsMessage> msg = message;
+ m_trafficRenderer->SetTexCoords(move(msg->AcceptTexCoords()));
+ break;
+ }
+
+ case Message::FlushTrafficData:
+ {
+ ref_ptr<FlushTrafficDataMessage> msg = message;
+ m_trafficRenderer->AddRenderData(make_ref(m_gpuProgramManager), msg->AcceptTrafficData());
+ break;
+ }
+
default:
ASSERT(false, ());
}
@@ -796,7 +818,6 @@ void FrontendRenderer::UpdateGLResources()
void FrontendRenderer::FollowRoute(int preferredZoomLevel, int preferredZoomLevelIn3d, bool enableAutoZoom)
{
-
m_myPositionController->ActivateRouting(!m_enablePerspectiveInNavigation ? preferredZoomLevel : preferredZoomLevelIn3d,
enableAutoZoom);
@@ -1086,11 +1107,11 @@ void FrontendRenderer::RenderScene(ScreenBase const & modelView)
Render3dLayer(modelView);
}
+ GLFunctions::glDisable(gl_const::GLDepthTest);
if (hasSelectedPOI)
- {
- GLFunctions::glDisable(gl_const::GLDepthTest);
m_selectionShape->Render(modelView, m_currentZoomLevel, make_ref(m_gpuProgramManager), m_generalUniforms);
- }
+
+ m_trafficRenderer->RenderTraffic(modelView, m_currentZoomLevel, make_ref(m_gpuProgramManager), m_generalUniforms);
GLFunctions::glEnable(gl_const::GLDepthTest);
GLFunctions::glClearDepth();
@@ -1168,7 +1189,7 @@ void FrontendRenderer::RenderUserMarksLayer(ScreenBase const & modelView)
}
}
}
-
+
void FrontendRenderer::BuildOverlayTree(ScreenBase const & modelView)
{
RenderLayer & overlay = m_layers[RenderLayer::OverlayID];
diff --git a/drape_frontend/frontend_renderer.hpp b/drape_frontend/frontend_renderer.hpp
index cccc8e4578..1dfdb783ee 100755
--- a/drape_frontend/frontend_renderer.hpp
+++ b/drape_frontend/frontend_renderer.hpp
@@ -20,6 +20,7 @@
#include "drape_frontend/route_renderer.hpp"
#include "drape_frontend/threads_commutator.hpp"
#include "drape_frontend/tile_info.hpp"
+#include "drape_frontend/traffic_renderer.hpp"
#include "drape_frontend/user_event_stream.hpp"
#include "drape/pointers.hpp"
@@ -279,6 +280,7 @@ private:
drape_ptr<MyPositionController> m_myPositionController;
drape_ptr<SelectionShape> m_selectionShape;
drape_ptr<RouteRenderer> m_routeRenderer;
+ drape_ptr<TrafficRenderer> m_trafficRenderer;
drape_ptr<Framebuffer> m_framebuffer;
drape_ptr<TransparentLayer> m_transparentLayer;
drape_ptr<GpsTrackRenderer> m_gpsTrackRenderer;
diff --git a/drape_frontend/gps_track_shape.cpp b/drape_frontend/gps_track_shape.cpp
index ffd0924de2..98b2586701 100644
--- a/drape_frontend/gps_track_shape.cpp
+++ b/drape_frontend/gps_track_shape.cpp
@@ -85,6 +85,8 @@ void GpsTrackHandle::GetAttributeMutation(ref_ptr<dp::AttributeBufferMutator> mu
mutateNode.m_region = node.second;
mutateNode.m_data = make_ref(buffer);
mutator->AddMutation(node.first, mutateNode);
+
+ m_needUpdate = false;
}
bool GpsTrackHandle::Update(ScreenBase const & screen)
diff --git a/drape_frontend/gps_track_shape.hpp b/drape_frontend/gps_track_shape.hpp
index 41f5a097d7..614068112b 100644
--- a/drape_frontend/gps_track_shape.hpp
+++ b/drape_frontend/gps_track_shape.hpp
@@ -61,7 +61,7 @@ public:
private:
vector<GpsTrackDynamicVertex> m_buffer;
- bool m_needUpdate;
+ mutable bool m_needUpdate;
};
class GpsTrackShape
diff --git a/drape_frontend/line_shape_helper.cpp b/drape_frontend/line_shape_helper.cpp
index 7a994e4b03..160dcdf3a7 100644
--- a/drape_frontend/line_shape_helper.cpp
+++ b/drape_frontend/line_shape_helper.cpp
@@ -207,7 +207,8 @@ void GenerateJoinNormals(dp::LineJoin joinType, glsl::vec2 const & normal1, glsl
}
void GenerateCapNormals(dp::LineCap capType, glsl::vec2 const & normal1, glsl::vec2 const & normal2,
- glsl::vec2 const & direction, float halfWidth, bool isStart, vector<glsl::vec2> & normals)
+ glsl::vec2 const & direction, float halfWidth, bool isStart, vector<glsl::vec2> & normals,
+ int segmentsCount)
{
if (capType == dp::ButtCap)
return;
@@ -229,7 +230,6 @@ void GenerateCapNormals(dp::LineCap capType, glsl::vec2 const & normal1, glsl::v
}
else
{
- int const segmentsCount = 8;
double const segmentSize = math::pi / segmentsCount * (isStart ? -1.0 : 1.0);
glsl::vec2 const normalizedNormal = glsl::normalize(normal2);
m2::PointD const startNormal(normalizedNormal.x, normalizedNormal.y);
diff --git a/drape_frontend/line_shape_helper.hpp b/drape_frontend/line_shape_helper.hpp
index e515949053..1b78e6a68b 100644
--- a/drape_frontend/line_shape_helper.hpp
+++ b/drape_frontend/line_shape_helper.hpp
@@ -61,7 +61,8 @@ void GenerateJoinNormals(dp::LineJoin joinType, glsl::vec2 const & normal1, glsl
vector<glsl::vec2> * uv = nullptr);
void GenerateCapNormals(dp::LineCap capType, glsl::vec2 const & normal1, glsl::vec2 const & normal2,
- glsl::vec2 const & direction, float halfWidth, bool isStart, vector<glsl::vec2> & normals);
+ glsl::vec2 const & direction, float halfWidth, bool isStart, vector<glsl::vec2> & normals,
+ int segmentsCount = 8);
glsl::vec2 GetNormal(LineSegment const & segment, bool isLeft, ENormalType normalType);
diff --git a/drape_frontend/message.hpp b/drape_frontend/message.hpp
index 851608e968..43aa925a57 100644
--- a/drape_frontend/message.hpp
+++ b/drape_frontend/message.hpp
@@ -64,7 +64,11 @@ public:
AllowAutoZoom,
RequestSymbolsSize,
RecoverGLResources,
- SetVisibleViewport
+ SetVisibleViewport,
+ AddTrafficSegments,
+ SetTrafficTexCoords,
+ UpdateTraffic,
+ FlushTrafficData
};
virtual ~Message() {}
diff --git a/drape_frontend/message_subclasses.hpp b/drape_frontend/message_subclasses.hpp
index 03c418a634..aafe817b36 100644
--- a/drape_frontend/message_subclasses.hpp
+++ b/drape_frontend/message_subclasses.hpp
@@ -12,6 +12,7 @@
#include "drape_frontend/route_builder.hpp"
#include "drape_frontend/selection_shape.hpp"
#include "drape_frontend/tile_utils.hpp"
+#include "drape_frontend/traffic_generator.hpp"
#include "drape_frontend/user_marks_provider.hpp"
#include "drape_frontend/user_mark_shapes.hpp"
#include "drape_frontend/viewport.hpp"
@@ -974,4 +975,60 @@ private:
TRequestSymbolsSizeCallback m_callback;
};
+class AddTrafficSegmentsMessage : public Message
+{
+public:
+ explicit AddTrafficSegmentsMessage(vector<pair<uint64_t, m2::PolylineD>> const & segments)
+ : m_segments(segments)
+ {}
+
+ Type GetType() const override { return Message::AddTrafficSegments; }
+ vector<pair<uint64_t, m2::PolylineD>> const & GetSegments() const { return m_segments; }
+
+private:
+ vector<pair<uint64_t, m2::PolylineD>> m_segments;
+};
+
+class SetTrafficTexCoordsMessage : public Message
+{
+public:
+ explicit SetTrafficTexCoordsMessage(unordered_map<int, glsl::vec2> && texCoords)
+ : m_texCoords(move(texCoords))
+ {}
+
+ Type GetType() const override { return Message::SetTrafficTexCoords; }
+ unordered_map<int, glsl::vec2> && AcceptTexCoords() { return move(m_texCoords); }
+
+private:
+ unordered_map<int, glsl::vec2> m_texCoords;
+};
+
+class UpdateTrafficMessage : public Message
+{
+public:
+ explicit UpdateTrafficMessage(vector<TrafficSegmentData> const & segmentsData)
+ : m_segmentsData(segmentsData)
+ {}
+
+ Type GetType() const override { return Message::UpdateTraffic; }
+ vector<TrafficSegmentData> const & GetSegmentsData() const { return m_segmentsData; }
+
+private:
+ vector<TrafficSegmentData> m_segmentsData;
+};
+
+class FlushTrafficDataMessage : public Message
+{
+public:
+ FlushTrafficDataMessage(vector<TrafficRenderData> && trafficData)
+ : m_trafficData(move(trafficData))
+ {}
+
+ Type GetType() const override { return Message::FlushTrafficData; }
+ vector<TrafficRenderData> && AcceptTrafficData() { return move(m_trafficData); }
+
+private:
+ vector<TrafficRenderData> m_trafficData;
+};
+
} // namespace df
diff --git a/drape_frontend/traffic_generator.cpp b/drape_frontend/traffic_generator.cpp
new file mode 100644
index 0000000000..41f39eab3e
--- /dev/null
+++ b/drape_frontend/traffic_generator.cpp
@@ -0,0 +1,362 @@
+#include "drape_frontend/traffic_generator.hpp"
+
+#include "drape_frontend/color_constants.hpp"
+#include "drape_frontend/line_shape_helper.hpp"
+#include "drape_frontend/map_shape.hpp"
+#include "drape_frontend/shape_view_params.hpp"
+#include "drape_frontend/tile_utils.hpp"
+
+#include "drape/attribute_provider.hpp"
+#include "drape/batcher.hpp"
+#include "drape/glsl_func.hpp"
+#include "drape/shader_def.hpp"
+#include "drape/texture_manager.hpp"
+
+#include "indexer/map_style_reader.hpp"
+
+#include "base/logging.hpp"
+
+#include "std/algorithm.hpp"
+
+namespace df
+{
+
+namespace
+{
+
+uint32_t const kDynamicStreamID = 0x7F;
+
+dp::BindingInfo const & GetTrafficStaticBindingInfo()
+{
+ static unique_ptr<dp::BindingInfo> s_info;
+ if (s_info == nullptr)
+ {
+ dp::BindingFiller<TrafficStaticVertex> filler(2);
+ filler.FillDecl<TrafficStaticVertex::TPosition>("a_position");
+ filler.FillDecl<TrafficStaticVertex::TNormal>("a_normal");
+ s_info.reset(new dp::BindingInfo(filler.m_info));
+ }
+ return *s_info;
+}
+
+dp::BindingInfo const & GetTrafficDynamicBindingInfo()
+{
+ static unique_ptr<dp::BindingInfo> s_info;
+ if (s_info == nullptr)
+ {
+ dp::BindingFiller<TrafficDynamicVertex> filler(1, kDynamicStreamID);
+ filler.FillDecl<TrafficDynamicVertex::TTexCoord>("a_colorTexCoord");
+ s_info.reset(new dp::BindingInfo(filler.m_info));
+ }
+ return *s_info;
+}
+
+void SubmitStaticVertex(glsl::vec3 const & pivot, glsl::vec2 const & normal, float side, float offsetFromStart,
+ vector<TrafficStaticVertex> & staticGeom)
+{
+ staticGeom.emplace_back(TrafficStaticVertex(pivot, TrafficStaticVertex::TNormal(normal, side, offsetFromStart)));
+}
+
+void SubmitDynamicVertex(glsl::vec2 const & texCoord, vector<TrafficDynamicVertex> & dynamicGeom)
+{
+ dynamicGeom.emplace_back(TrafficDynamicVertex(texCoord));
+}
+
+void GenerateCapTriangles(glsl::vec3 const & pivot, vector<glsl::vec2> const & normals,
+ dp::TextureManager::ColorRegion const & colorRegion,
+ vector<TrafficStaticVertex> & staticGeometry,
+ vector<TrafficDynamicVertex> & dynamicGeometry)
+{
+ float const kEps = 1e-5;
+ glsl::vec2 const uv = glsl::ToVec2(colorRegion.GetTexRect().Center());
+ size_t const trianglesCount = normals.size() / 3;
+ for (int j = 0; j < trianglesCount; j++)
+ {
+ SubmitStaticVertex(pivot, normals[3 * j],
+ glsl::length(normals[3 * j]) < kEps ? 0.0f : 1.0f, 0.0f, staticGeometry);
+ SubmitStaticVertex(pivot, normals[3 * j + 1],
+ glsl::length(normals[3 * j + 1]) < kEps ? 0.0f : 1.0f, 0.0f, staticGeometry);
+ SubmitStaticVertex(pivot, normals[3 * j + 2],
+ glsl::length(normals[3 * j + 2]) < kEps ? 0.0f : 1.0f, 0.0f, staticGeometry);
+
+ for (int k = 0; k < 3; k++)
+ SubmitDynamicVertex(uv, dynamicGeometry);
+ }
+}
+
+} // namespace
+
+TrafficHandle::TrafficHandle(uint64_t segmentId, m2::RectD const & bbox,
+ glsl::vec2 const & texCoord, size_t verticesCount)
+ : OverlayHandle(FeatureID(), dp::Anchor::Center, 0, false)
+ , m_segmentId(segmentId)
+ , m_bbox(bbox)
+ , m_needUpdate(false)
+{
+ m_buffer.resize(verticesCount);
+ for (size_t i = 0; i < m_buffer.size(); i++)
+ m_buffer[i] = texCoord;
+}
+
+void TrafficHandle::GetAttributeMutation(ref_ptr<dp::AttributeBufferMutator> mutator) const
+{
+ if (!m_needUpdate)
+ return;
+
+ TOffsetNode const & node = GetOffsetNode(kDynamicStreamID);
+ ASSERT(node.first.GetElementSize() == sizeof(TrafficDynamicVertex), ());
+ ASSERT(node.second.m_count == m_buffer.size(), ());
+
+ uint32_t const byteCount = m_buffer.size() * sizeof(TrafficDynamicVertex);
+ 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);
+
+ m_needUpdate = false;
+}
+
+bool TrafficHandle::Update(ScreenBase const & screen)
+{
+ UNUSED_VALUE(screen);
+ return true;
+}
+
+bool TrafficHandle::IndexesRequired() const
+{
+ return false;
+}
+
+m2::RectD TrafficHandle::GetPixelRect(ScreenBase const & screen, bool perspective) const
+{
+ UNUSED_VALUE(screen);
+ UNUSED_VALUE(perspective);
+ return m2::RectD();
+}
+
+void TrafficHandle::GetPixelShape(ScreenBase const & screen, bool perspective, Rects & rects) const
+{
+ UNUSED_VALUE(screen);
+ UNUSED_VALUE(perspective);
+}
+
+void TrafficHandle::SetTexCoord(glsl::vec2 const & texCoord)
+{
+ for (size_t i = 0; i < m_buffer.size(); i++)
+ m_buffer[i] = texCoord;
+ m_needUpdate = true;
+}
+
+uint64_t TrafficHandle::GetSegmentId() const
+{
+ return m_segmentId;
+}
+
+m2::RectD const & TrafficHandle::GetBoundingBox() const
+{
+ return m_bbox;
+}
+
+void TrafficGenerator::AddSegment(uint64_t segmentId, m2::PolylineD const & polyline)
+{
+ m_segments.insert(make_pair(segmentId, polyline));
+}
+
+void TrafficGenerator::ClearCache()
+{
+ m_colorsCache.clear();
+ m_segmentsCache.clear();
+}
+
+vector<TrafficSegmentData> TrafficGenerator::GetSegmentsToUpdate(vector<TrafficSegmentData> const & trafficData) const
+{
+ vector<TrafficSegmentData> result;
+ for (TrafficSegmentData const & segment : trafficData)
+ {
+ if (m_segmentsCache.find(segment.m_id) != m_segmentsCache.end())
+ result.push_back(segment);
+ }
+ return result;
+}
+
+void TrafficGenerator::GetTrafficGeom(ref_ptr<dp::TextureManager> textures,
+ vector<TrafficSegmentData> const & trafficData,
+ vector<TrafficRenderData> & data)
+{
+ FillColorsCache(textures);
+
+ dp::GLState state(gpu::TRAFFIC_PROGRAM, dp::GLState::GeometryLayer);
+ state.SetColorTexture(m_colorsCache[TrafficSpeedBucket::Normal].GetTexture());
+ state.SetMaskTexture(textures->GetTrafficArrowTexture());
+
+ int const kZoomLevel = 10;
+ uint32_t const kBatchSize = 5000;
+
+ using TSegIter = TSegmentCollection::iterator;
+ map<TileKey, list<pair<TSegIter, TrafficSpeedBucket>>> segmentsByTiles;
+ for (TrafficSegmentData const & segment : trafficData)
+ {
+ // Check if a segment hasn't been added.
+ auto it = m_segments.find(segment.m_id);
+ if (it == m_segments.end())
+ continue;
+
+ // Check if a segment has already generated.
+ if (m_segmentsCache.find(segment.m_id) != m_segmentsCache.end())
+ continue;
+
+ m_segmentsCache.insert(segment.m_id);
+ TileKey const tileKey = GetTileKeyByPoint(it->second.GetLimitRect().Center(), kZoomLevel);
+ segmentsByTiles[tileKey].emplace_back(make_pair(it, segment.m_speedBucket));
+ }
+
+ for (auto const & s : segmentsByTiles)
+ {
+ TileKey const & tileKey = s.first;
+ dp::Batcher batcher(kBatchSize, kBatchSize);
+ dp::SessionGuard guard(batcher, [&data, &tileKey](dp::GLState const & state, drape_ptr<dp::RenderBucket> && b)
+ {
+ TrafficRenderData bucket(state);
+ bucket.m_bucket = move(b);
+ bucket.m_tileKey = tileKey;
+ data.emplace_back(move(bucket));
+ });
+
+ for (auto const & segmentPair : s.second)
+ {
+ TSegIter it = segmentPair.first;
+ dp::TextureManager::ColorRegion const & colorRegion = m_colorsCache[segmentPair.second];
+ m2::PolylineD const & polyline = it->second;
+
+ vector<TrafficStaticVertex> staticGeometry;
+ vector<TrafficDynamicVertex> dynamicGeometry;
+ GenerateSegment(colorRegion, polyline, tileKey.GetGlobalRect().Center(), staticGeometry, dynamicGeometry);
+ ASSERT_EQUAL(staticGeometry.size(), dynamicGeometry.size(), ());
+
+ if ((staticGeometry.size() + dynamicGeometry.size()) == 0)
+ continue;
+
+ glsl::vec2 const uv = glsl::ToVec2(colorRegion.GetTexRect().Center());
+ drape_ptr<dp::OverlayHandle> handle = make_unique_dp<TrafficHandle>(it->first, polyline.GetLimitRect(),
+ uv, staticGeometry.size());
+
+ dp::AttributeProvider provider(2 /* stream count */, staticGeometry.size());
+ provider.InitStream(0 /* stream index */, GetTrafficStaticBindingInfo(), make_ref(staticGeometry.data()));
+ provider.InitStream(1 /* stream index */, GetTrafficDynamicBindingInfo(), make_ref(dynamicGeometry.data()));
+ batcher.InsertTriangleList(state, make_ref(&provider), move(handle));
+ }
+ }
+
+ GLFunctions::glFlush();
+}
+
+void TrafficGenerator::GenerateSegment(dp::TextureManager::ColorRegion const & colorRegion,
+ m2::PolylineD const & polyline, m2::PointD const & tileCenter,
+ vector<TrafficStaticVertex> & staticGeometry,
+ vector<TrafficDynamicVertex> & dynamicGeometry)
+{
+ vector<m2::PointD> const & path = polyline.GetPoints();
+ ASSERT_GREATER(path.size(), 1, ());
+
+ size_t const kAverageSize = path.size() * 4;
+ size_t const kAverageCapSize = 24;
+ staticGeometry.reserve(staticGeometry.size() + kAverageSize + kAverageCapSize * 2);
+ dynamicGeometry.reserve(dynamicGeometry.size() + kAverageSize + kAverageCapSize * 2);
+
+ float const kDepth = 0.0f;
+
+ // Build geometry.
+ glsl::vec2 firstPoint, firstTangent, firstLeftNormal, firstRightNormal;
+ glsl::vec2 lastPoint, lastTangent, lastLeftNormal, lastRightNormal;
+ bool firstFilled = false;
+
+ glsl::vec2 const uv = glsl::ToVec2(colorRegion.GetTexRect().Center());
+ for (size_t i = 1; i < path.size(); ++i)
+ {
+ if (path[i].EqualDxDy(path[i - 1], 1.0E-5))
+ continue;
+
+ glsl::vec2 const p1 = glsl::ToVec2(MapShape::ConvertToLocal(path[i - 1], tileCenter, kShapeCoordScalar));
+ glsl::vec2 const p2 = glsl::ToVec2(MapShape::ConvertToLocal(path[i], tileCenter, kShapeCoordScalar));
+ glsl::vec2 tangent, leftNormal, rightNormal;
+ CalculateTangentAndNormals(p1, p2, tangent, leftNormal, rightNormal);
+
+ // Fill first and last point, tangent and normals.
+ if (!firstFilled)
+ {
+ firstPoint = p1;
+ firstTangent = tangent;
+ firstLeftNormal = leftNormal;
+ firstRightNormal = rightNormal;
+ firstFilled = true;
+ }
+ lastTangent = tangent;
+ lastLeftNormal = leftNormal;
+ lastRightNormal = rightNormal;
+ lastPoint = p2;
+ float const maskSize = (path[i] - path[i - 1]).Length();
+
+ glsl::vec3 const startPivot = glsl::vec3(p1, kDepth);
+ glsl::vec3 const endPivot = glsl::vec3(p2, kDepth);
+ SubmitStaticVertex(startPivot, rightNormal, -1.0f, 0.0f, staticGeometry);
+ SubmitStaticVertex(startPivot, leftNormal, 1.0f, 0.0f, staticGeometry);
+ SubmitStaticVertex(endPivot, rightNormal, -1.0f, maskSize, staticGeometry);
+ SubmitStaticVertex(endPivot, rightNormal, -1.0f, maskSize, staticGeometry);
+ SubmitStaticVertex(startPivot, leftNormal, 1.0f, 0.0f, staticGeometry);
+ SubmitStaticVertex(endPivot, leftNormal, 1.0f, maskSize, staticGeometry);
+ for (int j = 0; j < 6; j++)
+ SubmitDynamicVertex(uv, dynamicGeometry);
+ }
+
+ // Generate caps.
+ if (firstFilled)
+ {
+ int const kSegmentsCount = 4;
+ vector<glsl::vec2> normals;
+ normals.reserve(kAverageCapSize);
+ GenerateCapNormals(dp::RoundCap, firstLeftNormal, firstRightNormal, -firstTangent,
+ 1.0f, true /* isStart */, normals, kSegmentsCount);
+ GenerateCapTriangles(glsl::vec3(firstPoint, kDepth), normals, colorRegion,
+ staticGeometry, dynamicGeometry);
+
+ normals.clear();
+ GenerateCapNormals(dp::RoundCap, lastLeftNormal, lastRightNormal, lastTangent,
+ 1.0f, false /* isStart */, normals, kSegmentsCount);
+ GenerateCapTriangles(glsl::vec3(lastPoint, kDepth), normals, colorRegion,
+ staticGeometry, dynamicGeometry);
+ }
+}
+
+void TrafficGenerator::FillColorsCache(ref_ptr<dp::TextureManager> textures)
+{
+ if (m_colorsCache.empty())
+ {
+ auto const & style = GetStyleReader().GetCurrentStyle();
+ dp::TextureManager::ColorRegion colorRegion;
+ textures->GetColorRegion(df::GetColorConstant(style, df::TrafficVerySlow), colorRegion);
+ m_colorsCache[TrafficSpeedBucket::VerySlow] = colorRegion;
+
+ textures->GetColorRegion(df::GetColorConstant(style, df::TrafficSlow), colorRegion);
+ m_colorsCache[TrafficSpeedBucket::Slow] = colorRegion;
+
+ textures->GetColorRegion(df::GetColorConstant(style, df::TrafficNormal), colorRegion);
+ m_colorsCache[TrafficSpeedBucket::Normal] = colorRegion;
+
+ m_colorsCacheRefreshed = true;
+ }
+}
+
+unordered_map<int, glsl::vec2> TrafficGenerator::ProcessCacheRefreshing()
+{
+ unordered_map<int, glsl::vec2> result;
+ for (auto it = m_colorsCache.begin(); it != m_colorsCache.end(); ++it)
+ result[it->first] = glsl::ToVec2(it->second.GetTexRect().Center());
+ m_colorsCacheRefreshed = false;
+ return result;
+}
+
+} // namespace df
+
diff --git a/drape_frontend/traffic_generator.hpp b/drape_frontend/traffic_generator.hpp
new file mode 100644
index 0000000000..a0b9620612
--- /dev/null
+++ b/drape_frontend/traffic_generator.hpp
@@ -0,0 +1,136 @@
+#pragma once
+
+#include "drape_frontend/tile_key.hpp"
+
+#include "drape/color.hpp"
+#include "drape/glsl_types.hpp"
+#include "drape/glstate.hpp"
+#include "drape/overlay_handle.hpp"
+#include "drape/render_bucket.hpp"
+#include "drape/texture_manager.hpp"
+
+#include "geometry/polyline2d.hpp"
+
+#include "std/map.hpp"
+#include "std/set.hpp"
+#include "std/string.hpp"
+#include "std/vector.hpp"
+#include "std/unordered_map.hpp"
+
+namespace df
+{
+
+enum TrafficSpeedBucket
+{
+ Normal = 3,
+ Slow = 2,
+ VerySlow = 1
+};
+
+struct TrafficSegmentData
+{
+ uint64_t m_id;
+ TrafficSpeedBucket m_speedBucket;
+
+ TrafficSegmentData() = default;
+ TrafficSegmentData(uint64_t id, TrafficSpeedBucket const & speedBucket)
+ : m_id(id)
+ , m_speedBucket(speedBucket)
+ {}
+};
+
+struct TrafficRenderData
+{
+ dp::GLState m_state;
+ drape_ptr<dp::RenderBucket> m_bucket;
+ TileKey m_tileKey;
+ TrafficRenderData(dp::GLState const & state) : m_state(state) {}
+};
+
+struct TrafficStaticVertex
+{
+ using TPosition = glsl::vec3;
+ using TNormal = glsl::vec4;
+
+ TrafficStaticVertex() = default;
+ TrafficStaticVertex(TPosition const & position, TNormal const & normal)
+ : m_position(position)
+ , m_normal(normal)
+ {}
+
+ TPosition m_position;
+ TNormal m_normal;
+};
+
+struct TrafficDynamicVertex
+{
+ using TTexCoord = glsl::vec2;
+
+ TrafficDynamicVertex() = default;
+ TrafficDynamicVertex(TTexCoord const & color)
+ : m_colorTexCoord(color)
+ {}
+
+ TTexCoord m_colorTexCoord;
+};
+
+class TrafficHandle : public dp::OverlayHandle
+{
+ using TBase = dp::OverlayHandle;
+
+public:
+ TrafficHandle(uint64_t segmentId, m2::RectD const & bbox,
+ glsl::vec2 const & texCoord, size_t verticesCount);
+
+ void GetAttributeMutation(ref_ptr<dp::AttributeBufferMutator> mutator) const override;
+ bool Update(ScreenBase const & screen) override;
+ bool IndexesRequired() const override;
+ m2::RectD GetPixelRect(ScreenBase const & screen, bool perspective) const override;
+ void GetPixelShape(ScreenBase const & screen, bool perspective, Rects & rects) const override;
+
+ void SetTexCoord(glsl::vec2 const & texCoord);
+ uint64_t GetSegmentId() const;
+ m2::RectD const & GetBoundingBox() const;
+
+private:
+ uint64_t m_segmentId;
+ m2::RectD m_bbox;
+ vector<glsl::vec2> m_buffer;
+ mutable bool m_needUpdate;
+};
+
+class TrafficGenerator final
+{
+public:
+ TrafficGenerator() = default;
+
+ void AddSegment(uint64_t segmentId, m2::PolylineD const & polyline);
+
+ vector<TrafficSegmentData> GetSegmentsToUpdate(vector<TrafficSegmentData> const & trafficData) const;
+
+ void GetTrafficGeom(ref_ptr<dp::TextureManager> textures,
+ vector<TrafficSegmentData> const & trafficData,
+ vector<TrafficRenderData> & data);
+
+ void ClearCache();
+
+ bool IsColorsCacheRefreshed() const { return m_colorsCacheRefreshed; }
+ unordered_map<int, glsl::vec2> ProcessCacheRefreshing();
+
+private:
+ using TSegmentCollection = map<uint64_t, m2::PolylineD>;
+
+ void GenerateSegment(dp::TextureManager::ColorRegion const & colorRegion,
+ m2::PolylineD const & polyline, m2::PointD const & tileCenter,
+ vector<TrafficStaticVertex> & staticGeometry,
+ vector<TrafficDynamicVertex> & dynamicGeometry);
+ void FillColorsCache(ref_ptr<dp::TextureManager> textures);
+
+ TSegmentCollection m_segments;
+
+ set<uint64_t> m_segmentsCache;
+ unordered_map<int, dp::TextureManager::ColorRegion> m_colorsCache;
+ bool m_colorsCacheRefreshed = false;
+};
+
+} // namespace df
diff --git a/drape_frontend/traffic_renderer.cpp b/drape_frontend/traffic_renderer.cpp
new file mode 100644
index 0000000000..e13cf54782
--- /dev/null
+++ b/drape_frontend/traffic_renderer.cpp
@@ -0,0 +1,145 @@
+#include "drape_frontend/traffic_renderer.hpp"
+#include "drape_frontend/color_constants.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/map_style_reader.hpp"
+#include "indexer/scales.hpp"
+
+#include "base/logging.hpp"
+
+#include "std/algorithm.hpp"
+
+namespace df
+{
+
+namespace
+{
+
+int const kMinVisibleZoomLevel = 10;
+int const kMinVisibleArrowZoomLevel = 16;
+
+float const kTrafficArrowAspect = 64.0f / 16.0f;
+
+float const kLeftWidthInPixel[] =
+{
+ // 1 2 3 4 5 6 7 8 9 10
+ 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f,
+ //11 12 13 14 15 16 17 18 19 20
+ 0.75f, 0.75f, 1.0f, 2.0f, 2.0f, 3.0f, 3.0f, 4.0f, 5.0f, 8.0f
+};
+
+float const kRightWidthInPixel[] =
+{
+ // 1 2 3 4 5 6 7 8 9 10
+ 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 4.0f, 4.0f,
+ //11 12 13 14 15 16 17 18 19 20
+ 4.0f, 4.0f, 4.0f, 2.0f, 2.0f, 3.0f, 3.0f, 4.0f, 5.0f, 8.0f
+};
+
+float CalculateHalfWidth(ScreenBase const & screen, bool left)
+{
+ 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 const * halfWidth = left ? kLeftWidthInPixel : kRightWidthInPixel;
+ float radius = 0.0f;
+ if (index < scales::UPPER_STYLE_SCALE)
+ radius = halfWidth[index] + lerpCoef * (halfWidth[index + 1] - halfWidth[index]);
+ else
+ radius = halfWidth[scales::UPPER_STYLE_SCALE];
+
+ return radius * VisualParams::Instance().GetVisualScale();
+}
+
+} // namespace
+
+void TrafficRenderer::AddRenderData(ref_ptr<dp::GpuProgramManager> mng,
+ vector<TrafficRenderData> && renderData)
+{
+ if (renderData.empty())
+ return;
+
+ size_t const startIndex = m_renderData.size();
+ m_renderData.reserve(m_renderData.size() + renderData.size());
+ move(renderData.begin(), renderData.end(), std::back_inserter(m_renderData));
+ for (size_t i = startIndex; i < m_renderData.size(); i++)
+ {
+ ref_ptr<dp::GpuProgram> program = mng->GetProgram(m_renderData[i].m_state.GetProgramIndex());
+ program->Bind();
+ m_renderData[i].m_bucket->GetBuffer()->Build(program);
+ for (size_t j = 0; j < m_renderData[i].m_bucket->GetOverlayHandlesCount(); j++)
+ {
+ TrafficHandle * handle = static_cast<TrafficHandle *>(m_renderData[i].m_bucket->GetOverlayHandle(j).get());
+ m_handles.insert(make_pair(handle->GetSegmentId(), handle));
+ }
+ }
+}
+
+void TrafficRenderer::UpdateTraffic(vector<TrafficSegmentData> const & trafficData)
+{
+ for (TrafficSegmentData const & segment : trafficData)
+ {
+ auto it = m_texCoords.find(segment.m_speedBucket);
+ if (it == m_texCoords.end())
+ continue;
+ TrafficHandle * handle = FindHandle(segment.m_id);
+ if (handle != nullptr)
+ handle->SetTexCoord(it->second);
+ }
+}
+
+TrafficHandle * TrafficRenderer::FindHandle(uint64_t segmentId) const
+{
+ auto it = m_handles.find(segmentId);
+ return it != m_handles.end() ? it->second : nullptr;
+}
+
+void TrafficRenderer::RenderTraffic(ScreenBase const & screen, int zoomLevel,
+ ref_ptr<dp::GpuProgramManager> mng,
+ dp::UniformValuesStorage const & commonUniforms)
+{
+ if (m_renderData.empty() || zoomLevel < kMinVisibleZoomLevel)
+ return;
+
+ float const pixelHalfWidth = CalculateHalfWidth(screen, true /* left */);
+ float const invPixelLength = 1.0f / (2.0f * pixelHalfWidth * kTrafficArrowAspect);
+
+ GLFunctions::glClearDepth();
+ for (TrafficRenderData & renderData : m_renderData)
+ {
+ ref_ptr<dp::GpuProgram> program = mng->GetProgram(renderData.m_state.GetProgramIndex());
+ program->Bind();
+ dp::ApplyState(renderData.m_state, program);
+
+ dp::UniformValuesStorage uniforms = commonUniforms;
+ math::Matrix<float, 4, 4> mv = renderData.m_tileKey.GetTileBasedModelView(screen);
+ uniforms.SetMatrix4x4Value("modelView", mv.m_data);
+ uniforms.SetFloatValue("u_opacity", 1.0f);
+ uniforms.SetFloatValue("u_trafficParams", pixelHalfWidth, CalculateHalfWidth(screen, false /* left */),
+ invPixelLength, zoomLevel >= kMinVisibleArrowZoomLevel ? 1.0f : 0.0f);
+ dp::ApplyUniforms(uniforms, program);
+
+ renderData.m_bucket->Render(renderData.m_state.GetDrawAsLine());
+ }
+}
+
+void TrafficRenderer::SetTexCoords(unordered_map<int, glsl::vec2> && texCoords)
+{
+ m_texCoords = move(texCoords);
+}
+
+void TrafficRenderer::Clear()
+{
+ m_renderData.clear();
+ m_handles.clear();
+}
+
+} // namespace df
+
diff --git a/drape_frontend/traffic_renderer.hpp b/drape_frontend/traffic_renderer.hpp
new file mode 100644
index 0000000000..59ea6beb4f
--- /dev/null
+++ b/drape_frontend/traffic_renderer.hpp
@@ -0,0 +1,45 @@
+#pragma once
+
+#include "drape_frontend/traffic_generator.hpp"
+
+#include "drape/gpu_program_manager.hpp"
+#include "drape/pointers.hpp"
+#include "drape/uniform_values_storage.hpp"
+
+#include "geometry/screenbase.hpp"
+#include "geometry/spline.hpp"
+
+#include "std/map.hpp"
+#include "std/vector.hpp"
+#include "std/unordered_map.hpp"
+
+namespace df
+{
+
+class TrafficRenderer final
+{
+public:
+ TrafficRenderer() = default;
+
+ void AddRenderData(ref_ptr<dp::GpuProgramManager> mng,
+ vector<TrafficRenderData> && renderData);
+
+ void SetTexCoords(unordered_map<int, glsl::vec2> && texCoords);
+
+ void UpdateTraffic(vector<TrafficSegmentData> const & trafficData);
+
+ void RenderTraffic(ScreenBase const & screen, int zoomLevel,
+ ref_ptr<dp::GpuProgramManager> mng,
+ dp::UniformValuesStorage const & commonUniforms);
+
+ void Clear();
+
+private:
+ TrafficHandle * FindHandle(uint64_t segmentId) const;
+
+ vector<TrafficRenderData> m_renderData;
+ unordered_map<int, glsl::vec2> m_texCoords;
+ unordered_map<uint64_t, TrafficHandle *> m_handles;
+};
+
+} // namespace df