Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
311 lines
8.5 KiB
C++
311 lines
8.5 KiB
C++
#pragma once
|
|
|
|
#include <mln/shaders/shader_source.hpp>
|
|
#include <mln/shaders/vulkan/shader_program.hpp>
|
|
|
|
namespace mln {
|
|
namespace shaders {
|
|
|
|
constexpr auto circleShaderPrelude = R"(
|
|
|
|
#define idCircleDrawableUBO idDrawableReservedVertexOnlyUBO
|
|
#define idCircleEvaluatedPropsUBO layerUBOStartId
|
|
|
|
)";
|
|
|
|
template <>
|
|
struct ShaderSource<BuiltIn::CircleShader, gfx::Backend::Type::Vulkan> {
|
|
static constexpr const char* name = "CircleShader";
|
|
|
|
static const std::array<AttributeInfo, 8> attributes;
|
|
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
|
static const std::array<TextureInfo, 0> textures;
|
|
|
|
static constexpr auto prelude = circleShaderPrelude;
|
|
static constexpr auto vertex = R"(
|
|
|
|
layout(location = 0) in ivec2 in_position;
|
|
|
|
#if !defined(HAS_UNIFORM_u_color)
|
|
layout(location = 1) in vec4 in_color;
|
|
#endif
|
|
|
|
#if !defined(HAS_UNIFORM_u_radius)
|
|
layout(location = 2) in vec2 in_radius;
|
|
#endif
|
|
|
|
#if !defined(HAS_UNIFORM_u_blur)
|
|
layout(location = 3) in vec2 in_blur;
|
|
#endif
|
|
|
|
#if !defined(HAS_UNIFORM_u_opacity)
|
|
layout(location = 4) in vec2 in_opacity;
|
|
#endif
|
|
|
|
#if !defined(HAS_UNIFORM_u_stroke_color)
|
|
layout(location = 5) in vec4 in_stroke_color;
|
|
#endif
|
|
|
|
#if !defined(HAS_UNIFORM_u_stroke_width)
|
|
layout(location = 6) in vec2 in_stroke_width;
|
|
#endif
|
|
|
|
#if !defined(HAS_UNIFORM_u_stroke_opacity)
|
|
layout(location = 7) in vec2 in_stroke_opacity;
|
|
#endif
|
|
|
|
layout(push_constant) uniform Constants {
|
|
int ubo_index;
|
|
} constant;
|
|
|
|
struct CircleDrawableUBO {
|
|
mat4 matrix;
|
|
vec2 extrude_scale;
|
|
// Interpolations
|
|
float color_t;
|
|
float radius_t;
|
|
float blur_t;
|
|
float opacity_t;
|
|
float stroke_color_t;
|
|
float stroke_width_t;
|
|
float stroke_opacity_t;
|
|
float pad1;
|
|
float pad2;
|
|
float pad3;
|
|
};
|
|
|
|
layout(std140, set = LAYER_SET_INDEX, binding = idCircleDrawableUBO) readonly buffer CircleDrawableUBOVector {
|
|
CircleDrawableUBO drawable_ubo[];
|
|
} drawableVector;
|
|
|
|
layout(set = LAYER_SET_INDEX, binding = idCircleEvaluatedPropsUBO) uniform CircleEvaluatedPropsUBO {
|
|
vec4 color;
|
|
vec4 stroke_color;
|
|
float radius;
|
|
float blur;
|
|
float opacity;
|
|
float stroke_width;
|
|
float stroke_opacity;
|
|
bool scale_with_map;
|
|
bool pitch_with_map;
|
|
float pad1;
|
|
} props;
|
|
|
|
layout(location = 0) out vec2 frag_extrude;
|
|
layout(location = 1) out float frag_antialiasblur;
|
|
|
|
#if !defined(HAS_UNIFORM_u_color)
|
|
layout(location = 2) out vec4 frag_color;
|
|
#endif
|
|
|
|
#if !defined(HAS_UNIFORM_u_radius)
|
|
layout(location = 3) out mediump float frag_radius;
|
|
#endif
|
|
|
|
#if !defined(HAS_UNIFORM_u_blur)
|
|
layout(location = 4) out lowp float frag_blur;
|
|
#endif
|
|
|
|
#if !defined(HAS_UNIFORM_u_opacity)
|
|
layout(location = 5) out lowp float frag_opacity;
|
|
#endif
|
|
|
|
#if !defined(HAS_UNIFORM_u_stroke_color)
|
|
layout(location = 6) out vec4 frag_stroke_color;
|
|
#endif
|
|
|
|
#if !defined(HAS_UNIFORM_u_stroke_width)
|
|
layout(location = 7) out mediump float frag_stroke_width;
|
|
#endif
|
|
|
|
#if !defined(HAS_UNIFORM_u_stroke_opacity)
|
|
layout(location = 8) out lowp float frag_stroke_opacity;
|
|
#endif
|
|
|
|
void main() {
|
|
const CircleDrawableUBO drawable = drawableVector.drawable_ubo[constant.ubo_index];
|
|
|
|
#if defined(HAS_UNIFORM_u_radius)
|
|
const float radius = props.radius;
|
|
#else
|
|
const float radius = unpack_mix_float(in_radius, drawable.radius_t);
|
|
#endif
|
|
|
|
#if defined(HAS_UNIFORM_u_stroke_width)
|
|
const float stroke_width = props.stroke_width;
|
|
#else
|
|
const float stroke_width = unpack_mix_float(in_stroke_width, drawable.stroke_width_t);
|
|
#endif
|
|
|
|
// unencode the extrusion vector that we snuck into the a_pos vector
|
|
const vec2 extrude = mod(in_position, 2.0) * 2.0 - 1.0;
|
|
const vec2 scaled_extrude = extrude * drawable.extrude_scale;
|
|
|
|
// multiply a_pos by 0.5, since we had it * 2 in order to sneak in extrusion data
|
|
const vec2 circle_center = floor(in_position * 0.5);
|
|
|
|
if (props.pitch_with_map) {
|
|
vec2 corner_position = circle_center;
|
|
if (props.scale_with_map) {
|
|
corner_position += scaled_extrude * (radius + stroke_width);
|
|
} else {
|
|
// Pitching the circle with the map effectively scales it with the map
|
|
// To counteract the effect for pitch-scale: viewport, we rescale the
|
|
// whole circle based on the pitch scaling effect at its central point
|
|
const vec4 projected_center = drawable.matrix * vec4(circle_center, 0, 1);
|
|
corner_position += scaled_extrude * (radius + stroke_width) *
|
|
(projected_center.w / paintParams.camera_to_center_distance);
|
|
}
|
|
|
|
gl_Position = drawable.matrix * vec4(corner_position, 0, 1);
|
|
} else {
|
|
gl_Position = drawable.matrix * vec4(circle_center, 0, 1);
|
|
|
|
const float factor = props.scale_with_map ? paintParams.camera_to_center_distance : gl_Position.w;
|
|
gl_Position.xy += scaled_extrude * (radius + stroke_width) * factor;
|
|
}
|
|
|
|
applySurfaceTransform();
|
|
|
|
// This is a minimum blur distance that serves as a faux-antialiasing for
|
|
// the circle. since blur is a ratio of the circle's size and the intent is
|
|
// to keep the blur at roughly 1px, the two are inversely related.
|
|
frag_antialiasblur = 1.0 / DEVICE_PIXEL_RATIO / (radius + stroke_width);
|
|
|
|
frag_extrude = extrude;
|
|
|
|
#if !defined(HAS_UNIFORM_u_color)
|
|
frag_color = unpack_mix_color(in_color, drawable.color_t);
|
|
#endif
|
|
|
|
#if !defined(HAS_UNIFORM_u_radius)
|
|
frag_radius = radius;
|
|
#endif
|
|
|
|
#if !defined(HAS_UNIFORM_u_blur)
|
|
frag_blur = unpack_mix_float(in_blur, drawable.blur_t);
|
|
#endif
|
|
|
|
#if !defined(HAS_UNIFORM_u_opacity)
|
|
frag_opacity = unpack_mix_float(in_opacity, drawable.opacity_t);
|
|
#endif
|
|
|
|
#if !defined(HAS_UNIFORM_u_stroke_color)
|
|
frag_stroke_color = unpack_mix_color(in_stroke_color, drawable.stroke_color_t);
|
|
#endif
|
|
|
|
#if !defined(HAS_UNIFORM_u_stroke_width)
|
|
frag_stroke_width = stroke_width;
|
|
#endif
|
|
|
|
#if !defined(HAS_UNIFORM_u_stroke_opacity)
|
|
frag_stroke_opacity = unpack_mix_float(in_stroke_opacity, drawable.stroke_opacity_t);
|
|
#endif
|
|
}
|
|
)";
|
|
|
|
static constexpr auto fragment = R"(
|
|
|
|
layout(location = 0) in vec2 frag_extrude;
|
|
layout(location = 1) in float frag_antialiasblur;
|
|
|
|
#if !defined(HAS_UNIFORM_u_color)
|
|
layout(location = 2) in vec4 frag_color;
|
|
#endif
|
|
|
|
#if !defined(HAS_UNIFORM_u_radius)
|
|
layout(location = 3) in mediump float frag_radius;
|
|
#endif
|
|
|
|
#if !defined(HAS_UNIFORM_u_blur)
|
|
layout(location = 4) in lowp float frag_blur;
|
|
#endif
|
|
|
|
#if !defined(HAS_UNIFORM_u_opacity)
|
|
layout(location = 5) in lowp float frag_opacity;
|
|
#endif
|
|
|
|
#if !defined(HAS_UNIFORM_u_stroke_color)
|
|
layout(location = 6) in vec4 frag_stroke_color;
|
|
#endif
|
|
|
|
#if !defined(HAS_UNIFORM_u_stroke_width)
|
|
layout(location = 7) in mediump float frag_stroke_width;
|
|
#endif
|
|
|
|
#if !defined(HAS_UNIFORM_u_stroke_opacity)
|
|
layout(location = 8) in lowp float frag_stroke_opacity;
|
|
#endif
|
|
|
|
layout(location = 0) out vec4 out_color;
|
|
|
|
layout(set = LAYER_SET_INDEX, binding = idCircleEvaluatedPropsUBO) uniform CircleEvaluatedPropsUBO {
|
|
vec4 color;
|
|
vec4 stroke_color;
|
|
float radius;
|
|
float blur;
|
|
float opacity;
|
|
float stroke_width;
|
|
float stroke_opacity;
|
|
bool scale_with_map;
|
|
bool pitch_with_map;
|
|
float pad1;
|
|
} props;
|
|
|
|
void main() {
|
|
|
|
#if defined(OVERDRAW_INSPECTOR)
|
|
out_color = vec4(1.0);
|
|
return;
|
|
#endif
|
|
|
|
#if defined(HAS_UNIFORM_u_color)
|
|
const vec4 color = props.color;
|
|
#else
|
|
const vec4 color = frag_color;
|
|
#endif
|
|
#if defined(HAS_UNIFORM_u_radius)
|
|
const float radius = props.radius;
|
|
#else
|
|
const float radius = frag_radius;
|
|
#endif
|
|
#if defined(HAS_UNIFORM_u_blur)
|
|
const float blur = props.blur;
|
|
#else
|
|
const float blur = frag_blur;
|
|
#endif
|
|
#if defined(HAS_UNIFORM_u_opacity)
|
|
const float opacity = props.opacity;
|
|
#else
|
|
const float opacity = frag_opacity;
|
|
#endif
|
|
#if defined(HAS_UNIFORM_u_stroke_color)
|
|
const vec4 stroke_color = props.stroke_color;
|
|
#else
|
|
const vec4 stroke_color = frag_stroke_color;
|
|
#endif
|
|
#if defined(HAS_UNIFORM_u_stroke_width)
|
|
const float stroke_width = props.stroke_width;
|
|
#else
|
|
const float stroke_width = frag_stroke_width;
|
|
#endif
|
|
#if defined(HAS_UNIFORM_u_stroke_opacity)
|
|
const float stroke_opacity = props.stroke_opacity;
|
|
#else
|
|
const float stroke_opacity = frag_stroke_opacity;
|
|
#endif
|
|
|
|
const float extrude_length = length(frag_extrude);
|
|
const float antialiased_blur = -max(blur, frag_antialiasblur);
|
|
const float opacity_t = smoothstep(0.0, antialiased_blur, extrude_length - 1.0);
|
|
const float color_t = (stroke_width < 0.01) ? 0.0 :
|
|
smoothstep(antialiased_blur, 0.0, extrude_length - radius / (radius + stroke_width));
|
|
|
|
out_color = opacity_t * mix(color * opacity, stroke_color * stroke_opacity, color_t);
|
|
}
|
|
)";
|
|
};
|
|
|
|
} // namespace shaders
|
|
} // namespace mln
|