Custom Drawable Layer: Symbol Icon (#1908)
This commit is contained in:
@@ -141,6 +141,7 @@ endif()
|
||||
|
||||
if(MLN_DRAWABLE_RENDERER)
|
||||
list(APPEND INCLUDE_FILES
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/gfx/context.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/gfx/drawable.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/gfx/drawable_data.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/gfx/drawable_impl.hpp
|
||||
@@ -465,7 +466,6 @@ list(APPEND SRC_FILES
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/gfx/attribute.hpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/gfx/color_mode.hpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/gfx/command_encoder.hpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/gfx/context.hpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/gfx/cull_face_mode.hpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/gfx/debug_group.hpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/gfx/depth_mode.hpp
|
||||
@@ -1142,6 +1142,7 @@ if(MLN_WITH_OPENGL)
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/hillshade_prepare_layer_ubo.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/layer_ubo.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/line_layer_ubo.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/custom_drawable_layer_ubo.hpp
|
||||
${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
|
||||
@@ -1211,6 +1212,7 @@ if(MBGL_WITH_METAL)
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/common.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/collision_box.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/collision_circle.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/custom_symbol_icon.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/debug.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/fill.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/fill_extrusion.hpp
|
||||
@@ -1256,6 +1258,7 @@ if(MBGL_WITH_METAL)
|
||||
${PROJECT_SOURCE_DIR}src/mbgl/shaders/mtl/collision_box.cpp
|
||||
${PROJECT_SOURCE_DIR}src/mbgl/shaders/mtl/collision_circle.cpp
|
||||
${PROJECT_SOURCE_DIR}src/mbgl/shaders/mtl/clipping_mask.cpp
|
||||
${PROJECT_SOURCE_DIR}src/mbgl/shaders/mtl/custom_symbol_icon.cpp
|
||||
${PROJECT_SOURCE_DIR}src/mbgl/shaders/mtl/debug.cpp
|
||||
${PROJECT_SOURCE_DIR}src/mbgl/shaders/mtl/fill.cpp
|
||||
${PROJECT_SOURCE_DIR}src/mbgl/shaders/mtl/fill_extrusion.cpp
|
||||
|
||||
@@ -67,6 +67,7 @@ MLN_GENERATED_OPENGL_SHADER_HEADERS = [
|
||||
"include/mbgl/shaders/gl/drawable_circle.hpp",
|
||||
"include/mbgl/shaders/gl/drawable_collision_box.hpp",
|
||||
"include/mbgl/shaders/gl/drawable_collision_circle.hpp",
|
||||
"include/mbgl/shaders/gl/drawable_custom_symbol_icon.hpp",
|
||||
"include/mbgl/shaders/gl/drawable_debug.hpp",
|
||||
"include/mbgl/shaders/gl/drawable_fill.hpp",
|
||||
"include/mbgl/shaders/gl/drawable_fill_outline.hpp",
|
||||
@@ -143,7 +144,6 @@ MLN_CORE_SOURCE = [
|
||||
"include/mbgl/gfx/backend.hpp",
|
||||
"src/mbgl/gfx/color_mode.hpp",
|
||||
"src/mbgl/gfx/command_encoder.hpp",
|
||||
"src/mbgl/gfx/context.hpp",
|
||||
"src/mbgl/gfx/cull_face_mode.hpp",
|
||||
"src/mbgl/gfx/debug_group.hpp",
|
||||
"src/mbgl/gfx/depth_mode.hpp",
|
||||
@@ -648,6 +648,7 @@ MLN_CORE_SOURCE = [
|
||||
]
|
||||
|
||||
MLN_CORE_HEADERS = [
|
||||
"include/mbgl/gfx/context.hpp",
|
||||
"include/mbgl/actor/actor.hpp",
|
||||
"include/mbgl/actor/actor_ref.hpp",
|
||||
"include/mbgl/actor/aspiring_actor.hpp",
|
||||
@@ -980,6 +981,7 @@ MLN_DRAWABLES_HEADERS = [
|
||||
"include/mbgl/shaders/background_layer_ubo.hpp",
|
||||
"include/mbgl/shaders/circle_layer_ubo.hpp",
|
||||
"include/mbgl/shaders/collision_layer_ubo.hpp",
|
||||
"include/mbgl/shaders/custom_drawable_layer_ubo.hpp",
|
||||
"include/mbgl/shaders/debug_layer_ubo.hpp",
|
||||
"include/mbgl/shaders/fill_layer_ubo.hpp",
|
||||
"include/mbgl/shaders/fill_extrusion_layer_ubo.hpp",
|
||||
@@ -1054,6 +1056,7 @@ MLN_DRAWABLES_MTL_SOURCE = [
|
||||
"src/mbgl/shaders/mtl/collision_box.cpp",
|
||||
"src/mbgl/shaders/mtl/collision_circle.cpp",
|
||||
"src/mbgl/shaders/mtl/clipping_mask.cpp",
|
||||
"src/mbgl/shaders/mtl/custom_symbol_icon.cpp",
|
||||
"src/mbgl/shaders/mtl/debug.cpp",
|
||||
"src/mbgl/shaders/mtl/fill.cpp",
|
||||
"src/mbgl/shaders/mtl/fill_extrusion.cpp",
|
||||
@@ -1098,6 +1101,7 @@ MLN_DRAWABLES_MTL_HEADERS = [
|
||||
"include/mbgl/shaders/mtl/collision_box.hpp",
|
||||
"include/mbgl/shaders/mtl/collision_circle.hpp",
|
||||
"include/mbgl/shaders/mtl/common.hpp",
|
||||
"include/mbgl/shaders/mtl/custom_symbol_icon.hpp",
|
||||
"include/mbgl/shaders/mtl/debug.hpp",
|
||||
"include/mbgl/shaders/mtl/fill.hpp",
|
||||
"include/mbgl/shaders/mtl/fill_extrusion.hpp",
|
||||
|
||||
36
include/mbgl/shaders/custom_drawable_layer_ubo.hpp
Normal file
36
include/mbgl/shaders/custom_drawable_layer_ubo.hpp
Normal file
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/shaders/layer_ubo.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace shaders {
|
||||
|
||||
/// Custom Symbol Icon matrix
|
||||
struct alignas(16) CustomSymbolIconDrawableUBO {
|
||||
/* 0 */ std::array<float, 4 * 4> matrix;
|
||||
/* 64 */
|
||||
};
|
||||
static_assert(sizeof(CustomSymbolIconDrawableUBO) == 4 * 16);
|
||||
|
||||
/// Custom Symbol Icon Parameters
|
||||
struct alignas(16) CustomSymbolIconParametersUBO {
|
||||
/* 0 */ std::array<float, 2> extrude_scale;
|
||||
/* 8 */ std::array<float, 2> anchor;
|
||||
/* 16 */ float angle_degrees;
|
||||
/* 20 */ uint32_t scale_with_map;
|
||||
/* 24 */ uint32_t pitch_with_map;
|
||||
/* 28 */ float camera_to_center_distance;
|
||||
/* 32 */ float aspect_ratio;
|
||||
/* 36 */ float pad0, pad1, pad2;
|
||||
/* 48 */
|
||||
};
|
||||
static_assert(sizeof(CustomSymbolIconParametersUBO) == 3 * 16);
|
||||
|
||||
enum {
|
||||
idCustomSymbolIconDrawableUBO,
|
||||
idCustomSymbolIconParametersUBO,
|
||||
customDrawableUBOCount
|
||||
};
|
||||
|
||||
} // namespace shaders
|
||||
} // namespace mbgl
|
||||
92
include/mbgl/shaders/gl/drawable_custom_symbol_icon.hpp
Normal file
92
include/mbgl/shaders/gl/drawable_custom_symbol_icon.hpp
Normal file
@@ -0,0 +1,92 @@
|
||||
// Generated code, do not modify this file!
|
||||
#pragma once
|
||||
#include <mbgl/shaders/shader_source.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace shaders {
|
||||
|
||||
template <>
|
||||
struct ShaderSource<BuiltIn::CustomSymbolIconShader, gfx::Backend::Type::OpenGL> {
|
||||
static constexpr const char* name = "CustomSymbolIconShader";
|
||||
static constexpr const char* vertex = R"(layout(location = 0) in vec2 a_pos;
|
||||
layout(location = 1) in vec2 a_tex;
|
||||
|
||||
layout(std140) uniform CustomSymbolIconDrawableUBO {
|
||||
highp mat4 u_matrix;
|
||||
};
|
||||
|
||||
layout(std140) uniform CustomSymbolIconParametersUBO {
|
||||
highp vec2 u_extrude_scale;
|
||||
highp vec2 u_anchor;
|
||||
highp float u_angle_degrees;
|
||||
bool u_scale_with_map;
|
||||
bool u_pitch_with_map;
|
||||
highp float u_camera_to_center_distance;
|
||||
highp float u_aspect_ratio;
|
||||
highp float pad0, pad1, pad3;
|
||||
};
|
||||
|
||||
out vec2 v_tex;
|
||||
|
||||
vec2 rotateVec2(vec2 v, float angle) {
|
||||
float cosA = cos(angle);
|
||||
float sinA = sin(angle);
|
||||
return vec2(v.x * cosA - v.y * sinA, v.x * sinA + v.y * cosA);
|
||||
}
|
||||
|
||||
vec2 ellipseRotateVec2(vec2 v, float angle, float radiusRatio /* A/B */) {
|
||||
float cosA = cos(angle);
|
||||
float sinA = sin(angle);
|
||||
float invRatio = 1.0 / radiusRatio;
|
||||
return vec2(v.x * cosA - radiusRatio * v.y * sinA, invRatio * v.x * sinA + v.y * cosA);
|
||||
}
|
||||
|
||||
void main() {
|
||||
// decode the extrusion vector (-1, -1) to (1, 1)
|
||||
vec2 extrude = vec2(mod(a_pos, 2.0) * 2.0 - 1.0);
|
||||
|
||||
// make anchor relative to (0.5, 0.5) and corners in range (-1, -1) to (1, 1)
|
||||
vec2 anchor = (u_anchor - vec2(0.5, 0.5)) * 2.0;
|
||||
|
||||
// decode center
|
||||
vec2 center = floor(a_pos * 0.5);
|
||||
|
||||
// rotate extrusion around anchor
|
||||
float angle = radians(-u_angle_degrees);
|
||||
vec2 corner = extrude - anchor;
|
||||
|
||||
// compute
|
||||
if (u_pitch_with_map) {
|
||||
if (u_scale_with_map) {
|
||||
corner *= u_extrude_scale;
|
||||
} else {
|
||||
vec4 projected_center = u_matrix * vec4(center, 0, 1);
|
||||
corner *= u_extrude_scale * (projected_center.w / u_camera_to_center_distance);
|
||||
}
|
||||
corner = center + rotateVec2(corner, angle);
|
||||
gl_Position = u_matrix * vec4(corner, 0, 1);
|
||||
} else {
|
||||
gl_Position = u_matrix * vec4(center, 0, 1);
|
||||
if (u_scale_with_map) {
|
||||
gl_Position.xy += ellipseRotateVec2(corner * u_extrude_scale * u_camera_to_center_distance, angle, u_aspect_ratio);
|
||||
} else {
|
||||
gl_Position.xy += ellipseRotateVec2(corner * u_extrude_scale * gl_Position.w, angle, u_aspect_ratio);
|
||||
}
|
||||
}
|
||||
|
||||
// texture coordinates
|
||||
v_tex = a_tex;
|
||||
}
|
||||
)";
|
||||
static constexpr const char* fragment = R"(uniform sampler2D u_texture;
|
||||
|
||||
in vec2 v_tex;
|
||||
|
||||
void main() {
|
||||
fragColor = texture(u_texture, v_tex);
|
||||
}
|
||||
)";
|
||||
};
|
||||
|
||||
} // namespace shaders
|
||||
} // namespace mbgl
|
||||
@@ -54,6 +54,12 @@ struct ShaderInfo<BuiltIn::CollisionCircleShader, gfx::Backend::Type::OpenGL> {
|
||||
static const std::vector<TextureInfo> textures;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ShaderInfo<BuiltIn::CustomSymbolIconShader, gfx::Backend::Type::OpenGL> {
|
||||
static const std::vector<UniformBlockInfo> uniformBlocks;
|
||||
static const std::vector<TextureInfo> textures;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ShaderInfo<BuiltIn::DebugShader, gfx::Backend::Type::OpenGL> {
|
||||
static const std::vector<UniformBlockInfo> uniformBlocks;
|
||||
|
||||
105
include/mbgl/shaders/mtl/custom_symbol_icon.hpp
Normal file
105
include/mbgl/shaders/mtl/custom_symbol_icon.hpp
Normal file
@@ -0,0 +1,105 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/shaders/mtl/common.hpp>
|
||||
#include <mbgl/shaders/mtl/shader_program.hpp>
|
||||
#include <mbgl/shaders/shader_source.hpp>
|
||||
#include <mbgl/shaders/custom_drawable_layer_ubo.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace shaders {
|
||||
|
||||
template <>
|
||||
struct ShaderSource<BuiltIn::CustomSymbolIconShader, gfx::Backend::Type::Metal> {
|
||||
static constexpr auto name = "CustomSymbolIconShader";
|
||||
static constexpr auto vertexMainFunction = "vertexMain";
|
||||
static constexpr auto fragmentMainFunction = "fragmentMain";
|
||||
|
||||
static const std::array<AttributeInfo, 2> attributes;
|
||||
static const std::array<UniformBlockInfo, 2> uniforms;
|
||||
static const std::array<TextureInfo, 1> textures;
|
||||
|
||||
static constexpr auto source = R"(
|
||||
struct alignas(16) CustomSymbolIconDrawableUBO {
|
||||
float4x4 matrix;
|
||||
};
|
||||
|
||||
struct alignas(16) CustomSymbolIconParametersUBO {
|
||||
float2 extrude_scale;
|
||||
float2 anchor;
|
||||
float angle_degrees;
|
||||
int scale_with_map;
|
||||
int pitch_with_map;
|
||||
float camera_to_center_distance;
|
||||
float aspect_ratio;
|
||||
float pad0, pad1, pad3;
|
||||
};
|
||||
|
||||
struct VertexStage {
|
||||
float2 a_pos [[attribute(0)]];
|
||||
float2 a_tex [[attribute(1)]];
|
||||
};
|
||||
|
||||
struct FragmentStage {
|
||||
float4 position [[position, invariant]];
|
||||
half2 tex;
|
||||
};
|
||||
|
||||
float2 rotateVec2(float2 v, float angle) {
|
||||
float cosA = cos(angle);
|
||||
float sinA = sin(angle);
|
||||
return float2(v.x * cosA - v.y * sinA, v.x * sinA + v.y * cosA);
|
||||
}
|
||||
|
||||
float2 ellipseRotateVec2(float2 v, float angle, float radiusRatio /* A/B */) {
|
||||
float cosA = cos(angle);
|
||||
float sinA = sin(angle);
|
||||
float invRatio = 1.0 / radiusRatio;
|
||||
return float2(v.x * cosA - radiusRatio * v.y * sinA, invRatio * v.x * sinA + v.y * cosA);
|
||||
}
|
||||
|
||||
FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
|
||||
device const CustomSymbolIconDrawableUBO& drawable [[buffer(2)]],
|
||||
device const CustomSymbolIconParametersUBO& parameters [[buffer(3)]]) {
|
||||
|
||||
const float2 extrude = glMod(float2(vertx.a_pos), 2.0) * 2.0 - 1.0;
|
||||
const float2 anchor = (parameters.anchor - float2(0.5, 0.5)) * 2.0;
|
||||
const float2 center = floor(float2(vertx.a_pos) * 0.5);
|
||||
const float angle = radians(-parameters.angle_degrees);
|
||||
float2 corner = extrude - anchor;
|
||||
|
||||
float4 position;
|
||||
if (parameters.pitch_with_map) {
|
||||
if (parameters.scale_with_map) {
|
||||
corner *= parameters.extrude_scale;
|
||||
} else {
|
||||
float4 projected_center = drawable.matrix * float4(center, 0, 1);
|
||||
corner *= parameters.extrude_scale * (projected_center.w / parameters.camera_to_center_distance);
|
||||
}
|
||||
corner = center + rotateVec2(corner, angle);
|
||||
position = drawable.matrix * float4(corner, 0, 1);
|
||||
} else {
|
||||
position = drawable.matrix * float4(center, 0, 1);
|
||||
const float factor = parameters.scale_with_map ? parameters.camera_to_center_distance : position.w;
|
||||
position.xy += ellipseRotateVec2(corner * parameters.extrude_scale * factor, angle, parameters.aspect_ratio);
|
||||
}
|
||||
|
||||
return {
|
||||
.position = position,
|
||||
.tex = half2(vertx.a_tex)
|
||||
};
|
||||
}
|
||||
|
||||
half4 fragment fragmentMain(FragmentStage in [[stage_in]],
|
||||
texture2d<float, access::sample> image [[texture(0)]],
|
||||
sampler image_sampler [[sampler(0)]]) {
|
||||
#if defined(OVERDRAW_INSPECTOR)
|
||||
return half4(1.0);
|
||||
#endif
|
||||
|
||||
return half4(image.sample(image_sampler, float2(in.tex)));
|
||||
}
|
||||
)";
|
||||
};
|
||||
|
||||
} // namespace shaders
|
||||
} // namespace mbgl
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <mbgl/shaders/background_layer_ubo.hpp>
|
||||
#include <mbgl/shaders/circle_layer_ubo.hpp>
|
||||
#include <mbgl/shaders/collision_layer_ubo.hpp>
|
||||
#include <mbgl/shaders/custom_drawable_layer_ubo.hpp>
|
||||
#include <mbgl/shaders/debug_layer_ubo.hpp>
|
||||
#include <mbgl/shaders/fill_layer_ubo.hpp>
|
||||
#include <mbgl/shaders/fill_extrusion_layer_ubo.hpp>
|
||||
@@ -22,6 +23,7 @@ namespace shaders {
|
||||
static constexpr auto maxUBOCountPerShader = std::max({static_cast<size_t>(backgroundUBOCount),
|
||||
static_cast<size_t>(circleUBOCount),
|
||||
static_cast<size_t>(collisionUBOCount),
|
||||
static_cast<size_t>(customDrawableUBOCount),
|
||||
static_cast<size_t>(debugUBOCount),
|
||||
static_cast<size_t>(fillUBOCount),
|
||||
static_cast<size_t>(fillOutlineUBOCount),
|
||||
@@ -53,6 +55,11 @@ enum {
|
||||
collisionTextureCount
|
||||
};
|
||||
|
||||
enum {
|
||||
idCustomSymbolIconTexture,
|
||||
customSymbolIconTextureCount
|
||||
};
|
||||
|
||||
enum {
|
||||
idDebugOverlayTexture,
|
||||
debugTextureCount
|
||||
@@ -99,6 +106,7 @@ enum {
|
||||
static constexpr auto maxTextureCountPerShader = std::max({static_cast<size_t>(backgroundTextureCount),
|
||||
static_cast<size_t>(circleTextureCount),
|
||||
static_cast<size_t>(collisionTextureCount),
|
||||
static_cast<size_t>(customSymbolIconTextureCount),
|
||||
static_cast<size_t>(debugTextureCount),
|
||||
static_cast<size_t>(fillTextureCount),
|
||||
static_cast<size_t>(fillExtrusionTextureCount),
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#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_custom_symbol_icon.hpp>
|
||||
#include <mbgl/shaders/gl/prelude.hpp>
|
||||
#include <mbgl/shaders/gl/background.hpp>
|
||||
#include <mbgl/shaders/gl/background_pattern.hpp>
|
||||
|
||||
@@ -34,6 +34,7 @@ enum class BuiltIn {
|
||||
SymbolIconShader,
|
||||
SymbolSDFIconShader,
|
||||
SymbolTextAndIconShader,
|
||||
CustomSymbolIconShader,
|
||||
Prelude,
|
||||
BackgroundProgram,
|
||||
BackgroundPatternProgram,
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#include <mbgl/renderer/render_tree.hpp>
|
||||
#include <mbgl/renderer/change_request.hpp>
|
||||
#include <mbgl/gfx/drawable_builder.hpp>
|
||||
#include <mbgl/gfx/texture2d.hpp>
|
||||
#include <mbgl/gfx/context.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
@@ -46,6 +48,16 @@ public:
|
||||
float opacity = 1.f;
|
||||
};
|
||||
|
||||
struct SymbolOptions {
|
||||
Size size;
|
||||
gfx::Texture2DPtr texture;
|
||||
std::array<float, 2> anchor{0.5f, 0.5f};
|
||||
std::array<std::array<float, 2>, 2> textureCoordinates{{{0, 0}, {1, 1}}};
|
||||
float angleDegrees{.0f};
|
||||
bool scaleWithMap{false};
|
||||
bool pitchWithMap{false};
|
||||
};
|
||||
|
||||
public:
|
||||
/// @brief Construct a new Interface object (internal core use only)
|
||||
Interface(RenderLayer& layer,
|
||||
@@ -84,6 +96,13 @@ public:
|
||||
*/
|
||||
void setFillOptions(const FillOptions& options);
|
||||
|
||||
/**
|
||||
* @brief Set the Symbol options
|
||||
*
|
||||
* @param options
|
||||
*/
|
||||
void setSymbolOptions(const SymbolOptions& options);
|
||||
|
||||
/**
|
||||
* @brief Add a polyline
|
||||
*
|
||||
@@ -92,8 +111,20 @@ public:
|
||||
*/
|
||||
void addPolyline(const GeometryCoordinates& coordinates);
|
||||
|
||||
/**
|
||||
* @brief Add a multipolygon area fill
|
||||
*
|
||||
* @param geometry a collection of rings with optional holes
|
||||
*/
|
||||
void addFill(const GeometryCollection& geometry);
|
||||
|
||||
/**
|
||||
* @brief Add a symbol
|
||||
*
|
||||
* @param point
|
||||
*/
|
||||
void addSymbol(const GeometryCoordinate& point);
|
||||
|
||||
/**
|
||||
* @brief Finish the current drawable building session
|
||||
*
|
||||
@@ -113,15 +144,20 @@ public:
|
||||
private:
|
||||
gfx::ShaderPtr lineShaderDefault() const;
|
||||
gfx::ShaderPtr fillShaderDefault() const;
|
||||
gfx::ShaderPtr symbolShaderDefault() const;
|
||||
|
||||
std::unique_ptr<gfx::DrawableBuilder> createBuilder(const std::string& name, gfx::ShaderPtr shader) const;
|
||||
|
||||
gfx::ShaderPtr lineShader;
|
||||
gfx::ShaderPtr fillShader;
|
||||
std::unique_ptr<gfx::DrawableBuilder> builder;
|
||||
std::optional<OverscaledTileID> tileID;
|
||||
|
||||
gfx::ShaderPtr lineShader;
|
||||
gfx::ShaderPtr fillShader;
|
||||
gfx::ShaderPtr symbolShader;
|
||||
|
||||
LineOptions lineOptions;
|
||||
FillOptions fillOptions;
|
||||
SymbolOptions symbolOptions;
|
||||
};
|
||||
|
||||
class CustomDrawableLayer final : public Layer {
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
#import "MLNStyleLayer.h"
|
||||
#import "MLNCustomDrawableStyleLayer.h"
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#include <mbgl/util/image+MLNAdditions.hpp>
|
||||
#include <mbgl/layermanager/layer_factory.hpp>
|
||||
#include <mbgl/style/layer.hpp>
|
||||
#include <mbgl/style/layers/custom_drawable_layer.hpp>
|
||||
@@ -81,7 +84,7 @@ public:
|
||||
interface.addPolyline(polyline);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// add fill polygon
|
||||
{
|
||||
using namespace mbgl;
|
||||
@@ -111,6 +114,36 @@ public:
|
||||
// add fill
|
||||
interface.addFill(geometry);
|
||||
}
|
||||
|
||||
// add symbol
|
||||
{
|
||||
using namespace mbgl;
|
||||
GeometryCoordinate position {static_cast<int16_t>(extent* 0.5f), static_cast<int16_t>(extent* 0.5f)};
|
||||
|
||||
// load image
|
||||
UIImage *assetImage = [UIImage imageNamed:@"pin"];
|
||||
assert(assetImage.CGImage != NULL);
|
||||
std::shared_ptr<PremultipliedImage> image = std::make_shared<PremultipliedImage>(MLNPremultipliedImageFromCGImage(assetImage.CGImage));
|
||||
|
||||
// set symbol options
|
||||
Interface::SymbolOptions options;
|
||||
options.texture = interface.context.createTexture2D();
|
||||
options.texture->setImage(image);
|
||||
options.texture->setSamplerConfiguration({gfx::TextureFilterType::Linear, gfx::TextureWrapType::Clamp, gfx::TextureWrapType::Clamp});
|
||||
options.textureCoordinates = {{{0.0f, 0.08f}, {1.0f, 0.9f}}};
|
||||
const float xspan = options.textureCoordinates[1][0] - options.textureCoordinates[0][0];
|
||||
const float yspan = options.textureCoordinates[1][1] - options.textureCoordinates[0][1];
|
||||
assert(xspan > 0.0f && yspan > 0.0f);
|
||||
options.size = {static_cast<uint32_t>(image->size.width * xspan), static_cast<uint32_t>(image->size.height * yspan)};
|
||||
options.anchor = {0.5f, 0.95f};
|
||||
options.angleDegrees = 45.0f;
|
||||
options.scaleWithMap = true;
|
||||
options.pitchWithMap = false;
|
||||
interface.setSymbolOptions(options);
|
||||
|
||||
// add symbol
|
||||
interface.addSymbol(position);
|
||||
}
|
||||
|
||||
// finish
|
||||
interface.finish();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
21
platform/ios/app/Assets.xcassets/pin.imageset/Contents.json
vendored
Normal file
21
platform/ios/app/Assets.xcassets/pin.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "pin1.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
platform/ios/app/Assets.xcassets/pin.imageset/pin1.png
vendored
Normal file
BIN
platform/ios/app/Assets.xcassets/pin.imageset/pin1.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
7
shaders/drawable.custom.symbol_icon.fragment.glsl
Normal file
7
shaders/drawable.custom.symbol_icon.fragment.glsl
Normal file
@@ -0,0 +1,7 @@
|
||||
uniform sampler2D u_texture;
|
||||
|
||||
in vec2 v_tex;
|
||||
|
||||
void main() {
|
||||
fragColor = texture(u_texture, v_tex);
|
||||
}
|
||||
69
shaders/drawable.custom.symbol_icon.vertex.glsl
Normal file
69
shaders/drawable.custom.symbol_icon.vertex.glsl
Normal file
@@ -0,0 +1,69 @@
|
||||
layout(location = 0) in vec2 a_pos;
|
||||
layout(location = 1) in vec2 a_tex;
|
||||
|
||||
layout(std140) uniform CustomSymbolIconDrawableUBO {
|
||||
highp mat4 u_matrix;
|
||||
};
|
||||
|
||||
layout(std140) uniform CustomSymbolIconParametersUBO {
|
||||
highp vec2 u_extrude_scale;
|
||||
highp vec2 u_anchor;
|
||||
highp float u_angle_degrees;
|
||||
bool u_scale_with_map;
|
||||
bool u_pitch_with_map;
|
||||
highp float u_camera_to_center_distance;
|
||||
highp float u_aspect_ratio;
|
||||
highp float pad0, pad1, pad3;
|
||||
};
|
||||
|
||||
out vec2 v_tex;
|
||||
|
||||
vec2 rotateVec2(vec2 v, float angle) {
|
||||
float cosA = cos(angle);
|
||||
float sinA = sin(angle);
|
||||
return vec2(v.x * cosA - v.y * sinA, v.x * sinA + v.y * cosA);
|
||||
}
|
||||
|
||||
vec2 ellipseRotateVec2(vec2 v, float angle, float radiusRatio /* A/B */) {
|
||||
float cosA = cos(angle);
|
||||
float sinA = sin(angle);
|
||||
float invRatio = 1.0 / radiusRatio;
|
||||
return vec2(v.x * cosA - radiusRatio * v.y * sinA, invRatio * v.x * sinA + v.y * cosA);
|
||||
}
|
||||
|
||||
void main() {
|
||||
// decode the extrusion vector (-1, -1) to (1, 1)
|
||||
vec2 extrude = vec2(mod(a_pos, 2.0) * 2.0 - 1.0);
|
||||
|
||||
// make anchor relative to (0.5, 0.5) and corners in range (-1, -1) to (1, 1)
|
||||
vec2 anchor = (u_anchor - vec2(0.5, 0.5)) * 2.0;
|
||||
|
||||
// decode center
|
||||
vec2 center = floor(a_pos * 0.5);
|
||||
|
||||
// rotate extrusion around anchor
|
||||
float angle = radians(-u_angle_degrees);
|
||||
vec2 corner = extrude - anchor;
|
||||
|
||||
// compute
|
||||
if (u_pitch_with_map) {
|
||||
if (u_scale_with_map) {
|
||||
corner *= u_extrude_scale;
|
||||
} else {
|
||||
vec4 projected_center = u_matrix * vec4(center, 0, 1);
|
||||
corner *= u_extrude_scale * (projected_center.w / u_camera_to_center_distance);
|
||||
}
|
||||
corner = center + rotateVec2(corner, angle);
|
||||
gl_Position = u_matrix * vec4(corner, 0, 1);
|
||||
} else {
|
||||
gl_Position = u_matrix * vec4(center, 0, 1);
|
||||
if (u_scale_with_map) {
|
||||
gl_Position.xy += ellipseRotateVec2(corner * u_extrude_scale * u_camera_to_center_distance, angle, u_aspect_ratio);
|
||||
} else {
|
||||
gl_Position.xy += ellipseRotateVec2(corner * u_extrude_scale * gl_Position.w, angle, u_aspect_ratio);
|
||||
}
|
||||
}
|
||||
|
||||
// texture coordinates
|
||||
v_tex = a_tex;
|
||||
}
|
||||
@@ -174,6 +174,13 @@
|
||||
"glsl_frag": "drawable.symbol_text_and_icon.fragment.glsl",
|
||||
"uses_ubos": true
|
||||
},
|
||||
{
|
||||
"name": "CustomSymbolIconShader",
|
||||
"header": "drawable_custom_symbol_icon",
|
||||
"glsl_vert": "drawable.custom.symbol_icon.vertex.glsl",
|
||||
"glsl_frag": "drawable.custom.symbol_icon.fragment.glsl",
|
||||
"uses_ubos": true
|
||||
},
|
||||
|
||||
{
|
||||
"name": "Prelude",
|
||||
|
||||
@@ -108,7 +108,7 @@ public:
|
||||
|
||||
template <class... Args>
|
||||
void emplace_back(Args&&... args) {
|
||||
static_assert(sizeof...(args) == groupSize, "wrong buffer element count");
|
||||
static_assert(sizeof...(args) % groupSize == 0, "wrong buffer element count");
|
||||
assert(!released);
|
||||
util::ignore({(v.emplace_back(std::forward<Args>(args)), 0)...});
|
||||
}
|
||||
|
||||
@@ -63,10 +63,10 @@ public:
|
||||
v(std::move(other.v)) {}
|
||||
~VertexVector() override = default;
|
||||
|
||||
template <typename Arg>
|
||||
void emplace_back(Arg&& vertex) {
|
||||
template <class... Args>
|
||||
void emplace_back(Args&&... args) {
|
||||
assert(!released);
|
||||
v.emplace_back(std::forward<Arg>(vertex));
|
||||
util::ignore({(v.emplace_back(std::forward<Args>(args)), 0)...});
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -98,6 +98,7 @@ void RendererBackend::initShaders(gfx::ShaderRegistry& shaders, const ProgramPar
|
||||
shaders::BuiltIn::CircleShader,
|
||||
shaders::BuiltIn::CollisionBoxShader,
|
||||
shaders::BuiltIn::CollisionCircleShader,
|
||||
shaders::BuiltIn::CustomSymbolIconShader,
|
||||
shaders::BuiltIn::DebugShader,
|
||||
shaders::BuiltIn::FillShader,
|
||||
shaders::BuiltIn::FillOutlineShader,
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <mbgl/shaders/mtl/clipping_mask.hpp>
|
||||
#include <mbgl/shaders/mtl/collision_box.hpp>
|
||||
#include <mbgl/shaders/mtl/collision_circle.hpp>
|
||||
#include <mbgl/shaders/mtl/custom_symbol_icon.hpp>
|
||||
#include <mbgl/shaders/mtl/debug.hpp>
|
||||
#include <mbgl/shaders/mtl/fill.hpp>
|
||||
#include <mbgl/shaders/mtl/fill_extrusion.hpp>
|
||||
@@ -129,6 +130,7 @@ void RendererBackend::initShaders(gfx::ShaderRegistry& shaders, const ProgramPar
|
||||
shaders::BuiltIn::ClippingMaskProgram,
|
||||
shaders::BuiltIn::CollisionBoxShader,
|
||||
shaders::BuiltIn::CollisionCircleShader,
|
||||
shaders::BuiltIn::CustomSymbolIconShader,
|
||||
shaders::BuiltIn::DebugShader,
|
||||
shaders::BuiltIn::FillShader,
|
||||
shaders::BuiltIn::FillOutlineShader,
|
||||
|
||||
@@ -48,6 +48,15 @@ const std::vector<UniformBlockInfo> ShaderInfo<BuiltIn::CollisionBoxShader, gfx:
|
||||
const std::vector<TextureInfo> ShaderInfo<BuiltIn::CollisionBoxShader, gfx::Backend::Type::OpenGL>::textures = {};
|
||||
|
||||
// Collision Circle
|
||||
const std::vector<UniformBlockInfo>
|
||||
ShaderInfo<BuiltIn::CustomSymbolIconShader, gfx::Backend::Type::OpenGL>::uniformBlocks = {
|
||||
UniformBlockInfo{"CustomSymbolIconDrawableUBO", idCustomSymbolIconDrawableUBO},
|
||||
UniformBlockInfo{"CustomSymbolIconParametersUBO", idCustomSymbolIconParametersUBO},
|
||||
};
|
||||
const std::vector<TextureInfo> ShaderInfo<BuiltIn::CustomSymbolIconShader, gfx::Backend::Type::OpenGL>::textures = {
|
||||
TextureInfo{"u_texture", idSymbolImageTexture},
|
||||
};
|
||||
|
||||
const std::vector<UniformBlockInfo>
|
||||
ShaderInfo<BuiltIn::CollisionCircleShader, gfx::Backend::Type::OpenGL>::uniformBlocks = {
|
||||
UniformBlockInfo{"CollisionCircleUBO", idCollisionUBO},
|
||||
|
||||
22
src/mbgl/shaders/mtl/custom_symbol_icon.cpp
Normal file
22
src/mbgl/shaders/mtl/custom_symbol_icon.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include <mbgl/shaders/mtl/custom_symbol_icon.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace shaders {
|
||||
|
||||
const std::array<AttributeInfo, 2>
|
||||
ShaderSource<BuiltIn::CustomSymbolIconShader, gfx::Backend::Type::Metal>::attributes = {
|
||||
// always attributes
|
||||
AttributeInfo{0, gfx::AttributeDataType::Float2, "a_pos"},
|
||||
AttributeInfo{1, gfx::AttributeDataType::Float2, "a_tex"},
|
||||
};
|
||||
const std::array<UniformBlockInfo, 2>
|
||||
ShaderSource<BuiltIn::CustomSymbolIconShader, gfx::Backend::Type::Metal>::uniforms = {
|
||||
UniformBlockInfo{2, true, false, sizeof(CustomSymbolIconDrawableUBO), idCustomSymbolIconDrawableUBO},
|
||||
UniformBlockInfo{3, true, false, sizeof(CustomSymbolIconParametersUBO), idCustomSymbolIconParametersUBO},
|
||||
};
|
||||
const std::array<TextureInfo, 1> ShaderSource<BuiltIn::CustomSymbolIconShader, gfx::Backend::Type::Metal>::textures = {
|
||||
TextureInfo{0, idCustomSymbolIconTexture},
|
||||
};
|
||||
|
||||
} // namespace shaders
|
||||
} // namespace mbgl
|
||||
@@ -21,8 +21,10 @@
|
||||
#include <mbgl/util/math.hpp>
|
||||
#include <mbgl/tile/geometry_tile_data.hpp>
|
||||
#include <mbgl/util/containers.hpp>
|
||||
|
||||
#include <mbgl/gfx/fill_generator.hpp>
|
||||
#include <mbgl/shaders/custom_drawable_layer_ubo.hpp>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
@@ -176,6 +178,59 @@ private:
|
||||
float opacity;
|
||||
};
|
||||
|
||||
class SymbolDrawableTweaker : public gfx::DrawableTweaker {
|
||||
public:
|
||||
SymbolDrawableTweaker(const CustomDrawableLayerHost::Interface::SymbolOptions& options_)
|
||||
: options(options_) {}
|
||||
~SymbolDrawableTweaker() override = default;
|
||||
|
||||
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);
|
||||
|
||||
const auto matrix = LayerTweaker::getTileMatrix(
|
||||
tileID, parameters, {{0, 0}}, style::TranslateAnchorType::Viewport, false, false, drawable, false);
|
||||
|
||||
const shaders::CustomSymbolIconDrawableUBO drawableUBO{/*matrix = */ util::cast<float>(matrix)};
|
||||
|
||||
const auto pixelsToTileUnits = tileID.pixelsToTileUnits(
|
||||
1.0f, options.scaleWithMap ? tileID.canonical.z : parameters.state.getZoom());
|
||||
const float factor = options.scaleWithMap
|
||||
? static_cast<float>(std::pow(2.f, parameters.state.getZoom() - tileID.canonical.z))
|
||||
: 1.0f;
|
||||
const auto extrudeScale = options.pitchWithMap ? std::array<float, 2>{pixelsToTileUnits, pixelsToTileUnits}
|
||||
: std::array<float, 2>{parameters.pixelsToGLUnits[0] * factor,
|
||||
parameters.pixelsToGLUnits[1] * factor};
|
||||
|
||||
const shaders::CustomSymbolIconParametersUBO parametersUBO{
|
||||
/*extrude_scale*/ {extrudeScale[0] * options.size.width, extrudeScale[1] * options.size.height},
|
||||
/*anchor*/ options.anchor,
|
||||
/*angle_degrees*/ options.angleDegrees,
|
||||
/*scale_with_map*/ options.scaleWithMap,
|
||||
/*pitch_with_map*/ options.pitchWithMap,
|
||||
/*camera_to_center_distance*/ parameters.state.getCameraToCenterDistance(),
|
||||
/*aspect_ratio*/ parameters.pixelsToGLUnits[0] / parameters.pixelsToGLUnits[1],
|
||||
0,
|
||||
0,
|
||||
0};
|
||||
|
||||
// set UBOs
|
||||
auto& uniforms = drawable.mutableUniformBuffers();
|
||||
uniforms.createOrUpdate(idCustomSymbolIconDrawableUBO, &drawableUBO, parameters.context);
|
||||
uniforms.createOrUpdate(idCustomSymbolIconParametersUBO, ¶metersUBO, parameters.context);
|
||||
};
|
||||
|
||||
private:
|
||||
CustomDrawableLayerHost::Interface::SymbolOptions options;
|
||||
};
|
||||
|
||||
CustomDrawableLayerHost::Interface::Interface(RenderLayer& layer_,
|
||||
LayerGroupBasePtr& layerGroup_,
|
||||
gfx::ShaderRegistry& shaders_,
|
||||
@@ -220,10 +275,16 @@ void CustomDrawableLayerHost::Interface::setFillOptions(const FillOptions& optio
|
||||
fillOptions = options;
|
||||
}
|
||||
|
||||
void CustomDrawableLayerHost::Interface::setSymbolOptions(const SymbolOptions& options) {
|
||||
finish();
|
||||
symbolOptions = options;
|
||||
}
|
||||
|
||||
void CustomDrawableLayerHost::Interface::addPolyline(const GeometryCoordinates& coordinates) {
|
||||
if (!lineShader) lineShader = lineShaderDefault();
|
||||
assert(lineShader);
|
||||
if (!builder || builder->getShader() != lineShader) {
|
||||
finish();
|
||||
builder = createBuilder("lines", lineShader);
|
||||
}
|
||||
assert(builder);
|
||||
@@ -235,6 +296,7 @@ void CustomDrawableLayerHost::Interface::addFill(const GeometryCollection& geome
|
||||
if (!fillShader) fillShader = fillShaderDefault();
|
||||
assert(fillShader);
|
||||
if (!builder || builder->getShader() != fillShader) {
|
||||
finish();
|
||||
builder = createBuilder("fill", fillShader);
|
||||
}
|
||||
assert(builder);
|
||||
@@ -274,15 +336,94 @@ void CustomDrawableLayerHost::Interface::addFill(const GeometryCollection& geome
|
||||
builder->flush(context);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// temporary: buffers
|
||||
struct CustomSymbolIcon {
|
||||
std::array<float, 2> a_pos;
|
||||
std::array<float, 2> a_tex;
|
||||
};
|
||||
|
||||
// vertices
|
||||
using VertexVector = gfx::VertexVector<CustomSymbolIcon>;
|
||||
const std::shared_ptr<VertexVector> sharedVertices = std::make_shared<VertexVector>();
|
||||
VertexVector& vertices = *sharedVertices;
|
||||
|
||||
// encode center and extrude direction into vertices
|
||||
for (int y = 0; y <= 1; ++y) {
|
||||
for (int x = 0; x <= 1; ++x) {
|
||||
vertices.emplace_back(
|
||||
CustomSymbolIcon{{static_cast<float>(point.x * 2 + x), static_cast<float>(point.y * 2 + y)},
|
||||
{symbolOptions.textureCoordinates[x][0], symbolOptions.textureCoordinates[y][1]}});
|
||||
}
|
||||
}
|
||||
|
||||
// indexes
|
||||
using TriangleIndexVector = gfx::IndexVector<gfx::Triangles>;
|
||||
const std::shared_ptr<TriangleIndexVector> sharedTriangles = std::make_shared<TriangleIndexVector>();
|
||||
TriangleIndexVector& triangles = *sharedTriangles;
|
||||
|
||||
triangles.emplace_back(0, 1, 2, 1, 2, 3);
|
||||
|
||||
SegmentVector<CustomSymbolIcon> triangleSegments;
|
||||
triangleSegments.emplace_back(Segment<CustomSymbolIcon>{0, 0, 4, 6});
|
||||
|
||||
// add to builder
|
||||
static const StringIdentity idPositionAttribName = stringIndexer().get("a_pos");
|
||||
static const StringIdentity idTextureAttribName = stringIndexer().get("a_tex");
|
||||
builder->setVertexAttrNameId(idPositionAttribName);
|
||||
|
||||
auto attrs = context.createVertexAttributeArray();
|
||||
if (const auto& attr = attrs->add(idPositionAttribName)) {
|
||||
attr->setSharedRawData(sharedVertices,
|
||||
offsetof(CustomSymbolIcon, a_pos),
|
||||
/*vertexOffset=*/0,
|
||||
sizeof(CustomSymbolIcon),
|
||||
gfx::AttributeDataType::Float2);
|
||||
}
|
||||
if (const auto& attr = attrs->add(idTextureAttribName)) {
|
||||
attr->setSharedRawData(sharedVertices,
|
||||
offsetof(CustomSymbolIcon, a_tex),
|
||||
/*vertexOffset=*/0,
|
||||
sizeof(CustomSymbolIcon),
|
||||
gfx::AttributeDataType::Float2);
|
||||
}
|
||||
builder->setVertexAttributes(std::move(attrs));
|
||||
builder->setRawVertices({}, vertices.elements(), gfx::AttributeDataType::Float2);
|
||||
builder->setSegments(gfx::Triangles(), sharedTriangles, triangleSegments.data(), triangleSegments.size());
|
||||
|
||||
// texture
|
||||
if (symbolOptions.texture) {
|
||||
builder->setTexture(symbolOptions.texture, idCustomSymbolIconTexture);
|
||||
}
|
||||
|
||||
// create fill tweaker
|
||||
auto tweaker = std::make_shared<SymbolDrawableTweaker>(symbolOptions);
|
||||
builder->addTweaker(tweaker);
|
||||
|
||||
// flush current builder drawable
|
||||
builder->flush(context);
|
||||
}
|
||||
|
||||
void CustomDrawableLayerHost::Interface::finish() {
|
||||
if (builder && !builder->empty()) {
|
||||
// finish
|
||||
const auto finish_ = [this](auto& tweaker) {
|
||||
const auto finish_ = [this](gfx::DrawableTweakerPtr tweaker) {
|
||||
builder->flush(context);
|
||||
for (auto& drawable : builder->clearDrawables()) {
|
||||
assert(tileID.has_value());
|
||||
drawable->setTileID(tileID.value());
|
||||
drawable->addTweaker(tweaker);
|
||||
if (tweaker) {
|
||||
drawable->addTweaker(tweaker);
|
||||
}
|
||||
|
||||
TileLayerGroup* tileLayerGroup = static_cast<TileLayerGroup*>(layerGroup.get());
|
||||
tileLayerGroup->addDrawable(RenderPass::Translucent, tileID.value(), std::move(drawable));
|
||||
@@ -314,12 +455,17 @@ void CustomDrawableLayerHost::Interface::finish() {
|
||||
|
||||
// finish drawables
|
||||
finish_(tweaker);
|
||||
} else if (builder->getShader() == symbolShader) {
|
||||
// finish building symbols
|
||||
|
||||
// finish drawables
|
||||
finish_(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gfx::ShaderPtr CustomDrawableLayerHost::Interface::lineShaderDefault() const {
|
||||
gfx::ShaderGroupPtr lineShaderGroup = shaders.getShaderGroup("LineShader");
|
||||
gfx::ShaderGroupPtr shaderGroup = shaders.getShaderGroup("LineShader");
|
||||
|
||||
const mbgl::unordered_set<StringIdentity> propertiesAsUniforms{
|
||||
stringIndexer().get("a_color"),
|
||||
@@ -330,18 +476,22 @@ gfx::ShaderPtr CustomDrawableLayerHost::Interface::lineShaderDefault() const {
|
||||
stringIndexer().get("a_width"),
|
||||
};
|
||||
|
||||
return lineShaderGroup->getOrCreateShader(context, propertiesAsUniforms);
|
||||
return shaderGroup->getOrCreateShader(context, propertiesAsUniforms);
|
||||
}
|
||||
|
||||
gfx::ShaderPtr CustomDrawableLayerHost::Interface::fillShaderDefault() const {
|
||||
gfx::ShaderGroupPtr fillShaderGroup = shaders.getShaderGroup("FillShader");
|
||||
gfx::ShaderGroupPtr shaderGroup = shaders.getShaderGroup("FillShader");
|
||||
|
||||
const mbgl::unordered_set<StringIdentity> propertiesAsUniforms{
|
||||
stringIndexer().get("a_color"),
|
||||
stringIndexer().get("a_opacity"),
|
||||
};
|
||||
|
||||
return fillShaderGroup->getOrCreateShader(context, propertiesAsUniforms);
|
||||
return shaderGroup->getOrCreateShader(context, propertiesAsUniforms);
|
||||
}
|
||||
|
||||
gfx::ShaderPtr CustomDrawableLayerHost::Interface::symbolShaderDefault() const {
|
||||
return context.getGenericShader(shaders, "CustomSymbolIconShader");
|
||||
}
|
||||
|
||||
std::unique_ptr<gfx::DrawableBuilder> CustomDrawableLayerHost::Interface::createBuilder(const std::string& name,
|
||||
|
||||
@@ -14,11 +14,14 @@
|
||||
|
||||
#include <mbgl/style/layers/custom_drawable_layer.hpp>
|
||||
#include <mbgl/util/constants.hpp>
|
||||
#include <mbgl/util/logging.hpp>
|
||||
#include <mbgl/util/image.hpp>
|
||||
#include <mbgl/util/io.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <cmath>
|
||||
|
||||
class TestDrawableLayer : public mbgl::style::CustomDrawableLayerHost {
|
||||
class LineTestDrawableLayer : public mbgl::style::CustomDrawableLayerHost {
|
||||
public:
|
||||
void initialize() override {}
|
||||
|
||||
@@ -104,6 +107,24 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// finish
|
||||
interface.finish();
|
||||
}
|
||||
|
||||
void deinitialize() override {}
|
||||
};
|
||||
|
||||
class FillTestDrawableLayer : public mbgl::style::CustomDrawableLayerHost {
|
||||
public:
|
||||
void initialize() override {}
|
||||
|
||||
void update(Interface& interface) override {
|
||||
// if we have built our drawable(s) already, either update or skip
|
||||
if (interface.getDrawableCount()) return;
|
||||
|
||||
// set tile
|
||||
interface.setTileID({11, 327, 791});
|
||||
|
||||
// add fill polygon
|
||||
{
|
||||
using namespace mbgl;
|
||||
@@ -141,7 +162,65 @@ public:
|
||||
void deinitialize() override {}
|
||||
};
|
||||
|
||||
TEST(CustomDrawableLayer, Basic) {
|
||||
class SymbolIconTestDrawableLayer : public mbgl::style::CustomDrawableLayerHost {
|
||||
public:
|
||||
void initialize() override {}
|
||||
|
||||
void update(Interface& interface) override {
|
||||
// if we have built our drawable(s) already, either update or skip
|
||||
if (interface.getDrawableCount()) return;
|
||||
|
||||
// set tile
|
||||
interface.setTileID({11, 327, 791});
|
||||
|
||||
// add symbol icon
|
||||
{
|
||||
using namespace mbgl;
|
||||
GeometryCoordinate position{static_cast<int16_t>(util::EXTENT * 0.5f),
|
||||
static_cast<int16_t>(util::EXTENT * 0.5f)};
|
||||
|
||||
// load image
|
||||
std::string imageData; // doh!
|
||||
constexpr auto imagePath = "test/fixtures/custom_drawable_layer/symbol_icon/pin1.png";
|
||||
try {
|
||||
imageData = util::read_file(imagePath);
|
||||
} catch (std::exception& ex) {
|
||||
using namespace std::string_literals;
|
||||
Log::Error(Event::Setup, "Failed to load expected image "s + imagePath + ": " + ex.what());
|
||||
throw;
|
||||
}
|
||||
std::shared_ptr<PremultipliedImage> image = std::make_shared<PremultipliedImage>(decodeImage(imageData));
|
||||
|
||||
// set symbol options
|
||||
Interface::SymbolOptions options;
|
||||
options.texture = interface.context.createTexture2D();
|
||||
options.texture->setImage(image);
|
||||
options.texture->setSamplerConfiguration(
|
||||
{gfx::TextureFilterType::Linear, gfx::TextureWrapType::Clamp, gfx::TextureWrapType::Clamp});
|
||||
options.textureCoordinates = {{{0.0f, 0.08f}, {1.0f, 0.9f}}};
|
||||
const float xspan = options.textureCoordinates[1][0] - options.textureCoordinates[0][0];
|
||||
const float yspan = options.textureCoordinates[1][1] - options.textureCoordinates[0][1];
|
||||
assert(xspan > 0.0f && yspan > 0.0f);
|
||||
options.size = {static_cast<uint32_t>(image->size.width * 0.2f * xspan),
|
||||
static_cast<uint32_t>(image->size.height * 0.2f * yspan)};
|
||||
options.anchor = {0.5f, 0.95f};
|
||||
options.angleDegrees = 45.0f;
|
||||
options.scaleWithMap = false;
|
||||
options.pitchWithMap = false;
|
||||
interface.setSymbolOptions(options);
|
||||
|
||||
// add symbol
|
||||
interface.addSymbol(position);
|
||||
}
|
||||
|
||||
// finish
|
||||
interface.finish();
|
||||
}
|
||||
|
||||
void deinitialize() override {}
|
||||
};
|
||||
|
||||
TEST(CustomDrawableLayer, Line) {
|
||||
using namespace mbgl;
|
||||
using namespace mbgl::style;
|
||||
|
||||
@@ -154,21 +233,63 @@ TEST(CustomDrawableLayer, Basic) {
|
||||
ResourceOptions().withCachePath(":memory:").withAssetPath("test/fixtures/api/assets"));
|
||||
|
||||
// load style
|
||||
map.getStyle().loadJSON(util::read_file("test/fixtures/api/water.json"));
|
||||
map.getStyle().loadJSON(util::read_file("test/fixtures/api/simple.json"));
|
||||
map.jumpTo(CameraOptions().withCenter(LatLng{37.8, -122.4426032}).withZoom(10.0));
|
||||
|
||||
// add fill layer
|
||||
auto layer = std::make_unique<FillLayer>("landcover", "mapbox");
|
||||
layer->setSourceLayer("landcover");
|
||||
layer->setFillColor(Color{1.0, 1.0, 0.0, 1.0});
|
||||
map.getStyle().addLayer(std::move(layer));
|
||||
|
||||
// add custom drawable layer
|
||||
map.getStyle().addLayer(
|
||||
std::make_unique<CustomDrawableLayer>("custom-drawable", std::make_unique<TestDrawableLayer>()));
|
||||
std::make_unique<CustomDrawableLayer>("custom-drawable", std::make_unique<LineTestDrawableLayer>()));
|
||||
|
||||
// render and test
|
||||
test::checkImage("test/fixtures/custom_drawable_layer/basic", frontend.render(map).image, 0.000657, 0.1);
|
||||
test::checkImage("test/fixtures/custom_drawable_layer/line", frontend.render(map).image, 0.000657, 0.1);
|
||||
}
|
||||
|
||||
TEST(CustomDrawableLayer, Fill) {
|
||||
using namespace mbgl;
|
||||
using namespace mbgl::style;
|
||||
|
||||
util::RunLoop loop;
|
||||
|
||||
HeadlessFrontend frontend{1};
|
||||
Map map(frontend,
|
||||
MapObserver::nullObserver(),
|
||||
MapOptions().withMapMode(MapMode::Static).withSize(frontend.getSize()),
|
||||
ResourceOptions().withCachePath(":memory:").withAssetPath("test/fixtures/api/assets"));
|
||||
|
||||
// load style
|
||||
map.getStyle().loadJSON(util::read_file("test/fixtures/api/simple.json"));
|
||||
map.jumpTo(CameraOptions().withCenter(LatLng{37.8, -122.4426032}).withZoom(10.0));
|
||||
|
||||
// add custom drawable layer
|
||||
map.getStyle().addLayer(
|
||||
std::make_unique<CustomDrawableLayer>("custom-drawable", std::make_unique<FillTestDrawableLayer>()));
|
||||
|
||||
// render and test
|
||||
test::checkImage("test/fixtures/custom_drawable_layer/fill", frontend.render(map).image, 0.000657, 0.1);
|
||||
}
|
||||
|
||||
TEST(CustomDrawableLayer, SymbolIcon) {
|
||||
using namespace mbgl;
|
||||
using namespace mbgl::style;
|
||||
|
||||
util::RunLoop loop;
|
||||
|
||||
HeadlessFrontend frontend{1};
|
||||
Map map(frontend,
|
||||
MapObserver::nullObserver(),
|
||||
MapOptions().withMapMode(MapMode::Static).withSize(frontend.getSize()),
|
||||
ResourceOptions().withCachePath(":memory:").withAssetPath("test/fixtures/api/assets"));
|
||||
|
||||
// load style
|
||||
map.getStyle().loadJSON(util::read_file("test/fixtures/api/simple.json"));
|
||||
map.jumpTo(CameraOptions().withCenter(LatLng{37.8, -122.4426032}).withZoom(10.0));
|
||||
|
||||
// add custom drawable layer
|
||||
map.getStyle().addLayer(
|
||||
std::make_unique<CustomDrawableLayer>("custom-drawable", std::make_unique<SymbolIconTestDrawableLayer>()));
|
||||
|
||||
// render and test
|
||||
test::checkImage("test/fixtures/custom_drawable_layer/symbol_icon", frontend.render(map).image, 0.000657, 0.1);
|
||||
}
|
||||
|
||||
#endif // MLN_DRAWABLE_RENDERER
|
||||
|
||||
25
test/fixtures/api/simple.json
vendored
Normal file
25
test/fixtures/api/simple.json
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"version": 8,
|
||||
"name": "Water",
|
||||
"sources": {
|
||||
"mapbox": {
|
||||
"type": "vector",
|
||||
"tiles": ["asset://streets/{z}-{x}-{y}.vector.pbf"]
|
||||
}
|
||||
},
|
||||
"layers": [{
|
||||
"id": "background",
|
||||
"type": "background",
|
||||
"paint": {
|
||||
"background-color": "gray"
|
||||
}
|
||||
}, {
|
||||
"id": "water",
|
||||
"type": "fill",
|
||||
"source": "mapbox",
|
||||
"source-layer": "water",
|
||||
"paint": {
|
||||
"fill-color": "#3440eb"
|
||||
}
|
||||
}]
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 30 KiB |
BIN
test/fixtures/custom_drawable_layer/fill/expected.png
vendored
Normal file
BIN
test/fixtures/custom_drawable_layer/fill/expected.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.6 KiB |
BIN
test/fixtures/custom_drawable_layer/line/expected.png
vendored
Normal file
BIN
test/fixtures/custom_drawable_layer/line/expected.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
BIN
test/fixtures/custom_drawable_layer/symbol_icon/expected.png
vendored
Normal file
BIN
test/fixtures/custom_drawable_layer/symbol_icon/expected.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
BIN
test/fixtures/custom_drawable_layer/symbol_icon/pin1.png
vendored
Normal file
BIN
test/fixtures/custom_drawable_layer/symbol_icon/pin1.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
Reference in New Issue
Block a user