change composer to chroma only - no src alpha blend, resize about pref, new expanders...
[goodguy/history.git] / cinelerra-5.1 / cinelerra / playback3d.C
index a6a721ba80feb38266e5c60ca0a30c7e2947ba69..2ca2a4c68e4d43f35f03595d76f23e8a6483d1d4 100644 (file)
 
 #define GL_GLEXT_PROTOTYPES
 
+#include "bccolors.h"
 #include "bcsignals.h"
 #include "bcwindowbase.h"
 #include "canvas.h"
 #include "clip.h"
 #include "condition.h"
+#include "edl.h"
 #include "maskautos.h"
 #include "maskauto.h"
 #include "mutex.h"
+#include "mwindow.h"
 #include "overlayframe.inc"
+#include "overlayframe.h"
 #include "playback3d.h"
 #include "pluginclient.h"
 #include "pluginvclient.h"
+#include "edlsession.h"
 #include "transportque.inc"
 #include "vframe.h"
 
@@ -46,6 +51,8 @@
 #include <unistd.h>
 #include <fcntl.h>
 
+#define QQ(q)#q
+#define SS(s)QQ(s)
 
 
 // Shaders
 // Can't hard code sampler2D
 
 
+#ifdef HAVE_GL
 static const char *yuv_to_rgb_frag =
        "uniform sampler2D tex;\n"
+       "uniform mat3 yuv_to_rgb_matrix;\n"
+       "uniform float yminf;\n"
        "void main()\n"
        "{\n"
        "       vec4 yuva = texture2D(tex, gl_TexCoord[0].st);\n"
-       "       yuva.rgb -= vec3(0, 0.5, 0.5);\n"
-       "       const mat3 yuv_to_rgb_matrix = mat3(\n"
-       "               1,       1,        1, \n"
-       "               0,       -0.34414, 1.77200, \n"
-       "               1.40200, -0.71414, 0);\n"
+       "       yuva.rgb -= vec3(yminf, 0.5, 0.5);\n"
        "       gl_FragColor = vec4(yuv_to_rgb_matrix * yuva.rgb, yuva.a);\n"
        "}\n";
 
@@ -82,14 +88,12 @@ static const char *yuva_to_yuv_frag =
 
 static const char *yuva_to_rgb_frag =
        "uniform sampler2D tex;\n"
+       "uniform mat3 yuv_to_rgb_matrix;\n"
+       "uniform float yminf;\n"
        "void main()\n"
        "{\n"
        "       vec4 yuva = texture2D(tex, gl_TexCoord[0].st);\n"
-       "       yuva.rgb -= vec3(0, 0.5, 0.5);\n"
-       "       const mat3 yuv_to_rgb_matrix = mat3(\n"
-       "               1,       1,        1, \n"
-       "               0,       -0.34414, 1.77200, \n"
-       "               1.40200, -0.71414, 0);\n"
+       "       yuva.rgb -= vec3(yminf, 0.5, 0.5);\n"
        "       yuva.rgb = yuv_to_rgb_matrix * yuva.rgb;\n"
        "       yuva.rgb *= yuva.a;\n"
        "       yuva.a = 1.0;\n"
@@ -98,15 +102,13 @@ static const char *yuva_to_rgb_frag =
 
 static const char *rgb_to_yuv_frag =
        "uniform sampler2D tex;\n"
+       "uniform mat3 rgb_to_yuv_matrix;\n"
+       "uniform float yminf;\n"
        "void main()\n"
        "{\n"
        "       vec4 rgba = texture2D(tex, gl_TexCoord[0].st);\n"
-       "       const mat3 rgb_to_yuv_matrix = mat3(\n"
-       "               0.29900, -0.16874, 0.50000, \n"
-       "               0.58700, -0.33126, -0.41869, \n"
-       "               0.11400, 0.50000,  -0.08131);\n"
        "       rgba.rgb = rgb_to_yuv_matrix * rgba.rgb;\n"
-       "       rgba.rgb += vec3(0, 0.5, 0.5);\n"
+       "       rgba.rgb += vec3(yminf, 0.5, 0.5);\n"
        "       gl_FragColor = rgba;\n"
        "}\n";
 
@@ -123,28 +125,69 @@ static const char *rgba_to_rgb_frag =
 
 static const char *rgba_to_yuv_frag =
        "uniform sampler2D tex;\n"
+       "uniform mat3 rgb_to_yuv_matrix;\n"
+       "uniform float yminf;\n"
        "void main()\n"
        "{\n"
        "       vec4 rgba = texture2D(tex, gl_TexCoord[0].st);\n"
-       "       const mat3 rgb_to_yuv_matrix = mat3(\n"
-       "               0.29900, -0.16874, 0.50000, \n"
-       "               0.58700, -0.33126, -0.41869, \n"
-       "               0.11400, 0.50000,  -0.08131);\n"
        "       rgba.rgb *= rgba.a;\n"
        "       rgba.a = 1.0;\n"
        "       rgba.rgb = rgb_to_yuv_matrix * rgba.rgb;\n"
-       "       rgba.rgb += vec3(0, 0.5, 0.5);\n"
+       "       rgba.rgb += vec3(yminf, 0.5, 0.5);\n"
        "       gl_FragColor = rgba;\n"
        "}\n";
 
