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