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