build tweaks for fc30, glFinish fix
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / playback3d.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2009 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #define GL_GLEXT_PROTOTYPES
23
24 #include "bccolors.h"
25 #include "bcsignals.h"
26 #include "bcwindowbase.h"
27 #include "canvas.h"
28 #include "clip.h"
29 #include "condition.h"
30 #include "edl.h"
31 #include "maskautos.h"
32 #include "maskauto.h"
33 #include "mutex.h"
34 #include "mwindow.h"
35 #include "overlayframe.inc"
36 #include "overlayframe.h"
37 #include "playback3d.h"
38 #include "pluginclient.h"
39 #include "pluginvclient.h"
40 #include "edlsession.h"
41 #include "transportque.inc"
42 #include "vframe.h"
43
44 #ifdef HAVE_GL
45 #include <GL/gl.h>
46 #include <GL/glext.h>
47 #include <GL/glu.h>
48 #endif
49
50 #include <string.h>
51 #include <unistd.h>
52 #include <fcntl.h>
53
54 #define QQ(q)#q
55 #define SS(s)QQ(s)
56
57
58 // Shaders
59 // These should be passed to VFrame::make_shader to construct shaders.
60 // Can't hard code sampler2D
61
62
63 #ifdef HAVE_GL
64 static const char *yuv_to_rgb_frag =
65         "uniform sampler2D tex;\n"
66         "uniform mat3 yuv_to_rgb_matrix;\n"
67         "uniform float yminf;\n"
68         "void main()\n"
69         "{\n"
70         "       vec4 yuva = texture2D(tex, gl_TexCoord[0].st);\n"
71         "       yuva.rgb -= vec3(yminf, 0.5, 0.5);\n"
72         "       gl_FragColor = vec4(yuv_to_rgb_matrix * yuva.rgb, yuva.a);\n"
73         "}\n";
74
75 static const char *yuva_to_yuv_frag =
76         "uniform sampler2D tex;\n"
77         "void main()\n"
78         "{\n"
79         "       vec4 yuva = texture2D(tex, gl_TexCoord[0].st);\n"
80         "       float a = yuva.a;\n"
81         "       float anti_a = 1.0 - a;\n"
82         "       yuva.r *= a;\n"
83         "       yuva.g = yuva.g * a + 0.5 * anti_a;\n"
84         "       yuva.b = yuva.b * a + 0.5 * anti_a;\n"
85         "       yuva.a = 1.0;\n"
86         "       gl_FragColor = yuva;\n"
87         "}\n";
88
89 static const char *yuva_to_rgb_frag =
90         "uniform sampler2D tex;\n"
91         "uniform mat3 yuv_to_rgb_matrix;\n"
92         "uniform float yminf;\n"
93         "void main()\n"
94         "{\n"
95         "       vec4 yuva = texture2D(tex, gl_TexCoord[0].st);\n"
96         "       yuva.rgb -= vec3(yminf, 0.5, 0.5);\n"
97         "       yuva.rgb = yuv_to_rgb_matrix * yuva.rgb;\n"
98         "       yuva.rgb *= yuva.a;\n"
99         "       yuva.a = 1.0;\n"
100         "       gl_FragColor = yuva;\n"
101         "}\n";
102
103 static const char *rgb_to_yuv_frag =
104         "uniform sampler2D tex;\n"
105         "uniform mat3 rgb_to_yuv_matrix;\n"
106         "uniform float yminf;\n"
107         "void main()\n"
108         "{\n"
109         "       vec4 rgba = texture2D(tex, gl_TexCoord[0].st);\n"
110         "       rgba.rgb = rgb_to_yuv_matrix * rgba.rgb;\n"
111         "       rgba.rgb += vec3(yminf, 0.5, 0.5);\n"
112         "       gl_FragColor = rgba;\n"
113         "}\n";
114
115
116 static const char *rgba_to_rgb_frag =
117         "uniform sampler2D tex;\n"
118         "void main()\n"
119         "{\n"
120         "       vec4 rgba = texture2D(tex, gl_TexCoord[0].st);\n"
121         "       rgba.rgb *= rgba.a;\n"
122         "       rgba.a = 1.0;\n"
123         "       gl_FragColor = rgba;\n"
124         "}\n";
125
126 static const char *rgba_to_yuv_frag =
127         "uniform sampler2D tex;\n"
128         "uniform mat3 rgb_to_yuv_matrix;\n"
129         "uniform float yminf;\n"
130         "void main()\n"
131         "{\n"
132         "       vec4 rgba = texture2D(tex, gl_TexCoord[0].st);\n"
133         "       rgba.rgb *= rgba.a;\n"
134         "       rgba.a = 1.0;\n"
135         "       rgba.rgb = rgb_to_yuv_matrix * rgba.rgb;\n"
136         "       rgba.rgb += vec3(yminf, 0.5, 0.5);\n"
137         "       gl_FragColor = rgba;\n"
138         "}\n";
139
140 //static const char *rgba_to_rgb_flatten =
141 //      "void main() {\n"
142 //      "       gl_FragColor.rgb *= gl_FragColor.a;\n"
143 //      "       gl_FragColor.a = 1.0;\n"
144 //      "}\n";
145
146 #define GL_STD_BLEND(FN) \
147 static const char *blend_##FN##_frag = \
148         "uniform sampler2D tex2;\n" \
149         "uniform vec2 tex2_dimensions;\n" \
150         "uniform float alpha;\n" \
151         "void main() {\n" \
152         "       vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n" \
153         "       vec4 result;\n" \
154         "       result.rgb = " SS(COLOR_##FN(1.0, gl_FragColor.rgb, gl_FragColor.a, canvas.rgb, canvas.a)) ";\n" \
155         "       result.a = " SS(ALPHA_##FN(1.0, gl_FragColor.a, canvas.a)) ";\n" \
156         "       gl_FragColor = mix(canvas, result, alpha);\n" \
157         "}\n"
158
159 #define GL_VEC_BLEND(FN) \
160 static const char *blend_##FN##_frag = \
161         "uniform sampler2D tex2;\n" \
162         "uniform vec2 tex2_dimensions;\n" \
163         "uniform float alpha;\n" \
164         "void main() {\n" \
165         "       vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n" \
166         "       vec4 result;\n" \
167         "       result.r = " SS(COLOR_##FN(1.0, gl_FragColor.r, gl_FragColor.a, canvas.r, canvas.a)) ";\n" \
168         "       result.g = " SS(COLOR_##FN(1.0, gl_FragColor.g, gl_FragColor.a, canvas.g, canvas.a)) ";\n" \
169         "       result.b = " SS(COLOR_##FN(1.0, gl_FragColor.b, gl_FragColor.a, canvas.b, canvas.a)) ";\n" \
170         "       result.a = " SS(ALPHA_##FN(1.0, gl_FragColor.a, canvas.a)) ";\n" \
171         "       result = clamp(result, 0.0, 1.0);\n" \
172         "       gl_FragColor = mix(canvas, result, alpha);\n" \
173         "}\n"
174
175 #undef mabs
176 #define mabs abs
177 #undef mmin
178 #define mmin min
179 #undef mmax
180 #define mmax max
181
182 #undef ZERO
183 #define ZERO 0.0
184 #undef ONE
185 #define ONE 1.0
186 #undef TWO
187 #define TWO 2.0
188
189 // NORMAL
190 static const char *blend_NORMAL_frag =
191         "uniform sampler2D tex2;\n"
192         "uniform vec2 tex2_dimensions;\n"
193         "uniform float alpha;\n"
194         "void main() {\n"
195         "       vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
196         "       vec4 result = mix(canvas, gl_FragColor, gl_FragColor.a);\n"
197         "       gl_FragColor = mix(canvas, result, alpha);\n"
198         "}\n";
199
200 // REPLACE
201 static const char *blend_REPLACE_frag =
202         "uniform float alpha;\n"
203         "void main() {\n"
204         "}\n";
205
206 // ADDITION
207 static const char *blend_ADDITION_frag =
208         "uniform sampler2D tex2;\n"
209         "uniform vec2 tex2_dimensions;\n"
210         "uniform float alpha;\n"
211         "void main() {\n"
212         "       vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
213         "       vec4 result = clamp(gl_FragColor + canvas, 0.0, 1.0);\n"
214         "       gl_FragColor = mix(canvas, result, alpha);\n"
215         "}\n";
216
217 // SUBTRACT
218 static const char *blend_SUBTRACT_frag =
219         "uniform sampler2D tex2;\n"
220         "uniform vec2 tex2_dimensions;\n"
221         "uniform float alpha;\n"
222         "void main() {\n"
223         "       vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
224         "       vec4 result = clamp(gl_FragColor - canvas, 0.0, 1.0);\n"
225         "       gl_FragColor = mix(canvas, result, alpha);\n"
226         "}\n";
227
228 GL_STD_BLEND(MULTIPLY);
229 GL_VEC_BLEND(DIVIDE);
230 GL_VEC_BLEND(MAX);
231 GL_VEC_BLEND(MIN);
232 GL_VEC_BLEND(DARKEN);
233 GL_VEC_BLEND(LIGHTEN);
234 GL_STD_BLEND(DST);
235 GL_STD_BLEND(DST_ATOP);
236 GL_STD_BLEND(DST_IN);
237 GL_STD_BLEND(DST_OUT);
238 GL_STD_BLEND(DST_OVER);
239 GL_STD_BLEND(SRC);
240 GL_STD_BLEND(SRC_ATOP);
241 GL_STD_BLEND(SRC_IN);
242 GL_STD_BLEND(SRC_OUT);
243 GL_STD_BLEND(SRC_OVER);
244 GL_STD_BLEND(AND);
245 GL_STD_BLEND(OR);
246 GL_STD_BLEND(XOR);
247 GL_VEC_BLEND(OVERLAY);
248 GL_STD_BLEND(SCREEN);
249 GL_VEC_BLEND(BURN);
250 GL_VEC_BLEND(DODGE);
251 GL_VEC_BLEND(HARDLIGHT);
252 GL_VEC_BLEND(SOFTLIGHT);
253 GL_VEC_BLEND(DIFFERENCE);
254
255 static const char *read_texture_frag =
256         "uniform sampler2D tex;\n"
257         "void main()\n"
258         "{\n"
259         "       gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
260         "}\n";
261
262 static const char *multiply_mask4_frag =
263         "uniform sampler2D tex;\n"
264         "uniform sampler2D tex1;\n"
265         "uniform float scale;\n"
266         "void main()\n"
267         "{\n"
268         "       gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
269         "       gl_FragColor.a *= texture2D(tex1, gl_TexCoord[0].st / vec2(scale, scale)).r;\n"
270         "}\n";
271
272 static const char *multiply_mask3_frag =
273         "uniform sampler2D tex;\n"
274         "uniform sampler2D tex1;\n"
275         "uniform float scale;\n"
276         "uniform bool is_yuv;\n"
277         "void main()\n"
278         "{\n"
279         "       gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
280         "       float a = texture2D(tex1, gl_TexCoord[0].st / vec2(scale, scale)).r;\n"
281         "       gl_FragColor.rgb *= vec3(a, a, a);\n"
282         "}\n";
283
284 static const char *multiply_yuvmask3_frag =
285         "uniform sampler2D tex;\n"
286         "uniform sampler2D tex1;\n"
287         "uniform float scale;\n"
288         "void main()\n"
289         "{\n"
290         "       gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
291         "       float a = texture2D(tex1, gl_TexCoord[0].st / vec2(scale, scale)).r;\n"
292         "       gl_FragColor.gb -= vec2(0.5, 0.5);\n"
293         "       gl_FragColor.rgb *= vec3(a, a, a);\n"
294         "       gl_FragColor.gb += vec2(0.5, 0.5);\n"
295         "}\n";
296
297 static const char *fade_rgba_frag =
298         "uniform sampler2D tex;\n"
299         "uniform float alpha;\n"
300         "void main()\n"
301         "{\n"
302         "       gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
303         "       gl_FragColor.a *= alpha;\n"
304         "}\n";
305
306 static const char *fade_yuv_frag =
307         "uniform sampler2D tex;\n"
308         "uniform float alpha;\n"
309         "void main()\n"
310         "{\n"
311         "       gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
312         "       gl_FragColor.r *= alpha;\n"
313         "       gl_FragColor.gb -= vec2(0.5, 0.5);\n"
314         "       gl_FragColor.g *= alpha;\n"
315         "       gl_FragColor.b *= alpha;\n"
316         "       gl_FragColor.gb += vec2(0.5, 0.5);\n"
317         "}\n";
318
319 #endif
320
321
322 Playback3DCommand::Playback3DCommand()
323  : BC_SynchronousCommand()
324 {
325         canvas = 0;
326         is_nested = 0;
327 }
328
329 void Playback3DCommand::copy_from(BC_SynchronousCommand *command)
330 {
331         Playback3DCommand *ptr = (Playback3DCommand*)command;
332         this->canvas = ptr->canvas;
333         this->is_cleared = ptr->is_cleared;
334
335         this->in_x1 = ptr->in_x1;
336         this->in_y1 = ptr->in_y1;
337         this->in_x2 = ptr->in_x2;
338         this->in_y2 = ptr->in_y2;
339         this->out_x1 = ptr->out_x1;
340         this->out_y1 = ptr->out_y1;
341         this->out_x2 = ptr->out_x2;
342         this->out_y2 = ptr->out_y2;
343         this->alpha = ptr->alpha;
344         this->mode = ptr->mode;
345         this->interpolation_type = ptr->interpolation_type;
346
347         this->input = ptr->input;
348         this->start_position_project = ptr->start_position_project;
349         this->keyframe_set = ptr->keyframe_set;
350         this->keyframe = ptr->keyframe;
351         this->default_auto = ptr->default_auto;
352         this->plugin_client = ptr->plugin_client;
353         this->want_texture = ptr->want_texture;
354         this->is_nested = ptr->is_nested;
355         this->dst_cmodel = ptr->dst_cmodel;
356
357         BC_SynchronousCommand::copy_from(command);
358 }
359
360
361 ///static void glDebugCallback(GLenum src, GLenum typ, GLuint id,
362 ///     GLenum svy, GLsizei len, const GLchar* msg, void* dat)
363 //static void glDebugCallback(unsigned int src, unsigned int typ, unsigned int id,
364 //      unsigned int svy, int len, const char* msg, const void* dat)
365 //{
366 //      printf("glDebug: %d:%d; %d/%d %s\n",src,typ,id,svy,msg);
367 //}
368
369
370 Playback3D::Playback3D(MWindow *mwindow)
371  : BC_Synchronous()
372 {
373         this->mwindow = mwindow;
374         temp_texture = 0;
375         //Enabling OpenGL debug output on nVidia drivers
376 //      glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, 0, GL_TRUE);
377 //      glEnable(GL_DEBUG_OUTPUT);
378 //      glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
379 //      glDebugMessageCallback(glDebugCallback, 0);
380 }
381
382 Playback3D::~Playback3D()
383 {
384 }
385
386
387
388
389 BC_SynchronousCommand* Playback3D::new_command()
390 {
391         return new Playback3DCommand;
392 }
393
394
395
396 void Playback3D::handle_command(BC_SynchronousCommand *command)
397 {
398 //printf("Playback3D::handle_command 1 %d\n", command->command);
399         switch(command->command)
400         {
401                 case Playback3DCommand::WRITE_BUFFER:
402                         write_buffer_sync((Playback3DCommand*)command);
403                         break;
404
405                 case Playback3DCommand::FINISH_OUTPUT:
406                         finish_output_sync((Playback3DCommand*)command);
407                         break;
408
409                 case Playback3DCommand::CLEAR_OUTPUT:
410                         clear_output_sync((Playback3DCommand*)command);
411                         break;
412
413                 case Playback3DCommand::CLEAR_INPUT:
414                         clear_input_sync((Playback3DCommand*)command);
415                         break;
416
417                 case Playback3DCommand::DO_CAMERA:
418                         do_camera_sync((Playback3DCommand*)command);
419                         break;
420
421                 case Playback3DCommand::OVERLAY:
422                         overlay_sync((Playback3DCommand*)command);
423                         break;
424
425                 case Playback3DCommand::DO_FADE:
426                         do_fade_sync((Playback3DCommand*)command);
427                         break;
428
429                 case Playback3DCommand::DO_MASK:
430                         do_mask_sync((Playback3DCommand*)command);
431                         break;
432
433                 case Playback3DCommand::PLUGIN:
434                         run_plugin_sync((Playback3DCommand*)command);
435                         break;
436
437                 case Playback3DCommand::COPY_FROM:
438                         copy_from_sync((Playback3DCommand*)command);
439                         break;
440
441                 case Playback3DCommand::CONVERT_CMODEL:
442                         convert_cmodel_sync((Playback3DCommand*)command);
443                         break;
444
445 //              case Playback3DCommand::DRAW_REFRESH:
446 //                      draw_refresh_sync((Playback3DCommand*)command);
447 //                      break;
448         }
449 //printf("Playback3D::handle_command 10\n");
450 }
451
452
453
454
455 void Playback3D::copy_from(Canvas *canvas,
456         VFrame *dst,
457         VFrame *src,
458         int want_texture)
459 {
460         Playback3DCommand command;
461         command.command = Playback3DCommand::COPY_FROM;
462         command.canvas = canvas;
463         command.frame = dst;
464         command.input = src;
465         command.want_texture = want_texture;
466         send_command(&command);
467 }
468
469 void Playback3D::copy_from_sync(Playback3DCommand *command)
470 {
471 #ifdef HAVE_GL
472         command->canvas->lock_canvas("Playback3D::draw_refresh_sync");
473         BC_WindowBase *window = command->canvas->get_canvas();
474         if(window)
475         {
476                 window->lock_window("Playback3D:draw_refresh_sync");
477                 window->enable_opengl();
478                 int w = command->input->get_w();
479                 int h = command->input->get_h();
480
481                 if(command->input->get_opengl_state() == VFrame::SCREEN &&
482                         w == command->frame->get_w() && h == command->frame->get_h())
483                 {
484 // printf("Playback3D::copy_from_sync 1 %d %d %d %d %d\n",
485 // command->input->get_w(),
486 // command->input->get_h(),
487 // command->frame->get_w(),
488 // command->frame->get_h(),
489 // command->frame->get_color_model());
490 // With NVidia at least,
491                         if(w % 4)
492                         {
493                                 printf("Playback3D::copy_from_sync: w=%d not supported because it is not divisible by 4.\n", w);
494                         }
495                         else
496 // Copy to texture
497                         if(command->want_texture)
498                         {
499 //printf("Playback3D::copy_from_sync 1 dst=%p src=%p\n", command->frame, command->input);
500 // Screen_to_texture requires the source pbuffer enabled.
501                                 command->input->enable_opengl();
502                                 command->frame->screen_to_texture();
503                                 command->frame->set_opengl_state(VFrame::TEXTURE);
504                         }
505                         else
506 // Copy to RAM
507                         {
508                                 command->input->to_texture();
509                                 command->input->bind_texture(0);
510                                 command->frame->enable_opengl();
511                                 command->frame->init_screen();
512                                 unsigned int shader = BC_CModels::is_yuv(command->input->get_color_model()) ?
513                                         VFrame::make_shader(0, yuv_to_rgb_frag, 0) : 0;
514                                 if( shader > 0 ) {
515                                         glUseProgram(shader);
516                                         int variable = glGetUniformLocation(shader, "tex");
517                                         glUniform1i(variable, 0);
518                                         BC_GL_YUV_TO_RGB(shader);
519                                 }
520                                 else
521                                         glUseProgram(0);
522                                 command->input->draw_texture(1);
523                                 command->frame->screen_to_ram();
524                                 glUseProgram(0);
525                         }
526                 }
527                 else
528                 {
529                         printf("Playback3D::copy_from_sync: invalid formats opengl_state=%d %dx%d -> %dx%d\n",
530                                 command->input->get_opengl_state(), w, h,
531                                 command->frame->get_w(), command->frame->get_h());
532                 }
533
534                 window->unlock_window();
535         }
536         command->canvas->unlock_canvas();
537 #endif
538 }
539
540
541
542
543 // void Playback3D::draw_refresh(Canvas *canvas,
544 //      VFrame *frame,
545 //      float in_x1,
546 //      float in_y1,
547 //      float in_x2,
548 //      float in_y2,
549 //      float out_x1,
550 //      float out_y1,
551 //      float out_x2,
552 //      float out_y2)
553 // {
554 //      Playback3DCommand command;
555 //      command.command = Playback3DCommand::DRAW_REFRESH;
556 //      command.canvas = canvas;
557 //      command.frame = frame;
558 //      command.in_x1 = in_x1;
559 //      command.in_y1 = in_y1;
560 //      command.in_x2 = in_x2;
561 //      command.in_y2 = in_y2;
562 //      command.out_x1 = out_x1;
563 //      command.out_y1 = out_y1;
564 //      command.out_x2 = out_x2;
565 //      command.out_y2 = out_y2;
566 //      send_command(&command);
567 // }
568 //
569 // void Playback3D::draw_refresh_sync(Playback3DCommand *command)
570 // {
571 //      command->canvas->lock_canvas("Playback3D::draw_refresh_sync");
572 //      BC_WindowBase *window = command->canvas->get_canvas();
573 //      if(window)
574 //      {
575 //              window->lock_window("Playback3D:draw_refresh_sync");
576 //              window->enable_opengl();
577 //
578 // // Read output pbuffer back to RAM in project colormodel
579 // // RGB 8bit is fastest for OpenGL to read back.
580 //              command->frame->reallocate(0,
581 //                      0,
582 //                      0,
583 //                      0,
584 //                      command->frame->get_w(),
585 //                      command->frame->get_h(),
586 //                      BC_RGB888,
587 //                      -1);
588 //              command->frame->screen_to_ram();
589 //
590 //              window->clear_box(0,
591 //                                              0,
592 //                                              window->get_w(),
593 //                                              window->get_h());
594 //              window->draw_vframe(command->frame,
595 //                                                      (int)command->out_x1,
596 //                                                      (int)command->out_y1,
597 //                                                      (int)(command->out_x2 - command->out_x1),
598 //                                                      (int)(command->out_y2 - command->out_y1),
599 //                                                      (int)command->in_x1,
600 //                                                      (int)command->in_y1,
601 //                                                      (int)(command->in_x2 - command->in_x1),
602 //                                                      (int)(command->in_y2 - command->in_y1),
603 //                                                      0);
604 //
605 //              window->unlock_window();
606 //      }
607 //      command->canvas->unlock_canvas();
608 // }
609
610
611
612
613
614 void Playback3D::write_buffer(Canvas *canvas,
615         VFrame *frame,
616         float in_x1,
617         float in_y1,
618         float in_x2,
619         float in_y2,
620         float out_x1,
621         float out_y1,
622         float out_x2,
623         float out_y2,
624         int is_cleared)
625 {
626         Playback3DCommand command;
627         command.command = Playback3DCommand::WRITE_BUFFER;
628         command.canvas = canvas;
629         command.frame = frame;
630         command.in_x1 = in_x1;
631         command.in_y1 = in_y1;
632         command.in_x2 = in_x2;
633         command.in_y2 = in_y2;
634         command.out_x1 = out_x1;
635         command.out_y1 = out_y1;
636         command.out_x2 = out_x2;
637         command.out_y2 = out_y2;
638         command.is_cleared = is_cleared;
639         send_command(&command);
640 }
641
642
643 void Playback3D::write_buffer_sync(Playback3DCommand *command)
644 {
645         command->canvas->lock_canvas("Playback3D::write_buffer_sync");
646         if(command->canvas->get_canvas())
647         {
648                 BC_WindowBase *window = command->canvas->get_canvas();
649                 window->lock_window("Playback3D::write_buffer_sync");
650 // Update hidden cursor
651                 window->update_video_cursor();
652 // Make sure OpenGL is enabled first.
653                 window->enable_opengl();
654
655 //printf("Playback3D::write_buffer_sync 1 %d\n", window->get_id());
656                 int flip_y = 0, frame_state = command->frame->get_opengl_state();
657                 switch( frame_state ) {
658 // Upload texture and composite to screen
659                         case VFrame::RAM:
660                                 flip_y = 1;
661                         case VFrame::SCREEN:
662                                 command->frame->to_texture();
663                                 window->enable_opengl();
664 // Composite texture to screen and swap buffer
665                         case VFrame::TEXTURE:
666                                 if( !flip_y ) {
667                                         int fh1 = command->frame->get_h()-1;
668                                         float in_y1 = fh1 - command->in_y1;
669                                         float in_y2 = fh1 - command->in_y2;
670                                         command->in_y1 = in_y2;
671                                         command->in_y2 = in_y1;
672                                 }
673                                 draw_output(command, flip_y);
674                                 break;
675                         default:
676                                 printf("Playback3D::write_buffer_sync unknown state\n");
677                                 break;
678                 }
679                 command->frame->set_opengl_state(frame_state);
680                 window->unlock_window();
681         }
682
683         command->canvas->unlock_canvas();
684 }
685
686
687
688 void Playback3D::draw_output(Playback3DCommand *command, int flip_y)
689 {
690 #ifdef HAVE_GL
691         int texture_id = command->frame->get_texture_id();
692         BC_WindowBase *window = command->canvas->get_canvas();
693
694 // printf("Playback3D::draw_output 1 texture_id=%d window=%p\n",
695 // texture_id,
696 // command->canvas->get_canvas());
697
698
699
700
701 // If virtual console is being used, everything in this function has
702 // already been done except the page flip.
703         if(texture_id >= 0)
704         {
705                 canvas_w = window->get_w();
706                 canvas_h = window->get_h();
707                 VFrame::init_screen(canvas_w, canvas_h);
708                 int color_model = command->frame->get_color_model();
709                 int is_yuv = BC_CModels::is_yuv(color_model);
710
711                 if(!command->is_cleared)
712                 {
713 // If we get here, the virtual console was not used.
714                         init_frame(command, 0);
715                 }
716
717 // Texture
718 // Undo any previous shader settings
719                 command->frame->bind_texture(0);
720
721 // Convert colormodel
722                 unsigned int shader = is_yuv ? VFrame::make_shader(0, yuv_to_rgb_frag, 0) : 0;
723                 if( shader > 0 ) {
724                         glUseProgram(shader);
725 // Set texture unit of the texture
726                         int variable = glGetUniformLocation(shader, "tex");
727                         glUniform1i(variable, 0);
728                         BC_GL_YUV_TO_RGB(shader);
729                 }
730
731 //              if(BC_CModels::components(color_model) == 4)
732 //              {
733 //                      glEnable(GL_BLEND);
734 //                      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
735 //              }
736
737                 command->frame->draw_texture(
738                         command->in_x1, command->in_y1, command->in_x2, command->in_y2,
739                         command->out_x1, command->out_y1, command->out_x2, command->out_y2,
740                         flip_y);
741
742
743 //printf("Playback3D::draw_output 2 %f,%f %f,%f -> %f,%f %f,%f\n",
744 // command->in_x1,
745 // command->in_y1,
746 // command->in_x2,
747 // command->in_y2,
748 // command->out_x1,
749 // command->out_y1,
750 // command->out_x2,
751 // command->out_y2);
752
753                 glUseProgram(0);
754
755                 command->canvas->get_canvas()->flip_opengl();
756
757         }
758 #endif
759 }
760
761
762 void Playback3D::init_frame(Playback3DCommand *command, int is_yuv)
763 {
764 #ifdef HAVE_GL
765         float gbuv = is_yuv ? 0.5 : 0.0;
766         glClearColor(0.0, gbuv, gbuv, 0.0);
767         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
768 #endif
769 }
770
771
772 void Playback3D::finish_output(Canvas *canvas)
773 {
774         Playback3DCommand command;
775         command.canvas = canvas;
776         command.command = Playback3DCommand::FINISH_OUTPUT;
777         send_command(&command);
778 }
779
780 void Playback3D::finish_output_sync(Playback3DCommand *command)
781 {
782 #ifdef HAVE_GL
783         command->canvas->lock_canvas("Playback3D::clear_output_sync");
784         if( command->canvas->get_canvas() ) {
785                 command->canvas->get_canvas()->enable_opengl();
786                 glFinish();
787         }
788         command->canvas->unlock_canvas();
789 #endif
790 }
791
792
793 void Playback3D::clear_output(Canvas *canvas, VFrame *output)
794 {
795         Playback3DCommand command;
796         command.command = Playback3DCommand::CLEAR_OUTPUT;
797         command.canvas = canvas;
798         command.frame = output;
799         send_command(&command);
800 }
801
802 void Playback3D::clear_output_sync(Playback3DCommand *command)
803 {
804         command->canvas->lock_canvas("Playback3D::clear_output_sync");
805         if(command->canvas->get_canvas())
806         {
807                 command->canvas->get_canvas()->lock_window("Playback3D::clear_output_sync");
808 // If we get here, the virtual console is being used.
809                 command->canvas->get_canvas()->enable_opengl();
810                 int is_yuv = 0;
811
812 // Using pbuffer for refresh frame.
813                 if(command->frame)
814                 {
815                         command->frame->enable_opengl();
816                         int color_model = command->canvas->mwindow->edl->session->color_model;
817                         is_yuv = BC_CModels::is_yuv(color_model);
818                 }
819
820                 init_frame(command, is_yuv);
821                 command->canvas->get_canvas()->unlock_window();
822         }
823         command->canvas->unlock_canvas();
824 }
825
826
827 void Playback3D::clear_input(Canvas *canvas, VFrame *frame)
828 {
829         Playback3DCommand command;
830         command.command = Playback3DCommand::CLEAR_INPUT;
831         command.canvas = canvas;
832         command.frame = frame;
833         send_command(&command);
834 }
835
836 void Playback3D::clear_input_sync(Playback3DCommand *command)
837 {
838         command->canvas->lock_canvas("Playback3D::clear_output_sync");
839         if(command->canvas->get_canvas())
840         {
841                 command->canvas->get_canvas()->lock_window("Playback3D::clear_output_sync");
842                 command->canvas->get_canvas()->enable_opengl();
843                 command->frame->enable_opengl();
844                 command->frame->clear_pbuffer();
845                 command->frame->set_opengl_state(VFrame::SCREEN);
846                 command->canvas->get_canvas()->unlock_window();
847         }
848         command->canvas->unlock_canvas();
849 }
850
851 void Playback3D::do_camera(Canvas *canvas,
852         VFrame *output,
853         VFrame *input,
854         float in_x1,
855         float in_y1,
856         float in_x2,
857         float in_y2,
858         float out_x1,
859         float out_y1,
860         float out_x2,
861         float out_y2)
862 {
863         Playback3DCommand command;
864         command.command = Playback3DCommand::DO_CAMERA;
865         command.canvas = canvas;
866         command.input = input;
867         command.frame = output;
868         command.in_x1 = in_x1;
869         command.in_y1 = in_y1;
870         command.in_x2 = in_x2;
871         command.in_y2 = in_y2;
872         command.out_x1 = out_x1;
873         command.out_y1 = out_y1;
874         command.out_x2 = out_x2;
875         command.out_y2 = out_y2;
876         send_command(&command);
877 }
878
879 void Playback3D::do_camera_sync(Playback3DCommand *command)
880 {
881         command->canvas->lock_canvas("Playback3D::do_camera_sync");
882         if(command->canvas->get_canvas())
883         {
884                 command->canvas->get_canvas()->lock_window("Playback3D::clear_output_sync");
885                 command->canvas->get_canvas()->enable_opengl();
886
887                 command->input->to_texture();
888                 command->frame->enable_opengl();
889                 command->frame->init_screen();
890                 command->frame->clear_pbuffer();
891
892                 command->input->bind_texture(0);
893 // Must call draw_texture in input frame to get the texture coordinates right.
894
895 // printf("Playback3D::do_camera_sync 1 %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f\n",
896 // command->in_x1,
897 // command->in_y2,
898 // command->in_x2,
899 // command->in_y1,
900 // command->out_x1,
901 // (float)command->input->get_h() - command->out_y1,
902 // command->out_x2,
903 // (float)command->input->get_h() - command->out_y2);
904                 command->input->draw_texture(
905                         command->in_x1, command->in_y2,
906                         command->in_x2, command->in_y1,
907                         command->out_x1,
908                         (float)command->frame->get_h() - command->out_y1,
909                         command->out_x2,
910                         (float)command->frame->get_h() - command->out_y2);
911
912
913                 command->frame->set_opengl_state(VFrame::SCREEN);
914                 command->frame->screen_to_ram();
915                 command->canvas->get_canvas()->unlock_window();
916         }
917         command->canvas->unlock_canvas();
918 }
919
920 void Playback3D::overlay(Canvas *canvas, VFrame *input,
921         float in_x1, float in_y1, float in_x2, float in_y2,
922         float out_x1, float out_y1, float out_x2, float out_y2,
923         float alpha, int mode, int interpolation_type,
924         VFrame *output, int is_nested)
925 {
926         Playback3DCommand command;
927         command.command = Playback3DCommand::OVERLAY;
928         command.canvas = canvas;
929         command.frame = output;
930         command.input = input;
931         command.in_x1 = in_x1;
932         command.in_y1 = in_y1;
933         command.in_x2 = in_x2;
934         command.in_y2 = in_y2;
935         command.out_x1 = out_x1;
936         command.out_y1 = out_y1;
937         command.out_x2 = out_x2;
938         command.out_y2 = out_y2;
939         command.alpha = alpha;
940         command.mode = mode;
941         command.interpolation_type = interpolation_type;
942         command.is_nested = is_nested;
943         send_command(&command);
944 }
945
946 void Playback3D::overlay_sync(Playback3DCommand *command)
947 {
948 #ifdef HAVE_GL
949 // To do these operations, we need to copy the input buffer to a texture
950 // and blend 2 textures in a shader
951         static const char * const overlay_shaders[TRANSFER_TYPES] = {
952                 blend_NORMAL_frag,      // TRANSFER_NORMAL
953                 blend_ADDITION_frag,    // TRANSFER_ADDITION
954                 blend_SUBTRACT_frag,    // TRANSFER_SUBTRACT
955                 blend_MULTIPLY_frag,    // TRANSFER_MULTIPLY
956                 blend_DIVIDE_frag,      // TRANSFER_DIVIDE
957                 blend_REPLACE_frag,     // TRANSFER_REPLACE
958                 blend_MAX_frag,         // TRANSFER_MAX
959                 blend_MIN_frag,         // TRANSFER_MIN
960                 blend_DARKEN_frag,      // TRANSFER_DARKEN
961                 blend_LIGHTEN_frag,     // TRANSFER_LIGHTEN
962                 blend_DST_frag,         // TRANSFER_DST
963                 blend_DST_ATOP_frag,    // TRANSFER_DST_ATOP
964                 blend_DST_IN_frag,      // TRANSFER_DST_IN
965                 blend_DST_OUT_frag,     // TRANSFER_DST_OUT
966                 blend_DST_OVER_frag,    // TRANSFER_DST_OVER
967                 blend_SRC_frag,         // TRANSFER_SRC
968                 blend_SRC_ATOP_frag,    // TRANSFER_SRC_ATOP
969                 blend_SRC_IN_frag,      // TRANSFER_SRC_IN
970                 blend_SRC_OUT_frag,     // TRANSFER_SRC_OUT
971                 blend_SRC_OVER_frag,    // TRANSFER_SRC_OVER
972                 blend_AND_frag,         // TRANSFER_AND
973                 blend_OR_frag,          // TRANSFER_OR
974                 blend_XOR_frag,         // TRANSFER_XOR
975                 blend_OVERLAY_frag,     // TRANSFER_OVERLAY
976                 blend_SCREEN_frag,      // TRANSFER_SCREEN
977                 blend_BURN_frag,        // TRANSFER_BURN
978                 blend_DODGE_frag,       // TRANSFER_DODGE
979                 blend_HARDLIGHT_frag,   // TRANSFER_HARDLIGHT
980                 blend_SOFTLIGHT_frag,   // TRANSFER_SOFTLIGHT
981                 blend_DIFFERENCE_frag,  // TRANSFER_DIFFERENCE
982         };
983
984         command->canvas->lock_canvas("Playback3D::overlay_sync");
985         if(command->canvas->get_canvas()) {
986                 BC_WindowBase *window = command->canvas->get_canvas();
987                 window->lock_window("Playback3D::overlay_sync");
988 // Make sure OpenGL is enabled first.
989                 window->enable_opengl();
990                 window->update_video_cursor();
991
992                 glColor4f(1, 1, 1, 1);
993                 glDisable(GL_BLEND);
994
995
996 //printf("Playback3D::overlay_sync 1 %d\n", command->input->get_opengl_state());
997                 switch( command->input->get_opengl_state() ) {
998 // Upload texture and composite to screen
999                 case VFrame::RAM:
1000                         command->input->to_texture();
1001                         break;
1002 // Just composite texture to screen
1003                 case VFrame::TEXTURE:
1004                         break;
1005 // read from PBuffer to texture, then composite texture to screen
1006                 case VFrame::SCREEN:
1007                         command->input->enable_opengl();
1008                         command->input->screen_to_texture();
1009                         break;
1010                 default:
1011                         printf("Playback3D::overlay_sync unknown state\n");
1012                         break;
1013                 }
1014
1015                 if(command->frame) {
1016 // Render to PBuffer
1017                         command->frame->enable_opengl();
1018                         command->frame->set_opengl_state(VFrame::SCREEN);
1019                         canvas_w = command->frame->get_w();
1020                         canvas_h = command->frame->get_h();
1021                 }
1022                 else {
1023 // Render to canvas
1024                         window->enable_opengl();
1025                         canvas_w = window->get_w();
1026                         canvas_h = window->get_h();
1027                 }
1028
1029
1030                 const char *shader_stack[16];
1031                 memset(shader_stack,0, sizeof(shader_stack));
1032                 int total_shaders = 0, need_matrix = 0;
1033
1034                 VFrame::init_screen(canvas_w, canvas_h);
1035
1036 // Enable texture
1037                 command->input->bind_texture(0);
1038
1039 // Convert colormodel to RGB if not nested.
1040 // The color model setting in the output frame is ignored.
1041 //              if( command->is_nested <= 0 &&  // not nested
1042 //                  BC_CModels::is_yuv(command->input->get_color_model()) ) {
1043 //                      need_matrix = 1;
1044 //                      shader_stack[total_shaders++] = yuv_to_rgb_frag;
1045 //              }
1046
1047 // get the shaders
1048 #define add_shader(s) \
1049   if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag; \
1050   shader_stack[total_shaders++] = s
1051
1052                 switch(command->mode) {
1053                 case TRANSFER_REPLACE:
1054 // This requires overlaying an alpha multiplied image on a black screen.
1055                         if( command->input->get_texture_components() != 4 ) break;
1056                         add_shader(overlay_shaders[command->mode]);
1057                         break;
1058                 default:
1059                         enable_overlay_texture(command);
1060                         add_shader(overlay_shaders[command->mode]);
1061                         break;
1062                 }
1063
1064 // if to flatten alpha
1065 //              if( command->is_nested < 0 ) {
1066 //                      switch(command->input->get_color_model()) {
1067 //// yuv has already been converted to rgb
1068 //                      case BC_YUVA8888:
1069 //                      case BC_RGBA_FLOAT:
1070 //                      case BC_RGBA8888:
1071 //                              add_shader(rgba_to_rgb_flatten);
1072 //                              break;
1073 //                      }
1074 //              }
1075
1076 // run the shaders
1077                 add_shader(0);
1078                 unsigned int shader = !shader_stack[0] ? 0 :
1079                         VFrame::make_shader(shader_stack);
1080                 if( shader > 0 ) {
1081                         glUseProgram(shader);
1082                         if( need_matrix ) BC_GL_YUV_TO_RGB(shader);
1083 // Set texture unit of the texture
1084                         glUniform1i(glGetUniformLocation(shader, "tex"), 0);
1085 // Set texture unit of the temp texture
1086                         glUniform1i(glGetUniformLocation(shader, "tex2"), 1);
1087 // Set alpha
1088                         int variable = glGetUniformLocation(shader, "alpha");
1089                         glUniform1f(variable, command->alpha);
1090 // Set dimensions of the temp texture
1091                         if(temp_texture)
1092                                 glUniform2f(glGetUniformLocation(shader, "tex2_dimensions"),
1093                                         (float)temp_texture->get_texture_w(),
1094                                         (float)temp_texture->get_texture_h());
1095                 }
1096                 else
1097                         glUseProgram(0);
1098
1099
1100 //printf("Playback3D::overlay_sync %f %f %f %f %f %f %f %f\n",
1101 // command->in_x1, command->in_y1, command->in_x2, command->in_y2,
1102 // command->out_x1, command->out_y1, command->out_x2, command->out_y2);
1103
1104                 command->input->draw_texture(
1105                         command->in_x1, command->in_y1, command->in_x2, command->in_y2,
1106                         command->out_x1, command->out_y1, command->out_x2, command->out_y2,
1107                         !command->is_nested);
1108                 glUseProgram(0);
1109
1110 // Delete temp texture
1111                 if(temp_texture) {
1112                         delete temp_texture;
1113                         temp_texture = 0;
1114                         glActiveTexture(GL_TEXTURE1);
1115                         glDisable(GL_TEXTURE_2D);
1116                 }
1117                 glActiveTexture(GL_TEXTURE0);
1118                 glDisable(GL_TEXTURE_2D);
1119
1120                 window->unlock_window();
1121         }
1122         command->canvas->unlock_canvas();
1123 #endif
1124 }
1125
1126 void Playback3D::enable_overlay_texture(Playback3DCommand *command)
1127 {
1128 #ifdef HAVE_GL
1129         glDisable(GL_BLEND);
1130
1131         glActiveTexture(GL_TEXTURE1);
1132         BC_Texture::new_texture(&temp_texture, canvas_w, canvas_h,
1133                 command->input->get_color_model());
1134         temp_texture->bind(1);
1135
1136 // Read canvas into texture
1137         glReadBuffer(GL_BACK);
1138         glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, canvas_w, canvas_h);
1139 #endif
1140 }
1141
1142
1143 void Playback3D::do_mask(Canvas *canvas,
1144         VFrame *output,
1145         int64_t start_position_project,
1146         MaskAutos *keyframe_set,
1147         MaskAuto *keyframe,
1148         MaskAuto *default_auto)
1149 {
1150         Playback3DCommand command;
1151         command.command = Playback3DCommand::DO_MASK;
1152         command.canvas = canvas;
1153         command.frame = output;
1154         command.start_position_project = start_position_project;
1155         command.keyframe_set = keyframe_set;
1156         command.keyframe = keyframe;
1157         command.default_auto = default_auto;
1158
1159         send_command(&command);
1160 }
1161
1162
1163
1164 #ifdef HAVE_GL
1165 struct Vertex : ListItem<Vertex>
1166 {
1167         GLdouble c[3];
1168 };
1169 // this list is only used from the main thread, no locking needed
1170 // this must be a list so that pointers to allocated entries remain valid
1171 // when new entries are added
1172 static List<Vertex> *vertex_cache = 0;
1173
1174 static void combine_callback(GLdouble coords[3],
1175         GLdouble *vertex_data[4],
1176         GLfloat weight[4],
1177         GLdouble **dataOut)
1178 {
1179 // can't use malloc here; GLU doesn't delete the memory for us!
1180         Vertex* vertex = vertex_cache->append();
1181         vertex->c[0] = coords[0];
1182         vertex->c[1] = coords[1];
1183         vertex->c[2] = coords[2];
1184 // we don't need to interpolate anything
1185
1186         *dataOut = &vertex->c[0];
1187 }
1188 #endif
1189
1190
1191 void Playback3D::do_mask_sync(Playback3DCommand *command)
1192 {
1193 #ifdef HAVE_GL
1194         command->canvas->lock_canvas("Playback3D::do_mask_sync");
1195         if(command->canvas->get_canvas())
1196         {
1197                 BC_WindowBase *window = command->canvas->get_canvas();
1198                 window->lock_window("Playback3D::do_mask_sync");
1199                 window->enable_opengl();
1200
1201                 switch(command->frame->get_opengl_state())
1202                 {
1203                         case VFrame::RAM:
1204 // Time to upload to the texture
1205                                 command->frame->to_texture();
1206                                 break;
1207
1208                         case VFrame::SCREEN:
1209 // Read back from PBuffer
1210 // Bind context to pbuffer
1211                                 command->frame->enable_opengl();
1212                                 command->frame->screen_to_texture();
1213                                 break;
1214                 }
1215
1216
1217
1218 // Create PBuffer and draw the mask on it
1219                 command->frame->enable_opengl();
1220
1221 // Initialize coordinate system
1222                 int w = command->frame->get_w();
1223                 int h = command->frame->get_h();
1224                 command->frame->init_screen();
1225
1226 // Clear screen
1227                 glDisable(GL_TEXTURE_2D);
1228                 if(command->default_auto->mode == MASK_MULTIPLY_ALPHA)
1229                 {
1230                         glClearColor(0.0, 0.0, 0.0, 0.0);
1231                         glColor4f((float)command->keyframe->value / 100,
1232                                 (float)command->keyframe->value / 100,
1233                                 (float)command->keyframe->value / 100,
1234                                 1.0);
1235                 }
1236                 else
1237                 {
1238                         glClearColor(1.0, 1.0, 1.0, 1.0);
1239                         glColor4f((float)1.0 - (float)command->keyframe->value / 100,
1240                                 (float)1.0 - (float)command->keyframe->value / 100,
1241                                 (float)1.0 - (float)command->keyframe->value / 100,
1242                                 1.0);
1243                 }
1244                 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1245
1246
1247 // Draw mask with scaling to simulate feathering
1248                 GLUtesselator *tesselator = gluNewTess();
1249                 gluTessProperty(tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);
1250                 gluTessCallback(tesselator, GLU_TESS_VERTEX, (GLvoid (*) ( )) &glVertex3dv);
1251                 gluTessCallback(tesselator, GLU_TESS_BEGIN, (GLvoid (*) ( )) &glBegin);
1252                 gluTessCallback(tesselator, GLU_TESS_END, (GLvoid (*) ( )) &glEnd);
1253                 gluTessCallback(tesselator, GLU_TESS_COMBINE, (GLvoid (*) ( ))&combine_callback);
1254
1255                 vertex_cache = new List<Vertex>;
1256
1257
1258 // Draw every submask as a new polygon
1259                 int total_submasks = command->keyframe_set->total_submasks(
1260                         command->start_position_project,
1261                         PLAY_FORWARD);
1262                 float scale = command->keyframe->feather + 1;
1263                 int display_list = glGenLists(1);
1264                 glNewList(display_list, GL_COMPILE);
1265                 for(int k = 0; k < total_submasks; k++)
1266                 {
1267                         gluTessBeginPolygon(tesselator, NULL);
1268                         gluTessBeginContour(tesselator);
1269                         ArrayList<MaskPoint*> *points = new ArrayList<MaskPoint*>;
1270                         command->keyframe_set->get_points(points,
1271                                 k,
1272                                 command->start_position_project,
1273                                 PLAY_FORWARD);
1274
1275                         int first_point = 0;
1276 // Need to tabulate every vertex in persistent memory because
1277 // gluTessVertex doesn't copy them.
1278                         ArrayList<GLdouble*> coords;
1279                         coords.set_array_delete();
1280                         for(int i = 0; i < points->total; i++)
1281                         {
1282                                 MaskPoint *point1 = points->values[i];
1283                                 MaskPoint *point2 = (i >= points->total - 1) ?
1284                                         points->values[0] :
1285                                         points->values[i + 1];
1286
1287                                 float x, y;
1288                                 int segments = 0;
1289                                 if(point1->control_x2 == 0 &&
1290                                         point1->control_y2 == 0 &&
1291                                         point2->control_x1 == 0 &&
1292                                         point2->control_y1 == 0)
1293                                         segments = 1;
1294
1295                                 float x0 = point1->x;
1296                                 float y0 = point1->y;
1297                                 float x1 = point1->x + point1->control_x2;
1298                                 float y1 = point1->y + point1->control_y2;
1299                                 float x2 = point2->x + point2->control_x1;
1300                                 float y2 = point2->y + point2->control_y1;
1301                                 float x3 = point2->x;
1302                                 float y3 = point2->y;
1303
1304                                 // forward differencing bezier curves implementation taken from GPL code at
1305                                 // http://cvs.sourceforge.net/viewcvs.py/guliverkli/guliverkli/src/subtitles/Rasterizer.cpp?rev=1.3
1306
1307                                 float cx3, cx2, cx1, cx0, cy3, cy2, cy1, cy0;
1308
1309                                 // [-1 +3 -3 +1]
1310                                 // [+3 -6 +3  0]
1311                                 // [-3 +3  0  0]
1312                                 // [+1  0  0  0]
1313
1314                                 cx3 = -  x0 + 3*x1 - 3*x2 + x3;
1315                                 cx2 =  3*x0 - 6*x1 + 3*x2;
1316                                 cx1 = -3*x0 + 3*x1;
1317                                 cx0 =    x0;
1318
1319                                 cy3 = -  y0 + 3*y1 - 3*y2 + y3;
1320                                 cy2 =  3*y0 - 6*y1 + 3*y2;
1321                                 cy1 = -3*y0 + 3*y1;
1322                                 cy0 =    y0;
1323
1324                                 // This equation is from Graphics Gems I.
1325                                 //
1326                                 // The idea is that since we're approximating a cubic curve with lines,
1327                                 // any error we incur is due to the curvature of the line, which we can
1328                                 // estimate by calculating the maximum acceleration of the curve.  For
1329                                 // a cubic, the acceleration (second derivative) is a line, meaning that
1330                                 // the absolute maximum acceleration must occur at either the beginning
1331                                 // (|c2|) or the end (|c2+c3|).  Our bounds here are a little more
1332                                 // conservative than that, but that's okay.
1333                                 if (segments == 0)
1334                                 {
1335                                         float maxaccel1 = fabs(2*cy2) + fabs(6*cy3);
1336                                         float maxaccel2 = fabs(2*cx2) + fabs(6*cx3);
1337
1338                                         float maxaccel = maxaccel1 > maxaccel2 ? maxaccel1 : maxaccel2;
1339                                         float h = 1.0;
1340
1341                                         if(maxaccel > 8.0) h = sqrt((8.0) / maxaccel);
1342                                         segments = int(1/h);
1343                                 }
1344
1345                                 for(int j = 0; j <= segments; j++)
1346                                 {
1347                                         float t = (float)j / segments;
1348                                         x = cx0 + t*(cx1 + t*(cx2 + t*cx3));
1349                                         y = cy0 + t*(cy1 + t*(cy2 + t*cy3));
1350
1351                                         if(j > 0 || first_point)
1352                                         {
1353                                                 GLdouble *coord = new GLdouble[3];
1354                                                 coord[0] = x / scale;
1355                                                 coord[1] = -h + y / scale;
1356                                                 coord[2] = 0;
1357                                                 coords.append(coord);
1358                                                 first_point = 0;
1359                                         }
1360                                 }
1361                         }
1362
1363 // Now that we know the total vertices, send them to GLU
1364                         for(int i = 0; i < coords.total; i++)
1365                                 gluTessVertex(tesselator, coords.values[i], coords.values[i]);
1366
1367                         gluTessEndContour(tesselator);
1368                         gluTessEndPolygon(tesselator);
1369                         points->remove_all_objects();
1370                         delete points;
1371                         coords.remove_all_objects();
1372                 }
1373                 glEndList();
1374                 glCallList(display_list);
1375                 glDeleteLists(display_list, 1);
1376                 gluDeleteTess(tesselator);
1377
1378                 delete vertex_cache;
1379                 vertex_cache = 0;
1380
1381                 glColor4f(1, 1, 1, 1);
1382
1383
1384 // Read mask into temporary texture.
1385 // For feathering, just read the part of the screen after the downscaling.
1386
1387
1388                 float w_scaled = w / scale;
1389                 float h_scaled = h / scale;
1390 // Don't vary the texture size according to scaling because that
1391 // would waste memory.
1392 // This enables and binds the temporary texture.
1393                 glActiveTexture(GL_TEXTURE1);
1394                 BC_Texture::new_texture(&temp_texture,
1395                         w,
1396                         h,
1397                         command->frame->get_color_model());
1398                 temp_texture->bind(1);
1399                 glReadBuffer(GL_BACK);
1400
1401 // Need to add extra size to fill in the bottom right
1402                 glCopyTexSubImage2D(GL_TEXTURE_2D,
1403                         0,
1404                         0,
1405                         0,
1406                         0,
1407                         0,
1408                         (int)MIN(w_scaled + 2, w),
1409                         (int)MIN(h_scaled + 2, h));
1410
1411                 command->frame->bind_texture(0);
1412
1413
1414 // For feathered masks, use a shader to multiply.
1415 // For unfeathered masks, we could use a stencil buffer
1416 // for further optimization but we also need a YUV algorithm.
1417                 unsigned int frag_shader = 0;
1418                 switch(temp_texture->get_texture_components()) {
1419                 case 3:
1420                         frag_shader = VFrame::make_shader(0,
1421                                 command->frame->get_color_model() == BC_YUV888 ?
1422                                         multiply_yuvmask3_frag : multiply_mask3_frag,
1423                                 0);
1424                         break;
1425                 case 4:
1426                         frag_shader = VFrame::make_shader(0, multiply_mask4_frag, 0);
1427                         break;
1428                 }
1429
1430                 if( frag_shader ) {
1431                         int variable;
1432                         glUseProgram(frag_shader);
1433                         if((variable = glGetUniformLocation(frag_shader, "tex")) >= 0)
1434                                 glUniform1i(variable, 0);
1435                         if((variable = glGetUniformLocation(frag_shader, "tex1")) >= 0)
1436                                 glUniform1i(variable, 1);
1437                         if((variable = glGetUniformLocation(frag_shader, "scale")) >= 0)
1438                                 glUniform1f(variable, scale);
1439                 }
1440
1441
1442
1443 // Write texture to PBuffer with multiply and scaling for feather.
1444
1445
1446                 command->frame->draw_texture(0, 0, w, h, 0, 0, w, h);
1447                 command->frame->set_opengl_state(VFrame::SCREEN);
1448
1449
1450 // Disable temp texture
1451                 glUseProgram(0);
1452
1453                 glActiveTexture(GL_TEXTURE1);
1454                 glDisable(GL_TEXTURE_2D);
1455                 delete temp_texture;
1456                 temp_texture = 0;
1457
1458                 glActiveTexture(GL_TEXTURE0);
1459                 glDisable(GL_TEXTURE_2D);
1460
1461 // Default drawable
1462                 window->enable_opengl();
1463                 window->unlock_window();
1464         }
1465         command->canvas->unlock_canvas();
1466 #endif
1467 }
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478 void Playback3D::convert_cmodel(Canvas *canvas,
1479         VFrame *output,
1480         int dst_cmodel)
1481 {
1482 // Do nothing if colormodels are equivalent in OpenGL & the image is in hardware.
1483         int src_cmodel = output->get_color_model();
1484         if(
1485                 (output->get_opengl_state() == VFrame::TEXTURE ||
1486                 output->get_opengl_state() == VFrame::SCREEN) &&
1487 // OpenGL has no floating point.
1488                 ( (src_cmodel == BC_RGB888 && dst_cmodel == BC_RGB_FLOAT) ||
1489                   (src_cmodel == BC_RGBA8888 && dst_cmodel == BC_RGBA_FLOAT) ||
1490                   (src_cmodel == BC_RGB_FLOAT && dst_cmodel == BC_RGB888) ||
1491                   (src_cmodel == BC_RGBA_FLOAT && dst_cmodel == BC_RGBA8888) ||
1492 // OpenGL sets alpha to 1 on import
1493                   (src_cmodel == BC_RGB888 && dst_cmodel == BC_RGBA8888) ||
1494                   (src_cmodel == BC_YUV888 && dst_cmodel == BC_YUVA8888) ||
1495                   (src_cmodel == BC_RGB_FLOAT && dst_cmodel == BC_RGBA_FLOAT) )
1496                 ) return;
1497
1498
1499
1500         Playback3DCommand command;
1501         command.command = Playback3DCommand::CONVERT_CMODEL;
1502         command.canvas = canvas;
1503         command.frame = output;
1504         command.dst_cmodel = dst_cmodel;
1505         send_command(&command);
1506 }
1507
1508 void Playback3D::convert_cmodel_sync(Playback3DCommand *command)
1509 {
1510 #ifdef HAVE_GL
1511         command->canvas->lock_canvas("Playback3D::convert_cmodel_sync");
1512
1513         if( command->canvas->get_canvas() ) {
1514                 BC_WindowBase *window = command->canvas->get_canvas();
1515                 window->lock_window("Playback3D::convert_cmodel_sync");
1516                 window->enable_opengl();
1517
1518 // Import into hardware
1519                 command->frame->enable_opengl();
1520                 command->frame->init_screen();
1521                 command->frame->to_texture();
1522
1523 // Colormodel permutation
1524                 int src_cmodel = command->frame->get_color_model();
1525                 int dst_cmodel = command->dst_cmodel;
1526                 typedef struct {
1527                         int src, dst, typ;
1528                         const char *shader;
1529                 } cmodel_shader_table_t;
1530                 enum { rgb_to_rgb, rgb_to_yuv, yuv_to_rgb, yuv_to_yuv, };
1531                 int type = -1;
1532                 static cmodel_shader_table_t cmodel_shader_table[]  = {
1533                         { BC_RGB888,    BC_YUV888,      rgb_to_yuv, rgb_to_yuv_frag  },
1534                         { BC_RGB888,    BC_YUVA8888,    rgb_to_yuv, rgb_to_yuv_frag  },
1535                         { BC_RGBA8888,  BC_RGB888,      rgb_to_rgb, rgba_to_rgb_frag },
1536                         { BC_RGBA8888,  BC_RGB_FLOAT,   rgb_to_rgb, rgba_to_rgb_frag },
1537                         { BC_RGBA8888,  BC_YUV888,      rgb_to_yuv, rgba_to_yuv_frag },
1538                         { BC_RGBA8888,  BC_YUVA8888,    rgb_to_yuv, rgb_to_yuv_frag  },
1539                         { BC_RGB_FLOAT, BC_YUV888,      rgb_to_yuv, rgb_to_yuv_frag  },
1540                         { BC_RGB_FLOAT, BC_YUVA8888,    rgb_to_yuv, rgb_to_yuv_frag  },
1541                         { BC_RGBA_FLOAT,BC_RGB888,      rgb_to_rgb, rgba_to_rgb_frag },
1542                         { BC_RGBA_FLOAT,BC_RGB_FLOAT,   rgb_to_rgb, rgba_to_rgb_frag },
1543                         { BC_RGBA_FLOAT,BC_YUV888,      rgb_to_yuv, rgba_to_yuv_frag },
1544                         { BC_RGBA_FLOAT,BC_YUVA8888,    rgb_to_yuv, rgb_to_yuv_frag  },
1545                         { BC_YUV888,    BC_RGB888,      yuv_to_rgb, yuv_to_rgb_frag  },
1546                         { BC_YUV888,    BC_RGBA8888,    yuv_to_rgb, yuv_to_rgb_frag  },
1547                         { BC_YUV888,    BC_RGB_FLOAT,   yuv_to_rgb, yuv_to_rgb_frag  },
1548                         { BC_YUV888,    BC_RGBA_FLOAT,  yuv_to_rgb, yuv_to_rgb_frag  },
1549                         { BC_YUVA8888,  BC_RGB888,      yuv_to_rgb, yuva_to_rgb_frag },
1550                         { BC_YUVA8888,  BC_RGBA8888,    yuv_to_rgb, yuv_to_rgb_frag  },
1551                         { BC_YUVA8888,  BC_RGB_FLOAT,   yuv_to_rgb, yuva_to_rgb_frag },
1552                         { BC_YUVA8888,  BC_RGBA_FLOAT,  yuv_to_rgb, yuv_to_rgb_frag  },
1553                         { BC_YUVA8888,  BC_YUV888,      yuv_to_yuv, yuva_to_yuv_frag },
1554                 };
1555
1556                 const char *shader = 0;
1557                 int table_size = sizeof(cmodel_shader_table) / sizeof(cmodel_shader_table_t);
1558                 for( int i=0; i<table_size; ++i ) {
1559                         if( cmodel_shader_table[i].src == src_cmodel &&
1560                             cmodel_shader_table[i].dst == dst_cmodel ) {
1561                                 shader = cmodel_shader_table[i].shader;
1562                                 type = cmodel_shader_table[i].typ;
1563                                 break;
1564                         }
1565                 }
1566
1567 // printf("Playback3D::convert_cmodel_sync %d %d %d shader=\n%s",
1568 // __LINE__,
1569 // command->frame->get_color_model(),
1570 // command->dst_cmodel,
1571 // shader);
1572
1573                 const char *shader_stack[9];
1574                 memset(shader_stack,0, sizeof(shader_stack));
1575                 int current_shader = 0;
1576
1577                 if( shader ) {
1578 //printf("Playback3D::convert_cmodel_sync %d\n", __LINE__);
1579                         shader_stack[current_shader++] = shader;
1580                         shader_stack[current_shader] = 0;
1581                         unsigned int shader_id = VFrame::make_shader(shader_stack);
1582
1583                         command->frame->bind_texture(0);
1584                         glUseProgram(shader_id);
1585
1586                         glUniform1i(glGetUniformLocation(shader_id, "tex"), 0);
1587                         switch( type ) {
1588                         case rgb_to_yuv:
1589                                 BC_GL_RGB_TO_YUV(shader_id);
1590                                 break;
1591                         case yuv_to_rgb:
1592                                 BC_GL_YUV_TO_RGB(shader_id);
1593                                 break;
1594                         }
1595
1596                         command->frame->draw_texture();
1597                         if(shader) glUseProgram(0);
1598                         command->frame->set_opengl_state(VFrame::SCREEN);
1599                 }
1600
1601                 window->unlock_window();
1602         }
1603
1604         command->canvas->unlock_canvas();
1605 #endif // HAVE_GL
1606 }
1607
1608 void Playback3D::do_fade(Canvas *canvas, VFrame *frame, float fade)
1609 {
1610         Playback3DCommand command;
1611         command.command = Playback3DCommand::DO_FADE;
1612         command.canvas = canvas;
1613         command.frame = frame;
1614         command.alpha = fade;
1615         send_command(&command);
1616 }
1617
1618 void Playback3D::do_fade_sync(Playback3DCommand *command)
1619 {
1620 #ifdef HAVE_GL
1621         command->canvas->lock_canvas("Playback3D::do_mask_sync");
1622         if(command->canvas->get_canvas())
1623         {
1624                 BC_WindowBase *window = command->canvas->get_canvas();
1625                 window->lock_window("Playback3D::do_fade_sync");
1626                 window->enable_opengl();
1627
1628                 switch(command->frame->get_opengl_state())
1629                 {
1630                         case VFrame::RAM:
1631                                 command->frame->to_texture();
1632                                 break;
1633
1634                         case VFrame::SCREEN:
1635 // Read back from PBuffer
1636 // Bind context to pbuffer
1637                                 command->frame->enable_opengl();
1638                                 command->frame->screen_to_texture();
1639                                 break;
1640                 }
1641
1642
1643                 command->frame->enable_opengl();
1644                 command->frame->init_screen();
1645                 command->frame->bind_texture(0);
1646
1647 //              glClearColor(0.0, 0.0, 0.0, 0.0);
1648 //              glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1649                 glDisable(GL_BLEND);
1650                 unsigned int frag_shader = 0;
1651                 switch(command->frame->get_color_model())
1652                 {
1653 // For the alpha colormodels, the native function seems to multiply the
1654 // components by the alpha instead of just the alpha.
1655                         case BC_RGBA8888:
1656                         case BC_RGBA_FLOAT:
1657                         case BC_YUVA8888:
1658                                 frag_shader = VFrame::make_shader(0, fade_rgba_frag, 0);
1659                                 break;
1660
1661                         case BC_RGB888:
1662                                 glEnable(GL_BLEND);
1663                                 glBlendFunc(GL_SRC_ALPHA, GL_ZERO);
1664                                 glColor4f(command->alpha, command->alpha, command->alpha, 1);
1665                                 break;
1666
1667
1668                         case BC_YUV888:
1669                                 frag_shader = VFrame::make_shader(0, fade_yuv_frag, 0);
1670                                 break;
1671                 }
1672
1673
1674                 if( frag_shader ) {
1675                         glUseProgram(frag_shader);
1676                         int variable;
1677                         if((variable = glGetUniformLocation(frag_shader, "tex")) >= 0)
1678                                 glUniform1i(variable, 0);
1679                         if((variable = glGetUniformLocation(frag_shader, "alpha")) >= 0)
1680                                 glUniform1f(variable, command->alpha);
1681                 }
1682
1683                 command->frame->draw_texture();
1684                 command->frame->set_opengl_state(VFrame::SCREEN);
1685
1686                 if(frag_shader)
1687                 {
1688                         glUseProgram(0);
1689                 }
1690
1691                 glColor4f(1, 1, 1, 1);
1692                 glDisable(GL_BLEND);
1693
1694                 window->unlock_window();
1695         }
1696         command->canvas->unlock_canvas();
1697 #endif
1698 }
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710 int Playback3D::run_plugin(Canvas *canvas, PluginClient *client)
1711 {
1712         Playback3DCommand command;
1713         command.command = Playback3DCommand::PLUGIN;
1714         command.canvas = canvas;
1715         command.plugin_client = client;
1716         return send_command(&command);
1717 }
1718
1719 void Playback3D::run_plugin_sync(Playback3DCommand *command)
1720 {
1721         command->canvas->lock_canvas("Playback3D::run_plugin_sync");
1722         if(command->canvas->get_canvas())
1723         {
1724                 BC_WindowBase *window = command->canvas->get_canvas();
1725                 window->lock_window("Playback3D::run_plugin_sync");
1726                 window->enable_opengl();
1727
1728                 command->result = ((PluginVClient*)command->plugin_client)->handle_opengl();
1729
1730                 window->unlock_window();
1731         }
1732         command->canvas->unlock_canvas();
1733 }
1734
1735