Merge branch 'ct' of git.pipapo.org:cinelerra-ct into ct
[cinelerra_cv/ct.git] / cinelerra / playback3d.C
blob57c823435bf34c89e98bdd7dc390956d2b216948
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 struct Vertex : ListItem<Vertex>
1067         GLdouble c[3];
1069 // this list is only used from the main thread, no locking needed
1070 // this must be a list so that pointers to allocated entries remain valid
1071 // when new entries are added
1072 static List<Vertex> *vertex_cache = 0;
1074 static void combine_callback(GLdouble coords[3], 
1075         GLdouble *vertex_data[4],
1076         GLfloat weight[4], 
1077         GLdouble **dataOut)
1079 // can't use malloc here; GLU doesn't delete the memory for us!
1080         Vertex* vertex = vertex_cache->append();
1081         vertex->c[0] = coords[0];
1082         vertex->c[1] = coords[1];
1083         vertex->c[2] = coords[2];
1084 // we don't need to interpolate anything
1086         *dataOut = &vertex->c[0];
1088 #endif
1091 void Playback3D::do_mask_sync(Playback3DCommand *command)
1093 #ifdef HAVE_GL
1094         command->canvas->lock_canvas("Playback3D::do_mask_sync");
1095         if(command->canvas->get_canvas())
1096         {
1097                 BC_WindowBase *window = command->canvas->get_canvas();
1098                 window->lock_window("Playback3D::do_mask_sync");
1099                 window->enable_opengl();
1100                 
1101                 switch(command->frame->get_opengl_state())
1102                 {
1103                         case VFrame::RAM:
1104 // Time to upload to the texture
1105                                 command->frame->to_texture();
1106                                 break;
1108                         case VFrame::SCREEN:
1109 // Read back from PBuffer
1110 // Bind context to pbuffer
1111                                 command->frame->enable_opengl();
1112                                 command->frame->screen_to_texture();
1113                                 break;
1114                 }
1118 // Create PBuffer and draw the mask on it
1119                 command->frame->enable_opengl();
1121 // Initialize coordinate system
1122                 int w = command->frame->get_w();
1123                 int h = command->frame->get_h();
1124                 command->frame->init_screen();
1126 // Clear screen
1127                 glDisable(GL_TEXTURE_2D);
1128                 if(command->default_auto->mode == MASK_MULTIPLY_ALPHA)
1129                 {
1130                         glClearColor(0.0, 0.0, 0.0, 0.0);
1131                         glColor4f((float)command->keyframe->value / 100, 
1132                                 (float)command->keyframe->value / 100, 
1133                                 (float)command->keyframe->value / 100, 
1134                                 1.0);
1135                 }
1136                 else
1137                 {
1138                         glClearColor(1.0, 1.0, 1.0, 1.0);
1139                         glColor4f((float)1.0 - (float)command->keyframe->value / 100, 
1140                                 (float)1.0 - (float)command->keyframe->value / 100, 
1141                                 (float)1.0 - (float)command->keyframe->value / 100, 
1142                                 1.0);
1143                 }
1144                 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1146                 
1147 // Draw mask with scaling to simulate feathering
1148                 GLUtesselator *tesselator = gluNewTess();
1149                 gluTessProperty(tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);
1150                 gluTessCallback(tesselator, GLU_TESS_VERTEX, (GLvoid (*) ( )) &glVertex3dv);
1151                 gluTessCallback(tesselator, GLU_TESS_BEGIN, (GLvoid (*) ( )) &glBegin);
1152                 gluTessCallback(tesselator, GLU_TESS_END, (GLvoid (*) ( )) &glEnd);
1153                 gluTessCallback(tesselator, GLU_TESS_COMBINE, (GLvoid (*) ( ))&combine_callback);
1155                 vertex_cache = new List<Vertex>;
1158 // Draw every submask as a new polygon
1159                 int total_submasks = command->keyframe_set->total_submasks(
1160                         command->start_position_project, 
1161                         PLAY_FORWARD);
1162                 float scale = command->keyframe->feather + 1;
1163                 int display_list = glGenLists(1);
1164                 glNewList(display_list, GL_COMPILE);
1165                 for(int k = 0; k < total_submasks; k++)
1166                 {
1167                         gluTessBeginPolygon(tesselator, NULL);
1168                         gluTessBeginContour(tesselator);
1169                         ArrayList<MaskPoint*> *points = new ArrayList<MaskPoint*>;
1170                         command->keyframe_set->get_points(points, 
1171                                 k, 
1172                                 command->start_position_project, 
1173                                 PLAY_FORWARD);
1175                         int first_point = 0;
1176 // Need to tabulate every vertex in persistent memory because
1177 // gluTessVertex doesn't copy them.
1178                         ArrayList<GLdouble*> coords;
1179                         for(int i = 0; i < points->total; i++)
1180                         {
1181                                 MaskPoint *point1 = points->values[i];
1182                                 MaskPoint *point2 = (i >= points->total - 1) ? 
1183                                         points->values[0] : 
1184                                         points->values[i + 1];
1187                                 float x, y;
1188                                 int segments = 0;
1189                                 if(point1->control_x2 == 0 &&
1190                                         point1->control_y2 == 0 &&
1191                                         point2->control_x1 == 0 &&
1192                                         point2->control_y1 == 0)
1193                                         segments = 1;
1195                                 float x0 = point1->x;
1196                                 float y0 = point1->y;
1197                                 float x1 = point1->x + point1->control_x2;
1198                                 float y1 = point1->y + point1->control_y2;
1199                                 float x2 = point2->x + point2->control_x1;
1200                                 float y2 = point2->y + point2->control_y1;
1201                                 float x3 = point2->x;
1202                                 float y3 = point2->y;
1204                                 // forward differencing bezier curves implementation taken from GPL code at
1205                                 // http://cvs.sourceforge.net/viewcvs.py/guliverkli/guliverkli/src/subtitles/Rasterizer.cpp?rev=1.3
1207                                 float cx3, cx2, cx1, cx0, cy3, cy2, cy1, cy0;
1209                                 // [-1 +3 -3 +1]
1210                                 // [+3 -6 +3  0]
1211                                 // [-3 +3  0  0]
1212                                 // [+1  0  0  0]
1214                                 cx3 = -  x0 + 3*x1 - 3*x2 + x3;
1215                                 cx2 =  3*x0 - 6*x1 + 3*x2;
1216                                 cx1 = -3*x0 + 3*x1;
1217                                 cx0 =    x0;
1219                                 cy3 = -  y0 + 3*y1 - 3*y2 + y3;
1220                                 cy2 =  3*y0 - 6*y1 + 3*y2;
1221                                 cy1 = -3*y0 + 3*y1;
1222                                 cy0 =    y0;
1224                                 // This equation is from Graphics Gems I.
1225                                 //
1226                                 // The idea is that since we're approximating a cubic curve with lines,
1227                                 // any error we incur is due to the curvature of the line, which we can
1228                                 // estimate by calculating the maximum acceleration of the curve.  For
1229                                 // a cubic, the acceleration (second derivative) is a line, meaning that
1230                                 // the absolute maximum acceleration must occur at either the beginning
1231                                 // (|c2|) or the end (|c2+c3|).  Our bounds here are a little more
1232                                 // conservative than that, but that's okay.
1233                                 if (segments == 0)
1234                                 {
1235                                         float maxaccel1 = fabs(2*cy2) + fabs(6*cy3);
1236                                         float maxaccel2 = fabs(2*cx2) + fabs(6*cx3);
1238                                         float maxaccel = maxaccel1 > maxaccel2 ? maxaccel1 : maxaccel2;
1239                                         float h = 1.0;
1241                                         if(maxaccel > 8.0) h = sqrt((8.0) / maxaccel);
1242                                         segments = int(1/h);
1243                                 }
1245                                 for(int j = 0; j <= segments; j++)
1246                                 {
1247                                         float t = (float)j / segments;
1248                                         x = cx0 + t*(cx1 + t*(cx2 + t*cx3));
1249                                         y = cy0 + t*(cy1 + t*(cy2 + t*cy3));
1251                                         if(j > 0 || first_point)
1252                                         {
1253                                                 GLdouble *coord = new GLdouble[3];
1254                                                 coord[0] = x / scale;
1255                                                 coord[1] = -h + y / scale;
1256                                                 coord[2] = 0;
1257                                                 coords.append(coord);
1258                                                 first_point = 0;
1259                                         }
1260                                 }
1261                         }
1263 // Now that we know the total vertices, send them to GLU
1264                         for(int i = 0; i < coords.total; i++)
1265                                 gluTessVertex(tesselator, coords.values[i], coords.values[i]);
1267                         gluTessEndContour(tesselator);
1268                         gluTessEndPolygon(tesselator);
1269                         points->remove_all_objects();
1270                         delete points;
1271                         coords.remove_all_objects();
1272                 }
1273                 glEndList();
1274                 glCallList(display_list);
1275                 glDeleteLists(display_list, 1);
1276                 gluDeleteTess(tesselator);
1278                 delete vertex_cache;
1279                 vertex_cache = 0;
1281                 glColor4f(1, 1, 1, 1);
1284 // Read mask into temporary texture.
1285 // For feathering, just read the part of the screen after the downscaling.
1288                 float w_scaled = w / scale;
1289                 float h_scaled = h / scale;
1290 // Don't vary the texture size according to scaling because that 
1291 // would waste memory.
1292 // This enables and binds the temporary texture.
1293                 glActiveTexture(GL_TEXTURE1);
1294                 BC_Texture::new_texture(&temp_texture,
1295                         w, 
1296                         h, 
1297                         command->frame->get_color_model());
1298                 temp_texture->bind(1);
1299                 glReadBuffer(GL_BACK);
1301 // Need to add extra size to fill in the bottom right
1302                 glCopyTexSubImage2D(GL_TEXTURE_2D,
1303                         0,
1304                         0,
1305                         0,
1306                         0,
1307                         0,
1308                         (int)MIN(w_scaled + 2, w),
1309                         (int)MIN(h_scaled + 2, h));
1311                 command->frame->bind_texture(0);
1314 // For feathered masks, use a shader to multiply.
1315 // For unfeathered masks, we could use a stencil buffer 
1316 // for further optimization but we also need a YUV algorithm.
1317                 unsigned int frag_shader = 0;
1318                 switch(temp_texture->get_texture_components())
1319                 {
1320                         case 3: 
1321                                 if(command->frame->get_color_model() == BC_YUV888)
1322                                         frag_shader = VFrame::make_shader(0,
1323                                                 multiply_yuvmask3_frag,
1324                                                 0);
1325                                 else
1326                                         frag_shader = VFrame::make_shader(0,
1327                                                 multiply_mask3_frag,
1328                                                 0);
1329                                 break;
1330                         case 4: 
1331                                 frag_shader = VFrame::make_shader(0,
1332                                         multiply_mask4_frag,
1333                                         0);
1334                                 break;
1335                 }
1337                 if(frag_shader)
1338                 {
1339                         int variable;
1340                         glUseProgram(frag_shader);
1341                         if((variable = glGetUniformLocation(frag_shader, "tex")) >= 0)
1342                                 glUniform1i(variable, 0);
1343                         if((variable = glGetUniformLocation(frag_shader, "tex1")) >= 0)
1344                                 glUniform1i(variable, 1);
1345                         if((variable = glGetUniformLocation(frag_shader, "scale")) >= 0)
1346                                 glUniform1f(variable, scale);
1347                 }
1351 // Write texture to PBuffer with multiply and scaling for feather.
1353                 
1354                 command->frame->draw_texture(0, 0, w, h, 0, 0, w, h);
1355                 command->frame->set_opengl_state(VFrame::SCREEN);
1358 // Disable temp texture
1359                 glUseProgram(0);
1361                 glActiveTexture(GL_TEXTURE1);
1362                 glDisable(GL_TEXTURE_2D);
1363                 delete temp_texture;
1364                 temp_texture = 0;
1366                 glActiveTexture(GL_TEXTURE0);
1367                 glDisable(GL_TEXTURE_2D);
1369 // Default drawable
1370                 window->enable_opengl();
1371                 window->unlock_window();
1372         }
1373         command->canvas->unlock_canvas();
1374 #endif
1388 void Playback3D::do_fade(Canvas *canvas, VFrame *frame, float fade)
1390         Playback3DCommand command;
1391         command.command = Playback3DCommand::DO_FADE;
1392         command.canvas = canvas;
1393         command.frame = frame;
1394         command.alpha = fade;
1395         send_command(&command);
1398 void Playback3D::do_fade_sync(Playback3DCommand *command)
1400 #ifdef HAVE_GL
1401         command->canvas->lock_canvas("Playback3D::do_mask_sync");
1402         if(command->canvas->get_canvas())
1403         {
1404                 BC_WindowBase *window = command->canvas->get_canvas();
1405                 window->lock_window("Playback3D::do_fade_sync");
1406                 window->enable_opengl();
1408                 switch(command->frame->get_opengl_state())
1409                 {
1410                         case VFrame::RAM:
1411                                 command->frame->to_texture();
1412                                 break;
1414                         case VFrame::SCREEN:
1415 // Read back from PBuffer
1416 // Bind context to pbuffer
1417                                 command->frame->enable_opengl();
1418                                 command->frame->screen_to_texture();
1419                                 break;
1420                 }
1423                 command->frame->enable_opengl();
1424                 command->frame->init_screen();
1425                 command->frame->bind_texture(0);
1427 //              glClearColor(0.0, 0.0, 0.0, 0.0);
1428 //              glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1429                 glDisable(GL_BLEND);
1430                 unsigned int frag_shader = 0;
1431                 switch(command->frame->get_color_model())
1432                 {
1433 // For the alpha colormodels, the native function seems to multiply the 
1434 // components by the alpha instead of just the alpha.
1435                         case BC_RGBA8888:
1436                         case BC_RGBA_FLOAT:
1437                         case BC_YUVA8888:
1438                                 frag_shader = VFrame::make_shader(0,
1439                                         fade_rgba_frag,
1440                                         0);
1441                                 break;
1443                         case BC_RGB888:
1444                                 glEnable(GL_BLEND);
1445                                 glBlendFunc(GL_SRC_ALPHA, GL_ZERO);
1446                                 glColor4f(command->alpha, command->alpha, command->alpha, 1);
1447                                 break;
1450                         case BC_YUV888:
1451                                 frag_shader = VFrame::make_shader(0,
1452                                         fade_yuv_frag,
1453                                         0);
1454                                 break;
1455                 }
1458                 if(frag_shader)
1459                 {
1460                         glUseProgram(frag_shader);
1461                         int variable;
1462                         if((variable = glGetUniformLocation(frag_shader, "tex")) >= 0)
1463                                 glUniform1i(variable, 0);
1464                         if((variable = glGetUniformLocation(frag_shader, "alpha")) >= 0)
1465                                 glUniform1f(variable, command->alpha);
1466                 }
1468                 command->frame->draw_texture();
1469                 command->frame->set_opengl_state(VFrame::SCREEN);
1471                 if(frag_shader)
1472                 {
1473                         glUseProgram(0);
1474                 }
1476                 glColor4f(1, 1, 1, 1);
1477                 glDisable(GL_BLEND);
1479                 window->unlock_window();
1480         }
1481         command->canvas->unlock_canvas();
1482 #endif
1495 int Playback3D::run_plugin(Canvas *canvas, PluginClient *client)
1497         Playback3DCommand command;
1498         command.command = Playback3DCommand::PLUGIN;
1499         command.canvas = canvas;
1500         command.plugin_client = client;
1501         return send_command(&command);
1504 void Playback3D::run_plugin_sync(Playback3DCommand *command)
1506         command->canvas->lock_canvas("Playback3D::run_plugin_sync");
1507         if(command->canvas->get_canvas())
1508         {
1509                 BC_WindowBase *window = command->canvas->get_canvas();
1510                 window->lock_window("Playback3D::run_plugin_sync");
1511                 window->enable_opengl();
1513                 command->result = ((PluginVClient*)command->plugin_client)->handle_opengl();
1515                 window->unlock_window();
1516         }
1517         command->canvas->unlock_canvas();
1522 //      Local Variables:
1523 //      mode: C++
1524 //      c-file-style: "linux"
1525 //      End: