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
57 static const char *yuv_to_rgb_frag =
58 "uniform sampler2D tex;\n"
61 " vec4 yuva = texture2D(tex, gl_TexCoord[0].st);\n"
62 " yuva.rgb -= vec3(0, 0.5, 0.5);\n"
63 " const mat3 yuv_to_rgb_matrix = mat3(\n"
65 " 0, -0.34414, 1.77200, \n"
66 " 1.40200, -0.71414, 0);\n"
67 " gl_FragColor = vec4(yuv_to_rgb_matrix * yuva.rgb, yuva.a);\n"
70 static const char *yuva_to_yuv_frag =
71 "uniform sampler2D tex;\n"
74 " vec4 yuva = texture2D(tex, gl_TexCoord[0].st);\n"
75 " float a = yuva.a;\n"
76 " float anti_a = 1.0 - a;\n"
78 " yuva.g = yuva.g * a + 0.5 * anti_a;\n"
79 " yuva.b = yuva.b * a + 0.5 * anti_a;\n"
81 " gl_FragColor = yuva;\n"
84 static const char *yuva_to_rgb_frag =
85 "uniform sampler2D tex;\n"
88 " vec4 yuva = texture2D(tex, gl_TexCoord[0].st);\n"
89 " yuva.rgb -= vec3(0, 0.5, 0.5);\n"
90 " const mat3 yuv_to_rgb_matrix = mat3(\n"
92 " 0, -0.34414, 1.77200, \n"
93 " 1.40200, -0.71414, 0);\n"
94 " yuva.rgb = yuv_to_rgb_matrix * yuva.rgb;\n"
95 " yuva.rgb *= yuva.a;\n"
97 " gl_FragColor = yuva;\n"
100 static const char *rgb_to_yuv_frag =
101 "uniform sampler2D tex;\n"
104 " vec4 rgba = texture2D(tex, gl_TexCoord[0].st);\n"
105 " const mat3 rgb_to_yuv_matrix = mat3(\n"
106 " 0.29900, -0.16874, 0.50000, \n"
107 " 0.58700, -0.33126, -0.41869, \n"
108 " 0.11400, 0.50000, -0.08131);\n"
109 " rgba.rgb = rgb_to_yuv_matrix * rgba.rgb;\n"
110 " rgba.rgb += vec3(0, 0.5, 0.5);\n"
111 " gl_FragColor = rgba;\n"
115 static const char *rgba_to_rgb_frag =
116 "uniform sampler2D tex;\n"
119 " vec4 rgba = texture2D(tex, gl_TexCoord[0].st);\n"
120 " rgba.rgb *= rgba.a;\n"
122 " gl_FragColor = rgba;\n"
125 static const char *rgba_to_yuv_frag =
126 "uniform sampler2D tex;\n"
129 " vec4 rgba = texture2D(tex, gl_TexCoord[0].st);\n"
130 " const mat3 rgb_to_yuv_matrix = mat3(\n"
131 " 0.29900, -0.16874, 0.50000, \n"
132 " 0.58700, -0.33126, -0.41869, \n"
133 " 0.11400, 0.50000, -0.08131);\n"
134 " rgba.rgb *= rgba.a;\n"
136 " rgba.rgb = rgb_to_yuv_matrix * rgba.rgb;\n"
137 " rgba.rgb += vec3(0, 0.5, 0.5);\n"
138 " gl_FragColor = rgba;\n"
141 static const char *rgba_to_rgb_flatten =
143 " gl_FragColor.rgb *= gl_FragColor.a;\n"
144 " gl_FragColor.a = 1.0;\n"
148 static const char *blend_normal_frag =
149 "uniform sampler2D tex2;\n"
150 "uniform vec2 tex2_dimensions;\n"
151 "uniform float alpha;\n"
153 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
154 " vec4 result = mix(canvas, gl_FragColor, gl_FragColor.a);\n"
155 " gl_FragColor = mix(canvas, result, alpha);\n"
159 static const char *blend_add_frag =
160 "uniform sampler2D tex2;\n"
161 "uniform vec2 tex2_dimensions;\n"
162 "uniform float alpha;\n"
164 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
165 " vec4 result = canvas + gl_FragColor;\n"
166 " result = clamp(result, 0.0, 1.0);\n"
167 " gl_FragColor = mix(canvas, result, alpha);\n"
171 static const char *blend_subtract_frag =
172 "uniform sampler2D tex2;\n"
173 "uniform vec2 tex2_dimensions;\n"
174 "uniform float alpha;\n"
176 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
177 " vec4 result = gl_FragColor - canvas;\n"
178 " result = clamp(result, 0.0, 1.0);\n"
179 " gl_FragColor = mix(canvas, result, alpha);\n"
183 static const char *blend_multiply_frag =
184 "uniform sampler2D tex2;\n"
185 "uniform vec2 tex2_dimensions;\n"
186 "uniform float alpha;\n"
188 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
189 " vec4 result = canvas * gl_FragColor;\n"
190 " gl_FragColor = mix(canvas, result, alpha);\n"
194 static const char *blend_divide_frag =
195 "uniform sampler2D tex2;\n"
196 "uniform vec2 tex2_dimensions;\n"
197 "uniform float alpha;\n"
199 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
200 " vec4 result = gl_FragColor / canvas;\n"
201 " if(canvas.r == 0.) result.r = 1.0;\n"
202 " if(canvas.g == 0.) result.g = 1.0;\n"
203 " if(canvas.b == 0.) result.b = 1.0;\n"
204 " if(canvas.a == 0.) result.a = 1.0;\n"
205 " result = clamp(result, 0.0, 1.0);\n"
206 " gl_FragColor = mix(canvas, result, alpha);\n"
210 static const char *blend_replace_frag =
211 "uniform float alpha;\n"
216 static const char *blend_max_frag =
217 "uniform sampler2D tex2;\n"
218 "uniform vec2 tex2_dimensions;\n"
219 "uniform float alpha;\n"
221 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
222 " vec4 result = max(canvas, gl_FragColor);\n"
223 " gl_FragColor = mix(canvas, result, alpha);\n"
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 " gl_FragColor = mix(canvas, result, alpha);\n"
238 static const char *blend_average_frag =
239 "uniform sampler2D tex2;\n"
240 "uniform vec2 tex2_dimensions;\n"
241 "uniform float alpha;\n"
243 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
244 " vec4 result = (canvas + gl_FragColor) * 0.5;\n"
245 " gl_FragColor = mix(canvas, result, alpha);\n"
249 static const char *blend_darken_frag =
250 "uniform sampler2D tex2;\n"
251 "uniform vec2 tex2_dimensions;\n"
252 "uniform float alpha;\n"
254 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
255 " vec4 result = vec4(canvas.rgb * (1.0 - gl_FragColor.a) +"
256 " gl_FragColor.rgb * (1.0 - canvas.a) +"
257 " min(canvas.rgb, gl_FragColor.rgb), "
258 " canvas.a + gl_FragColor.a - canvas.a * gl_FragColor.a);\n"
259 " result = clamp(result, 0.0, 1.0);\n"
260 " gl_FragColor = mix(canvas, result, alpha);\n"
264 static const char *blend_lighten_frag =
265 "uniform sampler2D tex2;\n"
266 "uniform vec2 tex2_dimensions;\n"
267 "uniform float alpha;\n"
269 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
270 " vec4 result = vec4(canvas.rgb * (1.0 - gl_FragColor.a) +"
271 " gl_FragColor.rgb * (1.0 - canvas.a) +"
272 " max(canvas.rgb, gl_FragColor.rgb), "
273 " canvas.a + gl_FragColor.a - canvas.a * gl_FragColor.a);\n"
274 " result = clamp(result, 0.0, 1.0);\n"
275 " gl_FragColor = mix(canvas, result, alpha);\n"
279 static const char *blend_dst_frag =
280 "uniform sampler2D tex2;\n"
281 "uniform vec2 tex2_dimensions;\n"
282 "uniform float alpha;\n"
284 // " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
285 // " vec4 result = canvas;\n"
286 // " gl_FragColor = mix(result, canvas, alpha);\n"
287 " gl_FragColor = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
291 static const char *blend_dst_atop_frag =
292 "uniform sampler2D tex2;\n"
293 "uniform vec2 tex2_dimensions;\n"
294 "uniform float alpha;\n"
296 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
297 " vec4 result = vec4(canvas.rgb * gl_FragColor.a + "
298 "(1.0 - canvas.a) * gl_FragColor.rgb, gl_FragColor.a);\n"
299 " gl_FragColor = mix(canvas, result, alpha);\n"
303 static const char *blend_dst_in_frag =
304 "uniform sampler2D tex2;\n"
305 "uniform vec2 tex2_dimensions;\n"
306 "uniform float alpha;\n"
308 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
309 " vec4 result = canvas * gl_FragColor.a;\n"
310 " gl_FragColor = mix(canvas, result, alpha);\n"
314 static const char *blend_dst_out_frag =
315 "uniform sampler2D tex2;\n"
316 "uniform vec2 tex2_dimensions;\n"
317 "uniform float alpha;\n"
319 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
320 " vec4 result = canvas * (1.0 - gl_FragColor.a);\n"
321 " gl_FragColor = mix(canvas, result, alpha);\n"
325 static const char *blend_dst_over_frag =
326 "uniform sampler2D tex2;\n"
327 "uniform vec2 tex2_dimensions;\n"
328 "uniform float alpha;\n"
330 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
331 " vec4 result = vec4(canvas.rgb + (1.0 - canvas.a) * gl_FragColor.rgb, "
332 " gl_FragColor.a + canvas.a - gl_FragColor.a * canvas.a);\n"
333 " gl_FragColor = mix(canvas, result, alpha);\n"
337 static const char *blend_src_frag =
338 "uniform sampler2D tex2;\n"
339 "uniform vec2 tex2_dimensions;\n"
340 "uniform float alpha;\n"
342 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
343 " vec4 result = gl_FragColor;\n"
344 " gl_FragColor = mix(canvas, result, alpha);\n"
348 static const char *blend_src_atop_frag =
349 "uniform sampler2D tex2;\n"
350 "uniform vec2 tex2_dimensions;\n"
351 "uniform float alpha;\n"
353 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
354 " vec4 result = vec4(gl_FragColor.rgb * canvas.a + "
355 "canvas.rgb * (1.0 - gl_FragColor.a), canvas.a);\n"
356 " gl_FragColor = mix(canvas, result, alpha);\n"
360 static const char *blend_src_in_frag =
361 "uniform sampler2D tex2;\n"
362 "uniform vec2 tex2_dimensions;\n"
363 "uniform float alpha;\n"
365 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
366 " vec4 result = gl_FragColor * canvas.a;\n"
367 " gl_FragColor = mix(canvas, result, alpha);\n"
371 static const char *blend_src_out_frag =
372 "uniform sampler2D tex2;\n"
373 "uniform vec2 tex2_dimensions;\n"
374 "uniform float alpha;\n"
376 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
377 " vec4 result = gl_FragColor * (1.0 - canvas.a);\n"
378 " gl_FragColor = mix(canvas, result, alpha);\n"
382 static const char *blend_src_over_frag =
383 "uniform sampler2D tex2;\n"
384 "uniform vec2 tex2_dimensions;\n"
385 "uniform float alpha;\n"
387 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
388 " vec4 result = vec4(gl_FragColor.rgb + (1.0 - gl_FragColor.a) * canvas.rgb, "
389 "gl_FragColor.a + canvas.a - gl_FragColor.a * canvas.a);\n"
390 " gl_FragColor = mix(canvas, result, alpha);\n"
394 static const char *blend_or_frag =
395 "uniform sampler2D tex2;\n"
396 "uniform vec2 tex2_dimensions;\n"
397 "uniform float alpha;\n"
399 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
400 " vec4 result = canvas + gl_FragColor - canvas * gl_FragColor;\n"
401 " gl_FragColor = mix(canvas, result, alpha);\n"
405 static const char *blend_xor_frag =
406 "uniform sampler2D tex2;\n"
407 "uniform vec2 tex2_dimensions;\n"
408 "uniform float alpha;\n"
410 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
411 " vec4 result = vec4(gl_FragColor.rgb * (1.0 - canvas.a) + "
412 "(1.0 - gl_FragColor.a) * canvas.rgb, "
413 "gl_FragColor.a + canvas.a - 2.0 * gl_FragColor.a * canvas.a);\n"
414 " gl_FragColor = mix(canvas, result, alpha);\n"
417 static const char *read_texture_frag =
418 "uniform sampler2D tex;\n"
421 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
424 static const char *multiply_mask4_frag =
425 "uniform sampler2D tex;\n"
426 "uniform sampler2D tex1;\n"
427 "uniform float scale;\n"
430 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
431 " gl_FragColor.a *= texture2D(tex1, gl_TexCoord[0].st / vec2(scale, scale)).r;\n"
434 static const char *multiply_mask3_frag =
435 "uniform sampler2D tex;\n"
436 "uniform sampler2D tex1;\n"
437 "uniform float scale;\n"
438 "uniform bool is_yuv;\n"
441 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
442 " float a = texture2D(tex1, gl_TexCoord[0].st / vec2(scale, scale)).r;\n"
443 " gl_FragColor.rgb *= vec3(a, a, a);\n"
446 static const char *multiply_yuvmask3_frag =
447 "uniform sampler2D tex;\n"
448 "uniform sampler2D tex1;\n"
449 "uniform float scale;\n"
452 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
453 " float a = texture2D(tex1, gl_TexCoord[0].st / vec2(scale, scale)).r;\n"
454 " gl_FragColor.gb -= vec2(0.5, 0.5);\n"
455 " gl_FragColor.rgb *= vec3(a, a, a);\n"
456 " gl_FragColor.gb += vec2(0.5, 0.5);\n"
459 static const char *fade_rgba_frag =
460 "uniform sampler2D tex;\n"
461 "uniform float alpha;\n"
464 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
465 " gl_FragColor.a *= alpha;\n"
468 static const char *fade_yuv_frag =
469 "uniform sampler2D tex;\n"
470 "uniform float alpha;\n"
473 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
474 " gl_FragColor.r *= alpha;\n"
475 " gl_FragColor.gb -= vec2(0.5, 0.5);\n"
476 " gl_FragColor.g *= alpha;\n"
477 " gl_FragColor.b *= alpha;\n"
478 " gl_FragColor.gb += vec2(0.5, 0.5);\n"
484 Playback3DCommand::Playback3DCommand()
485 : BC_SynchronousCommand()
491 void Playback3DCommand::copy_from(BC_SynchronousCommand *command)
493 Playback3DCommand *ptr = (Playback3DCommand*)command;
494 this->canvas = ptr->canvas;
495 this->is_cleared = ptr->is_cleared;
497 this->in_x1 = ptr->in_x1;
498 this->in_y1 = ptr->in_y1;
499 this->in_x2 = ptr->in_x2;
500 this->in_y2 = ptr->in_y2;
501 this->out_x1 = ptr->out_x1;
502 this->out_y1 = ptr->out_y1;
503 this->out_x2 = ptr->out_x2;
504 this->out_y2 = ptr->out_y2;
505 this->alpha = ptr->alpha;
506 this->mode = ptr->mode;
507 this->interpolation_type = ptr->interpolation_type;
509 this->input = ptr->input;
510 this->start_position_project = ptr->start_position_project;
511 this->keyframe_set = ptr->keyframe_set;
512 this->keyframe = ptr->keyframe;
513 this->default_auto = ptr->default_auto;
514 this->plugin_client = ptr->plugin_client;
515 this->want_texture = ptr->want_texture;
516 this->is_nested = ptr->is_nested;
517 this->dst_cmodel = ptr->dst_cmodel;
519 BC_SynchronousCommand::copy_from(command);
523 ///static void glDebugCallback(GLenum src, GLenum typ, GLuint id,
524 /// GLenum svy, GLsizei len, const GLchar* msg, void* dat)
525 //static void glDebugCallback(unsigned int src, unsigned int typ, unsigned int id,
526 // unsigned int svy, int len, const char* msg, const void* dat)
528 // printf("glDebug: %d:%d; %d/%d %s\n",src,typ,id,svy,msg);
532 Playback3D::Playback3D(MWindow *mwindow)
535 this->mwindow = mwindow;
537 //Enabling OpenGL debug output on nVidia drivers
538 // glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, 0, GL_TRUE);
539 // glEnable(GL_DEBUG_OUTPUT);
540 // glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
541 // glDebugMessageCallback(glDebugCallback, 0);
544 Playback3D::~Playback3D()
551 BC_SynchronousCommand* Playback3D::new_command()
553 return new Playback3DCommand;
558 void Playback3D::handle_command(BC_SynchronousCommand *command)
560 //printf("Playback3D::handle_command 1 %d\n", command->command);
561 switch(command->command)
563 case Playback3DCommand::WRITE_BUFFER:
564 write_buffer_sync((Playback3DCommand*)command);
567 case Playback3DCommand::CLEAR_OUTPUT:
568 clear_output_sync((Playback3DCommand*)command);
571 case Playback3DCommand::CLEAR_INPUT:
572 clear_input_sync((Playback3DCommand*)command);
575 case Playback3DCommand::DO_CAMERA:
576 do_camera_sync((Playback3DCommand*)command);
579 case Playback3DCommand::OVERLAY:
580 overlay_sync((Playback3DCommand*)command);
583 case Playback3DCommand::DO_FADE:
584 do_fade_sync((Playback3DCommand*)command);
587 case Playback3DCommand::DO_MASK:
588 do_mask_sync((Playback3DCommand*)command);
591 case Playback3DCommand::PLUGIN:
592 run_plugin_sync((Playback3DCommand*)command);
595 case Playback3DCommand::COPY_FROM:
596 copy_from_sync((Playback3DCommand*)command);
599 case Playback3DCommand::CONVERT_CMODEL:
600 convert_cmodel_sync((Playback3DCommand*)command);
603 // case Playback3DCommand::DRAW_REFRESH:
604 // draw_refresh_sync((Playback3DCommand*)command);
607 //printf("Playback3D::handle_command 10\n");
613 void Playback3D::copy_from(Canvas *canvas,
618 Playback3DCommand command;
619 command.command = Playback3DCommand::COPY_FROM;
620 command.canvas = canvas;
623 command.want_texture = want_texture;
624 send_command(&command);
627 void Playback3D::copy_from_sync(Playback3DCommand *command)
630 command->canvas->lock_canvas("Playback3D::draw_refresh_sync");
631 BC_WindowBase *window = command->canvas->get_canvas();
634 window->lock_window("Playback3D:draw_refresh_sync");
635 window->enable_opengl();
636 int w = command->input->get_w();
637 int h = command->input->get_h();
639 if(command->input->get_opengl_state() == VFrame::SCREEN &&
640 w == command->frame->get_w() && h == command->frame->get_h())
642 // printf("Playback3D::copy_from_sync 1 %d %d %d %d %d\n",
643 // command->input->get_w(),
644 // command->input->get_h(),
645 // command->frame->get_w(),
646 // command->frame->get_h(),
647 // command->frame->get_color_model());
648 // With NVidia at least,
651 printf("Playback3D::copy_from_sync: w=%d not supported because it is not divisible by 4.\n", w);
655 if(command->want_texture)
657 //printf("Playback3D::copy_from_sync 1 dst=%p src=%p\n", command->frame, command->input);
658 // Screen_to_texture requires the source pbuffer enabled.
659 command->input->enable_opengl();
660 command->frame->screen_to_texture();
661 command->frame->set_opengl_state(VFrame::TEXTURE);
666 command->input->enable_opengl();
667 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
668 glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE,
669 command->frame->get_rows()[0]);
670 command->frame->flip_vert();
671 command->frame->set_opengl_state(VFrame::RAM);
676 printf("Playback3D::copy_from_sync: invalid formats opengl_state=%d %dx%d -> %dx%d\n",
677 command->input->get_opengl_state(), w, h,
678 command->frame->get_w(), command->frame->get_h());
681 window->unlock_window();
683 command->canvas->unlock_canvas();
690 // void Playback3D::draw_refresh(Canvas *canvas,
701 // Playback3DCommand command;
702 // command.command = Playback3DCommand::DRAW_REFRESH;
703 // command.canvas = canvas;
704 // command.frame = frame;
705 // command.in_x1 = in_x1;
706 // command.in_y1 = in_y1;
707 // command.in_x2 = in_x2;
708 // command.in_y2 = in_y2;
709 // command.out_x1 = out_x1;
710 // command.out_y1 = out_y1;
711 // command.out_x2 = out_x2;
712 // command.out_y2 = out_y2;
713 // send_command(&command);
716 // void Playback3D::draw_refresh_sync(Playback3DCommand *command)
718 // command->canvas->lock_canvas("Playback3D::draw_refresh_sync");
719 // BC_WindowBase *window = command->canvas->get_canvas();
722 // window->lock_window("Playback3D:draw_refresh_sync");
723 // window->enable_opengl();
725 // // Read output pbuffer back to RAM in project colormodel
726 // // RGB 8bit is fastest for OpenGL to read back.
727 // command->frame->reallocate(0,
731 // command->frame->get_w(),
732 // command->frame->get_h(),
735 // command->frame->screen_to_ram();
737 // window->clear_box(0,
741 // window->draw_vframe(command->frame,
742 // (int)command->out_x1,
743 // (int)command->out_y1,
744 // (int)(command->out_x2 - command->out_x1),
745 // (int)(command->out_y2 - command->out_y1),
746 // (int)command->in_x1,
747 // (int)command->in_y1,
748 // (int)(command->in_x2 - command->in_x1),
749 // (int)(command->in_y2 - command->in_y1),
752 // window->unlock_window();
754 // command->canvas->unlock_canvas();
761 void Playback3D::write_buffer(Canvas *canvas,
773 Playback3DCommand command;
774 command.command = Playback3DCommand::WRITE_BUFFER;
775 command.canvas = canvas;
776 command.frame = frame;
777 command.in_x1 = in_x1;
778 command.in_y1 = in_y1;
779 command.in_x2 = in_x2;
780 command.in_y2 = in_y2;
781 command.out_x1 = out_x1;
782 command.out_y1 = out_y1;
783 command.out_x2 = out_x2;
784 command.out_y2 = out_y2;
785 command.is_cleared = is_cleared;
786 send_command(&command);
790 void Playback3D::write_buffer_sync(Playback3DCommand *command)
792 command->canvas->lock_canvas("Playback3D::write_buffer_sync");
793 if(command->canvas->get_canvas())
795 BC_WindowBase *window = command->canvas->get_canvas();
796 window->lock_window("Playback3D::write_buffer_sync");
797 // Update hidden cursor
798 window->update_video_cursor();
799 // Make sure OpenGL is enabled first.
800 window->enable_opengl();
803 //printf("Playback3D::write_buffer_sync 1 %d\n", window->get_id());
804 switch(command->frame->get_opengl_state())
806 // Upload texture and composite to screen
808 command->frame->to_texture();
809 draw_output(command);
811 // Composite texture to screen and swap buffer
812 case VFrame::TEXTURE:
813 draw_output(command);
817 window->flip_opengl();
820 printf("Playback3D::write_buffer_sync unknown state\n");
823 window->unlock_window();
826 command->canvas->unlock_canvas();
831 void Playback3D::draw_output(Playback3DCommand *command)
834 int texture_id = command->frame->get_texture_id();
835 BC_WindowBase *window = command->canvas->get_canvas();
837 // printf("Playback3D::draw_output 1 texture_id=%d window=%p\n",
839 // command->canvas->get_canvas());
844 // If virtual console is being used, everything in this function has
845 // already been done except the page flip.
848 canvas_w = window->get_w();
849 canvas_h = window->get_h();
850 VFrame::init_screen(canvas_w, canvas_h);
852 if(!command->is_cleared)
854 // If we get here, the virtual console was not used.
859 // Undo any previous shader settings
860 command->frame->bind_texture(0);
865 // Convert colormodel
866 unsigned int frag_shader = 0;
867 switch(command->frame->get_color_model())
871 frag_shader = VFrame::make_shader(0,
880 glUseProgram(frag_shader);
881 int variable = glGetUniformLocation(frag_shader, "tex");
882 // Set texture unit of the texture
883 glUniform1i(variable, 0);
886 if(BC_CModels::components(command->frame->get_color_model()) == 4)
889 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
892 command->frame->draw_texture(
893 command->in_x1, command->in_y1, command->in_x2, command->in_y2,
894 command->out_x1, command->out_y1, command->out_x2, command->out_y2,
898 // printf("Playback3D::draw_output 2 %f,%f %f,%f -> %f,%f %f,%f\n",
910 command->canvas->get_canvas()->flip_opengl();
917 void Playback3D::init_frame(Playback3DCommand *command)
920 canvas_w = command->canvas->get_canvas()->get_w();
921 canvas_h = command->canvas->get_canvas()->get_h();
923 glClearColor(0.0, 0.0, 0.0, 0.0);
924 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
929 void Playback3D::clear_output(Canvas *canvas, VFrame *output)
931 Playback3DCommand command;
932 command.command = Playback3DCommand::CLEAR_OUTPUT;
933 command.canvas = canvas;
934 command.frame = output;
935 send_command(&command);
938 void Playback3D::clear_output_sync(Playback3DCommand *command)
940 command->canvas->lock_canvas("Playback3D::clear_output_sync");
941 if(command->canvas->get_canvas())
943 command->canvas->get_canvas()->lock_window("Playback3D::clear_output_sync");
944 // If we get here, the virtual console is being used.
945 command->canvas->get_canvas()->enable_opengl();
947 // Using pbuffer for refresh frame.
950 command->frame->enable_opengl();
955 command->canvas->get_canvas()->unlock_window();
957 command->canvas->unlock_canvas();
961 void Playback3D::clear_input(Canvas *canvas, VFrame *frame)
963 Playback3DCommand command;
964 command.command = Playback3DCommand::CLEAR_INPUT;
965 command.canvas = canvas;
966 command.frame = frame;
967 send_command(&command);
970 void Playback3D::clear_input_sync(Playback3DCommand *command)
972 command->canvas->lock_canvas("Playback3D::clear_output_sync");
973 if(command->canvas->get_canvas())
975 command->canvas->get_canvas()->lock_window("Playback3D::clear_output_sync");
976 command->canvas->get_canvas()->enable_opengl();
977 command->frame->enable_opengl();
978 command->frame->clear_pbuffer();
979 command->frame->set_opengl_state(VFrame::SCREEN);
980 command->canvas->get_canvas()->unlock_window();
982 command->canvas->unlock_canvas();
985 void Playback3D::do_camera(Canvas *canvas,
997 Playback3DCommand command;
998 command.command = Playback3DCommand::DO_CAMERA;
999 command.canvas = canvas;
1000 command.input = input;
1001 command.frame = output;
1002 command.in_x1 = in_x1;
1003 command.in_y1 = in_y1;
1004 command.in_x2 = in_x2;
1005 command.in_y2 = in_y2;
1006 command.out_x1 = out_x1;
1007 command.out_y1 = out_y1;
1008 command.out_x2 = out_x2;
1009 command.out_y2 = out_y2;
1010 send_command(&command);
1013 void Playback3D::do_camera_sync(Playback3DCommand *command)
1015 command->canvas->lock_canvas("Playback3D::do_camera_sync");
1016 if(command->canvas->get_canvas())
1018 command->canvas->get_canvas()->lock_window("Playback3D::clear_output_sync");
1019 command->canvas->get_canvas()->enable_opengl();
1021 command->input->to_texture();
1022 command->frame->enable_opengl();
1023 command->frame->init_screen();
1024 command->frame->clear_pbuffer();
1026 command->input->bind_texture(0);
1027 // Must call draw_texture in input frame to get the texture coordinates right.
1029 // printf("Playback3D::do_camera_sync 1 %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f\n",
1035 // (float)command->input->get_h() - command->out_y1,
1037 // (float)command->input->get_h() - command->out_y2);
1038 command->input->draw_texture(
1039 command->in_x1, command->in_y2,
1040 command->in_x2, command->in_y1,
1042 (float)command->frame->get_h() - command->out_y1,
1044 (float)command->frame->get_h() - command->out_y2);
1047 command->frame->set_opengl_state(VFrame::SCREEN);
1048 command->canvas->get_canvas()->unlock_window();
1050 command->canvas->unlock_canvas();
1053 void Playback3D::overlay(Canvas *canvas, VFrame *input,
1054 float in_x1, float in_y1, float in_x2, float in_y2,
1055 float out_x1, float out_y1, float out_x2, float out_y2,
1056 float alpha, int mode, int interpolation_type,
1057 VFrame *output, int is_nested)
1059 Playback3DCommand command;
1060 command.command = Playback3DCommand::OVERLAY;
1061 command.canvas = canvas;
1062 command.frame = output;
1063 command.input = input;
1064 command.in_x1 = in_x1;
1065 command.in_y1 = in_y1;
1066 command.in_x2 = in_x2;
1067 command.in_y2 = in_y2;
1068 command.out_x1 = out_x1;
1069 command.out_y1 = out_y1;
1070 command.out_x2 = out_x2;
1071 command.out_y2 = out_y2;
1072 command.alpha = alpha;
1073 command.mode = mode;
1074 command.interpolation_type = interpolation_type;
1075 command.is_nested = is_nested;
1076 send_command(&command);
1079 void Playback3D::overlay_sync(Playback3DCommand *command)
1082 // To do these operations, we need to copy the input buffer to a texture
1083 // and blend 2 textures in a shader
1084 static const char * const overlay_shaders[TRANSFER_TYPES] = {
1085 blend_normal_frag, // TRANSFER_NORMAL
1086 blend_add_frag, // TRANSFER_ADDITION
1087 blend_subtract_frag, // TRANSFER_SUBTRACT
1088 blend_multiply_frag, // TRANSFER_MULTIPLY
1089 blend_divide_frag, // TRANSFER_DIVIDE
1090 blend_replace_frag, // TRANSFER_REPLACE
1091 blend_max_frag, // TRANSFER_MAX
1092 blend_min_frag, // TRANSFER_MIN
1093 blend_average_frag, // TRANSFER_AVERAGE
1094 blend_darken_frag, // TRANSFER_DARKEN
1095 blend_lighten_frag, // TRANSFER_LIGHTEN
1096 blend_dst_frag, // TRANSFER_DST
1097 blend_dst_atop_frag, // TRANSFER_DST_ATOP
1098 blend_dst_in_frag, // TRANSFER_DST_IN
1099 blend_dst_out_frag, // TRANSFER_DST_OUT
1100 blend_dst_over_frag, // TRANSFER_DST_OVER
1101 blend_src_frag, // TRANSFER_SRC
1102 blend_src_atop_frag, // TRANSFER_SRC_ATOP
1103 blend_src_in_frag, // TRANSFER_SRC_IN
1104 blend_src_out_frag, // TRANSFER_SRC_OUT
1105 blend_src_over_frag, // TRANSFER_SRC_OVER
1106 blend_or_frag, // TRANSFER_OR
1107 blend_xor_frag // TRANSFER_XOR
1110 command->canvas->lock_canvas("Playback3D::overlay_sync");
1111 if(command->canvas->get_canvas()) {
1112 BC_WindowBase *window = command->canvas->get_canvas();
1113 window->lock_window("Playback3D::overlay_sync");
1114 // Make sure OpenGL is enabled first.
1115 window->enable_opengl();
1116 window->update_video_cursor();
1118 glColor4f(1, 1, 1, 1);
1119 glDisable(GL_BLEND);
1121 if(command->frame) {
1122 // Render to PBuffer
1123 command->frame->enable_opengl();
1124 command->frame->set_opengl_state(VFrame::SCREEN);
1125 canvas_w = command->frame->get_w();
1126 canvas_h = command->frame->get_h();
1130 canvas_w = window->get_w();
1131 canvas_h = window->get_h();
1135 //printf("Playback3D::overlay_sync 1 %d\n", command->input->get_opengl_state());
1136 switch(command->input->get_opengl_state()) {
1137 // Upload texture and composite to screen
1139 command->input->to_texture();
1141 // Just composite texture to screen
1142 case VFrame::TEXTURE:
1144 // read from PBuffer to texture, then composite texture to screen
1145 case VFrame::SCREEN:
1146 command->input->enable_opengl();
1147 command->input->screen_to_texture();
1149 command->frame->enable_opengl();
1151 window->enable_opengl();
1154 printf("Playback3D::overlay_sync unknown state\n");
1159 const char *shader_stack[4] = { 0, 0, 0, 0, };
1160 int total_shaders = 0;
1162 VFrame::init_screen(canvas_w, canvas_h);
1165 command->input->bind_texture(0);
1167 // Convert colormodel to RGB if not nested.
1168 // The color model setting in the output frame is ignored.
1169 if( command->is_nested <= 0 ) { // not nested
1170 switch(command->input->get_color_model()) {
1173 shader_stack[total_shaders++] = yuv_to_rgb_frag;
1179 #define add_shader(s) \
1180 if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag; \
1181 shader_stack[total_shaders++] = s
1183 switch(command->mode) {
1184 case TRANSFER_REPLACE:
1185 // This requires overlaying an alpha multiplied image on a black screen.
1186 if( command->input->get_texture_components() != 4 ) break;
1187 add_shader(overlay_shaders[command->mode]);
1190 enable_overlay_texture(command);
1191 add_shader(overlay_shaders[command->mode]);
1195 // if to flatten alpha
1196 if( command->is_nested < 0 ) {
1197 switch(command->input->get_color_model()) {
1198 // yuv has already been converted to rgb
1202 add_shader(rgba_to_rgb_flatten);
1208 unsigned int frag_shader = 0;
1209 if(shader_stack[0]) {
1210 frag_shader = VFrame::make_shader(0,
1211 shader_stack[0], shader_stack[1],
1212 shader_stack[2], shader_stack[3], 0);
1214 glUseProgram(frag_shader);
1216 // Set texture unit of the texture
1217 glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0);
1218 // Set texture unit of the temp texture
1219 glUniform1i(glGetUniformLocation(frag_shader, "tex2"), 1);
1221 int variable = glGetUniformLocation(frag_shader, "alpha");
1222 glUniform1f(variable, command->alpha);
1223 // Set dimensions of the temp texture
1225 glUniform2f(glGetUniformLocation(frag_shader, "tex2_dimensions"),
1226 (float)temp_texture->get_texture_w(),
1227 (float)temp_texture->get_texture_h());
1233 // printf("Playback3D::overlay_sync %f %f %f %f %f %f %f %f\n",
1234 // command->in_x1, command->in_y1, command->in_x2, command->in_y2,
1235 // command->out_x1, command->out_y1, command->out_x2, command->out_y2);
1237 command->input->draw_texture(
1238 command->in_x1, command->in_y1, command->in_x2, command->in_y2,
1239 command->out_x1, command->out_y1, command->out_x2, command->out_y2,
1240 // Don't flip vertical if nested
1241 command->is_nested > 0 ? 0 : 1);
1244 // Delete temp texture
1246 delete temp_texture;
1248 glActiveTexture(GL_TEXTURE1);
1249 glDisable(GL_TEXTURE_2D);
1251 glActiveTexture(GL_TEXTURE0);
1252 glDisable(GL_TEXTURE_2D);
1254 window->unlock_window();
1256 command->canvas->unlock_canvas();
1260 void Playback3D::enable_overlay_texture(Playback3DCommand *command)
1263 glDisable(GL_BLEND);
1265 glActiveTexture(GL_TEXTURE1);
1266 BC_Texture::new_texture(&temp_texture, canvas_w, canvas_h,
1267 command->input->get_color_model());
1268 temp_texture->bind(1);
1270 // Read canvas into texture
1271 glReadBuffer(GL_BACK);
1272 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, canvas_w, canvas_h);
1277 void Playback3D::do_mask(Canvas *canvas,
1279 int64_t start_position_project,
1280 MaskAutos *keyframe_set,
1282 MaskAuto *default_auto)
1284 Playback3DCommand command;
1285 command.command = Playback3DCommand::DO_MASK;
1286 command.canvas = canvas;
1287 command.frame = output;
1288 command.start_position_project = start_position_project;
1289 command.keyframe_set = keyframe_set;
1290 command.keyframe = keyframe;
1291 command.default_auto = default_auto;
1293 send_command(&command);
1299 struct Vertex : ListItem<Vertex>
1303 // this list is only used from the main thread, no locking needed
1304 // this must be a list so that pointers to allocated entries remain valid
1305 // when new entries are added
1306 static List<Vertex> *vertex_cache = 0;
1308 static void combine_callback(GLdouble coords[3],
1309 GLdouble *vertex_data[4],
1313 // can't use malloc here; GLU doesn't delete the memory for us!
1314 Vertex* vertex = vertex_cache->append();
1315 vertex->c[0] = coords[0];
1316 vertex->c[1] = coords[1];
1317 vertex->c[2] = coords[2];
1318 // we don't need to interpolate anything
1320 *dataOut = &vertex->c[0];
1325 void Playback3D::do_mask_sync(Playback3DCommand *command)
1328 command->canvas->lock_canvas("Playback3D::do_mask_sync");
1329 if(command->canvas->get_canvas())
1331 BC_WindowBase *window = command->canvas->get_canvas();
1332 window->lock_window("Playback3D::do_mask_sync");
1333 window->enable_opengl();
1335 switch(command->frame->get_opengl_state())
1338 // Time to upload to the texture
1339 command->frame->to_texture();
1342 case VFrame::SCREEN:
1343 // Read back from PBuffer
1344 // Bind context to pbuffer
1345 command->frame->enable_opengl();
1346 command->frame->screen_to_texture();
1352 // Create PBuffer and draw the mask on it
1353 command->frame->enable_opengl();
1355 // Initialize coordinate system
1356 int w = command->frame->get_w();
1357 int h = command->frame->get_h();
1358 command->frame->init_screen();
1361 glDisable(GL_TEXTURE_2D);
1362 if(command->default_auto->mode == MASK_MULTIPLY_ALPHA)
1364 glClearColor(0.0, 0.0, 0.0, 0.0);
1365 glColor4f((float)command->keyframe->value / 100,
1366 (float)command->keyframe->value / 100,
1367 (float)command->keyframe->value / 100,
1372 glClearColor(1.0, 1.0, 1.0, 1.0);
1373 glColor4f((float)1.0 - (float)command->keyframe->value / 100,
1374 (float)1.0 - (float)command->keyframe->value / 100,
1375 (float)1.0 - (float)command->keyframe->value / 100,
1378 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1381 // Draw mask with scaling to simulate feathering
1382 GLUtesselator *tesselator = gluNewTess();
1383 gluTessProperty(tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);
1384 gluTessCallback(tesselator, GLU_TESS_VERTEX, (GLvoid (*) ( )) &glVertex3dv);
1385 gluTessCallback(tesselator, GLU_TESS_BEGIN, (GLvoid (*) ( )) &glBegin);
1386 gluTessCallback(tesselator, GLU_TESS_END, (GLvoid (*) ( )) &glEnd);
1387 gluTessCallback(tesselator, GLU_TESS_COMBINE, (GLvoid (*) ( ))&combine_callback);
1389 vertex_cache = new List<Vertex>;
1392 // Draw every submask as a new polygon
1393 int total_submasks = command->keyframe_set->total_submasks(
1394 command->start_position_project,
1396 float scale = command->keyframe->feather + 1;
1397 int display_list = glGenLists(1);
1398 glNewList(display_list, GL_COMPILE);
1399 for(int k = 0; k < total_submasks; k++)
1401 gluTessBeginPolygon(tesselator, NULL);
1402 gluTessBeginContour(tesselator);
1403 ArrayList<MaskPoint*> *points = new ArrayList<MaskPoint*>;
1404 command->keyframe_set->get_points(points,
1406 command->start_position_project,
1409 int first_point = 0;
1410 // Need to tabulate every vertex in persistent memory because
1411 // gluTessVertex doesn't copy them.
1412 ArrayList<GLdouble*> coords;
1413 for(int i = 0; i < points->total; i++)
1415 MaskPoint *point1 = points->values[i];
1416 MaskPoint *point2 = (i >= points->total - 1) ?
1418 points->values[i + 1];
1422 if(point1->control_x2 == 0 &&
1423 point1->control_y2 == 0 &&
1424 point2->control_x1 == 0 &&
1425 point2->control_y1 == 0)
1428 float x0 = point1->x;
1429 float y0 = point1->y;
1430 float x1 = point1->x + point1->control_x2;
1431 float y1 = point1->y + point1->control_y2;
1432 float x2 = point2->x + point2->control_x1;
1433 float y2 = point2->y + point2->control_y1;
1434 float x3 = point2->x;
1435 float y3 = point2->y;
1437 // forward differencing bezier curves implementation taken from GPL code at
1438 // http://cvs.sourceforge.net/viewcvs.py/guliverkli/guliverkli/src/subtitles/Rasterizer.cpp?rev=1.3
1440 float cx3, cx2, cx1, cx0, cy3, cy2, cy1, cy0;
1447 cx3 = - x0 + 3*x1 - 3*x2 + x3;
1448 cx2 = 3*x0 - 6*x1 + 3*x2;
1452 cy3 = - y0 + 3*y1 - 3*y2 + y3;
1453 cy2 = 3*y0 - 6*y1 + 3*y2;
1457 // This equation is from Graphics Gems I.
1459 // The idea is that since we're approximating a cubic curve with lines,
1460 // any error we incur is due to the curvature of the line, which we can
1461 // estimate by calculating the maximum acceleration of the curve. For
1462 // a cubic, the acceleration (second derivative) is a line, meaning that
1463 // the absolute maximum acceleration must occur at either the beginning
1464 // (|c2|) or the end (|c2+c3|). Our bounds here are a little more
1465 // conservative than that, but that's okay.
1468 float maxaccel1 = fabs(2*cy2) + fabs(6*cy3);
1469 float maxaccel2 = fabs(2*cx2) + fabs(6*cx3);
1471 float maxaccel = maxaccel1 > maxaccel2 ? maxaccel1 : maxaccel2;
1474 if(maxaccel > 8.0) h = sqrt((8.0) / maxaccel);
1475 segments = int(1/h);
1478 for(int j = 0; j <= segments; j++)
1480 float t = (float)j / segments;
1481 x = cx0 + t*(cx1 + t*(cx2 + t*cx3));
1482 y = cy0 + t*(cy1 + t*(cy2 + t*cy3));
1484 if(j > 0 || first_point)
1486 GLdouble *coord = new GLdouble[3];
1487 coord[0] = x / scale;
1488 coord[1] = -h + y / scale;
1490 coords.append(coord);
1496 // Now that we know the total vertices, send them to GLU
1497 for(int i = 0; i < coords.total; i++)
1498 gluTessVertex(tesselator, coords.values[i], coords.values[i]);
1500 gluTessEndContour(tesselator);
1501 gluTessEndPolygon(tesselator);
1502 points->remove_all_objects();
1504 coords.remove_all_objects();
1507 glCallList(display_list);
1508 glDeleteLists(display_list, 1);
1509 gluDeleteTess(tesselator);
1511 delete vertex_cache;
1514 glColor4f(1, 1, 1, 1);
1517 // Read mask into temporary texture.
1518 // For feathering, just read the part of the screen after the downscaling.
1521 float w_scaled = w / scale;
1522 float h_scaled = h / scale;
1523 // Don't vary the texture size according to scaling because that
1524 // would waste memory.
1525 // This enables and binds the temporary texture.
1526 glActiveTexture(GL_TEXTURE1);
1527 BC_Texture::new_texture(&temp_texture,
1530 command->frame->get_color_model());
1531 temp_texture->bind(1);
1532 glReadBuffer(GL_BACK);
1534 // Need to add extra size to fill in the bottom right
1535 glCopyTexSubImage2D(GL_TEXTURE_2D,
1541 (int)MIN(w_scaled + 2, w),
1542 (int)MIN(h_scaled + 2, h));
1544 command->frame->bind_texture(0);
1547 // For feathered masks, use a shader to multiply.
1548 // For unfeathered masks, we could use a stencil buffer
1549 // for further optimization but we also need a YUV algorithm.
1550 unsigned int frag_shader = 0;
1551 switch(temp_texture->get_texture_components())
1554 if(command->frame->get_color_model() == BC_YUV888)
1555 frag_shader = VFrame::make_shader(0,
1556 multiply_yuvmask3_frag,
1559 frag_shader = VFrame::make_shader(0,
1560 multiply_mask3_frag,
1564 frag_shader = VFrame::make_shader(0,
1565 multiply_mask4_frag,
1573 glUseProgram(frag_shader);
1574 if((variable = glGetUniformLocation(frag_shader, "tex")) >= 0)
1575 glUniform1i(variable, 0);
1576 if((variable = glGetUniformLocation(frag_shader, "tex1")) >= 0)
1577 glUniform1i(variable, 1);
1578 if((variable = glGetUniformLocation(frag_shader, "scale")) >= 0)
1579 glUniform1f(variable, scale);
1584 // Write texture to PBuffer with multiply and scaling for feather.
1587 command->frame->draw_texture(0, 0, w, h, 0, 0, w, h);
1588 command->frame->set_opengl_state(VFrame::SCREEN);
1591 // Disable temp texture
1594 glActiveTexture(GL_TEXTURE1);
1595 glDisable(GL_TEXTURE_2D);
1596 delete temp_texture;
1599 glActiveTexture(GL_TEXTURE0);
1600 glDisable(GL_TEXTURE_2D);
1603 window->enable_opengl();
1604 window->unlock_window();
1606 command->canvas->unlock_canvas();
1619 void Playback3D::convert_cmodel(Canvas *canvas,
1623 // Do nothing if colormodels are equivalent in OpenGL & the image is in hardware.
1624 int src_cmodel = output->get_color_model();
1626 (output->get_opengl_state() == VFrame::TEXTURE ||
1627 output->get_opengl_state() == VFrame::SCREEN) &&
1628 // OpenGL has no floating point.
1629 ( (src_cmodel == BC_RGB888 && dst_cmodel == BC_RGB_FLOAT) ||
1630 (src_cmodel == BC_RGBA8888 && dst_cmodel == BC_RGBA_FLOAT) ||
1631 (src_cmodel == BC_RGB_FLOAT && dst_cmodel == BC_RGB888) ||
1632 (src_cmodel == BC_RGBA_FLOAT && dst_cmodel == BC_RGBA8888) ||
1633 // OpenGL sets alpha to 1 on import
1634 (src_cmodel == BC_RGB888 && dst_cmodel == BC_RGBA8888) ||
1635 (src_cmodel == BC_YUV888 && dst_cmodel == BC_YUVA8888) ||
1636 (src_cmodel == BC_RGB_FLOAT && dst_cmodel == BC_RGBA_FLOAT) )
1641 Playback3DCommand command;
1642 command.command = Playback3DCommand::CONVERT_CMODEL;
1643 command.canvas = canvas;
1644 command.frame = output;
1645 command.dst_cmodel = dst_cmodel;
1646 send_command(&command);
1649 void Playback3D::convert_cmodel_sync(Playback3DCommand *command)
1652 command->canvas->lock_canvas("Playback3D::convert_cmodel_sync");
1654 if(command->canvas->get_canvas())
1656 BC_WindowBase *window = command->canvas->get_canvas();
1657 window->lock_window("Playback3D::convert_cmodel_sync");
1658 window->enable_opengl();
1660 // Import into hardware
1661 command->frame->enable_opengl();
1662 command->frame->init_screen();
1663 command->frame->to_texture();
1665 // Colormodel permutation
1666 const char *shader = 0;
1667 int src_cmodel = command->frame->get_color_model();
1668 int dst_cmodel = command->dst_cmodel;
1674 } cmodel_shader_table_t;
1675 static cmodel_shader_table_t cmodel_shader_table[] =
1677 { BC_RGB888, BC_YUV888, rgb_to_yuv_frag },
1678 { BC_RGB888, BC_YUVA8888, rgb_to_yuv_frag },
1679 { BC_RGBA8888, BC_RGB888, rgba_to_rgb_frag },
1680 { BC_RGBA8888, BC_RGB_FLOAT, rgba_to_rgb_frag },
1681 { BC_RGBA8888, BC_YUV888, rgba_to_yuv_frag },
1682 { BC_RGBA8888, BC_YUVA8888, rgb_to_yuv_frag },
1683 { BC_RGB_FLOAT, BC_YUV888, rgb_to_yuv_frag },
1684 { BC_RGB_FLOAT, BC_YUVA8888, rgb_to_yuv_frag },
1685 { BC_RGBA_FLOAT, BC_RGB888, rgba_to_rgb_frag },
1686 { BC_RGBA_FLOAT, BC_RGB_FLOAT, rgba_to_rgb_frag },
1687 { BC_RGBA_FLOAT, BC_YUV888, rgba_to_yuv_frag },
1688 { BC_RGBA_FLOAT, BC_YUVA8888, rgb_to_yuv_frag },
1689 { BC_YUV888, BC_RGB888, yuv_to_rgb_frag },
1690 { BC_YUV888, BC_RGBA8888, yuv_to_rgb_frag },
1691 { BC_YUV888, BC_RGB_FLOAT, yuv_to_rgb_frag },
1692 { BC_YUV888, BC_RGBA_FLOAT, yuv_to_rgb_frag },
1693 { BC_YUVA8888, BC_RGB888, yuva_to_rgb_frag },
1694 { BC_YUVA8888, BC_RGBA8888, yuv_to_rgb_frag },
1695 { BC_YUVA8888, BC_RGB_FLOAT, yuva_to_rgb_frag },
1696 { BC_YUVA8888, BC_RGBA_FLOAT, yuv_to_rgb_frag },
1697 { BC_YUVA8888, BC_YUV888, yuva_to_yuv_frag },
1700 int table_size = sizeof(cmodel_shader_table) / sizeof(cmodel_shader_table_t);
1701 for(int i = 0; i < table_size; i++)
1703 if(cmodel_shader_table[i].src == src_cmodel &&
1704 cmodel_shader_table[i].dst == dst_cmodel)
1706 shader = cmodel_shader_table[i].shader;
1711 // printf("Playback3D::convert_cmodel_sync %d %d %d shader=\n%s",
1713 // command->frame->get_color_model(),
1714 // command->dst_cmodel,
1719 //printf("Playback3D::convert_cmodel_sync %d\n", __LINE__);
1720 command->frame->bind_texture(0);
1721 unsigned int shader_id = -1;
1724 shader_id = VFrame::make_shader(0,
1727 glUseProgram(shader_id);
1728 glUniform1i(glGetUniformLocation(shader_id, "tex"), 0);
1731 command->frame->draw_texture();
1733 if(shader) glUseProgram(0);
1735 command->frame->set_opengl_state(VFrame::SCREEN);
1738 window->unlock_window();
1741 command->canvas->unlock_canvas();
1745 void Playback3D::do_fade(Canvas *canvas, VFrame *frame, float fade)
1747 Playback3DCommand command;
1748 command.command = Playback3DCommand::DO_FADE;
1749 command.canvas = canvas;
1750 command.frame = frame;
1751 command.alpha = fade;
1752 send_command(&command);
1755 void Playback3D::do_fade_sync(Playback3DCommand *command)
1758 command->canvas->lock_canvas("Playback3D::do_mask_sync");
1759 if(command->canvas->get_canvas())
1761 BC_WindowBase *window = command->canvas->get_canvas();
1762 window->lock_window("Playback3D::do_fade_sync");
1763 window->enable_opengl();
1765 switch(command->frame->get_opengl_state())
1768 command->frame->to_texture();
1771 case VFrame::SCREEN:
1772 // Read back from PBuffer
1773 // Bind context to pbuffer
1774 command->frame->enable_opengl();
1775 command->frame->screen_to_texture();
1780 command->frame->enable_opengl();
1781 command->frame->init_screen();
1782 command->frame->bind_texture(0);
1784 // glClearColor(0.0, 0.0, 0.0, 0.0);
1785 // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1786 glDisable(GL_BLEND);
1787 unsigned int frag_shader = 0;
1788 switch(command->frame->get_color_model())
1790 // For the alpha colormodels, the native function seems to multiply the
1791 // components by the alpha instead of just the alpha.
1795 frag_shader = VFrame::make_shader(0, fade_rgba_frag, 0);
1800 glBlendFunc(GL_SRC_ALPHA, GL_ZERO);
1801 glColor4f(command->alpha, command->alpha, command->alpha, 1);
1806 frag_shader = VFrame::make_shader(0, fade_yuv_frag, 0);
1813 glUseProgram(frag_shader);
1815 if((variable = glGetUniformLocation(frag_shader, "tex")) >= 0)
1816 glUniform1i(variable, 0);
1817 if((variable = glGetUniformLocation(frag_shader, "alpha")) >= 0)
1818 glUniform1f(variable, command->alpha);
1821 command->frame->draw_texture();
1822 command->frame->set_opengl_state(VFrame::SCREEN);
1829 glColor4f(1, 1, 1, 1);
1830 glDisable(GL_BLEND);
1832 window->unlock_window();
1834 command->canvas->unlock_canvas();
1848 int Playback3D::run_plugin(Canvas *canvas, PluginClient *client)
1850 Playback3DCommand command;
1851 command.command = Playback3DCommand::PLUGIN;
1852 command.canvas = canvas;
1853 command.plugin_client = client;
1854 return send_command(&command);
1857 void Playback3D::run_plugin_sync(Playback3DCommand *command)
1859 command->canvas->lock_canvas("Playback3D::run_plugin_sync");
1860 if(command->canvas->get_canvas())
1862 BC_WindowBase *window = command->canvas->get_canvas();
1863 window->lock_window("Playback3D::run_plugin_sync");
1864 window->enable_opengl();
1866 command->result = ((PluginVClient*)command->plugin_client)->handle_opengl();
1868 window->unlock_window();
1870 command->canvas->unlock_canvas();