diff options
author | Anand Thakker <anandthakker@users.noreply.github.com> | 2017-04-06 15:29:59 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-04-06 15:29:59 -0400 |
commit | 693c9f3641b3189b4cd439049904c95a516ae609 (patch) | |
tree | 8341a16f57ff184a2fe9e085c490e8762eb206ce /src/mbgl/programs | |
parent | f9cc044357d60dd5cf15ba951384529f88802089 (diff) | |
download | qtlocation-mapboxgl-693c9f3641b3189b4cd439049904c95a516ae609.tar.gz |
[core] Add DDS support for {text,icon}-size (#8593)
* Update gl-js and generate style code
* Factor out packUint8Pair() helper function
* Draft implementation of DDS for {text,icon}-size
Ports https://github.com/mapbox/mapbox-gl-js/pull/4455
* Fix text-size/composite-function-line-placement test
* Refactor to PaintPropertyBinders-like strategy
* Dedupe gl::Program construction
* Use exponential function base for interpolation
* Dedupe coveringZoomStops method
* Fixup tests
* Fix CI errors (hidden within #if block)
Diffstat (limited to 'src/mbgl/programs')
-rw-r--r-- | src/mbgl/programs/attributes.hpp | 19 | ||||
-rw-r--r-- | src/mbgl/programs/collision_box_program.hpp | 2 | ||||
-rw-r--r-- | src/mbgl/programs/line_program.hpp | 2 | ||||
-rw-r--r-- | src/mbgl/programs/program.hpp | 55 | ||||
-rw-r--r-- | src/mbgl/programs/symbol_program.cpp | 60 | ||||
-rw-r--r-- | src/mbgl/programs/symbol_program.hpp | 356 |
6 files changed, 400 insertions, 94 deletions
diff --git a/src/mbgl/programs/attributes.hpp b/src/mbgl/programs/attributes.hpp index 7d39c04395..e9ca18927e 100644 --- a/src/mbgl/programs/attributes.hpp +++ b/src/mbgl/programs/attributes.hpp @@ -8,6 +8,16 @@ namespace mbgl { namespace attributes { +/* + * Pack a pair of values, interpreted as uint8's, into a single float. + * Used to conserve vertex attributes. Values are unpacked in the vertex + * shader using the `unpack_float()` function, defined in _prelude.vertex.glsl. + */ +template <typename T> +inline uint16_t packUint8Pair(T a, T b) { + return static_cast<uint16_t>(a) * 256 + static_cast<uint16_t>(b); +} + // Layout attributes MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_pos); @@ -15,10 +25,15 @@ MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_extrude); MBGL_DEFINE_ATTRIBUTE(int16_t, 4, a_pos_offset); MBGL_DEFINE_ATTRIBUTE(uint16_t, 2, a_texture_pos); -template <std::size_t N> +template <typename T, std::size_t N> struct a_data { static auto name() { return "a_data"; } - using Type = gl::Attribute<uint8_t, N>; + using Type = gl::Attribute<T, N>; +}; + +struct a_size { + static auto name() { return "a_size"; } + using Type = gl::Attribute<uint16_t, 3>; }; template <std::size_t N> diff --git a/src/mbgl/programs/collision_box_program.hpp b/src/mbgl/programs/collision_box_program.hpp index 78ed6aa0c9..89b69484fd 100644 --- a/src/mbgl/programs/collision_box_program.hpp +++ b/src/mbgl/programs/collision_box_program.hpp @@ -18,7 +18,7 @@ MBGL_DEFINE_UNIFORM_SCALAR(float, u_maxzoom); using CollisionBoxAttributes = gl::Attributes< attributes::a_pos, attributes::a_extrude, - attributes::a_data<2>>; + attributes::a_data<uint8_t, 2>>; class CollisionBoxProgram : public Program< shaders::collision_box, diff --git a/src/mbgl/programs/line_program.hpp b/src/mbgl/programs/line_program.hpp index 842b4cc602..b2e55a4f3b 100644 --- a/src/mbgl/programs/line_program.hpp +++ b/src/mbgl/programs/line_program.hpp @@ -32,7 +32,7 @@ MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_gl_units_to_pixels); struct LineLayoutAttributes : gl::Attributes< attributes::a_pos, - attributes::a_data<4>> + attributes::a_data<uint8_t, 4>> {}; class LineProgram : public Program< diff --git a/src/mbgl/programs/program.hpp b/src/mbgl/programs/program.hpp index 8925bc75d6..7eec15e755 100644 --- a/src/mbgl/programs/program.hpp +++ b/src/mbgl/programs/program.hpp @@ -34,55 +34,12 @@ public: ProgramType program; Program(gl::Context& context, const ProgramParameters& programParameters) - : program([&] { -#if MBGL_HAS_BINARY_PROGRAMS - if (!programParameters.cacheDir.empty() && context.supportsProgramBinaries()) { - const std::string vertexSource = - shaders::vertexSource(programParameters, Shaders::vertexSource); - const std::string fragmentSource = - shaders::fragmentSource(programParameters, Shaders::fragmentSource); - const std::string cachePath = - shaders::programCachePath(programParameters, Shaders::name); - const std::string identifier = - shaders::programIdentifier(vertexSource, fragmentSource); - - try { - if (auto cachedBinaryProgram = util::readFile(cachePath)) { - const BinaryProgram binaryProgram(std::move(*cachedBinaryProgram)); - if (binaryProgram.identifier() == identifier) { - return ProgramType{ context, binaryProgram }; - } else { - Log::Warning(Event::OpenGL, - "Cached program %s changed. Recompilation required.", - Shaders::name); - } - } - } catch (std::runtime_error& error) { - Log::Warning(Event::OpenGL, "Could not load cached program: %s", - error.what()); - } - - // Compile the shader - ProgramType result{ context, vertexSource, fragmentSource }; - - try { - if (const auto binaryProgram = - result.template get<BinaryProgram>(context, identifier)) { - util::write_file(cachePath, binaryProgram->serialize()); - Log::Warning(Event::OpenGL, "Caching program in: %s", cachePath.c_str()); - } - } catch (std::runtime_error& error) { - Log::Warning(Event::OpenGL, "Failed to cache program: %s", error.what()); - } - - return std::move(result); - } -#endif - return ProgramType{ - context, shaders::vertexSource(programParameters, Shaders::vertexSource), - shaders::fragmentSource(programParameters, Shaders::fragmentSource) - }; - }()) { + : program(ProgramType::createProgram( + context, + programParameters, + Shaders::name, + Shaders::vertexSource, + Shaders::fragmentSource)) { } template <class DrawMode> diff --git a/src/mbgl/programs/symbol_program.cpp b/src/mbgl/programs/symbol_program.cpp index 19fe2bc2f6..86f61c4ad2 100644 --- a/src/mbgl/programs/symbol_program.cpp +++ b/src/mbgl/programs/symbol_program.cpp @@ -3,6 +3,7 @@ #include <mbgl/map/transform_state.hpp> #include <mbgl/style/layers/symbol_layer_impl.hpp> #include <mbgl/util/enum.hpp> +#include <mbgl/math/clamp.hpp> namespace mbgl { @@ -10,51 +11,66 @@ using namespace style; static_assert(sizeof(SymbolLayoutVertex) == 16, "expected SymbolLayoutVertex size"); +std::unique_ptr<SymbolSizeBinder> SymbolSizeBinder::create(const float tileZoom, + const style::DataDrivenPropertyValue<float>& sizeProperty, + const float defaultValue) { + return sizeProperty.match( + [&] (const style::CompositeFunction<float>& function) -> std::unique_ptr<SymbolSizeBinder> { + return std::make_unique<CompositeFunctionSymbolSizeBinder>(tileZoom, function, defaultValue); + }, + [&] (const style::SourceFunction<float>& function) { + return std::make_unique<SourceFunctionSymbolSizeBinder>(tileZoom, function, defaultValue); + }, + [&] (const auto& value) -> std::unique_ptr<SymbolSizeBinder> { + return std::make_unique<ConstantSymbolSizeBinder>(tileZoom, value, defaultValue); + } + ); +} + template <class Values, class...Args> -Values makeValues(const style::SymbolPropertyValues& values, +Values makeValues(const bool isText, + const style::SymbolPropertyValues& values, const Size& texsize, const std::array<float, 2>& pixelsToGLUnits, const RenderTile& tile, const TransformState& state, Args&&... args) { std::array<float, 2> extrudeScale; - - const float scale = values.paintSize / values.sdfScale; if (values.pitchAlignment == AlignmentType::Map) { - extrudeScale.fill(tile.id.pixelsToTileUnits(1, state.getZoom()) * scale); + extrudeScale.fill(tile.id.pixelsToTileUnits(1, state.getZoom())); } else { extrudeScale = {{ - pixelsToGLUnits[0] * scale * state.getCameraToCenterDistance(), - pixelsToGLUnits[1] * scale * state.getCameraToCenterDistance() + pixelsToGLUnits[0] * state.getCameraToCenterDistance(), + pixelsToGLUnits[1] * state.getCameraToCenterDistance() }}; } - - // adjust min/max zooms for variable font sies - float zoomAdjust = std::log(values.paintSize / values.layoutSize) / std::log(2); - + return Values { uniforms::u_matrix::Value{ tile.translatedMatrix(values.translate, values.translateAnchor, state) }, uniforms::u_extrude_scale::Value{ extrudeScale }, uniforms::u_texsize::Value{ std::array<float, 2> {{ float(texsize.width) / 4, float(texsize.height) / 4 }} }, - uniforms::u_zoom::Value{ float((state.getZoom() - zoomAdjust) * 10) }, + uniforms::u_zoom::Value{ float(state.getZoom()) }, uniforms::u_rotate_with_map::Value{ values.rotationAlignment == AlignmentType::Map }, uniforms::u_texture::Value{ 0 }, uniforms::u_fadetexture::Value{ 1 }, + uniforms::u_is_text::Value{ isText }, std::forward<Args>(args)... }; } SymbolIconProgram::UniformValues -SymbolIconProgram::uniformValues(const style::SymbolPropertyValues& values, +SymbolIconProgram::uniformValues(const bool isText, + const style::SymbolPropertyValues& values, const Size& texsize, const std::array<float, 2>& pixelsToGLUnits, const RenderTile& tile, const TransformState& state) { return makeValues<SymbolIconProgram::UniformValues>( + isText, values, texsize, pixelsToGLUnits, @@ -64,26 +80,26 @@ SymbolIconProgram::uniformValues(const style::SymbolPropertyValues& values, } template <class PaintProperties> -typename SymbolSDFProgram<PaintProperties>::UniformValues SymbolSDFProgram<PaintProperties>::uniformValues(const style::SymbolPropertyValues& values, - const Size& texsize, - const std::array<float, 2>& pixelsToGLUnits, - const RenderTile& tile, - const TransformState& state, - const SymbolSDFPart part) +typename SymbolSDFProgram<PaintProperties>::UniformValues SymbolSDFProgram<PaintProperties>::uniformValues( + const bool isText, + const style::SymbolPropertyValues& values, + const Size& texsize, + const std::array<float, 2>& pixelsToGLUnits, + const RenderTile& tile, + const TransformState& state, + const SymbolSDFPart part) { - const float scale = values.paintSize / values.sdfScale; - - const float gammaScale = scale * (values.pitchAlignment == AlignmentType::Map + const float gammaScale = (values.pitchAlignment == AlignmentType::Map ? std::cos(state.getPitch()) : 1.0) * state.getCameraToCenterDistance(); return makeValues<SymbolSDFProgram<PaintProperties>::UniformValues>( + isText, values, texsize, pixelsToGLUnits, tile, state, - uniforms::u_font_scale::Value{ scale }, uniforms::u_gamma_scale::Value{ gammaScale }, uniforms::u_pitch::Value{ state.getPitch() }, uniforms::u_bearing::Value{ -1.0f * state.getAngle() }, diff --git a/src/mbgl/programs/symbol_program.hpp b/src/mbgl/programs/symbol_program.hpp index fdd1aa5c3b..ae50e790be 100644 --- a/src/mbgl/programs/symbol_program.hpp +++ b/src/mbgl/programs/symbol_program.hpp @@ -1,6 +1,10 @@ #pragma once -#include <mbgl/programs/program.hpp> +#include <mbgl/gl/context.hpp> +#include <mbgl/gl/program.hpp> +#include <mbgl/math/clamp.hpp> +#include <mbgl/util/interpolate.hpp> + #include <mbgl/programs/attributes.hpp> #include <mbgl/programs/uniforms.hpp> #include <mbgl/shaders/symbol_icon.hpp> @@ -10,6 +14,7 @@ #include <mbgl/style/layers/symbol_layer_properties.hpp> #include <mbgl/style/layers/symbol_layer_impl.hpp> + #include <cmath> #include <array> @@ -30,14 +35,19 @@ MBGL_DEFINE_UNIFORM_SCALAR(gl::TextureUnit, u_texture); MBGL_DEFINE_UNIFORM_SCALAR(gl::TextureUnit, u_fadetexture); MBGL_DEFINE_UNIFORM_SCALAR(float, u_aspect_ratio); MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_halo); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_font_scale); MBGL_DEFINE_UNIFORM_SCALAR(float, u_gamma_scale); + +MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_text); +MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_size_zoom_constant); +MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_size_feature_constant); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_size_t); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_size); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_layout_size); } // namespace uniforms struct SymbolLayoutAttributes : gl::Attributes< attributes::a_pos_offset, - attributes::a_texture_pos, - attributes::a_data<4>> + attributes::a_data<uint16_t, 4>> { static Vertex vertex(Point<float> a, Point<float> o, @@ -57,19 +67,324 @@ struct SymbolLayoutAttributes : gl::Attributes< }}, {{ static_cast<uint16_t>(tx / 4), - static_cast<uint16_t>(ty / 4) - }}, + static_cast<uint16_t>(ty / 4), + mbgl::attributes::packUint8Pair( + static_cast<uint8_t>(labelminzoom * 10), // 1/10 zoom levels: z16 == 160 + static_cast<uint8_t>(labelangle) + ), + mbgl::attributes::packUint8Pair( + static_cast<uint8_t>(minzoom * 10), + static_cast<uint8_t>(::fmin(maxzoom, 25) * 10) + ) + }} + }; + } +}; + +class SymbolSizeAttributes : public gl::Attributes<attributes::a_size> { +public: + using Attribute = attributes::a_size::Type; +}; + +// Mimic the PaintPropertyBinder technique specifically for the {text,icon}-size layout properties +// in order to provide a 'custom' scheme for encoding the necessary attribute data. As with +// PaintPropertyBinder, SymbolSizeBinder is an abstract class whose implementations handle the +// particular attribute & uniform logic needed by each possible type of the {Text,Icon}Size properties. +class SymbolSizeBinder { +public: + using Uniforms = gl::Uniforms< + uniforms::u_is_size_zoom_constant, + uniforms::u_is_size_feature_constant, + uniforms::u_size_t, + uniforms::u_size, + uniforms::u_layout_size>; + using UniformValues = Uniforms::Values; + + static std::unique_ptr<SymbolSizeBinder> create(const float tileZoom, + const style::DataDrivenPropertyValue<float>& sizeProperty, + const float defaultValue); + + virtual SymbolSizeAttributes::Bindings attributeBindings(const style::PossiblyEvaluatedPropertyValue<float> currentValue) const = 0; + virtual void populateVertexVector(const GeometryTileFeature& feature) = 0; + virtual UniformValues uniformValues(float currentZoom) const = 0; + virtual void upload(gl::Context&) = 0; +}; + +// Return the smallest range of stops that covers the interval [lowerZoom, upperZoom] +template <class Stops> +Range<float> getCoveringStops(Stops s, float lowerZoom, float upperZoom) { + assert(!s.stops.empty()); + auto minIt = s.stops.lower_bound(lowerZoom); + auto maxIt = s.stops.lower_bound(upperZoom); + + // lower_bound yields first element >= lowerZoom, but we want the *last* + // element <= lowerZoom, so if we found a stop > lowerZoom, back up by one. + if (minIt != s.stops.begin() && minIt->first > lowerZoom) { + minIt--; + } + return Range<float> { + minIt == s.stops.end() ? s.stops.rbegin()->first : minIt->first, + maxIt == s.stops.end() ? s.stops.rbegin()->first : maxIt->first + }; +} + +class ConstantSymbolSizeBinder : public SymbolSizeBinder { +public: + using PropertyValue = variant<float, style::CameraFunction<float>>; + + ConstantSymbolSizeBinder(const float /*tileZoom*/, const float& size, const float /*defaultValue*/) + : layoutSize(size) {} + + ConstantSymbolSizeBinder(const float /*tileZoom*/, const style::Undefined&, const float defaultValue) + : layoutSize(defaultValue) {} + + ConstantSymbolSizeBinder(const float tileZoom, const style::CameraFunction<float>& function_, const float /*defaultValue*/) + : layoutSize(function_.evaluate(tileZoom + 1)) { + function_.stops.match( + [&] (const style::ExponentialStops<float>& stops) { + coveringRanges = std::make_tuple( + getCoveringStops(stops, tileZoom, tileZoom + 1), + Range<float> { function_.evaluate(tileZoom), function_.evaluate(tileZoom + 1) } + ); + functionInterpolationBase = stops.base; + }, + [&] (const style::IntervalStops<float>&) { + function = function_; + } + ); + } + + SymbolSizeAttributes::Bindings attributeBindings(const style::PossiblyEvaluatedPropertyValue<float>) const override { + return SymbolSizeAttributes::Bindings { SymbolSizeAttributes::Attribute::ConstantBinding {{{0, 0, 0}}} }; + } + void upload(gl::Context&) override {} + void populateVertexVector(const GeometryTileFeature&) override {}; + + UniformValues uniformValues(float currentZoom) const override { + float size = layoutSize; + bool isZoomConstant = !(coveringRanges || function); + if (coveringRanges) { + // Even though we could get the exact value of the camera function + // at z = currentZoom, we intentionally do not: instead, we interpolate + // between the camera function values at a pair of zoom stops covering + // [tileZoom, tileZoom + 1] in order to be consistent with this + // restriction on composite functions. + const Range<float>& zoomLevels = std::get<0>(*coveringRanges); + const Range<float>& sizeLevels = std::get<1>(*coveringRanges); + float t = util::clamp( + util::interpolationFactor(*functionInterpolationBase, zoomLevels, currentZoom), + 0.0f, 1.0f + ); + size = sizeLevels.min + t * (sizeLevels.max - sizeLevels.min); + } else if (function) { + size = function->evaluate(currentZoom); + } + + return UniformValues { + uniforms::u_is_size_zoom_constant::Value{ isZoomConstant }, + uniforms::u_is_size_feature_constant::Value{ true }, + uniforms::u_size_t::Value{ 0.0f }, // unused + uniforms::u_size::Value{ size }, + uniforms::u_layout_size::Value{ layoutSize } + }; + } + + float layoutSize; + // used for exponential functions + optional<std::tuple<Range<float>, Range<float>>> coveringRanges; + optional<float> functionInterpolationBase; + // used for interval functions + optional<style::CameraFunction<float>> function; +}; + +class SourceFunctionSymbolSizeBinder : public SymbolSizeBinder { +public: + using Vertex = gl::detail::Vertex<gl::Attribute<uint16_t, 1>>; + using VertexVector = gl::VertexVector<Vertex>; + using VertexBuffer = gl::VertexBuffer<Vertex>; + + SourceFunctionSymbolSizeBinder(const float /*tileZoom*/, const style::SourceFunction<float>& function_, const float defaultValue_) + : function(function_), + defaultValue(defaultValue_) { + } + + SymbolSizeAttributes::Bindings attributeBindings(const style::PossiblyEvaluatedPropertyValue<float> currentValue) const override { + if (currentValue.isConstant()) { + return SymbolSizeAttributes::Bindings { SymbolSizeAttributes::Attribute::ConstantBinding {{{0, 0, 0}}} }; + } + + return SymbolSizeAttributes::Bindings { SymbolSizeAttributes::Attribute::variableBinding(*buffer, 0, 1) }; + } + + void populateVertexVector(const GeometryTileFeature& feature) override { + const auto sizeVertex = Vertex { {{ - static_cast<uint8_t>(labelminzoom * 10), // 1/10 zoom levels: z16 == 160 - static_cast<uint8_t>(labelangle), - static_cast<uint8_t>(minzoom * 10), - static_cast<uint8_t>(::fmin(maxzoom, 25) * 10) + static_cast<uint16_t>(function.evaluate(feature, defaultValue) * 10) }} }; + + vertices.emplace_back(sizeVertex); + vertices.emplace_back(sizeVertex); + vertices.emplace_back(sizeVertex); + vertices.emplace_back(sizeVertex); + }; + + UniformValues uniformValues(float) const override { + return UniformValues { + uniforms::u_is_size_zoom_constant::Value{ true }, + uniforms::u_is_size_feature_constant::Value{ false }, + uniforms::u_size_t::Value{ 0.0f }, // unused + uniforms::u_size::Value{ 0.0f }, // unused + uniforms::u_layout_size::Value{ 0.0f } // unused + }; + } + + void upload(gl::Context& context) override { + buffer = VertexBuffer { context.createVertexBuffer(std::move(vertices)) }; + } + + const style::SourceFunction<float>& function; + const float defaultValue; + + VertexVector vertices; + optional<VertexBuffer> buffer; +}; + +class CompositeFunctionSymbolSizeBinder: public SymbolSizeBinder { +public: + using Vertex = SymbolSizeAttributes::Vertex; + using VertexVector = gl::VertexVector<Vertex>; + using VertexBuffer = gl::VertexBuffer<Vertex>; + + CompositeFunctionSymbolSizeBinder(const float tileZoom, const style::CompositeFunction<float>& function_, const float defaultValue_) + : function(function_), + defaultValue(defaultValue_), + layoutZoom(tileZoom + 1), + coveringZoomStops(function.stops.match( + [&] (const auto& stops) { + return getCoveringStops(stops, tileZoom, tileZoom + 1); })) + {} + + SymbolSizeAttributes::Bindings attributeBindings(const style::PossiblyEvaluatedPropertyValue<float> currentValue) const override { + if (currentValue.isConstant()) { + return SymbolSizeAttributes::Bindings { SymbolSizeAttributes::Attribute::ConstantBinding {{{0, 0, 0}}} }; + } + + return SymbolSizeAttributes::Bindings { SymbolSizeAttributes::Attribute::variableBinding(*buffer, 0) }; + } + + void populateVertexVector(const GeometryTileFeature& feature) override { + const auto sizeVertex = Vertex { + {{ + static_cast<uint16_t>(function.evaluate(coveringZoomStops.min, feature, defaultValue) * 10), + static_cast<uint16_t>(function.evaluate(coveringZoomStops.max, feature, defaultValue) * 10), + static_cast<uint16_t>(function.evaluate(layoutZoom, feature, defaultValue) * 10) + }} + }; + + vertices.emplace_back(sizeVertex); + vertices.emplace_back(sizeVertex); + vertices.emplace_back(sizeVertex); + vertices.emplace_back(sizeVertex); + }; + + UniformValues uniformValues(float currentZoom) const override { + float sizeInterpolationT = util::clamp( + util::interpolationFactor(1.0f, coveringZoomStops, currentZoom), + 0.0f, 1.0f + ); + + return UniformValues { + uniforms::u_is_size_zoom_constant::Value{ false }, + uniforms::u_is_size_feature_constant::Value{ false }, + uniforms::u_size_t::Value{ sizeInterpolationT }, + uniforms::u_size::Value{ 0.0f }, // unused + uniforms::u_layout_size::Value{ 0.0f } // unused + }; + } + + void upload(gl::Context& context) override { + buffer = VertexBuffer { context.createVertexBuffer(std::move(vertices)) }; } + + const style::CompositeFunction<float>& function; + const float defaultValue; + float layoutZoom; + Range<float> coveringZoomStops; + + VertexVector vertices; + optional<VertexBuffer> buffer; }; -class SymbolIconProgram : public Program< + +template <class Shaders, + class Primitive, + class LayoutAttrs, + class Uniforms, + class PaintProperties> +class SymbolProgram { +public: + using LayoutAttributes = LayoutAttrs; + using LayoutVertex = typename LayoutAttributes::Vertex; + + using LayoutAndSizeAttributes = gl::ConcatenateAttributes<LayoutAttributes, SymbolSizeAttributes>; + + using PaintPropertyBinders = typename PaintProperties::Binders; + using PaintAttributes = typename PaintPropertyBinders::Attributes; + using Attributes = gl::ConcatenateAttributes<LayoutAndSizeAttributes, PaintAttributes>; + + using UniformValues = typename Uniforms::Values; + using SizeUniforms = typename SymbolSizeBinder::Uniforms; + using PaintUniforms = typename PaintPropertyBinders::Uniforms; + using AllUniforms = gl::ConcatenateUniforms<Uniforms, gl::ConcatenateUniforms<SizeUniforms, PaintUniforms>>; + + using ProgramType = gl::Program<Primitive, Attributes, AllUniforms>; + + ProgramType program; + + SymbolProgram(gl::Context& context, const ProgramParameters& programParameters) + : program(ProgramType::createProgram( + context, + programParameters, + Shaders::name, + Shaders::vertexSource, + Shaders::fragmentSource)) { + } + + template <class DrawMode> + void draw(gl::Context& context, + DrawMode drawMode, + gl::DepthMode depthMode, + gl::StencilMode stencilMode, + gl::ColorMode colorMode, + UniformValues&& uniformValues, + const gl::VertexBuffer<LayoutVertex>& layoutVertexBuffer, + const SymbolSizeBinder& symbolSizeBinder, + const style::PossiblyEvaluatedPropertyValue<float>& currentSizeValue, + const gl::IndexBuffer<DrawMode>& indexBuffer, + const gl::SegmentVector<Attributes>& segments, + const PaintPropertyBinders& paintPropertyBinders, + const typename PaintProperties::Evaluated& currentProperties, + float currentZoom) { + program.draw( + context, + std::move(drawMode), + std::move(depthMode), + std::move(stencilMode), + std::move(colorMode), + uniformValues + .concat(symbolSizeBinder.uniformValues(currentZoom)) + .concat(paintPropertyBinders.uniformValues(currentZoom)), + LayoutAttributes::allVariableBindings(layoutVertexBuffer) + .concat(symbolSizeBinder.attributeBindings(currentSizeValue)) + .concat(paintPropertyBinders.attributeBindings(currentProperties)), + indexBuffer, + segments + ); + } +}; + +class SymbolIconProgram : public SymbolProgram< shaders::symbol_icon, gl::Triangle, SymbolLayoutAttributes, @@ -80,13 +395,15 @@ class SymbolIconProgram : public Program< uniforms::u_zoom, uniforms::u_rotate_with_map, uniforms::u_texture, - uniforms::u_fadetexture>, + uniforms::u_fadetexture, + uniforms::u_is_text>, style::IconPaintProperties> { public: - using Program::Program; + using SymbolProgram::SymbolProgram; - static UniformValues uniformValues(const style::SymbolPropertyValues&, + static UniformValues uniformValues(const bool isText, + const style::SymbolPropertyValues&, const Size& texsize, const std::array<float, 2>& pixelsToGLUnits, const RenderTile&, @@ -99,7 +416,7 @@ enum class SymbolSDFPart { }; template <class PaintProperties> -class SymbolSDFProgram : public Program< +class SymbolSDFProgram : public SymbolProgram< shaders::symbol_sdf, gl::Triangle, SymbolLayoutAttributes, @@ -111,7 +428,7 @@ class SymbolSDFProgram : public Program< uniforms::u_rotate_with_map, uniforms::u_texture, uniforms::u_fadetexture, - uniforms::u_font_scale, + uniforms::u_is_text, uniforms::u_gamma_scale, uniforms::u_pitch, uniforms::u_bearing, @@ -121,7 +438,7 @@ class SymbolSDFProgram : public Program< PaintProperties> { public: - using BaseProgram = Program<shaders::symbol_sdf, + using BaseProgram = SymbolProgram<shaders::symbol_sdf, gl::Triangle, SymbolLayoutAttributes, gl::Uniforms< @@ -132,7 +449,7 @@ public: uniforms::u_rotate_with_map, uniforms::u_texture, uniforms::u_fadetexture, - uniforms::u_font_scale, + uniforms::u_is_text, uniforms::u_gamma_scale, uniforms::u_pitch, uniforms::u_bearing, @@ -147,7 +464,8 @@ public: using BaseProgram::BaseProgram; - static UniformValues uniformValues(const style::SymbolPropertyValues&, + static UniformValues uniformValues(const bool isText, + const style::SymbolPropertyValues&, const Size& texsize, const std::array<float, 2>& pixelsToGLUnits, const RenderTile&, |