#pragma once #include #include #include namespace mbgl { namespace shaders { template <> struct ShaderSource { static constexpr const char* name = "CircleShader"; static const std::array attributes; static constexpr std::array instanceAttributes{}; static const std::array textures; static constexpr auto prelude = R"( struct CircleDrawableUBO { matrix: mat4x4, extrude_scale: vec2, color_t: f32, radius_t: f32, blur_t: f32, opacity_t: f32, stroke_color_t: f32, stroke_width_t: f32, stroke_opacity_t: f32, pad1: f32, pad2: f32, pad3: f32, }; struct CircleEvaluatedPropsUBO { color: vec4, stroke_color: vec4, radius: f32, blur: f32, opacity: f32, stroke_width: f32, stroke_opacity: f32, scale_with_map: i32, pitch_with_map: i32, pad1: f32, }; struct GlobalPaintParamsUBO { pattern_atlas_texsize: vec2, units_to_pixels: vec2, world_size: vec2, 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, }; @group(0) @binding(0) var paintParams: GlobalPaintParamsUBO; @group(0) @binding(1) var globalIndex: GlobalIndexUBO; @group(0) @binding(2) var drawableVector: array; @group(0) @binding(4) var props: CircleEvaluatedPropsUBO; )"; static constexpr auto vertex = R"( struct VertexInput { @location(0) position: vec2, @location(1) color: vec4, @location(2) radius: vec2, @location(3) blur: vec2, @location(4) opacity: vec2, @location(5) stroke_color: vec4, @location(6) stroke_width: vec2, @location(7) stroke_opacity: vec2, }; struct VertexOutput { @builtin(position) position: vec4, @location(0) extrude: vec2, @location(1) circle_data: vec4, @location(2) color: vec4, @location(3) stroke_color: vec4, @location(4) stroke_data: vec2, }; @vertex fn main(in: VertexInput) -> VertexOutput { var out: VertexOutput; let drawable = drawableVector[globalIndex.value]; let scale_with_map = props.scale_with_map != 0; let pitch_with_map = props.pitch_with_map != 0; let pos_f = vec2(f32(in.position.x), f32(in.position.y)); let extrude = glMod2v(pos_f, vec2(2.0, 2.0)) * 2.0 - vec2(1.0, 1.0); let scaled_extrude = extrude * drawable.extrude_scale; let circle_center = floor(pos_f * 0.5); var color = props.color; #ifndef HAS_UNIFORM_u_color color = unpack_mix_color(in.color, drawable.color_t); #endif var radius = props.radius; #ifndef HAS_UNIFORM_u_radius radius = unpack_mix_float(in.radius, drawable.radius_t); #endif var blur = props.blur; #ifndef HAS_UNIFORM_u_blur blur = unpack_mix_float(in.blur, drawable.blur_t); #endif var opacity = props.opacity; #ifndef HAS_UNIFORM_u_opacity opacity = unpack_mix_float(in.opacity, drawable.opacity_t); #endif var stroke_color = props.stroke_color; #ifndef HAS_UNIFORM_u_stroke_color stroke_color = unpack_mix_color(in.stroke_color, drawable.stroke_color_t); #endif var stroke_width = props.stroke_width; #ifndef HAS_UNIFORM_u_stroke_width stroke_width = unpack_mix_float(in.stroke_width, drawable.stroke_width_t); #endif var stroke_opacity = props.stroke_opacity; #ifndef HAS_UNIFORM_u_stroke_opacity stroke_opacity = unpack_mix_float(in.stroke_opacity, drawable.stroke_opacity_t); #endif let radius_with_stroke = radius + stroke_width; var position: vec4; if (pitch_with_map) { var corner_position = circle_center; if (scale_with_map) { corner_position += scaled_extrude * radius_with_stroke; } else { let projected_center = drawable.matrix * vec4(circle_center, 0.0, 1.0); corner_position += scaled_extrude * radius_with_stroke * (projected_center.w / paintParams.camera_to_center_distance); } position = drawable.matrix * vec4(corner_position, 0.0, 1.0); } else { position = drawable.matrix * vec4(circle_center, 0.0, 1.0); var factor = position.w; if (scale_with_map) { factor = paintParams.camera_to_center_distance; } let delta = scaled_extrude * radius_with_stroke * factor; position = vec4(position.x + delta.x, position.y + delta.y, position.z, position.w); } let antialiasblur = 1.0 / max(paintParams.pixel_ratio * radius_with_stroke, 1e-6); out.position = position; out.extrude = extrude; out.circle_data = vec4(antialiasblur, radius, blur, opacity); out.color = color; out.stroke_color = stroke_color; out.stroke_data = vec2(stroke_width, stroke_opacity); return out; } )"; static constexpr auto fragment = R"( struct FragmentInput { @location(0) extrude: vec2, @location(1) circle_data: vec4, @location(2) color: vec4, @location(3) stroke_color: vec4, @location(4) stroke_data: vec2, }; @fragment fn main(in: FragmentInput) -> @location(0) vec4 { let extrude_length = length(in.extrude); let antialiasblur = in.circle_data.x; let radius = in.circle_data.y; let blur = in.circle_data.z; let opacity = in.circle_data.w; let stroke_width = in.stroke_data.x; let stroke_opacity = in.stroke_data.y; let antialiased_blur = -max(blur, antialiasblur); let opacity_t = smoothstep(0.0, antialiased_blur, extrude_length - 1.0); var color_t: f32; if (stroke_width < 0.01) { color_t = 0.0; } else { color_t = smoothstep(antialiased_blur, 0.0, extrude_length - radius / (radius + stroke_width)); } let final_color = mix(in.color * opacity, in.stroke_color * stroke_opacity, color_t); return opacity_t * final_color; } )"; }; } // namespace shaders } // namespace mbgl