summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mbgl/geometry/feature_index.cpp1
-rw-r--r--src/mbgl/gl/attribute.cpp14
-rw-r--r--src/mbgl/gl/attribute.hpp18
-rw-r--r--src/mbgl/gl/context.cpp10
-rw-r--r--src/mbgl/gl/context.hpp4
-rw-r--r--src/mbgl/gl/program.hpp2
-rw-r--r--src/mbgl/gl/vertex_array.cpp6
-rw-r--r--src/mbgl/gl/vertex_array.hpp13
-rw-r--r--src/mbgl/layout/symbol_layout.cpp1
-rw-r--r--src/mbgl/programs/program.hpp34
-rw-r--r--src/mbgl/programs/symbol_program.hpp50
-rw-r--r--src/mbgl/renderer/layers/render_background_layer.cpp63
-rw-r--r--src/mbgl/renderer/layers/render_circle_layer.cpp37
-rw-r--r--src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp91
-rw-r--r--src/mbgl/renderer/layers/render_fill_layer.cpp66
-rw-r--r--src/mbgl/renderer/layers/render_heatmap_layer.cpp68
-rw-r--r--src/mbgl/renderer/layers/render_hillshade_layer.cpp65
-rw-r--r--src/mbgl/renderer/layers/render_line_layer.cpp27
-rw-r--r--src/mbgl/renderer/layers/render_raster_layer.cpp33
-rw-r--r--src/mbgl/renderer/layers/render_symbol_layer.cpp31
-rw-r--r--src/mbgl/renderer/render_layer.cpp29
-rw-r--r--src/mbgl/renderer/render_layer.hpp11
-rw-r--r--src/mbgl/renderer/render_tile.cpp70
-rw-r--r--src/mbgl/renderer/renderer_impl.cpp24
-rw-r--r--src/mbgl/renderer/sources/render_image_source.cpp28
-rw-r--r--src/mbgl/style/conversion/filter.cpp343
-rw-r--r--src/mbgl/style/conversion/stringify.hpp159
-rw-r--r--src/mbgl/style/expression/compound_expression.cpp325
-rw-r--r--src/mbgl/style/expression/literal.cpp8
-rw-r--r--src/mbgl/style/filter.cpp12
-rw-r--r--src/mbgl/style/filter_evaluator.cpp225
-rw-r--r--src/mbgl/tile/custom_geometry_tile.cpp1
-rw-r--r--src/mbgl/tile/geojson_tile.cpp1
-rw-r--r--src/mbgl/tile/geometry_tile.cpp1
-rw-r--r--src/mbgl/tile/geometry_tile_worker.cpp1
35 files changed, 990 insertions, 882 deletions
diff --git a/src/mbgl/geometry/feature_index.cpp b/src/mbgl/geometry/feature_index.cpp
index fdd9558d0b..cc69a60ca0 100644
--- a/src/mbgl/geometry/feature_index.cpp
+++ b/src/mbgl/geometry/feature_index.cpp
@@ -7,7 +7,6 @@
#include <mbgl/util/math.hpp>
#include <mbgl/math/minmax.hpp>
#include <mbgl/style/filter.hpp>
-#include <mbgl/style/filter_evaluator.hpp>
#include <mbgl/tile/tile_id.hpp>
#include <mapbox/geometry/envelope.hpp>
diff --git a/src/mbgl/gl/attribute.cpp b/src/mbgl/gl/attribute.cpp
index bb5b2ddc34..b2d05fe665 100644
--- a/src/mbgl/gl/attribute.cpp
+++ b/src/mbgl/gl/attribute.cpp
@@ -1,14 +1,20 @@
#include <mbgl/gl/attribute.hpp>
+#include <mbgl/gl/context.hpp>
#include <mbgl/gl/gl.hpp>
namespace mbgl {
namespace gl {
-void bindAttributeLocation(ProgramID id, AttributeLocation location, const char* name) {
- if (location >= MAX_ATTRIBUTES) {
- throw gl::Error("too many vertex attributes");
+void bindAttributeLocation(Context& context, ProgramID id, AttributeLocation location, const char* name) {
+ // We're using sequentially numberered attribute locations starting with 0. Therefore we can use
+ // the location as a proxy for the number of attributes.
+ if (location >= context.maximumVertexBindingCount) {
+ // Don't bind the location on this hardware since it exceeds the limit (otherwise we'd get
+ // an OpenGL error). This means we'll see rendering errors, and possibly slow rendering due
+ // to unbound attributes.
+ } else {
+ MBGL_CHECK_ERROR(glBindAttribLocation(id, location, name));
}
- MBGL_CHECK_ERROR(glBindAttribLocation(id, location, name));
}
std::set<std::string> getActiveAttributes(ProgramID id) {
diff --git a/src/mbgl/gl/attribute.hpp b/src/mbgl/gl/attribute.hpp
index fa6c2ddeab..3763f0a583 100644
--- a/src/mbgl/gl/attribute.hpp
+++ b/src/mbgl/gl/attribute.hpp
@@ -17,8 +17,6 @@
namespace mbgl {
namespace gl {
-static constexpr std::size_t MAX_ATTRIBUTES = 8;
-
template <class> struct DataTypeOf;
template <> struct DataTypeOf< int8_t> : std::integral_constant<DataType, DataType::Byte> {};
template <> struct DataTypeOf<uint8_t> : std::integral_constant<DataType, DataType::UnsignedByte> {};
@@ -45,7 +43,7 @@ public:
}
};
-using AttributeBindingArray = std::array<optional<AttributeBinding>, MAX_ATTRIBUTES>;
+using AttributeBindingArray = std::vector<optional<AttributeBinding>>;
/*
gl::Attribute<T,N> manages the binding of a vertex buffer to a GL program attribute.
@@ -214,7 +212,8 @@ const std::size_t Vertex<A1, A2, A3, A4, A5>::attributeOffsets[5] = {
} // namespace detail
-void bindAttributeLocation(ProgramID, AttributeLocation, const char * name);
+class Context;
+void bindAttributeLocation(Context&, ProgramID, AttributeLocation, const char * name);
std::set<std::string> getActiveAttributes(ProgramID);
template <class... As>
@@ -231,13 +230,13 @@ public:
using Vertex = detail::Vertex<typename As::Type...>;
- static Locations bindLocations(const ProgramID& id) {
+ static Locations bindLocations(Context& context, const ProgramID& id) {
std::set<std::string> activeAttributes = getActiveAttributes(id);
AttributeLocation location = 0;
auto maybeBindLocation = [&](const char* name) -> optional<AttributeLocation> {
if (activeAttributes.count(name)) {
- bindAttributeLocation(id, location, name);
+ bindAttributeLocation(context, id, location, name);
return location++;
} else {
return {};
@@ -277,6 +276,7 @@ public:
static AttributeBindingArray toBindingArray(const Locations& locations, const Bindings& bindings) {
AttributeBindingArray result;
+ result.resize(sizeof...(As));
auto maybeAddBinding = [&] (const optional<AttributeLocation>& location,
const optional<AttributeBinding>& binding) {
@@ -289,6 +289,12 @@ public:
return result;
}
+
+ static uint32_t activeBindingCount(const Bindings& bindings) {
+ uint32_t result = 0;
+ util::ignore({ ((result += bool(bindings.template get<As>())), 0)... });
+ return result;
+ }
};
namespace detail {
diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp
index ba44adb42b..c6352d3e84 100644
--- a/src/mbgl/gl/context.cpp
+++ b/src/mbgl/gl/context.cpp
@@ -94,7 +94,13 @@ static_assert(underlying_type(BufferUsage::DynamicDraw) == GL_DYNAMIC_DRAW, "Ope
static_assert(std::is_same<BinaryProgramFormat, GLenum>::value, "OpenGL type mismatch");
-Context::Context() = default;
+Context::Context()
+ : maximumVertexBindingCount([] {
+ GLint value;
+ MBGL_CHECK_ERROR(glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &value));
+ return value;
+ }()) {
+}
Context::~Context() {
if (cleanupOnDestruction) {
@@ -351,7 +357,7 @@ VertexArray Context::createVertexArray() {
VertexArrayID id = 0;
MBGL_CHECK_ERROR(vertexArray->genVertexArrays(1, &id));
UniqueVertexArray vao(std::move(id), { this });
- return { UniqueVertexArrayState(new VertexArrayState(std::move(vao), *this), VertexArrayStateDeleter { true })};
+ return { UniqueVertexArrayState(new VertexArrayState(std::move(vao)), VertexArrayStateDeleter { true })};
} else {
// On GL implementations which do not support vertex arrays, attribute bindings are global state.
// So return a VertexArray which shares our global state tracking and whose deleter is a no-op.
diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp
index 67624288e2..d95311115e 100644
--- a/src/mbgl/gl/context.hpp
+++ b/src/mbgl/gl/context.hpp
@@ -226,7 +226,7 @@ public:
State<value::BindVertexBuffer> vertexBuffer;
State<value::BindVertexArray, const Context&> bindVertexArray { *this };
- VertexArrayState globalVertexArrayState { UniqueVertexArray(0, { this }), *this };
+ VertexArrayState globalVertexArrayState { UniqueVertexArray(0, { this }) };
State<value::PixelStorePack> pixelStorePack;
State<value::PixelStoreUnpack> pixelStoreUnpack;
@@ -239,6 +239,8 @@ public:
#endif // MBGL_USE_GLES2
bool supportsHalfFloatTextures = false;
+ const uint32_t maximumVertexBindingCount;
+ static constexpr const uint32_t minimumRequiredVertexBindingCount = 8;
private:
State<value::StencilFunc> stencilFunc;
diff --git a/src/mbgl/gl/program.hpp b/src/mbgl/gl/program.hpp
index af02ad3d54..f33501cd11 100644
--- a/src/mbgl/gl/program.hpp
+++ b/src/mbgl/gl/program.hpp
@@ -35,7 +35,7 @@ public:
context.createProgram(context.createShader(ShaderType::Vertex, vertexSource),
context.createShader(ShaderType::Fragment, fragmentSource))),
uniformsState((context.linkProgram(program), Uniforms::bindLocations(program))),
- attributeLocations(Attributes::bindLocations(program)) {
+ attributeLocations(Attributes::bindLocations(context, program)) {
// Re-link program after manually binding only active attributes in Attributes::bindLocations
context.linkProgram(program);
diff --git a/src/mbgl/gl/vertex_array.cpp b/src/mbgl/gl/vertex_array.cpp
index 68a500ac45..d552a8292e 100644
--- a/src/mbgl/gl/vertex_array.cpp
+++ b/src/mbgl/gl/vertex_array.cpp
@@ -9,7 +9,11 @@ void VertexArray::bind(Context& context, BufferID indexBuffer, const AttributeBi
context.bindVertexArray = state->vertexArray;
state->indexBuffer = indexBuffer;
- for (AttributeLocation location = 0; location < MAX_ATTRIBUTES; ++location) {
+ state->bindings.reserve(bindings.size());
+ for (AttributeLocation location = 0; location < bindings.size(); ++location) {
+ if (state->bindings.size() <= location) {
+ state->bindings.emplace_back(context, AttributeLocation(location));
+ }
state->bindings[location] = bindings[location];
}
}
diff --git a/src/mbgl/gl/vertex_array.hpp b/src/mbgl/gl/vertex_array.hpp
index 46c67017bb..604754f672 100644
--- a/src/mbgl/gl/vertex_array.hpp
+++ b/src/mbgl/gl/vertex_array.hpp
@@ -15,9 +15,8 @@ class Context;
class VertexArrayState {
public:
- VertexArrayState(UniqueVertexArray vertexArray_, Context& context)
- : vertexArray(std::move(vertexArray_)),
- bindings(makeBindings(context, std::make_index_sequence<MAX_ATTRIBUTES>())) {
+ VertexArrayState(UniqueVertexArray vertexArray_)
+ : vertexArray(std::move(vertexArray_)) {
}
void setDirty() {
@@ -31,13 +30,7 @@ public:
State<value::BindElementBuffer> indexBuffer;
using AttributeState = State<value::VertexAttribute, Context&, AttributeLocation>;
- std::array<AttributeState, MAX_ATTRIBUTES> bindings;
-
-private:
- template <std::size_t... I>
- std::array<AttributeState, MAX_ATTRIBUTES> makeBindings(Context& context, std::index_sequence<I...>) {
- return {{ AttributeState { context, I }... }};
- }
+ std::vector<AttributeState> bindings;
};
class VertexArrayStateDeleter {
diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp
index b2f6fd450f..4249ffc24e 100644
--- a/src/mbgl/layout/symbol_layout.cpp
+++ b/src/mbgl/layout/symbol_layout.cpp
@@ -2,7 +2,6 @@
#include <mbgl/layout/merge_lines.hpp>
#include <mbgl/layout/clip_lines.hpp>
#include <mbgl/renderer/buckets/symbol_bucket.hpp>
-#include <mbgl/style/filter_evaluator.hpp>
#include <mbgl/renderer/bucket_parameters.hpp>
#include <mbgl/renderer/layers/render_symbol_layer.hpp>
#include <mbgl/renderer/image_atlas.hpp>
diff --git a/src/mbgl/programs/program.hpp b/src/mbgl/programs/program.hpp
index bcdb270b9c..4d5de05337 100644
--- a/src/mbgl/programs/program.hpp
+++ b/src/mbgl/programs/program.hpp
@@ -46,26 +46,38 @@ public:
Shaders::fragmentSource)) {
}
+ static typename AllUniforms::Values computeAllUniformValues(
+ const UniformValues& uniformValues,
+ const PaintPropertyBinders& paintPropertyBinders,
+ const typename PaintProperties::PossiblyEvaluated& currentProperties,
+ float currentZoom) {
+ return uniformValues
+ .concat(paintPropertyBinders.uniformValues(currentZoom, currentProperties));
+ }
+
+ static typename Attributes::Bindings computeAllAttributeBindings(
+ const gl::VertexBuffer<LayoutVertex>& layoutVertexBuffer,
+ const PaintPropertyBinders& paintPropertyBinders,
+ const typename PaintProperties::PossiblyEvaluated& currentProperties) {
+ return LayoutAttributes::bindings(layoutVertexBuffer)
+ .concat(paintPropertyBinders.attributeBindings(currentProperties));
+ }
+
+ static uint32_t activeBindingCount(const typename Attributes::Bindings& allAttributeBindings) {
+ return Attributes::activeBindingCount(allAttributeBindings);
+ }
+
template <class DrawMode>
void draw(gl::Context& context,
DrawMode drawMode,
gl::DepthMode depthMode,
gl::StencilMode stencilMode,
gl::ColorMode colorMode,
- const UniformValues& uniformValues,
- const gl::VertexBuffer<LayoutVertex>& layoutVertexBuffer,
const gl::IndexBuffer<DrawMode>& indexBuffer,
const SegmentVector<Attributes>& segments,
- const PaintPropertyBinders& paintPropertyBinders,
- const typename PaintProperties::PossiblyEvaluated& currentProperties,
- float currentZoom,
+ const typename AllUniforms::Values& allUniformValues,
+ const typename Attributes::Bindings& allAttributeBindings,
const std::string& layerID) {
- typename AllUniforms::Values allUniformValues = uniformValues
- .concat(paintPropertyBinders.uniformValues(currentZoom, currentProperties));
-
- typename Attributes::Bindings allAttributeBindings = LayoutAttributes::bindings(layoutVertexBuffer)
- .concat(paintPropertyBinders.attributeBindings(currentProperties));
-
for (auto& segment : segments) {
auto vertexArrayIt = segment.vertexArrays.find(layerID);
diff --git a/src/mbgl/programs/symbol_program.hpp b/src/mbgl/programs/symbol_program.hpp
index 9b5037ed9f..51f9a48f7f 100644
--- a/src/mbgl/programs/symbol_program.hpp
+++ b/src/mbgl/programs/symbol_program.hpp
@@ -278,35 +278,45 @@ public:
Shaders::fragmentSource)) {
}
+ static typename AllUniforms::Values computeAllUniformValues(
+ const UniformValues& uniformValues,
+ const SymbolSizeBinder& symbolSizeBinder,
+ const PaintPropertyBinders& paintPropertyBinders,
+ const typename PaintProperties::PossiblyEvaluated& currentProperties,
+ float currentZoom) {
+ return uniformValues.concat(symbolSizeBinder.uniformValues(currentZoom))
+ .concat(paintPropertyBinders.uniformValues(currentZoom, currentProperties));
+ }
+
+ static typename Attributes::Bindings computeAllAttributeBindings(
+ const gl::VertexBuffer<LayoutVertex>& layoutVertexBuffer,
+ const gl::VertexBuffer<SymbolDynamicLayoutAttributes::Vertex>& dynamicLayoutVertexBuffer,
+ const gl::VertexBuffer<SymbolOpacityAttributes::Vertex>& opacityVertexBuffer,
+ const PaintPropertyBinders& paintPropertyBinders,
+ const typename PaintProperties::PossiblyEvaluated& currentProperties) {
+ assert(layoutVertexBuffer.vertexCount == dynamicLayoutVertexBuffer.vertexCount &&
+ layoutVertexBuffer.vertexCount == opacityVertexBuffer.vertexCount);
+ return LayoutAttributes::bindings(layoutVertexBuffer)
+ .concat(SymbolDynamicLayoutAttributes::bindings(dynamicLayoutVertexBuffer))
+ .concat(SymbolOpacityAttributes::bindings(opacityVertexBuffer))
+ .concat(paintPropertyBinders.attributeBindings(currentProperties));
+ }
+
+ static uint32_t activeBindingCount(const typename Attributes::Bindings& allAttributeBindings) {
+ return Attributes::activeBindingCount(allAttributeBindings);
+ }
+
template <class DrawMode>
void draw(gl::Context& context,
DrawMode drawMode,
gl::DepthMode depthMode,
gl::StencilMode stencilMode,
gl::ColorMode colorMode,
- const UniformValues& uniformValues,
- const gl::VertexBuffer<LayoutVertex>& layoutVertexBuffer,
- const gl::VertexBuffer<SymbolDynamicLayoutAttributes::Vertex>& dynamicLayoutVertexBuffer,
- const gl::VertexBuffer<SymbolOpacityAttributes::Vertex>& opacityVertexBuffer,
- const SymbolSizeBinder& symbolSizeBinder,
const gl::IndexBuffer<DrawMode>& indexBuffer,
const SegmentVector<Attributes>& segments,
- const PaintPropertyBinders& paintPropertyBinders,
- const typename PaintProperties::PossiblyEvaluated& currentProperties,
- float currentZoom,
+ const typename AllUniforms::Values& allUniformValues,
+ const typename Attributes::Bindings& allAttributeBindings,
const std::string& layerID) {
- typename AllUniforms::Values allUniformValues = uniformValues
- .concat(symbolSizeBinder.uniformValues(currentZoom))
- .concat(paintPropertyBinders.uniformValues(currentZoom, currentProperties));
-
- typename Attributes::Bindings allAttributeBindings = LayoutAttributes::bindings(layoutVertexBuffer)
- .concat(SymbolDynamicLayoutAttributes::bindings(dynamicLayoutVertexBuffer))
- .concat(SymbolOpacityAttributes::bindings(opacityVertexBuffer))
- .concat(paintPropertyBinders.attributeBindings(currentProperties));
-
- assert(layoutVertexBuffer.vertexCount == dynamicLayoutVertexBuffer.vertexCount &&
- layoutVertexBuffer.vertexCount == opacityVertexBuffer.vertexCount);
-
for (auto& segment : segments) {
auto vertexArrayIt = segment.vertexArrays.find(layerID);
diff --git a/src/mbgl/renderer/layers/render_background_layer.cpp b/src/mbgl/renderer/layers/render_background_layer.cpp
index 44c3fffb6c..2dc5fe7339 100644
--- a/src/mbgl/renderer/layers/render_background_layer.cpp
+++ b/src/mbgl/renderer/layers/render_background_layer.cpp
@@ -50,6 +50,35 @@ void RenderBackgroundLayer::render(PaintParameters& parameters, RenderSource*) {
const Properties<>::PossiblyEvaluated properties;
const BackgroundProgram::PaintPropertyBinders paintAttributeData(properties, 0);
+ auto draw = [&](auto& program, auto&& uniformValues) {
+ const auto allUniformValues = program.computeAllUniformValues(
+ std::move(uniformValues),
+ paintAttributeData,
+ properties,
+ parameters.state.getZoom()
+ );
+ const auto allAttributeBindings = program.computeAllAttributeBindings(
+ parameters.staticData.tileVertexBuffer,
+ paintAttributeData,
+ properties
+ );
+
+ checkRenderability(parameters, program.activeBindingCount(allAttributeBindings));
+
+ program.draw(
+ parameters.context,
+ gl::Triangles(),
+ parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly),
+ gl::StencilMode::disabled(),
+ parameters.colorModeForRenderPass(),
+ parameters.staticData.quadTriangleIndexBuffer,
+ parameters.staticData.tileTriangleSegments,
+ allUniformValues,
+ allAttributeBindings,
+ getID()
+ );
+ };
+
if (!evaluated.get<BackgroundPattern>().to.empty()) {
optional<ImagePosition> imagePosA = parameters.imageManager.getPattern(evaluated.get<BackgroundPattern>().from);
optional<ImagePosition> imagePosB = parameters.imageManager.getPattern(evaluated.get<BackgroundPattern>().to);
@@ -60,12 +89,8 @@ void RenderBackgroundLayer::render(PaintParameters& parameters, RenderSource*) {
parameters.imageManager.bind(parameters.context, 0);
for (const auto& tileID : util::tileCover(parameters.state, parameters.state.getIntegerZoom())) {
- parameters.programs.backgroundPattern.draw(
- parameters.context,
- gl::Triangles(),
- parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly),
- gl::StencilMode::disabled(),
- parameters.colorModeForRenderPass(),
+ draw(
+ parameters.programs.backgroundPattern,
BackgroundPatternUniforms::values(
parameters.matrixForTile(tileID),
evaluated.get<BackgroundOpacity>(),
@@ -75,36 +100,18 @@ void RenderBackgroundLayer::render(PaintParameters& parameters, RenderSource*) {
evaluated.get<BackgroundPattern>(),
tileID,
parameters.state
- ),
- parameters.staticData.tileVertexBuffer,
- parameters.staticData.quadTriangleIndexBuffer,
- parameters.staticData.tileTriangleSegments,
- paintAttributeData,
- properties,
- parameters.state.getZoom(),
- getID()
+ )
);
}
} else {
for (const auto& tileID : util::tileCover(parameters.state, parameters.state.getIntegerZoom())) {
- parameters.programs.background.draw(
- parameters.context,
- gl::Triangles(),
- parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly),
- gl::StencilMode::disabled(),
- parameters.colorModeForRenderPass(),
+ draw(
+ parameters.programs.background,
BackgroundProgram::UniformValues {
uniforms::u_matrix::Value{ parameters.matrixForTile(tileID) },
uniforms::u_color::Value{ evaluated.get<BackgroundColor>() },
uniforms::u_opacity::Value{ evaluated.get<BackgroundOpacity>() },
- },
- parameters.staticData.tileVertexBuffer,
- parameters.staticData.quadTriangleIndexBuffer,
- parameters.staticData.tileTriangleSegments,
- paintAttributeData,
- properties,
- parameters.state.getZoom(),
- getID()
+ }
);
}
}
diff --git a/src/mbgl/renderer/layers/render_circle_layer.cpp b/src/mbgl/renderer/layers/render_circle_layer.cpp
index 56fccfe071..b433a9d3fa 100644
--- a/src/mbgl/renderer/layers/render_circle_layer.cpp
+++ b/src/mbgl/renderer/layers/render_circle_layer.cpp
@@ -59,14 +59,11 @@ void RenderCircleLayer::render(PaintParameters& parameters, RenderSource*) {
assert(dynamic_cast<CircleBucket*>(tile.tile.getBucket(*baseImpl)));
CircleBucket& bucket = *reinterpret_cast<CircleBucket*>(tile.tile.getBucket(*baseImpl));
- parameters.programs.circle.get(evaluated).draw(
- parameters.context,
- gl::Triangles(),
- parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly),
- parameters.mapMode != MapMode::Continuous
- ? parameters.stencilModeForClipping(tile.clip)
- : gl::StencilMode::disabled(),
- parameters.colorModeForRenderPass(),
+ const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID());
+
+ auto& programInstance = parameters.programs.circle.get(evaluated);
+
+ const auto allUniformValues = programInstance.computeAllUniformValues(
CircleProgram::UniformValues {
uniforms::u_matrix::Value{
tile.translatedMatrix(evaluated.get<CircleTranslate>(),
@@ -82,12 +79,30 @@ void RenderCircleLayer::render(PaintParameters& parameters, RenderSource*) {
uniforms::u_camera_to_center_distance::Value{ parameters.state.getCameraToCenterDistance() },
uniforms::u_pitch_with_map::Value{ pitchWithMap }
},
+ paintPropertyBinders,
+ evaluated,
+ parameters.state.getZoom()
+ );
+ const auto allAttributeBindings = programInstance.computeAllAttributeBindings(
*bucket.vertexBuffer,
+ paintPropertyBinders,
+ evaluated
+ );
+
+ checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings));
+
+ programInstance.draw(
+ parameters.context,
+ gl::Triangles(),
+ parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly),
+ parameters.mapMode != MapMode::Continuous
+ ? parameters.stencilModeForClipping(tile.clip)
+ : gl::StencilMode::disabled(),
+ parameters.colorModeForRenderPass(),
*bucket.indexBuffer,
bucket.segments,
- bucket.paintPropertyBinders.at(getID()),
- evaluated,
- parameters.state.getZoom(),
+ allUniformValues,
+ allAttributeBindings,
getID()
);
}
diff --git a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp
index 871464223c..d5282c9b0d 100644
--- a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp
+++ b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp
@@ -68,24 +68,53 @@ void RenderFillExtrusionLayer::render(PaintParameters& parameters, RenderSource*
parameters.context.setStencilMode(gl::StencilMode::disabled());
parameters.context.clear(Color{ 0.0f, 0.0f, 0.0f, 0.0f }, depthClearValue, {});
+ auto draw = [&](auto& programInstance, const auto& tileBucket, auto&& uniformValues) {
+ const auto& paintPropertyBinders = tileBucket.paintPropertyBinders.at(getID());
+
+ const auto allUniformValues = programInstance.computeAllUniformValues(
+ std::move(uniformValues),
+ paintPropertyBinders,
+ evaluated,
+ parameters.state.getZoom()
+ );
+ const auto allAttributeBindings = programInstance.computeAllAttributeBindings(
+ *tileBucket.vertexBuffer,
+ paintPropertyBinders,
+ evaluated
+ );
+
+ checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings));
+
+ programInstance.draw(
+ parameters.context,
+ gl::Triangles(),
+ parameters.depthModeFor3D(gl::DepthMode::ReadWrite),
+ gl::StencilMode::disabled(),
+ parameters.colorModeForRenderPass(),
+ *tileBucket.indexBuffer,
+ tileBucket.triangleSegments,
+ allUniformValues,
+ allAttributeBindings,
+ getID());
+ };
+
if (evaluated.get<FillExtrusionPattern>().from.empty()) {
for (const RenderTile& tile : renderTiles) {
assert(dynamic_cast<FillExtrusionBucket*>(tile.tile.getBucket(*baseImpl)));
FillExtrusionBucket& bucket =
*reinterpret_cast<FillExtrusionBucket*>(tile.tile.getBucket(*baseImpl));
- parameters.programs.fillExtrusion.get(evaluated).draw(
- parameters.context, gl::Triangles(),
- parameters.depthModeFor3D(gl::DepthMode::ReadWrite),
- gl::StencilMode::disabled(), parameters.colorModeForRenderPass(),
+ draw(
+ parameters.programs.fillExtrusion.get(evaluated),
+ bucket,
FillExtrusionUniforms::values(
tile.translatedClipMatrix(evaluated.get<FillExtrusionTranslate>(),
evaluated.get<FillExtrusionTranslateAnchor>(),
parameters.state),
- parameters.state, parameters.evaluatedLight),
- *bucket.vertexBuffer, *bucket.indexBuffer, bucket.triangleSegments,
- bucket.paintPropertyBinders.at(getID()), evaluated, parameters.state.getZoom(),
- getID());
+ parameters.state,
+ parameters.evaluatedLight
+ )
+ );
}
} else {
optional<ImagePosition> imagePosA =
@@ -104,10 +133,9 @@ void RenderFillExtrusionLayer::render(PaintParameters& parameters, RenderSource*
FillExtrusionBucket& bucket =
*reinterpret_cast<FillExtrusionBucket*>(tile.tile.getBucket(*baseImpl));
- parameters.programs.fillExtrusionPattern.get(evaluated).draw(
- parameters.context, gl::Triangles(),
- parameters.depthModeFor3D(gl::DepthMode::ReadWrite),
- gl::StencilMode::disabled(), parameters.colorModeForRenderPass(),
+ draw(
+ parameters.programs.fillExtrusionPattern.get(evaluated),
+ bucket,
FillExtrusionPatternUniforms::values(
tile.translatedClipMatrix(evaluated.get<FillExtrusionTranslate>(),
evaluated.get<FillExtrusionTranslateAnchor>(),
@@ -115,10 +143,9 @@ void RenderFillExtrusionLayer::render(PaintParameters& parameters, RenderSource*
parameters.imageManager.getPixelSize(), *imagePosA, *imagePosB,
evaluated.get<FillExtrusionPattern>(), tile.id, parameters.state,
-std::pow(2, tile.id.canonical.z) / util::tileSize / 8.0f,
- parameters.evaluatedLight),
- *bucket.vertexBuffer, *bucket.indexBuffer, bucket.triangleSegments,
- bucket.paintPropertyBinders.at(getID()), evaluated, parameters.state.getZoom(),
- getID());
+ parameters.evaluatedLight
+ )
+ );
}
}
@@ -131,19 +158,39 @@ void RenderFillExtrusionLayer::render(PaintParameters& parameters, RenderSource*
matrix::ortho(viewportMat, 0, size.width, size.height, 0, 0, 1);
const Properties<>::PossiblyEvaluated properties;
+ const ExtrusionTextureProgram::PaintPropertyBinders paintAttributeData{ properties, 0 };
+
+ auto& programInstance = parameters.programs.extrusionTexture;
- parameters.programs.extrusionTexture.draw(
- parameters.context, gl::Triangles(), gl::DepthMode::disabled(),
- gl::StencilMode::disabled(), parameters.colorModeForRenderPass(),
+ const auto allUniformValues = programInstance.computeAllUniformValues(
ExtrusionTextureProgram::UniformValues{
uniforms::u_matrix::Value{ viewportMat }, uniforms::u_world::Value{ size },
uniforms::u_image::Value{ 0 },
- uniforms::u_opacity::Value{ evaluated.get<FillExtrusionOpacity>() } },
+ uniforms::u_opacity::Value{ evaluated.get<FillExtrusionOpacity>() }
+ },
+ paintAttributeData,
+ properties,
+ parameters.state.getZoom()
+ );
+ const auto allAttributeBindings = programInstance.computeAllAttributeBindings(
parameters.staticData.extrusionTextureVertexBuffer,
+ paintAttributeData,
+ properties
+ );
+
+ checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings));
+
+ programInstance.draw(
+ parameters.context,
+ gl::Triangles(),
+ gl::DepthMode::disabled(),
+ gl::StencilMode::disabled(),
+ parameters.colorModeForRenderPass(),
parameters.staticData.quadTriangleIndexBuffer,
parameters.staticData.extrusionTextureSegments,
- ExtrusionTextureProgram::PaintPropertyBinders{ properties, 0 }, properties,
- parameters.state.getZoom(), getID());
+ allUniformValues,
+ allAttributeBindings,
+ getID());
}
}
diff --git a/src/mbgl/renderer/layers/render_fill_layer.cpp b/src/mbgl/renderer/layers/render_fill_layer.cpp
index efd3f4215c..c59ca6f906 100644
--- a/src/mbgl/renderer/layers/render_fill_layer.cpp
+++ b/src/mbgl/renderer/layers/render_fill_layer.cpp
@@ -69,12 +69,11 @@ void RenderFillLayer::render(PaintParameters& parameters, RenderSource*) {
const auto& depthMode,
const auto& indexBuffer,
const auto& segments) {
- program.get(evaluated).draw(
- parameters.context,
- drawMode,
- depthMode,
- parameters.stencilModeForClipping(tile.clip),
- parameters.colorModeForRenderPass(),
+ auto& programInstance = program.get(evaluated);
+
+ const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID());
+
+ const auto allUniformValues = programInstance.computeAllUniformValues(
FillProgram::UniformValues {
uniforms::u_matrix::Value{
tile.translatedMatrix(evaluated.get<FillTranslate>(),
@@ -83,12 +82,28 @@ void RenderFillLayer::render(PaintParameters& parameters, RenderSource*) {
},
uniforms::u_world::Value{ parameters.context.viewport.getCurrentValue().size },
},
+ paintPropertyBinders,
+ evaluated,
+ parameters.state.getZoom()
+ );
+ const auto allAttributeBindings = programInstance.computeAllAttributeBindings(
*bucket.vertexBuffer,
+ paintPropertyBinders,
+ evaluated
+ );
+
+ checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings));
+
+ programInstance.draw(
+ parameters.context,
+ drawMode,
+ depthMode,
+ parameters.stencilModeForClipping(tile.clip),
+ parameters.colorModeForRenderPass(),
indexBuffer,
segments,
- bucket.paintPropertyBinders.at(getID()),
- evaluated,
- parameters.state.getZoom(),
+ allUniformValues,
+ allAttributeBindings,
getID()
);
};
@@ -139,12 +154,11 @@ void RenderFillLayer::render(PaintParameters& parameters, RenderSource*) {
const auto& depthMode,
const auto& indexBuffer,
const auto& segments) {
- program.get(evaluated).draw(
- parameters.context,
- drawMode,
- depthMode,
- parameters.stencilModeForClipping(tile.clip),
- parameters.colorModeForRenderPass(),
+ auto& programInstance = program.get(evaluated);
+
+ const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID());
+
+ const auto allUniformValues = programInstance.computeAllUniformValues(
FillPatternUniforms::values(
tile.translatedMatrix(evaluated.get<FillTranslate>(),
evaluated.get<FillTranslateAnchor>(),
@@ -157,12 +171,28 @@ void RenderFillLayer::render(PaintParameters& parameters, RenderSource*) {
tile.id,
parameters.state
),
+ paintPropertyBinders,
+ evaluated,
+ parameters.state.getZoom()
+ );
+ const auto allAttributeBindings = programInstance.computeAllAttributeBindings(
*bucket.vertexBuffer,
+ paintPropertyBinders,
+ evaluated
+ );
+
+ checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings));
+
+ programInstance.draw(
+ parameters.context,
+ drawMode,
+ depthMode,
+ parameters.stencilModeForClipping(tile.clip),
+ parameters.colorModeForRenderPass(),
indexBuffer,
segments,
- bucket.paintPropertyBinders.at(getID()),
- evaluated,
- parameters.state.getZoom(),
+ allUniformValues,
+ allAttributeBindings,
getID()
);
};
diff --git a/src/mbgl/renderer/layers/render_heatmap_layer.cpp b/src/mbgl/renderer/layers/render_heatmap_layer.cpp
index 72c60446aa..dec9edb318 100644
--- a/src/mbgl/renderer/layers/render_heatmap_layer.cpp
+++ b/src/mbgl/renderer/layers/render_heatmap_layer.cpp
@@ -92,23 +92,38 @@ void RenderHeatmapLayer::render(PaintParameters& parameters, RenderSource*) {
? parameters.stencilModeForClipping(tile.clip)
: gl::StencilMode::disabled();
- parameters.programs.heatmap.get(evaluated).draw(
+ const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID());
+
+ auto& programInstance = parameters.programs.heatmap.get(evaluated);
+
+ const auto allUniformValues = programInstance.computeAllUniformValues(
+ HeatmapProgram::UniformValues {
+ uniforms::u_intensity::Value{ evaluated.get<style::HeatmapIntensity>() },
+ uniforms::u_matrix::Value{ tile.matrix },
+ uniforms::heatmap::u_extrude_scale::Value{ extrudeScale }
+ },
+ paintPropertyBinders,
+ evaluated,
+ parameters.state.getZoom()
+ );
+ const auto allAttributeBindings = programInstance.computeAllAttributeBindings(
+ *bucket.vertexBuffer,
+ paintPropertyBinders,
+ evaluated
+ );
+
+ checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings));
+
+ programInstance.draw(
parameters.context,
gl::Triangles(),
parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly),
stencilMode,
gl::ColorMode::additive(),
- HeatmapProgram::UniformValues {
- uniforms::u_intensity::Value{evaluated.get<style::HeatmapIntensity>()},
- uniforms::u_matrix::Value{tile.matrix},
- uniforms::heatmap::u_extrude_scale::Value{extrudeScale}
- },
- *bucket.vertexBuffer,
*bucket.indexBuffer,
bucket.segments,
- bucket.paintPropertyBinders.at(getID()),
- evaluated,
- parameters.state.getZoom(),
+ allUniformValues,
+ allAttributeBindings,
getID()
);
}
@@ -123,20 +138,41 @@ void RenderHeatmapLayer::render(PaintParameters& parameters, RenderSource*) {
matrix::ortho(viewportMat, 0, size.width, size.height, 0, 0, 1);
const Properties<>::PossiblyEvaluated properties;
+ const HeatmapTextureProgram::PaintPropertyBinders paintAttributeData{ properties, 0 };
+
+ auto& programInstance = parameters.programs.heatmapTexture;
- parameters.programs.heatmapTexture.draw(
- parameters.context, gl::Triangles(), gl::DepthMode::disabled(),
- gl::StencilMode::disabled(), parameters.colorModeForRenderPass(),
+ const auto allUniformValues = programInstance.computeAllUniformValues(
HeatmapTextureProgram::UniformValues{
uniforms::u_matrix::Value{ viewportMat }, uniforms::u_world::Value{ size },
uniforms::u_image::Value{ 0 },
uniforms::u_color_ramp::Value{ 1 },
- uniforms::u_opacity::Value{ evaluated.get<HeatmapOpacity>() } },
+ uniforms::u_opacity::Value{ evaluated.get<HeatmapOpacity>() }
+ },
+ paintAttributeData,
+ properties,
+ parameters.state.getZoom()
+ );
+ const auto allAttributeBindings = programInstance.computeAllAttributeBindings(
parameters.staticData.extrusionTextureVertexBuffer,
+ paintAttributeData,
+ properties
+ );
+
+ checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings));
+
+ programInstance.draw(
+ parameters.context,
+ gl::Triangles(),
+ gl::DepthMode::disabled(),
+ gl::StencilMode::disabled(),
+ parameters.colorModeForRenderPass(),
parameters.staticData.quadTriangleIndexBuffer,
parameters.staticData.extrusionTextureSegments,
- HeatmapTextureProgram::PaintPropertyBinders{ properties, 0 }, properties,
- parameters.state.getZoom(), getID());
+ allUniformValues,
+ allAttributeBindings,
+ getID()
+ );
}
}
diff --git a/src/mbgl/renderer/layers/render_hillshade_layer.cpp b/src/mbgl/renderer/layers/render_hillshade_layer.cpp
index bcfd4ffe99..411305edf4 100644
--- a/src/mbgl/renderer/layers/render_hillshade_layer.cpp
+++ b/src/mbgl/renderer/layers/render_hillshade_layer.cpp
@@ -69,12 +69,11 @@ void RenderHillshadeLayer::render(PaintParameters& parameters, RenderSource* src
const auto& indexBuffer,
const auto& segments,
const UnwrappedTileID& id) {
- parameters.programs.hillshade.draw(
- parameters.context,
- gl::Triangles(),
- parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly),
- gl::StencilMode::disabled(),
- parameters.colorModeForRenderPass(),
+ auto& programInstance = parameters.programs.hillshade;
+
+ const HillshadeProgram::PaintPropertyBinders paintAttributeData{ evaluated, 0 };
+
+ const auto allUniformValues = programInstance.computeAllUniformValues(
HillshadeProgram::UniformValues {
uniforms::u_matrix::Value{ matrix },
uniforms::u_image::Value{ 0 },
@@ -84,12 +83,28 @@ void RenderHillshadeLayer::render(PaintParameters& parameters, RenderSource* src
uniforms::u_light::Value{ getLight(parameters) },
uniforms::u_latrange::Value{ getLatRange(id) },
},
+ paintAttributeData,
+ evaluated,
+ parameters.state.getZoom()
+ );
+ const auto allAttributeBindings = programInstance.computeAllAttributeBindings(
vertexBuffer,
+ paintAttributeData,
+ evaluated
+ );
+
+ checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings));
+
+ programInstance.draw(
+ parameters.context,
+ gl::Triangles(),
+ parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly),
+ gl::StencilMode::disabled(),
+ parameters.colorModeForRenderPass(),
indexBuffer,
segments,
- HillshadeProgram::PaintPropertyBinders { evaluated, 0 },
- evaluated,
- parameters.state.getZoom(),
+ allUniformValues,
+ allAttributeBindings,
getID()
);
};
@@ -112,13 +127,11 @@ void RenderHillshadeLayer::render(PaintParameters& parameters, RenderSource* src
parameters.context.bindTexture(*bucket.dem, 0, gl::TextureFilter::Nearest, gl::TextureMipMap::No, gl::TextureWrap::Clamp, gl::TextureWrap::Clamp);
const Properties<>::PossiblyEvaluated properties;
+ const HillshadePrepareProgram::PaintPropertyBinders paintAttributeData{ properties, 0 };
- parameters.programs.hillshadePrepare.draw(
- parameters.context,
- gl::Triangles(),
- parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly),
- gl::StencilMode::disabled(),
- parameters.colorModeForRenderPass(),
+ auto& programInstance = parameters.programs.hillshadePrepare;
+
+ const auto allUniformValues = programInstance.computeAllUniformValues(
HillshadePrepareProgram::UniformValues {
uniforms::u_matrix::Value { mat },
uniforms::u_dimension::Value { {{uint16_t(tilesize * 2), uint16_t(tilesize * 2) }} },
@@ -126,12 +139,28 @@ void RenderHillshadeLayer::render(PaintParameters& parameters, RenderSource* src
uniforms::u_maxzoom::Value{ float(maxzoom) },
uniforms::u_image::Value{ 0 }
},
+ paintAttributeData,
+ properties,
+ parameters.state.getZoom()
+ );
+ const auto allAttributeBindings = programInstance.computeAllAttributeBindings(
parameters.staticData.rasterVertexBuffer,
+ paintAttributeData,
+ properties
+ );
+
+ checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings));
+
+ programInstance.draw(
+ parameters.context,
+ gl::Triangles(),
+ parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly),
+ gl::StencilMode::disabled(),
+ parameters.colorModeForRenderPass(),
parameters.staticData.quadTriangleIndexBuffer,
parameters.staticData.rasterSegments,
- HillshadePrepareProgram::PaintPropertyBinders { properties, 0 },
- properties,
- parameters.state.getZoom(),
+ allUniformValues,
+ allAttributeBindings,
getID()
);
bucket.texture = std::move(view.getTexture());
diff --git a/src/mbgl/renderer/layers/render_line_layer.cpp b/src/mbgl/renderer/layers/render_line_layer.cpp
index 02f61af0fa..361ad0c76b 100644
--- a/src/mbgl/renderer/layers/render_line_layer.cpp
+++ b/src/mbgl/renderer/layers/render_line_layer.cpp
@@ -62,19 +62,34 @@ void RenderLineLayer::render(PaintParameters& parameters, RenderSource*) {
LineBucket& bucket = *reinterpret_cast<LineBucket*>(tile.tile.getBucket(*baseImpl));
auto draw = [&] (auto& program, auto&& uniformValues) {
- program.get(evaluated).draw(
+ auto& programInstance = program.get(evaluated);
+
+ const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID());
+
+ const auto allUniformValues = programInstance.computeAllUniformValues(
+ std::move(uniformValues),
+ paintPropertyBinders,
+ evaluated,
+ parameters.state.getZoom()
+ );
+ const auto allAttributeBindings = programInstance.computeAllAttributeBindings(
+ *bucket.vertexBuffer,
+ paintPropertyBinders,
+ evaluated
+ );
+
+ checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings));
+
+ programInstance.draw(
parameters.context,
gl::Triangles(),
parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly),
parameters.stencilModeForClipping(tile.clip),
parameters.colorModeForRenderPass(),
- std::move(uniformValues),
- *bucket.vertexBuffer,
*bucket.indexBuffer,
bucket.segments,
- bucket.paintPropertyBinders.at(getID()),
- evaluated,
- parameters.state.getZoom(),
+ allUniformValues,
+ allAttributeBindings,
getID()
);
};
diff --git a/src/mbgl/renderer/layers/render_raster_layer.cpp b/src/mbgl/renderer/layers/render_raster_layer.cpp
index b41b2ac560..f202ed4ebb 100644
--- a/src/mbgl/renderer/layers/render_raster_layer.cpp
+++ b/src/mbgl/renderer/layers/render_raster_layer.cpp
@@ -73,16 +73,15 @@ void RenderRasterLayer::render(PaintParameters& parameters, RenderSource* source
if (parameters.pass != RenderPass::Translucent)
return;
+ RasterProgram::PaintPropertyBinders paintAttributeData{ evaluated, 0 };
+
auto draw = [&] (const mat4& matrix,
const auto& vertexBuffer,
const auto& indexBuffer,
const auto& segments) {
- parameters.programs.raster.draw(
- parameters.context,
- gl::Triangles(),
- parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly),
- gl::StencilMode::disabled(),
- parameters.colorModeForRenderPass(),
+ auto& programInstance = parameters.programs.raster;
+
+ const auto allUniformValues = programInstance.computeAllUniformValues(
RasterProgram::UniformValues {
uniforms::u_matrix::Value{ matrix },
uniforms::u_image0::Value{ 0 },
@@ -98,12 +97,28 @@ void RenderRasterLayer::render(PaintParameters& parameters, RenderSource* source
uniforms::u_scale_parent::Value{ 1.0f },
uniforms::u_tl_parent::Value{ std::array<float, 2> {{ 0.0f, 0.0f }} },
},
+ paintAttributeData,
+ evaluated,
+ parameters.state.getZoom()
+ );
+ const auto allAttributeBindings = programInstance.computeAllAttributeBindings(
vertexBuffer,
+ paintAttributeData,
+ evaluated
+ );
+
+ checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings));
+
+ programInstance.draw(
+ parameters.context,
+ gl::Triangles(),
+ parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly),
+ gl::StencilMode::disabled(),
+ parameters.colorModeForRenderPass(),
indexBuffer,
segments,
- RasterProgram::PaintPropertyBinders { evaluated, 0 },
- evaluated,
- parameters.state.getZoom(),
+ allUniformValues,
+ allAttributeBindings,
getID()
);
};
diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp
index 9e493003c0..e48c0e2f92 100644
--- a/src/mbgl/renderer/layers/render_symbol_layer.cpp
+++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp
@@ -88,7 +88,26 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) {
const auto& binders,
const auto& paintProperties)
{
- program.get(paintProperties).draw(
+ auto& programInstance = program.get(paintProperties);
+
+ const auto allUniformValues = programInstance.computeAllUniformValues(
+ std::move(uniformValues),
+ *symbolSizeBinder,
+ binders,
+ paintProperties,
+ parameters.state.getZoom()
+ );
+ const auto allAttributeBindings = programInstance.computeAllAttributeBindings(
+ *buffers.vertexBuffer,
+ *buffers.dynamicVertexBuffer,
+ *buffers.opacityVertexBuffer,
+ binders,
+ paintProperties
+ );
+
+ checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings));
+
+ programInstance.draw(
parameters.context,
gl::Triangles(),
values_.pitchAlignment == AlignmentType::Map
@@ -96,16 +115,10 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) {
: gl::DepthMode::disabled(),
gl::StencilMode::disabled(),
parameters.colorModeForRenderPass(),
- std::move(uniformValues),
- *buffers.vertexBuffer,
- *buffers.dynamicVertexBuffer,
- *buffers.opacityVertexBuffer,
- *symbolSizeBinder,
*buffers.indexBuffer,
buffers.segments,
- binders,
- paintProperties,
- parameters.state.getZoom(),
+ allUniformValues,
+ allAttributeBindings,
getID()
);
};
diff --git a/src/mbgl/renderer/render_layer.cpp b/src/mbgl/renderer/render_layer.cpp
index bcdc175f14..a667d5837e 100644
--- a/src/mbgl/renderer/render_layer.cpp
+++ b/src/mbgl/renderer/render_layer.cpp
@@ -9,8 +9,10 @@
#include <mbgl/renderer/layers/render_raster_layer.hpp>
#include <mbgl/renderer/layers/render_symbol_layer.hpp>
#include <mbgl/renderer/layers/render_heatmap_layer.hpp>
+#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/style/types.hpp>
#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/util/logging.hpp>
namespace mbgl {
@@ -73,5 +75,32 @@ void RenderLayer::setRenderTiles(std::vector<std::reference_wrapper<RenderTile>>
renderTiles = std::move(tiles);
}
+void RenderLayer::checkRenderability(const PaintParameters& parameters,
+ const uint32_t activeBindingCount) {
+ // Only warn once for every layer.
+ if (hasRenderFailures) {
+ return;
+ }
+
+ if (activeBindingCount > parameters.context.maximumVertexBindingCount) {
+ Log::Error(Event::OpenGL,
+ "The layer '%s' uses more data-driven properties than the current device "
+ "supports, and will have rendering errors. To ensure compatibility with this "
+ "device, use %d fewer data driven properties in this layer.",
+ getID().c_str(),
+ activeBindingCount - parameters.context.minimumRequiredVertexBindingCount);
+ hasRenderFailures = true;
+ } else if (activeBindingCount > parameters.context.minimumRequiredVertexBindingCount) {
+ Log::Error(Event::OpenGL,
+ "The layer '%s' uses more data-driven properties than some devices may support. "
+ "Though it will render correctly on this device, it may have rendering errors "
+ "on other devices. To ensure compatibility with all devices, use %d fewer "
+ "data-driven properties in this layer.",
+ getID().c_str(),
+ activeBindingCount - parameters.context.minimumRequiredVertexBindingCount);
+ hasRenderFailures = true;
+ }
+}
+
} //namespace mbgl
diff --git a/src/mbgl/renderer/render_layer.hpp b/src/mbgl/renderer/render_layer.hpp
index 04a1608564..3e2f1d7525 100644
--- a/src/mbgl/renderer/render_layer.hpp
+++ b/src/mbgl/renderer/render_layer.hpp
@@ -85,6 +85,11 @@ public:
friend std::string layoutKey(const RenderLayer&);
protected:
+ // Checks whether the current hardware can render this layer. If it can't, we'll show a warning
+ // in the console to inform the developer.
+ void checkRenderability(const PaintParameters&, uint32_t activeBindingCount);
+
+protected:
// renderTiles are exposed directly to CrossTileSymbolIndex and Placement so they
// can update opacities in the symbol buckets immediately before rendering
friend class CrossTileSymbolIndex;
@@ -95,6 +100,12 @@ protected:
// Stores what render passes this layer is currently enabled for. This depends on the
// evaluated StyleProperties object and is updated accordingly.
RenderPass passes = RenderPass::None;
+
+private:
+ // Some layers may not render correctly on some hardware when the vertex attribute limit of
+ // that GPU is exceeded. More attributes are used when adding many data driven paint properties
+ // to a layer.
+ bool hasRenderFailures = false;
};
} // namespace mbgl
diff --git a/src/mbgl/renderer/render_tile.cpp b/src/mbgl/renderer/render_tile.cpp
index 35b34833e4..64790938ef 100644
--- a/src/mbgl/renderer/render_tile.cpp
+++ b/src/mbgl/renderer/render_tile.cpp
@@ -74,6 +74,8 @@ void RenderTile::finishRender(PaintParameters& parameters) {
static const style::Properties<>::PossiblyEvaluated properties {};
static const DebugProgram::PaintPropertyBinders paintAttributeData(properties, 0);
+ auto& program = parameters.programs.debug;
+
if (parameters.debugOptions & (MapDebugOptions::Timestamps | MapDebugOptions::ParseStatus)) {
if (!tile.debugBucket || tile.debugBucket->renderable != tile.isRenderable() ||
tile.debugBucket->complete != tile.isComplete() ||
@@ -85,41 +87,51 @@ void RenderTile::finishRender(PaintParameters& parameters) {
tile.expires, parameters.debugOptions, parameters.context);
}
- parameters.programs.debug.draw(
+ const auto allAttributeBindings = program.computeAllAttributeBindings(
+ *tile.debugBucket->vertexBuffer,
+ paintAttributeData,
+ properties
+ );
+
+ program.draw(
parameters.context,
gl::Lines { 4.0f * parameters.pixelRatio },
gl::DepthMode::disabled(),
parameters.stencilModeForClipping(clip),
gl::ColorMode::unblended(),
- DebugProgram::UniformValues {
- uniforms::u_matrix::Value{ matrix },
- uniforms::u_color::Value{ Color::white() }
- },
- *tile.debugBucket->vertexBuffer,
*tile.debugBucket->indexBuffer,
tile.debugBucket->segments,
- paintAttributeData,
- properties,
- parameters.state.getZoom(),
+ program.computeAllUniformValues(
+ DebugProgram::UniformValues {
+ uniforms::u_matrix::Value{ matrix },
+ uniforms::u_color::Value{ Color::white() }
+ },
+ paintAttributeData,
+ properties,
+ parameters.state.getZoom()
+ ),
+ allAttributeBindings,
"debug"
);
- parameters.programs.debug.draw(
+ program.draw(
parameters.context,
gl::Lines { 2.0f * parameters.pixelRatio },
gl::DepthMode::disabled(),
parameters.stencilModeForClipping(clip),
gl::ColorMode::unblended(),
- DebugProgram::UniformValues {
- uniforms::u_matrix::Value{ matrix },
- uniforms::u_color::Value{ Color::black() }
- },
- *tile.debugBucket->vertexBuffer,
*tile.debugBucket->indexBuffer,
tile.debugBucket->segments,
- paintAttributeData,
- properties,
- parameters.state.getZoom(),
+ program.computeAllUniformValues(
+ DebugProgram::UniformValues {
+ uniforms::u_matrix::Value{ matrix },
+ uniforms::u_color::Value{ Color::black() }
+ },
+ paintAttributeData,
+ properties,
+ parameters.state.getZoom()
+ ),
+ allAttributeBindings,
"debug"
);
}
@@ -131,16 +143,22 @@ void RenderTile::finishRender(PaintParameters& parameters) {
gl::DepthMode::disabled(),
parameters.stencilModeForClipping(clip),
gl::ColorMode::unblended(),
- DebugProgram::UniformValues {
- uniforms::u_matrix::Value{ matrix },
- uniforms::u_color::Value{ Color::red() }
- },
- parameters.staticData.tileVertexBuffer,
parameters.staticData.tileBorderIndexBuffer,
parameters.staticData.tileBorderSegments,
- paintAttributeData,
- properties,
- parameters.state.getZoom(),
+ program.computeAllUniformValues(
+ DebugProgram::UniformValues {
+ uniforms::u_matrix::Value{ matrix },
+ uniforms::u_color::Value{ Color::red() }
+ },
+ paintAttributeData,
+ properties,
+ parameters.state.getZoom()
+ ),
+ program.computeAllAttributeBindings(
+ parameters.staticData.tileVertexBuffer,
+ paintAttributeData,
+ properties
+ ),
"debug"
);
}
diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp
index ded07a0909..4380ef24a1 100644
--- a/src/mbgl/renderer/renderer_impl.cpp
+++ b/src/mbgl/renderer/renderer_impl.cpp
@@ -486,7 +486,9 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) {
static const ClippingMaskProgram::PaintPropertyBinders paintAttributeData(properties, 0);
for (const auto& clipID : parameters.clipIDGenerator.getClipIDs()) {
- parameters.staticData.programs.clippingMask.draw(
+ auto& program = parameters.staticData.programs.clippingMask;
+
+ program.draw(
parameters.context,
gl::Triangles(),
gl::DepthMode::disabled(),
@@ -499,15 +501,21 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) {
gl::StencilMode::Replace
},
gl::ColorMode::disabled(),
- ClippingMaskProgram::UniformValues {
- uniforms::u_matrix::Value{ parameters.matrixForTile(clipID.first) },
- },
- parameters.staticData.tileVertexBuffer,
parameters.staticData.quadTriangleIndexBuffer,
parameters.staticData.tileTriangleSegments,
- paintAttributeData,
- properties,
- parameters.state.getZoom(),
+ program.computeAllUniformValues(
+ ClippingMaskProgram::UniformValues {
+ uniforms::u_matrix::Value{ parameters.matrixForTile(clipID.first) },
+ },
+ paintAttributeData,
+ properties,
+ parameters.state.getZoom()
+ ),
+ program.computeAllAttributeBindings(
+ parameters.staticData.tileVertexBuffer,
+ paintAttributeData,
+ properties
+ ),
"clipping"
);
}
diff --git a/src/mbgl/renderer/sources/render_image_source.cpp b/src/mbgl/renderer/sources/render_image_source.cpp
index 5c497e8144..dce5e40185 100644
--- a/src/mbgl/renderer/sources/render_image_source.cpp
+++ b/src/mbgl/renderer/sources/render_image_source.cpp
@@ -58,24 +58,32 @@ void RenderImageSource::finishRender(PaintParameters& parameters) {
static const style::Properties<>::PossiblyEvaluated properties {};
static const DebugProgram::PaintPropertyBinders paintAttributeData(properties, 0);
+ auto& programInstance = parameters.programs.debug;
+
for (auto matrix : matrices) {
- parameters.programs.debug.draw(
+ programInstance.draw(
parameters.context,
gl::LineStrip { 4.0f * parameters.pixelRatio },
gl::DepthMode::disabled(),
gl::StencilMode::disabled(),
gl::ColorMode::unblended(),
- DebugProgram::UniformValues {
- uniforms::u_matrix::Value{ matrix },
- uniforms::u_color::Value{ Color::red() }
- },
- parameters.staticData.tileVertexBuffer,
parameters.staticData.tileBorderIndexBuffer,
parameters.staticData.tileBorderSegments,
- paintAttributeData,
- properties,
- parameters.state.getZoom(),
- "debug"
+ programInstance.computeAllUniformValues(
+ DebugProgram::UniformValues {
+ uniforms::u_matrix::Value{ matrix },
+ uniforms::u_color::Value{ Color::red() }
+ },
+ paintAttributeData,
+ properties,
+ parameters.state.getZoom()
+ ),
+ programInstance.computeAllAttributeBindings(
+ parameters.staticData.tileVertexBuffer,
+ paintAttributeData,
+ properties
+ ),
+ "image"
);
}
}
diff --git a/src/mbgl/style/conversion/filter.cpp b/src/mbgl/style/conversion/filter.cpp
index 3c941945fd..386d85e921 100644
--- a/src/mbgl/style/conversion/filter.cpp
+++ b/src/mbgl/style/conversion/filter.cpp
@@ -1,17 +1,39 @@
#include <mbgl/style/conversion/filter.hpp>
+#include <mbgl/style/expression/literal.hpp>
#include <mbgl/util/geometry.hpp>
#include <mbgl/style/expression/expression.hpp>
#include <mbgl/style/expression/type.hpp>
-#include <mbgl/style/expression/parsing_context.hpp>
+#include <mbgl/style/expression/compound_expression.hpp>
+#include <mbgl/style/expression/boolean_operator.hpp>
namespace mbgl {
namespace style {
namespace conversion {
-using GeometryValue = mapbox::geometry::value;
+using namespace mbgl::style::expression;
+
+static bool isExpression(const Convertible& filter);
+std::unique_ptr<Expression> convertLegacyFilter(const Convertible& values, Error& error);
+
+optional<Filter> Converter<Filter>::operator()(const Convertible& value, Error& error) const {
+ if (isExpression(value)) {
+ ParsingContext parsingContext(type::Boolean);
+ ParseResult parseResult = parsingContext.parseExpression(value);
+ if (!parseResult) {
+ error = { parsingContext.getCombinedErrors() };
+ return {};
+ } else {
+ return { Filter(std::move(parseResult)) };
+ }
+ } else {
+ std::unique_ptr<Expression> expression = convertLegacyFilter(value, error);
+ if (!expression) return {};
+ return Filter(optional<std::unique_ptr<Expression>>(std::move(expression)));
+ }
+}
// This is a port from https://github.com/mapbox/mapbox-gl-js/blob/master/src/style-spec/feature_filter/index.js
-static bool isExpressionFilter(const Convertible& filter) {
+bool isExpression(const Convertible& filter) {
if (!isArray(filter) || arrayLength(filter) == 0) {
return false;
}
@@ -20,7 +42,7 @@ static bool isExpressionFilter(const Convertible& filter) {
if (!op) {
return false;
-
+
} else if (*op == "has") {
if (arrayLength(filter) < 2) return false;
optional<std::string> operand = toString(arrayMember(filter, 1));
@@ -35,7 +57,7 @@ static bool isExpressionFilter(const Convertible& filter) {
} else if (*op == "any" || *op == "all") {
for (std::size_t i = 1; i < arrayLength(filter); i++) {
Convertible f = arrayMember(filter, i);
- if (!isExpressionFilter(f) && !toBool(f)) {
+ if (!isExpression(f) && !toBool(f)) {
return false;
}
}
@@ -46,257 +68,136 @@ static bool isExpressionFilter(const Convertible& filter) {
}
}
-static optional<GeometryValue> normalizeValue(const optional<GeometryValue>& value, Error& error) {
- if (!value) {
- error = { "filter expression value must be a boolean, number, or string" };
- return {};
- } else {
- return *value;
- }
-}
+std::unique_ptr<Expression> createExpression(std::string op, std::vector<std::unique_ptr<Expression>> args, Error& error) {
+ if (op == "any") {
+ return std::make_unique<Any>(std::move(args));
+
+ } else if (op == "all") {
+ return std::make_unique<All>(std::move(args));
-static optional<FeatureType> toFeatureType(const Convertible& value, Error& error) {
- optional<std::string> type = toString(value);
- if (!type) {
- error = { "value for $type filter must be a string" };
- return {};
- } else if (*type == "Point") {
- return FeatureType::Point;
- } else if (*type == "LineString") {
- return FeatureType::LineString;
- } else if (*type == "Polygon") {
- return FeatureType::Polygon;
} else {
- error = { "value for $type filter must be Point, LineString, or Polygon" };
- return {};
+ ParsingContext parsingContext(type::Boolean);
+ ParseResult parseResult = createCompoundExpression(op, std::move(args), parsingContext);
+ if (!parseResult) {
+ error = { parsingContext.getCombinedErrors() };
+ return {};
+ } else {
+ return std::move(*parseResult);
+ }
}
}
-static optional<FeatureIdentifier> toFeatureIdentifier(const Convertible& value, Error& error) {
- optional<GeometryValue> identifier = toValue(value);
- if (!identifier) {
- error = { "filter expression value must be a boolean, number, or string" };
- return {};
- } else {
- return (*identifier).match(
- [] (uint64_t t) -> optional<FeatureIdentifier> { return { t }; },
- [] ( int64_t t) -> optional<FeatureIdentifier> { return { t }; },
- [] ( double t) -> optional<FeatureIdentifier> { return { t }; },
- [] (const std::string& t) -> optional<FeatureIdentifier> { return { t }; },
- [&] (const auto&) -> optional<FeatureIdentifier> {
- error = { "filter expression value must be a boolean, number, or string" };
- return {};
- });
- }
+std::unique_ptr<Expression> createExpression(std::string op, std::unique_ptr<Expression> expression, Error& error) {
+ std::vector<std::unique_ptr<Expression>> args;
+ args.push_back(std::move(expression));
+ return createExpression(op, std::move(args), error);
}
-template <class FilterType, class IdentifierFilterType>
-optional<Filter> convertUnaryFilter(const Convertible& value, Error& error) {
- if (arrayLength(value) < 2) {
- error = { "filter expression must have 2 elements" };
- return {};
- }
-
- optional<std::string> key = toString(arrayMember(value, 1));
- if (!key) {
- error = { "filter expression key must be a string" };
- return {};
- }
-
- if (*key == "$id") {
- return { IdentifierFilterType {} };
+std::unique_ptr<Expression> convertLiteral(const Convertible& convertible, Error& error) {
+ ParsingContext parsingContext;
+ ParseResult parseResult = Literal::parse(convertible, parsingContext);
+ if (parseResult) {
+ return std::move(*parseResult);
} else {
- return { FilterType { *key } };
+ error = { parsingContext.getCombinedErrors() };
+ return {};
}
}
-template <class FilterType, class TypeFilterType, class IdentifierFilterType>
-optional<Filter> convertEqualityFilter(const Convertible& value, Error& error) {
- if (arrayLength(value) < 3) {
- error = { "filter expression must have 3 elements" };
- return {};
+std::vector<std::unique_ptr<Expression>> convertLiteralArray(const Convertible &input, Error& error, std::size_t startIndex = 0) {
+ std::vector<std::unique_ptr<Expression>> output;
+ for (std::size_t i = startIndex; i < arrayLength(input); i++) {
+ output.push_back(convertLiteral(arrayMember(input, i), error));
}
+ return output;
+}
- optional<std::string> key = toString(arrayMember(value, 1));
- if (!key) {
- error = { "filter expression key must be a string" };
+std::unique_ptr<Expression> convertLegacyComparisonFilter(const Convertible& values, Error& error, optional<std::string> opOverride = {}) {
+ optional<std::string> op = opOverride ? opOverride : toString(arrayMember(values, 0));
+ optional<std::string> property = toString(arrayMember(values, 1));
+
+ if (!property) {
+ error = { "filter property must be a string" };
return {};
- }
-
- if (*key == "$type") {
- optional<FeatureType> filterValue = toFeatureType(arrayMember(value, 2), error);
- if (!filterValue) {
- return {};
- }
-
- return { TypeFilterType { *filterValue } };
-
- } else if (*key == "$id") {
- optional<FeatureIdentifier> filterValue = toFeatureIdentifier(arrayMember(value, 2), error);
- if (!filterValue) {
- return {};
- }
-
- return { IdentifierFilterType { *filterValue } };
-
+ } else if (*property == "$type") {
+ return createExpression("filter-type-" + *op, convertLiteralArray(values, error, 2), error);
+ } else if (*property == "$id") {
+ return createExpression("filter-id-" + *op, convertLiteralArray(values, error, 2), error);
} else {
- optional<GeometryValue> filterValue = normalizeValue(toValue(arrayMember(value, 2)), error);
- if (!filterValue) {
- return {};
- }
-
- return { FilterType { *key, *filterValue } };
+ return createExpression("filter-" + *op, convertLiteralArray(values, error, 1), error);
}
}
-
-template <class FilterType>
-optional<Filter> convertBinaryFilter(const Convertible& value, Error& error) {
- if (arrayLength(value) < 3) {
- error = { "filter expression must have 3 elements" };
- return {};
- }
-
- optional<std::string> key = toString(arrayMember(value, 1));
- if (!key) {
- error = { "filter expression key must be a string" };
- return {};
- }
-
- optional<GeometryValue> filterValue = normalizeValue(toValue(arrayMember(value, 2)), error);
- if (!filterValue) {
+
+std::unique_ptr<Expression> convertLegacyHasFilter(const Convertible& values, Error& error) {
+ optional<std::string> property = toString(arrayMember(values, 1));
+
+ if (!property) {
+ error = { "filter property must be a string" };
return {};
+ } else if (*property == "$type") {
+ return std::make_unique<Literal>(true);
+ } else if (*property == "$id") {
+ return createExpression("filter-has-id", std::vector<std::unique_ptr<Expression>>(), error);
+ } else {
+ return createExpression("filter-has", std::make_unique<Literal>(*property), error);
}
-
- return { FilterType { *key, *filterValue } };
}
-template <class FilterType, class TypeFilterType, class IdentifierFilterType>
-optional<Filter> convertSetFilter(const Convertible& value, Error& error) {
- if (arrayLength(value) < 2) {
- error = { "filter expression must at least 2 elements" };
- return {};
- }
-
- optional<std::string> key = toString(arrayMember(value, 1));
- if (!key) {
- error = { "filter expression key must be a string" };
- return {};
- }
-
- if (*key == "$type") {
- std::vector<FeatureType> values;
- for (std::size_t i = 2; i < arrayLength(value); ++i) {
- optional<FeatureType> filterValue = toFeatureType(arrayMember(value, i), error);
- if (!filterValue) {
- return {};
- }
- values.push_back(*filterValue);
- }
-
- return { TypeFilterType { std::move(values) } };
-
- } else if (*key == "$id") {
- std::vector<FeatureIdentifier> values;
- for (std::size_t i = 2; i < arrayLength(value); ++i) {
- optional<FeatureIdentifier> filterValue = toFeatureIdentifier(arrayMember(value, i), error);
- if (!filterValue) {
- return {};
- }
- values.push_back(*filterValue);
- }
-
- return { IdentifierFilterType { std::move(values) } };
-
+std::unique_ptr<Expression> convertLegacyInFilter(const Convertible& values, Error& error) {
+ optional<std::string> property = toString(arrayMember(values, 1));
+
+ if (!property) {
+ error = { "filter property must be a string" };
+ return {};
+ } else if (arrayLength(values) == 0) {
+ return std::make_unique<Literal>(false);
+ } else if (*property == "$type") {
+ return createExpression("filter-type-in", convertLiteralArray(values, error, 2), error);
+ } else if (*property == "$id") {
+ return createExpression("filter-id-in", convertLiteralArray(values, error, 2), error);
} else {
- std::vector<GeometryValue> values;
- for (std::size_t i = 2; i < arrayLength(value); ++i) {
- optional<GeometryValue> filterValue = normalizeValue(toValue(arrayMember(value, i)), error);
- if (!filterValue) {
- return {};
- }
- values.push_back(*filterValue);
- }
-
- return { FilterType { *key, std::move(values) } };
+ return createExpression("filter-in", convertLiteralArray(values, error, 1), error);
}
}
-template <class FilterType>
-optional<Filter> convertCompoundFilter(const Convertible& value, Error& error) {
- std::vector<Filter> filters;
- for (std::size_t i = 1; i < arrayLength(value); ++i) {
- optional<Filter> element = convert<Filter>(arrayMember(value, i), error);
- if (!element) {
- return {};
- }
- filters.push_back(*element);
+std::vector<std::unique_ptr<Expression>> convertLegacyFilterArray(const Convertible &input, Error& error, std::size_t startIndex = 0) {
+ std::vector<std::unique_ptr<Expression>> output;
+ for (std::size_t i = startIndex; i < arrayLength(input); i++) {
+ output.push_back(convertLegacyFilter(arrayMember(input, i), error));
}
-
- return { FilterType { std::move(filters) } };
+ return output;
}
-optional<Filter> convertExpressionFilter(const Convertible& value, Error& error) {
- expression::ParsingContext ctx(expression::type::Boolean);
- expression::ParseResult expression = ctx.parseExpression(value);
- if (!expression) {
- error = { ctx.getCombinedErrors() };
- return {};
- }
-
- return { ExpressionFilter { std::move(*expression) } };
-}
-
-optional<Filter> Converter<Filter>::operator()(const Convertible& value, Error& error) const {
- if (isExpressionFilter(value)) {
- return convertExpressionFilter(value, error);
+std::unique_ptr<Expression> convertLegacyFilter(const Convertible& values, Error& error) {
+ if (isUndefined(values)) {
+ return std::make_unique<Literal>(true);
}
- if (!isArray(value)) {
- error = { "filter expression must be an array" };
- return {};
- }
-
- if (arrayLength(value) < 1) {
- error = { "filter expression must have at least 1 element" };
- return {};
- }
+ optional<std::string> op = toString(arrayMember(values, 0));
- optional<std::string> op = toString(arrayMember(value, 0));
if (!op) {
error = { "filter operator must be a string" };
return {};
+ } else if (arrayLength(values) <= 1) {
+ return std::make_unique<Literal>(*op != "any");
+ } else {
+ return (
+ *op == "==" ||
+ *op == "<" ||
+ *op == ">" ||
+ *op == "<=" ||
+ *op == ">=" ? convertLegacyComparisonFilter(values, error) :
+ *op == "!=" ? createExpression("!", convertLegacyComparisonFilter(values, error, {"=="}), error) :
+ *op == "any" ? createExpression("any", convertLegacyFilterArray(values, error, 1), error) :
+ *op == "all" ? createExpression("all", convertLegacyFilterArray(values, error, 1), error) :
+ *op == "none" ? createExpression("!", createExpression("any", convertLegacyFilterArray(values, error, 1), error), error) :
+ *op == "in" ? convertLegacyInFilter(values, error) :
+ *op == "!in" ? createExpression("!", convertLegacyInFilter(values, error), error) :
+ *op == "has" ? convertLegacyHasFilter(values, error) :
+ *op == "!has" ? createExpression("!", convertLegacyHasFilter(values, error), error) :
+ std::make_unique<Literal>(true)
+ );
}
-
- if (*op == "==") {
- return convertEqualityFilter<EqualsFilter, TypeEqualsFilter, IdentifierEqualsFilter>(value, error);
- } else if (*op == "!=") {
- return convertEqualityFilter<NotEqualsFilter, TypeNotEqualsFilter, IdentifierNotEqualsFilter>(value, error);
- } else if (*op == ">") {
- return convertBinaryFilter<GreaterThanFilter>(value, error);
- } else if (*op == ">=") {
- return convertBinaryFilter<GreaterThanEqualsFilter>(value, error);
- } else if (*op == "<") {
- return convertBinaryFilter<LessThanFilter>(value, error);
- } else if (*op == "<=") {
- return convertBinaryFilter<LessThanEqualsFilter>(value, error);
- } else if (*op == "in") {
- return convertSetFilter<InFilter, TypeInFilter, IdentifierInFilter>(value, error);
- } else if (*op == "!in") {
- return convertSetFilter<NotInFilter, TypeNotInFilter, IdentifierNotInFilter>(value, error);
- } else if (*op == "all") {
- return convertCompoundFilter<AllFilter>(value, error);
- } else if (*op == "any") {
- return convertCompoundFilter<AnyFilter>(value, error);
- } else if (*op == "none") {
- return convertCompoundFilter<NoneFilter>(value, error);
- } else if (*op == "has") {
- return convertUnaryFilter<HasFilter, HasIdentifierFilter>(value, error);
- } else if (*op == "!has") {
- return convertUnaryFilter<NotHasFilter, NotHasIdentifierFilter>(value, error);
- }
-
- error = { R"(filter operator must be one of "==", "!=", ">", ">=", "<", "<=", "in", "!in", "all", "any", "none", "has", or "!has")" };
- return {};
}
} // namespace conversion
diff --git a/src/mbgl/style/conversion/stringify.hpp b/src/mbgl/style/conversion/stringify.hpp
index 7b7727d7c4..74171763a0 100644
--- a/src/mbgl/style/conversion/stringify.hpp
+++ b/src/mbgl/style/conversion/stringify.hpp
@@ -126,162 +126,9 @@ void stringify(Writer& writer, const FeatureIdentifier& id) {
}
template <class Writer>
-class StringifyFilter {
-public:
- Writer& writer;
-
- void operator()(const NullFilter&) {
- writer.Null();
- }
-
- void operator()(const EqualsFilter& f) {
- stringifyBinaryFilter(f, "==");
- }
-
- void operator()(const NotEqualsFilter& f) {
- stringifyBinaryFilter(f, "!=");
- }
-
- void operator()(const LessThanFilter& f) {
- stringifyBinaryFilter(f, "<");
- }
-
- void operator()(const LessThanEqualsFilter& f) {
- stringifyBinaryFilter(f, "<=");
- }
-
- void operator()(const GreaterThanFilter& f) {
- stringifyBinaryFilter(f, ">");
- }
-
- void operator()(const GreaterThanEqualsFilter& f) {
- stringifyBinaryFilter(f, ">=");
- }
-
- void operator()(const InFilter& f) {
- stringifySetFilter(f, "in");
- }
-
- void operator()(const NotInFilter& f) {
- stringifySetFilter(f, "!in");
- }
-
- void operator()(const AllFilter& f) {
- stringifyCompoundFilter(f, "all");
- }
-
- void operator()(const AnyFilter& f) {
- stringifyCompoundFilter(f, "any");
- }
-
- void operator()(const NoneFilter& f) {
- stringifyCompoundFilter(f, "none");
- }
-
- void operator()(const HasFilter& f) {
- stringifyUnaryFilter("has", f.key);
- }
-
- void operator()(const NotHasFilter& f) {
- stringifyUnaryFilter("!has", f.key);
- }
-
- void operator()(const TypeEqualsFilter& f) {
- stringifyBinaryFilter(f, "==", "$type");
- }
-
- void operator()(const TypeNotEqualsFilter& f) {
- stringifyBinaryFilter(f, "!=", "$type");
- }
-
- void operator()(const TypeInFilter& f) {
- stringifySetFilter(f, "in", "$type");
- }
-
- void operator()(const TypeNotInFilter& f) {
- stringifySetFilter(f, "!in", "$type");
- }
-
- void operator()(const IdentifierEqualsFilter& f) {
- stringifyBinaryFilter(f, "==", "$id");
- }
-
- void operator()(const IdentifierNotEqualsFilter& f) {
- stringifyBinaryFilter(f, "!=", "$id");
- }
-
- void operator()(const IdentifierInFilter& f) {
- stringifySetFilter(f, "in", "$id");
- }
-
- void operator()(const IdentifierNotInFilter& f) {
- stringifySetFilter(f, "!in", "$id");
- }
-
- void operator()(const HasIdentifierFilter&) {
- stringifyUnaryFilter("has", "$id");
- }
-
- void operator()(const NotHasIdentifierFilter&) {
- stringifyUnaryFilter("!has", "$id");
- }
-
- void operator()(const ExpressionFilter& filter) {
- stringify(writer, filter.expression->serialize());
- }
-
-private:
- template <class F>
- void stringifyBinaryFilter(const F& f, const char * op) {
- stringifyBinaryFilter(f, op, f.key);
- }
-
- template <class F>
- void stringifyBinaryFilter(const F& f, const char * op, const std::string& key) {
- writer.StartArray();
- writer.String(op);
- writer.String(key);
- stringify(writer, f.value);
- writer.EndArray();
- }
-
- template <class F>
- void stringifySetFilter(const F& f, const char * op) {
- stringifySetFilter(f, op, f.key);
- }
-
- template <class F>
- void stringifySetFilter(const F& f, const char * op, const std::string& key) {
- writer.StartArray();
- writer.String(op);
- writer.String(key);
- for (const auto& value : f.values) {
- stringify(writer, value);
- }
- writer.EndArray();
- }
-
- template <class F>
- void stringifyCompoundFilter(const F& f, const char * op) {
- writer.StartArray();
- writer.String(op);
- for (const auto& filter : f.filters) {
- Filter::visit(filter, *this);
- }
- writer.EndArray();
- }
-
- void stringifyUnaryFilter(const char * op, const std::string& key) {
- writer.StartArray();
- writer.String(op);
- writer.String(key);
- writer.EndArray();
- }
-};
-
-template <class Writer>
-void stringify(Writer& writer, const Filter& f) {
- Filter::visit(f, StringifyFilter<Writer> { writer });
+void stringify(Writer& writer, const Filter& filter) {
+ if (!filter.expression) writer.Null();
+ else stringify(writer, (*filter.expression)->serialize());
}
template <class Writer>
diff --git a/src/mbgl/style/expression/compound_expression.cpp b/src/mbgl/style/expression/compound_expression.cpp
index bcde09e1b6..4226756fe4 100644
--- a/src/mbgl/style/expression/compound_expression.cpp
+++ b/src/mbgl/style/expression/compound_expression.cpp
@@ -19,7 +19,7 @@ namespace detail {
The Signature<Fn> structs are wrappers around an "evaluate()" function whose
purpose is to extract the necessary Type data from the evaluate function's
type. There are three key (partial) specializations:
-
+
Signature<R (Params...)>:
Wraps a simple evaluate function (const T0&, const T1&, ...) -> Result<U>
@@ -30,9 +30,9 @@ namespace detail {
Signature<R (const EvaluationContext&, Params...)>:
Wraps an evaluate function that needs to access the expression evaluation
parameters in addition to its subexpressions, i.e.,
- (const EvaluationParams& const T0&, const T1&, ...) -> Result<U>. Needed
+ (const EvaluationParams&, const T0&, const T1&, ...) -> Result<U>. Needed
for expressions like ["zoom"], ["get", key], etc.
-
+
In each of the above evaluate signatures, T0, T1, etc. are the types of
the successfully evaluated subexpressions.
*/
@@ -43,7 +43,7 @@ struct Signature;
template <class R, class... Params>
struct Signature<R (Params...)> : SignatureBase {
using Args = std::array<std::unique_ptr<Expression>, sizeof...(Params)>;
-
+
Signature(R (*evaluate_)(Params...), std::string name_) :
SignatureBase(
valueTypeToExpressionType<std::decay_t<typename R::Value>>(),
@@ -55,7 +55,7 @@ struct Signature<R (Params...)> : SignatureBase {
EvaluationResult apply(const EvaluationContext& evaluationParameters, const Args& args) const {
return applyImpl(evaluationParameters, args, std::index_sequence_for<Params...>{});
}
-
+
std::unique_ptr<Expression> makeExpression(std::vector<std::unique_ptr<Expression>> args) const override {
typename Signature::Args argsArray;
std::copy_n(std::make_move_iterator(args.begin()), sizeof...(Params), argsArray.begin());
@@ -80,7 +80,7 @@ private:
template <class R, typename T>
struct Signature<R (const Varargs<T>&)> : SignatureBase {
using Args = std::vector<std::unique_ptr<Expression>>;
-
+
Signature(R (*evaluate_)(const Varargs<T>&), std::string name_) :
SignatureBase(
valueTypeToExpressionType<std::decay_t<typename R::Value>>(),
@@ -89,11 +89,11 @@ struct Signature<R (const Varargs<T>&)> : SignatureBase {
),
evaluate(evaluate_)
{}
-
+
std::unique_ptr<Expression> makeExpression(std::vector<std::unique_ptr<Expression>> args) const override {
return std::make_unique<CompoundExpression<Signature>>(name, *this, std::move(args));
};
-
+
EvaluationResult apply(const EvaluationContext& evaluationParameters, const Args& args) const {
Varargs<T> evaluated;
evaluated.reserve(args.size());
@@ -115,7 +115,7 @@ struct Signature<R (const Varargs<T>&)> : SignatureBase {
template <class R, class... Params>
struct Signature<R (const EvaluationContext&, Params...)> : SignatureBase {
using Args = std::array<std::unique_ptr<Expression>, sizeof...(Params)>;
-
+
Signature(R (*evaluate_)(const EvaluationContext&, Params...), std::string name_) :
SignatureBase(
valueTypeToExpressionType<std::decay_t<typename R::Value>>(),
@@ -124,17 +124,17 @@ struct Signature<R (const EvaluationContext&, Params...)> : SignatureBase {
),
evaluate(evaluate_)
{}
-
+
std::unique_ptr<Expression> makeExpression(std::vector<std::unique_ptr<Expression>> args) const override {
typename Signature::Args argsArray;
std::copy_n(std::make_move_iterator(args.begin()), sizeof...(Params), argsArray.begin());
return std::make_unique<CompoundExpression<Signature>>(name, *this, std::move(argsArray));
}
-
+
EvaluationResult apply(const EvaluationContext& evaluationParameters, const Args& args) const {
return applyImpl(evaluationParameters, args, std::index_sequence_for<Params...>{});
}
-
+
private:
template <std::size_t ...I>
EvaluationResult applyImpl(const EvaluationContext& evaluationParameters, const Args& args, std::index_sequence<I...>) const {
@@ -150,6 +150,41 @@ private:
R (*evaluate)(const EvaluationContext&, Params...);
};
+
+// Evaluate function needing EvaluationContext and Varargs
+// (const EvaluationContext&, const Varargs<T>&) -> Result<U>
+template <class R, typename T>
+struct Signature<R (const EvaluationContext&, const Varargs<T>&)> : SignatureBase {
+ using Args = std::vector<std::unique_ptr<Expression>>;
+
+ Signature(R (*evaluate_)(const EvaluationContext&, const Varargs<T>&), std::string name_) :
+ SignatureBase(
+ valueTypeToExpressionType<std::decay_t<typename R::Value>>(),
+ VarargsType { valueTypeToExpressionType<T>() },
+ std::move(name_)
+ ),
+ evaluate(evaluate_)
+ {}
+
+ std::unique_ptr<Expression> makeExpression(std::vector<std::unique_ptr<Expression>> args) const override {
+ return std::make_unique<CompoundExpression<Signature>>(name, *this, std::move(args));
+ };
+
+ EvaluationResult apply(const EvaluationContext& evaluationParameters, const Args& args) const {
+ Varargs<T> evaluated;
+ evaluated.reserve(args.size());
+ for (const auto& arg : args) {
+ const EvaluationResult evaluatedArg = arg->evaluate(evaluationParameters);
+ if(!evaluatedArg) return evaluatedArg.error();
+ evaluated.push_back(*fromExpressionValue<std::decay_t<T>>(*evaluatedArg));
+ }
+ const R value = evaluate(evaluationParameters, evaluated);
+ if (!value) return value.error();
+ return *value;
+ }
+
+ R (*evaluate)(const EvaluationContext&, const Varargs<T>&);
+};
// Machinery to pull out function types from class methods, lambdas, etc.
template <class R, class... Params>
@@ -181,29 +216,104 @@ static std::unique_ptr<detail::SignatureBase> makeSignature(Fn evaluateFunction,
return std::make_unique<detail::Signature<Fn>>(evaluateFunction, std::move(name));
}
+Value featureIdAsExpressionValue(EvaluationContext params) {
+ assert(params.feature);
+ auto id = params.feature->getID();
+ if (!id) return Null;
+ return id->match([](const auto& idid) {
+ return toExpressionValue(mbgl::Value(idid));
+ });
+};
+
+optional<Value> featurePropertyAsExpressionValue(EvaluationContext params, const std::string& key) {
+ assert(params.feature);
+ auto property = params.feature->getValue(key);
+ return property ? toExpressionValue(*property) : optional<Value>();
+};
+
+optional<std::string> featureTypeAsString(FeatureType type) {
+ switch(type) {
+ case FeatureType::Point:
+ return optional<std::string>("Point");
+ case FeatureType::LineString:
+ return optional<std::string>("LineString");
+ case FeatureType::Polygon:
+ return optional<std::string>("Polygon");
+ case FeatureType::Unknown:
+ return optional<std::string>("Unknown");
+ default:
+ return {};
+ }
+};
+
+optional<double> featurePropertyAsDouble(EvaluationContext params, const std::string& key) {
+ assert(params.feature);
+ auto property = params.feature->getValue(key);
+ if (!property) return {};
+ return property->match(
+ [](double value) { return value; },
+ [](uint64_t value) { return optional<double>(static_cast<double>(value)); },
+ [](int64_t value) { return optional<double>(static_cast<double>(value)); },
+ [](auto) { return optional<double>(); }
+ );
+};
+
+optional<std::string> featurePropertyAsString(EvaluationContext params, const std::string& key) {
+ assert(params.feature);
+ auto property = params.feature->getValue(key);
+ if (!property) return {};
+ return property->match(
+ [](std::string value) { return value; },
+ [](auto) { return optional<std::string>(); }
+ );
+};
+
+optional<double> featureIdAsDouble(EvaluationContext params) {
+ assert(params.feature);
+ auto id = params.feature->getID();
+ if (!id) return optional<double>();
+ return id->match(
+ [](double value) { return value; },
+ [](uint64_t value) { return optional<double>(static_cast<double>(value)); },
+ [](int64_t value) { return optional<double>(static_cast<double>(value)); },
+ [](auto) { return optional<double>(); }
+ );
+};
+
+optional<std::string> featureIdAsString(EvaluationContext params) {
+ assert(params.feature);
+ auto id = params.feature->getID();
+ if (!id) return optional<std::string>();
+ return id->match(
+ [](std::string value) { return value; },
+ [](auto) { return optional<std::string>(); }
+ );
+};
+
std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initializeDefinitions() {
std::unordered_map<std::string, CompoundExpressionRegistry::Definition> definitions;
auto define = [&](std::string name, auto fn) {
definitions[name].push_back(makeSignature(fn, name));
};
-
+
define("e", []() -> Result<double> { return 2.718281828459045; });
define("pi", []() -> Result<double> { return 3.141592653589793; });
define("ln2", []() -> Result<double> { return 0.6931471805599453; });
define("typeof", [](const Value& v) -> Result<std::string> { return toString(typeOf(v)); });
-
+
define("to-string", [](const Value& value) -> Result<std::string> {
return value.match(
+ [](const NullValue&) -> Result<std::string> { return std::string(); },
[](const Color& c) -> Result<std::string> { return c.stringify(); }, // avoid quoting
[](const std::string& s) -> Result<std::string> { return s; }, // avoid quoting
[](const auto& v) -> Result<std::string> { return stringify(v); }
);
});
-
+
define("to-boolean", [](const Value& v) -> Result<bool> {
return v.match(
- [&] (double f) { return (bool)f; },
+ [&] (double f) { return static_cast<bool>(f); },
[&] (const std::string& s) { return s.length() > 0; },
[&] (bool b) { return b; },
[&] (const NullValue&) { return false; },
@@ -213,10 +323,10 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali
define("to-rgba", [](const Color& color) -> Result<std::array<double, 4>> {
return color.toArray();
});
-
+
define("rgba", rgba);
define("rgb", [](double r, double g, double b) { return rgba(r, g, b, 1.0f); });
-
+
define("zoom", [](const EvaluationContext& params) -> Result<double> {
if (!params.zoom) {
return EvaluationError {
@@ -225,7 +335,7 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali
}
return *(params.zoom);
});
-
+
define("heatmap-density", [](const EvaluationContext& params) -> Result<double> {
if (!params.heatmapDensity) {
return EvaluationError {
@@ -241,7 +351,7 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali
"Feature data is unavailable in the current evaluation context."
};
}
-
+
return params.feature->getValue(key) ? true : false;
});
define("has", [](const std::string& key, const std::unordered_map<std::string, Value>& object) -> Result<bool> {
@@ -267,7 +377,7 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali
}
return object.at(key);
});
-
+
define("properties", [](const EvaluationContext& params) -> Result<std::unordered_map<std::string, Value>> {
if (!params.feature) {
return EvaluationError {
@@ -281,14 +391,14 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali
}
return result;
});
-
+
define("geometry-type", [](const EvaluationContext& params) -> Result<std::string> {
if (!params.feature) {
return EvaluationError {
"Feature data is unavailable in the current evaluation context."
};
}
-
+
auto type = params.feature->getType();
if (type == FeatureType::Point) {
return "Point";
@@ -300,14 +410,14 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali
return "Unknown";
}
});
-
+
define("id", [](const EvaluationContext& params) -> Result<Value> {
if (!params.feature) {
return EvaluationError {
"Feature data is unavailable in the current evaluation context."
};
}
-
+
auto id = params.feature->getID();
if (!id) {
return Null;
@@ -318,7 +428,7 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali
}
);
});
-
+
define("+", [](const Varargs<double>& args) -> Result<double> {
double sum = 0.0f;
for (auto arg : args) {
@@ -348,7 +458,7 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali
define("asin", [](double x) -> Result<double> { return asin(x); });
define("acos", [](double x) -> Result<double> { return acos(x); });
define("atan", [](double x) -> Result<double> { return atan(x); });
-
+
define("min", [](const Varargs<double>& args) -> Result<double> {
double result = std::numeric_limits<double>::infinity();
for (double arg : args) {
@@ -377,7 +487,7 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali
define("<", [](const std::string& lhs, const std::string& rhs) -> Result<bool> { return lhs < rhs; });
define("<=", [](double lhs, double rhs) -> Result<bool> { return lhs <= rhs; });
define("<=", [](const std::string& lhs, const std::string& rhs) -> Result<bool> { return lhs <= rhs; });
-
+
define("!", [](bool e) -> Result<bool> { return !e; });
define("is-supported-script", [](const std::string& x) -> Result<bool> {
@@ -400,7 +510,130 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali
define("error", [](const std::string& input) -> Result<type::ErrorType> {
return EvaluationError { input };
});
+
+ // Legacy Filters
+ define("filter-==", [](const EvaluationContext& params, const std::string& key, const Value &lhs) -> Result<bool> {
+ const auto rhs = featurePropertyAsExpressionValue(params, key);
+ return rhs ? lhs == *rhs : false;
+ });
+
+ define("filter-id-==", [](const EvaluationContext& params, const Value &lhs) -> Result<bool> {
+ return lhs == featureIdAsExpressionValue(params);
+ });
+
+ define("filter-type-==", [](const EvaluationContext& params, const std::string &lhs) -> Result<bool> {
+ if (!params.feature) return false;
+ return featureTypeAsString(params.feature->getType()) == lhs;
+ });
+
+ define("filter-<", [](const EvaluationContext& params, const std::string& key, double lhs) -> Result<bool> {
+ auto rhs = featurePropertyAsDouble(params, key);
+ return rhs ? rhs < lhs : false;
+ });
+
+ define("filter-<", [](const EvaluationContext& params, const std::string& key, std::string lhs) -> Result<bool> {
+ auto rhs = featurePropertyAsString(params, key);
+ return rhs ? rhs < lhs : false;
+ });
+
+ define("filter-id-<", [](const EvaluationContext& params, double lhs) -> Result<bool> {
+ auto rhs = featureIdAsDouble(params);
+ return rhs ? rhs < lhs : false;
+ });
+
+ define("filter-id-<", [](const EvaluationContext& params, std::string lhs) -> Result<bool> {
+ auto rhs = featureIdAsString(params);
+ return rhs ? rhs < lhs : false;
+ });
+
+ define("filter->", [](const EvaluationContext& params, const std::string& key, double lhs) -> Result<bool> {
+ auto rhs = featurePropertyAsDouble(params, key);
+ return rhs ? rhs > lhs : false;
+ });
+
+ define("filter->", [](const EvaluationContext& params, const std::string& key, std::string lhs) -> Result<bool> {
+ auto rhs = featurePropertyAsString(params, key);
+ return rhs ? rhs > lhs : false;
+ });
+
+ define("filter-id->", [](const EvaluationContext& params, double lhs) -> Result<bool> {
+ auto rhs = featureIdAsDouble(params);
+ return rhs ? rhs > lhs : false;
+ });
+
+ define("filter-id->", [](const EvaluationContext& params, std::string lhs) -> Result<bool> {
+ auto rhs = featureIdAsString(params);
+ return rhs ? rhs > lhs : false;
+ });
+
+ define("filter-<=", [](const EvaluationContext& params, const std::string& key, double lhs) -> Result<bool> {
+ auto rhs = featurePropertyAsDouble(params, key);
+ return rhs ? rhs <= lhs : false;
+ });
+
+ define("filter-<=", [](const EvaluationContext& params, const std::string& key, std::string lhs) -> Result<bool> {
+ auto rhs = featurePropertyAsString(params, key);
+ return rhs ? rhs <= lhs : false;
+ });
+
+ define("filter-id-<=", [](const EvaluationContext& params, double lhs) -> Result<bool> {
+ auto rhs = featureIdAsDouble(params);
+ return rhs ? rhs <= lhs : false;
+ });
+ define("filter-id-<=", [](const EvaluationContext& params, std::string lhs) -> Result<bool> {
+ auto rhs = featureIdAsString(params);
+ return rhs ? rhs <= lhs : false;
+ });
+
+ define("filter->=", [](const EvaluationContext& params, const std::string& key, double lhs) -> Result<bool> {
+ auto rhs = featurePropertyAsDouble(params, key);
+ return rhs ? rhs >= lhs : false;
+ });
+
+ define("filter->=", [](const EvaluationContext& params, const std::string& key, std::string lhs) -> Result<bool> {
+ auto rhs = featurePropertyAsString(params, key);
+ return rhs ? rhs >= lhs : false;
+ });
+
+ define("filter-id->=", [](const EvaluationContext& params, double lhs) -> Result<bool> {
+ auto rhs = featureIdAsDouble(params);
+ return rhs ? rhs >= lhs : false;
+ });
+
+ define("filter-id->=", [](const EvaluationContext& params, std::string lhs) -> Result<bool> {
+ auto rhs = featureIdAsString(params);
+ return rhs ? rhs >= lhs : false;
+ });
+
+ define("filter-has", [](const EvaluationContext& params, const std::string& key) -> Result<bool> {
+ assert(params.feature);
+ return bool(params.feature->getValue(key));
+ });
+
+ define("filter-has-id", [](const EvaluationContext& params) -> Result<bool> {
+ assert(params.feature);
+ return bool(params.feature->getID());
+ });
+
+ define("filter-type-in", [](const EvaluationContext& params, const Varargs<std::string>& types) -> Result<bool> {
+ assert(params.feature);
+ optional<std::string> type = featureTypeAsString(params.feature->getType());
+ return std::find(types.begin(), types.end(), type) != types.end();
+ });
+
+ define("filter-id-in", [](const EvaluationContext& params, const Varargs<Value>& ids) -> Result<bool> {
+ auto id = featureIdAsExpressionValue(params);
+ return std::find(ids.begin(), ids.end(), id) != ids.end();
+ });
+
+ define("filter-in", [](const EvaluationContext& params, const Varargs<Value>& varargs) -> Result<bool> {
+ if (varargs.size() < 2) return false;
+ assert(varargs[0].is<std::string>());
+ auto value = featurePropertyAsExpressionValue(params, varargs[0].get<std::string>());
+ return value ? std::find(varargs.begin() + 1, varargs.end(), *value) != varargs.end() : false;
+ });
+
return definitions;
}
@@ -419,7 +652,7 @@ ParseResult parseCompoundExpression(const std::string name, const Convertible& v
return ParseResult();
}
const CompoundExpressionRegistry::Definition& definition = it->second;
-
+
auto length = arrayLength(value);
// Check if we have a single signature with the correct number of
@@ -445,14 +678,14 @@ ParseResult parseCompoundExpression(const std::string name, const Convertible& v
args.reserve(length - 1);
for (std::size_t i = 1; i < length; i++) {
optional<type::Type> expected;
-
+
if (singleMatchingSignature) {
expected = definition[*singleMatchingSignature]->params.match(
[](const VarargsType& varargs) { return varargs.type; },
[&](const std::vector<type::Type>& params_) { return params_[i - 1]; }
);
}
-
+
auto parsed = ctx.parse(arrayMember(value, i), i, expected);
if (!parsed) {
return parsed;
@@ -479,7 +712,7 @@ ParseResult createCompoundExpression(const Definition& definition,
for (const std::unique_ptr<detail::SignatureBase>& signature : definition) {
signatureContext.clearErrors();
-
+
if (signature->params.is<std::vector<type::Type>>()) {
const std::vector<type::Type>& params = signature->params.get<std::vector<type::Type>>();
if (params.size() != args.size()) {
@@ -507,12 +740,12 @@ ParseResult createCompoundExpression(const Definition& definition,
}
}
}
-
+
if (signatureContext.getErrors().size() == 0) {
return ParseResult(signature->makeExpression(std::move(args)));
}
}
-
+
if (definition.size() == 1) {
ctx.appendErrors(std::move(signatureContext));
} else {
@@ -545,10 +778,32 @@ ParseResult createCompoundExpression(const Definition& definition,
}
ctx.error("Expected arguments of type " + signatures + ", but found (" + actualTypes + ") instead.");
}
-
+
return ParseResult();
}
+ParseResult createCompoundExpression(const std::string& name, ParsingContext& ctx) {
+ return createCompoundExpression(name, std::vector<std::unique_ptr<Expression>>(), ctx);
+}
+
+ParseResult createCompoundExpression(const std::string& name,
+ std::unique_ptr<Expression> arg1,
+ ParsingContext& ctx) {
+ std::vector<std::unique_ptr<Expression>> args;
+ args.push_back(std::move(arg1));
+ return createCompoundExpression(name, std::move(args), ctx);
+}
+
+ParseResult createCompoundExpression(const std::string& name,
+ std::unique_ptr<Expression> arg1,
+ std::unique_ptr<Expression> arg2,
+ ParsingContext& ctx) {
+ std::vector<std::unique_ptr<Expression>> args;
+ args.push_back(std::move(arg1));
+ args.push_back(std::move(arg2));
+ return createCompoundExpression(name, std::move(args), ctx);
+}
+
} // namespace expression
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/expression/literal.cpp b/src/mbgl/style/expression/literal.cpp
index 8a63980dba..f68cfd5cf5 100644
--- a/src/mbgl/style/expression/literal.cpp
+++ b/src/mbgl/style/expression/literal.cpp
@@ -109,6 +109,14 @@ mbgl::Value Literal::serialize() const {
return *fromExpressionValue<mbgl::Value>(value);
}
}
+
+std::unique_ptr<Literal> createLiteral(const char* value) {
+ return createLiteral(std::string(value));
+}
+
+std::unique_ptr<Literal> createLiteral(Value value) {
+ return std::make_unique<Literal>(value);
+}
} // namespace expression
} // namespace style
diff --git a/src/mbgl/style/filter.cpp b/src/mbgl/style/filter.cpp
index 51aa6bcf82..2559eb4816 100644
--- a/src/mbgl/style/filter.cpp
+++ b/src/mbgl/style/filter.cpp
@@ -1,12 +1,20 @@
#include <mbgl/style/filter.hpp>
-#include <mbgl/style/filter_evaluator.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
namespace mbgl {
namespace style {
bool Filter::operator()(const expression::EvaluationContext &context) const {
- return FilterBase::visit(*this, FilterEvaluator { context });
+
+ if (!this->expression) return true;
+
+ const expression::EvaluationResult result = (*this->expression)->evaluate(context);
+ if (result) {
+ const optional<bool> typed = expression::fromExpressionValue<bool>(*result);
+ return typed ? *typed : false;
+ } else {
+ return true;
+ }
}
} // namespace style
diff --git a/src/mbgl/style/filter_evaluator.cpp b/src/mbgl/style/filter_evaluator.cpp
deleted file mode 100644
index 72022172f4..0000000000
--- a/src/mbgl/style/filter_evaluator.cpp
+++ /dev/null
@@ -1,225 +0,0 @@
-#include <mbgl/style/filter.hpp>
-#include <mbgl/style/filter_evaluator.hpp>
-#include <mbgl/tile/geometry_tile_data.hpp>
-
-namespace mbgl {
-namespace style {
-
-template <class Op>
-struct Comparator {
- const Op& op;
-
- template <class T>
- bool operator()(const T& lhs, const T& rhs) const {
- return op(lhs, rhs);
- }
-
- template <class T0, class T1>
- auto operator()(const T0& lhs, const T1& rhs) const
- -> typename std::enable_if_t<std::is_arithmetic<T0>::value && !std::is_same<T0, bool>::value &&
- std::is_arithmetic<T1>::value && !std::is_same<T1, bool>::value, bool> {
- return op(double(lhs), double(rhs));
- }
-
- template <class T0, class T1>
- auto operator()(const T0&, const T1&) const
- -> typename std::enable_if_t<!std::is_arithmetic<T0>::value || std::is_same<T0, bool>::value ||
- !std::is_arithmetic<T1>::value || std::is_same<T1, bool>::value, bool> {
- return false;
- }
-
- bool operator()(const NullValue&,
- const NullValue&) const {
- // Should be unreachable; null is not currently allowed by the style specification.
- assert(false);
- return false;
- }
-
- bool operator()(const std::vector<Value>&,
- const std::vector<Value>&) const {
- // Should be unreachable; nested values are not currently allowed by the style specification.
- assert(false);
- return false;
- }
-
- bool operator()(const PropertyMap&,
- const PropertyMap&) const {
- // Should be unreachable; nested values are not currently allowed by the style specification.
- assert(false);
- return false;
- }
-};
-
-template <class Op>
-bool compare(const Value& lhs, const Value& rhs, const Op& op) {
- return Value::binary_visit(lhs, rhs, Comparator<Op> { op });
-}
-
-bool equal(const Value& lhs, const Value& rhs) {
- return compare(lhs, rhs, [] (const auto& lhs_, const auto& rhs_) { return lhs_ == rhs_; });
-}
-
-bool FilterEvaluator::operator()(const NullFilter&) const {
- return true;
-}
-
-bool FilterEvaluator::operator()(const EqualsFilter& filter) const {
- optional<Value> actual = context.feature->getValue(filter.key);
- return actual && equal(*actual, filter.value);
-}
-
-bool FilterEvaluator::operator()(const NotEqualsFilter& filter) const {
- optional<Value> actual = context.feature->getValue(filter.key);
- return !actual || !equal(*actual, filter.value);
-}
-
-bool FilterEvaluator::operator()(const LessThanFilter& filter) const {
- optional<Value> actual = context.feature->getValue(filter.key);
- return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ < rhs_; });
-}
-
-bool FilterEvaluator::operator()(const LessThanEqualsFilter& filter) const {
- optional<Value> actual = context.feature->getValue(filter.key);
- return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ <= rhs_; });
-}
-
-bool FilterEvaluator::operator()(const GreaterThanFilter& filter) const {
- optional<Value> actual = context.feature->getValue(filter.key);
- return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ > rhs_; });
-}
-
-bool FilterEvaluator::operator()(const GreaterThanEqualsFilter& filter) const {
- optional<Value> actual = context.feature->getValue(filter.key);
- return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ >= rhs_; });
-}
-
-bool FilterEvaluator::operator()(const InFilter& filter) const {
- optional<Value> actual = context.feature->getValue(filter.key);
- if (!actual)
- return false;
- for (const auto& v: filter.values) {
- if (equal(*actual, v)) {
- return true;
- }
- }
- return false;
-}
-
-bool FilterEvaluator::operator()(const NotInFilter& filter) const {
- optional<Value> actual = context.feature->getValue(filter.key);
- if (!actual)
- return true;
- for (const auto& v: filter.values) {
- if (equal(*actual, v)) {
- return false;
- }
- }
- return true;
-}
-
-bool FilterEvaluator::operator()(const AnyFilter& filter) const {
- for (const auto& f: filter.filters) {
- if (Filter::visit(f, *this)) {
- return true;
- }
- }
- return false;
-}
-
-bool FilterEvaluator::operator()(const AllFilter& filter) const {
- for (const auto& f: filter.filters) {
- if (!Filter::visit(f, *this)) {
- return false;
- }
- }
- return true;
-}
-
-bool FilterEvaluator::operator()(const NoneFilter& filter) const {
- for (const auto& f: filter.filters) {
- if (Filter::visit(f, *this)) {
- return false;
- }
- }
- return true;
-}
-
-bool FilterEvaluator::operator()(const HasFilter& filter) const {
- return bool(context.feature->getValue(filter.key));
-}
-
-bool FilterEvaluator::operator()(const NotHasFilter& filter) const {
- return !context.feature->getValue(filter.key);
-}
-
-bool FilterEvaluator::operator()(const TypeEqualsFilter& filter) const {
- return context.feature->getType() == filter.value;
-}
-
-bool FilterEvaluator::operator()(const TypeNotEqualsFilter& filter) const {
- return context.feature->getType() != filter.value;
-}
-
-bool FilterEvaluator::operator()(const TypeInFilter& filter) const {
- for (const auto& v: filter.values) {
- if (context.feature->getType() == v) {
- return true;
- }
- }
- return false;
-}
-
-bool FilterEvaluator::operator()(const TypeNotInFilter& filter) const {
- for (const auto& v: filter.values) {
- if (context.feature->getType() == v) {
- return false;
- }
- }
- return true;
-}
-
-bool FilterEvaluator::operator()(const IdentifierEqualsFilter& filter) const {
- return context.feature->getID() == filter.value;
-}
-
-bool FilterEvaluator::operator()(const IdentifierNotEqualsFilter& filter) const {
- return context.feature->getID() != filter.value;
-}
-
-bool FilterEvaluator::operator()(const IdentifierInFilter& filter) const {
- for (const auto& v: filter.values) {
- if (context.feature->getID() == v) {
- return true;
- }
- }
- return false;
-}
-
-bool FilterEvaluator::operator()(const IdentifierNotInFilter& filter) const {
- for (const auto& v: filter.values) {
- if (context.feature->getID() == v) {
- return false;
- }
- }
- return true;
-}
-
-bool FilterEvaluator::operator()(const HasIdentifierFilter&) const {
- return bool(context.feature->getID());
-}
-
-bool FilterEvaluator::operator()(const NotHasIdentifierFilter&) const {
- return !context.feature->getID();
-}
-
-bool FilterEvaluator::operator()(const ExpressionFilter& filter) const {
- const expression::EvaluationResult result = filter.expression->evaluate(context);
- if (result) {
- const optional<bool> typed = expression::fromExpressionValue<bool>(*result);
- return typed ? *typed : false;
- }
- return false;
-}
-
-} // namespace style
-} // namespace mbgl
diff --git a/src/mbgl/tile/custom_geometry_tile.cpp b/src/mbgl/tile/custom_geometry_tile.cpp
index a2fefcfa9f..272a1594d4 100644
--- a/src/mbgl/tile/custom_geometry_tile.cpp
+++ b/src/mbgl/tile/custom_geometry_tile.cpp
@@ -3,7 +3,6 @@
#include <mbgl/renderer/query.hpp>
#include <mbgl/renderer/tile_parameters.hpp>
#include <mbgl/actor/scheduler.hpp>
-#include <mbgl/style/filter_evaluator.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/tile/tile_observer.hpp>
#include <mbgl/style/custom_tile_loader.hpp>
diff --git a/src/mbgl/tile/geojson_tile.cpp b/src/mbgl/tile/geojson_tile.cpp
index f211c03569..7a83da2267 100644
--- a/src/mbgl/tile/geojson_tile.cpp
+++ b/src/mbgl/tile/geojson_tile.cpp
@@ -2,7 +2,6 @@
#include <mbgl/tile/geojson_tile_data.hpp>
#include <mbgl/renderer/query.hpp>
#include <mbgl/renderer/tile_parameters.hpp>
-#include <mbgl/style/filter_evaluator.hpp>
namespace mbgl {
diff --git a/src/mbgl/tile/geometry_tile.cpp b/src/mbgl/tile/geometry_tile.cpp
index 8efe12d54f..af28fe3963 100644
--- a/src/mbgl/tile/geometry_tile.cpp
+++ b/src/mbgl/tile/geometry_tile.cpp
@@ -16,7 +16,6 @@
#include <mbgl/storage/file_source.hpp>
#include <mbgl/geometry/feature_index.hpp>
#include <mbgl/map/transform_state.hpp>
-#include <mbgl/style/filter_evaluator.hpp>
#include <mbgl/util/logging.hpp>
#include <mbgl/actor/scheduler.hpp>
diff --git a/src/mbgl/tile/geometry_tile_worker.cpp b/src/mbgl/tile/geometry_tile_worker.cpp
index 2e7d588d9b..ca20c4b8ab 100644
--- a/src/mbgl/tile/geometry_tile_worker.cpp
+++ b/src/mbgl/tile/geometry_tile_worker.cpp
@@ -5,7 +5,6 @@
#include <mbgl/renderer/bucket_parameters.hpp>
#include <mbgl/renderer/group_by_layout.hpp>
#include <mbgl/style/filter.hpp>
-#include <mbgl/style/filter_evaluator.hpp>
#include <mbgl/style/layers/symbol_layer_impl.hpp>
#include <mbgl/renderer/layers/render_symbol_layer.hpp>
#include <mbgl/renderer/buckets/symbol_bucket.hpp>