add igors mask svgs, add composer clear_color pref, remove key DEL for mask gui,...
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / playback3d.C
index 68c914c381607e0ffa3d1594c0fe215b4eb4b6d4..53f6c9e6aa4abc298d6e4c37d9f9125c15fbb4c8 100644 (file)
@@ -38,6 +38,7 @@
 #include "pluginclient.h"
 #include "pluginvclient.h"
 #include "edlsession.h"
+#include "track.h"
 #include "transportque.inc"
 #include "vframe.h"
 
@@ -295,14 +296,35 @@ static const char *feather_frag =
        "       }\n"
        "}\n";
 
-static const char *alpha_frag =
+static const char *multiply_mask4_frag =
        "uniform sampler2D tex;\n"
-       "uniform sampler2D tex2;\n"
-       "uniform vec2 tex2_dimensions;\n"
-       "void main() {\n" \
+       "uniform sampler2D tex1;\n"
+       "void main()\n"
+       "{\n"
        "       gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
-       "       vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
-       "       gl_FragColor.a = canvas.a;\n"
+       "       gl_FragColor.a *= texture2D(tex1, gl_TexCoord[0].st).r;\n"
+       "}\n";
+
+static const char *multiply_mask3_frag =
+       "uniform sampler2D tex;\n"
+       "uniform sampler2D tex1;\n"
+       "void main()\n"
+       "{\n"
+       "       gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
+       "       float a = texture2D(tex1, gl_TexCoord[0].st).r;\n"
+       "       gl_FragColor.rgb *= vec3(a, a, a);\n"
+       "}\n";
+
+static const char *multiply_yuvmask3_frag =
+       "uniform sampler2D tex;\n"
+       "uniform sampler2D tex1;\n"
+       "void main()\n"
+       "{\n"
+       "       gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
+       "       float a = texture2D(tex1, gl_TexCoord[0].st).r;\n"
+       "       gl_FragColor.gb -= vec2(0.5, 0.5);\n"
+       "       gl_FragColor.rgb *= vec3(a, a, a);\n"
+       "       gl_FragColor.gb += vec2(0.5, 0.5);\n"
        "}\n";
 
 static const char *fade_rgba_frag =
@@ -368,32 +390,11 @@ void Playback3DCommand::copy_from(BC_SynchronousCommand *command)
        BC_SynchronousCommand::copy_from(command);
 }
 
-//#define GL_BUG 1
-#ifdef GL_BUG
-static void GLAPIENTRY glDebugCallback(GLenum source, GLenum type,
-       GLuint id, GLenum severity, GLsizei length, const GLchar* message,
-       const void* userParam)
-{
-  fprintf(stderr, "GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n",
-       ( type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : "" ),
-       type, severity, message );
-}
-#endif
-
 Playback3D::Playback3D(MWindow *mwindow)
  : BC_Synchronous()
 {
        this->mwindow = mwindow;
        temp_texture = 0;
-#ifdef GL_BUG
-       //Enabling OpenGL debug output
-       // this does not work
-       glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, 0, GL_TRUE);
-       glEnable(GL_DEBUG_OUTPUT);
-       glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
-       glDebugMessageCallback(glDebugCallback, 0);
-       glEnable(GL_DEBUG_OUTPUT);
-#endif
 }
 
 Playback3D::~Playback3D()
@@ -655,29 +656,21 @@ void Playback3D::write_buffer_sync(Playback3DCommand *command)
        BC_WindowBase *window =
                command->canvas->lock_canvas("Playback3D::write_buffer_sync");
        if( window ) {
+               window->enable_opengl();
 // Update hidden cursor
                window->update_video_cursor();
-// Make sure OpenGL is enabled first.
-               window->enable_opengl();
-
+               command->frame->enable_opengl();
+               command->frame->init_screen();
 //printf("Playback3D::write_buffer_sync 1 %d\n", window->get_id());
-               int flip_y = 0;
                int 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();
-                               window->enable_opengl();
-// Composite texture to screen and swap buffer
-                       case VFrame::TEXTURE:
-                               draw_output(command, flip_y);
-                               break;
-                       default:
-                               printf("Playback3D::write_buffer_sync unknown state\n");
-                               break;
+               if( frame_state != VFrame::TEXTURE )
+                       command->frame->to_texture();
+               if( frame_state != VFrame::RAM ) {
+                       command->in_y1 = command->frame->get_h() - command->in_y1;
+                       command->in_y2 = command->frame->get_h() - command->in_y2;
                }
+               window->enable_opengl();
+               draw_output(command, 1);
                command->frame->set_opengl_state(frame_state);
        }
        command->canvas->unlock_canvas();
