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