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