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