Add stroke alpha blend reference tests

This commit is contained in:
2026-06-02 17:23:44 +02:00
parent 995752da75
commit 8c0784f9c3
6 changed files with 194 additions and 7 deletions

View File

@@ -44,6 +44,67 @@ namespace {
return stroke;
}
[[nodiscard]] float blend_stroke_screen(float base, float stroke) noexcept
{
return base + stroke - (base * stroke);
}
[[nodiscard]] float blend_stroke_hard_light(float base, float stroke) noexcept
{
return stroke < 0.5F
? base * (stroke * 2.0F)
: blend_stroke_screen(base, 2.0F * stroke - 1.0F);
}
[[nodiscard]] float blend_stroke_hard_mix(float base, float stroke) noexcept
{
if (base == 0.0F) {
return 0.0F;
}
return base + stroke < 0.5F ? 0.0F : saturate(base + stroke);
}
[[nodiscard]] float blend_stroke_color_dodge(float base, float stroke) noexcept
{
if (base == 0.0F) {
return 0.0F;
}
if (stroke == 1.0F) {
return 1.0F;
}
return base / (1.0F - stroke);
}
[[nodiscard]] float blend_stroke_color_burn(float base, float stroke) noexcept
{
if (base == 1.0F) {
return 1.0F;
}
if (stroke == 0.0F) {
return 0.0F;
}
return 1.0F - std::min(1.0F, (1.0F - base) / stroke);
}
[[nodiscard]] float blend_stroke_linear_height(float base, float stroke, float depth) noexcept
{
const auto partial = (1.0F - stroke) * std::pow(depth, 0.25F) + (base * depth * 10.0F);
return base * partial;
}
[[nodiscard]] float blend_stroke_height(float base, float stroke, float depth) noexcept
{
const auto a = std::pow(1.0F - stroke, std::max(1.0F, (1.0F - depth) * 10.0F))
* std::pow(depth, 0.25F);
const auto b = base * depth * 5.0F;
return base * (a + b);
}
[[nodiscard]] float blend_rgb(float base, float stroke, float base_alpha, float stroke_alpha, float alpha_total, BlendMode mode) noexcept
{
if (alpha_total <= 0.0F) {
@@ -88,6 +149,44 @@ Rgba blend_pixels(Rgba base, Rgba stroke, BlendMode mode) noexcept
};
}
float blend_stroke_alpha(
float base,
float stroke,
float depth,
StrokeBlendMode mode) noexcept
{
base = saturate(base);
stroke = saturate(stroke);
depth = saturate(depth);
switch (mode) {
case StrokeBlendMode::normal:
return saturate(mix(base, stroke, depth));
case StrokeBlendMode::multiply:
return saturate(mix(base, base * stroke, depth));
case StrokeBlendMode::subtract:
return saturate(mix(base, std::max(0.0F, base - stroke), depth));
case StrokeBlendMode::darken:
return saturate(mix(base, std::min(base, stroke), depth));
case StrokeBlendMode::overlay:
return saturate(mix(base, blend_stroke_hard_light(stroke, base), depth));
case StrokeBlendMode::color_dodge:
return saturate(mix(base, blend_stroke_color_dodge(base, stroke), depth));
case StrokeBlendMode::color_burn:
return saturate(mix(base, blend_stroke_color_burn(base, stroke), depth));
case StrokeBlendMode::linear_burn:
return saturate(mix(base, saturate(base + stroke - 1.0F), depth));
case StrokeBlendMode::hard_mix:
return saturate(mix(base, blend_stroke_hard_mix(base, stroke), depth));
case StrokeBlendMode::linear_height:
return saturate(blend_stroke_linear_height(base, stroke, depth));
case StrokeBlendMode::height:
return saturate(blend_stroke_height(base, stroke, depth));
}
return 1.0F;
}
const char* blend_mode_name(BlendMode mode) noexcept
{
switch (mode) {
@@ -106,4 +205,34 @@ const char* blend_mode_name(BlendMode mode) noexcept
return "unknown";
}
const char* stroke_blend_mode_name(StrokeBlendMode mode) noexcept
{
switch (mode) {
case StrokeBlendMode::normal:
return "normal";
case StrokeBlendMode::multiply:
return "multiply";
case StrokeBlendMode::subtract:
return "subtract";
case StrokeBlendMode::darken:
return "darken";
case StrokeBlendMode::overlay:
return "overlay";
case StrokeBlendMode::color_dodge:
return "color_dodge";
case StrokeBlendMode::color_burn:
return "color_burn";
case StrokeBlendMode::linear_burn:
return "linear_burn";
case StrokeBlendMode::hard_mix:
return "hard_mix";
case StrokeBlendMode::linear_height:
return "linear_height";
case StrokeBlendMode::height:
return "height";
}
return "unknown";
}
}

View File

@@ -12,6 +12,20 @@ enum class BlendMode : std::uint8_t {
overlay,
};
enum class StrokeBlendMode : std::uint8_t {
normal,
multiply,
subtract,
darken,
overlay,
color_dodge,
color_burn,
linear_burn,
hard_mix,
linear_height,
height,
};
struct Rgba {
float r = 0.0F;
float g = 0.0F;
@@ -20,6 +34,12 @@ struct Rgba {
};
[[nodiscard]] Rgba blend_pixels(Rgba base, Rgba stroke, BlendMode mode) noexcept;
[[nodiscard]] float blend_stroke_alpha(
float base,
float stroke,
float depth,
StrokeBlendMode mode) noexcept;
[[nodiscard]] const char* blend_mode_name(BlendMode mode) noexcept;
[[nodiscard]] const char* stroke_blend_mode_name(StrokeBlendMode mode) noexcept;
}