1 #include "bcdisplayinfo.h"
8 #include "overlayframe.h"
10 #include "pluginvclient.h"
28 static char* mode_to_text(int mode);
31 static char* direction_to_text(int direction);
39 static char* output_to_text(int output_layer);
52 class OverlayMode : public BC_PopupMenu
55 OverlayMode(Overlay *plugin,
58 void create_objects();
63 class OverlayDirection : public BC_PopupMenu
66 OverlayDirection(Overlay *plugin,
69 void create_objects();
74 class OverlayOutput : public BC_PopupMenu
77 OverlayOutput(Overlay *plugin,
80 void create_objects();
86 class OverlayWindow : public BC_Window
89 OverlayWindow(Overlay *plugin, int x, int y);
92 void create_objects();
97 OverlayDirection *direction;
98 OverlayOutput *output;
102 PLUGIN_THREAD_HEADER(Overlay, OverlayThread, OverlayWindow)
106 class Overlay : public PluginVClient
109 Overlay(PluginServer *server);
113 PLUGIN_CLASS_MEMBERS(OverlayConfig, OverlayThread);
115 int process_buffer(VFrame **frame,
116 int64_t start_position,
119 int is_multichannel();
123 void save_data(KeyFrame *keyframe);
124 void read_data(KeyFrame *keyframe);
128 OverlayFrame *overlayer;
132 // Inclusive layer numbers
148 OverlayConfig::OverlayConfig()
150 mode = TRANSFER_NORMAL;
151 direction = OverlayConfig::BOTTOM_FIRST;
152 output_layer = OverlayConfig::TOP;
155 char* OverlayConfig::mode_to_text(int mode)
159 case TRANSFER_NORMAL:
163 case TRANSFER_REPLACE:
167 case TRANSFER_ADDITION:
171 case TRANSFER_SUBTRACT:
175 case TRANSFER_MULTIPLY:
179 case TRANSFER_DIVIDE:
194 char* OverlayConfig::direction_to_text(int direction)
198 case OverlayConfig::BOTTOM_FIRST: return _("Bottom first");
199 case OverlayConfig::TOP_FIRST: return _("Top first");
204 char* OverlayConfig::output_to_text(int output_layer)
208 case OverlayConfig::TOP: return _("Top");
209 case OverlayConfig::BOTTOM: return _("Bottom");
222 OverlayWindow::OverlayWindow(Overlay *plugin, int x, int y)
223 : BC_Window(plugin->gui_string,
234 this->plugin = plugin;
237 OverlayWindow::~OverlayWindow()
241 void OverlayWindow::create_objects()
246 add_subwindow(title = new BC_Title(x, y, _("Mode:")));
247 add_subwindow(mode = new OverlayMode(plugin,
248 x + title->get_w() + 5,
250 mode->create_objects();
253 add_subwindow(title = new BC_Title(x, y, _("Layer order:")));
254 add_subwindow(direction = new OverlayDirection(plugin,
255 x + title->get_w() + 5,
257 direction->create_objects();
260 add_subwindow(title = new BC_Title(x, y, _("Output layer:")));
261 add_subwindow(output = new OverlayOutput(plugin,
262 x + title->get_w() + 5,
264 output->create_objects();
270 WINDOW_CLOSE_EVENT(OverlayWindow)
276 OverlayMode::OverlayMode(Overlay *plugin,
282 OverlayConfig::mode_to_text(plugin->config.mode),
285 this->plugin = plugin;
288 void OverlayMode::create_objects()
290 for(int i = 0; i < TRANSFER_TYPES; i++)
291 add_item(new BC_MenuItem(OverlayConfig::mode_to_text(i)));
294 int OverlayMode::handle_event()
296 char *text = get_text();
298 for(int i = 0; i < TRANSFER_TYPES; i++)
300 if(!strcmp(text, OverlayConfig::mode_to_text(i)))
302 plugin->config.mode = i;
307 plugin->send_configure_change();
312 OverlayDirection::OverlayDirection(Overlay *plugin,
318 OverlayConfig::direction_to_text(plugin->config.direction),
321 this->plugin = plugin;
324 void OverlayDirection::create_objects()
326 add_item(new BC_MenuItem(
327 OverlayConfig::direction_to_text(
328 OverlayConfig::TOP_FIRST)));
329 add_item(new BC_MenuItem(
330 OverlayConfig::direction_to_text(
331 OverlayConfig::BOTTOM_FIRST)));
334 int OverlayDirection::handle_event()
336 char *text = get_text();
339 OverlayConfig::direction_to_text(
340 OverlayConfig::TOP_FIRST)))
341 plugin->config.direction = OverlayConfig::TOP_FIRST;
344 OverlayConfig::direction_to_text(
345 OverlayConfig::BOTTOM_FIRST)))
346 plugin->config.direction = OverlayConfig::BOTTOM_FIRST;
348 plugin->send_configure_change();
353 OverlayOutput::OverlayOutput(Overlay *plugin,
359 OverlayConfig::output_to_text(plugin->config.output_layer),
362 this->plugin = plugin;
365 void OverlayOutput::create_objects()
367 add_item(new BC_MenuItem(
368 OverlayConfig::output_to_text(
369 OverlayConfig::TOP)));
370 add_item(new BC_MenuItem(
371 OverlayConfig::output_to_text(
372 OverlayConfig::BOTTOM)));
375 int OverlayOutput::handle_event()
377 char *text = get_text();
380 OverlayConfig::output_to_text(
381 OverlayConfig::TOP)))
382 plugin->config.output_layer = OverlayConfig::TOP;
385 OverlayConfig::output_to_text(
386 OverlayConfig::BOTTOM)))
387 plugin->config.output_layer = OverlayConfig::BOTTOM;
389 plugin->send_configure_change();
401 PLUGIN_THREAD_OBJECT(Overlay, OverlayThread, OverlayWindow)
412 REGISTER_PLUGIN(Overlay)
419 Overlay::Overlay(PluginServer *server)
420 : PluginVClient(server)
422 PLUGIN_CONSTRUCTOR_MACRO
430 PLUGIN_DESTRUCTOR_MACRO
431 if(overlayer) delete overlayer;
432 if(temp) delete temp;
437 int Overlay::process_buffer(VFrame **frame,
438 int64_t start_position,
441 load_configuration();
443 if(!temp) temp = new VFrame(0,
446 frame[0]->get_color_model(),
450 overlayer = new OverlayFrame(get_project_smp() + 1);
455 if(config.direction == OverlayConfig::BOTTOM_FIRST)
457 input_layer1 = get_total_buffers() - 1;
464 input_layer2 = get_total_buffers();
468 if(config.output_layer == OverlayConfig::TOP)
474 output_layer = get_total_buffers() - 1;
479 // Direct copy the first layer
480 output = frame[output_layer];
487 if(get_total_buffers() == 1) return 0;
491 current_layer = input_layer1;
495 for(int i = input_layer1 + step; i != input_layer2; i += step)
509 // Call the opengl handler once for each layer
510 overlayer->overlay(output,
529 int Overlay::handle_opengl()
532 static char *get_pixels_frag =
533 "uniform sampler2D src_tex;\n"
534 "uniform sampler2D dst_tex;\n"
535 "uniform vec2 dst_tex_dimensions;\n"
536 "uniform vec3 chroma_offset;\n"
539 " vec4 result_color;\n"
540 " vec4 dst_color = texture2D(dst_tex, gl_FragCoord.xy / dst_tex_dimensions);\n"
541 " vec4 src_color = texture2D(src_tex, gl_TexCoord[0].st);\n"
542 " src_color.rgb -= chroma_offset;\n"
543 " dst_color.rgb -= chroma_offset;\n";
545 static char *put_pixels_frag =
546 " result_color.rgb += chroma_offset;\n"
547 " result_color.rgb = mix(dst_color.rgb, result_color.rgb, src_color.a);\n"
548 " result_color.a = max(src_color.a, dst_color.a);\n"
549 " gl_FragColor = result_color;\n"
552 static char *blend_add_frag =
553 " result_color.rgb = dst_color.rgb + src_color.rgb;\n";
555 static char *blend_max_frag =
556 " result_color.r = max(abs(dst_color.r, src_color.r);\n"
557 " result_color.g = max(abs(dst_color.g, src_color.g);\n"
558 " result_color.b = max(abs(dst_color.b, src_color.b);\n";
560 static char *blend_subtract_frag =
561 " result_color.rgb = dst_color.rgb - src_color.rgb;\n";
564 static char *blend_multiply_frag =
565 " result_color.rgb = dst_color.rgb * src_color.rgb;\n";
567 static char *blend_divide_frag =
568 " result_color.rgb = dst_color.rgb / src_color.rgb;\n"
569 " if(src_color.r == 0.0) result_color.r = 1.0;\n"
570 " if(src_color.g == 0.0) result_color.g = 1.0;\n"
571 " if(src_color.b == 0.0) result_color.b = 1.0;\n";
575 VFrame *dst = get_output(output_layer);
577 dst->enable_opengl();
580 char *shader_stack[] = { 0, 0, 0 };
581 int current_shader = 0;
587 if(config.mode == TRANSFER_REPLACE)
590 src->bind_texture(0);
591 dst->enable_opengl();
599 if(config.mode == TRANSFER_NORMAL)
601 dst->enable_opengl();
604 // Move destination to screen
605 if(dst->get_opengl_state() != VFrame::SCREEN)
608 dst->bind_texture(0);
613 src->bind_texture(0);
614 dst->enable_opengl();
618 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
623 // Read destination back to texture
626 src->enable_opengl();
630 dst->enable_opengl();
632 src->bind_texture(0);
633 dst->bind_texture(1);
636 shader_stack[current_shader++] = get_pixels_frag;
640 case TRANSFER_ADDITION:
641 shader_stack[current_shader++] = blend_add_frag;
643 case TRANSFER_SUBTRACT:
644 shader_stack[current_shader++] = blend_subtract_frag;
646 case TRANSFER_MULTIPLY:
647 shader_stack[current_shader++] = blend_multiply_frag;
649 case TRANSFER_DIVIDE:
650 shader_stack[current_shader++] = blend_divide_frag;
653 shader_stack[current_shader++] = blend_max_frag;
657 shader_stack[current_shader++] = put_pixels_frag;
659 unsigned int shader_id = 0;
660 shader_id = VFrame::make_shader(0,
666 glUseProgram(shader_id);
667 glUniform1i(glGetUniformLocation(shader_id, "src_tex"), 0);
668 glUniform1i(glGetUniformLocation(shader_id, "dst_tex"), 1);
669 if(cmodel_is_yuv(dst->get_color_model()))
670 glUniform3f(glGetUniformLocation(shader_id, "chroma_offset"), 0.0, 0.5, 0.5);
672 glUniform3f(glGetUniformLocation(shader_id, "chroma_offset"), 0.0, 0.0, 0.0);
673 glUniform2f(glGetUniformLocation(shader_id, "dst_tex_dimensions"),
674 (float)dst->get_texture_w(),
675 (float)dst->get_texture_h());
683 glActiveTexture(GL_TEXTURE1);
684 glDisable(GL_TEXTURE_2D);
685 glActiveTexture(GL_TEXTURE0);
686 glDisable(GL_TEXTURE_2D);
688 dst->set_opengl_state(VFrame::SCREEN);
693 char* Overlay::plugin_title() { return N_("Overlay"); }
694 int Overlay::is_realtime() { return 1; }
695 int Overlay::is_multichannel() { return 1; }
696 int Overlay::is_synthesis() { return 1; }
699 NEW_PICON_MACRO(Overlay)
701 SHOW_GUI_MACRO(Overlay, OverlayThread)
703 RAISE_WINDOW_MACRO(Overlay)
705 SET_STRING_MACRO(Overlay);
707 int Overlay::load_configuration()
709 KeyFrame *prev_keyframe;
710 prev_keyframe = get_prev_keyframe(get_source_position());
711 read_data(prev_keyframe);
715 int Overlay::load_defaults()
717 char directory[BCTEXTLEN];
718 // set the default directory
719 sprintf(directory, "%soverlay.rc", BCASTDIR);
722 defaults = new BC_Hash(directory);
725 config.mode = defaults->get("MODE", config.mode);
726 config.direction = defaults->get("DIRECTION", config.direction);
727 config.output_layer = defaults->get("OUTPUT_LAYER", config.output_layer);
731 int Overlay::save_defaults()
733 defaults->update("MODE", config.mode);
734 defaults->update("DIRECTION", config.direction);
735 defaults->update("OUTPUT_LAYER", config.output_layer);
740 void Overlay::save_data(KeyFrame *keyframe)
744 // cause data to be stored directly in text
745 output.set_shared_string(keyframe->data, MESSAGESIZE);
746 output.tag.set_title("OVERLAY");
747 output.tag.set_property("MODE", config.mode);
748 output.tag.set_property("DIRECTION", config.direction);
749 output.tag.set_property("OUTPUT_LAYER", config.output_layer);
751 output.tag.set_title("/OVERLAY");
753 output.terminate_string();
756 void Overlay::read_data(KeyFrame *keyframe)
760 input.set_shared_string(keyframe->data, strlen(keyframe->data));
764 while(!input.read_tag())
766 if(input.tag.title_is("OVERLAY"))
768 config.mode = input.tag.get_property("MODE", config.mode);
769 config.direction = input.tag.get_property("DIRECTION", config.direction);
770 config.output_layer = input.tag.get_property("OUTPUT_LAYER", config.output_layer);
775 void Overlay::update_gui()
779 thread->window->lock_window("Overlay::update_gui");
780 thread->window->mode->set_text(OverlayConfig::mode_to_text(config.mode));
781 thread->window->direction->set_text(OverlayConfig::direction_to_text(config.direction));
782 thread->window->output->set_text(OverlayConfig::output_to_text(config.output_layer));
783 thread->window->unlock_window();