#include <GL/gl.h>
#include <GL/glext.h>
+void set_uniform_int(GLuint glsl_program_num, const std::string &prefix, const std::string &key, int value)
+{
+ std::string name = prefix + "_" + key;
+ GLint l = glGetUniformLocation(glsl_program_num, name.c_str());
+ if (l == -1) {
+ return;
+ }
+ check_error();
+ glUniform1i(l, value);
+ check_error();
+}
+
void set_uniform_float(GLuint glsl_program_num, const std::string &prefix, const std::string &key, float value)
{
std::string name = prefix + "_" + key;
params_vec3[key] = values;
}
+void Effect::register_1d_texture(const std::string &key, float *values, size_t size)
+{
+ assert(params_tex_1d.count(key) == 0);
+
+ Texture1D tex;
+ tex.values = values;
+ tex.size = size;
+ tex.needs_update = false;
+ glGenTextures(1, &tex.texture_num);
+
+ glBindTexture(GL_TEXTURE_1D, tex.texture_num);
+ check_error();
+ glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ check_error();
+ glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ check_error();
+ glTexImage1D(GL_TEXTURE_1D, 0, GL_LUMINANCE16F_ARB, size, 0, GL_LUMINANCE, GL_FLOAT, values);
+ check_error();
+
+ params_tex_1d[key] = tex;
+}
+
+void Effect::invalidate_1d_texture(const std::string &key)
+{
+ assert(params_tex_1d.count(key) != 0);
+ params_tex_1d[key].needs_update = true;
+}
+
// Output convenience uniforms for each parameter.
// These will be filled in per-frame.
std::string Effect::output_convenience_uniforms()
sprintf(buf, "uniform vec3 PREFIX(%s);\n", it->first.c_str());
output.append(buf);
}
+ for (std::map<std::string, Texture1D>::const_iterator it = params_tex_1d.begin();
+ it != params_tex_1d.end();
+ ++it) {
+ char buf[256];
+ sprintf(buf, "uniform sampler1D PREFIX(%s);\n", it->first.c_str());
+ output.append(buf);
+ }
return output;
}
-void Effect::set_uniforms(GLuint glsl_program_num, const std::string& prefix)
+void Effect::set_uniforms(GLuint glsl_program_num, const std::string& prefix, unsigned *sampler_num)
{
for (std::map<std::string, float*>::const_iterator it = params_float.begin();
it != params_float.end();
++it) {
set_uniform_vec3(glsl_program_num, prefix, it->first, it->second);
}
+
+ for (std::map<std::string, Texture1D>::const_iterator it = params_tex_1d.begin();
+ it != params_tex_1d.end();
+ ++it) {
+ glActiveTexture(GL_TEXTURE0 + *sampler_num);
+ check_error();
+ glBindTexture(GL_TEXTURE_1D, it->second.texture_num);
+ check_error();
+
+ if (it->second.needs_update) {
+ glTexImage1D(GL_TEXTURE_1D, 0, GL_LUMINANCE16F_ARB, it->second.size, 0, GL_LUMINANCE, GL_FLOAT, it->second.values);
+ check_error();
+ }
+
+ set_uniform_int(glsl_program_num, prefix, it->first, *sampler_num);
+ ++*sampler_num;
+ }
}
};
// Convenience functions that deal with prepending the prefix.
+void set_uniform_int(GLuint glsl_program_num, const std::string &prefix, const std::string &key, int value);
void set_uniform_float(GLuint glsl_program_num, const std::string &prefix, const std::string &key, float value);
void set_uniform_vec2(GLuint glsl_program_num, const std::string &prefix, const std::string &key, const float *values);
void set_uniform_vec3(GLuint glsl_program_num, const std::string &prefix, const std::string &key, const float *values);
virtual std::string output_convenience_uniforms();
virtual std::string output_fragment_shader() = 0;
- virtual void set_uniforms(GLuint glsl_program_num, const std::string& prefix);
+ virtual void set_uniforms(GLuint glsl_program_num, const std::string& prefix, unsigned *sampler_num);
// Neither of these take ownership.
bool set_int(const std::string&, int value);
void register_float(const std::string &key, float *value);
void register_vec2(const std::string &key, float *values);
void register_vec3(const std::string &key, float *values);
+ void register_1d_texture(const std::string &key, float *values, size_t size);
+ void invalidate_1d_texture(const std::string &key);
private:
+ struct Texture1D {
+ float *values;
+ size_t size;
+ bool needs_update;
+ GLuint texture_num;
+ };
+
std::map<std::string, int *> params_int;
std::map<std::string, float *> params_float;
std::map<std::string, float *> params_vec2;
std::map<std::string, float *> params_vec3;
+ std::map<std::string, Texture1D> params_tex_1d;
};
#endif // !defined(_EFFECT_H)
check_error();
glUniform1i(glGetUniformLocation(glsl_program_num, "input_tex"), 0);
+ unsigned sampler_num = 1;
for (unsigned i = 0; i < effects.size(); ++i) {
char effect_id[256];
sprintf(effect_id, "eff%d", i);
- effects[i]->set_uniforms(glsl_program_num, effect_id);
+ effects[i]->set_uniforms(glsl_program_num, effect_id, &sampler_num);
}
glDisable(GL_BLEND);
+#include <math.h>
#include <assert.h>
#include "gamma_compression_effect.h"
: destination_curve(GAMMA_LINEAR)
{
register_int("destination_curve", (int *)&destination_curve);
+ register_1d_texture("compression_curve_tex", compression_curve, COMPRESSION_CURVE_SIZE);
}
std::string GammaCompressionEffect::output_fragment_shader()
{
- switch (destination_curve) {
- case GAMMA_LINEAR:
+ if (destination_curve == GAMMA_LINEAR) {
return read_file("identity.frag");
- case GAMMA_sRGB:
- return read_file("gamma_compression_effect_srgb.frag");
- case GAMMA_REC_709: // and GAMMA_REC_601
- return read_file("gamma_compression_effect_rec709.frag");
- default:
- assert(false);
}
+ if (destination_curve == GAMMA_sRGB) {
+ for (unsigned i = 0; i < COMPRESSION_CURVE_SIZE; ++i) {
+ float x = i / (float)(COMPRESSION_CURVE_SIZE - 1);
+ if (x < 0.0031308f) {
+ compression_curve[i] = 12.92f * x;
+ } else {
+ compression_curve[i] = 1.055f * pow(x, 1.0f / 2.4f) - 0.055f;
+ }
+ }
+ invalidate_1d_texture("compression_curve_tex");
+ return read_file("gamma_compression_effect.frag");
+ }
+ if (destination_curve == GAMMA_REC_709) { // And Rec. 601.
+ for (unsigned i = 0; i < COMPRESSION_CURVE_SIZE; ++i) {
+ float x = i / (float)(COMPRESSION_CURVE_SIZE - 1);
+ if (x < 0.018f) {
+ compression_curve[i] = 4.5f * x;
+ } else {
+ compression_curve[i] = 1.099f * pow(x, 0.45f) - 0.099;
+ }
+ }
+ invalidate_1d_texture("compression_curve_tex");
+ return read_file("gamma_compression_effect.frag");
+ }
+ assert(false);
}
--- /dev/null
+// Compress to sRGB gamma curve.
+
+vec4 FUNCNAME(vec2 tc) {
+ vec4 x = LAST_INPUT(tc);
+
+ x.r = texture1D(PREFIX(compression_curve_tex), x.r).x;
+ x.g = texture1D(PREFIX(compression_curve_tex), x.g).x;
+ x.b = texture1D(PREFIX(compression_curve_tex), x.b).x;
+
+ return x;
+}
#include "effect.h"
#include "effect_chain.h"
+#define COMPRESSION_CURVE_SIZE 4096
+
class GammaCompressionEffect : public Effect {
public:
GammaCompressionEffect();
private:
GammaCurve destination_curve;
+ float compression_curve[COMPRESSION_CURVE_SIZE];
};
#endif // !defined(_GAMMA_COMPRESSION_EFFECT_H)
+++ /dev/null
-// Compress to Rec. 601/Rec. 709 gamma curve.
-
-#if 0
-
-// if we have the lut
-uniform sampler1D PREFIX(rec709_inverse_tex);
-
-vec4 FUNCNAME(vec2 tc) {
- vec4 x = LAST_INPUT(tc);
-
- x.r = texture1D(PREFIX(rec709_inverse_tex), x.r).x;
- x.g = texture1D(PREFIX(rec709_inverse_tex), x.g).x;
- x.b = texture1D(PREFIX(rec709_inverse_tex), x.b).x;
-
- return x;
-}
-
-#else
-
-// use arithmetic (slow)
-vec4 FUNCNAME(vec2 tc) {
- vec4 x = LAST_INPUT(tc);
-
- vec3 a = vec3(4.5) * x.rgb;
- vec3 b = vec3(1.099) * pow(x.rgb, vec3(0.45)) - vec3(0.099);
- vec3 f = vec3(greaterThan(x.rgb, vec3(0.018)));
-
- return vec4(mix(a, b, f), x.a);
-}
-
-#endif
+++ /dev/null
-// Compress to sRGB gamma curve.
-
-#if 0
-
-// if we have the lut
-uniform sampler1D PREFIX(srgb_inverse_tex);
-
-vec4 FUNCNAME(vec2 tc) {
- vec4 x = LAST_INPUT(tc);
-
- x.r = texture1D(PREFIX(srgb_inverse_tex), x.r).x;
- x.g = texture1D(PREFIX(srgb_inverse_tex), x.g).x;
- x.b = texture1D(PREFIX(srgb_inverse_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
+#include <math.h>
#include <assert.h>
#include "gamma_expansion_effect.h"
: source_curve(GAMMA_LINEAR)
{
register_int("source_curve", (int *)&source_curve);
+ register_1d_texture("expansion_curve_tex", expansion_curve, EXPANSION_CURVE_SIZE);
}
std::string GammaExpansionEffect::output_fragment_shader()
{
- switch (source_curve) {
- case GAMMA_LINEAR:
+ if (source_curve == GAMMA_LINEAR) {
return read_file("identity.frag");
- case GAMMA_sRGB:
- return read_file("gamma_expansion_effect_srgb.frag");
- case GAMMA_REC_709: // and GAMMA_REC_601
- return read_file("gamma_expansion_effect_rec709.frag");
- default:
- assert(false);
}
+ if (source_curve == GAMMA_sRGB) {
+ for (unsigned i = 0; i < EXPANSION_CURVE_SIZE; ++i) {
+ float x = i / (float)(EXPANSION_CURVE_SIZE - 1);
+ if (x < 0.04045f) {
+ expansion_curve[i] = (1.0/12.92f) * x;
+ } else {
+ expansion_curve[i] = pow((x + 0.055) * (1.0/1.055f), 2.4);
+ }
+ }
+ invalidate_1d_texture("expansion_curve_tex");
+ return read_file("gamma_expansion_effect.frag");
+ }
+ if (source_curve == GAMMA_REC_709) { // And Rec. 601.
+ for (unsigned i = 0; i < EXPANSION_CURVE_SIZE; ++i) {
+ float x = i / (float)(EXPANSION_CURVE_SIZE - 1);
+ if (x < 0.081f) {
+ expansion_curve[i] = (1.0/4.5f) * x;
+ } else {
+ expansion_curve[i] = pow((x + 0.099) * (1.0/1.099f), 1.0f/0.45f);
+ }
+ }
+ invalidate_1d_texture("expansion_curve_tex");
+ return read_file("gamma_expansion_effect.frag");
+ }
+ assert(false);
}
--- /dev/null
+// Expand sRGB gamma curve.
+
+vec4 FUNCNAME(vec2 tc) {
+ vec4 x = LAST_INPUT(tc);
+
+ x.r = texture1D(PREFIX(expansion_curve_tex), x.r).x;
+ x.g = texture1D(PREFIX(expansion_curve_tex), x.g).x;
+ x.b = texture1D(PREFIX(expansion_curve_tex), x.b).x;
+
+ return x;
+}
#include "effect.h"
#include "effect_chain.h"
+#define EXPANSION_CURVE_SIZE 256
+
class GammaExpansionEffect : public Effect {
public:
GammaExpansionEffect();
private:
GammaCurve source_curve;
+ float expansion_curve[EXPANSION_CURVE_SIZE];
};
#endif // !defined(_GAMMA_EXPANSION_EFFECT_H)
+++ /dev/null
-// Expand Rec. 601/Rec. 709 gamma curve.
-
-#if 0
-
-// if we have the lut
-uniform sampler1D PREFIX(rec709_tex);
-
-vec4 FUNCNAME(vec2 tc) {
- vec4 x = LAST_INPUT(tc);
-
- x.r = texture1D(PREFIX(rec709_tex), x.r).x;
- x.g = texture1D(PREFIX(rec709_tex), x.g).x;
- x.b = texture1D(PREFIX(rec709_tex), x.b).x;
-
- return x;
-}
-
-#else
-
-// use arithmetic (slow)
-vec4 FUNCNAME(vec2 tc) {
- vec4 x = LAST_INPUT(tc);
-
- vec3 a = x.rgb * vec3(1.0/4.500);
- vec3 b = pow((x.rgb + vec3(0.099)) * vec3(1.0/1.099), vec3(1.0/0.45));
- vec3 f = vec3(greaterThan(x.rgb, vec3(0.081)));
-
- return vec4(mix(a, b, f), x.a);
-}
-
-#endif
+++ /dev/null
-// Expand 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 = x.rgb * vec3(1.0/12.92);
- vec3 b = pow((x.rgb + vec3(0.055)) * vec3(1.0/1.055), vec3(2.4));
- vec3 f = vec3(greaterThan(x.rgb, vec3(0.04045)));
-
- return vec4(mix(a, b, f), x.a);
-}
-
-#endif
return read_file("lift_gamma_gain_effect.frag");
}
-void LiftGammaGainEffect::set_uniforms(GLuint glsl_program_num, const std::string &prefix)
+void LiftGammaGainEffect::set_uniforms(GLuint glsl_program_num, const std::string &prefix, unsigned *sampler_num)
{
- Effect::set_uniforms(glsl_program_num, prefix);
+ Effect::set_uniforms(glsl_program_num, prefix, sampler_num);
RGBTriplet gain_pow_inv_gamma(
pow(gain.r, 1.0f / gamma.r),
LiftGammaGainEffect();
std::string output_fragment_shader();
- void set_uniforms(GLuint glsl_program_num, const std::string &prefix);
+ void set_uniforms(GLuint glsl_program_num, const std::string &prefix, unsigned *sampler_num);
private:
RGBTriplet lift, gamma, gain;
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 4);
//check_error();
-#if 0
- // sRGB reverse LUT
- glBindTexture(GL_TEXTURE_1D, SRGB_REVERSE_LUT);
- check_error();
- glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- check_error();
- float srgb_reverse_tex[4096];
- for (unsigned i = 0; i < 4096; ++i) {
- float x = i / 4095.0;
- if (x < 0.0031308f) {
- srgb_reverse_tex[i] = 12.92f * x;
- } else {
- srgb_reverse_tex[i] = 1.055f * pow(x, 1.0f / 2.4f) - 0.055f;
- }
- }
- glTexImage1D(GL_TEXTURE_1D, 0, GL_LUMINANCE16F_ARB, 4096, 0, GL_LUMINANCE, GL_FLOAT, srgb_reverse_tex);
- check_error();
-
- // sRGB LUT
- glBindTexture(GL_TEXTURE_1D, SRGB_LUT);
- check_error();
- glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- check_error();
- float srgb_tex[256];
- for (unsigned i = 0; i < 256; ++i) {
- float x = i / 255.0;
- if (x < 0.04045f) {
- srgb_tex[i] = x * (1.0f / 12.92f);
- } else {
- srgb_tex[i] = pow((x + 0.055) * (1.0 / 1.055f), 2.4);
- }
- }
- glTexImage1D(GL_TEXTURE_1D, 0, GL_LUMINANCE16F_ARB, 256, 0, GL_LUMINANCE, GL_FLOAT, srgb_tex);
- check_error();
-#endif
-
// generate a PDO to hold the data we read back with glReadPixels()
// (Intel/DRI goes into a slow path if we don't read to PDO)
glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 1);
return read_file("vignette_effect.frag");
}
-void VignetteEffect::set_uniforms(GLuint glsl_program_num, const std::string &prefix)
+void VignetteEffect::set_uniforms(GLuint glsl_program_num, const std::string &prefix, unsigned *sampler_num)
{
- Effect::set_uniforms(glsl_program_num, prefix);
+ Effect::set_uniforms(glsl_program_num, prefix, sampler_num);
set_uniform_float(glsl_program_num, prefix, "inv_radius", 1.0f / radius);
VignetteEffect();
std::string output_fragment_shader();
- void set_uniforms(GLuint glsl_program_num, const std::string &prefix);
+ void set_uniforms(GLuint glsl_program_num, const std::string &prefix, unsigned *sampler_num);
private:
Point2D center;