+// NORMAL
+static const char *blend_normal_frag =
+ " vec4 result = mix(src_color, src_color, src_color.a);\n";
+
+// ADDITION
+static const char *blend_add_frag =
+ " vec4 result = dst_color + src_color;\n"
+ " result = clamp(result, 0.0, 1.0);\n";
+
+// SUBTRACT
+static const char *blend_subtract_frag =
+ " vec4 result = dst_color - src_color;\n"
+ " result = clamp(result, 0.0, 1.0);\n";
+
+// MULTIPLY
+static const char *blend_multiply_frag =
+ " vec4 result = dst_color * src_color;\n";
+
+// DIVIDE
+static const char *blend_divide_frag =
+ " vec4 result = dst_color / src_color;\n"
+ " if(src_color.r == 0.) result.r = 1.0;\n"
+ " if(src_color.g == 0.) result.g = 1.0;\n"
+ " if(src_color.b == 0.) result.b = 1.0;\n"
+ " if(src_color.a == 0.) result.a = 1.0;\n"
+ " result = clamp(result, 0.0, 1.0);\n";
+
+// MAX
+static const char *blend_max_frag =
+ " vec4 result = max(src_color, dst_color);\n";
+
+// MIN
+static const char *blend_min_frag =
+ " vec4 result = min(src_color, dst_color);\n";
+
+// AVERAGE
+static const char *blend_average_frag =
+ " vec4 result = (src_color + dst_color) * 0.5;\n";
+
+// DARKEN
+static const char *blend_darken_frag =
+ " vec4 result = vec4(src_color.rgb * (1.0 - dst_color.a) +"
+ " dst_color.rgb * (1.0 - src_color.a) +"
+ " min(src_color.rgb, dst_color.rgb), "
+ " src_color.a + dst_color.a - src_color.a * dst_color.a);\n"
+ " result = clamp(result, 0.0, 1.0);\n";
+
+// LIGHTEN
+static const char *blend_lighten_frag =
+ " vec4 result = vec4(src_color.rgb * (1.0 - dst_color.a) +"
+ " dst_color.rgb * (1.0 - src_color.a) +"
+ " max(src_color.rgb, dst_color.rgb), "
+ " src_color.a + dst_color.a - src_color.a * dst_color.a);\n"
+ " result = clamp(result, 0.0, 1.0);\n";
+
+// DST
+static const char *blend_dst_frag =
+ " vec4 result = dst_color;\n";
+
+// DST_ATOP
+static const char *blend_dst_atop_frag =
+ " vec4 result = vec4(src_color.rgb * dst_color.a + "
+ "(1.0 - src_color.a) * dst_color.rgb, dst_color.a);\n";
+
+// DST_IN
+static const char *blend_dst_in_frag =
+ " vec4 result = src_color * dst_color.a;\n";
+
+// DST_OUT
+static const char *blend_dst_out_frag =
+ " vec4 result = src_color * (1.0 - dst_color.a);\n";
+
+// DST_OVER
+static const char *blend_dst_over_frag =
+ " vec4 result = vec4(src_color.rgb + (1.0 - src_color.a) * dst_color.rgb, "
+ " dst_color.a + src_color.a - dst_color.a * src_color.a);\n";
+
+// SRC
+static const char *blend_src_frag =
+ " vec4 result = src_color;\n";
+
+// SRC_ATOP
+static const char *blend_src_atop_frag =
+ " vec4 result = vec4(dst_color.rgb * src_color.a + "
+ "src_color.rgb * (1.0 - dst_color.a), src_color.a);\n";
+
+// SRC_IN
+static const char *blend_src_in_frag =
+ " vec4 result = dst_color * src_color.a;\n";
+
+// SRC_OUT
+static const char *blend_src_out_frag =
+ " vec4 result = dst_color * (1.0 - src_color.a);\n";
+
+// SRC_OVER
+static const char *blend_src_over_frag =
+ " vec4 result = vec4(dst_color.rgb + (1.0 - dst_color.a) * src_color.rgb, "
+ "dst_color.a + src_color.a - dst_color.a * src_color.a);\n";
+
+// OR
+static const char *blend_or_frag =
+ " vec4 result = src_color + dst_color - src_color * dst_color;\n";
+
+// XOR
+static const char *blend_xor_frag =
+ " vec4 result = vec4(dst_color.rgb * (1.0 - src_color.a) + "
+ "(1.0 - dst_color.a) * src_color.rgb, "
+ "dst_color.a + src_color.a - 2.0 * dst_color.a * src_color.a);\n";
+
+static const char * const overlay_shaders[TRANSFER_TYPES] = {
+ blend_normal_frag, // TRANSFER_NORMAL
+ blend_add_frag, // TRANSFER_ADDITION
+ blend_subtract_frag, // TRANSFER_SUBTRACT
+ blend_multiply_frag, // TRANSFER_MULTIPLY
+ blend_divide_frag, // TRANSFER_DIVIDE
+ blend_src_frag, // TRANSFER_REPLACE
+ blend_max_frag, // TRANSFER_MAX
+ blend_min_frag, // TRANSFER_MIN
+ blend_average_frag, // TRANSFER_AVERAGE
+ blend_darken_frag, // TRANSFER_DARKEN
+ blend_lighten_frag, // TRANSFER_LIGHTEN
+ blend_dst_frag, // TRANSFER_DST
+ blend_dst_atop_frag, // TRANSFER_DST_ATOP
+ blend_dst_in_frag, // TRANSFER_DST_IN
+ blend_dst_out_frag, // TRANSFER_DST_OUT
+ blend_dst_over_frag, // TRANSFER_DST_OVER
+ blend_src_frag, // TRANSFER_SRC
+ blend_src_atop_frag, // TRANSFER_SRC_ATOP
+ blend_src_in_frag, // TRANSFER_SRC_IN
+ blend_src_out_frag, // TRANSFER_SRC_OUT
+ blend_src_over_frag, // TRANSFER_SRC_OVER
+ blend_or_frag, // TRANSFER_OR
+ blend_xor_frag // TRANSFER_XOR
+ };