Add fill extrusion style property that enables rounded corners for extruded buildings (Core feature) (#4343)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Bart Louwers <bart@emeel.net>
This commit is contained in:
@@ -9,7 +9,8 @@ template <>
|
||||
struct ShaderSource<BuiltIn::FillExtrusionShader, gfx::Backend::Type::OpenGL> {
|
||||
static constexpr const char* name = "FillExtrusionShader";
|
||||
static constexpr const char* vertex = R"(layout (location = 0) in vec2 a_pos;
|
||||
layout (location = 1) in vec4 a_normal_ed;
|
||||
layout (location = 1) in vec2 a_decimals_ed;
|
||||
layout (location = 2) in vec2 a_normal2d;
|
||||
out vec4 v_color;
|
||||
|
||||
layout (std140) uniform FillExtrusionDrawableUBO {
|
||||
@@ -52,13 +53,13 @@ layout (std140) uniform FillExtrusionPropsUBO {
|
||||
};
|
||||
|
||||
#ifndef HAS_UNIFORM_u_base
|
||||
layout (location = 2) in highp vec2 a_base;
|
||||
layout (location = 3) in highp vec2 a_base;
|
||||
#endif
|
||||
#ifndef HAS_UNIFORM_u_height
|
||||
layout (location = 3) in highp vec2 a_height;
|
||||
layout (location = 4) in highp vec2 a_height;
|
||||
#endif
|
||||
#ifndef HAS_UNIFORM_u_color
|
||||
layout (location = 4) in highp vec4 a_color;
|
||||
layout (location = 5) in highp vec4 a_color;
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
@@ -78,14 +79,16 @@ highp vec4 color = unpack_mix_color(a_color, u_color_t);
|
||||
highp vec4 color = u_color;
|
||||
#endif
|
||||
|
||||
vec3 normal = a_normal_ed.xyz;
|
||||
vec3 normal = vec3(a_normal2d / 16384.0, a_normal2d.x == 0.0 && a_normal2d.y == 0.0 ? 1.0 : 0.0);
|
||||
|
||||
base = max(0.0, base);
|
||||
height = max(0.0, height);
|
||||
|
||||
float t = mod(normal.x, 2.0);
|
||||
float t = mod(a_decimals_ed.x, 2.0);
|
||||
float z = t > 0.0 ? height : base;
|
||||
vec2 decimals = unpack_float(floor(a_decimals_ed.x / 2.0)) / 128.0;
|
||||
|
||||
gl_Position = u_matrix * vec4(a_pos, t > 0.0 ? height : base, 1);
|
||||
gl_Position = u_matrix * vec4(a_pos + decimals, z, 1);
|
||||
|
||||
// Relative luminance (how dark/bright is the surface color?)
|
||||
float colorvalue = color.r * 0.2126 + color.g * 0.7152 + color.b * 0.0722;
|
||||
@@ -97,7 +100,7 @@ highp vec4 color = u_color;
|
||||
color += ambientlight;
|
||||
|
||||
// Calculate cos(theta), where theta is the angle between surface normal and diffuse light ray
|
||||
float directional = clamp(dot(normal / 16384.0, u_lightpos), 0.0, 1.0);
|
||||
float directional = clamp(dot(normal, u_lightpos), 0.0, 1.0);
|
||||
|
||||
// Adjust directional so that
|
||||
// the range of values for highlight/shading is narrower
|
||||
@@ -106,12 +109,12 @@ highp vec4 color = u_color;
|
||||
directional = mix((1.0 - u_lightintensity), max((1.0 - colorvalue + u_lightintensity), 1.0), directional);
|
||||
|
||||
// Add gradient along z axis of side surfaces
|
||||
if (normal.y != 0.0) {
|
||||
if (normal.z == 0.0) {
|
||||
// This avoids another branching statement, but multiplies by a constant of 0.84 if no vertical gradient,
|
||||
// and otherwise calculates the gradient based on base + height
|
||||
directional *= (
|
||||
(1.0 - u_vertical_gradient) +
|
||||
(u_vertical_gradient * clamp((t + base) * pow(height / 150.0, 0.5), mix(0.7, 0.98, 1.0 - u_lightintensity), 1.0)));
|
||||
float fMin = mix(0.7, 0.98, 1.0 - u_lightintensity);
|
||||
float factor = clamp((t + base) * pow(height / 150.0, 0.5), fMin, 1.0);
|
||||
directional *= (1.0 - u_vertical_gradient) + (u_vertical_gradient * factor);
|
||||
}
|
||||
|
||||
// Assign final color based on surface + ambient light color, diffuse light directional, and light color
|
||||
|
||||
@@ -9,7 +9,8 @@ template <>
|
||||
struct ShaderSource<BuiltIn::FillExtrusionPatternShader, gfx::Backend::Type::OpenGL> {
|
||||
static constexpr const char* name = "FillExtrusionPatternShader";
|
||||
static constexpr const char* vertex = R"(layout (location = 0) in vec2 a_pos;
|
||||
layout (location = 1) in vec4 a_normal_ed;
|
||||
layout (location = 1) in vec2 a_decimals_ed;
|
||||
layout (location = 2) in vec2 a_normal2d;
|
||||
|
||||
out vec2 v_pos_a;
|
||||
out vec2 v_pos_b;
|
||||
@@ -67,19 +68,19 @@ layout (std140) uniform FillExtrusionPropsUBO {
|
||||
};
|
||||
|
||||
#ifndef HAS_UNIFORM_u_base
|
||||
layout (location = 2) in lowp vec2 a_base;
|
||||
layout (location = 3) in lowp vec2 a_base;
|
||||
out lowp float base;
|
||||
#endif
|
||||
#ifndef HAS_UNIFORM_u_height
|
||||
layout (location = 3) in lowp vec2 a_height;
|
||||
layout (location = 4) in lowp vec2 a_height;
|
||||
out lowp float height;
|
||||
#endif
|
||||
#ifndef HAS_UNIFORM_u_pattern_from
|
||||
layout (location = 4) in mediump vec4 a_pattern_from;
|
||||
layout (location = 5) in mediump vec4 a_pattern_from;
|
||||
out mediump vec4 pattern_from;
|
||||
#endif
|
||||
#ifndef HAS_UNIFORM_u_pattern_to
|
||||
layout (location = 5) in mediump vec4 a_pattern_to;
|
||||
layout (location = 6) in mediump vec4 a_pattern_to;
|
||||
out mediump vec4 pattern_to;
|
||||
#endif
|
||||
|
||||
@@ -115,8 +116,8 @@ mediump vec4 pattern_to = u_pattern_to;
|
||||
float fromScale = u_from_scale;
|
||||
float toScale = u_to_scale;
|
||||
|
||||
vec3 normal = a_normal_ed.xyz;
|
||||
float edgedistance = a_normal_ed.w;
|
||||
vec3 normal = vec3(a_normal2d / 16384.0, a_normal2d.x == 0.0 && a_normal2d.y == 0.0 ? 1.0 : 0.0);
|
||||
float edgedistance = a_decimals_ed.y;
|
||||
|
||||
vec2 display_size_a = vec2((pattern_br_a.x - pattern_tl_a.x) / pixelRatio, (pattern_br_a.y - pattern_tl_a.y) / pixelRatio);
|
||||
vec2 display_size_b = vec2((pattern_br_b.x - pattern_tl_b.x) / pixelRatio, (pattern_br_b.y - pattern_tl_b.y) / pixelRatio);
|
||||
@@ -124,28 +125,28 @@ mediump vec4 pattern_to = u_pattern_to;
|
||||
base = max(0.0, base);
|
||||
height = max(0.0, height);
|
||||
|
||||
float t = mod(normal.x, 2.0);
|
||||
float t = mod(a_decimals_ed.x, 2.0);
|
||||
float z = t > 0.0 ? height : base;
|
||||
vec2 decimals = unpack_float(floor(a_decimals_ed.x / 2.0)) / 128.0;
|
||||
|
||||
gl_Position = u_matrix * vec4(a_pos, z, 1);
|
||||
gl_Position = u_matrix * vec4(a_pos + decimals, z, 1);
|
||||
|
||||
vec2 pos = normal.x == 1.0 && normal.y == 0.0 && normal.z == 16384.0
|
||||
? a_pos // extrusion top
|
||||
: vec2(edgedistance, z * u_height_factor); // extrusion side
|
||||
// extrusion top or side
|
||||
vec2 pos = normal.z == 1.0 ? a_pos : vec2(edgedistance, z * u_height_factor);
|
||||
|
||||
v_pos_a = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, fromScale * display_size_a, tileRatio, pos);
|
||||
v_pos_b = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, toScale * display_size_b, tileRatio, pos);
|
||||
|
||||
v_lighting = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
float directional = clamp(dot(normal / 16383.0, u_lightpos), 0.0, 1.0);
|
||||
float directional = clamp(dot(normal, u_lightpos), 0.0, 1.0);
|
||||
directional = mix((1.0 - u_lightintensity), max((0.5 + u_lightintensity), 1.0), directional);
|
||||
|
||||
if (normal.y != 0.0) {
|
||||
if (normal.z == 0.0) {
|
||||
// This avoids another branching statement, but multiplies by a constant of 0.84 if no vertical gradient,
|
||||
// and otherwise calculates the gradient based on base + height
|
||||
directional *= (
|
||||
(1.0 - u_vertical_gradient) +
|
||||
(u_vertical_gradient * clamp((t + base) * pow(height / 150.0, 0.5), mix(0.7, 0.98, 1.0 - u_lightintensity), 1.0)));
|
||||
float fMin = mix(0.7, 0.98, 1.0 - u_lightintensity);
|
||||
float factor = clamp((t + base) * pow(height / 150.0, 0.5), fMin, 1.0);
|
||||
directional *= (1.0 - u_vertical_gradient) + (u_vertical_gradient * factor);
|
||||
}
|
||||
|
||||
v_lighting.rgb += clamp(directional * u_lightcolor, mix(vec3(0.0), vec3(0.3), 1.0 - u_lightcolor), vec3(1.0));
|
||||
|
||||
@@ -69,7 +69,7 @@ struct ShaderSource<BuiltIn::FillExtrusionShader, gfx::Backend::Type::Metal> {
|
||||
static constexpr auto vertexMainFunction = "vertexMain";
|
||||
static constexpr auto fragmentMainFunction = "fragmentMain";
|
||||
|
||||
static const std::array<AttributeInfo, 4> attributes;
|
||||
static const std::array<AttributeInfo, 5> attributes;
|
||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||
static const std::array<TextureInfo, 0> textures;
|
||||
|
||||
@@ -78,15 +78,16 @@ struct ShaderSource<BuiltIn::FillExtrusionShader, gfx::Backend::Type::Metal> {
|
||||
|
||||
struct VertexStage {
|
||||
short2 pos [[attribute(0)]];
|
||||
ushort2 decimals_ed [[attribute(1)]];
|
||||
|
||||
#if !defined(HAS_UNIFORM_u_color)
|
||||
float4 color [[attribute(1)]];
|
||||
float4 color [[attribute(2)]];
|
||||
#endif
|
||||
#if !defined(HAS_UNIFORM_u_base)
|
||||
float base [[attribute(2)]];
|
||||
float base [[attribute(3)]];
|
||||
#endif
|
||||
#if !defined(HAS_UNIFORM_u_height)
|
||||
float height [[attribute(3)]];
|
||||
float height [[attribute(4)]];
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -121,7 +122,9 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
|
||||
const float3 normal = float3(0.0, 0.0, 1.0);
|
||||
const float t = 1.0;
|
||||
const float z = (t != 0.0) ? height : base; // TODO: This would come out wrong on GL for negative values, check it...
|
||||
const float4 position = drawable.matrix * float4(float2(vertx.pos), z, 1);
|
||||
const float2 decimals = unpack_float(float(vertx.decimals_ed.x / 2)) / 128.0;
|
||||
|
||||
const float4 position = drawable.matrix * float4(float2(vertx.pos) + decimals, z, 1);
|
||||
|
||||
#if defined(OVERDRAW_INSPECTOR)
|
||||
return {
|
||||
@@ -154,7 +157,7 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
|
||||
float directional = mix(minDirectional, maxDirectional, directionalFraction);
|
||||
|
||||
// Add gradient along z axis of side surfaces
|
||||
if (normal.y != 0.0) {
|
||||
if (normal.z == 0.0) {
|
||||
// This avoids another branching statement, but multiplies by a constant of 0.84 if no
|
||||
// vertical gradient, and otherwise calculates the gradient based on base + height
|
||||
// TODO: If we're optimizing to the level of avoiding branches, we should pre-compute
|
||||
@@ -212,7 +215,7 @@ struct VertexStage {
|
||||
|
||||
struct OutlineInstance {
|
||||
short2 pos;
|
||||
ushort2 ed_discard;
|
||||
ushort2 decimals_ed;
|
||||
};
|
||||
|
||||
struct FragmentStage {
|
||||
@@ -232,7 +235,8 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
|
||||
uint instanceID [[ instance_id ]],
|
||||
device const OutlineInstance* outline [[buffer(fillExtrusionUBOCount + 1)]]) {
|
||||
|
||||
if (outline[instanceID].ed_discard.y) {
|
||||
bool isDiscarded = glMod(float(outline[instanceID].decimals_ed.x), 2.0) > 0.0;
|
||||
if (isDiscarded) {
|
||||
return {
|
||||
.position = float4(0.0),
|
||||
.color = half4(0.0),
|
||||
@@ -252,18 +256,15 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
|
||||
const auto height = max(unpack_mix_float(vertx.height, drawable.height_t), 0.0);
|
||||
#endif
|
||||
|
||||
float2 p1 = float2(outline[instanceID + 1].pos);
|
||||
float2 p2 = float2(outline[instanceID + 0].pos);
|
||||
float2 perp = p1 - p2;
|
||||
float magnitude = sqrt(perp.x * perp.x + perp.y * perp.y);
|
||||
if (magnitude > 0) {
|
||||
perp = perp / magnitude;
|
||||
}
|
||||
const float2 p1 = float2(outline[instanceID + 0].pos) + unpack_float(float(outline[instanceID + 0].decimals_ed.x / 2)) / 128.0;
|
||||
const float2 p2 = float2(outline[instanceID + 1].pos) + unpack_float(float(outline[instanceID + 1].decimals_ed.x / 2)) / 128.0;
|
||||
const float2 edgevector = normalize(p2 - p1);
|
||||
|
||||
const float3 normal = float3(-perp.y, perp.x, 0.0);
|
||||
const float3 normal = float3(-edgevector.y, edgevector.x, 0.0);
|
||||
const float t = float(vertx.pos.y);
|
||||
const float z = (t != 0.0) ? height : base; // TODO: This would come out wrong on GL for negative values, check it...
|
||||
const float4 position = drawable.matrix * float4(float2(outline[instanceID + vertx.pos.x].pos), z, 1);
|
||||
|
||||
const float4 position = drawable.matrix * float4(vertx.pos.x == 0.0 ? p1 : p2, z, 1);
|
||||
|
||||
#if defined(OVERDRAW_INSPECTOR)
|
||||
return {
|
||||
@@ -296,7 +297,7 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
|
||||
float directional = mix(minDirectional, maxDirectional, directionalFraction);
|
||||
|
||||
// Add gradient along z axis of side surfaces
|
||||
if (normal.y != 0.0) {
|
||||
if (normal.z == 0.0) {
|
||||
// This avoids another branching statement, but multiplies by a constant of 0.84 if no
|
||||
// vertical gradient, and otherwise calculates the gradient based on base + height
|
||||
// TODO: If we're optimizing to the level of avoiding branches, we should pre-compute
|
||||
@@ -331,7 +332,7 @@ struct ShaderSource<BuiltIn::FillExtrusionPatternShader, gfx::Backend::Type::Met
|
||||
static constexpr auto vertexMainFunction = "vertexMain";
|
||||
static constexpr auto fragmentMainFunction = "fragmentMain";
|
||||
|
||||
static const std::array<AttributeInfo, 5> attributes;
|
||||
static const std::array<AttributeInfo, 6> attributes;
|
||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||
static const std::array<TextureInfo, 1> textures;
|
||||
|
||||
@@ -340,18 +341,19 @@ struct ShaderSource<BuiltIn::FillExtrusionPatternShader, gfx::Backend::Type::Met
|
||||
|
||||
struct VertexStage {
|
||||
short2 pos [[attribute(0)]];
|
||||
ushort2 decimals_ed [[attribute(1)]];
|
||||
|
||||
#if !defined(HAS_UNIFORM_u_base)
|
||||
float base [[attribute(1)]];
|
||||
float base [[attribute(2)]];
|
||||
#endif
|
||||
#if !defined(HAS_UNIFORM_u_height)
|
||||
float height [[attribute(2)]];
|
||||
float height [[attribute(3)]];
|
||||
#endif
|
||||
#if !defined(HAS_UNIFORM_u_pattern_from)
|
||||
ushort4 pattern_from [[attribute(3)]];
|
||||
ushort4 pattern_from [[attribute(4)]];
|
||||
#endif
|
||||
#if !defined(HAS_UNIFORM_u_pattern_to)
|
||||
ushort4 pattern_to [[attribute(4)]];
|
||||
ushort4 pattern_to [[attribute(5)]];
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -398,7 +400,9 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
|
||||
const float3 normal = float3(0.0, 0.0, 1.0);
|
||||
const float t = 1.0;
|
||||
const float z = (t != 0.0) ? height : base; // TODO: This would come out wrong on GL for negative values, check it...
|
||||
const float4 position = drawable.matrix * float4(float2(vertx.pos), z, 1);
|
||||
const float2 decimals = unpack_float(float(vertx.decimals_ed.x / 2)) / 128.0;
|
||||
|
||||
const float4 position = drawable.matrix * float4(float2(vertx.pos) + decimals, z, 1);
|
||||
|
||||
#if defined(OVERDRAW_INSPECTOR)
|
||||
return {
|
||||
@@ -441,12 +445,14 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
|
||||
float directional = clamp(dot(normal, props.light_position_base.xyz), 0.0, 1.0);
|
||||
directional = mix((1.0 - props.light_intensity), max((0.5 + props.light_intensity), 1.0), directional);
|
||||
|
||||
if (normal.y != 0.0) {
|
||||
if (normal.z == 0.0) {
|
||||
// This avoids another branching statement, but multiplies by a constant of 0.84 if no vertical gradient,
|
||||
// and otherwise calculates the gradient based on base + height
|
||||
directional *= (
|
||||
(1.0 - props.vertical_gradient) +
|
||||
(props.vertical_gradient * clamp((t + base) * pow(height / 150.0, 0.5), mix(0.7, 0.98, 1.0 - props.light_intensity), 1.0)));
|
||||
// TODO: If we're optimizing to the level of avoiding branches, we should pre-compute
|
||||
// the square root when height is a uniform.
|
||||
const float fMin = mix(0.7, 0.98, 1.0 - props.light_intensity);
|
||||
const float factor = clamp((t + base) * pow(height / 150.0, 0.5), fMin, 1.0);
|
||||
directional *= (1.0 - props.vertical_gradient) + (props.vertical_gradient * factor);
|
||||
}
|
||||
|
||||
lighting.rgb += clamp(directional * props.light_color_pad.rgb, mix(float3(0.0), float3(0.3), 1.0 - props.light_color_pad.rgb), float3(1.0));
|
||||
@@ -539,7 +545,7 @@ struct VertexStage {
|
||||
|
||||
struct OutlineInstance {
|
||||
short2 pos;
|
||||
ushort2 ed_discard;
|
||||
ushort2 decimals_ed;
|
||||
};
|
||||
|
||||
struct FragmentStage {
|
||||
@@ -570,7 +576,8 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
|
||||
uint instanceID [[ instance_id ]],
|
||||
device const OutlineInstance* outline [[buffer(fillExtrusionUBOCount + 1)]]) {
|
||||
|
||||
if (outline[instanceID].ed_discard.y) {
|
||||
bool isDiscarded = glMod(float(outline[instanceID].decimals_ed.x), 2.0) > 0.0;
|
||||
if (isDiscarded) {
|
||||
return {
|
||||
.position = float4(0.0),
|
||||
.lighting = float4(0.0),
|
||||
@@ -600,19 +607,16 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
|
||||
const auto height = max(unpack_mix_float(vertx.height, drawable.height_t), 0.0);
|
||||
#endif
|
||||
|
||||
float2 p1 = float2(outline[instanceID + 1].pos);
|
||||
float2 p2 = float2(outline[instanceID + 0].pos);
|
||||
float2 perp = p1 - p2;
|
||||
float magnitude = sqrt(perp.x * perp.x + perp.y * perp.y);
|
||||
if (magnitude > 0) {
|
||||
perp = perp / magnitude;
|
||||
}
|
||||
const float2 p1 = float2(outline[instanceID + 0].pos) + unpack_float(float(outline[instanceID + 0].decimals_ed.x / 2)) / 128.0;
|
||||
const float2 p2 = float2(outline[instanceID + 1].pos) + unpack_float(float(outline[instanceID + 1].decimals_ed.x / 2)) / 128.0;
|
||||
const float2 edgevector = normalize(p2 - p1);
|
||||
|
||||
const float3 normal = float3(-perp.y, perp.x, 0.0);
|
||||
const float edgedistance = outline[instanceID + 1 - vertx.pos.x].ed_discard.x;
|
||||
const float3 normal = float3(-edgevector.y, edgevector.x, 0.0);
|
||||
const float edgedistance = outline[instanceID + 1 - vertx.pos.x].decimals_ed.y;
|
||||
const float t = float(vertx.pos.y);
|
||||
const float z = (t != 0.0) ? height : base; // TODO: This would come out wrong on GL for negative values, check it...
|
||||
const float4 position = drawable.matrix * float4(float2(outline[instanceID + vertx.pos.x].pos), z, 1);
|
||||
|
||||
const float4 position = drawable.matrix * float4(vertx.pos.x == 0.0 ? p1 : p2, z, 1);
|
||||
|
||||
#if defined(OVERDRAW_INSPECTOR)
|
||||
return {
|
||||
@@ -660,12 +664,14 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
|
||||
float directional = clamp(dot(normal, props.light_position_base.xyz), 0.0, 1.0);
|
||||
directional = mix((1.0 - props.light_intensity), max((0.5 + props.light_intensity), 1.0), directional);
|
||||
|
||||
if (normal.y != 0.0) {
|
||||
if (normal.z == 0.0) {
|
||||
// This avoids another branching statement, but multiplies by a constant of 0.84 if no vertical gradient,
|
||||
// and otherwise calculates the gradient based on base + height
|
||||
directional *= (
|
||||
(1.0 - props.vertical_gradient) +
|
||||
(props.vertical_gradient * clamp((t + base) * pow(height / 150.0, 0.5), mix(0.7, 0.98, 1.0 - props.light_intensity), 1.0)));
|
||||
// TODO: If we're optimizing to the level of avoiding branches, we should pre-compute
|
||||
// the square root when height is a uniform.
|
||||
const float fMin = mix(0.7, 0.98, 1.0 - props.light_intensity);
|
||||
const float factor = clamp((t + base) * pow(height / 150.0, 0.5), fMin, 1.0);
|
||||
directional *= (1.0 - props.vertical_gradient) + (props.vertical_gradient * factor);
|
||||
}
|
||||
|
||||
lighting.rgb += clamp(directional * props.light_color_pad.rgb, mix(float3(0.0), float3(0.3), 1.0 - props.light_color_pad.rgb), float3(1.0));
|
||||
|
||||
@@ -450,12 +450,12 @@ enum {
|
||||
|
||||
enum {
|
||||
idFillExtrusionPosVertexAttribute,
|
||||
idFillExtrusionDecimalsEdAttribute,
|
||||
|
||||
#if MLN_USE_FILL_EXTRUSION_INSTANCING
|
||||
idFillExtrusionOutlinePosAttribute,
|
||||
idFillExtrusionEdDiscardAttribute,
|
||||
#else
|
||||
idFillExtrusionNormalEdVertexAttribute,
|
||||
idFillExtrusionNormal2DVertexAttribute,
|
||||
#endif
|
||||
|
||||
// Data driven
|
||||
|
||||
@@ -19,7 +19,7 @@ template <>
|
||||
struct ShaderSource<BuiltIn::FillExtrusionShader, gfx::Backend::Type::Vulkan> {
|
||||
static constexpr const char* name = "FillExtrusionShader";
|
||||
|
||||
static const std::array<AttributeInfo, 4> attributes;
|
||||
static const std::array<AttributeInfo, 5> attributes;
|
||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||
static const std::array<TextureInfo, 0> textures;
|
||||
|
||||
@@ -27,17 +27,18 @@ struct ShaderSource<BuiltIn::FillExtrusionShader, gfx::Backend::Type::Vulkan> {
|
||||
static constexpr auto vertex = R"(
|
||||
|
||||
layout(location = 0) in ivec2 in_position;
|
||||
layout(location = 1) in uvec2 in_decimals_ed;
|
||||
|
||||
#if !defined(HAS_UNIFORM_u_color)
|
||||
layout(location = 1) in vec4 in_color;
|
||||
layout(location = 2) in vec4 in_color;
|
||||
#endif
|
||||
|
||||
#if !defined(HAS_UNIFORM_u_base)
|
||||
layout(location = 2) in vec2 in_base;
|
||||
layout(location = 3) in vec2 in_base;
|
||||
#endif
|
||||
|
||||
#if !defined(HAS_UNIFORM_u_height)
|
||||
layout(location = 3) in vec2 in_height;
|
||||
layout(location = 4) in vec2 in_height;
|
||||
#endif
|
||||
|
||||
layout(push_constant) uniform Constants {
|
||||
@@ -102,9 +103,10 @@ void main() {
|
||||
|
||||
const vec3 normal = vec3(0.0, 0.0, 1.0);
|
||||
const float t = 1.0;
|
||||
const float z = t != 0.0 ? height : base;
|
||||
const float z = t > 0.0 ? height : base;
|
||||
const vec2 decimals = unpack_float(floor(in_decimals_ed.x / 2)) / 128.0;
|
||||
|
||||
gl_Position = drawable.matrix * vec4(in_position, z, 1.0);
|
||||
gl_Position = drawable.matrix * vec4(in_position + decimals, z, 1.0);
|
||||
applySurfaceTransform();
|
||||
|
||||
#if defined(OVERDRAW_INSPECTOR)
|
||||
@@ -130,7 +132,7 @@ void main() {
|
||||
float directional = mix(minDirectional, maxDirectional, directionalFraction);
|
||||
|
||||
// Add gradient along z axis of side surfaces
|
||||
if (normal.y != 0.0) {
|
||||
if (normal.z == 0.0) {
|
||||
// This avoids another branching statement, but multiplies by a constant of 0.84 if no
|
||||
// vertical gradient, and otherwise calculates the gradient based on base + height
|
||||
// TODO: If we're optimizing to the level of avoiding branches, we should pre-compute
|
||||
@@ -226,7 +228,7 @@ layout(set = LAYER_SET_INDEX, binding = idFillExtrusionPropsUBO) uniform FillExt
|
||||
|
||||
struct OutlineInstance {
|
||||
int pos;
|
||||
uint ed_discard;
|
||||
uint decimals_ed;
|
||||
};
|
||||
|
||||
layout(std430, set = DRAWABLE_UBO_SET_INDEX, binding = idFillExtrusionInstancedDrawableUBO) readonly buffer FillExtrusionInstanceVector {
|
||||
@@ -238,9 +240,10 @@ layout(location = 0) out mediump vec4 frag_color;
|
||||
void main() {
|
||||
|
||||
const vec2 instancePos = unpack_int(instanceVector.instance[gl_InstanceIndex].pos);
|
||||
const vec2 instanceEd = unpack_uint(instanceVector.instance[gl_InstanceIndex].ed_discard);
|
||||
const vec2 instanceDecimalsEd = unpack_uint(instanceVector.instance[gl_InstanceIndex].decimals_ed);
|
||||
|
||||
if (instanceEd.y > 0.0) {
|
||||
bool isDiscarded = mod(instanceDecimalsEd.x, 2.0) > 0.0;
|
||||
if (isDiscarded) {
|
||||
gl_Position = vec4(0.0);
|
||||
frag_color = vec4(0.0);
|
||||
return;
|
||||
@@ -265,16 +268,18 @@ void main() {
|
||||
#else
|
||||
vec4 color = unpack_mix_color(in_color, drawable.color_t);
|
||||
#endif
|
||||
const vec2 nextInstancePos = unpack_int(instanceVector.instance[gl_InstanceIndex + 1].pos);
|
||||
const vec2 nextInstanceDecimalsEd = unpack_uint(instanceVector.instance[gl_InstanceIndex + 1].decimals_ed);
|
||||
|
||||
const vec2 p1 = unpack_int(instanceVector.instance[gl_InstanceIndex + 1].pos);
|
||||
const vec2 p2 = unpack_int(instanceVector.instance[gl_InstanceIndex + 0].pos);
|
||||
const vec2 perp = normalize(p1 - p2);
|
||||
const vec2 p1 = instancePos + unpack_float(floor(instanceDecimalsEd.x / 2)) / 128.0;
|
||||
const vec2 p2 = nextInstancePos + unpack_float(floor(nextInstanceDecimalsEd.x / 2)) / 128.0;
|
||||
const vec2 edgevector = normalize(p2 - p1);
|
||||
|
||||
const vec3 normal = vec3(-perp.y, perp.x, 0.0);
|
||||
const vec3 normal = vec3(-edgevector.y, edgevector.x, 0.0);
|
||||
const float t = float(in_position.y);
|
||||
const float z = t != 0.0 ? height : base;
|
||||
const float z = t > 0.0 ? height : base;
|
||||
|
||||
gl_Position = drawable.matrix * vec4(unpack_int(instanceVector.instance[gl_InstanceIndex + in_position.x].pos), z, 1.0);
|
||||
gl_Position = drawable.matrix * vec4(in_position.x == 0.0 ? p1 : p2, z, 1.0);
|
||||
applySurfaceTransform();
|
||||
|
||||
#if defined(OVERDRAW_INSPECTOR)
|
||||
@@ -300,7 +305,7 @@ void main() {
|
||||
float directional = mix(minDirectional, maxDirectional, directionalFraction);
|
||||
|
||||
// Add gradient along z axis of side surfaces
|
||||
if (normal.y != 0.0) {
|
||||
if (normal.z == 0.0) {
|
||||
// This avoids another branching statement, but multiplies by a constant of 0.84 if no
|
||||
// vertical gradient, and otherwise calculates the gradient based on base + height
|
||||
// TODO: If we're optimizing to the level of avoiding branches, we should pre-compute
|
||||
@@ -336,7 +341,7 @@ template <>
|
||||
struct ShaderSource<BuiltIn::FillExtrusionPatternShader, gfx::Backend::Type::Vulkan> {
|
||||
static constexpr const char* name = "FillExtrusionPatternShader";
|
||||
|
||||
static const std::array<AttributeInfo, 5> attributes;
|
||||
static const std::array<AttributeInfo, 6> attributes;
|
||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||
static const std::array<TextureInfo, 1> textures;
|
||||
|
||||
@@ -344,21 +349,22 @@ struct ShaderSource<BuiltIn::FillExtrusionPatternShader, gfx::Backend::Type::Vul
|
||||
static constexpr auto vertex = R"(
|
||||
|
||||
layout(location = 0) in ivec2 in_position;
|
||||
layout(location = 1) in uvec2 in_decimals_ed;
|
||||
|
||||
#if !defined(HAS_UNIFORM_u_base)
|
||||
layout(location = 1) in vec2 in_base;
|
||||
layout(location = 2) in vec2 in_base;
|
||||
#endif
|
||||
|
||||
#if !defined(HAS_UNIFORM_u_height)
|
||||
layout(location = 2) in vec2 in_height;
|
||||
layout(location = 3) in vec2 in_height;
|
||||
#endif
|
||||
|
||||
#if !defined(HAS_UNIFORM_u_pattern_from)
|
||||
layout(location = 3) in uvec4 in_pattern_from;
|
||||
layout(location = 4) in uvec4 in_pattern_from;
|
||||
#endif
|
||||
|
||||
#if !defined(HAS_UNIFORM_u_pattern_to)
|
||||
layout(location = 4) in uvec4 in_pattern_to;
|
||||
layout(location = 5) in uvec4 in_pattern_to;
|
||||
#endif
|
||||
|
||||
layout(push_constant) uniform Constants {
|
||||
@@ -440,9 +446,10 @@ void main() {
|
||||
|
||||
const vec3 normal = vec3(0.0, 0.0, 1.0);
|
||||
const float t = 1.0;
|
||||
const float z = t != 0.0 ? height : base;
|
||||
const float z = t > 0.0 ? height : base;
|
||||
const vec2 decimals = unpack_float(floor(in_decimals_ed.x / 2)) / 128.0;
|
||||
|
||||
gl_Position = drawable.matrix * vec4(in_position, z, 1.0);
|
||||
gl_Position = drawable.matrix * vec4(in_position + decimals, z, 1.0);
|
||||
applySurfaceTransform();
|
||||
|
||||
#if defined(OVERDRAW_INSPECTOR)
|
||||
@@ -487,13 +494,14 @@ void main() {
|
||||
float directional = clamp(dot(normal, props.light_position_base.xyz), 0.0, 1.0);
|
||||
directional = mix((1.0 - props.light_intensity), max((0.5 + props.light_intensity), 1.0), directional);
|
||||
|
||||
if (normal.y != 0.0) {
|
||||
// This avoids another branching statement, but multiplies by a constant of 0.84 if no vertical gradient,
|
||||
// and otherwise calculates the gradient based on base + height
|
||||
directional *= (
|
||||
(1.0 - props.vertical_gradient) +
|
||||
(props.vertical_gradient * clamp((t + base) * pow(height / 150.0, 0.5), mix(0.7, 0.98, 1.0 - props.light_intensity), 1.0)));
|
||||
}
|
||||
if (normal.z == 0.0) {
|
||||
// This avoids another branching statement, but multiplies by a constant of 0.84 if no
|
||||
// vertical gradient, and otherwise calculates the gradient based on base + height
|
||||
// TODO: If we're optimizing to the level of avoiding branches, we should pre-compute
|
||||
// the square root when height is a uniform.
|
||||
const float fMin = mix(0.7, 0.98, 1.0 - props.light_intensity);
|
||||
const float factor = clamp((t + base) * pow(height / 150.0, 0.5), fMin, 1.0);
|
||||
directional *= (1.0 - props.vertical_gradient) + (props.vertical_gradient * factor); }
|
||||
|
||||
lighting.rgb += clamp(directional * props.light_color_pad.rgb, mix(vec3(0.0), vec3(0.3), 1.0 - props.light_color_pad.rgb), vec3(1.0));
|
||||
lighting *= props.opacity;
|
||||
@@ -652,7 +660,7 @@ layout(std140, set = LAYER_SET_INDEX, binding = idFillExtrusionDrawableUBO) read
|
||||
|
||||
struct OutlineInstance {
|
||||
int pos;
|
||||
uint ed_discard;
|
||||
uint decimals_ed;
|
||||
};
|
||||
|
||||
layout(std430, set = DRAWABLE_UBO_SET_INDEX, binding = idFillExtrusionInstancedDrawableUBO) readonly buffer FillExtrusionInstanceVector {
|
||||
@@ -699,9 +707,10 @@ layout(location = 4) out mediump vec4 frag_pattern_to;
|
||||
|
||||
void main() {
|
||||
const vec2 instancePos = unpack_int(instanceVector.instance[gl_InstanceIndex].pos);
|
||||
const vec2 instanceEd = unpack_uint(instanceVector.instance[gl_InstanceIndex].ed_discard);
|
||||
const vec2 instanceDecimalsEd = unpack_uint(instanceVector.instance[gl_InstanceIndex].decimals_ed);
|
||||
|
||||
if (instanceEd.y > 0.0) {
|
||||
bool isDiscarded = mod(instanceDecimalsEd.x, 2.0) > 0.0;
|
||||
if (isDiscarded) {
|
||||
gl_Position = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
@@ -720,17 +729,19 @@ void main() {
|
||||
#else
|
||||
const float height = max(unpack_mix_float(in_height, drawable.height_t), 0.0);
|
||||
#endif
|
||||
const vec2 nextInstancePos = unpack_int(instanceVector.instance[gl_InstanceIndex + 1].pos);
|
||||
const vec2 nextInstanceDecimalsEd = unpack_uint(instanceVector.instance[gl_InstanceIndex + 1].decimals_ed);
|
||||
|
||||
const vec2 p1 = unpack_int(instanceVector.instance[gl_InstanceIndex + 1].pos);
|
||||
const vec2 p2 = unpack_int(instanceVector.instance[gl_InstanceIndex + 0].pos);
|
||||
const vec2 perp = normalize(p1 - p2);
|
||||
const vec2 p1 = instancePos + unpack_float(floor(instanceDecimalsEd.x / 2)) / 128.0;
|
||||
const vec2 p2 = nextInstancePos + unpack_float(floor(nextInstanceDecimalsEd.x / 2)) / 128.0;
|
||||
const vec2 edgevector = normalize(p2 - p1);
|
||||
|
||||
const vec3 normal = vec3(-perp.y, perp.x, 0.0);
|
||||
const float edgedistance = unpack_uint(instanceVector.instance[gl_InstanceIndex + 1 - in_position.x].ed_discard).x;
|
||||
const vec3 normal = vec3(-edgevector.y, edgevector.x, 0.0);
|
||||
const float edgedistance = in_position.x == 0.0 ? nextInstanceDecimalsEd.y : instanceDecimalsEd.y;
|
||||
const float t = float(in_position.y);
|
||||
const float z = t != 0.0 ? height : base;
|
||||
const float z = t > 0.0 ? height : base;
|
||||
|
||||
gl_Position = drawable.matrix * vec4(unpack_int(instanceVector.instance[gl_InstanceIndex + in_position.x].pos), z, 1.0);
|
||||
gl_Position = drawable.matrix * vec4(in_position.x == 0.0 ? p1 : p2, z, 1.0);
|
||||
applySurfaceTransform();
|
||||
|
||||
#if defined(OVERDRAW_INSPECTOR)
|
||||
@@ -775,12 +786,14 @@ void main() {
|
||||
float directional = clamp(dot(normal, props.light_position_base.xyz), 0.0, 1.0);
|
||||
directional = mix((1.0 - props.light_intensity), max((0.5 + props.light_intensity), 1.0), directional);
|
||||
|
||||
if (normal.y != 0.0) {
|
||||
// This avoids another branching statement, but multiplies by a constant of 0.84 if no vertical gradient,
|
||||
// and otherwise calculates the gradient based on base + height
|
||||
directional *= (
|
||||
(1.0 - props.vertical_gradient) +
|
||||
(props.vertical_gradient * clamp((t + base) * pow(height / 150.0, 0.5), mix(0.7, 0.98, 1.0 - props.light_intensity), 1.0)));
|
||||
if (normal.z == 0.0) {
|
||||
// This avoids another branching statement, but multiplies by a constant of 0.84 if no
|
||||
// vertical gradient, and otherwise calculates the gradient based on base + height
|
||||
// TODO: If we're optimizing to the level of avoiding branches, we should pre-compute
|
||||
// the square root when height is a uniform.
|
||||
const float fMin = mix(0.7, 0.98, 1.0 - props.light_intensity);
|
||||
const float factor = clamp((t + base) * pow(height / 150.0, 0.5), fMin, 1.0);
|
||||
directional *= (1.0 - props.vertical_gradient) + (props.vertical_gradient * factor);
|
||||
}
|
||||
|
||||
lighting.rgb += clamp(directional * props.light_color_pad.rgb, mix(vec3(0.0), vec3(0.3), 1.0 - props.light_color_pad.rgb), vec3(1.0));
|
||||
|
||||
@@ -10,22 +10,23 @@ namespace shaders {
|
||||
template <>
|
||||
struct ShaderSource<BuiltIn::FillExtrusionShader, gfx::Backend::Type::WebGPU> {
|
||||
static constexpr const char* name = "FillExtrusionShader";
|
||||
static const std::array<AttributeInfo, 5> attributes;
|
||||
static const std::array<AttributeInfo, 6> attributes;
|
||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||
static const std::array<TextureInfo, 0> textures;
|
||||
|
||||
static constexpr auto vertex = R"(
|
||||
struct VertexInput {
|
||||
@location(3) position: vec2<i32>,
|
||||
@location(4) normal_ed: vec4<i32>,
|
||||
@location(4) decimals_ed: vec2<u32>,
|
||||
@location(5) normal2d: vec2<i32>,
|
||||
#ifndef HAS_UNIFORM_u_color
|
||||
@location(5) color: vec4<f32>,
|
||||
@location(6) color: vec4<f32>,
|
||||
#endif
|
||||
#ifndef HAS_UNIFORM_u_base
|
||||
@location(6) base: vec2<f32>,
|
||||
@location(7) base: vec2<f32>,
|
||||
#endif
|
||||
#ifndef HAS_UNIFORM_u_height
|
||||
@location(7) height: vec2<f32>,
|
||||
@location(8) height: vec2<f32>,
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -88,11 +89,13 @@ fn main(in: VertexInput) -> VertexOutput {
|
||||
let heightValue = max(props.height, 0.0);
|
||||
#endif
|
||||
|
||||
let normal_i = vec3<f32>(f32(in.normal_ed.x), f32(in.normal_ed.y), f32(in.normal_ed.z));
|
||||
let t = glMod(normal_i.x, 2.0);
|
||||
let z = select(baseValue, heightValue, t != 0.0);
|
||||
let normal = vec3<f32>(vec2<f32>(in.normal2d) / 16384.0, select(0.0, 1.0, in.normal2d.x == 0 && in.normal2d.y == 0));
|
||||
|
||||
out.position = drawable.matrix * vec4<f32>(f32(in.position.x), f32(in.position.y), z, 1.0);
|
||||
let t = glMod(f32(in.decimals_ed.x), 2.0);
|
||||
let z = select(baseValue, heightValue, t > 0.0);
|
||||
let decimals = unpack_float(f32(in.decimals_ed.x / 2)) / 128.0;
|
||||
|
||||
out.position = drawable.matrix * vec4<f32>(vec2<f32>(in.position) + decimals, z, 1.0);
|
||||
|
||||
#ifdef OVERDRAW_INSPECTOR
|
||||
out.color = vec4<f32>(1.0, 1.0, 1.0, 1.0);
|
||||
@@ -107,13 +110,12 @@ fn main(in: VertexInput) -> VertexOutput {
|
||||
color = color + min(vec4<f32>(0.03, 0.03, 0.03, 1.0), vec4<f32>(1.0));
|
||||
|
||||
let luminance = dot(color.rgb, vec3<f32>(0.2126, 0.7152, 0.0722));
|
||||
let unitNormal = normal_i / 16384.0;
|
||||
let directionalFraction = clamp(dot(unitNormal, props.light_position_base.xyz), 0.0, 1.0);
|
||||
let directionalFraction = clamp(dot(normal, props.light_position_base.xyz), 0.0, 1.0);
|
||||
let minDirectional = 1.0 - props.light_intensity;
|
||||
let maxDirectional = max(1.0 - luminance + props.light_intensity, 1.0);
|
||||
var directional = mix(minDirectional, maxDirectional, directionalFraction);
|
||||
|
||||
if (normal_i.y != 0.0) {
|
||||
if (normal.z == 0.0) {
|
||||
let gradientMin = mix(0.7, 0.98, 1.0 - props.light_intensity);
|
||||
let factor = clamp((t + baseValue) * pow(heightValue / 150.0, 0.5), gradientMin, 1.0);
|
||||
directional *= (1.0 - props.vertical_gradient) + props.vertical_gradient * factor;
|
||||
@@ -146,25 +148,26 @@ fn main(in: FragmentInput) -> @location(0) vec4<f32> {
|
||||
template <>
|
||||
struct ShaderSource<BuiltIn::FillExtrusionPatternShader, gfx::Backend::Type::WebGPU> {
|
||||
static constexpr const char* name = "FillExtrusionPatternShader";
|
||||
static const std::array<AttributeInfo, 6> attributes;
|
||||
static const std::array<AttributeInfo, 7> attributes;
|
||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||
static const std::array<TextureInfo, 1> textures;
|
||||
|
||||
static constexpr auto vertex = R"(
|
||||
struct VertexInput {
|
||||
@location(3) position: vec2<i32>,
|
||||
@location(4) normal_ed: vec4<i32>,
|
||||
@location(4) decimals_ed: vec2<u32>,
|
||||
@location(5) normal2d: vec2<i32>,
|
||||
#ifndef HAS_UNIFORM_u_base
|
||||
@location(5) base: vec2<f32>,
|
||||
@location(6) base: vec2<f32>,
|
||||
#endif
|
||||
#ifndef HAS_UNIFORM_u_height
|
||||
@location(6) height: vec2<f32>,
|
||||
@location(7) height: vec2<f32>,
|
||||
#endif
|
||||
#ifndef HAS_UNIFORM_u_pattern_from
|
||||
@location(7) pattern_from: vec4<u32>,
|
||||
@location(8) pattern_from: vec4<u32>,
|
||||
#endif
|
||||
#ifndef HAS_UNIFORM_u_pattern_to
|
||||
@location(8) pattern_to: vec4<u32>,
|
||||
@location(9) pattern_to: vec4<u32>,
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -250,16 +253,18 @@ fn main(in: VertexInput) -> VertexOutput {
|
||||
let heightValue = max(props.height, 0.0);
|
||||
#endif
|
||||
|
||||
let normal_i = vec3<f32>(f32(in.normal_ed.x), f32(in.normal_ed.y), f32(in.normal_ed.z));
|
||||
let edgedistance = f32(in.normal_ed.w);
|
||||
let t = glMod(normal_i.x, 2.0);
|
||||
let z = select(baseValue, heightValue, t != 0.0);
|
||||
let normal = vec3<f32>(vec2<f32>(in.normal2d) / 16384.0, select(0.0, 1.0, in.normal2d.x == 0 && in.normal2d.y == 0));
|
||||
let edgedistance = f32(in.decimals_ed.y);
|
||||
|
||||
out.position = drawable.matrix * vec4<f32>(f32(in.position.x), f32(in.position.y), z, 1.0);
|
||||
let t = glMod(f32(in.decimals_ed.x), 2.0);
|
||||
let z = select(baseValue, heightValue, t > 0.0);
|
||||
let decimals = unpack_float(f32(in.decimals_ed.x / 2)) / 128.0;
|
||||
|
||||
out.position = drawable.matrix * vec4<f32>(vec2<f32>(in.position) + decimals, z, 1.0);
|
||||
|
||||
var patternPos: vec2<f32>;
|
||||
if (normal_i.x == 1.0 && normal_i.y == 0.0 && normal_i.z == 16384.0) {
|
||||
patternPos = vec2<f32>(f32(in.position.x), f32(in.position.y));
|
||||
if (normal.z == 1.0) {
|
||||
patternPos = vec2<f32>(in.position);
|
||||
} else {
|
||||
patternPos = vec2<f32>(edgedistance, z * drawable.height_factor);
|
||||
}
|
||||
@@ -294,10 +299,10 @@ fn main(in: VertexInput) -> VertexOutput {
|
||||
(pattern_br_b.y - pattern_tl_b.y) / pixelRatio);
|
||||
|
||||
var lighting = vec4<f32>(0.0, 0.0, 0.0, 1.0);
|
||||
var directional = clamp(dot(normal_i / 16383.0, props.light_position_base.xyz), 0.0, 1.0);
|
||||
var directional = clamp(dot(normal, props.light_position_base.xyz), 0.0, 1.0);
|
||||
directional = mix(1.0 - props.light_intensity, max(0.5 + props.light_intensity, 1.0), directional);
|
||||
|
||||
if (normal_i.y != 0.0) {
|
||||
if (normal.z == 0.0) {
|
||||
let gradientMin = mix(0.7, 0.98, 1.0 - props.light_intensity);
|
||||
let factor = clamp((t + baseValue) * pow(heightValue / 150.0, 0.5), gradientMin, 1.0);
|
||||
directional *= (1.0 - props.vertical_gradient) + props.vertical_gradient * factor;
|
||||
|
||||
@@ -19,6 +19,12 @@ public:
|
||||
FillExtrusionLayer(const std::string& layerID, const std::string& sourceID);
|
||||
~FillExtrusionLayer() override;
|
||||
|
||||
// Layout properties
|
||||
|
||||
static PropertyValue<float> getDefaultFillExtrusionRoundedCornerDistance();
|
||||
const PropertyValue<float>& getFillExtrusionRoundedCornerDistance() const;
|
||||
void setFillExtrusionRoundedCornerDistance(const PropertyValue<float>&);
|
||||
|
||||
// Paint properties
|
||||
|
||||
static PropertyValue<float> getDefaultFillExtrusionBase();
|
||||
|
||||
@@ -39,6 +39,17 @@ FillExtrusionLayer::~FillExtrusionLayer() = default;
|
||||
|
||||
// Property getters
|
||||
|
||||
jni::Local<jni::Object<>> FillExtrusionLayer::getFillExtrusionRoundedCornerDistance(jni::JNIEnv& env) {
|
||||
using namespace mbgl::android::conversion;
|
||||
auto layer = layerPtr.get();
|
||||
if (!layer) {
|
||||
return std::move(*convert<jni::Local<jni::Object<>>>(
|
||||
env, style::FillExtrusionLayer::getDefaultFillExtrusionRoundedCornerDistance()));
|
||||
}
|
||||
return std::move(
|
||||
*convert<jni::Local<jni::Object<>>>(env, toFillExtrusionLayer(*layer).getFillExtrusionRoundedCornerDistance()));
|
||||
}
|
||||
|
||||
jni::Local<jni::Object<>> FillExtrusionLayer::getFillExtrusionOpacity(jni::JNIEnv& env) {
|
||||
using namespace mbgl::android::conversion;
|
||||
auto layer = layerPtr.get();
|
||||
@@ -288,6 +299,8 @@ void FillExtrusionJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) {
|
||||
jni::MakePeer<FillExtrusionLayer, jni::String&, jni::String&>,
|
||||
"initialize",
|
||||
"finalize",
|
||||
METHOD(&FillExtrusionLayer::getFillExtrusionRoundedCornerDistance,
|
||||
"nativeGetFillExtrusionRoundedCornerDistance"),
|
||||
METHOD(&FillExtrusionLayer::getFillExtrusionOpacityTransition, "nativeGetFillExtrusionOpacityTransition"),
|
||||
METHOD(&FillExtrusionLayer::setFillExtrusionOpacityTransition, "nativeSetFillExtrusionOpacityTransition"),
|
||||
METHOD(&FillExtrusionLayer::getFillExtrusionOpacity, "nativeGetFillExtrusionOpacity"),
|
||||
|
||||
@@ -26,6 +26,8 @@ public:
|
||||
|
||||
// Properties
|
||||
|
||||
jni::Local<jni::Object<jni::ObjectTag>> getFillExtrusionRoundedCornerDistance(jni::JNIEnv&);
|
||||
|
||||
jni::Local<jni::Object<jni::ObjectTag>> getFillExtrusionOpacity(jni::JNIEnv&);
|
||||
void setFillExtrusionOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay);
|
||||
jni::Local<jni::Object<TransitionOptions>> getFillExtrusionOpacityTransition(jni::JNIEnv&);
|
||||
|
||||
@@ -143,6 +143,18 @@ public class FillExtrusionLayer extends Layer {
|
||||
|
||||
// Property getters
|
||||
|
||||
/**
|
||||
* Get the FillExtrusionRoundedCornerDistance property
|
||||
*
|
||||
* @return property wrapper value around Float
|
||||
*/
|
||||
@NonNull
|
||||
@SuppressWarnings("unchecked")
|
||||
public PropertyValue<Float> getFillExtrusionRoundedCornerDistance() {
|
||||
checkThread();
|
||||
return (PropertyValue<Float>) new PropertyValue("fill-extrusion-rounded-corner-distance", nativeGetFillExtrusionRoundedCornerDistance());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the FillExtrusionOpacity property
|
||||
*
|
||||
@@ -382,6 +394,10 @@ public class FillExtrusionLayer extends Layer {
|
||||
return (PropertyValue<Boolean>) new PropertyValue("fill-extrusion-vertical-gradient", nativeGetFillExtrusionVerticalGradient());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Keep
|
||||
private native Object nativeGetFillExtrusionRoundedCornerDistance();
|
||||
|
||||
@NonNull
|
||||
@Keep
|
||||
private native Object nativeGetFillExtrusionOpacity();
|
||||
|
||||
@@ -2767,4 +2767,24 @@ The unit is in density-independent pixels only for SDF sprites that were created
|
||||
return new LayoutPropertyValue<>("circle-sort-key", value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The distance from the corner that will be cut and replaced with rounded corner.
|
||||
*
|
||||
* @param value a Float value
|
||||
* @return property wrapper around Float
|
||||
*/
|
||||
public static PropertyValue<Float> fillExtrusionRoundedCornerDistance(Float value) {
|
||||
return new LayoutPropertyValue<>("fill-extrusion-rounded-corner-distance", value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The distance from the corner that will be cut and replaced with rounded corner.
|
||||
*
|
||||
* @param value a Float value
|
||||
* @return property wrapper around Float
|
||||
*/
|
||||
public static PropertyValue<Expression> fillExtrusionRoundedCornerDistance(Expression value) {
|
||||
return new LayoutPropertyValue<>("fill-extrusion-rounded-corner-distance", value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -175,6 +175,19 @@ public class FillExtrusionLayerTest extends BaseLayerTest {
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillExtrusionRoundedCornerDistanceAsConstant() {
|
||||
Timber.i("fill-extrusion-rounded-corner-distance");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getFillExtrusionRoundedCornerDistance().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(fillExtrusionRoundedCornerDistance(propertyValue));
|
||||
assertEquals(layer.getFillExtrusionRoundedCornerDistance().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillExtrusionOpacityTransition() {
|
||||
|
||||
@@ -1050,6 +1050,20 @@
|
||||
}
|
||||
},
|
||||
"layout_fill-extrusion": {
|
||||
"fill-extrusion-rounded-corner-distance": {
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"minimum": 0,
|
||||
"units": "meters",
|
||||
"doc": "The distance from the corner that will be cut and replaced with rounded corner.",
|
||||
"sdk-support": {
|
||||
"basic functionality": {
|
||||
"android": "13.0.0",
|
||||
"ios": "6.0.0"
|
||||
}
|
||||
},
|
||||
"property-type": "constant"
|
||||
},
|
||||
"visibility": {
|
||||
"type": "enum",
|
||||
"values": {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
layout (location = 0) in vec2 a_pos;
|
||||
layout (location = 1) in vec4 a_normal_ed;
|
||||
layout (location = 1) in vec2 a_decimals_ed;
|
||||
layout (location = 2) in vec2 a_normal2d;
|
||||
out vec4 v_color;
|
||||
|
||||
layout (std140) uniform FillExtrusionDrawableUBO {
|
||||
@@ -50,14 +51,16 @@ void main() {
|
||||
#pragma mapbox: initialize highp float height
|
||||
#pragma mapbox: initialize highp vec4 color
|
||||
|
||||
vec3 normal = a_normal_ed.xyz;
|
||||
vec3 normal = vec3(a_normal2d / 16384.0, a_normal2d.x == 0.0 && a_normal2d.y == 0.0 ? 1.0 : 0.0);
|
||||
|
||||
base = max(0.0, base);
|
||||
height = max(0.0, height);
|
||||
|
||||
float t = mod(normal.x, 2.0);
|
||||
float t = mod(a_decimals_ed.x, 2.0);
|
||||
float z = t > 0.0 ? height : base;
|
||||
vec2 decimals = unpack_float(floor(a_decimals_ed.x / 2.0)) / 128.0;
|
||||
|
||||
gl_Position = u_matrix * vec4(a_pos, t > 0.0 ? height : base, 1);
|
||||
gl_Position = u_matrix * vec4(a_pos + decimals, z, 1);
|
||||
|
||||
// Relative luminance (how dark/bright is the surface color?)
|
||||
float colorvalue = color.r * 0.2126 + color.g * 0.7152 + color.b * 0.0722;
|
||||
@@ -69,7 +72,7 @@ void main() {
|
||||
color += ambientlight;
|
||||
|
||||
// Calculate cos(theta), where theta is the angle between surface normal and diffuse light ray
|
||||
float directional = clamp(dot(normal / 16384.0, u_lightpos), 0.0, 1.0);
|
||||
float directional = clamp(dot(normal, u_lightpos), 0.0, 1.0);
|
||||
|
||||
// Adjust directional so that
|
||||
// the range of values for highlight/shading is narrower
|
||||
@@ -78,12 +81,12 @@ void main() {
|
||||
directional = mix((1.0 - u_lightintensity), max((1.0 - colorvalue + u_lightintensity), 1.0), directional);
|
||||
|
||||
// Add gradient along z axis of side surfaces
|
||||
if (normal.y != 0.0) {
|
||||
if (normal.z == 0.0) {
|
||||
// This avoids another branching statement, but multiplies by a constant of 0.84 if no vertical gradient,
|
||||
// and otherwise calculates the gradient based on base + height
|
||||
directional *= (
|
||||
(1.0 - u_vertical_gradient) +
|
||||
(u_vertical_gradient * clamp((t + base) * pow(height / 150.0, 0.5), mix(0.7, 0.98, 1.0 - u_lightintensity), 1.0)));
|
||||
float fMin = mix(0.7, 0.98, 1.0 - u_lightintensity);
|
||||
float factor = clamp((t + base) * pow(height / 150.0, 0.5), fMin, 1.0);
|
||||
directional *= (1.0 - u_vertical_gradient) + (u_vertical_gradient * factor);
|
||||
}
|
||||
|
||||
// Assign final color based on surface + ambient light color, diffuse light directional, and light color
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
layout (location = 0) in vec2 a_pos;
|
||||
layout (location = 1) in vec4 a_normal_ed;
|
||||
layout (location = 1) in vec2 a_decimals_ed;
|
||||
layout (location = 2) in vec2 a_normal2d;
|
||||
|
||||
out vec2 v_pos_a;
|
||||
out vec2 v_pos_b;
|
||||
@@ -77,8 +78,8 @@ void main() {
|
||||
float fromScale = u_from_scale;
|
||||
float toScale = u_to_scale;
|
||||
|
||||
vec3 normal = a_normal_ed.xyz;
|
||||
float edgedistance = a_normal_ed.w;
|
||||
vec3 normal = vec3(a_normal2d / 16384.0, a_normal2d.x == 0.0 && a_normal2d.y == 0.0 ? 1.0 : 0.0);
|
||||
float edgedistance = a_decimals_ed.y;
|
||||
|
||||
vec2 display_size_a = vec2((pattern_br_a.x - pattern_tl_a.x) / pixelRatio, (pattern_br_a.y - pattern_tl_a.y) / pixelRatio);
|
||||
vec2 display_size_b = vec2((pattern_br_b.x - pattern_tl_b.x) / pixelRatio, (pattern_br_b.y - pattern_tl_b.y) / pixelRatio);
|
||||
@@ -86,28 +87,28 @@ void main() {
|
||||
base = max(0.0, base);
|
||||
height = max(0.0, height);
|
||||
|
||||
float t = mod(normal.x, 2.0);
|
||||
float t = mod(a_decimals_ed.x, 2.0);
|
||||
float z = t > 0.0 ? height : base;
|
||||
vec2 decimals = unpack_float(floor(a_decimals_ed.x / 2.0)) / 128.0;
|
||||
|
||||
gl_Position = u_matrix * vec4(a_pos, z, 1);
|
||||
gl_Position = u_matrix * vec4(a_pos + decimals, z, 1);
|
||||
|
||||
vec2 pos = normal.x == 1.0 && normal.y == 0.0 && normal.z == 16384.0
|
||||
? a_pos // extrusion top
|
||||
: vec2(edgedistance, z * u_height_factor); // extrusion side
|
||||
// extrusion top or side
|
||||
vec2 pos = normal.z == 1.0 ? a_pos : vec2(edgedistance, z * u_height_factor);
|
||||
|
||||
v_pos_a = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, fromScale * display_size_a, tileRatio, pos);
|
||||
v_pos_b = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, toScale * display_size_b, tileRatio, pos);
|
||||
|
||||
v_lighting = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
float directional = clamp(dot(normal / 16383.0, u_lightpos), 0.0, 1.0);
|
||||
float directional = clamp(dot(normal, u_lightpos), 0.0, 1.0);
|
||||
directional = mix((1.0 - u_lightintensity), max((0.5 + u_lightintensity), 1.0), directional);
|
||||
|
||||
if (normal.y != 0.0) {
|
||||
if (normal.z == 0.0) {
|
||||
// This avoids another branching statement, but multiplies by a constant of 0.84 if no vertical gradient,
|
||||
// and otherwise calculates the gradient based on base + height
|
||||
directional *= (
|
||||
(1.0 - u_vertical_gradient) +
|
||||
(u_vertical_gradient * clamp((t + base) * pow(height / 150.0, 0.5), mix(0.7, 0.98, 1.0 - u_lightintensity), 1.0)));
|
||||
float fMin = mix(0.7, 0.98, 1.0 - u_lightintensity);
|
||||
float factor = clamp((t + base) * pow(height / 150.0, 0.5), fMin, 1.0);
|
||||
directional *= (1.0 - u_vertical_gradient) + (u_vertical_gradient * factor);
|
||||
}
|
||||
|
||||
v_lighting.rgb += clamp(directional * u_lightcolor, mix(vec3(0.0), vec3(0.3), 1.0 - u_lightcolor), vec3(1.0));
|
||||
|
||||
@@ -22,7 +22,10 @@ std::unique_ptr<Layout> FillExtrusionLayerFactory::createLayout(
|
||||
std::unique_ptr<GeometryTileLayer> layer,
|
||||
const std::vector<Immutable<style::LayerProperties>>& group) {
|
||||
using namespace style;
|
||||
using LayoutType = PatternLayout<FillExtrusionBucket, FillExtrusionLayerProperties, FillExtrusionPattern>;
|
||||
using LayoutType = PatternLayout<FillExtrusionBucket,
|
||||
FillExtrusionLayerProperties,
|
||||
FillExtrusionPattern,
|
||||
FillExtrusionLayoutProperties>;
|
||||
return std::unique_ptr<Layout>(new (std::nothrow)
|
||||
LayoutType(parameters.bucketParameters, group, std::move(layer), parameters));
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include <mbgl/util/math.hpp>
|
||||
#include <mbgl/util/constants.hpp>
|
||||
|
||||
#include <variant>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4244)
|
||||
@@ -30,6 +32,16 @@ template <>
|
||||
struct nth<1, mbgl::GeometryCoordinate> {
|
||||
static int64_t get(const mbgl::GeometryCoordinate& t) { return t.y; };
|
||||
};
|
||||
|
||||
template <>
|
||||
struct nth<0, mbgl::GeometryCoordinateFloat> {
|
||||
static float get(const mbgl::GeometryCoordinateFloat& t) { return t.x; };
|
||||
};
|
||||
|
||||
template <>
|
||||
struct nth<1, mbgl::GeometryCoordinateFloat> {
|
||||
static float get(const mbgl::GeometryCoordinateFloat& t) { return t.y; };
|
||||
};
|
||||
} // namespace util
|
||||
} // namespace mapbox
|
||||
|
||||
@@ -40,10 +52,11 @@ using namespace style;
|
||||
struct GeometryTooLongException : std::exception {};
|
||||
|
||||
FillExtrusionBucket::FillExtrusionBucket(
|
||||
const FillExtrusionBucket::PossiblyEvaluatedLayoutProperties&,
|
||||
const FillExtrusionBucket::PossiblyEvaluatedLayoutProperties& layout_,
|
||||
const std::map<std::string, Immutable<style::LayerProperties>>& layerPaintProperties,
|
||||
const float zoom,
|
||||
const uint32_t) {
|
||||
const uint32_t)
|
||||
: layout(std::move(layout_)) {
|
||||
for (const auto& pair : layerPaintProperties) {
|
||||
paintPropertyBinders.emplace(
|
||||
std::piecewise_construct,
|
||||
@@ -66,12 +79,22 @@ void FillExtrusionBucket::addFeature(const GeometryTileFeature& feature,
|
||||
// Optimize polygons with many interior rings for earcut tessellation.
|
||||
limitHoles(polygon, 500);
|
||||
|
||||
std::variant<GeometryCollection, GeometryCollectionFloat> polyVariant = polygon;
|
||||
double roundedCornerDistance = layout.get<FillExtrusionRoundedCornerDistance>();
|
||||
if (roundedCornerDistance > 0) {
|
||||
polyVariant = roundPolygonCorners(polygon, roundedCornerDistance);
|
||||
}
|
||||
|
||||
std::size_t totalVertices = 0;
|
||||
|
||||
for (const auto& ring : polygon) {
|
||||
std::visit(
|
||||
[&totalVertices](const auto& poly) {
|
||||
for (const auto& ring : poly) {
|
||||
totalVertices += ring.size();
|
||||
if (totalVertices > std::numeric_limits<uint16_t>::max()) throw GeometryTooLongException();
|
||||
}
|
||||
},
|
||||
polyVariant);
|
||||
|
||||
if (totalVertices == 0) continue;
|
||||
|
||||
@@ -91,28 +114,15 @@ void FillExtrusionBucket::addFeature(const GeometryTileFeature& feature,
|
||||
|
||||
assert(triangleIndex + (5 * (totalVertices - 1) + 1) <= std::numeric_limits<uint16_t>::max());
|
||||
|
||||
for (const auto& ring : polygon) {
|
||||
std::size_t nVertices = ring.size();
|
||||
|
||||
if (nVertices == 0) continue;
|
||||
|
||||
std::size_t edgeDistance = 0;
|
||||
|
||||
for (std::size_t i = 0; i < nVertices; i++) {
|
||||
const auto& p1 = ring[i];
|
||||
|
||||
const auto processRingPoints =
|
||||
[&](const Point<double>& p1, const std::optional<Point<double>>& p2, std::size_t& edgeDistance) {
|
||||
#if MLN_USE_FILL_EXTRUSION_INSTANCING
|
||||
vertices.emplace_back(layoutVertex(p1, edgeDistance, i == nVertices - 1));
|
||||
vertices.emplace_back(layoutVertex(p1, edgeDistance, !p2));
|
||||
flatIndices.emplace_back(triangleIndex);
|
||||
triangleIndex++;
|
||||
|
||||
if (i < nVertices - 1) {
|
||||
const auto& p2 = ring[i + 1];
|
||||
|
||||
const auto d1 = convertPoint<double>(p1);
|
||||
const auto d2 = convertPoint<double>(p2);
|
||||
|
||||
const size_t dist = util::dist<uint16_t>(d1, d2);
|
||||
if (p2) {
|
||||
const size_t dist = util::dist<uint16_t>(p1, *p2);
|
||||
if (edgeDistance + dist > static_cast<size_t>(std::numeric_limits<uint16_t>::max())) {
|
||||
edgeDistance = 0;
|
||||
}
|
||||
@@ -120,34 +130,25 @@ void FillExtrusionBucket::addFeature(const GeometryTileFeature& feature,
|
||||
edgeDistance += dist;
|
||||
}
|
||||
#else
|
||||
vertices.emplace_back(
|
||||
FillExtrusionBucket::layoutVertex(p1, 0, 0, 1, 1, static_cast<uint16_t>(edgeDistance)));
|
||||
vertices.emplace_back(FillExtrusionBucket::layoutVertex(p1, 0, 0, 1, edgeDistance));
|
||||
flatIndices.emplace_back(triangleIndex);
|
||||
triangleIndex++;
|
||||
|
||||
if (i != 0) {
|
||||
const auto& p2 = ring[i - 1];
|
||||
if (p2) {
|
||||
const Point<double> perp = util::unit(util::perp(*p2 - p1));
|
||||
|
||||
const auto d1 = convertPoint<double>(p1);
|
||||
const auto d2 = convertPoint<double>(p2);
|
||||
|
||||
const Point<double> perp = util::unit(util::perp(d1 - d2));
|
||||
const size_t dist = util::dist<int16_t>(d1, d2);
|
||||
if (edgeDistance + dist > static_cast<size_t>(std::numeric_limits<int16_t>::max())) {
|
||||
const size_t dist = util::dist<uint16_t>(p1, *p2);
|
||||
if (edgeDistance + dist > static_cast<size_t>(std::numeric_limits<uint16_t>::max())) {
|
||||
edgeDistance = 0;
|
||||
}
|
||||
|
||||
vertices.emplace_back(FillExtrusionBucket::layoutVertex(
|
||||
p1, perp.x, perp.y, 0, 0, static_cast<uint16_t>(edgeDistance)));
|
||||
vertices.emplace_back(FillExtrusionBucket::layoutVertex(
|
||||
p1, perp.x, perp.y, 0, 1, static_cast<uint16_t>(edgeDistance)));
|
||||
vertices.emplace_back(FillExtrusionBucket::layoutVertex(*p2, perp.x, perp.y, 0, edgeDistance));
|
||||
vertices.emplace_back(FillExtrusionBucket::layoutVertex(*p2, perp.x, perp.y, 1, edgeDistance));
|
||||
|
||||
edgeDistance += dist;
|
||||
|
||||
vertices.emplace_back(FillExtrusionBucket::layoutVertex(
|
||||
p2, perp.x, perp.y, 0, 0, static_cast<uint16_t>(edgeDistance)));
|
||||
vertices.emplace_back(FillExtrusionBucket::layoutVertex(
|
||||
p2, perp.x, perp.y, 0, 1, static_cast<uint16_t>(edgeDistance)));
|
||||
vertices.emplace_back(FillExtrusionBucket::layoutVertex(p1, perp.x, perp.y, 0, edgeDistance));
|
||||
vertices.emplace_back(FillExtrusionBucket::layoutVertex(p1, perp.x, perp.y, 1, edgeDistance));
|
||||
|
||||
// ┌──────┐
|
||||
// │ 0 1 │ Counter-Clockwise winding order.
|
||||
@@ -161,10 +162,32 @@ void FillExtrusionBucket::addFeature(const GeometryTileFeature& feature,
|
||||
triangleSegment.indexLength += 6;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
std::vector<uint32_t> indices;
|
||||
std::visit(
|
||||
[&indices, processRingPoints](const auto& poly) {
|
||||
for (const auto& ring : poly) {
|
||||
std::size_t nVertices = ring.size();
|
||||
|
||||
if (nVertices == 0) continue;
|
||||
|
||||
std::size_t edgeDistance = 0;
|
||||
|
||||
for (std::size_t i = 0; i < nVertices; i++) {
|
||||
const auto p1 = convertPoint<double>(ring[i]);
|
||||
|
||||
std::optional<Point<double>> p2 = std::nullopt;
|
||||
if (i < nVertices - 1) {
|
||||
p2 = convertPoint<double>(ring[i + 1]);
|
||||
}
|
||||
processRingPoints(p1, p2, edgeDistance);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint32_t> indices = mapbox::earcut(polygon);
|
||||
indices = mapbox::earcut(poly);
|
||||
},
|
||||
polyVariant);
|
||||
|
||||
std::size_t nIndices = indices.size();
|
||||
assert(nIndices % 3 == 0);
|
||||
|
||||
@@ -18,18 +18,18 @@ using FillExtrusionBinders = PaintPropertyBinders<style::FillExtrusionPaintPrope
|
||||
using FillExtrusionStaticVertex = gfx::Vertex<TypeList<attributes::pos>>;
|
||||
|
||||
#if MLN_USE_FILL_EXTRUSION_INSTANCING
|
||||
using FillExtrusionLayoutVertex = gfx::Vertex<TypeList<attributes::pos, attributes::ed_discard>>;
|
||||
using FillExtrusionLayoutVertex = gfx::Vertex<TypeList<attributes::pos, attributes::decimals_ed>>;
|
||||
#else
|
||||
using FillExtrusionLayoutVertex = gfx::Vertex<TypeList<attributes::pos, attributes::normal_ed>>;
|
||||
using FillExtrusionLayoutVertex = gfx::Vertex<TypeList<attributes::pos, attributes::decimals_ed, attributes::normal2d>>;
|
||||
#endif
|
||||
|
||||
class FillExtrusionBucket final : public Bucket {
|
||||
public:
|
||||
~FillExtrusionBucket() override;
|
||||
using PossiblyEvaluatedPaintProperties = style::FillExtrusionPaintProperties::PossiblyEvaluated;
|
||||
using PossiblyEvaluatedLayoutProperties = style::Properties<>::PossiblyEvaluated;
|
||||
using PossiblyEvaluatedLayoutProperties = style::FillExtrusionLayoutProperties::PossiblyEvaluated;
|
||||
|
||||
FillExtrusionBucket(const PossiblyEvaluatedLayoutProperties&,
|
||||
FillExtrusionBucket(const PossiblyEvaluatedLayoutProperties& layout,
|
||||
const std::map<std::string, Immutable<style::LayerProperties>>&,
|
||||
float,
|
||||
uint32_t);
|
||||
@@ -50,31 +50,40 @@ public:
|
||||
void update(const FeatureStates&, const GeometryTileLayer&, const std::string&, const ImagePositions&) override;
|
||||
|
||||
#if MLN_USE_FILL_EXTRUSION_INSTANCING
|
||||
static FillExtrusionLayoutVertex layoutVertex(Point<int16_t> p, uint16_t edgeDistance, bool isDiscarded) {
|
||||
return FillExtrusionLayoutVertex{{p.x, p.y},
|
||||
{ // The edgeDistance attribute is used for wrapping fill_extrusion patterns
|
||||
edgeDistance,
|
||||
// When used as instance vector this specify if an instance is discarded
|
||||
static_cast<uint16_t>(isDiscarded)
|
||||
static FillExtrusionLayoutVertex layoutVertex(const Point<double>& p, uint16_t edgeDistance, bool isDiscarded) {
|
||||
auto intPart = Point<double>(std::floor(p.x), std::floor(p.y));
|
||||
// Multiply factional part by 2^7 to pack them into integers [0..127]
|
||||
auto fracPart = convertPoint<uint8_t>((p - intPart) * 128.0);
|
||||
|
||||
return FillExtrusionLayoutVertex{
|
||||
{static_cast<int16_t>(intPart.x), static_cast<int16_t>(intPart.y)},
|
||||
{ // We pack a bool (`isDiscarded`) indicating whether this instance is discarded
|
||||
static_cast<uint16_t>((fracPart.x * 256 + fracPart.y) * 2 + (isDiscarded ? 1 : 0)),
|
||||
// The edgeDistance attribute is used for wrapping fill_extrusion patterns
|
||||
edgeDistance
|
||||
}};
|
||||
}
|
||||
#else
|
||||
static FillExtrusionLayoutVertex layoutVertex(
|
||||
Point<int16_t> p, double nx, double ny, double nz, unsigned short t, uint16_t e) {
|
||||
const auto factor = pow(2, 13);
|
||||
const Point<double>& p, double nx, double ny, unsigned short t, uint16_t edgeDistance) {
|
||||
const auto factor = pow(2, 14);
|
||||
auto intPart = Point<double>(std::floor(p.x), std::floor(p.y));
|
||||
// Multiply factional part by 2^7 to pack them into integers [0..127]
|
||||
auto fracPart = convertPoint<uint8_t>((p - intPart) * 128.0);
|
||||
|
||||
return FillExtrusionLayoutVertex{{{p.x, p.y}},
|
||||
{{// Multiply normal vector components by 2^13 to pack them into
|
||||
// integers We pack a bool (`t`) into the x component indicating
|
||||
// whether it is an upper or lower vertex
|
||||
static_cast<int16_t>(floor(nx * factor) * 2 + t),
|
||||
static_cast<int16_t>(ny * factor * 2),
|
||||
static_cast<int16_t>(nz * factor * 2),
|
||||
return FillExtrusionLayoutVertex{
|
||||
{static_cast<int16_t>(intPart.x), static_cast<int16_t>(intPart.y)},
|
||||
{// We pack a bool (`t`) indicating whether it is an upper or lower vertex
|
||||
static_cast<uint16_t>((fracPart.x * 256 + fracPart.y) * 2 + t),
|
||||
// The edgedistance attribute is used for wrapping fill_extrusion patterns
|
||||
static_cast<int16_t>(e)}}};
|
||||
edgeDistance},
|
||||
// Multiply normal vector components in the 2D plane by 2^14 to pack them into integers
|
||||
{static_cast<int16_t>(nx * factor), static_cast<int16_t>(ny * factor)}};
|
||||
}
|
||||
#endif
|
||||
|
||||
PossiblyEvaluatedLayoutProperties layout;
|
||||
|
||||
static std::array<float, 3> lightColor(const EvaluatedLight&);
|
||||
static std::array<float, 3> lightPosition(const EvaluatedLight&, const TransformState&);
|
||||
static float lightIntensity(const EvaluatedLight&);
|
||||
|
||||
@@ -346,13 +346,22 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders,
|
||||
sizeof(FillExtrusionLayoutVertex),
|
||||
gfx::AttributeDataType::Short2);
|
||||
}
|
||||
#if !MLN_USE_FILL_EXTRUSION_INSTANCING
|
||||
if (const auto& attr = vertexAttrs->set(idFillExtrusionNormalEdVertexAttribute)) {
|
||||
|
||||
if (const auto& attr = vertexAttrs->set(idFillExtrusionDecimalsEdAttribute)) {
|
||||
attr->setSharedRawData(bucket.sharedVertices,
|
||||
offsetof(FillExtrusionLayoutVertex, a2),
|
||||
/*vertexOffset=*/0,
|
||||
sizeof(FillExtrusionLayoutVertex),
|
||||
gfx::AttributeDataType::Short4);
|
||||
gfx::AttributeDataType::UShort2);
|
||||
}
|
||||
|
||||
#if !MLN_USE_FILL_EXTRUSION_INSTANCING
|
||||
if (const auto& attr = vertexAttrs->set(idFillExtrusionNormal2DVertexAttribute)) {
|
||||
attr->setSharedRawData(bucket.sharedVertices,
|
||||
offsetof(FillExtrusionLayoutVertex, a3),
|
||||
/*vertexOffset=*/0,
|
||||
sizeof(FillExtrusionLayoutVertex),
|
||||
gfx::AttributeDataType::Short2);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -438,7 +447,7 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders,
|
||||
sizeof(FillExtrusionLayoutVertex),
|
||||
gfx::AttributeDataType::Short2);
|
||||
}
|
||||
if (const auto& attr = instanceAttrs->set(idFillExtrusionEdDiscardAttribute)) {
|
||||
if (const auto& attr = instanceAttrs->set(idFillExtrusionDecimalsEdAttribute)) {
|
||||
attr->setSharedRawData(bucket.sharedVertices,
|
||||
offsetof(FillExtrusionLayoutVertex, a2),
|
||||
/*vertexOffset=*/0,
|
||||
|
||||
@@ -22,12 +22,8 @@ MBGL_DEFINE_ATTRIBUTE(uint16_t, 2, placed);
|
||||
MBGL_DEFINE_ATTRIBUTE(uint16_t, 3, size);
|
||||
MBGL_DEFINE_ATTRIBUTE(float, 1, offset);
|
||||
MBGL_DEFINE_ATTRIBUTE(float, 2, shift);
|
||||
|
||||
#if MLN_USE_FILL_EXTRUSION_INSTANCING
|
||||
MBGL_DEFINE_ATTRIBUTE(uint16_t, 2, ed_discard);
|
||||
#else
|
||||
MBGL_DEFINE_ATTRIBUTE(int16_t, 4, normal_ed);
|
||||
#endif
|
||||
MBGL_DEFINE_ATTRIBUTE(uint16_t, 2, decimals_ed);
|
||||
MBGL_DEFINE_ATTRIBUTE(int16_t, 2, normal2d);
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
struct data {
|
||||
|
||||
@@ -228,7 +228,8 @@ const std::vector<UniformBlockInfo> FillExtrusionShaderInfo::uniformBlocks = {
|
||||
};
|
||||
const std::vector<AttributeInfo> FillExtrusionShaderInfo::attributes = {
|
||||
AttributeInfo{"a_pos", idFillExtrusionPosVertexAttribute},
|
||||
AttributeInfo{"a_normal_ed", idFillExtrusionNormalEdVertexAttribute},
|
||||
AttributeInfo{"a_decimals_ed", idFillExtrusionDecimalsEdAttribute},
|
||||
AttributeInfo{"a_normal2d", idFillExtrusionNormal2DVertexAttribute},
|
||||
AttributeInfo{"a_base", idFillExtrusionBaseVertexAttribute},
|
||||
AttributeInfo{"a_height", idFillExtrusionHeightVertexAttribute},
|
||||
AttributeInfo{"a_color", idFillExtrusionColorVertexAttribute},
|
||||
@@ -246,7 +247,8 @@ const std::vector<UniformBlockInfo> FillExtrusionPatternShaderInfo::uniformBlock
|
||||
};
|
||||
const std::vector<AttributeInfo> FillExtrusionPatternShaderInfo::attributes = {
|
||||
AttributeInfo{"a_pos", idFillExtrusionPosVertexAttribute},
|
||||
AttributeInfo{"a_normal_ed", idFillExtrusionNormalEdVertexAttribute},
|
||||
AttributeInfo{"a_decimals_ed", idFillExtrusionDecimalsEdAttribute},
|
||||
AttributeInfo{"a_normal2d", idFillExtrusionNormal2DVertexAttribute},
|
||||
AttributeInfo{"a_base", idFillExtrusionBaseVertexAttribute},
|
||||
AttributeInfo{"a_height", idFillExtrusionHeightVertexAttribute},
|
||||
AttributeInfo{"a_pattern_from", idFillExtrusionPatternFromVertexAttribute},
|
||||
|
||||
@@ -9,13 +9,14 @@ namespace shaders {
|
||||
|
||||
using FillExtrusionShaderSource = ShaderSource<BuiltIn::FillExtrusionShader, gfx::Backend::Type::Metal>;
|
||||
|
||||
const std::array<AttributeInfo, 4> FillExtrusionShaderSource::attributes = {
|
||||
const std::array<AttributeInfo, 5> FillExtrusionShaderSource::attributes = {
|
||||
AttributeInfo{0, gfx::AttributeDataType::Short2, fillExtrusionUBOCount + 0, idFillExtrusionPosVertexAttribute},
|
||||
AttributeInfo{1, gfx::AttributeDataType::UShort2, fillExtrusionUBOCount + 0, idFillExtrusionDecimalsEdAttribute},
|
||||
|
||||
// Data driven
|
||||
AttributeInfo{1, gfx::AttributeDataType::Float4, fillExtrusionUBOCount + 1, idFillExtrusionColorVertexAttribute},
|
||||
AttributeInfo{2, gfx::AttributeDataType::Float, fillExtrusionUBOCount + 1, idFillExtrusionBaseVertexAttribute},
|
||||
AttributeInfo{3, gfx::AttributeDataType::Float, fillExtrusionUBOCount + 1, idFillExtrusionHeightVertexAttribute},
|
||||
AttributeInfo{2, gfx::AttributeDataType::Float4, fillExtrusionUBOCount + 1, idFillExtrusionColorVertexAttribute},
|
||||
AttributeInfo{3, gfx::AttributeDataType::Float, fillExtrusionUBOCount + 1, idFillExtrusionBaseVertexAttribute},
|
||||
AttributeInfo{4, gfx::AttributeDataType::Float, fillExtrusionUBOCount + 1, idFillExtrusionHeightVertexAttribute},
|
||||
};
|
||||
const std::array<TextureInfo, 0> FillExtrusionShaderSource::textures = {};
|
||||
|
||||
@@ -30,7 +31,7 @@ const std::array<AttributeInfo, 1> FillExtrusionInstancedShaderSource::attribute
|
||||
};
|
||||
const std::array<AttributeInfo, 5> FillExtrusionInstancedShaderSource::instanceAttributes = {
|
||||
AttributeInfo{1, gfx::AttributeDataType::Short2, fillExtrusionUBOCount + 1, idFillExtrusionOutlinePosAttribute},
|
||||
AttributeInfo{2, gfx::AttributeDataType::UShort2, fillExtrusionUBOCount + 1, idFillExtrusionEdDiscardAttribute},
|
||||
AttributeInfo{2, gfx::AttributeDataType::UShort2, fillExtrusionUBOCount + 1, idFillExtrusionDecimalsEdAttribute},
|
||||
|
||||
// Data driven
|
||||
AttributeInfo{3, gfx::AttributeDataType::Float4, fillExtrusionUBOCount + 2, idFillExtrusionColorVertexAttribute},
|
||||
@@ -44,16 +45,17 @@ const std::array<TextureInfo, 0> FillExtrusionInstancedShaderSource::textures =
|
||||
|
||||
using FillExtrusionPatternShaderSource = ShaderSource<BuiltIn::FillExtrusionPatternShader, gfx::Backend::Type::Metal>;
|
||||
|
||||
const std::array<AttributeInfo, 5> FillExtrusionPatternShaderSource::attributes = {
|
||||
const std::array<AttributeInfo, 6> FillExtrusionPatternShaderSource::attributes = {
|
||||
AttributeInfo{0, gfx::AttributeDataType::Short2, fillExtrusionUBOCount + 0, idFillExtrusionPosVertexAttribute},
|
||||
AttributeInfo{1, gfx::AttributeDataType::UShort2, fillExtrusionUBOCount + 0, idFillExtrusionDecimalsEdAttribute},
|
||||
|
||||
// Data driven
|
||||
AttributeInfo{1, gfx::AttributeDataType::Float, fillExtrusionUBOCount + 1, idFillExtrusionBaseVertexAttribute},
|
||||
AttributeInfo{2, gfx::AttributeDataType::Float, fillExtrusionUBOCount + 1, idFillExtrusionHeightVertexAttribute},
|
||||
AttributeInfo{2, gfx::AttributeDataType::Float, fillExtrusionUBOCount + 1, idFillExtrusionBaseVertexAttribute},
|
||||
AttributeInfo{3, gfx::AttributeDataType::Float, fillExtrusionUBOCount + 1, idFillExtrusionHeightVertexAttribute},
|
||||
AttributeInfo{
|
||||
3, gfx::AttributeDataType::UShort4, fillExtrusionUBOCount + 1, idFillExtrusionPatternFromVertexAttribute},
|
||||
4, gfx::AttributeDataType::UShort4, fillExtrusionUBOCount + 1, idFillExtrusionPatternFromVertexAttribute},
|
||||
AttributeInfo{
|
||||
4, gfx::AttributeDataType::UShort4, fillExtrusionUBOCount + 1, idFillExtrusionPatternToVertexAttribute},
|
||||
5, gfx::AttributeDataType::UShort4, fillExtrusionUBOCount + 1, idFillExtrusionPatternToVertexAttribute},
|
||||
};
|
||||
const std::array<TextureInfo, 1> FillExtrusionPatternShaderSource::textures = {
|
||||
TextureInfo{0, idFillExtrusionImageTexture},
|
||||
@@ -70,7 +72,7 @@ const std::array<AttributeInfo, 1> FillExtrusionPatternInstancedShaderSource::at
|
||||
};
|
||||
const std::array<AttributeInfo, 6> FillExtrusionPatternInstancedShaderSource::instanceAttributes = {
|
||||
AttributeInfo{1, gfx::AttributeDataType::Short2, fillExtrusionUBOCount + 1, idFillExtrusionOutlinePosAttribute},
|
||||
AttributeInfo{2, gfx::AttributeDataType::UShort2, fillExtrusionUBOCount + 1, idFillExtrusionEdDiscardAttribute},
|
||||
AttributeInfo{2, gfx::AttributeDataType::UShort2, fillExtrusionUBOCount + 1, idFillExtrusionDecimalsEdAttribute},
|
||||
|
||||
// Data driven
|
||||
AttributeInfo{3, gfx::AttributeDataType::Float, fillExtrusionUBOCount + 2, idFillExtrusionBaseVertexAttribute},
|
||||
|
||||
@@ -12,11 +12,12 @@ namespace shaders {
|
||||
|
||||
using FillExtrusionShaderSource = ShaderSource<BuiltIn::FillExtrusionShader, gfx::Backend::Type::Vulkan>;
|
||||
|
||||
const std::array<AttributeInfo, 4> FillExtrusionShaderSource::attributes = {
|
||||
const std::array<AttributeInfo, 5> FillExtrusionShaderSource::attributes = {
|
||||
AttributeInfo{0, gfx::AttributeDataType::Short2, idFillExtrusionPosVertexAttribute, idFillExtrusionInstanced},
|
||||
AttributeInfo{1, gfx::AttributeDataType::Float4, idFillExtrusionColorVertexAttribute},
|
||||
AttributeInfo{2, gfx::AttributeDataType::Float, idFillExtrusionBaseVertexAttribute},
|
||||
AttributeInfo{3, gfx::AttributeDataType::Float, idFillExtrusionHeightVertexAttribute},
|
||||
AttributeInfo{1, gfx::AttributeDataType::UShort2, idFillExtrusionDecimalsEdAttribute, idFillExtrusionInstanced},
|
||||
AttributeInfo{2, gfx::AttributeDataType::Float4, idFillExtrusionColorVertexAttribute},
|
||||
AttributeInfo{3, gfx::AttributeDataType::Float, idFillExtrusionBaseVertexAttribute},
|
||||
AttributeInfo{4, gfx::AttributeDataType::Float, idFillExtrusionHeightVertexAttribute},
|
||||
};
|
||||
const std::array<TextureInfo, 0> FillExtrusionShaderSource::textures = {};
|
||||
|
||||
@@ -31,7 +32,7 @@ const std::array<AttributeInfo, 1> FillExtrusionInstancedShaderSource::attribute
|
||||
};
|
||||
const std::array<AttributeInfo, 5> FillExtrusionInstancedShaderSource::instanceAttributes = {
|
||||
AttributeInfo{1, gfx::AttributeDataType::Short2, idFillExtrusionOutlinePosAttribute, idFillExtrusionInstanced},
|
||||
AttributeInfo{2, gfx::AttributeDataType::UShort2, idFillExtrusionEdDiscardAttribute, idFillExtrusionInstanced},
|
||||
AttributeInfo{2, gfx::AttributeDataType::UShort2, idFillExtrusionDecimalsEdAttribute, idFillExtrusionInstanced},
|
||||
|
||||
// Data driven
|
||||
AttributeInfo{3, gfx::AttributeDataType::Float4, idFillExtrusionColorVertexAttribute},
|
||||
@@ -45,12 +46,13 @@ const std::array<TextureInfo, 0> FillExtrusionInstancedShaderSource::textures =
|
||||
|
||||
using FillExtrusionPatternShaderSource = ShaderSource<BuiltIn::FillExtrusionPatternShader, gfx::Backend::Type::Vulkan>;
|
||||
|
||||
const std::array<AttributeInfo, 5> FillExtrusionPatternShaderSource::attributes = {
|
||||
const std::array<AttributeInfo, 6> FillExtrusionPatternShaderSource::attributes = {
|
||||
AttributeInfo{0, gfx::AttributeDataType::Short2, idFillExtrusionPosVertexAttribute, idFillExtrusionInstanced},
|
||||
AttributeInfo{1, gfx::AttributeDataType::Float, idFillExtrusionBaseVertexAttribute},
|
||||
AttributeInfo{2, gfx::AttributeDataType::Float, idFillExtrusionHeightVertexAttribute},
|
||||
AttributeInfo{3, gfx::AttributeDataType::UShort4, idFillExtrusionPatternFromVertexAttribute},
|
||||
AttributeInfo{4, gfx::AttributeDataType::UShort4, idFillExtrusionPatternToVertexAttribute},
|
||||
AttributeInfo{1, gfx::AttributeDataType::UShort2, idFillExtrusionDecimalsEdAttribute, idFillExtrusionInstanced},
|
||||
AttributeInfo{2, gfx::AttributeDataType::Float, idFillExtrusionBaseVertexAttribute},
|
||||
AttributeInfo{3, gfx::AttributeDataType::Float, idFillExtrusionHeightVertexAttribute},
|
||||
AttributeInfo{4, gfx::AttributeDataType::UShort4, idFillExtrusionPatternFromVertexAttribute},
|
||||
AttributeInfo{5, gfx::AttributeDataType::UShort4, idFillExtrusionPatternToVertexAttribute},
|
||||
};
|
||||
const std::array<TextureInfo, 1> FillExtrusionPatternShaderSource::textures = {
|
||||
TextureInfo{0, idFillExtrusionImageTexture},
|
||||
@@ -67,7 +69,7 @@ const std::array<AttributeInfo, 1> FillExtrusionPatternInstancedShaderSource::at
|
||||
};
|
||||
const std::array<AttributeInfo, 6> FillExtrusionPatternInstancedShaderSource::instanceAttributes = {
|
||||
AttributeInfo{1, gfx::AttributeDataType::Short2, idFillExtrusionOutlinePosAttribute, idFillExtrusionInstanced},
|
||||
AttributeInfo{2, gfx::AttributeDataType::UShort2, idFillExtrusionEdDiscardAttribute, idFillExtrusionInstanced},
|
||||
AttributeInfo{2, gfx::AttributeDataType::UShort2, idFillExtrusionDecimalsEdAttribute, idFillExtrusionInstanced},
|
||||
|
||||
// Data driven
|
||||
AttributeInfo{3, gfx::AttributeDataType::Float, idFillExtrusionBaseVertexAttribute},
|
||||
|
||||
@@ -10,12 +10,13 @@ namespace shaders {
|
||||
|
||||
using FillExtrusionShaderSource = ShaderSource<BuiltIn::FillExtrusionShader, gfx::Backend::Type::WebGPU>;
|
||||
|
||||
const std::array<AttributeInfo, 5> FillExtrusionShaderSource::attributes = {
|
||||
const std::array<AttributeInfo, 6> FillExtrusionShaderSource::attributes = {
|
||||
AttributeInfo{3, gfx::AttributeDataType::Short2, idFillExtrusionPosVertexAttribute},
|
||||
AttributeInfo{4, gfx::AttributeDataType::Short4, idFillExtrusionNormalEdVertexAttribute},
|
||||
AttributeInfo{5, gfx::AttributeDataType::Float4, idFillExtrusionColorVertexAttribute},
|
||||
AttributeInfo{6, gfx::AttributeDataType::Float2, idFillExtrusionBaseVertexAttribute},
|
||||
AttributeInfo{7, gfx::AttributeDataType::Float2, idFillExtrusionHeightVertexAttribute},
|
||||
AttributeInfo{4, gfx::AttributeDataType::UShort2, idFillExtrusionDecimalsEdAttribute},
|
||||
AttributeInfo{5, gfx::AttributeDataType::Short2, idFillExtrusionNormal2DVertexAttribute},
|
||||
AttributeInfo{6, gfx::AttributeDataType::Float4, idFillExtrusionColorVertexAttribute},
|
||||
AttributeInfo{7, gfx::AttributeDataType::Float2, idFillExtrusionBaseVertexAttribute},
|
||||
AttributeInfo{8, gfx::AttributeDataType::Float2, idFillExtrusionHeightVertexAttribute},
|
||||
};
|
||||
const std::array<TextureInfo, 0> FillExtrusionShaderSource::textures = {};
|
||||
|
||||
@@ -24,13 +25,14 @@ const std::array<TextureInfo, 0> FillExtrusionShaderSource::textures = {};
|
||||
|
||||
using FillExtrusionPatternShaderSource = ShaderSource<BuiltIn::FillExtrusionPatternShader, gfx::Backend::Type::WebGPU>;
|
||||
|
||||
const std::array<AttributeInfo, 6> FillExtrusionPatternShaderSource::attributes = {
|
||||
const std::array<AttributeInfo, 7> FillExtrusionPatternShaderSource::attributes = {
|
||||
AttributeInfo{3, gfx::AttributeDataType::Short2, idFillExtrusionPosVertexAttribute},
|
||||
AttributeInfo{4, gfx::AttributeDataType::Short4, idFillExtrusionNormalEdVertexAttribute},
|
||||
AttributeInfo{5, gfx::AttributeDataType::Float2, idFillExtrusionBaseVertexAttribute},
|
||||
AttributeInfo{6, gfx::AttributeDataType::Float2, idFillExtrusionHeightVertexAttribute},
|
||||
AttributeInfo{7, gfx::AttributeDataType::UShort4, idFillExtrusionPatternFromVertexAttribute},
|
||||
AttributeInfo{8, gfx::AttributeDataType::UShort4, idFillExtrusionPatternToVertexAttribute},
|
||||
AttributeInfo{4, gfx::AttributeDataType::UShort2, idFillExtrusionDecimalsEdAttribute},
|
||||
AttributeInfo{5, gfx::AttributeDataType::Short2, idFillExtrusionNormal2DVertexAttribute},
|
||||
AttributeInfo{6, gfx::AttributeDataType::Float2, idFillExtrusionBaseVertexAttribute},
|
||||
AttributeInfo{7, gfx::AttributeDataType::Float2, idFillExtrusionHeightVertexAttribute},
|
||||
AttributeInfo{8, gfx::AttributeDataType::UShort4, idFillExtrusionPatternFromVertexAttribute},
|
||||
AttributeInfo{9, gfx::AttributeDataType::UShort4, idFillExtrusionPatternToVertexAttribute},
|
||||
};
|
||||
const std::array<TextureInfo, 1> FillExtrusionPatternShaderSource::textures = {
|
||||
TextureInfo{0, idFillExtrusionImageTexture},
|
||||
|
||||
@@ -58,11 +58,27 @@ std::unique_ptr<Layer> FillExtrusionLayer::cloneRef(const std::string& id_) cons
|
||||
return std::make_unique<FillExtrusionLayer>(std::move(impl_));
|
||||
}
|
||||
|
||||
void FillExtrusionLayer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const {
|
||||
void FillExtrusionLayer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>& writer) const {
|
||||
layout.stringify(writer);
|
||||
}
|
||||
|
||||
// Layout properties
|
||||
|
||||
PropertyValue<float> FillExtrusionLayer::getDefaultFillExtrusionRoundedCornerDistance() {
|
||||
return FillExtrusionRoundedCornerDistance::defaultValue();
|
||||
}
|
||||
|
||||
const PropertyValue<float>& FillExtrusionLayer::getFillExtrusionRoundedCornerDistance() const {
|
||||
return impl().layout.get<FillExtrusionRoundedCornerDistance>();
|
||||
}
|
||||
|
||||
void FillExtrusionLayer::setFillExtrusionRoundedCornerDistance(const PropertyValue<float>& value) {
|
||||
if (value == getFillExtrusionRoundedCornerDistance()) return;
|
||||
auto impl_ = mutableImpl();
|
||||
impl_->layout.get<FillExtrusionRoundedCornerDistance>() = value;
|
||||
baseImpl = std::move(impl_);
|
||||
observer->onLayerChanged(*this);
|
||||
}
|
||||
|
||||
// Paint properties
|
||||
|
||||
@@ -305,6 +321,7 @@ enum class Property : uint8_t {
|
||||
FillExtrusionTranslateTransition,
|
||||
FillExtrusionTranslateAnchorTransition,
|
||||
FillExtrusionVerticalGradientTransition,
|
||||
FillExtrusionRoundedCornerDistance = kPaintPropertyCount,
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
@@ -328,7 +345,8 @@ constexpr const auto layerProperties = mapbox::eternal::hash_map<mapbox::eternal
|
||||
{"fill-extrusion-pattern-transition", toUint8(Property::FillExtrusionPatternTransition)},
|
||||
{"fill-extrusion-translate-transition", toUint8(Property::FillExtrusionTranslateTransition)},
|
||||
{"fill-extrusion-translate-anchor-transition", toUint8(Property::FillExtrusionTranslateAnchorTransition)},
|
||||
{"fill-extrusion-vertical-gradient-transition", toUint8(Property::FillExtrusionVerticalGradientTransition)}});
|
||||
{"fill-extrusion-vertical-gradient-transition", toUint8(Property::FillExtrusionVerticalGradientTransition)},
|
||||
{"fill-extrusion-rounded-corner-distance", toUint8(Property::FillExtrusionRoundedCornerDistance)}});
|
||||
|
||||
StyleProperty getLayerProperty(const FillExtrusionLayer& layer, Property property) {
|
||||
switch (property) {
|
||||
@@ -364,6 +382,8 @@ StyleProperty getLayerProperty(const FillExtrusionLayer& layer, Property propert
|
||||
return makeStyleProperty(layer.getFillExtrusionTranslateAnchorTransition());
|
||||
case Property::FillExtrusionVerticalGradientTransition:
|
||||
return makeStyleProperty(layer.getFillExtrusionVerticalGradientTransition());
|
||||
case Property::FillExtrusionRoundedCornerDistance:
|
||||
return makeStyleProperty(layer.getFillExtrusionRoundedCornerDistance());
|
||||
}
|
||||
return {};
|
||||
}
|
||||
@@ -422,16 +442,23 @@ std::optional<Error> FillExtrusionLayer::setPropertyInternal(const std::string&
|
||||
setFillExtrusionColor(*typedValue);
|
||||
return std::nullopt;
|
||||
}
|
||||
if (property == Property::FillExtrusionOpacity) {
|
||||
if (property == Property::FillExtrusionOpacity || property == Property::FillExtrusionRoundedCornerDistance) {
|
||||
Error error;
|
||||
const auto& typedValue = convert<PropertyValue<float>>(value, error, false, false);
|
||||
if (!typedValue) {
|
||||
return error;
|
||||
}
|
||||
|
||||
if (property == Property::FillExtrusionOpacity) {
|
||||
setFillExtrusionOpacity(*typedValue);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (property == Property::FillExtrusionRoundedCornerDistance) {
|
||||
setFillExtrusionRoundedCornerDistance(*typedValue);
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
if (property == Property::FillExtrusionPattern) {
|
||||
Error error;
|
||||
const auto& typedValue = convert<PropertyValue<expression::Image>>(value, error, true, false);
|
||||
|
||||
@@ -14,7 +14,7 @@ public:
|
||||
bool hasLayoutDifference(const Layer::Impl&) const override;
|
||||
void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override;
|
||||
|
||||
Properties<>::Unevaluated layout;
|
||||
FillExtrusionLayoutProperties::Unevaluated layout;
|
||||
FillExtrusionPaintProperties::Transitionable paint;
|
||||
|
||||
DECLARE_LAYER_TYPE_INFO;
|
||||
|
||||
@@ -32,7 +32,7 @@ const FillExtrusionLayer::Impl& FillExtrusionLayerProperties::layerImpl() const
|
||||
}
|
||||
|
||||
expression::Dependency FillExtrusionLayerProperties::getDependencies() const noexcept {
|
||||
return layerImpl().paint.getDependencies();
|
||||
return layerImpl().paint.getDependencies() | layerImpl().layout.getDependencies();
|
||||
}
|
||||
|
||||
} // namespace style
|
||||
|
||||
@@ -16,6 +16,11 @@
|
||||
namespace mbgl {
|
||||
namespace style {
|
||||
|
||||
struct FillExtrusionRoundedCornerDistance : LayoutProperty<float> {
|
||||
static constexpr const char *name() { return "fill-extrusion-rounded-corner-distance"; }
|
||||
static float defaultValue() { return 0.f; }
|
||||
};
|
||||
|
||||
struct FillExtrusionBase : DataDrivenPaintProperty<float, attributes::base, uniforms::base> {
|
||||
static float defaultValue() { return 0.f; }
|
||||
};
|
||||
@@ -48,6 +53,10 @@ struct FillExtrusionVerticalGradient : PaintProperty<bool> {
|
||||
static bool defaultValue() { return true; }
|
||||
};
|
||||
|
||||
class FillExtrusionLayoutProperties : public Properties<
|
||||
FillExtrusionRoundedCornerDistance
|
||||
> {};
|
||||
|
||||
class FillExtrusionPaintProperties : public Properties<
|
||||
FillExtrusionBase,
|
||||
FillExtrusionColor,
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#include <mbgl/tile/geometry_tile_data.hpp>
|
||||
#include <mbgl/tile/tile_id.hpp>
|
||||
#include <mbgl/math/angles.hpp>
|
||||
#include <mbgl/math/clamp.hpp>
|
||||
#include <mbgl/util/instrumentation.hpp>
|
||||
#include <mbgl/util/math.hpp>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
@@ -299,4 +301,74 @@ const GeometryCollection& GeometryTileFeature::getGeometries() const {
|
||||
return dummy;
|
||||
}
|
||||
|
||||
GeometryCollectionFloat roundPolygonCorners(GeometryCollection& polygon, double desiredCornerDistance) {
|
||||
const int arcPoints = 3;
|
||||
const double maxEdgeLenPercent = 0.2;
|
||||
const double sinParallelTreshold = sin(util::deg2rad(5));
|
||||
GeometryCollectionFloat roundedCornerPolygon;
|
||||
|
||||
for (auto ring : polygon) {
|
||||
GeometryCoordinatesFloat roundedCornerRing;
|
||||
|
||||
std::size_t nVertices = ring.size() - 1;
|
||||
for (std::size_t i = 0; i < nVertices; i++) {
|
||||
auto prevPoint = convertPoint<double>(ring[(i - 1 + nVertices) % nVertices]);
|
||||
auto cornerPoint = convertPoint<double>(ring[i]);
|
||||
auto nextPoint = convertPoint<double>(ring[(i + 1) % nVertices]);
|
||||
|
||||
// Compute the start and end points of the rounded corner
|
||||
auto edge1Vector = util::normal<double>(prevPoint, cornerPoint);
|
||||
auto edge2Vector = util::normal<double>(cornerPoint, nextPoint);
|
||||
|
||||
auto edge1MaxCornerDistance = util::dist<double>(cornerPoint, prevPoint) * maxEdgeLenPercent;
|
||||
auto edge2MaxCornerDistance = util::dist<double>(cornerPoint, nextPoint) * maxEdgeLenPercent;
|
||||
auto cornerDistance = std::min({desiredCornerDistance, edge1MaxCornerDistance, edge2MaxCornerDistance});
|
||||
|
||||
auto startPoint = cornerPoint - edge1Vector * cornerDistance;
|
||||
auto endPoint = cornerPoint + edge2Vector * cornerDistance;
|
||||
|
||||
// Perpendicular directions
|
||||
auto perp1Vector = util::perp(edge1Vector);
|
||||
auto perp2Vector = util::perp(edge2Vector);
|
||||
|
||||
// Ensure perpendiculars point toward same side
|
||||
if (util::crossProduct(edge1Vector, edge2Vector) < 0) {
|
||||
perp1Vector *= -1.0;
|
||||
perp2Vector *= -1.0;
|
||||
}
|
||||
|
||||
// Center = intersection of perpendiculars
|
||||
auto perpCrossProduct = util::crossProduct(perp1Vector, perp2Vector);
|
||||
if (std::abs(perpCrossProduct) < sinParallelTreshold) {
|
||||
roundedCornerRing.emplace_back(convertPoint<float>(ring[i]));
|
||||
continue;
|
||||
}
|
||||
auto t = util::crossProduct(endPoint - startPoint, perp2Vector) / perpCrossProduct;
|
||||
auto centerPoint = startPoint + perp1Vector * t;
|
||||
|
||||
// Add the start point of the rounded corner
|
||||
roundedCornerRing.emplace_back(convertPoint<float>(startPoint));
|
||||
|
||||
// Generate points along the arc
|
||||
auto radius = util::dist<double>(startPoint, centerPoint);
|
||||
auto startAngle = std::atan2(startPoint.y - centerPoint.y, startPoint.x - centerPoint.x);
|
||||
auto arcAngle = util::angle_between(startPoint - centerPoint, endPoint - centerPoint);
|
||||
for (int k = 1; k <= arcPoints; k++) {
|
||||
double angle = startAngle + arcAngle * k / (arcPoints + 1);
|
||||
auto arcPoint = Point<double>(centerPoint.x + std::cos(angle) * radius,
|
||||
centerPoint.y + std::sin(angle) * radius);
|
||||
roundedCornerRing.emplace_back(convertPoint<float>(arcPoint));
|
||||
}
|
||||
|
||||
// Add the end point of the rounded corner
|
||||
roundedCornerRing.emplace_back(convertPoint<float>(endPoint));
|
||||
}
|
||||
// Close the ring by repeating the first point at the end
|
||||
roundedCornerRing.emplace_back(roundedCornerRing[0]);
|
||||
|
||||
// Add the ring to the rounded corner polygon
|
||||
roundedCornerPolygon.emplace_back(roundedCornerRing);
|
||||
}
|
||||
return roundedCornerPolygon;
|
||||
}
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -145,4 +145,10 @@ struct ToGeometryCollection {
|
||||
}
|
||||
};
|
||||
|
||||
using GeometryCoordinateFloat = Point<float>;
|
||||
using GeometryCoordinatesFloat = std::vector<GeometryCoordinateFloat>;
|
||||
using GeometryCollectionFloat = std::vector<GeometryCoordinatesFloat>;
|
||||
|
||||
GeometryCollectionFloat roundPolygonCorners(GeometryCollection& polygon, double radius);
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -12,6 +12,16 @@ namespace util {
|
||||
|
||||
// TODO: split this file up into individual headers, following mbgl/math/*.hpp.
|
||||
|
||||
template <typename T = double, typename S>
|
||||
T dotProduct(const Point<S>& a, const Point<S>& b) {
|
||||
return a.x * b.x + a.y * b.y;
|
||||
}
|
||||
|
||||
template <typename T = double, typename S>
|
||||
T crossProduct(const Point<S>& a, const Point<S>& b) {
|
||||
return a.x * b.y - a.y * b.x;
|
||||
}
|
||||
|
||||
// Find the angle of the two vectors, solving the formula for the cross product
|
||||
// a x b = |a||b|sin(θ) for θ.
|
||||
template <typename T = double, typename S>
|
||||
|
||||
Reference in New Issue
Block a user