diff options
author | Karim Naaji <karim.naaji@gmail.com> | 2020-06-01 18:47:36 -0700 |
---|---|---|
committer | Karim Naaji <karim.naaji@gmail.com> | 2020-06-04 10:04:06 -0700 |
commit | cb51b7cb60afa007532c02928a57e6e2a99222f5 (patch) | |
tree | b5daf0a2bbcf9c23a6150fc05197de508d6f16d2 | |
parent | 6bd46c1a3e9e0c9ab5c44f391f5c541ab3e87bf7 (diff) | |
download | qtlocation-mapboxgl-cb51b7cb60afa007532c02928a57e6e2a99222f5.tar.gz |
Port of https://github.com/mapbox/mapbox-gl-js/pull/9694
32 files changed, 294 insertions, 106 deletions
diff --git a/platform/glfw/glfw_view.cpp b/platform/glfw/glfw_view.cpp index 2eb98b113d..2488c1ce3b 100644 --- a/platform/glfw/glfw_view.cpp +++ b/platform/glfw/glfw_view.cpp @@ -25,6 +25,8 @@ #include <mbgl/util/logging.hpp> #include <mbgl/util/platform.hpp> #include <mbgl/util/string.hpp> +#include <mbgl/style/conversion/color_ramp_property_value.hpp> +#include <mbgl/style/conversion/json.hpp> #include <mapbox/cheap_ruler.hpp> #include <mapbox/geometry.hpp> @@ -408,6 +410,38 @@ void GLFWView::onKey(GLFWwindow *window, int key, int /*scancode*/, int action, case GLFW_KEY_T: view->toggleCustomSource(); break; + case GLFW_KEY_V: { + using namespace mbgl; + using namespace mbgl::style; + auto &style = view->map->getStyle(); + if (!style.getSource("line-gradient-source")) { + std::string url = "https://gist.githubusercontent.com/karimnaaji/0ea3016a825a4c2883fce309183f0c20/raw/9f67d55c3c797b8b1183dc27a26ec705ac619198/polylines.geojson"; + GeoJSONOptions options; + options.lineMetrics = true; + auto source = std::make_unique<GeoJSONSource>("line-gradient-source", Immutable<GeoJSONOptions>(makeMutable<GeoJSONOptions>(options))); + source->setURL(url); + style.addSource(std::move(source)); + + mbgl::CameraOptions cameraOptions; + cameraOptions.center = mbgl::LatLng{38.888, -77.01866}; + cameraOptions.zoom = 12.5; + cameraOptions.pitch = 0; + cameraOptions.bearing = 0; + view->map->jumpTo(cameraOptions); + } + + if (!style.getLayer("line-gradient")) { + auto lineLayer = std::make_unique<LineLayer>("line-gradient", "line-gradient-source"); + lineLayer->setLineWidth(PropertyValue<float>(14.0f)); + std::string rawValue = R"JSON(["step",["line-progress"],"rgba(0, 0, 255, 0.1)",0.25,"red",0.6,"yellow"])JSON"; + //std::string rawValue = R"JSON(["interpolate",["linear"],["line-progress"],0,"rgba(0, 0, 255, 0)",0.1,"royalblue",0.3,"cyan",0.5,"lime",0.7,"yellow",1,"red"])JSON"; + conversion::Error error; + auto ramp = conversion::convertJSON<ColorRampPropertyValue>(rawValue, error); + lineLayer->setLineGradient(ramp.value()); + style.addLayer(std::move(lineLayer)); + } + } + break; case GLFW_KEY_F: { using namespace mbgl; using namespace mbgl::style; diff --git a/src/mbgl/gfx/context.hpp b/src/mbgl/gfx/context.hpp index 75670c4c59..d6511a8db7 100644 --- a/src/mbgl/gfx/context.hpp +++ b/src/mbgl/gfx/context.hpp @@ -27,6 +27,7 @@ public: static constexpr const uint32_t minimumRequiredVertexBindingCount = 8; const uint32_t maximumVertexBindingCount; bool supportsHalfFloatTextures = false; + static int32_t maxTextureSize; public: Context(Context&&) = delete; diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index 9c7898cc1d..6e8b4591e8 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -16,6 +16,11 @@ #include <cstring> namespace mbgl { + +namespace gfx { +int32_t Context::maxTextureSize; +} // namespace gfx + namespace gl { using namespace platform; @@ -65,7 +70,7 @@ Context::~Context() { } } -void Context::initializeExtensions(const std::function<gl::ProcAddress(const char*)>& getProcAddress) { +void Context::initialize(const std::function<gl::ProcAddress(const char*)>& getProcAddress) { if (const auto* extensions = reinterpret_cast<const char*>(MBGL_CHECK_ERROR(glGetString(GL_EXTENSIONS)))) { @@ -123,6 +128,8 @@ void Context::initializeExtensions(const std::function<gl::ProcAddress(const cha Log::Warning(Event::OpenGL, "Not using Vertex Array Objects"); } } + + MBGL_CHECK_ERROR(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &Context::maxTextureSize)); } void Context::enableDebugging() { diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp index f9ca036d2c..b226ac3315 100644 --- a/src/mbgl/gl/context.hpp +++ b/src/mbgl/gl/context.hpp @@ -46,7 +46,7 @@ public: gfx::RenderingStats& renderingStats(); const gfx::RenderingStats& renderingStats() const override; - void initializeExtensions(const std::function<gl::ProcAddress(const char*)>&); + void initialize(const std::function<gl::ProcAddress(const char*)>&); void enableDebugging(); diff --git a/src/mbgl/gl/defines.hpp b/src/mbgl/gl/defines.hpp index 52dc92d230..a4d3d263d0 100644 --- a/src/mbgl/gl/defines.hpp +++ b/src/mbgl/gl/defines.hpp @@ -164,6 +164,7 @@ #define GL_VERTEX_SHADER 0x8B31 #define GL_VIEWPORT 0x0BA2 #define GL_ZERO 0 +#define GL_MAX_TEXTURE_SIZE 0x0D33 #ifdef MBGL_USE_GLES2 #define GL_HALF_FLOAT 0x8D61 #else diff --git a/src/mbgl/gl/renderer_backend.cpp b/src/mbgl/gl/renderer_backend.cpp index 1f52ce06a9..04e123e38d 100644 --- a/src/mbgl/gl/renderer_backend.cpp +++ b/src/mbgl/gl/renderer_backend.cpp @@ -15,7 +15,7 @@ RendererBackend::RendererBackend(const gfx::ContextMode contextMode_) std::unique_ptr<gfx::Context> RendererBackend::createContext() { auto result = std::make_unique<gl::Context>(*this); result->enableDebugging(); - result->initializeExtensions( + result->initialize( std::bind(&RendererBackend::getExtensionFunctionPointer, this, std::placeholders::_1)); return result; } diff --git a/src/mbgl/programs/collision_box_program.hpp b/src/mbgl/programs/collision_box_program.hpp index 9ba9679566..43d57303e1 100644 --- a/src/mbgl/programs/collision_box_program.hpp +++ b/src/mbgl/programs/collision_box_program.hpp @@ -67,7 +67,7 @@ public: const gfx::VertexBuffer<gfx::Vertex<CollisionBoxLayoutAttributes>>& layoutVertexBuffer, const gfx::VertexBuffer<gfx::Vertex<CollisionBoxDynamicAttributes>>& dynamicVertexBuffer, const gfx::IndexBuffer& indexBuffer, - const SegmentVector<AttributeList>& segments, + const SegmentVector& segments, const Binders& paintPropertyBinders, const typename PaintProperties::PossiblyEvaluated& currentProperties, const TextureBindings& textureBindings, @@ -152,7 +152,7 @@ public: const gfx::VertexBuffer<gfx::Vertex<CollisionBoxLayoutAttributes>>& layoutVertexBuffer, const gfx::VertexBuffer<gfx::Vertex<CollisionBoxDynamicAttributes>>& dynamicVertexBuffer, const gfx::IndexBuffer& indexBuffer, - const SegmentVector<AttributeList>& segments, + const SegmentVector& segments, const Binders& paintPropertyBinders, const typename PaintProperties::PossiblyEvaluated& currentProperties, const TextureBindings& textureBindings, diff --git a/src/mbgl/programs/line_program.cpp b/src/mbgl/programs/line_program.cpp index c808a95c0d..6ea38deed7 100644 --- a/src/mbgl/programs/line_program.cpp +++ b/src/mbgl/programs/line_program.cpp @@ -114,13 +114,15 @@ LineGradientProgram::LayoutUniformValues LineGradientProgram::layoutUniformValue const RenderTile& tile, const TransformState& state, const std::array<float, 2>& pixelsToGLUnits, - const float pixelRatio) { + const float pixelRatio, + const float imageHeight) { return makeValues<LineGradientProgram::LayoutUniformValues>( properties, tile, state, pixelsToGLUnits, - pixelRatio + pixelRatio, + imageHeight ); } diff --git a/src/mbgl/programs/line_program.hpp b/src/mbgl/programs/line_program.hpp index 145ac9d6cf..8b9eaf76a8 100644 --- a/src/mbgl/programs/line_program.hpp +++ b/src/mbgl/programs/line_program.hpp @@ -24,12 +24,24 @@ MBGL_DEFINE_UNIFORM_SCALAR(float, sdfgamma); MBGL_DEFINE_UNIFORM_VECTOR(float, 2, patternscale_a); MBGL_DEFINE_UNIFORM_VECTOR(float, 2, patternscale_b); MBGL_DEFINE_UNIFORM_VECTOR(float, 2, units_to_pixels); +MBGL_DEFINE_UNIFORM_SCALAR(float, image_height); } // namespace uniforms +namespace attributes { +MBGL_DEFINE_ATTRIBUTE(float, 1, line_progress); +MBGL_DEFINE_ATTRIBUTE(float, 1, line_clip); +MBGL_DEFINE_ATTRIBUTE(uint32_t, 1, split_index); +} // namespace attributes + using LineLayoutAttributes = TypeList< attributes::pos_normal, attributes::data<uint8_t, 4>>; +using LineLayoutAttributesExt = TypeList< + attributes::line_progress, + attributes::line_clip, + attributes::split_index>; + class LineProgram : public Program< LineProgram, gfx::PrimitiveType::Triangle, @@ -157,6 +169,10 @@ public: float atlasWidth); }; +using LineLayoutVertex = LineProgram::LayoutVertex; +using LineAttributes = LineProgram::AttributeList; +using LineLayoutVertexExt = gfx::Vertex<LineLayoutAttributesExt>; + class LineGradientProgram : public Program< LineGradientProgram, gfx::PrimitiveType::Triangle, @@ -165,10 +181,12 @@ class LineGradientProgram : public Program< uniforms::matrix, uniforms::ratio, uniforms::units_to_pixels, - uniforms::device_pixel_ratio>, + uniforms::device_pixel_ratio, + uniforms::image_height>, TypeList< textures::image>, - style::LinePaintProperties> + style::LinePaintProperties, + LineLayoutAttributesExt> { public: using Program::Program; @@ -177,12 +195,20 @@ public: const RenderTile&, const TransformState&, const std::array<float, 2>& pixelsToGLUnits, - float pixelRatio); + float pixelRatio, + float imageHeight); + + static AttributeBindings computeAllAttributeBindings( + const gfx::VertexBuffer<LineProgram::LayoutVertex>& layoutVertexBuffer, + const gfx::VertexBuffer<gfx::Vertex<LineLayoutAttributesExt>>& layoutVertexBufferExt, + const Binders& paintPropertyBinders, + const typename PaintProperties::PossiblyEvaluated& currentProperties) { + return gfx::AttributeBindings<LineLayoutAttributes>(layoutVertexBuffer) + .concat(paintPropertyBinders.attributeBindings(currentProperties)) + .concat(gfx::AttributeBindings<LineLayoutAttributesExt>(layoutVertexBufferExt)); + } }; -using LineLayoutVertex = LineProgram::LayoutVertex; -using LineAttributes = LineProgram::AttributeList; - class LineLayerPrograms final : public LayerTypePrograms { public: LineLayerPrograms(gfx::Context& context, const ProgramParameters& programParameters) diff --git a/src/mbgl/programs/program.hpp b/src/mbgl/programs/program.hpp index 9f833a774d..8d6b140929 100644 --- a/src/mbgl/programs/program.hpp +++ b/src/mbgl/programs/program.hpp @@ -23,7 +23,8 @@ template <class Name, class LayoutAttributeList, class LayoutUniformList, class Textures, - class PaintProps> + class PaintProps, + class LayoutAttributeListExt = TypeList<>> class Program { public: using LayoutVertex = gfx::Vertex<LayoutAttributeList>; @@ -32,7 +33,7 @@ public: using Binders = PaintPropertyBinders<typename PaintProperties::DataDrivenProperties>; using PaintAttributeList = typename Binders::AttributeList; - using AttributeList = TypeListConcat<LayoutAttributeList, PaintAttributeList>; + using AttributeList = TypeListConcat<LayoutAttributeList, PaintAttributeList, LayoutAttributeListExt>; using AttributeBindings = gfx::AttributeBindings<AttributeList>; using PaintUniformList = typename Binders::UniformList; @@ -79,7 +80,7 @@ public: const gfx::ColorMode& colorMode, const gfx::CullFaceMode& cullFaceMode, const gfx::IndexBuffer& indexBuffer, - const Segment<AttributeList>& segment, + const Segment& segment, const UniformValues& uniformValues, const AttributeBindings& allAttributeBindings, const TextureBindings& textureBindings, @@ -120,7 +121,7 @@ public: const gfx::ColorMode& colorMode, const gfx::CullFaceMode& cullFaceMode, const gfx::IndexBuffer& indexBuffer, - const SegmentVector<AttributeList>& segments, + const SegmentVector& segments, const UniformValues& uniformValues, const AttributeBindings& allAttributeBindings, const TextureBindings& textureBindings, diff --git a/src/mbgl/programs/segment.hpp b/src/mbgl/programs/segment.hpp index 908c0b5f3b..21e50c5558 100644 --- a/src/mbgl/programs/segment.hpp +++ b/src/mbgl/programs/segment.hpp @@ -8,7 +8,6 @@ namespace mbgl { -template <class AttributeList> class Segment { public: Segment(std::size_t vertexOffset_, @@ -47,7 +46,6 @@ public: float sortKey; }; -template <class AttributeList> -using SegmentVector = std::vector<Segment<AttributeList>>; +using SegmentVector = std::vector<Segment>; } // namespace mbgl diff --git a/src/mbgl/programs/symbol_program.hpp b/src/mbgl/programs/symbol_program.hpp index 848fc0b001..3dd5565c7c 100644 --- a/src/mbgl/programs/symbol_program.hpp +++ b/src/mbgl/programs/symbol_program.hpp @@ -311,7 +311,7 @@ public: const gfx::ColorMode& colorMode, const gfx::CullFaceMode& cullFaceMode, const gfx::IndexBuffer& indexBuffer, - const Segment<AttributeList>& segment, + const Segment& segment, const UniformValues& uniformValues, const AttributeBindings& allAttributeBindings, const TextureBindings& textureBindings, @@ -353,7 +353,7 @@ public: const gfx::ColorMode& colorMode, const gfx::CullFaceMode& cullFaceMode, const gfx::IndexBuffer& indexBuffer, - const SegmentVector<AttributeList>& segments, + const SegmentVector& segments, const UniformValues& uniformValues, const AttributeBindings& allAttributeBindings, const TextureBindings& textureBindings, diff --git a/src/mbgl/renderer/buckets/circle_bucket.hpp b/src/mbgl/renderer/buckets/circle_bucket.hpp index 1abd9c77f6..3f1d1a2703 100644 --- a/src/mbgl/renderer/buckets/circle_bucket.hpp +++ b/src/mbgl/renderer/buckets/circle_bucket.hpp @@ -32,7 +32,7 @@ public: gfx::VertexVector<CircleLayoutVertex> vertices; gfx::IndexVector<gfx::Triangles> triangles; - SegmentVector<CircleAttributes> segments; + SegmentVector segments; optional<gfx::VertexBuffer<CircleLayoutVertex>> vertexBuffer; optional<gfx::IndexBuffer> indexBuffer; diff --git a/src/mbgl/renderer/buckets/debug_bucket.hpp b/src/mbgl/renderer/buckets/debug_bucket.hpp index fb79cc834b..b10e6d98e0 100644 --- a/src/mbgl/renderer/buckets/debug_bucket.hpp +++ b/src/mbgl/renderer/buckets/debug_bucket.hpp @@ -35,8 +35,8 @@ public: gfx::VertexVector<FillLayoutVertex> vertices; gfx::IndexVector<gfx::Lines> indices; - SegmentVector<DebugAttributes> segments; - SegmentVector<DebugAttributes> tileBorderSegments; + SegmentVector segments; + SegmentVector tileBorderSegments; optional<gfx::VertexBuffer<DebugLayoutVertex>> vertexBuffer; optional<gfx::IndexBuffer> indexBuffer; optional<gfx::Texture> texture; diff --git a/src/mbgl/renderer/buckets/fill_bucket.hpp b/src/mbgl/renderer/buckets/fill_bucket.hpp index 2812e1fde0..78bd4ea72a 100644 --- a/src/mbgl/renderer/buckets/fill_bucket.hpp +++ b/src/mbgl/renderer/buckets/fill_bucket.hpp @@ -43,8 +43,8 @@ public: gfx::VertexVector<FillLayoutVertex> vertices; gfx::IndexVector<gfx::Lines> lines; gfx::IndexVector<gfx::Triangles> triangles; - SegmentVector<FillAttributes> lineSegments; - SegmentVector<FillAttributes> triangleSegments; + SegmentVector lineSegments; + SegmentVector triangleSegments; optional<gfx::VertexBuffer<FillLayoutVertex>> vertexBuffer; optional<gfx::IndexBuffer> lineIndexBuffer; diff --git a/src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp b/src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp index 7143d4326d..dfa0660cd2 100644 --- a/src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp +++ b/src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp @@ -41,7 +41,7 @@ public: gfx::VertexVector<FillExtrusionLayoutVertex> vertices; gfx::IndexVector<gfx::Triangles> triangles; - SegmentVector<FillExtrusionAttributes> triangleSegments; + SegmentVector triangleSegments; optional<gfx::VertexBuffer<FillExtrusionLayoutVertex>> vertexBuffer; optional<gfx::IndexBuffer> indexBuffer; diff --git a/src/mbgl/renderer/buckets/heatmap_bucket.hpp b/src/mbgl/renderer/buckets/heatmap_bucket.hpp index 0aaff7f298..a75c6efa08 100644 --- a/src/mbgl/renderer/buckets/heatmap_bucket.hpp +++ b/src/mbgl/renderer/buckets/heatmap_bucket.hpp @@ -32,7 +32,7 @@ public: gfx::VertexVector<HeatmapLayoutVertex> vertices; gfx::IndexVector<gfx::Triangles> triangles; - SegmentVector<HeatmapAttributes> segments; + SegmentVector segments; optional<gfx::VertexBuffer<HeatmapLayoutVertex>> vertexBuffer; optional<gfx::IndexBuffer> indexBuffer; diff --git a/src/mbgl/renderer/buckets/hillshade_bucket.hpp b/src/mbgl/renderer/buckets/hillshade_bucket.hpp index 60f529916b..822559bf2d 100644 --- a/src/mbgl/renderer/buckets/hillshade_bucket.hpp +++ b/src/mbgl/renderer/buckets/hillshade_bucket.hpp @@ -47,7 +47,7 @@ public: // Raster-DEM Tile Sources use the default buffers from Painter gfx::VertexVector<HillshadeLayoutVertex> vertices; gfx::IndexVector<gfx::Triangles> indices; - SegmentVector<HillshadeAttributes> segments; + SegmentVector segments; optional<gfx::VertexBuffer<HillshadeLayoutVertex>> vertexBuffer; optional<gfx::IndexBuffer> indexBuffer; diff --git a/src/mbgl/renderer/buckets/line_bucket.cpp b/src/mbgl/renderer/buckets/line_bucket.cpp index 256ce35eb5..1cd1f13851 100644 --- a/src/mbgl/renderer/buckets/line_bucket.cpp +++ b/src/mbgl/renderer/buckets/line_bucket.cpp @@ -15,7 +15,7 @@ LineBucket::LineBucket(LineBucket::PossiblyEvaluatedLayoutProperties layout_, const std::map<std::string, Immutable<LayerProperties>>& layerPaintProperties, const float zoom_, const uint32_t overscaling_) - : layout(std::move(layout_)), zoom(zoom_), overscaling(overscaling_) { + : layout(std::move(layout_)), gradientVersion(0), maxLineLength(0.0), zoom(zoom_), overscaling(overscaling_) { for (const auto& pair : layerPaintProperties) { paintPropertyBinders.emplace( std::piecewise_construct, @@ -34,6 +34,7 @@ void LineBucket::addFeature(const GeometryTileFeature& feature, const PatternLayerMap& patternDependencies, std::size_t index, const CanonicalTileID& canonical) { + lineClips.reserve(geometryCollection.size()); for (auto& line : geometryCollection) { addGeometry(line, feature, canonical); } @@ -92,7 +93,15 @@ public: return (relativeTileDistance * (clipEnd - clipStart) + clipStart) * (MAX_LINE_DISTANCE - 1); } -private: + double lineDistance(double tileDistance) const { + double relativeTileDistance = tileDistance / total; + if (std::isinf(relativeTileDistance) || std::isnan(relativeTileDistance)) { + assert(false); + relativeTileDistance = 0.0; + } + return relativeTileDistance * (clipEnd - clipStart) + clipStart; + } + double clipStart; double clipEnd; double total; @@ -136,8 +145,10 @@ void LineBucket::addGeometry(const GeometryCoordinates& coordinates, total_length += util::dist<double>(coordinates[i], coordinates[i + 1]); } + maxLineLength = std::max<double>(maxLineLength, total_length); lineDistances = Distances{ *numericValue<double>(clip_start_it->second), *numericValue<double>(clip_end_it->second), total_length}; + lineClips.push_back(LineClip{ lineDistances->clipStart, lineDistances->clipEnd }); } const LineJoinType joinType = layout.evaluate<LineJoin>(zoom, feature, canonical); @@ -466,6 +477,13 @@ void LineBucket::addCurrentVertex(const GeometryCoordinate& currentCoordinate, if (endLeft) extrude = extrude - (util::perp(normal) * endLeft); vertices.emplace_back(LineProgram::layoutVertex(currentCoordinate, extrude, round, false, endLeft, scaledDistance * LINE_DISTANCE_SCALE)); + if (lineDistances) { + vertices2.emplace_back(LineLayoutVertexExt { + { static_cast<float>(lineDistances->lineDistance(distance) - lineDistances->clipStart) }, + { static_cast<float>(lineDistances->clipEnd - lineDistances->clipStart) }, + { static_cast<uint32_t>(lineClips.size()) } + }); + } e3 = vertices.elements() - 1 - startVertex; if (e1 >= 0 && e2 >= 0) { triangleStore.emplace_back(e1, e2, e3); @@ -477,6 +495,13 @@ void LineBucket::addCurrentVertex(const GeometryCoordinate& currentCoordinate, if (endRight) extrude = extrude - (util::perp(normal) * endRight); vertices.emplace_back(LineProgram::layoutVertex(currentCoordinate, extrude, round, true, -endRight, scaledDistance * LINE_DISTANCE_SCALE)); + if (lineDistances) { + vertices2.emplace_back(LineLayoutVertexExt { + { static_cast<float>(lineDistances->lineDistance(distance) - lineDistances->clipStart) }, + { static_cast<float>(lineDistances->clipEnd - lineDistances->clipStart) }, + { static_cast<uint32_t>(lineClips.size()) } + }); + } e3 = vertices.elements() - 1 - startVertex; if (e1 >= 0 && e2 >= 0) { triangleStore.emplace_back(e1, e2, e3); @@ -507,6 +532,7 @@ void LineBucket::addPieSliceVertex(const GeometryCoordinate& currentVertex, } vertices.emplace_back(LineProgram::layoutVertex(currentVertex, flippedExtrude, false, lineTurnsLeft, 0, distance * LINE_DISTANCE_SCALE)); + vertices2.emplace_back(LineLayoutVertexExt{}); e3 = vertices.elements() - 1 - startVertex; if (e1 >= 0 && e2 >= 0) { triangleStore.emplace_back(e1, e2, e3); @@ -521,6 +547,9 @@ void LineBucket::addPieSliceVertex(const GeometryCoordinate& currentVertex, void LineBucket::upload(gfx::UploadPass& uploadPass) { if (!uploaded) { + if (vertices2.elements() > 0) { + vertexBuffer2 = uploadPass.createVertexBuffer(std::move(vertices2)); + } vertexBuffer = uploadPass.createVertexBuffer(std::move(vertices)); indexBuffer = uploadPass.createIndexBuffer(std::move(triangles)); } diff --git a/src/mbgl/renderer/buckets/line_bucket.hpp b/src/mbgl/renderer/buckets/line_bucket.hpp index 48092f41c0..2fb69c7753 100644 --- a/src/mbgl/renderer/buckets/line_bucket.hpp +++ b/src/mbgl/renderer/buckets/line_bucket.hpp @@ -44,10 +44,23 @@ public: gfx::VertexVector<LineLayoutVertex> vertices; gfx::IndexVector<gfx::Triangles> triangles; - SegmentVector<LineAttributes> segments; + SegmentVector segments; optional<gfx::VertexBuffer<LineLayoutVertex>> vertexBuffer; + gfx::VertexVector<LineLayoutVertexExt> vertices2; + optional<gfx::VertexBuffer<LineLayoutVertexExt>> vertexBuffer2; + optional<gfx::Texture> gradientTexture; optional<gfx::IndexBuffer> indexBuffer; + optional<PremultipliedImage> gradientColorRamp; + + uint32_t gradientVersion; + double maxLineLength; + + struct LineClip { + double start; + double end; + }; + std::vector<LineClip> lineClips; std::map<std::string, LineProgram::Binders> paintPropertyBinders; diff --git a/src/mbgl/renderer/buckets/raster_bucket.hpp b/src/mbgl/renderer/buckets/raster_bucket.hpp index 0fa3c4299e..a72fb96ea1 100644 --- a/src/mbgl/renderer/buckets/raster_bucket.hpp +++ b/src/mbgl/renderer/buckets/raster_bucket.hpp @@ -33,7 +33,7 @@ public: // Raster Tile Sources use the default buffers from Painter gfx::VertexVector<RasterLayoutVertex> vertices; gfx::IndexVector<gfx::Triangles> indices; - SegmentVector<RasterAttributes> segments; + SegmentVector segments; optional<gfx::VertexBuffer<RasterLayoutVertex>> vertexBuffer; optional<gfx::IndexBuffer> indexBuffer; diff --git a/src/mbgl/renderer/buckets/symbol_bucket.hpp b/src/mbgl/renderer/buckets/symbol_bucket.hpp index c6a07dde1c..d33241d46d 100644 --- a/src/mbgl/renderer/buckets/symbol_bucket.hpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.hpp @@ -136,7 +136,7 @@ public: gfx::VertexVector<gfx::Vertex<SymbolDynamicLayoutAttributes>> dynamicVertices; gfx::VertexVector<gfx::Vertex<SymbolOpacityAttributes>> opacityVertices; gfx::IndexVector<gfx::Triangles> triangles; - SegmentVector<SymbolTextAttributes> segments; + SegmentVector segments; std::vector<PlacedSymbol> placedSymbols; optional<gfx::VertexBuffer<SymbolLayoutVertex>> vertexBuffer; @@ -153,7 +153,7 @@ public: struct CollisionBuffer { gfx::VertexVector<gfx::Vertex<CollisionBoxLayoutAttributes>> vertices; gfx::VertexVector<gfx::Vertex<CollisionBoxDynamicAttributes>> dynamicVertices; - SegmentVector<CollisionBoxProgram::AttributeList> segments; + SegmentVector segments; optional<gfx::VertexBuffer<gfx::Vertex<CollisionBoxLayoutAttributes>>> vertexBuffer; optional<gfx::VertexBuffer<gfx::Vertex<CollisionBoxDynamicAttributes>>> dynamicVertexBuffer; diff --git a/src/mbgl/renderer/layers/render_background_layer.hpp b/src/mbgl/renderer/layers/render_background_layer.hpp index dab733172b..00198b0a73 100644 --- a/src/mbgl/renderer/layers/render_background_layer.hpp +++ b/src/mbgl/renderer/layers/render_background_layer.hpp @@ -23,7 +23,7 @@ private: // Paint properties style::BackgroundPaintProperties::Unevaluated unevaluated; - SegmentVector<BackgroundAttributes> segments; + SegmentVector segments; }; } // namespace mbgl diff --git a/src/mbgl/renderer/layers/render_circle_layer.cpp b/src/mbgl/renderer/layers/render_circle_layer.cpp index ffcc0be1b5..3f8fbbf1fd 100644 --- a/src/mbgl/renderer/layers/render_circle_layer.cpp +++ b/src/mbgl/renderer/layers/render_circle_layer.cpp @@ -18,13 +18,13 @@ using namespace style; namespace { struct RenderableSegment { - RenderableSegment(const Segment<CircleAttributes>& segment_, + RenderableSegment(const Segment& segment_, const RenderTile& tile_, const LayerRenderData* renderData_, float sortKey_) : segment(segment_), tile(tile_), renderData(renderData_), sortKey(sortKey_) {} - const Segment<CircleAttributes>& segment; + const Segment& segment; const RenderTile& tile; const LayerRenderData* renderData; const float sortKey; diff --git a/src/mbgl/renderer/layers/render_heatmap_layer.hpp b/src/mbgl/renderer/layers/render_heatmap_layer.hpp index 7085a87c90..bb1ccd5578 100644 --- a/src/mbgl/renderer/layers/render_heatmap_layer.hpp +++ b/src/mbgl/renderer/layers/render_heatmap_layer.hpp @@ -37,7 +37,7 @@ private: PremultipliedImage colorRamp; std::unique_ptr<gfx::OffscreenTexture> renderTexture; optional<gfx::Texture> colorRampTexture; - SegmentVector<HeatmapTextureAttributes> segments; + SegmentVector segments; }; } // namespace mbgl diff --git a/src/mbgl/renderer/layers/render_line_layer.cpp b/src/mbgl/renderer/layers/render_line_layer.cpp index b03ac8027b..b0ff011447 100644 --- a/src/mbgl/renderer/layers/render_line_layer.cpp +++ b/src/mbgl/renderer/layers/render_line_layer.cpp @@ -7,7 +7,6 @@ #include <mbgl/renderer/image_manager.hpp> #include <mbgl/renderer/layers/render_line_layer.hpp> #include <mbgl/renderer/paint_parameters.hpp> -#include <mbgl/renderer/render_source.hpp> #include <mbgl/renderer/render_tile.hpp> #include <mbgl/renderer/upload_parameters.hpp> #include <mbgl/style/expression/image.hpp> @@ -16,6 +15,8 @@ #include <mbgl/tile/tile.hpp> #include <mbgl/util/intersection_tests.hpp> #include <mbgl/util/math.hpp> +#include <mbgl/math/log2.hpp> +#include <mbgl/math/clamp.hpp> namespace mbgl { @@ -33,13 +34,14 @@ inline const LineLayer::Impl& impl_cast(const Immutable<style::Layer::Impl>& imp RenderLineLayer::RenderLineLayer(Immutable<style::LineLayer::Impl> _impl) : RenderLayer(makeMutable<LineLayerProperties>(std::move(_impl))), unevaluated(impl_cast(baseImpl).paint.untransitioned()), - colorRamp({256, 1}) {} + gradientVersion(0), + samplerFiler(gfx::TextureFilterType::Linear) {} RenderLineLayer::~RenderLineLayer() = default; void RenderLineLayer::transition(const TransitionParameters& parameters) { unevaluated = impl_cast(baseImpl).paint.transitioned(parameters, std::move(unevaluated)); - updateColorRamp(); + gradientVersion = (gradientVersion + 1) % std::numeric_limits<uint32_t>::max(); } void RenderLineLayer::evaluate(const PropertyEvaluationParameters& parameters) { @@ -72,20 +74,35 @@ void RenderLineLayer::prepare(const LayerPrepareParameters& params) { if (!renderData) continue; const auto& evaluated = getEvaluated<LineLayerProperties>(renderData->layerProperties); - if (evaluated.get<LineDasharray>().from.empty()) continue; - auto& bucket = static_cast<LineBucket&>(*renderData->bucket); - const LinePatternCap cap = bucket.layout.get<LineCap>() == LineCapType::Round - ? LinePatternCap::Round : LinePatternCap::Square; - // Ensures that the dash data gets added to the atlas. - params.lineAtlas.getDashPatternTexture( - evaluated.get<LineDasharray>().from, evaluated.get<LineDasharray>().to, cap); + if (!evaluated.get<LineDasharray>().from.empty()) { + const LinePatternCap cap = bucket.layout.get<LineCap>() == LineCapType::Round + ? LinePatternCap::Round : LinePatternCap::Square; + // Ensures that the dash data gets added to the atlas. + params.lineAtlas.getDashPatternTexture( + evaluated.get<LineDasharray>().from, evaluated.get<LineDasharray>().to, cap); + } else if (!unevaluated.get<LineGradient>().getValue().isUndefined()) { + updateColorRamp(bucket, tile, *params.source, params.state); + } } } void RenderLineLayer::upload(gfx::UploadPass& uploadPass) { - if (!unevaluated.get<LineGradient>().getValue().isUndefined() && !colorRampTexture) { - colorRampTexture = uploadPass.createTexture(colorRamp); + if (unevaluated.get<LineGradient>().getValue().isUndefined()) + return; + + for (const RenderTile& tile : *renderTiles) { + const LayerRenderData* renderData = tile.getLayerRenderData(*baseImpl); + if (!renderData) continue; + + auto& bucket = static_cast<LineBucket&>(*renderData->bucket); + + assert(bucket.gradientColorRamp && "Gradient color ramp should be set at this point"); + if (bucket.gradientTexture) { + uploadPass.updateTexture(*bucket.gradientTexture, *bucket.gradientColorRamp); + } else { + bucket.gradientTexture = uploadPass.createTexture(*bucket.gradientColorRamp); + } } } @@ -186,20 +203,48 @@ void RenderLineLayer::render(PaintParameters& parameters) { textures::image::Value{ tile.getIconAtlasTexture().getResource(), gfx::TextureFilterType::Linear }, }); } else if (!unevaluated.get<LineGradient>().getValue().isUndefined()) { - assert(colorRampTexture); - - draw(parameters.programs.getLineLayerPrograms().lineGradient, - LineGradientProgram::layoutUniformValues( - evaluated, - tile, - parameters.state, - parameters.pixelsToGLUnits, - parameters.pixelRatio), - {}, - {}, - LineGradientProgram::TextureBindings{ - textures::image::Value{ colorRampTexture->getResource(), gfx::TextureFilterType::Linear }, - }); + assert(bucket.gradientVersion == gradientVersion); + assert(bucket.gradientTexture); + + auto& programInstance = parameters.programs.getLineLayerPrograms().lineGradient; + auto&& uniformValues = LineGradientProgram::layoutUniformValues( + evaluated, + tile, + parameters.state, + parameters.pixelsToGLUnits, + parameters.pixelRatio, + bucket.lineClips.size()); + auto&& textureBindings = LineGradientProgram::TextureBindings{ + textures::image::Value{ bucket.gradientTexture->getResource(), samplerFiler }, + }; + const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); + const auto allUniformValues = + programInstance.computeAllUniformValues(std::forward<decltype(uniformValues)>(uniformValues), + paintPropertyBinders, + evaluated, + parameters.state.getZoom()); + const auto allAttributeBindings = LineGradientProgram::computeAllAttributeBindings( + *bucket.vertexBuffer, + *bucket.vertexBuffer2, + paintPropertyBinders, + evaluated + ); + + checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings)); + + programInstance.draw(parameters.context, + *parameters.renderPass, + gfx::Triangles(), + parameters.depthModeForSublayer(0, gfx::DepthMaskType::ReadOnly), + parameters.stencilModeForClipping(tile.id), + parameters.colorModeForRenderPass(), + gfx::CullFaceMode::disabled(), + *bucket.indexBuffer, + bucket.segments, + allUniformValues, + allAttributeBindings, + std::forward<decltype(textureBindings)>(textureBindings), + getID()); } else { draw(parameters.programs.getLineLayerPrograms().line, LineProgram::layoutUniformValues( @@ -287,24 +332,52 @@ bool RenderLineLayer::queryIntersectsFeature(const GeometryCoordinates& queryGeo halfWidth); } -void RenderLineLayer::updateColorRamp() { +void RenderLineLayer::updateColorRamp(LineBucket& lineBucket, const RenderTile& tile, const RenderSource& source, const TransformState& state) { auto colorValue = unevaluated.get<LineGradient>().getValue(); if (colorValue.isUndefined()) { return; } + if (!lineBucket.gradientTexture || gradientVersion != lineBucket.gradientVersion) { + uint32_t textureResolution = 256; + const expression::Expression& expression = colorValue.getExpression(); + const bool isStepExpression = expression.getKind() == style::expression::Kind::Step; + if (isStepExpression) { + const uint8_t sourceMaxZoom = source.getMaxZoom(); + const uint8_t zoomDiff = static_cast<uint8_t>(state.getMaxZoom()) - tile.id.canonical.z; + const float potentialOverzoom = tile.id.canonical.z == sourceMaxZoom ? + ceilf(static_cast<float>(1 << zoomDiff)) : 1.0f; + const float lineLength = lineBucket.maxLineLength / static_cast<float>(util::EXTENT); + // Logical pixel tile size is 512px, and 1024px right before current zoom + 1 + const float maxTileSize = 1024; + // Maximum possible texture coverage heuristic, bound by hardware max texture size + const float maxTextureCoverage = lineLength * maxTileSize * potentialOverzoom; + const uint32_t nextPowerOf2 = static_cast<uint32_t>(powf(2.0f, ceilf(util::log2<float>(maxTextureCoverage)))); + textureResolution = util::clamp<uint32_t>(nextPowerOf2, 256, gfx::Context::maxTextureSize); + + samplerFiler = gfx::TextureFilterType::Nearest; + } - const auto length = colorRamp.bytes(); + Size colorRampSize(textureResolution, static_cast<uint32_t>(lineBucket.lineClips.size())); + if (!(lineBucket.gradientColorRamp && lineBucket.gradientColorRamp->size == colorRampSize)) { + lineBucket.gradientColorRamp = PremultipliedImage(colorRampSize); + } - for (uint32_t i = 0; i < length; i += 4) { - const auto color = colorValue.evaluate(static_cast<double>(i) / length); - colorRamp.data[i] = std::floor(color.r * 255); - colorRamp.data[i + 1] = std::floor(color.g * 255); - colorRamp.data[i + 2] = std::floor(color.b * 255); - colorRamp.data[i + 3] = std::floor(color.a * 255); - } + uint32_t height = lineBucket.lineClips.size(); + for (uint32_t clip = 0, stride = 0; clip < height; ++clip, stride += textureResolution * 4) { + for (uint32_t i = 0, j = 0; i < textureResolution; i++, j += 4) { + const double progress = static_cast<double>(i) / (textureResolution - 1); + const double start = lineBucket.lineClips[clip].start; + const double end = lineBucket.lineClips[clip].end; + const double evaluationProgress = start * (1 - progress) + end * progress; + const auto color = colorValue.evaluate(evaluationProgress); + lineBucket.gradientColorRamp->data[stride + j + 0] = std::floor(color.r * 255); + lineBucket.gradientColorRamp->data[stride + j + 1] = std::floor(color.g * 255); + lineBucket.gradientColorRamp->data[stride + j + 2] = std::floor(color.b * 255); + lineBucket.gradientColorRamp->data[stride + j + 3] = std::floor(color.a * 255); + } + } - if (colorRampTexture) { - colorRampTexture = nullopt; + lineBucket.gradientVersion = gradientVersion; } } diff --git a/src/mbgl/renderer/layers/render_line_layer.hpp b/src/mbgl/renderer/layers/render_line_layer.hpp index fb5d64fcb2..45592822d1 100644 --- a/src/mbgl/renderer/layers/render_line_layer.hpp +++ b/src/mbgl/renderer/layers/render_line_layer.hpp @@ -10,6 +10,11 @@ namespace mbgl { +class LineBucket; +class RenderTile; +class RenderSource; +class TransformState; + class RenderLineLayer final : public RenderLayer { public: explicit RenderLineLayer(Immutable<style::LineLayer::Impl>); @@ -36,10 +41,10 @@ private: style::LinePaintProperties::Unevaluated unevaluated; float getLineWidth(const GeometryTileFeature&, float, const FeatureState&) const; - void updateColorRamp(); + void updateColorRamp(LineBucket& lineBucket, const RenderTile& tile, const RenderSource& source, const TransformState& state); - PremultipliedImage colorRamp; - optional<gfx::Texture> colorRampTexture; + uint32_t gradientVersion; + gfx::TextureFilterType samplerFiler; }; } // namespace mbgl diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp index 1d8c0a70a8..200a87fe9e 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.cpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp @@ -57,8 +57,8 @@ style::SymbolPropertyValues textPropertyValues(const style::SymbolPaintPropertie }; } -using SegmentWrapper = std::reference_wrapper<Segment<SymbolTextAttributes>>; -using SegmentVectorWrapper = std::reference_wrapper<SegmentVector<SymbolTextAttributes>>; +using SegmentWrapper = std::reference_wrapper<Segment>; +using SegmentVectorWrapper = std::reference_wrapper<SegmentVector>; using SegmentsWrapper = variant<SegmentWrapper, SegmentVectorWrapper>; struct RenderableSegment { @@ -377,7 +377,7 @@ void RenderSymbolLayer::render(PaintParameters& parameters) { this->checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings)); segments.match( - [&](const std::reference_wrapper<Segment<SymbolTextAttributes>>& segment) { + [&](const std::reference_wrapper<Segment>& segment) { programInstance.draw( parameters.context, *parameters.renderPass, @@ -394,7 +394,7 @@ void RenderSymbolLayer::render(PaintParameters& parameters) { this->getID() + "/" + suffix ); }, - [&](const std::reference_wrapper<SegmentVector<SymbolTextAttributes>>& segmentVector) { + [&](const std::reference_wrapper<SegmentVector>& segmentVector) { programInstance.draw( parameters.context, *parameters.renderPass, @@ -439,7 +439,7 @@ void RenderSymbolLayer::render(PaintParameters& parameters) { drawIcon(draw, tile, *renderData, std::ref(bucket.icon.segments), bucketPaintProperties, parameters, false /*sdfIcon*/); } } - + if (bucket.hasSdfIconData()) { if (sortFeaturesByKey) { addRenderables(bucket.sdfIcon.segments, SymbolType::IconSDF); diff --git a/src/mbgl/renderer/render_source.cpp b/src/mbgl/renderer/render_source.cpp index f39d3089d7..61340efe35 100644 --- a/src/mbgl/renderer/render_source.cpp +++ b/src/mbgl/renderer/render_source.cpp @@ -74,8 +74,7 @@ bool RenderSource::isEnabled() const { return enabled; } -uint8_t RenderSource::getMaxZoom() const { - assert(false); +uint8_t RenderSource::getMaxZoom() const { return util::TERRAIN_RGB_MAXZOOM; } diff --git a/src/mbgl/renderer/render_static_data.cpp b/src/mbgl/renderer/render_static_data.cpp index f7d9c18a78..3ef986d749 100644 --- a/src/mbgl/renderer/render_static_data.cpp +++ b/src/mbgl/renderer/render_static_data.cpp @@ -59,26 +59,26 @@ RenderStaticData::RenderStaticData(gfx::Context& context, float pixelRatio) { } -SegmentVector<BackgroundAttributes> RenderStaticData::tileTriangleSegments() { - SegmentVector<BackgroundAttributes> segments; +SegmentVector RenderStaticData::tileTriangleSegments() { + SegmentVector segments; segments.emplace_back(0, 0, 4, 6); return segments; } -SegmentVector<DebugAttributes> RenderStaticData::tileBorderSegments() { - SegmentVector<DebugAttributes> segments; +SegmentVector RenderStaticData::tileBorderSegments() { + SegmentVector segments; segments.emplace_back(0, 0, 4, 5); return segments; } -SegmentVector<RasterAttributes> RenderStaticData::rasterSegments() { - SegmentVector<RasterAttributes> segments; +SegmentVector RenderStaticData::rasterSegments() { + SegmentVector segments; segments.emplace_back(0, 0, 4, 6); return segments; } -SegmentVector<HeatmapTextureAttributes> RenderStaticData::heatmapTextureSegments() { - SegmentVector<HeatmapTextureAttributes> segments; +SegmentVector RenderStaticData::heatmapTextureSegments() { + SegmentVector segments; segments.emplace_back(0, 0, 4, 6); return segments; } diff --git a/src/mbgl/renderer/render_static_data.hpp b/src/mbgl/renderer/render_static_data.hpp index 22b29387db..0695c41ae6 100644 --- a/src/mbgl/renderer/render_static_data.hpp +++ b/src/mbgl/renderer/render_static_data.hpp @@ -30,10 +30,10 @@ public: optional<gfx::IndexBuffer> quadTriangleIndexBuffer; optional<gfx::IndexBuffer> tileBorderIndexBuffer; - static SegmentVector<BackgroundAttributes> tileTriangleSegments(); - static SegmentVector<DebugAttributes> tileBorderSegments(); - static SegmentVector<RasterAttributes> rasterSegments(); - static SegmentVector<HeatmapTextureAttributes> heatmapTextureSegments(); + static SegmentVector tileTriangleSegments(); + static SegmentVector tileBorderSegments(); + static SegmentVector rasterSegments(); + static SegmentVector heatmapTextureSegments(); optional<gfx::Renderbuffer<gfx::RenderbufferPixelType::Depth>> depthRenderbuffer; bool has3D = false; @@ -42,7 +42,7 @@ public: Programs programs; - const SegmentVector<BackgroundAttributes> clippingMaskSegments; + const SegmentVector clippingMaskSegments; #ifndef NDEBUG Programs overdrawPrograms; diff --git a/test/gl/bucket.test.cpp b/test/gl/bucket.test.cpp index fd8644bfbc..ab39d37540 100644 --- a/test/gl/bucket.test.cpp +++ b/test/gl/bucket.test.cpp @@ -16,8 +16,7 @@ namespace mbgl { -template <class Attributes> -bool operator==(const Segment<Attributes>& lhs, const Segment<Attributes>& rhs) { +bool operator==(const Segment& lhs, const Segment& rhs) { return std::tie(lhs.vertexOffset, lhs.indexOffset, lhs.vertexLength, lhs.indexLength) == std::tie(rhs.vertexOffset, rhs.indexOffset, rhs.vertexLength, rhs.indexLength); } @@ -219,7 +218,7 @@ TEST(Buckets, RasterBucketMaskEmpty) { bucket.setMask({}); EXPECT_EQ((std::vector<RasterLayoutVertex>{}), bucket.vertices.vector()); EXPECT_EQ((std::vector<uint16_t>{}), bucket.indices.vector()); - SegmentVector<RasterAttributes> expectedSegments; + SegmentVector expectedSegments; expectedSegments.emplace_back(0, 0, 0, 0); EXPECT_EQ(expectedSegments, bucket.segments); } @@ -231,7 +230,7 @@ TEST(Buckets, RasterBucketMaskNoChildren) { // A mask of 0/0/0 doesn't produce buffers since we're instead using the global shared buffers. EXPECT_EQ((std::vector<RasterLayoutVertex>{}), bucket.vertices.vector()); EXPECT_EQ((std::vector<uint16_t>{}), bucket.indices.vector()); - EXPECT_EQ((SegmentVector<RasterAttributes>{}), bucket.segments); + EXPECT_EQ((SegmentVector{}), bucket.segments); } TEST(Buckets, RasterBucketMaskTwoChildren) { @@ -268,7 +267,7 @@ TEST(Buckets, RasterBucketMaskNoChildren) { bucket.indices.vector()); - SegmentVector<RasterAttributes> expectedSegments; + SegmentVector expectedSegments; expectedSegments.emplace_back(0, 0, 8, 12); EXPECT_EQ(expectedSegments, bucket.segments); } @@ -348,7 +347,7 @@ TEST(Buckets, RasterBucketMaskNoChildren) { bucket.indices.vector()); - SegmentVector<RasterAttributes> expectedSegments; + SegmentVector expectedSegments; expectedSegments.emplace_back(0, 0, 24, 36); EXPECT_EQ(expectedSegments, bucket.segments); } |