4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "bcdisplayinfo.h"
24 #include "bcsignals.h"
38 REGISTER_PLUGIN(LensMain)
40 LensConfig::LensConfig()
45 void LensConfig::reset()
47 for( int i=0; i<FOV_CHANNELS; ++i )
51 mode = SPHERICAL_SHRINK;
52 interp = INTERP_DEFAULT;
58 int LensConfig::equivalent(LensConfig &that)
60 for( int i=0; i<FOV_CHANNELS; ++i )
61 if( !EQUIV(fov[i], that.fov[i]) ) return 0;
62 return EQUIV(aspect, that.aspect) &&
63 EQUIV(radius, that.radius) &&
64 EQUIV(center_x, that.center_x) &&
65 EQUIV(center_y, that.center_y) &&
67 interp == that.interp &&
68 draw_guides == that.draw_guides;
71 void LensConfig::copy_from(LensConfig &that)
73 for( int i=0; i<FOV_CHANNELS; ++i )
79 center_x = that.center_x;
80 center_y = that.center_y;
81 draw_guides = that.draw_guides;
84 void LensConfig::interpolate(LensConfig &prev, LensConfig &next,
85 int64_t prev_frame, int64_t next_frame, int64_t current_frame)
87 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
88 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
90 for( int i=0; i<FOV_CHANNELS; ++i )
91 fov[i] = prev.fov[i] * prev_scale + next.fov[i] * next_scale;
92 aspect = prev.aspect * prev_scale + next.aspect * next_scale;
93 radius = prev.radius * prev_scale + next.radius * next_scale;
94 center_x = prev.center_x * prev_scale + next.center_x * next_scale;
95 center_y = prev.center_y * prev_scale + next.center_y * next_scale;
98 draw_guides = prev.draw_guides;
103 void LensConfig::boundaries()
105 CLAMP(center_x, 0.0, 99.0);
106 CLAMP(center_y, 0.0, 99.0);
107 for( int i=0; i<FOV_CHANNELS; ++i )
108 CLAMP(fov[i], 0.0, 1.0);
109 CLAMP(aspect, 0.3, 3.0);
110 CLAMP(radius, 0.3, 3.0);
116 LensSlider::LensSlider(LensMain *plugin, LensGUI *gui,
117 LensText *text, float *output, int x, int y, float min, float max)
118 : BC_FSlider(x, y, 0, 200, 200, min, max, *output)
121 this->plugin = plugin;
122 this->output = output;
127 int LensSlider::handle_event()
129 float prev_output = *output;
130 *output = get_value();
131 text->update(*output);
133 float difference = *output - prev_output;
137 for( int i=0; i<FOV_CHANNELS; ++i ) {
138 if( output == &plugin->config.fov[i] ) {
145 for( int i=0; i<FOV_CHANNELS; ++i ) {
146 if( output != &plugin->config.fov[i] ) {
147 plugin->config.fov[i] += difference;
148 plugin->config.boundaries();
149 gui->fov_slider[i]->update(plugin->config.fov[i]);
150 gui->fov_text[i]->update(plugin->config.fov[i]);
156 plugin->send_configure_change();
162 LensText::LensText(LensMain *plugin, LensGUI *gui,
163 LensSlider *slider, float *output, int x, int y)
164 : BC_TextBox(x, y, 100, 1, *output)
167 this->plugin = plugin;
168 this->output = output;
169 this->slider = slider;
172 int LensText::handle_event()
174 float prev_output = *output;
175 *output = atof(get_text());
176 slider->update(*output);
178 float difference = *output - prev_output;
182 for( int i=0; i<FOV_CHANNELS; ++i ) {
183 if( output == &plugin->config.fov[i] ) {
190 for( int i=0; i<FOV_CHANNELS; ++i ) {
191 if( output != &plugin->config.fov[i] ) {
192 plugin->config.fov[i] += difference;
193 plugin->config.boundaries();
194 gui->fov_slider[i]->update(plugin->config.fov[i]);
195 gui->fov_text[i]->update(plugin->config.fov[i]);
201 plugin->send_configure_change();
206 LensToggle::LensToggle(LensMain *plugin,
211 : BC_CheckBox(x, y, *output, text)
213 this->output = output;
214 this->plugin = plugin;
217 int LensToggle::handle_event()
219 *output = get_value();
220 plugin->send_configure_change();
225 LensMode::LensMode(LensMain *plugin, LensGUI *gui, int x, int y)
226 : BC_PopupMenu(x, y, calculate_w(gui), "", 1)
228 this->plugin = plugin;
232 int LensMode::handle_event()
234 plugin->config.mode = from_text(get_text());
235 plugin->send_configure_change();
240 void LensMode::create_objects()
242 add_item(new BC_MenuItem(to_text(LensConfig::SPHERICAL_SHRINK)));
243 add_item(new BC_MenuItem(to_text(LensConfig::SPHERICAL_STRETCH)));
244 add_item(new BC_MenuItem(to_text(LensConfig::RECTILINEAR_STRETCH)));
245 add_item(new BC_MenuItem(to_text(LensConfig::RECTILINEAR_SHRINK)));
246 update(plugin->config.mode);
249 void LensMode::update(int mode)
251 char string[BCTEXTLEN];
252 sprintf(string, "%s", to_text(mode));
256 int LensMode::calculate_w(LensGUI *gui)
259 result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(LensConfig::SPHERICAL_STRETCH)));
260 result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(LensConfig::SPHERICAL_SHRINK)));
261 result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(LensConfig::RECTILINEAR_STRETCH)));
262 result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(LensConfig::RECTILINEAR_SHRINK)));
266 int LensMode::from_text(char *text)
268 if( !strcmp(text, _("Sphere Stretch")) ) return LensConfig::SPHERICAL_STRETCH;
269 else if( !strcmp(text, _("Sphere Shrink")) ) return LensConfig::SPHERICAL_SHRINK;
270 else if( !strcmp(text, _("Rectilinear Stretch")) ) return LensConfig::RECTILINEAR_STRETCH;
271 else if( !strcmp(text, _("Rectilinear Shrink")) ) return LensConfig::RECTILINEAR_SHRINK;
272 return LensConfig::SPHERICAL_STRETCH;
275 const char* LensMode::to_text(int mode)
278 case LensConfig::SPHERICAL_STRETCH: return _("Sphere Stretch");
279 case LensConfig::SPHERICAL_SHRINK: return _("Sphere Shrink");
280 case LensConfig::RECTILINEAR_STRETCH: return _("Rectilinear Stretch");
281 case LensConfig::RECTILINEAR_SHRINK: return _("Rectilinear Shrink");
283 return _("Sphere Stretch");
287 // LensPresets::LensPresets(LensMain *plugin,
288 // LensGUI *gui, int x, int y, int w)
289 // : BC_PopupMenu(x, y, w, "", 1)
291 // this->plugin = plugin;
295 // int LensPresets::handle_event()
300 // void LensPresets::create_objects()
302 // // Remove existing items
303 // int total = total_items();
304 // for( int i=0; i<total; ++i ) {
308 // // Create current items
309 // plugin->load_presets();
310 // for( int i=0; i<plugin->presets.total; ++i ) {
311 // add_item(new BC_MenuItem(plugin->presets.values[i]->title));
315 // if( plugin->current_preset >= 0 &&
316 // plugin->current_preset < plugin->presets.total ) {
317 // set_text(plugin->presets.values[plugin->current_preset]->title);
324 // int LensPresets::from_text(LensMain *plugin, char *text)
328 // char* LensPresets::to_text(LensMain *plugin, int preset)
332 // void LensPresets::update(int preset)
337 // LensSavePreset::LensSavePreset(LensMain *plugin, LensGUI *gui, int x, int y)
338 // : BC_GenericButton(x, y, _("Save Preset"))
340 // this->plugin = plugin;
344 // int LensSavePreset::handle_event()
349 // LensDeletePreset::LensDeletePreset(LensMain *plugin, LensGUI *gui, int x, int y)
350 // : BC_GenericButton(x, y, _("Delete Preset"))
354 // int LensDeletePreset::handle_event()
359 // LensPresetText::LensPresetText(LensMain *plugin, LensGUI *gui, int x, int y, int w)
360 // : BC_TextBox(x, y, w, 1, "")
362 // this->plugin = plugin;
366 // int LensPresetText::handle_event()
371 LensInterpItem::LensInterpItem(const char *text, int id)
377 int LensInterpItem::handle_event()
379 LensInterp *interp = (LensInterp *)get_popup_menu();
380 interp->set_value(id);
381 LensMain *plugin = interp->plugin;
382 plugin->config.interp = id;
383 plugin->send_configure_change();
387 LensInterp::LensInterp(LensMain *plugin, int x, int y)
388 : BC_PopupMenu(x, y, 120, "")
390 this->plugin = plugin;
393 void LensInterp::create_objects()
395 add_item(new LensInterpItem(_("Default"), LensConfig::INTERP_DEFAULT));
396 add_item(new LensInterpItem(_("Nearest"), LensConfig::INTERP_NEAREST));
397 add_item(new LensInterpItem(_("BiLinear"), LensConfig::INTERP_BILINEAR));
398 add_item(new LensInterpItem(_("BiCubic"), LensConfig::INTERP_BICUBIC));
399 set_value(plugin->config.interp);
402 void LensInterp::set_value(int id)
404 for( int i=0, n=total_items(); i<n; ++i ) {
405 LensInterpItem *item = (LensInterpItem *)get_item(i);
406 if( item->id == id ) {
407 set_text(item->get_text());
414 int LensInterp::get_value()
420 LensReset::LensReset(LensMain *plugin, LensGUI *gui, int x, int y)
421 : BC_GenericButton(x, y, _("Reset"))
423 this->plugin = plugin;
427 int LensReset::handle_event()
429 plugin->config.reset();
431 plugin->send_configure_change();
436 LensGUI::LensGUI(LensMain *plugin)
437 : PluginClientWindow(plugin, 350, 550, 350, 550, 0)
439 this->plugin = plugin;
447 void LensGUI::create_objects()
455 for( int i=0; i<FOV_CHANNELS; ++i ) {
457 case 0: add_tool(title = new BC_Title(x, y, _("R Field of View:"))); break;
458 case 1: add_tool(title = new BC_Title(x, y, _("G Field of View:"))); break;
459 case 2: add_tool(title = new BC_Title(x, y, _("B Field of View:"))); break;
460 case 3: add_tool(title = new BC_Title(x, y, _("A Field of View:"))); break;
463 y += title->get_h() + 5;
464 add_tool(fov_slider[i] = new LensSlider(plugin, this,
465 0, &plugin->config.fov[i], x, y, 0.0001, 1.0));
466 x1 = x + fov_slider[i]->get_w() + 5;
467 add_tool(fov_text[i] = new LensText(plugin, this,
468 fov_slider[i], &plugin->config.fov[i], x1, y));
469 fov_slider[i]->text = fov_text[i];
470 y += fov_text[i]->get_h() + 5;
473 add_tool(toggle = new LensToggle(plugin, &plugin->lock, x, y, _("Lock")));
474 y += toggle->get_h() + 10;
477 add_tool(bar = new BC_Bar(x, y, get_w() - x * 2));
478 y += bar->get_h() + 5;
480 add_tool(title = new BC_Title(x, y, _("Aspect Ratio:")));
481 y += title->get_h() + 5;
482 add_tool(aspect_slider = new LensSlider(plugin, this,
483 0, &plugin->config.aspect, x, y, 0.333, 3.0));
484 x1 = x + aspect_slider->get_w() + 5;
485 add_tool(aspect_text = new LensText(plugin, this,
486 aspect_slider, &plugin->config.aspect, x1, y));
487 aspect_slider->text = aspect_text;
488 y += aspect_text->get_h() + 5;
490 add_tool(title = new BC_Title(x, y, _("Radius:")));
491 y += title->get_h() + 5;
492 add_tool(radius_slider = new LensSlider(plugin, this,
493 0, &plugin->config.radius, x, y, 0.333, 3.0));
494 x1 = x + radius_slider->get_w() + 5;
495 add_tool(radius_text = new LensText(plugin, this,
496 radius_slider, &plugin->config.radius, x1, y));
497 radius_slider->text = radius_text;
498 y += radius_text->get_h() + 5;
500 add_tool(title = new BC_Title(x, y, _("Center X:")));
501 y += title->get_h() + 5;
502 add_tool(centerx_slider = new LensSlider(plugin, this,
503 0, &plugin->config.center_x, x, y, 0.0, 99.0));
504 x1 = x + centerx_slider->get_w() + 5;
505 add_tool(centerx_text = new LensText(plugin, this,
506 centerx_slider, &plugin->config.center_x, x1, y));
507 centerx_slider->text = centerx_text;
508 centerx_slider->set_precision(1.0);
509 y += centerx_text->get_h() + 5;
512 add_tool(title = new BC_Title(x, y, _("Center Y:")));
513 y += title->get_h() + 5;
514 add_tool(centery_slider = new LensSlider(plugin, this,
515 0, &plugin->config.center_y, x, y, 0.0, 99.0));
516 x1 = x + centery_slider->get_w() + 5;
517 add_tool(centery_text = new LensText(plugin, this,
518 centery_slider, &plugin->config.center_y, x1, y));
519 centery_slider->text = centery_text;
520 centery_slider->set_precision(1.0);
521 y += centery_text->get_h() + 10;
523 add_tool(bar = new BC_Bar(x, y, get_w() - x * 2));
524 y += bar->get_h() + 5;
527 // add_tool(reverse = new LensToggle(plugin,
528 // &plugin->config.reverse, x, y, _("Reverse")));
529 // y += reverse->get_h() + 5;
530 add_tool(draw_guides = new LensToggle(plugin,
531 &plugin->config.draw_guides, x, y, _("Draw center")));
532 y += draw_guides->get_h() + 5;
535 add_tool(title = new BC_Title(x, y, _("Mode:")));
536 add_tool(mode = new LensMode(plugin, this,
537 x + title->get_w() + 5, y));
538 mode->create_objects();
539 y += mode->get_h() + 5;
541 add_tool(title = new BC_Title(x, y, _("Interp:")));
542 x1 = x + title->get_w() + 5;
543 add_tool(interp = new LensInterp(plugin, x1, y));
544 interp->create_objects();
545 y += interp->get_h() + 5;
547 add_tool(reset = new LensReset(plugin, this, x, y));
548 y += reset->get_h() + 5;
550 // add_tool(title = new BC_Title(x, y, _("Preset:")));
551 // add_tool(presets = new LensPresets(plugin, this,
552 // x + title->get_w() + 5, y, get_w() - x - title->get_w() - 50));
553 // presets->create_objects();
554 // y += presets->get_h() + 5;
556 // add_tool(save_preset = new LensSavePreset(plugin, this, x, y));
557 // add_tool(preset_text = new LensPresetText(plugin, this,
558 // x + save_preset->get_w() + 5, y,
559 // get_w() - x - save_preset->get_w() - 10));
560 // y += preset_text->get_h() + 5;
561 // add_tool(delete_preset = new LensDeletePreset(plugin, this, x, y));
568 LensMain::LensMain(PluginServer *server)
569 : PluginVClient(server)
577 LensMain::~LensMain()
581 presets.remove_all_objects();
584 NEW_WINDOW_MACRO(LensMain, LensGUI)
585 LOAD_CONFIGURATION_MACRO(LensMain, LensConfig)
586 int LensMain::is_realtime() { return 1; }
587 const char* LensMain::plugin_title() { return _("Lens"); }
589 void LensMain::update_gui()
591 if( !thread ) return;
592 if( !load_configuration() ) return;
593 ((LensGUI *)thread->window)->lock_window("LensMain::update_gui");
594 LensGUI *gui = (LensGUI *)thread->window;
596 gui->unlock_window();
599 void LensGUI::update_gui()
601 LensConfig &config = plugin->config;
602 for( int i=0; i<FOV_CHANNELS; ++i ) {
603 fov_slider[i]->update(config.fov[i]);
604 fov_text[i]->update(config.fov[i]);
606 aspect_slider->update(config.aspect);
607 aspect_text->update(config.aspect);
608 radius_slider->update(config.radius);
609 radius_text->update(config.radius);
610 centerx_slider->update(config.center_x);
611 centerx_text->update(config.center_x);
612 centery_slider->update(config.center_y);
613 centery_text->update(config.center_y);
614 mode->update(config.mode);
615 draw_guides->update(config.draw_guides);
616 interp->set_value(config.interp);
619 //void LensMain::save_presets()
621 // char path[BCTEXTLEN], string[BCTEXTLEN];
622 // sprintf(path, "%s/lenspresets.rc", File::get_config_path());
623 // BC_Hash *defaults = new BC_Hash(path);
626 // defaults->update("TOTAL_PRESETS", presets.total);
627 // for( int i=0; i<presets.total; ++i ) {
628 // LensPreset *preset = presets.values[i];
629 // sprintf(string, "TITLE_%d", i);
630 // defaults->update(string, preset->title);
632 // for( int j=0; j<FOV_CHANNELS; ++j ) {
633 // sprintf(string, "FOCAL_LENGTH_%d_%d", i, j);
634 // defaults->update(string, preset->fov[j]);
637 // sprintf(string, "ASPECT_%d", i);
638 // defaults->update(string, preset->aspect);
639 // sprintf(string, "RADIUS_%d", i);
640 // defaults->update(string, preset->radius);
641 // sprintf(string, "MODE_%d", i);
642 // defaults->update(string, preset->mode);
650 void LensMain::save_data(KeyFrame *keyframe)
653 char string[BCTEXTLEN];
657 // cause data to be stored directly in text
658 output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
659 output.tag.set_title("LENS");
660 for( int i = 0; i < FOV_CHANNELS; ++i ) {
661 sprintf(string, "FOCAL_LENGTH%d", i);
662 output.tag.set_property(string, config.fov[i]);
664 output.tag.set_property("ASPECT", config.aspect);
665 output.tag.set_property("RADIUS", config.radius);
666 output.tag.set_property("MODE", config.mode);
667 output.tag.set_property("INTERP", config.interp);
668 output.tag.set_property("CENTER_X", config.center_x);
669 output.tag.set_property("CENTER_Y", config.center_y);
670 output.tag.set_property("DRAW_GUIDES", config.draw_guides);
672 output.tag.set_title("/LENS");
674 output.append_newline();
675 output.terminate_string();
680 void LensMain::read_data(KeyFrame *keyframe)
683 char string[BCTEXTLEN];
686 input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
692 result = input.read_tag();
695 if( input.tag.title_is("LENS") ) {
696 for( int i=0; i<FOV_CHANNELS; ++i ) {
697 sprintf(string, "FOCAL_LENGTH%d", i);
698 config.fov[i] = input.tag.get_property(string, config.fov[i]);
700 config.aspect = input.tag.get_property("ASPECT", config.aspect);
701 config.radius = input.tag.get_property("RADIUS", config.radius);
702 config.mode = input.tag.get_property("MODE", config.mode);
703 config.interp = input.tag.get_property("INTERP", config.interp);
704 config.center_x = input.tag.get_property("CENTER_X", config.center_x);
705 config.center_y = input.tag.get_property("CENTER_Y", config.center_y);
706 config.draw_guides = input.tag.get_property("DRAW_GUIDES", config.draw_guides);
714 int LensMain::process_buffer(VFrame *frame,
715 int64_t start_position,
718 load_configuration();
719 int use_opengl = config.interp != LensConfig::INTERP_DEFAULT ? 0 :
721 VFrame *input = use_opengl ? frame :
722 new_temp(frame->get_w(), frame->get_h(), frame->get_color_model());
723 read_frame(input, 0, start_position, frame_rate, use_opengl);
730 if( !engine ) engine = new LensEngine(this);
731 engine->process_packages();
733 if( config.draw_guides ) {
737 #define DRAW_GUIDES(components, type, max) \
739 type **rows = (type**)get_output()->get_rows(); \
740 if( (center_x >= 0 && center_x < w) || (center_y >= 0 && center_y < h) ) { \
741 type *hrow = rows[center_y] + components * (center_x - CENTER_W / 2); \
742 for( int i=center_x-CENTER_W/2; i<=center_x+CENTER_W/2; ++i ) { \
743 if( i >= 0 && i < w ) { \
744 hrow[0] = max - hrow[0]; \
745 hrow[1] = max - hrow[1]; \
746 hrow[2] = max - hrow[2]; \
747 hrow += components; \
751 for( int i=center_y-CENTER_H/2; i<=center_y+CENTER_H/2; ++i ) { \
752 if( i >= 0 && i < h ) { \
753 type *vrow = rows[i] + center_x * components; \
754 vrow[0] = max - vrow[0]; \
755 vrow[1] = max - vrow[1]; \
756 vrow[2] = max - vrow[2]; \
762 int w = get_output()->get_w();
763 int h = get_output()->get_h();
764 int center_x = (int)(config.center_x * w / 100);
765 int center_y = (int)(config.center_y * h / 100);
766 switch( get_output()->get_color_model() ) {
768 DRAW_GUIDES(3, float, 1.0)
771 DRAW_GUIDES(4, float, 1.0)
774 DRAW_GUIDES(3, unsigned char, 0xff)
777 DRAW_GUIDES(4, unsigned char, 0xff)
780 DRAW_GUIDES(3, unsigned char, 0xff)
783 DRAW_GUIDES(4, unsigned char, 0xff)
792 int LensMain::handle_opengl()
795 static const char *shrink_frag =
796 "uniform sampler2D tex;\n"
797 "uniform vec2 texture_extents;\n"
798 "uniform vec2 image_extents;\n"
799 "uniform vec2 aspect;\n"
800 "uniform vec2 center_coord;\n"
801 "uniform vec4 border_color;\n"
803 "uniform vec4 max_z;\n"
806 " vec2 outcoord = gl_TexCoord[0].st * texture_extents;\n"
807 " vec2 coord_diff = outcoord - center_coord;\n"
808 " if( coord_diff.x == 0.0 && coord_diff.y == 0.0 )\n"
810 " gl_FragColor = texture2D(tex, outcoord);\n"
814 " float z = sqrt(coord_diff.x * coord_diff.x +\n"
815 " coord_diff.y * coord_diff.y);\n"
816 " float a2 = atan(coord_diff.y, coord_diff.x);\n"
817 " vec4 a1 = asin(vec4(z, z, z, z) / r);\n"
818 " vec4 z_in = a1 * max_z * 2.0 / 3.14159;\n"
821 " in_x = z_in * cos(a2) * aspect.x + center_coord.x;\n"
822 " in_y = z_in * sin(a2) * aspect.y + center_coord.y;\n"
823 " 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"
824 " gl_FragColor.r = border_color.r;\n"
826 " gl_FragColor.r = texture2D(tex, vec2(in_x.r, in_y.r) / texture_extents).r;\n"
827 " 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"
828 " gl_FragColor.g = border_color.g;\n"
830 " gl_FragColor.g = texture2D(tex, vec2(in_x.g, in_y.g) / texture_extents).g;\n"
831 " 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"
832 " gl_FragColor.b = border_color.b;\n"
834 " gl_FragColor.b = texture2D(tex, vec2(in_x.b, in_y.b) / texture_extents).b;\n"
835 " 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"
836 " gl_FragColor.a = border_color.a;\n"
838 " gl_FragColor.a = texture2D(tex, vec2(in_x.a, in_y.a) / texture_extents).a;\n"
842 static const char *stretch_frag =
843 "uniform sampler2D tex;\n"
844 "uniform vec2 texture_extents;\n"
845 "uniform vec2 image_extents;\n"
846 "uniform vec2 aspect;\n"
847 "uniform vec2 center_coord;\n"
848 "uniform vec4 border_color;\n"
852 " vec2 outcoord = gl_TexCoord[0].st * texture_extents;\n"
853 " vec2 coord_diff = outcoord - center_coord;\n"
854 " float z = sqrt(coord_diff.x * coord_diff.x +\n"
855 " coord_diff.y * coord_diff.y);\n"
856 " vec4 a1 = (vec4(z, z, z, z) / (3.14159 * r / 2.0)) * (3.14159 / 2.0);\n"
857 " vec4 z_in = r * sin(a1);\n"
859 " if( coord_diff.x == 0.0 )\n"
861 " if( coord_diff.y < 0.0 )\n"
862 " a2 = 3.0 * 3.14159 / 2.0;\n"
864 " a2 = 3.14159 / 2.0;\n"
867 " a2 = atan(coord_diff.y, coord_diff.x);\n"
870 " in_x = z_in * cos(a2) * aspect.x + center_coord.x;\n"
871 " in_y = z_in * sin(a2) * aspect.y + center_coord.y;\n"
872 " if( in_x.r < 0.0 || in_x.r >= image_extents.x || in_y.r < 0.0 || in_y.r >= image_extents.y )\n"
873 " gl_FragColor.r = border_color.r;\n"
875 " gl_FragColor.r = texture2D(tex, vec2(in_x.r, in_y.r) / texture_extents).r;\n"
876 " if( in_x.g < 0.0 || in_x.g >= image_extents.x || in_y.g < 0.0 || in_y.g >= image_extents.y )\n"
877 " gl_FragColor.g = border_color.g;\n"
879 " gl_FragColor.g = texture2D(tex, vec2(in_x.g, in_y.g) / texture_extents).g;\n"
880 " if( in_x.b < 0.0 || in_x.b >= image_extents.x || in_y.b < 0.0 || in_y.b >= image_extents.y )\n"
881 " gl_FragColor.b = border_color.b;\n"
883 " gl_FragColor.b = texture2D(tex, vec2(in_x.b, in_y.b) / texture_extents).b;\n"
884 " if( in_x.a < 0.0 || in_x.a >= image_extents.x || in_y.a < 0.0 || in_y.a >= image_extents.y )\n"
885 " gl_FragColor.a = border_color.a;\n"
887 " gl_FragColor.a = texture2D(tex, vec2(in_x.a, in_y.a) / texture_extents).a;\n"
891 static const char *rectilinear_stretch_frag =
892 "uniform sampler2D tex;\n"
893 "uniform vec2 texture_extents;\n"
894 "uniform vec2 image_extents;\n"
895 "uniform vec2 aspect;\n"
896 "uniform vec2 center_coord;\n"
897 "uniform vec4 border_color;\n"
899 "uniform float radius;\n"
902 " vec2 outcoord = gl_TexCoord[0].st * texture_extents;\n"
903 " vec2 coord_diff = outcoord - center_coord;\n"
904 " float z = sqrt(coord_diff.x * coord_diff.x +\n"
905 " coord_diff.y * coord_diff.y);\n"
906 " vec4 radius1 = (vec4(z, z, z, z) / r) * 2.0 * radius;\n"
907 " vec4 z_in = r * atan(radius1) / (3.14159 / 2.0);\n"
910 " if( coord_diff.x == 0.0 )\n"
912 " if( coord_diff.y < 0.0 )\n"
913 " angle = 3.0 * 3.14159 / 2.0;\n"
915 " angle = 3.14159 / 2.0;\n"
918 " angle = atan(coord_diff.y, coord_diff.x);\n"
922 " in_x = z_in * cos(angle) * aspect.x + center_coord.x;\n"
923 " in_y = z_in * sin(angle) * aspect.y + center_coord.y;\n"
924 " if( in_x.r < 0.0 || in_x.r >= image_extents.x || in_y.r < 0.0 || in_y.r >= image_extents.y )\n"
925 " gl_FragColor.r = border_color.r;\n"
927 " gl_FragColor.r = texture2D(tex, vec2(in_x.r, in_y.r) / texture_extents).r;\n"
928 " if( in_x.g < 0.0 || in_x.g >= image_extents.x || in_y.g < 0.0 || in_y.g >= image_extents.y )\n"
929 " gl_FragColor.g = border_color.g;\n"
931 " gl_FragColor.g = texture2D(tex, vec2(in_x.g, in_y.g) / texture_extents).g;\n"
932 " if( in_x.b < 0.0 || in_x.b >= image_extents.x || in_y.b < 0.0 || in_y.b >= image_extents.y )\n"
933 " gl_FragColor.b = border_color.b;\n"
935 " gl_FragColor.b = texture2D(tex, vec2(in_x.b, in_y.b) / texture_extents).b;\n"
936 " if( in_x.a < 0.0 || in_x.a >= image_extents.x || in_y.a < 0.0 || in_y.a >= image_extents.y )\n"
937 " gl_FragColor.a = border_color.a;\n"
939 " gl_FragColor.a = texture2D(tex, vec2(in_x.a, in_y.a) / texture_extents).a;\n"
942 static const char *rectilinear_shrink_frag =
943 "uniform sampler2D tex;\n"
944 "uniform vec2 texture_extents;\n"
945 "uniform vec2 image_extents;\n"
946 "uniform vec2 aspect;\n"
947 "uniform vec2 center_coord;\n"
948 "uniform vec4 border_color;\n"
950 "uniform float radius;\n"
953 " vec2 outcoord = gl_TexCoord[0].st * texture_extents;\n"
954 " vec2 coord_diff = outcoord - center_coord;\n"
955 " float z = sqrt(coord_diff.x * coord_diff.x +\n"
956 " coord_diff.y * coord_diff.y);\n"
957 " vec4 radius1 = (vec4(z, z, z, z) / r) * 2.0 * radius;\n"
958 " vec4 z_in = r * atan(radius1) / (3.14159 / 2.0);\n"
961 " if( coord_diff.x == 0.0 )\n"
963 " if( coord_diff.y < 0.0 )\n"
964 " angle = 3.0 * 3.14159 / 2.0;\n"
966 " angle = 3.14159 / 2.0;\n"
969 " angle = atan(coord_diff.y, coord_diff.x);\n"
973 " in_x = z_in * cos(angle) * aspect.x + center_coord.x;\n"
974 " in_y = z_in * sin(angle) * aspect.y + center_coord.y;\n"
975 " if( in_x.r < 0.0 || in_x.r >= image_extents.x || in_y.r < 0.0 || in_y.r >= image_extents.y )\n"
976 " gl_FragColor.r = border_color.r;\n"
978 " gl_FragColor.r = texture2D(tex, vec2(in_x.r, in_y.r) / texture_extents).r;\n"
979 " if( in_x.g < 0.0 || in_x.g >= image_extents.x || in_y.g < 0.0 || in_y.g >= image_extents.y )\n"
980 " gl_FragColor.g = border_color.g;\n"
982 " gl_FragColor.g = texture2D(tex, vec2(in_x.g, in_y.g) / texture_extents).g;\n"
983 " if( in_x.b < 0.0 || in_x.b >= image_extents.x || in_y.b < 0.0 || in_y.b >= image_extents.y )\n"
984 " gl_FragColor.b = border_color.b;\n"
986 " gl_FragColor.b = texture2D(tex, vec2(in_x.b, in_y.b) / texture_extents).b;\n"
987 " if( in_x.a < 0.0 || in_x.a >= image_extents.x || in_y.a < 0.0 || in_y.a >= image_extents.y )\n"
988 " gl_FragColor.a = border_color.a;\n"
990 " gl_FragColor.a = texture2D(tex, vec2(in_x.a, in_y.a) / texture_extents).a;\n"
993 get_output()->to_texture();
994 get_output()->enable_opengl();
995 unsigned int frag_shader = 0;
997 switch( config.mode )
999 case LensConfig::SPHERICAL_SHRINK:
1000 frag_shader = VFrame::make_shader(0, shrink_frag, 0);
1002 case LensConfig::SPHERICAL_STRETCH:
1003 frag_shader = VFrame::make_shader(0, stretch_frag, 0);
1005 case LensConfig::RECTILINEAR_STRETCH:
1006 frag_shader = VFrame::make_shader(0, rectilinear_stretch_frag, 0);
1008 case LensConfig::RECTILINEAR_SHRINK:
1009 frag_shader = VFrame::make_shader(0, rectilinear_shrink_frag, 0);
1013 if( frag_shader > 0 ) {
1014 float border_color[] = { 0, 0, 0, 0 };
1015 if( BC_CModels::is_yuv(get_output()->get_color_model()) ) {
1016 border_color[1] = 0.5;
1017 border_color[2] = 0.5;
1020 double x_factor = config.aspect;
1021 double y_factor = 1.0 / config.aspect;
1022 if( x_factor < 1 ) x_factor = 1;
1023 if( y_factor < 1 ) y_factor = 1;
1025 glUseProgram(frag_shader);
1026 glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0);
1027 glUniform2f(glGetUniformLocation(frag_shader, "aspect"),
1030 glUniform2f(glGetUniformLocation(frag_shader, "center_coord"),
1031 (GLfloat)get_input()->get_w() * config.center_x / 100.0,
1032 (GLfloat)get_input()->get_h() * config.center_y / 100.0);
1033 glUniform2f(glGetUniformLocation(frag_shader, "texture_extents"),
1034 (GLfloat)get_input()->get_texture_w(),
1035 (GLfloat)get_input()->get_texture_h());
1036 glUniform2f(glGetUniformLocation(frag_shader, "image_extents"),
1037 (GLfloat)get_input()->get_w(),
1038 (GLfloat)get_input()->get_h());
1040 int width = get_output()->get_w();
1041 int height = get_output()->get_h();
1042 float *fov = config.fov;
1045 switch( config.mode )
1047 case LensConfig::SPHERICAL_SHRINK:
1048 dim = MAX(width, height) * config.radius;
1049 max_z = dim * sqrt(2.0) / 2;
1050 glUniform4fv(glGetUniformLocation(frag_shader, "border_color"),
1052 (GLfloat*)border_color);
1053 glUniform4f(glGetUniformLocation(frag_shader, "max_z"),
1058 glUniform4f(glGetUniformLocation(frag_shader, "r"),
1059 (max_z / fov[0]) * 2 / M_PI,
1060 (max_z / fov[1]) * 2 / M_PI,
1061 (max_z / fov[2]) * 2 / M_PI,
1062 (max_z / fov[3]) * 2 / M_PI);
1065 case LensConfig::SPHERICAL_STRETCH:
1066 dim = MAX(width, height) * config.radius;
1067 max_z = dim * sqrt(2.0) / 2;
1068 glUniform4f(glGetUniformLocation(frag_shader, "r"),
1069 max_z / M_PI / (fov[0] / 2.0),
1070 max_z / M_PI / (fov[1] / 2.0),
1071 max_z / M_PI / (fov[2] / 2.0),
1072 max_z / M_PI / (fov[3] / 2.0));
1075 case LensConfig::RECTILINEAR_STRETCH:
1076 max_z = sqrt(SQR(width) + SQR(height)) / 2;
1077 glUniform4f(glGetUniformLocation(frag_shader, "r"),
1078 max_z / M_PI / (fov[0] / 2.0),
1079 max_z / M_PI / (fov[1] / 2.0),
1080 max_z / M_PI / (fov[2] / 2.0),
1081 max_z / M_PI / (fov[3] / 2.0));
1082 glUniform1f(glGetUniformLocation(frag_shader, "radius"),
1086 case LensConfig::RECTILINEAR_SHRINK:
1087 max_z = sqrt(SQR(width) + SQR(height)) / 2;
1088 glUniform4f(glGetUniformLocation(frag_shader, "r"),
1089 max_z / M_PI / (fov[0] / 2.0),
1090 max_z / M_PI / (fov[1] / 2.0),
1091 max_z / M_PI / (fov[2] / 2.0),
1092 max_z / M_PI / (fov[3] / 2.0));
1093 glUniform1f(glGetUniformLocation(frag_shader, "radius"),
1099 get_output()->init_screen();
1100 get_output()->bind_texture(0);
1101 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
1102 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
1103 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
1104 get_output()->draw_texture();
1108 if( config.draw_guides ) {
1109 int w = get_output()->get_w();
1110 int h = get_output()->get_h();
1111 int center_x = (int)(config.center_x * w / 100);
1112 int center_y = (int)(config.center_y * h / 100);
1114 glDisable(GL_TEXTURE_2D);
1115 glColor4f(0.0, 0.0, 0.0, 1.0);
1117 glVertex3f(center_x, -h + center_y - CENTER_H / 2, 0.0);
1118 glVertex3f(center_x, -h + center_y + CENTER_H / 2, 0.0);
1121 glVertex3f(center_x - CENTER_W / 2, -h + center_y, 0.0);
1122 glVertex3f(center_x + CENTER_W / 2, -h + center_y, 0.0);
1124 glColor4f(1.0, 1.0, 1.0, 1.0);
1126 glVertex3f(center_x - 1, -h + center_y - CENTER_H / 2 - 1, 0.0);
1127 glVertex3f(center_x - 1, -h + center_y + CENTER_H / 2 - 1, 0.0);
1130 glVertex3f(center_x - CENTER_W / 2 - 1, -h + center_y - 1, 0.0);
1131 glVertex3f(center_x + CENTER_W / 2 - 1, -h + center_y - 1, 0.0);
1134 get_output()->set_opengl_state(VFrame::SCREEN);
1141 // do using specified interpolation
1142 #define DO_LENS(type) \
1143 int icolor_model = plugin->get_input()->get_color_model(); \
1144 switch( plugin->config.interp ) { \
1145 case LensConfig::INTERP_NEAREST: \
1146 switch( icolor_model ) { \
1148 DO_LENS_##type(unsigned char, 3, 0xff, 0x0, nearest); \
1151 DO_LENS_##type(unsigned char, 4, 0xff, 0x0, nearest); \
1153 case BC_RGB_FLOAT: \
1154 DO_LENS_##type(float, 3, 1.0, 0.0, nearest); \
1156 case BC_RGBA_FLOAT: \
1157 DO_LENS_##type(float, 4, 1.0, 0.0, nearest); \
1160 DO_LENS_##type(unsigned char, 3, 0xff, 0x80, nearest); \
1163 DO_LENS_##type(unsigned char, 4, 0xff, 0x80, nearest); \
1167 case LensConfig::INTERP_DEFAULT: \
1168 case LensConfig::INTERP_BILINEAR: \
1169 switch( icolor_model ) { \
1171 DO_LENS_##type(unsigned char, 3, 0xff, 0x0, bi_linear); \
1174 DO_LENS_##type(unsigned char, 4, 0xff, 0x0, bi_linear); \
1176 case BC_RGB_FLOAT: \
1177 DO_LENS_##type(float, 3, 1.0, 0.0, bi_linear); \
1179 case BC_RGBA_FLOAT: \
1180 DO_LENS_##type(float, 4, 1.0, 0.0, bi_linear); \
1183 DO_LENS_##type(unsigned char, 3, 0xff, 0x80, bi_linear); \
1186 DO_LENS_##type(unsigned char, 4, 0xff, 0x80, bi_linear); \
1190 case LensConfig::INTERP_BICUBIC: \
1191 switch( icolor_model ) { \
1193 DO_LENS_##type(unsigned char, 3, 0xff, 0x0, bi_cubic); \
1196 DO_LENS_##type(unsigned char, 4, 0xff, 0x0, bi_cubic); \
1198 case BC_RGB_FLOAT: \
1199 DO_LENS_##type(float, 3, 1.0, 0.0, bi_cubic); \
1201 case BC_RGBA_FLOAT: \
1202 DO_LENS_##type(float, 4, 1.0, 0.0, bi_cubic); \
1205 DO_LENS_##type(unsigned char, 3, 0xff, 0x80, bi_cubic); \
1208 DO_LENS_##type(unsigned char, 4, 0xff, 0x80, bi_cubic); \
1214 LensPackage::LensPackage()
1219 LensUnit::LensUnit(LensEngine *engine, LensMain *plugin)
1220 : LoadClient(engine)
1222 this->plugin = plugin;
1225 LensUnit::~LensUnit()
1229 void LensUnit::process_spherical_stretch(LensPackage *pkg)
1231 float *fov = plugin->config.fov;
1232 float aspect = plugin->config.aspect;
1233 int row1 = pkg->row1;
1234 int row2 = pkg->row2;
1235 double x_factor = aspect;
1236 double y_factor = 1.0 / aspect;
1237 if( x_factor < 1 ) x_factor = 1;
1238 if( y_factor < 1 ) y_factor = 1;
1239 int width = plugin->get_input()->get_w();
1240 int height = plugin->get_input()->get_h();
1241 double dim = MAX(width, height) * plugin->config.radius;
1242 double max_z = dim * sqrt(2.0) / 2;
1243 double center_x = width * plugin->config.center_x / 100.0;
1244 double center_y = height * plugin->config.center_y / 100.0;
1245 double r[FOV_CHANNELS];
1247 r[0] = max_z / M_PI / (fov[0] / 2.0);
1248 r[1] = max_z / M_PI / (fov[1] / 2.0);
1249 r[2] = max_z / M_PI / (fov[2] / 2.0);
1250 r[3] = max_z / M_PI / (fov[3] / 2.0);
1252 #define DO_LENS_SPHERICAL_STRETCH(type, components, max, chroma, interp) { \
1253 type **in_rows = (type**)plugin->get_temp()->get_rows(); \
1254 type **out_rows = (type**)plugin->get_input()->get_rows(); \
1255 type black[4] = { 0, chroma, chroma, 0 }; \
1256 INTERP_SETUP(in_rows, max, 0,0, width,height); \
1258 for( int y=row1; y<row2; ++y ) { \
1259 type *out_row = out_rows[y]; \
1260 double y_diff = y - center_y; \
1261 for( int x=0; x<width; ++x ) { \
1262 double x_diff = (x - center_x); \
1263 double z = sqrt(x_diff * x_diff + y_diff * y_diff); \
1264 double a2 = x != center_x ? atan(y_diff / x_diff) : \
1265 y < center_y ? 3*M_PI/2 : M_PI/2; \
1266 if( x_diff < 0.0 ) a2 += M_PI; \
1267 for( int i=0; i<components; ++i ) { \
1268 double a1 = (z / (M_PI * r[i] / 2)) * (M_PI / 2); \
1269 double z_in = r[i] * sin(a1); \
1270 double x_in = z_in * cos(a2) * x_factor + center_x; \
1271 double y_in = z_in * sin(a2) * y_factor + center_y; \
1272 interp##_SETUP(type, components, x_in, y_in); \
1273 for( int j=0; j<i; ++j ) interp##_next(); \
1274 *out_row++ = interp##_interp(black[i], black[i]); \
1279 type *out_pixel = out_rows[(int)center_y] + (int)center_x * components; \
1280 type *inp_pixel = in_rows[(int)center_y] + (int)center_x * components; \
1281 for( int i=0; i<components; ++i ) *out_pixel++ = *inp_pixel++; \
1284 DO_LENS(SPHERICAL_STRETCH);
1287 void LensUnit::process_spherical_shrink(LensPackage *pkg)
1290 float *fov = plugin->config.fov;
1291 float aspect = plugin->config.aspect;
1292 int row1 = pkg->row1;
1293 int row2 = pkg->row2;
1294 int width = plugin->get_input()->get_w();
1295 int height = plugin->get_input()->get_h();
1296 double x_factor = aspect;
1297 double y_factor = 1.0 / aspect;
1298 if( x_factor < 1 ) x_factor = 1;
1299 if( y_factor < 1 ) y_factor = 1;
1300 double dim = MAX(width, height) * plugin->config.radius;
1301 double max_z[FOV_CHANNELS];
1302 double center_x = width * plugin->config.center_x / 100.0;
1303 double center_y = height * plugin->config.center_y / 100.0;
1304 double r[FOV_CHANNELS];
1306 // max_z[0] = sqrt(SQR(width) + SQR(height)) / 2 / fov[0];
1307 // max_z[1] = sqrt(SQR(width) + SQR(height)) / 2 / fov[1];
1308 // max_z[2] = sqrt(SQR(width) + SQR(height)) / 2 / fov[2];
1309 // max_z[3] = sqrt(SQR(width) + SQR(height)) / 2 / fov[3];
1310 max_z[0] = dim * sqrt(2.0) / 2 / fov[0];
1311 max_z[1] = dim * sqrt(2.0) / 2 / fov[1];
1312 max_z[2] = dim * sqrt(2.0) / 2 / fov[2];
1313 max_z[3] = dim * sqrt(2.0) / 2 / fov[3];
1314 r[0] = max_z[0] * 2 / M_PI;
1315 r[1] = max_z[1] * 2 / M_PI;
1316 r[2] = max_z[2] * 2 / M_PI;
1317 r[3] = max_z[3] * 2 / M_PI;
1319 #define DO_LENS_SPHERICAL_SHRINK(type, components, max, chroma, interp) { \
1320 type **in_rows = (type**)plugin->get_temp()->get_rows(); \
1321 type **out_rows = (type**)plugin->get_input()->get_rows(); \
1322 type black[4] = { 0, chroma, chroma, 0 }; \
1323 INTERP_SETUP(in_rows, max, 0,0, width,height); \
1325 for( int y=row1; y<row2; ++y ) { \
1326 type *out_row = out_rows[y]; \
1327 type *in_row = in_rows[y]; \
1328 double y_diff = y - center_y; \
1329 for( int x=0; x<width; ++x ) { \
1330 double x_diff = x - center_x; \
1331 if( !x_diff && !y_diff ) { \
1332 type *inp_pixel = in_row + x * components; \
1333 for( int c=0; c<components; ++c ) \
1334 *out_row++ = *inp_pixel++; \
1337 double z = sqrt(x_diff * x_diff + y_diff * y_diff); \
1338 double a2 = atan(y_diff / x_diff); \
1339 if( x_diff < 0.0 ) a2 += M_PI; \
1340 for( int i=0; i<components; ++i ) { \
1341 if( z > r[i] ) { *out_row++ = black[i]; continue; } \
1342 double a1 = asin(z / r[i]); \
1343 double z_in = a1 * max_z[i] * 2 / M_PI; \
1344 float x_in = z_in * cos(a2) * x_factor + center_x; \
1345 float y_in = z_in * sin(a2) * y_factor + center_y; \
1346 interp##_SETUP(type, components, x_in, y_in); \
1347 for( int j=0; j<i; ++j ) interp##_next(); \
1348 *out_row++ = interp##_interp(black[i], black[i]); \
1353 type *out_pixel = out_rows[(int)center_y] + (int)center_x * components; \
1354 type *inp_pixel = in_rows[(int)center_y] + (int)center_x * components; \
1355 for( int i=0; i<components; ++i ) *out_pixel++ = *inp_pixel++; \
1358 DO_LENS(SPHERICAL_SHRINK);
1361 void LensUnit::process_rectilinear_stretch(LensPackage *pkg)
1363 float *fov = plugin->config.fov;
1364 float aspect = plugin->config.aspect;
1365 int row1 = pkg->row1;
1366 int row2 = pkg->row2;
1367 double x_factor = aspect;
1368 double y_factor = 1.0 / aspect;
1369 if( x_factor < 1 ) x_factor = 1;
1370 if( y_factor < 1 ) y_factor = 1;
1371 int width = plugin->get_input()->get_w();
1372 int height = plugin->get_input()->get_h();
1373 // double dim = MAX(width, height) * plugin->config.radius;
1374 // double max_z = dim * sqrt(2.0) / 2;
1375 double max_z = sqrt(SQR(width) + SQR(height)) / 2;
1376 double center_x = width * plugin->config.center_x / 100.0;
1377 double center_y = height * plugin->config.center_y / 100.0;
1378 double r[FOV_CHANNELS];
1380 r[0] = max_z / M_PI / (fov[0] / 2.0);
1381 r[1] = max_z / M_PI / (fov[1] / 2.0);
1382 r[2] = max_z / M_PI / (fov[2] / 2.0);
1383 r[3] = max_z / M_PI / (fov[3] / 2.0);
1385 #define DO_LENS_RECTILINEAR_STRETCH(type, components, max, chroma, interp) { \
1386 type **in_rows = (type**)plugin->get_temp()->get_rows(); \
1387 type **out_rows = (type**)plugin->get_input()->get_rows(); \
1388 type black[4] = { 0, chroma, chroma, 0 }; \
1389 INTERP_SETUP(in_rows, max, 0,0, width,height); \
1391 for( int y=row1; y<row2; ++y ) { \
1392 type *out_row = out_rows[y]; \
1393 double y_diff = y - center_y; \
1394 for( int x=0; x<width; ++x ) { \
1395 double x_diff = (x - center_x); /* Compute magnitude / angle */ \
1396 double z = sqrt(x_diff * x_diff + y_diff * y_diff); \
1397 double angle = x != center_x ? atan(y_diff / x_diff) : \
1398 y < center_y ? 3*M_PI/2 : M_PI/2; \
1399 if( x_diff < 0.0 ) angle += M_PI; \
1400 for( int i=0; i<components; ++i ) { /* Compute new radius */ \
1401 double radius1 = (z / r[i]) * 2 * plugin->config.radius; \
1402 double z_in = r[i] * atan(radius1) / (M_PI / 2); \
1403 double x_in = z_in * cos(angle) * x_factor + center_x; \
1404 double y_in = z_in * sin(angle) * y_factor + center_y; \
1405 interp##_SETUP(type, components, x_in, y_in); \
1406 for( int j=0; j<i; ++j ) interp##_next(); \
1407 *out_row++ = interp##_interp(black[i], black[i]); \
1412 type *out_pixel = out_rows[(int)center_y] + (int)center_x * components; \
1413 type *inp_pixel = in_rows[(int)center_y] + (int)center_x * components; \
1414 for( int i=0; i<components; ++i ) *out_pixel++ = *inp_pixel++; \
1417 DO_LENS(RECTILINEAR_STRETCH);
1420 void LensUnit::process_rectilinear_shrink(LensPackage *pkg)
1422 float *fov = plugin->config.fov;
1423 float aspect = plugin->config.aspect;
1424 int row1 = pkg->row1;
1425 int row2 = pkg->row2;
1426 double x_factor = aspect;
1427 double y_factor = 1.0 / aspect;
1428 if( x_factor < 1 ) x_factor = 1;
1429 if( y_factor < 1 ) y_factor = 1;
1430 int width = plugin->get_input()->get_w();
1431 int height = plugin->get_input()->get_h();
1432 double max_z = MAX(width, height) / 2 * plugin->config.radius;
1433 double center_x = width * plugin->config.center_x / 100.0;
1434 double center_y = height * plugin->config.center_y / 100.0;
1435 double r[FOV_CHANNELS];
1437 r[0] = max_z / fov[0];
1438 r[1] = max_z / fov[1];
1439 r[2] = max_z / fov[2];
1440 r[3] = max_z / fov[3];
1442 #define DO_LENS_RECTILINEAR_SHRINK(type, components, max, chroma, interp) { \
1443 type **in_rows = (type**)plugin->get_temp()->get_rows(); \
1444 type **out_rows = (type**)plugin->get_input()->get_rows(); \
1445 type black[4] = { 0, chroma, chroma, 0 }; \
1446 INTERP_SETUP(in_rows, max, 0,0, width,height); \
1448 for( int y=row1; y<row2; ++y ) { \
1449 type *out_row = out_rows[y]; \
1450 double y_diff = y - center_y; \
1451 for( int x=0; x<width; ++x ) { \
1452 double x_diff = (x - center_x); /* Compute magnitude/angle */ \
1453 double z = sqrt(x_diff * x_diff + y_diff * y_diff); \
1454 double angle = x != center_x ? atan(y_diff / x_diff) : \
1455 y < center_y ? 3*M_PI/2 : M_PI/2; \
1456 if( x_diff < 0.0 ) angle += M_PI; \
1457 for( int i=0; i<components; ++i ) { /* Compute new radius */ \
1458 double radius1 = z / r[i]; \
1459 double z_in = r[i] * tan(radius1) / (M_PI / 2); \
1460 double x_in = z_in * cos(angle) * x_factor + center_x; \
1461 double y_in = z_in * sin(angle) * y_factor + center_y; \
1462 interp##_SETUP(type, components, x_in, y_in); \
1463 for( int j=0; j<i; ++j ) interp##_next(); \
1464 *out_row++ = interp##_interp(black[i], black[i]); \
1469 type *out_pixel = out_rows[(int)center_y] + (int)center_x * components; \
1470 type *inp_pixel = in_rows[(int)center_y] + (int)center_x * components; \
1471 for( int i=0; i<components; ++i ) *out_pixel++ = *inp_pixel++; \
1474 DO_LENS(RECTILINEAR_SHRINK);
1477 void LensUnit::process_package(LoadPackage *package)
1479 LensPackage *pkg = (LensPackage*)package;
1481 switch( plugin->config.mode ) {
1482 case LensConfig::SPHERICAL_STRETCH:
1483 process_spherical_stretch(pkg);
1485 case LensConfig::SPHERICAL_SHRINK:
1486 process_spherical_shrink(pkg);
1488 case LensConfig::RECTILINEAR_STRETCH:
1489 process_rectilinear_stretch(pkg);
1491 case LensConfig::RECTILINEAR_SHRINK:
1492 process_rectilinear_shrink(pkg);
1498 LensEngine::LensEngine(LensMain *plugin)
1499 : LoadServer(plugin->PluginClient::smp + 1, plugin->PluginClient::smp + 1)
1500 // : LoadServer(1, 1)
1502 this->plugin = plugin;
1505 LensEngine::~LensEngine()
1509 void LensEngine::init_packages()
1511 int row1 = 0, row2 = 0, n = LoadServer::get_total_packages();
1512 for( int i=0; i<n; row1=row2 ) {
1513 LensPackage *package = (LensPackage*)LoadServer::get_package(i);
1514 row2 = plugin->get_input()->get_h() * ++i / n;
1515 package->row1 = row1; package->row2 = row2;
1519 LoadClient* LensEngine::new_client()
1521 return new LensUnit(this, plugin);
1524 LoadPackage* LensEngine::new_package()
1526 return new LensPackage;