X-Git-Url: https://git.sesse.net/?p=movit;a=blobdiff_plain;f=effect_chain.cpp;h=f860cad283e7983b543beb2e4cfbb93501e5f4cb;hp=5d9eaa3c596c88671d62dd81d4a22b9c29bee3d0;hb=bc31a9072da1d9bfe417fd850e92cabe049fd593;hpb=758f632c42befae7f2b7af137554429fa544d4cb diff --git a/effect_chain.cpp b/effect_chain.cpp index 5d9eaa3..f860cad 100644 --- a/effect_chain.cpp +++ b/effect_chain.cpp @@ -14,6 +14,8 @@ #include "lift_gamma_gain_effect.h" #include "colorspace_conversion_effect.h" #include "saturation_effect.h" +#include "mirror_effect.h" +#include "vignette_effect.h" #include "texture_enum.h" EffectChain::EffectChain(unsigned width, unsigned height) @@ -38,10 +40,16 @@ Effect *instantiate_effect(EffectId effect) return new GammaExpansionEffect(); case EFFECT_GAMMA_COMPRESSION: return new GammaCompressionEffect(); + case EFFECT_COLOR_SPACE_CONVERSION: + return new ColorSpaceConversionEffect(); case EFFECT_LIFT_GAMMA_GAIN: return new LiftGammaGainEffect(); case EFFECT_SATURATION: return new SaturationEffect(); + case EFFECT_MIRROR: + return new MirrorEffect(); + case EFFECT_VIGNETTE: + return new VignetteEffect(); } assert(false); } @@ -150,9 +158,26 @@ void EffectChain::finalize() effects.push_back(gamma_conversion); current_gamma_curve = output_format.gamma_curve; } + + std::string vert_shader = read_file("header.vert"); + for (unsigned i = 0; i < effects.size(); ++i) { + char effect_id[256]; + sprintf(effect_id, "eff%d", i); + + vert_shader += "\n"; + vert_shader += std::string("#define FUNCNAME ") + effect_id + "\n"; + vert_shader += replace_prefix(effects[i]->output_convenience_uniforms(), effect_id); + vert_shader += replace_prefix(effects[i]->output_vertex_shader(), effect_id); + vert_shader += "#undef PREFIX\n"; + vert_shader += "#undef FUNCNAME\n"; + vert_shader += "#undef LAST_INPUT\n"; + vert_shader += std::string("#define LAST_INPUT ") + effect_id + "\n"; + vert_shader += "\n"; + } + vert_shader.append(read_file("footer.vert")); + printf("%s\n", vert_shader.c_str()); - std::string frag_shader = read_file("header.glsl"); - + std::string frag_shader = read_file("header.frag"); for (unsigned i = 0; i < effects.size(); ++i) { char effect_id[256]; sprintf(effect_id, "eff%d", i); @@ -160,19 +185,19 @@ void EffectChain::finalize() frag_shader += "\n"; frag_shader += std::string("#define FUNCNAME ") + effect_id + "\n"; frag_shader += replace_prefix(effects[i]->output_convenience_uniforms(), effect_id); - frag_shader += replace_prefix(effects[i]->output_glsl(), effect_id); + frag_shader += replace_prefix(effects[i]->output_fragment_shader(), effect_id); frag_shader += "#undef PREFIX\n"; frag_shader += "#undef FUNCNAME\n"; frag_shader += "#undef LAST_INPUT\n"; frag_shader += std::string("#define LAST_INPUT ") + effect_id + "\n"; frag_shader += "\n"; } - frag_shader.append(read_file("footer.glsl")); + frag_shader.append(read_file("footer.frag")); printf("%s\n", frag_shader.c_str()); glsl_program_num = glCreateProgram(); - GLhandleARB vs_obj = compile_shader(read_file("vs.glsl"), GL_VERTEX_SHADER); - GLhandleARB fs_obj = compile_shader(frag_shader, GL_FRAGMENT_SHADER); + GLuint vs_obj = compile_shader(vert_shader, GL_VERTEX_SHADER); + GLuint fs_obj = compile_shader(frag_shader, GL_FRAGMENT_SHADER); glAttachShader(glsl_program_num, vs_obj); check_error(); glAttachShader(glsl_program_num, fs_obj); @@ -180,6 +205,46 @@ void EffectChain::finalize() glLinkProgram(glsl_program_num); check_error(); + // Translate the format to OpenGL's enums. + GLenum internal_format; + if (use_srgb_texture_format) { + internal_format = GL_SRGB8; + } else { + internal_format = GL_RGBA8; + } + if (input_format.pixel_format == FORMAT_RGB) { + format = GL_RGB; + bytes_per_pixel = 3; + } else if (input_format.pixel_format == FORMAT_RGBA) { + format = GL_RGBA; + bytes_per_pixel = 4; + } else if (input_format.pixel_format == FORMAT_BGR) { + format = GL_BGR; + bytes_per_pixel = 3; + } else if (input_format.pixel_format == FORMAT_BGRA) { + format = GL_BGRA; + bytes_per_pixel = 4; + } else { + assert(false); + } + + // Create PBO to hold the texture, and then the texture itself. + glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 2); + check_error(); + glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, width * height * bytes_per_pixel, NULL, GL_STREAM_DRAW); + check_error(); + + void *mapped_pbo = glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY); + memset(mapped_pbo, 0, width * height * bytes_per_pixel); + glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB); + + glBindTexture(GL_TEXTURE_2D, SOURCE_IMAGE); + check_error(); + glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, format, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0)); + check_error(); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0); + check_error(); + finalized = true; } @@ -187,25 +252,27 @@ void EffectChain::render_to_screen(unsigned char *src) { assert(finalized); + // Copy the pixel data into the PBO. + glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 2); check_error(); - glUseProgram(glsl_program_num); + void *mapped_pbo = glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY); + memcpy(mapped_pbo, src, width * height * bytes_per_pixel); + glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB); check_error(); + // Re-upload the texture from the PBO. glActiveTexture(GL_TEXTURE0); + check_error(); glBindTexture(GL_TEXTURE_2D, SOURCE_IMAGE); + check_error(); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0)); + check_error(); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0); + check_error(); - GLenum internal_format = GL_RGBA8; - if (use_srgb_texture_format) { - internal_format = GL_SRGB8; - } + glUseProgram(glsl_program_num); + check_error(); - if (input_format.pixel_format == FORMAT_RGB) { - glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, src); - } else if (input_format.pixel_format == FORMAT_RGBA) { - glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, src); - } else { - assert(false); - } check_error(); glUniform1i(glGetUniformLocation(glsl_program_num, "input_tex"), 0);