namespace movit {
LumaMixEffect::LumaMixEffect()
- : transition_width(1.0f), progress(0.5f)
+ : transition_width(1.0f), progress(0.5f), inverse(0)
{
register_float("transition_width", &transition_width);
register_float("progress", &progress);
+ register_int("inverse", &inverse);
}
string LumaMixEffect::output_fragment_shader()
{
Effect::set_gl_state(glsl_program_num, prefix, sampler_num);
set_uniform_float(glsl_program_num, prefix, "progress_mul_w_plus_one", progress * (transition_width + 1.0));
+ set_uniform_int(glsl_program_num, prefix, "inverse", inverse);
}
} // namespace movit
uniform float PREFIX(progress_mul_w_plus_one);
+uniform bool PREFIX(inverse);
vec4 FUNCNAME(vec2 tc) {
vec4 first = INPUT1(tc);
// So clearly, it should move (w+1) units to the right, and apart from that
// just stay a simple mapping.
float w = PREFIX(transition_width);
- float luma = INPUT3(tc).x * w;
- float m = clamp((luma - w) + PREFIX(progress_mul_w_plus_one), 0.0, 1.0);
+ float luma = INPUT3(tc).x;
+ if (PREFIX(inverse)) {
+ luma = 1.0f - luma;
+ }
+ float m = clamp((luma * w - w) + PREFIX(progress_mul_w_plus_one), 0.0, 1.0);
return mix(first, second, m);
}
#define _MOVIT_LUMA_MIX_EFFECT_H 1
// Fade between two images based on a third monochrome one; lighter pixels
-// will be faded before darker pixels. This allows a wide range of different
-// video wipes implemented using a single effect.
+// will be faded before darker pixels (unless the inverse flag is set,
+// in which case darker pixels will be faded before lighter pixels).
+// This allows a wide range of different video wipes implemented using
+// a single effect.
//
// Note that despite the name, the third input's _red_ channel is what's used
// for transitions; there is no luma calculation done. If you need that,
private:
float transition_width, progress;
+ int inverse; // 0 or 1.
};
} // namespace movit
expect_equal(expected_data, out_data, 2, 2);
}
+TEST(LumaMixEffectTest, Inverse) {
+ float data_a[] = {
+ 0.0f, 0.25f,
+ 0.75f, 1.0f,
+ };
+ float data_b[] = {
+ 1.0f, 0.5f,
+ 0.65f, 0.6f,
+ };
+ float data_luma[] = {
+ 0.0f, 0.25f,
+ 0.5f, 0.75f,
+ };
+
+ EffectChainTester tester(data_a, 2, 2, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR);
+ Effect *input1 = tester.get_chain()->last_added_effect();
+ Effect *input2 = tester.add_input(data_b, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR);
+ Effect *input3 = tester.add_input(data_luma, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR);
+
+ Effect *luma_mix_effect = tester.get_chain()->add_effect(new LumaMixEffect(), input1, input2, input3);
+ ASSERT_TRUE(luma_mix_effect->set_float("transition_width", 100000.0f));
+ ASSERT_TRUE(luma_mix_effect->set_int("inverse", 1));
+
+ // Inverse is not the same as reverse, so progress=0 should behave identically
+ // as HardWipe, ie. everything should be from A.
+ float out_data[4];
+ ASSERT_TRUE(luma_mix_effect->set_float("progress", 0.0f));
+ tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
+ expect_equal(data_a, out_data, 2, 2);
+
+ // Lower two from A, the rest from B.
+ float expected_data_049[] = {
+ 1.0f, 0.5f,
+ 0.75f, 1.0f,
+ };
+ ASSERT_TRUE(luma_mix_effect->set_float("progress", 0.49f));
+ tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
+ expect_equal(expected_data_049, out_data, 2, 2);
+}
+
} // namespace movit