Files
Bart Louwers 2a8ebc4906 core: rename mbgl directories to mln (#4511)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2026-08-22 20:50:14 +02:00

911 lines
23 KiB
C++

#pragma once
#include <mln/shaders/shader_source.hpp>
#include <mln/shaders/webgpu/shader_program.hpp>
#include <mln/shaders/fill_layer_ubo.hpp>
namespace mln {
namespace shaders {
template <>
struct ShaderSource<BuiltIn::FillShader, gfx::Backend::Type::WebGPU> {
static constexpr const char* name = "FillShader";
static const std::array<AttributeInfo, 3> attributes;
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
static const std::array<TextureInfo, 0> textures;
static constexpr const char* vertex = R"(
struct VertexInput {
@location(0) position: vec2<i32>,
#ifndef HAS_UNIFORM_u_color
@location(1) color: vec4<f32>,
#endif
#ifndef HAS_UNIFORM_u_opacity
@location(2) opacity: vec2<f32>,
#endif
};
struct VertexOutput {
@builtin(position) position: vec4<f32>,
@location(0) color: vec4<f32>,
@location(1) opacity: f32,
};
struct FillDrawableUBO {
matrix: mat4x4<f32>,
color_t: f32,
opacity_t: f32,
pad1: f32,
pad2: f32,
};
struct FillDrawableUnionUBO {
fill: FillDrawableUBO,
padding: vec4<f32>,
};
struct FillEvaluatedPropsUBO {
color: vec4<f32>,
outline_color: vec4<f32>,
opacity: f32,
fade: f32,
from_scale: f32,
to_scale: f32,
};
struct GlobalIndexUBO {
value: u32,
pad0: vec3<u32>,
};
@group(0) @binding(1) var<uniform> globalIndex: GlobalIndexUBO;
@group(0) @binding(2) var<storage, read> drawableVector: array<FillDrawableUnionUBO>;
@group(0) @binding(5) var<uniform> props: FillEvaluatedPropsUBO;
@vertex
fn main(in: VertexInput) -> VertexOutput {
var out: VertexOutput;
// Transform position using the matrix
let drawable = drawableVector[globalIndex.value].fill;
let clip = drawable.matrix * vec4<f32>(f32(in.position.x), f32(in.position.y), 0.0, 1.0);
out.position = clip;
var color: vec4<f32>;
#ifdef HAS_UNIFORM_u_color
color = props.color;
#else
color = unpack_mix_color(in.color, drawable.color_t);
#endif
var opacity: f32;
#ifdef HAS_UNIFORM_u_opacity
opacity = props.opacity;
#else
opacity = unpack_mix_float(in.opacity, drawable.opacity_t);
#endif
out.color = color;
out.opacity = opacity;
return out;
}
)";
static constexpr const char* fragment = R"(
struct FillEvaluatedPropsUBO {
color: vec4<f32>,
outline_color: vec4<f32>,
opacity: f32,
fade: f32,
from_scale: f32,
to_scale: f32,
};
@group(0) @binding(5) var<uniform> props: FillEvaluatedPropsUBO;
struct FragmentInput {
@location(0) color: vec4<f32>,
@location(1) opacity: f32,
};
@fragment
fn main(in: FragmentInput) -> @location(0) vec4<f32> {
var color: vec4<f32>;
#ifdef HAS_UNIFORM_u_color
color = props.color;
#else
color = in.color;
#endif
var opacity: f32;
#ifdef HAS_UNIFORM_u_opacity
opacity = props.opacity;
#else
opacity = in.opacity;
#endif
return color * opacity;
}
)";
};
template <>
struct ShaderSource<BuiltIn::FillOutlineShader, gfx::Backend::Type::WebGPU> {
static constexpr const char* name = "FillOutlineShader";
static const std::array<AttributeInfo, 3> attributes;
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
static const std::array<TextureInfo, 0> textures;
static constexpr const char* vertex = R"(
struct VertexInput {
@location(0) position: vec2<i32>,
#ifndef HAS_UNIFORM_u_outline_color
@location(1) outline_color: vec4<f32>,
#endif
#ifndef HAS_UNIFORM_u_opacity
@location(2) opacity: vec2<f32>,
#endif
};
struct VertexOutput {
@builtin(position) position: vec4<f32>,
@location(0) color: vec4<f32>,
@location(1) opacity: f32,
@location(2) pos: vec2<f32>,
};
struct FillOutlineDrawableUBO {
matrix: mat4x4<f32>,
outline_color_t: f32,
opacity_t: f32,
pad1: f32,
pad2: f32,
};
struct FillOutlineDrawableUnionUBO {
fill: FillOutlineDrawableUBO,
padding: vec4<f32>,
};
struct GlobalPaintParamsUBO {
pattern_atlas_texsize: vec2<f32>,
units_to_pixels: vec2<f32>,
world_size: vec2<f32>,
camera_to_center_distance: f32,
symbol_fade_change: f32,
aspect_ratio: f32,
pixel_ratio: f32,
map_zoom: f32,
pad1: f32,
};
struct FillOutlineEvaluatedPropsUBO {
color: vec4<f32>,
outline_color: vec4<f32>,
opacity: f32,
fade: f32,
from_scale: f32,
to_scale: f32,
};
struct GlobalIndexUBO {
value: u32,
pad0: vec3<u32>,
};
@group(0) @binding(0) var<uniform> paintParams: GlobalPaintParamsUBO;
@group(0) @binding(1) var<uniform> globalIndex: GlobalIndexUBO;
@group(0) @binding(2) var<storage, read> drawableVector: array<FillOutlineDrawableUnionUBO>;
@group(0) @binding(5) var<uniform> props: FillOutlineEvaluatedPropsUBO;
@vertex
fn main(in: VertexInput) -> VertexOutput {
var out: VertexOutput;
// Transform position using the matrix
let drawable = drawableVector[globalIndex.value].fill;
let clip = drawable.matrix * vec4<f32>(f32(in.position.x), f32(in.position.y), 0.0, 1.0);
let invW = 1.0 / clip.w;
let ndcXY = clip.xy * invW;
out.position = clip;
out.pos = (ndcXY + vec2<f32>(1.0)) * 0.5 * paintParams.world_size;
var color: vec4<f32>;
#ifdef HAS_UNIFORM_u_outline_color
color = props.outline_color;
#else
color = unpack_mix_color(in.outline_color, drawable.outline_color_t);
#endif
var opacity: f32;
#ifdef HAS_UNIFORM_u_opacity
opacity = props.opacity;
#else
opacity = unpack_mix_float(in.opacity, drawable.opacity_t);
#endif
out.color = color;
out.opacity = opacity;
return out;
}
)";
static constexpr const char* fragment = R"(
struct FillOutlineEvaluatedPropsUBO {
color: vec4<f32>,
outline_color: vec4<f32>,
opacity: f32,
fade: f32,
from_scale: f32,
to_scale: f32,
};
@group(0) @binding(5) var<uniform> props: FillOutlineEvaluatedPropsUBO;
struct FragmentInput {
@location(0) color: vec4<f32>,
@location(1) opacity: f32,
@location(2) pos: vec2<f32>,
};
@fragment
fn main(in: FragmentInput) -> @location(0) vec4<f32> {
var color: vec4<f32>;
#ifdef HAS_UNIFORM_u_outline_color
color = props.outline_color;
#else
color = in.color;
#endif
var opacity: f32;
#ifdef HAS_UNIFORM_u_opacity
opacity = props.opacity;
#else
opacity = in.opacity;
#endif
return color * opacity;
}
)";
};
template <>
struct ShaderSource<BuiltIn::FillPatternShader, gfx::Backend::Type::WebGPU> {
static constexpr const char* name = "FillPatternShader";
static const std::array<AttributeInfo, 4> attributes;
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
static const std::array<TextureInfo, 1> textures;
static constexpr const char* vertex = R"(
struct VertexInput {
@location(4) position: vec2<i32>,
#ifndef HAS_UNIFORM_u_pattern_from
@location(5) pattern_from: vec4<u32>,
#endif
#ifndef HAS_UNIFORM_u_pattern_to
@location(6) pattern_to: vec4<u32>,
#endif
#ifndef HAS_UNIFORM_u_opacity
@location(7) opacity: vec2<f32>,
#endif
};
struct VertexOutput {
@builtin(position) position: vec4<f32>,
@location(0) v_pos_a: vec2<f32>,
@location(1) v_pos_b: vec2<f32>,
#ifndef HAS_UNIFORM_u_pattern_from
@location(2) pattern_from: vec4<f32>,
#endif
#ifndef HAS_UNIFORM_u_pattern_to
@location(3) pattern_to: vec4<f32>,
#endif
#ifndef HAS_UNIFORM_u_opacity
@location(4) opacity: f32,
#endif
};
struct FillPatternDrawableUBO {
matrix: mat4x4<f32>,
pixel_coord_upper: vec2<f32>,
pixel_coord_lower: vec2<f32>,
tile_ratio: f32,
pattern_from_t: f32,
pattern_to_t: f32,
opacity_t: f32,
};
struct FillPatternTilePropsUBO {
pattern_from: vec4<f32>,
pattern_to: vec4<f32>,
texsize: vec2<f32>,
pad1: f32,
pad2: f32,
};
struct FillEvaluatedPropsUBO {
color: vec4<f32>,
outline_color: vec4<f32>,
opacity: f32,
fade: f32,
from_scale: f32,
to_scale: f32,
};
struct GlobalPaintParamsUBO {
pattern_atlas_texsize: vec2<f32>,
units_to_pixels: vec2<f32>,
world_size: vec2<f32>,
camera_to_center_distance: f32,
symbol_fade_change: f32,
aspect_ratio: f32,
pixel_ratio: f32,
map_zoom: f32,
pad1: f32,
};
struct GlobalIndexUBO {
value: u32,
pad0: vec3<u32>,
};
@group(0) @binding(0) var<uniform> paintParams: GlobalPaintParamsUBO;
@group(0) @binding(2) var<storage, read> drawableVector: array<FillPatternDrawableUBO>;
@group(0) @binding(4) var<storage, read> tilePropsVector: array<FillPatternTilePropsUBO>;
@group(0) @binding(5) var<uniform> props: FillEvaluatedPropsUBO;
@group(0) @binding(1) var<uniform> globalIndex: GlobalIndexUBO;
@vertex
fn main(in: VertexInput) -> VertexOutput {
var out: VertexOutput;
let index = globalIndex.value;
let drawable = drawableVector[index];
let tileProps = tilePropsVector[index];
var pattern_from: vec4<f32>;
#ifdef HAS_UNIFORM_u_pattern_from
pattern_from = tileProps.pattern_from;
#else
pattern_from = vec4<f32>(in.pattern_from);
#endif
var pattern_to: vec4<f32>;
#ifdef HAS_UNIFORM_u_pattern_to
pattern_to = tileProps.pattern_to;
#else
pattern_to = vec4<f32>(in.pattern_to);
#endif
let pattern_tl_a = pattern_from.xy;
let pattern_br_a = pattern_from.zw;
let pattern_tl_b = pattern_to.xy;
let pattern_br_b = pattern_to.zw;
let pixelRatio = paintParams.pixel_ratio;
let tileZoomRatio = drawable.tile_ratio;
let fromScale = props.from_scale;
let toScale = props.to_scale;
let display_size_a = vec2<f32>(
(pattern_br_a.x - pattern_tl_a.x) / pixelRatio,
(pattern_br_a.y - pattern_tl_a.y) / pixelRatio
);
let display_size_b = vec2<f32>(
(pattern_br_b.x - pattern_tl_b.x) / pixelRatio,
(pattern_br_b.y - pattern_tl_b.y) / pixelRatio
);
let pos = vec2<f32>(f32(in.position.x), f32(in.position.y));
let clip = drawable.matrix * vec4<f32>(pos, 0.0, 1.0);
out.position = clip;
out.v_pos_a = get_pattern_pos(
drawable.pixel_coord_upper,
drawable.pixel_coord_lower,
fromScale * display_size_a,
tileZoomRatio,
pos
);
out.v_pos_b = get_pattern_pos(
drawable.pixel_coord_upper,
drawable.pixel_coord_lower,
toScale * display_size_b,
tileZoomRatio,
pos
);
#ifndef HAS_UNIFORM_u_pattern_from
out.pattern_from = pattern_from;
#endif
#ifndef HAS_UNIFORM_u_pattern_to
out.pattern_to = pattern_to;
#endif
#ifndef HAS_UNIFORM_u_opacity
out.opacity = unpack_mix_float(in.opacity, drawable.opacity_t);
#endif
return out;
}
)";
static constexpr const char* fragment = R"(
struct FragmentInput {
@location(0) v_pos_a: vec2<f32>,
@location(1) v_pos_b: vec2<f32>,
#ifndef HAS_UNIFORM_u_pattern_from
@location(2) pattern_from: vec4<f32>,
#endif
#ifndef HAS_UNIFORM_u_pattern_to
@location(3) pattern_to: vec4<f32>,
#endif
#ifndef HAS_UNIFORM_u_opacity
@location(4) opacity: f32,
#endif
};
struct FillPatternTilePropsUBO {
pattern_from: vec4<f32>,
pattern_to: vec4<f32>,
texsize: vec2<f32>,
pad1: f32,
pad2: f32,
};
struct FillEvaluatedPropsUBO {
color: vec4<f32>,
outline_color: vec4<f32>,
opacity: f32,
fade: f32,
from_scale: f32,
to_scale: f32,
};
struct GlobalIndexUBO {
value: u32,
pad0: vec3<u32>,
};
@group(0) @binding(4) var<storage, read> tilePropsVector: array<FillPatternTilePropsUBO>;
@group(0) @binding(5) var<uniform> props: FillEvaluatedPropsUBO;
@group(0) @binding(1) var<uniform> globalIndex: GlobalIndexUBO;
@group(1) @binding(0) var texture_sampler: sampler;
@group(1) @binding(1) var pattern_texture: texture_2d<f32>;
@fragment
fn main(in: FragmentInput) -> @location(0) vec4<f32> {
let tileProps = tilePropsVector[globalIndex.value];
let pattern_from =
#ifdef HAS_UNIFORM_u_pattern_from
tileProps.pattern_from;
#else
in.pattern_from;
#endif
let pattern_to =
#ifdef HAS_UNIFORM_u_pattern_to
tileProps.pattern_to;
#else
in.pattern_to;
#endif
let pattern_tl_a = pattern_from.xy;
let pattern_br_a = pattern_from.zw;
let pattern_tl_b = pattern_to.xy;
let pattern_br_b = pattern_to.zw;
// Sample pattern A
let imagecoord_a = gl_mod(in.v_pos_a, vec2<f32>(1.0));
let pos_a = mix(pattern_tl_a / tileProps.texsize, pattern_br_a / tileProps.texsize, imagecoord_a);
let color_a = textureSample(pattern_texture, texture_sampler, pos_a);
// Sample pattern B
let imagecoord_b = gl_mod(in.v_pos_b, vec2<f32>(1.0));
let pos_b = mix(pattern_tl_b / tileProps.texsize, pattern_br_b / tileProps.texsize, imagecoord_b);
let color_b = textureSample(pattern_texture, texture_sampler, pos_b);
// Mix patterns and apply opacity
let opacity =
#ifdef HAS_UNIFORM_u_opacity
props.opacity;
#else
in.opacity;
#endif
return mix(color_a, color_b, props.fade) * opacity;
}
)";
};
template <>
struct ShaderSource<BuiltIn::FillOutlinePatternShader, gfx::Backend::Type::WebGPU> {
static constexpr const char* name = "FillOutlinePatternShader";
static const std::array<AttributeInfo, 4> attributes;
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
static const std::array<TextureInfo, 1> textures;
static constexpr const char* vertex = R"(
struct VertexInput {
@location(4) position: vec2<i32>,
#ifndef HAS_UNIFORM_u_pattern_from
@location(5) pattern_from: vec4<u32>,
#endif
#ifndef HAS_UNIFORM_u_pattern_to
@location(6) pattern_to: vec4<u32>,
#endif
#ifndef HAS_UNIFORM_u_opacity
@location(7) opacity: vec2<f32>,
#endif
};
struct VertexOutput {
@builtin(position) position: vec4<f32>,
@location(0) v_pos_a: vec2<f32>,
@location(1) v_pos_b: vec2<f32>,
@location(2) v_pos: vec2<f32>,
#ifndef HAS_UNIFORM_u_pattern_from
@location(3) pattern_from: vec4<f32>,
#endif
#ifndef HAS_UNIFORM_u_pattern_to
@location(4) pattern_to: vec4<f32>,
#endif
#ifndef HAS_UNIFORM_u_opacity
@location(5) opacity: f32,
#endif
};
struct FillOutlinePatternDrawableUBO {
matrix: mat4x4<f32>,
pixel_coord_upper: vec2<f32>,
pixel_coord_lower: vec2<f32>,
tile_ratio: f32,
pattern_from_t: f32,
pattern_to_t: f32,
opacity_t: f32,
};
struct FillOutlinePatternTilePropsUBO {
pattern_from: vec4<f32>,
pattern_to: vec4<f32>,
texsize: vec2<f32>,
pad1: f32,
pad2: f32,
};
struct FillEvaluatedPropsUBO {
color: vec4<f32>,
outline_color: vec4<f32>,
opacity: f32,
fade: f32,
from_scale: f32,
to_scale: f32,
};
struct GlobalPaintParamsUBO {
pattern_atlas_texsize: vec2<f32>,
units_to_pixels: vec2<f32>,
world_size: vec2<f32>,
camera_to_center_distance: f32,
symbol_fade_change: f32,
aspect_ratio: f32,
pixel_ratio: f32,
map_zoom: f32,
pad1: f32,
};
struct GlobalIndexUBO {
value: u32,
pad0: vec3<u32>,
};
@group(0) @binding(0) var<uniform> paintParams: GlobalPaintParamsUBO;
@group(0) @binding(2) var<storage, read> drawableVector: array<FillOutlinePatternDrawableUBO>;
@group(0) @binding(4) var<storage, read> tilePropsVector: array<FillOutlinePatternTilePropsUBO>;
@group(0) @binding(5) var<uniform> props: FillEvaluatedPropsUBO;
@group(0) @binding(1) var<uniform> globalIndex: GlobalIndexUBO;
@vertex
fn main(in: VertexInput) -> VertexOutput {
var out: VertexOutput;
let index = globalIndex.value;
let drawable = drawableVector[index];
let tileProps = tilePropsVector[index];
var pattern_from: vec4<f32>;
#ifdef HAS_UNIFORM_u_pattern_from
pattern_from = tileProps.pattern_from;
#else
pattern_from = vec4<f32>(in.pattern_from);
#endif
var pattern_to: vec4<f32>;
#ifdef HAS_UNIFORM_u_pattern_to
pattern_to = tileProps.pattern_to;
#else
pattern_to = vec4<f32>(in.pattern_to);
#endif
let pattern_tl_a = pattern_from.xy;
let pattern_br_a = pattern_from.zw;
let pattern_tl_b = pattern_to.xy;
let pattern_br_b = pattern_to.zw;
let pixelRatio = paintParams.pixel_ratio;
let tileZoomRatio = drawable.tile_ratio;
let fromScale = props.from_scale;
let toScale = props.to_scale;
let display_size_a = vec2<f32>(
(pattern_br_a.x - pattern_tl_a.x) / pixelRatio,
(pattern_br_a.y - pattern_tl_a.y) / pixelRatio
);
let display_size_b = vec2<f32>(
(pattern_br_b.x - pattern_tl_b.x) / pixelRatio,
(pattern_br_b.y - pattern_tl_b.y) / pixelRatio
);
let pos = vec2<f32>(f32(in.position.x), f32(in.position.y));
let clip = drawable.matrix * vec4<f32>(pos, 0.0, 1.0);
let invW = 1.0 / clip.w;
let ndcXY = clip.xy * invW;
out.position = clip;
out.v_pos_a = get_pattern_pos(
drawable.pixel_coord_upper,
drawable.pixel_coord_lower,
fromScale * display_size_a,
tileZoomRatio,
pos
);
out.v_pos_b = get_pattern_pos(
drawable.pixel_coord_upper,
drawable.pixel_coord_lower,
toScale * display_size_b,
tileZoomRatio,
pos
);
out.v_pos = (ndcXY + vec2<f32>(1.0, 1.0)) * 0.5 * paintParams.world_size;
#ifndef HAS_UNIFORM_u_pattern_from
out.pattern_from = pattern_from;
#endif
#ifndef HAS_UNIFORM_u_pattern_to
out.pattern_to = pattern_to;
#endif
#ifndef HAS_UNIFORM_u_opacity
out.opacity = unpack_mix_float(in.opacity, drawable.opacity_t);
#endif
return out;
}
)";
static constexpr const char* fragment = R"(
struct FragmentInput {
@location(0) v_pos_a: vec2<f32>,
@location(1) v_pos_b: vec2<f32>,
@location(2) v_pos: vec2<f32>,
#ifndef HAS_UNIFORM_u_pattern_from
@location(3) pattern_from: vec4<f32>,
#endif
#ifndef HAS_UNIFORM_u_pattern_to
@location(4) pattern_to: vec4<f32>,
#endif
#ifndef HAS_UNIFORM_u_opacity
@location(5) opacity: f32,
#endif
};
struct FillOutlinePatternTilePropsUBO {
pattern_from: vec4<f32>,
pattern_to: vec4<f32>,
texsize: vec2<f32>,
pad1: f32,
pad2: f32,
};
struct FillEvaluatedPropsUBO {
color: vec4<f32>,
outline_color: vec4<f32>,
opacity: f32,
fade: f32,
from_scale: f32,
to_scale: f32,
};
struct GlobalIndexUBO {
value: u32,
pad0: vec3<u32>,
};
@group(0) @binding(4) var<storage, read> tilePropsVector: array<FillOutlinePatternTilePropsUBO>;
@group(0) @binding(5) var<uniform> props: FillEvaluatedPropsUBO;
@group(0) @binding(1) var<uniform> globalIndex: GlobalIndexUBO;
@group(1) @binding(0) var texture_sampler: sampler;
@group(1) @binding(1) var pattern_texture: texture_2d<f32>;
@fragment
fn main(in: FragmentInput) -> @location(0) vec4<f32> {
let tileProps = tilePropsVector[globalIndex.value];
let pattern_from =
#ifdef HAS_UNIFORM_u_pattern_from
tileProps.pattern_from;
#else
in.pattern_from;
#endif
let pattern_to =
#ifdef HAS_UNIFORM_u_pattern_to
tileProps.pattern_to;
#else
in.pattern_to;
#endif
let pattern_tl_a = pattern_from.xy;
let pattern_br_a = pattern_from.zw;
let pattern_tl_b = pattern_to.xy;
let pattern_br_b = pattern_to.zw;
// Sample pattern A
let imagecoord_a = gl_mod(in.v_pos_a, vec2<f32>(1.0));
let pos_a = mix(pattern_tl_a / tileProps.texsize, pattern_br_a / tileProps.texsize, imagecoord_a);
let color_a = textureSample(pattern_texture, texture_sampler, pos_a);
// Sample pattern B
let imagecoord_b = gl_mod(in.v_pos_b, vec2<f32>(1.0));
let pos_b = mix(pattern_tl_b / tileProps.texsize, pattern_br_b / tileProps.texsize, imagecoord_b);
let color_b = textureSample(pattern_texture, texture_sampler, pos_b);
// Mix patterns and apply opacity
let opacity =
#ifdef HAS_UNIFORM_u_opacity
props.opacity;
#else
in.opacity;
#endif
return mix(color_a, color_b, props.fade) * opacity;
}
)";
};
template <>
struct ShaderSource<BuiltIn::FillOutlineTriangulatedShader, gfx::Backend::Type::WebGPU> {
static constexpr const char* name = "FillOutlineTriangulatedShader";
static const std::array<AttributeInfo, 2> attributes;
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
static const std::array<TextureInfo, 0> textures;
static constexpr const char* vertex = R"(
const SCALE: f32 = 0.015873016;
struct VertexInput {
@location(0) pos_normal: vec2<i32>,
@location(1) data: vec4<u32>,
};
struct VertexOutput {
@builtin(position) position: vec4<f32>,
@location(0) normal: vec2<f32>,
@location(1) width: f32,
@location(2) gamma_scale: f32,
};
struct FillOutlineTriangulatedDrawableUnionUBO {
matrix_col0: vec4<f32>,
matrix_col1: vec4<f32>,
matrix_col2: vec4<f32>,
matrix_col3: vec4<f32>,
params: vec4<f32>,
padding: vec4<f32>,
};
struct GlobalPaintParamsUBO {
pattern_atlas_texsize: vec2<f32>,
units_to_pixels: vec2<f32>,
world_size: vec2<f32>,
camera_to_center_distance: f32,
symbol_fade_change: f32,
aspect_ratio: f32,
pixel_ratio: f32,
map_zoom: f32,
pad1: f32,
};
struct GlobalIndexUBO {
value: u32,
pad0: vec3<u32>,
};
@group(0) @binding(0) var<uniform> paintParams: GlobalPaintParamsUBO;
@group(0) @binding(1) var<uniform> globalIndex: GlobalIndexUBO;
@group(0) @binding(2) var<storage, read> drawableVector: array<FillOutlineTriangulatedDrawableUnionUBO>;
@vertex
fn main(in: VertexInput) -> VertexOutput {
var out: VertexOutput;
let drawable = drawableVector[globalIndex.value];
let matrix = mat4x4<f32>(drawable.matrix_col0,
drawable.matrix_col1,
drawable.matrix_col2,
drawable.matrix_col3);
let ratio = max(drawable.params.x, 1e-6);
let pos_normal = vec2<f32>(f32(in.pos_normal.x), f32(in.pos_normal.y));
let pos = floor(pos_normal * 0.5);
var normal = pos_normal - pos * 2.0;
normal.y = normal.y * 2.0 - 1.0;
let data = vec4<f32>(in.data);
let extrude = data.xy - vec2<f32>(128.0, 128.0);
let half_width = 0.5;
let antialiasing = 0.5 / paintParams.pixel_ratio;
let outset = half_width + antialiasing;
let dist = extrude * outset * SCALE;
let extrude_vec = dist / ratio;
let projected_extrude = matrix * vec4<f32>(extrude_vec, 0.0, 0.0);
let base = matrix * vec4<f32>(pos, 0.0, 1.0);
let clip = base + projected_extrude;
out.position = clip;
let extrude_length_without_perspective = length(dist);
let extrude_length_with_perspective = length((projected_extrude.xy / clip.w) * paintParams.units_to_pixels);
let gamma_denom = max(extrude_length_with_perspective, 1e-6);
out.normal = normal;
out.width = outset;
out.gamma_scale = extrude_length_without_perspective / gamma_denom;
return out;
}
)";
static constexpr const char* fragment = R"(
struct FragmentInput {
@location(0) normal: vec2<f32>,
@location(1) width: f32,
@location(2) gamma_scale: f32,
};
struct FillEvaluatedPropsUBO {
color: vec4<f32>,
outline_color: vec4<f32>,
opacity: f32,
fade: f32,
from_scale: f32,
to_scale: f32,
};
struct GlobalPaintParamsUBO {
pattern_atlas_texsize: vec2<f32>,
units_to_pixels: vec2<f32>,
world_size: vec2<f32>,
camera_to_center_distance: f32,
symbol_fade_change: f32,
aspect_ratio: f32,
pixel_ratio: f32,
map_zoom: f32,
pad1: f32,
};
@group(0) @binding(0) var<uniform> paintParams: GlobalPaintParamsUBO;
@group(0) @binding(5) var<uniform> props: FillEvaluatedPropsUBO;
@fragment
fn main(in: FragmentInput) -> @location(0) vec4<f32> {
let dist = length(in.normal) * in.width;
let blur2 = (1.0 / paintParams.pixel_ratio) * in.gamma_scale;
let denom = max(blur2, 1e-6);
let alpha = clamp(min(dist + blur2, in.width - dist) / denom, 0.0, 1.0);
return props.outline_color * (alpha * props.opacity);
}
)";
};
} // namespace shaders
} // namespace mln