From: Steinar H. Gunderson Date: Mon, 14 Jan 2013 01:27:35 +0000 (+0100) Subject: Make Movit work in premultiplied alpha. X-Git-Tag: 1.0~183 X-Git-Url: https://git.sesse.net/?p=movit;a=commitdiff_plain;h=caa05550e868db406e4b54e69d60b5573f59cb60 Make Movit work in premultiplied alpha. This is a pretty big change, even though the most visible change right now is that OverlayEffect looks better in the edges of upscaled material (which you won't really notice too much, given that our handling of different resolutions already sucks). Since most material is going to assume postmultiplied alpha, we need to track the status around the graph pretty much as we already do with gamma and colorspaces, so it's quite a lot of new code (and associated test complexity). It really does look better, though. Negative sides: MixEffect has gotten less flexible since it now also handles the alpha; for instance, you can't really use it to subtract things the same way anymore. Also, I think the glow effect has been broken by the changes to MixEffect, so I'll need to fix it and then add a test so it doesn't break again. --- diff --git a/alpha_division_effect.cpp b/alpha_division_effect.cpp new file mode 100644 index 0000000..9f7b3b7 --- /dev/null +++ b/alpha_division_effect.cpp @@ -0,0 +1,7 @@ +#include "alpha_division_effect.h" +#include "util.h" + +std::string AlphaDivisionEffect::output_fragment_shader() +{ + return read_file("alpha_division_effect.frag"); +} diff --git a/alpha_division_effect.frag b/alpha_division_effect.frag new file mode 100644 index 0000000..6b58148 --- /dev/null +++ b/alpha_division_effect.frag @@ -0,0 +1,8 @@ +// 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; +} diff --git a/alpha_division_effect.h b/alpha_division_effect.h new file mode 100644 index 0000000..e700112 --- /dev/null +++ b/alpha_division_effect.h @@ -0,0 +1,15 @@ +#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) diff --git a/alpha_division_effect_test.cpp b/alpha_division_effect_test.cpp new file mode 100644 index 0000000..8c29702 --- /dev/null +++ b/alpha_division_effect_test.cpp @@ -0,0 +1,35 @@ +// 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]); +} diff --git a/alpha_multiplication_effect.cpp b/alpha_multiplication_effect.cpp new file mode 100644 index 0000000..dff6f15 --- /dev/null +++ b/alpha_multiplication_effect.cpp @@ -0,0 +1,7 @@ +#include "alpha_multiplication_effect.h" +#include "util.h" + +std::string AlphaMultiplicationEffect::output_fragment_shader() +{ + return read_file("alpha_multiplication_effect.frag"); +} diff --git a/alpha_multiplication_effect.frag b/alpha_multiplication_effect.frag new file mode 100644 index 0000000..0a0a6eb --- /dev/null +++ b/alpha_multiplication_effect.frag @@ -0,0 +1,5 @@ +vec4 FUNCNAME(vec2 tc) { + vec4 x = INPUT(tc); + x.rgb *= x.aaa; + return x; +} diff --git a/alpha_multiplication_effect.h b/alpha_multiplication_effect.h new file mode 100644 index 0000000..c64f2dc --- /dev/null +++ b/alpha_multiplication_effect.h @@ -0,0 +1,15 @@ +#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) diff --git a/alpha_multiplication_effect_test.cpp b/alpha_multiplication_effect_test.cpp new file mode 100644 index 0000000..eab4b25 --- /dev/null +++ b/alpha_multiplication_effect_test.cpp @@ -0,0 +1,23 @@ +// 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); +} diff --git a/blue.frag b/blue.frag new file mode 100644 index 0000000..fae19ba --- /dev/null +++ b/blue.frag @@ -0,0 +1,3 @@ +vec4 FUNCNAME(vec2 tc) { + return vec4(0.0, 0.0, 1.0, 1.0); +}