X-Git-Url: https://git.cinelerra-gg.org/git/?p=goodguy%2Fcinelerra.git;a=blobdiff_plain;f=cinelerra-5.1%2Fcinelerra%2Fplayback3d.C;h=9eee736f36d47d926bd6ca8909c03ec897c5ed52;hp=8d58deb3787880a2bd6dc3d1206163c8763b6337;hb=7ffa6954689f14a41a3bae7a0fdb3f2abeaa9679;hpb=307d7f624510fcca7a7f6c1e683796cb73637106 diff --git a/cinelerra-5.1/cinelerra/playback3d.C b/cinelerra-5.1/cinelerra/playback3d.C index 8d58deb3..9eee736f 100644 --- a/cinelerra-5.1/cinelerra/playback3d.C +++ b/cinelerra-5.1/cinelerra/playback3d.C @@ -38,6 +38,7 @@ #include "pluginclient.h" #include "pluginvclient.h" #include "edlsession.h" +#include "track.h" #include "transportque.inc" #include "vframe.h" @@ -259,36 +260,89 @@ static const char *read_texture_frag = " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n" "}\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 *feather_frag = + "#version 430\n" + "layout(location=0) out vec4 color;\n" + "uniform sampler2D tex;\n" + "const int MAX = " SS(MAX_FEATHER) "+1;\n" + "uniform float psf[MAX];\n" + "uniform int n;\n" + "uniform vec2 dxy;\n" + "uniform vec2 twh;\n" + "\n" + "void main() {\n" + " vec2 tc = gl_FragCoord.xy/textureSize(tex,0);\n" + " color = texture(tex, tc);\n" + " float c = color.r, f = c*psf[0];\n" + " for( int i=1; i=0. ? 1. : -1.;\n" + " float rr = r!=0. ? r : 1.;\n" + " float rv = rr*v>=0. ? 1. : -1.;\n" + " float vv = v>=0. ? 1.-v : 1.+v;\n" + " float fg = rv>0. ? vv : 1.;\n" + " float bg = rv>0. ? 1. : vv;\n" + " float a = c*fg + (1.-c)*bg;\n" + " if( iv*(color.a-a) > 0. ) color = vec4(a);\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" + " 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" - "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" + " 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" - "uniform float scale;\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" + " 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" @@ -357,26 +411,11 @@ 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); -//} - - 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); } Playback3D::~Playback3D() @@ -402,10 +441,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,65 +504,68 @@ void Playback3D::copy_from(Canvas *canvas, void Playback3D::copy_from_sync(Playback3DCommand *command) { #ifdef HAVE_GL - BC_WindowBase *window = + BC_WindowBase *window = command->canvas->lock_canvas("Playback3D::copy_from_sync"); if( window ) { window->enable_opengl(); + glFinish(); + int copy_to_ram = 0; int w = command->input->get_w(); int h = command->input->get_h(); - - if(command->input->get_opengl_state() == VFrame::SCREEN && - w == command->frame->get_w() && h == command->frame->get_h()) - { + if( command->input->get_opengl_state() == VFrame::SCREEN && + w == command->frame->get_w() && h == command->frame->get_h() ) { // printf("Playback3D::copy_from_sync 1 %d %d %d %d %d\n", -// command->input->get_w(), -// command->input->get_h(), -// command->frame->get_w(), -// command->frame->get_h(), +// command->input->get_w(), command->input->get_h(), +// command->frame->get_w(), command->frame->get_h(), // command->frame->get_color_model()); -// With NVidia at least, - if(w % 4) - { +#ifdef GLx4 +// With NVidia at least + if(w % 4) { printf("Playback3D::copy_from_sync: w=%d not supported because it is not divisible by 4.\n", w); } else +#endif // Copy to texture - if(command->want_texture) - { + if( command->want_texture ) { //printf("Playback3D::copy_from_sync 1 dst=%p src=%p\n", command->frame, command->input); // Screen_to_texture requires the source pbuffer enabled. command->input->enable_opengl(); command->frame->screen_to_texture(); command->frame->set_opengl_state(VFrame::TEXTURE); } - else -// Copy to RAM - { + else { 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); + copy_to_ram = 1; } } - else - { + else if( command->input->get_opengl_state() == VFrame::TEXTURE && + w == command->frame->get_w() && h == command->frame->get_h() ) { + copy_to_ram = 1; + } + else { printf("Playback3D::copy_from_sync: invalid formats opengl_state=%d %dx%d -> %dx%d\n", command->input->get_opengl_state(), w, h, command->frame->get_w(), command->frame->get_h()); } + + if( copy_to_ram ) { + 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); + } } command->canvas->unlock_canvas(); #endif @@ -641,35 +679,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, 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: - 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; + int frame_state = command->frame->get_opengl_state(); + 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(); @@ -704,7 +728,11 @@ 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); + int color = command->canvas->get_clear_color(); + int r = (color>>16) & 0xff; // always rgb + int g = (color>>8) & 0xff; + int b = (color>>0) & 0xff; + color_frame(command, r/255.f, g/255.f, b/255.f, 0.f); } // Texture @@ -734,14 +762,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); @@ -752,38 +774,16 @@ 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 } -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 - BC_WindowBase *window = - command->canvas->lock_canvas("Playback3D::finish_output_sync"); - if( window ) { - command->canvas->get_canvas()->enable_opengl(); - glFinish(); - } - command->canvas->unlock_canvas(); -#endif -} - - void Playback3D::clear_output(Canvas *canvas, VFrame *output) { Playback3DCommand command; @@ -802,14 +802,24 @@ 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(); + command->frame->set_opengl_state(VFrame::SCREEN); + 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); + else + color = command->canvas->get_clear_color(); + 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 @@ -1149,33 +1159,144 @@ 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(); + void unset_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); +} + +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); } -#endif +void fb_texture::read_screen(int x, int y, int w, int h) +{ + bind(1); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glReadBuffer(GL_BACK); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0,0, x,y, w,h); +} + +void fb_texture::set_output_texture() +{ + GLenum at = GL_COLOR_ATTACHMENT0; + glFramebufferTexture(GL_FRAMEBUFFER, at, get_texture_id(), 0); + GLenum dbo[1] = { at, }; // 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; + } +} +void fb_texture::unset_output_texture() +{ + glDrawBuffers(0, 0); + int at = GL_COLOR_ATTACHMENT0; + glFramebufferTexture(GL_FRAMEBUFFER, at, 0, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glDisable(GL_TEXTURE_2D); +} + + +class zglTessData : public ArrayList +{ +public: + zglTessData() { set_array_delete(); } + ~zglTessData() { remove_all_objects(); } +}; + +static void combineData(GLdouble coords[3], + GLdouble *vertex_data[4], GLfloat weight[4], + GLdouble **outData, void *data) +{ + zglTessData *invented = (zglTessData *)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 ) { + 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; +} + +// dbug +static void zglBegin(GLenum mode) { glBegin(mode); } +static void zglEnd() { glEnd(); } +static void zglVertex(const GLdouble *v) { glVertex3dv(v); } + +#endif void Playback3D::do_mask_sync(Playback3DCommand *command) { @@ -1187,7 +1308,7 @@ void Playback3D::do_mask_sync(Playback3DCommand *command) switch( command->frame->get_opengl_state() ) { case VFrame::RAM: -// Time to upload to the texture +// upload frame to the texture command->frame->to_texture(); break; @@ -1198,248 +1319,171 @@ void Playback3D::do_mask_sync(Playback3DCommand *command) 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], cc = 1; + 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); - 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); - - 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]; - - 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; - float 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; - - // 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) - { - GLdouble *coord = new GLdouble[3]; - coord[0] = x / scale; - coord[1] = -h + y / scale; - coord[2] = 0; - coords.append(coord); - 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(); + command->start_position_project, PLAY_FORWARD); + int show_mask = command->keyframe_set->track->masks; + + for(int k = 0; k < total_submasks; 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( + command->start_position_project, k, PLAY_FORWARD); + float v = fader/100.; + faders[k] = v; + float feather = command->keyframe_set->get_feather( + command->start_position_project, k, PLAY_FORWARD); + feathers[k] = feather; + MaskEdge &edge = *edges.append(new MaskEdge()); + if( !v || !((show_mask>>k) & 1) || !points.size() ) continue; + edge.load(point_set[k], h); + if( v >= 0 ) continue; + float vv = 1 + v; + if( cc > vv ) cc = vv; } - 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); + fb_texture *mask = new fb_texture(w, h, color_model); + mask->set_output_texture(); + glClearColor(cc, cc, cc, cc); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + mask->unset_output_texture(); + + unsigned int feather_shader = + VFrame::make_shader(0, in_vertex_frag, feather_frag, 0); + unsigned int max_shader = + VFrame::make_shader(0, in_vertex_frag, max_frag, 0); + if( feather_shader && max_shader ) { + fb_texture *in = new fb_texture(w, h, color_model); + fb_texture *out = new fb_texture(w, h, color_model); + float tw = 1./out->get_texture_w(), th = 1./out->get_texture_h(); + float tw1 = (w-1)*tw, th1 = (h-1)*th; + for(int k = 0; k < total_submasks; k++) { + MaskEdge &edge = *edges[k]; + if( edge.size() < 3 ) continue; + float r = feathers[k], v = faders[k]; + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glActiveTexture(GL_TEXTURE0); + glDisable(GL_TEXTURE_2D); + float b = r>=0 ? 0. : 1.; + float f = r>=0 ? 1. : 0.; + glClearColor(b, b, b, b); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glColor4f(f, f, f, f); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + int display_list = glGenLists(1); +#if 0 + glNewList(display_list, GL_COMPILE); + glBegin(GL_POLYGON); + MaskCoord *c = &edge[0]; + for( int i=edge.size(); --i>=0; ++c ) + glVertex2f(c->x, c->y); + glEnd(); + glEndList(); + glCallList(display_list); +#else + { zglTessData invented; + GLUtesselator *tess = gluNewTess(); + gluTessProperty(tess, GLU_TESS_TOLERANCE, 0.5); + gluTessCallback(tess, GLU_TESS_VERTEX,(GLvoid (*)()) &zglVertex); + gluTessCallback(tess, GLU_TESS_BEGIN,(GLvoid (*)()) &zglBegin); + gluTessCallback(tess, GLU_TESS_END,(GLvoid (*)()) &zglEnd); + gluTessCallback(tess, GLU_TESS_COMBINE_DATA,(GLvoid (*)()) &combineData); + glNewList(display_list, GL_COMPILE); + 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); + glEndList(); + glCallList(display_list); + gluDeleteTess(tess); } +#endif + glDeleteLists(1, display_list); + in->read_screen(0,0, w,h); +//in->write_tex("/tmp/in0.ppm"); + if( r ) { + double sig2 = -log(255.0)/(r*r); + int n = abs((int)r) + 1; + if( n > MAX_FEATHER+1 ) n = MAX_FEATHER+1; + float psf[n]; // point spot fn + for( int i=0; ibind(0); + out->set_output_texture(); + out->draw_texture(0,0, w,h, 0,0, w,h); + out->unset_output_texture(); +//out->write_tex("/tmp/out1.ppm"); + fb_texture *t = in; in = out; out = t; + glUniform2f(glGetUniformLocation(feather_shader, "dxy"), 0., th); + in->bind(0); + out->set_output_texture(); + out->draw_texture(0,0, w,h, 0,0, w,h); + out->unset_output_texture(); +//out->write_tex("/tmp/out2.ppm"); + glUseProgram(0); + t = in; in = out; out = t; + } -// 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; + glUseProgram(max_shader); + in->bind(0); +//in->write_tex("/tmp/in1.ppm"); +//mask->write_tex("/tmp/mask1.ppm"); + mask->bind(1); + glUniform1i(glGetUniformLocation(max_shader, "tex"), 0); + glUniform1i(glGetUniformLocation(max_shader, "tex1"), 1); + glUniform1f(glGetUniformLocation(max_shader, "r"), r); + glUniform1f(glGetUniformLocation(max_shader, "v"), v); + glViewport(0,0, w,h); + out->set_output_texture(); + out->draw_texture(0,0, w,h, 0,0, w,h); + out->unset_output_texture(); + glUseProgram(0); + fb_texture *t = mask; mask = out; out = t; +//mask->write_tex("/tmp/mask2.ppm"); + } + delete in; + delete out; } - 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); + 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); + mask->BC_Texture::bind(1); + glUniform1i(glGetUniformLocation(shader, "tex"), 0); + glUniform1i(glGetUniformLocation(shader, "tex1"), 1); } - - - -// Write texture to PBuffer with multiply and scaling for feather. - - - command->frame->draw_texture(0, 0, w, h, 0, 0, w, h); + command->frame->draw_texture(); command->frame->set_opengl_state(VFrame::SCREEN); - - -// Disable temp texture glUseProgram(0); - - glActiveTexture(GL_TEXTURE1); - glDisable(GL_TEXTURE_2D); - delete temp_texture; - temp_texture = 0; - + delete mask; + glColor4f(1, 1, 1, 1); glActiveTexture(GL_TEXTURE0); glDisable(GL_TEXTURE_2D); - -// Default drawable window->enable_opengl(); } command->canvas->unlock_canvas(); @@ -1447,14 +1491,6 @@ void Playback3D::do_mask_sync(Playback3DCommand *command) } - - - - - - - - void Playback3D::convert_cmodel(Canvas *canvas, VFrame *output, int dst_cmodel) @@ -1488,7 +1524,7 @@ void Playback3D::convert_cmodel(Canvas *canvas, void Playback3D::convert_cmodel_sync(Playback3DCommand *command) { #ifdef HAVE_GL - BC_WindowBase *window = + BC_WindowBase *window = command->canvas->lock_canvas("Playback3D::convert_cmodel_sync"); if( window ) { window->enable_opengl(); @@ -1678,7 +1714,7 @@ int Playback3D::run_plugin(Canvas *canvas, PluginClient *client) void Playback3D::run_plugin_sync(Playback3DCommand *command) { - BC_WindowBase *window = + BC_WindowBase *window = command->canvas->lock_canvas("Playback3D::run_plugin_sync"); if( window ) { window->enable_opengl();