--- /dev/null
+#include "alpha_division_effect.h"
+#include "util.h"
+
+std::string AlphaDivisionEffect::output_fragment_shader()
+{
+ return read_file("alpha_division_effect.frag");
+}
--- /dev/null
+// Note: Division by zero will give inf or nan, whose conversion to
+// integer types is implementation-defined. However, anything is fine for
+// alpha=0, since that's undefined anyway.
+vec4 FUNCNAME(vec2 tc) {
+ vec4 x = INPUT(tc);
+ x.rgb /= x.aaa;
+ return x;
+}
--- /dev/null
+#ifndef _ALPHA_DIVISION_EFFECT_H
+#define _ALPHA_DIVISION_EFFECT_H 1
+
+// Convert premultiplied alpha to postmultiplied alpha, simply by multiplying.
+
+#include "effect.h"
+
+class AlphaDivisionEffect : public Effect {
+public:
+ AlphaDivisionEffect() {}
+ virtual std::string effect_type_id() const { return "AlphaDivisionEffect"; }
+ std::string output_fragment_shader();
+};
+
+#endif // !defined(_ALPHA_DIVISION_EFFECT_H)
--- /dev/null
+// Unit tests for AlphaDivisionEffect.
+
+#include "test_util.h"
+#include "gtest/gtest.h"
+
+TEST(AlphaDivisionEffectTest, SimpleTest) {
+ const int size = 2;
+ float data[4 * size] = {
+ 0.1f, 0.5f, 0.1f, 0.5f,
+ 0.2f, 0.2f, 1.0f, 1.0f,
+ };
+ float expected_data[4 * size] = {
+ 0.2f, 1.0f, 0.2f, 0.5f,
+ 0.2f, 0.2f, 1.0f, 1.0f,
+ };
+ float out_data[4 * size];
+ EffectChainTester tester(data, 1, size, FORMAT_RGBA_PREMULTIPLIED_ALPHA, COLORSPACE_sRGB, GAMMA_LINEAR);
+ tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_LINEAR);
+
+ expect_equal(expected_data, out_data, 4, size);
+}
+
+TEST(AlphaDivisionEffectTest, ZeroAlphaIsPreserved) {
+ const int size = 2;
+ float data[4 * size] = {
+ 0.1f, 0.5f, 0.1f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f,
+ };
+ float out_data[4 * size];
+ EffectChainTester tester(data, 1, size, FORMAT_RGBA_PREMULTIPLIED_ALPHA, COLORSPACE_sRGB, GAMMA_LINEAR);
+ tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_LINEAR);
+
+ EXPECT_EQ(0.0f, out_data[3]);
+ EXPECT_EQ(0.0f, out_data[7]);
+}
--- /dev/null
+#include "alpha_multiplication_effect.h"
+#include "util.h"
+
+std::string AlphaMultiplicationEffect::output_fragment_shader()
+{
+ return read_file("alpha_multiplication_effect.frag");
+}
--- /dev/null
+vec4 FUNCNAME(vec2 tc) {
+ vec4 x = INPUT(tc);
+ x.rgb *= x.aaa;
+ return x;
+}
--- /dev/null
+#ifndef _ALPHA_MULTIPLICATION_EFFECT_H
+#define _ALPHA_MULTIPLICATION_EFFECT_H 1
+
+// Convert postmultiplied alpha to premultiplied alpha, simply by multiplying.
+
+#include "effect.h"
+
+class AlphaMultiplicationEffect : public Effect {
+public:
+ AlphaMultiplicationEffect() {}
+ virtual std::string effect_type_id() const { return "AlphaMultiplicationEffect"; }
+ std::string output_fragment_shader();
+};
+
+#endif // !defined(_ALPHA_MULTIPLICATION_EFFECT_H)
--- /dev/null
+// Unit tests for AlphaMultiplicationEffect.
+
+#include "test_util.h"
+#include "gtest/gtest.h"
+
+TEST(AlphaMultiplicationEffectTest, SimpleTest) {
+ const int size = 3;
+ float data[4 * size] = {
+ 1.0f, 0.2f, 0.2f, 0.0f,
+ 0.2f, 1.0f, 0.2f, 0.5f,
+ 0.2f, 0.2f, 1.0f, 1.0f,
+ };
+ float expected_data[4 * size] = {
+ 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.1f, 0.5f, 0.1f, 0.5f,
+ 0.2f, 0.2f, 1.0f, 1.0f,
+ };
+ float out_data[4 * size];
+ EffectChainTester tester(data, 1, size, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, COLORSPACE_sRGB, GAMMA_LINEAR);
+ tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_LINEAR, OUTPUT_ALPHA_PREMULTIPLIED);
+
+ expect_equal(expected_data, out_data, 4, size);
+}
--- /dev/null
+vec4 FUNCNAME(vec2 tc) {
+ return vec4(0.0, 0.0, 1.0, 1.0);
+}