mask fade/feather rounding problem, mask mode sense err, add mask
[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 *in_vertex_frag =
263         "#version 430 // vertex shader\n"
264         "in vec3 in_pos;\n"
265         "void main() {\n"
266         "       gl_Position = vec4(in_pos-vec3(0.5,0.5,0.), .5);\n"
267         "}\n";
268
269 static const char *feather_frag =
270         "#version 430\n"
271         "layout(location=0) out vec4 color;\n"
272         "uniform sampler2D tex;\n"
273 // apparently, only doubles index properly in shared buffers
274         "buffer buf { dvec2 points[]; };\n"
275         "uniform float r;\n"
276         "uniform float v;\n"
277         "void main() {\n"
278         "       vec2 tex_st = gl_FragCoord.xy/textureSize(tex,0);\n"
279         "       color = texture(tex, tex_st);\n"
280         "       if( r==0. ) return;\n"
281         "       float rv = r*v>0. ? 1 : -1;\n"
282         "       float rr = r*r, dr = 1./rr;\n"
283         "       float vv = v>=0 ? 1.-v : 1.+v;\n"
284         "       float fg = rv>=0 ? vv : 1.;\n"
285         "       float bg = rv>=0 ? 1. : vv;\n"
286         "       int len = points.length();\n"
287         "       for( int i=0; i<len; ++i ) {\n"
288         "               float dx = float(points[i].x) - gl_FragCoord.x;\n"
289         "               float dy = float(points[i].y) - gl_FragCoord.y;\n"
290         "               float dd = dx*dx + dy*dy;\n"
291         "               if( dd >= rr ) continue;\n"
292         "               float d = dd*dr;\n"
293         "               float a = (1.-d)*fg + d*bg;\n"
294         "               if( rv*(color.a-a) > 0 ) color = vec4(a);\n"
295         "       }\n"
296         "}\n";
297
298 static const char *alpha_frag =
299         "uniform sampler2D tex;\n"
300         "uniform sampler2D tex2;\n"
301         "uniform vec2 tex2_dimensions;\n"
302         "void main() {\n" \
303         "       gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
304         "       vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
305         "       gl_FragColor.a = canvas.a;\n"
306         "}\n";
307
308 static const char *fade_rgba_frag =
309         "uniform sampler2D tex;\n"
310         "uniform float alpha;\n"
311         "void main()\n"
312         "{\n"
313         "       gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
314         "       gl_FragColor.a *= alpha;\n"
315         "}\n";
316
317 static const char *fade_yuv_frag =
318         "uniform sampler2D tex;\n"
319         "uniform float alpha;\n"
320         "void main()\n"
321         "{\n"
322         "       gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
323         "       gl_FragColor.r *= alpha;\n"
324         "       gl_FragColor.gb -= vec2(0.5, 0.5);\n"
325         "       gl_FragColor.g *= alpha;\n"
326         "       gl_FragColor.b *= alpha;\n"
327         "       gl_FragColor.gb += vec2(0.5, 0.5);\n"
328         "}\n";
329
330 #endif
331
332
333 Playback3DCommand::Playback3DCommand()
334  : BC_SynchronousCommand()
335 {
336         canvas = 0;
337         is_nested = 0;
338 }
339
340 void Playback3DCommand::copy_from(BC_SynchronousCommand *command)
341 {
342         Playback3DCommand *ptr = (Playback3DCommand*)command;
343         this->canvas = ptr->canvas;
344         this->is_cleared = ptr->is_cleared;
345
346         this->in_x1 = ptr->in_x1;
347         this->in_y1 = ptr->in_y1;
348         this->in_x2 = ptr->in_x2;
349         this->in_y2 = ptr->in_y2;
350         this->out_x1 = ptr->out_x1;
351         this->out_y1 = ptr->out_y1;
352         this->out_x2 = ptr->out_x2;
353         this->out_y2 = ptr->out_y2;
354         this->alpha = ptr->alpha;
355         this->mode = ptr->mode;
356         this->interpolation_type = ptr->interpolation_type;
357
358         this->input = ptr->input;
359         this->start_position_project = ptr->start_position_project;
360         this->keyframe_set = ptr->keyframe_set;
361         this->keyframe = ptr->keyframe;
362         this->default_auto = ptr->default_auto;
363         this->plugin_client = ptr->plugin_client;
364         this->want_texture = ptr->want_texture;
365         this->is_nested = ptr->is_nested;
366         this->dst_cmodel = ptr->dst_cmodel;
367
368         BC_SynchronousCommand::copy_from(command);
369 }
370
371 //#define GL_BUG 1
372 #ifdef GL_BUG
373 static void GLAPIENTRY glDebugCallback(GLenum source, GLenum type,
374         GLuint id, GLenum severity, GLsizei length, const GLchar* message,
375         const void* userParam)
376 {
377   fprintf(stderr, "GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n",
378         ( type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : "" ),
379         type, severity, message );
380 }
381 #endif
382
383 Playback3D::Playback3D(MWindow *mwindow)
384  : BC_Synchronous()
385 {
386         this->mwindow = mwindow;
387         temp_texture = 0;
388 #ifdef GL_BUG
389         //Enabling OpenGL debug output
390         // this does not work
391         glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, 0, GL_TRUE);
392         glEnable(GL_DEBUG_OUTPUT);
393         glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
394         glDebugMessageCallback(glDebugCallback, 0);
395         glEnable(GL_DEBUG_OUTPUT);
396 #endif
397 }
398
399 Playback3D::~Playback3D()
400 {
401 }
402
403
404
405
406 BC_SynchronousCommand* Playback3D::new_command()
407 {
408         return new Playback3DCommand;
409 }
410
411
412
413 void Playback3D::handle_command(BC_SynchronousCommand *command)
414 {
415 //printf("Playback3D::handle_command 1 %d\n", command->command);
416         switch(command->command)
417         {
418                 case Playback3DCommand::WRITE_BUFFER:
419                         write_buffer_sync((Playback3DCommand*)command);
420                         break;
421
422                 case Playback3DCommand::FINISH_OUTPUT:
423                         finish_output_sync((Playback3DCommand*)command);
424                         break;
425
426                 case Playback3DCommand::CLEAR_OUTPUT:
427                         clear_output_sync((Playback3DCommand*)command);
428                         break;
429
430                 case Playback3DCommand::CLEAR_INPUT:
431                         clear_input_sync((Playback3DCommand*)command);
432                         break;
433
434                 case Playback3DCommand::DO_CAMERA:
435                         do_camera_sync((Playback3DCommand*)command);
436                         break;
437
438                 case Playback3DCommand::OVERLAY:
439                         overlay_sync((Playback3DCommand*)command);
440                         break;
441
442                 case Playback3DCommand::DO_FADE:
443                         do_fade_sync((Playback3DCommand*)command);
444                         break;
445
446                 case Playback3DCommand::DO_MASK:
447                         do_mask_sync((Playback3DCommand*)command);
448                         break;
449
450                 case Playback3DCommand::PLUGIN:
451                         run_plugin_sync((Playback3DCommand*)command);
452                         break;
453
454                 case Playback3DCommand::COPY_FROM:
455                         copy_from_sync((Playback3DCommand*)command);
456                         break;
457
458                 case Playback3DCommand::CONVERT_CMODEL:
459                         convert_cmodel_sync((Playback3DCommand*)command);
460                         break;
461
462 //              case Playback3DCommand::DRAW_REFRESH:
463 //                      draw_refresh_sync((Playback3DCommand*)command);
464 //                      break;
465         }
466 //printf("Playback3D::handle_command 10\n");
467 }
468
469
470
471
472 void Playback3D::copy_from(Canvas *canvas,
473         VFrame *dst,
474         VFrame *src,
475         int want_texture)
476 {
477         Playback3DCommand command;
478         command.command = Playback3DCommand::COPY_FROM;
479         command.canvas = canvas;
480         command.frame = dst;
481         command.input = src;
482         command.want_texture = want_texture;
483         send_command(&command);
484 }
485
486 void Playback3D::copy_from_sync(Playback3DCommand *command)
487 {
488 #ifdef HAVE_GL
489         BC_WindowBase *window =
490                 command->canvas->lock_canvas("Playback3D::copy_from_sync");
491         if( window ) {
492                 window->enable_opengl();
493                 int w = command->input->get_w();
494                 int h = command->input->get_h();
495
496                 if(command->input->get_opengl_state() == VFrame::SCREEN &&
497                         w == command->frame->get_w() && h == command->frame->get_h())
498                 {
499 // printf("Playback3D::copy_from_sync 1 %d %d %d %d %d\n",
500 // command->input->get_w(),
501 // command->input->get_h(),
502 // command->frame->get_w(),
503 // command->frame->get_h(),
504 // command->frame->get_color_model());
505 // With NVidia at least,
506                         if(w % 4)
507                         {
508                                 printf("Playback3D::copy_from_sync: w=%d not supported because it is not divisible by 4.\n", w);
509                         }
510                         else
511 // Copy to texture
512                         if(command->want_texture)
513                         {
514 //printf("Playback3D::copy_from_sync 1 dst=%p src=%p\n", command->frame, command->input);
515 // Screen_to_texture requires the source pbuffer enabled.
516                                 command->input->enable_opengl();
517                                 command->frame->screen_to_texture();
518                                 command->frame->set_opengl_state(VFrame::TEXTURE);
519                         }
520                         else
521 // Copy to RAM
522                         {
523                                 command->input->to_texture();
524                                 command->input->bind_texture(0);
525                                 command->frame->enable_opengl();
526                                 command->frame->init_screen();
527                                 unsigned int shader = BC_CModels::is_yuv(command->input->get_color_model()) ?
528                                         VFrame::make_shader(0, yuv_to_rgb_frag, 0) : 0;
529                                 if( shader > 0 ) {
530                                         glUseProgram(shader);
531                                         int variable = glGetUniformLocation(shader, "tex");
532                                         glUniform1i(variable, 0);
533                                         BC_GL_YUV_TO_RGB(shader);
534                                 }
535                                 else
536                                         glUseProgram(0);
537                                 command->input->draw_texture(1);
538                                 command->frame->screen_to_ram();
539                                 glUseProgram(0);
540                         }
541                 }
542                 else
543                 {
544                         printf("Playback3D::copy_from_sync: invalid formats opengl_state=%d %dx%d -> %dx%d\n",
545                                 command->input->get_opengl_state(), w, h,
546                                 command->frame->get_w(), command->frame->get_h());
547                 }
548         }
549         command->canvas->unlock_canvas();
550 #endif
551 }
552
553
554
555
556 // void Playback3D::draw_refresh(Canvas *canvas,
557 //      VFrame *frame,
558 //      float in_x1,
559 //      float in_y1,
560 //      float in_x2,
561 //      float in_y2,
562 //      float out_x1,
563 //      float out_y1,
564 //      float out_x2,
565 //      float out_y2)
566 // {
567 //      Playback3DCommand command;
568 //      command.command = Playback3DCommand::DRAW_REFRESH;
569 //      command.canvas = canvas;
570 //      command.frame = frame;
571 //      command.in_x1 = in_x1;
572 //      command.in_y1 = in_y1;
573 //      command.in_x2 = in_x2;
574 //      command.in_y2 = in_y2;
575 //      command.out_x1 = out_x1;
576 //      command.out_y1 = out_y1;
577 //      command.out_x2 = out_x2;
578 //      command.out_y2 = out_y2;
579 //      send_command(&command);
580 // }
581 //
582 // void Playback3D::draw_refresh_sync(Playback3DCommand *command)
583 // {
584 // #ifdef HAVE_GL
585 //      BC_WindowBase *window =
586 //              command->canvas->lock_canvas("Playback3D::draw_refresh_sync");
587 //      if( window ) {
588 //              window->enable_opengl();
589 //
590 // // Read output pbuffer back to RAM in project colormodel
591 // // RGB 8bit is fastest for OpenGL to read back.
592 //              command->frame->reallocate(0,
593 //                      0,
594 //                      0,
595 //                      0,
596 //                      command->frame->get_w(),
597 //                      command->frame->get_h(),
598 //                      BC_RGB888,
599 //                      -1);
600 //              command->frame->screen_to_ram();
601 //
602 //              window->clear_box(0,
603 //                                              0,
604 //                                              window->get_w(),
605 //                                              window->get_h());
606 //              window->draw_vframe(command->frame,
607 //                                                      (int)command->out_x1,
608 //                                                      (int)command->out_y1,
609 //                                                      (int)(command->out_x2 - command->out_x1),
610 //                                                      (int)(command->out_y2 - command->out_y1),
611 //                                                      (int)command->in_x1,
612 //                                                      (int)command->in_y1,
613 //                                                      (int)(command->in_x2 - command->in_x1),
614 //                                                      (int)(command->in_y2 - command->in_y1),
615 //                                                      0);
616 //
617 //      }
618 //      command->canvas->unlock_canvas();
619 // #endif
620 // }
621
622
623
624
625
626 void Playback3D::write_buffer(Canvas *canvas,
627         VFrame *frame,
628         float in_x1,
629         float in_y1,
630         float in_x2,
631         float in_y2,
632         float out_x1,
633         float out_y1,
634         float out_x2,
635         float out_y2,
636         int is_cleared)
637 {
638         Playback3DCommand command;
639         command.command = Playback3DCommand::WRITE_BUFFER;
640         command.canvas = canvas;
641         command.frame = frame;
642         command.in_x1 = in_x1;
643         command.in_y1 = in_y1;
644         command.in_x2 = in_x2;
645         command.in_y2 = in_y2;
646         command.out_x1 = out_x1;
647         command.out_y1 = out_y1;
648         command.out_x2 = out_x2;
649         command.out_y2 = out_y2;
650         command.is_cleared = is_cleared;
651         send_command(&command);
652 }
653
654
655 void Playback3D::write_buffer_sync(Playback3DCommand *command)
656 {
657 #ifdef HAVE_GL
658         BC_WindowBase *window =
659                 command->canvas->lock_canvas("Playback3D::write_buffer_sync");
660         if( window ) {
661 // Update hidden cursor
662                 window->update_video_cursor();
663 // Make sure OpenGL is enabled first.
664                 window->enable_opengl();
665
666 //printf("Playback3D::write_buffer_sync 1 %d\n", window->get_id());
667                 int flip_y = 0, frame_state = command->frame->get_opengl_state();
668                 switch( frame_state ) {
669 // Upload texture and composite to screen
670                         case VFrame::RAM:
671                                 flip_y = 1;
672                         case VFrame::SCREEN:
673                                 command->frame->to_texture();
674                                 window->enable_opengl();
675 // Composite texture to screen and swap buffer
676                         case VFrame::TEXTURE:
677                                 if( !flip_y ) {
678                                         int fh1 = command->frame->get_h()-1;
679                                         float in_y1 = fh1 - command->in_y1;
680                                         float in_y2 = fh1 - command->in_y2;
681                                         command->in_y1 = in_y2;
682                                         command->in_y2 = in_y1;
683                                 }
684                                 draw_output(command, flip_y);
685                                 break;
686                         default:
687                                 printf("Playback3D::write_buffer_sync unknown state\n");
688                                 break;
689                 }
690                 command->frame->set_opengl_state(frame_state);
691         }
692         command->canvas->unlock_canvas();
693 #endif
694 }
695
696
697
698 void Playback3D::draw_output(Playback3DCommand *command, int flip_y)
699 {
700 #ifdef HAVE_GL
701         int texture_id = command->frame->get_texture_id();
702         BC_WindowBase *window = command->canvas->get_canvas();
703
704 // printf("Playback3D::draw_output 1 texture_id=%d window=%p\n",
705 // texture_id,
706 // command->canvas->get_canvas());
707
708
709
710
711 // If virtual console is being used, everything in this function has
712 // already been done except the page flip.
713         if(texture_id >= 0)
714         {
715                 canvas_w = window->get_w();
716                 canvas_h = window->get_h();
717                 VFrame::init_screen(canvas_w, canvas_h);
718                 int color_model = command->frame->get_color_model();
719                 int is_yuv = BC_CModels::is_yuv(color_model);
720
721                 if(!command->is_cleared)
722                 {
723 // If we get here, the virtual console was not used.
724                         init_frame(command, 0);
725                 }
726
727 // Texture
728 // Undo any previous shader settings
729                 command->frame->bind_texture(0);
730
731 // Convert colormodel
732                 unsigned int shader = is_yuv ? VFrame::make_shader(0, yuv_to_rgb_frag, 0) : 0;
733                 if( shader > 0 ) {
734                         glUseProgram(shader);
735 // Set texture unit of the texture
736                         int variable = glGetUniformLocation(shader, "tex");
737                         glUniform1i(variable, 0);
738                         BC_GL_YUV_TO_RGB(shader);
739                 }
740
741 //              if(BC_CModels::components(color_model) == 4)
742 //              {
743 //                      glEnable(GL_BLEND);
744 //                      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
745 //              }
746
747                 command->frame->draw_texture(
748                         command->in_x1, command->in_y1, command->in_x2, command->in_y2,
749                         command->out_x1, command->out_y1, command->out_x2, command->out_y2,
750                         flip_y);
751
752
753 //printf("Playback3D::draw_output 2 %f,%f %f,%f -> %f,%f %f,%f\n",
754 // command->in_x1,
755 // command->in_y1,
756 // command->in_x2,
757 // command->in_y2,
758 // command->out_x1,
759 // command->out_y1,
760 // command->out_x2,
761 // command->out_y2);
762
763                 glUseProgram(0);
764
765                 command->canvas->get_canvas()->flip_opengl();
766
767         }
768 #endif
769 }
770
771
772 void Playback3D::init_frame(Playback3DCommand *command, int is_yuv)
773 {
774 #ifdef HAVE_GL
775         float gbuv = is_yuv ? 0.5 : 0.0;
776         glClearColor(0.0, gbuv, gbuv, 0.0);
777         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
778 #endif
779 }
780
781
782 void Playback3D::finish_output(Canvas *canvas)
783 {
784         Playback3DCommand command;
785         command.canvas = canvas;
786         command.command = Playback3DCommand::FINISH_OUTPUT;
787         send_command(&command);
788 }
789
790 void Playback3D::finish_output_sync(Playback3DCommand *command)
791 {
792 #ifdef HAVE_GL
793         BC_WindowBase *window =
794                 command->canvas->lock_canvas("Playback3D::finish_output_sync");
795         if( window ) {
796                 command->canvas->get_canvas()->enable_opengl();
797                 glFinish();
798         }
799         command->canvas->unlock_canvas();
800 #endif
801 }
802
803
804 void Playback3D::clear_output(Canvas *canvas, VFrame *output)
805 {
806         Playback3DCommand command;
807         command.command = Playback3DCommand::CLEAR_OUTPUT;
808         command.canvas = canvas;
809         command.frame = output;
810         send_command(&command);
811 }
812
813 void Playback3D::clear_output_sync(Playback3DCommand *command)
814 {
815 #ifdef HAVE_GL
816         BC_WindowBase *window =
817                 command->canvas->lock_canvas("Playback3D::clear_output_sync");
818         if( window ) {
819 // If we get here, the virtual console is being used.
820                 command->canvas->get_canvas()->enable_opengl();
821                 int is_yuv = 0;
822 // Using pbuffer for refresh frame.
823                 if( command->frame ) {
824                         command->frame->enable_opengl();
825                         int color_model = command->canvas->mwindow->edl->session->color_model;
826                         is_yuv = BC_CModels::is_yuv(color_model);
827                 }
828
829                 init_frame(command, is_yuv);
830         }
831         command->canvas->unlock_canvas();
832 #endif
833 }
834
835
836 void Playback3D::clear_input(Canvas *canvas, VFrame *frame)
837 {
838         Playback3DCommand command;
839         command.command = Playback3DCommand::CLEAR_INPUT;
840         command.canvas = canvas;
841         command.frame = frame;
842         send_command(&command);
843 }
844
845 void Playback3D::clear_input_sync(Playback3DCommand *command)
846 {
847 #ifdef HAVE_GL
848         BC_WindowBase *window =
849                 command->canvas->lock_canvas("Playback3D::clear_input_sync");
850         if( window ) {
851                 command->canvas->get_canvas()->enable_opengl();
852                 command->frame->enable_opengl();
853                 command->frame->clear_pbuffer();
854                 command->frame->set_opengl_state(VFrame::SCREEN);
855         }
856         command->canvas->unlock_canvas();
857 #endif
858 }
859
860 void Playback3D::do_camera(Canvas *canvas,
861         VFrame *output,
862         VFrame *input,
863         float in_x1,
864         float in_y1,
865         float in_x2,
866         float in_y2,
867         float out_x1,
868         float out_y1,
869         float out_x2,
870         float out_y2)
871 {
872         Playback3DCommand command;
873         command.command = Playback3DCommand::DO_CAMERA;
874         command.canvas = canvas;
875         command.input = input;
876         command.frame = output;
877         command.in_x1 = in_x1;
878         command.in_y1 = in_y1;
879         command.in_x2 = in_x2;
880         command.in_y2 = in_y2;
881         command.out_x1 = out_x1;
882         command.out_y1 = out_y1;
883         command.out_x2 = out_x2;
884         command.out_y2 = out_y2;
885         send_command(&command);
886 }
887
888 void Playback3D::do_camera_sync(Playback3DCommand *command)
889 {
890 #ifdef HAVE_GL
891         BC_WindowBase *window =
892                 command->canvas->lock_canvas("Playback3D::do_camera_sync");
893         if( window ) {
894                 command->canvas->get_canvas()->enable_opengl();
895
896                 command->input->to_texture();
897                 command->frame->enable_opengl();
898                 command->frame->init_screen();
899                 command->frame->clear_pbuffer();
900
901                 command->input->bind_texture(0);
902 // Must call draw_texture in input frame to get the texture coordinates right.
903
904 // printf("Playback3D::do_camera_sync 1 %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f\n",
905 // command->in_x1,
906 // command->in_y2,
907 // command->in_x2,
908 // command->in_y1,
909 // command->out_x1,
910 // (float)command->input->get_h() - command->out_y1,
911 // command->out_x2,
912 // (float)command->input->get_h() - command->out_y2);
913                 command->input->draw_texture(
914                         command->in_x1, command->in_y2,
915                         command->in_x2, command->in_y1,
916                         command->out_x1,
917                         (float)command->frame->get_h() - command->out_y1,
918                         command->out_x2,
919                         (float)command->frame->get_h() - command->out_y2);
920
921
922                 command->frame->set_opengl_state(VFrame::SCREEN);
923                 command->frame->screen_to_ram();
924         }
925         command->canvas->unlock_canvas();
926 #endif
927 }
928
929 void Playback3D::overlay(Canvas *canvas, VFrame *input,
930         float in_x1, float in_y1, float in_x2, float in_y2,
931         float out_x1, float out_y1, float out_x2, float out_y2,
932         float alpha, int mode, int interpolation_type,
933         VFrame *output, int is_nested)
934 {
935         Playback3DCommand command;
936         command.command = Playback3DCommand::OVERLAY;
937         command.canvas = canvas;
938         command.frame = output;
939         command.input = input;
940         command.in_x1 = in_x1;
941         command.in_y1 = in_y1;
942         command.in_x2 = in_x2;
943         command.in_y2 = in_y2;
944         command.out_x1 = out_x1;
945         command.out_y1 = out_y1;
946         command.out_x2 = out_x2;
947         command.out_y2 = out_y2;
948         command.alpha = alpha;
949         command.mode = mode;
950         command.interpolation_type = interpolation_type;
951         command.is_nested = is_nested;
952         send_command(&command);
953 }
954
955 void Playback3D::overlay_sync(Playback3DCommand *command)
956 {
957 #ifdef HAVE_GL
958 // To do these operations, we need to copy the input buffer to a texture
959 // and blend 2 textures in a shader
960         static const char * const overlay_shaders[TRANSFER_TYPES] = {
961                 blend_NORMAL_frag,      // TRANSFER_NORMAL
962                 blend_ADDITION_frag,    // TRANSFER_ADDITION
963                 blend_SUBTRACT_frag,    // TRANSFER_SUBTRACT
964                 blend_MULTIPLY_frag,    // TRANSFER_MULTIPLY
965                 blend_DIVIDE_frag,      // TRANSFER_DIVIDE
966                 blend_REPLACE_frag,     // TRANSFER_REPLACE
967                 blend_MAX_frag,         // TRANSFER_MAX
968                 blend_MIN_frag,         // TRANSFER_MIN
969                 blend_DARKEN_frag,      // TRANSFER_DARKEN
970                 blend_LIGHTEN_frag,     // TRANSFER_LIGHTEN
971                 blend_DST_frag,         // TRANSFER_DST
972                 blend_DST_ATOP_frag,    // TRANSFER_DST_ATOP
973                 blend_DST_IN_frag,      // TRANSFER_DST_IN
974                 blend_DST_OUT_frag,     // TRANSFER_DST_OUT
975                 blend_DST_OVER_frag,    // TRANSFER_DST_OVER
976                 blend_SRC_frag,         // TRANSFER_SRC
977                 blend_SRC_ATOP_frag,    // TRANSFER_SRC_ATOP
978                 blend_SRC_IN_frag,      // TRANSFER_SRC_IN
979                 blend_SRC_OUT_frag,     // TRANSFER_SRC_OUT
980                 blend_SRC_OVER_frag,    // TRANSFER_SRC_OVER
981                 blend_AND_frag,         // TRANSFER_AND
982                 blend_OR_frag,          // TRANSFER_OR
983                 blend_XOR_frag,         // TRANSFER_XOR
984                 blend_OVERLAY_frag,     // TRANSFER_OVERLAY
985                 blend_SCREEN_frag,      // TRANSFER_SCREEN
986                 blend_BURN_frag,        // TRANSFER_BURN
987                 blend_DODGE_frag,       // TRANSFER_DODGE
988                 blend_HARDLIGHT_frag,   // TRANSFER_HARDLIGHT
989                 blend_SOFTLIGHT_frag,   // TRANSFER_SOFTLIGHT
990                 blend_DIFFERENCE_frag,  // TRANSFER_DIFFERENCE
991         };
992
993         BC_WindowBase *window =
994                 command->canvas->lock_canvas("Playback3D::overlay_sync");
995         if( window ) {
996 // Make sure OpenGL is enabled first.
997                 window->enable_opengl();
998                 window->update_video_cursor();
999
1000                 glColor4f(1, 1, 1, 1);
1001                 glDisable(GL_BLEND);
1002
1003
1004 //printf("Playback3D::overlay_sync 1 %d\n", command->input->get_opengl_state());
1005                 switch( command->input->get_opengl_state() ) {
1006 // Upload texture and composite to screen
1007                 case VFrame::RAM:
1008                         command->input->to_texture();
1009                         break;
1010 // Just composite texture to screen
1011                 case VFrame::TEXTURE:
1012                         break;
1013 // read from PBuffer to texture, then composite texture to screen
1014                 case VFrame::SCREEN:
1015                         command->input->enable_opengl();
1016                         command->input->screen_to_texture();
1017                         break;
1018                 default:
1019                         printf("Playback3D::overlay_sync unknown state\n");
1020                         break;
1021                 }
1022
1023                 if(command->frame) {
1024 // Render to PBuffer
1025                         command->frame->enable_opengl();
1026                         command->frame->set_opengl_state(VFrame::SCREEN);
1027                         canvas_w = command->frame->get_w();
1028                         canvas_h = command->frame->get_h();
1029                 }
1030                 else {
1031 // Render to canvas
1032                         window->enable_opengl();
1033                         canvas_w = window->get_w();
1034                         canvas_h = window->get_h();
1035                 }
1036
1037
1038                 const char *shader_stack[16];
1039                 memset(shader_stack,0, sizeof(shader_stack));
1040                 int total_shaders = 0, need_matrix = 0;
1041
1042                 VFrame::init_screen(canvas_w, canvas_h);
1043
1044 // Enable texture
1045                 command->input->bind_texture(0);
1046
1047 // Convert colormodel to RGB if not nested.
1048 // The color model setting in the output frame is ignored.
1049 //              if( command->is_nested <= 0 &&  // not nested
1050 //                  BC_CModels::is_yuv(command->input->get_color_model()) ) {
1051 //                      need_matrix = 1;
1052 //                      shader_stack[total_shaders++] = yuv_to_rgb_frag;
1053 //              }
1054
1055 // get the shaders
1056 #define add_shader(s) \
1057   if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag; \
1058   shader_stack[total_shaders++] = s
1059
1060                 switch(command->mode) {
1061                 case TRANSFER_REPLACE:
1062 // This requires overlaying an alpha multiplied image on a black screen.
1063                         if( command->input->get_texture_components() != 4 ) break;
1064                         add_shader(overlay_shaders[command->mode]);
1065                         break;
1066                 default:
1067                         enable_overlay_texture(command);
1068                         add_shader(overlay_shaders[command->mode]);
1069                         break;
1070                 }
1071
1072 // if to flatten alpha
1073 //              if( command->is_nested < 0 ) {
1074 //                      switch(command->input->get_color_model()) {
1075 //// yuv has already been converted to rgb
1076 //                      case BC_YUVA8888:
1077 //                      case BC_RGBA_FLOAT:
1078 //                      case BC_RGBA8888:
1079 //                              add_shader(rgba_to_rgb_flatten);
1080 //                              break;
1081 //                      }
1082 //              }
1083
1084 // run the shaders
1085                 add_shader(0);
1086                 unsigned int shader = !shader_stack[0] ? 0 :
1087                         VFrame::make_shader(shader_stack);
1088                 if( shader > 0 ) {
1089                         glUseProgram(shader);
1090                         if( need_matrix ) BC_GL_YUV_TO_RGB(shader);
1091 // Set texture unit of the texture
1092                         glUniform1i(glGetUniformLocation(shader, "tex"), 0);
1093 // Set texture unit of the temp texture
1094                         glUniform1i(glGetUniformLocation(shader, "tex2"), 1);
1095 // Set alpha
1096                         int variable = glGetUniformLocation(shader, "alpha");
1097                         glUniform1f(variable, command->alpha);
1098 // Set dimensions of the temp texture
1099                         if(temp_texture)
1100                                 glUniform2f(glGetUniformLocation(shader, "tex2_dimensions"),
1101                                         (float)temp_texture->get_texture_w(),
1102                                         (float)temp_texture->get_texture_h());
1103                 }
1104                 else
1105                         glUseProgram(0);
1106
1107
1108 //printf("Playback3D::overlay_sync %f %f %f %f %f %f %f %f\n",
1109 // command->in_x1, command->in_y1, command->in_x2, command->in_y2,
1110 // command->out_x1, command->out_y1, command->out_x2, command->out_y2);
1111
1112                 command->input->draw_texture(
1113                         command->in_x1, command->in_y1, command->in_x2, command->in_y2,
1114                         command->out_x1, command->out_y1, command->out_x2, command->out_y2,
1115                         !command->is_nested);
1116                 glUseProgram(0);
1117
1118 // Delete temp texture
1119                 if(temp_texture) {
1120                         delete temp_texture;
1121                         temp_texture = 0;
1122                         glActiveTexture(GL_TEXTURE1);
1123                         glDisable(GL_TEXTURE_2D);
1124                 }
1125                 glActiveTexture(GL_TEXTURE0);
1126                 glDisable(GL_TEXTURE_2D);
1127         }
1128         command->canvas->unlock_canvas();
1129 #endif
1130 }
1131
1132 void Playback3D::enable_overlay_texture(Playback3DCommand *command)
1133 {
1134 #ifdef HAVE_GL
1135         glDisable(GL_BLEND);
1136
1137         glActiveTexture(GL_TEXTURE1);
1138         BC_Texture::new_texture(&temp_texture, canvas_w, canvas_h,
1139                 command->input->get_color_model());
1140         temp_texture->bind(1);
1141
1142 // Read canvas into texture
1143         glReadBuffer(GL_BACK);
1144         glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, canvas_w, canvas_h);
1145 #endif
1146 }
1147
1148
1149 void Playback3D::do_mask(Canvas *canvas,
1150         VFrame *output,
1151         int64_t start_position_project,
1152         MaskAutos *keyframe_set,
1153         MaskAuto *keyframe,
1154         MaskAuto *default_auto)
1155 {
1156         Playback3DCommand command;
1157         command.command = Playback3DCommand::DO_MASK;
1158         command.canvas = canvas;
1159         command.frame = output;
1160         command.start_position_project = start_position_project;
1161         command.keyframe_set = keyframe_set;
1162         command.keyframe = keyframe;
1163         command.default_auto = default_auto;
1164
1165         send_command(&command);
1166 }
1167
1168
1169 void Playback3D::draw_spots(MaskSpots &spots, int ix1,int iy1, int ix2,int iy2)
1170 {
1171         int x1 = iy1 < iy2 ? ix1 : ix2;
1172         int y1 = iy1 < iy2 ? iy1 : iy2;
1173         int x2 = iy1 < iy2 ? ix2 : ix1;
1174         int y2 = iy1 < iy2 ? iy2 : iy1;
1175
1176         int x = x1, y = y1;
1177         int dx = x2-x1, dy = y2-y1;
1178         int dx2 = 2*dx, dy2 = 2*dy;
1179         if( dx < 0 ) dx = -dx;
1180         int m = dx > dy ? dx : dy, n = m;
1181         if( dy >= dx ) {
1182                 if( dx2 >= 0 ) do {     /* +Y, +X */
1183                         spots.append(x, y++);
1184                         if( (m -= dx2) < 0 ) { m += dy2;  ++x; }
1185                 } while( --n >= 0 );
1186                 else do {              /* +Y, -X */
1187                         spots.append(x, y++);
1188                         if( (m += dx2) < 0 ) { m += dy2;  --x; }
1189                 } while( --n >= 0 );
1190         }
1191         else {
1192                 if( dx2 >= 0 ) do {     /* +X, +Y */
1193                         spots.append(x++, y);
1194                         if( (m -= dy2) < 0 ) { m += dx2;  ++y; }
1195                 } while( --n >= 0 );
1196                 else do {              /* -X, +Y */
1197                         spots.append(x--, y);
1198                         if( (m -= dy2) < 0 ) { m -= dx2;  ++y; }
1199                 } while( --n >= 0 );
1200         }
1201 }
1202
1203 #ifdef HAVE_GL
1204 class fb_texture : public BC_Texture
1205 {
1206 public:
1207         fb_texture(int w, int h, int colormodel);
1208         ~fb_texture();
1209         void bind(int texture_unit);
1210         void read_screen(int x, int y, int w, int h);
1211         void set_output_texture();
1212         GLuint fb, rb;
1213 };
1214
1215 fb_texture::fb_texture(int w, int h, int colormodel)
1216  : BC_Texture(w, h, colormodel)
1217 {
1218         fb = 0;  rb = 0;
1219 //      glGenRenderbuffers(1, &rb);
1220 //      glBindRenderbuffer(GL_RENDERBUFFER, rb);
1221 //      glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, get_texture_w(), get_texture_w());
1222         glGenFramebuffers(1, &fb);
1223         glBindFramebuffer(GL_FRAMEBUFFER, fb);
1224 //      glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rb);
1225 }
1226
1227 fb_texture::~fb_texture()
1228 {
1229         glBindFramebuffer(GL_FRAMEBUFFER, 0);
1230         glDeleteFramebuffers(1, (GLuint *)&fb);
1231 //      glBindRenderbuffer(GL_RENDERBUFFER, 0);
1232 //      glGenRenderbuffers(1, &rb);
1233 }
1234
1235 void fb_texture::bind(int texture_unit)
1236 {
1237         glBindFramebuffer(GL_FRAMEBUFFER, fb);
1238 //      glBindRenderbuffer(GL_RENDERBUFFER, rb);
1239         BC_Texture::bind(texture_unit);
1240 }
1241
1242 void fb_texture::read_screen(int x, int y, int w, int h)
1243 {
1244         glBindFramebuffer(GL_FRAMEBUFFER, 0);
1245         glReadBuffer(GL_BACK);
1246         glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0,0, x,y, w,h);
1247 }
1248
1249 void fb_texture::set_output_texture()
1250 {
1251         glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, get_texture_id(), 0);
1252         GLenum dbo[1] = { GL_COLOR_ATTACHMENT0, }; // bind layout(location=0) out vec4 color;
1253         glDrawBuffers(1, dbo);
1254         int ret = glCheckFramebufferStatus(GL_FRAMEBUFFER);
1255         if( ret != GL_FRAMEBUFFER_COMPLETE ) {
1256                 printf("glDrawBuffer error 0x%04x\n", ret);
1257                 return;
1258         }
1259 }
1260
1261 static void combineData(GLdouble coords[3],
1262                 GLdouble *vertex_data[4], GLfloat weight[4],
1263                 GLdouble **outData, void *data)
1264 {
1265         ArrayList<double *> *invented = (ArrayList<double *> *)data;
1266         GLdouble *vertex = new double[6];
1267         invented->append(vertex);
1268         vertex[0] = coords[0];
1269         vertex[1] = coords[1];
1270         vertex[2] = coords[2];
1271         for( int i=3; i<6; ++i ) {
1272                 vertex[i] = weight[0] * vertex_data[0][i] +
1273                         weight[1] * vertex_data[1][i] +
1274                         weight[2] * vertex_data[2][i] +
1275                         weight[3] * vertex_data[3][i];
1276         }
1277         *outData = vertex;
1278 }
1279
1280 // dbug
1281 static void zglBegin(GLenum mode) { glBegin(mode); }
1282 static void zglEnd() { glEnd(); }
1283 static void zglVertex3dv(const GLdouble *v) { glVertex3dv(v); }
1284
1285 #endif
1286
1287 void Playback3D::do_mask_sync(Playback3DCommand *command)
1288 {
1289 #ifdef HAVE_GL
1290         BC_WindowBase *window =
1291                 command->canvas->lock_canvas("Playback3D::do_mask_sync");
1292         if( window ) {
1293                 window->enable_opengl();
1294
1295                 switch( command->frame->get_opengl_state() ) {
1296                 case VFrame::RAM:
1297 // upload frame to the texture
1298                         command->frame->to_texture();
1299                         break;
1300
1301                 case VFrame::SCREEN:
1302 // Read back from PBuffer
1303 // Bind context to pbuffer
1304                         command->frame->enable_opengl();
1305                         command->frame->screen_to_texture();
1306                         break;
1307                 }
1308
1309 // Initialize coordinate system
1310                 command->frame->enable_opengl();
1311                 command->frame->init_screen();
1312                 int color_model = command->frame->get_color_model();
1313                 int w = command->frame->get_w();
1314                 int h = command->frame->get_h();
1315                 MaskEdges edges;
1316                 float faders[SUBMASKS], feathers[SUBMASKS], bg = 1;
1317                 MaskPointSet point_set[SUBMASKS];
1318 // Draw every submask as a new polygon
1319                 int total_submasks = command->keyframe_set->total_submasks(
1320                         command->start_position_project, PLAY_FORWARD);
1321
1322                 for(int k = 0; k < total_submasks; k++) {
1323                         MaskPointSet &points = point_set[k];
1324                         command->keyframe_set->get_points(&points,
1325                                 k, command->start_position_project, PLAY_FORWARD);
1326                         float fader = command->keyframe_set->get_fader(
1327                                 command->start_position_project, k, PLAY_FORWARD);
1328                         float v = fader/100.;
1329                         faders[k] = v;
1330                         if( v < 0 && (v+=1) < bg ) bg = v;
1331                         float feather = command->keyframe_set->get_feather(
1332                                 command->start_position_project, k, PLAY_FORWARD);
1333                         feathers[k] = feather;
1334                 }
1335 // clear screen
1336                 glDisable(GL_TEXTURE_2D);
1337                 glClearColor(bg, bg, bg, bg);
1338                 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1339
1340                 for(int k = 0; k < total_submasks; k++) {
1341                         MaskPointSet &points = point_set[k];
1342                         MaskEdge &edge = *edges.append(new MaskEdge());
1343                         int first_point = 0;
1344 // Need to tabulate every vertex in persistent memory because
1345 // gluTessVertex doesn't copy them.
1346                         for(int i = 0; i < points.total; i++) {
1347                                 MaskPoint *point1 = points.values[i];
1348                                 MaskPoint *point2 = (i >= points.total - 1) ?
1349                                         points.values[0] : points.values[i + 1];
1350
1351                                 float x, y;
1352                                 int segments = 0;
1353                                 if( point1->control_x2 == 0 && point1->control_y2 == 0 &&
1354                                     point2->control_x1 == 0 && point2->control_y1 == 0 )
1355                                         segments = 1;
1356
1357                                 float x0 = point1->x, y0 = point1->y;
1358                                 float x1 = point1->x + point1->control_x2;
1359                                 float y1 = point1->y + point1->control_y2;
1360                                 float x2 = point2->x + point2->control_x1;
1361                                 float y2 = point2->y + point2->control_y1;
1362                                 float x3 = point2->x, y3 = point2->y;
1363
1364                                 // forward differencing bezier curves implementation taken from GPL code at
1365                                 // http://cvs.sourceforge.net/viewcvs.py/guliverkli/guliverkli/src/subtitles/Rasterizer.cpp?rev=1.3
1366
1367                                 float cx3, cx2, cx1, cx0, cy3, cy2, cy1, cy0;
1368
1369                                 // [-1 +3 -3 +1]
1370                                 // [+3 -6 +3  0]
1371                                 // [-3 +3  0  0]
1372                                 // [+1  0  0  0]
1373
1374                                 cx3 = -  x0 + 3*x1 - 3*x2 + x3;
1375                                 cx2 =  3*x0 - 6*x1 + 3*x2;
1376                                 cx1 = -3*x0 + 3*x1;
1377                                 cx0 =    x0;
1378
1379                                 cy3 = -  y0 + 3*y1 - 3*y2 + y3;
1380                                 cy2 =  3*y0 - 6*y1 + 3*y2;
1381                                 cy1 = -3*y0 + 3*y1;
1382                                 cy0 =    y0;
1383
1384                                 // This equation is from Graphics Gems I.
1385                                 //
1386                                 // The idea is that since we're approximating a cubic curve with lines,
1387                                 // any error we incur is due to the curvature of the line, which we can
1388                                 // estimate by calculating the maximum acceleration of the curve.  For
1389                                 // a cubic, the acceleration (second derivative) is a line, meaning that
1390                                 // the absolute maximum acceleration must occur at either the beginning
1391                                 // (|c2|) or the end (|c2+c3|).  Our bounds here are a little more
1392                                 // conservative than that, but that's okay.
1393                                 if (segments == 0) {
1394                                         float maxaccel1 = fabs(2*cy2) + fabs(6*cy3);
1395                                         float maxaccel2 = fabs(2*cx2) + fabs(6*cx3);
1396
1397                                         float maxaccel = maxaccel1 > maxaccel2 ? maxaccel1 : maxaccel2;
1398                                         float h = 1.0;
1399
1400                                         if(maxaccel > 8.0) h = sqrt((8.0) / maxaccel);
1401                                         segments = int(1/h);
1402                                 }
1403
1404                                 for(int j = 0; j <= segments; j++) {
1405                                         float t = (float)j / segments;
1406                                         x = cx0 + t*(cx1 + t*(cx2 + t*cx3));
1407                                         y = cy0 + t*(cy1 + t*(cy2 + t*cy3));
1408
1409                                         if(j > 0 || first_point) {
1410                                                 edge.append(x, y - h);
1411                                                 first_point = 0;
1412                                         }
1413                                 }
1414                         }
1415                         if( edge.size() > 0 ) {
1416 // draw polygon
1417                                 float fader = faders[k];
1418                                 float v = fader < 0 ? 1 : 1-fader;
1419                                 glColor4f(v, v, v, v);
1420                                 int display_list = glGenLists(1);
1421                                 glNewList(display_list, GL_COMPILE);
1422 #if 0
1423                                 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1424                                 glBegin(GL_POLYGON);
1425                                 MaskCoord *c = &edge[0];
1426                                 for( int i=edge.size(); --i>=0; ++c )
1427                                         glVertex2f(c->x, c->y);
1428                                 glEnd();
1429 #else
1430                                 GLUtesselator *tess = gluNewTess();
1431                                 gluTessCallback(tess, GLU_TESS_VERTEX,(GLvoid (*)()) &zglVertex3dv);
1432                                 gluTessCallback(tess, GLU_TESS_BEGIN,(GLvoid (*)()) &zglBegin);
1433                                 gluTessCallback(tess, GLU_TESS_END,(GLvoid (*)()) &zglEnd);
1434                                 gluTessCallback(tess, GLU_TESS_COMBINE_DATA,(GLvoid (*)()) &combineData);
1435                                 ArrayList<double *> invented;
1436                                 invented.set_array_delete();
1437
1438                                 gluTessBeginPolygon(tess, &invented);
1439                                 gluTessBeginContour(tess);
1440                                 MaskCoord *c = &edge[0];
1441                                 for( int i=edge.size(); --i>=0; ++c )
1442                                         gluTessVertex(tess, (GLdouble *)c, c);
1443                                 gluTessEndContour(tess);
1444                                 gluTessEndPolygon(tess);
1445                                 gluDeleteTess(tess);
1446                                 invented.remove_all_objects();
1447 #endif
1448                                 glEndList();
1449                                 glCallList(display_list);
1450                                 glDeleteLists(1, display_list);
1451                         }
1452                 }
1453
1454 // in/out textures
1455                 fb_texture *in = new fb_texture(w, h, color_model);
1456                 in->bind(0);
1457                 in->read_screen(0,0, w,h);
1458                 fb_texture *out = new fb_texture(w, h, color_model);
1459
1460                 unsigned int frag_shader =
1461                         VFrame::make_shader(0, in_vertex_frag, feather_frag, 0);
1462                 if( frag_shader > 0 ) {
1463                         GLuint points[1];
1464                         glGenBuffers(1, points);
1465                         for(int k = 0; k < total_submasks; k++) {
1466                                 MaskEdge &edge = *edges[k];
1467                                 if( !edge.size() ) continue;
1468                                 if( !faders[k] ) continue;
1469                                 if( !feathers[k] ) continue;
1470                                 MaskSpots spots;
1471                                 for( int i=0; i<edge.size(); ++i ) {
1472                                         MaskCoord &a = edge[i];
1473                                         MaskCoord &b = i<edge.size()-1 ? edge[i+1] : edge[0];
1474                                         draw_spots(spots, a.x,a.y+h, b.x,b.y+h);
1475                                 }
1476                                 int sz = spots.size() * sizeof(MaskSpot);
1477                                 glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 0, points[0], 0, sz);
1478                                 glBufferData(GL_SHADER_STORAGE_BUFFER, sz, &spots[0], GL_DYNAMIC_COPY);
1479                                 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
1480                                 glUseProgram(frag_shader);
1481                                 float r = feathers[k], v = faders[k];
1482                                 glUniform1f(glGetUniformLocation(frag_shader, "r"), r);
1483                                 glUniform1f(glGetUniformLocation(frag_shader, "v"), v);
1484                                 in->bind(0);
1485                                 glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0);
1486                                 out->set_output_texture();
1487                                 glViewport(0,0, w,h);
1488                                 out->draw_texture(0,0, w,h, 0,0, w,h);
1489                                 glUseProgram(0);
1490                                 fb_texture *t = in;  in = out;  out = t;
1491                         }
1492                         glDeleteBuffers(1, points);
1493                 }
1494
1495                 glDrawBuffers(0, 0);
1496                 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1497
1498                 unsigned int shader = VFrame::make_shader(0, alpha_frag, 0);
1499                 glUseProgram(shader);
1500                 if( shader > 0 ) {
1501                         command->frame->bind_texture(0);
1502                         in->BC_Texture::bind(1);
1503                         glUniform1i(glGetUniformLocation(shader, "tex"), 0);
1504                         glUniform1i(glGetUniformLocation(shader, "tex2"), 1);
1505                         glUniform2f(glGetUniformLocation(shader, "tex2_dimensions"),
1506                                         (float)in->get_texture_w(),
1507                                         (float)in->get_texture_h());
1508 //                      if( BC_CModels::components(color_model ) == 4) {
1509 //                              glEnable(GL_BLEND);
1510 //                              glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1511 //                      }
1512                 }
1513                 command->frame->draw_texture();
1514                 command->frame->set_opengl_state(VFrame::SCREEN);
1515                 glUseProgram(0);
1516                 delete in;
1517                 delete out;
1518 // Default drawable
1519                 glDisable(GL_TEXTURE_2D);
1520                 glColor4f(1, 1, 1, 1);
1521                 glActiveTexture(GL_TEXTURE0);
1522                 window->enable_opengl();
1523         }
1524         command->canvas->unlock_canvas();
1525 #endif
1526 }
1527
1528
1529 void Playback3D::convert_cmodel(Canvas *canvas,
1530         VFrame *output,
1531         int dst_cmodel)
1532 {
1533 // Do nothing if colormodels are equivalent in OpenGL & the image is in hardware.
1534         int src_cmodel = output->get_color_model();
1535         if(
1536                 (output->get_opengl_state() == VFrame::TEXTURE ||
1537                 output->get_opengl_state() == VFrame::SCREEN) &&
1538 // OpenGL has no floating point.
1539                 ( (src_cmodel == BC_RGB888 && dst_cmodel == BC_RGB_FLOAT) ||
1540                   (src_cmodel == BC_RGBA8888 && dst_cmodel == BC_RGBA_FLOAT) ||
1541                   (src_cmodel == BC_RGB_FLOAT && dst_cmodel == BC_RGB888) ||
1542                   (src_cmodel == BC_RGBA_FLOAT && dst_cmodel == BC_RGBA8888) ||
1543 // OpenGL sets alpha to 1 on import
1544                   (src_cmodel == BC_RGB888 && dst_cmodel == BC_RGBA8888) ||
1545                   (src_cmodel == BC_YUV888 && dst_cmodel == BC_YUVA8888) ||
1546                   (src_cmodel == BC_RGB_FLOAT && dst_cmodel == BC_RGBA_FLOAT) )
1547                 ) return;
1548
1549
1550
1551         Playback3DCommand command;
1552         command.command = Playback3DCommand::CONVERT_CMODEL;
1553         command.canvas = canvas;
1554         command.frame = output;
1555         command.dst_cmodel = dst_cmodel;
1556         send_command(&command);
1557 }
1558
1559 void Playback3D::convert_cmodel_sync(Playback3DCommand *command)
1560 {
1561 #ifdef HAVE_GL
1562         BC_WindowBase *window =
1563                 command->canvas->lock_canvas("Playback3D::convert_cmodel_sync");
1564         if( window ) {
1565                 window->enable_opengl();
1566
1567 // Import into hardware
1568                 command->frame->enable_opengl();
1569                 command->frame->init_screen();
1570                 command->frame->to_texture();
1571
1572 // Colormodel permutation
1573                 int src_cmodel = command->frame->get_color_model();
1574                 int dst_cmodel = command->dst_cmodel;
1575                 typedef struct {
1576                         int src, dst, typ;
1577                         const char *shader;
1578                 } cmodel_shader_table_t;
1579                 enum { rgb_to_rgb, rgb_to_yuv, yuv_to_rgb, yuv_to_yuv, };
1580                 int type = -1;
1581                 static cmodel_shader_table_t cmodel_shader_table[]  = {
1582                         { BC_RGB888,    BC_YUV888,      rgb_to_yuv, rgb_to_yuv_frag  },
1583                         { BC_RGB888,    BC_YUVA8888,    rgb_to_yuv, rgb_to_yuv_frag  },
1584                         { BC_RGBA8888,  BC_RGB888,      rgb_to_rgb, rgba_to_rgb_frag },
1585                         { BC_RGBA8888,  BC_RGB_FLOAT,   rgb_to_rgb, rgba_to_rgb_frag },
1586                         { BC_RGBA8888,  BC_YUV888,      rgb_to_yuv, rgba_to_yuv_frag },
1587                         { BC_RGBA8888,  BC_YUVA8888,    rgb_to_yuv, rgb_to_yuv_frag  },
1588                         { BC_RGB_FLOAT, BC_YUV888,      rgb_to_yuv, rgb_to_yuv_frag  },
1589                         { BC_RGB_FLOAT, BC_YUVA8888,    rgb_to_yuv, rgb_to_yuv_frag  },
1590                         { BC_RGBA_FLOAT,BC_RGB888,      rgb_to_rgb, rgba_to_rgb_frag },
1591                         { BC_RGBA_FLOAT,BC_RGB_FLOAT,   rgb_to_rgb, rgba_to_rgb_frag },
1592                         { BC_RGBA_FLOAT,BC_YUV888,      rgb_to_yuv, rgba_to_yuv_frag },
1593                         { BC_RGBA_FLOAT,BC_YUVA8888,    rgb_to_yuv, rgb_to_yuv_frag  },
1594                         { BC_YUV888,    BC_RGB888,      yuv_to_rgb, yuv_to_rgb_frag  },
1595                         { BC_YUV888,    BC_RGBA8888,    yuv_to_rgb, yuv_to_rgb_frag  },
1596                         { BC_YUV888,    BC_RGB_FLOAT,   yuv_to_rgb, yuv_to_rgb_frag  },
1597                         { BC_YUV888,    BC_RGBA_FLOAT,  yuv_to_rgb, yuv_to_rgb_frag  },
1598                         { BC_YUVA8888,  BC_RGB888,      yuv_to_rgb, yuva_to_rgb_frag },
1599                         { BC_YUVA8888,  BC_RGBA8888,    yuv_to_rgb, yuv_to_rgb_frag  },
1600                         { BC_YUVA8888,  BC_RGB_FLOAT,   yuv_to_rgb, yuva_to_rgb_frag },
1601                         { BC_YUVA8888,  BC_RGBA_FLOAT,  yuv_to_rgb, yuv_to_rgb_frag  },
1602                         { BC_YUVA8888,  BC_YUV888,      yuv_to_yuv, yuva_to_yuv_frag },
1603                 };
1604
1605                 const char *shader = 0;
1606                 int table_size = sizeof(cmodel_shader_table) / sizeof(cmodel_shader_table_t);
1607                 for( int i=0; i<table_size; ++i ) {
1608                         if( cmodel_shader_table[i].src == src_cmodel &&
1609                             cmodel_shader_table[i].dst == dst_cmodel ) {
1610                                 shader = cmodel_shader_table[i].shader;
1611                                 type = cmodel_shader_table[i].typ;
1612                                 break;
1613                         }
1614                 }
1615
1616 // printf("Playback3D::convert_cmodel_sync %d %d %d shader=\n%s",
1617 // __LINE__,
1618 // command->frame->get_color_model(),
1619 // command->dst_cmodel,
1620 // shader);
1621
1622                 const char *shader_stack[9];
1623                 memset(shader_stack,0, sizeof(shader_stack));
1624                 int current_shader = 0;
1625
1626                 if( shader ) {
1627 //printf("Playback3D::convert_cmodel_sync %d\n", __LINE__);
1628                         shader_stack[current_shader++] = shader;
1629                         shader_stack[current_shader] = 0;
1630                         unsigned int shader_id = VFrame::make_shader(shader_stack);
1631
1632                         command->frame->bind_texture(0);
1633                         glUseProgram(shader_id);
1634
1635                         glUniform1i(glGetUniformLocation(shader_id, "tex"), 0);
1636                         switch( type ) {
1637                         case rgb_to_yuv:
1638                                 BC_GL_RGB_TO_YUV(shader_id);
1639                                 break;
1640                         case yuv_to_rgb:
1641                                 BC_GL_YUV_TO_RGB(shader_id);
1642                                 break;
1643                         }
1644
1645                         command->frame->draw_texture();
1646                         if(shader) glUseProgram(0);
1647                         command->frame->set_opengl_state(VFrame::SCREEN);
1648                 }
1649         }
1650
1651         command->canvas->unlock_canvas();
1652 #endif // HAVE_GL
1653 }
1654
1655 void Playback3D::do_fade(Canvas *canvas, VFrame *frame, float fade)
1656 {
1657         Playback3DCommand command;
1658         command.command = Playback3DCommand::DO_FADE;
1659         command.canvas = canvas;
1660         command.frame = frame;
1661         command.alpha = fade;
1662         send_command(&command);
1663 }
1664
1665 void Playback3D::do_fade_sync(Playback3DCommand *command)
1666 {
1667 #ifdef HAVE_GL
1668         BC_WindowBase *window =
1669                 command->canvas->lock_canvas("Playback3D::do_fade_sync");
1670         if( window ) {
1671                 window->enable_opengl();
1672                 switch( command->frame->get_opengl_state() ) {
1673                 case VFrame::RAM:
1674                         command->frame->to_texture();
1675                         break;
1676
1677                 case VFrame::SCREEN:
1678 // Read back from PBuffer
1679 // Bind context to pbuffer
1680                         command->frame->enable_opengl();
1681                         command->frame->screen_to_texture();
1682                         break;
1683                 }
1684
1685                 command->frame->enable_opengl();
1686                 command->frame->init_screen();
1687                 command->frame->bind_texture(0);
1688
1689 //              glClearColor(0.0, 0.0, 0.0, 0.0);
1690 //              glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1691                 glDisable(GL_BLEND);
1692                 unsigned int frag_shader = 0;
1693                 switch(command->frame->get_color_model())
1694                 {
1695 // For the alpha colormodels, the native function seems to multiply the
1696 // components by the alpha instead of just the alpha.
1697                         case BC_RGBA8888:
1698                         case BC_RGBA_FLOAT:
1699                         case BC_YUVA8888:
1700                                 frag_shader = VFrame::make_shader(0, fade_rgba_frag, 0);
1701                                 break;
1702
1703                         case BC_RGB888:
1704                                 glEnable(GL_BLEND);
1705                                 glBlendFunc(GL_SRC_ALPHA, GL_ZERO);
1706                                 glColor4f(command->alpha, command->alpha, command->alpha, 1);
1707                                 break;
1708
1709
1710                         case BC_YUV888:
1711                                 frag_shader = VFrame::make_shader(0, fade_yuv_frag, 0);
1712                                 break;
1713                 }
1714
1715
1716                 if( frag_shader ) {
1717                         glUseProgram(frag_shader);
1718                         int variable;
1719                         if((variable = glGetUniformLocation(frag_shader, "tex")) >= 0)
1720                                 glUniform1i(variable, 0);
1721                         if((variable = glGetUniformLocation(frag_shader, "alpha")) >= 0)
1722                                 glUniform1f(variable, command->alpha);
1723                 }
1724
1725                 command->frame->draw_texture();
1726                 command->frame->set_opengl_state(VFrame::SCREEN);
1727
1728                 if(frag_shader)
1729                 {
1730                         glUseProgram(0);
1731                 }
1732
1733                 glColor4f(1, 1, 1, 1);
1734                 glDisable(GL_BLEND);
1735         }
1736         command->canvas->unlock_canvas();
1737 #endif
1738 }
1739
1740
1741 int Playback3D::run_plugin(Canvas *canvas, PluginClient *client)
1742 {
1743         Playback3DCommand command;
1744         command.command = Playback3DCommand::PLUGIN;
1745         command.canvas = canvas;
1746         command.plugin_client = client;
1747         return send_command(&command);
1748 }
1749
1750 void Playback3D::run_plugin_sync(Playback3DCommand *command)
1751 {
1752         BC_WindowBase *window =
1753                 command->canvas->lock_canvas("Playback3D::run_plugin_sync");
1754         if( window ) {
1755                 window->enable_opengl();
1756                 command->result = ((PluginVClient*)command->plugin_client)->handle_opengl();
1757         }
1758         command->canvas->unlock_canvas();
1759 }
1760
1761