/* * 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 "filexml.h" #include "language.h" #include "lens.h" #include REGISTER_PLUGIN(LensMain) LensConfig::LensConfig() { for(int i = 0; i < FOV_CHANNELS; i++) fov[i] = 1.0; aspect = 1.0; radius = 1.0; mode = LensConfig::SHRINK; center_x = 50.0; center_y = 50.0; draw_guides = 0; } int LensConfig::equivalent(LensConfig &that) { for(int i = 0; i < FOV_CHANNELS; i++) if(!EQUIV(fov[i], that.fov[i])) return 0; return EQUIV(aspect, that.aspect) && EQUIV(radius, that.radius) && EQUIV(center_x, that.center_x) && EQUIV(center_y, that.center_y) && mode == that.mode && draw_guides == that.draw_guides; } void LensConfig::copy_from(LensConfig &that) { for(int i = 0; i < FOV_CHANNELS; i++) fov[i] = that.fov[i]; aspect = that.aspect; radius = that.radius; mode = that.mode; center_x = that.center_x; center_y = that.center_y; draw_guides = that.draw_guides; } void LensConfig::interpolate(LensConfig &prev, LensConfig &next, int64_t prev_frame, int64_t next_frame, int64_t current_frame) { double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame); double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame); for(int i = 0; i < FOV_CHANNELS; i++) fov[i] = prev.fov[i] * prev_scale + next.fov[i] * next_scale; aspect = prev.aspect * prev_scale + next.aspect * next_scale; radius = prev.radius * prev_scale + next.radius * next_scale; center_x = prev.center_x * prev_scale + next.center_x * next_scale; center_y = prev.center_y * prev_scale + next.center_y * next_scale; mode = prev.mode; draw_guides = prev.draw_guides; boundaries(); } void LensConfig::boundaries() { CLAMP(center_x, 0.0, 99.0); CLAMP(center_y, 0.0, 99.0); for(int i = 0; i < FOV_CHANNELS; i++) CLAMP(fov[i], 0.0, 1.0); CLAMP(aspect, 0.3, 3.0); CLAMP(radius, 0.3, 3.0); } LensSlider::LensSlider(LensMain *client, LensGUI *gui, LensText *text, float *output, int x, int y, float min, float max) : BC_FSlider(x, y, 0, 200, 200, min, max, *output) { this->gui = gui; this->client = client; 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(client->lock) { for(int i = 0; i < FOV_CHANNELS; i++) { if(output == &client->config.fov[i]) { is_fov = 1; break; } } if(is_fov) { for(int i = 0; i < FOV_CHANNELS; i++) { if(output != &client->config.fov[i]) { client->config.fov[i] += difference; client->config.boundaries(); gui->fov_slider[i]->update(client->config.fov[i]); gui->fov_text[i]->update(client->config.fov[i]); } } } } client->send_configure_change(); return 1; } LensText::LensText(LensMain *client, LensGUI *gui, LensSlider *slider, float *output, int x, int y) : BC_TextBox(x, y, 100, 1, *output) { this->gui = gui; this->client = client; 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(client->lock) { for(int i = 0; i < FOV_CHANNELS; i++) { if(output == &client->config.fov[i]) { is_fov = 1; break; } } if(is_fov) { for(int i = 0; i < FOV_CHANNELS; i++) { if(output != &client->config.fov[i]) { client->config.fov[i] += difference; client->config.boundaries(); gui->fov_slider[i]->update(client->config.fov[i]); gui->fov_text[i]->update(client->config.fov[i]); } } } } client->send_configure_change(); return 1; } LensToggle::LensToggle(LensMain *client, int *output, int x, int y, const char *text) : BC_CheckBox(x, y, *output, text) { this->output = output; this->client = client; } int LensToggle::handle_event() { *output = get_value(); client->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::SHRINK))); add_item(new BC_MenuItem(to_text(LensConfig::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::STRETCH))); result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(LensConfig::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::STRETCH; else if(!strcmp(text, _("Sphere Shrink"))) return LensConfig::SHRINK; else if(!strcmp(text, _("Rectilinear Stretch"))) return LensConfig::RECTILINEAR_STRETCH; else if(!strcmp(text, _("Rectilinear Shrink"))) return LensConfig::RECTILINEAR_SHRINK; return LensConfig::STRETCH; } const char* LensMode::to_text(int mode) { switch(mode) { case LensConfig::STRETCH: return _("Sphere Stretch"); break; case LensConfig::SHRINK: return _("Sphere Shrink"); break; case LensConfig::RECTILINEAR_STRETCH: return _("Rectilinear Stretch"); break; case LensConfig::RECTILINEAR_SHRINK: return _("Rectilinear Shrink"); break; } return _("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; i < total; i++) // { // del_item(); // } // // // Create current items // plugin->load_presets(); // for(int i = 0; i < plugin->presets.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() // { // } LensGUI::LensGUI(LensMain *client) : PluginClientWindow(client, 350, 510, 350, 510, 0) { this->client = client; } LensGUI::~LensGUI() { } void LensGUI::create_objects() { int x = 10; int y = 10; int x1; BC_Title *title = 0; LensToggle *toggle; for(int i = 0; i < FOV_CHANNELS; i++) { switch(i) { case 0: add_tool(title = new BC_Title(x, y, _("R Field of View:"))); break; case 1: add_tool(title = new BC_Title(x, y, _("G Field of View:"))); break; case 2: add_tool(title = new BC_Title(x, y, _("B Field of View:"))); break; case 3: add_tool(title = new BC_Title(x, y, _("A Field of View:"))); break; } y += title->get_h() + 5; add_tool(fov_slider[i] = new LensSlider(client, this, 0, &client->config.fov[i], x, y, 0.0001, 1.0)); x1 = x + fov_slider[i]->get_w() + 5; add_tool(fov_text[i] = new LensText(client, this, fov_slider[i], &client->config.fov[i], x1, y)); fov_slider[i]->text = fov_text[i]; y += fov_text[i]->get_h() + 5; } add_tool(toggle = new LensToggle(client, &client->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(client, this, 0, &client->config.aspect, x, y, 0.333, 3.0)); x1 = x + aspect_slider->get_w() + 5; add_tool(aspect_text = new LensText(client, this, aspect_slider, &client->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(client, this, 0, &client->config.radius, x, y, 0.333, 3.0)); x1 = x + radius_slider->get_w() + 5; add_tool(radius_text = new LensText(client, this, radius_slider, &client->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(client, this, 0, &client->config.center_x, x, y, 0.0, 99.0)); x1 = x + centerx_slider->get_w() + 5; add_tool(centerx_text = new LensText(client, this, centerx_slider, &client->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(client, this, 0, &client->config.center_y, x, y, 0.0, 99.0)); x1 = x + centery_slider->get_w() + 5; add_tool(centery_text = new LensText(client, this, centery_slider, &client->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(client, // &client->config.reverse, // x, // y, // _("Reverse"))); // y += reverse->get_h() + 5; add_tool(draw_guides = new LensToggle(client, &client->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(client, this, x + title->get_w() + 5, y)); mode->create_objects(); y += mode->get_h() + 5; // add_tool(title = new BC_Title(x, y, _("Preset:"))); // add_tool(presets = new LensPresets(client, // 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(client, // this, // x, // y)); // add_tool(preset_text = new LensPresetText(client, // 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(client, // 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 _("Lens"); } void LensMain::update_gui() { if(thread) { if(load_configuration()) { ((LensGUI*)thread->window)->lock_window("LensMain::update_gui"); for(int i = 0; i < FOV_CHANNELS; i++) { ((LensGUI*)thread->window)->fov_slider[i]->update(config.fov[i]); ((LensGUI*)thread->window)->fov_text[i]->update(config.fov[i]); } ((LensGUI*)thread->window)->aspect_slider->update(config.aspect); ((LensGUI*)thread->window)->aspect_text->update(config.aspect); ((LensGUI*)thread->window)->radius_slider->update(config.radius); ((LensGUI*)thread->window)->radius_text->update(config.radius); ((LensGUI*)thread->window)->centerx_slider->update(config.center_x); ((LensGUI*)thread->window)->centerx_text->update(config.center_x); ((LensGUI*)thread->window)->centery_slider->update(config.center_y); ((LensGUI*)thread->window)->centery_text->update(config.center_y); ((LensGUI*)thread->window)->mode->update(config.mode); ((LensGUI*)thread->window)->draw_guides->update(config.draw_guides); ((LensGUI*)thread->window)->unlock_window(); } } } //void LensMain::save_presets() //{ // char path[BCTEXTLEN], string[BCTEXTLEN]; // sprintf(path, "%slenspresets.rc", BCASTDIR); // BC_Hash *defaults = new BC_Hash(path); // //// Save presets // defaults->update("TOTAL_PRESETS", presets.total); // for(int i = 0; i < presets.total; i++) // { // LensPreset *preset = presets.values[i]; // sprintf(string, "TITLE_%d", i); // defaults->update(string, preset->title); // // for(int j = 0; j < FOV_CHANNELS; j++) // { // sprintf(string, "FOCAL_LENGTH_%d_%d", i, j); // defaults->update(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->get_data(), MESSAGESIZE); 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("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->get_data(), strlen(keyframe->get_data())); int result = 0; while(!result) { result = input.read_tag(); if(!result) { if(input.tag.title_is("LENS")) { for(int i = 0; i < FOV_CHANNELS; i++) { sprintf(string, "FOCAL_LENGTH%d", i); config.fov[i] = input.tag.get_property(string, config.fov[i]); } config.aspect = input.tag.get_property("ASPECT", config.aspect); config.radius = input.tag.get_property("RADIUS", config.radius); config.mode = input.tag.get_property("MODE", config.mode); config.center_x = input.tag.get_property("CENTER_X", config.center_x); config.center_y = input.tag.get_property("CENTER_Y", config.center_y); config.draw_guides = input.tag.get_property("DRAW_GUIDES", config.draw_guides); } } } } int LensMain::process_buffer(VFrame *frame, int64_t start_position, double frame_rate) { VFrame *input; load_configuration(); if(get_use_opengl()) { input = frame; } else { input = new_temp(frame->get_w(), frame->get_h(), frame->get_color_model()); } read_frame(input, 0, start_position, frame_rate, get_use_opengl()); if(get_use_opengl()) { run_opengl(); return 0; } else { 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_W / 2; i <= center_y + CENTER_W / 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" "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"; get_output()->to_texture(); get_output()->enable_opengl(); unsigned int frag_shader = 0; switch(config.mode) { case LensConfig::SHRINK: frag_shader = VFrame::make_shader(0, shrink_frag, 0); break; case LensConfig::STRETCH: frag_shader = VFrame::make_shader(0, stretch_frag, 0); break; case LensConfig::RECTILINEAR_STRETCH: frag_shader = VFrame::make_shader(0, rectilinear_stretch_frag, 0); break; case LensConfig::RECTILINEAR_SHRINK: frag_shader = VFrame::make_shader(0, rectilinear_shrink_frag, 0); break; } if(frag_shader > 0) { float border_color[] = { 0, 0, 0, 0 }; if(BC_CModels::is_yuv(get_output()->get_color_model())) { border_color[1] = 0.5; 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(frag_shader); glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0); glUniform2f(glGetUniformLocation(frag_shader, "aspect"), x_factor, y_factor); glUniform2f(glGetUniformLocation(frag_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(frag_shader, "texture_extents"), (GLfloat)get_input()->get_texture_w(), (GLfloat)get_input()->get_texture_h()); glUniform2f(glGetUniformLocation(frag_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::SHRINK: dim = MAX(width, height) * config.radius; max_z = dim * sqrt(2.0) / 2; glUniform4fv(glGetUniformLocation(frag_shader, "border_color"), 1, (GLfloat*)border_color); glUniform4f(glGetUniformLocation(frag_shader, "max_z"), max_z / fov[0], max_z / fov[1], max_z / fov[2], max_z / fov[3]); glUniform4f(glGetUniformLocation(frag_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::STRETCH: dim = MAX(width, height) * config.radius; max_z = dim * sqrt(2.0) / 2; glUniform4f(glGetUniformLocation(frag_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(frag_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(frag_shader, "radius"), config.radius); break; case LensConfig::RECTILINEAR_SHRINK: max_z = sqrt(SQR(width) + SQR(height)) / 2; glUniform4f(glGetUniformLocation(frag_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(frag_shader, "radius"), config.radius); 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; } LensPackage::LensPackage() : LoadPackage() {} LensUnit::LensUnit(LensEngine *engine, LensMain *plugin) : LoadClient(engine) { this->plugin = plugin; } LensUnit::~LensUnit() { } void LensUnit::process_shrink(LensPackage *pkg) { float *fov = plugin->config.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_SHRINK(type, components, chroma) \ { \ 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 }; \ \ for(int y = row1; y < row2; y++) \ { \ type *out_row = out_rows[y]; \ type *in_row = in_rows[y]; \ double y_diff = y - center_y; \ \ for(int x = 0; x < width; x++) \ { \ double x_diff = x - center_x; \ if(!x_diff && !y_diff) \ { \ type *in_pixel = in_row + x * components; \ for(int c = 0; c < components; c++) \ { \ *out_row++ = *in_pixel++; \ } \ continue; \ } \ \ double z = sqrt(x_diff * x_diff + y_diff * y_diff); \ double a2 = atan(y_diff / x_diff); \ if(x_diff < 0.0) a2 += M_PI; \ \ for(int i = 0; i < components; i++) \ { \ if(z > r[i]) \ { \ *out_row++ = black[i]; \ } \ else \ { \ 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; \ \ if(x_in < 0.0 || x_in >= width - 1 || \ y_in < 0.0 || y_in >= height - 1) \ { \ *out_row++ = black[i]; \ } \ else \ { \ float y1_fraction = y_in - floor(y_in); \ float y2_fraction = 1.0 - y1_fraction; \ float x1_fraction = x_in - floor(x_in); \ float x2_fraction = 1.0 - x1_fraction; \ type *in_pixel1 = in_rows[(int)y_in] + (int)x_in * components; \ type *in_pixel2 = in_rows[(int)y_in + 1] + (int)x_in * components; \ *out_row++ = (type)(in_pixel1[i] * x2_fraction * y2_fraction + \ in_pixel2[i] * x2_fraction * y1_fraction + \ in_pixel1[i + components] * x1_fraction * y2_fraction + \ in_pixel2[i + components] * x1_fraction * y1_fraction); \ } \ } \ } \ } \ } \ \ type *out_pixel = out_rows[(int)center_y] + (int)center_x * components; \ type *in_pixel = in_rows[(int)center_y] + (int)center_x * components; \ for(int c = 0; c < components; c++) \ { \ *out_pixel++ = *in_pixel++; \ } \ } switch(plugin->get_input()->get_color_model()) { case BC_RGB888: DO_LENS_SHRINK(unsigned char, 3, 0x0); break; case BC_RGBA8888: DO_LENS_SHRINK(unsigned char, 4, 0x0); break; case BC_RGB_FLOAT: DO_LENS_SHRINK(float, 3, 0.0); break; case BC_RGBA_FLOAT: DO_LENS_SHRINK(float, 4, 0.0); break; case BC_YUV888: DO_LENS_SHRINK(unsigned char, 3, 0x80); break; case BC_YUVA8888: DO_LENS_SHRINK(unsigned char, 4, 0x80); break; } } void LensUnit::process_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_STRETCH(type, components, chroma) \ { \ 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 }; \ \ for(int y = row1; y < row2; y++) \ { \ type *out_row = out_rows[y]; \ double y_diff = y - center_y; \ \ for(int x = 0; x < width; x++) \ { \ double x_diff = (x - center_x); \ double z = sqrt(x_diff * x_diff + \ y_diff * y_diff); \ double a2; \ if(x == center_x) \ { \ if(y < center_y) \ a2 = 3 * M_PI / 2; \ else \ a2 = M_PI / 2; \ } \ else \ { \ a2 = atan(y_diff / x_diff); \ } \ if(x_diff < 0.0) a2 += M_PI; \ \ for(int i = 0; i < components; i++) \ { \ double a1 = (z / (M_PI * r[i] / 2)) * (M_PI / 2); \ double z_in = r[i] * sin(a1); \ \ double x_in = z_in * cos(a2) * x_factor + center_x; \ double y_in = z_in * sin(a2) * y_factor + center_y; \ \ if(x_in < 0.0 || x_in >= width - 1 || \ y_in < 0.0 || y_in >= height - 1) \ { \ *out_row++ = black[i]; \ } \ else \ { \ float y1_fraction = y_in - floor(y_in); \ float y2_fraction = 1.0 - y1_fraction; \ float x1_fraction = x_in - floor(x_in); \ float x2_fraction = 1.0 - x1_fraction; \ type *in_pixel1 = in_rows[(int)y_in] + (int)x_in * components; \ type *in_pixel2 = in_rows[(int)y_in + 1] + (int)x_in * components; \ *out_row++ = (type)(in_pixel1[i] * x2_fraction * y2_fraction + \ in_pixel2[i] * x2_fraction * y1_fraction + \ in_pixel1[i + components] * x1_fraction * y2_fraction + \ in_pixel2[i + components] * x1_fraction * y1_fraction); \ } \ } \ } \ } \ \ type *out_pixel = out_rows[(int)center_y] + (int)center_x * components; \ type *in_pixel = in_rows[(int)center_y] + (int)center_x * components; \ for(int c = 0; c < components; c++) \ { \ *out_pixel++ = *in_pixel++; \ } \ } switch(plugin->get_input()->get_color_model()) { case BC_RGB888: DO_LENS_STRETCH(unsigned char, 3, 0x0); break; case BC_RGBA8888: DO_LENS_STRETCH(unsigned char, 4, 0x0); break; case BC_RGB_FLOAT: DO_LENS_STRETCH(float, 3, 0.0); break; case BC_RGBA_FLOAT: DO_LENS_STRETCH(float, 4, 0.0); break; case BC_YUV888: DO_LENS_STRETCH(unsigned char, 3, 0x80); break; case BC_YUVA8888: DO_LENS_STRETCH(unsigned char, 4, 0x80); break; } } void LensUnit::process_rectilinear_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 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, chroma) \ { \ 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 }; \ \ for(int y = row1; y < row2; y++) \ { \ type *out_row = out_rows[y]; \ double y_diff = y - center_y; \ \ for(int x = 0; x < width; x++) \ { \ double x_diff = (x - center_x); \ /* Compute magnitude */ \ double z = sqrt(x_diff * x_diff + \ y_diff * y_diff); \ /* Compute angle */ \ double angle; \ if(x == center_x) \ { \ if(y < center_y) \ angle = 3 * M_PI / 2; \ else \ angle = M_PI / 2; \ } \ else \ { \ angle = atan(y_diff / x_diff); \ } \ if(x_diff < 0.0) angle += M_PI; \ \ for(int i = 0; i < components; i++) \ { \ /* Compute new radius */ \ double radius1 = (z / r[i]) * 2 * plugin->config.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; \ \ if(x_in < 0.0 || x_in >= width - 1 || \ y_in < 0.0 || y_in >= height - 1) \ { \ *out_row++ = black[i]; \ } \ else \ { \ float y1_fraction = y_in - floor(y_in); \ float y2_fraction = 1.0 - y1_fraction; \ float x1_fraction = x_in - floor(x_in); \ float x2_fraction = 1.0 - x1_fraction; \ type *in_pixel1 = in_rows[(int)y_in] + (int)x_in * components; \ type *in_pixel2 = in_rows[(int)y_in + 1] + (int)x_in * components; \ *out_row++ = (type)(in_pixel1[i] * x2_fraction * y2_fraction + \ in_pixel2[i] * x2_fraction * y1_fraction + \ in_pixel1[i + components] * x1_fraction * y2_fraction + \ in_pixel2[i + components] * x1_fraction * y1_fraction); \ } \ } \ } \ } \ \ type *out_pixel = out_rows[(int)center_y] + (int)center_x * components; \ type *in_pixel = in_rows[(int)center_y] + (int)center_x * components; \ for(int c = 0; c < components; c++) \ { \ *out_pixel++ = *in_pixel++; \ } \ } switch(plugin->get_input()->get_color_model()) { case BC_RGB888: DO_LENS_RECTILINEAR_STRETCH(unsigned char, 3, 0x0); break; case BC_RGBA8888: DO_LENS_RECTILINEAR_STRETCH(unsigned char, 4, 0x0); break; case BC_RGB_FLOAT: DO_LENS_RECTILINEAR_STRETCH(float, 3, 0.0); break; case BC_RGBA_FLOAT: DO_LENS_RECTILINEAR_STRETCH(float, 4, 0.0); break; case BC_YUV888: DO_LENS_RECTILINEAR_STRETCH(unsigned char, 3, 0x80); break; case BC_YUVA8888: DO_LENS_RECTILINEAR_STRETCH(unsigned char, 4, 0x80); break; } } void LensUnit::process_rectilinear_shrink(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 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, chroma) \ { \ 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 }; \ \ for(int y = row1; y < row2; y++) \ { \ type *out_row = out_rows[y]; \ double y_diff = y - center_y; \ \ for(int x = 0; x < width; x++) \ { \ double x_diff = (x - center_x); \ /* Compute magnitude */ \ double z = sqrt(x_diff * x_diff + \ y_diff * y_diff); \ /* Compute angle */ \ double angle; \ if(x == center_x) \ { \ if(y < center_y) \ angle = 3 * M_PI / 2; \ else \ angle = M_PI / 2; \ } \ else \ { \ angle = atan(y_diff / x_diff); \ } \ if(x_diff < 0.0) angle += M_PI; \ \ for(int i = 0; i < components; i++) \ { \ /* Compute new radius */ \ double radius1 = z / r[i]; \ double z_in = r[i] * tan(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; \ \ if(x_in < 0.0 || x_in >= width - 1 || \ y_in < 0.0 || y_in >= height - 1) \ { \ *out_row++ = black[i]; \ } \ else \ { \ float y1_fraction = y_in - floor(y_in); \ float y2_fraction = 1.0 - y1_fraction; \ float x1_fraction = x_in - floor(x_in); \ float x2_fraction = 1.0 - x1_fraction; \ type *in_pixel1 = in_rows[(int)y_in] + (int)x_in * components; \ type *in_pixel2 = in_rows[(int)y_in + 1] + (int)x_in * components; \ *out_row++ = (type)(in_pixel1[i] * x2_fraction * y2_fraction + \ in_pixel2[i] * x2_fraction * y1_fraction + \ in_pixel1[i + components] * x1_fraction * y2_fraction + \ in_pixel2[i + components] * x1_fraction * y1_fraction); \ } \ } \ } \ } \ \ type *out_pixel = out_rows[(int)center_y] + (int)center_x * components; \ type *in_pixel = in_rows[(int)center_y] + (int)center_x * components; \ for(int c = 0; c < components; c++) \ { \ *out_pixel++ = *in_pixel++; \ } \ } switch(plugin->get_input()->get_color_model()) { case BC_RGB888: DO_LENS_RECTILINEAR_SHRINK(unsigned char, 3, 0x0); break; case BC_RGBA8888: DO_LENS_RECTILINEAR_SHRINK(unsigned char, 4, 0x0); break; case BC_RGB_FLOAT: DO_LENS_RECTILINEAR_SHRINK(float, 3, 0.0); break; case BC_RGBA_FLOAT: DO_LENS_RECTILINEAR_SHRINK(float, 4, 0.0); break; case BC_YUV888: DO_LENS_RECTILINEAR_SHRINK(unsigned char, 3, 0x80); break; case BC_YUVA8888: DO_LENS_RECTILINEAR_SHRINK(unsigned char, 4, 0x80); break; } } void LensUnit::process_package(LoadPackage *package) { LensPackage *pkg = (LensPackage*)package; switch(plugin->config.mode) { case LensConfig::SHRINK: process_shrink(pkg); break; case LensConfig::STRETCH: process_stretch(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() { for(int i = 0; i < LoadServer::get_total_packages(); i++) { LensPackage *package = (LensPackage*)LoadServer::get_package(i); package->row1 = plugin->get_input()->get_h() * i / LoadServer::get_total_packages(); package->row2 = plugin->get_input()->get_h() * (i + 1) / LoadServer::get_total_packages(); } } LoadClient* LensEngine::new_client() { return new LensUnit(this, plugin); } LoadPackage* LensEngine::new_package() { return new LensPackage; }