Add a diffusion effect, and hook it up in the GUI.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Fri, 5 Oct 2012 10:43:35 +0000 (12:43 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Fri, 5 Oct 2012 10:43:35 +0000 (12:43 +0200)
Makefile
diffusion_effect.cpp [new file with mode: 0644]
diffusion_effect.h [new file with mode: 0644]
effect_chain.cpp
effect_id.h
main.cpp
overlay_matte_effect.frag [new file with mode: 0644]

index 1b6bdd5..e17e229 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@ CXX=g++
 CXXFLAGS=-Wall -g
 LDFLAGS=-lSDL -lSDL_image -lGL
 OBJS=main.o util.o widgets.o effect.o effect_chain.o
-OBJS += lift_gamma_gain_effect.o gamma_expansion_effect.o gamma_compression_effect.o colorspace_conversion_effect.o saturation_effect.o vignette_effect.o mirror_effect.o blur_effect.o sandbox_effect.o
+OBJS += lift_gamma_gain_effect.o gamma_expansion_effect.o gamma_compression_effect.o colorspace_conversion_effect.o saturation_effect.o vignette_effect.o mirror_effect.o blur_effect.o diffusion_effect.o sandbox_effect.o
 
 test: $(OBJS)
        $(CXX) -o test $(OBJS) $(LDFLAGS)
diff --git a/diffusion_effect.cpp b/diffusion_effect.cpp
new file mode 100644 (file)
index 0000000..cf3188b
--- /dev/null
@@ -0,0 +1,46 @@
+#include <math.h>
+#include <assert.h>
+
+#include "diffusion_effect.h"
+#include "blur_effect.h"
+#include "effect_chain.h"
+#include "util.h"
+
+DiffusionEffect::DiffusionEffect()
+       : blur(new BlurEffect),
+         overlay_matte(new OverlayMatteEffect)
+{
+}
+
+std::string DiffusionEffect::output_fragment_shader()
+{
+       return read_file("sandbox_effect.frag");
+}
+
+void DiffusionEffect::add_self_to_effect_chain(EffectChain *chain, const std::vector<Effect *> &inputs) {
+       assert(inputs.size() == 1);
+       blur->add_self_to_effect_chain(chain, inputs);
+
+       std::vector<Effect *> overlay_matte_inputs;
+       overlay_matte_inputs.push_back(inputs[0]);
+       overlay_matte_inputs.push_back(chain->get_last_added_effect());  // FIXME
+       overlay_matte->add_self_to_effect_chain(chain, overlay_matte_inputs);
+}
+
+bool DiffusionEffect::set_float(const std::string &key, float value) {
+       if (key == "blurred_mix_amount") {
+               return overlay_matte->set_float(key, value);
+       }
+       return blur->set_float(key, value);
+}
+
+OverlayMatteEffect::OverlayMatteEffect()
+       : blurred_mix_amount(0.3f)
+{
+       register_float("blurred_mix_amount", &blurred_mix_amount);
+}
+
+std::string OverlayMatteEffect::output_fragment_shader()
+{
+       return read_file("overlay_matte_effect.frag");
+}
diff --git a/diffusion_effect.h b/diffusion_effect.h
new file mode 100644 (file)
index 0000000..4223d22
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef _DIFFUSION_EFFECT_H
+#define _DIFFUSION_EFFECT_H 1
+
+// There are many different effects that go under the name of "diffusion",
+// seemingly all of the inspired by the effect you get when you put a
+// diffusion filter in front of your camera lens. The effect most people
+// want is a general flattening/smoothing of the light, and reduction of
+// fine detail (most notably, blemishes in people's skin), without ruining
+// edges, which a regular blur would do.
+//
+// We do a relatively simple version, sometimes known as "white diffusion",
+// where we first blur the picture, and then overlay it on the original
+// using the original as a matte.
+
+#include "effect.h"
+
+class BlurEffect;
+class OverlayMatteEffect;
+
+class DiffusionEffect : public Effect {
+public:
+       DiffusionEffect();
+       std::string output_fragment_shader();
+
+       virtual void add_self_to_effect_chain(EffectChain *chain, const std::vector<Effect *> &input);
+       virtual bool set_float(const std::string &key, float value);
+
+private:
+       BlurEffect *blur;
+       OverlayMatteEffect *overlay_matte;
+};
+
+// Used internally by DiffusionEffect; combines the blurred and the original
+// version using the original as a matte.
+class OverlayMatteEffect : public Effect {
+public:
+       OverlayMatteEffect();
+       std::string output_fragment_shader();
+
+       unsigned num_inputs() const { return 2; }
+
+private:
+       float blurred_mix_amount;
+};
+
+
+#endif // !defined(_DIFFUSION_EFFECT_H)
index 1244ecb..fdc08cf 100644 (file)
@@ -21,6 +21,7 @@
 #include "mirror_effect.h"
 #include "vignette_effect.h"
 #include "blur_effect.h"
+#include "diffusion_effect.h"
 
 EffectChain::EffectChain(unsigned width, unsigned height)
        : width(width),
@@ -81,6 +82,8 @@ Effect *instantiate_effect(EffectId effect)
                return new VignetteEffect();
        case EFFECT_BLUR:
                return new BlurEffect();
+       case EFFECT_DIFFUSION:
+               return new DiffusionEffect();
        }
        assert(false);
 }
