#include <GL/glext.h>
#include "effect.h"
+#include "effect_chain.h"
#include "util.h"
#include "widgets.h"
#include "texture_enum.h"
float gamma_r = 1.0f, gamma_g = 1.0f, gamma_b = 1.0f;
float gain_r = 1.0f, gain_g = 1.0f, gain_b = 1.0f;
-enum PixelFormat { FORMAT_RGB, FORMAT_RGBA };
-
-enum ColorSpace {
- COLORSPACE_sRGB = 0,
- COLORSPACE_REC_709 = 0, // Same as sRGB.
- COLORSPACE_REC_601_525 = 1,
- COLORSPACE_REC_601_625 = 2,
-};
-
-enum GammaCurve {
- GAMMA_LINEAR = 0,
- GAMMA_sRGB = 1,
- GAMMA_REC_601 = 2,
- GAMMA_REC_709 = 2, // Same as Rec. 601.
-};
-
-struct ImageFormat {
- PixelFormat pixel_format;
- ColorSpace color_space;
- GammaCurve gamma_curve;
-};
-
-enum EffectId {
- // Mostly for internal use.
- GAMMA_CONVERSION = 0,
- RGB_PRIMARIES_CONVERSION,
-
- // Color.
- LIFT_GAMMA_GAIN,
-};
-
-// Can alias on a float[3].
-struct RGBTriplet {
- RGBTriplet(float r, float g, float b)
- : r(r), g(g), b(b) {}
-
- float r, g, b;
-};
-
-class GammaExpansionEffect : public Effect {
-public:
- GammaExpansionEffect()
- : source_curve(GAMMA_LINEAR)
- {
- register_int("source_curve", (int *)&source_curve);
- }
-
-private:
- GammaCurve source_curve;
-};
-
-class ColorSpaceConversionEffect : public Effect {
-public:
- ColorSpaceConversionEffect()
- : source_space(COLORSPACE_sRGB),
- destination_space(COLORSPACE_sRGB)
- {
- register_int("source_space", (int *)&source_space);
- register_int("destination_space", (int *)&destination_space);
- }
-
-private:
- ColorSpace source_space, destination_space;
-};
-
-class ColorSpaceConversionEffect;
-
-class LiftGammaGainEffect : public Effect {
-public:
- LiftGammaGainEffect()
- : lift(0.0f, 0.0f, 0.0f),
- gamma(1.0f, 1.0f, 1.0f),
- gain(1.0f, 1.0f, 1.0f),
- saturation(1.0f)
- {
- register_vec3("lift", (float *)&lift);
- register_vec3("gamma", (float *)&gamma);
- register_vec3("gain", (float *)&gain);
- register_float("saturation", &saturation);
- }
-
-private:
- RGBTriplet lift, gamma, gain;
- float saturation;
-};
-
-class EffectChain {
-public:
- EffectChain(unsigned width, unsigned height);
- void add_input(const ImageFormat &format);
-
- // The pointer is owned by EffectChain.
- Effect *add_effect(EffectId effect);
-
- void add_output(const ImageFormat &format);
-
- void render(unsigned char *src, unsigned char *dst);
-
-private:
- unsigned width, height;
- ImageFormat input_format, output_format;
- std::vector<Effect *> effects;
-
- ColorSpace current_color_space;
- GammaCurve current_gamma_curve;
-};
-
-EffectChain::EffectChain(unsigned width, unsigned height)
- : width(width), height(height) {}
-
-void EffectChain::add_input(const ImageFormat &format)
-{
- input_format = format;
- current_color_space = format.color_space;
- current_gamma_curve = format.gamma_curve;
-}
-
-void EffectChain::add_output(const ImageFormat &format)
-{
- output_format = format;
-}
-
-Effect *instantiate_effect(EffectId effect)
-{
- switch (effect) {
- case GAMMA_CONVERSION:
- return new GammaExpansionEffect();
- case RGB_PRIMARIES_CONVERSION:
- return new GammaExpansionEffect();
- case LIFT_GAMMA_GAIN:
- return new LiftGammaGainEffect();
- }
- assert(false);
-}
-
-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;
- }
-
- 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;
- }
-
- effects.push_back(effect);
- return effect;
-}
-
-GLhandleARB read_shader(const char* filename, GLenum type)
-{
- static char buf[131072];
- FILE *fp = fopen(filename, "r");
- if (fp == NULL) {
- perror(filename);
- exit(1);
- }
-
- int len = fread(buf, 1, sizeof(buf), fp);
- fclose(fp);
-
- GLhandleARB obj = glCreateShaderObjectARB(type);
- const GLchar* source[] = { buf };
- const GLint length[] = { len };
- glShaderSource(obj, 1, source, length);
- glCompileShader(obj);
-
- GLchar info_log[4096];
- GLsizei log_length = sizeof(info_log) - 1;
- glGetShaderInfoLog(obj, log_length, &log_length, info_log);
- info_log[log_length] = 0;
- printf("shader compile log: %s\n", info_log);
-
- GLint status;
- glGetShaderiv(obj, GL_COMPILE_STATUS, &status);
- if (status == GL_FALSE) {
- exit(1);
- }
-
- return obj;
-}
-
void draw_picture_quad(GLint prog, int frame)
{
glUseProgramObjectARB(prog);
update_hsv();
}
-void load_texture(const char *filename)
+unsigned char *load_image(const char *filename, unsigned *w, unsigned *h)
{
SDL_Surface *img = IMG_Load(filename);
if (img == NULL) {
}
SDL_UnlockSurface(img);
+ *w = img->w;
+ *h = img->h;
+
+ SDL_FreeSurface(img);
+
+ return dst_pixels;
+}
+
+void load_texture(const char *filename)
+{
+ unsigned w, h;
+ unsigned char *pixels = load_image(filename, &w, &h);
+
#if 1
// we will convert to sRGB in the shader
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, img->w, img->h, 0, GL_RGB, GL_UNSIGNED_BYTE, dst_pixels);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
check_error();
#else
// implicit sRGB conversion in hardware
- glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB8, img->w, img->h, 0, GL_RGB, GL_UNSIGNED_BYTE, dst_pixels);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB8, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
check_error();
#endif
- free(dst_pixels);
- SDL_FreeSurface(img);
+
+ free(pixels);
}
void write_ppm(const char *filename, unsigned char *screenbuf)
check_error();
load_texture("blg_wheels_woman_1.jpg");
+
+ EffectChain chain(WIDTH, HEIGHT);
+
+ ImageFormat inout_format;
+ inout_format.pixel_format = FORMAT_RGB;
+ inout_format.color_space = COLORSPACE_sRGB;
+ inout_format.gamma_curve = GAMMA_sRGB;
+
+ chain.add_input(inout_format);
+ Effect *lift_gamma_gain_effect = chain.add_effect(LIFT_GAMMA_GAIN);
+ chain.add_output(inout_format);
+ chain.finalize();
+
//glGenerateMipmap(GL_TEXTURE_2D);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 4);
//check_error();
update_hsv();
int prog = glCreateProgram();
- GLhandleARB vs_obj = read_shader("vs.glsl", GL_VERTEX_SHADER);
- GLhandleARB fs_obj = read_shader("fs.glsl", GL_FRAGMENT_SHADER);
+ GLhandleARB vs_obj = compile_shader(read_file("vs.glsl"), GL_VERTEX_SHADER);
+ GLhandleARB fs_obj = compile_shader(read_file("fs.glsl"), GL_FRAGMENT_SHADER);
glAttachObjectARB(prog, vs_obj);
check_error();
glAttachObjectARB(prog, fs_obj);
++frame;
+
draw_picture_quad(prog, frame);
glReadPixels(0, 0, WIDTH, HEIGHT, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, BUFFER_OFFSET(0));