/* * CINELERRA * Copyright (C) 2008 Adam Williams * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "bcdisplayinfo.h" #include "bchash.h" #include "bcsignals.h" #include "clip.h" #include "file.h" #include "filexml.h" #include "interp.h" #include "language.h" #include "lens.h" #include REGISTER_PLUGIN(LensMain) LensConfig::LensConfig() { reset(); } void LensConfig::reset() { for( int i=0; igui = gui; this->plugin = plugin; this->output = output; this->text = text; set_precision(0.01); } int LensSlider::handle_event() { float prev_output = *output; *output = get_value(); text->update(*output); float difference = *output - prev_output; int is_fov = 0; if( plugin->lock ) { for( int i=0; iconfig.fov[i] ) { is_fov = 1; break; } } if( is_fov ) { for( int i=0; iconfig.fov[i] ) { plugin->config.fov[i] += difference; plugin->config.boundaries(); gui->fov_slider[i]->update(plugin->config.fov[i]); gui->fov_text[i]->update(plugin->config.fov[i]); } } } } plugin->send_configure_change(); return 1; } LensText::LensText(LensMain *plugin, LensGUI *gui, LensSlider *slider, float *output, int x, int y) : BC_TextBox(x, y, 100, 1, *output) { this->gui = gui; this->plugin = plugin; this->output = output; this->slider = slider; } int LensText::handle_event() { float prev_output = *output; *output = atof(get_text()); slider->update(*output); float difference = *output - prev_output; int is_fov = 0; if( plugin->lock ) { for( int i=0; iconfig.fov[i] ) { is_fov = 1; break; } } if( is_fov ) { for( int i=0; iconfig.fov[i] ) { plugin->config.fov[i] += difference; plugin->config.boundaries(); gui->fov_slider[i]->update(plugin->config.fov[i]); gui->fov_text[i]->update(plugin->config.fov[i]); } } } } plugin->send_configure_change(); return 1; } LensToggle::LensToggle(LensMain *plugin, int *output, int x, int y, const char *text) : BC_CheckBox(x, y, *output, text) { this->output = output; this->plugin = plugin; } int LensToggle::handle_event() { *output = get_value(); plugin->send_configure_change(); return 1; } LensMode::LensMode(LensMain *plugin, LensGUI *gui, int x, int y) : BC_PopupMenu(x, y, calculate_w(gui), "", 1) { this->plugin = plugin; this->gui = gui; } int LensMode::handle_event() { plugin->config.mode = from_text(get_text()); plugin->send_configure_change(); return 1; } void LensMode::create_objects() { add_item(new BC_MenuItem(to_text(LensConfig::SPHERICAL_SHRINK))); add_item(new BC_MenuItem(to_text(LensConfig::SPHERICAL_STRETCH))); add_item(new BC_MenuItem(to_text(LensConfig::RECTILINEAR_STRETCH))); add_item(new BC_MenuItem(to_text(LensConfig::RECTILINEAR_SHRINK))); update(plugin->config.mode); } void LensMode::update(int mode) { char string[BCTEXTLEN]; sprintf(string, "%s", to_text(mode)); set_text(string); } int LensMode::calculate_w(LensGUI *gui) { int result = 0; result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(LensConfig::SPHERICAL_STRETCH))); result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(LensConfig::SPHERICAL_SHRINK))); result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(LensConfig::RECTILINEAR_STRETCH))); result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(LensConfig::RECTILINEAR_SHRINK))); return result + 50; } int LensMode::from_text(char *text) { if( !strcmp(text, _("Sphere Stretch")) ) return LensConfig::SPHERICAL_STRETCH; else if( !strcmp(text, _("Sphere Shrink")) ) return LensConfig::SPHERICAL_SHRINK; else if( !strcmp(text, _("Rectilinear Stretch")) ) return LensConfig::RECTILINEAR_STRETCH; else if( !strcmp(text, _("Rectilinear Shrink")) ) return LensConfig::RECTILINEAR_SHRINK; return LensConfig::SPHERICAL_STRETCH; } const char* LensMode::to_text(int mode) { switch( mode ) { case LensConfig::SPHERICAL_STRETCH: return _("Sphere Stretch"); case LensConfig::SPHERICAL_SHRINK: return _("Sphere Shrink"); case LensConfig::RECTILINEAR_STRETCH: return _("Rectilinear Stretch"); case LensConfig::RECTILINEAR_SHRINK: return _("Rectilinear Shrink"); } return _("Sphere Stretch"); } // LensPresets::LensPresets(LensMain *plugin, // LensGUI *gui, int x, int y, int w) // : BC_PopupMenu(x, y, w, "", 1) // { // this->plugin = plugin; // this->gui = gui; // } // // int LensPresets::handle_event() // { // return 1; // } // // void LensPresets::create_objects() // { // // Remove existing items // int total = total_items(); // for( int i=0; iload_presets(); // for( int i=0; ipresets.total; ++i ) { // add_item(new BC_MenuItem(plugin->presets.values[i]->title)); // } // // // Update text // if( plugin->current_preset >= 0 && // plugin->current_preset < plugin->presets.total ) { // set_text(plugin->presets.values[plugin->current_preset]->title); // } // else { // set_text("None"); // } // } // // int LensPresets::from_text(LensMain *plugin, char *text) // { // } // // char* LensPresets::to_text(LensMain *plugin, int preset) // { // } // // void LensPresets::update(int preset) // { // } // // // LensSavePreset::LensSavePreset(LensMain *plugin, LensGUI *gui, int x, int y) // : BC_GenericButton(x, y, _("Save Preset")) // { // this->plugin = plugin; // this->gui = gui; // } // // int LensSavePreset::handle_event() // { // } // // // LensDeletePreset::LensDeletePreset(LensMain *plugin, LensGUI *gui, int x, int y) // : BC_GenericButton(x, y, _("Delete Preset")) // { // } // // int LensDeletePreset::handle_event() // { // } // // // LensPresetText::LensPresetText(LensMain *plugin, LensGUI *gui, int x, int y, int w) // : BC_TextBox(x, y, w, 1, "") // { // this->plugin = plugin; // this->gui = gui; // } // // int LensPresetText::handle_event() // { // } LensInterpItem::LensInterpItem(const char *text, int id) : BC_MenuItem(text) { this->id = id; } int LensInterpItem::handle_event() { LensInterp *interp = (LensInterp *)get_popup_menu(); interp->set_value(id); LensMain *plugin = interp->plugin; plugin->config.interp = id; plugin->send_configure_change(); return 1; } LensInterp::LensInterp(LensMain *plugin, int x, int y) : BC_PopupMenu(x, y, 120, "") { this->plugin = plugin; } void LensInterp::create_objects() { add_item(new LensInterpItem(_("Default"), LensConfig::INTERP_DEFAULT)); add_item(new LensInterpItem(_("Nearest"), LensConfig::INTERP_NEAREST)); add_item(new LensInterpItem(_("BiLinear"), LensConfig::INTERP_BILINEAR)); add_item(new LensInterpItem(_("BiCubic"), LensConfig::INTERP_BICUBIC)); set_value(plugin->config.interp); } void LensInterp::set_value(int id) { for( int i=0, n=total_items(); iid == id ) { set_text(item->get_text()); value = id; return; } } } int LensInterp::get_value() { return value; } LensReset::LensReset(LensMain *plugin, LensGUI *gui, int x, int y) : BC_GenericButton(x, y, _("Reset")) { this->plugin = plugin; this->gui = gui; } int LensReset::handle_event() { plugin->config.reset(); gui->update_gui(); plugin->send_configure_change(); return 1; } LensGUI::LensGUI(LensMain *plugin) : PluginClientWindow(plugin, 350, 550, 350, 550, 0) { this->plugin = plugin; } LensGUI::~LensGUI() { } void LensGUI::create_objects() { int x = 10; int y = 10; int x1; BC_Title *title = 0; LensToggle *toggle; for( int i=0; iget_h() + 5; add_tool(fov_slider[i] = new LensSlider(plugin, this, 0, &plugin->config.fov[i], x, y, 0.0001, 1.0)); x1 = x + fov_slider[i]->get_w() + 5; add_tool(fov_text[i] = new LensText(plugin, this, fov_slider[i], &plugin->config.fov[i], x1, y)); fov_slider[i]->text = fov_text[i]; y += fov_text[i]->get_h() + 5; } add_tool(toggle = new LensToggle(plugin, &plugin->lock, x, y, _("Lock"))); y += toggle->get_h() + 10; BC_Bar *bar; add_tool(bar = new BC_Bar(x, y, get_w() - x * 2)); y += bar->get_h() + 5; add_tool(title = new BC_Title(x, y, _("Aspect Ratio:"))); y += title->get_h() + 5; add_tool(aspect_slider = new LensSlider(plugin, this, 0, &plugin->config.aspect, x, y, 0.333, 3.0)); x1 = x + aspect_slider->get_w() + 5; add_tool(aspect_text = new LensText(plugin, this, aspect_slider, &plugin->config.aspect, x1, y)); aspect_slider->text = aspect_text; y += aspect_text->get_h() + 5; add_tool(title = new BC_Title(x, y, _("Radius:"))); y += title->get_h() + 5; add_tool(radius_slider = new LensSlider(plugin, this, 0, &plugin->config.radius, x, y, 0.333, 3.0)); x1 = x + radius_slider->get_w() + 5; add_tool(radius_text = new LensText(plugin, this, radius_slider, &plugin->config.radius, x1, y)); radius_slider->text = radius_text; y += radius_text->get_h() + 5; add_tool(title = new BC_Title(x, y, _("Center X:"))); y += title->get_h() + 5; add_tool(centerx_slider = new LensSlider(plugin, this, 0, &plugin->config.center_x, x, y, 0.0, 99.0)); x1 = x + centerx_slider->get_w() + 5; add_tool(centerx_text = new LensText(plugin, this, centerx_slider, &plugin->config.center_x, x1, y)); centerx_slider->text = centerx_text; centerx_slider->set_precision(1.0); y += centerx_text->get_h() + 5; add_tool(title = new BC_Title(x, y, _("Center Y:"))); y += title->get_h() + 5; add_tool(centery_slider = new LensSlider(plugin, this, 0, &plugin->config.center_y, x, y, 0.0, 99.0)); x1 = x + centery_slider->get_w() + 5; add_tool(centery_text = new LensText(plugin, this, centery_slider, &plugin->config.center_y, x1, y)); centery_slider->text = centery_text; centery_slider->set_precision(1.0); y += centery_text->get_h() + 10; add_tool(bar = new BC_Bar(x, y, get_w() - x * 2)); y += bar->get_h() + 5; // add_tool(reverse = new LensToggle(plugin, // &plugin->config.reverse, x, y, _("Reverse"))); // y += reverse->get_h() + 5; add_tool(draw_guides = new LensToggle(plugin, &plugin->config.draw_guides, x, y, _("Draw center"))); y += draw_guides->get_h() + 5; add_tool(title = new BC_Title(x, y, _("Mode:"))); add_tool(mode = new LensMode(plugin, this, x + title->get_w() + 5, y)); mode->create_objects(); y += mode->get_h() + 5; add_tool(title = new BC_Title(x, y, _("Interp:"))); x1 = x + title->get_w() + 5; add_tool(interp = new LensInterp(plugin, x1, y)); interp->create_objects(); y += interp->get_h() + 5; add_tool(reset = new LensReset(plugin, this, x, y)); y += reset->get_h() + 5; // add_tool(title = new BC_Title(x, y, _("Preset:"))); // add_tool(presets = new LensPresets(plugin, this, // x + title->get_w() + 5, y, get_w() - x - title->get_w() - 50)); // presets->create_objects(); // y += presets->get_h() + 5; // // add_tool(save_preset = new LensSavePreset(plugin, this, x, y)); // add_tool(preset_text = new LensPresetText(plugin, this, // x + save_preset->get_w() + 5, y, // get_w() - x - save_preset->get_w() - 10)); // y += preset_text->get_h() + 5; // add_tool(delete_preset = new LensDeletePreset(plugin, this, x, y)); show_window(); flush(); } LensMain::LensMain(PluginServer *server) : PluginVClient(server) { engine = 0; lock = 0; current_preset = -1; } LensMain::~LensMain() { delete engine; presets.remove_all_objects(); } NEW_WINDOW_MACRO(LensMain, LensGUI) LOAD_CONFIGURATION_MACRO(LensMain, LensConfig) int LensMain::is_realtime() { return 1; } const char* LensMain::plugin_title() { return N_("Lens"); } void LensMain::update_gui() { if( !thread ) return; if( !load_configuration() ) return; ((LensGUI *)thread->window)->lock_window("LensMain::update_gui"); LensGUI *gui = (LensGUI *)thread->window; gui->update_gui(); gui->unlock_window(); } void LensGUI::update_gui() { LensConfig &config = plugin->config; for( int i=0; iupdate(config.fov[i]); fov_text[i]->update(config.fov[i]); } aspect_slider->update(config.aspect); aspect_text->update(config.aspect); radius_slider->update(config.radius); radius_text->update(config.radius); centerx_slider->update(config.center_x); centerx_text->update(config.center_x); centery_slider->update(config.center_y); centery_text->update(config.center_y); mode->update(config.mode); draw_guides->update(config.draw_guides); interp->set_value(config.interp); } //void LensMain::save_presets() //{ // char path[BCTEXTLEN], string[BCTEXTLEN]; // sprintf(path, "%s/lenspresets.rc", File::get_config_path()); // BC_Hash *defaults = new BC_Hash(path); // //// Save presets // defaults->update("TOTAL_PRESETS", presets.total); // for( int i=0; iupdate(string, preset->title); // // for( int j=0; jupdate(string, preset->fov[j]); // } // // sprintf(string, "ASPECT_%d", i); // defaults->update(string, preset->aspect); // sprintf(string, "RADIUS_%d", i); // defaults->update(string, preset->radius); // sprintf(string, "MODE_%d", i); // defaults->update(string, preset->mode); // } // // defaults->save(); // delete defaults; //} void LensMain::save_data(KeyFrame *keyframe) { FileXML output; char string[BCTEXTLEN]; // cause data to be stored directly in text output.set_shared_output(keyframe->xbuf); output.tag.set_title("LENS"); for( int i = 0; i < FOV_CHANNELS; ++i ) { sprintf(string, "FOCAL_LENGTH%d", i); output.tag.set_property(string, config.fov[i]); } output.tag.set_property("ASPECT", config.aspect); output.tag.set_property("RADIUS", config.radius); output.tag.set_property("MODE", config.mode); output.tag.set_property("INTERP", config.interp); output.tag.set_property("CENTER_X", config.center_x); output.tag.set_property("CENTER_Y", config.center_y); output.tag.set_property("DRAW_GUIDES", config.draw_guides); output.append_tag(); output.tag.set_title("/LENS"); output.append_tag(); output.append_newline(); output.terminate_string(); } void LensMain::read_data(KeyFrame *keyframe) { FileXML input; char string[BCTEXTLEN]; input.set_shared_input(keyframe->xbuf); int result = 0; while(!result) { result = input.read_tag(); if( !result ) { if( input.tag.title_is("LENS") ) { for( int i=0; iget_w(), frame->get_h(), frame->get_color_model()); read_frame(input, 0, start_position, frame_rate, use_opengl); if( use_opengl ) { run_opengl(); return 0; } if( !engine ) engine = new LensEngine(this); engine->process_packages(); if( config.draw_guides ) { // Draw center #define CENTER_H 20 #define CENTER_W 20 #define DRAW_GUIDES(components, type, max) \ { \ type **rows = (type**)get_output()->get_rows(); \ if( (center_x >= 0 && center_x < w) || (center_y >= 0 && center_y < h) ) { \ type *hrow = rows[center_y] + components * (center_x - CENTER_W / 2); \ for( int i=center_x-CENTER_W/2; i<=center_x+CENTER_W/2; ++i ) { \ if( i >= 0 && i < w ) { \ hrow[0] = max - hrow[0]; \ hrow[1] = max - hrow[1]; \ hrow[2] = max - hrow[2]; \ hrow += components; \ } \ } \ \ for( int i=center_y-CENTER_H/2; i<=center_y+CENTER_H/2; ++i ) { \ if( i >= 0 && i < h ) { \ type *vrow = rows[i] + center_x * components; \ vrow[0] = max - vrow[0]; \ vrow[1] = max - vrow[1]; \ vrow[2] = max - vrow[2]; \ } \ } \ } \ } int w = get_output()->get_w(); int h = get_output()->get_h(); int center_x = (int)(config.center_x * w / 100); int center_y = (int)(config.center_y * h / 100); switch( get_output()->get_color_model() ) { case BC_RGB_FLOAT: DRAW_GUIDES(3, float, 1.0) break; case BC_RGBA_FLOAT: DRAW_GUIDES(4, float, 1.0) break; case BC_RGB888: DRAW_GUIDES(3, unsigned char, 0xff) break; case BC_RGBA8888: DRAW_GUIDES(4, unsigned char, 0xff) break; case BC_YUV888: DRAW_GUIDES(3, unsigned char, 0xff) break; case BC_YUVA8888: DRAW_GUIDES(4, unsigned char, 0xff) break; } } return 0; } int LensMain::handle_opengl() { #ifdef HAVE_GL static const char *shrink_frag = "uniform sampler2D tex;\n" "uniform vec2 texture_extents;\n" "uniform vec2 image_extents;\n" "uniform vec2 aspect;\n" "uniform vec2 center_coord;\n" "uniform vec4 border_color;\n" "uniform vec4 r;\n" "uniform vec4 max_z;\n" "void main()\n" "{\n" " vec2 outcoord = gl_TexCoord[0].st * texture_extents;\n" " vec2 coord_diff = outcoord - center_coord;\n" " if( coord_diff.x == 0.0 && coord_diff.y == 0.0 )\n" " {\n" " gl_FragColor = texture2D(tex, outcoord);\n" " }\n" " else\n" " {\n" " float z = sqrt(coord_diff.x * coord_diff.x +\n" " coord_diff.y * coord_diff.y);\n" " float a2 = atan(coord_diff.y, coord_diff.x);\n" " vec4 a1 = asin(vec4(z, z, z, z) / r);\n" " vec4 z_in = a1 * max_z * 2.0 / 3.14159;\n" " vec4 in_x;\n" " vec4 in_y;\n" " in_x = z_in * cos(a2) * aspect.x + center_coord.x;\n" " in_y = z_in * sin(a2) * aspect.y + center_coord.y;\n" " if( z > r.r || in_x.r < 0.0 || in_x.r >= image_extents.x || in_y.r < 0.0 || in_y.r >= image_extents.y )\n" " gl_FragColor.r = border_color.r;\n" " else\n" " gl_FragColor.r = texture2D(tex, vec2(in_x.r, in_y.r) / texture_extents).r;\n" " if( z > r.g || in_x.g < 0.0 || in_x.g >= image_extents.x || in_y.g < 0.0 || in_y.g >= image_extents.y )\n" " gl_FragColor.g = border_color.g;\n" " else\n" " gl_FragColor.g = texture2D(tex, vec2(in_x.g, in_y.g) / texture_extents).g;\n" " if( z > r.b || in_x.b < 0.0 || in_x.b >= image_extents.x || in_y.b < 0.0 || in_y.b >= image_extents.y )\n" " gl_FragColor.b = border_color.b;\n" " else\n" " gl_FragColor.b = texture2D(tex, vec2(in_x.b, in_y.b) / texture_extents).b;\n" " if( z > r.a || in_x.a < 0.0 || in_x.a >= image_extents.x || in_y.a < 0.0 || in_y.a >= image_extents.y )\n" " gl_FragColor.a = border_color.a;\n" " else\n" " gl_FragColor.a = texture2D(tex, vec2(in_x.a, in_y.a) / texture_extents).a;\n" " }\n" "}\n"; static const char *stretch_frag = "uniform sampler2D tex;\n" "uniform vec2 texture_extents;\n" "uniform vec2 image_extents;\n" "uniform vec2 aspect;\n" "uniform vec2 center_coord;\n" "uniform vec4 border_color;\n" "uniform vec4 r;\n" "void main()\n" "{\n" " vec2 outcoord = gl_TexCoord[0].st * texture_extents;\n" " vec2 coord_diff = outcoord - center_coord;\n" " float z = sqrt(coord_diff.x * coord_diff.x +\n" " coord_diff.y * coord_diff.y);\n" " vec4 a1 = (vec4(z, z, z, z) / (3.14159 * r / 2.0)) * (3.14159 / 2.0);\n" " vec4 z_in = r * sin(a1);\n" " float a2;\n" " if( coord_diff.x == 0.0 )\n" " {\n" " if( coord_diff.y < 0.0 )\n" " a2 = 3.0 * 3.14159 / 2.0;\n" " else\n" " a2 = 3.14159 / 2.0;\n" " }\n" " else\n" " a2 = atan(coord_diff.y, coord_diff.x);\n" " vec4 in_x;\n" " vec4 in_y;\n" " in_x = z_in * cos(a2) * aspect.x + center_coord.x;\n" " in_y = z_in * sin(a2) * aspect.y + center_coord.y;\n" " if( in_x.r < 0.0 || in_x.r >= image_extents.x || in_y.r < 0.0 || in_y.r >= image_extents.y )\n" " gl_FragColor.r = border_color.r;\n" " else\n" " gl_FragColor.r = texture2D(tex, vec2(in_x.r, in_y.r) / texture_extents).r;\n" " if( in_x.g < 0.0 || in_x.g >= image_extents.x || in_y.g < 0.0 || in_y.g >= image_extents.y )\n" " gl_FragColor.g = border_color.g;\n" " else\n" " gl_FragColor.g = texture2D(tex, vec2(in_x.g, in_y.g) / texture_extents).g;\n" " if( in_x.b < 0.0 || in_x.b >= image_extents.x || in_y.b < 0.0 || in_y.b >= image_extents.y )\n" " gl_FragColor.b = border_color.b;\n" " else\n" " gl_FragColor.b = texture2D(tex, vec2(in_x.b, in_y.b) / texture_extents).b;\n" " if( in_x.a < 0.0 || in_x.a >= image_extents.x || in_y.a < 0.0 || in_y.a >= image_extents.y )\n" " gl_FragColor.a = border_color.a;\n" " else\n" " gl_FragColor.a = texture2D(tex, vec2(in_x.a, in_y.a) / texture_extents).a;\n" "}\n"; static const char *rectilinear_stretch_frag = "uniform sampler2D tex;\n" "uniform vec2 texture_extents;\n" "uniform vec2 image_extents;\n" "uniform vec2 aspect;\n" "uniform vec2 center_coord;\n" "uniform vec4 border_color;\n" "uniform vec4 r;\n" "uniform float radius;\n" "void main()\n" "{\n" " vec2 outcoord = gl_TexCoord[0].st * texture_extents;\n" " vec2 coord_diff = outcoord - center_coord;\n" " float z = sqrt(coord_diff.x * coord_diff.x +\n" " coord_diff.y * coord_diff.y);\n" " vec4 radius1 = (vec4(z, z, z, z) / r) * 2.0 * radius;\n" " vec4 z_in = r * atan(radius1) / (3.14159 / 2.0);\n" "\n" " float angle;\n" " if( coord_diff.x == 0.0 )\n" " {\n" " if( coord_diff.y < 0.0 )\n" " angle = 3.0 * 3.14159 / 2.0;\n" " else\n" " angle = 3.14159 / 2.0;\n" " }\n" " else\n" " angle = atan(coord_diff.y, coord_diff.x);\n" " vec4 in_x;\n" " vec4 in_y;\n" "\n" " in_x = z_in * cos(angle) * aspect.x + center_coord.x;\n" " in_y = z_in * sin(angle) * aspect.y + center_coord.y;\n" " if( in_x.r < 0.0 || in_x.r >= image_extents.x || in_y.r < 0.0 || in_y.r >= image_extents.y )\n" " gl_FragColor.r = border_color.r;\n" " else\n" " gl_FragColor.r = texture2D(tex, vec2(in_x.r, in_y.r) / texture_extents).r;\n" " if( in_x.g < 0.0 || in_x.g >= image_extents.x || in_y.g < 0.0 || in_y.g >= image_extents.y )\n" " gl_FragColor.g = border_color.g;\n" " else\n" " gl_FragColor.g = texture2D(tex, vec2(in_x.g, in_y.g) / texture_extents).g;\n" " if( in_x.b < 0.0 || in_x.b >= image_extents.x || in_y.b < 0.0 || in_y.b >= image_extents.y )\n" " gl_FragColor.b = border_color.b;\n" " else\n" " gl_FragColor.b = texture2D(tex, vec2(in_x.b, in_y.b) / texture_extents).b;\n" " if( in_x.a < 0.0 || in_x.a >= image_extents.x || in_y.a < 0.0 || in_y.a >= image_extents.y )\n" " gl_FragColor.a = border_color.a;\n" " else\n" " gl_FragColor.a = texture2D(tex, vec2(in_x.a, in_y.a) / texture_extents).a;\n" "}\n"; static const char *rectilinear_shrink_frag = "uniform sampler2D tex;\n" "uniform vec2 texture_extents;\n" "uniform vec2 image_extents;\n" "uniform vec2 aspect;\n" "uniform vec2 center_coord;\n" "uniform vec4 border_color;\n" "uniform vec4 r;\n" "void main()\n" "{\n" " vec2 outcoord = gl_TexCoord[0].st * texture_extents;\n" " vec2 coord_diff = outcoord - center_coord;\n" " float z = sqrt(coord_diff.x * coord_diff.x +\n" " coord_diff.y * coord_diff.y);\n" " vec4 radius1 = vec4(z, z, z, z) / r;\n" " vec4 z_in = r * tan(radius1) / (3.14159 / 2.0);\n" "\n" " float angle;\n" " if( coord_diff.x == 0.0 )\n" " {\n" " if( coord_diff.y < 0.0 )\n" " angle = 3.0 * 3.14159 / 2.0;\n" " else\n" " angle = 3.14159 / 2.0;\n" " }\n" " else\n" " angle = atan(coord_diff.y, coord_diff.x);\n" " vec4 in_x;\n" " vec4 in_y;\n" "\n" " in_x = z_in * cos(angle) * aspect.x + center_coord.x;\n" " in_y = z_in * sin(angle) * aspect.y + center_coord.y;\n" " if( in_x.r < 0.0 || in_x.r >= image_extents.x || in_y.r < 0.0 || in_y.r >= image_extents.y )\n" " gl_FragColor.r = border_color.r;\n" " else\n" " gl_FragColor.r = texture2D(tex, vec2(in_x.r, in_y.r) / texture_extents).r;\n" " if( in_x.g < 0.0 || in_x.g >= image_extents.x || in_y.g < 0.0 || in_y.g >= image_extents.y )\n" " gl_FragColor.g = border_color.g;\n" " else\n" " gl_FragColor.g = texture2D(tex, vec2(in_x.g, in_y.g) / texture_extents).g;\n" " if( in_x.b < 0.0 || in_x.b >= image_extents.x || in_y.b < 0.0 || in_y.b >= image_extents.y )\n" " gl_FragColor.b = border_color.b;\n" " else\n" " gl_FragColor.b = texture2D(tex, vec2(in_x.b, in_y.b) / texture_extents).b;\n" " if( in_x.a < 0.0 || in_x.a >= image_extents.x || in_y.a < 0.0 || in_y.a >= image_extents.y )\n" " gl_FragColor.a = border_color.a;\n" " else\n" " gl_FragColor.a = texture2D(tex, vec2(in_x.a, in_y.a) / texture_extents).a;\n" "}\n"; get_output()->to_texture(); get_output()->enable_opengl(); unsigned int shader = 0; const char *shader_frag = 0; switch( config.mode ) { case LensConfig::SPHERICAL_SHRINK: shader_frag = shrink_frag; break; case LensConfig::SPHERICAL_STRETCH: shader_frag = stretch_frag; break; case LensConfig::RECTILINEAR_STRETCH: shader_frag = rectilinear_stretch_frag; break; case LensConfig::RECTILINEAR_SHRINK: shader_frag = rectilinear_shrink_frag; break; } if( shader_frag ) shader = VFrame::make_shader(0, shader_frag, 0); if( shader > 0 ) { float border_color[] = { 0, 0, 0, 0 }; if( BC_CModels::is_yuv(get_output()->get_color_model()) ) { border_color[1] = border_color[2] = 0.5; } double x_factor = config.aspect; double y_factor = 1.0 / config.aspect; if( x_factor < 1 ) x_factor = 1; if( y_factor < 1 ) y_factor = 1; glUseProgram(shader); glUniform1i(glGetUniformLocation(shader, "tex"), 0); glUniform2f(glGetUniformLocation(shader, "aspect"), x_factor, y_factor); glUniform2f(glGetUniformLocation(shader, "center_coord"), (GLfloat)get_input()->get_w() * config.center_x / 100.0, (GLfloat)get_input()->get_h() * config.center_y / 100.0); glUniform2f(glGetUniformLocation(shader, "texture_extents"), (GLfloat)get_input()->get_texture_w(), (GLfloat)get_input()->get_texture_h()); glUniform2f(glGetUniformLocation(shader, "image_extents"), (GLfloat)get_input()->get_w(), (GLfloat)get_input()->get_h()); int width = get_output()->get_w(); int height = get_output()->get_h(); float *fov = config.fov; float dim; float max_z; switch( config.mode ) { case LensConfig::SPHERICAL_SHRINK: dim = MAX(width, height) * config.radius; max_z = dim * sqrt(2.0) / 2; glUniform4fv(glGetUniformLocation(shader, "border_color"), 1, (GLfloat*)border_color); glUniform4f(glGetUniformLocation(shader, "max_z"), max_z / fov[0], max_z / fov[1], max_z / fov[2], max_z / fov[3]); glUniform4f(glGetUniformLocation(shader, "r"), (max_z / fov[0]) * 2 / M_PI, (max_z / fov[1]) * 2 / M_PI, (max_z / fov[2]) * 2 / M_PI, (max_z / fov[3]) * 2 / M_PI); break; case LensConfig::SPHERICAL_STRETCH: dim = MAX(width, height) * config.radius; max_z = dim * sqrt(2.0) / 2; glUniform4f(glGetUniformLocation(shader, "r"), max_z / M_PI / (fov[0] / 2.0), max_z / M_PI / (fov[1] / 2.0), max_z / M_PI / (fov[2] / 2.0), max_z / M_PI / (fov[3] / 2.0)); break; case LensConfig::RECTILINEAR_STRETCH: max_z = sqrt(SQR(width) + SQR(height)) / 2; glUniform4f(glGetUniformLocation(shader, "r"), max_z / M_PI / (fov[0] / 2.0), max_z / M_PI / (fov[1] / 2.0), max_z / M_PI / (fov[2] / 2.0), max_z / M_PI / (fov[3] / 2.0)); glUniform1f(glGetUniformLocation(shader, "radius"), config.radius); break; case LensConfig::RECTILINEAR_SHRINK: max_z = MAX(width, height) / 2 * config.radius; glUniform4f(glGetUniformLocation(shader, "r"), max_z / fov[0], max_z / fov[1], max_z / fov[2], max_z / fov[3]); break; } get_output()->init_screen(); get_output()->bind_texture(0); glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); get_output()->draw_texture(); glUseProgram(0); if( config.draw_guides ) { int w = get_output()->get_w(); int h = get_output()->get_h(); int center_x = (int)(config.center_x * w / 100); int center_y = (int)(config.center_y * h / 100); glDisable(GL_TEXTURE_2D); glColor4f(0.0, 0.0, 0.0, 1.0); glBegin(GL_LINES); glVertex3f(center_x, -h + center_y - CENTER_H / 2, 0.0); glVertex3f(center_x, -h + center_y + CENTER_H / 2, 0.0); glEnd(); glBegin(GL_LINES); glVertex3f(center_x - CENTER_W / 2, -h + center_y, 0.0); glVertex3f(center_x + CENTER_W / 2, -h + center_y, 0.0); glEnd(); glColor4f(1.0, 1.0, 1.0, 1.0); glBegin(GL_LINES); glVertex3f(center_x - 1, -h + center_y - CENTER_H / 2 - 1, 0.0); glVertex3f(center_x - 1, -h + center_y + CENTER_H / 2 - 1, 0.0); glEnd(); glBegin(GL_LINES); glVertex3f(center_x - CENTER_W / 2 - 1, -h + center_y - 1, 0.0); glVertex3f(center_x + CENTER_W / 2 - 1, -h + center_y - 1, 0.0); glEnd(); } get_output()->set_opengl_state(VFrame::SCREEN); } #endif return 0; } // do using specified interpolation #define DO_LENS(type) \ int icolor_model = plugin->get_input()->get_color_model(); \ switch( plugin->config.interp ) { \ case LensConfig::INTERP_NEAREST: \ switch( icolor_model ) { \ case BC_RGB888: \ DO_LENS_##type(unsigned char, 3, 0xff, 0x0, nearest); \ break; \ case BC_RGBA8888: \ DO_LENS_##type(unsigned char, 4, 0xff, 0x0, nearest); \ break; \ case BC_RGB_FLOAT: \ DO_LENS_##type(float, 3, 1.0, 0.0, nearest); \ break; \ case BC_RGBA_FLOAT: \ DO_LENS_##type(float, 4, 1.0, 0.0, nearest); \ break; \ case BC_YUV888: \ DO_LENS_##type(unsigned char, 3, 0xff, 0x80, nearest); \ break; \ case BC_YUVA8888: \ DO_LENS_##type(unsigned char, 4, 0xff, 0x80, nearest); \ break; \ } \ break; \ case LensConfig::INTERP_DEFAULT: \ case LensConfig::INTERP_BILINEAR: \ switch( icolor_model ) { \ case BC_RGB888: \ DO_LENS_##type(unsigned char, 3, 0xff, 0x0, bi_linear); \ break; \ case BC_RGBA8888: \ DO_LENS_##type(unsigned char, 4, 0xff, 0x0, bi_linear); \ break; \ case BC_RGB_FLOAT: \ DO_LENS_##type(float, 3, 1.0, 0.0, bi_linear); \ break; \ case BC_RGBA_FLOAT: \ DO_LENS_##type(float, 4, 1.0, 0.0, bi_linear); \ break; \ case BC_YUV888: \ DO_LENS_##type(unsigned char, 3, 0xff, 0x80, bi_linear); \ break; \ case BC_YUVA8888: \ DO_LENS_##type(unsigned char, 4, 0xff, 0x80, bi_linear); \ break; \ } \ break; \ case LensConfig::INTERP_BICUBIC: \ switch( icolor_model ) { \ case BC_RGB888: \ DO_LENS_##type(unsigned char, 3, 0xff, 0x0, bi_cubic); \ break; \ case BC_RGBA8888: \ DO_LENS_##type(unsigned char, 4, 0xff, 0x0, bi_cubic); \ break; \ case BC_RGB_FLOAT: \ DO_LENS_##type(float, 3, 1.0, 0.0, bi_cubic); \ break; \ case BC_RGBA_FLOAT: \ DO_LENS_##type(float, 4, 1.0, 0.0, bi_cubic); \ break; \ case BC_YUV888: \ DO_LENS_##type(unsigned char, 3, 0xff, 0x80, bi_cubic); \ break; \ case BC_YUVA8888: \ DO_LENS_##type(unsigned char, 4, 0xff, 0x80, bi_cubic); \ break; \ } \ break; \ } LensPackage::LensPackage() : LoadPackage() { } LensUnit::LensUnit(LensEngine *engine, LensMain *plugin) : LoadClient(engine) { this->plugin = plugin; } LensUnit::~LensUnit() { } void LensUnit::process_spherical_stretch(LensPackage *pkg) { float *fov = plugin->config.fov; float aspect = plugin->config.aspect; int row1 = pkg->row1; int row2 = pkg->row2; double x_factor = aspect; double y_factor = 1.0 / aspect; if( x_factor < 1 ) x_factor = 1; if( y_factor < 1 ) y_factor = 1; int width = plugin->get_input()->get_w(); int height = plugin->get_input()->get_h(); double dim = MAX(width, height) * plugin->config.radius; double max_z = dim * sqrt(2.0) / 2; double center_x = width * plugin->config.center_x / 100.0; double center_y = height * plugin->config.center_y / 100.0; double r[FOV_CHANNELS]; r[0] = max_z / M_PI / (fov[0] / 2.0); r[1] = max_z / M_PI / (fov[1] / 2.0); r[2] = max_z / M_PI / (fov[2] / 2.0); r[3] = max_z / M_PI / (fov[3] / 2.0); #define DO_LENS_SPHERICAL_STRETCH(type, components, max, chroma, interp) { \ type **in_rows = (type**)plugin->get_temp()->get_rows(); \ type **out_rows = (type**)plugin->get_input()->get_rows(); \ type black[4] = { 0, chroma, chroma, 0 }; \ INTERP_SETUP(in_rows, max, 0,0, width,height); \ \ for( int y=row1; yconfig.fov; float aspect = plugin->config.aspect; int row1 = pkg->row1; int row2 = pkg->row2; int width = plugin->get_input()->get_w(); int height = plugin->get_input()->get_h(); double x_factor = aspect; double y_factor = 1.0 / aspect; if( x_factor < 1 ) x_factor = 1; if( y_factor < 1 ) y_factor = 1; double dim = MAX(width, height) * plugin->config.radius; double max_z[FOV_CHANNELS]; double center_x = width * plugin->config.center_x / 100.0; double center_y = height * plugin->config.center_y / 100.0; double r[FOV_CHANNELS]; // max_z[0] = sqrt(SQR(width) + SQR(height)) / 2 / fov[0]; // max_z[1] = sqrt(SQR(width) + SQR(height)) / 2 / fov[1]; // max_z[2] = sqrt(SQR(width) + SQR(height)) / 2 / fov[2]; // max_z[3] = sqrt(SQR(width) + SQR(height)) / 2 / fov[3]; max_z[0] = dim * sqrt(2.0) / 2 / fov[0]; max_z[1] = dim * sqrt(2.0) / 2 / fov[1]; max_z[2] = dim * sqrt(2.0) / 2 / fov[2]; max_z[3] = dim * sqrt(2.0) / 2 / fov[3]; r[0] = max_z[0] * 2 / M_PI; r[1] = max_z[1] * 2 / M_PI; r[2] = max_z[2] * 2 / M_PI; r[3] = max_z[3] * 2 / M_PI; #define DO_LENS_SPHERICAL_SHRINK(type, components, max, chroma, interp) { \ type **in_rows = (type**)plugin->get_temp()->get_rows(); \ type **out_rows = (type**)plugin->get_input()->get_rows(); \ type black[4] = { 0, chroma, chroma, 0 }; \ INTERP_SETUP(in_rows, max, 0,0, width,height); \ \ for( int y=row1; y r[i] ) { *out_row++ = black[i]; continue; } \ double a1 = asin(z / r[i]); \ double z_in = a1 * max_z[i] * 2 / M_PI; \ float x_in = z_in * cos(a2) * x_factor + center_x; \ float y_in = z_in * sin(a2) * y_factor + center_y; \ interp##_SETUP(type, components, x_in, y_in); \ for( int j=0; jconfig.fov; float aspect = plugin->config.aspect; int row1 = pkg->row1; int row2 = pkg->row2; double x_factor = aspect; double y_factor = 1.0 / aspect; if( x_factor < 1 ) x_factor = 1; if( y_factor < 1 ) y_factor = 1; int width = plugin->get_input()->get_w(); int height = plugin->get_input()->get_h(); // double dim = MAX(width, height) * plugin->config.radius; // double max_z = dim * sqrt(2.0) / 2; double max_z = sqrt(SQR(width) + SQR(height)) / 2; double center_x = width * plugin->config.center_x / 100.0; double center_y = height * plugin->config.center_y / 100.0; double r[FOV_CHANNELS]; r[0] = max_z / M_PI / (fov[0] / 2.0); r[1] = max_z / M_PI / (fov[1] / 2.0); r[2] = max_z / M_PI / (fov[2] / 2.0); r[3] = max_z / M_PI / (fov[3] / 2.0); #define DO_LENS_RECTILINEAR_STRETCH(type, components, max, chroma, interp) { \ type **in_rows = (type**)plugin->get_temp()->get_rows(); \ type **out_rows = (type**)plugin->get_input()->get_rows(); \ type black[4] = { 0, chroma, chroma, 0 }; \ INTERP_SETUP(in_rows, max, 0,0, width,height); \ \ for( int y=row1; yconfig.radius; \ double z_in = r[i] * atan(radius1) / (M_PI / 2); \ double x_in = z_in * cos(angle) * x_factor + center_x; \ double y_in = z_in * sin(angle) * y_factor + center_y; \ interp##_SETUP(type, components, x_in, y_in); \ for( int j=0; jconfig.fov; float aspect = plugin->config.aspect; int row1 = pkg->row1; int row2 = pkg->row2; double x_factor = aspect; double y_factor = 1.0 / aspect; if( x_factor < 1 ) x_factor = 1; if( y_factor < 1 ) y_factor = 1; int width = plugin->get_input()->get_w(); int height = plugin->get_input()->get_h(); double max_z = MAX(width, height) / 2 * plugin->config.radius; double center_x = width * plugin->config.center_x / 100.0; double center_y = height * plugin->config.center_y / 100.0; double r[FOV_CHANNELS]; r[0] = max_z / fov[0]; r[1] = max_z / fov[1]; r[2] = max_z / fov[2]; r[3] = max_z / fov[3]; #define DO_LENS_RECTILINEAR_SHRINK(type, components, max, chroma, interp) { \ type **in_rows = (type**)plugin->get_temp()->get_rows(); \ type **out_rows = (type**)plugin->get_input()->get_rows(); \ type black[4] = { 0, chroma, chroma, 0 }; \ INTERP_SETUP(in_rows, max, 0,0, width,height); \ \ for( int y=row1; yconfig.mode ) { case LensConfig::SPHERICAL_STRETCH: process_spherical_stretch(pkg); break; case LensConfig::SPHERICAL_SHRINK: process_spherical_shrink(pkg); break; case LensConfig::RECTILINEAR_STRETCH: process_rectilinear_stretch(pkg); break; case LensConfig::RECTILINEAR_SHRINK: process_rectilinear_shrink(pkg); break; } } LensEngine::LensEngine(LensMain *plugin) : LoadServer(plugin->PluginClient::smp + 1, plugin->PluginClient::smp + 1) // : LoadServer(1, 1) { this->plugin = plugin; } LensEngine::~LensEngine() { } void LensEngine::init_packages() { int row1 = 0, row2 = 0, n = LoadServer::get_total_packages(); for( int i=0; iget_input()->get_h() * ++i / n; package->row1 = row1; package->row2 = row2; } } LoadClient* LensEngine::new_client() { return new LensUnit(this, plugin); } LoadPackage* LensEngine::new_package() { return new LensPackage; }