index bed27f5..545a7be 100644 (file)
@@ -16,6 +16,7 @@ enum EffectId {
        EFFECT_MIRROR,
        EFFECT_VIGNETTE,
        EFFECT_BLUR,
+       EFFECT_DIFFUSION,
 };
 
 #endif // !defined(_EFFECT_ID_H)
index abc0a38..bbc7752 100644 (file)
--- a/main.cpp
+++ b/main.cpp
@@ -33,9 +33,10 @@ float gamma_theta = 0.0f, gamma_rad = 0.0f, gamma_v = 0.5f;
 float gain_theta = 0.0f, gain_rad = 0.0f, gain_v = 0.25f;
 float saturation = 1.0f;
 
-float radius = 0.3f;
-float inner_radius = 0.3f;
-float blur_radius = 3.0f;
+//float radius = 0.3f;
+// float inner_radius = 0.3f;
+float blur_radius = 20.0f;
+float blurred_mix_amount = 0.5f;
        
 void update_hsv(Effect *lift_gamma_gain_effect, Effect *saturation_effect)
 {
@@ -72,12 +73,16 @@ void mouse(int x, int y)
                read_colorwheel(xf, yf - 0.4f, &gain_rad, &gain_theta, &gain_v);
        } else if (yf >= 0.6f && yf < 0.62f && xf < 0.2f) {
                saturation = (xf / 0.2f) * 4.0f;
+#if 0
        } else if (yf >= 0.65f && yf < 0.67f && xf < 0.2f) {
                radius = (xf / 0.2f);
        } else if (yf >= 0.70f && yf < 0.72f && xf < 0.2f) {
                inner_radius = (xf / 0.2f);
+#endif
        } else if (yf >= 0.75f && yf < 0.77f && xf < 0.2f) {
                blur_radius = (xf / 0.2f) * 100.0f;
+       } else if (yf >= 0.80f && yf < 0.82f && xf < 0.2f) {
+               blurred_mix_amount = (xf / 0.2f);
        }
 }
 
@@ -162,8 +167,8 @@ int main(int argc, char **argv)
        chain.add_input(inout_format);
        Effect *lift_gamma_gain_effect = chain.add_effect(EFFECT_LIFT_GAMMA_GAIN);
        Effect *saturation_effect = chain.add_effect(EFFECT_SATURATION);
-       Effect *blur_effect = chain.add_effect(EFFECT_BLUR);
-       Effect *vignette_effect = chain.add_effect(EFFECT_VIGNETTE);
+       Effect *diffusion_effect = chain.add_effect(EFFECT_DIFFUSION);
+       //Effect *vignette_effect = chain.add_effect(EFFECT_VIGNETTE);
        //Effect *sandbox_effect = chain.add_effect(EFFECT_SANDBOX);
        //sandbox_effect->set_float("parm", 42.0f);
        //chain.add_effect(EFFECT_MIRROR);
@@ -205,11 +210,12 @@ int main(int argc, char **argv)
                ++frame;
 
                update_hsv(lift_gamma_gain_effect, saturation_effect);
-               vignette_effect->set_float("radius", radius);
-               vignette_effect->set_float("inner_radius", inner_radius);
+               //vignette_effect->set_float("radius", radius);
+               //vignette_effect->set_float("inner_radius", inner_radius);
                //vignette_effect->set_vec2("center", (float[]){ 0.7f, 0.5f });
 
-               blur_effect->set_float("radius", blur_radius);
+               diffusion_effect->set_float("radius", blur_radius);
+               diffusion_effect->set_float("blurred_mix_amount", blurred_mix_amount);
 
                chain.render_to_screen(src_img);
                
@@ -225,9 +231,12 @@ int main(int argc, char **argv)
                draw_hsv_wheel(0.2f, gamma_rad, gamma_theta, gamma_v);
                draw_hsv_wheel(0.4f, gain_rad, gain_theta, gain_v);
                draw_saturation_bar(0.6f, saturation / 4.0f);
+#if 0
                draw_saturation_bar(0.65f, radius);
                draw_saturation_bar(0.70f, inner_radius);
+#endif
                draw_saturation_bar(0.75f, blur_radius / 100.0f);
+               draw_saturation_bar(0.80f, blurred_mix_amount);
 
                SDL_GL_SwapBuffers();
                check_error();
diff --git a/overlay_matte_effect.frag b/overlay_matte_effect.frag
new file mode 100644 (file)
index 0000000..f80f0b1
--- /dev/null
@@ -0,0 +1,5 @@
+vec4 FUNCNAME(vec2 tc) {
+       vec4 orig = INPUT1(tc);
+       vec4 blurred = INPUT2(tc);
+       return mix(orig, blurred, orig * vec4(PREFIX(blurred_mix_amount)));
+}