diff --git a/drape/batcher.hpp b/drape/batcher.hpp index a8da3eee98..e3db046245 100644 --- a/drape/batcher.hpp +++ b/drape/batcher.hpp @@ -14,7 +14,6 @@ namespace dp { - class RenderBucket; class AttributeProvider; class OverlayHandle; diff --git a/drape_frontend/traffic_generator.cpp b/drape_frontend/traffic_generator.cpp index 0f44da5a76..b3963a0b2c 100644 --- a/drape_frontend/traffic_generator.cpp +++ b/drape_frontend/traffic_generator.cpp @@ -18,6 +18,7 @@ #include "base/logging.hpp" #include +#include using namespace std::placeholders; @@ -52,7 +53,7 @@ static std::array(traffic::SpeedGroup::Count)> kMinCo dp::BindingInfo const & GetTrafficStaticBindingInfo() { - static unique_ptr s_info; + static std::unique_ptr s_info; if (s_info == nullptr) { dp::BindingFiller filler(3); @@ -66,7 +67,7 @@ dp::BindingInfo const & GetTrafficStaticBindingInfo() dp::BindingInfo const & GetTrafficLineStaticBindingInfo() { - static unique_ptr s_info; + static std::unique_ptr s_info; if (s_info == nullptr) { dp::BindingFiller filler(2); @@ -77,6 +78,20 @@ dp::BindingInfo const & GetTrafficLineStaticBindingInfo() return *s_info; } +dp::BindingInfo const & GetTrafficCircleStaticBindingInfo() +{ + static std::unique_ptr s_info; + if (s_info == nullptr) + { + dp::BindingFiller filler(3); + filler.FillDecl("a_position"); + filler.FillDecl("a_normal"); + filler.FillDecl("a_colorTexCoord"); + s_info = std::make_unique(filler.m_info); + } + return *s_info; +} + void SubmitStaticVertex(glsl::vec3 const & pivot, glsl::vec2 const & normal, float side, float offsetFromStart, glsl::vec4 const & texCoord, std::vector & staticGeom) @@ -84,22 +99,16 @@ void SubmitStaticVertex(glsl::vec3 const & pivot, glsl::vec2 const & normal, flo staticGeom.emplace_back(pivot, TrafficStaticVertex::TNormal(normal, side, offsetFromStart), texCoord); } -void GenerateCapTriangles(glsl::vec3 const & pivot, std::vector const & normals, - dp::TextureManager::ColorRegion const & colorRegion, - std::vector & staticGeometry) +void SubmitCircleStaticVertices(RoadClass roadClass, glsl::vec3 const & pivot, + glsl::vec2 const & rightNormal, glsl::vec2 const & uv, + std::vector & circlesGeometry) { - float const kEps = 1e-5; - glsl::vec4 const uv = glsl::vec4(glsl::ToVec2(colorRegion.GetTexRect().Center()), 0.0f, 0.0f); - size_t const trianglesCount = normals.size() / 3; - for (size_t j = 0; j < trianglesCount; j++) - { - SubmitStaticVertex(pivot, normals[3 * j], - glsl::length(normals[3 * j]) < kEps ? 0.0f : 1.0f, 0.0f, uv, staticGeometry); - SubmitStaticVertex(pivot, normals[3 * j + 1], - glsl::length(normals[3 * j + 1]) < kEps ? 0.0f : 1.0f, 0.0f, uv, staticGeometry); - SubmitStaticVertex(pivot, normals[3 * j + 2], - glsl::length(normals[3 * j + 2]) < kEps ? 0.0f : 1.0f, 0.0f, uv, staticGeometry); - } + // Here we use an equilateral triangle to render circle (incircle of a triangle). + static float const kSqrt3 = sqrt(3.0f); + auto const p = glsl::vec4(pivot, static_cast(roadClass)); + circlesGeometry.emplace_back(p, glsl::vec4(rightNormal, -kSqrt3, -1.0f), uv); + circlesGeometry.emplace_back(p, glsl::vec4(rightNormal, kSqrt3, -1.0f), uv); + circlesGeometry.emplace_back(p, glsl::vec4(rightNormal, 0.0f, 2.0f), uv); } } // namespace @@ -107,109 +116,147 @@ bool TrafficGenerator::m_simplifiedColorScheme = true; void TrafficGenerator::Init() { - int constexpr kBatchersCount = 3; - int constexpr kBatchSize = 65000; + uint32_t constexpr kBatchersCount = 3; + uint32_t constexpr kBatchSize = 5000; m_batchersPool = make_unique_dp>( - kBatchersCount, bind(&TrafficGenerator::FlushGeometry, this, _1, _2, _3), + kBatchersCount, std::bind(&TrafficGenerator::FlushGeometry, this, _1, _2, _3), kBatchSize, kBatchSize); + uint32_t constexpr kCirclesBatchSize = 1000; + m_circlesBatcher = make_unique_dp(kCirclesBatchSize, kCirclesBatchSize); + m_providerLines.InitStream(0 /* stream index */, GetTrafficLineStaticBindingInfo(), nullptr); m_providerTriangles.InitStream(0 /* stream index */, GetTrafficStaticBindingInfo(), nullptr); + m_providerCircles.InitStream(0 /* stream index */, GetTrafficCircleStaticBindingInfo(), nullptr); } void TrafficGenerator::ClearGLDependentResources() { InvalidateTexturesCache(); m_batchersPool.reset(); + m_circlesBatcher.reset(); +} + +void TrafficGenerator::GenerateSegmentsGeometry(MwmSet::MwmId const & mwmId, TileKey const & tileKey, + TrafficSegmentsGeometryValue const & geometry, + traffic::TrafficInfo::Coloring const & coloring, + ref_ptr texturesMgr) +{ + static std::vector const kGenerateCirclesZoomLevel = {14, 14, 16}; + + ASSERT(m_colorsCacheValid, ()); + auto const colorTexture = m_colorsCache[static_cast(traffic::SpeedGroup::G0)].GetTexture(); + + auto state = CreateGLState(gpu::Program::Traffic, RenderState::GeometryLayer); + state.SetColorTexture(colorTexture); + state.SetMaskTexture(texturesMgr->GetTrafficArrowTexture()); + + auto lineState = CreateGLState(gpu::Program::TrafficLine, RenderState::GeometryLayer); + lineState.SetColorTexture(colorTexture); + lineState.SetDrawAsLine(true); + + auto circleState = CreateGLState(gpu::Program::TrafficCircle, RenderState::GeometryLayer); + circleState.SetColorTexture(colorTexture); + + bool isLeftHand = false; + if (mwmId.GetInfo()) + { + auto const & regionData = mwmId.GetInfo()->GetRegionData(); + isLeftHand = (regionData.Get(feature::RegionData::RD_DRIVING) == "l"); + } + + static std::vector const kRoadClassDepths = {30.0f, 20.0f, 10.0f}; + + for (auto const & geomPair : geometry) + { + auto const coloringIt = coloring.find(geomPair.first); + if (coloringIt == coloring.cend() || coloringIt->second == traffic::SpeedGroup::Unknown) + continue; + + auto const & colorRegion = m_colorsCache[static_cast(coloringIt->second)]; + auto const vOffset = kCoordVOffsets[static_cast(coloringIt->second)]; + auto const minU = kMinCoordU[static_cast(coloringIt->second)]; + + TrafficSegmentGeometry const & g = geomPair.second; + ref_ptr batcher = + m_batchersPool->GetBatcher(TrafficBatcherKey(mwmId, tileKey, g.m_roadClass)); + + auto const finalDepth = kRoadClassDepths[static_cast(g.m_roadClass)] + + static_cast(coloringIt->second); + + int width = 0; + if (TrafficRenderer::CanBeRenderedAsLine(g.m_roadClass, tileKey.m_zoomLevel, width)) + { + std::vector staticGeometry; + GenerateLineSegment(colorRegion, g.m_polyline, tileKey.GetGlobalRect().Center(), finalDepth, + staticGeometry); + if (staticGeometry.empty()) + continue; + + m_providerLines.Reset(static_cast(staticGeometry.size())); + m_providerLines.UpdateStream(0 /* stream index */, make_ref(staticGeometry.data())); + + dp::GLState curLineState = lineState; + curLineState.SetLineWidth(width); + batcher->InsertLineStrip(curLineState, make_ref(&m_providerLines)); + } + else + { + std::vector staticGeometry; + bool const generateCircles = + (tileKey.m_zoomLevel > kGenerateCirclesZoomLevel[static_cast(g.m_roadClass)]); + + std::vector circlesGeometry; + GenerateSegment(g.m_roadClass, colorRegion, g.m_polyline, tileKey.GetGlobalRect().Center(), + generateCircles, finalDepth, vOffset, minU, isLeftHand, staticGeometry, + circlesGeometry); + if (staticGeometry.empty()) + continue; + + m_providerTriangles.Reset(static_cast(staticGeometry.size())); + m_providerTriangles.UpdateStream(0 /* stream index */, make_ref(staticGeometry.data())); + batcher->InsertTriangleList(state, make_ref(&m_providerTriangles)); + + if (circlesGeometry.empty()) + continue; + + m_providerCircles.Reset(static_cast(circlesGeometry.size())); + m_providerCircles.UpdateStream(0 /* stream index */, make_ref(circlesGeometry.data())); + m_circlesBatcher->InsertTriangleList(circleState, make_ref(&m_providerCircles)); + } + } } void TrafficGenerator::FlushSegmentsGeometry(TileKey const & tileKey, TrafficSegmentsGeometry const & geom, ref_ptr textures) { FillColorsCache(textures); - ASSERT(m_colorsCacheValid, ()); - auto const texture = m_colorsCache[static_cast(traffic::SpeedGroup::G0)].GetTexture(); - - auto state = CreateGLState(gpu::Program::Traffic, RenderState::GeometryLayer); - state.SetColorTexture(texture); - state.SetMaskTexture(textures->GetTrafficArrowTexture()); - - auto lineState = CreateGLState(gpu::Program::TrafficLine, RenderState::GeometryLayer); - lineState.SetColorTexture(texture); - lineState.SetDrawAsLine(true); static std::vector const kRoadClasses = {RoadClass::Class0, RoadClass::Class1, RoadClass::Class2}; - static float const kDepths[] = {2.0f, 1.0f, 0.0f}; - static std::vector const kGenerateCapsZoomLevel = {14, 14, 16}; - - for (auto geomIt = geom.begin(); geomIt != geom.end(); ++geomIt) + for (auto const & g : geom) { - auto coloringIt = m_coloring.find(geomIt->first); - if (coloringIt != m_coloring.end()) + auto const & mwmId = g.first; + auto coloringIt = m_coloring.find(mwmId); + if (coloringIt == m_coloring.cend()) + continue; + + for (auto const & roadClass : kRoadClasses) + m_batchersPool->ReserveBatcher(TrafficBatcherKey(mwmId, tileKey, roadClass)); + + m_circlesBatcher->StartSession([this, mwmId, tileKey](dp::GLState const & state, + drape_ptr && renderBucket) { - for (auto const & roadClass : kRoadClasses) - m_batchersPool->ReserveBatcher(TrafficBatcherKey(geomIt->first, tileKey, roadClass)); + FlushGeometry(TrafficBatcherKey(mwmId, tileKey, RoadClass::Class0), state, + std::move(renderBucket)); + }); - auto & coloring = coloringIt->second; - for (size_t i = 0; i < geomIt->second.size(); i++) - { - traffic::TrafficInfo::RoadSegmentId const & sid = geomIt->second[i].first; - auto segmentColoringIt = coloring.find(sid); - if (segmentColoringIt != coloring.end()) - { - // We do not generate geometry for unknown segments. - if (segmentColoringIt->second == traffic::SpeedGroup::Unknown) - continue; + GenerateSegmentsGeometry(mwmId, tileKey, g.second, coloringIt->second, textures); - TrafficSegmentGeometry const & g = geomIt->second[i].second; - ref_ptr batcher = - m_batchersPool->GetBatcher(TrafficBatcherKey(geomIt->first, tileKey, g.m_roadClass)); + for (auto const & roadClass : kRoadClasses) + m_batchersPool->ReleaseBatcher(TrafficBatcherKey(mwmId, tileKey, roadClass)); - float const depth = kDepths[static_cast(g.m_roadClass)]; - - ASSERT(m_colorsCacheValid, ()); - dp::TextureManager::ColorRegion const & colorRegion = - m_colorsCache[static_cast(segmentColoringIt->second)]; - float const vOffset = kCoordVOffsets[static_cast(segmentColoringIt->second)]; - float const minU = kMinCoordU[static_cast(segmentColoringIt->second)]; - - int width = 0; - if (TrafficRenderer::CanBeRenderedAsLine(g.m_roadClass, tileKey.m_zoomLevel, width)) - { - std::vector staticGeometry; - GenerateLineSegment(colorRegion, g.m_polyline, tileKey.GetGlobalRect().Center(), depth, - staticGeometry); - if (staticGeometry.empty()) - continue; - - m_providerLines.Reset(static_cast(staticGeometry.size())); - m_providerLines.UpdateStream(0 /* stream index */, make_ref(staticGeometry.data())); - - dp::GLState curLineState = lineState; - curLineState.SetLineWidth(width); - batcher->InsertLineStrip(curLineState, make_ref(&m_providerLines)); - } - else - { - std::vector staticGeometry; - bool const generateCaps = - (tileKey.m_zoomLevel > kGenerateCapsZoomLevel[static_cast(g.m_roadClass)]); - GenerateSegment(colorRegion, g.m_polyline, tileKey.GetGlobalRect().Center(), - generateCaps, depth, vOffset, minU, staticGeometry); - if (staticGeometry.empty()) - continue; - - m_providerTriangles.Reset(static_cast(staticGeometry.size())); - m_providerTriangles.UpdateStream(0 /* stream index */, make_ref(staticGeometry.data())); - batcher->InsertTriangleList(state, make_ref(&m_providerTriangles)); - } - } - } - - for (auto const & roadClass : kRoadClasses) - m_batchersPool->ReleaseBatcher(TrafficBatcherKey(geomIt->first, tileKey, roadClass)); - } + m_circlesBatcher->EndSession(); } GLFunctions::glFlush(); @@ -248,22 +295,25 @@ void TrafficGenerator::FlushGeometry(TrafficBatcherKey const & key, dp::GLState m_flushRenderDataFn(std::move(renderData)); } -void TrafficGenerator::GenerateSegment(dp::TextureManager::ColorRegion const & colorRegion, - m2::PolylineD const & polyline, m2::PointD const & tileCenter, - bool generateCaps, float depth, float vOffset, float minU, - std::vector & staticGeometry) +void TrafficGenerator::GenerateSegment(RoadClass roadClass, + dp::TextureManager::ColorRegion const & colorRegion, + m2::PolylineD const & polyline, + m2::PointD const & tileCenter, bool generateCircles, + float depth, float vOffset, float minU, bool isLeftHand, + std::vector & staticGeometry, + std::vector & circlesGeometry) { auto const & path = polyline.GetPoints(); ASSERT_GREATER(path.size(), 1, ()); size_t const kAverageSize = path.size() * 4; - size_t const kAverageCapSize = 12; - staticGeometry.reserve(staticGeometry.size() + kAverageSize + kAverageCapSize * 2); + staticGeometry.reserve(staticGeometry.size() + kAverageSize); + circlesGeometry.reserve(circlesGeometry.size() + (path.size() + 1) * 3); // Build geometry. - glsl::vec2 firstPoint, firstTangent, firstLeftNormal, firstRightNormal; - glsl::vec2 lastPoint, lastTangent, lastLeftNormal, lastRightNormal; + glsl::vec2 lastPoint, lastRightNormal; bool firstFilled = false; + auto const circleDepth = depth - 0.5f; glsl::vec4 const uvStart = glsl::vec4(glsl::ToVec2(colorRegion.GetTexRect().Center()), vOffset, 1.0f); glsl::vec4 const uvEnd = glsl::vec4(uvStart.x, uvStart.y, uvStart.z, minU); @@ -277,45 +327,47 @@ void TrafficGenerator::GenerateSegment(dp::TextureManager::ColorRegion const & c 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; + if (isLeftHand) + std::swap(leftNormal, rightNormal); + float const maskSize = static_cast((path[i] - path[i - 1]).Length()); glsl::vec3 const startPivot = glsl::vec3(p1, depth); glsl::vec3 const endPivot = glsl::vec3(p2, depth); - SubmitStaticVertex(startPivot, rightNormal, -1.0f, 0.0f, uvStart, staticGeometry); - SubmitStaticVertex(startPivot, leftNormal, 1.0f, 0.0f, uvStart, staticGeometry); - SubmitStaticVertex(endPivot, rightNormal, -1.0f, maskSize, uvEnd, staticGeometry); - SubmitStaticVertex(endPivot, rightNormal, -1.0f, maskSize, uvEnd, staticGeometry); - SubmitStaticVertex(startPivot, leftNormal, 1.0f, 0.0f, uvStart, staticGeometry); - SubmitStaticVertex(endPivot, leftNormal, 1.0f, maskSize, uvEnd, staticGeometry); + if (isLeftHand) + { + SubmitStaticVertex(startPivot, leftNormal, 1.0f, 0.0f, uvStart, staticGeometry); + SubmitStaticVertex(startPivot, rightNormal, -1.0f, 0.0f, uvStart, staticGeometry); + SubmitStaticVertex(endPivot, leftNormal, 1.0f, maskSize, uvEnd, staticGeometry); + SubmitStaticVertex(endPivot, leftNormal, 1.0f, maskSize, uvEnd, staticGeometry); + SubmitStaticVertex(startPivot, rightNormal, -1.0f, 0.0f, uvStart, staticGeometry); + SubmitStaticVertex(endPivot, rightNormal, -1.0f, maskSize, uvEnd, staticGeometry); + } + else + { + SubmitStaticVertex(startPivot, rightNormal, -1.0f, 0.0f, uvStart, staticGeometry); + SubmitStaticVertex(startPivot, leftNormal, 1.0f, 0.0f, uvStart, staticGeometry); + SubmitStaticVertex(endPivot, rightNormal, -1.0f, maskSize, uvEnd, staticGeometry); + SubmitStaticVertex(endPivot, rightNormal, -1.0f, maskSize, uvEnd, staticGeometry); + SubmitStaticVertex(startPivot, leftNormal, 1.0f, 0.0f, uvStart, staticGeometry); + SubmitStaticVertex(endPivot, leftNormal, 1.0f, maskSize, uvEnd, staticGeometry); + } + + if (generateCircles && !firstFilled) + { + SubmitCircleStaticVertices(roadClass, glsl::vec3(p1, circleDepth), rightNormal, + uvStart.xy(), circlesGeometry); + } + + firstFilled = true; + lastRightNormal = rightNormal; + lastPoint = p2; } - // Generate caps. - if (generateCaps && firstFilled) + if (generateCircles && firstFilled) { - int const kSegmentsCount = 4; - std::vector normals; - normals.reserve(kAverageCapSize); - GenerateCapNormals(dp::RoundCap, firstLeftNormal, firstRightNormal, -firstTangent, - 1.0f, true /* isStart */, normals, kSegmentsCount); - GenerateCapTriangles(glsl::vec3(firstPoint, depth), normals, colorRegion, staticGeometry); - - normals.clear(); - GenerateCapNormals(dp::RoundCap, lastLeftNormal, lastRightNormal, lastTangent, - 1.0f, false /* isStart */, normals, kSegmentsCount); - GenerateCapTriangles(glsl::vec3(lastPoint, depth), normals, colorRegion, staticGeometry); + SubmitCircleStaticVertices(roadClass, glsl::vec3(lastPoint, circleDepth), lastRightNormal, + uvStart.xy(), circlesGeometry); } } diff --git a/drape_frontend/traffic_generator.hpp b/drape_frontend/traffic_generator.hpp index 4f10d6f37e..4d2f26b8d0 100644 --- a/drape_frontend/traffic_generator.hpp +++ b/drape_frontend/traffic_generator.hpp @@ -67,13 +67,14 @@ struct TrafficSegmentGeometry RoadClass m_roadClass; TrafficSegmentGeometry(m2::PolylineD && polyline, RoadClass const & roadClass) - : m_polyline(move(polyline)) + : m_polyline(std::move(polyline)) , m_roadClass(roadClass) {} }; -using TrafficSegmentsGeometry = std::map>>; +using TrafficSegmentsGeometryValue = std::vector>; +using TrafficSegmentsGeometry = std::map; using TrafficSegmentsColoring = std::map; struct TrafficRenderData @@ -82,9 +83,16 @@ struct TrafficRenderData drape_ptr m_bucket; TileKey m_tileKey; MwmSet::MwmId m_mwmId; - RoadClass m_roadClass; + RoadClass m_roadClass = RoadClass::Class0; explicit TrafficRenderData(dp::GLState const & state) : m_state(state) {} + + bool operator<(TrafficRenderData const & renderData) const + { + if (m_roadClass != renderData.m_roadClass) + return m_roadClass > renderData.m_roadClass; + return m_state < renderData.m_state; + } }; struct TrafficStaticVertex @@ -121,17 +129,37 @@ struct TrafficLineStaticVertex TTexCoord m_colorTexCoord; }; +struct TrafficCircleStaticVertex +{ + using TPosition = glsl::vec4; + using TNormal = glsl::vec4; + using TTexCoord = glsl::vec2; + + TrafficCircleStaticVertex() = default; + TrafficCircleStaticVertex(TPosition const & position, TNormal const & normal, + TTexCoord const & colorTexCoord) + : m_position(position) + , m_normal(normal) + , m_colorTexCoord(colorTexCoord) + {} + + TPosition m_position; + TNormal m_normal; + TTexCoord m_colorTexCoord; +}; + using TrafficTexCoords = std::unordered_map; class TrafficGenerator final { public: - using TFlushRenderDataFn = std::function; + using FlushRenderDataFn = std::function; - explicit TrafficGenerator(TFlushRenderDataFn flushFn) + explicit TrafficGenerator(FlushRenderDataFn flushFn) : m_flushRenderDataFn(std::move(flushFn)) , m_providerTriangles(1 /* stream count */, 0 /* vertices count*/) , m_providerLines(1 /* stream count */, 0 /* vertices count*/) + , m_providerCircles(1 /* stream count */, 0 /* vertices count*/) {} void Init(); @@ -166,7 +194,7 @@ private: struct TrafficBatcherKeyComparator { - bool operator() (TrafficBatcherKey const & lhs, TrafficBatcherKey const & rhs) const + bool operator()(TrafficBatcherKey const & lhs, TrafficBatcherKey const & rhs) const { if (lhs.m_mwmId == rhs.m_mwmId) { @@ -178,10 +206,11 @@ private: } }; - void GenerateSegment(dp::TextureManager::ColorRegion const & colorRegion, + void GenerateSegment(RoadClass roadClass, dp::TextureManager::ColorRegion const & colorRegion, m2::PolylineD const & polyline, m2::PointD const & tileCenter, - bool generateCaps, float depth, float vOffset, float minU, - std::vector & staticGeometry); + bool generateCircles, float depth, float vOffset, float minU, + bool isLeftHand, std::vector & staticGeometry, + std::vector & circlesGeometry); void GenerateLineSegment(dp::TextureManager::ColorRegion const & colorRegion, m2::PolylineD const & polyline, m2::PointD const & tileCenter, float depth, std::vector & staticGeometry); @@ -189,17 +218,24 @@ private: void FlushGeometry(TrafficBatcherKey const & key, dp::GLState const & state, drape_ptr && buffer); + void GenerateSegmentsGeometry(MwmSet::MwmId const & mwmId, TileKey const & tileKey, + TrafficSegmentsGeometryValue const & geometry, + traffic::TrafficInfo::Coloring const & coloring, + ref_ptr texturesMgr); TrafficSegmentsColoring m_coloring; std::array(traffic::SpeedGroup::Count)> m_colorsCache; bool m_colorsCacheValid = false; - drape_ptr> m_batchersPool; - TFlushRenderDataFn m_flushRenderDataFn; + using BatcherPoolType = BatchersPool; + drape_ptr m_batchersPool; + drape_ptr m_circlesBatcher; + FlushRenderDataFn m_flushRenderDataFn; dp::AttributeProvider m_providerTriangles; dp::AttributeProvider m_providerLines; + dp::AttributeProvider m_providerCircles; static bool m_simplifiedColorScheme; }; diff --git a/drape_frontend/traffic_renderer.cpp b/drape_frontend/traffic_renderer.cpp index 62edd3e268..66cf4eabb2 100644 --- a/drape_frontend/traffic_renderer.cpp +++ b/drape_frontend/traffic_renderer.cpp @@ -95,37 +95,40 @@ void TrafficRenderer::AddRenderData(ref_ptr mng, TrafficRen { // Remove obsolete render data. TileKey const tileKey(renderData.m_tileKey); - m_renderData.erase(remove_if(m_renderData.begin(), m_renderData.end(), [&tileKey](TrafficRenderData const & rd) + m_renderData.erase(std::remove_if(m_renderData.begin(), m_renderData.end(), + [&tileKey](TrafficRenderData const & rd) { return tileKey == rd.m_tileKey && rd.m_tileKey.m_generation < tileKey.m_generation; }), m_renderData.end()); // Add new render data. - m_renderData.emplace_back(move(renderData)); + m_renderData.emplace_back(std::move(renderData)); TrafficRenderData & rd = m_renderData.back(); auto program = mng->GetProgram(rd.m_state.GetProgram()); program->Bind(); rd.m_bucket->GetBuffer()->Build(program); + + std::sort(m_renderData.begin(), m_renderData.end()); } void TrafficRenderer::OnUpdateViewport(CoverageResult const & coverage, int currentZoomLevel, buffer_vector const & tilesToDelete) { - m_renderData.erase(remove_if(m_renderData.begin(), m_renderData.end(), - [&coverage, ¤tZoomLevel, &tilesToDelete](TrafficRenderData const & rd) + m_renderData.erase(std::remove_if(m_renderData.begin(), m_renderData.end(), + [&coverage, ¤tZoomLevel, &tilesToDelete](TrafficRenderData const & rd) { return rd.m_tileKey.m_zoomLevel == currentZoomLevel && (rd.m_tileKey.m_x < coverage.m_minTileX || rd.m_tileKey.m_x >= coverage.m_maxTileX || rd.m_tileKey.m_y < coverage.m_minTileY || rd.m_tileKey.m_y >= coverage.m_maxTileY || - find(tilesToDelete.begin(), tilesToDelete.end(), rd.m_tileKey) != tilesToDelete.end()); + std::find(tilesToDelete.begin(), tilesToDelete.end(), rd.m_tileKey) != tilesToDelete.end()); }), m_renderData.end()); } void TrafficRenderer::OnGeometryReady(int currentZoomLevel) { - m_renderData.erase(remove_if(m_renderData.begin(), m_renderData.end(), - [¤tZoomLevel](TrafficRenderData const & rd) + m_renderData.erase(std::remove_if(m_renderData.begin(), m_renderData.end(), + [¤tZoomLevel](TrafficRenderData const & rd) { return rd.m_tileKey.m_zoomLevel != currentZoomLevel; }), m_renderData.end()); @@ -159,6 +162,31 @@ void TrafficRenderer::RenderTraffic(ScreenBase const & screen, int zoomLevel, fl } else { + auto const program = renderData.m_state.GetProgram(); + if (program == gpu::Program::TrafficCircle) + { + ref_ptr programPtr = mng->GetProgram(program); + programPtr->Bind(); + dp::ApplyState(renderData.m_state, programPtr); + + gpu::TrafficProgramParams params; + frameValues.SetTo(params); + math::Matrix const mv = renderData.m_tileKey.GetTileBasedModelView(screen); + params.m_modelView = glsl::make_mat4(mv.m_data); + params.m_opacity = opacity; + // Here we reinterpret light/dark colors as left/right sizes by road classes. + params.m_lightArrowColor = glsl::vec3(CalculateHalfWidth(screen, RoadClass::Class0, true /* left */), + CalculateHalfWidth(screen, RoadClass::Class1, true /* left */), + CalculateHalfWidth(screen, RoadClass::Class2, true /* left */)); + params.m_darkArrowColor = glsl::vec3(CalculateHalfWidth(screen, RoadClass::Class0, false /* left */), + CalculateHalfWidth(screen, RoadClass::Class1, false /* left */), + CalculateHalfWidth(screen, RoadClass::Class2, false /* left */)); + mng->GetParamsSetter()->Apply(programPtr, params); + + renderData.m_bucket->Render(false /* draw as line */); + continue; + } + // Filter by road class. int minVisibleArrowZoomLevel = kMinVisibleArrowZoomLevel; float outline = 0.0f; @@ -190,9 +218,9 @@ void TrafficRenderer::RenderTraffic(ScreenBase const & screen, int zoomLevel, fl if (fabs(leftPixelHalfWidth) < kEps && fabs(rightPixelHalfWidth) < kEps) continue; - ref_ptr program = mng->GetProgram(renderData.m_state.GetProgram()); - program->Bind(); - dp::ApplyState(renderData.m_state, program); + ref_ptr programPtr = mng->GetProgram(program); + programPtr->Bind(); + dp::ApplyState(renderData.m_state, programPtr); gpu::TrafficProgramParams params; frameValues.SetTo(params); @@ -205,7 +233,7 @@ void TrafficRenderer::RenderTraffic(ScreenBase const & screen, int zoomLevel, fl params.m_outlineColor = glsl::ToVec3(outlineColor); params.m_trafficParams = glsl::vec4(leftPixelHalfWidth, rightPixelHalfWidth, invLeftPixelLength, zoomLevel >= minVisibleArrowZoomLevel ? 1.0f : 0.0f); - mng->GetParamsSetter()->Apply(program, params); + mng->GetParamsSetter()->Apply(programPtr, params); renderData.m_bucket->Render(false /* draw as line */); } @@ -221,8 +249,8 @@ void TrafficRenderer::Clear(MwmSet::MwmId const & mwmId) { auto removePredicate = [&mwmId](TrafficRenderData const & data) { return data.m_mwmId == mwmId; }; - m_renderData.erase(remove_if(m_renderData.begin(), m_renderData.end(), removePredicate), - m_renderData.end()); + m_renderData.erase(std::remove_if(m_renderData.begin(), m_renderData.end(), removePredicate), + m_renderData.end()); } // static diff --git a/shaders/CMakeLists.txt b/shaders/CMakeLists.txt index 1a61cfbaa2..2c65193980 100644 --- a/shaders/CMakeLists.txt +++ b/shaders/CMakeLists.txt @@ -96,6 +96,8 @@ set( GL/texturing_gui.vsh.glsl GL/traffic.fsh.glsl GL/traffic.vsh.glsl + GL/traffic_circle.fsh.glsl + GL/traffic_circle.vsh.glsl GL/traffic_line.fsh.glsl GL/traffic_line.vsh.glsl GL/transit.fsh.glsl diff --git a/shaders/GL/shader_index.txt b/shaders/GL/shader_index.txt index 26b82eb11a..2514ad6075 100644 --- a/shaders/GL/shader_index.txt +++ b/shaders/GL/shader_index.txt @@ -43,6 +43,7 @@ TextBillboard text_billboard.vsh.glsl text.fsh.glsl TextFixedBillboard text_billboard.vsh.glsl text_fixed.fsh.glsl Traffic traffic.vsh.glsl traffic.fsh.glsl TrafficLine traffic_line.vsh.glsl traffic_line.fsh.glsl +TrafficCircle traffic_circle.vsh.glsl traffic_circle.fsh.glsl SmaaEdges smaa_edges.vsh.glsl smaa_edges.fsh.glsl SmaaBlendingWeight smaa_blending_weight.vsh.glsl smaa_blending_weight.fsh.glsl SmaaFinal smaa_final.vsh.glsl smaa_final.fsh.glsl diff --git a/shaders/GL/traffic_circle.fsh.glsl b/shaders/GL/traffic_circle.fsh.glsl new file mode 100644 index 0000000000..e26402112d --- /dev/null +++ b/shaders/GL/traffic_circle.fsh.glsl @@ -0,0 +1,23 @@ +// Warning! Beware to use this shader. "discard" command may significally reduce performance. +// Unfortunately some CG algorithms cannot be implemented on OpenGL ES 2.0 without discarding +// fragments from depth buffer. + +varying vec2 v_colorTexCoord; +varying vec3 v_radius; + +uniform sampler2D u_colorTex; +uniform float u_opacity; + +const float kAntialiasingThreshold = 0.92; + +void main() +{ + vec4 color = texture2D(u_colorTex, v_colorTexCoord); + float smallRadius = v_radius.z * kAntialiasingThreshold; + float stepValue = smoothstep(smallRadius * smallRadius, v_radius.z * v_radius.z, + v_radius.x * v_radius.x + v_radius.y * v_radius.y); + color.a = u_opacity * (1.0 - stepValue); + if (color.a < 0.01) + discard; + gl_FragColor = color; +} diff --git a/shaders/GL/traffic_circle.vsh.glsl b/shaders/GL/traffic_circle.vsh.glsl new file mode 100644 index 0000000000..914f0ba838 --- /dev/null +++ b/shaders/GL/traffic_circle.vsh.glsl @@ -0,0 +1,36 @@ +attribute vec4 a_position; +attribute vec4 a_normal; +attribute vec2 a_colorTexCoord; + +uniform mat4 u_modelView; +uniform mat4 u_projection; +uniform mat4 u_pivotTransform; + +uniform vec3 u_lightArrowColor; // Here we store left sizes by road classes. +uniform vec3 u_darkArrowColor; // Here we store right sizes by road classes. + +varying vec2 v_colorTexCoord; +varying vec3 v_radius; + +void main() +{ + vec2 normal = a_normal.xy; + vec2 transformedAxisPos = (vec4(a_position.xy, 0.0, 1.0) * u_modelView).xy; + int index = int(a_position.w); + float leftSize = u_lightArrowColor[index]; + float rightSize = u_darkArrowColor[index]; + if (dot(normal, normal) != 0.0) + { + // offset by normal = rightVec * (rightSize - leftSize) / 2 + vec2 norm = normal * 0.5 * (rightSize - leftSize); + transformedAxisPos = calcLineTransformedAxisPos(transformedAxisPos, a_position.xy + norm, + u_modelView, length(norm)); + } + // radius = (leftSize + rightSize) / 2 + v_radius = vec3(a_normal.zw, 1.0) * 0.5 * (leftSize + rightSize); + + vec2 finalPos = transformedAxisPos + v_radius.xy; + v_colorTexCoord = a_colorTexCoord; + vec4 pos = vec4(finalPos, a_position.z, 1.0) * u_projection; + gl_Position = applyPivotTransform(pos, u_pivotTransform, 0.0); +} diff --git a/shaders/program_params.hpp b/shaders/program_params.hpp index 4dd1077bff..3ea1478c90 100644 --- a/shaders/program_params.hpp +++ b/shaders/program_params.hpp @@ -118,7 +118,8 @@ struct TrafficProgramParams BIND_PROGRAMS(TrafficProgramParams, Program::Traffic, - Program::TrafficLine) + Program::TrafficLine, + Program::TrafficCircle) }; struct TransitProgramParams @@ -163,7 +164,7 @@ struct ShapesProgramParams float m_opacity = 1.0f; float m_azimut = 0.0; - BIND_PROGRAMS(AccuracyProgramParams, + BIND_PROGRAMS(ShapesProgramParams, Program::Accuracy, Program::MyPosition) }; diff --git a/shaders/programs.hpp b/shaders/programs.hpp index 1a5379b141..0510369343 100644 --- a/shaders/programs.hpp +++ b/shaders/programs.hpp @@ -54,6 +54,7 @@ enum class Program TextFixedBillboard, Traffic, TrafficLine, + TrafficCircle, SmaaEdges, SmaaBlendingWeight, SmaaFinal, @@ -110,6 +111,7 @@ inline std::string DebugPrint(Program p) case Program::TextFixedBillboard: return "TextFixedBillboard"; case Program::Traffic: return "Traffic"; case Program::TrafficLine: return "TrafficLine"; + case Program::TrafficCircle: return "TrafficCircle"; case Program::SmaaEdges: return "SmaaEdges"; case Program::SmaaBlendingWeight: return "SmaaBlendingWeight"; case Program::SmaaFinal: return "SmaaFinal";