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