@@ -712,7 +705,7 @@ void Playback3D::draw_output(Playback3DCommand *command, int flip_y)
                if(!command->is_cleared)
                {
 // If we get here, the virtual console was not used.
-                       init_frame(command, 0);
+                       color_frame(command, 0,0,0,0);
                }
 
 // Texture
@@ -742,14 +735,8 @@ void Playback3D::draw_output(Playback3DCommand *command, int flip_y)
 
 
 //printf("Playback3D::draw_output 2 %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->in_x1, command->in_y1, command->in_x2, command->in_y2,
+// command->out_x1, command->out_y1, command->out_x2, command->out_y2);
 
                glUseProgram(0);
 
@@ -760,11 +747,11 @@ void Playback3D::draw_output(Playback3DCommand *command, int flip_y)
 }
 
 
-void Playback3D::init_frame(Playback3DCommand *command, int is_yuv)
+void Playback3D::color_frame(Playback3DCommand *command,
+               float r, float g, float b, float a)
 {
 #ifdef HAVE_GL
-       float gbuv = is_yuv ? 0.5 : 0.0;
-       glClearColor(0.0, gbuv, gbuv, 0.0);
+       glClearColor(r, g, b, a);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 #endif
 }
@@ -788,14 +775,21 @@ void Playback3D::clear_output_sync(Playback3DCommand *command)
 // If we get here, the virtual console is being used.
                command->canvas->get_canvas()->enable_opengl();
                int is_yuv = 0;
+               int color = BLACK, alpha = 0;
 // Using pbuffer for refresh frame.
                if( command->frame ) {
                        command->frame->enable_opengl();
+                       color = command->frame->get_clear_color();
+                       alpha = command->frame->get_clear_alpha();
                        int color_model = command->canvas->mwindow->edl->session->color_model;
                        is_yuv = BC_CModels::is_yuv(color_model);
                }
-
-               init_frame(command, is_yuv);
+               int a = alpha;
+               int r = (color>>16) & 0xff;
+               int g = (color>>8) & 0xff;
+               int b = (color>>0) & 0xff;
+               if( is_yuv ) YUV::yuv.rgb_to_yuv_8(r, g, b);
+               color_frame(command, r/255.f, g/255.f, b/255.f, a/255.f);
        }
        command->canvas->unlock_canvas();
 #endif
@@ -1238,10 +1232,12 @@ static void combineData(GLdouble coords[3],
        vertex[1] = coords[1];
        vertex[2] = coords[2];
        for( int i=3; i<6; ++i ) {
-               vertex[i] = weight[0] * vertex_data[0][i] +
-                       weight[1] * vertex_data[1][i] +
-                       weight[2] * vertex_data[2][i] +
-                       weight[3] * vertex_data[3][i];
+               GLdouble v = 0;
+               for( int k=0; k<4; ++k ) {
+                       if( !weight[k] || !vertex_data[k] ) continue;
+                       v += weight[k] * vertex_data[k][i];
+               }
+               vertex[i] = v;
        }
        *outData = vertex;
 }
@@ -1283,13 +1279,13 @@ void Playback3D::do_mask_sync(Playback3DCommand *command)
                int h = command->frame->get_h();
                MaskEdges edges;
                float faders[SUBMASKS], feathers[SUBMASKS], bg = 1;
