X-Git-Url: https://git.cinelerra-gg.org/git/?p=goodguy%2Fcinelerra.git;a=blobdiff_plain;f=cinelerra-5.1%2Fcinelerra%2Fplayback3d.C;h=68c914c381607e0ffa3d1594c0fe215b4eb4b6d4;hp=0f5e84fe559000f7db3d9d938b349ce4ea1112d6;hb=3305343c3d9bfb889f6892e7821cc0e2d68669de;hpb=017728ea68874203d45b3f16050626d540608e35 diff --git a/cinelerra-5.1/cinelerra/playback3d.C b/cinelerra-5.1/cinelerra/playback3d.C index 0f5e84fe..68c914c3 100644 --- a/cinelerra-5.1/cinelerra/playback3d.C +++ b/cinelerra-5.1/cinelerra/playback3d.C @@ -259,39 +259,50 @@ static const char *read_texture_frag = " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n" "}\n"; -static const char *multiply_mask4_frag = - "uniform sampler2D tex;\n" - "uniform sampler2D tex1;\n" - "uniform float scale;\n" - "void main()\n" - "{\n" - " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n" - " gl_FragColor.a *= texture2D(tex1, gl_TexCoord[0].st / vec2(scale, scale)).r;\n" +static const char *in_vertex_frag = + "#version 430 // vertex shader\n" + "in vec3 in_pos;\n" + "void main() {\n" + " gl_Position = vec4(in_pos-vec3(0.5,0.5,0.), .5);\n" "}\n"; -static const char *multiply_mask3_frag = +static const char *feather_frag = + "#version 430\n" + "layout(location=0) out vec4 color;\n" "uniform sampler2D tex;\n" - "uniform sampler2D tex1;\n" - "uniform float scale;\n" - "uniform bool is_yuv;\n" - "void main()\n" - "{\n" - " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n" - " float a = texture2D(tex1, gl_TexCoord[0].st / vec2(scale, scale)).r;\n" - " gl_FragColor.rgb *= vec3(a, a, a);\n" +// apparently, only doubles index properly in shared buffers + "buffer buf { dvec2 points[]; };\n" + "uniform float r;\n" + "uniform float v;\n" + "void main() {\n" + " vec2 tex_st = gl_FragCoord.xy/textureSize(tex,0);\n" + " color = texture(tex, tex_st);\n" + " if( r==0. ) return;\n" + " float rv = r*v>0. ? 1 : -1;\n" + " float rr = r*r, dr = 1./rr;\n" + " float vv = v>=0 ? 1.-v : 1.+v;\n" + " float fg = rv>=0 ? vv : 1.;\n" + " float bg = rv>=0 ? 1. : vv;\n" + " int len = points.length();\n" + " for( int i=0; i= rr ) continue;\n" + " float d = dd*dr;\n" + " float a = (1.-d)*fg + d*bg;\n" + " if( rv*(color.a-a) > 0 ) color = vec4(a);\n" + " }\n" "}\n"; -static const char *multiply_yuvmask3_frag = +static const char *alpha_frag = "uniform sampler2D tex;\n" - "uniform sampler2D tex1;\n" - "uniform float scale;\n" - "void main()\n" - "{\n" + "uniform sampler2D tex2;\n" + "uniform vec2 tex2_dimensions;\n" + "void main() {\n" \ " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n" - " float a = texture2D(tex1, gl_TexCoord[0].st / vec2(scale, scale)).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" + " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n" + " gl_FragColor.a = canvas.a;\n" "}\n"; static const char *fade_rgba_frag = @@ -357,26 +368,32 @@ void Playback3DCommand::copy_from(BC_SynchronousCommand *command) BC_SynchronousCommand::copy_from(command); } - -///static void glDebugCallback(GLenum src, GLenum typ, GLuint id, -/// GLenum svy, GLsizei len, const GLchar* msg, void* dat) -//static void glDebugCallback(unsigned int src, unsigned int typ, unsigned int id, -// unsigned int svy, int len, const char* msg, const void* dat) -//{ -// printf("glDebug: %d:%d; %d/%d %s\n",src,typ,id,svy,msg); -//} - +//#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; - //Enabling OpenGL debug output on nVidia drivers -// 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); +#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() @@ -402,10 +419,6 @@ void Playback3D::handle_command(BC_SynchronousCommand *command) write_buffer_sync((Playback3DCommand*)command); break; - case Playback3DCommand::FINISH_OUTPUT: - finish_output_sync((Playback3DCommand*)command); - break; - case Playback3DCommand::CLEAR_OUTPUT: clear_output_sync((Playback3DCommand*)command); break; @@ -469,12 +482,11 @@ void Playback3D::copy_from(Canvas *canvas, void Playback3D::copy_from_sync(Playback3DCommand *command) { #ifdef HAVE_GL - command->canvas->lock_canvas("Playback3D::draw_refresh_sync"); - BC_WindowBase *window = command->canvas->get_canvas(); - if(window) - { - window->lock_window("Playback3D:draw_refresh_sync"); + BC_WindowBase *window = + command->canvas->lock_canvas("Playback3D::copy_from_sync"); + if( window ) { window->enable_opengl(); + glFinish(); int w = command->input->get_w(); int h = command->input->get_h(); @@ -530,8 +542,6 @@ void Playback3D::copy_from_sync(Playback3DCommand *command) command->input->get_opengl_state(), w, h, command->frame->get_w(), command->frame->get_h()); } - - window->unlock_window(); } command->canvas->unlock_canvas(); #endif @@ -568,11 +578,10 @@ void Playback3D::copy_from_sync(Playback3DCommand *command) // // void Playback3D::draw_refresh_sync(Playback3DCommand *command) // { -// command->canvas->lock_canvas("Playback3D::draw_refresh_sync"); -// BC_WindowBase *window = command->canvas->get_canvas(); -// if(window) -// { -// window->lock_window("Playback3D:draw_refresh_sync"); +// #ifdef HAVE_GL +// BC_WindowBase *window = +// command->canvas->lock_canvas("Playback3D::draw_refresh_sync"); +// if( window ) { // window->enable_opengl(); // // // Read output pbuffer back to RAM in project colormodel @@ -602,9 +611,9 @@ void Playback3D::copy_from_sync(Playback3DCommand *command) // (int)(command->in_y2 - command->in_y1), // 0); // -// window->unlock_window(); // } // command->canvas->unlock_canvas(); +// #endif // } @@ -642,18 +651,18 @@ void Playback3D::write_buffer(Canvas *canvas, void Playback3D::write_buffer_sync(Playback3DCommand *command) { - command->canvas->lock_canvas("Playback3D::write_buffer_sync"); - if(command->canvas->get_canvas()) - { - BC_WindowBase *window = command->canvas->get_canvas(); - window->lock_window("Playback3D::write_buffer_sync"); +#ifdef HAVE_GL + BC_WindowBase *window = + command->canvas->lock_canvas("Playback3D::write_buffer_sync"); + if( window ) { // Update hidden cursor window->update_video_cursor(); // Make sure OpenGL is enabled first. window->enable_opengl(); //printf("Playback3D::write_buffer_sync 1 %d\n", window->get_id()); - int flip_y = 0, frame_state = command->frame->get_opengl_state(); + int flip_y = 0; + int frame_state = command->frame->get_opengl_state(); switch( frame_state ) { // Upload texture and composite to screen case VFrame::RAM: @@ -663,13 +672,6 @@ void Playback3D::write_buffer_sync(Playback3DCommand *command) window->enable_opengl(); // Composite texture to screen and swap buffer case VFrame::TEXTURE: - 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: @@ -677,10 +679,9 @@ void Playback3D::write_buffer_sync(Playback3DCommand *command) break; } command->frame->set_opengl_state(frame_state); - window->unlock_window(); } - command->canvas->unlock_canvas(); +#endif } @@ -769,27 +770,6 @@ void Playback3D::init_frame(Playback3DCommand *command, int is_yuv) } -void Playback3D::finish_output(Canvas *canvas) -{ - Playback3DCommand command; - command.canvas = canvas; - command.command = Playback3DCommand::FINISH_OUTPUT; - send_command(&command); -} - -void Playback3D::finish_output_sync(Playback3DCommand *command) -{ -#ifdef HAVE_GL - command->canvas->lock_canvas("Playback3D::clear_output_sync"); - if( command->canvas->get_canvas() ) { - command->canvas->get_canvas()->enable_opengl(); - glFinish(); - } - command->canvas->unlock_canvas(); -#endif -} - - void Playback3D::clear_output(Canvas *canvas, VFrame *output) { Playback3DCommand command; @@ -801,26 +781,24 @@ void Playback3D::clear_output(Canvas *canvas, VFrame *output) void Playback3D::clear_output_sync(Playback3DCommand *command) { - command->canvas->lock_canvas("Playback3D::clear_output_sync"); - if(command->canvas->get_canvas()) - { - command->canvas->get_canvas()->lock_window("Playback3D::clear_output_sync"); +#ifdef HAVE_GL + BC_WindowBase *window = + command->canvas->lock_canvas("Playback3D::clear_output_sync"); + if( window ) { // 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) - { + 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, is_yuv); - command->canvas->get_canvas()->unlock_window(); } command->canvas->unlock_canvas(); +#endif } @@ -835,17 +813,17 @@ void Playback3D::clear_input(Canvas *canvas, VFrame *frame) void Playback3D::clear_input_sync(Playback3DCommand *command) { - command->canvas->lock_canvas("Playback3D::clear_output_sync"); - if(command->canvas->get_canvas()) - { - command->canvas->get_canvas()->lock_window("Playback3D::clear_output_sync"); +#ifdef HAVE_GL + BC_WindowBase *window = + command->canvas->lock_canvas("Playback3D::clear_input_sync"); + if( window ) { command->canvas->get_canvas()->enable_opengl(); command->frame->enable_opengl(); command->frame->clear_pbuffer(); command->frame->set_opengl_state(VFrame::SCREEN); - command->canvas->get_canvas()->unlock_window(); } command->canvas->unlock_canvas(); +#endif } void Playback3D::do_camera(Canvas *canvas, @@ -878,10 +856,10 @@ void Playback3D::do_camera(Canvas *canvas, void Playback3D::do_camera_sync(Playback3DCommand *command) { - command->canvas->lock_canvas("Playback3D::do_camera_sync"); - if(command->canvas->get_canvas()) - { - command->canvas->get_canvas()->lock_window("Playback3D::clear_output_sync"); +#ifdef HAVE_GL + BC_WindowBase *window = + command->canvas->lock_canvas("Playback3D::do_camera_sync"); + if( window ) { command->canvas->get_canvas()->enable_opengl(); command->input->to_texture(); @@ -912,9 +890,9 @@ 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(); +#endif } void Playback3D::overlay(Canvas *canvas, VFrame *input, @@ -981,10 +959,9 @@ void Playback3D::overlay_sync(Playback3DCommand *command) blend_DIFFERENCE_frag, // TRANSFER_DIFFERENCE }; - command->canvas->lock_canvas("Playback3D::overlay_sync"); - if(command->canvas->get_canvas()) { - BC_WindowBase *window = command->canvas->get_canvas(); - window->lock_window("Playback3D::overlay_sync"); + BC_WindowBase *window = + command->canvas->lock_canvas("Playback3D::overlay_sync"); + if( window ) { // Make sure OpenGL is enabled first. window->enable_opengl(); window->update_video_cursor(); @@ -1116,8 +1093,6 @@ void Playback3D::overlay_sync(Playback3DCommand *command) } glActiveTexture(GL_TEXTURE0); glDisable(GL_TEXTURE_2D); - - window->unlock_window(); } command->canvas->unlock_canvas(); #endif @@ -1160,146 +1135,200 @@ void Playback3D::do_mask(Canvas *canvas, } +void Playback3D::draw_spots(MaskSpots &spots, int ix1,int iy1, int ix2,int iy2) +{ + int x1 = iy1 < iy2 ? ix1 : ix2; + int y1 = iy1 < iy2 ? iy1 : iy2; + int x2 = iy1 < iy2 ? ix2 : ix1; + int y2 = iy1 < iy2 ? iy2 : iy1; + + int x = x1, y = y1; + int dx = x2-x1, dy = y2-y1; + int dx2 = 2*dx, dy2 = 2*dy; + if( dx < 0 ) dx = -dx; + int m = dx > dy ? dx : dy, n = m; + if( dy >= dx ) { + if( dx2 >= 0 ) do { /* +Y, +X */ + spots.append(x, y++); + if( (m -= dx2) < 0 ) { m += dy2; ++x; } + } while( --n >= 0 ); + else do { /* +Y, -X */ + spots.append(x, y++); + if( (m += dx2) < 0 ) { m += dy2; --x; } + } while( --n >= 0 ); + } + else { + if( dx2 >= 0 ) do { /* +X, +Y */ + spots.append(x++, y); + if( (m -= dy2) < 0 ) { m += dx2; ++y; } + } while( --n >= 0 ); + else do { /* -X, +Y */ + spots.append(x--, y); + if( (m -= dy2) < 0 ) { m -= dx2; ++y; } + } while( --n >= 0 ); + } +} #ifdef HAVE_GL -struct Vertex : ListItem +class fb_texture : public BC_Texture { - GLdouble c[3]; +public: + fb_texture(int w, int h, int colormodel); + ~fb_texture(); + void bind(int texture_unit); + void read_screen(int x, int y, int w, int h); + void set_output_texture(); + GLuint fb, rb; }; -// this list is only used from the main thread, no locking needed -// this must be a list so that pointers to allocated entries remain valid -// when new entries are added -static List *vertex_cache = 0; - -static void combine_callback(GLdouble coords[3], - GLdouble *vertex_data[4], - GLfloat weight[4], - GLdouble **dataOut) + +fb_texture::fb_texture(int w, int h, int colormodel) + : BC_Texture(w, h, colormodel) { -// can't use malloc here; GLU doesn't delete the memory for us! - Vertex* vertex = vertex_cache->append(); - vertex->c[0] = coords[0]; - vertex->c[1] = coords[1]; - vertex->c[2] = coords[2]; -// we don't need to interpolate anything - - *dataOut = &vertex->c[0]; + fb = 0; rb = 0; +// glGenRenderbuffers(1, &rb); +// glBindRenderbuffer(GL_RENDERBUFFER, rb); +// glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, get_texture_w(), get_texture_w()); + glGenFramebuffers(1, &fb); + glBindFramebuffer(GL_FRAMEBUFFER, fb); +// glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rb); } -#endif +fb_texture::~fb_texture() +{ + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glDeleteFramebuffers(1, (GLuint *)&fb); +// glBindRenderbuffer(GL_RENDERBUFFER, 0); +// glGenRenderbuffers(1, &rb); +} + +void fb_texture::bind(int texture_unit) +{ + glBindFramebuffer(GL_FRAMEBUFFER, fb); +// glBindRenderbuffer(GL_RENDERBUFFER, rb); + BC_Texture::bind(texture_unit); +} + +void fb_texture::read_screen(int x, int y, int w, int h) +{ + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glReadBuffer(GL_BACK); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0,0, x,y, w,h); +} + +void fb_texture::set_output_texture() +{ + glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, get_texture_id(), 0); + GLenum dbo[1] = { GL_COLOR_ATTACHMENT0, }; // bind layout(location=0) out vec4 color; + glDrawBuffers(1, dbo); + int ret = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if( ret != GL_FRAMEBUFFER_COMPLETE ) { + printf("glDrawBuffer error 0x%04x\n", ret); + return; + } +} + +static void combineData(GLdouble coords[3], + GLdouble *vertex_data[4], GLfloat weight[4], + GLdouble **outData, void *data) +{ + ArrayList *invented = (ArrayList *)data; + GLdouble *vertex = new double[6]; + invented->append(vertex); + vertex[0] = coords[0]; + 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]; + } + *outData = vertex; +} + +// dbug +static void zglBegin(GLenum mode) { glBegin(mode); } +static void zglEnd() { glEnd(); } +static void zglVertex3dv(const GLdouble *v) { glVertex3dv(v); } + +#endif void Playback3D::do_mask_sync(Playback3DCommand *command) { #ifdef HAVE_GL - command->canvas->lock_canvas("Playback3D::do_mask_sync"); - if(command->canvas->get_canvas()) - { - BC_WindowBase *window = command->canvas->get_canvas(); - window->lock_window("Playback3D::do_mask_sync"); + BC_WindowBase *window = + command->canvas->lock_canvas("Playback3D::do_mask_sync"); + if( window ) { window->enable_opengl(); - switch(command->frame->get_opengl_state()) - { - case VFrame::RAM: -// Time to upload to the texture - command->frame->to_texture(); - break; + switch( command->frame->get_opengl_state() ) { + case VFrame::RAM: +// upload frame to the texture + command->frame->to_texture(); + break; - case VFrame::SCREEN: + case VFrame::SCREEN: // Read back from PBuffer // Bind context to pbuffer - command->frame->enable_opengl(); - command->frame->screen_to_texture(); - break; + command->frame->enable_opengl(); + command->frame->screen_to_texture(); + break; } - - -// Create PBuffer and draw the mask on it - command->frame->enable_opengl(); - // Initialize coordinate system + command->frame->enable_opengl(); + command->frame->init_screen(); + int color_model = command->frame->get_color_model(); int w = command->frame->get_w(); int h = command->frame->get_h(); - command->frame->init_screen(); - -// Clear screen - glDisable(GL_TEXTURE_2D); - if(command->default_auto->mode == MASK_MULTIPLY_ALPHA) - { - glClearColor(0.0, 0.0, 0.0, 0.0); - glColor4f((float)command->keyframe->value / 100, - (float)command->keyframe->value / 100, - (float)command->keyframe->value / 100, - 1.0); - } - else - { - glClearColor(1.0, 1.0, 1.0, 1.0); - glColor4f((float)1.0 - (float)command->keyframe->value / 100, - (float)1.0 - (float)command->keyframe->value / 100, - (float)1.0 - (float)command->keyframe->value / 100, - 1.0); - } - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - -// Draw mask with scaling to simulate feathering - GLUtesselator *tesselator = gluNewTess(); - gluTessProperty(tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD); - gluTessCallback(tesselator, GLU_TESS_VERTEX, (GLvoid (*) ( )) &glVertex3dv); - gluTessCallback(tesselator, GLU_TESS_BEGIN, (GLvoid (*) ( )) &glBegin); - gluTessCallback(tesselator, GLU_TESS_END, (GLvoid (*) ( )) &glEnd); - gluTessCallback(tesselator, GLU_TESS_COMBINE, (GLvoid (*) ( ))&combine_callback); - - vertex_cache = new List; - - + MaskEdges edges; + float faders[SUBMASKS], feathers[SUBMASKS], bg = 1; + MaskPointSet point_set[SUBMASKS]; // Draw every submask as a new polygon int total_submasks = command->keyframe_set->total_submasks( - command->start_position_project, - PLAY_FORWARD); - float scale = command->keyframe->feather + 1; - int display_list = glGenLists(1); - glNewList(display_list, GL_COMPILE); - for(int k = 0; k < total_submasks; k++) - { - gluTessBeginPolygon(tesselator, NULL); - gluTessBeginContour(tesselator); - ArrayList *points = new ArrayList; - command->keyframe_set->get_points(points, - k, - command->start_position_project, - PLAY_FORWARD); + command->start_position_project, PLAY_FORWARD); + + for(int k = 0; k < total_submasks; k++) { + MaskPointSet &points = point_set[k]; + command->keyframe_set->get_points(&points, + k, command->start_position_project, PLAY_FORWARD); + float fader = command->keyframe_set->get_fader( + command->start_position_project, k, PLAY_FORWARD); + float v = fader/100.; + faders[k] = v; + if( v < 0 && (v+=1) < bg ) bg = v; + float feather = command->keyframe_set->get_feather( + command->start_position_project, k, PLAY_FORWARD); + feathers[k] = feather; + } +// clear screen + glDisable(GL_TEXTURE_2D); + glClearColor(bg, bg, bg, bg); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + 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. - ArrayList coords; - coords.set_array_delete(); - 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]; + 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) + if( point1->control_x2 == 0 && point1->control_y2 == 0 && + point2->control_x1 == 0 && point2->control_y1 == 0 ) segments = 1; - float x0 = point1->x; - float y0 = point1->y; + 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; - float y3 = point2->y; + 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 @@ -1330,8 +1359,7 @@ void Playback3D::do_mask_sync(Playback3DCommand *command) // 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) - { + if (segments == 0) { float maxaccel1 = fabs(2*cy2) + fabs(6*cy3); float maxaccel2 = fabs(2*cx2) + fabs(6*cx3); @@ -1342,139 +1370,131 @@ void Playback3D::do_mask_sync(Playback3DCommand *command) segments = int(1/h); } - for(int j = 0; j <= segments; j++) - { + 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) - { - GLdouble *coord = new GLdouble[3]; - coord[0] = x / scale; - coord[1] = -h + y / scale; - coord[2] = 0; - coords.append(coord); + if(j > 0 || first_point) { + edge.append(x, y - h); first_point = 0; } } } - -// Now that we know the total vertices, send them to GLU - for(int i = 0; i < coords.total; i++) - gluTessVertex(tesselator, coords.values[i], coords.values[i]); - - gluTessEndContour(tesselator); - gluTessEndPolygon(tesselator); - points->remove_all_objects(); - delete points; - coords.remove_all_objects(); - } - glEndList(); - glCallList(display_list); - glDeleteLists(display_list, 1); - gluDeleteTess(tesselator); - - delete vertex_cache; - vertex_cache = 0; - - glColor4f(1, 1, 1, 1); - - -// Read mask into temporary texture. -// For feathering, just read the part of the screen after the downscaling. - - - float w_scaled = w / scale; - float h_scaled = h / scale; -// Don't vary the texture size according to scaling because that -// would waste memory. -// This enables and binds the temporary texture. - glActiveTexture(GL_TEXTURE1); - BC_Texture::new_texture(&temp_texture, - w, - h, - command->frame->get_color_model()); - temp_texture->bind(1); - glReadBuffer(GL_BACK); - -// Need to add extra size to fill in the bottom right - glCopyTexSubImage2D(GL_TEXTURE_2D, - 0, - 0, - 0, - 0, - 0, - (int)MIN(w_scaled + 2, w), - (int)MIN(h_scaled + 2, h)); - - command->frame->bind_texture(0); - - -// For feathered masks, use a shader to multiply. -// 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: - 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( edge.size() > 0 ) { +// draw polygon + float fader = faders[k]; + float v = fader < 0 ? 1 : 1-fader; + glColor4f(v, v, v, v); + int display_list = glGenLists(1); + glNewList(display_list, GL_COMPILE); +#if 0 + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glBegin(GL_POLYGON); + MaskCoord *c = &edge[0]; + for( int i=edge.size(); --i>=0; ++c ) + glVertex2f(c->x, c->y); + glEnd(); +#else + GLUtesselator *tess = gluNewTess(); + gluTessCallback(tess, GLU_TESS_VERTEX,(GLvoid (*)()) &zglVertex3dv); + gluTessCallback(tess, GLU_TESS_BEGIN,(GLvoid (*)()) &zglBegin); + gluTessCallback(tess, GLU_TESS_END,(GLvoid (*)()) &zglEnd); + gluTessCallback(tess, GLU_TESS_COMBINE_DATA,(GLvoid (*)()) &combineData); + ArrayList invented; + invented.set_array_delete(); + + gluTessBeginPolygon(tess, &invented); + gluTessBeginContour(tess); + MaskCoord *c = &edge[0]; + for( int i=edge.size(); --i>=0; ++c ) + gluTessVertex(tess, (GLdouble *)c, c); + gluTessEndContour(tess); + gluTessEndPolygon(tess); + gluDeleteTess(tess); + invented.remove_all_objects(); +#endif + glEndList(); + glCallList(display_list); + glDeleteLists(1, display_list); + } } - if( frag_shader ) { - int variable; - glUseProgram(frag_shader); - if((variable = glGetUniformLocation(frag_shader, "tex")) >= 0) - glUniform1i(variable, 0); - if((variable = glGetUniformLocation(frag_shader, "tex1")) >= 0) - glUniform1i(variable, 1); - if((variable = glGetUniformLocation(frag_shader, "scale")) >= 0) - glUniform1f(variable, scale); +// in/out textures + fb_texture *in = new fb_texture(w, h, color_model); + in->bind(0); + in->read_screen(0,0, w,h); + fb_texture *out = new fb_texture(w, h, color_model); + + unsigned int frag_shader = + VFrame::make_shader(0, in_vertex_frag, feather_frag, 0); + if( frag_shader > 0 ) { + GLuint points[1]; + glGenBuffers(1, points); + for(int k = 0; k < total_submasks; k++) { + MaskEdge &edge = *edges[k]; + if( !edge.size() ) continue; + if( !faders[k] ) continue; + if( !feathers[k] ) continue; + MaskSpots spots; + for( int i=0; ibind(0); + glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0); + out->set_output_texture(); + glViewport(0,0, w,h); + out->draw_texture(0,0, w,h, 0,0, w,h); + glUseProgram(0); + fb_texture *t = in; in = out; out = t; + } + glDeleteBuffers(1, points); } + glDrawBuffers(0, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); - -// Write texture to PBuffer with multiply and scaling for feather. - - - command->frame->draw_texture(0, 0, w, h, 0, 0, w, h); + unsigned int shader = VFrame::make_shader(0, alpha_frag, 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); +// } + } + command->frame->draw_texture(); command->frame->set_opengl_state(VFrame::SCREEN); - - -// Disable temp texture glUseProgram(0); - - glActiveTexture(GL_TEXTURE1); + delete in; + delete out; +// Default drawable glDisable(GL_TEXTURE_2D); - delete temp_texture; - temp_texture = 0; - + glColor4f(1, 1, 1, 1); glActiveTexture(GL_TEXTURE0); - glDisable(GL_TEXTURE_2D); - -// Default drawable window->enable_opengl(); - window->unlock_window(); } command->canvas->unlock_canvas(); #endif } - - - - - - - - void Playback3D::convert_cmodel(Canvas *canvas, VFrame *output, int dst_cmodel) @@ -1508,11 +1528,9 @@ void Playback3D::convert_cmodel(Canvas *canvas, void Playback3D::convert_cmodel_sync(Playback3DCommand *command) { #ifdef HAVE_GL - command->canvas->lock_canvas("Playback3D::convert_cmodel_sync"); - - if( command->canvas->get_canvas() ) { - BC_WindowBase *window = command->canvas->get_canvas(); - window->lock_window("Playback3D::convert_cmodel_sync"); + BC_WindowBase *window = + command->canvas->lock_canvas("Playback3D::convert_cmodel_sync"); + if( window ) { window->enable_opengl(); // Import into hardware @@ -1597,8 +1615,6 @@ void Playback3D::convert_cmodel_sync(Playback3DCommand *command) if(shader) glUseProgram(0); command->frame->set_opengl_state(VFrame::SCREEN); } - - window->unlock_window(); } command->canvas->unlock_canvas(); @@ -1618,28 +1634,23 @@ void Playback3D::do_fade(Canvas *canvas, VFrame *frame, float fade) void Playback3D::do_fade_sync(Playback3DCommand *command) { #ifdef HAVE_GL - command->canvas->lock_canvas("Playback3D::do_mask_sync"); - if(command->canvas->get_canvas()) - { - BC_WindowBase *window = command->canvas->get_canvas(); - window->lock_window("Playback3D::do_fade_sync"); + BC_WindowBase *window = + command->canvas->lock_canvas("Playback3D::do_fade_sync"); + if( window ) { window->enable_opengl(); + switch( command->frame->get_opengl_state() ) { + case VFrame::RAM: + command->frame->to_texture(); + break; - switch(command->frame->get_opengl_state()) - { - case VFrame::RAM: - command->frame->to_texture(); - break; - - case VFrame::SCREEN: + case VFrame::SCREEN: // Read back from PBuffer // Bind context to pbuffer - command->frame->enable_opengl(); - command->frame->screen_to_texture(); - break; + command->frame->enable_opengl(); + command->frame->screen_to_texture(); + break; } - command->frame->enable_opengl(); command->frame->init_screen(); command->frame->bind_texture(0); @@ -1690,23 +1701,12 @@ void Playback3D::do_fade_sync(Playback3DCommand *command) glColor4f(1, 1, 1, 1); glDisable(GL_BLEND); - - window->unlock_window(); } command->canvas->unlock_canvas(); #endif } - - - - - - - - - int Playback3D::run_plugin(Canvas *canvas, PluginClient *client) { Playback3DCommand command; @@ -1718,16 +1718,11 @@ int Playback3D::run_plugin(Canvas *canvas, PluginClient *client) void Playback3D::run_plugin_sync(Playback3DCommand *command) { - command->canvas->lock_canvas("Playback3D::run_plugin_sync"); - if(command->canvas->get_canvas()) - { - BC_WindowBase *window = command->canvas->get_canvas(); - window->lock_window("Playback3D::run_plugin_sync"); + BC_WindowBase *window = + command->canvas->lock_canvas("Playback3D::run_plugin_sync"); + if( window ) { window->enable_opengl(); - command->result = ((PluginVClient*)command->plugin_client)->handle_opengl(); - - window->unlock_window(); } command->canvas->unlock_canvas(); }