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 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
153 " vec4 result = mix(canvas, gl_FragColor, gl_FragColor.a);\n"
154 " gl_FragColor = mix(canvas, result, alpha);\n"
158 static const char *blend_add_frag =
159 "uniform sampler2D tex2;\n"
160 "uniform vec2 tex2_dimensions;\n"
161 "uniform float alpha;\n"
163 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
164 " vec4 result = canvas + gl_FragColor;\n"
165 " result = clamp(result, 0.0, 1.0);\n"
166 " gl_FragColor = mix(canvas, result, alpha);\n"
170 static const char *blend_subtract_frag =
171 "uniform sampler2D tex2;\n"
172 "uniform vec2 tex2_dimensions;\n"
173 "uniform float alpha;\n"
175 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
176 " vec4 result = gl_FragColor - canvas;\n"
177 " result = clamp(result, 0.0, 1.0);\n"
178 " gl_FragColor = mix(canvas, result, alpha);\n"
182 static const char *blend_multiply_frag =
183 "uniform sampler2D tex2;\n"
184 "uniform vec2 tex2_dimensions;\n"
185 "uniform float alpha;\n"
187 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
188 " vec4 result = canvas * gl_FragColor;\n"
189 " gl_FragColor = mix(canvas, result, alpha);\n"
193 static const char *blend_divide_frag =
194 "uniform sampler2D tex2;\n"
195 "uniform vec2 tex2_dimensions;\n"
196 "uniform float alpha;\n"
198 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
199 " vec4 result = gl_FragColor / canvas;\n"
200 " if(!canvas.r) result.r = 1.0;\n"
201 " if(!canvas.g) result.g = 1.0;\n"
202 " if(!canvas.b) result.b = 1.0;\n"
203 " if(!canvas.a) result.a = 1.0;\n"
204 " result = clamp(result, 0.0, 1.0);\n"
205 " gl_FragColor = mix(canvas, result, alpha);\n"
209 static const char *blend_replace_frag =
210 "uniform float alpha;\n"
215 static const char *blend_max_frag =
216 "uniform sampler2D tex2;\n"
217 "uniform vec2 tex2_dimensions;\n"
218 "uniform float alpha;\n"
220 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
221 " vec4 result = max(canvas, gl_FragColor);\n"
222 " result = clamp(result, 0.0, 1.0);\n"
223 " gl_FragColor = mix(canvas, result, alpha);\n"
227 static const char *blend_min_frag =
228 "uniform sampler2D tex2;\n"
229 "uniform vec2 tex2_dimensions;\n"
230 "uniform float alpha;\n"
232 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
233 " vec4 result = min(canvas, gl_FragColor);\n"
234 " result = clamp(result, 0.0, 1.0);\n"
235 " gl_FragColor = mix(canvas, result, alpha);\n"
239 static const char *blend_average_frag =
240 "uniform sampler2D tex2;\n"
241 "uniform vec2 tex2_dimensions;\n"
242 "uniform float alpha;\n"
244 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
245 " vec4 result = (canvas + gl_FragColor) * 0.5;\n"
246 " result = clamp(result, 0.0, 1.0);\n"
247 " gl_FragColor = mix(canvas, result, alpha);\n"
251 static const char *blend_darken_frag =
252 "uniform sampler2D tex2;\n"
253 "uniform vec2 tex2_dimensions;\n"
254 "uniform float alpha;\n"
256 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
257 " vec4 result = vec4(canvas.rgb * (1.0 - gl_FragColor.a) +"
258 " gl_FragColor.rgb * (1.0 - canvas.a) +"
259 " min(canvas.rgb, gl_FragColor.rgb), "
260 " canvas.a + gl_FragColor.a - canvas.a * gl_FragColor.a);\n"
261 " result = clamp(result, 0.0, 1.0);\n"
262 " gl_FragColor = mix(canvas, result, alpha);\n"
266 static const char *blend_lighten_frag =
267 "uniform sampler2D tex2;\n"
268 "uniform vec2 tex2_dimensions;\n"
269 "uniform float alpha;\n"
271 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
272 " vec4 result = vec4(canvas.rgb * (1.0 - gl_FragColor.a) +"
273 " gl_FragColor.rgb * (1.0 - canvas.a) +"
274 " max(canvas.rgb, gl_FragColor.rgb), "
275 " canvas.a + gl_FragColor.a - canvas.a * gl_FragColor.a);\n"
276 " result = clamp(result, 0.0, 1.0);\n"
277 " gl_FragColor = mix(canvas, result, alpha);\n"
281 static const char *blend_dst_frag =
282 "uniform sampler2D tex2;\n"
283 "uniform vec2 tex2_dimensions;\n"
284 "uniform float alpha;\n"
286 // " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
287 // " vec4 result = canvas;\n"
288 // " gl_FragColor = mix(result, canvas, alpha);\n"
289 " gl_FragColor = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
293 static const char *blend_dst_atop_frag =
294 "uniform sampler2D tex2;\n"
295 "uniform vec2 tex2_dimensions;\n"
296 "uniform float alpha;\n"
298 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
299 " vec4 result = vec4(canvas.rgb * gl_FragColor.a + "
300 "(1.0 - canvas.a) * gl_FragColor.rgb, gl_FragColor.a);\n"
301 " gl_FragColor = mix(canvas, result, alpha);\n"
305 static const char *blend_dst_in_frag =
306 "uniform sampler2D tex2;\n"
307 "uniform vec2 tex2_dimensions;\n"
308 "uniform float alpha;\n"
310 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
311 " vec4 result = canvas * gl_FragColor.a;\n"
312 " gl_FragColor = mix(canvas, result, alpha);\n"
316 static const char *blend_dst_out_frag =
317 "uniform sampler2D tex2;\n"
318 "uniform vec2 tex2_dimensions;\n"
319 "uniform float alpha;\n"
321 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
322 " vec4 result = canvas * (1.0 - gl_FragColor.a);\n"
323 " gl_FragColor = mix(canvas, result, alpha);\n"
327 static const char *blend_dst_over_frag =
328 "uniform sampler2D tex2;\n"
329 "uniform vec2 tex2_dimensions;\n"
330 "uniform float alpha;\n"
332 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
333 " vec4 result = vec4(canvas.rgb + (1.0 - canvas.a) * gl_FragColor.rgb, "
334 " gl_FragColor.a + canvas.a - gl_FragColor.a * canvas.a);\n"
335 " gl_FragColor = mix(canvas, result, alpha);\n"
339 static const char *blend_src_frag =
340 "uniform sampler2D tex2;\n"
341 "uniform vec2 tex2_dimensions;\n"
342 "uniform float alpha;\n"
344 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
345 " vec4 result = gl_FragColor;\n"
346 " gl_FragColor = mix(canvas, result, alpha);\n"
350 static const char *blend_src_atop_frag =
351 "uniform sampler2D tex2;\n"
352 "uniform vec2 tex2_dimensions;\n"
353 "uniform float alpha;\n"
355 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
356 " vec4 result = vec4(gl_FragColor.rgb * canvas.a + "
357 "canvas.rgb * (1.0 - gl_FragColor.a), canvas.a);\n"
358 " gl_FragColor = mix(canvas, result, alpha);\n"
362 static const char *blend_src_in_frag =
363 "uniform sampler2D tex2;\n"
364 "uniform vec2 tex2_dimensions;\n"
365 "uniform float alpha;\n"
367 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
368 " vec4 result = gl_FragColor * canvas.a;\n"
369 " gl_FragColor = mix(canvas, result, alpha);\n"
373 static const char *blend_src_out_frag =
374 "uniform sampler2D tex2;\n"
375 "uniform vec2 tex2_dimensions;\n"
376 "uniform float alpha;\n"
378 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
379 " vec4 result = gl_FragColor * (1.0 - canvas.a);\n"
380 " gl_FragColor = mix(canvas, result, alpha);\n"
384 static const char *blend_src_over_frag =
385 "uniform sampler2D tex2;\n"
386 "uniform vec2 tex2_dimensions;\n"
387 "uniform float alpha;\n"
389 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
390 " vec4 result = vec4(gl_FragColor.rgb + (1.0 - gl_FragColor.a) * canvas.rgb, "
391 "gl_FragColor.a + canvas.a - gl_FragColor.a * canvas.a);\n"
392 " gl_FragColor = mix(canvas, result, alpha);\n"
396 static const char *blend_or_frag =
397 "uniform sampler2D tex2;\n"
398 "uniform vec2 tex2_dimensions;\n"
399 "uniform float alpha;\n"
401 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
402 " vec4 result = canvas + gl_FragColor - canvas * gl_FragColor;\n"
403 " result = clamp(result, 0.0, 1.0);\n"
404 " gl_FragColor = mix(canvas, result, alpha);\n"
408 static const char *blend_xor_frag =
409 "uniform sampler2D tex2;\n"
410 "uniform vec2 tex2_dimensions;\n"
411 "uniform float alpha;\n"
413 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
414 " vec4 result = vec4(gl_FragColor.rgb * (1.0 - canvas.a) + "
415 "(1.0 - gl_FragColor.a) * canvas.rgb, "
416 "gl_FragColor.a + canvas.a - 2.0 * gl_FragColor.a * canvas.a);\n"
417 " gl_FragColor = mix(canvas, result, alpha);\n"
420 static const char *read_texture_frag =
421 "uniform sampler2D tex;\n"
424 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
427 static const char *multiply_mask4_frag =
428 "uniform sampler2D tex;\n"
429 "uniform sampler2D tex1;\n"
430 "uniform float scale;\n"
433 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
434 " gl_FragColor.a *= texture2D(tex1, gl_TexCoord[0].st / vec2(scale, scale)).r;\n"
437 static const char *multiply_mask3_frag =
438 "uniform sampler2D tex;\n"
439 "uniform sampler2D tex1;\n"
440 "uniform float scale;\n"
441 "uniform bool is_yuv;\n"
444 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
445 " float a = texture2D(tex1, gl_TexCoord[0].st / vec2(scale, scale)).r;\n"
446 " gl_FragColor.rgb *= vec3(a, a, a);\n"
449 static const char *multiply_yuvmask3_frag =
450 "uniform sampler2D tex;\n"
451 "uniform sampler2D tex1;\n"
452 "uniform float scale;\n"
455 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
456 " float a = texture2D(tex1, gl_TexCoord[0].st / vec2(scale, scale)).r;\n"
457 " gl_FragColor.gb -= vec2(0.5, 0.5);\n"
458 " gl_FragColor.rgb *= vec3(a, a, a);\n"
459 " gl_FragColor.gb += vec2(0.5, 0.5);\n"
462 static const char *fade_rgba_frag =
463 "uniform sampler2D tex;\n"
464 "uniform float alpha;\n"
467 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
468 " gl_FragColor.a *= alpha;\n"
471 static const char *fade_yuv_frag =
472 "uniform sampler2D tex;\n"
473 "uniform float alpha;\n"
476 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
477 " gl_FragColor.r *= alpha;\n"
478 " gl_FragColor.gb -= vec2(0.5, 0.5);\n"
479 " gl_FragColor.g *= alpha;\n"
480 " gl_FragColor.b *= alpha;\n"
481 " gl_FragColor.gb += vec2(0.5, 0.5);\n"
491 Playback3DCommand::Playback3DCommand()
492 : BC_SynchronousCommand()
498 void Playback3DCommand::copy_from(BC_SynchronousCommand *command)
500 Playback3DCommand *ptr = (Playback3DCommand*)command;
501 this->canvas = ptr->canvas;
502 this->is_cleared = ptr->is_cleared;
504 this->in_x1 = ptr->in_x1;
505 this->in_y1 = ptr->in_y1;
506 this->in_x2 = ptr->in_x2;
507 this->in_y2 = ptr->in_y2;
508 this->out_x1 = ptr->out_x1;
509 this->out_y1 = ptr->out_y1;
510 this->out_x2 = ptr->out_x2;
511 this->out_y2 = ptr->out_y2;
512 this->alpha = ptr->alpha;
513 this->mode = ptr->mode;
514 this->interpolation_type = ptr->interpolation_type;
516 this->input = ptr->input;
517 this->start_position_project = ptr->start_position_project;
518 this->keyframe_set = ptr->keyframe_set;
519 this->keyframe = ptr->keyframe;
520 this->default_auto = ptr->default_auto;
521 this->plugin_client = ptr->plugin_client;
522 this->want_texture = ptr->want_texture;
523 this->is_nested = ptr->is_nested;
524 this->dst_cmodel = ptr->dst_cmodel;
526 BC_SynchronousCommand::copy_from(command);
530 ///static void glDebugCallback(GLenum src, GLenum typ, GLuint id,
531 /// GLenum svy, GLsizei len, const GLchar* msg, void* dat)
532 //static void glDebugCallback(unsigned int src, unsigned int typ, unsigned int id,
533 // unsigned int svy, int len, const char* msg, const void* dat)
535 // printf("glDebug: %d:%d; %d/%d %s\n",src,typ,id,svy,msg);
539 Playback3D::Playback3D(MWindow *mwindow)
542 this->mwindow = mwindow;
544 //Enabling OpenGL debug output on nVidia drivers
545 // glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, 0, GL_TRUE);
546 // glEnable(GL_DEBUG_OUTPUT);
547 // glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
548 // glDebugMessageCallback(glDebugCallback, 0);
551 Playback3D::~Playback3D()
558 BC_SynchronousCommand* Playback3D::new_command()
560 return new Playback3DCommand;
565 void Playback3D::handle_command(BC_SynchronousCommand *command)
567 //printf("Playback3D::handle_command 1 %d\n", command->command);
568 switch(command->command)
570 case Playback3DCommand::WRITE_BUFFER:
571 write_buffer_sync((Playback3DCommand*)command);
574 case Playback3DCommand::CLEAR_OUTPUT:
575 clear_output_sync((Playback3DCommand*)command);
578 case Playback3DCommand::CLEAR_INPUT:
579 clear_input_sync((Playback3DCommand*)command);
582 case Playback3DCommand::DO_CAMERA:
583 do_camera_sync((Playback3DCommand*)command);
586 case Playback3DCommand::OVERLAY:
587 overlay_sync((Playback3DCommand*)command);
590 case Playback3DCommand::DO_FADE:
591 do_fade_sync((Playback3DCommand*)command);
594 case Playback3DCommand::DO_MASK:
595 do_mask_sync((Playback3DCommand*)command);
598 case Playback3DCommand::PLUGIN:
599 run_plugin_sync((Playback3DCommand*)command);
602 case Playback3DCommand::COPY_FROM:
603 copy_from_sync((Playback3DCommand*)command);
606 case Playback3DCommand::CONVERT_CMODEL:
607 convert_cmodel_sync((Playback3DCommand*)command);
610 // case Playback3DCommand::DRAW_REFRESH:
611 // draw_refresh_sync((Playback3DCommand*)command);
614 //printf("Playback3D::handle_command 10\n");
620 void Playback3D::copy_from(Canvas *canvas,
625 Playback3DCommand command;
626 command.command = Playback3DCommand::COPY_FROM;
627 command.canvas = canvas;
630 command.want_texture = want_texture;
631 send_command(&command);
634 void Playback3D::copy_from_sync(Playback3DCommand *command)
637 command->canvas->lock_canvas("Playback3D::draw_refresh_sync");
638 BC_WindowBase *window = command->canvas->get_canvas();
641 window->lock_window("Playback3D:draw_refresh_sync");
642 window->enable_opengl();
643 int w = command->input->get_w();
644 int h = command->input->get_h();
646 if(command->input->get_opengl_state() == VFrame::SCREEN &&
647 w == command->frame->get_w() && h == command->frame->get_h())
649 // printf("Playback3D::copy_from_sync 1 %d %d %d %d %d\n",
650 // command->input->get_w(),
651 // command->input->get_h(),
652 // command->frame->get_w(),
653 // command->frame->get_h(),
654 // command->frame->get_color_model());
655 // With NVidia at least,
658 printf("Playback3D::copy_from_sync: w=%d not supported because it is not divisible by 4.\n", w);
662 if(command->want_texture)
664 //printf("Playback3D::copy_from_sync 1 dst=%p src=%p\n", command->frame, command->input);
665 // Screen_to_texture requires the source pbuffer enabled.
666 command->input->enable_opengl();
667 command->frame->screen_to_texture();
668 command->frame->set_opengl_state(VFrame::TEXTURE);
673 command->input->enable_opengl();
674 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
675 glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE,
676 command->frame->get_rows()[0]);
677 command->frame->flip_vert();
678 command->frame->set_opengl_state(VFrame::RAM);
683 printf("Playback3D::copy_from_sync: invalid formats opengl_state=%d %dx%d -> %dx%d\n",
684 command->input->get_opengl_state(), w, h,
685 command->frame->get_w(), command->frame->get_h());
688 window->unlock_window();
690 command->canvas->unlock_canvas();
697 // void Playback3D::draw_refresh(Canvas *canvas,
708 // Playback3DCommand command;
709 // command.command = Playback3DCommand::DRAW_REFRESH;
710 // command.canvas = canvas;
711 // command.frame = frame;
712 // command.in_x1 = in_x1;
713 // command.in_y1 = in_y1;
714 // command.in_x2 = in_x2;
715 // command.in_y2 = in_y2;
716 // command.out_x1 = out_x1;
717 // command.out_y1 = out_y1;
718 // command.out_x2 = out_x2;
719 // command.out_y2 = out_y2;
720 // send_command(&command);
723 // void Playback3D::draw_refresh_sync(Playback3DCommand *command)
725 // command->canvas->lock_canvas("Playback3D::draw_refresh_sync");
726 // BC_WindowBase *window = command->canvas->get_canvas();
729 // window->lock_window("Playback3D:draw_refresh_sync");
730 // window->enable_opengl();
732 // // Read output pbuffer back to RAM in project colormodel
733 // // RGB 8bit is fastest for OpenGL to read back.
734 // command->frame->reallocate(0,
738 // command->frame->get_w(),
739 // command->frame->get_h(),
742 // command->frame->to_ram();
744 // window->clear_box(0,
748 // window->draw_vframe(command->frame,
749 // (int)command->out_x1,
750 // (int)command->out_y1,
751 // (int)(command->out_x2 - command->out_x1),
752 // (int)(command->out_y2 - command->out_y1),
753 // (int)command->in_x1,
754 // (int)command->in_y1,
755 // (int)(command->in_x2 - command->in_x1),
756 // (int)(command->in_y2 - command->in_y1),
759 // window->unlock_window();
761 // command->canvas->unlock_canvas();
768 void Playback3D::write_buffer(Canvas *canvas,
780 Playback3DCommand command;
781 command.command = Playback3DCommand::WRITE_BUFFER;
782 command.canvas = canvas;
783 command.frame = frame;
784 command.in_x1 = in_x1;
785 command.in_y1 = in_y1;
786 command.in_x2 = in_x2;
787 command.in_y2 = in_y2;
788 command.out_x1 = out_x1;
789 command.out_y1 = out_y1;
790 command.out_x2 = out_x2;
791 command.out_y2 = out_y2;
792 command.is_cleared = is_cleared;
793 send_command(&command);
797 void Playback3D::write_buffer_sync(Playback3DCommand *command)
799 command->canvas->lock_canvas("Playback3D::write_buffer_sync");
800 if(command->canvas->get_canvas())
802 BC_WindowBase *window = command->canvas->get_canvas();
803 window->lock_window("Playback3D::write_buffer_sync");
804 // Update hidden cursor
805 window->update_video_cursor();
806 // Make sure OpenGL is enabled first.
807 window->enable_opengl();
810 //printf("Playback3D::write_buffer_sync 1 %d\n", window->get_id());
811 switch(command->frame->get_opengl_state())
813 // Upload texture and composite to screen
815 command->frame->to_texture();
816 draw_output(command);
818 // Composite texture to screen and swap buffer
819 case VFrame::TEXTURE:
820 draw_output(command);
824 window->flip_opengl();
827 printf("Playback3D::write_buffer_sync unknown state\n");
830 window->unlock_window();
833 command->canvas->unlock_canvas();
838 void Playback3D::draw_output(Playback3DCommand *command)
841 int texture_id = command->frame->get_texture_id();
842 BC_WindowBase *window = command->canvas->get_canvas();
844 // printf("Playback3D::draw_output 1 texture_id=%d window=%p\n",
846 // command->canvas->get_canvas());
851 // If virtual console is being used, everything in this function has
852 // already been done except the page flip.
855 canvas_w = window->get_w();
856 canvas_h = window->get_h();
857 VFrame::init_screen(canvas_w, canvas_h);
859 if(!command->is_cleared)
861 // If we get here, the virtual console was not used.
866 // Undo any previous shader settings
867 command->frame->bind_texture(0);
872 // Convert colormodel
873 unsigned int frag_shader = 0;
874 switch(command->frame->get_color_model())
878 frag_shader = VFrame::make_shader(0,
887 glUseProgram(frag_shader);
888 int variable = glGetUniformLocation(frag_shader, "tex");
889 // Set texture unit of the texture
890 glUniform1i(variable, 0);
893 if(BC_CModels::components(command->frame->get_color_model()) == 4)
896 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
899 command->frame->draw_texture(
900 command->in_x1, command->in_y1, command->in_x2, command->in_y2,
901 command->out_x1, command->out_y1, command->out_x2, command->out_y2,
905 // printf("Playback3D::draw_output 2 %f,%f %f,%f -> %f,%f %f,%f\n",
917 command->canvas->get_canvas()->flip_opengl();
924 void Playback3D::init_frame(Playback3DCommand *command)
927 canvas_w = command->canvas->get_canvas()->get_w();
928 canvas_h = command->canvas->get_canvas()->get_h();
930 glClearColor(0.0, 0.0, 0.0, 0.0);
931 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
936 void Playback3D::clear_output(Canvas *canvas, VFrame *output)
938 Playback3DCommand command;
939 command.command = Playback3DCommand::CLEAR_OUTPUT;
940 command.canvas = canvas;
941 command.frame = output;
942 send_command(&command);
945 void Playback3D::clear_output_sync(Playback3DCommand *command)
947 command->canvas->lock_canvas("Playback3D::clear_output_sync");
948 if(command->canvas->get_canvas())
950 command->canvas->get_canvas()->lock_window("Playback3D::clear_output_sync");
951 // If we get here, the virtual console is being used.
952 command->canvas->get_canvas()->enable_opengl();
954 // Using pbuffer for refresh frame.
957 command->frame->enable_opengl();
962 command->canvas->get_canvas()->unlock_window();
964 command->canvas->unlock_canvas();
968 void Playback3D::clear_input(Canvas *canvas, VFrame *frame)
970 Playback3DCommand command;
971 command.command = Playback3DCommand::CLEAR_INPUT;
972 command.canvas = canvas;
973 command.frame = frame;
974 send_command(&command);
977 void Playback3D::clear_input_sync(Playback3DCommand *command)
979 command->canvas->lock_canvas("Playback3D::clear_output_sync");
980 if(command->canvas->get_canvas())
982 command->canvas->get_canvas()->lock_window("Playback3D::clear_output_sync");
983 command->canvas->get_canvas()->enable_opengl();
984 command->frame->enable_opengl();
985 command->frame->clear_pbuffer();
986 command->frame->set_opengl_state(VFrame::SCREEN);
987 command->canvas->get_canvas()->unlock_window();
989 command->canvas->unlock_canvas();
992 void Playback3D::do_camera(Canvas *canvas,
1004 Playback3DCommand command;
1005 command.command = Playback3DCommand::DO_CAMERA;
1006 command.canvas = canvas;
1007 command.input = input;
1008 command.frame = output;
1009 command.in_x1 = in_x1;
1010 command.in_y1 = in_y1;
1011 command.in_x2 = in_x2;
1012 command.in_y2 = in_y2;
1013 command.out_x1 = out_x1;
1014 command.out_y1 = out_y1;
1015 command.out_x2 = out_x2;
1016 command.out_y2 = out_y2;
1017 send_command(&command);
1020 void Playback3D::do_camera_sync(Playback3DCommand *command)
1022 command->canvas->lock_canvas("Playback3D::do_camera_sync");
1023 if(command->canvas->get_canvas())
1025 command->canvas->get_canvas()->lock_window("Playback3D::clear_output_sync");
1026 command->canvas->get_canvas()->enable_opengl();
1028 command->input->to_texture();
1029 command->frame->enable_opengl();
1030 command->frame->init_screen();
1031 command->frame->clear_pbuffer();
1033 command->input->bind_texture(0);
1034 // Must call draw_texture in input frame to get the texture coordinates right.
1036 // printf("Playback3D::do_camera_sync 1 %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f\n",
1042 // (float)command->input->get_h() - command->out_y1,
1044 // (float)command->input->get_h() - command->out_y2);
1045 command->input->draw_texture(
1046 command->in_x1, command->in_y2,
1047 command->in_x2, command->in_y1,
1049 (float)command->frame->get_h() - command->out_y1,
1051 (float)command->frame->get_h() - command->out_y2);
1054 command->frame->set_opengl_state(VFrame::SCREEN);
1055 command->canvas->get_canvas()->unlock_window();
1057 command->canvas->unlock_canvas();
1060 void Playback3D::overlay(Canvas *canvas, VFrame *input,
1061 float in_x1, float in_y1, float in_x2, float in_y2,
1062 float out_x1, float out_y1, float out_x2, float out_y2,
1063 float alpha, int mode, int interpolation_type,
1064 VFrame *output, int is_nested)
1066 Playback3DCommand command;
1067 command.command = Playback3DCommand::OVERLAY;
1068 command.canvas = canvas;
1069 command.frame = output;
1070 command.input = input;
1071 command.in_x1 = in_x1;
1072 command.in_y1 = in_y1;
1073 command.in_x2 = in_x2;
1074 command.in_y2 = in_y2;
1075 command.out_x1 = out_x1;
1076 command.out_y1 = out_y1;
1077 command.out_x2 = out_x2;
1078 command.out_y2 = out_y2;
1079 command.alpha = alpha;
1080 command.mode = mode;
1081 command.interpolation_type = interpolation_type;
1082 command.is_nested = is_nested;
1083 send_command(&command);
1086 void Playback3D::overlay_sync(Playback3DCommand *command)
1089 // To do these operations, we need to copy the input buffer to a texture
1090 // and blend 2 textures in a shader
1091 static const char * const overlay_shaders[TRANSFER_TYPES] = {
1092 blend_normal_frag, // TRANSFER_NORMAL
1093 blend_add_frag, // TRANSFER_ADDITION
1094 blend_subtract_frag, // TRANSFER_SUBTRACT
1095 blend_multiply_frag, // TRANSFER_MULTIPLY
1096 blend_divide_frag, // TRANSFER_DIVIDE
1097 blend_replace_frag, // TRANSFER_REPLACE
1098 blend_max_frag, // TRANSFER_MAX
1099 blend_min_frag, // TRANSFER_MIN
1100 blend_average_frag, // TRANSFER_AVERAGE
1101 blend_darken_frag, // TRANSFER_DARKEN
1102 blend_lighten_frag, // TRANSFER_LIGHTEN
1103 blend_dst_frag, // TRANSFER_DST
1104 blend_dst_atop_frag, // TRANSFER_DST_ATOP
1105 blend_dst_in_frag, // TRANSFER_DST_IN
1106 blend_dst_out_frag, // TRANSFER_DST_OUT
1107 blend_dst_over_frag, // TRANSFER_DST_OVER
1108 blend_src_frag, // TRANSFER_SRC
1109 blend_src_atop_frag, // TRANSFER_SRC_ATOP
1110 blend_src_in_frag, // TRANSFER_SRC_IN
1111 blend_src_out_frag, // TRANSFER_SRC_OUT
1112 blend_src_over_frag, // TRANSFER_SRC_OVER
1113 blend_or_frag, // TRANSFER_OR
1114 blend_xor_frag // TRANSFER_XOR
1117 command->canvas->lock_canvas("Playback3D::overlay_sync");
1118 if(command->canvas->get_canvas()) {
1119 BC_WindowBase *window = command->canvas->get_canvas();
1120 window->lock_window("Playback3D::overlay_sync");
1121 // Make sure OpenGL is enabled first.
1122 window->enable_opengl();
1123 window->update_video_cursor();
1125 glColor4f(1, 1, 1, 1);
1126 glDisable(GL_BLEND);
1128 if(command->frame) {
1129 // Render to PBuffer
1130 command->frame->enable_opengl();
1131 command->frame->set_opengl_state(VFrame::SCREEN);
1132 canvas_w = command->frame->get_w();
1133 canvas_h = command->frame->get_h();
1137 canvas_w = window->get_w();
1138 canvas_h = window->get_h();
1142 //printf("Playback3D::overlay_sync 1 %d\n", command->input->get_opengl_state());
1143 switch(command->input->get_opengl_state()) {
1144 // Upload texture and composite to screen
1146 command->input->to_texture();
1148 // Just composite texture to screen
1149 case VFrame::TEXTURE:
1151 // read from PBuffer to texture, then composite texture to screen
1152 case VFrame::SCREEN:
1153 command->input->enable_opengl();
1154 command->input->screen_to_texture();
1156 command->frame->enable_opengl();
1158 window->enable_opengl();
1161 printf("Playback3D::overlay_sync unknown state\n");
1166 const char *shader_stack[4] = { 0, 0, 0, 0, };
1167 int total_shaders = 0;
1169 VFrame::init_screen(canvas_w, canvas_h);
1172 command->input->bind_texture(0);
1174 // Convert colormodel to RGB if not nested.
1175 // The color model setting in the output frame is ignored.
1176 if( command->is_nested <= 0 ) { // not nested
1177 switch(command->input->get_color_model()) {
1180 shader_stack[total_shaders++] = yuv_to_rgb_frag;
1186 #define add_shader(s) \
1187 if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag; \
1188 shader_stack[total_shaders++] = s
1190 switch(command->mode) {
1191 case TRANSFER_REPLACE:
1192 // This requires overlaying an alpha multiplied image on a black screen.
1193 if( command->input->get_texture_components() != 4 ) break;
1194 add_shader(overlay_shaders[command->mode]);
1197 enable_overlay_texture(command);
1198 add_shader(overlay_shaders[command->mode]);
1202 // if to flatten alpha
1203 if( command->is_nested < 0 ) {
1204 switch(command->input->get_color_model()) {
1205 // yuv has already been converted to rgb
1209 add_shader(rgba_to_rgb_flatten);
1215 unsigned int frag_shader = 0;
1216 if(shader_stack[0]) {
1217 frag_shader = VFrame::make_shader(0,
1218 shader_stack[0], shader_stack[1],
1219 shader_stack[2], shader_stack[3], 0);
1221 glUseProgram(frag_shader);
1223 // Set texture unit of the texture
1224 glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0);
1225 // Set texture unit of the temp texture
1226 glUniform1i(glGetUniformLocation(frag_shader, "tex2"), 1);
1228 int variable = glGetUniformLocation(frag_shader, "alpha");
1229 glUniform1f(variable, command->alpha);
1230 // Set dimensions of the temp texture
1232 glUniform2f(glGetUniformLocation(frag_shader, "tex2_dimensions"),
1233 (float)temp_texture->get_texture_w(),
1234 (float)temp_texture->get_texture_h());
1240 // printf("Playback3D::overlay_sync %f %f %f %f %f %f %f %f\n",
1241 // command->in_x1, command->in_y1, command->in_x2, command->in_y2,
1242 // command->out_x1, command->out_y1, command->out_x2, command->out_y2);
1244 command->input->draw_texture(
1245 command->in_x1, command->in_y1, command->in_x2, command->in_y2,
1246 command->out_x1, command->out_y1, command->out_x2, command->out_y2,
1247 // Don't flip vertical if nested
1248 command->is_nested > 0 ? 0 : 1);
1251 // Delete temp texture
1253 delete temp_texture;
1255 glActiveTexture(GL_TEXTURE1);
1256 glDisable(GL_TEXTURE_2D);
1258 glActiveTexture(GL_TEXTURE0);
1259 glDisable(GL_TEXTURE_2D);
1261 window->unlock_window();
1263 command->canvas->unlock_canvas();
1267 void Playback3D::enable_overlay_texture(Playback3DCommand *command)
1270 glDisable(GL_BLEND);
1272 glActiveTexture(GL_TEXTURE1);
1273 BC_Texture::new_texture(&temp_texture, canvas_w, canvas_h,
1274 command->input->get_color_model());
1275 temp_texture->bind(1);
1277 // Read canvas into texture
1278 glReadBuffer(GL_BACK);
1279 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, canvas_w, canvas_h);
1284 void Playback3D::do_mask(Canvas *canvas,
1286 int64_t start_position_project,
1287 MaskAutos *keyframe_set,
1289 MaskAuto *default_auto)
1291 Playback3DCommand command;
1292 command.command = Playback3DCommand::DO_MASK;
1293 command.canvas = canvas;
1294 command.frame = output;
1295 command.start_position_project = start_position_project;
1296 command.keyframe_set = keyframe_set;
1297 command.keyframe = keyframe;
1298 command.default_auto = default_auto;
1300 send_command(&command);
1306 struct Vertex : ListItem<Vertex>
1310 // this list is only used from the main thread, no locking needed
1311 // this must be a list so that pointers to allocated entries remain valid
1312 // when new entries are added
1313 static List<Vertex> *vertex_cache = 0;
1315 static void combine_callback(GLdouble coords[3],
1316 GLdouble *vertex_data[4],
1320 // can't use malloc here; GLU doesn't delete the memory for us!
1321 Vertex* vertex = vertex_cache->append();
1322 vertex->c[0] = coords[0];
1323 vertex->c[1] = coords[1];
1324 vertex->c[2] = coords[2];
1325 // we don't need to interpolate anything
1327 *dataOut = &vertex->c[0];
1332 void Playback3D::do_mask_sync(Playback3DCommand *command)
1335 command->canvas->lock_canvas("Playback3D::do_mask_sync");
1336 if(command->canvas->get_canvas())
1338 BC_WindowBase *window = command->canvas->get_canvas();
1339 window->lock_window("Playback3D::do_mask_sync");
1340 window->enable_opengl();
1342 switch(command->frame->get_opengl_state())
1345 // Time to upload to the texture
1346 command->frame->to_texture();
1349 case VFrame::SCREEN:
1350 // Read back from PBuffer
1351 // Bind context to pbuffer
1352 command->frame->enable_opengl();
1353 command->frame->screen_to_texture();
1359 // Create PBuffer and draw the mask on it
1360 command->frame->enable_opengl();
1362 // Initialize coordinate system
1363 int w = command->frame->get_w();
1364 int h = command->frame->get_h();
1365 command->frame->init_screen();
1368 glDisable(GL_TEXTURE_2D);
1369 if(command->default_auto->mode == MASK_MULTIPLY_ALPHA)
1371 glClearColor(0.0, 0.0, 0.0, 0.0);
1372 glColor4f((float)command->keyframe->value / 100,
1373 (float)command->keyframe->value / 100,
1374 (float)command->keyframe->value / 100,
1379 glClearColor(1.0, 1.0, 1.0, 1.0);
1380 glColor4f((float)1.0 - (float)command->keyframe->value / 100,
1381 (float)1.0 - (float)command->keyframe->value / 100,
1382 (float)1.0 - (float)command->keyframe->value / 100,
1385 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1388 // Draw mask with scaling to simulate feathering
1389 GLUtesselator *tesselator = gluNewTess();
1390 gluTessProperty(tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);
1391 gluTessCallback(tesselator, GLU_TESS_VERTEX, (GLvoid (*) ( )) &glVertex3dv);
1392 gluTessCallback(tesselator, GLU_TESS_BEGIN, (GLvoid (*) ( )) &glBegin);
1393 gluTessCallback(tesselator, GLU_TESS_END, (GLvoid (*) ( )) &glEnd);
1394 gluTessCallback(tesselator, GLU_TESS_COMBINE, (GLvoid (*) ( ))&combine_callback);
1396 vertex_cache = new List<Vertex>;
1399 // Draw every submask as a new polygon
1400 int total_submasks = command->keyframe_set->total_submasks(
1401 command->start_position_project,
1403 float scale = command->keyframe->feather + 1;
1404 int display_list = glGenLists(1);
1405 glNewList(display_list, GL_COMPILE);
1406 for(int k = 0; k < total_submasks; k++)
1408 gluTessBeginPolygon(tesselator, NULL);
1409 gluTessBeginContour(tesselator);
1410 ArrayList<MaskPoint*> *points = new ArrayList<MaskPoint*>;
1411 command->keyframe_set->get_points(points,
1413 command->start_position_project,
1416 int first_point = 0;
1417 // Need to tabulate every vertex in persistent memory because
1418 // gluTessVertex doesn't copy them.
1419 ArrayList<GLdouble*> coords;
1420 for(int i = 0; i < points->total; i++)
1422 MaskPoint *point1 = points->values[i];
1423 MaskPoint *point2 = (i >= points->total - 1) ?
1425 points->values[i + 1];
1429 if(point1->control_x2 == 0 &&
1430 point1->control_y2 == 0 &&
1431 point2->control_x1 == 0 &&
1432 point2->control_y1 == 0)
1435 float x0 = point1->x;
1436 float y0 = point1->y;
1437 float x1 = point1->x + point1->control_x2;
1438 float y1 = point1->y + point1->control_y2;
1439 float x2 = point2->x + point2->control_x1;
1440 float y2 = point2->y + point2->control_y1;
1441 float x3 = point2->x;
1442 float y3 = point2->y;
1444 // forward differencing bezier curves implementation taken from GPL code at
1445 // http://cvs.sourceforge.net/viewcvs.py/guliverkli/guliverkli/src/subtitles/Rasterizer.cpp?rev=1.3
1447 float cx3, cx2, cx1, cx0, cy3, cy2, cy1, cy0;
1454 cx3 = - x0 + 3*x1 - 3*x2 + x3;
1455 cx2 = 3*x0 - 6*x1 + 3*x2;
1459 cy3 = - y0 + 3*y1 - 3*y2 + y3;
1460 cy2 = 3*y0 - 6*y1 + 3*y2;
1464 // This equation is from Graphics Gems I.
1466 // The idea is that since we're approximating a cubic curve with lines,
1467 // any error we incur is due to the curvature of the line, which we can
1468 // estimate by calculating the maximum acceleration of the curve. For
1469 // a cubic, the acceleration (second derivative) is a line, meaning that
1470 // the absolute maximum acceleration must occur at either the beginning
1471 // (|c2|) or the end (|c2+c3|). Our bounds here are a little more
1472 // conservative than that, but that's okay.
1475 float maxaccel1 = fabs(2*cy2) + fabs(6*cy3);
1476 float maxaccel2 = fabs(2*cx2) + fabs(6*cx3);
1478 float maxaccel = maxaccel1 > maxaccel2 ? maxaccel1 : maxaccel2;
1481 if(maxaccel > 8.0) h = sqrt((8.0) / maxaccel);
1482 segments = int(1/h);
1485 for(int j = 0; j <= segments; j++)
1487 float t = (float)j / segments;
1488 x = cx0 + t*(cx1 + t*(cx2 + t*cx3));
1489 y = cy0 + t*(cy1 + t*(cy2 + t*cy3));
1491 if(j > 0 || first_point)
1493 GLdouble *coord = new GLdouble[3];
1494 coord[0] = x / scale;
1495 coord[1] = -h + y / scale;
1497 coords.append(coord);
1503 // Now that we know the total vertices, send them to GLU
1504 for(int i = 0; i < coords.total; i++)
1505 gluTessVertex(tesselator, coords.values[i], coords.values[i]);
1507 gluTessEndContour(tesselator);
1508 gluTessEndPolygon(tesselator);
1509 points->remove_all_objects();
1511 coords.remove_all_objects();
1514 glCallList(display_list);
1515 glDeleteLists(display_list, 1);
1516 gluDeleteTess(tesselator);
1518 delete vertex_cache;
1521 glColor4f(1, 1, 1, 1);
1524 // Read mask into temporary texture.
1525 // For feathering, just read the part of the screen after the downscaling.
1528 float w_scaled = w / scale;
1529 float h_scaled = h / scale;
1530 // Don't vary the texture size according to scaling because that
1531 // would waste memory.
1532 // This enables and binds the temporary texture.
1533 glActiveTexture(GL_TEXTURE1);
1534 BC_Texture::new_texture(&temp_texture,
1537 command->frame->get_color_model());
1538 temp_texture->bind(1);
1539 glReadBuffer(GL_BACK);
1541 // Need to add extra size to fill in the bottom right
1542 glCopyTexSubImage2D(GL_TEXTURE_2D,
1548 (int)MIN(w_scaled + 2, w),
1549 (int)MIN(h_scaled + 2, h));
1551 command->frame->bind_texture(0);
1554 // For feathered masks, use a shader to multiply.
1555 // For unfeathered masks, we could use a stencil buffer
1556 // for further optimization but we also need a YUV algorithm.
1557 unsigned int frag_shader = 0;
1558 switch(temp_texture->get_texture_components())
1561 if(command->frame->get_color_model() == BC_YUV888)
1562 frag_shader = VFrame::make_shader(0,
1563 multiply_yuvmask3_frag,
1566 frag_shader = VFrame::make_shader(0,
1567 multiply_mask3_frag,
1571 frag_shader = VFrame::make_shader(0,
1572 multiply_mask4_frag,
1580 glUseProgram(frag_shader);
1581 if((variable = glGetUniformLocation(frag_shader, "tex")) >= 0)
1582 glUniform1i(variable, 0);
1583 if((variable = glGetUniformLocation(frag_shader, "tex1")) >= 0)
1584 glUniform1i(variable, 1);
1585 if((variable = glGetUniformLocation(frag_shader, "scale")) >= 0)
1586 glUniform1f(variable, scale);
1591 // Write texture to PBuffer with multiply and scaling for feather.
1594 command->frame->draw_texture(0, 0, w, h, 0, 0, w, h);
1595 command->frame->set_opengl_state(VFrame::SCREEN);
1598 // Disable temp texture
1601 glActiveTexture(GL_TEXTURE1);
1602 glDisable(GL_TEXTURE_2D);
1603 delete temp_texture;
1606 glActiveTexture(GL_TEXTURE0);
1607 glDisable(GL_TEXTURE_2D);
1610 window->enable_opengl();
1611 window->unlock_window();
1613 command->canvas->unlock_canvas();
1626 void Playback3D::convert_cmodel(Canvas *canvas,
1630 // Do nothing if colormodels are equivalent in OpenGL & the image is in hardware.
1631 int src_cmodel = output->get_color_model();
1633 (output->get_opengl_state() == VFrame::TEXTURE ||
1634 output->get_opengl_state() == VFrame::SCREEN) &&
1635 // OpenGL has no floating point.
1636 ( (src_cmodel == BC_RGB888 && dst_cmodel == BC_RGB_FLOAT) ||
1637 (src_cmodel == BC_RGBA8888 && dst_cmodel == BC_RGBA_FLOAT) ||
1638 (src_cmodel == BC_RGB_FLOAT && dst_cmodel == BC_RGB888) ||
1639 (src_cmodel == BC_RGBA_FLOAT && dst_cmodel == BC_RGBA8888) ||
1640 // OpenGL sets alpha to 1 on import
1641 (src_cmodel == BC_RGB888 && dst_cmodel == BC_RGBA8888) ||
1642 (src_cmodel == BC_YUV888 && dst_cmodel == BC_YUVA8888) ||
1643 (src_cmodel == BC_RGB_FLOAT && dst_cmodel == BC_RGBA_FLOAT) )
1648 Playback3DCommand command;
1649 command.command = Playback3DCommand::CONVERT_CMODEL;
1650 command.canvas = canvas;
1651 command.frame = output;
1652 command.dst_cmodel = dst_cmodel;
1653 send_command(&command);
1656 void Playback3D::convert_cmodel_sync(Playback3DCommand *command)
1659 command->canvas->lock_canvas("Playback3D::convert_cmodel_sync");
1661 if(command->canvas->get_canvas())
1663 BC_WindowBase *window = command->canvas->get_canvas();
1664 window->lock_window("Playback3D::convert_cmodel_sync");
1665 window->enable_opengl();
1667 // Import into hardware
1668 command->frame->enable_opengl();
1669 command->frame->init_screen();
1670 command->frame->to_texture();
1672 // Colormodel permutation
1673 const char *shader = 0;
1674 int src_cmodel = command->frame->get_color_model();
1675 int dst_cmodel = command->dst_cmodel;
1681 } cmodel_shader_table_t;
1682 static cmodel_shader_table_t cmodel_shader_table[] =
1684 { BC_RGB888, BC_YUV888, rgb_to_yuv_frag },
1685 { BC_RGB888, BC_YUVA8888, rgb_to_yuv_frag },
1686 { BC_RGBA8888, BC_RGB888, rgba_to_rgb_frag },
1687 { BC_RGBA8888, BC_RGB_FLOAT, rgba_to_rgb_frag },
1688 { BC_RGBA8888, BC_YUV888, rgba_to_yuv_frag },
1689 { BC_RGBA8888, BC_YUVA8888, rgb_to_yuv_frag },
1690 { BC_RGB_FLOAT, BC_YUV888, rgb_to_yuv_frag },
1691 { BC_RGB_FLOAT, BC_YUVA8888, rgb_to_yuv_frag },
1692 { BC_RGBA_FLOAT, BC_RGB888, rgba_to_rgb_frag },
1693 { BC_RGBA_FLOAT, BC_RGB_FLOAT, rgba_to_rgb_frag },
1694 { BC_RGBA_FLOAT, BC_YUV888, rgba_to_yuv_frag },
1695 { BC_RGBA_FLOAT, BC_YUVA8888, rgb_to_yuv_frag },
1696 { BC_YUV888, BC_RGB888, yuv_to_rgb_frag },
1697 { BC_YUV888, BC_RGBA8888, yuv_to_rgb_frag },
1698 { BC_YUV888, BC_RGB_FLOAT, yuv_to_rgb_frag },
1699 { BC_YUV888, BC_RGBA_FLOAT, yuv_to_rgb_frag },
1700 { BC_YUVA8888, BC_RGB888, yuva_to_rgb_frag },
1701 { BC_YUVA8888, BC_RGBA8888, yuv_to_rgb_frag },
1702 { BC_YUVA8888, BC_RGB_FLOAT, yuva_to_rgb_frag },
1703 { BC_YUVA8888, BC_RGBA_FLOAT, yuv_to_rgb_frag },
1704 { BC_YUVA8888, BC_YUV888, yuva_to_yuv_frag },
1707 int table_size = sizeof(cmodel_shader_table) / sizeof(cmodel_shader_table_t);
1708 for(int i = 0; i < table_size; i++)
1710 if(cmodel_shader_table[i].src == src_cmodel &&
1711 cmodel_shader_table[i].dst == dst_cmodel)
1713 shader = cmodel_shader_table[i].shader;
1718 // printf("Playback3D::convert_cmodel_sync %d %d %d shader=\n%s",
1720 // command->frame->get_color_model(),
1721 // command->dst_cmodel,
1726 //printf("Playback3D::convert_cmodel_sync %d\n", __LINE__);
1727 command->frame->bind_texture(0);
1728 unsigned int shader_id = -1;
1731 shader_id = VFrame::make_shader(0,
1734 glUseProgram(shader_id);
1735 glUniform1i(glGetUniformLocation(shader_id, "tex"), 0);
1738 command->frame->draw_texture();
1740 if(shader) glUseProgram(0);
1742 command->frame->set_opengl_state(VFrame::SCREEN);
1745 window->unlock_window();
1748 command->canvas->unlock_canvas();
1752 void Playback3D::do_fade(Canvas *canvas, VFrame *frame, float fade)
1754 Playback3DCommand command;
1755 command.command = Playback3DCommand::DO_FADE;
1756 command.canvas = canvas;
1757 command.frame = frame;
1758 command.alpha = fade;
1759 send_command(&command);
1762 void Playback3D::do_fade_sync(Playback3DCommand *command)
1765 command->canvas->lock_canvas("Playback3D::do_mask_sync");
1766 if(command->canvas->get_canvas())
1768 BC_WindowBase *window = command->canvas->get_canvas();
1769 window->lock_window("Playback3D::do_fade_sync");
1770 window->enable_opengl();
1772 switch(command->frame->get_opengl_state())
1775 command->frame->to_texture();
1778 case VFrame::SCREEN:
1779 // Read back from PBuffer
1780 // Bind context to pbuffer
1781 command->frame->enable_opengl();
1782 command->frame->screen_to_texture();
1787 command->frame->enable_opengl();
1788 command->frame->init_screen();
1789 command->frame->bind_texture(0);
1791 // glClearColor(0.0, 0.0, 0.0, 0.0);
1792 // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1793 glDisable(GL_BLEND);
1794 unsigned int frag_shader = 0;
1795 switch(command->frame->get_color_model())
1797 // For the alpha colormodels, the native function seems to multiply the
1798 // components by the alpha instead of just the alpha.
1802 frag_shader = VFrame::make_shader(0, fade_rgba_frag, 0);
1807 glBlendFunc(GL_SRC_ALPHA, GL_ZERO);
1808 glColor4f(command->alpha, command->alpha, command->alpha, 1);
1813 frag_shader = VFrame::make_shader(0, fade_yuv_frag, 0);
1820 glUseProgram(frag_shader);
1822 if((variable = glGetUniformLocation(frag_shader, "tex")) >= 0)
1823 glUniform1i(variable, 0);
1824 if((variable = glGetUniformLocation(frag_shader, "alpha")) >= 0)
1825 glUniform1f(variable, command->alpha);
1828 command->frame->draw_texture();
1829 command->frame->set_opengl_state(VFrame::SCREEN);
1836 glColor4f(1, 1, 1, 1);
1837 glDisable(GL_BLEND);
1839 window->unlock_window();
1841 command->canvas->unlock_canvas();
1855 int Playback3D::run_plugin(Canvas *canvas, PluginClient *client)
1857 Playback3DCommand command;
1858 command.command = Playback3DCommand::PLUGIN;
1859 command.canvas = canvas;
1860 command.plugin_client = client;
1861 return send_command(&command);
1864 void Playback3D::run_plugin_sync(Playback3DCommand *command)
1866 command->canvas->lock_canvas("Playback3D::run_plugin_sync");
1867 if(command->canvas->get_canvas())
1869 BC_WindowBase *window = command->canvas->get_canvas();
1870 window->lock_window("Playback3D::run_plugin_sync");
1871 window->enable_opengl();
1873 command->result = ((PluginVClient*)command->plugin_client)->handle_opengl();
1875 window->unlock_window();
1877 command->canvas->unlock_canvas();