-               MaskPointSet point_set[SUBMASKS];
+               MaskPoints point_set[SUBMASKS];
 // Draw every submask as a new polygon
                int total_submasks = command->keyframe_set->total_submasks(
                        command->start_position_project, PLAY_FORWARD);
 
                for(int k = 0; k < total_submasks; k++) {
-                       MaskPointSet &points = point_set[k];
+                       MaskPoints &points = point_set[k];
                        command->keyframe_set->get_points(&points,
                                k, command->start_position_project, PLAY_FORWARD);
                        float fader = command->keyframe_set->get_fader(
@@ -1306,81 +1302,11 @@ void Playback3D::do_mask_sync(Playback3DCommand *command)
                glClearColor(bg, bg, bg, bg);
                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
+               int show_mask = command->keyframe_set->track->masks;
                for(int k = 0; k < total_submasks; k++) {
-                       MaskPointSet &points = point_set[k];
                        MaskEdge &edge = *edges.append(new MaskEdge());
-                       int first_point = 0;
-// Need to tabulate every vertex in persistent memory because
-// gluTessVertex doesn't copy them.
-                       for(int i = 0; i < points.total; i++) {
-                               MaskPoint *point1 = points.values[i];
-                               MaskPoint *point2 = (i >= points.total - 1) ?
-                                       points.values[0] : points.values[i + 1];
-
-                               float x, y;
-                               int segments = 0;
-                               if( point1->control_x2 == 0 && point1->control_y2 == 0 &&
-                                   point2->control_x1 == 0 && point2->control_y1 == 0 )
-                                       segments = 1;
-
-                               float x0 = point1->x, y0 = point1->y;
-                               float x1 = point1->x + point1->control_x2;
-                               float y1 = point1->y + point1->control_y2;
-                               float x2 = point2->x + point2->control_x1;
-                               float y2 = point2->y + point2->control_y1;
-                               float x3 = point2->x, y3 = point2->y;
-
-                               // forward differencing bezier curves implementation taken from GPL code at
-                               // http://cvs.sourceforge.net/viewcvs.py/guliverkli/guliverkli/src/subtitles/Rasterizer.cpp?rev=1.3
-
-                               float cx3, cx2, cx1, cx0, cy3, cy2, cy1, cy0;
-
-                               // [-1 +3 -3 +1]
-                               // [+3 -6 +3  0]
-                               // [-3 +3  0  0]
-                               // [+1  0  0  0]
-
-                               cx3 = -  x0 + 3*x1 - 3*x2 + x3;
-                               cx2 =  3*x0 - 6*x1 + 3*x2;
-                               cx1 = -3*x0 + 3*x1;
-                               cx0 =    x0;
-
-                               cy3 = -  y0 + 3*y1 - 3*y2 + y3;
-                               cy2 =  3*y0 - 6*y1 + 3*y2;
-                               cy1 = -3*y0 + 3*y1;
-                               cy0 =    y0;
-
-                               // This equation is from Graphics Gems I.
-                               //
-                               // The idea is that since we're approximating a cubic curve with lines,
-                               // any error we incur is due to the curvature of the line, which we can
-                               // estimate by calculating the maximum acceleration of the curve.  For
-                               // a cubic, the acceleration (second derivative) is a line, meaning that
-                               // the absolute maximum acceleration must occur at either the beginning
-                               // (|c2|) or the end (|c2+c3|).  Our bounds here are a little more
-                               // conservative than that, but that's okay.
-                               if (segments == 0) {
-                                       float maxaccel1 = fabs(2*cy2) + fabs(6*cy3);
-                                       float maxaccel2 = fabs(2*cx2) + fabs(6*cx3);
-
-                                       float maxaccel = maxaccel1 > maxaccel2 ? maxaccel1 : maxaccel2;
-                                       float h = 1.0;
-
-                                       if(maxaccel > 8.0) h = sqrt((8.0) / maxaccel);
-                                       segments = int(1/h);
-                               }
-
-                               for(int j = 0; j <= segments; j++) {
-                                       float t = (float)j / segments;
-                                       x = cx0 + t*(cx1 + t*(cx2 + t*cx3));
-                                       y = cy0 + t*(cy1 + t*(cy2 + t*cy3));
-
-                                       if(j > 0 || first_point) {
-                                               edge.append(x, y - h);
-                                               first_point = 0;
-                                       }
-                               }
-                       }
+                       if( !((show_mask>>k) & 1) ) continue;
+                       edge.load(point_set[k], h);
                        if( edge.size() > 0 ) {
 // draw polygon
                                float fader = faders[k];
@@ -1464,20 +1390,18 @@ void Playback3D::do_mask_sync(Playback3DCommand *command)
                glDrawBuffers(0, 0);
                glBindFramebuffer(GL_FRAMEBUFFER, 0);
 
-               unsigned int shader = VFrame::make_shader(0, alpha_frag, 0);
+               const char *alpha_shader = BC_CModels::has_alpha(color_model) ?
+                               multiply_mask4_frag :
+                       !BC_CModels::is_yuv(color_model) ?
+                               multiply_mask3_frag :
+                               multiply_yuvmask3_frag;
+               unsigned int shader = VFrame::make_shader(0, alpha_shader, 0);
                glUseProgram(shader);
                if( shader > 0 ) {
                        command->frame->bind_texture(0);
                        in->BC_Texture::bind(1);
                        glUniform1i(glGetUniformLocation(shader, "tex"), 0);
-                       glUniform1i(glGetUniformLocation(shader, "tex2"), 1);
-                       glUniform2f(glGetUniformLocation(shader, "tex2_dimensions"),
-                                       (float)in->get_texture_w(),
-                                       (float)in->get_texture_h());
-//                     if( BC_CModels::components(color_model ) == 4) {
-//                             glEnable(GL_BLEND);
-//                             glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-//                     }
+                       glUniform1i(glGetUniformLocation(shader, "tex1"), 1);
                }
                command->frame->draw_texture();
                command->frame->set_opengl_state(VFrame::SCREEN);