search fixes, preset fixes, ladspa icon logging, igor pref theme, drag btn rollover
[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->frame->screen_to_ram();
891                 command->canvas->get_canvas()->unlock_window();
892         }
893         command->canvas->unlock_canvas();
894 }
895
896 void Playback3D::overlay(Canvas *canvas, VFrame *input,
897         float in_x1, float in_y1, float in_x2, float in_y2,
898         float out_x1, float out_y1, float out_x2, float out_y2,
899         float alpha, int mode, int interpolation_type,
900         VFrame *output, int is_nested)
901 {
902         Playback3DCommand command;
903         command.command = Playback3DCommand::OVERLAY;
904         command.canvas = canvas;
905         command.frame = output;
906         command.input = input;
907         command.in_x1 = in_x1;
908         command.in_y1 = in_y1;
909         command.in_x2 = in_x2;
910         command.in_y2 = in_y2;
911         command.out_x1 = out_x1;
912         command.out_y1 = out_y1;
913         command.out_x2 = out_x2;
914         command.out_y2 = out_y2;
915         command.alpha = alpha;
916         command.mode = mode;
917         command.interpolation_type = interpolation_type;
918         command.is_nested = is_nested;
919         send_command(&command);
920 }
921
922 void Playback3D::overlay_sync(Playback3DCommand *command)
923 {
924 #ifdef HAVE_GL
925 // To do these operations, we need to copy the input buffer to a texture
926 // and blend 2 textures in a shader
927         static const char * const overlay_shaders[TRANSFER_TYPES] = {
928                 blend_NORMAL_frag,      // TRANSFER_NORMAL
929                 blend_ADDITION_frag,    // TRANSFER_ADDITION
930                 blend_SUBTRACT_frag,    // TRANSFER_SUBTRACT
931                 blend_MULTIPLY_frag,    // TRANSFER_MULTIPLY
932                 blend_DIVIDE_frag,      // TRANSFER_DIVIDE
933                 blend_REPLACE_frag,     // TRANSFER_REPLACE
934                 blend_MAX_frag,         // TRANSFER_MAX
935                 blend_MIN_frag,         // TRANSFER_MIN
936                 blend_DARKEN_frag,      // TRANSFER_DARKEN
937                 blend_LIGHTEN_frag,     // TRANSFER_LIGHTEN
938                 blend_DST_frag,         // TRANSFER_DST
939                 blend_DST_ATOP_frag,    // TRANSFER_DST_ATOP
940                 blend_DST_IN_frag,      // TRANSFER_DST_IN
941                 blend_DST_OUT_frag,     // TRANSFER_DST_OUT
942                 blend_DST_OVER_frag,    // TRANSFER_DST_OVER
943                 blend_SRC_frag,         // TRANSFER_SRC
944                 blend_SRC_ATOP_frag,    // TRANSFER_SRC_ATOP
945                 blend_SRC_IN_frag,      // TRANSFER_SRC_IN
946                 blend_SRC_OUT_frag,     // TRANSFER_SRC_OUT
947                 blend_SRC_OVER_frag,    // TRANSFER_SRC_OVER
948                 blend_AND_frag,         // TRANSFER_AND
949                 blend_OR_frag,          // TRANSFER_OR
950                 blend_XOR_frag,         // TRANSFER_XOR
951                 blend_OVERLAY_frag,     // TRANSFER_OVERLAY
952                 blend_SCREEN_frag,      // TRANSFER_SCREEN
953                 blend_BURN_frag,        // TRANSFER_BURN
954                 blend_DODGE_frag,       // TRANSFER_DODGE
955                 blend_HARDLIGHT_frag,   // TRANSFER_HARDLIGHT
956                 blend_SOFTLIGHT_frag,   // TRANSFER_SOFTLIGHT
957                 blend_DIFFERENCE_frag,  // TRANSFER_DIFFERENCE
958         };
959
960         command->canvas->lock_canvas("Playback3D::overlay_sync");
961         if(command->canvas->get_canvas()) {
962                 BC_WindowBase *window = command->canvas->get_canvas();
963                 window->lock_window("Playback3D::overlay_sync");
964 // Make sure OpenGL is enabled first.
965                 window->enable_opengl();
966                 window->update_video_cursor();
967
968                 glColor4f(1, 1, 1, 1);
969                 glDisable(GL_BLEND);
970
971                 if(command->frame) {
972 // Render to PBuffer
973                         command->frame->enable_opengl();
974                         command->frame->set_opengl_state(VFrame::SCREEN);
975                         canvas_w = command->frame->get_w();
976                         canvas_h = command->frame->get_h();
977                 }
978                 else {
979 // Render to canvas
980                         canvas_w = window->get_w();
981                         canvas_h = window->get_h();
982                 }
983
984
985 //printf("Playback3D::overlay_sync 1 %d\n", command->input->get_opengl_state());
986                 switch(command->input->get_opengl_state()) {
987 // Upload texture and composite to screen
988                 case VFrame::RAM:
989                         command->input->to_texture();
990                         break;
991 // Just composite texture to screen
992                 case VFrame::TEXTURE:
993                         break;
994 // read from PBuffer to texture, then composite texture to screen
995                 case VFrame::SCREEN:
996                         command->input->enable_opengl();
997                         command->input->screen_to_texture();
998                         if(command->frame)
999                                 command->frame->enable_opengl();
1000                         else
1001                                 window->enable_opengl();
1002                         break;
1003                 default:
1004                         printf("Playback3D::overlay_sync unknown state\n");
1005                         break;
1006                 }
1007
1008
1009                 const char *shader_stack[4] = { 0, 0, 0, 0, };
1010                 int total_shaders = 0;
1011
1012                 VFrame::init_screen(canvas_w, canvas_h);
1013
1014 // Enable texture
1015                 command->input->bind_texture(0);
1016
1017 // Convert colormodel to RGB if not nested.
1018 // The color model setting in the output frame is ignored.
1019                 if( command->is_nested <= 0 ) {  // not nested
1020                         switch(command->input->get_color_model()) {
1021                         case BC_YUV888:
1022                         case BC_YUVA8888:
1023                                 shader_stack[total_shaders++] = yuv_to_rgb_frag;
1024                                 break;
1025                         }
1026                 }
1027
1028 // get the shaders
1029 #define add_shader(s) \
1030   if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag; \
1031   shader_stack[total_shaders++] = s
1032
1033                 switch(command->mode) {
1034                 case TRANSFER_REPLACE:
1035 // This requires overlaying an alpha multiplied image on a black screen.
1036                         if( command->input->get_texture_components() != 4 ) break;
1037                         add_shader(overlay_shaders[command->mode]);
1038                         break;
1039                 default:
1040                         enable_overlay_texture(command);
1041                         add_shader(overlay_shaders[command->mode]);
1042                         break;
1043                 }
1044
1045 // if to flatten alpha
1046                 if( command->is_nested < 0 ) {
1047                         switch(command->input->get_color_model()) {
1048 // yuv has already been converted to rgb
1049                         case BC_YUVA8888:
1050                         case BC_RGBA_FLOAT:
1051                         case BC_RGBA8888:
1052                                 add_shader(rgba_to_rgb_flatten);
1053                                 break;
1054                         }
1055                 }
1056
1057 // run the shaders
1058                 unsigned int frag_shader = 0;
1059                 if(shader_stack[0]) {
1060                         frag_shader = VFrame::make_shader(0,
1061                                 shader_stack[0], shader_stack[1],
1062                                 shader_stack[2], shader_stack[3], 0);
1063
1064                         glUseProgram(frag_shader);
1065
1066 // Set texture unit of the texture
1067                         glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0);
1068 // Set texture unit of the temp texture
1069                         glUniform1i(glGetUniformLocation(frag_shader, "tex2"), 1);
1070 // Set alpha
1071                         int variable = glGetUniformLocation(frag_shader, "alpha");
1072                         glUniform1f(variable, command->alpha);
1073 // Set dimensions of the temp texture
1074                         if(temp_texture)
1075                                 glUniform2f(glGetUniformLocation(frag_shader, "tex2_dimensions"),
1076                                         (float)temp_texture->get_texture_w(),
1077                                         (float)temp_texture->get_texture_h());
1078                 }
1079                 else
1080                         glUseProgram(0);
1081
1082
1083 // printf("Playback3D::overlay_sync %f %f %f %f %f %f %f %f\n",
1084 // command->in_x1, command->in_y1, command->in_x2, command->in_y2,
1085 // command->out_x1, command->out_y1, command->out_x2, command->out_y2);
1086
1087                 command->input->draw_texture(
1088                         command->in_x1, command->in_y1, command->in_x2, command->in_y2,
1089                         command->out_x1, command->out_y1, command->out_x2, command->out_y2,
1090 // Don't flip vertical if nested
1091                         command->is_nested > 0 ? 0 : 1);
1092                 glUseProgram(0);
1093
1094 // Delete temp texture
1095                 if(temp_texture) {
1096                         delete temp_texture;
1097                         temp_texture = 0;
1098                         glActiveTexture(GL_TEXTURE1);
1099                         glDisable(GL_TEXTURE_2D);
1100                 }
1101                 glActiveTexture(GL_TEXTURE0);
1102                 glDisable(GL_TEXTURE_2D);
1103
1104                 window->unlock_window();
1105         }
1106         command->canvas->unlock_canvas();
1107 #endif
1108 }
1109
1110 void Playback3D::enable_overlay_texture(Playback3DCommand *command)
1111 {
1112 #ifdef HAVE_GL
1113         glDisable(GL_BLEND);
1114
1115         glActiveTexture(GL_TEXTURE1);
1116         BC_Texture::new_texture(&temp_texture, canvas_w, canvas_h,
1117                 command->input->get_color_model());
1118         temp_texture->bind(1);
1119
1120 // Read canvas into texture
1121         glReadBuffer(GL_BACK);
1122         glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, canvas_w, canvas_h);
1123 #endif
1124 }
1125
1126
1127 void Playback3D::do_mask(Canvas *canvas,
1128         VFrame *output,
1129         int64_t start_position_project,
1130         MaskAutos *keyframe_set,
1131         MaskAuto *keyframe,
1132         MaskAuto *default_auto)
1133 {
1134         Playback3DCommand command;
1135         command.command = Playback3DCommand::DO_MASK;
1136         command.canvas = canvas;
1137         command.frame = output;
1138         command.start_position_project = start_position_project;
1139         command.keyframe_set = keyframe_set;
1140         command.keyframe = keyframe;
1141         command.default_auto = default_auto;
1142
1143         send_command(&command);
1144 }
1145
1146
1147
1148 #ifdef HAVE_GL
1149 struct Vertex : ListItem<Vertex>
1150 {
1151         GLdouble c[3];
1152 };
1153 // this list is only used from the main thread, no locking needed
1154 // this must be a list so that pointers to allocated entries remain valid
1155 // when new entries are added
1156 static List<Vertex> *vertex_cache = 0;
1157
1158 static void combine_callback(GLdouble coords[3],
1159         GLdouble *vertex_data[4],
1160         GLfloat weight[4],
1161         GLdouble **dataOut)
1162 {
1163 // can't use malloc here; GLU doesn't delete the memory for us!
1164         Vertex* vertex = vertex_cache->append();
1165         vertex->c[0] = coords[0];
1166         vertex->c[1] = coords[1];
1167         vertex->c[2] = coords[2];
1168 // we don't need to interpolate anything
1169
1170         *dataOut = &vertex->c[0];
1171 }
1172 #endif
1173
1174
1175 void Playback3D::do_mask_sync(Playback3DCommand *command)
1176 {
1177 #ifdef HAVE_GL
1178         command->canvas->lock_canvas("Playback3D::do_mask_sync");
1179         if(command->canvas->get_canvas())
1180         {
1181                 BC_WindowBase *window = command->canvas->get_canvas();
1182                 window->lock_window("Playback3D::do_mask_sync");
1183                 window->enable_opengl();
1184
1185                 switch(command->frame->get_opengl_state())
1186                 {
1187                         case VFrame::RAM:
1188 // Time to upload to the texture
1189                                 command->frame->to_texture();
1190                                 break;
1191
1192                         case VFrame::SCREEN:
1193 // Read back from PBuffer
1194 // Bind context to pbuffer
1195                                 command->frame->enable_opengl();
1196                                 command->frame->screen_to_texture();
1197                                 break;
1198                 }
1199
1200
1201
1202 // Create PBuffer and draw the mask on it
1203                 command->frame->enable_opengl();
1204
1205 // Initialize coordinate system
1206                 int w = command->frame->get_w();
1207                 int h = command->frame->get_h();
1208                 command->frame->init_screen();
1209
1210 // Clear screen
1211                 glDisable(GL_TEXTURE_2D);
1212                 if(command->default_auto->mode == MASK_MULTIPLY_ALPHA)
1213                 {
1214                         glClearColor(0.0, 0.0, 0.0, 0.0);
1215                         glColor4f((float)command->keyframe->value / 100,
1216                                 (float)command->keyframe->value / 100,
1217                                 (float)command->keyframe->value / 100,
1218                                 1.0);
1219                 }
1220                 else
1221                 {
1222                         glClearColor(1.0, 1.0, 1.0, 1.0);
1223                         glColor4f((float)1.0 - (float)command->keyframe->value / 100,
1224                                 (float)1.0 - (float)command->keyframe->value / 100,
1225                                 (float)1.0 - (float)command->keyframe->value / 100,
1226                                 1.0);
1227                 }
1228                 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1229
1230
1231 // Draw mask with scaling to simulate feathering
1232                 GLUtesselator *tesselator = gluNewTess();
1233                 gluTessProperty(tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);
1234                 gluTessCallback(tesselator, GLU_TESS_VERTEX, (GLvoid (*) ( )) &glVertex3dv);
1235                 gluTessCallback(tesselator, GLU_TESS_BEGIN, (GLvoid (*) ( )) &glBegin);
1236                 gluTessCallback(tesselator, GLU_TESS_END, (GLvoid (*) ( )) &glEnd);
1237                 gluTessCallback(tesselator, GLU_TESS_COMBINE, (GLvoid (*) ( ))&combine_callback);
1238
1239                 vertex_cache = new List<Vertex>;
1240
1241
1242 // Draw every submask as a new polygon
1243                 int total_submasks = command->keyframe_set->total_submasks(
1244                         command->start_position_project,
1245                         PLAY_FORWARD);
1246                 float scale = command->keyframe->feather + 1;
1247                 int display_list = glGenLists(1);
1248                 glNewList(display_list, GL_COMPILE);
1249                 for(int k = 0; k < total_submasks; k++)
1250                 {
1251                         gluTessBeginPolygon(tesselator, NULL);
1252                         gluTessBeginContour(tesselator);
1253                         ArrayList<MaskPoint*> *points = new ArrayList<MaskPoint*>;
1254                         command->keyframe_set->get_points(points,
1255                                 k,
1256                                 command->start_position_project,
1257                                 PLAY_FORWARD);
1258
1259                         int first_point = 0;
1260 // Need to tabulate every vertex in persistent memory because
1261 // gluTessVertex doesn't copy them.
1262                         ArrayList<GLdouble*> coords;
1263                         for(int i = 0; i < points->total; i++)
1264                         {
1265                                 MaskPoint *point1 = points->values[i];
1266                                 MaskPoint *point2 = (i >= points->total - 1) ?
1267                                         points->values[0] :
1268                                         points->values[i + 1];
1269
1270                                 float x, y;
1271                                 int segments = 0;
1272                                 if(point1->control_x2 == 0 &&
1273                                         point1->control_y2 == 0 &&
1274                                         point2->control_x1 == 0 &&
1275                                         point2->control_y1 == 0)
1276                                         segments = 1;
1277
1278                                 float x0 = point1->x;
1279                                 float y0 = point1->y;
1280                                 float x1 = point1->x + point1->control_x2;
1281                                 float y1 = point1->y + point1->control_y2;
1282                                 float x2 = point2->x + point2->control_x1;
1283                                 float y2 = point2->y + point2->control_y1;
1284                                 float x3 = point2->x;
1285                                 float y3 = point2->y;
1286
1287                                 // forward differencing bezier curves implementation taken from GPL code at
1288                                 // http://cvs.sourceforge.net/viewcvs.py/guliverkli/guliverkli/src/subtitles/Rasterizer.cpp?rev=1.3
1289
1290                                 float cx3, cx2, cx1, cx0, cy3, cy2, cy1, cy0;
1291
1292                                 // [-1 +3 -3 +1]
1293                                 // [+3 -6 +3  0]
1294                                 // [-3 +3  0  0]
1295                                 // [+1  0  0  0]
1296
1297                                 cx3 = -  x0 + 3*x1 - 3*x2 + x3;
1298                                 cx2 =  3*x0 - 6*x1 + 3*x2;
1299                                 cx1 = -3*x0 + 3*x1;
1300                                 cx0 =    x0;
1301
1302                                 cy3 = -  y0 + 3*y1 - 3*y2 + y3;
1303                                 cy2 =  3*y0 - 6*y1 + 3*y2;
1304                                 cy1 = -3*y0 + 3*y1;
1305                                 cy0 =    y0;
1306
1307                                 // This equation is from Graphics Gems I.
1308                                 //
1309                                 // The idea is that since we're approximating a cubic curve with lines,
1310                                 // any error we incur is due to the curvature of the line, which we can
1311                                 // estimate by calculating the maximum acceleration of the curve.  For
1312                                 // a cubic, the acceleration (second derivative) is a line, meaning that
1313                                 // the absolute maximum acceleration must occur at either the beginning
1314                                 // (|c2|) or the end (|c2+c3|).  Our bounds here are a little more
1315                                 // conservative than that, but that's okay.
1316                                 if (segments == 0)
1317                                 {
1318                                         float maxaccel1 = fabs(2*cy2) + fabs(6*cy3);
1319                                         float maxaccel2 = fabs(2*cx2) + fabs(6*cx3);
1320
1321                                         float maxaccel = maxaccel1 > maxaccel2 ? maxaccel1 : maxaccel2;
1322                                         float h = 1.0;
1323
1324                                         if(maxaccel > 8.0) h = sqrt((8.0) / maxaccel);
1325                                         segments = int(1/h);
1326                                 }
1327
1328                                 for(int j = 0; j <= segments; j++)
1329                                 {
1330                                         float t = (float)j / segments;
1331                                         x = cx0 + t*(cx1 + t*(cx2 + t*cx3));
1332                                         y = cy0 + t*(cy1 + t*(cy2 + t*cy3));
1333
1334                                         if(j > 0 || first_point)
1335                                         {
1336                                                 GLdouble *coord = new GLdouble[3];
1337                                                 coord[0] = x / scale;
1338                                                 coord[1] = -h + y / scale;
1339                                                 coord[2] = 0;
1340                                                 coords.append(coord);
1341                                                 first_point = 0;
1342                                         }
1343                                 }
1344                         }
1345
1346 // Now that we know the total vertices, send them to GLU
1347                         for(int i = 0; i < coords.total; i++)
1348                                 gluTessVertex(tesselator, coords.values[i], coords.values[i]);
1349
1350                         gluTessEndContour(tesselator);
1351                         gluTessEndPolygon(tesselator);
1352                         points->remove_all_objects();
1353                         delete points;
1354                         coords.remove_all_objects();
1355                 }
1356                 glEndList();
1357                 glCallList(display_list);
1358                 glDeleteLists(display_list, 1);
1359                 gluDeleteTess(tesselator);
1360
1361                 delete vertex_cache;
1362                 vertex_cache = 0;
1363
1364                 glColor4f(1, 1, 1, 1);
1365
1366
1367 // Read mask into temporary texture.
1368 // For feathering, just read the part of the screen after the downscaling.
1369
1370
1371                 float w_scaled = w / scale;
1372                 float h_scaled = h / scale;
1373 // Don't vary the texture size according to scaling because that
1374 // would waste memory.
1375 // This enables and binds the temporary texture.
1376                 glActiveTexture(GL_TEXTURE1);
1377                 BC_Texture::new_texture(&temp_texture,
1378                         w,
1379                         h,
1380                         command->frame->get_color_model());
1381                 temp_texture->bind(1);
1382                 glReadBuffer(GL_BACK);
1383
1384 // Need to add extra size to fill in the bottom right
1385                 glCopyTexSubImage2D(GL_TEXTURE_2D,
1386                         0,
1387                         0,
1388                         0,
1389                         0,
1390                         0,
1391                         (int)MIN(w_scaled + 2, w),
1392                         (int)MIN(h_scaled + 2, h));
1393
1394                 command->frame->bind_texture(0);
1395
1396
1397 // For feathered masks, use a shader to multiply.
1398 // For unfeathered masks, we could use a stencil buffer
1399 // for further optimization but we also need a YUV algorithm.
1400                 unsigned int frag_shader = 0;
1401                 switch(temp_texture->get_texture_components())
1402                 {
1403                         case 3:
1404                                 if(command->frame->get_color_model() == BC_YUV888)
1405                                         frag_shader = VFrame::make_shader(0,
1406                                                 multiply_yuvmask3_frag,
1407                                                 0);
1408                                 else
1409                                         frag_shader = VFrame::make_shader(0,
1410                                                 multiply_mask3_frag,
1411                                                 0);
1412                                 break;
1413                         case 4:
1414                                 frag_shader = VFrame::make_shader(0,
1415                                         multiply_mask4_frag,
1416                                         0);
1417                                 break;
1418                 }
1419
1420                 if(frag_shader)
1421                 {
1422                         int variable;
1423                         glUseProgram(frag_shader);
1424                         if((variable = glGetUniformLocation(frag_shader, "tex")) >= 0)
1425                                 glUniform1i(variable, 0);
1426                         if((variable = glGetUniformLocation(frag_shader, "tex1")) >= 0)
1427                                 glUniform1i(variable, 1);
1428                         if((variable = glGetUniformLocation(frag_shader, "scale")) >= 0)
1429                                 glUniform1f(variable, scale);
1430                 }
1431
1432
1433
1434 // Write texture to PBuffer with multiply and scaling for feather.
1435
1436
1437                 command->frame->draw_texture(0, 0, w, h, 0, 0, w, h);
1438                 command->frame->set_opengl_state(VFrame::SCREEN);
1439
1440
1441 // Disable temp texture
1442                 glUseProgram(0);
1443
1444                 glActiveTexture(GL_TEXTURE1);
1445                 glDisable(GL_TEXTURE_2D);
1446                 delete temp_texture;
1447                 temp_texture = 0;
1448
1449                 glActiveTexture(GL_TEXTURE0);
1450                 glDisable(GL_TEXTURE_2D);
1451
1452 // Default drawable
1453                 window->enable_opengl();
1454                 window->unlock_window();
1455         }
1456         command->canvas->unlock_canvas();
1457 #endif
1458 }
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469 void Playback3D::convert_cmodel(Canvas *canvas,
1470         VFrame *output,
1471         int dst_cmodel)
1472 {
1473 // Do nothing if colormodels are equivalent in OpenGL & the image is in hardware.
1474         int src_cmodel = output->get_color_model();
1475         if(
1476                 (output->get_opengl_state() == VFrame::TEXTURE ||
1477                 output->get_opengl_state() == VFrame::SCREEN) &&
1478 // OpenGL has no floating point.
1479                 ( (src_cmodel == BC_RGB888 && dst_cmodel == BC_RGB_FLOAT) ||
1480                   (src_cmodel == BC_RGBA8888 && dst_cmodel == BC_RGBA_FLOAT) ||
1481                   (src_cmodel == BC_RGB_FLOAT && dst_cmodel == BC_RGB888) ||
1482                   (src_cmodel == BC_RGBA_FLOAT && dst_cmodel == BC_RGBA8888) ||
1483 // OpenGL sets alpha to 1 on import
1484                   (src_cmodel == BC_RGB888 && dst_cmodel == BC_RGBA8888) ||
1485                   (src_cmodel == BC_YUV888 && dst_cmodel == BC_YUVA8888) ||
1486                   (src_cmodel == BC_RGB_FLOAT && dst_cmodel == BC_RGBA_FLOAT) )
1487                 ) return;
1488
1489
1490
1491         Playback3DCommand command;
1492         command.command = Playback3DCommand::CONVERT_CMODEL;
1493         command.canvas = canvas;
1494         command.frame = output;
1495         command.dst_cmodel = dst_cmodel;
1496         send_command(&command);
1497 }
1498
1499 void Playback3D::convert_cmodel_sync(Playback3DCommand *command)
1500 {
1501 #ifdef HAVE_GL
1502         command->canvas->lock_canvas("Playback3D::convert_cmodel_sync");
1503
1504         if(command->canvas->get_canvas())
1505         {
1506                 BC_WindowBase *window = command->canvas->get_canvas();
1507                 window->lock_window("Playback3D::convert_cmodel_sync");
1508                 window->enable_opengl();
1509
1510 // Import into hardware
1511                 command->frame->enable_opengl();
1512                 command->frame->init_screen();
1513                 command->frame->to_texture();
1514
1515 // Colormodel permutation
1516                 const char *shader = 0;
1517                 int src_cmodel = command->frame->get_color_model();
1518                 int dst_cmodel = command->dst_cmodel;
1519                 typedef struct
1520                 {
1521                         int src;
1522                         int dst;
1523                         const char *shader;
1524                 } cmodel_shader_table_t;
1525                 static cmodel_shader_table_t cmodel_shader_table[]  =
1526                 {
1527                         { BC_RGB888, BC_YUV888, rgb_to_yuv_frag },
1528                         { BC_RGB888, BC_YUVA8888, rgb_to_yuv_frag },
1529                         { BC_RGBA8888, BC_RGB888, rgba_to_rgb_frag },
1530                         { BC_RGBA8888, BC_RGB_FLOAT, rgba_to_rgb_frag },
1531                         { BC_RGBA8888, BC_YUV888, rgba_to_yuv_frag },
1532                         { BC_RGBA8888, BC_YUVA8888, rgb_to_yuv_frag },
1533                         { BC_RGB_FLOAT, BC_YUV888, rgb_to_yuv_frag },
1534                         { BC_RGB_FLOAT, BC_YUVA8888, rgb_to_yuv_frag },
1535                         { BC_RGBA_FLOAT, BC_RGB888, rgba_to_rgb_frag },
1536                         { BC_RGBA_FLOAT, BC_RGB_FLOAT, rgba_to_rgb_frag },
1537                         { BC_RGBA_FLOAT, BC_YUV888, rgba_to_yuv_frag },
1538                         { BC_RGBA_FLOAT, BC_YUVA8888, rgb_to_yuv_frag },
1539                         { BC_YUV888, BC_RGB888, yuv_to_rgb_frag },
1540                         { BC_YUV888, BC_RGBA8888, yuv_to_rgb_frag },
1541                         { BC_YUV888, BC_RGB_FLOAT, yuv_to_rgb_frag },
1542                         { BC_YUV888, BC_RGBA_FLOAT, yuv_to_rgb_frag },
1543                         { BC_YUVA8888, BC_RGB888, yuva_to_rgb_frag },
1544                         { BC_YUVA8888, BC_RGBA8888, yuv_to_rgb_frag },
1545                         { BC_YUVA8888, BC_RGB_FLOAT, yuva_to_rgb_frag },
1546                         { BC_YUVA8888, BC_RGBA_FLOAT, yuv_to_rgb_frag },
1547                         { BC_YUVA8888, BC_YUV888, yuva_to_yuv_frag },
1548                 };
1549
1550                 int table_size = sizeof(cmodel_shader_table) / sizeof(cmodel_shader_table_t);
1551                 for(int i = 0; i < table_size; i++)
1552                 {
1553                         if(cmodel_shader_table[i].src == src_cmodel &&
1554                                 cmodel_shader_table[i].dst == dst_cmodel)
1555                         {
1556                                 shader = cmodel_shader_table[i].shader;
1557                                 break;
1558                         }
1559                 }
1560
1561 // printf("Playback3D::convert_cmodel_sync %d %d %d shader=\n%s",
1562 // __LINE__,
1563 // command->frame->get_color_model(),
1564 // command->dst_cmodel,
1565 // shader);
1566
1567                 if(shader)
1568                 {
1569 //printf("Playback3D::convert_cmodel_sync %d\n", __LINE__);
1570                         command->frame->bind_texture(0);
1571                         unsigned int shader_id = -1;
1572                         if(shader)
1573                         {
1574                                 shader_id = VFrame::make_shader(0,
1575                                         shader,
1576                                         0);
1577                                 glUseProgram(shader_id);
1578                                 glUniform1i(glGetUniformLocation(shader_id, "tex"), 0);
1579                         }
1580
1581                         command->frame->draw_texture();
1582
1583                         if(shader) glUseProgram(0);
1584
1585                         command->frame->set_opengl_state(VFrame::SCREEN);
1586                 }
1587
1588                 window->unlock_window();
1589         }
1590
1591         command->canvas->unlock_canvas();
1592 #endif // HAVE_GL
1593 }
1594
1595 void Playback3D::do_fade(Canvas *canvas, VFrame *frame, float fade)
1596 {
1597         Playback3DCommand command;
1598         command.command = Playback3DCommand::DO_FADE;
1599         command.canvas = canvas;
1600         command.frame = frame;
1601         command.alpha = fade;
1602         send_command(&command);
1603 }
1604
1605 void Playback3D::do_fade_sync(Playback3DCommand *command)
1606 {
1607 #ifdef HAVE_GL
1608         command->canvas->lock_canvas("Playback3D::do_mask_sync");
1609         if(command->canvas->get_canvas())
1610         {
1611                 BC_WindowBase *window = command->canvas->get_canvas();
1612                 window->lock_window("Playback3D::do_fade_sync");
1613                 window->enable_opengl();
1614
1615                 switch(command->frame->get_opengl_state())
1616                 {
1617                         case VFrame::RAM:
1618                                 command->frame->to_texture();
1619                                 break;
1620
1621                         case VFrame::SCREEN:
1622 // Read back from PBuffer
1623 // Bind context to pbuffer
1624                                 command->frame->enable_opengl();
1625                                 command->frame->screen_to_texture();
1626                                 break;
1627                 }
1628
1629
1630                 command->frame->enable_opengl();
1631                 command->frame->init_screen();
1632                 command->frame->bind_texture(0);
1633
1634 //              glClearColor(0.0, 0.0, 0.0, 0.0);
1635 //              glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1636                 glDisable(GL_BLEND);
1637                 unsigned int frag_shader = 0;
1638                 switch(command->frame->get_color_model())
1639                 {
1640 // For the alpha colormodels, the native function seems to multiply the
1641 // components by the alpha instead of just the alpha.
1642                         case BC_RGBA8888:
1643                         case BC_RGBA_FLOAT:
1644                         case BC_YUVA8888:
1645                                 frag_shader = VFrame::make_shader(0, fade_rgba_frag, 0);
1646                                 break;
1647
1648                         case BC_RGB888:
1649                                 glEnable(GL_BLEND);
1650                                 glBlendFunc(GL_SRC_ALPHA, GL_ZERO);
1651                                 glColor4f(command->alpha, command->alpha, command->alpha, 1);
1652                                 break;
1653
1654
1655                         case BC_YUV888:
1656                                 frag_shader = VFrame::make_shader(0, fade_yuv_frag, 0);
1657                                 break;
1658                 }
1659
1660
1661                 if(frag_shader)
1662                 {
1663                         glUseProgram(frag_shader);
1664                         int variable;
1665                         if((variable = glGetUniformLocation(frag_shader, "tex")) >= 0)
1666                                 glUniform1i(variable, 0);
1667                         if((variable = glGetUniformLocation(frag_shader, "alpha")) >= 0)
1668                                 glUniform1f(variable, command->alpha);
1669                 }
1670
1671                 command->frame->draw_texture();
1672                 command->frame->set_opengl_state(VFrame::SCREEN);
1673
1674                 if(frag_shader)
1675                 {
1676                         glUseProgram(0);
1677                 }
1678
1679                 glColor4f(1, 1, 1, 1);
1680                 glDisable(GL_BLEND);
1681
1682                 window->unlock_window();
1683         }
1684         command->canvas->unlock_canvas();
1685 #endif
1686 }
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698 int Playback3D::run_plugin(Canvas *canvas, PluginClient *client)
1699 {
1700         Playback3DCommand command;
1701         command.command = Playback3DCommand::PLUGIN;
1702         command.canvas = canvas;
1703         command.plugin_client = client;
1704         return send_command(&command);
1705 }
1706
1707 void Playback3D::run_plugin_sync(Playback3DCommand *command)
1708 {
1709         command->canvas->lock_canvas("Playback3D::run_plugin_sync");
1710         if(command->canvas->get_canvas())
1711         {
1712                 BC_WindowBase *window = command->canvas->get_canvas();
1713                 window->lock_window("Playback3D::run_plugin_sync");
1714                 window->enable_opengl();
1715
1716                 command->result = ((PluginVClient*)command->plugin_client)->handle_opengl();
1717
1718                 window->unlock_window();
1719         }
1720         command->canvas->unlock_canvas();
1721 }
1722
1723