Add wide vector shader option to Custom Drawable Layer (#2183)
This commit is contained in:
@@ -1150,6 +1150,7 @@ if(MLN_WITH_OPENGL)
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/raster_layer_ubo.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/shader_defines.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/symbol_layer_ubo.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/widevector_ubo.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/shader_program_gl.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/gl/drawable_gl.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/gl/drawable_gl_builder.hpp
|
||||
|
||||
@@ -88,6 +88,7 @@ MLN_GENERATED_OPENGL_SHADER_HEADERS = [
|
||||
"include/mbgl/shaders/gl/drawable_symbol_icon.hpp",
|
||||
"include/mbgl/shaders/gl/drawable_symbol_sdf.hpp",
|
||||
"include/mbgl/shaders/gl/drawable_symbol_text_and_icon.hpp",
|
||||
"include/mbgl/shaders/gl/drawable_wide_vector.hpp",
|
||||
"include/mbgl/shaders/gl/fill_extrusion_pattern.hpp",
|
||||
"include/mbgl/shaders/gl/fill_extrusion.hpp",
|
||||
"include/mbgl/shaders/gl/fill_outline_pattern.hpp",
|
||||
@@ -1000,6 +1001,7 @@ MLN_DRAWABLES_HEADERS = [
|
||||
"include/mbgl/shaders/shader_defines.hpp",
|
||||
"include/mbgl/shaders/shader_program_base.hpp",
|
||||
"include/mbgl/shaders/symbol_layer_ubo.hpp",
|
||||
"include/mbgl/shaders/widevector_ubo.hpp",
|
||||
"include/mbgl/util/suppress_copies.hpp",
|
||||
"include/mbgl/style/layers/custom_drawable_layer.hpp",
|
||||
"include/mbgl/layermanager/custom_drawable_layer_factory.hpp",
|
||||
@@ -1123,4 +1125,5 @@ MLN_DRAWABLES_MTL_HEADERS = [
|
||||
"include/mbgl/shaders/mtl/symbol_sdf.hpp",
|
||||
"include/mbgl/shaders/mtl/symbol_text_and_icon.hpp",
|
||||
"include/mbgl/style/layers/mtl/custom_layer_render_parameters.hpp",
|
||||
"include/mbgl/shaders/mtl/widevector.hpp",
|
||||
]
|
||||
|
||||
@@ -189,6 +189,12 @@ public:
|
||||
/// Set vertex attribute array
|
||||
void setVertexAttributes(gfx::VertexAttributeArrayPtr value) noexcept { vertexAttributes = std::move(value); }
|
||||
|
||||
/// Get the instance attributes
|
||||
const gfx::VertexAttributeArrayPtr& getInstanceAttributes() const noexcept { return instanceAttributes; }
|
||||
|
||||
/// Set instance attribute array
|
||||
void setInstanceAttributes(gfx::VertexAttributeArrayPtr value) noexcept { instanceAttributes = std::move(value); }
|
||||
|
||||
/// Provide raw data for vertices. Incompatible with adding primitives
|
||||
virtual void setVertices(std::vector<uint8_t>&&, std::size_t, AttributeDataType) = 0;
|
||||
|
||||
@@ -232,6 +238,12 @@ public:
|
||||
void setLayerTweaker(LayerTweakerPtr tweaker) { layerTweaker = std::move(tweaker); }
|
||||
const LayerTweakerPtr& getLayerTweaker() const { return layerTweaker; }
|
||||
|
||||
/// Get origin point
|
||||
const std::optional<mbgl::Point<double>>& getOrigin() const { return origin; }
|
||||
|
||||
/// Set origin point
|
||||
void setOrigin(std::optional<Point<double>> p) { origin = std::move(p); }
|
||||
|
||||
protected:
|
||||
bool enabled = true;
|
||||
bool enableColor = true;
|
||||
@@ -251,6 +263,7 @@ protected:
|
||||
DepthMaskType depthType; // = DepthMaskType::ReadOnly;
|
||||
UniqueDrawableData drawableData{};
|
||||
gfx::VertexAttributeArrayPtr vertexAttributes;
|
||||
gfx::VertexAttributeArrayPtr instanceAttributes;
|
||||
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> impl;
|
||||
@@ -260,6 +273,7 @@ protected:
|
||||
LayerTweakerPtr layerTweaker;
|
||||
|
||||
std::size_t type = 0;
|
||||
std::optional<mbgl::Point<double>> origin;
|
||||
};
|
||||
|
||||
using DrawablePtr = std::shared_ptr<Drawable>;
|
||||
|
||||
@@ -160,6 +160,13 @@ public:
|
||||
/// A set of attribute values to be added for each vertex
|
||||
void setVertexAttributes(VertexAttributeArrayPtr attrs) { vertexAttrs = std::move(attrs); }
|
||||
|
||||
/// Get the instance attributes that override default values in the shader program
|
||||
VertexAttributeArrayPtr& getInstanceAttributes() { return instanceAttrs; }
|
||||
const VertexAttributeArrayPtr& getInstanceAttributes() const { return instanceAttrs; }
|
||||
|
||||
/// A set of attribute values to be added for each instance
|
||||
void setInstanceAttributes(VertexAttributeArrayPtr attrs) { instanceAttrs = std::move(attrs); }
|
||||
|
||||
/// Add some vertex elements, returns the index of the first one added
|
||||
std::size_t addVertices(const std::vector<std::array<int16_t, 2>>& vertices,
|
||||
std::size_t vertexOffset,
|
||||
@@ -200,6 +207,12 @@ public:
|
||||
/// Add a polyline. If the last point equals the first it will be closed, otherwise open
|
||||
void addPolyline(const GeometryCoordinates& coordinates, const gfx::PolylineGeneratorOptions&);
|
||||
|
||||
/// Add a polyline in Tile coordinates, using wide vectors.
|
||||
void addWideVectorPolylineLocal(const GeometryCoordinates& coordinates, const gfx::PolylineGeneratorOptions&);
|
||||
|
||||
/// Add a polyline in geographic coordinates, using wide vectors.
|
||||
void addWideVectorPolylineGlobal(const LineString<double>& coordinates, const gfx::PolylineGeneratorOptions&);
|
||||
|
||||
/// return the curent vertex count
|
||||
std::size_t curVertexCount() const;
|
||||
|
||||
@@ -232,6 +245,8 @@ protected:
|
||||
gfx::Drawable::Textures textures;
|
||||
std::vector<DrawableTweakerPtr> tweakers;
|
||||
gfx::VertexAttributeArrayPtr vertexAttrs;
|
||||
gfx::VertexAttributeArrayPtr instanceAttrs;
|
||||
std::optional<mbgl::Point<double>> origin;
|
||||
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> impl;
|
||||
|
||||
@@ -319,7 +319,7 @@ public:
|
||||
|
||||
/// Do something with each attribute
|
||||
template <typename Func /* void(VertexAttribute&) */>
|
||||
void visitAttributes(Func f) {
|
||||
void visitAttributes(Func f) const {
|
||||
std::for_each(attrs.begin(), attrs.end(), [&](const auto& attr) {
|
||||
if (attr) {
|
||||
f(*attr);
|
||||
|
||||
@@ -64,6 +64,8 @@ protected:
|
||||
void bindAttributes(RenderPass&) const noexcept;
|
||||
void unbindAttributes(RenderPass&) const noexcept {}
|
||||
|
||||
void bindInstanceAttributes(RenderPass&) const noexcept;
|
||||
|
||||
void bindUniformBuffers(RenderPass&) const noexcept;
|
||||
void unbindUniformBuffers(RenderPass&) const noexcept {}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <mbgl/shaders/shader_source.hpp>
|
||||
#include <mbgl/util/immutable.hpp>
|
||||
#include <mbgl/util/containers.hpp>
|
||||
#include <mbgl/util/mat4.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
@@ -28,8 +29,6 @@ class PaintParameters;
|
||||
class RenderTree;
|
||||
class UnwrappedTileID;
|
||||
|
||||
using mat4 = std::array<double, 16>;
|
||||
|
||||
/**
|
||||
Base class for layer tweakers, which manipulate layer group per frame
|
||||
*/
|
||||
|
||||
16
include/mbgl/shaders/gl/drawable_wide_vector.hpp
Normal file
16
include/mbgl/shaders/gl/drawable_wide_vector.hpp
Normal file
@@ -0,0 +1,16 @@
|
||||
// Generated code, do not modify this file!
|
||||
#pragma once
|
||||
#include <mbgl/shaders/shader_source.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace shaders {
|
||||
|
||||
template <>
|
||||
struct ShaderSource<BuiltIn::WideVectorShader, gfx::Backend::Type::OpenGL> {
|
||||
static constexpr const char* name = "WideVectorShader";
|
||||
static constexpr const char* vertex = R"()";
|
||||
static constexpr const char* fragment = R"()";
|
||||
};
|
||||
|
||||
} // namespace shaders
|
||||
} // namespace mbgl
|
||||
@@ -46,6 +46,8 @@ public:
|
||||
|
||||
const gfx::VertexAttributeArray& getVertexAttributes() const override { return vertexAttributes; }
|
||||
|
||||
const gfx::VertexAttributeArray& getInstanceAttributes() const override { return instanceAttributes; }
|
||||
|
||||
ProgramID getGLProgramID() const { return glProgram; }
|
||||
|
||||
protected:
|
||||
@@ -56,6 +58,7 @@ protected:
|
||||
|
||||
UniformBlockArrayGL uniformBlocks;
|
||||
VertexAttributeArrayGL vertexAttributes;
|
||||
VertexAttributeArrayGL instanceAttributes;
|
||||
SamplerLocationArray samplerLocations;
|
||||
};
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ struct ShaderSource<BuiltIn::BackgroundShader, gfx::Backend::Type::Metal> {
|
||||
static constexpr auto fragmentMainFunction = "fragmentMain";
|
||||
|
||||
static const std::array<AttributeInfo, 1> attributes;
|
||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||
static const std::array<UniformBlockInfo, 2> uniforms;
|
||||
static const std::array<TextureInfo, 0> textures;
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ struct ShaderSource<BuiltIn::BackgroundPatternShader, gfx::Backend::Type::Metal>
|
||||
static constexpr auto fragmentMainFunction = "fragmentMain";
|
||||
|
||||
static const std::array<AttributeInfo, 1> attributes;
|
||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||
static const std::array<UniformBlockInfo, 2> uniforms;
|
||||
static const std::array<TextureInfo, 1> textures;
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ struct ShaderSource<BuiltIn::CircleShader, gfx::Backend::Type::Metal> {
|
||||
static constexpr auto fragmentMainFunction = "fragmentMain";
|
||||
|
||||
static const std::array<AttributeInfo, 8> attributes;
|
||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||
static const std::array<UniformBlockInfo, 4> uniforms;
|
||||
static const std::array<TextureInfo, 0> textures;
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ struct ShaderSource<BuiltIn::ClippingMaskProgram, gfx::Backend::Type::Metal> {
|
||||
static constexpr auto fragmentMainFunction = "fragmentMain";
|
||||
|
||||
static const std::array<AttributeInfo, 1> attributes;
|
||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||
static const std::array<UniformBlockInfo, 1> uniforms;
|
||||
static const std::array<TextureInfo, 0> textures;
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ struct ShaderSource<BuiltIn::CollisionBoxShader, gfx::Backend::Type::Metal> {
|
||||
static constexpr auto fragmentMainFunction = "fragmentMain";
|
||||
|
||||
static const std::array<AttributeInfo, 5> attributes;
|
||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||
static const std::array<UniformBlockInfo, 1> uniforms;
|
||||
static const std::array<TextureInfo, 0> textures;
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ struct ShaderSource<BuiltIn::CollisionCircleShader, gfx::Backend::Type::Metal> {
|
||||
static constexpr auto fragmentMainFunction = "fragmentMain";
|
||||
|
||||
static const std::array<AttributeInfo, 4> attributes;
|
||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||
static const std::array<UniformBlockInfo, 1> uniforms;
|
||||
static const std::array<TextureInfo, 0> textures;
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ struct ShaderSource<BuiltIn::CustomSymbolIconShader, gfx::Backend::Type::Metal>
|
||||
static constexpr auto fragmentMainFunction = "fragmentMain";
|
||||
|
||||
static const std::array<AttributeInfo, 2> attributes;
|
||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||
static const std::array<UniformBlockInfo, 2> uniforms;
|
||||
static const std::array<TextureInfo, 1> textures;
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ struct ShaderSource<BuiltIn::DebugShader, gfx::Backend::Type::Metal> {
|
||||
static constexpr auto fragmentMainFunction = "fragmentMain";
|
||||
|
||||
static const std::array<AttributeInfo, 1> attributes;
|
||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||
static const std::array<UniformBlockInfo, 1> uniforms;
|
||||
static const std::array<TextureInfo, 1> textures;
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ struct ShaderSource<BuiltIn::FillShader, gfx::Backend::Type::Metal> {
|
||||
static constexpr auto fragmentMainFunction = "fragmentMain";
|
||||
|
||||
static const std::array<AttributeInfo, 3> attributes;
|
||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||
static const std::array<UniformBlockInfo, 3> uniforms;
|
||||
static const std::array<TextureInfo, 0> textures;
|
||||
|
||||
@@ -101,6 +102,7 @@ struct ShaderSource<BuiltIn::FillOutlineShader, gfx::Backend::Type::Metal> {
|
||||
static constexpr auto fragmentMainFunction = "fragmentMain";
|
||||
|
||||
static const std::array<AttributeInfo, 3> attributes;
|
||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||
static const std::array<UniformBlockInfo, 3> uniforms;
|
||||
static const std::array<TextureInfo, 0> textures;
|
||||
|
||||
@@ -191,6 +193,7 @@ struct ShaderSource<BuiltIn::FillPatternShader, gfx::Backend::Type::Metal> {
|
||||
static constexpr auto fragmentMainFunction = "fragmentMain";
|
||||
|
||||
static const std::array<AttributeInfo, 4> attributes;
|
||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||
static const std::array<UniformBlockInfo, 4> uniforms;
|
||||
static const std::array<TextureInfo, 1> textures;
|
||||
|
||||
@@ -349,6 +352,7 @@ struct ShaderSource<BuiltIn::FillOutlinePatternShader, gfx::Backend::Type::Metal
|
||||
static constexpr auto fragmentMainFunction = "fragmentMain";
|
||||
|
||||
static const std::array<AttributeInfo, 4> attributes;
|
||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||
static const std::array<UniformBlockInfo, 4> uniforms;
|
||||
static const std::array<TextureInfo, 1> textures;
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ struct ShaderSource<BuiltIn::FillExtrusionShader, gfx::Backend::Type::Metal> {
|
||||
static constexpr auto fragmentMainFunction = "fragmentMain";
|
||||
|
||||
static const std::array<AttributeInfo, 5> attributes;
|
||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||
static const std::array<UniformBlockInfo, 3> uniforms;
|
||||
static const std::array<TextureInfo, 0> textures;
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ struct ShaderSource<BuiltIn::FillExtrusionPatternShader, gfx::Backend::Type::Met
|
||||
static constexpr auto fragmentMainFunction = "fragmentMain";
|
||||
|
||||
static const std::array<AttributeInfo, 6> attributes;
|
||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||
static const std::array<UniformBlockInfo, 4> uniforms;
|
||||
static const std::array<TextureInfo, 1> textures;
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ struct ShaderSource<BuiltIn::HeatmapShader, gfx::Backend::Type::Metal> {
|
||||
static constexpr auto fragmentMainFunction = "fragmentMain";
|
||||
|
||||
static const std::array<AttributeInfo, 3> attributes;
|
||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||
static const std::array<UniformBlockInfo, 3> uniforms;
|
||||
static const std::array<TextureInfo, 0> textures;
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ struct ShaderSource<BuiltIn::HeatmapTextureShader, gfx::Backend::Type::Metal> {
|
||||
static constexpr auto fragmentMainFunction = "fragmentMain";
|
||||
|
||||
static const std::array<AttributeInfo, 1> attributes;
|
||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||
static const std::array<UniformBlockInfo, 1> uniforms;
|
||||
static const std::array<TextureInfo, 2> textures;
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ struct ShaderSource<BuiltIn::HillshadeShader, gfx::Backend::Type::Metal> {
|
||||
static constexpr auto fragmentMainFunction = "fragmentMain";
|
||||
|
||||
static const std::array<AttributeInfo, 2> attributes;
|
||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||
static const std::array<UniformBlockInfo, 2> uniforms;
|
||||
static const std::array<TextureInfo, 1> textures;
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ struct ShaderSource<BuiltIn::HillshadePrepareShader, gfx::Backend::Type::Metal>
|
||||
static constexpr auto fragmentMainFunction = "fragmentMain";
|
||||
|
||||
static const std::array<AttributeInfo, 2> attributes;
|
||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||
static const std::array<UniformBlockInfo, 1> uniforms;
|
||||
static const std::array<TextureInfo, 1> textures;
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ struct ShaderSource<BuiltIn::LineShader, gfx::Backend::Type::Metal> {
|
||||
static constexpr auto fragmentMainFunction = "fragmentMain";
|
||||
|
||||
static const std::array<AttributeInfo, 8> attributes;
|
||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||
static const std::array<UniformBlockInfo, 4> uniforms;
|
||||
static const std::array<TextureInfo, 0> textures;
|
||||
|
||||
@@ -179,6 +180,7 @@ struct ShaderSource<BuiltIn::LinePatternShader, gfx::Backend::Type::Metal> {
|
||||
static constexpr auto fragmentMainFunction = "fragmentMain";
|
||||
|
||||
static const std::array<AttributeInfo, 9> attributes;
|
||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||
static const std::array<UniformBlockInfo, 5> uniforms;
|
||||
static const std::array<TextureInfo, 1> textures;
|
||||
|
||||
@@ -430,6 +432,7 @@ struct ShaderSource<BuiltIn::LineSDFShader, gfx::Backend::Type::Metal> {
|
||||
static constexpr auto fragmentMainFunction = "fragmentMain";
|
||||
|
||||
static const std::array<AttributeInfo, 9> attributes;
|
||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||
static const std::array<UniformBlockInfo, 4> uniforms;
|
||||
static const std::array<TextureInfo, 1> textures;
|
||||
|
||||
@@ -658,6 +661,7 @@ struct ShaderSource<BuiltIn::LineBasicShader, gfx::Backend::Type::Metal> {
|
||||
static constexpr auto fragmentMainFunction = "fragmentMain";
|
||||
|
||||
static const std::array<AttributeInfo, 2> attributes;
|
||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||
static const std::array<UniformBlockInfo, 2> uniforms;
|
||||
static const std::array<TextureInfo, 0> textures;
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ struct ShaderSource<BuiltIn::LineGradientShader, gfx::Backend::Type::Metal> {
|
||||
static constexpr auto fragmentMainFunction = "fragmentMain";
|
||||
|
||||
static const std::array<AttributeInfo, 7> attributes;
|
||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||
static const std::array<UniformBlockInfo, 4> uniforms;
|
||||
static const std::array<TextureInfo, 1> textures;
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ struct ShaderSource<BuiltIn::RasterShader, gfx::Backend::Type::Metal> {
|
||||
static constexpr auto fragmentMainFunction = "fragmentMain";
|
||||
|
||||
static const std::array<AttributeInfo, 2> attributes;
|
||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||
static const std::array<UniformBlockInfo, 1> uniforms;
|
||||
static const std::array<TextureInfo, 2> textures;
|
||||
|
||||
|
||||
@@ -78,6 +78,9 @@ public:
|
||||
shader->initAttribute(attrib);
|
||||
}
|
||||
}
|
||||
for (const auto& attrib : ShaderClass::instanceAttributes) {
|
||||
shader->initInstanceAttribute(attrib);
|
||||
}
|
||||
for (const auto& uniform : ShaderClass::uniforms) {
|
||||
shader->initUniformBlock(uniform);
|
||||
}
|
||||
|
||||
@@ -14,13 +14,21 @@
|
||||
namespace mbgl {
|
||||
namespace shaders {
|
||||
struct AttributeInfo {
|
||||
AttributeInfo(std::size_t index, gfx::AttributeDataType dataType, std::size_t id);
|
||||
constexpr AttributeInfo(std::size_t index_, gfx::AttributeDataType dataType_, std::size_t id_)
|
||||
: index(index_),
|
||||
dataType(dataType_),
|
||||
id(id_) {}
|
||||
std::size_t index;
|
||||
gfx::AttributeDataType dataType;
|
||||
std::size_t id;
|
||||
};
|
||||
struct UniformBlockInfo {
|
||||
UniformBlockInfo(std::size_t index, bool vertex, bool fragment, std::size_t size, std::size_t id);
|
||||
constexpr UniformBlockInfo(std::size_t index_, bool vertex_, bool fragment_, std::size_t size_, std::size_t id_)
|
||||
: index(index_),
|
||||
vertex(vertex_),
|
||||
fragment(fragment_),
|
||||
size(size_),
|
||||
id(id_) {}
|
||||
std::size_t index;
|
||||
bool vertex;
|
||||
bool fragment;
|
||||
@@ -28,7 +36,9 @@ struct UniformBlockInfo {
|
||||
std::size_t id;
|
||||
};
|
||||
struct TextureInfo {
|
||||
TextureInfo(std::size_t index, std::size_t id);
|
||||
constexpr TextureInfo(std::size_t index_, std::size_t id_)
|
||||
: index(index_),
|
||||
id(id_) {}
|
||||
std::size_t index;
|
||||
std::size_t id;
|
||||
};
|
||||
@@ -58,10 +68,13 @@ public:
|
||||
|
||||
const gfx::VertexAttributeArray& getVertexAttributes() const override { return vertexAttributes; }
|
||||
|
||||
const gfx::VertexAttributeArray& getInstanceAttributes() const override { return instanceAttributes; }
|
||||
|
||||
const gfx::UniformBlockArray& getUniformBlocks() const override { return uniformBlocks; }
|
||||
gfx::UniformBlockArray& mutableUniformBlocks() override { return uniformBlocks; }
|
||||
|
||||
void initAttribute(const shaders::AttributeInfo&);
|
||||
void initInstanceAttribute(const shaders::AttributeInfo&);
|
||||
void initUniformBlock(const shaders::UniformBlockInfo&);
|
||||
void initTexture(const shaders::TextureInfo&);
|
||||
|
||||
@@ -72,6 +85,7 @@ protected:
|
||||
MTLFunctionPtr fragmentFunction;
|
||||
UniformBlockArray uniformBlocks;
|
||||
VertexAttributeArray vertexAttributes;
|
||||
VertexAttributeArray instanceAttributes;
|
||||
std::array<std::optional<size_t>, shaders::maxTextureCountPerShader> textureBindings;
|
||||
};
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ struct ShaderSource<BuiltIn::SymbolIconShader, gfx::Backend::Type::Metal> {
|
||||
static constexpr auto fragmentMainFunction = "fragmentMain";
|
||||
|
||||
static const std::array<AttributeInfo, 6> attributes;
|
||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||
static const std::array<UniformBlockInfo, 5> uniforms;
|
||||
static const std::array<TextureInfo, 1> textures;
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ struct ShaderSource<BuiltIn::SymbolSDFIconShader, gfx::Backend::Type::Metal> {
|
||||
static constexpr auto fragmentMainFunction = "fragmentMain";
|
||||
|
||||
static const std::array<AttributeInfo, 10> attributes;
|
||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||
static const std::array<UniformBlockInfo, 5> uniforms;
|
||||
static const std::array<TextureInfo, 1> textures;
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ struct ShaderSource<BuiltIn::SymbolTextAndIconShader, gfx::Backend::Type::Metal>
|
||||
static constexpr auto fragmentMainFunction = "fragmentMain";
|
||||
|
||||
static const std::array<AttributeInfo, 9> attributes;
|
||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||
static const std::array<UniformBlockInfo, 5> uniforms;
|
||||
static const std::array<TextureInfo, 2> textures;
|
||||
|
||||
|
||||
587
include/mbgl/shaders/mtl/widevector.hpp
Normal file
587
include/mbgl/shaders/mtl/widevector.hpp
Normal file
@@ -0,0 +1,587 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/shaders/shader_source.hpp>
|
||||
#include <mbgl/shaders/mtl/common.hpp>
|
||||
#include <mbgl/shaders/mtl/shader_program.hpp>
|
||||
#include <mbgl/shaders/widevector_ubo.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace shaders {
|
||||
|
||||
template <>
|
||||
struct ShaderSource<BuiltIn::WideVectorShader, gfx::Backend::Type::Metal> {
|
||||
static constexpr auto name = "WideVectorShader";
|
||||
static constexpr auto vertexMainFunction = "vertexTri_wideVecPerf";
|
||||
static constexpr auto fragmentMainFunction = "fragmentTri_wideVecPerf";
|
||||
|
||||
static constexpr std::array<AttributeInfo, 3> attributes{
|
||||
AttributeInfo{0, gfx::AttributeDataType::Float3, idWideVectorScreenPos},
|
||||
AttributeInfo{1, gfx::AttributeDataType::Float4, idWideVectorColor},
|
||||
AttributeInfo{2, gfx::AttributeDataType::Int, idWideVectorIndex}};
|
||||
static constexpr std::array<UniformBlockInfo, 2> uniforms{
|
||||
UniformBlockInfo{3, true, false, sizeof(WideVectorUniformsUBO), idWideVectorUniformsUBO},
|
||||
UniformBlockInfo{4, true, false, sizeof(WideVectorUniformWideVecUBO), idWideVectorUniformWideVecUBO},
|
||||
};
|
||||
static constexpr std::array<AttributeInfo, 4> instanceAttributes{
|
||||
AttributeInfo{5, gfx::AttributeDataType::Float3, idWideVectorInstanceCenter},
|
||||
AttributeInfo{5, gfx::AttributeDataType::Float4, idWideVectorInstanceColor},
|
||||
AttributeInfo{5, gfx::AttributeDataType::Int, idWideVectorInstancePrevious},
|
||||
AttributeInfo{5, gfx::AttributeDataType::Int, idWideVectorInstanceNext}};
|
||||
static constexpr std::array<TextureInfo, 0> textures{};
|
||||
|
||||
static constexpr auto source = R"(
|
||||
#include <metal_stdlib>
|
||||
|
||||
namespace WhirlyKitShader
|
||||
{
|
||||
|
||||
/** Expressions are used to change values like width and opacity over zoom levels. **/
|
||||
#define WKSExpStops 8
|
||||
|
||||
// Line Joins
|
||||
// These are assumed to match WideVectorLineJoinType
|
||||
typedef enum {
|
||||
WKSVertexLineJoinMiter = 0,
|
||||
WKSVertexLineJoinBevel = 1,
|
||||
WKSVertexLineJoinRound = 2,
|
||||
WKSVertexLineJoinMiterClip = 3,
|
||||
WKSVertexLineJoinMiterSimple = 4,
|
||||
WKSVertexLineJoinNone = 5,
|
||||
} WKSVertexLineJoinType;
|
||||
|
||||
// Line Caps
|
||||
// These are assumed to match WideVectorLineCapType
|
||||
typedef enum {
|
||||
WKSVertexLineCapRound = 0,
|
||||
WKSVertexLineCapButt = 1,
|
||||
WKSVertexLineCapSquare = 2,
|
||||
} WKSVertexLineCapType;
|
||||
|
||||
// Uniforms for the basic case.
|
||||
struct Uniforms
|
||||
{
|
||||
simd::float4x4 mvpMatrix;
|
||||
simd::float4x4 mvpMatrixDiff;
|
||||
simd::float4x4 mvMatrix;
|
||||
simd::float4x4 mvMatrixDiff;
|
||||
simd::float4x4 pMatrix;
|
||||
simd::float4x4 pMatrixDiff;
|
||||
simd::float2 frameSize;
|
||||
};
|
||||
|
||||
// Instructions to the wide vector shaders, usually per-drawable
|
||||
struct UniformWideVec {
|
||||
simd::float4 color; // Color
|
||||
float w2; // Width / 2.0 in screen space
|
||||
float offset; // Offset from center in screen space
|
||||
float edge; // Edge falloff control
|
||||
float texRepeat; // Texture scaling specific to wide vectors
|
||||
simd::float2 texOffset; // Texture offset.
|
||||
float miterLimit; // Miter join limit, multiples of width
|
||||
WKSVertexLineJoinType join; // Line joins
|
||||
WKSVertexLineCapType cap; // Line endcaps
|
||||
bool hasExp; // Look for a UniformWideVecExp structure for color, opacity, and width
|
||||
float interClipLimit; // Allow clipping of out-of-bounds intersection points
|
||||
// Value is the multiple of distance-squared that is allowed.
|
||||
};
|
||||
|
||||
// Instance info for the wide vector (new) vertex shader
|
||||
typedef struct
|
||||
{
|
||||
// Center of the point on the line
|
||||
simd::float3 center;
|
||||
// Color
|
||||
simd::float4 color;
|
||||
// Used to track loops and such
|
||||
int prev,next; // set to -1 for non-loops
|
||||
} VertexTriWideVecInstance;
|
||||
|
||||
}
|
||||
|
||||
// These have syntax that only the shader language can grok
|
||||
// We put them here so we can include them in other Metal libraries
|
||||
#ifdef __METAL_VERSION__
|
||||
|
||||
/**
|
||||
Wide Vector Shaders
|
||||
These work to build/render objects in 2D space, but based
|
||||
on 3D locations.
|
||||
*/
|
||||
|
||||
// Vertex definition for wide vector (new version)
|
||||
struct VertexTriWideVecB
|
||||
{
|
||||
// x, y offset around the center
|
||||
float3 screenPos [[attribute(0)]];
|
||||
float4 color [[attribute(1)]];
|
||||
int index [[attribute(2)]];
|
||||
};
|
||||
|
||||
// Wide vector vertex passed to fragment shader (new version)
|
||||
struct ProjVertexTriWideVecPerf {
|
||||
float4 position [[invariant]] [[position]]; // transformed to NDC
|
||||
float2 screenPos; // un-transformed vertex position
|
||||
float2 centerPos; // un-transformed circle center
|
||||
float2 midDir; // Turn direction
|
||||
float4 color;
|
||||
float2 texCoord;
|
||||
float w2;
|
||||
float edge;
|
||||
uint2 maskIDs;
|
||||
bool roundJoin;
|
||||
|
||||
//uint whichVert; // helpful for debugging
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
#endif
|
||||
|
||||
using namespace metal;
|
||||
using namespace WhirlyKitShader;
|
||||
|
||||
struct IntersectInfo {
|
||||
bool valid;
|
||||
float2 interPt;
|
||||
float c;
|
||||
float ta,tb;
|
||||
};
|
||||
|
||||
// wedge product (2D cross product)
|
||||
// if A ^ B > 0, A is to the right of B
|
||||
float wedge(float2 a, float2 b) {
|
||||
return a.x * b.y - a.y * b.x;
|
||||
}
|
||||
|
||||
// Intersect two lines
|
||||
IntersectInfo intersectLines(float2 a0, float2 a1, float2 b0, float2 b1)
|
||||
{
|
||||
const float2 dA = a0 - a1;
|
||||
const float2 dB = b0 - b1;
|
||||
|
||||
// Solve the system of equations formed by equating the lines to get their common point.
|
||||
const float denom = wedge(dA, dB);
|
||||
if (denom == 0.0) {
|
||||
// If the denominator comes out zero, the lines are parallel and do not intersect
|
||||
return { .valid = false };
|
||||
}
|
||||
|
||||
const float tA = wedge(a0, a1);
|
||||
const float tB = wedge(b0, b1);
|
||||
const float2 inter = float2((tA * dB.x - dA.x * tB), (tA * dB.y - dA.y * tB)) / denom;
|
||||
|
||||
return {
|
||||
.valid = true,
|
||||
.interPt = inter,
|
||||
.ta = 0.0,
|
||||
.tb = 0.0,
|
||||
};
|
||||
}
|
||||
|
||||
// Intersect two offset lines
|
||||
IntersectInfo intersectWideLines(float2 p0,float2 p1,float2 p2,
|
||||
float2 n0,float2 n1)
|
||||
{
|
||||
return intersectLines(p0 + n0, p1 + n0, p1 + n1, p2 + n1);
|
||||
}
|
||||
|
||||
// Used to track what info we have about a center point
|
||||
struct CenterInfo {
|
||||
/// Screen coordinates of the line segment endpoint
|
||||
float2 screenPos;
|
||||
/// Length of the segment (in screen coordinates)
|
||||
float len;
|
||||
/// Normalized direction of the segment
|
||||
float2 nDir;
|
||||
/// Normalized plane normal, perpendicular to the segment
|
||||
float2 norm;
|
||||
};
|
||||
|
||||
float3 viewPos(constant simd::float4x4 &mat, float3 vec) {
|
||||
const float4 p = mat * float4(vec,1.0);
|
||||
return p.xyz; // / p.w; ?
|
||||
}
|
||||
|
||||
float2 screenPos_MVP(constant Uniforms &u, float3 viewPos) {
|
||||
const float4 p4 = float4(viewPos, 1.0);
|
||||
|
||||
// Use the MVP matrix
|
||||
const float4 s = u.mvpMatrix * p4;
|
||||
|
||||
return s.xy/s.w;
|
||||
}
|
||||
|
||||
constant constexpr float wideVecMinTurnThreshold = 1e-5;
|
||||
constant constexpr float wideVecMaxTurnThreshold = 0.99999998476; // sin(89.99 deg)
|
||||
constant constexpr int WideVecPolyStartGeom = 0;
|
||||
constant constexpr int WideVecPolyBodyGeom = 1;
|
||||
constant constexpr int WideVecPolyEndGeom = 2;
|
||||
constant constexpr float4 discardPt(0,0,-1e6,NAN);
|
||||
|
||||
// Performance version of wide vector shader
|
||||
vertex ProjVertexTriWideVecPerf vertexTri_wideVecPerf(
|
||||
thread const VertexTriWideVecB vert [[ stage_in ]],
|
||||
constant Uniforms &uniforms [[ buffer(3) ]],
|
||||
constant UniformWideVec &wideVec [[ buffer(4) ]],
|
||||
uint instanceID [[ instance_id ]],
|
||||
constant VertexTriWideVecInstance *wideVecInsts [[ buffer(5) ]])
|
||||
{
|
||||
ProjVertexTriWideVecPerf outVert = {
|
||||
.position = discardPt,
|
||||
.roundJoin = false,
|
||||
};
|
||||
|
||||
// Vertex index within the instance, 0-11
|
||||
// Odd indexes are on the left, evens are on the right.
|
||||
const int whichVert = (vert.index >> 16) & 0xffff;
|
||||
// Polygon index within the segment. 0=Start cap, 1=body, 2=end cap
|
||||
const int whichPoly = vert.index & 0xffff;
|
||||
// Are we on the left edge, or the right?
|
||||
const bool isLeft = (whichVert & 1);
|
||||
// Are we on the starting end of the segment or the end?
|
||||
const bool isEnd = (whichVert > 5);
|
||||
|
||||
// Track vertex for debugging
|
||||
//outVert.whichVert = whichVert;
|
||||
|
||||
// Pull out the width and possibly calculate one
|
||||
float w2 = wideVec.w2;
|
||||
|
||||
// w2 includes edge-blend, strokeWidth does not
|
||||
const float strokeWidth = 2 * w2;
|
||||
if (w2 > 0.0) {
|
||||
w2 = w2 + wideVec.edge;
|
||||
}
|
||||
|
||||
// Disable joins for narrow lines
|
||||
auto joinType = (w2 >= 1) ? wideVec.join : WKSVertexLineJoinNone;
|
||||
|
||||
// Find the various instances representing center points.
|
||||
// We need one behind and one ahead of us.
|
||||
// previous segment
|
||||
// | this segment
|
||||
// | | next segment
|
||||
// | | |
|
||||
bool instValid[4] = { false, true, false, false };
|
||||
VertexTriWideVecInstance inst[4] = { {}, wideVecInsts[instanceID], {}, {} };
|
||||
|
||||
if (inst[1].prev != -1 && joinType != WKSVertexLineJoinNone) {
|
||||
inst[0] = wideVecInsts[inst[1].prev];
|
||||
instValid[0] = true;
|
||||
}
|
||||
if (inst[1].next != -1) {
|
||||
inst[2] = wideVecInsts[inst[1].next];
|
||||
instValid[2] = true;
|
||||
|
||||
if (inst[2].next != -1 && joinType != WKSVertexLineJoinNone) {
|
||||
inst[3] = wideVecInsts[inst[2].next];
|
||||
instValid[3] = true;
|
||||
}
|
||||
} else {
|
||||
// We need at least this and next
|
||||
return outVert;
|
||||
}
|
||||
|
||||
const auto capType = wideVec.cap;
|
||||
const auto isStartCap = (whichPoly == WideVecPolyStartGeom && !instValid[0]);
|
||||
const auto isEndCap = (whichPoly == WideVecPolyEndGeom && !instValid[3]);
|
||||
|
||||
// Butt is the default cap style, the line ends at the point.
|
||||
if ((isStartCap || isEndCap) && capType == WhirlyKitShader::WKSVertexLineCapButt) {
|
||||
return outVert;
|
||||
}
|
||||
|
||||
// Figure out position on the screen for each center point.
|
||||
// centers[1] represents the segment leading to the current point.
|
||||
// centers[2] represents the segment leading from the current point.
|
||||
// centers[X] = vector from centers[X-1] to centers[X]
|
||||
CenterInfo centers[4];
|
||||
for (unsigned int ii=0;ii<4;ii++) {
|
||||
if (!instValid[ii]) {
|
||||
continue;
|
||||
}
|
||||
centers[ii].screenPos = screenPos_MVP(uniforms, inst[ii].center);
|
||||
}
|
||||
|
||||
const float2 screenScale(2.0/uniforms.frameSize.x,2.0/uniforms.frameSize.y); // ~(0.001,0.001)
|
||||
|
||||
// Calculate directions and normals. Done in isotropic coords to
|
||||
// avoid skewing everything when later multiplying by `screenScale`.
|
||||
for (unsigned int ii=1;ii<4;ii++) {
|
||||
if (instValid[ii-1]) {
|
||||
const float2 scaledDir = (centers[ii].screenPos - centers[ii-1].screenPos) / screenScale;
|
||||
centers[ii].len = length(scaledDir);
|
||||
centers[ii].nDir = normalize(scaledDir);
|
||||
centers[ii].norm = float2(-centers[ii].nDir.y, centers[ii].nDir.x);
|
||||
}
|
||||
}
|
||||
|
||||
// Pull out the center line offset, or calculate one
|
||||
float centerLine = wideVec.offset;
|
||||
|
||||
// Intersect on the left or right depending
|
||||
const float interSgn = (whichVert & 1) ? 1 : -1;
|
||||
|
||||
// Do the offset intersection
|
||||
bool intersectValid = false;
|
||||
bool turningLeft = false;
|
||||
const int interIdx = isEnd ? 1 : 0;
|
||||
float2 offsetCenter = centers[interIdx + 1].screenPos + centers[2].norm * centerLine * screenScale;
|
||||
float2 interPt(0, 0), realInterPt(0, 0);
|
||||
float dotProd = 0, theta = 0, miterLength = 0;
|
||||
|
||||
// If we're on the far end of the body segment, we need this and the next two segments.
|
||||
// Otherwise we need the previous, this, and the next segment.
|
||||
if (instValid[interIdx] && instValid[interIdx+1] && instValid[interIdx+2]) {
|
||||
|
||||
// Don't even bother computing intersections for very acute angles or very small turns
|
||||
dotProd = dot(centers[interIdx+1].nDir, centers[interIdx+2].nDir);
|
||||
if (-wideVecMaxTurnThreshold < dotProd &&
|
||||
dotProd < wideVecMaxTurnThreshold &&
|
||||
abs(abs(dotProd) - 1) >= wideVecMinTurnThreshold) {
|
||||
|
||||
// Interior turn angle, both vectors are normalized.
|
||||
theta = M_PI_F - acos(dotProd);
|
||||
|
||||
// "If the miter length divided by the stroke width exceeds the miterlimit then:
|
||||
// miter: the join is converted to a bevel
|
||||
// miter-clip: the miter is clipped at half the miter length from the intersection"
|
||||
if (joinType == WKSVertexLineJoinMiter || joinType == WKSVertexLineJoinMiterClip) {
|
||||
miterLength = abs(1 / sin(theta / 2));
|
||||
if (miterLength > wideVec.miterLimit) {
|
||||
if (joinType == WKSVertexLineJoinMiter) {
|
||||
joinType = WKSVertexLineJoinBevel;
|
||||
} else if (joinType == WKSVertexLineJoinMiterClip) {
|
||||
miterLength = wideVec.miterLimit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Intersect the left or right sides of prev-this and this-next, plus offset
|
||||
thread const CenterInfo &prev = centers[interIdx+0];
|
||||
thread const CenterInfo &cur = centers[interIdx+1];
|
||||
thread const CenterInfo &next = centers[interIdx+2];
|
||||
const float2 edgeDist = screenScale * (interSgn * w2 + centerLine);
|
||||
const float2 n0 = edgeDist * cur.norm;
|
||||
const float2 n1 = edgeDist * next.norm;
|
||||
const IntersectInfo interInfo = intersectLines(prev.screenPos + n0, cur.screenPos + n0,
|
||||
cur.screenPos + n1, next.screenPos + n1);
|
||||
if (interInfo.valid) {
|
||||
const float c = wedge(next.screenPos - cur.screenPos, cur.screenPos - prev.screenPos);
|
||||
turningLeft = (c < 0);
|
||||
realInterPt = interPt = interInfo.interPt;
|
||||
|
||||
// Limit the distance to the smaller of half way back along the previous segment
|
||||
// or half way forward along the next one to keep consecutive segments from colliding.
|
||||
const float maxAdjDist = min(cur.len, next.len) / 2;
|
||||
|
||||
// If we're using offsets, we also need to know the point where the offset lines
|
||||
// intersect, as the distance to the original intersection point isn't helpful.
|
||||
// todo: this doesn't make sense for small angles, but what's the actual threshold?
|
||||
if (centerLine != 0) {
|
||||
const float2 cn0 = cur.norm * centerLine * screenScale;
|
||||
const float2 cn1 = next.norm * centerLine * screenScale;
|
||||
const IntersectInfo i2 = intersectLines(prev.screenPos + cn0, cur.screenPos + cn0,
|
||||
cur.screenPos + cn1, next.screenPos + cn1);
|
||||
if (i2.valid && length_squared((i2.interPt - offsetCenter)/screenScale) < maxAdjDist*maxAdjDist) {
|
||||
offsetCenter = i2.interPt;
|
||||
}
|
||||
}
|
||||
|
||||
const float2 interVec = (interPt - offsetCenter) / screenScale;
|
||||
const float interDist2 = length_squared(interVec);
|
||||
const float maxClipDist2 = (maxAdjDist * wideVec.interClipLimit) *
|
||||
(maxAdjDist * wideVec.interClipLimit);
|
||||
|
||||
// Limit intersection distance.
|
||||
// For up to a multiple of that, adjust the intersection point back along its
|
||||
// length to that limit, effectively narrowing the line instead of just giving up.
|
||||
if (interDist2 <= maxAdjDist*maxAdjDist) {
|
||||
intersectValid = true;
|
||||
} else if (wideVec.interClipLimit > 0 && interDist2 <= maxClipDist2) {
|
||||
interPt = offsetCenter + normalize(interVec) * sqrt(interDist2) * screenScale;
|
||||
intersectValid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Endcaps not used for miter case, discard them.
|
||||
if ((joinType == WKSVertexLineJoinMiter || joinType == WKSVertexLineJoinMiterSimple) &&
|
||||
whichPoly != WideVecPolyBodyGeom && !isStartCap && !isEndCap) {
|
||||
return outVert;
|
||||
}
|
||||
|
||||
// Get the color from the uniform:
|
||||
float4 color = wideVec.color;
|
||||
|
||||
outVert.color = color;
|
||||
outVert.w2 = w2;
|
||||
outVert.edge = wideVec.edge;
|
||||
|
||||
// Work out the corner positions by extending the normals
|
||||
const float2 realEdge = interSgn * w2 * screenScale;
|
||||
const float2 corner = offsetCenter + centers[2].norm * realEdge;
|
||||
const float turnSgn = turningLeft ? -1 : 1;
|
||||
const bool isInsideEdge = (isLeft == turningLeft);
|
||||
|
||||
// Current corner is the default result for all points.
|
||||
float2 pos = corner;
|
||||
|
||||
bool discardTri = false;
|
||||
|
||||
if (isStartCap || isEndCap) {
|
||||
// Square extends beyond the point by half a width.
|
||||
// Round uses the same geometry but rounds it off with the fragment shader.
|
||||
if (capType == WhirlyKitShader::WKSVertexLineCapSquare ||
|
||||
capType == WhirlyKitShader::WKSVertexLineCapRound) {
|
||||
switch (whichVert) {
|
||||
case 0: case 1: case 10: case 11:
|
||||
pos = corner + centers[2].nDir * w2 * screenScale * (isEnd ? 1 : -1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (capType == WhirlyKitShader::WKSVertexLineCapRound) {
|
||||
outVert.roundJoin = true;
|
||||
outVert.centerPos = offsetCenter / screenScale;
|
||||
outVert.screenPos = pos / screenScale;
|
||||
outVert.midDir = centers[2].nDir * (isEnd ? 1 : -1);
|
||||
}
|
||||
} else {
|
||||
if (joinType == WKSVertexLineJoinNone || !intersectValid) {
|
||||
// Trivial case, just use the corner
|
||||
outVert.position = float4(pos, 0, 1);
|
||||
return outVert;
|
||||
}
|
||||
|
||||
// Since there is one, use the intersect point by default
|
||||
pos = interPt;
|
||||
|
||||
// We'll need the corner on the opposite side for several things.
|
||||
const float2 realOtherEdge = -interSgn * w2 * screenScale;
|
||||
const float2 otherCorner = offsetCenter + centers[2].norm * realOtherEdge;
|
||||
|
||||
// For a bevel, use the intersect point for the inside of the turn, but not the outside.
|
||||
// Round piggypacks on bevel.
|
||||
if (joinType == WKSVertexLineJoinBevel || joinType == WKSVertexLineJoinRound) {
|
||||
switch (whichVert) {
|
||||
// Start cap, 0-3-1, 0-2-3
|
||||
case 2: case 10:
|
||||
discardTri = true; // Not using triangle #2
|
||||
break;
|
||||
// Merge inside corners to avoid overlap, use default outside corner.
|
||||
case 0: case 3: case 8: case 9:
|
||||
case 4: case 5: case 6: case 7:
|
||||
pos = isInsideEdge ? interPt : corner;
|
||||
break;
|
||||
case 1: case 11: {
|
||||
// Use the point halfway between the outside corner and the one on the opposite side.
|
||||
const float2 norm = centers[(whichVert == 1) ? 1 : 3].norm;
|
||||
const float2 c = offsetCenter + centers[2].norm * realEdge * turnSgn;
|
||||
const float2 e = turnSgn * interSgn * w2 * screenScale;
|
||||
pos = (offsetCenter + c + norm * e) / 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// For the round case, extend the center of the bevel out into a "tip," which will be
|
||||
// turned into a round extension by the fragment shader. This isn't exactly right, but
|
||||
// I think we need more geometry to do better.
|
||||
// todo: fix texture Y-coords
|
||||
if (joinType == WKSVertexLineJoinRound && whichPoly != WideVecPolyBodyGeom && !discardTri) {
|
||||
outVert.roundJoin = true;
|
||||
outVert.centerPos = offsetCenter / screenScale;
|
||||
outVert.screenPos = pos / screenScale;
|
||||
|
||||
// Direction bisecting the turn toward the outside (right for a left turn)
|
||||
const float2 mid = isEnd ? (centers[2].nDir - centers[3].nDir) :
|
||||
(centers[1].nDir - centers[2].nDir);
|
||||
outVert.midDir = normalize(mid / screenScale);
|
||||
|
||||
if (whichVert == 1 || whichVert == 11) {
|
||||
// Extend the corner far enough to cover the necessary round-ness.
|
||||
// This should probably be related to the turn angle, we're just fudging it.
|
||||
const float extend = 2 * w2;
|
||||
pos += outVert.midDir * extend * screenScale;
|
||||
outVert.screenPos = pos / screenScale;
|
||||
}
|
||||
}
|
||||
} else if (joinType == WKSVertexLineJoinMiterClip) {
|
||||
// Direction of intersect point (bisecting the segment directions)
|
||||
const float2 interVec = (realInterPt - offsetCenter) / screenScale;
|
||||
const float2 interDir = normalize(interVec) * turnSgn * interSgn;
|
||||
// And the perpendicular
|
||||
const float2 interNorm = float2(-interDir.y, interDir.x);
|
||||
// Distance from centerline intersect and edge intersect
|
||||
const float interDist = length(interVec);
|
||||
// "the miter is clipped by a line perpendicular to the line bisecting
|
||||
// the angle between the two path segments at a distance of half the
|
||||
// value of miter length from the intersection of the two path segments."
|
||||
const float midExt = miterLength / 2 * strokeWidth + wideVec.edge;
|
||||
|
||||
switch (whichVert) {
|
||||
// Start cap, 0-3-1, 0-2-3
|
||||
case 0: case 8: {
|
||||
// Out to the miter cap, then perpendicular to the line edge.
|
||||
// The half-width of the clipped miter cap is the tangent of half the interior
|
||||
// turn angle times the amount the original intersection extends beyond the cap.
|
||||
const float miterEdgeW2 = (interDist - midExt) * tan(theta / 2);
|
||||
pos = offsetCenter + screenScale * (interDir * midExt -
|
||||
interNorm * miterEdgeW2 * turnSgn * (whichVert ? -1 : 1));
|
||||
break;
|
||||
}
|
||||
case 1: case 10:
|
||||
// Extend the turn bisector to the miter clip edge
|
||||
pos = turningLeft ? (offsetCenter + interDir * midExt * screenScale) :
|
||||
((whichVert == 1) ? corner : otherCorner);
|
||||
break;
|
||||
case 2: case 9:
|
||||
// Extend segment endpoint outward along the intersection angle by the miter length
|
||||
pos = turningLeft ? ((whichVert == 2) ? corner : otherCorner) :
|
||||
(offsetCenter + interDir * midExt * screenScale);
|
||||
break;
|
||||
case 3: case 11:
|
||||
// The edge intersect, or the one on the other side
|
||||
pos = turningLeft ? interPt : (offsetCenter + (offsetCenter - interPt));
|
||||
break;
|
||||
// Body segment, 4-7-5, 4-6-7
|
||||
// Merge inside corners to avoid overlap, use default outside corner.
|
||||
case 4: case 5: case 6: case 7:
|
||||
pos = isInsideEdge ? interPt : corner;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!discardTri) {
|
||||
outVert.position = float4(pos, 0, 1);
|
||||
}
|
||||
|
||||
return outVert;
|
||||
}
|
||||
|
||||
// Fragment shader that takes the back of the globe into account
|
||||
fragment float4 fragmentTri_wideVecPerf(
|
||||
ProjVertexTriWideVecPerf vert [[stage_in]],
|
||||
constant Uniforms &uniforms [[ buffer(3) ]])
|
||||
{
|
||||
float patternAlpha = 1.0;
|
||||
|
||||
// Reduce alpha of the "tip" for round joins to get a round look.
|
||||
float roundAlpha = 1.0;
|
||||
if (vert.roundJoin && dot(vert.screenPos - vert.centerPos, vert.midDir) > 0) {
|
||||
const float r = length_squared(vert.screenPos - vert.centerPos) / vert.w2 / vert.w2;
|
||||
roundAlpha = clamp((r > 0.95) ? (1 - r) * 20 : 1.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
// Reduce alpha along the edges to get smooth blending.
|
||||
const float edgeAlpha = (vert.edge > 0) ? clamp((1 - abs(vert.texCoord.x)) * vert.w2 / vert.edge, 0.0, 1.0) : 1.0;
|
||||
|
||||
return vert.color * float4(1,1,1,edgeAlpha * patternAlpha * roundAlpha);
|
||||
}
|
||||
|
||||
)";
|
||||
};
|
||||
|
||||
} // namespace shaders
|
||||
} // namespace mbgl
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <mbgl/shaders/line_layer_ubo.hpp>
|
||||
#include <mbgl/shaders/raster_layer_ubo.hpp>
|
||||
#include <mbgl/shaders/symbol_layer_ubo.hpp>
|
||||
#include <mbgl/shaders/widevector_ubo.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@@ -47,7 +48,8 @@ static constexpr auto maxUBOCountPerShader = std::max({static_cast<size_t>(backg
|
||||
static_cast<size_t>(lineSDFUBOCount),
|
||||
static_cast<size_t>(lineBasicUBOCount),
|
||||
static_cast<size_t>(rasterUBOCount),
|
||||
static_cast<size_t>(symbolUBOCount)});
|
||||
static_cast<size_t>(symbolUBOCount),
|
||||
static_cast<size_t>(wideVectorUBOCount)});
|
||||
|
||||
// Texture defines
|
||||
enum {
|
||||
@@ -259,20 +261,40 @@ enum {
|
||||
symbolVertexAttributeCount
|
||||
};
|
||||
|
||||
static constexpr auto maxVertexAttributeCountPerShader = std::max(
|
||||
{static_cast<size_t>(backgroundVertexAttributeCount),
|
||||
static_cast<size_t>(circleVertexAttributeCount),
|
||||
static_cast<size_t>(clippingMaskVertexAttributeCount),
|
||||
static_cast<size_t>(collisionVertexAttributeCount),
|
||||
static_cast<size_t>(customSymbolVertexAttributeCount),
|
||||
static_cast<size_t>(debugVertexAttributeCount),
|
||||
static_cast<size_t>(fillVertexAttributeCount),
|
||||
static_cast<size_t>(fillExtrusionVertexAttributeCount),
|
||||
static_cast<size_t>(heatmapVertexAttributeCount),
|
||||
static_cast<size_t>(hillshadeVertexAttributeCount),
|
||||
static_cast<size_t>(lineVertexAttributeCount),
|
||||
static_cast<size_t>(rasterVertexAttributeCount),
|
||||
static_cast<size_t>(symbolVertexAttributeCount)});
|
||||
enum {
|
||||
idWideVectorScreenPos,
|
||||
idWideVectorColor,
|
||||
idWideVectorIndex,
|
||||
|
||||
wideVectorAttributeCount
|
||||
};
|
||||
|
||||
enum {
|
||||
idWideVectorInstanceCenter,
|
||||
idWideVectorInstanceColor,
|
||||
idWideVectorInstancePrevious,
|
||||
idWideVectorInstanceNext,
|
||||
|
||||
wideVectorInstanceAttributeCount
|
||||
};
|
||||
|
||||
static constexpr auto maxVertexAttributeCountPerShader = std::max({
|
||||
static_cast<size_t>(backgroundVertexAttributeCount),
|
||||
static_cast<size_t>(circleVertexAttributeCount),
|
||||
static_cast<size_t>(clippingMaskVertexAttributeCount),
|
||||
static_cast<size_t>(collisionVertexAttributeCount),
|
||||
static_cast<size_t>(customSymbolVertexAttributeCount),
|
||||
static_cast<size_t>(debugVertexAttributeCount),
|
||||
static_cast<size_t>(fillVertexAttributeCount),
|
||||
static_cast<size_t>(fillExtrusionVertexAttributeCount),
|
||||
static_cast<size_t>(heatmapVertexAttributeCount),
|
||||
static_cast<size_t>(hillshadeVertexAttributeCount),
|
||||
static_cast<size_t>(lineVertexAttributeCount),
|
||||
static_cast<size_t>(rasterVertexAttributeCount),
|
||||
static_cast<size_t>(symbolVertexAttributeCount),
|
||||
static_cast<size_t>(wideVectorAttributeCount),
|
||||
static_cast<size_t>(wideVectorInstanceAttributeCount),
|
||||
});
|
||||
|
||||
} // namespace shaders
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <mbgl/shaders/gl/drawable_symbol_sdf.hpp>
|
||||
#include <mbgl/shaders/gl/drawable_symbol_text_and_icon.hpp>
|
||||
#include <mbgl/shaders/gl/drawable_custom_symbol_icon.hpp>
|
||||
#include <mbgl/shaders/gl/drawable_wide_vector.hpp>
|
||||
#include <mbgl/shaders/gl/prelude.hpp>
|
||||
#include <mbgl/shaders/gl/background.hpp>
|
||||
#include <mbgl/shaders/gl/background_pattern.hpp>
|
||||
|
||||
@@ -40,6 +40,9 @@ public:
|
||||
/// Get the available vertex attributes and their default values
|
||||
virtual const gfx::VertexAttributeArray& getVertexAttributes() const = 0;
|
||||
|
||||
/// Get the available instance attributes and their default values
|
||||
virtual const gfx::VertexAttributeArray& getInstanceAttributes() const = 0;
|
||||
|
||||
protected:
|
||||
virtual gfx::UniformBlockArray& mutableUniformBlocks() = 0;
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ enum class BuiltIn {
|
||||
SymbolSDFIconShader,
|
||||
SymbolTextAndIconShader,
|
||||
CustomSymbolIconShader,
|
||||
WideVectorShader,
|
||||
Prelude,
|
||||
BackgroundProgram,
|
||||
BackgroundPatternProgram,
|
||||
|
||||
58
include/mbgl/shaders/widevector_ubo.hpp
Normal file
58
include/mbgl/shaders/widevector_ubo.hpp
Normal file
@@ -0,0 +1,58 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/shaders/layer_ubo.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace shaders {
|
||||
|
||||
struct alignas(16) WideVectorUniformsUBO {
|
||||
std::array<float, 4 * 4> mvpMatrix;
|
||||
std::array<float, 4 * 4> mvpMatrixDiff;
|
||||
std::array<float, 4 * 4> mvMatrix;
|
||||
std::array<float, 4 * 4> mvMatrixDiff;
|
||||
std::array<float, 4 * 4> pMatrix;
|
||||
std::array<float, 4 * 4> pMatrixDiff;
|
||||
std::array<float, 2> frameSize;
|
||||
};
|
||||
static_assert(sizeof(WideVectorUniformsUBO) % 16 == 0);
|
||||
|
||||
struct alignas(16) WideVectorUniformWideVecUBO {
|
||||
std::array<float, 4> color;
|
||||
float w2;
|
||||
float offset;
|
||||
float edge;
|
||||
float texRepeat;
|
||||
std::array<float, 2> texOffset;
|
||||
float miterLimit;
|
||||
int32_t join;
|
||||
int32_t cap;
|
||||
int32_t hasExp;
|
||||
float interClipLimit;
|
||||
};
|
||||
static_assert(sizeof(WideVectorUniformWideVecUBO) % 16 == 0);
|
||||
|
||||
enum {
|
||||
idWideVectorUniformsUBO,
|
||||
idWideVectorUniformWideVecUBO,
|
||||
wideVectorUBOCount
|
||||
};
|
||||
|
||||
struct VertexTriWideVecB {
|
||||
// x, y offset around the center
|
||||
std::array<float, 3> screenPos;
|
||||
std::array<float, 4> color;
|
||||
int index;
|
||||
};
|
||||
static_assert(sizeof(VertexTriWideVecB) == 32);
|
||||
|
||||
struct VertexTriWideVecInstance {
|
||||
std::array<float, 4> center;
|
||||
std::array<float, 4> color;
|
||||
int32_t prev;
|
||||
int32_t next;
|
||||
int64_t pad_;
|
||||
};
|
||||
static_assert(sizeof(VertexTriWideVecInstance) == 48);
|
||||
|
||||
} // namespace shaders
|
||||
} // namespace mbgl
|
||||
@@ -33,14 +33,20 @@ public:
|
||||
|
||||
class CustomDrawableLayerHost::Interface {
|
||||
public:
|
||||
enum class LineShaderType {
|
||||
Classic,
|
||||
MetalWideVector
|
||||
};
|
||||
|
||||
struct LineOptions {
|
||||
Color color;
|
||||
gfx::PolylineGeneratorOptions geometry;
|
||||
float blur = 0.f;
|
||||
float opacity = 1.f;
|
||||
float gapWidth = 0.f;
|
||||
float offset = 0.f;
|
||||
float width = 1.f;
|
||||
gfx::PolylineGeneratorOptions geometry;
|
||||
LineShaderType shaderType = LineShaderType::Classic;
|
||||
Color color;
|
||||
};
|
||||
|
||||
struct FillOptions {
|
||||
@@ -106,24 +112,34 @@ public:
|
||||
/**
|
||||
* @brief Add a polyline
|
||||
*
|
||||
* @param coordinates
|
||||
* @param options Polyline options
|
||||
* @param coordinates in tile range
|
||||
* @return true if the polyline was added
|
||||
*/
|
||||
void addPolyline(const GeometryCoordinates& coordinates);
|
||||
bool addPolyline(const GeometryCoordinates& coordinates);
|
||||
|
||||
/**
|
||||
* @brief Add a polyline
|
||||
*
|
||||
* @param coordinates Geographic coordinates
|
||||
* @return true if the polyline was added
|
||||
*/
|
||||
bool addPolyline(const LineString<double>& coordinates);
|
||||
|
||||
/**
|
||||
* @brief Add a multipolygon area fill
|
||||
*
|
||||
* @param geometry a collection of rings with optional holes
|
||||
* @return true if the fill was added
|
||||
*/
|
||||
void addFill(const GeometryCollection& geometry);
|
||||
bool addFill(const GeometryCollection& geometry);
|
||||
|
||||
/**
|
||||
* @brief Add a symbol
|
||||
*
|
||||
* @param point
|
||||
* @return true if the symbol was added
|
||||
*/
|
||||
void addSymbol(const GeometryCoordinate& point);
|
||||
bool addSymbol(const GeometryCoordinate& point);
|
||||
|
||||
/**
|
||||
* @brief Finish the current drawable building session
|
||||
@@ -143,10 +159,20 @@ public:
|
||||
|
||||
private:
|
||||
gfx::ShaderPtr lineShaderDefault() const;
|
||||
gfx::ShaderPtr lineShaderWideVector() const;
|
||||
gfx::ShaderPtr fillShaderDefault() const;
|
||||
gfx::ShaderPtr symbolShaderDefault() const;
|
||||
|
||||
enum class BuilderType {
|
||||
None,
|
||||
LineClassic,
|
||||
LineWideVector,
|
||||
Fill,
|
||||
Symbol
|
||||
};
|
||||
|
||||
std::unique_ptr<gfx::DrawableBuilder> createBuilder(const std::string& name, gfx::ShaderPtr shader) const;
|
||||
bool updateBuilder(BuilderType type, const std::string& name, gfx::ShaderPtr shader);
|
||||
|
||||
std::unique_ptr<gfx::DrawableBuilder> builder;
|
||||
std::optional<OverscaledTileID> tileID;
|
||||
@@ -158,6 +184,8 @@ private:
|
||||
LineOptions lineOptions;
|
||||
FillOptions fillOptions;
|
||||
SymbolOptions symbolOptions;
|
||||
|
||||
BuilderType builderType{BuilderType::None};
|
||||
};
|
||||
|
||||
class CustomDrawableLayer final : public Layer {
|
||||
|
||||
@@ -43,6 +43,7 @@ public:
|
||||
static std::optional<Color> parse(const std::string&);
|
||||
std::string stringify() const;
|
||||
std::array<double, 4> toArray() const;
|
||||
operator std::array<float, 4>() const { return {r, g, b, a}; }
|
||||
mbgl::Value toObject() const;
|
||||
mbgl::Value serialize() const;
|
||||
};
|
||||
|
||||
@@ -47,30 +47,31 @@ public:
|
||||
if (interface.getDrawableCount())
|
||||
return;
|
||||
|
||||
// set tile
|
||||
interface.setTileID({11, 327, 791});
|
||||
constexpr float extent = mbgl::util::EXTENT;
|
||||
|
||||
// add polylines
|
||||
// add classic polylines
|
||||
{
|
||||
using namespace mbgl;
|
||||
|
||||
// set tile
|
||||
interface.setTileID({11, 327, 792});
|
||||
|
||||
constexpr auto numLines = 6;
|
||||
Interface::LineOptions options[numLines] {
|
||||
{/*color=*/Color::red(), /*blur=*/0.0f, /*opacity=*/1.0f, /*gapWidth=*/0.0f, /*offset=*/0.0f, /*width=*/8.0f, {} },
|
||||
{/*color=*/Color::blue(), /*blur=*/4.0f, /*opacity=*/1.0f, /*gapWidth=*/2.0f, /*offset=*/-1.0f, /*width=*/4.0f, {} },
|
||||
{/*color=*/Color(1.f, 0.5f, 0, 0.5f), /*blur=*/16.0f, /*opacity=*/1.0f, /*gapWidth=*/1.0f, /*offset=*/2.0f, /*width=*/16.0f, {} },
|
||||
{/*color=*/Color(1.f, 1.f, 0, 0.3f), /*blur=*/2.0f, /*opacity=*/1.0f, /*gapWidth=*/1.0f, /*offset=*/-2.0f, /*width=*/2.0f, {} },
|
||||
{/*color=*/Color::black(), /*blur=*/0.5f, /*opacity=*/0.5f, /*gapWidth=*/1.0f, /*offset=*/0.5f, /*width=*/0.5f, {} },
|
||||
{/*color=*/Color(1.f, 0, 1.f, 0.2f), /*blur=*/24.0f, /*opacity=*/0.5f, /*gapWidth=*/1.0f, /*offset=*/-5.0f, /*width=*/24.0f, {} },
|
||||
{/*geometry=*/{}, /*blur=*/0.0f, /*opacity=*/1.0f, /*gapWidth=*/0.0f, /*offset=*/0.0f, /*width=*/8.0f, /*shaderType=*/{}, /*color=*/Color::red() },
|
||||
{/*geometry=*/{}, /*blur=*/4.0f, /*opacity=*/1.0f, /*gapWidth=*/2.0f, /*offset=*/-1.0f, /*width=*/4.0f, /*shaderType=*/{}, /*color=*/Color::blue() },
|
||||
{/*geometry=*/{}, /*blur=*/16.0f, /*opacity=*/1.0f, /*gapWidth=*/1.0f, /*offset=*/2.0f, /*width=*/16.0f, /*shaderType=*/{}, /*color=*/Color(1.f, 0.5f, 0, 0.5f) },
|
||||
{/*geometry=*/{}, /*blur=*/2.0f, /*opacity=*/1.0f, /*gapWidth=*/1.0f, /*offset=*/-2.0f, /*width=*/2.0f, /*shaderType=*/{}, /*color=*/Color(1.f, 1.f, 0, 0.3f) },
|
||||
{/*geometry=*/{}, /*blur=*/0.5f, /*opacity=*/0.5f, /*gapWidth=*/1.0f, /*offset=*/0.5f, /*width=*/0.5f, /*shaderType=*/{}, /*color=*/Color::black() },
|
||||
{/*geometry=*/{}, /*blur=*/24.0f, /*opacity=*/0.5f, /*gapWidth=*/1.0f, /*offset=*/-5.0f, /*width=*/24.0f, /*shaderType=*/{}, /*color=*/Color(1.f, 0, 1.f, 0.2f) },
|
||||
};
|
||||
for(auto& opt: options) {
|
||||
opt.geometry.beginCap = style::LineCapType::Round;
|
||||
opt.geometry.endCap = style::LineCapType::Round;
|
||||
opt.geometry.joinType = style::LineJoinType::Round;
|
||||
opt.geometry.beginCap = style::LineCapType::Butt;
|
||||
opt.geometry.endCap = style::LineCapType::Butt;
|
||||
opt.geometry.joinType = style::LineJoinType::Miter;
|
||||
}
|
||||
|
||||
constexpr auto numPoints = 100;
|
||||
constexpr auto numPoints = 10;
|
||||
GeometryCoordinates polyline;
|
||||
for (auto ipoint{0}; ipoint < numPoints; ++ipoint) {
|
||||
polyline.emplace_back(ipoint * extent / numPoints, std::sin(ipoint * 2 * M_PI / numPoints) * extent / numLines / 2.f);
|
||||
@@ -89,10 +90,64 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// add wide vector polylines with tile coordinates
|
||||
{
|
||||
using namespace mbgl;
|
||||
|
||||
// set tile
|
||||
interface.setTileID({11, 327, 792});
|
||||
|
||||
constexpr auto numLines = 6;
|
||||
Interface::LineOptions options[numLines] {
|
||||
{/*geometry=*/{}, /*blur=*/0.0f, /*opacity=*/1.0f, /*gapWidth=*/0.0f, /*offset=*/0.0f, /*width=*/8.0f, /*shaderType=*/Interface::LineShaderType::MetalWideVector, /*color=*/Color::red() },
|
||||
{/*geometry=*/{}, /*blur=*/4.0f, /*opacity=*/1.0f, /*gapWidth=*/2.0f, /*offset=*/-1.0f, /*width=*/4.0f, /*shaderType=*/Interface::LineShaderType::MetalWideVector, /*color=*/Color::blue() },
|
||||
{/*geometry=*/{}, /*blur=*/16.0f, /*opacity=*/1.0f, /*gapWidth=*/1.0f, /*offset=*/2.0f, /*width=*/16.0f, /*shaderType=*/Interface::LineShaderType::MetalWideVector, /*color=*/Color(1.f, 0.5f, 0, 0.5f) },
|
||||
{/*geometry=*/{}, /*blur=*/2.0f, /*opacity=*/1.0f, /*gapWidth=*/1.0f, /*offset=*/-2.0f, /*width=*/2.0f, /*shaderType=*/Interface::LineShaderType::MetalWideVector, /*color=*/Color(1.f, 1.f, 0, 0.3f) },
|
||||
{/*geometry=*/{}, /*blur=*/0.5f, /*opacity=*/0.5f, /*gapWidth=*/1.0f, /*offset=*/0.5f, /*width=*/0.5f, /*shaderType=*/Interface::LineShaderType::MetalWideVector, /*color=*/Color::black() },
|
||||
{/*geometry=*/{}, /*blur=*/24.0f, /*opacity=*/0.5f, /*gapWidth=*/1.0f, /*offset=*/-5.0f, /*width=*/24.0f, /*shaderType=*/Interface::LineShaderType::MetalWideVector, /*color=*/Color(1.f, 0, 1.f, 0.2f) },
|
||||
};
|
||||
for(auto& opt: options) {
|
||||
opt.geometry.beginCap = style::LineCapType::Butt;
|
||||
opt.geometry.endCap = style::LineCapType::Butt;
|
||||
opt.geometry.joinType = style::LineJoinType::Miter;
|
||||
}
|
||||
|
||||
constexpr auto numPoints = 10;
|
||||
GeometryCoordinates polyline;
|
||||
for (auto ipoint{0}; ipoint < numPoints; ++ipoint) {
|
||||
polyline.emplace_back(ipoint * extent / numPoints, std::sin(ipoint * 2 * M_PI / numPoints) * extent / numLines / 2.f);
|
||||
}
|
||||
|
||||
for (auto index {0}; index < numLines; ++index) {
|
||||
for(auto &p : polyline) {
|
||||
if (0 == index) p.y += 0.25f * extent / numLines;
|
||||
p.y += extent / numLines;
|
||||
}
|
||||
|
||||
// set property values
|
||||
interface.setLineOptions(options[index]);
|
||||
|
||||
// add polyline
|
||||
interface.addPolyline(polyline);
|
||||
|
||||
// add clone
|
||||
for(auto &p : polyline) {
|
||||
p.y += 0.05f * extent / numLines;
|
||||
}
|
||||
interface.addPolyline(polyline);
|
||||
for(auto &p : polyline) {
|
||||
p.y -= 0.05f * extent / numLines;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add fill polygon
|
||||
{
|
||||
using namespace mbgl;
|
||||
|
||||
// set tile
|
||||
interface.setTileID({11, 327, 790});
|
||||
|
||||
GeometryCollection geometry{
|
||||
{
|
||||
// ring 1
|
||||
@@ -122,6 +177,10 @@ public:
|
||||
// add symbol
|
||||
{
|
||||
using namespace mbgl;
|
||||
|
||||
// set tile
|
||||
interface.setTileID({11, 327, 789});
|
||||
|
||||
GeometryCoordinate position {static_cast<int16_t>(extent* 0.5f), static_cast<int16_t>(extent* 0.5f)};
|
||||
|
||||
// load image
|
||||
@@ -148,7 +207,75 @@ public:
|
||||
// add symbol
|
||||
interface.addSymbol(position);
|
||||
}
|
||||
|
||||
|
||||
// add polylines using wide vectors using geographic coordinates
|
||||
{
|
||||
using namespace mbgl;
|
||||
|
||||
// add polyline with geographic coordinates
|
||||
Interface::LineOptions options = {/*geometry=*/{}, /*blur=*/0.0f, /*opacity=*/1.0f, /*gapWidth=*/0.0f, /*offset=*/0.0f, /*width=*/12.0f, /*shaderType=*/Interface::LineShaderType::MetalWideVector, /*color=*/{.0f, .0f, .0f, .5f} };
|
||||
options.geometry.beginCap = style::LineCapType::Square;
|
||||
options.geometry.endCap = style::LineCapType::Square;
|
||||
options.geometry.joinType = style::LineJoinType::Bevel;
|
||||
options.geometry.type = FeatureType::LineString;
|
||||
interface.setLineOptions(options);
|
||||
|
||||
LineString<double> polyline_geo {
|
||||
// San Francisco
|
||||
{-122.38186800073211, 37.77466003457463},
|
||||
{-122.3869373450997, 37.774352128895615},
|
||||
{-122.38680767979824, 37.773294612880306},
|
||||
{-122.38476465260224, 37.773350946288765},
|
||||
{-122.38146223043374, 37.77194168964067},
|
||||
{-122.6813560305925, 37.666084247570964},
|
||||
{-122.26765538866474, 37.65037232584494},
|
||||
{-122.42528413673159, 38.020443518012584},
|
||||
// Seattle
|
||||
{-122.34927775216809, 47.62050663596438},
|
||||
// New York
|
||||
{-74.04454331829972, 40.6892168305434},
|
||||
};
|
||||
interface.addPolyline(polyline_geo);
|
||||
}
|
||||
|
||||
// add polylines using wide vectors in tile coordinates
|
||||
{
|
||||
using namespace mbgl;
|
||||
|
||||
// set tile
|
||||
interface.setTileID({11, 327, 790});
|
||||
|
||||
Interface::LineOptions options
|
||||
{/*geometry=*/{}, /*blur=*/0.0f, /*opacity=*/1.0f, /*gapWidth=*/0.0f, /*offset=*/0.0f, /*width=*/7.0f, /*shaderType=*/Interface::LineShaderType::MetalWideVector, /*color=*/{1.0f, 0, 0, .5f} };
|
||||
options.geometry.beginCap = style::LineCapType::Round;
|
||||
options.geometry.endCap = style::LineCapType::Round;
|
||||
options.geometry.joinType = style::LineJoinType::Round;
|
||||
|
||||
// add polyline with tile coordinates
|
||||
GeometryCollection polyline_tile{
|
||||
{
|
||||
// ring 1
|
||||
{static_cast<int16_t>(extent* 0.1f), static_cast<int16_t>(extent* 0.2f)},
|
||||
{static_cast<int16_t>(extent* 0.5f), static_cast<int16_t>(extent* 0.5f)},
|
||||
{static_cast<int16_t>(extent* 0.7f), static_cast<int16_t>(extent* 0.5f)},
|
||||
{static_cast<int16_t>(extent* 0.5f), static_cast<int16_t>(extent* 1.0f)},
|
||||
{static_cast<int16_t>(extent* 0.0f), static_cast<int16_t>(extent* 0.5f)},
|
||||
},
|
||||
{
|
||||
// ring 2
|
||||
{static_cast<int16_t>(extent* 0.1f), static_cast<int16_t>(extent* 0.25f)},
|
||||
{static_cast<int16_t>(extent* 0.15f), static_cast<int16_t>(extent* 0.5f)},
|
||||
{static_cast<int16_t>(extent* 0.25f), static_cast<int16_t>(extent* 0.45f)},
|
||||
},
|
||||
};
|
||||
|
||||
options.geometry.type = FeatureType::Polygon;
|
||||
interface.setLineOptions(options);
|
||||
interface.addPolyline(polyline_tile[0]);
|
||||
interface.addPolyline(polyline_tile[1]);
|
||||
|
||||
}
|
||||
|
||||
// finish
|
||||
interface.finish();
|
||||
}
|
||||
|
||||
@@ -247,4 +247,16 @@ class iosapp_UITests: XCTestCase {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Make sure the Custom Drawable Layer does not crash
|
||||
func testCustomDrawableLayer() {
|
||||
app.windows.children(matching: .other).element.children(matching: .other).element.children(matching: .other).element.doubleTap()
|
||||
|
||||
let mapSettingsButton = app.navigationBars["MapLibre Basic"].buttons["Map settings"]
|
||||
mapSettingsButton.tap()
|
||||
|
||||
let tablesQuery = app.tables
|
||||
tablesQuery.staticTexts["Add Custom Drawable Layer"].tap()
|
||||
sleep(5)
|
||||
}
|
||||
}
|
||||
|
||||
0
shaders/_empty.glsl
Normal file
0
shaders/_empty.glsl
Normal file
@@ -181,6 +181,13 @@
|
||||
"glsl_frag": "drawable.custom.symbol_icon.fragment.glsl",
|
||||
"uses_ubos": true
|
||||
},
|
||||
{
|
||||
"name": "WideVectorShader",
|
||||
"header": "drawable_wide_vector",
|
||||
"glsl_vert": "_empty.glsl",
|
||||
"glsl_frag": "_empty.glsl",
|
||||
"uses_ubos": false
|
||||
},
|
||||
|
||||
{
|
||||
"name": "Prelude",
|
||||
|
||||
@@ -44,6 +44,9 @@ void DrawableBuilder::flush(gfx::Context& context) {
|
||||
if (Impl::Mode::Polylines == impl->getMode()) {
|
||||
// setup for polylines
|
||||
impl->setupForPolylines(context, *this);
|
||||
} else if (Impl::Mode::WideVectorLocal == impl->getMode() || Impl::Mode::WideVectorGlobal == impl->getMode()) {
|
||||
// setup for wide vectors
|
||||
impl->setupForWideVectors(context, *this);
|
||||
}
|
||||
|
||||
const auto& draw = getCurrentDrawable(/*createIfNone=*/true);
|
||||
@@ -62,6 +65,7 @@ void DrawableBuilder::flush(gfx::Context& context) {
|
||||
draw->setShader(shader);
|
||||
draw->setTextures(textures);
|
||||
draw->setTweakers(tweakers);
|
||||
draw->setOrigin(origin);
|
||||
|
||||
if (vertexAttrs) {
|
||||
draw->setVertexAttributes(vertexAttrs);
|
||||
@@ -69,10 +73,17 @@ void DrawableBuilder::flush(gfx::Context& context) {
|
||||
draw->setVertexAttributes(context.createVertexAttributeArray());
|
||||
}
|
||||
|
||||
if (instanceAttrs) {
|
||||
draw->setInstanceAttributes(instanceAttrs);
|
||||
}
|
||||
|
||||
init();
|
||||
|
||||
// reset mode
|
||||
impl->setMode(Impl::Mode::Custom);
|
||||
|
||||
// reset origin
|
||||
origin.reset();
|
||||
}
|
||||
if (currentDrawable) {
|
||||
drawables.emplace_back(std::move(currentDrawable));
|
||||
@@ -280,5 +291,23 @@ void DrawableBuilder::addPolyline(const GeometryCoordinates& coordinates,
|
||||
impl->addPolyline(*this, coordinates, options);
|
||||
}
|
||||
|
||||
void DrawableBuilder::addWideVectorPolylineLocal(const GeometryCoordinates& coordinates,
|
||||
const gfx::PolylineGeneratorOptions& options) {
|
||||
// mark the current mode
|
||||
if (!impl->checkAndSetMode(Impl::Mode::WideVectorLocal)) return;
|
||||
|
||||
// append polyline
|
||||
impl->addWideVectorPolylineLocal(*this, coordinates, options);
|
||||
}
|
||||
|
||||
void DrawableBuilder::addWideVectorPolylineGlobal(const LineString<double>& coordinates,
|
||||
const gfx::PolylineGeneratorOptions& options) {
|
||||
// mark the current mode
|
||||
if (!impl->checkAndSetMode(Impl::Mode::WideVectorGlobal)) return;
|
||||
|
||||
// append polyline
|
||||
origin = impl->addWideVectorPolylineGlobal(*this, coordinates, options);
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <mbgl/style/types.hpp>
|
||||
#include <mbgl/util/logging.hpp>
|
||||
#include <mbgl/util/math.hpp>
|
||||
#include <mbgl/util/projection.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
@@ -13,6 +14,8 @@ namespace gfx {
|
||||
|
||||
using namespace shaders;
|
||||
|
||||
// MARK: - Polylines
|
||||
|
||||
DrawableBuilder::Impl::LineLayoutVertex DrawableBuilder::Impl::layoutVertex(
|
||||
Point<int16_t> p, Point<double> e, bool round, bool up, int8_t dir, int32_t linesofar /*= 0*/) {
|
||||
/*
|
||||
@@ -91,6 +94,186 @@ void DrawableBuilder::Impl::setupForPolylines(gfx::Context& context, gfx::Drawab
|
||||
sharedIndexes = std::make_shared<gfx::IndexVectorBase>(std::move(polylineIndexes));
|
||||
}
|
||||
|
||||
// MARK: - Wide Vector Polylines
|
||||
|
||||
namespace {
|
||||
inline void genInstanceLinks(
|
||||
int32_t& outPrev, int32_t& outNext, const int base, const int coord_size, const int index, bool loop) {
|
||||
if (loop) {
|
||||
// loop line
|
||||
outPrev = base + (index - 1 + coord_size) % coord_size;
|
||||
outNext = base + (index + 1) % coord_size;
|
||||
} else {
|
||||
// line string
|
||||
outPrev = (0 == index) ? -1 : base + index - 1;
|
||||
outNext = (index + 1 >= coord_size) ? -1 : base + index + 1;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void DrawableBuilder::Impl::addWideVectorPolylineLocal(gfx::DrawableBuilder& /*builder*/,
|
||||
const GeometryCoordinates& coordinates,
|
||||
const gfx::PolylineGeneratorOptions& options) {
|
||||
// add instance data
|
||||
const int base = static_cast<int>(wideVectorInstanceData.elements());
|
||||
const int coord_size = static_cast<int>(coordinates.size());
|
||||
int index = 0;
|
||||
for (const auto& coord : coordinates) {
|
||||
VertexTriWideVecInstance data;
|
||||
data.center = {static_cast<float>(coord.x), static_cast<float>(coord.y), 0};
|
||||
genInstanceLinks(data.prev, data.next, base, coord_size, index, FeatureType::Polygon == options.type);
|
||||
wideVectorInstanceData.emplace_back(std::move(data));
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
mbgl::Point<double> DrawableBuilder::Impl::addWideVectorPolylineGlobal(gfx::DrawableBuilder& /*builder*/,
|
||||
const LineString<double>& coordinates,
|
||||
const gfx::PolylineGeneratorOptions& options) {
|
||||
constexpr int32_t zoom = 0;
|
||||
|
||||
// get center
|
||||
constexpr double maxd = std::numeric_limits<double>::max();
|
||||
constexpr double mind = std::numeric_limits<double>::min();
|
||||
Point<double> minPoint{maxd, maxd}, maxPoint{mind, mind};
|
||||
for (const auto& coord : coordinates) {
|
||||
auto merc = Projection::project(LatLng(coord.y, coord.x), zoom);
|
||||
Point<double> pSource{merc.x * mbgl::util::EXTENT, merc.y * mbgl::util::EXTENT};
|
||||
minPoint.x = std::min(pSource.x, minPoint.x);
|
||||
minPoint.y = std::min(pSource.y, minPoint.y);
|
||||
maxPoint.x = std::max(pSource.x, maxPoint.x);
|
||||
maxPoint.y = std::max(pSource.y, maxPoint.y);
|
||||
}
|
||||
Point<double> pCenter{(minPoint.x + maxPoint.x) / 2.0, (minPoint.y + maxPoint.y) / 2.0};
|
||||
|
||||
// add centerline instance data
|
||||
const int base = static_cast<int>(wideVectorInstanceData.elements());
|
||||
const int coord_size = static_cast<int>(coordinates.size());
|
||||
int index = 0;
|
||||
for (const auto& coord : coordinates) {
|
||||
auto merc = Projection::project(LatLng(coord.y, coord.x), zoom);
|
||||
Point<double> pSource{merc.x * mbgl::util::EXTENT, merc.y * mbgl::util::EXTENT};
|
||||
pSource.x -= pCenter.x;
|
||||
pSource.y -= pCenter.y;
|
||||
VertexTriWideVecInstance data;
|
||||
data.center = {static_cast<float>(pSource.x), static_cast<float>(pSource.y), 0};
|
||||
genInstanceLinks(data.prev, data.next, base, coord_size, index, FeatureType::Polygon == options.type);
|
||||
wideVectorInstanceData.emplace_back(std::move(data));
|
||||
++index;
|
||||
}
|
||||
|
||||
return pCenter;
|
||||
}
|
||||
|
||||
void DrawableBuilder::Impl::setupForWideVectors(gfx::Context& context, gfx::DrawableBuilder& builder) {
|
||||
// vertices
|
||||
if (!wideVectorVertices) {
|
||||
constexpr shaders::VertexTriWideVecB kWideVectorVertices[]{
|
||||
{{0}, {0}, (0 << 16) + 0},
|
||||
{{0}, {0}, (1 << 16) + 0},
|
||||
{{0}, {0}, (2 << 16) + 0},
|
||||
{{0}, {0}, (3 << 16) + 0},
|
||||
|
||||
{{0}, {0}, (4 << 16) + 1},
|
||||
{{0}, {0}, (5 << 16) + 1},
|
||||
{{0}, {0}, (6 << 16) + 1},
|
||||
{{0}, {0}, (7 << 16) + 1},
|
||||
|
||||
{{0}, {0}, (8 << 16) + 2},
|
||||
{{0}, {0}, (9 << 16) + 2},
|
||||
{{0}, {0}, (10 << 16) + 2},
|
||||
{{0}, {0}, (11 << 16) + 2},
|
||||
};
|
||||
wideVectorVertices = std::make_shared<gfx::VertexVector<shaders::VertexTriWideVecB>>();
|
||||
for (auto& v : kWideVectorVertices) {
|
||||
wideVectorVertices->emplace_back(v);
|
||||
}
|
||||
}
|
||||
|
||||
// instance data
|
||||
using InstanceVector = gfx::VertexVector<VertexTriWideVecInstance>;
|
||||
const std::shared_ptr<InstanceVector> sharedInstanceData = std::make_shared<InstanceVector>(
|
||||
std::move(wideVectorInstanceData));
|
||||
|
||||
// indexes
|
||||
if (!wideVectorIndexes) {
|
||||
wideVectorIndexes = std::make_shared<gfx::IndexVector<gfx::Triangles>>();
|
||||
wideVectorIndexes->emplace_back(
|
||||
0, 3, 1, 0, 2, 3, 4 + 0, 4 + 3, 4 + 1, 4 + 0, 4 + 2, 4 + 3, 8 + 0, 8 + 3, 8 + 1, 8 + 0, 8 + 2, 8 + 3);
|
||||
}
|
||||
|
||||
// segments
|
||||
SegmentVector<VertexTriWideVecB> triangleSegments;
|
||||
triangleSegments.emplace_back(Segment<VertexTriWideVecB>{0, 0, 12, 18});
|
||||
|
||||
// add to builder
|
||||
{
|
||||
// add vertex attributes
|
||||
auto vertexAttributes = context.createVertexAttributeArray();
|
||||
if (const auto& attr = vertexAttributes->set(idWideVectorScreenPos)) {
|
||||
attr->setSharedRawData(wideVectorVertices,
|
||||
offsetof(VertexTriWideVecB, screenPos),
|
||||
/*vertexOffset=*/0,
|
||||
sizeof(VertexTriWideVecB),
|
||||
gfx::AttributeDataType::Float3);
|
||||
}
|
||||
if (const auto& attr = vertexAttributes->set(idWideVectorColor)) {
|
||||
attr->setSharedRawData(wideVectorVertices,
|
||||
offsetof(VertexTriWideVecB, color),
|
||||
/*vertexOffset=*/0,
|
||||
sizeof(VertexTriWideVecB),
|
||||
gfx::AttributeDataType::Float4);
|
||||
}
|
||||
if (const auto& attr = vertexAttributes->set(idWideVectorIndex)) {
|
||||
attr->setSharedRawData(wideVectorVertices,
|
||||
offsetof(VertexTriWideVecB, index),
|
||||
/*vertexOffset=*/0,
|
||||
sizeof(VertexTriWideVecB),
|
||||
gfx::AttributeDataType::Int);
|
||||
}
|
||||
builder.setVertexAttributes(std::move(vertexAttributes));
|
||||
}
|
||||
|
||||
{
|
||||
// add instance attributes
|
||||
auto instanceAttributes = context.createVertexAttributeArray();
|
||||
if (const auto& attr = instanceAttributes->set(idWideVectorInstanceCenter)) {
|
||||
attr->setSharedRawData(sharedInstanceData,
|
||||
offsetof(VertexTriWideVecInstance, center),
|
||||
/*vertexOffset=*/0,
|
||||
sizeof(VertexTriWideVecInstance),
|
||||
gfx::AttributeDataType::Float3);
|
||||
}
|
||||
if (const auto& attr = instanceAttributes->set(idWideVectorInstanceColor)) {
|
||||
attr->setSharedRawData(sharedInstanceData,
|
||||
offsetof(VertexTriWideVecInstance, color),
|
||||
/*vertexOffset=*/0,
|
||||
sizeof(VertexTriWideVecInstance),
|
||||
gfx::AttributeDataType::Float4);
|
||||
}
|
||||
if (const auto& attr = instanceAttributes->set(idWideVectorInstancePrevious)) {
|
||||
attr->setSharedRawData(sharedInstanceData,
|
||||
offsetof(VertexTriWideVecInstance, prev),
|
||||
/*vertexOffset=*/0,
|
||||
sizeof(VertexTriWideVecInstance),
|
||||
gfx::AttributeDataType::Int);
|
||||
}
|
||||
if (const auto& attr = instanceAttributes->set(idWideVectorInstanceNext)) {
|
||||
attr->setSharedRawData(sharedInstanceData,
|
||||
offsetof(VertexTriWideVecInstance, next),
|
||||
/*vertexOffset=*/0,
|
||||
sizeof(VertexTriWideVecInstance),
|
||||
gfx::AttributeDataType::Int);
|
||||
}
|
||||
builder.setInstanceAttributes(std::move(instanceAttributes));
|
||||
}
|
||||
|
||||
builder.setRawVertices({}, wideVectorVertices->elements(), gfx::AttributeDataType::Float2);
|
||||
builder.setSegments(gfx::Triangles(), wideVectorIndexes, triangleSegments.data(), triangleSegments.size());
|
||||
}
|
||||
|
||||
// MARK: - Common
|
||||
|
||||
bool DrawableBuilder::Impl::checkAndSetMode(Mode target) {
|
||||
if (target != mode && vertexCount()) {
|
||||
// log error
|
||||
@@ -101,6 +284,10 @@ bool DrawableBuilder::Impl::checkAndSetMode(Mode target) {
|
||||
return "Mode::Primitives";
|
||||
case Mode::Polylines:
|
||||
return "Mode::Polylines";
|
||||
case Mode::WideVectorLocal:
|
||||
return "Mode::WideVectorLocal";
|
||||
case Mode::WideVectorGlobal:
|
||||
return "Mode::WideVectorGlobal";
|
||||
case Mode::Custom:
|
||||
return "Mode::Custom";
|
||||
default:
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <mbgl/programs/segment.hpp>
|
||||
#include <mbgl/gfx/drawable_builder.hpp>
|
||||
#include <mbgl/gfx/polyline_generator.hpp>
|
||||
#include <mbgl/shaders/widevector_ubo.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
@@ -21,9 +22,11 @@ class DrawableBuilder::Impl {
|
||||
public:
|
||||
using VT = gfx::detail::VertexType<gfx::AttributeType<std::int16_t, 2>>;
|
||||
enum class Mode {
|
||||
Primitives, ///< building primitive drawables. Not implemented
|
||||
Polylines, ///< building drawables for thick polylines
|
||||
Custom ///< building custom drawables.
|
||||
Primitives, ///< building primitive drawables. Not implemented
|
||||
Polylines, ///< building drawables for thick polylines
|
||||
WideVectorLocal, ///< building drawables for thick polylines using wide vectors in local coordinates
|
||||
WideVectorGlobal, ///< building drawables for thick polylines using wide vectors in global coordinates
|
||||
Custom ///< building custom drawables.
|
||||
};
|
||||
struct LineLayoutVertex {
|
||||
std::array<int16_t, 2> a1;
|
||||
@@ -39,6 +42,10 @@ public:
|
||||
gfx::VertexVector<LineLayoutVertex> polylineVertices;
|
||||
gfx::IndexVector<gfx::Triangles> polylineIndexes;
|
||||
|
||||
std::shared_ptr<gfx::VertexVector<shaders::VertexTriWideVecB>> wideVectorVertices;
|
||||
gfx::VertexVector<shaders::VertexTriWideVecInstance> wideVectorInstanceData;
|
||||
std::shared_ptr<gfx::IndexVector<gfx::Triangles>> wideVectorIndexes;
|
||||
|
||||
std::vector<uint16_t> buildIndexes;
|
||||
std::shared_ptr<gfx::IndexVectorBase> sharedIndexes;
|
||||
std::vector<std::unique_ptr<Drawable::DrawSegment>> segments;
|
||||
@@ -47,12 +54,23 @@ public:
|
||||
gfx::ColorMode colorMode = gfx::ColorMode::disabled();
|
||||
gfx::CullFaceMode cullFaceMode = gfx::CullFaceMode::disabled();
|
||||
|
||||
// methods
|
||||
void addPolyline(gfx::DrawableBuilder& builder,
|
||||
const GeometryCoordinates& coordinates,
|
||||
const gfx::PolylineGeneratorOptions& options);
|
||||
|
||||
void setupForPolylines(gfx::Context&, gfx::DrawableBuilder&);
|
||||
|
||||
void addWideVectorPolylineLocal(gfx::DrawableBuilder& builder,
|
||||
const GeometryCoordinates& coordinates,
|
||||
const gfx::PolylineGeneratorOptions& options);
|
||||
|
||||
mbgl::Point<double> addWideVectorPolylineGlobal(gfx::DrawableBuilder& builder,
|
||||
const LineString<double>& coordinates,
|
||||
const gfx::PolylineGeneratorOptions& options);
|
||||
|
||||
void setupForWideVectors(gfx::Context&, gfx::DrawableBuilder&);
|
||||
|
||||
bool checkAndSetMode(Mode);
|
||||
|
||||
Mode getMode() const { return mode; };
|
||||
@@ -60,7 +78,8 @@ public:
|
||||
bool setMode(Mode value) { return mode == value; };
|
||||
|
||||
std::size_t vertexCount() const {
|
||||
return std::max(rawVerticesCount, std::max(vertices.elements(), polylineVertices.elements()));
|
||||
return std::max(
|
||||
{rawVerticesCount, vertices.elements(), polylineVertices.elements(), wideVectorInstanceData.elements()});
|
||||
}
|
||||
|
||||
void clear() {
|
||||
|
||||
@@ -186,6 +186,7 @@ void Drawable::draw(PaintParameters& parameters) const {
|
||||
#endif
|
||||
|
||||
bindAttributes(renderPass);
|
||||
bindInstanceAttributes(renderPass);
|
||||
bindUniformBuffers(renderPass);
|
||||
bindTextures(renderPass);
|
||||
|
||||
@@ -256,7 +257,7 @@ void Drawable::draw(PaintParameters& parameters) const {
|
||||
const auto primitiveType = getPrimitiveType(mode.type);
|
||||
constexpr auto indexType = MTL::IndexType::IndexTypeUInt16;
|
||||
constexpr auto indexSize = sizeof(std::uint16_t);
|
||||
constexpr NS::UInteger instanceCount = 1;
|
||||
const NS::UInteger instanceCount = instanceAttributes ? instanceAttributes->getMaxCount() : 1;
|
||||
constexpr NS::UInteger baseInstance = 0;
|
||||
const NS::UInteger indexOffset = static_cast<NS::UInteger>(indexSize *
|
||||
mlSegment.indexOffset); // in bytes, not indexes
|
||||
@@ -360,6 +361,25 @@ void Drawable::bindAttributes(RenderPass& renderPass) const noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
void Drawable::bindInstanceAttributes(RenderPass& renderPass) const noexcept {
|
||||
const auto& encoder = renderPass.getMetalEncoder();
|
||||
|
||||
NS::UInteger attributeIndex = 0;
|
||||
for (const auto& binding : impl->instanceBindings) {
|
||||
if (binding.has_value()) {
|
||||
const auto* buffer = static_cast<const mtl::VertexBufferResource*>(binding->vertexBufferResource);
|
||||
if (buffer && buffer->get()) {
|
||||
renderPass.bindVertex(buffer->get(), /*offset=*/0, attributeIndex);
|
||||
} else {
|
||||
const auto* shaderMTL = static_cast<const ShaderProgram*>(shader.get());
|
||||
auto& context = renderPass.getCommandEncoder().getContext();
|
||||
renderPass.bindVertex(context.getEmptyBuffer(), /*offset=*/0, attributeIndex);
|
||||
}
|
||||
}
|
||||
attributeIndex += 1;
|
||||
}
|
||||
}
|
||||
|
||||
void Drawable::bindUniformBuffers(RenderPass& renderPass) const noexcept {
|
||||
if (shader) {
|
||||
const auto& uniformBlocks = shader->getUniformBlocks();
|
||||
@@ -584,6 +604,30 @@ void Drawable::upload(gfx::UploadPass& uploadPass_) {
|
||||
}
|
||||
}
|
||||
|
||||
// build instance buffer
|
||||
const bool buildInstanceBuffer = (instanceAttributes && instanceAttributes->isDirty());
|
||||
|
||||
if (buildInstanceBuffer) {
|
||||
// Build instance attribute buffers
|
||||
std::vector<std::unique_ptr<gfx::VertexBufferResource>> instanceBuffers;
|
||||
auto instanceBindings_ = uploadPass.buildAttributeBindings(instanceAttributes->getMaxCount(),
|
||||
/*vertexType*/ gfx::AttributeDataType::Byte,
|
||||
/*vertexAttributeIndex=*/-1,
|
||||
/*vertexData=*/{},
|
||||
shader->getInstanceAttributes(),
|
||||
*instanceAttributes,
|
||||
usage,
|
||||
instanceBuffers);
|
||||
impl->instanceBuffers = std::move(instanceBuffers);
|
||||
|
||||
// clear dirty flag
|
||||
instanceAttributes->visitAttributes([](gfx::VertexAttribute& attrib) { attrib.setDirty(false); });
|
||||
|
||||
if (impl->instanceBindings != instanceBindings_) {
|
||||
impl->instanceBindings = std::move(instanceBindings_);
|
||||
}
|
||||
}
|
||||
|
||||
const bool texturesNeedUpload = std::any_of(
|
||||
textures.begin(), textures.end(), [](const auto& texture) { return texture && texture->needsUpload(); });
|
||||
|
||||
|
||||
@@ -45,6 +45,10 @@ public:
|
||||
gfx::AttributeDataType vertexType = gfx::AttributeDataType::Invalid;
|
||||
|
||||
std::vector<gfx::UniqueVertexBufferResource> attributeBuffers;
|
||||
gfx::AttributeBindingArray attributeBindings;
|
||||
|
||||
std::vector<gfx::UniqueVertexBufferResource> instanceBuffers;
|
||||
gfx::AttributeBindingArray instanceBindings;
|
||||
|
||||
UniformBufferArray uniformBuffers;
|
||||
|
||||
@@ -56,8 +60,6 @@ public:
|
||||
|
||||
VertexBufferResource* noBindingBuffer = nullptr;
|
||||
|
||||
gfx::AttributeBindingArray attributeBindings;
|
||||
|
||||
MTLRenderPipelineStatePtr pipelineState;
|
||||
|
||||
std::optional<gfx::RenderPassDescriptor> renderPassDescriptor;
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <mbgl/shaders/mtl/symbol_icon.hpp>
|
||||
#include <mbgl/shaders/mtl/symbol_sdf.hpp>
|
||||
#include <mbgl/shaders/mtl/symbol_text_and_icon.hpp>
|
||||
#include <mbgl/shaders/mtl/widevector.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
@@ -150,7 +151,8 @@ void RendererBackend::initShaders(gfx::ShaderRegistry& shaders, const ProgramPar
|
||||
shaders::BuiltIn::RasterShader,
|
||||
shaders::BuiltIn::SymbolIconShader,
|
||||
shaders::BuiltIn::SymbolSDFIconShader,
|
||||
shaders::BuiltIn::SymbolTextAndIconShader>(shaders, programParameters);
|
||||
shaders::BuiltIn::SymbolTextAndIconShader,
|
||||
shaders::BuiltIn::WideVectorShader>(shaders, programParameters);
|
||||
}
|
||||
|
||||
} // namespace mtl
|
||||
|
||||
@@ -37,6 +37,9 @@ mat4 LayerTweaker::getTileMatrix(const UnwrappedTileID& tileID,
|
||||
// from RenderTile::prepare
|
||||
mat4 tileMatrix;
|
||||
parameters.state.matrixFor(/*out*/ tileMatrix, tileID);
|
||||
if (const auto& origin{drawable.getOrigin()}; origin.has_value()) {
|
||||
matrix::translate(tileMatrix, tileMatrix, origin->x, origin->y, 0);
|
||||
}
|
||||
|
||||
// nearClippedMatrix has near plane moved further, to enhance depth buffer precision
|
||||
auto projMatrix = aligned ? parameters.transformParams.alignedProjMatrix
|
||||
|
||||
@@ -23,23 +23,6 @@ using namespace std::string_literals;
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
shaders::AttributeInfo::AttributeInfo(std::size_t index_, gfx::AttributeDataType dataType_, std::size_t id_)
|
||||
: index(index_),
|
||||
dataType(dataType_),
|
||||
id(id_) {}
|
||||
|
||||
shaders::UniformBlockInfo::UniformBlockInfo(
|
||||
std::size_t index_, bool vertex_, bool fragment_, std::size_t size_, std::size_t id_)
|
||||
: index(index_),
|
||||
vertex(vertex_),
|
||||
fragment(fragment_),
|
||||
size(size_),
|
||||
id(id_) {}
|
||||
|
||||
shaders::TextureInfo::TextureInfo(std::size_t index_, std::size_t id_)
|
||||
: index(index_),
|
||||
id(id_) {}
|
||||
|
||||
namespace mtl {
|
||||
namespace {
|
||||
MTL::BlendOperation metalBlendOperation(const gfx::ColorBlendEquationType& colorBlend) {
|
||||
@@ -194,16 +177,30 @@ void ShaderProgram::initAttribute(const shaders::AttributeInfo& info) {
|
||||
#if !defined(NDEBUG)
|
||||
// Indexes must be unique, if there's a conflict check the `attributes` array in the shader
|
||||
vertexAttributes.visitAttributes([&](const gfx::VertexAttribute& attrib) { assert(attrib.getIndex() != index); });
|
||||
instanceAttributes.visitAttributes([&](const gfx::VertexAttribute& attrib) { assert(attrib.getIndex() != index); });
|
||||
uniformBlocks.visit([&](const gfx::UniformBlock& block) { assert(block.getIndex() != index); });
|
||||
#endif
|
||||
vertexAttributes.set(info.id, index, info.dataType, 1);
|
||||
}
|
||||
|
||||
void ShaderProgram::initInstanceAttribute(const shaders::AttributeInfo& info) {
|
||||
// Index is the block index of the instance attribute
|
||||
const auto index = static_cast<int>(info.index);
|
||||
#if !defined(NDEBUG)
|
||||
// Indexes must not be reused by regular attributes or uniform blocks
|
||||
// More than one instance attribute can have the same index, if they share the block
|
||||
vertexAttributes.visitAttributes([&](const gfx::VertexAttribute& attrib) { assert(attrib.getIndex() != index); });
|
||||
uniformBlocks.visit([&](const gfx::UniformBlock& block) { assert(block.getIndex() != index); });
|
||||
#endif
|
||||
instanceAttributes.set(info.id, index, info.dataType, 1);
|
||||
}
|
||||
|
||||
void ShaderProgram::initUniformBlock(const shaders::UniformBlockInfo& info) {
|
||||
const auto index = static_cast<int>(info.index);
|
||||
#if !defined(NDEBUG)
|
||||
// Indexes must be unique, if there's a conflict check the `attributes` array in the shader
|
||||
vertexAttributes.visitAttributes([&](const gfx::VertexAttribute& attrib) { assert(attrib.getIndex() != index); });
|
||||
instanceAttributes.visitAttributes([&](const gfx::VertexAttribute& attrib) { assert(attrib.getIndex() != index); });
|
||||
uniformBlocks.visit([&](const gfx::UniformBlock& block) { assert(block.getIndex() != index); });
|
||||
#endif
|
||||
if (const auto& block_ = uniformBlocks.set(info.id, index, info.size)) {
|
||||
|
||||
@@ -22,6 +22,13 @@
|
||||
#include <mbgl/util/containers.hpp>
|
||||
#include <mbgl/gfx/fill_generator.hpp>
|
||||
#include <mbgl/shaders/custom_drawable_layer_ubo.hpp>
|
||||
#include <mbgl/shaders/shader_source.hpp>
|
||||
#include <mbgl/gfx/renderable.hpp>
|
||||
#include <mbgl/gfx/renderer_backend.hpp>
|
||||
#include <mbgl/shaders/widevector_ubo.hpp>
|
||||
#include <mbgl/util/projection.hpp>
|
||||
#include <mbgl/util/mat4.hpp>
|
||||
#include <mbgl/renderer/render_tile.hpp>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
@@ -84,7 +91,6 @@ class LineDrawableTweaker : public gfx::DrawableTweaker {
|
||||
public:
|
||||
LineDrawableTweaker(const shaders::LinePropertiesUBO& properties)
|
||||
: linePropertiesUBO(properties) {}
|
||||
~LineDrawableTweaker() override = default;
|
||||
|
||||
void init(gfx::Drawable&) override {};
|
||||
|
||||
@@ -129,12 +135,74 @@ private:
|
||||
shaders::LinePropertiesUBO linePropertiesUBO;
|
||||
};
|
||||
|
||||
class WideVectorDrawableTweaker : public gfx::DrawableTweaker {
|
||||
public:
|
||||
WideVectorDrawableTweaker(const CustomDrawableLayerHost::Interface::LineOptions& options)
|
||||
: options(options) {}
|
||||
|
||||
void init(gfx::Drawable&) override {};
|
||||
|
||||
void execute(gfx::Drawable& drawable, const PaintParameters& parameters) override {
|
||||
if (!drawable.getTileID().has_value()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const UnwrappedTileID tileID = drawable.getTileID()->toUnwrapped();
|
||||
|
||||
mat4 tileMatrix;
|
||||
parameters.state.matrixFor(/*out*/ tileMatrix, tileID);
|
||||
if (const auto& origin{drawable.getOrigin()}; origin.has_value()) {
|
||||
matrix::translate(tileMatrix, tileMatrix, origin->x, origin->y, 0);
|
||||
}
|
||||
|
||||
mat4 projMatrix = parameters.transformParams.projMatrix;
|
||||
const auto matrix = LayerTweaker::getTileMatrix(
|
||||
tileID, parameters, {{0, 0}}, style::TranslateAnchorType::Viewport, false, false, drawable, false);
|
||||
|
||||
matf4 mvpMatrix, mvpMatrixDiff, mvMatrix, mvMatrixDiff, pMatrix, pMatrixDiff;
|
||||
matrix::diffsplit(mvpMatrix, mvpMatrixDiff, matrix);
|
||||
matrix::diffsplit(mvMatrix, mvMatrixDiff, tileMatrix);
|
||||
matrix::diffsplit(pMatrix, pMatrixDiff, projMatrix);
|
||||
|
||||
const auto renderableSize = parameters.backend.getDefaultRenderable().getSize();
|
||||
shaders::WideVectorUniformsUBO uniform{
|
||||
/*mvpMatrix */ mvpMatrix,
|
||||
/*mvpMatrixDiff */ mvpMatrixDiff,
|
||||
/*mvMatrix */ mvMatrix,
|
||||
/*mvMatrixDiff */ mvMatrixDiff,
|
||||
/*pMatrix */ pMatrix,
|
||||
/*pMatrixDiff */ pMatrixDiff,
|
||||
/*frameSize */ {(float)renderableSize.width, (float)renderableSize.height}};
|
||||
|
||||
shaders::WideVectorUniformWideVecUBO wideVec{
|
||||
/*color */ options.color,
|
||||
/*w2 */ options.width,
|
||||
/*offset */ options.offset,
|
||||
/*edge */ 0.0f, // TODO: MLN does not provide a value. Analyze impact.
|
||||
/*texRepeat */ 0.0f, // N/A
|
||||
/*texOffset */ {}, // N/A
|
||||
/*miterLimit */ options.geometry.miterLimit,
|
||||
/*join */ static_cast<int32_t>(options.geometry.joinType),
|
||||
/*cap */ static_cast<int32_t>(options.geometry.beginCap), // TODO: MLN option for endCap to be
|
||||
// implemented in the shader!
|
||||
/*hasExp */ false, // N/A
|
||||
/*interClipLimit*/ 0.0f // N/A
|
||||
};
|
||||
|
||||
auto& uniforms = drawable.mutableUniformBuffers();
|
||||
uniforms.createOrUpdate(idWideVectorUniformsUBO, &uniform, parameters.context);
|
||||
uniforms.createOrUpdate(idWideVectorUniformWideVecUBO, &wideVec, parameters.context);
|
||||
};
|
||||
|
||||
private:
|
||||
CustomDrawableLayerHost::Interface::LineOptions options;
|
||||
};
|
||||
|
||||
class FillDrawableTweaker : public gfx::DrawableTweaker {
|
||||
public:
|
||||
FillDrawableTweaker(const Color& color_, float opacity_)
|
||||
: color(color_),
|
||||
opacity(opacity_) {}
|
||||
~FillDrawableTweaker() override = default;
|
||||
|
||||
void init(gfx::Drawable&) override {};
|
||||
|
||||
@@ -181,7 +249,6 @@ class SymbolDrawableTweaker : public gfx::DrawableTweaker {
|
||||
public:
|
||||
SymbolDrawableTweaker(const CustomDrawableLayerHost::Interface::SymbolOptions& options_)
|
||||
: options(options_) {}
|
||||
~SymbolDrawableTweaker() override = default;
|
||||
|
||||
void init(gfx::Drawable&) override {};
|
||||
|
||||
@@ -261,6 +328,7 @@ std::size_t CustomDrawableLayerHost::Interface::getDrawableCount() const {
|
||||
}
|
||||
|
||||
void CustomDrawableLayerHost::Interface::setTileID(OverscaledTileID tileID_) {
|
||||
if (tileID != tileID_) finish();
|
||||
tileID = tileID_;
|
||||
}
|
||||
|
||||
@@ -279,27 +347,65 @@ void CustomDrawableLayerHost::Interface::setSymbolOptions(const SymbolOptions& o
|
||||
symbolOptions = options;
|
||||
}
|
||||
|
||||
void CustomDrawableLayerHost::Interface::addPolyline(const GeometryCoordinates& coordinates) {
|
||||
if (!lineShader) lineShader = lineShaderDefault();
|
||||
assert(lineShader);
|
||||
if (!builder || builder->getShader() != lineShader) {
|
||||
bool CustomDrawableLayerHost::Interface::updateBuilder(BuilderType type,
|
||||
const std::string& name,
|
||||
gfx::ShaderPtr shader) {
|
||||
if (!shader) return false;
|
||||
if (type != builderType || !builder || builder->getShader() != shader) {
|
||||
finish();
|
||||
builder = createBuilder("lines", lineShader);
|
||||
builder = createBuilder(name, shader);
|
||||
builderType = type;
|
||||
}
|
||||
assert(builder);
|
||||
assert(builder->getShader() == lineShader);
|
||||
builder->addPolyline(coordinates, lineOptions.geometry);
|
||||
assert(builder->getShader() == shader);
|
||||
return true;
|
||||
};
|
||||
|
||||
bool CustomDrawableLayerHost::Interface::addPolyline(const LineString<double>& coordinates) {
|
||||
switch (lineOptions.shaderType) {
|
||||
case LineShaderType::Classic: {
|
||||
// TODO: build classic polyline with Geo coordinates
|
||||
return false;
|
||||
} break;
|
||||
|
||||
case LineShaderType::MetalWideVector: {
|
||||
// build wide vector polyline with Geo coordinates
|
||||
if (!updateBuilder(BuilderType::LineWideVector, "custom-lines-widevector", lineShaderWideVector()))
|
||||
return false;
|
||||
|
||||
// geographic coordinates require tile {0, 0, 0}
|
||||
setTileID({0, 0, 0});
|
||||
|
||||
builder->addWideVectorPolylineGlobal(coordinates, lineOptions.geometry);
|
||||
} break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CustomDrawableLayerHost::Interface::addFill(const GeometryCollection& geometry) {
|
||||
if (!fillShader) fillShader = fillShaderDefault();
|
||||
assert(fillShader);
|
||||
if (!builder || builder->getShader() != fillShader) {
|
||||
finish();
|
||||
builder = createBuilder("fill", fillShader);
|
||||
bool CustomDrawableLayerHost::Interface::addPolyline(const GeometryCoordinates& coordinates) {
|
||||
switch (lineOptions.shaderType) {
|
||||
case LineShaderType::Classic: {
|
||||
// build classic polyline with Tile coordinates
|
||||
if (!updateBuilder(BuilderType::LineClassic, "custom-lines", lineShaderDefault())) return false;
|
||||
builder->addPolyline(coordinates, lineOptions.geometry);
|
||||
} break;
|
||||
|
||||
case LineShaderType::MetalWideVector: {
|
||||
// build wide vector polyline
|
||||
if (!updateBuilder(BuilderType::LineWideVector, "custom-lines-widevector", lineShaderWideVector()))
|
||||
return false;
|
||||
|
||||
builder->addWideVectorPolylineLocal(coordinates, lineOptions.geometry);
|
||||
} break;
|
||||
}
|
||||
assert(builder);
|
||||
assert(builder->getShader() == fillShader);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CustomDrawableLayerHost::Interface::addFill(const GeometryCollection& geometry) {
|
||||
// build fill
|
||||
if (!updateBuilder(BuilderType::Fill, "custom-fill", fillShaderDefault())) return false;
|
||||
|
||||
// provision buffers for fill vertices, indexes and segments
|
||||
using VertexVector = gfx::VertexVector<FillLayoutVertex>;
|
||||
@@ -330,17 +436,13 @@ void CustomDrawableLayerHost::Interface::addFill(const GeometryCollection& geome
|
||||
|
||||
// flush current builder drawable
|
||||
builder->flush(context);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CustomDrawableLayerHost::Interface::addSymbol(const GeometryCoordinate& point) {
|
||||
if (!symbolShader) symbolShader = symbolShaderDefault();
|
||||
assert(symbolShader);
|
||||
if (!builder || builder->getShader() != symbolShader) {
|
||||
finish();
|
||||
builder = createBuilder("symbol", symbolShader);
|
||||
}
|
||||
assert(builder);
|
||||
assert(builder->getShader() == symbolShader);
|
||||
bool CustomDrawableLayerHost::Interface::addSymbol(const GeometryCoordinate& point) {
|
||||
// build symbol
|
||||
if (!updateBuilder(BuilderType::Symbol, "custom-symbol", symbolShaderDefault())) return false;
|
||||
|
||||
// temporary: buffers
|
||||
struct CustomSymbolIcon {
|
||||
@@ -403,11 +505,16 @@ void CustomDrawableLayerHost::Interface::addSymbol(const GeometryCoordinate& poi
|
||||
|
||||
// flush current builder drawable
|
||||
builder->flush(context);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CustomDrawableLayerHost::Interface::finish() {
|
||||
if (builder && !builder->empty()) {
|
||||
// finish
|
||||
// flush current builder drawable
|
||||
builder->flush(context);
|
||||
|
||||
// finish function
|
||||
const auto finish_ = [this](gfx::DrawableTweakerPtr tweaker) {
|
||||
builder->flush(context);
|
||||
for (auto& drawable : builder->clearDrawables()) {
|
||||
@@ -422,42 +529,58 @@ void CustomDrawableLayerHost::Interface::finish() {
|
||||
}
|
||||
};
|
||||
|
||||
if (builder->getShader() == lineShader) {
|
||||
// finish building lines
|
||||
// what were we building?
|
||||
switch (builderType) {
|
||||
case BuilderType::LineClassic: {
|
||||
// finish building classic lines
|
||||
|
||||
// create line tweaker
|
||||
const shaders::LinePropertiesUBO linePropertiesUBO{lineOptions.color,
|
||||
lineOptions.blur,
|
||||
lineOptions.opacity,
|
||||
lineOptions.gapWidth,
|
||||
lineOptions.offset,
|
||||
lineOptions.width,
|
||||
0,
|
||||
0,
|
||||
0};
|
||||
auto tweaker = std::make_shared<LineDrawableTweaker>(linePropertiesUBO);
|
||||
// create line tweaker
|
||||
const shaders::LinePropertiesUBO linePropertiesUBO{lineOptions.color,
|
||||
lineOptions.blur,
|
||||
lineOptions.opacity,
|
||||
lineOptions.gapWidth,
|
||||
lineOptions.offset,
|
||||
lineOptions.width,
|
||||
0,
|
||||
0,
|
||||
0};
|
||||
auto tweaker = std::make_shared<LineDrawableTweaker>(linePropertiesUBO);
|
||||
|
||||
// finish drawables
|
||||
finish_(tweaker);
|
||||
} else if (builder->getShader() == fillShader) {
|
||||
// finish building fills
|
||||
// finish drawables
|
||||
finish_(tweaker);
|
||||
} break;
|
||||
case BuilderType::LineWideVector: {
|
||||
// finish building wide vector lines
|
||||
|
||||
// create fill tweaker
|
||||
auto tweaker = std::make_shared<FillDrawableTweaker>(fillOptions.color, fillOptions.opacity);
|
||||
// create line tweaker
|
||||
auto tweaker = std::make_shared<WideVectorDrawableTweaker>(lineOptions);
|
||||
|
||||
// finish drawables
|
||||
finish_(tweaker);
|
||||
} else if (builder->getShader() == symbolShader) {
|
||||
// finish building symbols
|
||||
// finish drawables
|
||||
finish_(tweaker);
|
||||
} break;
|
||||
case BuilderType::Fill: {
|
||||
// finish building fills
|
||||
|
||||
// finish drawables
|
||||
finish_(nullptr);
|
||||
// create fill tweaker
|
||||
auto tweaker = std::make_shared<FillDrawableTweaker>(fillOptions.color, fillOptions.opacity);
|
||||
|
||||
// finish drawables
|
||||
finish_(tweaker);
|
||||
} break;
|
||||
case BuilderType::Symbol:
|
||||
// finish building symbols
|
||||
finish_(nullptr);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gfx::ShaderPtr CustomDrawableLayerHost::Interface::lineShaderDefault() const {
|
||||
gfx::ShaderGroupPtr shaderGroup = shaders.getShaderGroup("LineShader");
|
||||
assert(shaderGroup);
|
||||
if (!shaderGroup) return gfx::ShaderPtr();
|
||||
|
||||
const StringIDSetsPair propertiesAsUniforms{{"a_color", "a_blur", "a_opacity", "a_gapwidth", "a_offset", "a_width"},
|
||||
{idLineColorVertexAttribute,
|
||||
@@ -470,6 +593,13 @@ gfx::ShaderPtr CustomDrawableLayerHost::Interface::lineShaderDefault() const {
|
||||
return shaderGroup->getOrCreateShader(context, propertiesAsUniforms);
|
||||
}
|
||||
|
||||
gfx::ShaderPtr CustomDrawableLayerHost::Interface::lineShaderWideVector() const {
|
||||
gfx::ShaderGroupPtr shaderGroup = shaders.getShaderGroup("WideVectorShader");
|
||||
if (!shaderGroup) return gfx::ShaderPtr();
|
||||
|
||||
return shaderGroup->getOrCreateShader(context, {});
|
||||
}
|
||||
|
||||
gfx::ShaderPtr CustomDrawableLayerHost::Interface::fillShaderDefault() const {
|
||||
gfx::ShaderGroupPtr shaderGroup = shaders.getShaderGroup("FillShader");
|
||||
|
||||
|
||||
@@ -407,6 +407,13 @@ void transformMat4(vec4& out, const vec4& a, const mat4& m) {
|
||||
out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
|
||||
}
|
||||
|
||||
void diffsplit(matf4& outValue, matf4& outDiff, const mat4& source) {
|
||||
for (auto i = 0; i < 16; ++i) {
|
||||
outValue[i] = static_cast<float>(source[i]);
|
||||
outDiff[i] = source[i] - outValue[i];
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace matrix
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -53,5 +53,6 @@ void multiply(mat4& out, const mat4& a, const mat4& b);
|
||||
|
||||
void transformMat4(vec4& out, const vec4& a, const mat4& m);
|
||||
|
||||
void diffsplit(matf4& outValue, matf4& outDiff, const mat4& source);
|
||||
} // namespace matrix
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -38,48 +38,66 @@ public:
|
||||
|
||||
constexpr auto numLines = 6;
|
||||
Interface::LineOptions options[numLines]{
|
||||
{/*color=*/Color::red(),
|
||||
/*blur=*/0.0f,
|
||||
/*opacity=*/1.0f,
|
||||
/*gapWidth=*/0.0f,
|
||||
/*offset=*/0.0f,
|
||||
/*width=*/8.0f,
|
||||
{}},
|
||||
{/*color=*/Color::blue(),
|
||||
/*blur=*/4.0f,
|
||||
/*opacity=*/1.0f,
|
||||
/*gapWidth=*/2.0f,
|
||||
/*offset=*/-1.0f,
|
||||
/*width=*/4.0f,
|
||||
{}},
|
||||
{/*color=*/Color(1.f, 0.5f, 0, 0.5f),
|
||||
/*blur=*/16.0f,
|
||||
/*opacity=*/1.0f,
|
||||
/*gapWidth=*/1.0f,
|
||||
/*offset=*/2.0f,
|
||||
/*width=*/16.0f,
|
||||
{}},
|
||||
{/*color=*/Color(1.f, 1.f, 0, 0.3f),
|
||||
/*blur=*/2.0f,
|
||||
/*opacity=*/1.0f,
|
||||
/*gapWidth=*/1.0f,
|
||||
/*offset=*/-2.0f,
|
||||
/*width=*/2.0f,
|
||||
{}},
|
||||
{/*color=*/Color::black(),
|
||||
/*blur=*/0.5f,
|
||||
/*opacity=*/0.5f,
|
||||
/*gapWidth=*/1.0f,
|
||||
/*offset=*/0.5f,
|
||||
/*width=*/0.5f,
|
||||
{}},
|
||||
{/*color=*/Color(1.f, 0, 1.f, 0.2f),
|
||||
/*blur=*/24.0f,
|
||||
/*opacity=*/0.5f,
|
||||
/*gapWidth=*/1.0f,
|
||||
/*offset=*/-5.0f,
|
||||
/*width=*/24.0f,
|
||||
{}},
|
||||
{
|
||||
/*geometry=*/{},
|
||||
/*blur=*/0.0f,
|
||||
/*opacity=*/1.0f,
|
||||
/*gapWidth=*/0.0f,
|
||||
/*offset=*/0.0f,
|
||||
/*width=*/8.0f,
|
||||
/*shaderType*/ {},
|
||||
/*color=*/Color::red(),
|
||||
},
|
||||
{
|
||||
/*geometry=*/{},
|
||||
/*blur=*/4.0f,
|
||||
/*opacity=*/1.0f,
|
||||
/*gapWidth=*/2.0f,
|
||||
/*offset=*/-1.0f,
|
||||
/*width=*/4.0f,
|
||||
{},
|
||||
/*color=*/Color::blue(),
|
||||
},
|
||||
{
|
||||
/*geometry=*/{},
|
||||
/*blur=*/16.0f,
|
||||
/*opacity=*/1.0f,
|
||||
/*gapWidth=*/1.0f,
|
||||
/*offset=*/2.0f,
|
||||
/*width=*/16.0f,
|
||||
{},
|
||||
/*color=*/Color(1.f, 0.5f, 0, 0.5f),
|
||||
},
|
||||
{
|
||||
/*geometry=*/{},
|
||||
/*blur=*/2.0f,
|
||||
/*opacity=*/1.0f,
|
||||
/*gapWidth=*/1.0f,
|
||||
/*offset=*/-2.0f,
|
||||
/*width=*/2.0f,
|
||||
{},
|
||||
/*color=*/Color(1.f, 1.f, 0, 0.3f),
|
||||
},
|
||||
{
|
||||
/*geometry=*/{},
|
||||
/*blur=*/0.5f,
|
||||
/*opacity=*/0.5f,
|
||||
/*gapWidth=*/1.0f,
|
||||
/*offset=*/0.5f,
|
||||
/*width=*/0.5f,
|
||||
{},
|
||||
/*color=*/Color::black(),
|
||||
},
|
||||
{
|
||||
/*geometry=*/{},
|
||||
/*blur=*/24.0f,
|
||||
/*opacity=*/0.5f,
|
||||
/*gapWidth=*/1.0f,
|
||||
/*offset=*/-5.0f,
|
||||
/*width=*/24.0f,
|
||||
{},
|
||||
/*color=*/Color(1.f, 0, 1.f, 0.2f),
|
||||
},
|
||||
};
|
||||
for (auto& opt : options) {
|
||||
opt.geometry.beginCap = style::LineCapType::Round;
|
||||
|
||||
Reference in New Issue
Block a user