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
25 #include "bcsignals.h"
26 #include "bcwindowbase.h"
29 #include "condition.h"
30 #include "maskautos.h"
33 #include "overlayframe.inc"
34 #include "overlayframe.h"
35 #include "playback3d.h"
36 #include "pluginclient.h"
37 #include "pluginvclient.h"
38 #include "transportque.inc"
56 // These should be passed to VFrame::make_shader to construct shaders.
57 // Can't hard code sampler2D
61 static const char *yuv_to_rgb_frag =
62 "uniform sampler2D tex;\n"
63 "uniform mat3 yuv_to_rgb_matrix;\n"
64 "uniform float yminf;\n"
67 " vec4 yuva = texture2D(tex, gl_TexCoord[0].st);\n"
68 " yuva.rgb -= vec3(yminf, 0.5, 0.5);\n"
69 " gl_FragColor = vec4(yuv_to_rgb_matrix * yuva.rgb, yuva.a);\n"
72 static const char *yuva_to_yuv_frag =
73 "uniform sampler2D tex;\n"
76 " vec4 yuva = texture2D(tex, gl_TexCoord[0].st);\n"
77 " float a = yuva.a;\n"
78 " float anti_a = 1.0 - a;\n"
80 " yuva.g = yuva.g * a + 0.5 * anti_a;\n"
81 " yuva.b = yuva.b * a + 0.5 * anti_a;\n"
83 " gl_FragColor = yuva;\n"
86 static const char *yuva_to_rgb_frag =
87 "uniform sampler2D tex;\n"
88 "uniform mat3 yuv_to_rgb_matrix;\n"
89 "uniform float yminf;\n"
92 " vec4 yuva = texture2D(tex, gl_TexCoord[0].st);\n"
93 " yuva.rgb -= vec3(yminf, 0.5, 0.5);\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"
102 "uniform mat3 rgb_to_yuv_matrix;\n"
103 "uniform float yminf;\n"
106 " vec4 rgba = texture2D(tex, gl_TexCoord[0].st);\n"
107 " rgba.rgb = rgb_to_yuv_matrix * rgba.rgb;\n"
108 " rgba.rgb += vec3(yminf, 0.5, 0.5);\n"
109 " gl_FragColor = rgba;\n"
113 static const char *rgba_to_rgb_frag =
114 "uniform sampler2D tex;\n"
117 " vec4 rgba = texture2D(tex, gl_TexCoord[0].st);\n"
118 " rgba.rgb *= rgba.a;\n"
120 " gl_FragColor = rgba;\n"
123 static const char *rgba_to_yuv_frag =
124 "uniform sampler2D tex;\n"
125 "uniform mat3 rgb_to_yuv_matrix;\n"
126 "uniform float yminf;\n"
129 " vec4 rgba = texture2D(tex, gl_TexCoord[0].st);\n"
130 " rgba.rgb *= rgba.a;\n"
132 " rgba.rgb = rgb_to_yuv_matrix * rgba.rgb;\n"
133 " rgba.rgb += vec3(yminf, 0.5, 0.5);\n"
134 " gl_FragColor = rgba;\n"
137 static const char *rgba_to_rgb_flatten =
139 " gl_FragColor.rgb *= gl_FragColor.a;\n"
140 " gl_FragColor.a = 1.0;\n"
143 #define GL_STD_BLEND(FN) \
144 static const char *blend_##FN##_frag = \
145 "uniform sampler2D tex2;\n" \
146 "uniform vec2 tex2_dimensions;\n" \
147 "uniform float alpha;\n" \
149 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n" \
151 " result.rgb = " SS(COLOR_##FN(1.0, gl_FragColor.rgb, gl_FragColor.a, canvas.rgb, canvas.a)) ";\n" \
152 " result.a = " SS(ALPHA_##FN(1.0, gl_FragColor.a, canvas.a)) ";\n" \
153 " gl_FragColor = mix(canvas, result, alpha);\n" \
156 #define GL_VEC_BLEND(FN) \
157 static const char *blend_##FN##_frag = \
158 "uniform sampler2D tex2;\n" \
159 "uniform vec2 tex2_dimensions;\n" \
160 "uniform float alpha;\n" \
162 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n" \
164 " result.r = " SS(COLOR_##FN(1.0, gl_FragColor.r, gl_FragColor.a, canvas.r, canvas.a)) ";\n" \
165 " result.g = " SS(COLOR_##FN(1.0, gl_FragColor.g, gl_FragColor.a, canvas.g, canvas.a)) ";\n" \
166 " result.b = " SS(COLOR_##FN(1.0, gl_FragColor.b, gl_FragColor.a, canvas.b, canvas.a)) ";\n" \
167 " result.a = " SS(ALPHA_##FN(1.0, gl_FragColor.a, canvas.a)) ";\n" \
168 " result = clamp(result, 0.0, 1.0);\n" \
169 " gl_FragColor = mix(canvas, result, alpha);\n" \
187 static const char *blend_NORMAL_frag =
188 "uniform sampler2D tex2;\n"
189 "uniform vec2 tex2_dimensions;\n"
190 "uniform float alpha;\n"
192 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
193 " vec4 result = mix(canvas, gl_FragColor, gl_FragColor.a);\n"
194 " gl_FragColor = mix(canvas, result, alpha);\n"
198 static const char *blend_REPLACE_frag =
199 "uniform float alpha;\n"
204 static const char *blend_ADDITION_frag =
205 "uniform sampler2D tex2;\n"
206 "uniform vec2 tex2_dimensions;\n"
207 "uniform float alpha;\n"
209 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
210 " vec4 result = clamp(gl_FragColor + canvas, 0.0, 1.0);\n"
211 " gl_FragColor = mix(canvas, result, alpha);\n"
215 static const char *blend_SUBTRACT_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 = clamp(gl_FragColor - canvas, 0.0, 1.0);\n"
222 " gl_FragColor = mix(canvas, result, alpha);\n"
225 GL_STD_BLEND(MULTIPLY);
226 GL_VEC_BLEND(DIVIDE);
229 GL_VEC_BLEND(DARKEN);
230 GL_VEC_BLEND(LIGHTEN);
232 GL_STD_BLEND(DST_ATOP);
233 GL_STD_BLEND(DST_IN);
234 GL_STD_BLEND(DST_OUT);
235 GL_STD_BLEND(DST_OVER);
237 GL_STD_BLEND(SRC_ATOP);
238 GL_STD_BLEND(SRC_IN);
239 GL_STD_BLEND(SRC_OUT);
240 GL_STD_BLEND(SRC_OVER);
244 GL_VEC_BLEND(OVERLAY);
245 GL_STD_BLEND(SCREEN);
248 GL_VEC_BLEND(HARDLIGHT);
249 GL_VEC_BLEND(SOFTLIGHT);
250 GL_VEC_BLEND(DIFFERENCE);
252 static const char *read_texture_frag =
253 "uniform sampler2D tex;\n"
256 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
259 static const char *multiply_mask4_frag =
260 "uniform sampler2D tex;\n"
261 "uniform sampler2D tex1;\n"
262 "uniform float scale;\n"
265 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
266 " gl_FragColor.a *= texture2D(tex1, gl_TexCoord[0].st / vec2(scale, scale)).r;\n"
269 static const char *multiply_mask3_frag =
270 "uniform sampler2D tex;\n"
271 "uniform sampler2D tex1;\n"
272 "uniform float scale;\n"
273 "uniform bool is_yuv;\n"
276 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
277 " float a = texture2D(tex1, gl_TexCoord[0].st / vec2(scale, scale)).r;\n"
278 " gl_FragColor.rgb *= vec3(a, a, a);\n"
281 static const char *multiply_yuvmask3_frag =
282 "uniform sampler2D tex;\n"
283 "uniform sampler2D tex1;\n"
284 "uniform float scale;\n"
287 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
288 " float a = texture2D(tex1, gl_TexCoord[0].st / vec2(scale, scale)).r;\n"
289 " gl_FragColor.gb -= vec2(0.5, 0.5);\n"
290 " gl_FragColor.rgb *= vec3(a, a, a);\n"
291 " gl_FragColor.gb += vec2(0.5, 0.5);\n"
294 static const char *fade_rgba_frag =
295 "uniform sampler2D tex;\n"
296 "uniform float alpha;\n"
299 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
300 " gl_FragColor.a *= alpha;\n"
303 static const char *fade_yuv_frag =
304 "uniform sampler2D tex;\n"
305 "uniform float alpha;\n"
308 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
309 " gl_FragColor.r *= alpha;\n"
310 " gl_FragColor.gb -= vec2(0.5, 0.5);\n"
311 " gl_FragColor.g *= alpha;\n"
312 " gl_FragColor.b *= alpha;\n"
313 " gl_FragColor.gb += vec2(0.5, 0.5);\n"
319 Playback3DCommand::Playback3DCommand()
320 : BC_SynchronousCommand()
326 void Playback3DCommand::copy_from(BC_SynchronousCommand *command)
328 Playback3DCommand *ptr = (Playback3DCommand*)command;
329 this->canvas = ptr->canvas;
330 this->is_cleared = ptr->is_cleared;
332 this->in_x1 = ptr->in_x1;
333 this->in_y1 = ptr->in_y1;
334 this->in_x2 = ptr->in_x2;
335 this->in_y2 = ptr->in_y2;
336 this->out_x1 = ptr->out_x1;
337 this->out_y1 = ptr->out_y1;
338 this->out_x2 = ptr->out_x2;
339 this->out_y2 = ptr->out_y2;
340 this->alpha = ptr->alpha;
341 this->mode = ptr->mode;
342 this->interpolation_type = ptr->interpolation_type;
344 this->input = ptr->input;
345 this->start_position_project = ptr->start_position_project;
346 this->keyframe_set = ptr->keyframe_set;
347 this->keyframe = ptr->keyframe;
348 this->default_auto = ptr->default_auto;
349 this->plugin_client = ptr->plugin_client;
350 this->want_texture = ptr->want_texture;
351 this->is_nested = ptr->is_nested;
352 this->dst_cmodel = ptr->dst_cmodel;
354 BC_SynchronousCommand::copy_from(command);
358 ///static void glDebugCallback(GLenum src, GLenum typ, GLuint id,
359 /// GLenum svy, GLsizei len, const GLchar* msg, void* dat)
360 //static void glDebugCallback(unsigned int src, unsigned int typ, unsigned int id,
361 // unsigned int svy, int len, const char* msg, const void* dat)
363 // printf("glDebug: %d:%d; %d/%d %s\n",src,typ,id,svy,msg);
367 Playback3D::Playback3D(MWindow *mwindow)
370 this->mwindow = mwindow;
372 //Enabling OpenGL debug output on nVidia drivers
373 // glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, 0, GL_TRUE);
374 // glEnable(GL_DEBUG_OUTPUT);
375 // glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
376 // glDebugMessageCallback(glDebugCallback, 0);
379 Playback3D::~Playback3D()
386 BC_SynchronousCommand* Playback3D::new_command()
388 return new Playback3DCommand;
393 void Playback3D::handle_command(BC_SynchronousCommand *command)
395 //printf("Playback3D::handle_command 1 %d\n", command->command);
396 switch(command->command)
398 case Playback3DCommand::WRITE_BUFFER:
399 write_buffer_sync((Playback3DCommand*)command);
402 case Playback3DCommand::CLEAR_OUTPUT:
403 clear_output_sync((Playback3DCommand*)command);
406 case Playback3DCommand::CLEAR_INPUT:
407 clear_input_sync((Playback3DCommand*)command);
410 case Playback3DCommand::DO_CAMERA:
411 do_camera_sync((Playback3DCommand*)command);
414 case Playback3DCommand::OVERLAY:
415 overlay_sync((Playback3DCommand*)command);
418 case Playback3DCommand::DO_FADE:
419 do_fade_sync((Playback3DCommand*)command);
422 case Playback3DCommand::DO_MASK:
423 do_mask_sync((Playback3DCommand*)command);
426 case Playback3DCommand::PLUGIN:
427 run_plugin_sync((Playback3DCommand*)command);
430 case Playback3DCommand::COPY_FROM:
431 copy_from_sync((Playback3DCommand*)command);
434 case Playback3DCommand::CONVERT_CMODEL:
435 convert_cmodel_sync((Playback3DCommand*)command);
438 // case Playback3DCommand::DRAW_REFRESH:
439 // draw_refresh_sync((Playback3DCommand*)command);
442 //printf("Playback3D::handle_command 10\n");
448 void Playback3D::copy_from(Canvas *canvas,
453 Playback3DCommand command;
454 command.command = Playback3DCommand::COPY_FROM;
455 command.canvas = canvas;
458 command.want_texture = want_texture;
459 send_command(&command);
462 void Playback3D::copy_from_sync(Playback3DCommand *command)
465 command->canvas->lock_canvas("Playback3D::draw_refresh_sync");
466 BC_WindowBase *window = command->canvas->get_canvas();
469 window->lock_window("Playback3D:draw_refresh_sync");
470 window->enable_opengl();
471 int w = command->input->get_w();
472 int h = command->input->get_h();
474 if(command->input->get_opengl_state() == VFrame::SCREEN &&
475 w == command->frame->get_w() && h == command->frame->get_h())
477 // printf("Playback3D::copy_from_sync 1 %d %d %d %d %d\n",
478 // command->input->get_w(),
479 // command->input->get_h(),
480 // command->frame->get_w(),
481 // command->frame->get_h(),
482 // command->frame->get_color_model());
483 // With NVidia at least,
486 printf("Playback3D::copy_from_sync: w=%d not supported because it is not divisible by 4.\n", w);
490 if(command->want_texture)
492 //printf("Playback3D::copy_from_sync 1 dst=%p src=%p\n", command->frame, command->input);
493 // Screen_to_texture requires the source pbuffer enabled.
494 command->input->enable_opengl();
495 command->frame->screen_to_texture();
496 command->frame->set_opengl_state(VFrame::TEXTURE);
501 command->input->enable_opengl();
502 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
503 glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE,
504 command->frame->get_rows()[0]);
505 command->frame->flip_vert();
506 command->frame->set_opengl_state(VFrame::RAM);
511 printf("Playback3D::copy_from_sync: invalid formats opengl_state=%d %dx%d -> %dx%d\n",
512 command->input->get_opengl_state(), w, h,
513 command->frame->get_w(), command->frame->get_h());
516 window->unlock_window();
518 command->canvas->unlock_canvas();
525 // void Playback3D::draw_refresh(Canvas *canvas,
536 // Playback3DCommand command;
537 // command.command = Playback3DCommand::DRAW_REFRESH;
538 // command.canvas = canvas;
539 // command.frame = frame;
540 // command.in_x1 = in_x1;
541 // command.in_y1 = in_y1;
542 // command.in_x2 = in_x2;
543 // command.in_y2 = in_y2;
544 // command.out_x1 = out_x1;
545 // command.out_y1 = out_y1;
546 // command.out_x2 = out_x2;
547 // command.out_y2 = out_y2;
548 // send_command(&command);
551 // void Playback3D::draw_refresh_sync(Playback3DCommand *command)
553 // command->canvas->lock_canvas("Playback3D::draw_refresh_sync");
554 // BC_WindowBase *window = command->canvas->get_canvas();
557 // window->lock_window("Playback3D:draw_refresh_sync");
558 // window->enable_opengl();
560 // // Read output pbuffer back to RAM in project colormodel
561 // // RGB 8bit is fastest for OpenGL to read back.
562 // command->frame->reallocate(0,
566 // command->frame->get_w(),
567 // command->frame->get_h(),
570 // command->frame->screen_to_ram();
572 // window->clear_box(0,
576 // window->draw_vframe(command->frame,
577 // (int)command->out_x1,
578 // (int)command->out_y1,
579 // (int)(command->out_x2 - command->out_x1),
580 // (int)(command->out_y2 - command->out_y1),
581 // (int)command->in_x1,
582 // (int)command->in_y1,
583 // (int)(command->in_x2 - command->in_x1),
584 // (int)(command->in_y2 - command->in_y1),
587 // window->unlock_window();
589 // command->canvas->unlock_canvas();
596 void Playback3D::write_buffer(Canvas *canvas,
608 Playback3DCommand command;
609 command.command = Playback3DCommand::WRITE_BUFFER;
610 command.canvas = canvas;
611 command.frame = frame;
612 command.in_x1 = in_x1;
613 command.in_y1 = in_y1;
614 command.in_x2 = in_x2;
615 command.in_y2 = in_y2;
616 command.out_x1 = out_x1;
617 command.out_y1 = out_y1;
618 command.out_x2 = out_x2;
619 command.out_y2 = out_y2;
620 command.is_cleared = is_cleared;
621 send_command(&command);
625 void Playback3D::write_buffer_sync(Playback3DCommand *command)
627 command->canvas->lock_canvas("Playback3D::write_buffer_sync");
628 if(command->canvas->get_canvas())
630 BC_WindowBase *window = command->canvas->get_canvas();
631 window->lock_window("Playback3D::write_buffer_sync");
632 // Update hidden cursor
633 window->update_video_cursor();
634 // Make sure OpenGL is enabled first.
635 window->enable_opengl();
638 //printf("Playback3D::write_buffer_sync 1 %d\n", window->get_id());
639 switch(command->frame->get_opengl_state())
641 // Upload texture and composite to screen
643 command->frame->to_texture();
644 draw_output(command);
646 // Composite texture to screen and swap buffer
647 case VFrame::TEXTURE:
648 draw_output(command);
652 window->flip_opengl();
655 printf("Playback3D::write_buffer_sync unknown state\n");
658 window->unlock_window();
661 command->canvas->unlock_canvas();
666 void Playback3D::draw_output(Playback3DCommand *command)
669 int texture_id = command->frame->get_texture_id();
670 BC_WindowBase *window = command->canvas->get_canvas();
672 // printf("Playback3D::draw_output 1 texture_id=%d window=%p\n",
674 // command->canvas->get_canvas());
679 // If virtual console is being used, everything in this function has
680 // already been done except the page flip.
683 canvas_w = window->get_w();
684 canvas_h = window->get_h();
685 VFrame::init_screen(canvas_w, canvas_h);
687 if(!command->is_cleared)
689 // If we get here, the virtual console was not used.
694 // Undo any previous shader settings
695 command->frame->bind_texture(0);
697 // Convert colormodel
698 unsigned int shader = !BC_CModels::is_yuv(command->frame->get_color_model()) ? 0 :
699 VFrame::make_shader(0, yuv_to_rgb_frag, 0);
701 glUseProgram(shader);
702 // Set texture unit of the texture
703 int variable = glGetUniformLocation(shader, "tex");
704 glUniform1i(variable, 0);
705 BC_GL_YUV_TO_RGB(shader);
708 if(BC_CModels::components(command->frame->get_color_model()) == 4)
711 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
714 command->frame->draw_texture(
715 command->in_x1, command->in_y1, command->in_x2, command->in_y2,
716 command->out_x1, command->out_y1, command->out_x2, command->out_y2,
720 // printf("Playback3D::draw_output 2 %f,%f %f,%f -> %f,%f %f,%f\n",
732 command->canvas->get_canvas()->flip_opengl();
739 void Playback3D::init_frame(Playback3DCommand *command)
742 canvas_w = command->canvas->get_canvas()->get_w();
743 canvas_h = command->canvas->get_canvas()->get_h();
745 glClearColor(0.0, 0.0, 0.0, 0.0);
746 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
751 void Playback3D::clear_output(Canvas *canvas, VFrame *output)
753 Playback3DCommand command;
754 command.command = Playback3DCommand::CLEAR_OUTPUT;
755 command.canvas = canvas;
756 command.frame = output;
757 send_command(&command);
760 void Playback3D::clear_output_sync(Playback3DCommand *command)
762 command->canvas->lock_canvas("Playback3D::clear_output_sync");
763 if(command->canvas->get_canvas())
765 command->canvas->get_canvas()->lock_window("Playback3D::clear_output_sync");
766 // If we get here, the virtual console is being used.
767 command->canvas->get_canvas()->enable_opengl();
769 // Using pbuffer for refresh frame.
772 command->frame->enable_opengl();
777 command->canvas->get_canvas()->unlock_window();
779 command->canvas->unlock_canvas();
783 void Playback3D::clear_input(Canvas *canvas, VFrame *frame)
785 Playback3DCommand command;
786 command.command = Playback3DCommand::CLEAR_INPUT;
787 command.canvas = canvas;
788 command.frame = frame;
789 send_command(&command);
792 void Playback3D::clear_input_sync(Playback3DCommand *command)
794 command->canvas->lock_canvas("Playback3D::clear_output_sync");
795 if(command->canvas->get_canvas())
797 command->canvas->get_canvas()->lock_window("Playback3D::clear_output_sync");
798 command->canvas->get_canvas()->enable_opengl();
799 command->frame->enable_opengl();
800 command->frame->clear_pbuffer();
801 command->frame->set_opengl_state(VFrame::SCREEN);
802 command->canvas->get_canvas()->unlock_window();
804 command->canvas->unlock_canvas();
807 void Playback3D::do_camera(Canvas *canvas,
819 Playback3DCommand command;
820 command.command = Playback3DCommand::DO_CAMERA;
821 command.canvas = canvas;
822 command.input = input;
823 command.frame = output;
824 command.in_x1 = in_x1;
825 command.in_y1 = in_y1;
826 command.in_x2 = in_x2;
827 command.in_y2 = in_y2;
828 command.out_x1 = out_x1;
829 command.out_y1 = out_y1;
830 command.out_x2 = out_x2;
831 command.out_y2 = out_y2;
832 send_command(&command);
835 void Playback3D::do_camera_sync(Playback3DCommand *command)
837 command->canvas->lock_canvas("Playback3D::do_camera_sync");
838 if(command->canvas->get_canvas())
840 command->canvas->get_canvas()->lock_window("Playback3D::clear_output_sync");
841 command->canvas->get_canvas()->enable_opengl();
843 command->input->to_texture();
844 command->frame->enable_opengl();
845 command->frame->init_screen();
846 command->frame->clear_pbuffer();
848 command->input->bind_texture(0);
849 // Must call draw_texture in input frame to get the texture coordinates right.
851 // printf("Playback3D::do_camera_sync 1 %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f\n",
857 // (float)command->input->get_h() - command->out_y1,
859 // (float)command->input->get_h() - command->out_y2);
860 command->input->draw_texture(
861 command->in_x1, command->in_y2,
862 command->in_x2, command->in_y1,
864 (float)command->frame->get_h() - command->out_y1,
866 (float)command->frame->get_h() - command->out_y2);
869 command->frame->set_opengl_state(VFrame::SCREEN);
870 command->frame->screen_to_ram();
871 command->canvas->get_canvas()->unlock_window();
873 command->canvas->unlock_canvas();
876 void Playback3D::overlay(Canvas *canvas, VFrame *input,
877 float in_x1, float in_y1, float in_x2, float in_y2,
878 float out_x1, float out_y1, float out_x2, float out_y2,
879 float alpha, int mode, int interpolation_type,
880 VFrame *output, int is_nested)
882 Playback3DCommand command;
883 command.command = Playback3DCommand::OVERLAY;
884 command.canvas = canvas;
885 command.frame = output;
886 command.input = input;
887 command.in_x1 = in_x1;
888 command.in_y1 = in_y1;
889 command.in_x2 = in_x2;
890 command.in_y2 = in_y2;
891 command.out_x1 = out_x1;
892 command.out_y1 = out_y1;
893 command.out_x2 = out_x2;
894 command.out_y2 = out_y2;
895 command.alpha = alpha;
897 command.interpolation_type = interpolation_type;
898 command.is_nested = is_nested;
899 send_command(&command);
902 void Playback3D::overlay_sync(Playback3DCommand *command)
905 // To do these operations, we need to copy the input buffer to a texture
906 // and blend 2 textures in a shader
907 static const char * const overlay_shaders[TRANSFER_TYPES] = {
908 blend_NORMAL_frag, // TRANSFER_NORMAL
909 blend_ADDITION_frag, // TRANSFER_ADDITION
910 blend_SUBTRACT_frag, // TRANSFER_SUBTRACT
911 blend_MULTIPLY_frag, // TRANSFER_MULTIPLY
912 blend_DIVIDE_frag, // TRANSFER_DIVIDE
913 blend_REPLACE_frag, // TRANSFER_REPLACE
914 blend_MAX_frag, // TRANSFER_MAX
915 blend_MIN_frag, // TRANSFER_MIN
916 blend_DARKEN_frag, // TRANSFER_DARKEN
917 blend_LIGHTEN_frag, // TRANSFER_LIGHTEN
918 blend_DST_frag, // TRANSFER_DST
919 blend_DST_ATOP_frag, // TRANSFER_DST_ATOP
920 blend_DST_IN_frag, // TRANSFER_DST_IN
921 blend_DST_OUT_frag, // TRANSFER_DST_OUT
922 blend_DST_OVER_frag, // TRANSFER_DST_OVER
923 blend_SRC_frag, // TRANSFER_SRC
924 blend_SRC_ATOP_frag, // TRANSFER_SRC_ATOP
925 blend_SRC_IN_frag, // TRANSFER_SRC_IN
926 blend_SRC_OUT_frag, // TRANSFER_SRC_OUT
927 blend_SRC_OVER_frag, // TRANSFER_SRC_OVER
928 blend_AND_frag, // TRANSFER_AND
929 blend_OR_frag, // TRANSFER_OR
930 blend_XOR_frag, // TRANSFER_XOR
931 blend_OVERLAY_frag, // TRANSFER_OVERLAY
932 blend_SCREEN_frag, // TRANSFER_SCREEN
933 blend_BURN_frag, // TRANSFER_BURN
934 blend_DODGE_frag, // TRANSFER_DODGE
935 blend_HARDLIGHT_frag, // TRANSFER_HARDLIGHT
936 blend_SOFTLIGHT_frag, // TRANSFER_SOFTLIGHT
937 blend_DIFFERENCE_frag, // TRANSFER_DIFFERENCE
940 command->canvas->lock_canvas("Playback3D::overlay_sync");
941 if(command->canvas->get_canvas()) {
942 BC_WindowBase *window = command->canvas->get_canvas();
943 window->lock_window("Playback3D::overlay_sync");
944 // Make sure OpenGL is enabled first.
945 window->enable_opengl();
946 window->update_video_cursor();
948 glColor4f(1, 1, 1, 1);
953 command->frame->enable_opengl();
954 command->frame->set_opengl_state(VFrame::SCREEN);
955 canvas_w = command->frame->get_w();
956 canvas_h = command->frame->get_h();
960 canvas_w = window->get_w();
961 canvas_h = window->get_h();
965 //printf("Playback3D::overlay_sync 1 %d\n", command->input->get_opengl_state());
966 switch(command->input->get_opengl_state()) {
967 // Upload texture and composite to screen
969 command->input->to_texture();
971 // Just composite texture to screen
972 case VFrame::TEXTURE:
974 // read from PBuffer to texture, then composite texture to screen
976 command->input->enable_opengl();
977 command->input->screen_to_texture();
979 command->frame->enable_opengl();
981 window->enable_opengl();
984 printf("Playback3D::overlay_sync unknown state\n");
989 const char *shader_stack[16];
990 memset(shader_stack,0, sizeof(shader_stack));
991 int total_shaders = 0, need_matrix = 0;
993 VFrame::init_screen(canvas_w, canvas_h);
996 command->input->bind_texture(0);
998 // Convert colormodel to RGB if not nested.
999 // The color model setting in the output frame is ignored.
1000 if( command->is_nested <= 0 && // not nested
1001 BC_CModels::is_yuv(command->input->get_color_model()) ) {
1003 shader_stack[total_shaders++] = yuv_to_rgb_frag;
1007 #define add_shader(s) \
1008 if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag; \
1009 shader_stack[total_shaders++] = s
1011 switch(command->mode) {
1012 case TRANSFER_REPLACE:
1013 // This requires overlaying an alpha multiplied image on a black screen.
1014 if( command->input->get_texture_components() != 4 ) break;
1015 add_shader(overlay_shaders[command->mode]);
1018 enable_overlay_texture(command);
1019 add_shader(overlay_shaders[command->mode]);
1023 // if to flatten alpha
1024 if( command->is_nested < 0 ) {
1025 switch(command->input->get_color_model()) {
1026 // yuv has already been converted to rgb
1030 add_shader(rgba_to_rgb_flatten);
1037 unsigned int shader = !shader_stack[0] ? 0 :
1038 VFrame::make_shader(shader_stack);
1040 glUseProgram(shader);
1041 if( need_matrix ) BC_GL_YUV_TO_RGB(shader);
1042 // Set texture unit of the texture
1043 glUniform1i(glGetUniformLocation(shader, "tex"), 0);
1044 // Set texture unit of the temp texture
1045 glUniform1i(glGetUniformLocation(shader, "tex2"), 1);
1047 int variable = glGetUniformLocation(shader, "alpha");
1048 glUniform1f(variable, command->alpha);
1049 // Set dimensions of the temp texture
1051 glUniform2f(glGetUniformLocation(shader, "tex2_dimensions"),
1052 (float)temp_texture->get_texture_w(),
1053 (float)temp_texture->get_texture_h());
1059 // printf("Playback3D::overlay_sync %f %f %f %f %f %f %f %f\n",
1060 // command->in_x1, command->in_y1, command->in_x2, command->in_y2,
1061 // command->out_x1, command->out_y1, command->out_x2, command->out_y2);
1063 command->input->draw_texture(
1064 command->in_x1, command->in_y1, command->in_x2, command->in_y2,
1065 command->out_x1, command->out_y1, command->out_x2, command->out_y2,
1066 // Don't flip vertical if nested
1067 command->is_nested > 0 ? 0 : 1);
1070 // Delete temp texture
1072 delete temp_texture;
1074 glActiveTexture(GL_TEXTURE1);
1075 glDisable(GL_TEXTURE_2D);
1077 glActiveTexture(GL_TEXTURE0);
1078 glDisable(GL_TEXTURE_2D);
1080 window->unlock_window();
1082 command->canvas->unlock_canvas();
1086 void Playback3D::enable_overlay_texture(Playback3DCommand *command)
1089 glDisable(GL_BLEND);
1091 glActiveTexture(GL_TEXTURE1);
1092 BC_Texture::new_texture(&temp_texture, canvas_w, canvas_h,
1093 command->input->get_color_model());
1094 temp_texture->bind(1);
1096 // Read canvas into texture
1097 glReadBuffer(GL_BACK);
1098 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, canvas_w, canvas_h);
1103 void Playback3D::do_mask(Canvas *canvas,
1105 int64_t start_position_project,
1106 MaskAutos *keyframe_set,
1108 MaskAuto *default_auto)
1110 Playback3DCommand command;
1111 command.command = Playback3DCommand::DO_MASK;
1112 command.canvas = canvas;
1113 command.frame = output;
1114 command.start_position_project = start_position_project;
1115 command.keyframe_set = keyframe_set;
1116 command.keyframe = keyframe;
1117 command.default_auto = default_auto;
1119 send_command(&command);
1125 struct Vertex : ListItem<Vertex>
1129 // this list is only used from the main thread, no locking needed
1130 // this must be a list so that pointers to allocated entries remain valid
1131 // when new entries are added
1132 static List<Vertex> *vertex_cache = 0;
1134 static void combine_callback(GLdouble coords[3],
1135 GLdouble *vertex_data[4],
1139 // can't use malloc here; GLU doesn't delete the memory for us!
1140 Vertex* vertex = vertex_cache->append();
1141 vertex->c[0] = coords[0];
1142 vertex->c[1] = coords[1];
1143 vertex->c[2] = coords[2];
1144 // we don't need to interpolate anything
1146 *dataOut = &vertex->c[0];
1151 void Playback3D::do_mask_sync(Playback3DCommand *command)
1154 command->canvas->lock_canvas("Playback3D::do_mask_sync");
1155 if(command->canvas->get_canvas())
1157 BC_WindowBase *window = command->canvas->get_canvas();
1158 window->lock_window("Playback3D::do_mask_sync");
1159 window->enable_opengl();
1161 switch(command->frame->get_opengl_state())
1164 // Time to upload to the texture
1165 command->frame->to_texture();
1168 case VFrame::SCREEN:
1169 // Read back from PBuffer
1170 // Bind context to pbuffer
1171 command->frame->enable_opengl();
1172 command->frame->screen_to_texture();
1178 // Create PBuffer and draw the mask on it
1179 command->frame->enable_opengl();
1181 // Initialize coordinate system
1182 int w = command->frame->get_w();
1183 int h = command->frame->get_h();
1184 command->frame->init_screen();
1187 glDisable(GL_TEXTURE_2D);
1188 if(command->default_auto->mode == MASK_MULTIPLY_ALPHA)
1190 glClearColor(0.0, 0.0, 0.0, 0.0);
1191 glColor4f((float)command->keyframe->value / 100,
1192 (float)command->keyframe->value / 100,
1193 (float)command->keyframe->value / 100,
1198 glClearColor(1.0, 1.0, 1.0, 1.0);
1199 glColor4f((float)1.0 - (float)command->keyframe->value / 100,
1200 (float)1.0 - (float)command->keyframe->value / 100,
1201 (float)1.0 - (float)command->keyframe->value / 100,
1204 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1207 // Draw mask with scaling to simulate feathering
1208 GLUtesselator *tesselator = gluNewTess();
1209 gluTessProperty(tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);
1210 gluTessCallback(tesselator, GLU_TESS_VERTEX, (GLvoid (*) ( )) &glVertex3dv);
1211 gluTessCallback(tesselator, GLU_TESS_BEGIN, (GLvoid (*) ( )) &glBegin);
1212 gluTessCallback(tesselator, GLU_TESS_END, (GLvoid (*) ( )) &glEnd);
1213 gluTessCallback(tesselator, GLU_TESS_COMBINE, (GLvoid (*) ( ))&combine_callback);
1215 vertex_cache = new List<Vertex>;
1218 // Draw every submask as a new polygon
1219 int total_submasks = command->keyframe_set->total_submasks(
1220 command->start_position_project,
1222 float scale = command->keyframe->feather + 1;
1223 int display_list = glGenLists(1);
1224 glNewList(display_list, GL_COMPILE);
1225 for(int k = 0; k < total_submasks; k++)
1227 gluTessBeginPolygon(tesselator, NULL);
1228 gluTessBeginContour(tesselator);
1229 ArrayList<MaskPoint*> *points = new ArrayList<MaskPoint*>;
1230 command->keyframe_set->get_points(points,
1232 command->start_position_project,
1235 int first_point = 0;
1236 // Need to tabulate every vertex in persistent memory because
1237 // gluTessVertex doesn't copy them.
1238 ArrayList<GLdouble*> coords;
1239 coords.set_array_delete();
1240 for(int i = 0; i < points->total; i++)
1242 MaskPoint *point1 = points->values[i];
1243 MaskPoint *point2 = (i >= points->total - 1) ?
1245 points->values[i + 1];
1249 if(point1->control_x2 == 0 &&
1250 point1->control_y2 == 0 &&
1251 point2->control_x1 == 0 &&
1252 point2->control_y1 == 0)
1255 float x0 = point1->x;
1256 float y0 = point1->y;
1257 float x1 = point1->x + point1->control_x2;
1258 float y1 = point1->y + point1->control_y2;
1259 float x2 = point2->x + point2->control_x1;
1260 float y2 = point2->y + point2->control_y1;
1261 float x3 = point2->x;
1262 float y3 = point2->y;
1264 // forward differencing bezier curves implementation taken from GPL code at
1265 // http://cvs.sourceforge.net/viewcvs.py/guliverkli/guliverkli/src/subtitles/Rasterizer.cpp?rev=1.3
1267 float cx3, cx2, cx1, cx0, cy3, cy2, cy1, cy0;
1274 cx3 = - x0 + 3*x1 - 3*x2 + x3;
1275 cx2 = 3*x0 - 6*x1 + 3*x2;
1279 cy3 = - y0 + 3*y1 - 3*y2 + y3;
1280 cy2 = 3*y0 - 6*y1 + 3*y2;
1284 // This equation is from Graphics Gems I.
1286 // The idea is that since we're approximating a cubic curve with lines,
1287 // any error we incur is due to the curvature of the line, which we can
1288 // estimate by calculating the maximum acceleration of the curve. For
1289 // a cubic, the acceleration (second derivative) is a line, meaning that
1290 // the absolute maximum acceleration must occur at either the beginning
1291 // (|c2|) or the end (|c2+c3|). Our bounds here are a little more
1292 // conservative than that, but that's okay.
1295 float maxaccel1 = fabs(2*cy2) + fabs(6*cy3);
1296 float maxaccel2 = fabs(2*cx2) + fabs(6*cx3);
1298 float maxaccel = maxaccel1 > maxaccel2 ? maxaccel1 : maxaccel2;
1301 if(maxaccel > 8.0) h = sqrt((8.0) / maxaccel);
1302 segments = int(1/h);
1305 for(int j = 0; j <= segments; j++)
1307 float t = (float)j / segments;
1308 x = cx0 + t*(cx1 + t*(cx2 + t*cx3));
1309 y = cy0 + t*(cy1 + t*(cy2 + t*cy3));
1311 if(j > 0 || first_point)
1313 GLdouble *coord = new GLdouble[3];
1314 coord[0] = x / scale;
1315 coord[1] = -h + y / scale;
1317 coords.append(coord);
1323 // Now that we know the total vertices, send them to GLU
1324 for(int i = 0; i < coords.total; i++)
1325 gluTessVertex(tesselator, coords.values[i], coords.values[i]);
1327 gluTessEndContour(tesselator);
1328 gluTessEndPolygon(tesselator);
1329 points->remove_all_objects();
1331 coords.remove_all_objects();
1334 glCallList(display_list);
1335 glDeleteLists(display_list, 1);
1336 gluDeleteTess(tesselator);
1338 delete vertex_cache;
1341 glColor4f(1, 1, 1, 1);
1344 // Read mask into temporary texture.
1345 // For feathering, just read the part of the screen after the downscaling.
1348 float w_scaled = w / scale;
1349 float h_scaled = h / scale;
1350 // Don't vary the texture size according to scaling because that
1351 // would waste memory.
1352 // This enables and binds the temporary texture.
1353 glActiveTexture(GL_TEXTURE1);
1354 BC_Texture::new_texture(&temp_texture,
1357 command->frame->get_color_model());
1358 temp_texture->bind(1);
1359 glReadBuffer(GL_BACK);
1361 // Need to add extra size to fill in the bottom right
1362 glCopyTexSubImage2D(GL_TEXTURE_2D,
1368 (int)MIN(w_scaled + 2, w),
1369 (int)MIN(h_scaled + 2, h));
1371 command->frame->bind_texture(0);
1374 // For feathered masks, use a shader to multiply.
1375 // For unfeathered masks, we could use a stencil buffer
1376 // for further optimization but we also need a YUV algorithm.
1377 unsigned int frag_shader = 0;
1378 switch(temp_texture->get_texture_components()) {
1380 frag_shader = VFrame::make_shader(0,
1381 command->frame->get_color_model() == BC_YUV888 ?
1382 multiply_yuvmask3_frag : multiply_mask3_frag,
1386 frag_shader = VFrame::make_shader(0, multiply_mask4_frag, 0);
1392 glUseProgram(frag_shader);
1393 if((variable = glGetUniformLocation(frag_shader, "tex")) >= 0)
1394 glUniform1i(variable, 0);
1395 if((variable = glGetUniformLocation(frag_shader, "tex1")) >= 0)
1396 glUniform1i(variable, 1);
1397 if((variable = glGetUniformLocation(frag_shader, "scale")) >= 0)
1398 glUniform1f(variable, scale);
1403 // Write texture to PBuffer with multiply and scaling for feather.
1406 command->frame->draw_texture(0, 0, w, h, 0, 0, w, h);
1407 command->frame->set_opengl_state(VFrame::SCREEN);
1410 // Disable temp texture
1413 glActiveTexture(GL_TEXTURE1);
1414 glDisable(GL_TEXTURE_2D);
1415 delete temp_texture;
1418 glActiveTexture(GL_TEXTURE0);
1419 glDisable(GL_TEXTURE_2D);
1422 window->enable_opengl();
1423 window->unlock_window();
1425 command->canvas->unlock_canvas();
1438 void Playback3D::convert_cmodel(Canvas *canvas,
1442 // Do nothing if colormodels are equivalent in OpenGL & the image is in hardware.
1443 int src_cmodel = output->get_color_model();
1445 (output->get_opengl_state() == VFrame::TEXTURE ||
1446 output->get_opengl_state() == VFrame::SCREEN) &&
1447 // OpenGL has no floating point.
1448 ( (src_cmodel == BC_RGB888 && dst_cmodel == BC_RGB_FLOAT) ||
1449 (src_cmodel == BC_RGBA8888 && dst_cmodel == BC_RGBA_FLOAT) ||
1450 (src_cmodel == BC_RGB_FLOAT && dst_cmodel == BC_RGB888) ||
1451 (src_cmodel == BC_RGBA_FLOAT && dst_cmodel == BC_RGBA8888) ||
1452 // OpenGL sets alpha to 1 on import
1453 (src_cmodel == BC_RGB888 && dst_cmodel == BC_RGBA8888) ||
1454 (src_cmodel == BC_YUV888 && dst_cmodel == BC_YUVA8888) ||
1455 (src_cmodel == BC_RGB_FLOAT && dst_cmodel == BC_RGBA_FLOAT) )
1460 Playback3DCommand command;
1461 command.command = Playback3DCommand::CONVERT_CMODEL;
1462 command.canvas = canvas;
1463 command.frame = output;
1464 command.dst_cmodel = dst_cmodel;
1465 send_command(&command);
1468 void Playback3D::convert_cmodel_sync(Playback3DCommand *command)
1471 command->canvas->lock_canvas("Playback3D::convert_cmodel_sync");
1473 if( command->canvas->get_canvas() ) {
1474 BC_WindowBase *window = command->canvas->get_canvas();
1475 window->lock_window("Playback3D::convert_cmodel_sync");
1476 window->enable_opengl();
1478 // Import into hardware
1479 command->frame->enable_opengl();
1480 command->frame->init_screen();
1481 command->frame->to_texture();
1483 // Colormodel permutation
1484 int src_cmodel = command->frame->get_color_model();
1485 int dst_cmodel = command->dst_cmodel;
1489 } cmodel_shader_table_t;
1490 enum { rgb_to_rgb, rgb_to_yuv, yuv_to_rgb, yuv_to_yuv, };
1492 static cmodel_shader_table_t cmodel_shader_table[] = {
1493 { BC_RGB888, BC_YUV888, rgb_to_yuv, rgb_to_yuv_frag },
1494 { BC_RGB888, BC_YUVA8888, rgb_to_yuv, rgb_to_yuv_frag },
1495 { BC_RGBA8888, BC_RGB888, rgb_to_rgb, rgba_to_rgb_frag },
1496 { BC_RGBA8888, BC_RGB_FLOAT, rgb_to_rgb, rgba_to_rgb_frag },
1497 { BC_RGBA8888, BC_YUV888, rgb_to_yuv, rgba_to_yuv_frag },
1498 { BC_RGBA8888, BC_YUVA8888, rgb_to_yuv, rgb_to_yuv_frag },
1499 { BC_RGB_FLOAT, BC_YUV888, rgb_to_yuv, rgb_to_yuv_frag },
1500 { BC_RGB_FLOAT, BC_YUVA8888, rgb_to_yuv, rgb_to_yuv_frag },
1501 { BC_RGBA_FLOAT,BC_RGB888, rgb_to_rgb, rgba_to_rgb_frag },
1502 { BC_RGBA_FLOAT,BC_RGB_FLOAT, rgb_to_rgb, rgba_to_rgb_frag },
1503 { BC_RGBA_FLOAT,BC_YUV888, rgb_to_yuv, rgba_to_yuv_frag },
1504 { BC_RGBA_FLOAT,BC_YUVA8888, rgb_to_yuv, rgb_to_yuv_frag },
1505 { BC_YUV888, BC_RGB888, yuv_to_rgb, yuv_to_rgb_frag },
1506 { BC_YUV888, BC_RGBA8888, yuv_to_rgb, yuv_to_rgb_frag },
1507 { BC_YUV888, BC_RGB_FLOAT, yuv_to_rgb, yuv_to_rgb_frag },
1508 { BC_YUV888, BC_RGBA_FLOAT, yuv_to_rgb, yuv_to_rgb_frag },
1509 { BC_YUVA8888, BC_RGB888, yuv_to_rgb, yuva_to_rgb_frag },
1510 { BC_YUVA8888, BC_RGBA8888, yuv_to_rgb, yuv_to_rgb_frag },
1511 { BC_YUVA8888, BC_RGB_FLOAT, yuv_to_rgb, yuva_to_rgb_frag },
1512 { BC_YUVA8888, BC_RGBA_FLOAT, yuv_to_rgb, yuv_to_rgb_frag },
1513 { BC_YUVA8888, BC_YUV888, yuv_to_yuv, yuva_to_yuv_frag },
1516 const char *shader = 0;
1517 int table_size = sizeof(cmodel_shader_table) / sizeof(cmodel_shader_table_t);
1518 for( int i=0; i<table_size; ++i ) {
1519 if( cmodel_shader_table[i].src == src_cmodel &&
1520 cmodel_shader_table[i].dst == dst_cmodel ) {
1521 shader = cmodel_shader_table[i].shader;
1522 type = cmodel_shader_table[i].typ;
1527 // printf("Playback3D::convert_cmodel_sync %d %d %d shader=\n%s",
1529 // command->frame->get_color_model(),
1530 // command->dst_cmodel,
1533 const char *shader_stack[9];
1534 memset(shader_stack,0, sizeof(shader_stack));
1535 int current_shader = 0;
1538 //printf("Playback3D::convert_cmodel_sync %d\n", __LINE__);
1539 shader_stack[current_shader++] = shader;
1540 shader_stack[current_shader] = 0;
1541 unsigned int shader_id = VFrame::make_shader(shader_stack);
1543 command->frame->bind_texture(0);
1544 glUseProgram(shader_id);
1546 glUniform1i(glGetUniformLocation(shader_id, "tex"), 0);
1549 BC_GL_RGB_TO_YUV(shader_id);
1552 BC_GL_YUV_TO_RGB(shader_id);
1556 command->frame->draw_texture();
1557 if(shader) glUseProgram(0);
1558 command->frame->set_opengl_state(VFrame::SCREEN);
1561 window->unlock_window();
1564 command->canvas->unlock_canvas();
1568 void Playback3D::do_fade(Canvas *canvas, VFrame *frame, float fade)
1570 Playback3DCommand command;
1571 command.command = Playback3DCommand::DO_FADE;
1572 command.canvas = canvas;
1573 command.frame = frame;
1574 command.alpha = fade;
1575 send_command(&command);
1578 void Playback3D::do_fade_sync(Playback3DCommand *command)
1581 command->canvas->lock_canvas("Playback3D::do_mask_sync");
1582 if(command->canvas->get_canvas())
1584 BC_WindowBase *window = command->canvas->get_canvas();
1585 window->lock_window("Playback3D::do_fade_sync");
1586 window->enable_opengl();
1588 switch(command->frame->get_opengl_state())
1591 command->frame->to_texture();
1594 case VFrame::SCREEN:
1595 // Read back from PBuffer
1596 // Bind context to pbuffer
1597 command->frame->enable_opengl();
1598 command->frame->screen_to_texture();
1603 command->frame->enable_opengl();
1604 command->frame->init_screen();
1605 command->frame->bind_texture(0);
1607 // glClearColor(0.0, 0.0, 0.0, 0.0);
1608 // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1609 glDisable(GL_BLEND);
1610 unsigned int frag_shader = 0;
1611 switch(command->frame->get_color_model())
1613 // For the alpha colormodels, the native function seems to multiply the
1614 // components by the alpha instead of just the alpha.
1618 frag_shader = VFrame::make_shader(0, fade_rgba_frag, 0);
1623 glBlendFunc(GL_SRC_ALPHA, GL_ZERO);
1624 glColor4f(command->alpha, command->alpha, command->alpha, 1);
1629 frag_shader = VFrame::make_shader(0, fade_yuv_frag, 0);
1635 glUseProgram(frag_shader);
1637 if((variable = glGetUniformLocation(frag_shader, "tex")) >= 0)
1638 glUniform1i(variable, 0);
1639 if((variable = glGetUniformLocation(frag_shader, "alpha")) >= 0)
1640 glUniform1f(variable, command->alpha);
1643 command->frame->draw_texture();
1644 command->frame->set_opengl_state(VFrame::SCREEN);
1651 glColor4f(1, 1, 1, 1);
1652 glDisable(GL_BLEND);
1654 window->unlock_window();
1656 command->canvas->unlock_canvas();
1670 int Playback3D::run_plugin(Canvas *canvas, PluginClient *client)
1672 Playback3DCommand command;
1673 command.command = Playback3DCommand::PLUGIN;
1674 command.canvas = canvas;
1675 command.plugin_client = client;
1676 return send_command(&command);
1679 void Playback3D::run_plugin_sync(Playback3DCommand *command)
1681 command->canvas->lock_canvas("Playback3D::run_plugin_sync");
1682 if(command->canvas->get_canvas())
1684 BC_WindowBase *window = command->canvas->get_canvas();
1685 window->lock_window("Playback3D::run_plugin_sync");
1686 window->enable_opengl();
1688 command->result = ((PluginVClient*)command->plugin_client)->handle_opengl();
1690 window->unlock_window();
1692 command->canvas->unlock_canvas();