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"
31 #include "maskautos.h"
35 #include "overlayframe.inc"
36 #include "overlayframe.h"
37 #include "playback3d.h"
38 #include "pluginclient.h"
39 #include "pluginvclient.h"
40 #include "edlsession.h"
41 #include "transportque.inc"
59 // These should be passed to VFrame::make_shader to construct shaders.
60 // Can't hard code sampler2D
64 static const char *yuv_to_rgb_frag =
65 "uniform sampler2D tex;\n"
66 "uniform mat3 yuv_to_rgb_matrix;\n"
67 "uniform float yminf;\n"
70 " vec4 yuva = texture2D(tex, gl_TexCoord[0].st);\n"
71 " yuva.rgb -= vec3(yminf, 0.5, 0.5);\n"
72 " gl_FragColor = vec4(yuv_to_rgb_matrix * yuva.rgb, yuva.a);\n"
75 static const char *yuva_to_yuv_frag =
76 "uniform sampler2D tex;\n"
79 " vec4 yuva = texture2D(tex, gl_TexCoord[0].st);\n"
80 " float a = yuva.a;\n"
81 " float anti_a = 1.0 - a;\n"
83 " yuva.g = yuva.g * a + 0.5 * anti_a;\n"
84 " yuva.b = yuva.b * a + 0.5 * anti_a;\n"
86 " gl_FragColor = yuva;\n"
89 static const char *yuva_to_rgb_frag =
90 "uniform sampler2D tex;\n"
91 "uniform mat3 yuv_to_rgb_matrix;\n"
92 "uniform float yminf;\n"
95 " vec4 yuva = texture2D(tex, gl_TexCoord[0].st);\n"
96 " yuva.rgb -= vec3(yminf, 0.5, 0.5);\n"
97 " yuva.rgb = yuv_to_rgb_matrix * yuva.rgb;\n"
98 " yuva.rgb *= yuva.a;\n"
100 " gl_FragColor = yuva;\n"
103 static const char *rgb_to_yuv_frag =
104 "uniform sampler2D tex;\n"
105 "uniform mat3 rgb_to_yuv_matrix;\n"
106 "uniform float yminf;\n"
109 " vec4 rgba = texture2D(tex, gl_TexCoord[0].st);\n"
110 " rgba.rgb = rgb_to_yuv_matrix * rgba.rgb;\n"
111 " rgba.rgb += vec3(yminf, 0.5, 0.5);\n"
112 " gl_FragColor = rgba;\n"
116 static const char *rgba_to_rgb_frag =
117 "uniform sampler2D tex;\n"
120 " vec4 rgba = texture2D(tex, gl_TexCoord[0].st);\n"
121 " rgba.rgb *= rgba.a;\n"
123 " gl_FragColor = rgba;\n"
126 static const char *rgba_to_yuv_frag =
127 "uniform sampler2D tex;\n"
128 "uniform mat3 rgb_to_yuv_matrix;\n"
129 "uniform float yminf;\n"
132 " vec4 rgba = texture2D(tex, gl_TexCoord[0].st);\n"
133 " rgba.rgb *= rgba.a;\n"
135 " rgba.rgb = rgb_to_yuv_matrix * rgba.rgb;\n"
136 " rgba.rgb += vec3(yminf, 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"
146 #define GL_STD_BLEND(FN) \
147 static const char *blend_##FN##_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" \
154 " result.rgb = " SS(COLOR_##FN(1.0, gl_FragColor.rgb, gl_FragColor.a, canvas.rgb, canvas.a)) ";\n" \
155 " result.a = " SS(ALPHA_##FN(1.0, gl_FragColor.a, canvas.a)) ";\n" \
156 " gl_FragColor = mix(canvas, result, alpha);\n" \
159 #define GL_VEC_BLEND(FN) \
160 static const char *blend_##FN##_frag = \
161 "uniform sampler2D tex2;\n" \
162 "uniform vec2 tex2_dimensions;\n" \
163 "uniform float alpha;\n" \
165 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n" \
167 " result.r = " SS(COLOR_##FN(1.0, gl_FragColor.r, gl_FragColor.a, canvas.r, canvas.a)) ";\n" \
168 " result.g = " SS(COLOR_##FN(1.0, gl_FragColor.g, gl_FragColor.a, canvas.g, canvas.a)) ";\n" \
169 " result.b = " SS(COLOR_##FN(1.0, gl_FragColor.b, gl_FragColor.a, canvas.b, canvas.a)) ";\n" \
170 " result.a = " SS(ALPHA_##FN(1.0, gl_FragColor.a, canvas.a)) ";\n" \
171 " result = clamp(result, 0.0, 1.0);\n" \
172 " gl_FragColor = mix(canvas, result, alpha);\n" \
190 static const char *blend_NORMAL_frag =
191 "uniform sampler2D tex2;\n"
192 "uniform vec2 tex2_dimensions;\n"
193 "uniform float alpha;\n"
195 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
196 " vec4 result = mix(canvas, gl_FragColor, gl_FragColor.a);\n"
197 " gl_FragColor = mix(canvas, result, alpha);\n"
201 static const char *blend_REPLACE_frag =
202 "uniform float alpha;\n"
207 static const char *blend_ADDITION_frag =
208 "uniform sampler2D tex2;\n"
209 "uniform vec2 tex2_dimensions;\n"
210 "uniform float alpha;\n"
212 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
213 " vec4 result = clamp(gl_FragColor + canvas, 0.0, 1.0);\n"
214 " gl_FragColor = mix(canvas, result, alpha);\n"
218 static const char *blend_SUBTRACT_frag =
219 "uniform sampler2D tex2;\n"
220 "uniform vec2 tex2_dimensions;\n"
221 "uniform float alpha;\n"
223 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
224 " vec4 result = clamp(gl_FragColor - canvas, 0.0, 1.0);\n"
225 " gl_FragColor = mix(canvas, result, alpha);\n"
228 GL_STD_BLEND(MULTIPLY);
229 GL_VEC_BLEND(DIVIDE);
232 GL_VEC_BLEND(DARKEN);
233 GL_VEC_BLEND(LIGHTEN);
235 GL_STD_BLEND(DST_ATOP);
236 GL_STD_BLEND(DST_IN);
237 GL_STD_BLEND(DST_OUT);
238 GL_STD_BLEND(DST_OVER);
240 GL_STD_BLEND(SRC_ATOP);
241 GL_STD_BLEND(SRC_IN);
242 GL_STD_BLEND(SRC_OUT);
243 GL_STD_BLEND(SRC_OVER);
247 GL_VEC_BLEND(OVERLAY);
248 GL_STD_BLEND(SCREEN);
251 GL_VEC_BLEND(HARDLIGHT);
252 GL_VEC_BLEND(SOFTLIGHT);
253 GL_VEC_BLEND(DIFFERENCE);
255 static const char *read_texture_frag =
256 "uniform sampler2D tex;\n"
259 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
262 static const char *multiply_mask4_frag =
263 "uniform sampler2D tex;\n"
264 "uniform sampler2D tex1;\n"
265 "uniform float scale;\n"
268 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
269 " gl_FragColor.a *= texture2D(tex1, gl_TexCoord[0].st / vec2(scale, scale)).r;\n"
272 static const char *multiply_mask3_frag =
273 "uniform sampler2D tex;\n"
274 "uniform sampler2D tex1;\n"
275 "uniform float scale;\n"
276 "uniform bool is_yuv;\n"
279 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
280 " float a = texture2D(tex1, gl_TexCoord[0].st / vec2(scale, scale)).r;\n"
281 " gl_FragColor.rgb *= vec3(a, a, a);\n"
284 static const char *multiply_yuvmask3_frag =
285 "uniform sampler2D tex;\n"
286 "uniform sampler2D tex1;\n"
287 "uniform float scale;\n"
290 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
291 " float a = texture2D(tex1, gl_TexCoord[0].st / vec2(scale, scale)).r;\n"
292 " gl_FragColor.gb -= vec2(0.5, 0.5);\n"
293 " gl_FragColor.rgb *= vec3(a, a, a);\n"
294 " gl_FragColor.gb += vec2(0.5, 0.5);\n"
297 static const char *fade_rgba_frag =
298 "uniform sampler2D tex;\n"
299 "uniform float alpha;\n"
302 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
303 " gl_FragColor.a *= alpha;\n"
306 static const char *fade_yuv_frag =
307 "uniform sampler2D tex;\n"
308 "uniform float alpha;\n"
311 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
312 " gl_FragColor.r *= alpha;\n"
313 " gl_FragColor.gb -= vec2(0.5, 0.5);\n"
314 " gl_FragColor.g *= alpha;\n"
315 " gl_FragColor.b *= alpha;\n"
316 " gl_FragColor.gb += vec2(0.5, 0.5);\n"
322 Playback3DCommand::Playback3DCommand()
323 : BC_SynchronousCommand()
329 void Playback3DCommand::copy_from(BC_SynchronousCommand *command)
331 Playback3DCommand *ptr = (Playback3DCommand*)command;
332 this->canvas = ptr->canvas;
333 this->is_cleared = ptr->is_cleared;
335 this->in_x1 = ptr->in_x1;
336 this->in_y1 = ptr->in_y1;
337 this->in_x2 = ptr->in_x2;
338 this->in_y2 = ptr->in_y2;
339 this->out_x1 = ptr->out_x1;
340 this->out_y1 = ptr->out_y1;
341 this->out_x2 = ptr->out_x2;
342 this->out_y2 = ptr->out_y2;
343 this->alpha = ptr->alpha;
344 this->mode = ptr->mode;
345 this->interpolation_type = ptr->interpolation_type;
347 this->input = ptr->input;
348 this->start_position_project = ptr->start_position_project;
349 this->keyframe_set = ptr->keyframe_set;
350 this->keyframe = ptr->keyframe;
351 this->default_auto = ptr->default_auto;
352 this->plugin_client = ptr->plugin_client;
353 this->want_texture = ptr->want_texture;
354 this->is_nested = ptr->is_nested;
355 this->dst_cmodel = ptr->dst_cmodel;
357 BC_SynchronousCommand::copy_from(command);
361 ///static void glDebugCallback(GLenum src, GLenum typ, GLuint id,
362 /// GLenum svy, GLsizei len, const GLchar* msg, void* dat)
363 //static void glDebugCallback(unsigned int src, unsigned int typ, unsigned int id,
364 // unsigned int svy, int len, const char* msg, const void* dat)
366 // printf("glDebug: %d:%d; %d/%d %s\n",src,typ,id,svy,msg);
370 Playback3D::Playback3D(MWindow *mwindow)
373 this->mwindow = mwindow;
375 //Enabling OpenGL debug output on nVidia drivers
376 // glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, 0, GL_TRUE);
377 // glEnable(GL_DEBUG_OUTPUT);
378 // glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
379 // glDebugMessageCallback(glDebugCallback, 0);
382 Playback3D::~Playback3D()
389 BC_SynchronousCommand* Playback3D::new_command()
391 return new Playback3DCommand;
396 void Playback3D::handle_command(BC_SynchronousCommand *command)
398 //printf("Playback3D::handle_command 1 %d\n", command->command);
399 switch(command->command)
401 case Playback3DCommand::WRITE_BUFFER:
402 write_buffer_sync((Playback3DCommand*)command);
405 case Playback3DCommand::FINISH_OUTPUT:
406 finish_output_sync((Playback3DCommand*)command);
409 case Playback3DCommand::CLEAR_OUTPUT:
410 clear_output_sync((Playback3DCommand*)command);
413 case Playback3DCommand::CLEAR_INPUT:
414 clear_input_sync((Playback3DCommand*)command);
417 case Playback3DCommand::DO_CAMERA:
418 do_camera_sync((Playback3DCommand*)command);
421 case Playback3DCommand::OVERLAY:
422 overlay_sync((Playback3DCommand*)command);
425 case Playback3DCommand::DO_FADE:
426 do_fade_sync((Playback3DCommand*)command);
429 case Playback3DCommand::DO_MASK:
430 do_mask_sync((Playback3DCommand*)command);
433 case Playback3DCommand::PLUGIN:
434 run_plugin_sync((Playback3DCommand*)command);
437 case Playback3DCommand::COPY_FROM:
438 copy_from_sync((Playback3DCommand*)command);
441 case Playback3DCommand::CONVERT_CMODEL:
442 convert_cmodel_sync((Playback3DCommand*)command);
445 // case Playback3DCommand::DRAW_REFRESH:
446 // draw_refresh_sync((Playback3DCommand*)command);
449 //printf("Playback3D::handle_command 10\n");
455 void Playback3D::copy_from(Canvas *canvas,
460 Playback3DCommand command;
461 command.command = Playback3DCommand::COPY_FROM;
462 command.canvas = canvas;
465 command.want_texture = want_texture;
466 send_command(&command);
469 void Playback3D::copy_from_sync(Playback3DCommand *command)
472 command->canvas->lock_canvas("Playback3D::draw_refresh_sync");
473 BC_WindowBase *window = command->canvas->get_canvas();
476 window->lock_window("Playback3D:draw_refresh_sync");
477 window->enable_opengl();
478 int w = command->input->get_w();
479 int h = command->input->get_h();
481 if(command->input->get_opengl_state() == VFrame::SCREEN &&
482 w == command->frame->get_w() && h == command->frame->get_h())
484 // printf("Playback3D::copy_from_sync 1 %d %d %d %d %d\n",
485 // command->input->get_w(),
486 // command->input->get_h(),
487 // command->frame->get_w(),
488 // command->frame->get_h(),
489 // command->frame->get_color_model());
490 // With NVidia at least,
493 printf("Playback3D::copy_from_sync: w=%d not supported because it is not divisible by 4.\n", w);
497 if(command->want_texture)
499 //printf("Playback3D::copy_from_sync 1 dst=%p src=%p\n", command->frame, command->input);
500 // Screen_to_texture requires the source pbuffer enabled.
501 command->input->enable_opengl();
502 command->frame->screen_to_texture();
503 command->frame->set_opengl_state(VFrame::TEXTURE);
508 command->input->to_texture();
509 command->input->bind_texture(0);
510 command->frame->enable_opengl();
511 command->frame->init_screen();
512 unsigned int shader = BC_CModels::is_yuv(command->input->get_color_model()) ?
513 VFrame::make_shader(0, yuv_to_rgb_frag, 0) : 0;
515 glUseProgram(shader);
516 int variable = glGetUniformLocation(shader, "tex");
517 glUniform1i(variable, 0);
518 BC_GL_YUV_TO_RGB(shader);
522 command->input->draw_texture(1);
523 command->frame->screen_to_ram();
529 printf("Playback3D::copy_from_sync: invalid formats opengl_state=%d %dx%d -> %dx%d\n",
530 command->input->get_opengl_state(), w, h,
531 command->frame->get_w(), command->frame->get_h());
534 window->unlock_window();
536 command->canvas->unlock_canvas();
543 // void Playback3D::draw_refresh(Canvas *canvas,
554 // Playback3DCommand command;
555 // command.command = Playback3DCommand::DRAW_REFRESH;
556 // command.canvas = canvas;
557 // command.frame = frame;
558 // command.in_x1 = in_x1;
559 // command.in_y1 = in_y1;
560 // command.in_x2 = in_x2;
561 // command.in_y2 = in_y2;
562 // command.out_x1 = out_x1;
563 // command.out_y1 = out_y1;
564 // command.out_x2 = out_x2;
565 // command.out_y2 = out_y2;
566 // send_command(&command);
569 // void Playback3D::draw_refresh_sync(Playback3DCommand *command)
571 // command->canvas->lock_canvas("Playback3D::draw_refresh_sync");
572 // BC_WindowBase *window = command->canvas->get_canvas();
575 // window->lock_window("Playback3D:draw_refresh_sync");
576 // window->enable_opengl();
578 // // Read output pbuffer back to RAM in project colormodel
579 // // RGB 8bit is fastest for OpenGL to read back.
580 // command->frame->reallocate(0,
584 // command->frame->get_w(),
585 // command->frame->get_h(),
588 // command->frame->screen_to_ram();
590 // window->clear_box(0,
594 // window->draw_vframe(command->frame,
595 // (int)command->out_x1,
596 // (int)command->out_y1,
597 // (int)(command->out_x2 - command->out_x1),
598 // (int)(command->out_y2 - command->out_y1),
599 // (int)command->in_x1,
600 // (int)command->in_y1,
601 // (int)(command->in_x2 - command->in_x1),
602 // (int)(command->in_y2 - command->in_y1),
605 // window->unlock_window();
607 // command->canvas->unlock_canvas();
614 void Playback3D::write_buffer(Canvas *canvas,
626 Playback3DCommand command;
627 command.command = Playback3DCommand::WRITE_BUFFER;
628 command.canvas = canvas;
629 command.frame = frame;
630 command.in_x1 = in_x1;
631 command.in_y1 = in_y1;
632 command.in_x2 = in_x2;
633 command.in_y2 = in_y2;
634 command.out_x1 = out_x1;
635 command.out_y1 = out_y1;
636 command.out_x2 = out_x2;
637 command.out_y2 = out_y2;
638 command.is_cleared = is_cleared;
639 send_command(&command);
643 void Playback3D::write_buffer_sync(Playback3DCommand *command)
645 command->canvas->lock_canvas("Playback3D::write_buffer_sync");
646 if(command->canvas->get_canvas())
648 BC_WindowBase *window = command->canvas->get_canvas();
649 window->lock_window("Playback3D::write_buffer_sync");
650 // Update hidden cursor
651 window->update_video_cursor();
652 // Make sure OpenGL is enabled first.
653 window->enable_opengl();
655 //printf("Playback3D::write_buffer_sync 1 %d\n", window->get_id());
656 int flip_y = 0, frame_state = command->frame->get_opengl_state();
657 switch( frame_state ) {
658 // Upload texture and composite to screen
662 command->frame->to_texture();
663 window->enable_opengl();
664 // Composite texture to screen and swap buffer
665 case VFrame::TEXTURE:
667 int fh1 = command->frame->get_h()-1;
668 float in_y1 = fh1 - command->in_y1;
669 float in_y2 = fh1 - command->in_y2;
670 command->in_y1 = in_y2;
671 command->in_y2 = in_y1;
673 draw_output(command, flip_y);
676 printf("Playback3D::write_buffer_sync unknown state\n");
679 command->frame->set_opengl_state(frame_state);
680 window->unlock_window();
683 command->canvas->unlock_canvas();
688 void Playback3D::draw_output(Playback3DCommand *command, int flip_y)
691 int texture_id = command->frame->get_texture_id();
692 BC_WindowBase *window = command->canvas->get_canvas();
694 // printf("Playback3D::draw_output 1 texture_id=%d window=%p\n",
696 // command->canvas->get_canvas());
701 // If virtual console is being used, everything in this function has
702 // already been done except the page flip.
705 canvas_w = window->get_w();
706 canvas_h = window->get_h();
707 VFrame::init_screen(canvas_w, canvas_h);
708 int color_model = command->frame->get_color_model();
709 int is_yuv = BC_CModels::is_yuv(color_model);
711 if(!command->is_cleared)
713 // If we get here, the virtual console was not used.
714 init_frame(command, 0);
718 // Undo any previous shader settings
719 command->frame->bind_texture(0);
721 // Convert colormodel
722 unsigned int shader = is_yuv ? VFrame::make_shader(0, yuv_to_rgb_frag, 0) : 0;
724 glUseProgram(shader);
725 // Set texture unit of the texture
726 int variable = glGetUniformLocation(shader, "tex");
727 glUniform1i(variable, 0);
728 BC_GL_YUV_TO_RGB(shader);
731 // if(BC_CModels::components(color_model) == 4)
733 // glEnable(GL_BLEND);
734 // glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
737 command->frame->draw_texture(
738 command->in_x1, command->in_y1, command->in_x2, command->in_y2,
739 command->out_x1, command->out_y1, command->out_x2, command->out_y2,
743 //printf("Playback3D::draw_output 2 %f,%f %f,%f -> %f,%f %f,%f\n",
755 command->canvas->get_canvas()->flip_opengl();
762 void Playback3D::init_frame(Playback3DCommand *command, int is_yuv)
765 float gbuv = is_yuv ? 0.5 : 0.0;
766 glClearColor(0.0, gbuv, gbuv, 0.0);
767 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
772 void Playback3D::finish_output(Canvas *canvas)
774 Playback3DCommand command;
775 command.canvas = canvas;
776 command.command = Playback3DCommand::FINISH_OUTPUT;
777 send_command(&command);
780 void Playback3D::finish_output_sync(Playback3DCommand *command)
783 command->canvas->lock_canvas("Playback3D::clear_output_sync");
784 if( command->canvas->get_canvas() ) {
785 command->canvas->get_canvas()->enable_opengl();
788 command->canvas->unlock_canvas();
793 void Playback3D::clear_output(Canvas *canvas, VFrame *output)
795 Playback3DCommand command;
796 command.command = Playback3DCommand::CLEAR_OUTPUT;
797 command.canvas = canvas;
798 command.frame = output;
799 send_command(&command);
802 void Playback3D::clear_output_sync(Playback3DCommand *command)
804 command->canvas->lock_canvas("Playback3D::clear_output_sync");
805 if(command->canvas->get_canvas())
807 command->canvas->get_canvas()->lock_window("Playback3D::clear_output_sync");
808 // If we get here, the virtual console is being used.
809 command->canvas->get_canvas()->enable_opengl();
812 // Using pbuffer for refresh frame.
815 command->frame->enable_opengl();
816 int color_model = command->canvas->mwindow->edl->session->color_model;
817 is_yuv = BC_CModels::is_yuv(color_model);
820 init_frame(command, is_yuv);
821 command->canvas->get_canvas()->unlock_window();
823 command->canvas->unlock_canvas();
827 void Playback3D::clear_input(Canvas *canvas, VFrame *frame)
829 Playback3DCommand command;
830 command.command = Playback3DCommand::CLEAR_INPUT;
831 command.canvas = canvas;
832 command.frame = frame;
833 send_command(&command);
836 void Playback3D::clear_input_sync(Playback3DCommand *command)
838 command->canvas->lock_canvas("Playback3D::clear_output_sync");
839 if(command->canvas->get_canvas())
841 command->canvas->get_canvas()->lock_window("Playback3D::clear_output_sync");
842 command->canvas->get_canvas()->enable_opengl();
843 command->frame->enable_opengl();
844 command->frame->clear_pbuffer();
845 command->frame->set_opengl_state(VFrame::SCREEN);
846 command->canvas->get_canvas()->unlock_window();
848 command->canvas->unlock_canvas();
851 void Playback3D::do_camera(Canvas *canvas,
863 Playback3DCommand command;
864 command.command = Playback3DCommand::DO_CAMERA;
865 command.canvas = canvas;
866 command.input = input;
867 command.frame = output;
868 command.in_x1 = in_x1;
869 command.in_y1 = in_y1;
870 command.in_x2 = in_x2;
871 command.in_y2 = in_y2;
872 command.out_x1 = out_x1;
873 command.out_y1 = out_y1;
874 command.out_x2 = out_x2;
875 command.out_y2 = out_y2;
876 send_command(&command);
879 void Playback3D::do_camera_sync(Playback3DCommand *command)
881 command->canvas->lock_canvas("Playback3D::do_camera_sync");
882 if(command->canvas->get_canvas())
884 command->canvas->get_canvas()->lock_window("Playback3D::clear_output_sync");
885 command->canvas->get_canvas()->enable_opengl();
887 command->input->to_texture();
888 command->frame->enable_opengl();
889 command->frame->init_screen();
890 command->frame->clear_pbuffer();
892 command->input->bind_texture(0);
893 // Must call draw_texture in input frame to get the texture coordinates right.
895 // printf("Playback3D::do_camera_sync 1 %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f\n",
901 // (float)command->input->get_h() - command->out_y1,
903 // (float)command->input->get_h() - command->out_y2);
904 command->input->draw_texture(
905 command->in_x1, command->in_y2,
906 command->in_x2, command->in_y1,
908 (float)command->frame->get_h() - command->out_y1,
910 (float)command->frame->get_h() - command->out_y2);
913 command->frame->set_opengl_state(VFrame::SCREEN);
914 command->frame->screen_to_ram();
915 command->canvas->get_canvas()->unlock_window();
917 command->canvas->unlock_canvas();
920 void Playback3D::overlay(Canvas *canvas, VFrame *input,
921 float in_x1, float in_y1, float in_x2, float in_y2,
922 float out_x1, float out_y1, float out_x2, float out_y2,
923 float alpha, int mode, int interpolation_type,
924 VFrame *output, int is_nested)
926 Playback3DCommand command;
927 command.command = Playback3DCommand::OVERLAY;
928 command.canvas = canvas;
929 command.frame = output;
930 command.input = input;
931 command.in_x1 = in_x1;
932 command.in_y1 = in_y1;
933 command.in_x2 = in_x2;
934 command.in_y2 = in_y2;
935 command.out_x1 = out_x1;
936 command.out_y1 = out_y1;
937 command.out_x2 = out_x2;
938 command.out_y2 = out_y2;
939 command.alpha = alpha;
941 command.interpolation_type = interpolation_type;
942 command.is_nested = is_nested;
943 send_command(&command);
946 void Playback3D::overlay_sync(Playback3DCommand *command)
949 // To do these operations, we need to copy the input buffer to a texture
950 // and blend 2 textures in a shader
951 static const char * const overlay_shaders[TRANSFER_TYPES] = {
952 blend_NORMAL_frag, // TRANSFER_NORMAL
953 blend_ADDITION_frag, // TRANSFER_ADDITION
954 blend_SUBTRACT_frag, // TRANSFER_SUBTRACT
955 blend_MULTIPLY_frag, // TRANSFER_MULTIPLY
956 blend_DIVIDE_frag, // TRANSFER_DIVIDE
957 blend_REPLACE_frag, // TRANSFER_REPLACE
958 blend_MAX_frag, // TRANSFER_MAX
959 blend_MIN_frag, // TRANSFER_MIN
960 blend_DARKEN_frag, // TRANSFER_DARKEN
961 blend_LIGHTEN_frag, // TRANSFER_LIGHTEN
962 blend_DST_frag, // TRANSFER_DST
963 blend_DST_ATOP_frag, // TRANSFER_DST_ATOP
964 blend_DST_IN_frag, // TRANSFER_DST_IN
965 blend_DST_OUT_frag, // TRANSFER_DST_OUT
966 blend_DST_OVER_frag, // TRANSFER_DST_OVER
967 blend_SRC_frag, // TRANSFER_SRC
968 blend_SRC_ATOP_frag, // TRANSFER_SRC_ATOP
969 blend_SRC_IN_frag, // TRANSFER_SRC_IN
970 blend_SRC_OUT_frag, // TRANSFER_SRC_OUT
971 blend_SRC_OVER_frag, // TRANSFER_SRC_OVER
972 blend_AND_frag, // TRANSFER_AND
973 blend_OR_frag, // TRANSFER_OR
974 blend_XOR_frag, // TRANSFER_XOR
975 blend_OVERLAY_frag, // TRANSFER_OVERLAY
976 blend_SCREEN_frag, // TRANSFER_SCREEN
977 blend_BURN_frag, // TRANSFER_BURN
978 blend_DODGE_frag, // TRANSFER_DODGE
979 blend_HARDLIGHT_frag, // TRANSFER_HARDLIGHT
980 blend_SOFTLIGHT_frag, // TRANSFER_SOFTLIGHT
981 blend_DIFFERENCE_frag, // TRANSFER_DIFFERENCE
984 command->canvas->lock_canvas("Playback3D::overlay_sync");
985 if(command->canvas->get_canvas()) {
986 BC_WindowBase *window = command->canvas->get_canvas();
987 window->lock_window("Playback3D::overlay_sync");
988 // Make sure OpenGL is enabled first.
989 window->enable_opengl();
990 window->update_video_cursor();
992 glColor4f(1, 1, 1, 1);
996 //printf("Playback3D::overlay_sync 1 %d\n", command->input->get_opengl_state());
997 switch( command->input->get_opengl_state() ) {
998 // Upload texture and composite to screen
1000 command->input->to_texture();
1002 // Just composite texture to screen
1003 case VFrame::TEXTURE:
1005 // read from PBuffer to texture, then composite texture to screen
1006 case VFrame::SCREEN:
1007 command->input->enable_opengl();
1008 command->input->screen_to_texture();
1011 printf("Playback3D::overlay_sync unknown state\n");
1015 if(command->frame) {
1016 // Render to PBuffer
1017 command->frame->enable_opengl();
1018 command->frame->set_opengl_state(VFrame::SCREEN);
1019 canvas_w = command->frame->get_w();
1020 canvas_h = command->frame->get_h();
1024 window->enable_opengl();
1025 canvas_w = window->get_w();
1026 canvas_h = window->get_h();
1030 const char *shader_stack[16];
1031 memset(shader_stack,0, sizeof(shader_stack));
1032 int total_shaders = 0, need_matrix = 0;
1034 VFrame::init_screen(canvas_w, canvas_h);
1037 command->input->bind_texture(0);
1039 // Convert colormodel to RGB if not nested.
1040 // The color model setting in the output frame is ignored.
1041 // if( command->is_nested <= 0 && // not nested
1042 // BC_CModels::is_yuv(command->input->get_color_model()) ) {
1044 // shader_stack[total_shaders++] = yuv_to_rgb_frag;
1048 #define add_shader(s) \
1049 if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag; \
1050 shader_stack[total_shaders++] = s
1052 switch(command->mode) {
1053 case TRANSFER_REPLACE:
1054 // This requires overlaying an alpha multiplied image on a black screen.
1055 if( command->input->get_texture_components() != 4 ) break;
1056 add_shader(overlay_shaders[command->mode]);
1059 enable_overlay_texture(command);
1060 add_shader(overlay_shaders[command->mode]);
1064 // if to flatten alpha
1065 // if( command->is_nested < 0 ) {
1066 // switch(command->input->get_color_model()) {
1067 //// yuv has already been converted to rgb
1068 // case BC_YUVA8888:
1069 // case BC_RGBA_FLOAT:
1070 // case BC_RGBA8888:
1071 // add_shader(rgba_to_rgb_flatten);
1078 unsigned int shader = !shader_stack[0] ? 0 :
1079 VFrame::make_shader(shader_stack);
1081 glUseProgram(shader);
1082 if( need_matrix ) BC_GL_YUV_TO_RGB(shader);
1083 // Set texture unit of the texture
1084 glUniform1i(glGetUniformLocation(shader, "tex"), 0);
1085 // Set texture unit of the temp texture
1086 glUniform1i(glGetUniformLocation(shader, "tex2"), 1);
1088 int variable = glGetUniformLocation(shader, "alpha");
1089 glUniform1f(variable, command->alpha);
1090 // Set dimensions of the temp texture
1092 glUniform2f(glGetUniformLocation(shader, "tex2_dimensions"),
1093 (float)temp_texture->get_texture_w(),
1094 (float)temp_texture->get_texture_h());
1100 //printf("Playback3D::overlay_sync %f %f %f %f %f %f %f %f\n",
1101 // command->in_x1, command->in_y1, command->in_x2, command->in_y2,
1102 // command->out_x1, command->out_y1, command->out_x2, command->out_y2);
1104 command->input->draw_texture(
1105 command->in_x1, command->in_y1, command->in_x2, command->in_y2,
1106 command->out_x1, command->out_y1, command->out_x2, command->out_y2,
1107 !command->is_nested);
1110 // Delete temp texture
1112 delete temp_texture;
1114 glActiveTexture(GL_TEXTURE1);
1115 glDisable(GL_TEXTURE_2D);
1117 glActiveTexture(GL_TEXTURE0);
1118 glDisable(GL_TEXTURE_2D);
1120 window->unlock_window();
1122 command->canvas->unlock_canvas();
1126 void Playback3D::enable_overlay_texture(Playback3DCommand *command)
1129 glDisable(GL_BLEND);
1131 glActiveTexture(GL_TEXTURE1);
1132 BC_Texture::new_texture(&temp_texture, canvas_w, canvas_h,
1133 command->input->get_color_model());
1134 temp_texture->bind(1);
1136 // Read canvas into texture
1137 glReadBuffer(GL_BACK);
1138 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, canvas_w, canvas_h);
1143 void Playback3D::do_mask(Canvas *canvas,
1145 int64_t start_position_project,
1146 MaskAutos *keyframe_set,
1148 MaskAuto *default_auto)
1150 Playback3DCommand command;
1151 command.command = Playback3DCommand::DO_MASK;
1152 command.canvas = canvas;
1153 command.frame = output;
1154 command.start_position_project = start_position_project;
1155 command.keyframe_set = keyframe_set;
1156 command.keyframe = keyframe;
1157 command.default_auto = default_auto;
1159 send_command(&command);
1165 struct Vertex : ListItem<Vertex>
1169 // this list is only used from the main thread, no locking needed
1170 // this must be a list so that pointers to allocated entries remain valid
1171 // when new entries are added
1172 static List<Vertex> *vertex_cache = 0;
1174 static void combine_callback(GLdouble coords[3],
1175 GLdouble *vertex_data[4],
1179 // can't use malloc here; GLU doesn't delete the memory for us!
1180 Vertex* vertex = vertex_cache->append();
1181 vertex->c[0] = coords[0];
1182 vertex->c[1] = coords[1];
1183 vertex->c[2] = coords[2];
1184 // we don't need to interpolate anything
1186 *dataOut = &vertex->c[0];
1191 void Playback3D::do_mask_sync(Playback3DCommand *command)
1194 command->canvas->lock_canvas("Playback3D::do_mask_sync");
1195 if(command->canvas->get_canvas())
1197 BC_WindowBase *window = command->canvas->get_canvas();
1198 window->lock_window("Playback3D::do_mask_sync");
1199 window->enable_opengl();
1201 switch(command->frame->get_opengl_state())
1204 // Time to upload to the texture
1205 command->frame->to_texture();
1208 case VFrame::SCREEN:
1209 // Read back from PBuffer
1210 // Bind context to pbuffer
1211 command->frame->enable_opengl();
1212 command->frame->screen_to_texture();
1218 // Create PBuffer and draw the mask on it
1219 command->frame->enable_opengl();
1221 // Initialize coordinate system
1222 int w = command->frame->get_w();
1223 int h = command->frame->get_h();
1224 command->frame->init_screen();
1227 glDisable(GL_TEXTURE_2D);
1228 if(command->default_auto->mode == MASK_MULTIPLY_ALPHA)
1230 glClearColor(0.0, 0.0, 0.0, 0.0);
1231 glColor4f((float)command->keyframe->value / 100,
1232 (float)command->keyframe->value / 100,
1233 (float)command->keyframe->value / 100,
1238 glClearColor(1.0, 1.0, 1.0, 1.0);
1239 glColor4f((float)1.0 - (float)command->keyframe->value / 100,
1240 (float)1.0 - (float)command->keyframe->value / 100,
1241 (float)1.0 - (float)command->keyframe->value / 100,
1244 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1247 // Draw mask with scaling to simulate feathering
1248 GLUtesselator *tesselator = gluNewTess();
1249 gluTessProperty(tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);
1250 gluTessCallback(tesselator, GLU_TESS_VERTEX, (GLvoid (*) ( )) &glVertex3dv);
1251 gluTessCallback(tesselator, GLU_TESS_BEGIN, (GLvoid (*) ( )) &glBegin);
1252 gluTessCallback(tesselator, GLU_TESS_END, (GLvoid (*) ( )) &glEnd);
1253 gluTessCallback(tesselator, GLU_TESS_COMBINE, (GLvoid (*) ( ))&combine_callback);
1255 vertex_cache = new List<Vertex>;
1258 // Draw every submask as a new polygon
1259 int total_submasks = command->keyframe_set->total_submasks(
1260 command->start_position_project,
1262 float scale = command->keyframe->feather + 1;
1263 int display_list = glGenLists(1);
1264 glNewList(display_list, GL_COMPILE);
1265 for(int k = 0; k < total_submasks; k++)
1267 gluTessBeginPolygon(tesselator, NULL);
1268 gluTessBeginContour(tesselator);
1269 ArrayList<MaskPoint*> *points = new ArrayList<MaskPoint*>;
1270 command->keyframe_set->get_points(points,
1272 command->start_position_project,
1275 int first_point = 0;
1276 // Need to tabulate every vertex in persistent memory because
1277 // gluTessVertex doesn't copy them.
1278 ArrayList<GLdouble*> coords;
1279 coords.set_array_delete();
1280 for(int i = 0; i < points->total; i++)
1282 MaskPoint *point1 = points->values[i];
1283 MaskPoint *point2 = (i >= points->total - 1) ?
1285 points->values[i + 1];
1289 if(point1->control_x2 == 0 &&
1290 point1->control_y2 == 0 &&
1291 point2->control_x1 == 0 &&
1292 point2->control_y1 == 0)
1295 float x0 = point1->x;
1296 float y0 = point1->y;
1297 float x1 = point1->x + point1->control_x2;
1298 float y1 = point1->y + point1->control_y2;
1299 float x2 = point2->x + point2->control_x1;
1300 float y2 = point2->y + point2->control_y1;
1301 float x3 = point2->x;
1302 float y3 = point2->y;
1304 // forward differencing bezier curves implementation taken from GPL code at
1305 // http://cvs.sourceforge.net/viewcvs.py/guliverkli/guliverkli/src/subtitles/Rasterizer.cpp?rev=1.3
1307 float cx3, cx2, cx1, cx0, cy3, cy2, cy1, cy0;
1314 cx3 = - x0 + 3*x1 - 3*x2 + x3;
1315 cx2 = 3*x0 - 6*x1 + 3*x2;
1319 cy3 = - y0 + 3*y1 - 3*y2 + y3;
1320 cy2 = 3*y0 - 6*y1 + 3*y2;
1324 // This equation is from Graphics Gems I.
1326 // The idea is that since we're approximating a cubic curve with lines,
1327 // any error we incur is due to the curvature of the line, which we can
1328 // estimate by calculating the maximum acceleration of the curve. For
1329 // a cubic, the acceleration (second derivative) is a line, meaning that
1330 // the absolute maximum acceleration must occur at either the beginning
1331 // (|c2|) or the end (|c2+c3|). Our bounds here are a little more
1332 // conservative than that, but that's okay.
1335 float maxaccel1 = fabs(2*cy2) + fabs(6*cy3);
1336 float maxaccel2 = fabs(2*cx2) + fabs(6*cx3);
1338 float maxaccel = maxaccel1 > maxaccel2 ? maxaccel1 : maxaccel2;
1341 if(maxaccel > 8.0) h = sqrt((8.0) / maxaccel);
1342 segments = int(1/h);
1345 for(int j = 0; j <= segments; j++)
1347 float t = (float)j / segments;
1348 x = cx0 + t*(cx1 + t*(cx2 + t*cx3));
1349 y = cy0 + t*(cy1 + t*(cy2 + t*cy3));
1351 if(j > 0 || first_point)
1353 GLdouble *coord = new GLdouble[3];
1354 coord[0] = x / scale;
1355 coord[1] = -h + y / scale;
1357 coords.append(coord);
1363 // Now that we know the total vertices, send them to GLU
1364 for(int i = 0; i < coords.total; i++)
1365 gluTessVertex(tesselator, coords.values[i], coords.values[i]);
1367 gluTessEndContour(tesselator);
1368 gluTessEndPolygon(tesselator);
1369 points->remove_all_objects();
1371 coords.remove_all_objects();
1374 glCallList(display_list);
1375 glDeleteLists(display_list, 1);
1376 gluDeleteTess(tesselator);
1378 delete vertex_cache;
1381 glColor4f(1, 1, 1, 1);
1384 // Read mask into temporary texture.
1385 // For feathering, just read the part of the screen after the downscaling.
1388 float w_scaled = w / scale;
1389 float h_scaled = h / scale;
1390 // Don't vary the texture size according to scaling because that
1391 // would waste memory.
1392 // This enables and binds the temporary texture.
1393 glActiveTexture(GL_TEXTURE1);
1394 BC_Texture::new_texture(&temp_texture,
1397 command->frame->get_color_model());
1398 temp_texture->bind(1);
1399 glReadBuffer(GL_BACK);
1401 // Need to add extra size to fill in the bottom right
1402 glCopyTexSubImage2D(GL_TEXTURE_2D,
1408 (int)MIN(w_scaled + 2, w),
1409 (int)MIN(h_scaled + 2, h));
1411 command->frame->bind_texture(0);
1414 // For feathered masks, use a shader to multiply.
1415 // For unfeathered masks, we could use a stencil buffer
1416 // for further optimization but we also need a YUV algorithm.
1417 unsigned int frag_shader = 0;
1418 switch(temp_texture->get_texture_components()) {
1420 frag_shader = VFrame::make_shader(0,
1421 command->frame->get_color_model() == BC_YUV888 ?
1422 multiply_yuvmask3_frag : multiply_mask3_frag,
1426 frag_shader = VFrame::make_shader(0, multiply_mask4_frag, 0);
1432 glUseProgram(frag_shader);
1433 if((variable = glGetUniformLocation(frag_shader, "tex")) >= 0)
1434 glUniform1i(variable, 0);
1435 if((variable = glGetUniformLocation(frag_shader, "tex1")) >= 0)
1436 glUniform1i(variable, 1);
1437 if((variable = glGetUniformLocation(frag_shader, "scale")) >= 0)
1438 glUniform1f(variable, scale);
1443 // Write texture to PBuffer with multiply and scaling for feather.
1446 command->frame->draw_texture(0, 0, w, h, 0, 0, w, h);
1447 command->frame->set_opengl_state(VFrame::SCREEN);
1450 // Disable temp texture
1453 glActiveTexture(GL_TEXTURE1);
1454 glDisable(GL_TEXTURE_2D);
1455 delete temp_texture;
1458 glActiveTexture(GL_TEXTURE0);
1459 glDisable(GL_TEXTURE_2D);
1462 window->enable_opengl();
1463 window->unlock_window();
1465 command->canvas->unlock_canvas();
1478 void Playback3D::convert_cmodel(Canvas *canvas,
1482 // Do nothing if colormodels are equivalent in OpenGL & the image is in hardware.
1483 int src_cmodel = output->get_color_model();
1485 (output->get_opengl_state() == VFrame::TEXTURE ||
1486 output->get_opengl_state() == VFrame::SCREEN) &&
1487 // OpenGL has no floating point.
1488 ( (src_cmodel == BC_RGB888 && dst_cmodel == BC_RGB_FLOAT) ||
1489 (src_cmodel == BC_RGBA8888 && dst_cmodel == BC_RGBA_FLOAT) ||
1490 (src_cmodel == BC_RGB_FLOAT && dst_cmodel == BC_RGB888) ||
1491 (src_cmodel == BC_RGBA_FLOAT && dst_cmodel == BC_RGBA8888) ||
1492 // OpenGL sets alpha to 1 on import
1493 (src_cmodel == BC_RGB888 && dst_cmodel == BC_RGBA8888) ||
1494 (src_cmodel == BC_YUV888 && dst_cmodel == BC_YUVA8888) ||
1495 (src_cmodel == BC_RGB_FLOAT && dst_cmodel == BC_RGBA_FLOAT) )
1500 Playback3DCommand command;
1501 command.command = Playback3DCommand::CONVERT_CMODEL;
1502 command.canvas = canvas;
1503 command.frame = output;
1504 command.dst_cmodel = dst_cmodel;
1505 send_command(&command);
1508 void Playback3D::convert_cmodel_sync(Playback3DCommand *command)
1511 command->canvas->lock_canvas("Playback3D::convert_cmodel_sync");
1513 if( command->canvas->get_canvas() ) {
1514 BC_WindowBase *window = command->canvas->get_canvas();
1515 window->lock_window("Playback3D::convert_cmodel_sync");
1516 window->enable_opengl();
1518 // Import into hardware
1519 command->frame->enable_opengl();
1520 command->frame->init_screen();
1521 command->frame->to_texture();
1523 // Colormodel permutation
1524 int src_cmodel = command->frame->get_color_model();
1525 int dst_cmodel = command->dst_cmodel;
1529 } cmodel_shader_table_t;
1530 enum { rgb_to_rgb, rgb_to_yuv, yuv_to_rgb, yuv_to_yuv, };
1532 static cmodel_shader_table_t cmodel_shader_table[] = {
1533 { BC_RGB888, BC_YUV888, rgb_to_yuv, rgb_to_yuv_frag },
1534 { BC_RGB888, BC_YUVA8888, rgb_to_yuv, rgb_to_yuv_frag },
1535 { BC_RGBA8888, BC_RGB888, rgb_to_rgb, rgba_to_rgb_frag },
1536 { BC_RGBA8888, BC_RGB_FLOAT, rgb_to_rgb, rgba_to_rgb_frag },
1537 { BC_RGBA8888, BC_YUV888, rgb_to_yuv, rgba_to_yuv_frag },
1538 { BC_RGBA8888, BC_YUVA8888, rgb_to_yuv, rgb_to_yuv_frag },
1539 { BC_RGB_FLOAT, BC_YUV888, rgb_to_yuv, rgb_to_yuv_frag },
1540 { BC_RGB_FLOAT, BC_YUVA8888, rgb_to_yuv, rgb_to_yuv_frag },
1541 { BC_RGBA_FLOAT,BC_RGB888, rgb_to_rgb, rgba_to_rgb_frag },
1542 { BC_RGBA_FLOAT,BC_RGB_FLOAT, rgb_to_rgb, rgba_to_rgb_frag },
1543 { BC_RGBA_FLOAT,BC_YUV888, rgb_to_yuv, rgba_to_yuv_frag },
1544 { BC_RGBA_FLOAT,BC_YUVA8888, rgb_to_yuv, rgb_to_yuv_frag },
1545 { BC_YUV888, BC_RGB888, yuv_to_rgb, yuv_to_rgb_frag },
1546 { BC_YUV888, BC_RGBA8888, yuv_to_rgb, yuv_to_rgb_frag },
1547 { BC_YUV888, BC_RGB_FLOAT, yuv_to_rgb, yuv_to_rgb_frag },
1548 { BC_YUV888, BC_RGBA_FLOAT, yuv_to_rgb, yuv_to_rgb_frag },
1549 { BC_YUVA8888, BC_RGB888, yuv_to_rgb, yuva_to_rgb_frag },
1550 { BC_YUVA8888, BC_RGBA8888, yuv_to_rgb, yuv_to_rgb_frag },
1551 { BC_YUVA8888, BC_RGB_FLOAT, yuv_to_rgb, yuva_to_rgb_frag },
1552 { BC_YUVA8888, BC_RGBA_FLOAT, yuv_to_rgb, yuv_to_rgb_frag },
1553 { BC_YUVA8888, BC_YUV888, yuv_to_yuv, yuva_to_yuv_frag },
1556 const char *shader = 0;
1557 int table_size = sizeof(cmodel_shader_table) / sizeof(cmodel_shader_table_t);
1558 for( int i=0; i<table_size; ++i ) {
1559 if( cmodel_shader_table[i].src == src_cmodel &&
1560 cmodel_shader_table[i].dst == dst_cmodel ) {
1561 shader = cmodel_shader_table[i].shader;
1562 type = cmodel_shader_table[i].typ;
1567 // printf("Playback3D::convert_cmodel_sync %d %d %d shader=\n%s",
1569 // command->frame->get_color_model(),
1570 // command->dst_cmodel,
1573 const char *shader_stack[9];
1574 memset(shader_stack,0, sizeof(shader_stack));
1575 int current_shader = 0;
1578 //printf("Playback3D::convert_cmodel_sync %d\n", __LINE__);
1579 shader_stack[current_shader++] = shader;
1580 shader_stack[current_shader] = 0;
1581 unsigned int shader_id = VFrame::make_shader(shader_stack);
1583 command->frame->bind_texture(0);
1584 glUseProgram(shader_id);
1586 glUniform1i(glGetUniformLocation(shader_id, "tex"), 0);
1589 BC_GL_RGB_TO_YUV(shader_id);
1592 BC_GL_YUV_TO_RGB(shader_id);
1596 command->frame->draw_texture();
1597 if(shader) glUseProgram(0);
1598 command->frame->set_opengl_state(VFrame::SCREEN);
1601 window->unlock_window();
1604 command->canvas->unlock_canvas();
1608 void Playback3D::do_fade(Canvas *canvas, VFrame *frame, float fade)
1610 Playback3DCommand command;
1611 command.command = Playback3DCommand::DO_FADE;
1612 command.canvas = canvas;
1613 command.frame = frame;
1614 command.alpha = fade;
1615 send_command(&command);
1618 void Playback3D::do_fade_sync(Playback3DCommand *command)
1621 command->canvas->lock_canvas("Playback3D::do_mask_sync");
1622 if(command->canvas->get_canvas())
1624 BC_WindowBase *window = command->canvas->get_canvas();
1625 window->lock_window("Playback3D::do_fade_sync");
1626 window->enable_opengl();
1628 switch(command->frame->get_opengl_state())
1631 command->frame->to_texture();
1634 case VFrame::SCREEN:
1635 // Read back from PBuffer
1636 // Bind context to pbuffer
1637 command->frame->enable_opengl();
1638 command->frame->screen_to_texture();
1643 command->frame->enable_opengl();
1644 command->frame->init_screen();
1645 command->frame->bind_texture(0);
1647 // glClearColor(0.0, 0.0, 0.0, 0.0);
1648 // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1649 glDisable(GL_BLEND);
1650 unsigned int frag_shader = 0;
1651 switch(command->frame->get_color_model())
1653 // For the alpha colormodels, the native function seems to multiply the
1654 // components by the alpha instead of just the alpha.
1658 frag_shader = VFrame::make_shader(0, fade_rgba_frag, 0);
1663 glBlendFunc(GL_SRC_ALPHA, GL_ZERO);
1664 glColor4f(command->alpha, command->alpha, command->alpha, 1);
1669 frag_shader = VFrame::make_shader(0, fade_yuv_frag, 0);
1675 glUseProgram(frag_shader);
1677 if((variable = glGetUniformLocation(frag_shader, "tex")) >= 0)
1678 glUniform1i(variable, 0);
1679 if((variable = glGetUniformLocation(frag_shader, "alpha")) >= 0)
1680 glUniform1f(variable, command->alpha);
1683 command->frame->draw_texture();
1684 command->frame->set_opengl_state(VFrame::SCREEN);
1691 glColor4f(1, 1, 1, 1);
1692 glDisable(GL_BLEND);
1694 window->unlock_window();
1696 command->canvas->unlock_canvas();
1710 int Playback3D::run_plugin(Canvas *canvas, PluginClient *client)
1712 Playback3DCommand command;
1713 command.command = Playback3DCommand::PLUGIN;
1714 command.canvas = canvas;
1715 command.plugin_client = client;
1716 return send_command(&command);
1719 void Playback3D::run_plugin_sync(Playback3DCommand *command)
1721 command->canvas->lock_canvas("Playback3D::run_plugin_sync");
1722 if(command->canvas->get_canvas())
1724 BC_WindowBase *window = command->canvas->get_canvas();
1725 window->lock_window("Playback3D::run_plugin_sync");
1726 window->enable_opengl();
1728 command->result = ((PluginVClient*)command->plugin_client)->handle_opengl();
1730 window->unlock_window();
1732 command->canvas->unlock_canvas();