highp float blend_stroke_screen(highp float base, highp float stroke)
{
    return base + stroke - (base * stroke);
}

mediump float blend_stroke_hard_light(highp float base, highp float stroke)
{
    if (stroke < 0.5)
        return base * (stroke * 2.0); // multiply
    else
        return blend_stroke_screen(base, 2.0 * stroke - 1.0);
}

highp float blend_stroke_hard_mix(highp float base, highp float stroke)
{
    if (base == 0.0)
        return 0.0;
    return base + stroke < 0.5 ? 0.0 : clamp(base + stroke, 0.0, 1.0);
}

highp float blend_stroke_color_dodge(highp float base, highp float stroke)
{
    if (base == 0.0)
        return 0.0;
    else if (stroke == 1.0)
        return 1.0;
    else
        return base / (1.0 - stroke);
}

highp float blend_stroke_color_burn(highp float base, highp float stroke)
{
    if (base == 1.0)
        return 1.0;
    else if (stroke == 0.0)
        return 0.0;
    else
        return 1.0 - min(1.0, (1.0 - base) / stroke);
}

highp float blend_stroke_linear_height(highp float base, highp float stroke, highp float depth)
{
    highp float partial = (1.0 - stroke) * pow(depth, 0.25) + (base * depth * 10.0);
    return base * partial;
}

highp float blend_stroke_height(highp float base, highp float stroke, highp float depth)
{
    highp float A = pow((1.0 - stroke), max(1.0, (1.0 - depth) * 10.0)) * pow(depth, 0.25);
    highp float B = (base * depth * 5.0);
    return base * (A + B);
}

highp float blend_stroke(highp float base, highp float stroke, highp float depth, int mode)
{
   if      (mode == 0) /* normal      */ return mix(base, stroke, depth);
   else if (mode == 1) /* multiply    */ return mix(base, base * stroke, depth);
   else if (mode == 2) /* subtract    */ return mix(base, max(0.0, base - stroke), depth);
   else if (mode == 3) /* darken      */ return mix(base, min(base, stroke), depth);
   else if (mode == 4) /* overlay     */ return mix(base, blend_stroke_hard_light(stroke, base), depth);
   else if (mode == 5) /* col-dodge   */ return mix(base, blend_stroke_color_dodge(base, stroke), depth);
   else if (mode == 6) /* col-burn    */ return mix(base, blend_stroke_color_burn(base, stroke), depth);
   else if (mode == 7) /* lin-burn    */ return mix(base, clamp(base + stroke - 1.0, 0.0, 1.0), depth);
   else if (mode == 8) /* hard-mix    */ return mix(base, blend_stroke_hard_mix(base, stroke), depth);
   else if (mode == 9) /* lin-height  */ return blend_stroke_linear_height(base, stroke, depth);
   else if (mode ==10) /* height      */ return blend_stroke_height(base, stroke, depth);
   else return 1.0;
}
