#include "pluginclient.h"
#include "pluginvclient.h"
#include "edlsession.h"
+#include "track.h"
#include "transportque.inc"
#include "vframe.h"
" 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"
+// 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<len; ++i ) {\n"
+ " float dx = float(points[i].x) - gl_FragCoord.x;\n"
+ " float dy = float(points[i].y) - gl_FragCoord.y;\n"
+ " float dd = dx*dx + dy*dy;\n"
+ " if( dd >= 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_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"
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()
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;
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();
command->input->get_opengl_state(), w, h,
command->frame->get_w(), command->frame->get_h());
}
-
- window->unlock_window();
}
command->canvas->unlock_canvas();
#endif
//
// 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
// (int)(command->in_y2 - command->in_y1),
// 0);
//
-// window->unlock_window();
// }
// command->canvas->unlock_canvas();
+// #endif
// }
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 ) {
+ 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);
- window->unlock_window();
}
-
command->canvas->unlock_canvas();
+#endif
}
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
//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);
}
-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
- 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;
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;
-
+ int color = BLACK, alpha = 0;
// Using pbuffer for refresh frame.
- if(command->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);
- command->canvas->get_canvas()->unlock_window();
+ 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
}
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,
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();
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,
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();
}
glActiveTexture(GL_TEXTURE0);
glDisable(GL_TEXTURE_2D);
-
- window->unlock_window();
}
command->canvas->unlock_canvas();
#endif
}
+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<Vertex>
+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> *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<double *> *invented = (ArrayList<double *> *)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 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);
+ MaskEdges edges;
+ float faders[SUBMASKS], feathers[SUBMASKS], bg = 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);
+
+ 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;
+ 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);
+ int show_mask = command->keyframe_set->track->masks;
+ for(int k = 0; k < total_submasks; k++) {
+ MaskEdge &edge = *edges.append(new MaskEdge());
+ if( !((show_mask>>k) & 1) ) continue;
+ edge.load(point_set[k], h);
+ 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<double *> 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);
+ }
+ }
-// 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<Vertex>;
-
-
-// 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<MaskPoint*> *points = new ArrayList<MaskPoint*>;
- 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<GLdouble*> 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;
- }
+// 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; i<edge.size(); ++i ) {
+ MaskCoord &a = edge[i];
+ MaskCoord &b = i<edge.size()-1 ? edge[i+1] : edge[0];
+ draw_spots(spots, a.x,a.y+h, b.x,b.y+h);
}
+ int sz = spots.size() * sizeof(MaskSpot);
+ glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 0, points[0], 0, sz);
+ glBufferData(GL_SHADER_STORAGE_BUFFER, sz, &spots[0], GL_DYNAMIC_COPY);
+ glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
+ glUseProgram(frag_shader);
+ float r = feathers[k], v = faders[k];
+ glUniform1f(glGetUniformLocation(frag_shader, "r"), r);
+ glUniform1f(glGetUniformLocation(frag_shader, "v"), v);
+ in->bind(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;
}
-
-// 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();
+ glDeleteBuffers(1, points);
}
- 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);
+ glDrawBuffers(0, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 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( 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);
+ in->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);
+ 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)
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
if(shader) glUseProgram(0);
command->frame->set_opengl_state(VFrame::SCREEN);
}
-
- window->unlock_window();
}
command->canvas->unlock_canvas();
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);
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;
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();
}