1 #define GL_GLEXT_PROTOTYPES
4 #include "bcwindowbase.h"
11 #include "overlayframe.inc"
12 #include "playback3d.h"
13 #include "pluginclient.h"
14 #include "pluginvclient.h"
15 #include "transportque.inc"
18 #if defined(HAVE_CONFIG_H)
33 // These should be passed to VFrame::make_shader to construct shaders.
34 // Can't hard code sampler2D
36 static char *yuv_to_rgb_frag =
37 "uniform sampler2D tex;\n"
40 " vec3 yuv = vec3(texture2D(tex, gl_TexCoord[0].st));\n"
41 " yuv -= vec3(0, 0.5, 0.5);\n"
42 " const mat3 yuv_to_rgb_matrix = mat3(\n"
44 " 0, -0.34414, 1.77200, \n"
45 " 1.40200, -0.71414, 0);\n"
46 " gl_FragColor = vec4(yuv_to_rgb_matrix * yuv, 1);\n"
49 static char *yuva_to_rgba_frag =
50 "uniform sampler2D tex;\n"
53 " vec4 yuva = texture2D(tex, gl_TexCoord[0].st);\n"
54 " yuva.rgb -= vec3(0, 0.5, 0.5);\n"
55 " const mat3 yuv_to_rgb_matrix = mat3(\n"
57 " 0, -0.34414, 1.77200, \n"
58 " 1.40200, -0.71414, 0);\n"
59 " gl_FragColor = vec4(yuv_to_rgb_matrix * yuva.rgb, yuva.a);\n"
62 static char *blend_add_frag =
63 "uniform sampler2D tex2;\n"
64 "uniform vec2 tex2_dimensions;\n"
67 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
68 " vec3 opacity = vec3(gl_FragColor.a, gl_FragColor.a, gl_FragColor.a);\n"
69 " vec3 transparency = vec3(1.0, 1.0, 1.0) - opacity;\n"
70 " gl_FragColor.rgb += canvas.rgb;\n"
71 " gl_FragColor.rgb *= opacity;\n"
72 " gl_FragColor.rgb += canvas.rgb * transparency;\n"
73 " gl_FragColor.a = max(gl_FragColor.a, canvas.a);\n"
76 static char *blend_max_frag =
77 "uniform sampler2D tex2;\n"
78 "uniform vec2 tex2_dimensions;\n"
81 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
82 " vec3 opacity = vec3(gl_FragColor.a, gl_FragColor.a, gl_FragColor.a);\n"
83 " vec3 transparency = vec3(1.0, 1.0, 1.0) - opacity;\n"
84 " gl_FragColor.r = max(canvas.r, gl_FragColor.r);\n"
85 " gl_FragColor.g = max(canvas.g, gl_FragColor.g);\n"
86 " gl_FragColor.b = max(canvas.b, gl_FragColor.b);\n"
87 " gl_FragColor.rgb *= opacity;\n"
88 " gl_FragColor.rgb += canvas.rgb * transparency;\n"
89 " gl_FragColor.a = max(gl_FragColor.a, canvas.a);\n"
92 static char *blend_subtract_frag =
93 "uniform sampler2D tex2;\n"
94 "uniform vec2 tex2_dimensions;\n"
97 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
98 " vec3 opacity = vec3(gl_FragColor.a, gl_FragColor.a, gl_FragColor.a);\n"
99 " vec3 transparency = vec3(1.0, 1.0, 1.0) - opacity;\n"
100 " gl_FragColor.rgb = canvas.rgb - gl_FragColor.rgb;\n"
101 " gl_FragColor.rgb *= opacity;\n"
102 " gl_FragColor.rgb += canvas.rgb * transparency;\n"
103 " gl_FragColor.a = max(gl_FragColor.a, canvas.a);\n"
106 static char *blend_multiply_frag =
107 "uniform sampler2D tex2;\n"
108 "uniform vec2 tex2_dimensions;\n"
111 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
112 " vec3 opacity = vec3(gl_FragColor.a, gl_FragColor.a, gl_FragColor.a);\n"
113 " vec3 transparency = vec3(1.0, 1.0, 1.0) - opacity;\n"
114 " gl_FragColor.rgb *= canvas.rgb;\n"
115 " gl_FragColor.rgb *= opacity;\n"
116 " gl_FragColor.rgb += canvas.rgb * transparency;\n"
117 " gl_FragColor.a = max(gl_FragColor.a, canvas.a);\n"
120 static char *blend_divide_frag =
121 "uniform sampler2D tex2;\n"
122 "uniform vec2 tex2_dimensions;\n"
125 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
126 " vec3 opacity = vec3(gl_FragColor.a, gl_FragColor.a, gl_FragColor.a);\n"
127 " vec3 transparency = vec3(1.0, 1.0, 1.0) - opacity;\n"
128 " vec3 result = canvas.rgb / gl_FragColor.rgb;\n"
129 " if(!gl_FragColor.r) result.r = 1.0;\n"
130 " if(!gl_FragColor.g) result.g = 1.0;\n"
131 " if(!gl_FragColor.b) result.b = 1.0;\n"
132 " result *= opacity;\n"
133 " result += canvas.rgb * transparency;\n"
134 " gl_FragColor = vec4(result, max(gl_FragColor.a, canvas.a));\n"
137 static char *multiply_alpha_frag =
140 " gl_FragColor.rgb *= vec3(gl_FragColor.a, gl_FragColor.a, gl_FragColor.a);\n"
143 static char *read_texture_frag =
144 "uniform sampler2D tex;\n"
147 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
150 static char *multiply_mask4_frag =
151 "uniform sampler2D tex;\n"
152 "uniform sampler2D tex1;\n"
153 "uniform float scale;\n"
156 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
157 " gl_FragColor.a *= texture2D(tex1, gl_TexCoord[0].st / vec2(scale, scale)).r;\n"
160 static char *multiply_mask3_frag =
161 "uniform sampler2D tex;\n"
162 "uniform sampler2D tex1;\n"
163 "uniform float scale;\n"
164 "uniform bool is_yuv;\n"
167 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
168 " float a = texture2D(tex1, gl_TexCoord[0].st / vec2(scale, scale)).r;\n"
169 " gl_FragColor.rgb *= vec3(a, a, a);\n"
172 static char *multiply_yuvmask3_frag =
173 "uniform sampler2D tex;\n"
174 "uniform sampler2D tex1;\n"
175 "uniform float scale;\n"
178 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
179 " float a = texture2D(tex1, gl_TexCoord[0].st / vec2(scale, scale)).r;\n"
180 " gl_FragColor.gb -= vec2(0.5, 0.5);\n"
181 " gl_FragColor.rgb *= vec3(a, a, a);\n"
182 " gl_FragColor.gb += vec2(0.5, 0.5);\n"
185 static char *fade_rgba_frag =
186 "uniform sampler2D tex;\n"
187 "uniform float alpha;\n"
190 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
191 " gl_FragColor.a *= alpha;\n"
194 static char *fade_yuv_frag =
195 "uniform sampler2D tex;\n"
196 "uniform float alpha;\n"
199 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
200 " gl_FragColor.r *= alpha;\n"
201 " gl_FragColor.gb -= vec2(0.5, 0.5);\n"
202 " gl_FragColor.g *= alpha;\n"
203 " gl_FragColor.b *= alpha;\n"
204 " gl_FragColor.gb += vec2(0.5, 0.5);\n"
214 Playback3DCommand::Playback3DCommand()
215 : BC_SynchronousCommand()
220 void Playback3DCommand::copy_from(BC_SynchronousCommand *command)
222 Playback3DCommand *ptr = (Playback3DCommand*)command;
223 this->canvas = ptr->canvas;
224 this->is_cleared = ptr->is_cleared;
226 this->in_x1 = ptr->in_x1;
227 this->in_y1 = ptr->in_y1;
228 this->in_x2 = ptr->in_x2;
229 this->in_y2 = ptr->in_y2;
230 this->out_x1 = ptr->out_x1;
231 this->out_y1 = ptr->out_y1;
232 this->out_x2 = ptr->out_x2;
233 this->out_y2 = ptr->out_y2;
234 this->alpha = ptr->alpha;
235 this->mode = ptr->mode;
236 this->interpolation_type = ptr->interpolation_type;
238 this->input = ptr->input;
239 this->start_position_project = ptr->start_position_project;
240 this->keyframe_set = ptr->keyframe_set;
241 this->keyframe = ptr->keyframe;
242 this->default_auto = ptr->default_auto;
243 this->plugin_client = ptr->plugin_client;
244 this->want_texture = ptr->want_texture;
246 BC_SynchronousCommand::copy_from(command);
252 Playback3D::Playback3D(MWindow *mwindow)
255 this->mwindow = mwindow;
259 Playback3D::~Playback3D()
266 BC_SynchronousCommand* Playback3D::new_command()
268 return new Playback3DCommand;
273 void Playback3D::handle_command(BC_SynchronousCommand *command)
275 //printf("Playback3D::handle_command 1 %d\n", command->command);
276 switch(command->command)
278 case Playback3DCommand::WRITE_BUFFER:
279 write_buffer_sync((Playback3DCommand*)command);
282 case Playback3DCommand::CLEAR_OUTPUT:
283 clear_output_sync((Playback3DCommand*)command);
286 case Playback3DCommand::CLEAR_INPUT:
287 clear_input_sync((Playback3DCommand*)command);
290 case Playback3DCommand::DO_CAMERA:
291 do_camera_sync((Playback3DCommand*)command);
294 case Playback3DCommand::OVERLAY:
295 overlay_sync((Playback3DCommand*)command);
298 case Playback3DCommand::DO_FADE:
299 do_fade_sync((Playback3DCommand*)command);
302 case Playback3DCommand::DO_MASK:
303 do_mask_sync((Playback3DCommand*)command);
306 case Playback3DCommand::PLUGIN:
307 run_plugin_sync((Playback3DCommand*)command);
310 case Playback3DCommand::COPY_FROM:
311 copy_from_sync((Playback3DCommand*)command);
314 // case Playback3DCommand::DRAW_REFRESH:
315 // draw_refresh_sync((Playback3DCommand*)command);
318 //printf("Playback3D::handle_command 10\n");
324 void Playback3D::copy_from(Canvas *canvas,
329 Playback3DCommand command;
330 command.command = Playback3DCommand::COPY_FROM;
331 command.canvas = canvas;
334 command.want_texture = want_texture;
335 send_command(&command);
338 void Playback3D::copy_from_sync(Playback3DCommand *command)
341 command->canvas->lock_canvas("Playback3D::draw_refresh_sync");
342 BC_WindowBase *window = command->canvas->get_canvas();
345 window->lock_window("Playback3D:draw_refresh_sync");
346 window->enable_opengl();
348 if(command->input->get_opengl_state() == VFrame::SCREEN &&
349 command->input->get_w() == command->frame->get_w() &&
350 command->input->get_h() == command->frame->get_h())
352 // printf("Playback3D::copy_from_sync 1 %d %d %d %d %d\n",
353 // command->input->get_w(),
354 // command->input->get_h(),
355 // command->frame->get_w(),
356 // command->frame->get_h(),
357 // command->frame->get_color_model());
358 int w = command->input->get_w();
359 int h = command->input->get_h();
360 // With NVidia at least,
361 if(command->input->get_w() % 4)
363 printf("Playback3D::copy_from_sync: w=%d not supported because it is not divisible by 4.\n", w);
367 if(command->want_texture)
369 //printf("Playback3D::copy_from_sync 1 dst=%p src=%p\n", command->frame, command->input);
370 // Screen_to_texture requires the source pbuffer enabled.
371 command->input->enable_opengl();
372 command->frame->screen_to_texture();
373 command->frame->set_opengl_state(VFrame::TEXTURE);
378 command->input->enable_opengl();
379 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
383 command->input->get_h(),
386 command->frame->get_rows()[0]);
387 command->frame->flip_vert();
388 command->frame->set_opengl_state(VFrame::RAM);
393 printf("Playback3D::copy_from_sync: invalid formats opengl_state=%d %dx%d -> %dx%d\n",
394 command->input->get_opengl_state(),
395 command->input->get_w(),
396 command->input->get_h(),
397 command->frame->get_w(),
398 command->frame->get_h());
401 window->unlock_window();
403 command->canvas->unlock_canvas();
410 // void Playback3D::draw_refresh(Canvas *canvas,
421 // Playback3DCommand command;
422 // command.command = Playback3DCommand::DRAW_REFRESH;
423 // command.canvas = canvas;
424 // command.frame = frame;
425 // command.in_x1 = in_x1;
426 // command.in_y1 = in_y1;
427 // command.in_x2 = in_x2;
428 // command.in_y2 = in_y2;
429 // command.out_x1 = out_x1;
430 // command.out_y1 = out_y1;
431 // command.out_x2 = out_x2;
432 // command.out_y2 = out_y2;
433 // send_command(&command);
436 // void Playback3D::draw_refresh_sync(Playback3DCommand *command)
438 // command->canvas->lock_canvas("Playback3D::draw_refresh_sync");
439 // BC_WindowBase *window = command->canvas->get_canvas();
442 // window->lock_window("Playback3D:draw_refresh_sync");
443 // window->enable_opengl();
445 // // Read output pbuffer back to RAM in project colormodel
446 // // RGB 8bit is fastest for OpenGL to read back.
447 // command->frame->reallocate(0,
451 // command->frame->get_w(),
452 // command->frame->get_h(),
455 // command->frame->to_ram();
457 // window->clear_box(0,
461 // window->draw_vframe(command->frame,
462 // (int)command->out_x1,
463 // (int)command->out_y1,
464 // (int)(command->out_x2 - command->out_x1),
465 // (int)(command->out_y2 - command->out_y1),
466 // (int)command->in_x1,
467 // (int)command->in_y1,
468 // (int)(command->in_x2 - command->in_x1),
469 // (int)(command->in_y2 - command->in_y1),
472 // window->unlock_window();
474 // command->canvas->unlock_canvas();
481 void Playback3D::write_buffer(Canvas *canvas,
493 Playback3DCommand command;
494 command.command = Playback3DCommand::WRITE_BUFFER;
495 command.canvas = canvas;
496 command.frame = frame;
497 command.in_x1 = in_x1;
498 command.in_y1 = in_y1;
499 command.in_x2 = in_x2;
500 command.in_y2 = in_y2;
501 command.out_x1 = out_x1;
502 command.out_y1 = out_y1;
503 command.out_x2 = out_x2;
504 command.out_y2 = out_y2;
505 command.is_cleared = is_cleared;
506 send_command(&command);
510 void Playback3D::write_buffer_sync(Playback3DCommand *command)
512 command->canvas->lock_canvas("Playback3D::write_buffer_sync");
513 if(command->canvas->get_canvas())
515 BC_WindowBase *window = command->canvas->get_canvas();
516 window->lock_window("Playback3D::write_buffer_sync");
517 // Update hidden cursor
518 window->update_video_cursor();
519 // Make sure OpenGL is enabled first.
520 window->enable_opengl();
523 //printf("Playback3D::write_buffer_sync 1 %d\n", window->get_id());
524 switch(command->frame->get_opengl_state())
526 // Upload texture and composite to screen
528 command->frame->to_texture();
529 draw_output(command);
531 // Composite texture to screen and swap buffer
532 case VFrame::TEXTURE:
533 draw_output(command);
537 window->flip_opengl();
540 printf("Playback3D::write_buffer_sync unknown state\n");
543 window->unlock_window();
546 command->canvas->unlock_canvas();
551 void Playback3D::draw_output(Playback3DCommand *command)
554 int texture_id = command->frame->get_texture_id();
555 BC_WindowBase *window = command->canvas->get_canvas();
557 // printf("Playback3D::draw_output 1 texture_id=%d window=%p\n",
559 // command->canvas->get_canvas());
564 // If virtual console is being used, everything in this function has
565 // already been done except the page flip.
568 canvas_w = window->get_w();
569 canvas_h = window->get_h();
570 VFrame::init_screen(canvas_w, canvas_h);
572 if(!command->is_cleared)
574 // If we get here, the virtual console was not used.
579 // Undo any previous shader settings
580 command->frame->bind_texture(0);
585 // Convert colormodel
586 unsigned int frag_shader = 0;
587 switch(command->frame->get_color_model())
590 frag_shader = VFrame::make_shader(0,
596 frag_shader = VFrame::make_shader(0,
605 glUseProgram(frag_shader);
606 int variable = glGetUniformLocation(frag_shader, "tex");
607 // Set texture unit of the texture
608 glUniform1i(variable, 0);
611 if(cmodel_components(command->frame->get_color_model()) == 4)
614 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
617 command->frame->draw_texture(command->in_x1,
628 // printf("Playback3D::draw_output 2 %f,%f %f,%f -> %f,%f %f,%f\n",
640 command->canvas->get_canvas()->flip_opengl();
647 void Playback3D::init_frame(Playback3DCommand *command)
650 canvas_w = command->canvas->get_canvas()->get_w();
651 canvas_h = command->canvas->get_canvas()->get_h();
653 glClearColor(0.0, 0.0, 0.0, 0.0);
654 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
659 void Playback3D::clear_output(Canvas *canvas, VFrame *output)
661 Playback3DCommand command;
662 command.command = Playback3DCommand::CLEAR_OUTPUT;
663 command.canvas = canvas;
664 command.frame = output;
665 send_command(&command);
668 void Playback3D::clear_output_sync(Playback3DCommand *command)
670 command->canvas->lock_canvas("Playback3D::clear_output_sync");
671 if(command->canvas->get_canvas())
673 command->canvas->get_canvas()->lock_window("Playback3D::clear_output_sync");
674 // If we get here, the virtual console is being used.
675 command->canvas->get_canvas()->enable_opengl();
677 // Using pbuffer for refresh frame.
680 command->frame->enable_opengl();
685 command->canvas->get_canvas()->unlock_window();
687 command->canvas->unlock_canvas();
691 void Playback3D::clear_input(Canvas *canvas, VFrame *frame)
693 Playback3DCommand command;
694 command.command = Playback3DCommand::CLEAR_INPUT;
695 command.canvas = canvas;
696 command.frame = frame;
697 send_command(&command);
700 void Playback3D::clear_input_sync(Playback3DCommand *command)
702 command->canvas->lock_canvas("Playback3D::clear_output_sync");
703 if(command->canvas->get_canvas())
705 command->canvas->get_canvas()->lock_window("Playback3D::clear_output_sync");
706 command->canvas->get_canvas()->enable_opengl();
707 command->frame->enable_opengl();
708 command->frame->clear_pbuffer();
709 command->frame->set_opengl_state(VFrame::SCREEN);
710 command->canvas->get_canvas()->unlock_window();
712 command->canvas->unlock_canvas();
715 void Playback3D::do_camera(Canvas *canvas,
727 Playback3DCommand command;
728 command.command = Playback3DCommand::DO_CAMERA;
729 command.canvas = canvas;
730 command.input = input;
731 command.frame = output;
732 command.in_x1 = in_x1;
733 command.in_y1 = in_y1;
734 command.in_x2 = in_x2;
735 command.in_y2 = in_y2;
736 command.out_x1 = out_x1;
737 command.out_y1 = out_y1;
738 command.out_x2 = out_x2;
739 command.out_y2 = out_y2;
740 send_command(&command);
743 void Playback3D::do_camera_sync(Playback3DCommand *command)
745 command->canvas->lock_canvas("Playback3D::do_camera_sync");
746 if(command->canvas->get_canvas())
748 command->canvas->get_canvas()->lock_window("Playback3D::clear_output_sync");
749 command->canvas->get_canvas()->enable_opengl();
751 command->input->to_texture();
752 command->frame->enable_opengl();
753 command->frame->init_screen();
754 command->frame->clear_pbuffer();
756 command->input->bind_texture(0);
757 // Must call draw_texture in input frame to get the texture coordinates right.
759 // printf("Playback3D::do_camera_sync 1 %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f\n",
765 // (float)command->input->get_h() - command->out_y1,
767 // (float)command->input->get_h() - command->out_y2);
768 command->input->draw_texture(
774 (float)command->frame->get_h() - command->out_y1,
776 (float)command->frame->get_h() - command->out_y2);
779 command->frame->set_opengl_state(VFrame::SCREEN);
780 command->canvas->get_canvas()->unlock_window();
782 command->canvas->unlock_canvas();
785 void Playback3D::overlay(Canvas *canvas,
795 float alpha, // 0 - 1
797 int interpolation_type,
800 Playback3DCommand command;
801 command.command = Playback3DCommand::OVERLAY;
802 command.canvas = canvas;
803 command.frame = output;
804 command.input = input;
805 command.in_x1 = in_x1;
806 command.in_y1 = in_y1;
807 command.in_x2 = in_x2;
808 command.in_y2 = in_y2;
809 command.out_x1 = out_x1;
810 command.out_y1 = out_y1;
811 command.out_x2 = out_x2;
812 command.out_y2 = out_y2;
813 command.alpha = alpha;
815 command.interpolation_type = interpolation_type;
816 send_command(&command);
819 void Playback3D::overlay_sync(Playback3DCommand *command)
822 command->canvas->lock_canvas("Playback3D::overlay_sync");
823 if(command->canvas->get_canvas())
825 BC_WindowBase *window = command->canvas->get_canvas();
826 window->lock_window("Playback3D::overlay_sync");
827 // Make sure OpenGL is enabled first.
828 window->enable_opengl();
830 window->update_video_cursor();
836 command->frame->enable_opengl();
837 command->frame->set_opengl_state(VFrame::SCREEN);
838 canvas_w = command->frame->get_w();
839 canvas_h = command->frame->get_h();
843 canvas_w = window->get_w();
844 canvas_h = window->get_h();
847 glColor4f(1, 1, 1, 1);
849 //printf("Playback3D::overlay_sync 1 %d\n", command->input->get_opengl_state());
850 switch(command->input->get_opengl_state())
852 // Upload texture and composite to screen
854 command->input->to_texture();
856 // Just composite texture to screen
857 case VFrame::TEXTURE:
859 // read from PBuffer to texture, then composite texture to screen
861 command->input->enable_opengl();
862 command->input->screen_to_texture();
864 command->frame->enable_opengl();
866 window->enable_opengl();
869 printf("Playback3D::overlay_sync unknown state\n");
874 char *shader_stack[3] = { 0, 0, 0 };
875 int total_shaders = 0;
877 VFrame::init_screen(canvas_w, canvas_h);
880 command->input->bind_texture(0);
883 // Convert colormodel.
884 switch(command->input->get_color_model())
887 shader_stack[total_shaders++] = yuv_to_rgb_frag;
890 shader_stack[total_shaders++] = yuva_to_rgba_frag;
894 // Change blend operation
895 switch(command->mode)
897 case TRANSFER_NORMAL:
899 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
902 case TRANSFER_REPLACE:
903 // This requires overlaying an alpha multiplied image on a black screen.
905 if(command->input->get_texture_components() == 4)
907 if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag;
908 shader_stack[total_shaders++] = multiply_alpha_frag;
912 // To do these operations, we need to copy the input buffer to a texture
913 // and blend 2 textures in another shader
914 case TRANSFER_ADDITION:
915 enable_overlay_texture(command);
916 if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag;
917 shader_stack[total_shaders++] = blend_add_frag;
919 case TRANSFER_SUBTRACT:
920 enable_overlay_texture(command);
921 if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag;
922 shader_stack[total_shaders++] = blend_subtract_frag;
924 case TRANSFER_MULTIPLY:
925 enable_overlay_texture(command);
926 if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag;
927 shader_stack[total_shaders++] = blend_multiply_frag;
930 enable_overlay_texture(command);
931 if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag;
932 shader_stack[total_shaders++] = blend_max_frag;
934 case TRANSFER_DIVIDE:
935 enable_overlay_texture(command);
936 if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag;
937 shader_stack[total_shaders++] = blend_divide_frag;
941 unsigned int frag_shader = 0;
944 frag_shader = VFrame::make_shader(0,
949 glUseProgram(frag_shader);
952 // Set texture unit of the texture
953 glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0);
954 // Set texture unit of the temp texture
955 glUniform1i(glGetUniformLocation(frag_shader, "tex2"), 1);
956 // Set dimensions of the temp texture
958 glUniform2f(glGetUniformLocation(frag_shader, "tex2_dimensions"),
959 (float)temp_texture->get_texture_w(),
960 (float)temp_texture->get_texture_h());
970 // printf("Playback3D::overlay_sync %f %f %f %f %f %f %f %f\n",
983 command->input->draw_texture(command->in_x1,
997 // Delete temp texture
1000 delete temp_texture;
1002 glActiveTexture(GL_TEXTURE1);
1003 glDisable(GL_TEXTURE_2D);
1005 glActiveTexture(GL_TEXTURE0);
1006 glDisable(GL_TEXTURE_2D);
1010 window->unlock_window();
1012 command->canvas->unlock_canvas();
1017 void Playback3D::enable_overlay_texture(Playback3DCommand *command)
1020 glDisable(GL_BLEND);
1022 glActiveTexture(GL_TEXTURE1);
1023 BC_Texture::new_texture(&temp_texture,
1026 command->input->get_color_model());
1027 temp_texture->bind(1);
1029 // Read canvas into texture
1030 glReadBuffer(GL_BACK);
1031 glCopyTexSubImage2D(GL_TEXTURE_2D,
1043 void Playback3D::do_mask(Canvas *canvas,
1045 int64_t start_position_project,
1046 MaskAutos *keyframe_set,
1048 MaskAuto *default_auto)
1050 Playback3DCommand command;
1051 command.command = Playback3DCommand::DO_MASK;
1052 command.canvas = canvas;
1053 command.frame = output;
1054 command.start_position_project = start_position_project;
1055 command.keyframe_set = keyframe_set;
1056 command.keyframe = keyframe;
1057 command.default_auto = default_auto;
1059 send_command(&command);
1065 static void combine_callback(GLdouble coords[3],
1066 GLdouble *vertex_data[4],
1072 vertex = (GLdouble *) malloc(6 * sizeof(GLdouble));
1073 vertex[0] = coords[0];
1074 vertex[1] = coords[1];
1075 vertex[2] = coords[2];
1077 for (int i = 3; i < 6; i++)
1079 vertex[i] = weight[0] * vertex_data[0][i] +
1080 weight[1] * vertex_data[1][i] +
1081 weight[2] * vertex_data[2][i] +
1082 weight[3] * vertex_data[3][i];
1090 void Playback3D::do_mask_sync(Playback3DCommand *command)
1093 command->canvas->lock_canvas("Playback3D::do_mask_sync");
1094 if(command->canvas->get_canvas())
1096 BC_WindowBase *window = command->canvas->get_canvas();
1097 window->lock_window("Playback3D::do_mask_sync");
1098 window->enable_opengl();
1100 switch(command->frame->get_opengl_state())
1103 // Time to upload to the texture
1104 command->frame->to_texture();
1107 case VFrame::SCREEN:
1108 // Read back from PBuffer
1109 // Bind context to pbuffer
1110 command->frame->enable_opengl();
1111 command->frame->screen_to_texture();
1117 // Create PBuffer and draw the mask on it
1118 command->frame->enable_opengl();
1120 // Initialize coordinate system
1121 int w = command->frame->get_w();
1122 int h = command->frame->get_h();
1123 command->frame->init_screen();
1126 glDisable(GL_TEXTURE_2D);
1127 if(command->default_auto->mode == MASK_MULTIPLY_ALPHA)
1129 glClearColor(0.0, 0.0, 0.0, 0.0);
1130 glColor4f((float)command->keyframe->value / 100,
1131 (float)command->keyframe->value / 100,
1132 (float)command->keyframe->value / 100,
1137 glClearColor(1.0, 1.0, 1.0, 1.0);
1138 glColor4f((float)1.0 - (float)command->keyframe->value / 100,
1139 (float)1.0 - (float)command->keyframe->value / 100,
1140 (float)1.0 - (float)command->keyframe->value / 100,
1143 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1146 // Draw mask with scaling to simulate feathering
1147 GLUtesselator *tesselator = gluNewTess();
1148 gluTessProperty(tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);
1149 gluTessCallback(tesselator, GLU_TESS_VERTEX, (GLvoid (*) ( )) &glVertex3dv);
1150 gluTessCallback(tesselator, GLU_TESS_BEGIN, (GLvoid (*) ( )) &glBegin);
1151 gluTessCallback(tesselator, GLU_TESS_END, (GLvoid (*) ( )) &glEnd);
1152 gluTessCallback(tesselator, GLU_TESS_COMBINE, (GLvoid (*) ( ))&combine_callback);
1155 // Draw every submask as a new polygon
1156 int total_submasks = command->keyframe_set->total_submasks(
1157 command->start_position_project,
1159 float scale = command->keyframe->feather + 1;
1160 int display_list = glGenLists(1);
1161 glNewList(display_list, GL_COMPILE);
1162 for(int k = 0; k < total_submasks; k++)
1164 gluTessBeginPolygon(tesselator, NULL);
1165 gluTessBeginContour(tesselator);
1166 ArrayList<MaskPoint*> *points = new ArrayList<MaskPoint*>;
1167 command->keyframe_set->get_points(points,
1169 command->start_position_project,
1172 int first_point = 0;
1173 // Need to tabulate every vertex in persistent memory because
1174 // gluTessVertex doesn't copy them.
1175 ArrayList<GLdouble*> coords;
1176 for(int i = 0; i < points->total; i++)
1178 MaskPoint *point1 = points->values[i];
1179 MaskPoint *point2 = (i >= points->total - 1) ?
1181 points->values[i + 1];
1184 #define SQR(x) ((x) * (x))
1187 // This is very slow.
1189 int segments = (int)(sqrt(SQR(point1->x - point2->x) + SQR(point1->y - point2->y)));
1190 if(point1->control_x2 == 0 &&
1191 point1->control_y2 == 0 &&
1192 point2->control_x1 == 0 &&
1193 point2->control_y1 == 0)
1196 float x0 = point1->x;
1197 float y0 = point1->y;
1198 float x1 = point1->x + point1->control_x2;
1199 float y1 = point1->y + point1->control_y2;
1200 float x2 = point2->x + point2->control_x1;
1201 float y2 = point2->y + point2->control_y1;
1202 float x3 = point2->x;
1203 float y3 = point2->y;
1205 for(int j = 0; j <= segments; j++)
1207 float t = (float)j / segments;
1208 float tpow2 = t * t;
1209 float tpow3 = t * t * t;
1211 float invtpow2 = invt * invt;
1212 float invtpow3 = invt * invt * invt;
1215 + 3 * t * invtpow2 * x1
1216 + 3 * tpow2 * invt * x2
1219 + 3 * t * invtpow2 * y1
1220 + 3 * tpow2 * invt * y2
1224 if(j > 0 || first_point)
1226 GLdouble *coord = new GLdouble[3];
1227 coord[0] = x / scale;
1228 coord[1] = -h + y / scale;
1230 coords.append(coord);
1236 // Now that we know the total vertices, send them to GLU
1237 for(int i = 0; i < coords.total; i++)
1238 gluTessVertex(tesselator, coords.values[i], coords.values[i]);
1240 gluTessEndContour(tesselator);
1241 gluTessEndPolygon(tesselator);
1242 points->remove_all_objects();
1244 coords.remove_all_objects();
1247 glCallList(display_list);
1248 glDeleteLists(display_list, 1);
1250 glColor4f(1, 1, 1, 1);
1253 // Read mask into temporary texture.
1254 // For feathering, just read the part of the screen after the downscaling.
1257 float w_scaled = w / scale;
1258 float h_scaled = h / scale;
1259 // Don't vary the texture size according to scaling because that
1260 // would waste memory.
1261 // This enables and binds the temporary texture.
1262 glActiveTexture(GL_TEXTURE1);
1263 BC_Texture::new_texture(&temp_texture,
1266 command->frame->get_color_model());
1267 temp_texture->bind(1);
1268 glReadBuffer(GL_BACK);
1270 // Need to add extra size to fill in the bottom right
1271 glCopyTexSubImage2D(GL_TEXTURE_2D,
1277 (int)MIN(w_scaled + 2, w),
1278 (int)MIN(h_scaled + 2, h));
1280 command->frame->bind_texture(0);
1283 // For feathered masks, use a shader to multiply.
1284 // For unfeathered masks, we could use a stencil buffer
1285 // for further optimization but we also need a YUV algorithm.
1286 unsigned int frag_shader = 0;
1287 switch(temp_texture->get_texture_components())
1290 if(command->frame->get_color_model() == BC_YUV888)
1291 frag_shader = VFrame::make_shader(0,
1292 multiply_yuvmask3_frag,
1295 frag_shader = VFrame::make_shader(0,
1296 multiply_mask3_frag,
1300 frag_shader = VFrame::make_shader(0,
1301 multiply_mask4_frag,
1309 glUseProgram(frag_shader);
1310 if((variable = glGetUniformLocation(frag_shader, "tex")) >= 0)
1311 glUniform1i(variable, 0);
1312 if((variable = glGetUniformLocation(frag_shader, "tex1")) >= 0)
1313 glUniform1i(variable, 1);
1314 if((variable = glGetUniformLocation(frag_shader, "scale")) >= 0)
1315 glUniform1f(variable, scale);
1320 // Write texture to PBuffer with multiply and scaling for feather.
1323 command->frame->draw_texture(0, 0, w, h, 0, 0, w, h);
1324 command->frame->set_opengl_state(VFrame::SCREEN);
1327 // Disable temp texture
1330 glActiveTexture(GL_TEXTURE1);
1331 glDisable(GL_TEXTURE_2D);
1332 delete temp_texture;
1335 glActiveTexture(GL_TEXTURE0);
1336 glDisable(GL_TEXTURE_2D);
1339 window->enable_opengl();
1340 window->unlock_window();
1342 command->canvas->unlock_canvas();
1357 void Playback3D::do_fade(Canvas *canvas, VFrame *frame, float fade)
1359 Playback3DCommand command;
1360 command.command = Playback3DCommand::DO_FADE;
1361 command.canvas = canvas;
1362 command.frame = frame;
1363 command.alpha = fade;
1364 send_command(&command);
1367 void Playback3D::do_fade_sync(Playback3DCommand *command)
1370 command->canvas->lock_canvas("Playback3D::do_mask_sync");
1371 if(command->canvas->get_canvas())
1373 BC_WindowBase *window = command->canvas->get_canvas();
1374 window->lock_window("Playback3D::do_fade_sync");
1375 window->enable_opengl();
1377 switch(command->frame->get_opengl_state())
1380 command->frame->to_texture();
1383 case VFrame::SCREEN:
1384 // Read back from PBuffer
1385 // Bind context to pbuffer
1386 command->frame->enable_opengl();
1387 command->frame->screen_to_texture();
1392 command->frame->enable_opengl();
1393 command->frame->init_screen();
1394 command->frame->bind_texture(0);
1396 // glClearColor(0.0, 0.0, 0.0, 0.0);
1397 // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1398 glDisable(GL_BLEND);
1399 unsigned int frag_shader = 0;
1400 switch(command->frame->get_color_model())
1402 // For the alpha colormodels, the native function seems to multiply the
1403 // components by the alpha instead of just the alpha.
1407 frag_shader = VFrame::make_shader(0,
1414 glBlendFunc(GL_SRC_ALPHA, GL_ZERO);
1415 glColor4f(command->alpha, command->alpha, command->alpha, 1);
1420 frag_shader = VFrame::make_shader(0,
1429 glUseProgram(frag_shader);
1431 if((variable = glGetUniformLocation(frag_shader, "tex")) >= 0)
1432 glUniform1i(variable, 0);
1433 if((variable = glGetUniformLocation(frag_shader, "alpha")) >= 0)
1434 glUniform1f(variable, command->alpha);
1437 command->frame->draw_texture();
1438 command->frame->set_opengl_state(VFrame::SCREEN);
1445 glColor4f(1, 1, 1, 1);
1446 glDisable(GL_BLEND);
1448 window->unlock_window();
1450 command->canvas->unlock_canvas();
1464 int Playback3D::run_plugin(Canvas *canvas, PluginClient *client)
1466 Playback3DCommand command;
1467 command.command = Playback3DCommand::PLUGIN;
1468 command.canvas = canvas;
1469 command.plugin_client = client;
1470 return send_command(&command);
1473 void Playback3D::run_plugin_sync(Playback3DCommand *command)
1475 command->canvas->lock_canvas("Playback3D::run_plugin_sync");
1476 if(command->canvas->get_canvas())
1478 BC_WindowBase *window = command->canvas->get_canvas();
1479 window->lock_window("Playback3D::run_plugin_sync");
1480 window->enable_opengl();
1482 command->result = ((PluginVClient*)command->plugin_client)->handle_opengl();
1484 window->unlock_window();
1486 command->canvas->unlock_canvas();