From: Steinar H. Gunderson Date: Mon, 1 Oct 2012 17:16:45 +0000 (+0200) Subject: Squash linear gamma back into the sRGB curve at the end. X-Git-Tag: 1.0~467 X-Git-Url: https://git.sesse.net/?p=movit;a=commitdiff_plain;h=f6c44598c9dad9ddd024c5f8f010d179a6d971fd Squash linear gamma back into the sRGB curve at the end. --- diff --git a/Makefile b/Makefile index 728b6f0..4dbaf12 100644 --- 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 colorspace_conversion_effect.o +OBJS += lift_gamma_gain_effect.o gamma_expansion_effect.o gamma_compression_effect.o colorspace_conversion_effect.o test: $(OBJS) $(CXX) -o test $(OBJS) $(LDFLAGS) diff --git a/effect_chain.cpp b/effect_chain.cpp index a838150..56d470f 100644 --- a/effect_chain.cpp +++ b/effect_chain.cpp @@ -10,6 +10,7 @@ #include "util.h" #include "effect_chain.h" #include "gamma_expansion_effect.h" +#include "gamma_compression_effect.h" #include "lift_gamma_gain_effect.h" #include "colorspace_conversion_effect.h" #include "texture_enum.h" @@ -42,24 +43,34 @@ Effect *instantiate_effect(EffectId effect) assert(false); } +void EffectChain::normalize_to_linear_gamma() +{ + GammaExpansionEffect *gamma_conversion = new GammaExpansionEffect(); + gamma_conversion->set_int("source_curve", current_gamma_curve); + effects.push_back(gamma_conversion); + current_gamma_curve = GAMMA_LINEAR; +} + +void EffectChain::normalize_to_srgb() +{ + assert(current_gamma_curve == GAMMA_LINEAR); + ColorSpaceConversionEffect *colorspace_conversion = new ColorSpaceConversionEffect(); + colorspace_conversion->set_int("source_space", current_color_space); + colorspace_conversion->set_int("destination_space", COLORSPACE_sRGB); + effects.push_back(colorspace_conversion); + current_color_space = COLORSPACE_sRGB; +} + Effect *EffectChain::add_effect(EffectId effect_id) { Effect *effect = instantiate_effect(effect_id); if (effect->needs_linear_light() && current_gamma_curve != GAMMA_LINEAR) { - GammaExpansionEffect *gamma_conversion = new GammaExpansionEffect(); - gamma_conversion->set_int("source_curve", current_gamma_curve); - effects.push_back(gamma_conversion); - current_gamma_curve = GAMMA_LINEAR; + normalize_to_linear_gamma(); } if (effect->needs_srgb_primaries() && current_color_space != COLORSPACE_sRGB) { - assert(current_gamma_curve == GAMMA_LINEAR); - ColorSpaceConversionEffect *colorspace_conversion = new ColorSpaceConversionEffect(); - colorspace_conversion->set_int("source_space", current_color_space); - colorspace_conversion->set_int("destination_space", COLORSPACE_sRGB); - effects.push_back(colorspace_conversion); - current_color_space = COLORSPACE_sRGB; + normalize_to_srgb(); } // not handled yet @@ -113,6 +124,19 @@ std::string replace_prefix(const std::string &text, const std::string &prefix) void EffectChain::finalize() { + // TODO: If we want a non-sRGB output color space, convert. + + if (current_gamma_curve != output_format.gamma_curve) { + if (current_gamma_curve != GAMMA_LINEAR) { + normalize_to_linear_gamma(); + } + assert(current_gamma_curve == GAMMA_LINEAR); + GammaCompressionEffect *gamma_conversion = new GammaCompressionEffect(); + gamma_conversion->set_int("destination_curve", output_format.gamma_curve); + effects.push_back(gamma_conversion); + current_gamma_curve = output_format.gamma_curve; + } + std::string frag_shader = read_file("header.glsl"); for (unsigned i = 0; i < effects.size(); ++i) { diff --git a/effect_chain.h b/effect_chain.h index 9622abc..045c9aa 100644 --- a/effect_chain.h +++ b/effect_chain.h @@ -46,6 +46,9 @@ public: void render_to_screen(unsigned char *src); private: + void normalize_to_linear_gamma(); + void normalize_to_srgb(); + unsigned width, height; ImageFormat input_format, output_format; std::vector effects; diff --git a/gamma_compression_effect.cpp b/gamma_compression_effect.cpp new file mode 100644 index 0000000..2c88b02 --- /dev/null +++ b/gamma_compression_effect.cpp @@ -0,0 +1,23 @@ +#include + +#include "gamma_compression_effect.h" +#include "util.h" + +GammaCompressionEffect::GammaCompressionEffect() + : destination_curve(GAMMA_LINEAR) +{ + register_int("destination_curve", (int *)&destination_curve); +} + +std::string GammaCompressionEffect::output_glsl() +{ + switch (destination_curve) { + case GAMMA_sRGB: + return read_file("gamma_compression_effect_srgb.glsl"); + case GAMMA_REC_709: // and GAMMA_REC_601 + // Not implemented yet. + assert(false); + default: + assert(false); + } +} diff --git a/gamma_compression_effect.h b/gamma_compression_effect.h new file mode 100644 index 0000000..ec2a77a --- /dev/null +++ b/gamma_compression_effect.h @@ -0,0 +1,16 @@ +#ifndef _GAMMA_COMPRESSION_EFFECT_H +#define _GAMMA_COMPRESSION_EFFECT_H 1 + +#include "effect.h" +#include "effect_chain.h" + +class GammaCompressionEffect : public Effect { +public: + GammaCompressionEffect(); + std::string output_glsl(); + +private: + GammaCurve destination_curve; +}; + +#endif // !defined(_GAMMA_COMPRESSION_EFFECT_H) diff --git a/gamma_compression_effect_srgb.glsl b/gamma_compression_effect_srgb.glsl new file mode 100644 index 0000000..2d53e08 --- /dev/null +++ b/gamma_compression_effect_srgb.glsl @@ -0,0 +1,31 @@ +// Compress to sRGB gamma curve. + +#if 0 + +// if we have the lut +uniform sampler1D PREFIX(srgb_tex); + +vec4 FUNCNAME(vec2 tc) { + vec4 x = LAST_INPUT(tc); + + x.r = texture1D(PREFIX(srgb_tex), x.r).x; + x.g = texture1D(PREFIX(srgb_tex), x.g).x; + x.b = texture1D(PREFIX(srgb_tex), x.b).x; + + return x; +} + +#else + +// use arithmetic (slow) +vec4 FUNCNAME(vec2 tc) { + vec4 x = LAST_INPUT(tc); + + vec3 a = vec3(12.92) * x.rgb; + vec3 b = vec3(1.055) * pow(x.rgb, vec3(1.0/2.4)) - vec3(0.055); + vec3 f = vec3(greaterThan(x.rgb, vec3(0.0031308))); + + return vec4(mix(a, b, f), x.a); +} + +#endif