r870: Merge 2.1:
[cinelerra_cv.git] / cinelerra / playback3d.C
blob2b5d47e87a7fb4111096f183a067e7f51179daae
1 #define GL_GLEXT_PROTOTYPES
3 #include "bcsignals.h"
4 #include "bcwindowbase.h"
5 #include "canvas.h"
6 #include "clip.h"
7 #include "condition.h"
8 #include "maskautos.h"
9 #include "maskauto.h"
10 #include "mutex.h"
11 #include "overlayframe.inc"
12 #include "playback3d.h"
13 #include "pluginclient.h"
14 #include "pluginvclient.h"
15 #include "transportque.inc"
16 #include "vframe.h"
18 #if defined(HAVE_CONFIG_H)
19 #include "config.h"
20 #endif
22 #ifdef HAVE_GL
23 #include <GL/gl.h>
24 #include <GL/glext.h>
25 #include <GL/glu.h>
26 #endif
28 #include <string.h>
29 #include <unistd.h>
32 // Shaders
33 // These should be passed to VFrame::make_shader to construct shaders.
34 // Can't hard code sampler2D
36 static char *yuv_to_rgb_frag = 
37         "uniform sampler2D tex;\n"
38         "void main()\n"
39         "{\n"
40         "       vec3 yuv = vec3(texture2D(tex, gl_TexCoord[0].st));\n"
41         "   yuv -= vec3(0, 0.5, 0.5);\n"
42         "       const mat3 yuv_to_rgb_matrix = mat3(\n"
43         "               1,       1,        1, \n"
44         "               0,       -0.34414, 1.77200, \n"
45         "               1.40200, -0.71414, 0);\n"
46         "       gl_FragColor = vec4(yuv_to_rgb_matrix * yuv, 1);\n"
47         "}\n";
49 static char *yuva_to_rgba_frag = 
50         "uniform sampler2D tex;\n"
51         "void main()\n"
52         "{\n"
53         "       vec4 yuva = texture2D(tex, gl_TexCoord[0].st);\n"
54         "       yuva.rgb -= vec3(0, 0.5, 0.5);\n"
55         "       const mat3 yuv_to_rgb_matrix = mat3(\n"
56         "               1,       1,        1, \n"
57         "               0,       -0.34414, 1.77200, \n"
58         "               1.40200, -0.71414, 0);\n"
59         "       gl_FragColor = vec4(yuv_to_rgb_matrix * yuva.rgb, yuva.a);\n"
60         "}\n";
62 static char *blend_add_frag = 
63         "uniform sampler2D tex2;\n"
64         "uniform vec2 tex2_dimensions;\n"
65         "void main()\n"
66         "{\n"
67         "       vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
68         "       vec3 opacity = vec3(gl_FragColor.a, gl_FragColor.a, gl_FragColor.a);\n"
69         "       vec3 transparency = vec3(1.0, 1.0, 1.0) - opacity;\n"
70         "       gl_FragColor.rgb += canvas.rgb;\n"
71         "       gl_FragColor.rgb *= opacity;\n"
72         "       gl_FragColor.rgb += canvas.rgb * transparency;\n"
73         "       gl_FragColor.a = max(gl_FragColor.a, canvas.a);\n"
74         "}\n";
76 static char *blend_max_frag = 
77         "uniform sampler2D tex2;\n"
78         "uniform vec2 tex2_dimensions;\n"
79         "void main()\n"
80         "{\n"
81         "       vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
82         "       vec3 opacity = vec3(gl_FragColor.a, gl_FragColor.a, gl_FragColor.a);\n"
83         "       vec3 transparency = vec3(1.0, 1.0, 1.0) - opacity;\n"
84         "       gl_FragColor.r = max(canvas.r, gl_FragColor.r);\n"
85         "       gl_FragColor.g = max(canvas.g, gl_FragColor.g);\n"
86         "       gl_FragColor.b = max(canvas.b, gl_FragColor.b);\n"
87         "       gl_FragColor.rgb *= opacity;\n"
88         "       gl_FragColor.rgb += canvas.rgb * transparency;\n"
89         "       gl_FragColor.a = max(gl_FragColor.a, canvas.a);\n"
90         "}\n";
92 static char *blend_subtract_frag = 
93         "uniform sampler2D tex2;\n"
94         "uniform vec2 tex2_dimensions;\n"
95         "void main()\n"
96         "{\n"
97         "       vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
98         "       vec3 opacity = vec3(gl_FragColor.a, gl_FragColor.a, gl_FragColor.a);\n"
99         "       vec3 transparency = vec3(1.0, 1.0, 1.0) - opacity;\n"
100         "       gl_FragColor.rgb = canvas.rgb - gl_FragColor.rgb;\n"
101         "       gl_FragColor.rgb *= opacity;\n"
102         "       gl_FragColor.rgb += canvas.rgb * transparency;\n"
103         "       gl_FragColor.a = max(gl_FragColor.a, canvas.a);\n"
104         "}\n";
106 static char *blend_multiply_frag = 
107         "uniform sampler2D tex2;\n"
108         "uniform vec2 tex2_dimensions;\n"
109         "void main()\n"
110         "{\n"
111         "       vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
112         "       vec3 opacity = vec3(gl_FragColor.a, gl_FragColor.a, gl_FragColor.a);\n"
113         "       vec3 transparency = vec3(1.0, 1.0, 1.0) - opacity;\n"
114         "       gl_FragColor.rgb *= canvas.rgb;\n"
115         "       gl_FragColor.rgb *= opacity;\n"
116         "       gl_FragColor.rgb += canvas.rgb * transparency;\n"
117         "       gl_FragColor.a = max(gl_FragColor.a, canvas.a);\n"
118         "}\n";
120 static char *blend_divide_frag = 
121         "uniform sampler2D tex2;\n"
122         "uniform vec2 tex2_dimensions;\n"
123         "void main()\n"
124         "{\n"
125         "       vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
126         "       vec3 opacity = vec3(gl_FragColor.a, gl_FragColor.a, gl_FragColor.a);\n"
127         "       vec3 transparency = vec3(1.0, 1.0, 1.0) - opacity;\n"
128         "       vec3 result = canvas.rgb / gl_FragColor.rgb;\n"
129         "       if(!gl_FragColor.r) result.r = 1.0;\n"
130         "       if(!gl_FragColor.g) result.g = 1.0;\n"
131         "       if(!gl_FragColor.b) result.b = 1.0;\n"
132         "       result *= opacity;\n"
133         "       result += canvas.rgb * transparency;\n"
134         "       gl_FragColor = vec4(result, max(gl_FragColor.a, canvas.a));\n"
135         "}\n";
137 static char *multiply_alpha_frag = 
138         "void main()\n"
139         "{\n"
140         "       gl_FragColor.rgb *= vec3(gl_FragColor.a, gl_FragColor.a, gl_FragColor.a);\n"
141         "}\n";
143 static char *read_texture_frag = 
144         "uniform sampler2D tex;\n"
145         "void main()\n"
146         "{\n"
147         "       gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
148         "}\n";
150 static char *multiply_mask4_frag = 
151         "uniform sampler2D tex;\n"
152         "uniform sampler2D tex1;\n"
153         "uniform float scale;\n"
154         "void main()\n"
155         "{\n"
156         "       gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
157         "       gl_FragColor.a *= texture2D(tex1, gl_TexCoord[0].st / vec2(scale, scale)).r;\n"
158         "}\n";
160 static char *multiply_mask3_frag = 
161         "uniform sampler2D tex;\n"
162         "uniform sampler2D tex1;\n"
163         "uniform float scale;\n"
164         "uniform bool is_yuv;\n"
165         "void main()\n"
166         "{\n"
167         "       gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
168         "   float a = texture2D(tex1, gl_TexCoord[0].st / vec2(scale, scale)).r;\n"
169         "       gl_FragColor.rgb *= vec3(a, a, a);\n"
170         "}\n";
172 static char *multiply_yuvmask3_frag = 
173         "uniform sampler2D tex;\n"
174         "uniform sampler2D tex1;\n"
175         "uniform float scale;\n"
176         "void main()\n"
177         "{\n"
178         "       gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
179         "   float a = texture2D(tex1, gl_TexCoord[0].st / vec2(scale, scale)).r;\n"
180         "       gl_FragColor.gb -= vec2(0.5, 0.5);\n"
181         "       gl_FragColor.rgb *= vec3(a, a, a);\n"
182         "       gl_FragColor.gb += vec2(0.5, 0.5);\n"
183         "}\n";
185 static char *fade_rgba_frag =
186         "uniform sampler2D tex;\n"
187         "uniform float alpha;\n"
188         "void main()\n"
189         "{\n"
190         "       gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
191         "       gl_FragColor.a *= alpha;\n"
192         "}\n";
194 static char *fade_yuv_frag =
195         "uniform sampler2D tex;\n"
196         "uniform float alpha;\n"
197         "void main()\n"
198         "{\n"
199         "       gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
200         "       gl_FragColor.r *= alpha;\n"
201         "       gl_FragColor.gb -= vec2(0.5, 0.5);\n"
202         "       gl_FragColor.g *= alpha;\n"
203         "       gl_FragColor.b *= alpha;\n"
204         "       gl_FragColor.gb += vec2(0.5, 0.5);\n"
205         "}\n";
214 Playback3DCommand::Playback3DCommand()
215  : BC_SynchronousCommand()
217         canvas = 0;
220 void Playback3DCommand::copy_from(BC_SynchronousCommand *command)
222         Playback3DCommand *ptr = (Playback3DCommand*)command;
223         this->canvas = ptr->canvas;
224         this->is_cleared = ptr->is_cleared;
226         this->in_x1 = ptr->in_x1;
227         this->in_y1 = ptr->in_y1;
228         this->in_x2 = ptr->in_x2;
229         this->in_y2 = ptr->in_y2;
230         this->out_x1 = ptr->out_x1;
231         this->out_y1 = ptr->out_y1;
232         this->out_x2 = ptr->out_x2;
233         this->out_y2 = ptr->out_y2;
234         this->alpha = ptr->alpha;
235         this->mode = ptr->mode;
236         this->interpolation_type = ptr->interpolation_type;
238         this->input = ptr->input;
239         this->start_position_project = ptr->start_position_project;
240         this->keyframe_set = ptr->keyframe_set;
241         this->keyframe = ptr->keyframe;
242         this->default_auto = ptr->default_auto;
243         this->plugin_client = ptr->plugin_client;
244         this->want_texture = ptr->want_texture;
246         BC_SynchronousCommand::copy_from(command);
252 Playback3D::Playback3D(MWindow *mwindow)
253  : BC_Synchronous()
255         this->mwindow = mwindow;
256         temp_texture = 0;
259 Playback3D::~Playback3D()
266 BC_SynchronousCommand* Playback3D::new_command()
268         return new Playback3DCommand;
273 void Playback3D::handle_command(BC_SynchronousCommand *command)
275 //printf("Playback3D::handle_command 1 %d\n", command->command);
276         switch(command->command)
277         {
278                 case Playback3DCommand::WRITE_BUFFER:
279                         write_buffer_sync((Playback3DCommand*)command);
280                         break;
282                 case Playback3DCommand::CLEAR_OUTPUT:
283                         clear_output_sync((Playback3DCommand*)command);
284                         break;
286                 case Playback3DCommand::CLEAR_INPUT:
287                         clear_input_sync((Playback3DCommand*)command);
288                         break;
290                 case Playback3DCommand::DO_CAMERA:
291                         do_camera_sync((Playback3DCommand*)command);
292                         break;
294                 case Playback3DCommand::OVERLAY:
295                         overlay_sync((Playback3DCommand*)command);
296                         break;
298                 case Playback3DCommand::DO_FADE:
299                         do_fade_sync((Playback3DCommand*)command);
300                         break;
302                 case Playback3DCommand::DO_MASK:
303                         do_mask_sync((Playback3DCommand*)command);
304                         break;
306                 case Playback3DCommand::PLUGIN:
307                         run_plugin_sync((Playback3DCommand*)command);
308                         break;
310                 case Playback3DCommand::COPY_FROM:
311                         copy_from_sync((Playback3DCommand*)command);
312                         break;
314 //              case Playback3DCommand::DRAW_REFRESH:
315 //                      draw_refresh_sync((Playback3DCommand*)command);
316 //                      break;
317         }
318 //printf("Playback3D::handle_command 10\n");
324 void Playback3D::copy_from(Canvas *canvas, 
325         VFrame *dst,
326         VFrame *src,
327         int want_texture)
329         Playback3DCommand command;
330         command.command = Playback3DCommand::COPY_FROM;
331         command.canvas = canvas;
332         command.frame = dst;
333         command.input = src;
334         command.want_texture = want_texture;
335         send_command(&command);
338 void Playback3D::copy_from_sync(Playback3DCommand *command)
340 #ifdef HAVE_GL
341         command->canvas->lock_canvas("Playback3D::draw_refresh_sync");
342         BC_WindowBase *window = command->canvas->get_canvas();
343         if(window)
344         {
345                 window->lock_window("Playback3D:draw_refresh_sync");
346                 window->enable_opengl();
348                 if(command->input->get_opengl_state() == VFrame::SCREEN &&
349                         command->input->get_w() == command->frame->get_w() &&
350                         command->input->get_h() == command->frame->get_h())
351                 {
352 // printf("Playback3D::copy_from_sync 1 %d %d %d %d %d\n", 
353 // command->input->get_w(),
354 // command->input->get_h(),
355 // command->frame->get_w(),
356 // command->frame->get_h(),
357 // command->frame->get_color_model());
358                         int w = command->input->get_w();
359                         int h = command->input->get_h();
360 // With NVidia at least,
361                         if(command->input->get_w() % 4)
362                         {
363                                 printf("Playback3D::copy_from_sync: w=%d not supported because it is not divisible by 4.\n", w);
364                         }
365                         else
366 // Copy to texture
367                         if(command->want_texture)
368                         {
369 //printf("Playback3D::copy_from_sync 1 dst=%p src=%p\n", command->frame, command->input);
370 // Screen_to_texture requires the source pbuffer enabled.
371                                 command->input->enable_opengl();
372                                 command->frame->screen_to_texture();
373                                 command->frame->set_opengl_state(VFrame::TEXTURE);
374                         }
375                         else
376 // Copy to RAM
377                         {
378                                 command->input->enable_opengl();
379                                 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
380                                 glReadPixels(0,
381                                         0,
382                                         w,
383                                         command->input->get_h(),
384                                         GL_RGB,
385                                         GL_UNSIGNED_BYTE,
386                                         command->frame->get_rows()[0]);
387                                 command->frame->flip_vert();
388                                 command->frame->set_opengl_state(VFrame::RAM);
389                         }
390                 }
391                 else
392                 {
393                         printf("Playback3D::copy_from_sync: invalid formats opengl_state=%d %dx%d -> %dx%d\n",
394                                 command->input->get_opengl_state(),
395                                 command->input->get_w(),
396                                 command->input->get_h(),
397                                 command->frame->get_w(),
398                                 command->frame->get_h());
399                 }
401                 window->unlock_window();
402         }
403         command->canvas->unlock_canvas();
404 #endif
410 // void Playback3D::draw_refresh(Canvas *canvas, 
411 //      VFrame *frame,
412 //      float in_x1, 
413 //      float in_y1, 
414 //      float in_x2, 
415 //      float in_y2, 
416 //      float out_x1, 
417 //      float out_y1, 
418 //      float out_x2, 
419 //      float out_y2)
420 // {
421 //      Playback3DCommand command;
422 //      command.command = Playback3DCommand::DRAW_REFRESH;
423 //      command.canvas = canvas;
424 //      command.frame = frame;
425 //      command.in_x1 = in_x1;
426 //      command.in_y1 = in_y1;
427 //      command.in_x2 = in_x2;
428 //      command.in_y2 = in_y2;
429 //      command.out_x1 = out_x1;
430 //      command.out_y1 = out_y1;
431 //      command.out_x2 = out_x2;
432 //      command.out_y2 = out_y2;
433 //      send_command(&command);
434 // }
435 // 
436 // void Playback3D::draw_refresh_sync(Playback3DCommand *command)
437 // {
438 //      command->canvas->lock_canvas("Playback3D::draw_refresh_sync");
439 //      BC_WindowBase *window = command->canvas->get_canvas();
440 //      if(window)
441 //      {
442 //              window->lock_window("Playback3D:draw_refresh_sync");
443 //              window->enable_opengl();
444 // 
445 // // Read output pbuffer back to RAM in project colormodel
446 // // RGB 8bit is fastest for OpenGL to read back.
447 //              command->frame->reallocate(0, 
448 //                      0,
449 //                      0,
450 //                      0,
451 //                      command->frame->get_w(), 
452 //                      command->frame->get_h(), 
453 //                      BC_RGB888, 
454 //                      -1);
455 //              command->frame->to_ram();
456 // 
457 //              window->clear_box(0, 
458 //                                              0, 
459 //                                              window->get_w(), 
460 //                                              window->get_h());
461 //              window->draw_vframe(command->frame,
462 //                                                      (int)command->out_x1, 
463 //                                                      (int)command->out_y1, 
464 //                                                      (int)(command->out_x2 - command->out_x1), 
465 //                                                      (int)(command->out_y2 - command->out_y1),
466 //                                                      (int)command->in_x1, 
467 //                                                      (int)command->in_y1, 
468 //                                                      (int)(command->in_x2 - command->in_x1), 
469 //                                                      (int)(command->in_y2 - command->in_y1),
470 //                                                      0);
471 // 
472 //              window->unlock_window();
473 //      }
474 //      command->canvas->unlock_canvas();
475 // }
481 void Playback3D::write_buffer(Canvas *canvas, 
482         VFrame *frame,
483         float in_x1, 
484         float in_y1, 
485         float in_x2, 
486         float in_y2, 
487         float out_x1, 
488         float out_y1, 
489         float out_x2, 
490         float out_y2, 
491         int is_cleared)
493         Playback3DCommand command;
494         command.command = Playback3DCommand::WRITE_BUFFER;
495         command.canvas = canvas;
496         command.frame = frame;
497         command.in_x1 = in_x1;
498         command.in_y1 = in_y1;
499         command.in_x2 = in_x2;
500         command.in_y2 = in_y2;
501         command.out_x1 = out_x1;
502         command.out_y1 = out_y1;
503         command.out_x2 = out_x2;
504         command.out_y2 = out_y2;
505         command.is_cleared = is_cleared;
506         send_command(&command);
510 void Playback3D::write_buffer_sync(Playback3DCommand *command)
512         command->canvas->lock_canvas("Playback3D::write_buffer_sync");
513         if(command->canvas->get_canvas())
514         {
515                 BC_WindowBase *window = command->canvas->get_canvas();
516                 window->lock_window("Playback3D::write_buffer_sync");
517 // Update hidden cursor
518                 window->update_video_cursor();
519 // Make sure OpenGL is enabled first.
520                 window->enable_opengl();
523 //printf("Playback3D::write_buffer_sync 1 %d\n", window->get_id());
524                 switch(command->frame->get_opengl_state())
525                 {
526 // Upload texture and composite to screen
527                         case VFrame::RAM:
528                                 command->frame->to_texture();
529                                 draw_output(command);
530                                 break;
531 // Composite texture to screen and swap buffer
532                         case VFrame::TEXTURE:
533                                 draw_output(command);
534                                 break;
535                         case VFrame::SCREEN:
536 // swap buffers only
537                                 window->flip_opengl();
538                                 break;
539                         default:
540                                 printf("Playback3D::write_buffer_sync unknown state\n");
541                                 break;
542                 }
543                 window->unlock_window();
544         }
546         command->canvas->unlock_canvas();
551 void Playback3D::draw_output(Playback3DCommand *command)
553 #ifdef HAVE_GL
554         int texture_id = command->frame->get_texture_id();
555         BC_WindowBase *window = command->canvas->get_canvas();
557 // printf("Playback3D::draw_output 1 texture_id=%d window=%p\n", 
558 // texture_id,
559 // command->canvas->get_canvas());
564 // If virtual console is being used, everything in this function has
565 // already been done except the page flip.
566         if(texture_id >= 0)
567         {
568                 canvas_w = window->get_w();
569                 canvas_h = window->get_h();
570                 VFrame::init_screen(canvas_w, canvas_h);
572                 if(!command->is_cleared)
573                 {
574 // If we get here, the virtual console was not used.
575                         init_frame(command);
576                 }
578 // Texture
579 // Undo any previous shader settings
580                 command->frame->bind_texture(0);
585 // Convert colormodel
586                 unsigned int frag_shader = 0;
587                 switch(command->frame->get_color_model())
588                 {
589                         case BC_YUV888:
590                                 frag_shader = VFrame::make_shader(0,
591                                         yuv_to_rgb_frag,
592                                         0);
593                                 break;
595                         case BC_YUVA8888:
596                                 frag_shader = VFrame::make_shader(0,
597                                         yuva_to_rgba_frag,
598                                         0);
599                                 break;
600                 }
603                 if(frag_shader > 0) 
604                 {
605                         glUseProgram(frag_shader);
606                         int variable = glGetUniformLocation(frag_shader, "tex");
607 // Set texture unit of the texture
608                         glUniform1i(variable, 0);
609                 }
611                 if(cmodel_components(command->frame->get_color_model()) == 4)
612                 {
613                         glEnable(GL_BLEND);
614                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
615                 }
617                 command->frame->draw_texture(command->in_x1, 
618                         command->in_y1,
619                         command->in_x2,
620                         command->in_y2,
621                         command->out_x1,
622                         command->out_y1,
623                         command->out_x2,
624                         command->out_y2,
625                         1);
628 // printf("Playback3D::draw_output 2 %f,%f %f,%f -> %f,%f %f,%f\n",
629 // command->in_x1,
630 // command->in_y1,
631 // command->in_x2,
632 // command->in_y2,
633 // command->out_x1,
634 // command->out_y1,
635 // command->out_x2,
636 // command->out_y2);
638                 glUseProgram(0);
640                 command->canvas->get_canvas()->flip_opengl();
641                 
642         }
643 #endif
647 void Playback3D::init_frame(Playback3DCommand *command)
649 #ifdef HAVE_GL
650         canvas_w = command->canvas->get_canvas()->get_w();
651         canvas_h = command->canvas->get_canvas()->get_h();
653         glClearColor(0.0, 0.0, 0.0, 0.0);
654         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
655 #endif
659 void Playback3D::clear_output(Canvas *canvas, VFrame *output)
661         Playback3DCommand command;
662         command.command = Playback3DCommand::CLEAR_OUTPUT;
663         command.canvas = canvas;
664         command.frame = output;
665         send_command(&command);
668 void Playback3D::clear_output_sync(Playback3DCommand *command)
670         command->canvas->lock_canvas("Playback3D::clear_output_sync");
671         if(command->canvas->get_canvas())
672         {
673                 command->canvas->get_canvas()->lock_window("Playback3D::clear_output_sync");
674 // If we get here, the virtual console is being used.
675                 command->canvas->get_canvas()->enable_opengl();
677 // Using pbuffer for refresh frame.
678                 if(command->frame)
679                 {
680                         command->frame->enable_opengl();
681                 }       
684                 init_frame(command);
685                 command->canvas->get_canvas()->unlock_window();
686         }
687         command->canvas->unlock_canvas();
691 void Playback3D::clear_input(Canvas *canvas, VFrame *frame)
693         Playback3DCommand command;
694         command.command = Playback3DCommand::CLEAR_INPUT;
695         command.canvas = canvas;
696         command.frame = frame;
697         send_command(&command);
700 void Playback3D::clear_input_sync(Playback3DCommand *command)
702         command->canvas->lock_canvas("Playback3D::clear_output_sync");
703         if(command->canvas->get_canvas())
704         {
705                 command->canvas->get_canvas()->lock_window("Playback3D::clear_output_sync");
706                 command->canvas->get_canvas()->enable_opengl();
707                 command->frame->enable_opengl();
708                 command->frame->clear_pbuffer();
709                 command->frame->set_opengl_state(VFrame::SCREEN);
710                 command->canvas->get_canvas()->unlock_window();
711         }
712         command->canvas->unlock_canvas();
715 void Playback3D::do_camera(Canvas *canvas,
716         VFrame *output,
717         VFrame *input,
718         float in_x1, 
719         float in_y1, 
720         float in_x2, 
721         float in_y2, 
722         float out_x1, 
723         float out_y1, 
724         float out_x2, 
725         float out_y2)
727         Playback3DCommand command;
728         command.command = Playback3DCommand::DO_CAMERA;
729         command.canvas = canvas;
730         command.input = input;
731         command.frame = output;
732         command.in_x1 = in_x1;
733         command.in_y1 = in_y1;
734         command.in_x2 = in_x2;
735         command.in_y2 = in_y2;
736         command.out_x1 = out_x1;
737         command.out_y1 = out_y1;
738         command.out_x2 = out_x2;
739         command.out_y2 = out_y2;
740         send_command(&command);
743 void Playback3D::do_camera_sync(Playback3DCommand *command)
745         command->canvas->lock_canvas("Playback3D::do_camera_sync");
746         if(command->canvas->get_canvas())
747         {
748                 command->canvas->get_canvas()->lock_window("Playback3D::clear_output_sync");
749                 command->canvas->get_canvas()->enable_opengl();
751                 command->input->to_texture();
752                 command->frame->enable_opengl();
753                 command->frame->init_screen();
754                 command->frame->clear_pbuffer();
756                 command->input->bind_texture(0);
757 // Must call draw_texture in input frame to get the texture coordinates right.
759 // printf("Playback3D::do_camera_sync 1 %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f\n", 
760 // command->in_x1, 
761 // command->in_y2, 
762 // command->in_x2, 
763 // command->in_y1, 
764 // command->out_x1,
765 // (float)command->input->get_h() - command->out_y1,
766 // command->out_x2,
767 // (float)command->input->get_h() - command->out_y2);
768                 command->input->draw_texture(
769                         command->in_x1, 
770                         command->in_y2, 
771                         command->in_x2, 
772                         command->in_y1, 
773                         command->out_x1,
774                         (float)command->frame->get_h() - command->out_y1,
775                         command->out_x2,
776                         (float)command->frame->get_h() - command->out_y2);
779                 command->frame->set_opengl_state(VFrame::SCREEN);
780                 command->canvas->get_canvas()->unlock_window();
781         }
782         command->canvas->unlock_canvas();
785 void Playback3D::overlay(Canvas *canvas,
786         VFrame *input, 
787         float in_x1, 
788         float in_y1, 
789         float in_x2, 
790         float in_y2, 
791         float out_x1, 
792         float out_y1, 
793         float out_x2, 
794         float out_y2, 
795         float alpha,        // 0 - 1
796         int mode,
797         int interpolation_type,
798         VFrame *output)
800         Playback3DCommand command;
801         command.command = Playback3DCommand::OVERLAY;
802         command.canvas = canvas;
803         command.frame = output;
804         command.input = input;
805         command.in_x1 = in_x1;
806         command.in_y1 = in_y1;
807         command.in_x2 = in_x2;
808         command.in_y2 = in_y2;
809         command.out_x1 = out_x1;
810         command.out_y1 = out_y1;
811         command.out_x2 = out_x2;
812         command.out_y2 = out_y2;
813         command.alpha = alpha;
814         command.mode = mode;
815         command.interpolation_type = interpolation_type;
816         send_command(&command);
819 void Playback3D::overlay_sync(Playback3DCommand *command)
821 #ifdef HAVE_GL
822         command->canvas->lock_canvas("Playback3D::overlay_sync");
823         if(command->canvas->get_canvas())
824         {
825                 BC_WindowBase *window = command->canvas->get_canvas();
826             window->lock_window("Playback3D::overlay_sync");
827 // Make sure OpenGL is enabled first.
828                 window->enable_opengl();
830                 window->update_video_cursor();
833 // Render to PBuffer
834                 if(command->frame)
835                 {
836                         command->frame->enable_opengl();
837                         command->frame->set_opengl_state(VFrame::SCREEN);
838                         canvas_w = command->frame->get_w();
839                         canvas_h = command->frame->get_h();
840                 }
841                 else
842                 {
843                         canvas_w = window->get_w();
844                         canvas_h = window->get_h();
845                 }
847                 glColor4f(1, 1, 1, 1);
849 //printf("Playback3D::overlay_sync 1 %d\n", command->input->get_opengl_state());
850                 switch(command->input->get_opengl_state())
851                 {
852 // Upload texture and composite to screen
853                         case VFrame::RAM:
854                                 command->input->to_texture();
855                                 break;
856 // Just composite texture to screen
857                         case VFrame::TEXTURE:
858                                 break;
859 // read from PBuffer to texture, then composite texture to screen
860                         case VFrame::SCREEN:
861                                 command->input->enable_opengl();
862                                 command->input->screen_to_texture();
863                                 if(command->frame)
864                                         command->frame->enable_opengl();
865                                 else
866                                         window->enable_opengl();
867                                 break;
868                         default:
869                                 printf("Playback3D::overlay_sync unknown state\n");
870                                 break;
871                 }
874                 char *shader_stack[3] = { 0, 0, 0 };
875                 int total_shaders = 0;
877                 VFrame::init_screen(canvas_w, canvas_h);
879 // Enable texture
880                 command->input->bind_texture(0);
883 // Convert colormodel.
884                 switch(command->input->get_color_model())
885                 {
886                         case BC_YUV888:
887                                 shader_stack[total_shaders++] = yuv_to_rgb_frag;
888                                 break;
889                         case BC_YUVA8888:
890                                 shader_stack[total_shaders++] = yuva_to_rgba_frag;
891                                 break;
892                 }
894 // Change blend operation
895                 switch(command->mode)
896                 {
897                         case TRANSFER_NORMAL:
898                                 glEnable(GL_BLEND);
899                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
900                                 break;
902                         case TRANSFER_REPLACE:
903 // This requires overlaying an alpha multiplied image on a black screen.
904                                 glDisable(GL_BLEND);
905                                 if(command->input->get_texture_components() == 4)
906                                 {
907                                         if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag;
908                                         shader_stack[total_shaders++] = multiply_alpha_frag;
909                                 }
910                                 break;
912 // To do these operations, we need to copy the input buffer to a texture
913 // and blend 2 textures in another shader
914                         case TRANSFER_ADDITION:
915                                 enable_overlay_texture(command);
916                                 if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag;
917                                 shader_stack[total_shaders++] = blend_add_frag;
918                                 break;
919                         case TRANSFER_SUBTRACT:
920                                 enable_overlay_texture(command);
921                                 if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag;
922                                 shader_stack[total_shaders++] = blend_subtract_frag;
923                                 break;
924                         case TRANSFER_MULTIPLY:
925                                 enable_overlay_texture(command);
926                                 if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag;
927                                 shader_stack[total_shaders++] = blend_multiply_frag;
928                                 break;
929                         case TRANSFER_MAX:
930                                 enable_overlay_texture(command);
931                                 if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag;
932                                 shader_stack[total_shaders++] = blend_max_frag;
933                                 break;
934                         case TRANSFER_DIVIDE:
935                                 enable_overlay_texture(command);
936                                 if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag;
937                                 shader_stack[total_shaders++] = blend_divide_frag;
938                                 break;
939                 }
941                 unsigned int frag_shader = 0;
942                 if(shader_stack[0]) 
943                 {
944                         frag_shader = VFrame::make_shader(0,
945                                 shader_stack[0],
946                                 shader_stack[1],
947                                 0);
949                         glUseProgram(frag_shader);
952 // Set texture unit of the texture
953                         glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0);
954 // Set texture unit of the temp texture
955                         glUniform1i(glGetUniformLocation(frag_shader, "tex2"), 1);
956 // Set dimensions of the temp texture
957                         if(temp_texture)
958                                 glUniform2f(glGetUniformLocation(frag_shader, "tex2_dimensions"), 
959                                         (float)temp_texture->get_texture_w(), 
960                                         (float)temp_texture->get_texture_h());
961                 }
962                 else
963                         glUseProgram(0);
970 // printf("Playback3D::overlay_sync %f %f %f %f %f %f %f %f\n",
971 // command->in_x1,
972 // command->in_y1,
973 // command->in_x2,
974 // command->in_y2,
975 // command->out_x1,
976 // command->out_y1,
977 // command->out_x2,
978 // command->out_y2);
983                 command->input->draw_texture(command->in_x1, 
984                         command->in_y1,
985                         command->in_x2,
986                         command->in_y2,
987                         command->out_x1,
988                         command->out_y1,
989                         command->out_x2,
990                         command->out_y2,
991                         1);
994                 glUseProgram(0);
997 // Delete temp texture
998                 if(temp_texture)
999                 {
1000                         delete temp_texture;
1001                         temp_texture = 0;
1002                         glActiveTexture(GL_TEXTURE1);
1003                         glDisable(GL_TEXTURE_2D);
1004                 }
1005                 glActiveTexture(GL_TEXTURE0);
1006                 glDisable(GL_TEXTURE_2D);
1010                 window->unlock_window();
1011         }
1012         command->canvas->unlock_canvas();
1013 #endif
1017 void Playback3D::enable_overlay_texture(Playback3DCommand *command)
1019 #ifdef HAVE_GL
1020         glDisable(GL_BLEND);
1022         glActiveTexture(GL_TEXTURE1);
1023         BC_Texture::new_texture(&temp_texture,
1024                 canvas_w, 
1025                 canvas_h, 
1026                 command->input->get_color_model());
1027         temp_texture->bind(1);
1029 // Read canvas into texture
1030         glReadBuffer(GL_BACK);
1031         glCopyTexSubImage2D(GL_TEXTURE_2D,
1032                 0,
1033                 0,
1034                 0,
1035                 0,
1036                 0,
1037                 canvas_w,
1038                 canvas_h);
1039 #endif
1043 void Playback3D::do_mask(Canvas *canvas,
1044         VFrame *output, 
1045         int64_t start_position_project,
1046         MaskAutos *keyframe_set, 
1047         MaskAuto *keyframe,
1048         MaskAuto *default_auto)
1050         Playback3DCommand command;
1051         command.command = Playback3DCommand::DO_MASK;
1052         command.canvas = canvas;
1053         command.frame = output;
1054         command.start_position_project = start_position_project;
1055         command.keyframe_set = keyframe_set;
1056         command.keyframe = keyframe;
1057         command.default_auto = default_auto;
1059         send_command(&command);
1064 #ifdef HAVE_GL
1065 static void combine_callback(GLdouble coords[3], 
1066         GLdouble *vertex_data[4],
1067         GLfloat weight[4], 
1068         GLdouble **dataOut)
1070         GLdouble *vertex;
1072         vertex = (GLdouble *) malloc(6 * sizeof(GLdouble));
1073         vertex[0] = coords[0];
1074         vertex[1] = coords[1];
1075         vertex[2] = coords[2];
1077         for (int i = 3; i < 6; i++)
1078         {
1079                 vertex[i] = weight[0] * vertex_data[0][i] +
1080                         weight[1] * vertex_data[1][i] +
1081                         weight[2] * vertex_data[2][i] +
1082                         weight[3] * vertex_data[3][i];
1083         }
1085         *dataOut = vertex;
1087 #endif
1090 void Playback3D::do_mask_sync(Playback3DCommand *command)
1092 #ifdef HAVE_GL
1093         command->canvas->lock_canvas("Playback3D::do_mask_sync");
1094         if(command->canvas->get_canvas())
1095         {
1096                 BC_WindowBase *window = command->canvas->get_canvas();
1097                 window->lock_window("Playback3D::do_mask_sync");
1098                 window->enable_opengl();
1099                 
1100                 switch(command->frame->get_opengl_state())
1101                 {
1102                         case VFrame::RAM:
1103 // Time to upload to the texture
1104                                 command->frame->to_texture();
1105                                 break;
1107                         case VFrame::SCREEN:
1108 // Read back from PBuffer
1109 // Bind context to pbuffer
1110                                 command->frame->enable_opengl();
1111                                 command->frame->screen_to_texture();
1112                                 break;
1113                 }
1117 // Create PBuffer and draw the mask on it
1118                 command->frame->enable_opengl();
1120 // Initialize coordinate system
1121                 int w = command->frame->get_w();
1122                 int h = command->frame->get_h();
1123                 command->frame->init_screen();
1125 // Clear screen
1126                 glDisable(GL_TEXTURE_2D);
1127                 if(command->default_auto->mode == MASK_MULTIPLY_ALPHA)
1128                 {
1129                         glClearColor(0.0, 0.0, 0.0, 0.0);
1130                         glColor4f((float)command->keyframe->value / 100, 
1131                                 (float)command->keyframe->value / 100, 
1132                                 (float)command->keyframe->value / 100, 
1133                                 1.0);
1134                 }
1135                 else
1136                 {
1137                         glClearColor(1.0, 1.0, 1.0, 1.0);
1138                         glColor4f((float)1.0 - (float)command->keyframe->value / 100, 
1139                                 (float)1.0 - (float)command->keyframe->value / 100, 
1140                                 (float)1.0 - (float)command->keyframe->value / 100, 
1141                                 1.0);
1142                 }
1143                 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1145                 
1146 // Draw mask with scaling to simulate feathering
1147                 GLUtesselator *tesselator = gluNewTess();
1148                 gluTessProperty(tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);
1149                 gluTessCallback(tesselator, GLU_TESS_VERTEX, (GLvoid (*) ( )) &glVertex3dv);
1150                 gluTessCallback(tesselator, GLU_TESS_BEGIN, (GLvoid (*) ( )) &glBegin);
1151                 gluTessCallback(tesselator, GLU_TESS_END, (GLvoid (*) ( )) &glEnd);
1152                 gluTessCallback(tesselator, GLU_TESS_COMBINE, (GLvoid (*) ( ))&combine_callback);
1155 // Draw every submask as a new polygon
1156                 int total_submasks = command->keyframe_set->total_submasks(
1157                         command->start_position_project, 
1158                         PLAY_FORWARD);
1159                 float scale = command->keyframe->feather + 1;
1160                 int display_list = glGenLists(1);
1161                 glNewList(display_list, GL_COMPILE);
1162                 for(int k = 0; k < total_submasks; k++)
1163                 {
1164                         gluTessBeginPolygon(tesselator, NULL);
1165                         gluTessBeginContour(tesselator);
1166                         ArrayList<MaskPoint*> *points = new ArrayList<MaskPoint*>;
1167                         command->keyframe_set->get_points(points, 
1168                                 k, 
1169                                 command->start_position_project, 
1170                                 PLAY_FORWARD);
1172                         int first_point = 0;
1173 // Need to tabulate every vertex in persistent memory because
1174 // gluTessVertex doesn't copy them.
1175                         ArrayList<GLdouble*> coords;
1176                         for(int i = 0; i < points->total; i++)
1177                         {
1178                                 MaskPoint *point1 = points->values[i];
1179                                 MaskPoint *point2 = (i >= points->total - 1) ? 
1180                                         points->values[0] : 
1181                                         points->values[i + 1];
1183 #ifndef SQR
1184 #define SQR(x) ((x) * (x))
1185 #endif
1187 // This is very slow.
1188                                 float x, y;
1189                                 int segments = (int)(sqrt(SQR(point1->x - point2->x) + SQR(point1->y - point2->y)));
1190                                 if(point1->control_x2 == 0 &&
1191                                         point1->control_y2 == 0 &&
1192                                         point2->control_x1 == 0 &&
1193                                         point2->control_y1 == 0)
1194                                         segments = 1;
1196                                 float x0 = point1->x;
1197                                 float y0 = point1->y;
1198                                 float x1 = point1->x + point1->control_x2;
1199                                 float y1 = point1->y + point1->control_y2;
1200                                 float x2 = point2->x + point2->control_x1;
1201                                 float y2 = point2->y + point2->control_y1;
1202                                 float x3 = point2->x;
1203                                 float y3 = point2->y;
1205                                 for(int j = 0; j <= segments; j++)
1206                                 {
1207                                         float t = (float)j / segments;
1208                                         float tpow2 = t * t;
1209                                         float tpow3 = t * t * t;
1210                                         float invt = 1 - t;
1211                                         float invtpow2 = invt * invt;
1212                                         float invtpow3 = invt * invt * invt;
1214                                         x = (        invtpow3 * x0
1215                                                 + 3 * t     * invtpow2 * x1
1216                                                 + 3 * tpow2 * invt     * x2 
1217                                                 +     tpow3            * x3);
1218                                         y = (        invtpow3 * y0 
1219                                                 + 3 * t     * invtpow2 * y1
1220                                                 + 3 * tpow2 * invt     * y2 
1221                                                 +     tpow3            * y3);
1224                                         if(j > 0 || first_point)
1225                                         {
1226                                                 GLdouble *coord = new GLdouble[3];
1227                                                 coord[0] = x / scale;
1228                                                 coord[1] = -h + y / scale;
1229                                                 coord[2] = 0;
1230                                                 coords.append(coord);
1231                                                 first_point = 0;
1232                                         }
1233                                 }
1234                         }
1236 // Now that we know the total vertices, send them to GLU
1237                         for(int i = 0; i < coords.total; i++)
1238                                 gluTessVertex(tesselator, coords.values[i], coords.values[i]);
1240                         gluTessEndContour(tesselator);
1241                         gluTessEndPolygon(tesselator);
1242                         points->remove_all_objects();
1243                         delete points;
1244                         coords.remove_all_objects();
1245                 }
1246                 glEndList();
1247                 glCallList(display_list);
1248                 glDeleteLists(display_list, 1);
1250                 glColor4f(1, 1, 1, 1);
1253 // Read mask into temporary texture.
1254 // For feathering, just read the part of the screen after the downscaling.
1257                 float w_scaled = w / scale;
1258                 float h_scaled = h / scale;
1259 // Don't vary the texture size according to scaling because that 
1260 // would waste memory.
1261 // This enables and binds the temporary texture.
1262                 glActiveTexture(GL_TEXTURE1);
1263                 BC_Texture::new_texture(&temp_texture,
1264                         w, 
1265                         h, 
1266                         command->frame->get_color_model());
1267                 temp_texture->bind(1);
1268                 glReadBuffer(GL_BACK);
1270 // Need to add extra size to fill in the bottom right
1271                 glCopyTexSubImage2D(GL_TEXTURE_2D,
1272                         0,
1273                         0,
1274                         0,
1275                         0,
1276                         0,
1277                         (int)MIN(w_scaled + 2, w),
1278                         (int)MIN(h_scaled + 2, h));
1280                 command->frame->bind_texture(0);
1283 // For feathered masks, use a shader to multiply.
1284 // For unfeathered masks, we could use a stencil buffer 
1285 // for further optimization but we also need a YUV algorithm.
1286                 unsigned int frag_shader = 0;
1287                 switch(temp_texture->get_texture_components())
1288                 {
1289                         case 3: 
1290                                 if(command->frame->get_color_model() == BC_YUV888)
1291                                         frag_shader = VFrame::make_shader(0,
1292                                                 multiply_yuvmask3_frag,
1293                                                 0);
1294                                 else
1295                                         frag_shader = VFrame::make_shader(0,
1296                                                 multiply_mask3_frag,
1297                                                 0);
1298                                 break;
1299                         case 4: 
1300                                 frag_shader = VFrame::make_shader(0,
1301                                         multiply_mask4_frag,
1302                                         0);
1303                                 break;
1304                 }
1306                 if(frag_shader)
1307                 {
1308                         int variable;
1309                         glUseProgram(frag_shader);
1310                         if((variable = glGetUniformLocation(frag_shader, "tex")) >= 0)
1311                                 glUniform1i(variable, 0);
1312                         if((variable = glGetUniformLocation(frag_shader, "tex1")) >= 0)
1313                                 glUniform1i(variable, 1);
1314                         if((variable = glGetUniformLocation(frag_shader, "scale")) >= 0)
1315                                 glUniform1f(variable, scale);
1316                 }
1320 // Write texture to PBuffer with multiply and scaling for feather.
1322                 
1323                 command->frame->draw_texture(0, 0, w, h, 0, 0, w, h);
1324                 command->frame->set_opengl_state(VFrame::SCREEN);
1327 // Disable temp texture
1328                 glUseProgram(0);
1330                 glActiveTexture(GL_TEXTURE1);
1331                 glDisable(GL_TEXTURE_2D);
1332                 delete temp_texture;
1333                 temp_texture = 0;
1335                 glActiveTexture(GL_TEXTURE0);
1336                 glDisable(GL_TEXTURE_2D);
1338 // Default drawable
1339                 window->enable_opengl();
1340                 window->unlock_window();
1341         }
1342         command->canvas->unlock_canvas();
1343 #endif
1357 void Playback3D::do_fade(Canvas *canvas, VFrame *frame, float fade)
1359         Playback3DCommand command;
1360         command.command = Playback3DCommand::DO_FADE;
1361         command.canvas = canvas;
1362         command.frame = frame;
1363         command.alpha = fade;
1364         send_command(&command);
1367 void Playback3D::do_fade_sync(Playback3DCommand *command)
1369 #ifdef HAVE_GL
1370         command->canvas->lock_canvas("Playback3D::do_mask_sync");
1371         if(command->canvas->get_canvas())
1372         {
1373                 BC_WindowBase *window = command->canvas->get_canvas();
1374                 window->lock_window("Playback3D::do_fade_sync");
1375                 window->enable_opengl();
1377                 switch(command->frame->get_opengl_state())
1378                 {
1379                         case VFrame::RAM:
1380                                 command->frame->to_texture();
1381                                 break;
1383                         case VFrame::SCREEN:
1384 // Read back from PBuffer
1385 // Bind context to pbuffer
1386                                 command->frame->enable_opengl();
1387                                 command->frame->screen_to_texture();
1388                                 break;
1389                 }
1392                 command->frame->enable_opengl();
1393                 command->frame->init_screen();
1394                 command->frame->bind_texture(0);
1396 //              glClearColor(0.0, 0.0, 0.0, 0.0);
1397 //              glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1398                 glDisable(GL_BLEND);
1399                 unsigned int frag_shader = 0;
1400                 switch(command->frame->get_color_model())
1401                 {
1402 // For the alpha colormodels, the native function seems to multiply the 
1403 // components by the alpha instead of just the alpha.
1404                         case BC_RGBA8888:
1405                         case BC_RGBA_FLOAT:
1406                         case BC_YUVA8888:
1407                                 frag_shader = VFrame::make_shader(0,
1408                                         fade_rgba_frag,
1409                                         0);
1410                                 break;
1412                         case BC_RGB888:
1413                                 glEnable(GL_BLEND);
1414                                 glBlendFunc(GL_SRC_ALPHA, GL_ZERO);
1415                                 glColor4f(command->alpha, command->alpha, command->alpha, 1);
1416                                 break;
1419                         case BC_YUV888:
1420                                 frag_shader = VFrame::make_shader(0,
1421                                         fade_yuv_frag,
1422                                         0);
1423                                 break;
1424                 }
1427                 if(frag_shader)
1428                 {
1429                         glUseProgram(frag_shader);
1430                         int variable;
1431                         if((variable = glGetUniformLocation(frag_shader, "tex")) >= 0)
1432                                 glUniform1i(variable, 0);
1433                         if((variable = glGetUniformLocation(frag_shader, "alpha")) >= 0)
1434                                 glUniform1f(variable, command->alpha);
1435                 }
1437                 command->frame->draw_texture();
1438                 command->frame->set_opengl_state(VFrame::SCREEN);
1440                 if(frag_shader)
1441                 {
1442                         glUseProgram(0);
1443                 }
1445                 glColor4f(1, 1, 1, 1);
1446                 glDisable(GL_BLEND);
1448                 window->unlock_window();
1449         }
1450         command->canvas->unlock_canvas();
1451 #endif
1464 int Playback3D::run_plugin(Canvas *canvas, PluginClient *client)
1466         Playback3DCommand command;
1467         command.command = Playback3DCommand::PLUGIN;
1468         command.canvas = canvas;
1469         command.plugin_client = client;
1470         return send_command(&command);
1473 void Playback3D::run_plugin_sync(Playback3DCommand *command)
1475         command->canvas->lock_canvas("Playback3D::run_plugin_sync");
1476         if(command->canvas->get_canvas())
1477         {
1478                 BC_WindowBase *window = command->canvas->get_canvas();
1479                 window->lock_window("Playback3D::run_plugin_sync");
1480                 window->enable_opengl();
1482                 command->result = ((PluginVClient*)command->plugin_client)->handle_opengl();
1484                 window->unlock_window();
1485         }
1486         command->canvas->unlock_canvas();