00001 #define GL_GLEXT_PROTOTYPES
00002
00003 #include "bcsignals.h"
00004 #include "bcwindowbase.h"
00005 #include "canvas.h"
00006 #include "clip.h"
00007 #include "condition.h"
00008 #include "maskautos.h"
00009 #include "maskauto.h"
00010 #include "mutex.h"
00011 #include "overlayframe.inc"
00012 #include "playback3d.h"
00013 #include "pluginclient.h"
00014 #include "pluginvclient.h"
00015 #include "transportque.inc"
00016 #include "vframe.h"
00017
00018 #if defined(HAVE_CONFIG_H)
00019 #include "config.h"
00020 #endif
00021
00022 #ifdef HAVE_GL
00023 #include <GL/gl.h>
00024 #include <GL/glext.h>
00025 #include <GL/glu.h>
00026 #endif
00027
00028 #include <string.h>
00029 #include <unistd.h>
00030
00031
00032
00033
00034
00035
00036 static char *yuv_to_rgb_frag =
00037 "uniform sampler2D tex;\n"
00038 "void main()\n"
00039 "{\n"
00040 " vec3 yuv = vec3(texture2D(tex, gl_TexCoord[0].st));\n"
00041 " yuv -= vec3(0, 0.5, 0.5);\n"
00042 " const mat3 yuv_to_rgb_matrix = mat3(\n"
00043 " 1, 1, 1, \n"
00044 " 0, -0.34414, 1.77200, \n"
00045 " 1.40200, -0.71414, 0);\n"
00046 " gl_FragColor = vec4(yuv_to_rgb_matrix * yuv, 1);\n"
00047 "}\n";
00048
00049 static char *yuva_to_rgba_frag =
00050 "uniform sampler2D tex;\n"
00051 "void main()\n"
00052 "{\n"
00053 " vec4 yuva = texture2D(tex, gl_TexCoord[0].st);\n"
00054 " yuva.rgb -= vec3(0, 0.5, 0.5);\n"
00055 " const mat3 yuv_to_rgb_matrix = mat3(\n"
00056 " 1, 1, 1, \n"
00057 " 0, -0.34414, 1.77200, \n"
00058 " 1.40200, -0.71414, 0);\n"
00059 " gl_FragColor = vec4(yuv_to_rgb_matrix * yuva.rgb, yuva.a);\n"
00060 "}\n";
00061
00062 static char *blend_add_frag =
00063 "uniform sampler2D tex2;\n"
00064 "uniform vec2 tex2_dimensions;\n"
00065 "void main()\n"
00066 "{\n"
00067 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
00068 " vec3 opacity = vec3(gl_FragColor.a, gl_FragColor.a, gl_FragColor.a);\n"
00069 " vec3 transparency = vec3(1.0, 1.0, 1.0) - opacity;\n"
00070 " gl_FragColor.rgb += canvas.rgb;\n"
00071 " gl_FragColor.rgb *= opacity;\n"
00072 " gl_FragColor.rgb += canvas.rgb * transparency;\n"
00073 " gl_FragColor.a = max(gl_FragColor.a, canvas.a);\n"
00074 "}\n";
00075
00076 static char *blend_max_frag =
00077 "uniform sampler2D tex2;\n"
00078 "uniform vec2 tex2_dimensions;\n"
00079 "void main()\n"
00080 "{\n"
00081 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
00082 " vec3 opacity = vec3(gl_FragColor.a, gl_FragColor.a, gl_FragColor.a);\n"
00083 " vec3 transparency = vec3(1.0, 1.0, 1.0) - opacity;\n"
00084 " gl_FragColor.r = max(canvas.r, gl_FragColor.r);\n"
00085 " gl_FragColor.g = max(canvas.g, gl_FragColor.g);\n"
00086 " gl_FragColor.b = max(canvas.b, gl_FragColor.b);\n"
00087 " gl_FragColor.rgb *= opacity;\n"
00088 " gl_FragColor.rgb += canvas.rgb * transparency;\n"
00089 " gl_FragColor.a = max(gl_FragColor.a, canvas.a);\n"
00090 "}\n";
00091
00092 static char *blend_subtract_frag =
00093 "uniform sampler2D tex2;\n"
00094 "uniform vec2 tex2_dimensions;\n"
00095 "void main()\n"
00096 "{\n"
00097 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
00098 " vec3 opacity = vec3(gl_FragColor.a, gl_FragColor.a, gl_FragColor.a);\n"
00099 " vec3 transparency = vec3(1.0, 1.0, 1.0) - opacity;\n"
00100 " gl_FragColor.rgb = canvas.rgb - gl_FragColor.rgb;\n"
00101 " gl_FragColor.rgb *= opacity;\n"
00102 " gl_FragColor.rgb += canvas.rgb * transparency;\n"
00103 " gl_FragColor.a = max(gl_FragColor.a, canvas.a);\n"
00104 "}\n";
00105
00106 static char *blend_multiply_frag =
00107 "uniform sampler2D tex2;\n"
00108 "uniform vec2 tex2_dimensions;\n"
00109 "void main()\n"
00110 "{\n"
00111 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
00112 " vec3 opacity = vec3(gl_FragColor.a, gl_FragColor.a, gl_FragColor.a);\n"
00113 " vec3 transparency = vec3(1.0, 1.0, 1.0) - opacity;\n"
00114 " gl_FragColor.rgb *= canvas.rgb;\n"
00115 " gl_FragColor.rgb *= opacity;\n"
00116 " gl_FragColor.rgb += canvas.rgb * transparency;\n"
00117 " gl_FragColor.a = max(gl_FragColor.a, canvas.a);\n"
00118 "}\n";
00119
00120 static char *blend_divide_frag =
00121 "uniform sampler2D tex2;\n"
00122 "uniform vec2 tex2_dimensions;\n"
00123 "void main()\n"
00124 "{\n"
00125 " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
00126 " vec3 opacity = vec3(gl_FragColor.a, gl_FragColor.a, gl_FragColor.a);\n"
00127 " vec3 transparency = vec3(1.0, 1.0, 1.0) - opacity;\n"
00128 " vec3 result = canvas.rgb / gl_FragColor.rgb;\n"
00129 " if(!gl_FragColor.r) result.r = 1.0;\n"
00130 " if(!gl_FragColor.g) result.g = 1.0;\n"
00131 " if(!gl_FragColor.b) result.b = 1.0;\n"
00132 " result *= opacity;\n"
00133 " result += canvas.rgb * transparency;\n"
00134 " gl_FragColor = vec4(result, max(gl_FragColor.a, canvas.a));\n"
00135 "}\n";
00136
00137 static char *multiply_alpha_frag =
00138 "void main()\n"
00139 "{\n"
00140 " gl_FragColor.rgb *= vec3(gl_FragColor.a, gl_FragColor.a, gl_FragColor.a);\n"
00141 "}\n";
00142
00143 static char *read_texture_frag =
00144 "uniform sampler2D tex;\n"
00145 "void main()\n"
00146 "{\n"
00147 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
00148 "}\n";
00149
00150 static char *multiply_mask4_frag =
00151 "uniform sampler2D tex;\n"
00152 "uniform sampler2D tex1;\n"
00153 "uniform float scale;\n"
00154 "void main()\n"
00155 "{\n"
00156 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
00157 " gl_FragColor.a *= texture2D(tex1, gl_TexCoord[0].st / vec2(scale, scale)).r;\n"
00158 "}\n";
00159
00160 static char *multiply_mask3_frag =
00161 "uniform sampler2D tex;\n"
00162 "uniform sampler2D tex1;\n"
00163 "uniform float scale;\n"
00164 "uniform bool is_yuv;\n"
00165 "void main()\n"
00166 "{\n"
00167 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
00168 " float a = texture2D(tex1, gl_TexCoord[0].st / vec2(scale, scale)).r;\n"
00169 " gl_FragColor.rgb *= vec3(a, a, a);\n"
00170 "}\n";
00171
00172 static char *multiply_yuvmask3_frag =
00173 "uniform sampler2D tex;\n"
00174 "uniform sampler2D tex1;\n"
00175 "uniform float scale;\n"
00176 "void main()\n"
00177 "{\n"
00178 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
00179 " float a = texture2D(tex1, gl_TexCoord[0].st / vec2(scale, scale)).r;\n"
00180 " gl_FragColor.gb -= vec2(0.5, 0.5);\n"
00181 " gl_FragColor.rgb *= vec3(a, a, a);\n"
00182 " gl_FragColor.gb += vec2(0.5, 0.5);\n"
00183 "}\n";
00184
00185 static char *fade_rgba_frag =
00186 "uniform sampler2D tex;\n"
00187 "uniform float alpha;\n"
00188 "void main()\n"
00189 "{\n"
00190 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
00191 " gl_FragColor.a *= alpha;\n"
00192 "}\n";
00193
00194 static char *fade_yuv_frag =
00195 "uniform sampler2D tex;\n"
00196 "uniform float alpha;\n"
00197 "void main()\n"
00198 "{\n"
00199 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
00200 " gl_FragColor.r *= alpha;\n"
00201 " gl_FragColor.gb -= vec2(0.5, 0.5);\n"
00202 " gl_FragColor.g *= alpha;\n"
00203 " gl_FragColor.b *= alpha;\n"
00204 " gl_FragColor.gb += vec2(0.5, 0.5);\n"
00205 "}\n";
00206
00207
00208
00209
00210
00211
00212
00213
00214 Playback3DCommand::Playback3DCommand()
00215 : BC_SynchronousCommand()
00216 {
00217 canvas = 0;
00218 }
00219
00220 void Playback3DCommand::copy_from(BC_SynchronousCommand *command)
00221 {
00222 Playback3DCommand *ptr = (Playback3DCommand*)command;
00223 this->canvas = ptr->canvas;
00224 this->is_cleared = ptr->is_cleared;
00225
00226 this->in_x1 = ptr->in_x1;
00227 this->in_y1 = ptr->in_y1;
00228 this->in_x2 = ptr->in_x2;
00229 this->in_y2 = ptr->in_y2;
00230 this->out_x1 = ptr->out_x1;
00231 this->out_y1 = ptr->out_y1;
00232 this->out_x2 = ptr->out_x2;
00233 this->out_y2 = ptr->out_y2;
00234 this->alpha = ptr->alpha;
00235 this->mode = ptr->mode;
00236 this->interpolation_type = ptr->interpolation_type;
00237
00238 this->input = ptr->input;
00239 this->start_position_project = ptr->start_position_project;
00240 this->keyframe_set = ptr->keyframe_set;
00241 this->keyframe = ptr->keyframe;
00242 this->default_auto = ptr->default_auto;
00243 this->plugin_client = ptr->plugin_client;
00244 this->want_texture = ptr->want_texture;
00245
00246 BC_SynchronousCommand::copy_from(command);
00247 }
00248
00249
00250
00251
00252 Playback3D::Playback3D(MWindow *mwindow)
00253 : BC_Synchronous()
00254 {
00255 this->mwindow = mwindow;
00256 temp_texture = 0;
00257 }
00258
00259 Playback3D::~Playback3D()
00260 {
00261 }
00262
00263
00264
00265
00266 BC_SynchronousCommand* Playback3D::new_command()
00267 {
00268 return new Playback3DCommand;
00269 }
00270
00271
00272
00273 void Playback3D::handle_command(BC_SynchronousCommand *command)
00274 {
00275
00276 switch(command->command)
00277 {
00278 case Playback3DCommand::WRITE_BUFFER:
00279 write_buffer_sync((Playback3DCommand*)command);
00280 break;
00281
00282 case Playback3DCommand::CLEAR_OUTPUT:
00283 clear_output_sync((Playback3DCommand*)command);
00284 break;
00285
00286 case Playback3DCommand::CLEAR_INPUT:
00287 clear_input_sync((Playback3DCommand*)command);
00288 break;
00289
00290 case Playback3DCommand::DO_CAMERA:
00291 do_camera_sync((Playback3DCommand*)command);
00292 break;
00293
00294 case Playback3DCommand::OVERLAY:
00295 overlay_sync((Playback3DCommand*)command);
00296 break;
00297
00298 case Playback3DCommand::DO_FADE:
00299 do_fade_sync((Playback3DCommand*)command);
00300 break;
00301
00302 case Playback3DCommand::DO_MASK:
00303 do_mask_sync((Playback3DCommand*)command);
00304 break;
00305
00306 case Playback3DCommand::PLUGIN:
00307 run_plugin_sync((Playback3DCommand*)command);
00308 break;
00309
00310 case Playback3DCommand::COPY_FROM:
00311 copy_from_sync((Playback3DCommand*)command);
00312 break;
00313
00314
00315
00316
00317 }
00318
00319 }
00320
00321
00322
00323
00324 void Playback3D::copy_from(Canvas *canvas,
00325 VFrame *dst,
00326 VFrame *src,
00327 int want_texture)
00328 {
00329 Playback3DCommand command;
00330 command.command = Playback3DCommand::COPY_FROM;
00331 command.canvas = canvas;
00332 command.frame = dst;
00333 command.input = src;
00334 command.want_texture = want_texture;
00335 send_command(&command);
00336 }
00337
00338 void Playback3D::copy_from_sync(Playback3DCommand *command)
00339 {
00340 #ifdef HAVE_GL
00341 command->canvas->lock_canvas("Playback3D::draw_refresh_sync");
00342 BC_WindowBase *window = command->canvas->get_canvas();
00343 if(window)
00344 {
00345 window->lock_window("Playback3D:draw_refresh_sync");
00346 window->enable_opengl();
00347
00348 if(command->input->get_opengl_state() == VFrame::SCREEN &&
00349 command->input->get_w() == command->frame->get_w() &&
00350 command->input->get_h() == command->frame->get_h())
00351 {
00352
00353
00354
00355
00356
00357
00358 int w = command->input->get_w();
00359 int h = command->input->get_h();
00360
00361 if(command->input->get_w() % 4)
00362 {
00363 printf("Playback3D::copy_from_sync: w=%d not supported because it is not divisible by 4.\n", w);
00364 }
00365 else
00366
00367 if(command->want_texture)
00368 {
00369
00370
00371 command->input->enable_opengl();
00372 command->frame->screen_to_texture();
00373 command->frame->set_opengl_state(VFrame::TEXTURE);
00374 }
00375 else
00376
00377 {
00378 command->input->enable_opengl();
00379 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
00380 glReadPixels(0,
00381 0,
00382 w,
00383 command->input->get_h(),
00384 GL_RGB,
00385 GL_UNSIGNED_BYTE,
00386 command->frame->get_rows()[0]);
00387 command->frame->flip_vert();
00388 command->frame->set_opengl_state(VFrame::RAM);
00389 }
00390 }
00391 else
00392 {
00393 printf("Playback3D::copy_from_sync: invalid formats opengl_state=%d %dx%d -> %dx%d\n",
00394 command->input->get_opengl_state(),
00395 command->input->get_w(),
00396 command->input->get_h(),
00397 command->frame->get_w(),
00398 command->frame->get_h());
00399 }
00400
00401 window->unlock_window();
00402 }
00403 command->canvas->unlock_canvas();
00404 #endif
00405 }
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481 void Playback3D::write_buffer(Canvas *canvas,
00482 VFrame *frame,
00483 float in_x1,
00484 float in_y1,
00485 float in_x2,
00486 float in_y2,
00487 float out_x1,
00488 float out_y1,
00489 float out_x2,
00490 float out_y2,
00491 int is_cleared)
00492 {
00493 Playback3DCommand command;
00494 command.command = Playback3DCommand::WRITE_BUFFER;
00495 command.canvas = canvas;
00496 command.frame = frame;
00497 command.in_x1 = in_x1;
00498 command.in_y1 = in_y1;
00499 command.in_x2 = in_x2;
00500 command.in_y2 = in_y2;
00501 command.out_x1 = out_x1;
00502 command.out_y1 = out_y1;
00503 command.out_x2 = out_x2;
00504 command.out_y2 = out_y2;
00505 command.is_cleared = is_cleared;
00506 send_command(&command);
00507 }
00508
00509
00510 void Playback3D::write_buffer_sync(Playback3DCommand *command)
00511 {
00512 command->canvas->lock_canvas("Playback3D::write_buffer_sync");
00513 if(command->canvas->get_canvas())
00514 {
00515 BC_WindowBase *window = command->canvas->get_canvas();
00516 window->lock_window("Playback3D::write_buffer_sync");
00517
00518 window->update_video_cursor();
00519
00520 window->enable_opengl();
00521
00522
00523
00524 switch(command->frame->get_opengl_state())
00525 {
00526
00527 case VFrame::RAM:
00528 command->frame->to_texture();
00529 draw_output(command);
00530 break;
00531
00532 case VFrame::TEXTURE:
00533 draw_output(command);
00534 break;
00535 case VFrame::SCREEN:
00536
00537 window->flip_opengl();
00538 break;
00539 default:
00540 printf("Playback3D::write_buffer_sync unknown state\n");
00541 break;
00542 }
00543 window->unlock_window();
00544 }
00545
00546 command->canvas->unlock_canvas();
00547 }
00548
00549
00550
00551 void Playback3D::draw_output(Playback3DCommand *command)
00552 {
00553 #ifdef HAVE_GL
00554 int texture_id = command->frame->get_texture_id();
00555 BC_WindowBase *window = command->canvas->get_canvas();
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566 if(texture_id >= 0)
00567 {
00568 canvas_w = window->get_w();
00569 canvas_h = window->get_h();
00570 VFrame::init_screen(canvas_w, canvas_h);
00571
00572 if(!command->is_cleared)
00573 {
00574
00575 init_frame(command);
00576 }
00577
00578
00579
00580 command->frame->bind_texture(0);
00581
00582
00583
00584
00585
00586 unsigned int frag_shader = 0;
00587 switch(command->frame->get_color_model())
00588 {
00589 case BC_YUV888:
00590 frag_shader = VFrame::make_shader(0,
00591 yuv_to_rgb_frag,
00592 0);
00593 break;
00594
00595 case BC_YUVA8888:
00596 frag_shader = VFrame::make_shader(0,
00597 yuva_to_rgba_frag,
00598 0);
00599 break;
00600 }
00601
00602
00603 if(frag_shader > 0)
00604 {
00605 glUseProgram(frag_shader);
00606 int variable = glGetUniformLocation(frag_shader, "tex");
00607
00608 glUniform1i(variable, 0);
00609 }
00610
00611 if(cmodel_components(command->frame->get_color_model()) == 4)
00612 {
00613 glEnable(GL_BLEND);
00614 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00615 }
00616
00617 command->frame->draw_texture(command->in_x1,
00618 command->in_y1,
00619 command->in_x2,
00620 command->in_y2,
00621 command->out_x1,
00622 command->out_y1,
00623 command->out_x2,
00624 command->out_y2,
00625 1);
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638 glUseProgram(0);
00639
00640 command->canvas->get_canvas()->flip_opengl();
00641
00642 }
00643 #endif
00644 }
00645
00646
00647 void Playback3D::init_frame(Playback3DCommand *command)
00648 {
00649 #ifdef HAVE_GL
00650 canvas_w = command->canvas->get_canvas()->get_w();
00651 canvas_h = command->canvas->get_canvas()->get_h();
00652
00653 glClearColor(0.0, 0.0, 0.0, 0.0);
00654 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00655 #endif
00656 }
00657
00658
00659 void Playback3D::clear_output(Canvas *canvas, VFrame *output)
00660 {
00661 Playback3DCommand command;
00662 command.command = Playback3DCommand::CLEAR_OUTPUT;
00663 command.canvas = canvas;
00664 command.frame = output;
00665 send_command(&command);
00666 }
00667
00668 void Playback3D::clear_output_sync(Playback3DCommand *command)
00669 {
00670 command->canvas->lock_canvas("Playback3D::clear_output_sync");
00671 if(command->canvas->get_canvas())
00672 {
00673 command->canvas->get_canvas()->lock_window("Playback3D::clear_output_sync");
00674
00675 command->canvas->get_canvas()->enable_opengl();
00676
00677
00678 if(command->frame)
00679 {
00680 command->frame->enable_opengl();
00681 }
00682
00683
00684 init_frame(command);
00685 command->canvas->get_canvas()->unlock_window();
00686 }
00687 command->canvas->unlock_canvas();
00688 }
00689
00690
00691 void Playback3D::clear_input(Canvas *canvas, VFrame *frame)
00692 {
00693 Playback3DCommand command;
00694 command.command = Playback3DCommand::CLEAR_INPUT;
00695 command.canvas = canvas;
00696 command.frame = frame;
00697 send_command(&command);
00698 }
00699
00700 void Playback3D::clear_input_sync(Playback3DCommand *command)
00701 {
00702 command->canvas->lock_canvas("Playback3D::clear_output_sync");
00703 if(command->canvas->get_canvas())
00704 {
00705 command->canvas->get_canvas()->lock_window("Playback3D::clear_output_sync");
00706 command->canvas->get_canvas()->enable_opengl();
00707 command->frame->enable_opengl();
00708 command->frame->clear_pbuffer();
00709 command->frame->set_opengl_state(VFrame::SCREEN);
00710 command->canvas->get_canvas()->unlock_window();
00711 }
00712 command->canvas->unlock_canvas();
00713 }
00714
00715 void Playback3D::do_camera(Canvas *canvas,
00716 VFrame *output,
00717 VFrame *input,
00718 float in_x1,
00719 float in_y1,
00720 float in_x2,
00721 float in_y2,
00722 float out_x1,
00723 float out_y1,
00724 float out_x2,
00725 float out_y2)
00726 {
00727 Playback3DCommand command;
00728 command.command = Playback3DCommand::DO_CAMERA;
00729 command.canvas = canvas;
00730 command.input = input;
00731 command.frame = output;
00732 command.in_x1 = in_x1;
00733 command.in_y1 = in_y1;
00734 command.in_x2 = in_x2;
00735 command.in_y2 = in_y2;
00736 command.out_x1 = out_x1;
00737 command.out_y1 = out_y1;
00738 command.out_x2 = out_x2;
00739 command.out_y2 = out_y2;
00740 send_command(&command);
00741 }
00742
00743 void Playback3D::do_camera_sync(Playback3DCommand *command)
00744 {
00745 command->canvas->lock_canvas("Playback3D::do_camera_sync");
00746 if(command->canvas->get_canvas())
00747 {
00748 command->canvas->get_canvas()->lock_window("Playback3D::clear_output_sync");
00749 command->canvas->get_canvas()->enable_opengl();
00750
00751 command->input->to_texture();
00752 command->frame->enable_opengl();
00753 command->frame->init_screen();
00754 command->frame->clear_pbuffer();
00755
00756 command->input->bind_texture(0);
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768 command->input->draw_texture(
00769 command->in_x1,
00770 command->in_y2,
00771 command->in_x2,
00772 command->in_y1,
00773 command->out_x1,
00774 (float)command->frame->get_h() - command->out_y1,
00775 command->out_x2,
00776 (float)command->frame->get_h() - command->out_y2);
00777
00778
00779 command->frame->set_opengl_state(VFrame::SCREEN);
00780 command->canvas->get_canvas()->unlock_window();
00781 }
00782 command->canvas->unlock_canvas();
00783 }
00784
00785 void Playback3D::overlay(Canvas *canvas,
00786 VFrame *input,
00787 float in_x1,
00788 float in_y1,
00789 float in_x2,
00790 float in_y2,
00791 float out_x1,
00792 float out_y1,
00793 float out_x2,
00794 float out_y2,
00795 float alpha,
00796 int mode,
00797 int interpolation_type,
00798 VFrame *output)
00799 {
00800 Playback3DCommand command;
00801 command.command = Playback3DCommand::OVERLAY;
00802 command.canvas = canvas;
00803 command.frame = output;
00804 command.input = input;
00805 command.in_x1 = in_x1;
00806 command.in_y1 = in_y1;
00807 command.in_x2 = in_x2;
00808 command.in_y2 = in_y2;
00809 command.out_x1 = out_x1;
00810 command.out_y1 = out_y1;
00811 command.out_x2 = out_x2;
00812 command.out_y2 = out_y2;
00813 command.alpha = alpha;
00814 command.mode = mode;
00815 command.interpolation_type = interpolation_type;
00816 send_command(&command);
00817 }
00818
00819 void Playback3D::overlay_sync(Playback3DCommand *command)
00820 {
00821 #ifdef HAVE_GL
00822 command->canvas->lock_canvas("Playback3D::overlay_sync");
00823 if(command->canvas->get_canvas())
00824 {
00825 BC_WindowBase *window = command->canvas->get_canvas();
00826 window->lock_window("Playback3D::overlay_sync");
00827
00828 window->enable_opengl();
00829
00830 window->update_video_cursor();
00831
00832
00833
00834 if(command->frame)
00835 {
00836 command->frame->enable_opengl();
00837 command->frame->set_opengl_state(VFrame::SCREEN);
00838 canvas_w = command->frame->get_w();
00839 canvas_h = command->frame->get_h();
00840 }
00841 else
00842 {
00843 canvas_w = window->get_w();
00844 canvas_h = window->get_h();
00845 }
00846
00847 glColor4f(1, 1, 1, 1);
00848
00849
00850 switch(command->input->get_opengl_state())
00851 {
00852
00853 case VFrame::RAM:
00854 command->input->to_texture();
00855 break;
00856
00857 case VFrame::TEXTURE:
00858 break;
00859
00860 case VFrame::SCREEN:
00861 command->input->enable_opengl();
00862 command->input->screen_to_texture();
00863 if(command->frame)
00864 command->frame->enable_opengl();
00865 else
00866 window->enable_opengl();
00867 break;
00868 default:
00869 printf("Playback3D::overlay_sync unknown state\n");
00870 break;
00871 }
00872
00873
00874 char *shader_stack[3] = { 0, 0, 0 };
00875 int total_shaders = 0;
00876
00877 VFrame::init_screen(canvas_w, canvas_h);
00878
00879
00880 command->input->bind_texture(0);
00881
00882
00883
00884 switch(command->input->get_color_model())
00885 {
00886 case BC_YUV888:
00887 shader_stack[total_shaders++] = yuv_to_rgb_frag;
00888 break;
00889 case BC_YUVA8888:
00890 shader_stack[total_shaders++] = yuva_to_rgba_frag;
00891 break;
00892 }
00893
00894
00895 switch(command->mode)
00896 {
00897 case TRANSFER_NORMAL:
00898 glEnable(GL_BLEND);
00899 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00900 break;
00901
00902 case TRANSFER_REPLACE:
00903
00904 glDisable(GL_BLEND);
00905 if(command->input->get_texture_components() == 4)
00906 {
00907 if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag;
00908 shader_stack[total_shaders++] = multiply_alpha_frag;
00909 }
00910 break;
00911
00912
00913
00914 case TRANSFER_ADDITION:
00915 enable_overlay_texture(command);
00916 if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag;
00917 shader_stack[total_shaders++] = blend_add_frag;
00918 break;
00919 case TRANSFER_SUBTRACT:
00920 enable_overlay_texture(command);
00921 if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag;
00922 shader_stack[total_shaders++] = blend_subtract_frag;
00923 break;
00924 case TRANSFER_MULTIPLY:
00925 enable_overlay_texture(command);
00926 if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag;
00927 shader_stack[total_shaders++] = blend_multiply_frag;
00928 break;
00929 case TRANSFER_MAX:
00930 enable_overlay_texture(command);
00931 if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag;
00932 shader_stack[total_shaders++] = blend_max_frag;
00933 break;
00934 case TRANSFER_DIVIDE:
00935 enable_overlay_texture(command);
00936 if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag;
00937 shader_stack[total_shaders++] = blend_divide_frag;
00938 break;
00939 }
00940
00941 unsigned int frag_shader = 0;
00942 if(shader_stack[0])
00943 {
00944 frag_shader = VFrame::make_shader(0,
00945 shader_stack[0],
00946 shader_stack[1],
00947 0);
00948
00949 glUseProgram(frag_shader);
00950
00951
00952
00953 glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0);
00954
00955 glUniform1i(glGetUniformLocation(frag_shader, "tex2"), 1);
00956
00957 if(temp_texture)
00958 glUniform2f(glGetUniformLocation(frag_shader, "tex2_dimensions"),
00959 (float)temp_texture->get_texture_w(),
00960 (float)temp_texture->get_texture_h());
00961 }
00962 else
00963 glUseProgram(0);
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983 command->input->draw_texture(command->in_x1,
00984 command->in_y1,
00985 command->in_x2,
00986 command->in_y2,
00987 command->out_x1,
00988 command->out_y1,
00989 command->out_x2,
00990 command->out_y2,
00991 1);
00992
00993
00994 glUseProgram(0);
00995
00996
00997
00998 if(temp_texture)
00999 {
01000 delete temp_texture;
01001 temp_texture = 0;
01002 glActiveTexture(GL_TEXTURE1);
01003 glDisable(GL_TEXTURE_2D);
01004 }
01005 glActiveTexture(GL_TEXTURE0);
01006 glDisable(GL_TEXTURE_2D);
01007
01008
01009
01010 window->unlock_window();
01011 }
01012 command->canvas->unlock_canvas();
01013 #endif
01014 }
01015
01016
01017 void Playback3D::enable_overlay_texture(Playback3DCommand *command)
01018 {
01019 #ifdef HAVE_GL
01020 glDisable(GL_BLEND);
01021
01022 glActiveTexture(GL_TEXTURE1);
01023 BC_Texture::new_texture(&temp_texture,
01024 canvas_w,
01025 canvas_h,
01026 command->input->get_color_model());
01027 temp_texture->bind(1);
01028
01029
01030 glReadBuffer(GL_BACK);
01031 glCopyTexSubImage2D(GL_TEXTURE_2D,
01032 0,
01033 0,
01034 0,
01035 0,
01036 0,
01037 canvas_w,
01038 canvas_h);
01039 #endif
01040 }
01041
01042
01043 void Playback3D::do_mask(Canvas *canvas,
01044 VFrame *output,
01045 int64_t start_position_project,
01046 MaskAutos *keyframe_set,
01047 MaskAuto *keyframe,
01048 MaskAuto *default_auto)
01049 {
01050 Playback3DCommand command;
01051 command.command = Playback3DCommand::DO_MASK;
01052 command.canvas = canvas;
01053 command.frame = output;
01054 command.start_position_project = start_position_project;
01055 command.keyframe_set = keyframe_set;
01056 command.keyframe = keyframe;
01057 command.default_auto = default_auto;
01058
01059 send_command(&command);
01060 }
01061
01062
01063
01064 #ifdef HAVE_GL
01065 struct Vertex : ListItem<Vertex>
01066 {
01067 GLdouble c[3];
01068 };
01069
01070
01071
01072 static List<Vertex> *vertex_cache = 0;
01073
01074 static void combine_callback(GLdouble coords[3],
01075 GLdouble *vertex_data[4],
01076 GLfloat weight[4],
01077 GLdouble **dataOut)
01078 {
01079
01080 Vertex* vertex = vertex_cache->append();
01081 vertex->c[0] = coords[0];
01082 vertex->c[1] = coords[1];
01083 vertex->c[2] = coords[2];
01084
01085
01086 *dataOut = &vertex->c[0];
01087 }
01088 #endif
01089
01090
01091 void Playback3D::do_mask_sync(Playback3DCommand *command)
01092 {
01093 #ifdef HAVE_GL
01094 command->canvas->lock_canvas("Playback3D::do_mask_sync");
01095 if(command->canvas->get_canvas())
01096 {
01097 BC_WindowBase *window = command->canvas->get_canvas();
01098 window->lock_window("Playback3D::do_mask_sync");
01099 window->enable_opengl();
01100
01101 switch(command->frame->get_opengl_state())
01102 {
01103 case VFrame::RAM:
01104
01105 command->frame->to_texture();
01106 break;
01107
01108 case VFrame::SCREEN:
01109
01110
01111 command->frame->enable_opengl();
01112 command->frame->screen_to_texture();
01113 break;
01114 }
01115
01116
01117
01118
01119 command->frame->enable_opengl();
01120
01121
01122 int w = command->frame->get_w();
01123 int h = command->frame->get_h();
01124 command->frame->init_screen();
01125
01126
01127 glDisable(GL_TEXTURE_2D);
01128 if(command->default_auto->mode == MASK_MULTIPLY_ALPHA)
01129 {
01130 glClearColor(0.0, 0.0, 0.0, 0.0);
01131 glColor4f((float)command->keyframe->value / 100,
01132 (float)command->keyframe->value / 100,
01133 (float)command->keyframe->value / 100,
01134 1.0);
01135 }
01136 else
01137 {
01138 glClearColor(1.0, 1.0, 1.0, 1.0);
01139 glColor4f((float)1.0 - (float)command->keyframe->value / 100,
01140 (float)1.0 - (float)command->keyframe->value / 100,
01141 (float)1.0 - (float)command->keyframe->value / 100,
01142 1.0);
01143 }
01144 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
01145
01146
01147
01148 GLUtesselator *tesselator = gluNewTess();
01149 gluTessProperty(tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);
01150 gluTessCallback(tesselator, GLU_TESS_VERTEX, (GLvoid (*) ( )) &glVertex3dv);
01151 gluTessCallback(tesselator, GLU_TESS_BEGIN, (GLvoid (*) ( )) &glBegin);
01152 gluTessCallback(tesselator, GLU_TESS_END, (GLvoid (*) ( )) &glEnd);
01153 gluTessCallback(tesselator, GLU_TESS_COMBINE, (GLvoid (*) ( ))&combine_callback);
01154
01155 vertex_cache = new List<Vertex>;
01156
01157
01158
01159 int total_submasks = command->keyframe_set->total_submasks(
01160 command->start_position_project,
01161 PLAY_FORWARD);
01162 float scale = command->keyframe->feather + 1;
01163 int display_list = glGenLists(1);
01164 glNewList(display_list, GL_COMPILE);
01165 for(int k = 0; k < total_submasks; k++)
01166 {
01167 gluTessBeginPolygon(tesselator, NULL);
01168 gluTessBeginContour(tesselator);
01169 ArrayList<MaskPoint*> *points = new ArrayList<MaskPoint*>;
01170 command->keyframe_set->get_points(points,
01171 k,
01172 command->start_position_project,
01173 PLAY_FORWARD);
01174
01175 int first_point = 0;
01176
01177
01178 ArrayList<GLdouble*> coords;
01179 for(int i = 0; i < points->total; i++)
01180 {
01181 MaskPoint *point1 = points->values[i];
01182 MaskPoint *point2 = (i >= points->total - 1) ?
01183 points->values[0] :
01184 points->values[i + 1];
01185
01186
01187 float x, y;
01188 int segments = 0;
01189 if(point1->control_x2 == 0 &&
01190 point1->control_y2 == 0 &&
01191 point2->control_x1 == 0 &&
01192 point2->control_y1 == 0)
01193 segments = 1;
01194
01195 float x0 = point1->x;
01196 float y0 = point1->y;
01197 float x1 = point1->x + point1->control_x2;
01198 float y1 = point1->y + point1->control_y2;
01199 float x2 = point2->x + point2->control_x1;
01200 float y2 = point2->y + point2->control_y1;
01201 float x3 = point2->x;
01202 float y3 = point2->y;
01203
01204
01205
01206
01207 float cx3, cx2, cx1, cx0, cy3, cy2, cy1, cy0;
01208
01209
01210
01211
01212
01213
01214 cx3 = - x0 + 3*x1 - 3*x2 + x3;
01215 cx2 = 3*x0 - 6*x1 + 3*x2;
01216 cx1 = -3*x0 + 3*x1;
01217 cx0 = x0;
01218
01219 cy3 = - y0 + 3*y1 - 3*y2 + y3;
01220 cy2 = 3*y0 - 6*y1 + 3*y2;
01221 cy1 = -3*y0 + 3*y1;
01222 cy0 = y0;
01223
01224
01225
01226
01227
01228
01229
01230
01231
01232
01233 if (segments == 0)
01234 {
01235 float maxaccel1 = fabs(2*cy2) + fabs(6*cy3);
01236 float maxaccel2 = fabs(2*cx2) + fabs(6*cx3);
01237
01238 float maxaccel = maxaccel1 > maxaccel2 ? maxaccel1 : maxaccel2;
01239 float h = 1.0;
01240
01241 if(maxaccel > 8.0) h = sqrt((8.0) / maxaccel);
01242 segments = int(1/h);
01243 }
01244
01245 for(int j = 0; j <= segments; j++)
01246 {
01247 float t = (float)j / segments;
01248 x = cx0 + t*(cx1 + t*(cx2 + t*cx3));
01249 y = cy0 + t*(cy1 + t*(cy2 + t*cy3));
01250
01251 if(j > 0 || first_point)
01252 {
01253 GLdouble *coord = new GLdouble[3];
01254 coord[0] = x / scale;
01255 coord[1] = -h + y / scale;
01256 coord[2] = 0;
01257 coords.append(coord);
01258 first_point = 0;
01259 }
01260 }
01261 }
01262
01263
01264 for(int i = 0; i < coords.total; i++)
01265 gluTessVertex(tesselator, coords.values[i], coords.values[i]);
01266
01267 gluTessEndContour(tesselator);
01268 gluTessEndPolygon(tesselator);
01269 points->remove_all_objects();
01270 delete points;
01271 coords.remove_all_objects();
01272 }
01273 glEndList();
01274 glCallList(display_list);
01275 glDeleteLists(display_list, 1);
01276 gluDeleteTess(tesselator);
01277
01278 delete vertex_cache;
01279 vertex_cache = 0;
01280
01281 glColor4f(1, 1, 1, 1);
01282
01283
01284
01285
01286
01287
01288 float w_scaled = w / scale;
01289 float h_scaled = h / scale;
01290
01291
01292
01293 glActiveTexture(GL_TEXTURE1);
01294 BC_Texture::new_texture(&temp_texture,
01295 w,
01296 h,
01297 command->frame->get_color_model());
01298 temp_texture->bind(1);
01299 glReadBuffer(GL_BACK);
01300
01301
01302 glCopyTexSubImage2D(GL_TEXTURE_2D,
01303 0,
01304 0,
01305 0,
01306 0,
01307 0,
01308 (int)MIN(w_scaled + 2, w),
01309 (int)MIN(h_scaled + 2, h));
01310
01311 command->frame->bind_texture(0);
01312
01313
01314
01315
01316
01317 unsigned int frag_shader = 0;
01318 switch(temp_texture->get_texture_components())
01319 {
01320 case 3:
01321 if(command->frame->get_color_model() == BC_YUV888)
01322 frag_shader = VFrame::make_shader(0,
01323 multiply_yuvmask3_frag,
01324 0);
01325 else
01326 frag_shader = VFrame::make_shader(0,
01327 multiply_mask3_frag,
01328 0);
01329 break;
01330 case 4:
01331 frag_shader = VFrame::make_shader(0,
01332 multiply_mask4_frag,
01333 0);
01334 break;
01335 }
01336
01337 if(frag_shader)
01338 {
01339 int variable;
01340 glUseProgram(frag_shader);
01341 if((variable = glGetUniformLocation(frag_shader, "tex")) >= 0)
01342 glUniform1i(variable, 0);
01343 if((variable = glGetUniformLocation(frag_shader, "tex1")) >= 0)
01344 glUniform1i(variable, 1);
01345 if((variable = glGetUniformLocation(frag_shader, "scale")) >= 0)
01346 glUniform1f(variable, scale);
01347 }
01348
01349
01350
01351
01352
01353
01354 command->frame->draw_texture(0, 0, w, h, 0, 0, w, h);
01355 command->frame->set_opengl_state(VFrame::SCREEN);
01356
01357
01358
01359 glUseProgram(0);
01360
01361 glActiveTexture(GL_TEXTURE1);
01362 glDisable(GL_TEXTURE_2D);
01363 delete temp_texture;
01364 temp_texture = 0;
01365
01366 glActiveTexture(GL_TEXTURE0);
01367 glDisable(GL_TEXTURE_2D);
01368
01369
01370 window->enable_opengl();
01371 window->unlock_window();
01372 }
01373 command->canvas->unlock_canvas();
01374 #endif
01375 }
01376
01377
01378
01379
01380
01381
01382
01383
01384
01385
01386
01387
01388 void Playback3D::do_fade(Canvas *canvas, VFrame *frame, float fade)
01389 {
01390 Playback3DCommand command;
01391 command.command = Playback3DCommand::DO_FADE;
01392 command.canvas = canvas;
01393 command.frame = frame;
01394 command.alpha = fade;
01395 send_command(&command);
01396 }
01397
01398 void Playback3D::do_fade_sync(Playback3DCommand *command)
01399 {
01400 #ifdef HAVE_GL
01401 command->canvas->lock_canvas("Playback3D::do_mask_sync");
01402 if(command->canvas->get_canvas())
01403 {
01404 BC_WindowBase *window = command->canvas->get_canvas();
01405 window->lock_window("Playback3D::do_fade_sync");
01406 window->enable_opengl();
01407
01408 switch(command->frame->get_opengl_state())
01409 {
01410 case VFrame::RAM:
01411 command->frame->to_texture();
01412 break;
01413
01414 case VFrame::SCREEN:
01415
01416
01417 command->frame->enable_opengl();
01418 command->frame->screen_to_texture();
01419 break;
01420 }
01421
01422
01423 command->frame->enable_opengl();
01424 command->frame->init_screen();
01425 command->frame->bind_texture(0);
01426
01427
01428
01429 glDisable(GL_BLEND);
01430 unsigned int frag_shader = 0;
01431 switch(command->frame->get_color_model())
01432 {
01433
01434
01435 case BC_RGBA8888:
01436 case BC_RGBA_FLOAT:
01437 case BC_YUVA8888:
01438 frag_shader = VFrame::make_shader(0,
01439 fade_rgba_frag,
01440 0);
01441 break;
01442
01443 case BC_RGB888:
01444 glEnable(GL_BLEND);
01445 glBlendFunc(GL_SRC_ALPHA, GL_ZERO);
01446 glColor4f(command->alpha, command->alpha, command->alpha, 1);
01447 break;
01448
01449
01450 case BC_YUV888:
01451 frag_shader = VFrame::make_shader(0,
01452 fade_yuv_frag,
01453 0);
01454 break;
01455 }
01456
01457
01458 if(frag_shader)
01459 {
01460 glUseProgram(frag_shader);
01461 int variable;
01462 if((variable = glGetUniformLocation(frag_shader, "tex")) >= 0)
01463 glUniform1i(variable, 0);
01464 if((variable = glGetUniformLocation(frag_shader, "alpha")) >= 0)
01465 glUniform1f(variable, command->alpha);
01466 }
01467
01468 command->frame->draw_texture();
01469 command->frame->set_opengl_state(VFrame::SCREEN);
01470
01471 if(frag_shader)
01472 {
01473 glUseProgram(0);
01474 }
01475
01476 glColor4f(1, 1, 1, 1);
01477 glDisable(GL_BLEND);
01478
01479 window->unlock_window();
01480 }
01481 command->canvas->unlock_canvas();
01482 #endif
01483 }
01484
01485
01486
01487
01488
01489
01490
01491
01492
01493
01494
01495 int Playback3D::run_plugin(Canvas *canvas, PluginClient *client)
01496 {
01497 Playback3DCommand command;
01498 command.command = Playback3DCommand::PLUGIN;
01499 command.canvas = canvas;
01500 command.plugin_client = client;
01501 return send_command(&command);
01502 }
01503
01504 void Playback3D::run_plugin_sync(Playback3DCommand *command)
01505 {
01506 command->canvas->lock_canvas("Playback3D::run_plugin_sync");
01507 if(command->canvas->get_canvas())
01508 {
01509 BC_WindowBase *window = command->canvas->get_canvas();
01510 window->lock_window("Playback3D::run_plugin_sync");
01511 window->enable_opengl();
01512
01513 command->result = ((PluginVClient*)command->plugin_client)->handle_opengl();
01514
01515 window->unlock_window();
01516 }
01517 command->canvas->unlock_canvas();
01518 }
01519
01520