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 "overlayframe.h"
34 #include "playback3d.h"
35 #include "pluginclient.h"
36 #include "pluginvclient.h"
37 #include "transportque.inc"
55 // These should be passed to VFrame::make_shader to construct shaders.
56 // Can't hard code sampler2D
60 static const char *yuv_to_rgb_frag =
61 "uniform sampler2D tex;\n"
64 " vec4 yuva = texture2D(tex, gl_TexCoord[0].st);\n"
65 " yuva.rgb -= vec3(0, 0.5, 0.5);\n"
66 " const mat3 yuv_to_rgb_matrix = mat3(\n"
68 " 0, -0.34414, 1.77200, \n"
69 " 1.40200, -0.71414, 0);\n"
70 " gl_FragColor = vec4(yuv_to_rgb_matrix * yuva.rgb, yuva.a);\n"
73 static const char *yuva_to_yuv_frag =
74 "uniform sampler2D tex;\n"
77 " vec4 yuva = texture2D(tex, gl_TexCoord[0].st);\n"
78 " float a = yuva.a;\n"
79 " float anti_a = 1.0 - a;\n"
81 " yuva.g = yuva.g * a + 0.5 * anti_a;\n"
82 " yuva.b = yuva.b * a + 0.5 * anti_a;\n"
84 " gl_FragColor = yuva;\n"
87 static const char *yuva_to_rgb_frag =
88 "uniform sampler2D tex;\n"
91 " vec4 yuva = texture2D(tex, gl_TexCoord[0].st);\n"
92 " yuva.rgb -= vec3(0, 0.5, 0.5);\n"
93 " const mat3 yuv_to_rgb_matrix = mat3(\n"
95 " 0, -0.34414, 1.77200, \n"
96 " 1.40200, -0.71414, 0);\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"
107 " vec4 rgba = texture2D(tex, gl_TexCoord[0].st);\n"
108 " const mat3 rgb_to_yuv_matrix = mat3(\n"
109 " 0.29900, -0.16874, 0.50000, \n"
110 " 0.58700, -0.33126, -0.41869, \n"
111 " 0.11400, 0.50000, -0.08131);\n"
112 " rgba.rgb = rgb_to_yuv_matrix * rgba.rgb;\n"
113 " rgba.rgb += vec3(0, 0.5, 0.5);\n"
114 " gl_FragColor = rgba;\n"
118 static const char *rgba_to_rgb_frag =
119 "uniform sampler2D tex;\n"
122 " vec4 rgba = texture2D(tex, gl_TexCoord[0].st);\n"
123 " rgba.rgb *= rgba.a;\n"
125 " gl_FragColor = rgba;\n"
128 static const char *rgba_to_yuv_frag =
129 "uniform sampler2D tex;\n"
132 " vec4 rgba = texture2D(tex, gl_TexCoord[0].st);\n"
133 " const mat3 rgb_to_yuv_matrix = mat3(\n"
134 " 0.29900, -0.16874, 0.50000, \n"
135 " 0.58700, -0.33126, -0.41869, \n"
136 " 0.11400, 0.50000, -0.08131);\n"
137 " rgba.rgb *= rgba.a;\n"
139 " rgba.rgb = rgb_to_yuv_matrix * rgba.rgb;\n"
140 " rgba.rgb += vec3(0, 0.5, 0.5);\n"
141 " gl_FragColor = rgba;\n"
144 static const char *rgba_to_rgb_flatten =
146 " gl_FragColor.rgb *= gl_FragColor.a;\n"
147 " gl_FragColor.a = 1.0;\n"
150 #define GL_STD_BLEND(FN) \
151 static const char *blend_##FN##_frag = \
152 "uniform sampler2D tex2;\n" \
153 "uniform vec2 tex2_dimensions;\n" \
154 "uniform float alpha;\n" \
156 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n" \
158 " result.rgb = " SS(COLOR_##FN(1.0, gl_FragColor.rgb, gl_FragColor.a, canvas.rgb, canvas.a)) ";\n" \
159 " result.a = " SS(ALPHA_##FN(1.0, gl_FragColor.a, canvas.a)) ";\n" \
160 " gl_FragColor = mix(canvas, result, alpha);\n" \
163 #define GL_VEC_BLEND(FN) \
164 static const char *blend_##FN##_frag = \
165 "uniform sampler2D tex2;\n" \
166 "uniform vec2 tex2_dimensions;\n" \
167 "uniform float alpha;\n" \
169 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n" \
171 " result.r = " SS(COLOR_##FN(1.0, gl_FragColor.r, gl_FragColor.a, canvas.r, canvas.a)) ";\n" \
172 " result.g = " SS(COLOR_##FN(1.0, gl_FragColor.g, gl_FragColor.a, canvas.g, canvas.a)) ";\n" \
173 " result.b = " SS(COLOR_##FN(1.0, gl_FragColor.b, gl_FragColor.a, canvas.b, canvas.a)) ";\n" \
174 " result.a = " SS(ALPHA_##FN(1.0, gl_FragColor.a, canvas.a)) ";\n" \
175 " result = clamp(result, 0.0, 1.0);\n" \
176 " gl_FragColor = mix(canvas, result, alpha);\n" \
194 static const char *blend_NORMAL_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 = mix(canvas, gl_FragColor, gl_FragColor.a);\n"
201 " gl_FragColor = mix(canvas, result, alpha);\n"
205 static const char *blend_REPLACE_frag =
206 "uniform float alpha;\n"
211 static const char *blend_ADDITION_frag =
212 "uniform sampler2D tex2;\n"
213 "uniform vec2 tex2_dimensions;\n"
214 "uniform float alpha;\n"
216 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
217 " vec4 result = clamp(gl_FragColor + canvas, 0.0, 1.0);\n"
218 " gl_FragColor = mix(canvas, result, alpha);\n"
222 static const char *blend_SUBTRACT_frag =
223 "uniform sampler2D tex2;\n"
224 "uniform vec2 tex2_dimensions;\n"
225 "uniform float alpha;\n"
227 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
228 " vec4 result = clamp(gl_FragColor - canvas, 0.0, 1.0);\n"
229 " gl_FragColor = mix(canvas, result, alpha);\n"
232 GL_STD_BLEND(MULTIPLY);
233 GL_VEC_BLEND(DIVIDE);
236 GL_VEC_BLEND(DARKEN);
237 GL_VEC_BLEND(LIGHTEN);
239 GL_STD_BLEND(DST_ATOP);
240 GL_STD_BLEND(DST_IN);
241 GL_STD_BLEND(DST_OUT);
242 GL_STD_BLEND(DST_OVER);
244 GL_STD_BLEND(SRC_ATOP);
245 GL_STD_BLEND(SRC_IN);
246 GL_STD_BLEND(SRC_OUT);
247 GL_STD_BLEND(SRC_OVER);
251 GL_VEC_BLEND(OVERLAY);
252 GL_STD_BLEND(SCREEN);
255 GL_VEC_BLEND(HARDLIGHT);
256 GL_VEC_BLEND(SOFTLIGHT);
257 GL_VEC_BLEND(DIFFERENCE);
259 static const char *read_texture_frag =
260 "uniform sampler2D tex;\n"
263 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
266 static const char *multiply_mask4_frag =
267 "uniform sampler2D tex;\n"
268 "uniform sampler2D tex1;\n"
269 "uniform float scale;\n"
272 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
273 " gl_FragColor.a *= texture2D(tex1, gl_TexCoord[0].st / vec2(scale, scale)).r;\n"
276 static const char *multiply_mask3_frag =
277 "uniform sampler2D tex;\n"
278 "uniform sampler2D tex1;\n"
279 "uniform float scale;\n"
280 "uniform bool is_yuv;\n"
283 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
284 " float a = texture2D(tex1, gl_TexCoord[0].st / vec2(scale, scale)).r;\n"
285 " gl_FragColor.rgb *= vec3(a, a, a);\n"
288 static const char *multiply_yuvmask3_frag =
289 "uniform sampler2D tex;\n"
290 "uniform sampler2D tex1;\n"
291 "uniform float scale;\n"
294 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
295 " float a = texture2D(tex1, gl_TexCoord[0].st / vec2(scale, scale)).r;\n"
296 " gl_FragColor.gb -= vec2(0.5, 0.5);\n"
297 " gl_FragColor.rgb *= vec3(a, a, a);\n"
298 " gl_FragColor.gb += vec2(0.5, 0.5);\n"
301 static const char *fade_rgba_frag =
302 "uniform sampler2D tex;\n"
303 "uniform float alpha;\n"
306 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
307 " gl_FragColor.a *= alpha;\n"
310 static const char *fade_yuv_frag =
311 "uniform sampler2D tex;\n"
312 "uniform float alpha;\n"
315 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
316 " gl_FragColor.r *= alpha;\n"
317 " gl_FragColor.gb -= vec2(0.5, 0.5);\n"
318 " gl_FragColor.g *= alpha;\n"
319 " gl_FragColor.b *= alpha;\n"
320 " gl_FragColor.gb += vec2(0.5, 0.5);\n"
326 Playback3DCommand::Playback3DCommand()
327 : BC_SynchronousCommand()
333 void Playback3DCommand::copy_from(BC_SynchronousCommand *command)
335 Playback3DCommand *ptr = (Playback3DCommand*)command;
336 this->canvas = ptr->canvas;
337 this->is_cleared = ptr->is_cleared;
339 this->in_x1 = ptr->in_x1;
340 this->in_y1 = ptr->in_y1;
341 this->in_x2 = ptr->in_x2;
342 this->in_y2 = ptr->in_y2;
343 this->out_x1 = ptr->out_x1;
344 this->out_y1 = ptr->out_y1;
345 this->out_x2 = ptr->out_x2;
346 this->out_y2 = ptr->out_y2;
347 this->alpha = ptr->alpha;
348 this->mode = ptr->mode;
349 this->interpolation_type = ptr->interpolation_type;
351 this->input = ptr->input;
352 this->start_position_project = ptr->start_position_project;
353 this->keyframe_set = ptr->keyframe_set;
354 this->keyframe = ptr->keyframe;
355 this->default_auto = ptr->default_auto;
356 this->plugin_client = ptr->plugin_client;
357 this->want_texture = ptr->want_texture;
358 this->is_nested = ptr->is_nested;
359 this->dst_cmodel = ptr->dst_cmodel;
361 BC_SynchronousCommand::copy_from(command);
365 ///static void glDebugCallback(GLenum src, GLenum typ, GLuint id,
366 /// GLenum svy, GLsizei len, const GLchar* msg, void* dat)
367 //static void glDebugCallback(unsigned int src, unsigned int typ, unsigned int id,
368 // unsigned int svy, int len, const char* msg, const void* dat)
370 // printf("glDebug: %d:%d; %d/%d %s\n",src,typ,id,svy,msg);
374 Playback3D::Playback3D(MWindow *mwindow)
377 this->mwindow = mwindow;
379 //Enabling OpenGL debug output on nVidia drivers
380 // glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, 0, GL_TRUE);
381 // glEnable(GL_DEBUG_OUTPUT);
382 // glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
383 // glDebugMessageCallback(glDebugCallback, 0);
386 Playback3D::~Playback3D()
393 BC_SynchronousCommand* Playback3D::new_command()
395 return new Playback3DCommand;
400 void Playback3D::handle_command(BC_SynchronousCommand *command)
402 //printf("Playback3D::handle_command 1 %d\n", command->command);
403 switch(command->command)
405 case Playback3DCommand::WRITE_BUFFER:
406 write_buffer_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->enable_opengl();
509 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
510 glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE,
511 command->frame->get_rows()[0]);
512 command->frame->flip_vert();
513 command->frame->set_opengl_state(VFrame::RAM);
518 printf("Playback3D::copy_from_sync: invalid formats opengl_state=%d %dx%d -> %dx%d\n",
519 command->input->get_opengl_state(), w, h,
520 command->frame->get_w(), command->frame->get_h());
523 window->unlock_window();
525 command->canvas->unlock_canvas();
532 // void Playback3D::draw_refresh(Canvas *canvas,
543 // Playback3DCommand command;
544 // command.command = Playback3DCommand::DRAW_REFRESH;
545 // command.canvas = canvas;
546 // command.frame = frame;
547 // command.in_x1 = in_x1;
548 // command.in_y1 = in_y1;
549 // command.in_x2 = in_x2;
550 // command.in_y2 = in_y2;
551 // command.out_x1 = out_x1;
552 // command.out_y1 = out_y1;
553 // command.out_x2 = out_x2;
554 // command.out_y2 = out_y2;
555 // send_command(&command);
558 // void Playback3D::draw_refresh_sync(Playback3DCommand *command)
560 // command->canvas->lock_canvas("Playback3D::draw_refresh_sync");
561 // BC_WindowBase *window = command->canvas->get_canvas();
564 // window->lock_window("Playback3D:draw_refresh_sync");
565 // window->enable_opengl();
567 // // Read output pbuffer back to RAM in project colormodel
568 // // RGB 8bit is fastest for OpenGL to read back.
569 // command->frame->reallocate(0,
573 // command->frame->get_w(),
574 // command->frame->get_h(),
577 // command->frame->screen_to_ram();
579 // window->clear_box(0,
583 // window->draw_vframe(command->frame,
584 // (int)command->out_x1,
585 // (int)command->out_y1,
586 // (int)(command->out_x2 - command->out_x1),
587 // (int)(command->out_y2 - command->out_y1),
588 // (int)command->in_x1,
589 // (int)command->in_y1,
590 // (int)(command->in_x2 - command->in_x1),
591 // (int)(command->in_y2 - command->in_y1),
594 // window->unlock_window();
596 // command->canvas->unlock_canvas();
603 void Playback3D::write_buffer(Canvas *canvas,
615 Playback3DCommand command;
616 command.command = Playback3DCommand::WRITE_BUFFER;
617 command.canvas = canvas;
618 command.frame = frame;
619 command.in_x1 = in_x1;
620 command.in_y1 = in_y1;
621 command.in_x2 = in_x2;
622 command.in_y2 = in_y2;
623 command.out_x1 = out_x1;
624 command.out_y1 = out_y1;
625 command.out_x2 = out_x2;
626 command.out_y2 = out_y2;
627 command.is_cleared = is_cleared;
628 send_command(&command);
632 void Playback3D::write_buffer_sync(Playback3DCommand *command)
634 command->canvas->lock_canvas("Playback3D::write_buffer_sync");
635 if(command->canvas->get_canvas())
637 BC_WindowBase *window = command->canvas->get_canvas();
638 window->lock_window("Playback3D::write_buffer_sync");
639 // Update hidden cursor
640 window->update_video_cursor();
641 // Make sure OpenGL is enabled first.
642 window->enable_opengl();
645 //printf("Playback3D::write_buffer_sync 1 %d\n", window->get_id());
646 switch(command->frame->get_opengl_state())
648 // Upload texture and composite to screen
650 command->frame->to_texture();
651 draw_output(command);
653 // Composite texture to screen and swap buffer
654 case VFrame::TEXTURE:
655 draw_output(command);
659 window->flip_opengl();
662 printf("Playback3D::write_buffer_sync unknown state\n");
665 window->unlock_window();
668 command->canvas->unlock_canvas();
673 void Playback3D::draw_output(Playback3DCommand *command)
676 int texture_id = command->frame->get_texture_id();
677 BC_WindowBase *window = command->canvas->get_canvas();
679 // printf("Playback3D::draw_output 1 texture_id=%d window=%p\n",
681 // command->canvas->get_canvas());
686 // If virtual console is being used, everything in this function has
687 // already been done except the page flip.
690 canvas_w = window->get_w();
691 canvas_h = window->get_h();
692 VFrame::init_screen(canvas_w, canvas_h);
694 if(!command->is_cleared)
696 // If we get here, the virtual console was not used.
701 // Undo any previous shader settings
702 command->frame->bind_texture(0);
707 // Convert colormodel
708 unsigned int frag_shader = 0;
709 switch(command->frame->get_color_model())
713 frag_shader = VFrame::make_shader(0,
722 glUseProgram(frag_shader);
723 int variable = glGetUniformLocation(frag_shader, "tex");
724 // Set texture unit of the texture
725 glUniform1i(variable, 0);
728 if(BC_CModels::components(command->frame->get_color_model()) == 4)
731 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
734 command->frame->draw_texture(
735 command->in_x1, command->in_y1, command->in_x2, command->in_y2,
736 command->out_x1, command->out_y1, command->out_x2, command->out_y2,
740 // printf("Playback3D::draw_output 2 %f,%f %f,%f -> %f,%f %f,%f\n",
752 command->canvas->get_canvas()->flip_opengl();
759 void Playback3D::init_frame(Playback3DCommand *command)
762 canvas_w = command->canvas->get_canvas()->get_w();
763 canvas_h = command->canvas->get_canvas()->get_h();
765 glClearColor(0.0, 0.0, 0.0, 0.0);
766 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
771 void Playback3D::clear_output(Canvas *canvas, VFrame *output)
773 Playback3DCommand command;
774 command.command = Playback3DCommand::CLEAR_OUTPUT;
775 command.canvas = canvas;
776 command.frame = output;
777 send_command(&command);
780 void Playback3D::clear_output_sync(Playback3DCommand *command)
782 command->canvas->lock_canvas("Playback3D::clear_output_sync");
783 if(command->canvas->get_canvas())
785 command->canvas->get_canvas()->lock_window("Playback3D::clear_output_sync");
786 // If we get here, the virtual console is being used.
787 command->canvas->get_canvas()->enable_opengl();
789 // Using pbuffer for refresh frame.
792 command->frame->enable_opengl();
797 command->canvas->get_canvas()->unlock_window();
799 command->canvas->unlock_canvas();
803 void Playback3D::clear_input(Canvas *canvas, VFrame *frame)
805 Playback3DCommand command;
806 command.command = Playback3DCommand::CLEAR_INPUT;
807 command.canvas = canvas;
808 command.frame = frame;
809 send_command(&command);
812 void Playback3D::clear_input_sync(Playback3DCommand *command)
814 command->canvas->lock_canvas("Playback3D::clear_output_sync");
815 if(command->canvas->get_canvas())
817 command->canvas->get_canvas()->lock_window("Playback3D::clear_output_sync");
818 command->canvas->get_canvas()->enable_opengl();
819 command->frame->enable_opengl();
820 command->frame->clear_pbuffer();
821 command->frame->set_opengl_state(VFrame::SCREEN);
822 command->canvas->get_canvas()->unlock_window();
824 command->canvas->unlock_canvas();
827 void Playback3D::do_camera(Canvas *canvas,
839 Playback3DCommand command;
840 command.command = Playback3DCommand::DO_CAMERA;
841 command.canvas = canvas;
842 command.input = input;
843 command.frame = output;
844 command.in_x1 = in_x1;
845 command.in_y1 = in_y1;
846 command.in_x2 = in_x2;
847 command.in_y2 = in_y2;
848 command.out_x1 = out_x1;
849 command.out_y1 = out_y1;
850 command.out_x2 = out_x2;
851 command.out_y2 = out_y2;
852 send_command(&command);
855 void Playback3D::do_camera_sync(Playback3DCommand *command)
857 command->canvas->lock_canvas("Playback3D::do_camera_sync");
858 if(command->canvas->get_canvas())
860 command->canvas->get_canvas()->lock_window("Playback3D::clear_output_sync");
861 command->canvas->get_canvas()->enable_opengl();
863 command->input->to_texture();
864 command->frame->enable_opengl();
865 command->frame->init_screen();
866 command->frame->clear_pbuffer();
868 command->input->bind_texture(0);
869 // Must call draw_texture in input frame to get the texture coordinates right.
871 // printf("Playback3D::do_camera_sync 1 %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f\n",
877 // (float)command->input->get_h() - command->out_y1,
879 // (float)command->input->get_h() - command->out_y2);
880 command->input->draw_texture(
881 command->in_x1, command->in_y2,
882 command->in_x2, command->in_y1,
884 (float)command->frame->get_h() - command->out_y1,
886 (float)command->frame->get_h() - command->out_y2);
889 command->frame->set_opengl_state(VFrame::SCREEN);
890 command->canvas->get_canvas()->unlock_window();
892 command->canvas->unlock_canvas();
895 void Playback3D::overlay(Canvas *canvas, VFrame *input,
896 float in_x1, float in_y1, float in_x2, float in_y2,
897 float out_x1, float out_y1, float out_x2, float out_y2,
898 float alpha, int mode, int interpolation_type,
899 VFrame *output, int is_nested)
901 Playback3DCommand command;
902 command.command = Playback3DCommand::OVERLAY;
903 command.canvas = canvas;
904 command.frame = output;
905 command.input = input;
906 command.in_x1 = in_x1;
907 command.in_y1 = in_y1;
908 command.in_x2 = in_x2;
909 command.in_y2 = in_y2;
910 command.out_x1 = out_x1;
911 command.out_y1 = out_y1;
912 command.out_x2 = out_x2;
913 command.out_y2 = out_y2;
914 command.alpha = alpha;
916 command.interpolation_type = interpolation_type;
917 command.is_nested = is_nested;
918 send_command(&command);
921 void Playback3D::overlay_sync(Playback3DCommand *command)
924 // To do these operations, we need to copy the input buffer to a texture
925 // and blend 2 textures in a shader
926 static const char * const overlay_shaders[TRANSFER_TYPES] = {
927 blend_NORMAL_frag, // TRANSFER_NORMAL
928 blend_ADDITION_frag, // TRANSFER_ADDITION
929 blend_SUBTRACT_frag, // TRANSFER_SUBTRACT
930 blend_MULTIPLY_frag, // TRANSFER_MULTIPLY
931 blend_DIVIDE_frag, // TRANSFER_DIVIDE
932 blend_REPLACE_frag, // TRANSFER_REPLACE
933 blend_MAX_frag, // TRANSFER_MAX
934 blend_MIN_frag, // TRANSFER_MIN
935 blend_DARKEN_frag, // TRANSFER_DARKEN
936 blend_LIGHTEN_frag, // TRANSFER_LIGHTEN
937 blend_DST_frag, // TRANSFER_DST
938 blend_DST_ATOP_frag, // TRANSFER_DST_ATOP
939 blend_DST_IN_frag, // TRANSFER_DST_IN
940 blend_DST_OUT_frag, // TRANSFER_DST_OUT
941 blend_DST_OVER_frag, // TRANSFER_DST_OVER
942 blend_SRC_frag, // TRANSFER_SRC
943 blend_SRC_ATOP_frag, // TRANSFER_SRC_ATOP
944 blend_SRC_IN_frag, // TRANSFER_SRC_IN
945 blend_SRC_OUT_frag, // TRANSFER_SRC_OUT
946 blend_SRC_OVER_frag, // TRANSFER_SRC_OVER
947 blend_AND_frag, // TRANSFER_AND
948 blend_OR_frag, // TRANSFER_OR
949 blend_XOR_frag, // TRANSFER_XOR
950 blend_OVERLAY_frag, // TRANSFER_OVERLAY
951 blend_SCREEN_frag, // TRANSFER_SCREEN
952 blend_BURN_frag, // TRANSFER_BURN
953 blend_DODGE_frag, // TRANSFER_DODGE
954 blend_HARDLIGHT_frag, // TRANSFER_HARDLIGHT
955 blend_SOFTLIGHT_frag, // TRANSFER_SOFTLIGHT
956 blend_DIFFERENCE_frag, // TRANSFER_DIFFERENCE
959 command->canvas->lock_canvas("Playback3D::overlay_sync");
960 if(command->canvas->get_canvas()) {
961 BC_WindowBase *window = command->canvas->get_canvas();
962 window->lock_window("Playback3D::overlay_sync");
963 // Make sure OpenGL is enabled first.
964 window->enable_opengl();
965 window->update_video_cursor();
967 glColor4f(1, 1, 1, 1);
972 command->frame->enable_opengl();
973 command->frame->set_opengl_state(VFrame::SCREEN);
974 canvas_w = command->frame->get_w();
975 canvas_h = command->frame->get_h();
979 canvas_w = window->get_w();
980 canvas_h = window->get_h();
984 //printf("Playback3D::overlay_sync 1 %d\n", command->input->get_opengl_state());
985 switch(command->input->get_opengl_state()) {
986 // Upload texture and composite to screen
988 command->input->to_texture();
990 // Just composite texture to screen
991 case VFrame::TEXTURE:
993 // read from PBuffer to texture, then composite texture to screen
995 command->input->enable_opengl();
996 command->input->screen_to_texture();
998 command->frame->enable_opengl();
1000 window->enable_opengl();
1003 printf("Playback3D::overlay_sync unknown state\n");
1008 const char *shader_stack[4] = { 0, 0, 0, 0, };
1009 int total_shaders = 0;
1011 VFrame::init_screen(canvas_w, canvas_h);
1014 command->input->bind_texture(0);
1016 // Convert colormodel to RGB if not nested.
1017 // The color model setting in the output frame is ignored.
1018 if( command->is_nested <= 0 ) { // not nested
1019 switch(command->input->get_color_model()) {
1022 shader_stack[total_shaders++] = yuv_to_rgb_frag;
1028 #define add_shader(s) \
1029 if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag; \
1030 shader_stack[total_shaders++] = s
1032 switch(command->mode) {
1033 case TRANSFER_REPLACE:
1034 // This requires overlaying an alpha multiplied image on a black screen.
1035 if( command->input->get_texture_components() != 4 ) break;
1036 add_shader(overlay_shaders[command->mode]);
1039 enable_overlay_texture(command);
1040 add_shader(overlay_shaders[command->mode]);
1044 // if to flatten alpha
1045 if( command->is_nested < 0 ) {
1046 switch(command->input->get_color_model()) {
1047 // yuv has already been converted to rgb
1051 add_shader(rgba_to_rgb_flatten);
1057 unsigned int frag_shader = 0;
1058 if(shader_stack[0]) {
1059 frag_shader = VFrame::make_shader(0,
1060 shader_stack[0], shader_stack[1],
1061 shader_stack[2], shader_stack[3], 0);
1063 glUseProgram(frag_shader);
1065 // Set texture unit of the texture
1066 glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0);
1067 // Set texture unit of the temp texture
1068 glUniform1i(glGetUniformLocation(frag_shader, "tex2"), 1);
1070 int variable = glGetUniformLocation(frag_shader, "alpha");
1071 glUniform1f(variable, command->alpha);
1072 // Set dimensions of the temp texture
1074 glUniform2f(glGetUniformLocation(frag_shader, "tex2_dimensions"),
1075 (float)temp_texture->get_texture_w(),
1076 (float)temp_texture->get_texture_h());
1082 // printf("Playback3D::overlay_sync %f %f %f %f %f %f %f %f\n",
1083 // command->in_x1, command->in_y1, command->in_x2, command->in_y2,
1084 // command->out_x1, command->out_y1, command->out_x2, command->out_y2);
1086 command->input->draw_texture(
1087 command->in_x1, command->in_y1, command->in_x2, command->in_y2,
1088 command->out_x1, command->out_y1, command->out_x2, command->out_y2,
1089 // Don't flip vertical if nested
1090 command->is_nested > 0 ? 0 : 1);
1093 // Delete temp texture
1095 delete temp_texture;
1097 glActiveTexture(GL_TEXTURE1);
1098 glDisable(GL_TEXTURE_2D);
1100 glActiveTexture(GL_TEXTURE0);
1101 glDisable(GL_TEXTURE_2D);
1103 window->unlock_window();
1105 command->canvas->unlock_canvas();
1109 void Playback3D::enable_overlay_texture(Playback3DCommand *command)
1112 glDisable(GL_BLEND);
1114 glActiveTexture(GL_TEXTURE1);
1115 BC_Texture::new_texture(&temp_texture, canvas_w, canvas_h,
1116 command->input->get_color_model());
1117 temp_texture->bind(1);
1119 // Read canvas into texture
1120 glReadBuffer(GL_BACK);
1121 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, canvas_w, canvas_h);
1126 void Playback3D::do_mask(Canvas *canvas,
1128 int64_t start_position_project,
1129 MaskAutos *keyframe_set,
1131 MaskAuto *default_auto)
1133 Playback3DCommand command;
1134 command.command = Playback3DCommand::DO_MASK;
1135 command.canvas = canvas;
1136 command.frame = output;
1137 command.start_position_project = start_position_project;
1138 command.keyframe_set = keyframe_set;
1139 command.keyframe = keyframe;
1140 command.default_auto = default_auto;
1142 send_command(&command);
1148 struct Vertex : ListItem<Vertex>
1152 // this list is only used from the main thread, no locking needed
1153 // this must be a list so that pointers to allocated entries remain valid
1154 // when new entries are added
1155 static List<Vertex> *vertex_cache = 0;
1157 static void combine_callback(GLdouble coords[3],
1158 GLdouble *vertex_data[4],
1162 // can't use malloc here; GLU doesn't delete the memory for us!
1163 Vertex* vertex = vertex_cache->append();
1164 vertex->c[0] = coords[0];
1165 vertex->c[1] = coords[1];
1166 vertex->c[2] = coords[2];
1167 // we don't need to interpolate anything
1169 *dataOut = &vertex->c[0];
1174 void Playback3D::do_mask_sync(Playback3DCommand *command)
1177 command->canvas->lock_canvas("Playback3D::do_mask_sync");
1178 if(command->canvas->get_canvas())
1180 BC_WindowBase *window = command->canvas->get_canvas();
1181 window->lock_window("Playback3D::do_mask_sync");
1182 window->enable_opengl();
1184 switch(command->frame->get_opengl_state())
1187 // Time to upload to the texture
1188 command->frame->to_texture();
1191 case VFrame::SCREEN:
1192 // Read back from PBuffer
1193 // Bind context to pbuffer
1194 command->frame->enable_opengl();
1195 command->frame->screen_to_texture();
1201 // Create PBuffer and draw the mask on it
1202 command->frame->enable_opengl();
1204 // Initialize coordinate system
1205 int w = command->frame->get_w();
1206 int h = command->frame->get_h();
1207 command->frame->init_screen();
1210 glDisable(GL_TEXTURE_2D);
1211 if(command->default_auto->mode == MASK_MULTIPLY_ALPHA)
1213 glClearColor(0.0, 0.0, 0.0, 0.0);
1214 glColor4f((float)command->keyframe->value / 100,
1215 (float)command->keyframe->value / 100,
1216 (float)command->keyframe->value / 100,
1221 glClearColor(1.0, 1.0, 1.0, 1.0);
1222 glColor4f((float)1.0 - (float)command->keyframe->value / 100,
1223 (float)1.0 - (float)command->keyframe->value / 100,
1224 (float)1.0 - (float)command->keyframe->value / 100,
1227 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1230 // Draw mask with scaling to simulate feathering
1231 GLUtesselator *tesselator = gluNewTess();
1232 gluTessProperty(tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);
1233 gluTessCallback(tesselator, GLU_TESS_VERTEX, (GLvoid (*) ( )) &glVertex3dv);
1234 gluTessCallback(tesselator, GLU_TESS_BEGIN, (GLvoid (*) ( )) &glBegin);
1235 gluTessCallback(tesselator, GLU_TESS_END, (GLvoid (*) ( )) &glEnd);
1236 gluTessCallback(tesselator, GLU_TESS_COMBINE, (GLvoid (*) ( ))&combine_callback);
1238 vertex_cache = new List<Vertex>;
1241 // Draw every submask as a new polygon
1242 int total_submasks = command->keyframe_set->total_submasks(
1243 command->start_position_project,
1245 float scale = command->keyframe->feather + 1;
1246 int display_list = glGenLists(1);
1247 glNewList(display_list, GL_COMPILE);
1248 for(int k = 0; k < total_submasks; k++)
1250 gluTessBeginPolygon(tesselator, NULL);
1251 gluTessBeginContour(tesselator);
1252 ArrayList<MaskPoint*> *points = new ArrayList<MaskPoint*>;
1253 command->keyframe_set->get_points(points,
1255 command->start_position_project,
1258 int first_point = 0;
1259 // Need to tabulate every vertex in persistent memory because
1260 // gluTessVertex doesn't copy them.
1261 ArrayList<GLdouble*> coords;
1262 for(int i = 0; i < points->total; i++)
1264 MaskPoint *point1 = points->values[i];
1265 MaskPoint *point2 = (i >= points->total - 1) ?
1267 points->values[i + 1];
1271 if(point1->control_x2 == 0 &&
1272 point1->control_y2 == 0 &&
1273 point2->control_x1 == 0 &&
1274 point2->control_y1 == 0)
1277 float x0 = point1->x;
1278 float y0 = point1->y;
1279 float x1 = point1->x + point1->control_x2;
1280 float y1 = point1->y + point1->control_y2;
1281 float x2 = point2->x + point2->control_x1;
1282 float y2 = point2->y + point2->control_y1;
1283 float x3 = point2->x;
1284 float y3 = point2->y;
1286 // forward differencing bezier curves implementation taken from GPL code at
1287 // http://cvs.sourceforge.net/viewcvs.py/guliverkli/guliverkli/src/subtitles/Rasterizer.cpp?rev=1.3
1289 float cx3, cx2, cx1, cx0, cy3, cy2, cy1, cy0;
1296 cx3 = - x0 + 3*x1 - 3*x2 + x3;
1297 cx2 = 3*x0 - 6*x1 + 3*x2;
1301 cy3 = - y0 + 3*y1 - 3*y2 + y3;
1302 cy2 = 3*y0 - 6*y1 + 3*y2;
1306 // This equation is from Graphics Gems I.
1308 // The idea is that since we're approximating a cubic curve with lines,
1309 // any error we incur is due to the curvature of the line, which we can
1310 // estimate by calculating the maximum acceleration of the curve. For
1311 // a cubic, the acceleration (second derivative) is a line, meaning that
1312 // the absolute maximum acceleration must occur at either the beginning
1313 // (|c2|) or the end (|c2+c3|). Our bounds here are a little more
1314 // conservative than that, but that's okay.
1317 float maxaccel1 = fabs(2*cy2) + fabs(6*cy3);
1318 float maxaccel2 = fabs(2*cx2) + fabs(6*cx3);
1320 float maxaccel = maxaccel1 > maxaccel2 ? maxaccel1 : maxaccel2;
1323 if(maxaccel > 8.0) h = sqrt((8.0) / maxaccel);
1324 segments = int(1/h);
1327 for(int j = 0; j <= segments; j++)
1329 float t = (float)j / segments;
1330 x = cx0 + t*(cx1 + t*(cx2 + t*cx3));
1331 y = cy0 + t*(cy1 + t*(cy2 + t*cy3));
1333 if(j > 0 || first_point)
1335 GLdouble *coord = new GLdouble[3];
1336 coord[0] = x / scale;
1337 coord[1] = -h + y / scale;
1339 coords.append(coord);
1345 // Now that we know the total vertices, send them to GLU
1346 for(int i = 0; i < coords.total; i++)
1347 gluTessVertex(tesselator, coords.values[i], coords.values[i]);
1349 gluTessEndContour(tesselator);
1350 gluTessEndPolygon(tesselator);
1351 points->remove_all_objects();
1353 coords.remove_all_objects();
1356 glCallList(display_list);
1357 glDeleteLists(display_list, 1);
1358 gluDeleteTess(tesselator);
1360 delete vertex_cache;
1363 glColor4f(1, 1, 1, 1);
1366 // Read mask into temporary texture.
1367 // For feathering, just read the part of the screen after the downscaling.
1370 float w_scaled = w / scale;
1371 float h_scaled = h / scale;
1372 // Don't vary the texture size according to scaling because that
1373 // would waste memory.
1374 // This enables and binds the temporary texture.
1375 glActiveTexture(GL_TEXTURE1);
1376 BC_Texture::new_texture(&temp_texture,
1379 command->frame->get_color_model());
1380 temp_texture->bind(1);
1381 glReadBuffer(GL_BACK);
1383 // Need to add extra size to fill in the bottom right
1384 glCopyTexSubImage2D(GL_TEXTURE_2D,
1390 (int)MIN(w_scaled + 2, w),
1391 (int)MIN(h_scaled + 2, h));
1393 command->frame->bind_texture(0);
1396 // For feathered masks, use a shader to multiply.
1397 // For unfeathered masks, we could use a stencil buffer
1398 // for further optimization but we also need a YUV algorithm.
1399 unsigned int frag_shader = 0;
1400 switch(temp_texture->get_texture_components())
1403 if(command->frame->get_color_model() == BC_YUV888)
1404 frag_shader = VFrame::make_shader(0,
1405 multiply_yuvmask3_frag,
1408 frag_shader = VFrame::make_shader(0,
1409 multiply_mask3_frag,
1413 frag_shader = VFrame::make_shader(0,
1414 multiply_mask4_frag,
1422 glUseProgram(frag_shader);
1423 if((variable = glGetUniformLocation(frag_shader, "tex")) >= 0)
1424 glUniform1i(variable, 0);
1425 if((variable = glGetUniformLocation(frag_shader, "tex1")) >= 0)
1426 glUniform1i(variable, 1);
1427 if((variable = glGetUniformLocation(frag_shader, "scale")) >= 0)
1428 glUniform1f(variable, scale);
1433 // Write texture to PBuffer with multiply and scaling for feather.
1436 command->frame->draw_texture(0, 0, w, h, 0, 0, w, h);
1437 command->frame->set_opengl_state(VFrame::SCREEN);
1440 // Disable temp texture
1443 glActiveTexture(GL_TEXTURE1);
1444 glDisable(GL_TEXTURE_2D);
1445 delete temp_texture;
1448 glActiveTexture(GL_TEXTURE0);
1449 glDisable(GL_TEXTURE_2D);
1452 window->enable_opengl();
1453 window->unlock_window();
1455 command->canvas->unlock_canvas();
1468 void Playback3D::convert_cmodel(Canvas *canvas,
1472 // Do nothing if colormodels are equivalent in OpenGL & the image is in hardware.
1473 int src_cmodel = output->get_color_model();
1475 (output->get_opengl_state() == VFrame::TEXTURE ||
1476 output->get_opengl_state() == VFrame::SCREEN) &&
1477 // OpenGL has no floating point.
1478 ( (src_cmodel == BC_RGB888 && dst_cmodel == BC_RGB_FLOAT) ||
1479 (src_cmodel == BC_RGBA8888 && dst_cmodel == BC_RGBA_FLOAT) ||
1480 (src_cmodel == BC_RGB_FLOAT && dst_cmodel == BC_RGB888) ||
1481 (src_cmodel == BC_RGBA_FLOAT && dst_cmodel == BC_RGBA8888) ||
1482 // OpenGL sets alpha to 1 on import
1483 (src_cmodel == BC_RGB888 && dst_cmodel == BC_RGBA8888) ||
1484 (src_cmodel == BC_YUV888 && dst_cmodel == BC_YUVA8888) ||
1485 (src_cmodel == BC_RGB_FLOAT && dst_cmodel == BC_RGBA_FLOAT) )
1490 Playback3DCommand command;
1491 command.command = Playback3DCommand::CONVERT_CMODEL;
1492 command.canvas = canvas;
1493 command.frame = output;
1494 command.dst_cmodel = dst_cmodel;
1495 send_command(&command);
1498 void Playback3D::convert_cmodel_sync(Playback3DCommand *command)
1501 command->canvas->lock_canvas("Playback3D::convert_cmodel_sync");
1503 if(command->canvas->get_canvas())
1505 BC_WindowBase *window = command->canvas->get_canvas();
1506 window->lock_window("Playback3D::convert_cmodel_sync");
1507 window->enable_opengl();
1509 // Import into hardware
1510 command->frame->enable_opengl();
1511 command->frame->init_screen();
1512 command->frame->to_texture();
1514 // Colormodel permutation
1515 const char *shader = 0;
1516 int src_cmodel = command->frame->get_color_model();
1517 int dst_cmodel = command->dst_cmodel;
1523 } cmodel_shader_table_t;
1524 static cmodel_shader_table_t cmodel_shader_table[] =
1526 { BC_RGB888, BC_YUV888, rgb_to_yuv_frag },
1527 { BC_RGB888, BC_YUVA8888, rgb_to_yuv_frag },
1528 { BC_RGBA8888, BC_RGB888, rgba_to_rgb_frag },
1529 { BC_RGBA8888, BC_RGB_FLOAT, rgba_to_rgb_frag },
1530 { BC_RGBA8888, BC_YUV888, rgba_to_yuv_frag },
1531 { BC_RGBA8888, BC_YUVA8888, rgb_to_yuv_frag },
1532 { BC_RGB_FLOAT, BC_YUV888, rgb_to_yuv_frag },
1533 { BC_RGB_FLOAT, BC_YUVA8888, rgb_to_yuv_frag },
1534 { BC_RGBA_FLOAT, BC_RGB888, rgba_to_rgb_frag },
1535 { BC_RGBA_FLOAT, BC_RGB_FLOAT, rgba_to_rgb_frag },
1536 { BC_RGBA_FLOAT, BC_YUV888, rgba_to_yuv_frag },
1537 { BC_RGBA_FLOAT, BC_YUVA8888, rgb_to_yuv_frag },
1538 { BC_YUV888, BC_RGB888, yuv_to_rgb_frag },
1539 { BC_YUV888, BC_RGBA8888, yuv_to_rgb_frag },
1540 { BC_YUV888, BC_RGB_FLOAT, yuv_to_rgb_frag },
1541 { BC_YUV888, BC_RGBA_FLOAT, yuv_to_rgb_frag },
1542 { BC_YUVA8888, BC_RGB888, yuva_to_rgb_frag },
1543 { BC_YUVA8888, BC_RGBA8888, yuv_to_rgb_frag },
1544 { BC_YUVA8888, BC_RGB_FLOAT, yuva_to_rgb_frag },
1545 { BC_YUVA8888, BC_RGBA_FLOAT, yuv_to_rgb_frag },
1546 { BC_YUVA8888, BC_YUV888, yuva_to_yuv_frag },
1549 int table_size = sizeof(cmodel_shader_table) / sizeof(cmodel_shader_table_t);
1550 for(int i = 0; i < table_size; i++)
1552 if(cmodel_shader_table[i].src == src_cmodel &&
1553 cmodel_shader_table[i].dst == dst_cmodel)
1555 shader = cmodel_shader_table[i].shader;
1560 // printf("Playback3D::convert_cmodel_sync %d %d %d shader=\n%s",
1562 // command->frame->get_color_model(),
1563 // command->dst_cmodel,
1568 //printf("Playback3D::convert_cmodel_sync %d\n", __LINE__);
1569 command->frame->bind_texture(0);
1570 unsigned int shader_id = -1;
1573 shader_id = VFrame::make_shader(0,
1576 glUseProgram(shader_id);
1577 glUniform1i(glGetUniformLocation(shader_id, "tex"), 0);
1580 command->frame->draw_texture();
1582 if(shader) glUseProgram(0);
1584 command->frame->set_opengl_state(VFrame::SCREEN);
1587 window->unlock_window();
1590 command->canvas->unlock_canvas();
1594 void Playback3D::do_fade(Canvas *canvas, VFrame *frame, float fade)
1596 Playback3DCommand command;
1597 command.command = Playback3DCommand::DO_FADE;
1598 command.canvas = canvas;
1599 command.frame = frame;
1600 command.alpha = fade;
1601 send_command(&command);
1604 void Playback3D::do_fade_sync(Playback3DCommand *command)
1607 command->canvas->lock_canvas("Playback3D::do_mask_sync");
1608 if(command->canvas->get_canvas())
1610 BC_WindowBase *window = command->canvas->get_canvas();
1611 window->lock_window("Playback3D::do_fade_sync");
1612 window->enable_opengl();
1614 switch(command->frame->get_opengl_state())
1617 command->frame->to_texture();
1620 case VFrame::SCREEN:
1621 // Read back from PBuffer
1622 // Bind context to pbuffer
1623 command->frame->enable_opengl();
1624 command->frame->screen_to_texture();
1629 command->frame->enable_opengl();
1630 command->frame->init_screen();
1631 command->frame->bind_texture(0);
1633 // glClearColor(0.0, 0.0, 0.0, 0.0);
1634 // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1635 glDisable(GL_BLEND);
1636 unsigned int frag_shader = 0;
1637 switch(command->frame->get_color_model())
1639 // For the alpha colormodels, the native function seems to multiply the
1640 // components by the alpha instead of just the alpha.
1644 frag_shader = VFrame::make_shader(0, fade_rgba_frag, 0);
1649 glBlendFunc(GL_SRC_ALPHA, GL_ZERO);
1650 glColor4f(command->alpha, command->alpha, command->alpha, 1);
1655 frag_shader = VFrame::make_shader(0, fade_yuv_frag, 0);
1662 glUseProgram(frag_shader);
1664 if((variable = glGetUniformLocation(frag_shader, "tex")) >= 0)
1665 glUniform1i(variable, 0);
1666 if((variable = glGetUniformLocation(frag_shader, "alpha")) >= 0)
1667 glUniform1f(variable, command->alpha);
1670 command->frame->draw_texture();
1671 command->frame->set_opengl_state(VFrame::SCREEN);
1678 glColor4f(1, 1, 1, 1);
1679 glDisable(GL_BLEND);
1681 window->unlock_window();
1683 command->canvas->unlock_canvas();
1697 int Playback3D::run_plugin(Canvas *canvas, PluginClient *client)
1699 Playback3DCommand command;
1700 command.command = Playback3DCommand::PLUGIN;
1701 command.canvas = canvas;
1702 command.plugin_client = client;
1703 return send_command(&command);
1706 void Playback3D::run_plugin_sync(Playback3DCommand *command)
1708 command->canvas->lock_canvas("Playback3D::run_plugin_sync");
1709 if(command->canvas->get_canvas())
1711 BC_WindowBase *window = command->canvas->get_canvas();
1712 window->lock_window("Playback3D::run_plugin_sync");
1713 window->enable_opengl();
1715 command->result = ((PluginVClient*)command->plugin_client)->handle_opengl();
1717 window->unlock_window();
1719 command->canvas->unlock_canvas();