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 struct Vertex : ListItem<Vertex>
1069 // this list is only used from the main thread, no locking needed
1070 // this must be a list so that pointers to allocated entries remain valid
1071 // when new entries are added
1072 static List<Vertex> *vertex_cache = 0;
1074 static void combine_callback(GLdouble coords[3],
1075 GLdouble *vertex_data[4],
1079 // can't use malloc here; GLU doesn't delete the memory for us!
1080 Vertex* vertex = vertex_cache->append();
1081 vertex->c[0] = coords[0];
1082 vertex->c[1] = coords[1];
1083 vertex->c[2] = coords[2];
1084 // we don't need to interpolate anything
1086 *dataOut = &vertex->c[0];
1091 void Playback3D::do_mask_sync(Playback3DCommand *command)
1094 command->canvas->lock_canvas("Playback3D::do_mask_sync");
1095 if(command->canvas->get_canvas())
1097 BC_WindowBase *window = command->canvas->get_canvas();
1098 window->lock_window("Playback3D::do_mask_sync");
1099 window->enable_opengl();
1101 switch(command->frame->get_opengl_state())
1104 // Time to upload to the texture
1105 command->frame->to_texture();
1108 case VFrame::SCREEN:
1109 // Read back from PBuffer
1110 // Bind context to pbuffer
1111 command->frame->enable_opengl();
1112 command->frame->screen_to_texture();
1118 // Create PBuffer and draw the mask on it
1119 command->frame->enable_opengl();
1121 // Initialize coordinate system
1122 int w = command->frame->get_w();
1123 int h = command->frame->get_h();
1124 command->frame->init_screen();
1127 glDisable(GL_TEXTURE_2D);
1128 if(command->default_auto->mode == MASK_MULTIPLY_ALPHA)
1130 glClearColor(0.0, 0.0, 0.0, 0.0);
1131 glColor4f((float)command->keyframe->value / 100,
1132 (float)command->keyframe->value / 100,
1133 (float)command->keyframe->value / 100,
1138 glClearColor(1.0, 1.0, 1.0, 1.0);
1139 glColor4f((float)1.0 - (float)command->keyframe->value / 100,
1140 (float)1.0 - (float)command->keyframe->value / 100,
1141 (float)1.0 - (float)command->keyframe->value / 100,
1144 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1147 // Draw mask with scaling to simulate feathering
1148 GLUtesselator *tesselator = gluNewTess();
1149 gluTessProperty(tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);
1150 gluTessCallback(tesselator, GLU_TESS_VERTEX, (GLvoid (*) ( )) &glVertex3dv);
1151 gluTessCallback(tesselator, GLU_TESS_BEGIN, (GLvoid (*) ( )) &glBegin);
1152 gluTessCallback(tesselator, GLU_TESS_END, (GLvoid (*) ( )) &glEnd);
1153 gluTessCallback(tesselator, GLU_TESS_COMBINE, (GLvoid (*) ( ))&combine_callback);
1155 vertex_cache = new List<Vertex>;
1158 // Draw every submask as a new polygon
1159 int total_submasks = command->keyframe_set->total_submasks(
1160 command->start_position_project,
1162 float scale = command->keyframe->feather + 1;
1163 int display_list = glGenLists(1);
1164 glNewList(display_list, GL_COMPILE);
1165 for(int k = 0; k < total_submasks; k++)
1167 gluTessBeginPolygon(tesselator, NULL);
1168 gluTessBeginContour(tesselator);
1169 ArrayList<MaskPoint*> *points = new ArrayList<MaskPoint*>;
1170 command->keyframe_set->get_points(points,
1172 command->start_position_project,
1175 int first_point = 0;
1176 // Need to tabulate every vertex in persistent memory because
1177 // gluTessVertex doesn't copy them.
1178 ArrayList<GLdouble*> coords;
1179 for(int i = 0; i < points->total; i++)
1181 MaskPoint *point1 = points->values[i];
1182 MaskPoint *point2 = (i >= points->total - 1) ?
1184 points->values[i + 1];
1189 if(point1->control_x2 == 0 &&
1190 point1->control_y2 == 0 &&
1191 point2->control_x1 == 0 &&
1192 point2->control_y1 == 0)
1195 float x0 = point1->x;
1196 float y0 = point1->y;
1197 float x1 = point1->x + point1->control_x2;
1198 float y1 = point1->y + point1->control_y2;
1199 float x2 = point2->x + point2->control_x1;
1200 float y2 = point2->y + point2->control_y1;
1201 float x3 = point2->x;
1202 float y3 = point2->y;
1204 // forward differencing bezier curves implementation taken from GPL code at
1205 // http://cvs.sourceforge.net/viewcvs.py/guliverkli/guliverkli/src/subtitles/Rasterizer.cpp?rev=1.3
1207 float cx3, cx2, cx1, cx0, cy3, cy2, cy1, cy0;
1214 cx3 = - x0 + 3*x1 - 3*x2 + x3;
1215 cx2 = 3*x0 - 6*x1 + 3*x2;
1219 cy3 = - y0 + 3*y1 - 3*y2 + y3;
1220 cy2 = 3*y0 - 6*y1 + 3*y2;
1224 // This equation is from Graphics Gems I.
1226 // The idea is that since we're approximating a cubic curve with lines,
1227 // any error we incur is due to the curvature of the line, which we can
1228 // estimate by calculating the maximum acceleration of the curve. For
1229 // a cubic, the acceleration (second derivative) is a line, meaning that
1230 // the absolute maximum acceleration must occur at either the beginning
1231 // (|c2|) or the end (|c2+c3|). Our bounds here are a little more
1232 // conservative than that, but that's okay.
1235 float maxaccel1 = fabs(2*cy2) + fabs(6*cy3);
1236 float maxaccel2 = fabs(2*cx2) + fabs(6*cx3);
1238 float maxaccel = maxaccel1 > maxaccel2 ? maxaccel1 : maxaccel2;
1241 if(maxaccel > 8.0) h = sqrt((8.0) / maxaccel);
1242 segments = int(1/h);
1245 for(int j = 0; j <= segments; j++)
1247 float t = (float)j / segments;
1248 x = cx0 + t*(cx1 + t*(cx2 + t*cx3));
1249 y = cy0 + t*(cy1 + t*(cy2 + t*cy3));
1251 if(j > 0 || first_point)
1253 GLdouble *coord = new GLdouble[3];
1254 coord[0] = x / scale;
1255 coord[1] = -h + y / scale;
1257 coords.append(coord);
1263 // Now that we know the total vertices, send them to GLU
1264 for(int i = 0; i < coords.total; i++)
1265 gluTessVertex(tesselator, coords.values[i], coords.values[i]);
1267 gluTessEndContour(tesselator);
1268 gluTessEndPolygon(tesselator);
1269 points->remove_all_objects();
1271 coords.remove_all_objects();
1274 glCallList(display_list);
1275 glDeleteLists(display_list, 1);
1276 gluDeleteTess(tesselator);
1278 delete vertex_cache;
1281 glColor4f(1, 1, 1, 1);
1284 // Read mask into temporary texture.
1285 // For feathering, just read the part of the screen after the downscaling.
1288 float w_scaled = w / scale;
1289 float h_scaled = h / scale;
1290 // Don't vary the texture size according to scaling because that
1291 // would waste memory.
1292 // This enables and binds the temporary texture.
1293 glActiveTexture(GL_TEXTURE1);
1294 BC_Texture::new_texture(&temp_texture,
1297 command->frame->get_color_model());
1298 temp_texture->bind(1);
1299 glReadBuffer(GL_BACK);
1301 // Need to add extra size to fill in the bottom right
1302 glCopyTexSubImage2D(GL_TEXTURE_2D,
1308 (int)MIN(w_scaled + 2, w),
1309 (int)MIN(h_scaled + 2, h));
1311 command->frame->bind_texture(0);
1314 // For feathered masks, use a shader to multiply.
1315 // For unfeathered masks, we could use a stencil buffer
1316 // for further optimization but we also need a YUV algorithm.
1317 unsigned int frag_shader = 0;
1318 switch(temp_texture->get_texture_components())
1321 if(command->frame->get_color_model() == BC_YUV888)
1322 frag_shader = VFrame::make_shader(0,
1323 multiply_yuvmask3_frag,
1326 frag_shader = VFrame::make_shader(0,
1327 multiply_mask3_frag,
1331 frag_shader = VFrame::make_shader(0,
1332 multiply_mask4_frag,
1340 glUseProgram(frag_shader);
1341 if((variable = glGetUniformLocation(frag_shader, "tex")) >= 0)
1342 glUniform1i(variable, 0);
1343 if((variable = glGetUniformLocation(frag_shader, "tex1")) >= 0)
1344 glUniform1i(variable, 1);
1345 if((variable = glGetUniformLocation(frag_shader, "scale")) >= 0)
1346 glUniform1f(variable, scale);
1351 // Write texture to PBuffer with multiply and scaling for feather.
1354 command->frame->draw_texture(0, 0, w, h, 0, 0, w, h);
1355 command->frame->set_opengl_state(VFrame::SCREEN);
1358 // Disable temp texture
1361 glActiveTexture(GL_TEXTURE1);
1362 glDisable(GL_TEXTURE_2D);
1363 delete temp_texture;
1366 glActiveTexture(GL_TEXTURE0);
1367 glDisable(GL_TEXTURE_2D);
1370 window->enable_opengl();
1371 window->unlock_window();
1373 command->canvas->unlock_canvas();
1388 void Playback3D::do_fade(Canvas *canvas, VFrame *frame, float fade)
1390 Playback3DCommand command;
1391 command.command = Playback3DCommand::DO_FADE;
1392 command.canvas = canvas;
1393 command.frame = frame;
1394 command.alpha = fade;
1395 send_command(&command);
1398 void Playback3D::do_fade_sync(Playback3DCommand *command)
1401 command->canvas->lock_canvas("Playback3D::do_mask_sync");
1402 if(command->canvas->get_canvas())
1404 BC_WindowBase *window = command->canvas->get_canvas();
1405 window->lock_window("Playback3D::do_fade_sync");
1406 window->enable_opengl();
1408 switch(command->frame->get_opengl_state())
1411 command->frame->to_texture();
1414 case VFrame::SCREEN:
1415 // Read back from PBuffer
1416 // Bind context to pbuffer
1417 command->frame->enable_opengl();
1418 command->frame->screen_to_texture();
1423 command->frame->enable_opengl();
1424 command->frame->init_screen();
1425 command->frame->bind_texture(0);
1427 // glClearColor(0.0, 0.0, 0.0, 0.0);
1428 // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1429 glDisable(GL_BLEND);
1430 unsigned int frag_shader = 0;
1431 switch(command->frame->get_color_model())
1433 // For the alpha colormodels, the native function seems to multiply the
1434 // components by the alpha instead of just the alpha.
1438 frag_shader = VFrame::make_shader(0,
1445 glBlendFunc(GL_SRC_ALPHA, GL_ZERO);
1446 glColor4f(command->alpha, command->alpha, command->alpha, 1);
1451 frag_shader = VFrame::make_shader(0,
1460 glUseProgram(frag_shader);
1462 if((variable = glGetUniformLocation(frag_shader, "tex")) >= 0)
1463 glUniform1i(variable, 0);
1464 if((variable = glGetUniformLocation(frag_shader, "alpha")) >= 0)
1465 glUniform1f(variable, command->alpha);
1468 command->frame->draw_texture();
1469 command->frame->set_opengl_state(VFrame::SCREEN);
1476 glColor4f(1, 1, 1, 1);
1477 glDisable(GL_BLEND);
1479 window->unlock_window();
1481 command->canvas->unlock_canvas();
1495 int Playback3D::run_plugin(Canvas *canvas, PluginClient *client)
1497 Playback3DCommand command;
1498 command.command = Playback3DCommand::PLUGIN;
1499 command.canvas = canvas;
1500 command.plugin_client = client;
1501 return send_command(&command);
1504 void Playback3D::run_plugin_sync(Playback3DCommand *command)
1506 command->canvas->lock_canvas("Playback3D::run_plugin_sync");
1507 if(command->canvas->get_canvas())
1509 BC_WindowBase *window = command->canvas->get_canvas();
1510 window->lock_window("Playback3D::run_plugin_sync");
1511 window->enable_opengl();
1513 command->result = ((PluginVClient*)command->plugin_client)->handle_opengl();
1515 window->unlock_window();
1517 command->canvas->unlock_canvas();
1524 // c-file-style: "linux"