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