c5b4648c9bb825fafe47a3fd8a2e68cafeedfce9
[goodguy/history.git] / cinelerra-5.1 / plugins / lens / lens.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
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.
10  *
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.
15  *
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
19  *
20  */
21
22 #include "bcdisplayinfo.h"
23 #include "bchash.h"
24 #include "bcsignals.h"
25 #include "clip.h"
26 #include "file.h"
27 #include "filexml.h"
28 #include "interp.h"
29 #include "language.h"
30 #include "lens.h"
31
32
33 #include <string.h>
34
35
36
37
38 REGISTER_PLUGIN(LensMain)
39
40 LensConfig::LensConfig()
41 {
42         reset();
43 }
44
45 void LensConfig::reset()
46 {
47         for( int i=0; i<FOV_CHANNELS; ++i )
48                 fov[i] = 1.0;
49         aspect = 1.0;
50         radius = 1.0;
51         mode = SPHERICAL_SHRINK;
52         interp = INTERP_DEFAULT;
53         center_x = 50.0;
54         center_y = 50.0;
55         draw_guides = 0;
56 }
57
58 int LensConfig::equivalent(LensConfig &that)
59 {
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) &&
66                 mode == that.mode &&
67                 interp == that.interp &&
68                 draw_guides == that.draw_guides;
69 }
70
71 void LensConfig::copy_from(LensConfig &that)
72 {
73         for( int i=0; i<FOV_CHANNELS; ++i )
74                 fov[i] = that.fov[i];
75         aspect = that.aspect;
76         radius = that.radius;
77         mode = that.mode;
78         interp = that.interp;
79         center_x = that.center_x;
80         center_y = that.center_y;
81         draw_guides = that.draw_guides;
82 }
83
84 void LensConfig::interpolate(LensConfig &prev, LensConfig &next,
85         int64_t prev_frame, int64_t next_frame, int64_t current_frame)
86 {
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);
89
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;
96         mode = prev.mode;
97         interp = prev.interp;
98         draw_guides = prev.draw_guides;
99
100         boundaries();
101 }
102
103 void LensConfig::boundaries()
104 {
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);
111 }
112
113
114
115
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)
119 {
120         this->gui = gui;
121         this->plugin = plugin;
122         this->output = output;
123         this->text = text;
124         set_precision(0.01);
125 }
126
127 int LensSlider::handle_event()
128 {
129         float prev_output = *output;
130         *output = get_value();
131         text->update(*output);
132
133         float difference = *output - prev_output;
134         int is_fov = 0;
135
136         if( plugin->lock ) {
137                 for( int i=0; i<FOV_CHANNELS; ++i ) {
138                         if( output == &plugin->config.fov[i] ) {
139                                 is_fov = 1;
140                                 break;
141                         }
142                 }
143
144                 if( is_fov ) {
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]);
151                                 }
152                         }
153                 }
154         }
155
156         plugin->send_configure_change();
157         return 1;
158 }
159
160
161
162 LensText::LensText(LensMain *plugin, LensGUI *gui,
163         LensSlider *slider, float *output, int x, int y)
164  : BC_TextBox(x, y, 100, 1, *output)
165 {
166         this->gui = gui;
167         this->plugin = plugin;
168         this->output = output;
169         this->slider = slider;
170 }
171
172 int LensText::handle_event()
173 {
174         float prev_output = *output;
175         *output = atof(get_text());
176         slider->update(*output);
177
178         float difference = *output - prev_output;
179         int is_fov = 0;
180
181         if( plugin->lock ) {
182                 for( int i=0; i<FOV_CHANNELS; ++i ) {
183                         if( output == &plugin->config.fov[i] ) {
184                                 is_fov = 1;
185                                 break;
186                         }
187                 }
188
189                 if( is_fov ) {
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]);
196                                 }
197                         }
198                 }
199         }
200
201         plugin->send_configure_change();
202         return 1;
203 }
204
205
206 LensToggle::LensToggle(LensMain *plugin,
207         int *output,
208         int x,
209         int y,
210         const char *text)
211  : BC_CheckBox(x, y, *output, text)
212 {
213         this->output = output;
214         this->plugin = plugin;
215 }
216
217 int LensToggle::handle_event()
218 {
219         *output = get_value();
220         plugin->send_configure_change();
221         return 1;
222 }
223
224
225 LensMode::LensMode(LensMain *plugin, LensGUI *gui, int x, int y)
226  : BC_PopupMenu(x, y, calculate_w(gui), "", 1)
227 {
228         this->plugin = plugin;
229         this->gui = gui;
230 }
231
232 int LensMode::handle_event()
233 {
234         plugin->config.mode = from_text(get_text());
235         plugin->send_configure_change();
236         return 1;
237
238 }
239
240 void LensMode::create_objects()
241 {
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);
247 }
248
249 void LensMode::update(int mode)
250 {
251         char string[BCTEXTLEN];
252         sprintf(string, "%s", to_text(mode));
253         set_text(string);
254 }
255
256 int LensMode::calculate_w(LensGUI *gui)
257 {
258         int result = 0;
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)));
263         return result + 50;
264 }
265
266 int LensMode::from_text(char *text)
267 {
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;
273 }
274
275 const char* LensMode::to_text(int mode)
276 {
277         switch( 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");
282         }
283         return _("Sphere Stretch");
284 }
285
286
287 // LensPresets::LensPresets(LensMain *plugin,
288 //      LensGUI *gui, int x, int y, int w)
289 //  : BC_PopupMenu(x, y, w, "", 1)
290 // {
291 //      this->plugin = plugin;
292 //      this->gui = gui;
293 // }
294 //
295 // int LensPresets::handle_event()
296 // {
297 //      return 1;
298 // }
299 //
300 // void LensPresets::create_objects()
301 // {
302 // // Remove existing items
303 //      int total = total_items();
304 //      for( int i=0; i<total; ++i ) {
305 //              del_item();
306 //      }
307 //
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));
312 //      }
313 //
314 // // Update text
315 //      if( plugin->current_preset >= 0 &&
316 //          plugin->current_preset < plugin->presets.total ) {
317 //              set_text(plugin->presets.values[plugin->current_preset]->title);
318 //      }
319 //      else {
320 //              set_text("None");
321 //      }
322 // }
323 //
324 // int LensPresets::from_text(LensMain *plugin, char *text)
325 // {
326 // }
327 //
328 // char* LensPresets::to_text(LensMain *plugin, int preset)
329 // {
330 // }
331 //
332 // void LensPresets::update(int preset)
333 // {
334 // }
335 //
336 //
337 // LensSavePreset::LensSavePreset(LensMain *plugin, LensGUI *gui, int x, int y)
338 //  : BC_GenericButton(x, y, _("Save Preset"))
339 // {
340 //      this->plugin = plugin;
341 //      this->gui = gui;
342 // }
343 //
344 // int LensSavePreset::handle_event()
345 // {
346 // }
347 //
348 //
349 // LensDeletePreset::LensDeletePreset(LensMain *plugin, LensGUI *gui, int x, int y)
350 //  : BC_GenericButton(x, y, _("Delete Preset"))
351 // {
352 // }
353 //
354 // int LensDeletePreset::handle_event()
355 // {
356 // }
357 //
358 //
359 // LensPresetText::LensPresetText(LensMain *plugin, LensGUI *gui, int x, int y, int w)
360 //  : BC_TextBox(x, y, w, 1, "")
361 // {
362 //      this->plugin = plugin;
363 //      this->gui = gui;
364 // }
365 //
366 // int LensPresetText::handle_event()
367 // {
368 // }
369
370
371 LensInterpItem::LensInterpItem(const char *text, int id)
372  : BC_MenuItem(text)
373 {
374         this->id = id;
375 }
376
377 int LensInterpItem::handle_event()
378 {
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();
384         return 1;
385 }
386
387 LensInterp::LensInterp(LensMain *plugin, int x, int y)
388  : BC_PopupMenu(x, y, 120, "")
389 {
390         this->plugin = plugin;
391 }
392
393 void LensInterp::create_objects()
394 {
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);
400 }
401
402 void LensInterp::set_value(int id)
403 {
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());
408                         value = id;
409                         return;
410                 }
411         }
412 }
413
414 int LensInterp::get_value()
415 {
416         return value;
417 }
418
419
420 LensReset::LensReset(LensMain *plugin, LensGUI *gui, int x, int y)
421  : BC_GenericButton(x, y, _("Reset"))
422 {
423         this->plugin = plugin;
424         this->gui = gui;
425 }
426
427 int LensReset::handle_event()
428 {
429         plugin->config.reset();
430         gui->update_gui();
431         plugin->send_configure_change();
432         return 1;
433 }
434
435
436 LensGUI::LensGUI(LensMain *plugin)
437  : PluginClientWindow(plugin, 350, 550, 350, 550, 0)
438 {
439         this->plugin = plugin;
440 }
441
442 LensGUI::~LensGUI()
443 {
444 }
445
446
447 void LensGUI::create_objects()
448 {
449         int x = 10;
450         int y = 10;
451         int x1;
452         BC_Title *title = 0;
453         LensToggle *toggle;
454
455         for( int i=0; i<FOV_CHANNELS; ++i ) {
456                 switch( 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;
461                 }
462
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;
471         }
472
473         add_tool(toggle = new LensToggle(plugin, &plugin->lock, x, y, _("Lock")));
474         y += toggle->get_h() + 10;
475
476         BC_Bar *bar;
477         add_tool(bar = new BC_Bar(x, y, get_w() - x * 2));
478         y += bar->get_h() + 5;
479
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;
489
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;
499
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;
510
511
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;
522
523         add_tool(bar = new BC_Bar(x, y, get_w() - x * 2));
524         y += bar->get_h() + 5;
525
526
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;
533
534
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;
540
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;
546
547         add_tool(reset = new LensReset(plugin, this, x, y));
548         y += reset->get_h() + 5;
549
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;
555 //
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));
562
563         show_window();
564         flush();
565 }
566
567
568 LensMain::LensMain(PluginServer *server)
569  : PluginVClient(server)
570 {
571
572         engine = 0;
573         lock = 0;
574         current_preset = -1;
575 }
576
577 LensMain::~LensMain()
578 {
579
580         delete engine;
581         presets.remove_all_objects();
582 }
583
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"); }
588
589 void LensMain::update_gui()
590 {
591         if( !thread ) return;
592         if( !load_configuration() ) return;
593         ((LensGUI *)thread->window)->lock_window("LensMain::update_gui");
594         LensGUI *gui = (LensGUI *)thread->window;
595         gui->update_gui();
596         gui->unlock_window();
597 }
598
599 void LensGUI::update_gui()
600 {
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]);
605         }
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);
617 }
618
619 //void LensMain::save_presets()
620 //{
621 //      char path[BCTEXTLEN], string[BCTEXTLEN];
622 //      sprintf(path, "%s/lenspresets.rc", File::get_config_path());
623 //      BC_Hash *defaults = new BC_Hash(path);
624 //
625 //// Save presets
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);
631 //
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]);
635 //              }
636 //
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);
643 //      }
644 //
645 //      defaults->save();
646 //      delete defaults;
647 //}
648
649
650 void LensMain::save_data(KeyFrame *keyframe)
651 {
652         FileXML output;
653         char string[BCTEXTLEN];
654
655
656
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]);
663         }
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);
671         output.append_tag();
672         output.tag.set_title("/LENS");
673         output.append_tag();
674         output.append_newline();
675         output.terminate_string();
676
677 }
678
679
680 void LensMain::read_data(KeyFrame *keyframe)
681 {
682         FileXML input;
683         char string[BCTEXTLEN];
684
685
686         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
687
688         int result = 0;
689
690         while(!result)
691         {
692                 result = input.read_tag();
693
694                 if( !result ) {
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]);
699                                 }
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);
707                         }
708                 }
709         }
710 }
711
712
713
714 int LensMain::process_buffer(VFrame *frame,
715         int64_t start_position,
716         double frame_rate)
717 {
718         load_configuration();
719         int use_opengl = config.interp != LensConfig::INTERP_DEFAULT ? 0 :
720                 get_use_opengl();
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);
724
725         if( use_opengl ) {
726                 run_opengl();
727                 return 0;
728         }
729
730         if( !engine ) engine = new LensEngine(this);
731         engine->process_packages();
732
733         if( config.draw_guides ) {
734 // Draw center
735 #define CENTER_H 20
736 #define CENTER_W 20
737 #define DRAW_GUIDES(components, type, max) \
738 { \
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; \
748                         } \
749                 } \
750  \
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]; \
757                         } \
758                 } \
759         } \
760 }
761
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() ) {
767                 case BC_RGB_FLOAT:
768                         DRAW_GUIDES(3, float, 1.0)
769                         break;
770                 case BC_RGBA_FLOAT:
771                         DRAW_GUIDES(4, float, 1.0)
772                         break;
773                 case BC_RGB888:
774                         DRAW_GUIDES(3, unsigned char, 0xff)
775                         break;
776                 case BC_RGBA8888:
777                         DRAW_GUIDES(4, unsigned char, 0xff)
778                         break;
779                 case BC_YUV888:
780                         DRAW_GUIDES(3, unsigned char, 0xff)
781                         break;
782                 case BC_YUVA8888:
783                         DRAW_GUIDES(4, unsigned char, 0xff)
784                         break;
785                 }
786         }
787
788         return 0;
789 }
790
791
792 int LensMain::handle_opengl()
793 {
794 #ifdef HAVE_GL
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"
802                 "uniform vec4 r;\n"
803                 "uniform vec4 max_z;\n"
804                 "void main()\n"
805                 "{\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"
809                 "       {\n"
810                 "               gl_FragColor = texture2D(tex, outcoord);\n"
811                 "       }\n"
812                 "       else\n"
813                 "       {\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"
819                 "               vec4 in_x;\n"
820                 "               vec4 in_y;\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"
825                 "               else\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"
829                 "               else\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"
833                 "               else\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"
837                 "               else\n"
838                 "                       gl_FragColor.a = texture2D(tex, vec2(in_x.a, in_y.a) / texture_extents).a;\n"
839                 "       }\n"
840                 "}\n";
841
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"
849                 "uniform vec4 r;\n"
850                 "void main()\n"
851                 "{\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"
858                 "       float a2;\n"
859                 "       if( coord_diff.x == 0.0 )\n"
860                 "       {\n"
861                 "               if( coord_diff.y < 0.0 )\n"
862                 "                       a2 = 3.0 * 3.14159 / 2.0;\n"
863                 "               else\n"
864                 "                       a2 = 3.14159 / 2.0;\n"
865                 "       }\n"
866                 "       else\n"
867                 "               a2 = atan(coord_diff.y, coord_diff.x);\n"
868                 "       vec4 in_x;\n"
869                 "       vec4 in_y;\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"
874                 "       else\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"
878                 "       else\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"
882                 "       else\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"
886                 "       else\n"
887                 "               gl_FragColor.a = texture2D(tex, vec2(in_x.a, in_y.a) / texture_extents).a;\n"
888                 "}\n";
889
890
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"
898                 "uniform vec4 r;\n"
899                 "uniform float radius;\n"
900                 "void main()\n"
901                 "{\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"
908                 "\n"
909                 "       float angle;\n"
910                 "       if( coord_diff.x == 0.0 )\n"
911                 "       {\n"
912                 "               if( coord_diff.y < 0.0 )\n"
913                 "                       angle = 3.0 * 3.14159 / 2.0;\n"
914                 "               else\n"
915                 "                       angle = 3.14159 / 2.0;\n"
916                 "       }\n"
917                 "       else\n"
918                 "               angle = atan(coord_diff.y, coord_diff.x);\n"
919                 "       vec4 in_x;\n"
920                 "       vec4 in_y;\n"
921                 "\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"
926                 "       else\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"
930                 "       else\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"
934                 "       else\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"
938                 "       else\n"
939                 "               gl_FragColor.a = texture2D(tex, vec2(in_x.a, in_y.a) / texture_extents).a;\n"
940                 "}\n";
941
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"
949                 "uniform vec4 r;\n"
950                 "void main()\n"
951                 "{\n"
952                 "       vec2 outcoord = gl_TexCoord[0].st * texture_extents;\n"
953                 "       vec2 coord_diff = outcoord - center_coord;\n"
954                 "       float z = sqrt(coord_diff.x * coord_diff.x +\n"
955                 "                                       coord_diff.y * coord_diff.y);\n"
956                 "       vec4 radius1 = vec4(z, z, z, z) / r;\n"
957                 "       vec4 z_in = r * tan(radius1) / (3.14159 / 2.0);\n"
958                 "\n"
959                 "       float angle;\n"
960                 "       if( coord_diff.x == 0.0 )\n"
961                 "       {\n"
962                 "               if( coord_diff.y < 0.0 )\n"
963                 "                       angle = 3.0 * 3.14159 / 2.0;\n"
964                 "               else\n"
965                 "                       angle = 3.14159 / 2.0;\n"
966                 "       }\n"
967                 "       else\n"
968                 "               angle = atan(coord_diff.y, coord_diff.x);\n"
969                 "       vec4 in_x;\n"
970                 "       vec4 in_y;\n"
971                 "\n"
972                 "       in_x = z_in * cos(angle) * aspect.x + center_coord.x;\n"
973                 "       in_y = z_in * sin(angle) * aspect.y + center_coord.y;\n"
974                 "       if( in_x.r < 0.0 || in_x.r >= image_extents.x || in_y.r < 0.0 || in_y.r >= image_extents.y )\n"
975                 "               gl_FragColor.r = border_color.r;\n"
976                 "       else\n"
977                 "               gl_FragColor.r = texture2D(tex, vec2(in_x.r, in_y.r) / texture_extents).r;\n"
978                 "       if( in_x.g < 0.0 || in_x.g >= image_extents.x || in_y.g < 0.0 || in_y.g >= image_extents.y )\n"
979                 "               gl_FragColor.g = border_color.g;\n"
980                 "       else\n"
981                 "               gl_FragColor.g = texture2D(tex, vec2(in_x.g, in_y.g) / texture_extents).g;\n"
982                 "       if( in_x.b < 0.0 || in_x.b >= image_extents.x || in_y.b < 0.0 || in_y.b >= image_extents.y )\n"
983                 "               gl_FragColor.b = border_color.b;\n"
984                 "       else\n"
985                 "               gl_FragColor.b = texture2D(tex, vec2(in_x.b, in_y.b) / texture_extents).b;\n"
986                 "       if( in_x.a < 0.0 || in_x.a >= image_extents.x || in_y.a < 0.0 || in_y.a >= image_extents.y )\n"
987                 "               gl_FragColor.a = border_color.a;\n"
988                 "       else\n"
989                 "               gl_FragColor.a = texture2D(tex, vec2(in_x.a, in_y.a) / texture_extents).a;\n"
990                 "}\n";
991
992         get_output()->to_texture();
993         get_output()->enable_opengl();
994
995         unsigned int shader = 0;
996         const char *shader_frag = 0;
997         switch( config.mode ) {
998         case LensConfig::SPHERICAL_SHRINK:
999                 shader_frag = shrink_frag;
1000                 break;
1001         case LensConfig::SPHERICAL_STRETCH:
1002                 shader_frag = stretch_frag;
1003                 break;
1004         case LensConfig::RECTILINEAR_STRETCH:
1005                 shader_frag = rectilinear_stretch_frag;
1006                 break;
1007         case LensConfig::RECTILINEAR_SHRINK:
1008                 shader_frag = rectilinear_shrink_frag;
1009                 break;
1010         }
1011         if( shader_frag )
1012                 shader = VFrame::make_shader(0, shader_frag, 0);
1013         if( 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] = border_color[2] = 0.5;
1017                 }
1018
1019                 double x_factor = config.aspect;
1020                 double y_factor = 1.0 / config.aspect;
1021                 if( x_factor < 1 ) x_factor = 1;
1022                 if( y_factor < 1 ) y_factor = 1;
1023
1024                 glUseProgram(shader);
1025                 glUniform1i(glGetUniformLocation(shader, "tex"), 0);
1026                 glUniform2f(glGetUniformLocation(shader, "aspect"),
1027                         x_factor,
1028                         y_factor);
1029                 glUniform2f(glGetUniformLocation(shader, "center_coord"),
1030                                 (GLfloat)get_input()->get_w() * config.center_x / 100.0,
1031                                 (GLfloat)get_input()->get_h() * config.center_y / 100.0);
1032                 glUniform2f(glGetUniformLocation(shader, "texture_extents"),
1033                                 (GLfloat)get_input()->get_texture_w(),
1034                                 (GLfloat)get_input()->get_texture_h());
1035                 glUniform2f(glGetUniformLocation(shader, "image_extents"),
1036                                 (GLfloat)get_input()->get_w(),
1037                                 (GLfloat)get_input()->get_h());
1038
1039                 int width = get_output()->get_w();
1040                 int height = get_output()->get_h();
1041                 float *fov = config.fov;
1042                 float dim;
1043                 float max_z;
1044                 switch( config.mode ) {
1045                 case LensConfig::SPHERICAL_SHRINK:
1046                         dim = MAX(width, height) * config.radius;
1047                         max_z = dim * sqrt(2.0) / 2;
1048                         glUniform4fv(glGetUniformLocation(shader, "border_color"),
1049                                         1, (GLfloat*)border_color);
1050                         glUniform4f(glGetUniformLocation(shader, "max_z"),
1051                                         max_z / fov[0],
1052                                         max_z / fov[1],
1053                                         max_z / fov[2],
1054                                         max_z / fov[3]);
1055                         glUniform4f(glGetUniformLocation(shader, "r"),
1056                                         (max_z / fov[0]) * 2 / M_PI,
1057                                         (max_z / fov[1]) * 2 / M_PI,
1058                                         (max_z / fov[2]) * 2 / M_PI,
1059                                         (max_z / fov[3]) * 2 / M_PI);
1060                         break;
1061
1062                 case LensConfig::SPHERICAL_STRETCH:
1063                         dim = MAX(width, height) * config.radius;
1064                         max_z = dim * sqrt(2.0) / 2;
1065                         glUniform4f(glGetUniformLocation(shader, "r"),
1066                                         max_z / M_PI / (fov[0] / 2.0),
1067                                         max_z / M_PI / (fov[1] / 2.0),
1068                                         max_z / M_PI / (fov[2] / 2.0),
1069                                         max_z / M_PI / (fov[3] / 2.0));
1070                         break;
1071
1072                 case LensConfig::RECTILINEAR_STRETCH:
1073                         max_z = sqrt(SQR(width) + SQR(height)) / 2;
1074                         glUniform4f(glGetUniformLocation(shader, "r"),
1075                                         max_z / M_PI / (fov[0] / 2.0),
1076                                         max_z / M_PI / (fov[1] / 2.0),
1077                                         max_z / M_PI / (fov[2] / 2.0),
1078                                         max_z / M_PI / (fov[3] / 2.0));
1079                         glUniform1f(glGetUniformLocation(shader, "radius"),
1080                                         config.radius);
1081                         break;
1082
1083                 case LensConfig::RECTILINEAR_SHRINK:
1084                         max_z = MAX(width, height) / 2 * config.radius;
1085                         glUniform4f(glGetUniformLocation(shader, "r"),
1086                                         max_z / fov[0],
1087                                         max_z / fov[1],
1088                                         max_z / fov[2],
1089                                         max_z / fov[3]);
1090                         break;
1091                 }
1092
1093                 get_output()->init_screen();
1094                 get_output()->bind_texture(0);
1095                 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
1096                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
1097                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
1098                 get_output()->draw_texture();
1099                 glUseProgram(0);
1100
1101                 if( config.draw_guides ) {
1102                         int w = get_output()->get_w();
1103                         int h = get_output()->get_h();
1104                         int center_x = (int)(config.center_x * w / 100);
1105                         int center_y = (int)(config.center_y * h / 100);
1106
1107                         glDisable(GL_TEXTURE_2D);
1108                         glColor4f(0.0, 0.0, 0.0, 1.0);
1109                         glBegin(GL_LINES);
1110                         glVertex3f(center_x, -h + center_y - CENTER_H / 2, 0.0);
1111                         glVertex3f(center_x, -h + center_y + CENTER_H / 2, 0.0);
1112                         glEnd();
1113                         glBegin(GL_LINES);
1114                         glVertex3f(center_x - CENTER_W / 2, -h + center_y, 0.0);
1115                         glVertex3f(center_x + CENTER_W / 2, -h + center_y, 0.0);
1116                         glEnd();
1117                         glColor4f(1.0, 1.0, 1.0, 1.0);
1118                         glBegin(GL_LINES);
1119                         glVertex3f(center_x - 1, -h + center_y - CENTER_H / 2 - 1, 0.0);
1120                         glVertex3f(center_x - 1, -h + center_y + CENTER_H / 2 - 1, 0.0);
1121                         glEnd();
1122                         glBegin(GL_LINES);
1123                         glVertex3f(center_x - CENTER_W / 2 - 1, -h + center_y - 1, 0.0);
1124                         glVertex3f(center_x + CENTER_W / 2 - 1, -h + center_y - 1, 0.0);
1125                         glEnd();
1126                 }
1127                 get_output()->set_opengl_state(VFrame::SCREEN);
1128         }
1129
1130 #endif
1131         return 0;
1132 }
1133
1134 // do using specified interpolation
1135 #define DO_LENS(type) \
1136         int icolor_model = plugin->get_input()->get_color_model(); \
1137         switch( plugin->config.interp ) { \
1138         case LensConfig::INTERP_NEAREST: \
1139                 switch( icolor_model ) { \
1140                 case BC_RGB888: \
1141                         DO_LENS_##type(unsigned char, 3, 0xff, 0x0, nearest); \
1142                         break; \
1143                 case BC_RGBA8888: \
1144                         DO_LENS_##type(unsigned char, 4, 0xff, 0x0, nearest); \
1145                         break; \
1146                 case BC_RGB_FLOAT: \
1147                         DO_LENS_##type(float, 3, 1.0, 0.0, nearest); \
1148                         break; \
1149                 case BC_RGBA_FLOAT: \
1150                         DO_LENS_##type(float, 4, 1.0, 0.0, nearest); \
1151                         break; \
1152                 case BC_YUV888: \
1153                         DO_LENS_##type(unsigned char, 3, 0xff, 0x80, nearest); \
1154                         break; \
1155                 case BC_YUVA8888: \
1156                         DO_LENS_##type(unsigned char, 4, 0xff, 0x80, nearest); \
1157                         break; \
1158                 } \
1159                 break; \
1160         case LensConfig::INTERP_DEFAULT: \
1161         case LensConfig::INTERP_BILINEAR: \
1162                 switch( icolor_model ) { \
1163                 case BC_RGB888: \
1164                         DO_LENS_##type(unsigned char, 3, 0xff, 0x0, bi_linear); \
1165                         break; \
1166                 case BC_RGBA8888: \
1167                         DO_LENS_##type(unsigned char, 4, 0xff, 0x0, bi_linear); \
1168                         break; \
1169                 case BC_RGB_FLOAT: \
1170                         DO_LENS_##type(float, 3, 1.0, 0.0, bi_linear); \
1171                         break; \
1172                 case BC_RGBA_FLOAT: \
1173                         DO_LENS_##type(float, 4, 1.0, 0.0, bi_linear); \
1174                         break; \
1175                 case BC_YUV888: \
1176                         DO_LENS_##type(unsigned char, 3, 0xff, 0x80, bi_linear); \
1177                         break; \
1178                 case BC_YUVA8888: \
1179                         DO_LENS_##type(unsigned char, 4, 0xff, 0x80, bi_linear); \
1180                         break; \
1181                 } \
1182                 break; \
1183         case LensConfig::INTERP_BICUBIC: \
1184                 switch( icolor_model ) { \
1185                 case BC_RGB888: \
1186                         DO_LENS_##type(unsigned char, 3, 0xff, 0x0, bi_cubic); \
1187                         break; \
1188                 case BC_RGBA8888: \
1189                         DO_LENS_##type(unsigned char, 4, 0xff, 0x0, bi_cubic); \
1190                         break; \
1191                 case BC_RGB_FLOAT: \
1192                         DO_LENS_##type(float, 3, 1.0, 0.0, bi_cubic); \
1193                         break; \
1194                 case BC_RGBA_FLOAT: \
1195                         DO_LENS_##type(float, 4, 1.0, 0.0, bi_cubic); \
1196                         break; \
1197                 case BC_YUV888: \
1198                         DO_LENS_##type(unsigned char, 3, 0xff, 0x80, bi_cubic); \
1199                         break; \
1200                 case BC_YUVA8888: \
1201                         DO_LENS_##type(unsigned char, 4, 0xff, 0x80, bi_cubic); \
1202                         break; \
1203                 } \
1204                 break; \
1205         }
1206
1207 LensPackage::LensPackage()
1208  : LoadPackage()
1209 {
1210 }
1211
1212 LensUnit::LensUnit(LensEngine *engine, LensMain *plugin)
1213  : LoadClient(engine)
1214 {
1215         this->plugin = plugin;
1216 }
1217
1218 LensUnit::~LensUnit()
1219 {
1220 }
1221
1222 void LensUnit::process_spherical_stretch(LensPackage *pkg)
1223 {
1224         float *fov = plugin->config.fov;
1225         float aspect = plugin->config.aspect;
1226         int row1 = pkg->row1;
1227         int row2 = pkg->row2;
1228         double x_factor = aspect;
1229         double y_factor = 1.0 / aspect;
1230         if( x_factor < 1 ) x_factor = 1;
1231         if( y_factor < 1 ) y_factor = 1;
1232         int width = plugin->get_input()->get_w();
1233         int height = plugin->get_input()->get_h();
1234         double dim = MAX(width, height) * plugin->config.radius;
1235         double max_z = dim * sqrt(2.0) / 2;
1236         double center_x = width * plugin->config.center_x / 100.0;
1237         double center_y = height * plugin->config.center_y / 100.0;
1238         double r[FOV_CHANNELS];
1239
1240         r[0] = max_z / M_PI / (fov[0] / 2.0);
1241         r[1] = max_z / M_PI / (fov[1] / 2.0);
1242         r[2] = max_z / M_PI / (fov[2] / 2.0);
1243         r[3] = max_z / M_PI / (fov[3] / 2.0);
1244
1245 #define DO_LENS_SPHERICAL_STRETCH(type, components, max, chroma, interp) { \
1246         type **in_rows = (type**)plugin->get_temp()->get_rows(); \
1247         type **out_rows = (type**)plugin->get_input()->get_rows(); \
1248         type black[4] = { 0, chroma, chroma, 0 }; \
1249         INTERP_SETUP(in_rows, max, 0,0, width,height); \
1250  \
1251         for( int y=row1; y<row2; ++y ) { \
1252                 type *out_row = out_rows[y]; \
1253                 double y_diff = y - center_y; \
1254                 for( int x=0; x<width; ++x ) { \
1255                         double x_diff = (x - center_x); \
1256                         double z = sqrt(x_diff * x_diff + y_diff * y_diff); \
1257                         double a2 = x != center_x ? atan(y_diff / x_diff) : \
1258                                 y < center_y ? 3*M_PI/2 : M_PI/2; \
1259                         if( x_diff < 0.0 ) a2 += M_PI; \
1260                         for( int i=0; i<components; ++i ) { \
1261                                 double a1 = (z / (M_PI * r[i] / 2)) * (M_PI / 2); \
1262                                 double z_in = r[i] * sin(a1); \
1263                                 double x_in = z_in * cos(a2) * x_factor + center_x; \
1264                                 double y_in = z_in * sin(a2) * y_factor + center_y; \
1265                                 interp##_SETUP(type, components, x_in, y_in); \
1266                                 for( int j=0; j<i; ++j ) interp##_next(); \
1267                                 *out_row++ = interp##_interp(black[i], black[i]); \
1268                         } \
1269                 } \
1270         } \
1271  \
1272         type *out_pixel = out_rows[(int)center_y] + (int)center_x * components; \
1273         type *inp_pixel = in_rows[(int)center_y] + (int)center_x * components; \
1274         for( int i=0; i<components; ++i ) *out_pixel++ = *inp_pixel++; \
1275 }
1276
1277         DO_LENS(SPHERICAL_STRETCH);
1278 }
1279
1280 void LensUnit::process_spherical_shrink(LensPackage *pkg)
1281 {
1282
1283         float *fov = plugin->config.fov;
1284         float aspect = plugin->config.aspect;
1285         int row1 = pkg->row1;
1286         int row2 = pkg->row2;
1287         int width = plugin->get_input()->get_w();
1288         int height = plugin->get_input()->get_h();
1289         double x_factor = aspect;
1290         double y_factor = 1.0 / aspect;
1291         if( x_factor < 1 ) x_factor = 1;
1292         if( y_factor < 1 ) y_factor = 1;
1293         double dim = MAX(width, height) * plugin->config.radius;
1294         double max_z[FOV_CHANNELS];
1295         double center_x = width * plugin->config.center_x / 100.0;
1296         double center_y = height * plugin->config.center_y / 100.0;
1297         double r[FOV_CHANNELS];
1298
1299 //      max_z[0] = sqrt(SQR(width) + SQR(height)) / 2 / fov[0];
1300 //      max_z[1] = sqrt(SQR(width) + SQR(height)) / 2 / fov[1];
1301 //      max_z[2] = sqrt(SQR(width) + SQR(height)) / 2 / fov[2];
1302 //      max_z[3] = sqrt(SQR(width) + SQR(height)) / 2 / fov[3];
1303         max_z[0] = dim * sqrt(2.0) / 2 / fov[0];
1304         max_z[1] = dim * sqrt(2.0) / 2 / fov[1];
1305         max_z[2] = dim * sqrt(2.0) / 2 / fov[2];
1306         max_z[3] = dim * sqrt(2.0) / 2 / fov[3];
1307         r[0] = max_z[0] * 2 / M_PI;
1308         r[1] = max_z[1] * 2 / M_PI;
1309         r[2] = max_z[2] * 2 / M_PI;
1310         r[3] = max_z[3] * 2 / M_PI;
1311
1312 #define DO_LENS_SPHERICAL_SHRINK(type, components, max, chroma, interp) { \
1313         type **in_rows = (type**)plugin->get_temp()->get_rows(); \
1314         type **out_rows = (type**)plugin->get_input()->get_rows(); \
1315         type black[4] = { 0, chroma, chroma, 0 }; \
1316         INTERP_SETUP(in_rows, max, 0,0, width,height); \
1317  \
1318         for( int y=row1; y<row2; ++y ) { \
1319                 type *out_row = out_rows[y]; \
1320                 type *in_row = in_rows[y]; \
1321                 double y_diff = y - center_y; \
1322                 for( int x=0; x<width; ++x ) { \
1323                         double x_diff = x - center_x; \
1324                         if( !x_diff && !y_diff ) { \
1325                                 type *inp_pixel = in_row + x * components; \
1326                                 for( int c=0; c<components; ++c ) \
1327                                         *out_row++ = *inp_pixel++; \
1328                                 continue; \
1329                         } \
1330                         double z = sqrt(x_diff * x_diff + y_diff * y_diff); \
1331                         double a2 = atan(y_diff / x_diff); \
1332                         if( x_diff < 0.0 ) a2 += M_PI; \
1333                         for( int i=0; i<components; ++i ) { \
1334                                 if( z > r[i] ) { *out_row++ = black[i]; continue; } \
1335                                 double a1 = asin(z / r[i]); \
1336                                 double z_in = a1 * max_z[i] * 2 / M_PI; \
1337                                 float x_in = z_in * cos(a2) * x_factor + center_x; \
1338                                 float y_in = z_in * sin(a2) * y_factor + center_y; \
1339                                 interp##_SETUP(type, components, x_in, y_in); \
1340                                 for( int j=0; j<i; ++j ) interp##_next(); \
1341                                 *out_row++ = interp##_interp(black[i], black[i]); \
1342                         } \
1343                 } \
1344         } \
1345  \
1346         type *out_pixel = out_rows[(int)center_y] + (int)center_x * components; \
1347         type *inp_pixel = in_rows[(int)center_y] + (int)center_x * components; \
1348         for( int i=0; i<components; ++i ) *out_pixel++ = *inp_pixel++; \
1349 }
1350
1351         DO_LENS(SPHERICAL_SHRINK);
1352 }
1353
1354 void LensUnit::process_rectilinear_stretch(LensPackage *pkg)
1355 {
1356         float *fov = plugin->config.fov;
1357         float aspect = plugin->config.aspect;
1358         int row1 = pkg->row1;
1359         int row2 = pkg->row2;
1360         double x_factor = aspect;
1361         double y_factor = 1.0 / aspect;
1362         if( x_factor < 1 ) x_factor = 1;
1363         if( y_factor < 1 ) y_factor = 1;
1364         int width = plugin->get_input()->get_w();
1365         int height = plugin->get_input()->get_h();
1366 //      double dim = MAX(width, height) * plugin->config.radius;
1367 //      double max_z = dim * sqrt(2.0) / 2;
1368         double max_z = sqrt(SQR(width) + SQR(height)) / 2;
1369         double center_x = width * plugin->config.center_x / 100.0;
1370         double center_y = height * plugin->config.center_y / 100.0;
1371         double r[FOV_CHANNELS];
1372
1373         r[0] = max_z / M_PI / (fov[0] / 2.0);
1374         r[1] = max_z / M_PI / (fov[1] / 2.0);
1375         r[2] = max_z / M_PI / (fov[2] / 2.0);
1376         r[3] = max_z / M_PI / (fov[3] / 2.0);
1377
1378 #define DO_LENS_RECTILINEAR_STRETCH(type, components, max, chroma, interp) { \
1379         type **in_rows = (type**)plugin->get_temp()->get_rows(); \
1380         type **out_rows = (type**)plugin->get_input()->get_rows(); \
1381         type black[4] = { 0, chroma, chroma, 0 }; \
1382         INTERP_SETUP(in_rows, max, 0,0, width,height); \
1383  \
1384         for( int y=row1; y<row2; ++y ) { \
1385                 type *out_row = out_rows[y]; \
1386                 double y_diff = y - center_y; \
1387                 for( int x=0; x<width; ++x ) { \
1388                         double x_diff = (x - center_x); /* Compute magnitude / angle */ \
1389                         double z = sqrt(x_diff * x_diff + y_diff * y_diff); \
1390                         double angle = x != center_x ? atan(y_diff / x_diff) : \
1391                                 y < center_y ? 3*M_PI/2 : M_PI/2; \
1392                         if( x_diff < 0.0 ) angle += M_PI; \
1393                         for( int i=0; i<components; ++i ) { /* Compute new radius */ \
1394                                 double radius1 = (z / r[i]) * 2 * plugin->config.radius; \
1395                                 double z_in = r[i] * atan(radius1) / (M_PI / 2); \
1396                                 double x_in = z_in * cos(angle) * x_factor + center_x; \
1397                                 double y_in = z_in * sin(angle) * y_factor + center_y; \
1398                                 interp##_SETUP(type, components, x_in, y_in); \
1399                                 for( int j=0; j<i; ++j ) interp##_next(); \
1400                                 *out_row++ = interp##_interp(black[i], black[i]); \
1401                         } \
1402                 } \
1403         } \
1404  \
1405         type *out_pixel = out_rows[(int)center_y] + (int)center_x * components; \
1406         type *inp_pixel = in_rows[(int)center_y] + (int)center_x * components; \
1407         for( int i=0; i<components; ++i ) *out_pixel++ = *inp_pixel++; \
1408 }
1409
1410         DO_LENS(RECTILINEAR_STRETCH);
1411 }
1412
1413 void LensUnit::process_rectilinear_shrink(LensPackage *pkg)
1414 {
1415         float *fov = plugin->config.fov;
1416         float aspect = plugin->config.aspect;
1417         int row1 = pkg->row1;
1418         int row2 = pkg->row2;
1419         double x_factor = aspect;
1420         double y_factor = 1.0 / aspect;
1421         if( x_factor < 1 ) x_factor = 1;
1422         if( y_factor < 1 ) y_factor = 1;
1423         int width = plugin->get_input()->get_w();
1424         int height = plugin->get_input()->get_h();
1425         double max_z = MAX(width, height) / 2 * plugin->config.radius;
1426         double center_x = width * plugin->config.center_x / 100.0;
1427         double center_y = height * plugin->config.center_y / 100.0;
1428         double r[FOV_CHANNELS];
1429
1430         r[0] = max_z / fov[0];
1431         r[1] = max_z / fov[1];
1432         r[2] = max_z / fov[2];
1433         r[3] = max_z / fov[3];
1434
1435 #define DO_LENS_RECTILINEAR_SHRINK(type, components, max, chroma, interp) { \
1436         type **in_rows = (type**)plugin->get_temp()->get_rows(); \
1437         type **out_rows = (type**)plugin->get_input()->get_rows(); \
1438         type black[4] = { 0, chroma, chroma, 0 }; \
1439         INTERP_SETUP(in_rows, max, 0,0, width,height); \
1440  \
1441         for( int y=row1; y<row2; ++y ) { \
1442                 type *out_row = out_rows[y]; \
1443                 double y_diff = y - center_y; \
1444                 for( int x=0; x<width; ++x ) { \
1445                         double x_diff = (x - center_x); /* Compute magnitude/angle */ \
1446                         double z = sqrt(x_diff * x_diff + y_diff * y_diff); \
1447                         double angle = x != center_x ? atan(y_diff / x_diff) : \
1448                                 y < center_y ? 3*M_PI/2 : M_PI/2; \
1449                         if( x_diff < 0.0 ) angle += M_PI; \
1450                         for( int i=0; i<components; ++i ) { /* Compute new radius */ \
1451                                 double radius1 = z / r[i]; \
1452                                 double z_in = r[i] * tan(radius1) / (M_PI / 2); \
1453                                 double x_in = z_in * cos(angle) * x_factor + center_x; \
1454                                 double y_in = z_in * sin(angle) * y_factor + center_y; \
1455                                 interp##_SETUP(type, components, x_in, y_in); \
1456                                 for( int j=0; j<i; ++j ) interp##_next(); \
1457                                 *out_row++ = interp##_interp(black[i], black[i]); \
1458                         } \
1459                 } \
1460         } \
1461  \
1462         type *out_pixel = out_rows[(int)center_y] + (int)center_x * components; \
1463         type *inp_pixel = in_rows[(int)center_y] + (int)center_x * components; \
1464         for( int i=0; i<components; ++i ) *out_pixel++ = *inp_pixel++; \
1465 }
1466
1467         DO_LENS(RECTILINEAR_SHRINK);
1468 }
1469
1470 void LensUnit::process_package(LoadPackage *package)
1471 {
1472         LensPackage *pkg = (LensPackage*)package;
1473
1474         switch( plugin->config.mode ) {
1475         case LensConfig::SPHERICAL_STRETCH:
1476                 process_spherical_stretch(pkg);
1477                 break;
1478         case LensConfig::SPHERICAL_SHRINK:
1479                 process_spherical_shrink(pkg);
1480                 break;
1481         case LensConfig::RECTILINEAR_STRETCH:
1482                 process_rectilinear_stretch(pkg);
1483                 break;
1484         case LensConfig::RECTILINEAR_SHRINK:
1485                 process_rectilinear_shrink(pkg);
1486                 break;
1487         }
1488 }
1489
1490
1491 LensEngine::LensEngine(LensMain *plugin)
1492  : LoadServer(plugin->PluginClient::smp + 1, plugin->PluginClient::smp + 1)
1493 // : LoadServer(1, 1)
1494 {
1495         this->plugin = plugin;
1496 }
1497
1498 LensEngine::~LensEngine()
1499 {
1500 }
1501
1502 void LensEngine::init_packages()
1503 {
1504         int row1 = 0, row2 = 0, n = LoadServer::get_total_packages();
1505         for( int i=0; i<n; row1=row2 ) {
1506                 LensPackage *package = (LensPackage*)LoadServer::get_package(i);
1507                 row2 = plugin->get_input()->get_h() * ++i / n;
1508                 package->row1 = row1;  package->row2 = row2;
1509         }
1510 }
1511
1512 LoadClient* LensEngine::new_client()
1513 {
1514         return new LensUnit(this, plugin);
1515 }
1516
1517 LoadPackage* LensEngine::new_package()
1518 {
1519         return new LensPackage;
1520 }
1521
1522