-static const char *rgba_to_rgb_flatten =
-       "void main() {\n"
-       "       gl_FragColor.rgb *= gl_FragColor.a;\n"
-       "       gl_FragColor.a = 1.0;\n"
-       "}\n";
+//static const char *rgba_to_rgb_flatten =
+//     "void main() {\n"
+//     "       gl_FragColor.rgb *= gl_FragColor.a;\n"
+//     "       gl_FragColor.a = 1.0;\n"
+//     "}\n";
+
+#define GL_STD_BLEND(FN) \
+static const char *blend_##FN##_frag = \
+       "uniform sampler2D tex2;\n" \
+       "uniform vec2 tex2_dimensions;\n" \
+       "uniform float alpha;\n" \
+       "void main() {\n" \
+       "       vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n" \
+       "       vec4 result;\n" \
+       "       result.rgb = " SS(COLOR_##FN(1.0, gl_FragColor.rgb, gl_FragColor.a, canvas.rgb, canvas.a)) ";\n" \
+       "       result.a = " SS(ALPHA_##FN(1.0, gl_FragColor.a, canvas.a)) ";\n" \
+       "       gl_FragColor = mix(canvas, result, alpha);\n" \
+       "}\n"
+
+#define GL_VEC_BLEND(FN) \
+static const char *blend_##FN##_frag = \
+       "uniform sampler2D tex2;\n" \
+       "uniform vec2 tex2_dimensions;\n" \
+       "uniform float alpha;\n" \
+       "void main() {\n" \
+       "       vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n" \
+       "       vec4 result;\n" \
+       "       result.r = " SS(COLOR_##FN(1.0, gl_FragColor.r, gl_FragColor.a, canvas.r, canvas.a)) ";\n" \
+       "       result.g = " SS(COLOR_##FN(1.0, gl_FragColor.g, gl_FragColor.a, canvas.g, canvas.a)) ";\n" \
+       "       result.b = " SS(COLOR_##FN(1.0, gl_FragColor.b, gl_FragColor.a, canvas.b, canvas.a)) ";\n" \
+       "       result.a = " SS(ALPHA_##FN(1.0, gl_FragColor.a, canvas.a)) ";\n" \
+       "       result = clamp(result, 0.0, 1.0);\n" \
+       "       gl_FragColor = mix(canvas, result, alpha);\n" \
+       "}\n"
+
+#undef mabs
+#define mabs abs
+#undef mmin
+#define mmin min
+#undef mmax
+#define mmax max
+
+#undef ZERO
+#define ZERO 0.0
+#undef ONE
+#define ONE 1.0
+#undef TWO
+#define TWO 2.0
 
 // NORMAL
-static const char *blend_normal_frag =
+static const char *blend_NORMAL_frag =
        "uniform sampler2D tex2;\n"
        "uniform vec2 tex2_dimensions;\n"
        "uniform float alpha;\n"
@@ -154,268 +197,60 @@ static const char *blend_normal_frag =
        "       gl_FragColor = mix(canvas, result, alpha);\n"
        "}\n";
 
-// ADDITION
-static const char *blend_add_frag =
-       "uniform sampler2D tex2;\n"
-       "uniform vec2 tex2_dimensions;\n"
-       "uniform float alpha;\n"
-       "void main() {\n"
-       "       vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
-       "       vec4 result = canvas + gl_FragColor;\n"
-       "       result = clamp(result, 0.0, 1.0);\n"
-       "       gl_FragColor = mix(canvas, result, alpha);\n"
-       "}\n";
-
-// SUBTRACT
-static const char *blend_subtract_frag =
-       "uniform sampler2D tex2;\n"
-       "uniform vec2 tex2_dimensions;\n"
-       "uniform float alpha;\n"
-       "void main() {\n"
-       "       vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
-       "       vec4 result = gl_FragColor - canvas;\n"
-       "       result = clamp(result, 0.0, 1.0);\n"
-       "       gl_FragColor = mix(canvas, result, alpha);\n"
-       "}\n";
-
-// MULTIPLY
-static const char *blend_multiply_frag =
-       "uniform sampler2D tex2;\n"
-       "uniform vec2 tex2_dimensions;\n"
-       "uniform float alpha;\n"
-       "void main() {\n"
-       "       vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
-       "       vec4 result = canvas * gl_FragColor;\n"
-       "       gl_FragColor = mix(canvas, result, alpha);\n"
-       "}\n";
-
-// DIVIDE
-static const char *blend_divide_frag =
-       "uniform sampler2D tex2;\n"
-       "uniform vec2 tex2_dimensions;\n"
-       "uniform float alpha;\n"
-       "void main() {\n"
-       "       vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
-       "       vec4 result = gl_FragColor / canvas;\n"
-       "       if(!canvas.r) result.r = 1.0;\n"
-       "       if(!canvas.g) result.g = 1.0;\n"
-       "       if(!canvas.b) result.b = 1.0;\n"
-       "       if(!canvas.a) result.a = 1.0;\n"
-       "       result = clamp(result, 0.0, 1.0);\n"
-       "       gl_FragColor = mix(canvas, result, alpha);\n"
-       "}\n";
-
 // REPLACE
-static const char *blend_replace_frag =
-       "uniform float alpha;\n"
-       "void main() {\n"
-       "}\n";
-
-// MAX
-static const char *blend_max_frag =
-       "uniform sampler2D tex2;\n"
-       "uniform vec2 tex2_dimensions;\n"
-       "uniform float alpha;\n"
-       "void main() {\n"
-       "       vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
-       "       vec4 result = max(canvas, gl_FragColor);\n"
-       "       result = clamp(result, 0.0, 1.0);\n"
-       "       gl_FragColor = mix(canvas, result, alpha);\n"
-       "}\n";
-
-// MIN
-static const char *blend_min_frag =
-       "uniform sampler2D tex2;\n"
-       "uniform vec2 tex2_dimensions;\n"
-       "uniform float alpha;\n"
-       "void main() {\n"
-       "       vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
-       "       vec4 result = min(canvas, gl_FragColor);\n"
-       "       result = clamp(result, 0.0, 1.0);\n"
-       "       gl_FragColor = mix(canvas, result, alpha);\n"
-       "}\n";
-
-// AVERAGE
-static const char *blend_average_frag =
-       "uniform sampler2D tex2;\n"
-       "uniform vec2 tex2_dimensions;\n"
-       "uniform float alpha;\n"
-       "void main() {\n"
-       "       vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
-       "       vec4 result = (canvas + gl_FragColor) * 0.5;\n"
-       "       result = clamp(result, 0.0, 1.0);\n"
-       "       gl_FragColor = mix(canvas, result, alpha);\n"
-       "}\n";
-
-// DARKEN
-static const char *blend_darken_frag =
-       "uniform sampler2D tex2;\n"
-       "uniform vec2 tex2_dimensions;\n"
-       "uniform float alpha;\n"
-       "void main() {\n"
-       "       vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
-       "       vec4 result = vec4(canvas.rgb * (1.0 - gl_FragColor.a) +"
-                       " gl_FragColor.rgb * (1.0 - canvas.a) +"
-                       " min(canvas.rgb, gl_FragColor.rgb), "
-                       " canvas.a + gl_FragColor.a - canvas.a * gl_FragColor.a);\n"
-       "       result = clamp(result, 0.0, 1.0);\n"
-       "       gl_FragColor = mix(canvas, result, alpha);\n"
-       "}\n";
-
-// LIGHTEN
-static const char *blend_lighten_frag =
-       "uniform sampler2D tex2;\n"
-       "uniform vec2 tex2_dimensions;\n"
-       "uniform float alpha;\n"
-       "void main() {\n"
-       "       vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
-       "       vec4 result = vec4(canvas.rgb * (1.0 - gl_FragColor.a) +"
-                       " gl_FragColor.rgb * (1.0 - canvas.a) +"
-                       " max(canvas.rgb, gl_FragColor.rgb), "
-                       " canvas.a + gl_FragColor.a - canvas.a * gl_FragColor.a);\n"
-       "       result = clamp(result, 0.0, 1.0);\n"
-       "       gl_FragColor = mix(canvas, result, alpha);\n"
-       "}\n";
-
-// DST
-static const char *blend_dst_frag =
-       "uniform sampler2D tex2;\n"
-       "uniform vec2 tex2_dimensions;\n"
-       "uniform float alpha;\n"
-       "void main() {\n"
-//     "       vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
-//     "       vec4 result = canvas;\n"
-//     "       gl_FragColor = mix(result, canvas, alpha);\n"
-       "       gl_FragColor = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
-       "}\n";
-
-// DST_ATOP
-static const char *blend_dst_atop_frag =
-       "uniform sampler2D tex2;\n"
-       "uniform vec2 tex2_dimensions;\n"
-       "uniform float alpha;\n"
-       "void main() {\n"
-       "       vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
-       "       vec4 result = vec4(canvas.rgb * gl_FragColor.a + "
-                       "(1.0 - canvas.a) * gl_FragColor.rgb, gl_FragColor.a);\n"
-       "       gl_FragColor = mix(canvas, result, alpha);\n"
-       "}\n";
-
-// DST_IN
-static const char *blend_dst_in_frag =
-       "uniform sampler2D tex2;\n"
-       "uniform vec2 tex2_dimensions;\n"
-       "uniform float alpha;\n"
-       "void main() {\n"
-       "       vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
-       "       vec4 result = canvas * gl_FragColor.a;\n"
-       "       gl_FragColor = mix(canvas, result, alpha);\n"
-       "}\n";
-
-// DST_OUT
-static const char *blend_dst_out_frag =
-       "uniform sampler2D tex2;\n"
-       "uniform vec2 tex2_dimensions;\n"
-       "uniform float alpha;\n"
-       "void main() {\n"
-       "       vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
-       "       vec4 result = canvas * (1.0 - gl_FragColor.a);\n"
-       "       gl_FragColor = mix(canvas, result, alpha);\n"
-       "}\n";
-
-// DST_OVER
-static const char *blend_dst_over_frag =
-       "uniform sampler2D tex2;\n"
-       "uniform vec2 tex2_dimensions;\n"
-       "uniform float alpha;\n"
-       "void main() {\n"
-       "       vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
-       "       vec4 result = vec4(canvas.rgb + (1.0 - canvas.a) * gl_FragColor.rgb, "
-                       " gl_FragColor.a + canvas.a - gl_FragColor.a * canvas.a);\n"
-       "       gl_FragColor = mix(canvas, result, alpha);\n"
-       "}\n";
-
-// SRC
-static const char *blend_src_frag =
-       "uniform sampler2D tex2;\n"
-       "uniform vec2 tex2_dimensions;\n"
-       "uniform float alpha;\n"
-       "void main() {\n"
-       "       vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
-       "       vec4 result = gl_FragColor;\n"
-       "       gl_FragColor = mix(canvas, result, alpha);\n"
-       "}\n";
-
-// SRC_ATOP
-static const char *blend_src_atop_frag =
-       "uniform sampler2D tex2;\n"
-       "uniform vec2 tex2_dimensions;\n"
-       "uniform float alpha;\n"
-       "void main() {\n"
-       "       vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
-       "       vec4 result = vec4(gl_FragColor.rgb * canvas.a + "
-                       "canvas.rgb * (1.0 - gl_FragColor.a), canvas.a);\n"
-       "       gl_FragColor = mix(canvas, result, alpha);\n"
-       "}\n";
-
-// SRC_IN
-static const char *blend_src_in_frag =
-       "uniform sampler2D tex2;\n"
-       "uniform vec2 tex2_dimensions;\n"
+static const char *blend_REPLACE_frag =
        "uniform float alpha;\n"
        "void main() {\n"
-       "       vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
-       "       vec4 result = gl_FragColor * canvas.a;\n"
-       "       gl_FragColor = mix(canvas, result, alpha);\n"
        "}\n";
 
-// SRC_OUT
-static const char *blend_src_out_frag =
-       "uniform sampler2D tex2;\n"
-       "uniform vec2 tex2_dimensions;\n"
-       "uniform float alpha;\n"
-       "void main() {\n"
-       "       vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
-       "       vec4 result = gl_FragColor * (1.0 - canvas.a);\n"
-       "       gl_FragColor = mix(canvas, result, alpha);\n"
-       "}\n";
-
-// SRC_OVER
-static const char *blend_src_over_frag =
+// ADDITION
+static const char *blend_ADDITION_frag =
        "uniform sampler2D tex2;\n"
        "uniform vec2 tex2_dimensions;\n"
        "uniform float alpha;\n"
        "void main() {\n"
        "       vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
-       "       vec4 result = vec4(gl_FragColor.rgb + (1.0 - gl_FragColor.a) * canvas.rgb, "
-                               "gl_FragColor.a + canvas.a - gl_FragColor.a * canvas.a);\n"
+       "       vec4 result = clamp(gl_FragColor + canvas, 0.0, 1.0);\n"
        "       gl_FragColor = mix(canvas, result, alpha);\n"
        "}\n";
 
-// OR
-static const char *blend_or_frag =
+// SUBTRACT
+static const char *blend_SUBTRACT_frag =
        "uniform sampler2D tex2;\n"
        "uniform vec2 tex2_dimensions;\n"
        "uniform float alpha;\n"
        "void main() {\n"
        "       vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
-       "       vec4 result = canvas + gl_FragColor - canvas * gl_FragColor;\n"
-       "       result = clamp(result, 0.0, 1.0);\n"
+       "       vec4 result = clamp(gl_FragColor - canvas, 0.0, 1.0);\n"
        "       gl_FragColor = mix(canvas, result, alpha);\n"
        "}\n";
 
-// XOR
-static const char *blend_xor_frag =
-       "uniform sampler2D tex2;\n"
-       "uniform vec2 tex2_dimensions;\n"
-       "uniform float alpha;\n"
-       "void main() {\n"
-       "       vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
-       "       vec4 result = vec4(gl_FragColor.rgb * (1.0 - canvas.a) + "
-                       "(1.0 - gl_FragColor.a) * canvas.rgb, "
-                       "gl_FragColor.a + canvas.a - 2.0 * gl_FragColor.a * canvas.a);\n"
-       "       gl_FragColor = mix(canvas, result, alpha);\n"
-       "}\n";
+GL_STD_BLEND(MULTIPLY);
+GL_VEC_BLEND(DIVIDE);
+GL_VEC_BLEND(MAX);
+GL_VEC_BLEND(MIN);
+GL_VEC_BLEND(DARKEN);
+GL_VEC_BLEND(LIGHTEN);
+GL_STD_BLEND(DST);
+GL_STD_BLEND(DST_ATOP);
+GL_STD_BLEND(DST_IN);
+GL_STD_BLEND(DST_OUT);
+GL_STD_BLEND(DST_OVER);
+GL_STD_BLEND(SRC);
+GL_STD_BLEND(SRC_ATOP);
+GL_STD_BLEND(SRC_IN);
+GL_STD_BLEND(SRC_OUT);
+GL_STD_BLEND(SRC_OVER);
+GL_STD_BLEND(AND);
+GL_STD_BLEND(OR);
+GL_STD_BLEND(XOR);
+GL_VEC_BLEND(OVERLAY);
+GL_STD_BLEND(SCREEN);
+GL_VEC_BLEND(BURN);
+GL_VEC_BLEND(DODGE);
+GL_VEC_BLEND(HARDLIGHT);
+GL_VEC_BLEND(SOFTLIGHT);
+GL_VEC_BLEND(DIFFERENCE);
 
 static const char *read_texture_frag =
        "uniform sampler2D tex;\n"
@@ -481,11 +316,7 @@ static const char *fade_yuv_frag =
        "       gl_FragColor.gb += vec2(0.5, 0.5);\n"
        "}\n";
 
-
-
-
-
-
+#endif
 
 
 Playback3DCommand::Playback3DCommand()
@@ -670,12 +501,23 @@ void Playback3D::copy_from_sync(Playback3DCommand *command)
                        else
 // Copy to RAM
                        {
-                               command->input->enable_opengl();
-                               glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-                               glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE,
-                                       command->frame->get_rows()[0]);
-                               command->frame->flip_vert();
-                               command->frame->set_opengl_state(VFrame::RAM);
+                               command->input->to_texture();
+                               command->input->bind_texture(0);
+                               command->frame->enable_opengl();
+                               command->frame->init_screen();
+                               unsigned int shader = BC_CModels::is_yuv(command->input->get_color_model()) ?
+                                       VFrame::make_shader(0, yuv_to_rgb_frag, 0) : 0;
+                               if( shader > 0 ) {
+                                       glUseProgram(shader);
+                                       int variable = glGetUniformLocation(shader, "tex");
+                                       glUniform1i(variable, 0);
+                                       BC_GL_YUV_TO_RGB(shader);
+                               }
+                               else
+                                       glUseProgram(0);
+                               command->input->draw_texture(1);
+                               command->frame->screen_to_ram();
+                               glUseProgram(0);
                        }
                }
                else
@@ -739,7 +581,7 @@ void Playback3D::copy_from_sync(Playback3DCommand *command)
 //                     command->frame->get_h(),
 //                     BC_RGB888,
 //                     -1);
-//             command->frame->to_ram();
+//             command->frame->screen_to_ram();
 //
 //             window->clear_box(0,
 //                                             0,
@@ -806,27 +648,31 @@ void Playback3D::write_buffer_sync(Playback3DCommand *command)
 // Make sure OpenGL is enabled first.
                window->enable_opengl();
 
-
 //printf("Playback3D::write_buffer_sync 1 %d\n", window->get_id());
-               switch(command->frame->get_opengl_state())
-               {
+               int flip_y = 0, frame_state = command->frame->get_opengl_state();
+               switch( frame_state ) {
 // Upload texture and composite to screen
                        case VFrame::RAM:
+                               flip_y = 1;
+                       case VFrame::SCREEN:
                                command->frame->to_texture();
-                               draw_output(command);
-                               break;
+                               window->enable_opengl();
 // Composite texture to screen and swap buffer
                        case VFrame::TEXTURE:
-                               draw_output(command);
-                               break;
-                       case VFrame::SCREEN:
-// swap buffers only
-                               window->flip_opengl();
+                               if( !flip_y ) {
+                                       int fh1 = command->frame->get_h()-1;
+                                       float in_y1 = fh1 - command->in_y1;
+                                       float in_y2 = fh1 - command->in_y2;
+                                       command->in_y1 = in_y2;
+                                       command->in_y2 = in_y1;
+                               }
+                               draw_output(command, flip_y);
                                break;
                        default:
                                printf("Playback3D::write_buffer_sync unknown state\n");
                                break;
                }
+               command->frame->set_opengl_state(frame_state);
                window->unlock_window();
        }
 
@@ -835,7 +681,7 @@ void Playback3D::write_buffer_sync(Playback3DCommand *command)
 
 
 
-void Playback3D::draw_output(Playback3DCommand *command)
+void Playback3D::draw_output(Playback3DCommand *command, int flip_y)
 {
 #ifdef HAVE_GL
        int texture_id = command->frame->get_texture_id();
@@ -855,54 +701,42 @@ void Playback3D::draw_output(Playback3DCommand *command)
                canvas_w = window->get_w();
                canvas_h = window->get_h();
                VFrame::init_screen(canvas_w, canvas_h);
+               int color_model = command->frame->get_color_model();
+               int is_yuv = BC_CModels::is_yuv(color_model);
 
                if(!command->is_cleared)
                {
 // If we get here, the virtual console was not used.
-                       init_frame(command);
+                       init_frame(command, 0);
                }
 
 // Texture
 // Undo any previous shader settings
                command->frame->bind_texture(0);
 
-
-
-
 // Convert colormodel
-               unsigned int frag_shader = 0;
-               switch(command->frame->get_color_model())
-               {
-                       case BC_YUV888:
-                       case BC_YUVA8888:
-                               frag_shader = VFrame::make_shader(0,
-                                       yuv_to_rgb_frag,
-                                       0);
-                               break;
-               }
-
-
-               if(frag_shader > 0)
-               {
-                       glUseProgram(frag_shader);
-                       int variable = glGetUniformLocation(frag_shader, "tex");
+               unsigned int shader = is_yuv ? VFrame::make_shader(0, yuv_to_rgb_frag, 0) : 0;
+               if( shader > 0 ) {
+                       glUseProgram(shader);
 // Set texture unit of the texture
+                       int variable = glGetUniformLocation(shader, "tex");
                        glUniform1i(variable, 0);
+                       BC_GL_YUV_TO_RGB(shader);
                }
 
-               if(BC_CModels::components(command->frame->get_color_model()) == 4)
-               {
-                       glEnable(GL_BLEND);
-                       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-               }
+//             if(BC_CModels::components(color_model) == 4)
+//             {
+//                     glEnable(GL_BLEND);
+//                     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+//             }
 
                command->frame->draw_texture(
                        command->in_x1, command->in_y1, command->in_x2, command->in_y2,
                        command->out_x1, command->out_y1, command->out_x2, command->out_y2,
-                       1);
+                       flip_y);
 
 
-// printf("Playback3D::draw_output 2 %f,%f %f,%f -> %f,%f %f,%f\n",
+//printf("Playback3D::draw_output 2 %f,%f %f,%f -> %f,%f %f,%f\n",
 // command->in_x1,
 // command->in_y1,
 // command->in_x2,
@@ -921,13 +755,11 @@ void Playback3D::draw_output(Playback3DCommand *command)
 }
 
 
-void Playback3D::init_frame(Playback3DCommand *command)
+void Playback3D::init_frame(Playback3DCommand *command, int is_yuv)
 {
 #ifdef HAVE_GL
-       canvas_w = command->canvas->get_canvas()->get_w();
-       canvas_h = command->canvas->get_canvas()->get_h();
-
-       glClearColor(0.0, 0.0, 0.0, 0.0);
+       float gbuv = is_yuv ? 0.5 : 0.0;
+       glClearColor(0.0, gbuv, gbuv, 0.0);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 #endif
 }
@@ -950,15 +782,17 @@ void Playback3D::clear_output_sync(Playback3DCommand *command)
                command->canvas->get_canvas()->lock_window("Playback3D::clear_output_sync");
 // If we get here, the virtual console is being used.
                command->canvas->get_canvas()->enable_opengl();
+               int is_yuv = 0;
 
 // Using pbuffer for refresh frame.
                if(command->frame)
                {
                        command->frame->enable_opengl();
+                       int color_model = command->canvas->mwindow->edl->session->color_model;
+                       is_yuv = BC_CModels::is_yuv(color_model);
                }
 
-
-               init_frame(command);
+               init_frame(command, is_yuv);
                command->canvas->get_canvas()->unlock_window();
        }
        command->canvas->unlock_canvas();
@@ -1052,6 +886,7 @@ void Playback3D::do_camera_sync(Playback3DCommand *command)
 
 
                command->frame->set_opengl_state(VFrame::SCREEN);
+               command->frame->screen_to_ram();
                command->canvas->get_canvas()->unlock_window();
        }
        command->canvas->unlock_canvas();
@@ -1089,29 +924,36 @@ void Playback3D::overlay_sync(Playback3DCommand *command)
 // To do these operations, we need to copy the input buffer to a texture
 // and blend 2 textures in a shader
        static const char * const overlay_shaders[TRANSFER_TYPES] = {
-               blend_normal_frag,      // TRANSFER_NORMAL
-               blend_add_frag,         // TRANSFER_ADDITION
-               blend_subtract_frag,    // TRANSFER_SUBTRACT
-               blend_multiply_frag,    // TRANSFER_MULTIPLY
-               blend_divide_frag,      // TRANSFER_DIVIDE
-               blend_replace_frag,     // TRANSFER_REPLACE
-               blend_max_frag,         // TRANSFER_MAX
-               blend_min_frag,         // TRANSFER_MIN
-               blend_average_frag,     // TRANSFER_AVERAGE
-               blend_darken_frag,      // TRANSFER_DARKEN
-               blend_lighten_frag,     // TRANSFER_LIGHTEN
-               blend_dst_frag,         // TRANSFER_DST
-               blend_dst_atop_frag,    // TRANSFER_DST_ATOP
-               blend_dst_in_frag,      // TRANSFER_DST_IN
-               blend_dst_out_frag,     // TRANSFER_DST_OUT
-               blend_dst_over_frag,    // TRANSFER_DST_OVER
-               blend_src_frag,         // TRANSFER_SRC
-               blend_src_atop_frag,    // TRANSFER_SRC_ATOP
-               blend_src_in_frag,      // TRANSFER_SRC_IN
-               blend_src_out_frag,     // TRANSFER_SRC_OUT
-               blend_src_over_frag,    // TRANSFER_SRC_OVER
-               blend_or_frag,          // TRANSFER_OR
-               blend_xor_frag          // TRANSFER_XOR
+               blend_NORMAL_frag,      // TRANSFER_NORMAL
+               blend_ADDITION_frag,    // TRANSFER_ADDITION
+               blend_SUBTRACT_frag,    // TRANSFER_SUBTRACT
+               blend_MULTIPLY_frag,    // TRANSFER_MULTIPLY
+               blend_DIVIDE_frag,      // TRANSFER_DIVIDE
+               blend_REPLACE_frag,     // TRANSFER_REPLACE
+               blend_MAX_frag,         // TRANSFER_MAX
+               blend_MIN_frag,         // TRANSFER_MIN
+               blend_DARKEN_frag,      // TRANSFER_DARKEN
+               blend_LIGHTEN_frag,     // TRANSFER_LIGHTEN
+               blend_DST_frag,         // TRANSFER_DST
+               blend_DST_ATOP_frag,    // TRANSFER_DST_ATOP
+               blend_DST_IN_frag,      // TRANSFER_DST_IN
+               blend_DST_OUT_frag,     // TRANSFER_DST_OUT
+               blend_DST_OVER_frag,    // TRANSFER_DST_OVER
+               blend_SRC_frag,         // TRANSFER_SRC
+               blend_SRC_ATOP_frag,    // TRANSFER_SRC_ATOP
+               blend_SRC_IN_frag,      // TRANSFER_SRC_IN
+               blend_SRC_OUT_frag,     // TRANSFER_SRC_OUT
+               blend_SRC_OVER_frag,    // TRANSFER_SRC_OVER
+               blend_AND_frag,         // TRANSFER_AND
+               blend_OR_frag,          // TRANSFER_OR
+               blend_XOR_frag,         // TRANSFER_XOR
+               blend_OVERLAY_frag,     // TRANSFER_OVERLAY
+               blend_SCREEN_frag,      // TRANSFER_SCREEN
+               blend_BURN_frag,        // TRANSFER_BURN
+               blend_DODGE_frag,       // TRANSFER_DODGE
+               blend_HARDLIGHT_frag,   // TRANSFER_HARDLIGHT
+               blend_SOFTLIGHT_frag,   // TRANSFER_SOFTLIGHT
+               blend_DIFFERENCE_frag,  // TRANSFER_DIFFERENCE
        };
 
        command->canvas->lock_canvas("Playback3D::overlay_sync");
@@ -1125,22 +967,9 @@ void Playback3D::overlay_sync(Playback3DCommand *command)
                glColor4f(1, 1, 1, 1);
                glDisable(GL_BLEND);
 
-               if(command->frame) {
-// Render to PBuffer
-                       command->frame->enable_opengl();
-                       command->frame->set_opengl_state(VFrame::SCREEN);
-                       canvas_w = command->frame->get_w();
-                       canvas_h = command->frame->get_h();
-               }
-               else {
-// Render to canvas
-                       canvas_w = window->get_w();
-                       canvas_h = window->get_h();
-               }
-
 
 //printf("Playback3D::overlay_sync 1 %d\n", command->input->get_opengl_state());
-               switch(command->input->get_opengl_state()) {
+               switch( command->input->get_opengl_state() ) {
 // Upload texture and composite to screen
                case VFrame::RAM:
                        command->input->to_texture();
@@ -1152,19 +981,30 @@ void Playback3D::overlay_sync(Playback3DCommand *command)
                case VFrame::SCREEN:
                        command->input->enable_opengl();
                        command->input->screen_to_texture();
-                       if(command->frame)
-                               command->frame->enable_opengl();
-                       else
-                               window->enable_opengl();
                        break;
                default:
                        printf("Playback3D::overlay_sync unknown state\n");
                        break;
                }
 
+               if(command->frame) {
+// Render to PBuffer
+                       command->frame->enable_opengl();
+                       command->frame->set_opengl_state(VFrame::SCREEN);
+                       canvas_w = command->frame->get_w();
+                       canvas_h = command->frame->get_h();
+               }
+               else {
+// Render to canvas
+                       window->enable_opengl();
+                       canvas_w = window->get_w();
+                       canvas_h = window->get_h();
+               }
 
-               const char *shader_stack[4] = { 0, 0, 0, 0, };
-               int total_shaders = 0;
+
+               const char *shader_stack[16];
+               memset(shader_stack,0, sizeof(shader_stack));
+               int total_shaders = 0, need_matrix = 0;
 
                VFrame::init_screen(canvas_w, canvas_h);
 
@@ -1173,14 +1013,11 @@ void Playback3D::overlay_sync(Playback3DCommand *command)
 
 // Convert colormodel to RGB if not nested.
 // The color model setting in the output frame is ignored.
-               if( command->is_nested <= 0 ) {  // not nested
-                       switch(command->input->get_color_model()) {
-                       case BC_YUV888:
-                       case BC_YUVA8888:
-                               shader_stack[total_shaders++] = yuv_to_rgb_frag;
-                               break;
-                       }
-               }
+//             if( command->is_nested <= 0 &&  // not nested
+//                 BC_CModels::is_yuv(command->input->get_color_model()) ) {
+//                     need_matrix = 1;
+//                     shader_stack[total_shaders++] = yuv_to_rgb_frag;
+//             }
 
 // get the shaders
 #define add_shader(s) \
@@ -1200,36 +1037,34 @@ void Playback3D::overlay_sync(Playback3DCommand *command)
                }
 
 // if to flatten alpha
-               if( command->is_nested < 0 ) {
-                       switch(command->input->get_color_model()) {
-// yuv has already been converted to rgb
-                       case BC_YUVA8888:
-                       case BC_RGBA_FLOAT:
-                       case BC_RGBA8888:
-                               add_shader(rgba_to_rgb_flatten);
-                               break;
-                       }
-               }
+//             if( command->is_nested < 0 ) {
+//                     switch(command->input->get_color_model()) {
+//// yuv has already been converted to rgb
+//                     case BC_YUVA8888:
+//                     case BC_RGBA_FLOAT:
+//                     case BC_RGBA8888:
+//                             add_shader(rgba_to_rgb_flatten);
+//                             break;
+//                     }
+//             }
 
 // run the shaders
-               unsigned int frag_shader = 0;
-               if(shader_stack[0]) {
-                       frag_shader = VFrame::make_shader(0,
-                               shader_stack[0], shader_stack[1],
-                               shader_stack[2], shader_stack[3], 0);
-
-                       glUseProgram(frag_shader);
-
+               add_shader(0);
+               unsigned int shader = !shader_stack[0] ? 0 :
+                       VFrame::make_shader(shader_stack);
+               if( shader > 0 ) {
+                       glUseProgram(shader);
+                       if( need_matrix ) BC_GL_YUV_TO_RGB(shader);
 // Set texture unit of the texture
-                       glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0);
+                       glUniform1i(glGetUniformLocation(shader, "tex"), 0);
 // Set texture unit of the temp texture
-                       glUniform1i(glGetUniformLocation(frag_shader, "tex2"), 1);
+                       glUniform1i(glGetUniformLocation(shader, "tex2"), 1);
 // Set alpha
-                       int variable = glGetUniformLocation(frag_shader, "alpha");
+                       int variable = glGetUniformLocation(shader, "alpha");
                        glUniform1f(variable, command->alpha);
 // Set dimensions of the temp texture
                        if(temp_texture)
-                               glUniform2f(glGetUniformLocation(frag_shader, "tex2_dimensions"),
+                               glUniform2f(glGetUniformLocation(shader, "tex2_dimensions"),
                                        (float)temp_texture->get_texture_w(),
                                        (float)temp_texture->get_texture_h());
                }
@@ -1237,15 +1072,14 @@ void Playback3D::overlay_sync(Playback3DCommand *command)
                        glUseProgram(0);
 
 
-// printf("Playback3D::overlay_sync %f %f %f %f %f %f %f %f\n",
+//printf("Playback3D::overlay_sync %f %f %f %f %f %f %f %f\n",
 // command->in_x1, command->in_y1, command->in_x2, command->in_y2,
 // command->out_x1, command->out_y1, command->out_x2, command->out_y2);
 
                command->input->draw_texture(
                        command->in_x1, command->in_y1, command->in_x2, command->in_y2,
                        command->out_x1, command->out_y1, command->out_x2, command->out_y2,
-// Don't flip vertical if nested
-                       command->is_nested > 0 ? 0 : 1);
+                       !command->is_nested);
                glUseProgram(0);
 
 // Delete temp texture
@@ -1417,6 +1251,7 @@ void Playback3D::do_mask_sync(Playback3DCommand *command)
 // Need to tabulate every vertex in persistent memory because
 // gluTessVertex doesn't copy them.
                        ArrayList<GLdouble*> coords;
+                       coords.set_array_delete();
                        for(int i = 0; i < points->total; i++)
                        {
                                MaskPoint *point1 = points->values[i];
@@ -1555,27 +1390,19 @@ void Playback3D::do_mask_sync(Playback3DCommand *command)
 // For unfeathered masks, we could use a stencil buffer
 // for further optimization but we also need a YUV algorithm.
                unsigned int frag_shader = 0;
-               switch(temp_texture->get_texture_components())
-               {
-                       case 3:
-                               if(command->frame->get_color_model() == BC_YUV888)
-                                       frag_shader = VFrame::make_shader(0,
-                                               multiply_yuvmask3_frag,
-                                               0);
-                               else
-                                       frag_shader = VFrame::make_shader(0,
-                                               multiply_mask3_frag,
-                                               0);
-                               break;
-                       case 4:
-                               frag_shader = VFrame::make_shader(0,
-                                       multiply_mask4_frag,
-                                       0);
-                               break;
+               switch(temp_texture->get_texture_components()) {
+               case 3:
+                       frag_shader = VFrame::make_shader(0,
+                               command->frame->get_color_model() == BC_YUV888 ?
+                                       multiply_yuvmask3_frag : multiply_mask3_frag,
+                               0);
+                       break;
+               case 4:
+                       frag_shader = VFrame::make_shader(0, multiply_mask4_frag, 0);
+                       break;
                }
 
-               if(frag_shader)
-               {
+               if( frag_shader ) {
                        int variable;
                        glUseProgram(frag_shader);
                        if((variable = glGetUniformLocation(frag_shader, "tex")) >= 0)
@@ -1658,8 +1485,7 @@ void Playback3D::convert_cmodel_sync(Playback3DCommand *command)
 #ifdef HAVE_GL
        command->canvas->lock_canvas("Playback3D::convert_cmodel_sync");
 
-       if(command->canvas->get_canvas())
-       {
+       if( command->canvas->get_canvas() ) {
                BC_WindowBase *window = command->canvas->get_canvas();
                window->lock_window("Playback3D::convert_cmodel_sync");
                window->enable_opengl();
@@ -1670,47 +1496,45 @@ void Playback3D::convert_cmodel_sync(Playback3DCommand *command)
                command->frame->to_texture();
 
 // Colormodel permutation
-               const char *shader = 0;
                int src_cmodel = command->frame->get_color_model();
                int dst_cmodel = command->dst_cmodel;
-               typedef struct
-               {
-                       int src;
-                       int dst;
+               typedef struct {
+                       int src, dst, typ;
                        const char *shader;
                } cmodel_shader_table_t;
-               static cmodel_shader_table_t cmodel_shader_table[]  =
-               {
-                       { BC_RGB888, BC_YUV888, rgb_to_yuv_frag },
-                       { BC_RGB888, BC_YUVA8888, rgb_to_yuv_frag },
-                       { BC_RGBA8888, BC_RGB888, rgba_to_rgb_frag },
-                       { BC_RGBA8888, BC_RGB_FLOAT, rgba_to_rgb_frag },
-                       { BC_RGBA8888, BC_YUV888, rgba_to_yuv_frag },
-                       { BC_RGBA8888, BC_YUVA8888, rgb_to_yuv_frag },
-                       { BC_RGB_FLOAT, BC_YUV888, rgb_to_yuv_frag },
-                       { BC_RGB_FLOAT, BC_YUVA8888, rgb_to_yuv_frag },
-                       { BC_RGBA_FLOAT, BC_RGB888, rgba_to_rgb_frag },
-                       { BC_RGBA_FLOAT, BC_RGB_FLOAT, rgba_to_rgb_frag },
-                       { BC_RGBA_FLOAT, BC_YUV888, rgba_to_yuv_frag },
-                       { BC_RGBA_FLOAT, BC_YUVA8888, rgb_to_yuv_frag },
-                       { BC_YUV888, BC_RGB888, yuv_to_rgb_frag },
-                       { BC_YUV888, BC_RGBA8888, yuv_to_rgb_frag },
-                       { BC_YUV888, BC_RGB_FLOAT, yuv_to_rgb_frag },
-                       { BC_YUV888, BC_RGBA_FLOAT, yuv_to_rgb_frag },
-                       { BC_YUVA8888, BC_RGB888, yuva_to_rgb_frag },
-                       { BC_YUVA8888, BC_RGBA8888, yuv_to_rgb_frag },
-                       { BC_YUVA8888, BC_RGB_FLOAT, yuva_to_rgb_frag },
-                       { BC_YUVA8888, BC_RGBA_FLOAT, yuv_to_rgb_frag },
-                       { BC_YUVA8888, BC_YUV888, yuva_to_yuv_frag },
+               enum { rgb_to_rgb, rgb_to_yuv, yuv_to_rgb, yuv_to_yuv, };
+               int type = -1;
+               static cmodel_shader_table_t cmodel_shader_table[]  = {
+                       { BC_RGB888,    BC_YUV888,      rgb_to_yuv, rgb_to_yuv_frag  },
+                       { BC_RGB888,    BC_YUVA8888,    rgb_to_yuv, rgb_to_yuv_frag  },
+                       { BC_RGBA8888,  BC_RGB888,      rgb_to_rgb, rgba_to_rgb_frag },
+                       { BC_RGBA8888,  BC_RGB_FLOAT,   rgb_to_rgb, rgba_to_rgb_frag },
+                       { BC_RGBA8888,  BC_YUV888,      rgb_to_yuv, rgba_to_yuv_frag },
+                       { BC_RGBA8888,  BC_YUVA8888,    rgb_to_yuv, rgb_to_yuv_frag  },
+                       { BC_RGB_FLOAT, BC_YUV888,      rgb_to_yuv, rgb_to_yuv_frag  },
+                       { BC_RGB_FLOAT, BC_YUVA8888,    rgb_to_yuv, rgb_to_yuv_frag  },
+                       { BC_RGBA_FLOAT,BC_RGB888,      rgb_to_rgb, rgba_to_rgb_frag },
+                       { BC_RGBA_FLOAT,BC_RGB_FLOAT,   rgb_to_rgb, rgba_to_rgb_frag },
+                       { BC_RGBA_FLOAT,BC_YUV888,      rgb_to_yuv, rgba_to_yuv_frag },
+                       { BC_RGBA_FLOAT,BC_YUVA8888,    rgb_to_yuv, rgb_to_yuv_frag  },
+                       { BC_YUV888,    BC_RGB888,      yuv_to_rgb, yuv_to_rgb_frag  },
+                       { BC_YUV888,    BC_RGBA8888,    yuv_to_rgb, yuv_to_rgb_frag  },
+                       { BC_YUV888,    BC_RGB_FLOAT,   yuv_to_rgb, yuv_to_rgb_frag  },
+                       { BC_YUV888,    BC_RGBA_FLOAT,  yuv_to_rgb, yuv_to_rgb_frag  },
+                       { BC_YUVA8888,  BC_RGB888,      yuv_to_rgb, yuva_to_rgb_frag },
+                       { BC_YUVA8888,  BC_RGBA8888,    yuv_to_rgb, yuv_to_rgb_frag  },
+                       { BC_YUVA8888,  BC_RGB_FLOAT,   yuv_to_rgb, yuva_to_rgb_frag },
+                       { BC_YUVA8888,  BC_RGBA_FLOAT,  yuv_to_rgb, yuv_to_rgb_frag  },
+                       { BC_YUVA8888,  BC_YUV888,      yuv_to_yuv, yuva_to_yuv_frag },
                };
 
+               const char *shader = 0;
                int table_size = sizeof(cmodel_shader_table) / sizeof(cmodel_shader_table_t);
-               for(int i = 0; i < table_size; i++)
-               {
-                       if(cmodel_shader_table[i].src == src_cmodel &&
-                               cmodel_shader_table[i].dst == dst_cmodel)
-                       {
+               for( int i=0; i<table_size; ++i ) {
+                       if( cmodel_shader_table[i].src == src_cmodel &&
+                           cmodel_shader_table[i].dst == dst_cmodel ) {
                                shader = cmodel_shader_table[i].shader;
+                               type = cmodel_shader_table[i].typ;
                                break;
                        }
                }
@@ -1721,24 +1545,31 @@ void Playback3D::convert_cmodel_sync(Playback3DCommand *command)
 // command->dst_cmodel,
 // shader);
 
-               if(shader)
-               {
+               const char *shader_stack[9];
+               memset(shader_stack,0, sizeof(shader_stack));
+               int current_shader = 0;
+
+               if( shader ) {
 //printf("Playback3D::convert_cmodel_sync %d\n", __LINE__);
+                       shader_stack[current_shader++] = shader;
+                       shader_stack[current_shader] = 0;
+                       unsigned int shader_id = VFrame::make_shader(shader_stack);
+
                        command->frame->bind_texture(0);
-                       unsigned int shader_id = -1;
-                       if(shader)
-                       {
-                               shader_id = VFrame::make_shader(0,
-                                       shader,
-                                       0);
-                               glUseProgram(shader_id);
-                               glUniform1i(glGetUniformLocation(shader_id, "tex"), 0);
+                       glUseProgram(shader_id);
+
+                       glUniform1i(glGetUniformLocation(shader_id, "tex"), 0);
+                       switch( type ) {
+                       case rgb_to_yuv:
+                               BC_GL_RGB_TO_YUV(shader_id);
+                               break;
+                       case yuv_to_rgb:
+                               BC_GL_YUV_TO_RGB(shader_id);
+                               break;
                        }
 
                        command->frame->draw_texture();
-
                        if(shader) glUseProgram(0);
-
                        command->frame->set_opengl_state(VFrame::SCREEN);
                }
 
@@ -1815,8 +1646,7 @@ void Playback3D::do_fade_sync(Playback3DCommand *command)
                }
 
 
-               if(frag_shader)
-               {
+               if( frag_shader ) {
                        glUseProgram(frag_shader);
                        int variable;
                        if((variable = glGetUniformLocation(frag_shader, "tex")) >= 0)