4 * Copyright (C) 2009 Adam Williams <broadcast at earthling dot net>
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.
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.
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
22 #define GL_GLEXT_PROTOTYPES
24 #include "bcsignals.h"
25 #include "bcwindowbase.h"
28 #include "condition.h"
29 #include "maskautos.h"
32 #include "overlayframe.inc"
33 #include "playback3d.h"
34 #include "pluginclient.h"
35 #include "pluginvclient.h"
36 #include "transportque.inc"
52 // These should be passed to VFrame::make_shader to construct shaders.
53 // Can't hard code sampler2D
56 static const char *yuv_to_rgb_frag =
57 "uniform sampler2D tex;\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"
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"
69 static const char *yuva_to_yuv_frag =
70 "uniform sampler2D tex;\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"
77 " yuva.g = yuva.g * a + 0.5 * anti_a;\n"
78 " yuva.b = yuva.b * a + 0.5 * anti_a;\n"
80 " gl_FragColor = yuva;\n"
83 static const char *yuva_to_rgb_frag =
84 "uniform sampler2D tex;\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"
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"
96 " gl_FragColor = yuva;\n"
99 static const char *rgb_to_yuv_frag =
100 "uniform sampler2D tex;\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"
114 static const char *rgba_to_rgb_frag =
115 "uniform sampler2D tex;\n"
118 " vec4 rgba = texture2D(tex, gl_TexCoord[0].st);\n"
119 " rgba.rgb *= rgba.a;\n"
121 " gl_FragColor = rgba;\n"
124 static const char *rgba_to_yuv_frag =
125 "uniform sampler2D tex;\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"
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"
140 static const char *rgba_to_rgb_flatten =
142 " gl_FragColor.rgb *= gl_FragColor.a;\n"
143 " gl_FragColor.a = 1.0;\n"
147 static const char *blend_normal_frag =
148 "uniform sampler2D tex2;\n"
149 "uniform vec2 tex2_dimensions;\n"
150 "uniform float alpha;\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"
159 static const char *blend_add_frag =
160 "uniform sampler2D tex2;\n"
161 "uniform vec2 tex2_dimensions;\n"
162 "uniform float alpha;\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"
172 static const char *blend_subtract_frag =
173 "uniform sampler2D tex2;\n"
174 "uniform vec2 tex2_dimensions;\n"
175 "uniform float alpha;\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"
185 static const char *blend_multiply_frag =
186 "uniform sampler2D tex2;\n"
187 "uniform vec2 tex2_dimensions;\n"
188 "uniform float alpha;\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"
197 static const char *blend_divide_frag =
198 "uniform sampler2D tex2;\n"
199 "uniform vec2 tex2_dimensions;\n"
200 "uniform float alpha;\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"
214 static const char *blend_replace_frag =
215 "uniform float alpha;\n"
217 " gl_FragColor.a *= alpha;\n"
221 static const char *blend_max_frag =
222 "uniform sampler2D tex2;\n"
223 "uniform vec2 tex2_dimensions;\n"
224 "uniform float alpha;\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"
234 static const char *blend_min_frag =
235 "uniform sampler2D tex2;\n"
236 "uniform vec2 tex2_dimensions;\n"
237 "uniform float alpha;\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"
247 static const char *blend_average_frag =
248 "uniform sampler2D tex2;\n"
249 "uniform vec2 tex2_dimensions;\n"
250 "uniform float alpha;\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"
260 static const char *blend_darken_frag =
261 "uniform sampler2D tex2;\n"
262 "uniform vec2 tex2_dimensions;\n"
263 "uniform float alpha;\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"
276 static const char *blend_lighten_frag =
277 "uniform sampler2D tex2;\n"
278 "uniform vec2 tex2_dimensions;\n"
279 "uniform float alpha;\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"
292 static const char *blend_dst_frag =
293 "uniform sampler2D tex2;\n"
294 "uniform vec2 tex2_dimensions;\n"
295 "uniform float alpha;\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"
305 static const char *blend_dst_atop_frag =
306 "uniform sampler2D tex2;\n"
307 "uniform vec2 tex2_dimensions;\n"
308 "uniform float alpha;\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"
318 static const char *blend_dst_in_frag =
319 "uniform sampler2D tex2;\n"
320 "uniform vec2 tex2_dimensions;\n"
321 "uniform float alpha;\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"
330 static const char *blend_dst_out_frag =
331 "uniform sampler2D tex2;\n"
332 "uniform vec2 tex2_dimensions;\n"
333 "uniform float alpha;\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"
342 static const char *blend_dst_over_frag =
343 "uniform sampler2D tex2;\n"
344 "uniform vec2 tex2_dimensions;\n"
345 "uniform float alpha;\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"
355 static const char *blend_src_frag =
356 "uniform sampler2D tex2;\n"
357 "uniform vec2 tex2_dimensions;\n"
358 "uniform float alpha;\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"
367 static const char *blend_src_atop_frag =
368 "uniform sampler2D tex2;\n"
369 "uniform vec2 tex2_dimensions;\n"
370 "uniform float alpha;\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"
380 static const char *blend_src_in_frag =
381 "uniform sampler2D tex2;\n"
382 "uniform vec2 tex2_dimensions;\n"
383 "uniform float alpha;\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"
392 static const char *blend_src_out_frag =
393 "uniform sampler2D tex2;\n"
394 "uniform vec2 tex2_dimensions;\n"
395 "uniform float alpha;\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"
404 static const char *blend_src_over_frag =
405 "uniform sampler2D tex2;\n"
406 "uniform vec2 tex2_dimensions;\n"
407 "uniform float alpha;\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"
417 static const char *blend_or_frag =
418 "uniform sampler2D tex2;\n"
419 "uniform vec2 tex2_dimensions;\n"
420 "uniform float alpha;\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"
430 static const char *blend_xor_frag =
431 "uniform sampler2D tex2;\n"
432 "uniform vec2 tex2_dimensions;\n"
433 "uniform float alpha;\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"
443 static const char *read_texture_frag =
444 "uniform sampler2D tex;\n"
447 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
450 static const char *multiply_mask4_frag =
451 "uniform sampler2D tex;\n"
452 "uniform sampler2D tex1;\n"
453 "uniform float scale;\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"
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"
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"
472 static const char *multiply_yuvmask3_frag =
473 "uniform sampler2D tex;\n"
474 "uniform sampler2D tex1;\n"
475 "uniform float scale;\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"
485 static const char *fade_rgba_frag =
486 "uniform sampler2D tex;\n"
487 "uniform float alpha;\n"
490 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
491 " gl_FragColor.a *= alpha;\n"
494 static const char *fade_yuv_frag =
495 "uniform sampler2D tex;\n"
496 "uniform float alpha;\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"
514 Playback3DCommand::Playback3DCommand()
515 : BC_SynchronousCommand()
521 void Playback3DCommand::copy_from(BC_SynchronousCommand *command)
523 Playback3DCommand *ptr = (Playback3DCommand*)command;
524 this->canvas = ptr->canvas;
525 this->is_cleared = ptr->is_cleared;
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;
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;
549 BC_SynchronousCommand::copy_from(command);
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)
558 // printf("glDebug: %d:%d; %d/%d %s\n",src,typ,id,svy,msg);
562 Playback3D::Playback3D(MWindow *mwindow)
565 this->mwindow = mwindow;
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);
574 Playback3D::~Playback3D()
581 BC_SynchronousCommand* Playback3D::new_command()
583 return new Playback3DCommand;
588 void Playback3D::handle_command(BC_SynchronousCommand *command)
590 //printf("Playback3D::handle_command 1 %d\n", command->command);
591 switch(command->command)
593 case Playback3DCommand::WRITE_BUFFER:
594 write_buffer_sync((Playback3DCommand*)command);
597 case Playback3DCommand::CLEAR_OUTPUT:
598 clear_output_sync((Playback3DCommand*)command);
601 case Playback3DCommand::CLEAR_INPUT:
602 clear_input_sync((Playback3DCommand*)command);
605 case Playback3DCommand::DO_CAMERA:
606 do_camera_sync((Playback3DCommand*)command);
609 case Playback3DCommand::OVERLAY:
610 overlay_sync((Playback3DCommand*)command);
613 case Playback3DCommand::DO_FADE:
614 do_fade_sync((Playback3DCommand*)command);
617 case Playback3DCommand::DO_MASK:
618 do_mask_sync((Playback3DCommand*)command);
621 case Playback3DCommand::PLUGIN:
622 run_plugin_sync((Playback3DCommand*)command);
625 case Playback3DCommand::COPY_FROM:
626 copy_from_sync((Playback3DCommand*)command);
629 case Playback3DCommand::CONVERT_CMODEL:
630 convert_cmodel_sync((Playback3DCommand*)command);
633 // case Playback3DCommand::DRAW_REFRESH:
634 // draw_refresh_sync((Playback3DCommand*)command);
637 //printf("Playback3D::handle_command 10\n");
643 void Playback3D::copy_from(Canvas *canvas,
648 Playback3DCommand command;
649 command.command = Playback3DCommand::COPY_FROM;
650 command.canvas = canvas;
653 command.want_texture = want_texture;
654 send_command(&command);
657 void Playback3D::copy_from_sync(Playback3DCommand *command)
660 command->canvas->lock_canvas("Playback3D::draw_refresh_sync");
661 BC_WindowBase *window = command->canvas->get_canvas();
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();
669 if(command->input->get_opengl_state() == VFrame::SCREEN &&
670 w == command->frame->get_w() && h == command->frame->get_h())
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,
681 printf("Playback3D::copy_from_sync: w=%d not supported because it is not divisible by 4.\n", w);
685 if(command->want_texture)
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);
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);
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());
711 window->unlock_window();
713 command->canvas->unlock_canvas();
720 // void Playback3D::draw_refresh(Canvas *canvas,
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);
746 // void Playback3D::draw_refresh_sync(Playback3DCommand *command)
748 // command->canvas->lock_canvas("Playback3D::draw_refresh_sync");
749 // BC_WindowBase *window = command->canvas->get_canvas();
752 // window->lock_window("Playback3D:draw_refresh_sync");
753 // window->enable_opengl();
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,
761 // command->frame->get_w(),
762 // command->frame->get_h(),
765 // command->frame->to_ram();
767 // window->clear_box(0,
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),
782 // window->unlock_window();
784 // command->canvas->unlock_canvas();
791 void Playback3D::write_buffer(Canvas *canvas,
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);
820 void Playback3D::write_buffer_sync(Playback3DCommand *command)
822 command->canvas->lock_canvas("Playback3D::write_buffer_sync");
823 if(command->canvas->get_canvas())
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();
833 //printf("Playback3D::write_buffer_sync 1 %d\n", window->get_id());
834 switch(command->frame->get_opengl_state())
836 // Upload texture and composite to screen
838 command->frame->to_texture();
839 draw_output(command);
841 // Composite texture to screen and swap buffer
842 case VFrame::TEXTURE:
843 draw_output(command);
847 window->flip_opengl();
850 printf("Playback3D::write_buffer_sync unknown state\n");
853 window->unlock_window();
856 command->canvas->unlock_canvas();
861 void Playback3D::draw_output(Playback3DCommand *command)
864 int texture_id = command->frame->get_texture_id();
865 BC_WindowBase *window = command->canvas->get_canvas();
867 // printf("Playback3D::draw_output 1 texture_id=%d window=%p\n",
869 // command->canvas->get_canvas());
874 // If virtual console is being used, everything in this function has
875 // already been done except the page flip.
878 canvas_w = window->get_w();
879 canvas_h = window->get_h();
880 VFrame::init_screen(canvas_w, canvas_h);
882 if(!command->is_cleared)
884 // If we get here, the virtual console was not used.
889 // Undo any previous shader settings
890 command->frame->bind_texture(0);
895 // Convert colormodel
896 unsigned int frag_shader = 0;
897 switch(command->frame->get_color_model())
901 frag_shader = VFrame::make_shader(0,
910 glUseProgram(frag_shader);
911 int variable = glGetUniformLocation(frag_shader, "tex");
912 // Set texture unit of the texture
913 glUniform1i(variable, 0);
916 if(BC_CModels::components(command->frame->get_color_model()) == 4)
919 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
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,
928 // printf("Playback3D::draw_output 2 %f,%f %f,%f -> %f,%f %f,%f\n",
940 command->canvas->get_canvas()->flip_opengl();
947 void Playback3D::init_frame(Playback3DCommand *command)
950 canvas_w = command->canvas->get_canvas()->get_w();
951 canvas_h = command->canvas->get_canvas()->get_h();
953 glClearColor(0.0, 0.0, 0.0, 0.0);
954 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
959 void Playback3D::clear_output(Canvas *canvas, VFrame *output)
961 Playback3DCommand command;
962 command.command = Playback3DCommand::CLEAR_OUTPUT;
963 command.canvas = canvas;
964 command.frame = output;
965 send_command(&command);
968 void Playback3D::clear_output_sync(Playback3DCommand *command)
970 command->canvas->lock_canvas("Playback3D::clear_output_sync");
971 if(command->canvas->get_canvas())
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();
977 // Using pbuffer for refresh frame.
980 command->frame->enable_opengl();
985 command->canvas->get_canvas()->unlock_window();
987 command->canvas->unlock_canvas();
991 void Playback3D::clear_input(Canvas *canvas, VFrame *frame)
993 Playback3DCommand command;
994 command.command = Playback3DCommand::CLEAR_INPUT;
995 command.canvas = canvas;
996 command.frame = frame;
997 send_command(&command);
1000 void Playback3D::clear_input_sync(Playback3DCommand *command)
1002 command->canvas->lock_canvas("Playback3D::clear_output_sync");
1003 if(command->canvas->get_canvas())
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();
1012 command->canvas->unlock_canvas();
1015 void Playback3D::do_camera(Canvas *canvas,
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);
1043 void Playback3D::do_camera_sync(Playback3DCommand *command)
1045 command->canvas->lock_canvas("Playback3D::do_camera_sync");
1046 if(command->canvas->get_canvas())
1048 command->canvas->get_canvas()->lock_window("Playback3D::clear_output_sync");
1049 command->canvas->get_canvas()->enable_opengl();
1051 command->input->to_texture();
1052 command->frame->enable_opengl();
1053 command->frame->init_screen();
1054 command->frame->clear_pbuffer();
1056 command->input->bind_texture(0);
1057 // Must call draw_texture in input frame to get the texture coordinates right.
1059 // printf("Playback3D::do_camera_sync 1 %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f\n",
1065 // (float)command->input->get_h() - command->out_y1,
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,
1072 (float)command->frame->get_h() - command->out_y1,
1074 (float)command->frame->get_h() - command->out_y2);
1077 command->frame->set_opengl_state(VFrame::SCREEN);
1078 command->canvas->get_canvas()->unlock_window();
1080 command->canvas->unlock_canvas();
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)
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);
1109 void Playback3D::overlay_sync(Playback3DCommand *command)
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
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();
1148 glColor4f(1, 1, 1, 1);
1149 glDisable(GL_BLEND);
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();
1160 canvas_w = window->get_w();
1161 canvas_h = window->get_h();
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
1169 command->input->to_texture();
1171 // Just composite texture to screen
1172 case VFrame::TEXTURE:
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();
1179 command->frame->enable_opengl();
1181 window->enable_opengl();
1184 printf("Playback3D::overlay_sync unknown state\n");
1189 const char *shader_stack[4] = { 0, 0, 0, 0, };
1190 int total_shaders = 0;
1192 VFrame::init_screen(canvas_w, canvas_h);
1195 command->input->bind_texture(0);
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()) {
1203 shader_stack[total_shaders++] = yuv_to_rgb_frag;
1209 #define add_shader(s) \
1210 if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag; \
1211 shader_stack[total_shaders++] = s
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]);
1220 enable_overlay_texture(command);
1221 add_shader(overlay_shaders[command->mode]);
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
1232 add_shader(rgba_to_rgb_flatten);
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);
1244 glUseProgram(frag_shader);
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);
1251 int variable = glGetUniformLocation(frag_shader, "alpha");
1252 glUniform1f(variable, command->alpha);
1253 // Set dimensions of the temp texture
1255 glUniform2f(glGetUniformLocation(frag_shader, "tex2_dimensions"),
1256 (float)temp_texture->get_texture_w(),
1257 (float)temp_texture->get_texture_h());
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);
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);
1274 // Delete temp texture
1276 delete temp_texture;
1278 glActiveTexture(GL_TEXTURE1);
1279 glDisable(GL_TEXTURE_2D);
1281 glActiveTexture(GL_TEXTURE0);
1282 glDisable(GL_TEXTURE_2D);
1284 window->unlock_window();
1286 command->canvas->unlock_canvas();
1290 void Playback3D::enable_overlay_texture(Playback3DCommand *command)
1293 glDisable(GL_BLEND);
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);
1300 // Read canvas into texture
1301 glReadBuffer(GL_BACK);
1302 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, canvas_w, canvas_h);
1307 void Playback3D::do_mask(Canvas *canvas,
1309 int64_t start_position_project,
1310 MaskAutos *keyframe_set,
1312 MaskAuto *default_auto)
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;
1323 send_command(&command);
1329 struct Vertex : ListItem<Vertex>
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;
1338 static void combine_callback(GLdouble coords[3],
1339 GLdouble *vertex_data[4],
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
1350 *dataOut = &vertex->c[0];
1355 void Playback3D::do_mask_sync(Playback3DCommand *command)
1358 command->canvas->lock_canvas("Playback3D::do_mask_sync");
1359 if(command->canvas->get_canvas())
1361 BC_WindowBase *window = command->canvas->get_canvas();
1362 window->lock_window("Playback3D::do_mask_sync");
1363 window->enable_opengl();
1365 switch(command->frame->get_opengl_state())
1368 // Time to upload to the texture
1369 command->frame->to_texture();
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();
1382 // Create PBuffer and draw the mask on it
1383 command->frame->enable_opengl();
1385 // Initialize coordinate system
1386 int w = command->frame->get_w();
1387 int h = command->frame->get_h();
1388 command->frame->init_screen();
1391 glDisable(GL_TEXTURE_2D);
1392 if(command->default_auto->mode == MASK_MULTIPLY_ALPHA)
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,
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,
1408 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
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);
1419 vertex_cache = new List<Vertex>;
1422 // Draw every submask as a new polygon
1423 int total_submasks = command->keyframe_set->total_submasks(
1424 command->start_position_project,
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++)
1431 gluTessBeginPolygon(tesselator, NULL);
1432 gluTessBeginContour(tesselator);
1433 ArrayList<MaskPoint*> *points = new ArrayList<MaskPoint*>;
1434 command->keyframe_set->get_points(points,
1436 command->start_position_project,
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++)
1445 MaskPoint *point1 = points->values[i];
1446 MaskPoint *point2 = (i >= points->total - 1) ?
1448 points->values[i + 1];
1452 if(point1->control_x2 == 0 &&
1453 point1->control_y2 == 0 &&
1454 point2->control_x1 == 0 &&
1455 point2->control_y1 == 0)
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;
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
1470 float cx3, cx2, cx1, cx0, cy3, cy2, cy1, cy0;
1477 cx3 = - x0 + 3*x1 - 3*x2 + x3;
1478 cx2 = 3*x0 - 6*x1 + 3*x2;
1482 cy3 = - y0 + 3*y1 - 3*y2 + y3;
1483 cy2 = 3*y0 - 6*y1 + 3*y2;
1487 // This equation is from Graphics Gems I.
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.
1498 float maxaccel1 = fabs(2*cy2) + fabs(6*cy3);
1499 float maxaccel2 = fabs(2*cx2) + fabs(6*cx3);
1501 float maxaccel = maxaccel1 > maxaccel2 ? maxaccel1 : maxaccel2;
1504 if(maxaccel > 8.0) h = sqrt((8.0) / maxaccel);
1505 segments = int(1/h);
1508 for(int j = 0; j <= segments; j++)
1510 float t = (float)j / segments;
1511 x = cx0 + t*(cx1 + t*(cx2 + t*cx3));
1512 y = cy0 + t*(cy1 + t*(cy2 + t*cy3));
1514 if(j > 0 || first_point)
1516 GLdouble *coord = new GLdouble[3];
1517 coord[0] = x / scale;
1518 coord[1] = -h + y / scale;
1520 coords.append(coord);
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]);
1530 gluTessEndContour(tesselator);
1531 gluTessEndPolygon(tesselator);
1532 points->remove_all_objects();
1534 coords.remove_all_objects();
1537 glCallList(display_list);
1538 glDeleteLists(display_list, 1);
1539 gluDeleteTess(tesselator);
1541 delete vertex_cache;
1544 glColor4f(1, 1, 1, 1);
1547 // Read mask into temporary texture.
1548 // For feathering, just read the part of the screen after the downscaling.
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,
1560 command->frame->get_color_model());
1561 temp_texture->bind(1);
1562 glReadBuffer(GL_BACK);
1564 // Need to add extra size to fill in the bottom right
1565 glCopyTexSubImage2D(GL_TEXTURE_2D,
1571 (int)MIN(w_scaled + 2, w),
1572 (int)MIN(h_scaled + 2, h));
1574 command->frame->bind_texture(0);
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())
1584 if(command->frame->get_color_model() == BC_YUV888)
1585 frag_shader = VFrame::make_shader(0,
1586 multiply_yuvmask3_frag,
1589 frag_shader = VFrame::make_shader(0,
1590 multiply_mask3_frag,
1594 frag_shader = VFrame::make_shader(0,
1595 multiply_mask4_frag,
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);
1614 // Write texture to PBuffer with multiply and scaling for feather.
1617 command->frame->draw_texture(0, 0, w, h, 0, 0, w, h);
1618 command->frame->set_opengl_state(VFrame::SCREEN);
1621 // Disable temp texture
1624 glActiveTexture(GL_TEXTURE1);
1625 glDisable(GL_TEXTURE_2D);
1626 delete temp_texture;
1629 glActiveTexture(GL_TEXTURE0);
1630 glDisable(GL_TEXTURE_2D);
1633 window->enable_opengl();
1634 window->unlock_window();
1636 command->canvas->unlock_canvas();
1649 void Playback3D::convert_cmodel(Canvas *canvas,
1653 // Do nothing if colormodels are equivalent in OpenGL & the image is in hardware.
1654 int src_cmodel = output->get_color_model();
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) )
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);
1679 void Playback3D::convert_cmodel_sync(Playback3DCommand *command)
1682 command->canvas->lock_canvas("Playback3D::convert_cmodel_sync");
1684 if(command->canvas->get_canvas())
1686 BC_WindowBase *window = command->canvas->get_canvas();
1687 window->lock_window("Playback3D::convert_cmodel_sync");
1688 window->enable_opengl();
1690 // Import into hardware
1691 command->frame->enable_opengl();
1692 command->frame->init_screen();
1693 command->frame->to_texture();
1695 // Colormodel permutation
1696 const char *shader = 0;
1697 int src_cmodel = command->frame->get_color_model();
1698 int dst_cmodel = command->dst_cmodel;
1704 } cmodel_shader_table_t;
1705 static cmodel_shader_table_t cmodel_shader_table[] =
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 },
1730 int table_size = sizeof(cmodel_shader_table) / sizeof(cmodel_shader_table_t);
1731 for(int i = 0; i < table_size; i++)
1733 if(cmodel_shader_table[i].src == src_cmodel &&
1734 cmodel_shader_table[i].dst == dst_cmodel)
1736 shader = cmodel_shader_table[i].shader;
1741 // printf("Playback3D::convert_cmodel_sync %d %d %d shader=\n%s",
1743 // command->frame->get_color_model(),
1744 // command->dst_cmodel,
1749 //printf("Playback3D::convert_cmodel_sync %d\n", __LINE__);
1750 command->frame->bind_texture(0);
1751 unsigned int shader_id = -1;
1754 shader_id = VFrame::make_shader(0,
1757 glUseProgram(shader_id);
1758 glUniform1i(glGetUniformLocation(shader_id, "tex"), 0);
1761 command->frame->draw_texture();
1763 if(shader) glUseProgram(0);
1765 command->frame->set_opengl_state(VFrame::SCREEN);
1768 window->unlock_window();
1771 command->canvas->unlock_canvas();
1775 void Playback3D::do_fade(Canvas *canvas, VFrame *frame, float fade)
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);
1785 void Playback3D::do_fade_sync(Playback3DCommand *command)
1788 command->canvas->lock_canvas("Playback3D::do_mask_sync");
1789 if(command->canvas->get_canvas())
1791 BC_WindowBase *window = command->canvas->get_canvas();
1792 window->lock_window("Playback3D::do_fade_sync");
1793 window->enable_opengl();
1795 switch(command->frame->get_opengl_state())
1798 command->frame->to_texture();
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();
1810 command->frame->enable_opengl();
1811 command->frame->init_screen();
1812 command->frame->bind_texture(0);
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())
1820 // For the alpha colormodels, the native function seems to multiply the
1821 // components by the alpha instead of just the alpha.
1825 frag_shader = VFrame::make_shader(0, fade_rgba_frag, 0);
1830 glBlendFunc(GL_SRC_ALPHA, GL_ZERO);
1831 glColor4f(command->alpha, command->alpha, command->alpha, 1);
1836 frag_shader = VFrame::make_shader(0, fade_yuv_frag, 0);
1843 glUseProgram(frag_shader);
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);
1851 command->frame->draw_texture();
1852 command->frame->set_opengl_state(VFrame::SCREEN);
1859 glColor4f(1, 1, 1, 1);
1860 glDisable(GL_BLEND);
1862 window->unlock_window();
1864 command->canvas->unlock_canvas();
1878 int Playback3D::run_plugin(Canvas *canvas, PluginClient *client)
1880 Playback3DCommand command;
1881 command.command = Playback3DCommand::PLUGIN;
1882 command.canvas = canvas;
1883 command.plugin_client = client;
1884 return send_command(&command);
1887 void Playback3D::run_plugin_sync(Playback3DCommand *command)
1889 command->canvas->lock_canvas("Playback3D::run_plugin_sync");
1890 if(command->canvas->get_canvas())
1892 BC_WindowBase *window = command->canvas->get_canvas();
1893 window->lock_window("Playback3D::run_plugin_sync");
1894 window->enable_opengl();
1896 command->result = ((PluginVClient*)command->plugin_client)->handle_opengl();
1898 window->unlock_window();
1900 command->canvas->unlock_canvas();