c345333b381fb036e58626abae57882875491c6c
[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_BILINEAR;
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(_("Nearest"), LensConfig::INTERP_NEAREST));
396         add_item(new LensInterpItem(_("BiLinear"), LensConfig::INTERP_BILINEAR));
397         add_item(new LensInterpItem(_("BiCubic"), LensConfig::INTERP_BICUBIC));
398         set_value(plugin->config.interp);
399 }
400
401 void LensInterp::set_value(int id)
402 {
403         for( int i=0, n=total_items(); i<n; ++i ) {
404                 LensInterpItem *item = (LensInterpItem *)get_item(i);
405                 if( item->id == id ) {
406                         set_text(item->get_text());
407                         value = id;
408                         return;
409                 }
410         }
411 }
412
413 int LensInterp::get_value()
414 {
415         return value;
416 }
417
418
419 LensReset::LensReset(LensMain *plugin, LensGUI *gui, int x, int y)
420  : BC_GenericButton(x, y, _("Reset"))
421 {
422         this->plugin = plugin;
423         this->gui = gui;
424 }
425
426 int LensReset::handle_event()
427 {
428         plugin->config.reset();
429         gui->update_gui();
430         plugin->send_configure_change();
431         return 1;
432 }
433
434
435 LensGUI::LensGUI(LensMain *plugin)
436  : PluginClientWindow(plugin, 350, 550, 350, 550, 0)
437 {
438         this->plugin = plugin;
439 }
440
441 LensGUI::~LensGUI()
442 {
443 }
444
445
446 void LensGUI::create_objects()
447 {
448         int x = 10;
449         int y = 10;
450         int x1;
451         BC_Title *title = 0;
452         LensToggle *toggle;
453
454         for( int i=0; i<FOV_CHANNELS; ++i ) {
455                 switch( i ) {
456                 case 0: add_tool(title = new BC_Title(x, y, _("R Field of View:"))); break;
457                 case 1: add_tool(title = new BC_Title(x, y, _("G Field of View:"))); break;
458                 case 2: add_tool(title = new BC_Title(x, y, _("B Field of View:"))); break;
459                 case 3: add_tool(title = new BC_Title(x, y, _("A Field of View:"))); break;
460                 }
461
462                 y += title->get_h() + 5;
463                 add_tool(fov_slider[i] = new LensSlider(plugin, this,
464                         0, &plugin->config.fov[i], x, y, 0.0001, 1.0));
465                 x1 = x + fov_slider[i]->get_w() + 5;
466                 add_tool(fov_text[i] = new LensText(plugin, this,
467                         fov_slider[i], &plugin->config.fov[i], x1, y));
468                 fov_slider[i]->text = fov_text[i];
469                 y += fov_text[i]->get_h() + 5;
470         }
471
472         add_tool(toggle = new LensToggle(plugin, &plugin->lock, x, y, _("Lock")));
473         y += toggle->get_h() + 10;
474
475         BC_Bar *bar;
476         add_tool(bar = new BC_Bar(x, y, get_w() - x * 2));
477         y += bar->get_h() + 5;
478
479         add_tool(title = new BC_Title(x, y, _("Aspect Ratio:")));
480         y += title->get_h() + 5;
481         add_tool(aspect_slider = new LensSlider(plugin, this,
482                 0, &plugin->config.aspect, x, y, 0.333, 3.0));
483         x1 = x + aspect_slider->get_w() + 5;
484         add_tool(aspect_text = new LensText(plugin, this,
485                 aspect_slider, &plugin->config.aspect, x1, y));
486         aspect_slider->text = aspect_text;
487         y += aspect_text->get_h() + 5;
488
489         add_tool(title = new BC_Title(x, y, _("Radius:")));
490         y += title->get_h() + 5;
491         add_tool(radius_slider = new LensSlider(plugin, this,
492                 0, &plugin->config.radius, x, y, 0.333, 3.0));
493         x1 = x + radius_slider->get_w() + 5;
494         add_tool(radius_text = new LensText(plugin, this,
495                 radius_slider, &plugin->config.radius, x1, y));
496         radius_slider->text = radius_text;
497         y += radius_text->get_h() + 5;
498
499         add_tool(title = new BC_Title(x, y, _("Center X:")));
500         y += title->get_h() + 5;
501         add_tool(centerx_slider = new LensSlider(plugin, this,
502                 0, &plugin->config.center_x, x, y, 0.0, 99.0));
503         x1 = x + centerx_slider->get_w() + 5;
504         add_tool(centerx_text = new LensText(plugin, this,
505                 centerx_slider, &plugin->config.center_x, x1, y));
506         centerx_slider->text = centerx_text;
507         centerx_slider->set_precision(1.0);
508         y += centerx_text->get_h() + 5;
509
510
511         add_tool(title = new BC_Title(x, y, _("Center Y:")));
512         y += title->get_h() + 5;
513         add_tool(centery_slider = new LensSlider(plugin, this,
514                 0, &plugin->config.center_y, x, y, 0.0, 99.0));
515         x1 = x + centery_slider->get_w() + 5;
516         add_tool(centery_text = new LensText(plugin, this,
517                 centery_slider, &plugin->config.center_y, x1, y));
518         centery_slider->text = centery_text;
519         centery_slider->set_precision(1.0);
520         y += centery_text->get_h() + 10;
521
522         add_tool(bar = new BC_Bar(x, y, get_w() - x * 2));
523         y += bar->get_h() + 5;
524
525
526 //      add_tool(reverse = new LensToggle(plugin,
527 //              &plugin->config.reverse, x, y, _("Reverse")));
528 //      y += reverse->get_h() + 5;
529         add_tool(draw_guides = new LensToggle(plugin,
530                 &plugin->config.draw_guides, x, y, _("Draw center")));
531         y += draw_guides->get_h() + 5;
532
533
534         add_tool(title = new BC_Title(x, y, _("Mode:")));
535         add_tool(mode = new LensMode(plugin, this,
536                 x + title->get_w() + 5, y));
537         mode->create_objects();
538         y += mode->get_h() + 5;
539
540         add_tool(title = new BC_Title(x, y, _("Interp:")));
541         x1 = x + title->get_w() + 5;
542         add_tool(interp = new LensInterp(plugin, x1, y));
543         interp->create_objects();
544         y += interp->get_h() + 5;
545
546         add_tool(reset = new LensReset(plugin, this, x, y));
547         y += reset->get_h() + 5;
548
549 //      add_tool(title = new BC_Title(x, y, _("Preset:")));
550 //      add_tool(presets = new LensPresets(plugin, this,
551 //              x + title->get_w() + 5, y, get_w() - x - title->get_w() - 50));
552 //      presets->create_objects();
553 //      y += presets->get_h() + 5;
554 //
555 //      add_tool(save_preset = new LensSavePreset(plugin, this, x, y));
556 //      add_tool(preset_text = new LensPresetText(plugin, this,
557 //              x + save_preset->get_w() + 5, y,
558 //              get_w() - x - save_preset->get_w() - 10));
559 //      y += preset_text->get_h() + 5;
560 //      add_tool(delete_preset = new LensDeletePreset(plugin, this, x, y));
561
562         show_window();
563         flush();
564 }
565
566
567 LensMain::LensMain(PluginServer *server)
568  : PluginVClient(server)
569 {
570
571         engine = 0;
572         lock = 0;
573         current_preset = -1;
574 }
575
576 LensMain::~LensMain()
577 {
578
579         delete engine;
580         presets.remove_all_objects();
581 }
582
583 NEW_WINDOW_MACRO(LensMain, LensGUI)
584 LOAD_CONFIGURATION_MACRO(LensMain, LensConfig)
585 int LensMain::is_realtime() { return 1; }
586 const char* LensMain::plugin_title() { return _("Lens"); }
587
588 void LensMain::update_gui()
589 {
590         if( !thread ) return;
591         if( !load_configuration() ) return;
592         ((LensGUI *)thread->window)->lock_window("LensMain::update_gui");
593         LensGUI *gui = (LensGUI *)thread->window;
594         gui->update_gui();
595         gui->unlock_window();
596 }
597
598 void LensGUI::update_gui()
599 {
600         LensConfig &config = plugin->config;
601         for( int i=0; i<FOV_CHANNELS; ++i ) {
602                 fov_slider[i]->update(config.fov[i]);
603                 fov_text[i]->update(config.fov[i]);
604         }
605         aspect_slider->update(config.aspect);
606         aspect_text->update(config.aspect);
607         radius_slider->update(config.radius);
608         radius_text->update(config.radius);
609         centerx_slider->update(config.center_x);
610         centerx_text->update(config.center_x);
611         centery_slider->update(config.center_y);
612         centery_text->update(config.center_y);
613         mode->update(config.mode);
614         draw_guides->update(config.draw_guides);
615         interp->set_value(config.interp);
616 }
617
618 //void LensMain::save_presets()
619 //{
620 //      char path[BCTEXTLEN], string[BCTEXTLEN];
621 //      sprintf(path, "%s/lenspresets.rc", File::get_config_path());
622 //      BC_Hash *defaults = new BC_Hash(path);
623 //
624 //// Save presets
625 //      defaults->update("TOTAL_PRESETS", presets.total);
626 //      for( int i=0; i<presets.total; ++i ) {
627 //              LensPreset *preset = presets.values[i];
628 //              sprintf(string, "TITLE_%d", i);
629 //              defaults->update(string, preset->title);
630 //
631 //              for( int j=0; j<FOV_CHANNELS; ++j ) {
632 //                      sprintf(string, "FOCAL_LENGTH_%d_%d", i, j);
633 //                      defaults->update(string, preset->fov[j]);
634 //              }
635 //
636 //              sprintf(string, "ASPECT_%d", i);
637 //              defaults->update(string, preset->aspect);
638 //              sprintf(string, "RADIUS_%d", i);
639 //              defaults->update(string, preset->radius);
640 //              sprintf(string, "MODE_%d", i);
641 //              defaults->update(string, preset->mode);
642 //      }
643 //
644 //      defaults->save();
645 //      delete defaults;
646 //}
647
648
649 void LensMain::save_data(KeyFrame *keyframe)
650 {
651         FileXML output;
652         char string[BCTEXTLEN];
653
654
655
656 // cause data to be stored directly in text
657         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
658         output.tag.set_title("LENS");
659         for( int i = 0; i < FOV_CHANNELS; ++i ) {
660                 sprintf(string, "FOCAL_LENGTH%d", i);
661                 output.tag.set_property(string, config.fov[i]);
662         }
663         output.tag.set_property("ASPECT", config.aspect);
664         output.tag.set_property("RADIUS", config.radius);
665         output.tag.set_property("MODE", config.mode);
666         output.tag.set_property("INTERP", config.interp);
667         output.tag.set_property("CENTER_X", config.center_x);
668         output.tag.set_property("CENTER_Y", config.center_y);
669         output.tag.set_property("DRAW_GUIDES", config.draw_guides);
670         output.append_tag();
671         output.tag.set_title("/LENS");
672         output.append_tag();
673         output.append_newline();
674         output.terminate_string();
675
676 }
677
678
679 void LensMain::read_data(KeyFrame *keyframe)
680 {
681         FileXML input;
682         char string[BCTEXTLEN];
683
684
685         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
686
687         int result = 0;
688
689         while(!result)
690         {
691                 result = input.read_tag();
692
693                 if( !result ) {
694                         if( input.tag.title_is("LENS") ) {
695                                 for( int i=0; i<FOV_CHANNELS; ++i ) {
696                                         sprintf(string, "FOCAL_LENGTH%d", i);
697                                         config.fov[i] = input.tag.get_property(string, config.fov[i]);
698                                 }
699                                 config.aspect = input.tag.get_property("ASPECT", config.aspect);
700                                 config.radius = input.tag.get_property("RADIUS", config.radius);
701                                 config.mode = input.tag.get_property("MODE", config.mode);
702                                 config.interp = input.tag.get_property("INTERP", config.interp);
703                                 config.center_x = input.tag.get_property("CENTER_X", config.center_x);
704                                 config.center_y = input.tag.get_property("CENTER_Y", config.center_y);
705                                 config.draw_guides = input.tag.get_property("DRAW_GUIDES", config.draw_guides);
706                         }
707                 }
708         }
709 }
710
711
712
713 int LensMain::process_buffer(VFrame *frame,
714         int64_t start_position,
715         double frame_rate)
716 {
717         VFrame *input;
718         load_configuration();
719
720         if( get_use_opengl() ) {
721                 input = frame;
722         }
723         else {
724                 input = new_temp(frame->get_w(), frame->get_h(), frame->get_color_model());
725         }
726
727         read_frame(input,
728                 0,
729                 start_position,
730                 frame_rate,
731                 get_use_opengl());
732
733
734         if( get_use_opengl() ) {
735                 run_opengl();
736                 return 0;
737         }
738         else {
739                 if( !engine ) engine = new LensEngine(this);
740                 engine->process_packages();
741                 if( config.draw_guides ) {
742 // Draw center
743 #define CENTER_H 20
744 #define CENTER_W 20
745 #define DRAW_GUIDES(components, type, max) \
746 { \
747         type **rows = (type**)get_output()->get_rows(); \
748         if( (center_x >= 0 && center_x < w) || (center_y >= 0 && center_y < h) ) { \
749                 type *hrow = rows[center_y] + components * (center_x - CENTER_W / 2); \
750                 for( int i=center_x-CENTER_W/2; i<=center_x+CENTER_W/2; ++i ) { \
751                         if( i >= 0 && i < w ) { \
752                                 hrow[0] = max - hrow[0]; \
753                                 hrow[1] = max - hrow[1]; \
754                                 hrow[2] = max - hrow[2]; \
755                                 hrow += components; \
756                         } \
757                 } \
758  \
759                 for( int i=center_y-CENTER_H/2; i<=center_y+CENTER_H/2; ++i ) { \
760                         if( i >= 0 && i < h ) { \
761                                 type *vrow = rows[i] + center_x * components; \
762                                 vrow[0] = max - vrow[0]; \
763                                 vrow[1] = max - vrow[1]; \
764                                 vrow[2] = max - vrow[2]; \
765                         } \
766                 } \
767         } \
768 }
769
770                         int w = get_output()->get_w();
771                         int h = get_output()->get_h();
772                         int center_x = (int)(config.center_x * w / 100);
773                         int center_y = (int)(config.center_y * h / 100);
774                         switch( get_output()->get_color_model() )
775                         {
776                                 case BC_RGB_FLOAT:
777                                         DRAW_GUIDES(3, float, 1.0)
778                                         break;
779                                 case BC_RGBA_FLOAT:
780                                         DRAW_GUIDES(4, float, 1.0)
781                                         break;
782                                 case BC_RGB888:
783                                         DRAW_GUIDES(3, unsigned char, 0xff)
784                                         break;
785                                 case BC_RGBA8888:
786                                         DRAW_GUIDES(4, unsigned char, 0xff)
787                                         break;
788                                 case BC_YUV888:
789                                         DRAW_GUIDES(3, unsigned char, 0xff)
790                                         break;
791                                 case BC_YUVA8888:
792                                         DRAW_GUIDES(4, unsigned char, 0xff)
793                                         break;
794                         }
795
796                 }
797         }
798
799         return 0;
800 }
801
802
803 int LensMain::handle_opengl()
804 {
805 #ifdef HAVE_GL
806         static const char *shrink_frag =
807                 "uniform sampler2D tex;\n"
808                 "uniform vec2 texture_extents;\n"
809                 "uniform vec2 image_extents;\n"
810                 "uniform vec2 aspect;\n"
811                 "uniform vec2 center_coord;\n"
812                 "uniform vec4 border_color;\n"
813                 "uniform vec4 r;\n"
814                 "uniform vec4 max_z;\n"
815                 "void main()\n"
816                 "{\n"
817                 "       vec2 outcoord = gl_TexCoord[0].st * texture_extents;\n"
818                 "       vec2 coord_diff = outcoord - center_coord;\n"
819                 "       if( coord_diff.x == 0.0 && coord_diff.y == 0.0 )\n"
820                 "       {\n"
821                 "               gl_FragColor = texture2D(tex, outcoord);\n"
822                 "       }\n"
823                 "       else\n"
824                 "       {\n"
825                 "               float z = sqrt(coord_diff.x * coord_diff.x +\n"
826                 "                                               coord_diff.y * coord_diff.y);\n"
827                 "               float a2 = atan(coord_diff.y, coord_diff.x);\n"
828                 "               vec4 a1 = asin(vec4(z, z, z, z) / r);\n"
829                 "               vec4 z_in = a1 * max_z * 2.0 / 3.14159;\n"
830                 "               vec4 in_x;\n"
831                 "               vec4 in_y;\n"
832                 "               in_x = z_in * cos(a2) * aspect.x + center_coord.x;\n"
833                 "               in_y = z_in * sin(a2) * aspect.y + center_coord.y;\n"
834                 "               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"
835                 "                       gl_FragColor.r = border_color.r;\n"
836                 "               else\n"
837                 "                       gl_FragColor.r = texture2D(tex, vec2(in_x.r, in_y.r) / texture_extents).r;\n"
838                 "               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"
839                 "                       gl_FragColor.g = border_color.g;\n"
840                 "               else\n"
841                 "                       gl_FragColor.g = texture2D(tex, vec2(in_x.g, in_y.g) / texture_extents).g;\n"
842                 "               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"
843                 "                       gl_FragColor.b = border_color.b;\n"
844                 "               else\n"
845                 "                       gl_FragColor.b = texture2D(tex, vec2(in_x.b, in_y.b) / texture_extents).b;\n"
846                 "               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"
847                 "                       gl_FragColor.a = border_color.a;\n"
848                 "               else\n"
849                 "                       gl_FragColor.a = texture2D(tex, vec2(in_x.a, in_y.a) / texture_extents).a;\n"
850                 "       }\n"
851                 "}\n";
852
853         static const char *stretch_frag =
854                 "uniform sampler2D tex;\n"
855                 "uniform vec2 texture_extents;\n"
856                 "uniform vec2 image_extents;\n"
857                 "uniform vec2 aspect;\n"
858                 "uniform vec2 center_coord;\n"
859                 "uniform vec4 border_color;\n"
860                 "uniform vec4 r;\n"
861                 "void main()\n"
862                 "{\n"
863                 "       vec2 outcoord = gl_TexCoord[0].st * texture_extents;\n"
864                 "       vec2 coord_diff = outcoord - center_coord;\n"
865                 "       float z = sqrt(coord_diff.x * coord_diff.x +\n"
866                 "                                       coord_diff.y * coord_diff.y);\n"
867                 "       vec4 a1 = (vec4(z, z, z, z) / (3.14159 * r / 2.0)) * (3.14159 / 2.0);\n"
868                 "       vec4 z_in = r * sin(a1);\n"
869                 "       float a2;\n"
870                 "       if( coord_diff.x == 0.0 )\n"
871                 "       {\n"
872                 "               if( coord_diff.y < 0.0 )\n"
873                 "                       a2 = 3.0 * 3.14159 / 2.0;\n"
874                 "               else\n"
875                 "                       a2 = 3.14159 / 2.0;\n"
876                 "       }\n"
877                 "       else\n"
878                 "               a2 = atan(coord_diff.y, coord_diff.x);\n"
879                 "       vec4 in_x;\n"
880                 "       vec4 in_y;\n"
881                 "       in_x = z_in * cos(a2) * aspect.x + center_coord.x;\n"
882                 "       in_y = z_in * sin(a2) * aspect.y + center_coord.y;\n"
883                 "       if( in_x.r < 0.0 || in_x.r >= image_extents.x || in_y.r < 0.0 || in_y.r >= image_extents.y )\n"
884                 "               gl_FragColor.r = border_color.r;\n"
885                 "       else\n"
886                 "               gl_FragColor.r = texture2D(tex, vec2(in_x.r, in_y.r) / texture_extents).r;\n"
887                 "       if( in_x.g < 0.0 || in_x.g >= image_extents.x || in_y.g < 0.0 || in_y.g >= image_extents.y )\n"
888                 "               gl_FragColor.g = border_color.g;\n"
889                 "       else\n"
890                 "               gl_FragColor.g = texture2D(tex, vec2(in_x.g, in_y.g) / texture_extents).g;\n"
891                 "       if( in_x.b < 0.0 || in_x.b >= image_extents.x || in_y.b < 0.0 || in_y.b >= image_extents.y )\n"
892                 "               gl_FragColor.b = border_color.b;\n"
893                 "       else\n"
894                 "               gl_FragColor.b = texture2D(tex, vec2(in_x.b, in_y.b) / texture_extents).b;\n"
895                 "       if( in_x.a < 0.0 || in_x.a >= image_extents.x || in_y.a < 0.0 || in_y.a >= image_extents.y )\n"
896                 "               gl_FragColor.a = border_color.a;\n"
897                 "       else\n"
898                 "               gl_FragColor.a = texture2D(tex, vec2(in_x.a, in_y.a) / texture_extents).a;\n"
899                 "}\n";
900
901
902         static const char *rectilinear_stretch_frag =
903                 "uniform sampler2D tex;\n"
904                 "uniform vec2 texture_extents;\n"
905                 "uniform vec2 image_extents;\n"
906                 "uniform vec2 aspect;\n"
907                 "uniform vec2 center_coord;\n"
908                 "uniform vec4 border_color;\n"
909                 "uniform vec4 r;\n"
910                 "uniform float radius;\n"
911                 "void main()\n"
912                 "{\n"
913                 "       vec2 outcoord = gl_TexCoord[0].st * texture_extents;\n"
914                 "       vec2 coord_diff = outcoord - center_coord;\n"
915                 "       float z = sqrt(coord_diff.x * coord_diff.x +\n"
916                 "                                       coord_diff.y * coord_diff.y);\n"
917                 "       vec4 radius1 = (vec4(z, z, z, z) / r) * 2.0 * radius;\n"
918                 "       vec4 z_in = r * atan(radius1) / (3.14159 / 2.0);\n"
919                 "\n"
920                 "       float angle;\n"
921                 "       if( coord_diff.x == 0.0 )\n"
922                 "       {\n"
923                 "               if( coord_diff.y < 0.0 )\n"
924                 "                       angle = 3.0 * 3.14159 / 2.0;\n"
925                 "               else\n"
926                 "                       angle = 3.14159 / 2.0;\n"
927                 "       }\n"
928                 "       else\n"
929                 "               angle = atan(coord_diff.y, coord_diff.x);\n"
930                 "       vec4 in_x;\n"
931                 "       vec4 in_y;\n"
932                 "\n"
933                 "       in_x = z_in * cos(angle) * aspect.x + center_coord.x;\n"
934                 "       in_y = z_in * sin(angle) * aspect.y + center_coord.y;\n"
935                 "       if( in_x.r < 0.0 || in_x.r >= image_extents.x || in_y.r < 0.0 || in_y.r >= image_extents.y )\n"
936                 "               gl_FragColor.r = border_color.r;\n"
937                 "       else\n"
938                 "               gl_FragColor.r = texture2D(tex, vec2(in_x.r, in_y.r) / texture_extents).r;\n"
939                 "       if( in_x.g < 0.0 || in_x.g >= image_extents.x || in_y.g < 0.0 || in_y.g >= image_extents.y )\n"
940                 "               gl_FragColor.g = border_color.g;\n"
941                 "       else\n"
942                 "               gl_FragColor.g = texture2D(tex, vec2(in_x.g, in_y.g) / texture_extents).g;\n"
943                 "       if( in_x.b < 0.0 || in_x.b >= image_extents.x || in_y.b < 0.0 || in_y.b >= image_extents.y )\n"
944                 "               gl_FragColor.b = border_color.b;\n"
945                 "       else\n"
946                 "               gl_FragColor.b = texture2D(tex, vec2(in_x.b, in_y.b) / texture_extents).b;\n"
947                 "       if( in_x.a < 0.0 || in_x.a >= image_extents.x || in_y.a < 0.0 || in_y.a >= image_extents.y )\n"
948                 "               gl_FragColor.a = border_color.a;\n"
949                 "       else\n"
950                 "               gl_FragColor.a = texture2D(tex, vec2(in_x.a, in_y.a) / texture_extents).a;\n"
951                 "}\n";
952
953         static const char *rectilinear_shrink_frag =
954                 "uniform sampler2D tex;\n"
955                 "uniform vec2 texture_extents;\n"
956                 "uniform vec2 image_extents;\n"
957                 "uniform vec2 aspect;\n"
958                 "uniform vec2 center_coord;\n"
959                 "uniform vec4 border_color;\n"
960                 "uniform vec4 r;\n"
961                 "uniform float radius;\n"
962                 "void main()\n"
963                 "{\n"
964                 "       vec2 outcoord = gl_TexCoord[0].st * texture_extents;\n"
965                 "       vec2 coord_diff = outcoord - center_coord;\n"
966                 "       float z = sqrt(coord_diff.x * coord_diff.x +\n"
967                 "                                       coord_diff.y * coord_diff.y);\n"
968                 "       vec4 radius1 = (vec4(z, z, z, z) / r) * 2.0 * radius;\n"
969                 "       vec4 z_in = r * atan(radius1) / (3.14159 / 2.0);\n"
970                 "\n"
971                 "       float angle;\n"
972                 "       if( coord_diff.x == 0.0 )\n"
973                 "       {\n"
974                 "               if( coord_diff.y < 0.0 )\n"
975                 "                       angle = 3.0 * 3.14159 / 2.0;\n"
976                 "               else\n"
977                 "                       angle = 3.14159 / 2.0;\n"
978                 "       }\n"
979                 "       else\n"
980                 "               angle = atan(coord_diff.y, coord_diff.x);\n"
981                 "       vec4 in_x;\n"
982                 "       vec4 in_y;\n"
983                 "\n"
984                 "       in_x = z_in * cos(angle) * aspect.x + center_coord.x;\n"
985                 "       in_y = z_in * sin(angle) * aspect.y + center_coord.y;\n"
986                 "       if( in_x.r < 0.0 || in_x.r >= image_extents.x || in_y.r < 0.0 || in_y.r >= image_extents.y )\n"
987                 "               gl_FragColor.r = border_color.r;\n"
988                 "       else\n"
989                 "               gl_FragColor.r = texture2D(tex, vec2(in_x.r, in_y.r) / texture_extents).r;\n"
990                 "       if( in_x.g < 0.0 || in_x.g >= image_extents.x || in_y.g < 0.0 || in_y.g >= image_extents.y )\n"
991                 "               gl_FragColor.g = border_color.g;\n"
992                 "       else\n"
993                 "               gl_FragColor.g = texture2D(tex, vec2(in_x.g, in_y.g) / texture_extents).g;\n"
994                 "       if( in_x.b < 0.0 || in_x.b >= image_extents.x || in_y.b < 0.0 || in_y.b >= image_extents.y )\n"
995                 "               gl_FragColor.b = border_color.b;\n"
996                 "       else\n"
997                 "               gl_FragColor.b = texture2D(tex, vec2(in_x.b, in_y.b) / texture_extents).b;\n"
998                 "       if( in_x.a < 0.0 || in_x.a >= image_extents.x || in_y.a < 0.0 || in_y.a >= image_extents.y )\n"
999                 "               gl_FragColor.a = border_color.a;\n"
1000                 "       else\n"
1001                 "               gl_FragColor.a = texture2D(tex, vec2(in_x.a, in_y.a) / texture_extents).a;\n"
1002                 "}\n";
1003
1004         get_output()->to_texture();
1005         get_output()->enable_opengl();
1006         unsigned int frag_shader = 0;
1007
1008         switch( config.mode )
1009         {
1010         case LensConfig::SPHERICAL_SHRINK:
1011                 frag_shader = VFrame::make_shader(0, shrink_frag, 0);
1012                 break;
1013         case LensConfig::SPHERICAL_STRETCH:
1014                 frag_shader = VFrame::make_shader(0, stretch_frag, 0);
1015                 break;
1016         case LensConfig::RECTILINEAR_STRETCH:
1017                 frag_shader = VFrame::make_shader(0, rectilinear_stretch_frag, 0);
1018                 break;
1019         case LensConfig::RECTILINEAR_SHRINK:
1020                 frag_shader = VFrame::make_shader(0, rectilinear_shrink_frag, 0);
1021                 break;
1022         }
1023
1024         if( frag_shader > 0 ) {
1025                 float border_color[] = { 0, 0, 0, 0 };
1026                 if( BC_CModels::is_yuv(get_output()->get_color_model()) ) {
1027                         border_color[1] = 0.5;
1028                         border_color[2] = 0.5;
1029                 }
1030
1031                 double x_factor = config.aspect;
1032                 double y_factor = 1.0 / config.aspect;
1033                 if( x_factor < 1 ) x_factor = 1;
1034                 if( y_factor < 1 ) y_factor = 1;
1035
1036                 glUseProgram(frag_shader);
1037                 glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0);
1038                 glUniform2f(glGetUniformLocation(frag_shader, "aspect"),
1039                         x_factor,
1040                         y_factor);
1041                 glUniform2f(glGetUniformLocation(frag_shader, "center_coord"),
1042                                 (GLfloat)get_input()->get_w() * config.center_x / 100.0,
1043                                 (GLfloat)get_input()->get_h() * config.center_y / 100.0);
1044                 glUniform2f(glGetUniformLocation(frag_shader, "texture_extents"),
1045                                 (GLfloat)get_input()->get_texture_w(),
1046                                 (GLfloat)get_input()->get_texture_h());
1047                 glUniform2f(glGetUniformLocation(frag_shader, "image_extents"),
1048                                 (GLfloat)get_input()->get_w(),
1049                                 (GLfloat)get_input()->get_h());
1050
1051                 int width = get_output()->get_w();
1052                 int height = get_output()->get_h();
1053                 float *fov = config.fov;
1054                 float dim;
1055                 float max_z;
1056                 switch( config.mode )
1057                 {
1058                         case LensConfig::SPHERICAL_SHRINK:
1059                                 dim = MAX(width, height) * config.radius;
1060                                 max_z = dim * sqrt(2.0) / 2;
1061                                 glUniform4fv(glGetUniformLocation(frag_shader, "border_color"),
1062                                                 1,
1063                                                 (GLfloat*)border_color);
1064                                 glUniform4f(glGetUniformLocation(frag_shader, "max_z"),
1065                                         max_z / fov[0],
1066                                         max_z / fov[1],
1067                                         max_z / fov[2],
1068                                         max_z / fov[3]);
1069                                 glUniform4f(glGetUniformLocation(frag_shader, "r"),
1070                                         (max_z / fov[0]) * 2 / M_PI,
1071                                         (max_z / fov[1]) * 2 / M_PI,
1072                                         (max_z / fov[2]) * 2 / M_PI,
1073                                         (max_z / fov[3]) * 2 / M_PI);
1074                                 break;
1075
1076                         case LensConfig::SPHERICAL_STRETCH:
1077                                 dim = MAX(width, height) * config.radius;
1078                                 max_z = dim * sqrt(2.0) / 2;
1079                                 glUniform4f(glGetUniformLocation(frag_shader, "r"),
1080                                         max_z / M_PI / (fov[0] / 2.0),
1081                                         max_z / M_PI / (fov[1] / 2.0),
1082                                         max_z / M_PI / (fov[2] / 2.0),
1083                                         max_z / M_PI / (fov[3] / 2.0));
1084                                 break;
1085
1086                         case LensConfig::RECTILINEAR_STRETCH:
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"),
1094                                         config.radius);
1095                                 break;
1096
1097                         case LensConfig::RECTILINEAR_SHRINK:
1098                                 max_z = sqrt(SQR(width) + SQR(height)) / 2;
1099                                 glUniform4f(glGetUniformLocation(frag_shader, "r"),
1100                                         max_z / M_PI / (fov[0] / 2.0),
1101                                         max_z / M_PI / (fov[1] / 2.0),
1102                                         max_z / M_PI / (fov[2] / 2.0),
1103                                         max_z / M_PI / (fov[3] / 2.0));
1104                                 glUniform1f(glGetUniformLocation(frag_shader, "radius"),
1105                                         config.radius);
1106                                 break;
1107                 }
1108
1109
1110                 get_output()->init_screen();
1111                 get_output()->bind_texture(0);
1112                 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
1113                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
1114                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
1115                 get_output()->draw_texture();
1116                 glUseProgram(0);
1117
1118
1119                 if( config.draw_guides ) {
1120                         int w = get_output()->get_w();
1121                         int h = get_output()->get_h();
1122                         int center_x = (int)(config.center_x * w / 100);
1123                         int center_y = (int)(config.center_y * h / 100);
1124
1125                         glDisable(GL_TEXTURE_2D);
1126                         glColor4f(0.0, 0.0, 0.0, 1.0);
1127                         glBegin(GL_LINES);
1128                         glVertex3f(center_x, -h + center_y - CENTER_H / 2, 0.0);
1129                         glVertex3f(center_x, -h + center_y + CENTER_H / 2, 0.0);
1130                         glEnd();
1131                         glBegin(GL_LINES);
1132                         glVertex3f(center_x - CENTER_W / 2, -h + center_y, 0.0);
1133                         glVertex3f(center_x + CENTER_W / 2, -h + center_y, 0.0);
1134                         glEnd();
1135                         glColor4f(1.0, 1.0, 1.0, 1.0);
1136                         glBegin(GL_LINES);
1137                         glVertex3f(center_x - 1, -h + center_y - CENTER_H / 2 - 1, 0.0);
1138                         glVertex3f(center_x - 1, -h + center_y + CENTER_H / 2 - 1, 0.0);
1139                         glEnd();
1140                         glBegin(GL_LINES);
1141                         glVertex3f(center_x - CENTER_W / 2 - 1, -h + center_y - 1, 0.0);
1142                         glVertex3f(center_x + CENTER_W / 2 - 1, -h + center_y - 1, 0.0);
1143                         glEnd();
1144                 }
1145                 get_output()->set_opengl_state(VFrame::SCREEN);
1146         }
1147
1148 #endif
1149         return 0;
1150 }
1151
1152 // do using specified interpolation
1153 #define DO_LENS(type) \
1154         int icolor_model = plugin->get_input()->get_color_model(); \
1155         switch( plugin->config.interp ) { \
1156         case LensConfig::INTERP_NEAREST: \
1157                 switch( icolor_model ) { \
1158                 case BC_RGB888: \
1159                         DO_LENS_##type(unsigned char, 3, 0xff, 0x0, nearest); \
1160                         break; \
1161                 case BC_RGBA8888: \
1162                         DO_LENS_##type(unsigned char, 4, 0xff, 0x0, nearest); \
1163                         break; \
1164                 case BC_RGB_FLOAT: \
1165                         DO_LENS_##type(float, 3, 1.0, 0.0, nearest); \
1166                         break; \
1167                 case BC_RGBA_FLOAT: \
1168                         DO_LENS_##type(float, 4, 1.0, 0.0, nearest); \
1169                         break; \
1170                 case BC_YUV888: \
1171                         DO_LENS_##type(unsigned char, 3, 0xff, 0x80, nearest); \
1172                         break; \
1173                 case BC_YUVA8888: \
1174                         DO_LENS_##type(unsigned char, 4, 0xff, 0x80, nearest); \
1175                         break; \
1176                 } \
1177                 break; \
1178         case LensConfig::INTERP_BILINEAR: \
1179                 switch( icolor_model ) { \
1180                 case BC_RGB888: \
1181                         DO_LENS_##type(unsigned char, 3, 0xff, 0x0, bi_linear); \
1182                         break; \
1183                 case BC_RGBA8888: \
1184                         DO_LENS_##type(unsigned char, 4, 0xff, 0x0, bi_linear); \
1185                         break; \
1186                 case BC_RGB_FLOAT: \
1187                         DO_LENS_##type(float, 3, 1.0, 0.0, bi_linear); \
1188                         break; \
1189                 case BC_RGBA_FLOAT: \
1190                         DO_LENS_##type(float, 4, 1.0, 0.0, bi_linear); \
1191                         break; \
1192                 case BC_YUV888: \
1193                         DO_LENS_##type(unsigned char, 3, 0xff, 0x80, bi_linear); \
1194                         break; \
1195                 case BC_YUVA8888: \
1196                         DO_LENS_##type(unsigned char, 4, 0xff, 0x80, bi_linear); \
1197                         break; \
1198                 } \
1199                 break; \
1200         case LensConfig::INTERP_BICUBIC: \
1201                 switch( icolor_model ) { \
1202                 case BC_RGB888: \
1203                         DO_LENS_##type(unsigned char, 3, 0xff, 0x0, bi_cubic); \
1204                         break; \
1205                 case BC_RGBA8888: \
1206                         DO_LENS_##type(unsigned char, 4, 0xff, 0x0, bi_cubic); \
1207                         break; \
1208                 case BC_RGB_FLOAT: \
1209                         DO_LENS_##type(float, 3, 1.0, 0.0, bi_cubic); \
1210                         break; \
1211                 case BC_RGBA_FLOAT: \
1212                         DO_LENS_##type(float, 4, 1.0, 0.0, bi_cubic); \
1213                         break; \
1214                 case BC_YUV888: \
1215                         DO_LENS_##type(unsigned char, 3, 0xff, 0x80, bi_cubic); \
1216                         break; \
1217                 case BC_YUVA8888: \
1218                         DO_LENS_##type(unsigned char, 4, 0xff, 0x80, bi_cubic); \
1219                         break; \
1220                 } \
1221                 break; \
1222         }
1223
1224 LensPackage::LensPackage()
1225  : LoadPackage()
1226 {
1227 }
1228
1229 LensUnit::LensUnit(LensEngine *engine, LensMain *plugin)
1230  : LoadClient(engine)
1231 {
1232         this->plugin = plugin;
1233 }
1234
1235 LensUnit::~LensUnit()
1236 {
1237 }
1238
1239 void LensUnit::process_spherical_stretch(LensPackage *pkg)
1240 {
1241         float *fov = plugin->config.fov;
1242         float aspect = plugin->config.aspect;
1243         int row1 = pkg->row1;
1244         int row2 = pkg->row2;
1245         double x_factor = aspect;
1246         double y_factor = 1.0 / aspect;
1247         if( x_factor < 1 ) x_factor = 1;
1248         if( y_factor < 1 ) y_factor = 1;
1249         int width = plugin->get_input()->get_w();
1250         int height = plugin->get_input()->get_h();
1251         double dim = MAX(width, height) * plugin->config.radius;
1252         double max_z = dim * sqrt(2.0) / 2;
1253         double center_x = width * plugin->config.center_x / 100.0;
1254         double center_y = height * plugin->config.center_y / 100.0;
1255         double r[FOV_CHANNELS];
1256
1257         r[0] = max_z / M_PI / (fov[0] / 2.0);
1258         r[1] = max_z / M_PI / (fov[1] / 2.0);
1259         r[2] = max_z / M_PI / (fov[2] / 2.0);
1260         r[3] = max_z / M_PI / (fov[3] / 2.0);
1261
1262 #define DO_LENS_SPHERICAL_STRETCH(type, components, max, chroma, interp) { \
1263         type **in_rows = (type**)plugin->get_temp()->get_rows(); \
1264         type **out_rows = (type**)plugin->get_input()->get_rows(); \
1265         type black[4] = { 0, chroma, chroma, 0 }; \
1266         INTERP_SETUP(in_rows, max, 0,0, width,height); \
1267  \
1268         for( int y=row1; y<row2; ++y ) { \
1269                 type *out_row = out_rows[y]; \
1270                 double y_diff = y - center_y; \
1271                 for( int x=0; x<width; ++x ) { \
1272                         double x_diff = (x - center_x); \
1273                         double z = sqrt(x_diff * x_diff + y_diff * y_diff); \
1274                         double a2 = x != center_x ? atan(y_diff / x_diff) : \
1275                                 y < center_y ? 3*M_PI/2 : M_PI/2; \
1276                         if( x_diff < 0.0 ) a2 += M_PI; \
1277                         for( int i=0; i<components; ++i ) { \
1278                                 double a1 = (z / (M_PI * r[i] / 2)) * (M_PI / 2); \
1279                                 double z_in = r[i] * sin(a1); \
1280                                 double x_in = z_in * cos(a2) * x_factor + center_x; \
1281                                 double y_in = z_in * sin(a2) * y_factor + center_y; \
1282                                 interp##_SETUP(type, components, x_in, y_in); \
1283                                 for( int j=0; j<i; ++j ) interp##_next(); \
1284                                 *out_row++ = interp##_interp(black[i], black[i]); \
1285                         } \
1286                 } \
1287         } \
1288  \
1289         type *out_pixel = out_rows[(int)center_y] + (int)center_x * components; \
1290         type *inp_pixel = in_rows[(int)center_y] + (int)center_x * components; \
1291         for( int i=0; i<components; ++i ) *out_pixel++ = *inp_pixel++; \
1292 }
1293
1294         DO_LENS(SPHERICAL_STRETCH);
1295 }
1296
1297 void LensUnit::process_spherical_shrink(LensPackage *pkg)
1298 {
1299
1300         float *fov = plugin->config.fov;
1301         float aspect = plugin->config.aspect;
1302         int row1 = pkg->row1;
1303         int row2 = pkg->row2;
1304         int width = plugin->get_input()->get_w();
1305         int height = plugin->get_input()->get_h();
1306         double x_factor = aspect;
1307         double y_factor = 1.0 / aspect;
1308         if( x_factor < 1 ) x_factor = 1;
1309         if( y_factor < 1 ) y_factor = 1;
1310         double dim = MAX(width, height) * plugin->config.radius;
1311         double max_z[FOV_CHANNELS];
1312         double center_x = width * plugin->config.center_x / 100.0;
1313         double center_y = height * plugin->config.center_y / 100.0;
1314         double r[FOV_CHANNELS];
1315
1316 //      max_z[0] = sqrt(SQR(width) + SQR(height)) / 2 / fov[0];
1317 //      max_z[1] = sqrt(SQR(width) + SQR(height)) / 2 / fov[1];
1318 //      max_z[2] = sqrt(SQR(width) + SQR(height)) / 2 / fov[2];
1319 //      max_z[3] = sqrt(SQR(width) + SQR(height)) / 2 / fov[3];
1320         max_z[0] = dim * sqrt(2.0) / 2 / fov[0];
1321         max_z[1] = dim * sqrt(2.0) / 2 / fov[1];
1322         max_z[2] = dim * sqrt(2.0) / 2 / fov[2];
1323         max_z[3] = dim * sqrt(2.0) / 2 / fov[3];
1324         r[0] = max_z[0] * 2 / M_PI;
1325         r[1] = max_z[1] * 2 / M_PI;
1326         r[2] = max_z[2] * 2 / M_PI;
1327         r[3] = max_z[3] * 2 / M_PI;
1328
1329 #define DO_LENS_SPHERICAL_SHRINK(type, components, max, chroma, interp) { \
1330         type **in_rows = (type**)plugin->get_temp()->get_rows(); \
1331         type **out_rows = (type**)plugin->get_input()->get_rows(); \
1332         type black[4] = { 0, chroma, chroma, 0 }; \
1333         INTERP_SETUP(in_rows, max, 0,0, width,height); \
1334  \
1335         for( int y=row1; y<row2; ++y ) { \
1336                 type *out_row = out_rows[y]; \
1337                 type *in_row = in_rows[y]; \
1338                 double y_diff = y - center_y; \
1339                 for( int x=0; x<width; ++x ) { \
1340                         double x_diff = x - center_x; \
1341                         if( !x_diff && !y_diff ) { \
1342                                 type *inp_pixel = in_row + x * components; \
1343                                 for( int c=0; c<components; ++c ) \
1344                                         *out_row++ = *inp_pixel++; \
1345                                 continue; \
1346                         } \
1347                         double z = sqrt(x_diff * x_diff + y_diff * y_diff); \
1348                         double a2 = atan(y_diff / x_diff); \
1349                         if( x_diff < 0.0 ) a2 += M_PI; \
1350                         for( int i=0; i<components; ++i ) { \
1351                                 if( z > r[i] ) { *out_row++ = black[i]; continue; } \
1352                                 double a1 = asin(z / r[i]); \
1353                                 double z_in = a1 * max_z[i] * 2 / M_PI; \
1354                                 float x_in = z_in * cos(a2) * x_factor + center_x; \
1355                                 float y_in = z_in * sin(a2) * y_factor + center_y; \
1356                                 interp##_SETUP(type, components, x_in, y_in); \
1357                                 for( int j=0; j<i; ++j ) interp##_next(); \
1358                                 *out_row++ = interp##_interp(black[i], black[i]); \
1359                         } \
1360                 } \
1361         } \
1362  \
1363         type *out_pixel = out_rows[(int)center_y] + (int)center_x * components; \
1364         type *inp_pixel = in_rows[(int)center_y] + (int)center_x * components; \
1365         for( int i=0; i<components; ++i ) *out_pixel++ = *inp_pixel++; \
1366 }
1367
1368         DO_LENS(SPHERICAL_SHRINK);
1369 }
1370
1371 void LensUnit::process_rectilinear_stretch(LensPackage *pkg)
1372 {
1373         float *fov = plugin->config.fov;
1374         float aspect = plugin->config.aspect;
1375         int row1 = pkg->row1;
1376         int row2 = pkg->row2;
1377         double x_factor = aspect;
1378         double y_factor = 1.0 / aspect;
1379         if( x_factor < 1 ) x_factor = 1;
1380         if( y_factor < 1 ) y_factor = 1;
1381         int width = plugin->get_input()->get_w();
1382         int height = plugin->get_input()->get_h();
1383 //      double dim = MAX(width, height) * plugin->config.radius;
1384 //      double max_z = dim * sqrt(2.0) / 2;
1385         double max_z = sqrt(SQR(width) + SQR(height)) / 2;
1386         double center_x = width * plugin->config.center_x / 100.0;
1387         double center_y = height * plugin->config.center_y / 100.0;
1388         double r[FOV_CHANNELS];
1389
1390         r[0] = max_z / M_PI / (fov[0] / 2.0);
1391         r[1] = max_z / M_PI / (fov[1] / 2.0);
1392         r[2] = max_z / M_PI / (fov[2] / 2.0);
1393         r[3] = max_z / M_PI / (fov[3] / 2.0);
1394
1395 #define DO_LENS_RECTILINEAR_STRETCH(type, components, max, chroma, interp) { \
1396         type **in_rows = (type**)plugin->get_temp()->get_rows(); \
1397         type **out_rows = (type**)plugin->get_input()->get_rows(); \
1398         type black[4] = { 0, chroma, chroma, 0 }; \
1399         INTERP_SETUP(in_rows, max, 0,0, width,height); \
1400  \
1401         for( int y=row1; y<row2; ++y ) { \
1402                 type *out_row = out_rows[y]; \
1403                 double y_diff = y - center_y; \
1404                 for( int x=0; x<width; ++x ) { \
1405                         double x_diff = (x - center_x); /* Compute magnitude / angle */ \
1406                         double z = sqrt(x_diff * x_diff + y_diff * y_diff); \
1407                         double angle = x != center_x ? atan(y_diff / x_diff) : \
1408                                 y < center_y ? 3*M_PI/2 : M_PI/2; \
1409                         if( x_diff < 0.0 ) angle += M_PI; \
1410                         for( int i=0; i<components; ++i ) { /* Compute new radius */ \
1411                                 double radius1 = (z / r[i]) * 2 * plugin->config.radius; \
1412                                 double z_in = r[i] * atan(radius1) / (M_PI / 2); \
1413                                 double x_in = z_in * cos(angle) * x_factor + center_x; \
1414                                 double y_in = z_in * sin(angle) * y_factor + center_y; \
1415                                 interp##_SETUP(type, components, x_in, y_in); \
1416                                 for( int j=0; j<i; ++j ) interp##_next(); \
1417                                 *out_row++ = interp##_interp(black[i], black[i]); \
1418                         } \
1419                 } \
1420         } \
1421  \
1422         type *out_pixel = out_rows[(int)center_y] + (int)center_x * components; \
1423         type *inp_pixel = in_rows[(int)center_y] + (int)center_x * components; \
1424         for( int i=0; i<components; ++i ) *out_pixel++ = *inp_pixel++; \
1425 }
1426
1427         DO_LENS(RECTILINEAR_STRETCH);
1428 }
1429
1430 void LensUnit::process_rectilinear_shrink(LensPackage *pkg)
1431 {
1432         float *fov = plugin->config.fov;
1433         float aspect = plugin->config.aspect;
1434         int row1 = pkg->row1;
1435         int row2 = pkg->row2;
1436         double x_factor = aspect;
1437         double y_factor = 1.0 / aspect;
1438         if( x_factor < 1 ) x_factor = 1;
1439         if( y_factor < 1 ) y_factor = 1;
1440         int width = plugin->get_input()->get_w();
1441         int height = plugin->get_input()->get_h();
1442         double max_z = MAX(width, height) / 2 * plugin->config.radius;
1443         double center_x = width * plugin->config.center_x / 100.0;
1444         double center_y = height * plugin->config.center_y / 100.0;
1445         double r[FOV_CHANNELS];
1446
1447         r[0] = max_z / fov[0];
1448         r[1] = max_z / fov[1];
1449         r[2] = max_z / fov[2];
1450         r[3] = max_z / fov[3];
1451
1452 #define DO_LENS_RECTILINEAR_SHRINK(type, components, max, chroma, interp) { \
1453         type **in_rows = (type**)plugin->get_temp()->get_rows(); \
1454         type **out_rows = (type**)plugin->get_input()->get_rows(); \
1455         type black[4] = { 0, chroma, chroma, 0 }; \
1456         INTERP_SETUP(in_rows, max, 0,0, width,height); \
1457  \
1458         for( int y=row1; y<row2; ++y ) { \
1459                 type *out_row = out_rows[y]; \
1460                 double y_diff = y - center_y; \
1461                 for( int x=0; x<width; ++x ) { \
1462                         double x_diff = (x - center_x); /* Compute magnitude/angle */ \
1463                         double z = sqrt(x_diff * x_diff + y_diff * y_diff); \
1464                         double angle = x != center_x ? atan(y_diff / x_diff) : \
1465                                 y < center_y ? 3*M_PI/2 : M_PI/2; \
1466                         if( x_diff < 0.0 ) angle += M_PI; \
1467                         for( int i=0; i<components; ++i ) { /* Compute new radius */ \
1468                                 double radius1 = z / r[i]; \
1469                                 double z_in = r[i] * tan(radius1) / (M_PI / 2); \
1470                                 double x_in = z_in * cos(angle) * x_factor + center_x; \
1471                                 double y_in = z_in * sin(angle) * y_factor + center_y; \
1472                                 interp##_SETUP(type, components, x_in, y_in); \
1473                                 for( int j=0; j<i; ++j ) interp##_next(); \
1474                                 *out_row++ = interp##_interp(black[i], black[i]); \
1475                         } \
1476                 } \
1477         } \
1478  \
1479         type *out_pixel = out_rows[(int)center_y] + (int)center_x * components; \
1480         type *inp_pixel = in_rows[(int)center_y] + (int)center_x * components; \
1481         for( int i=0; i<components; ++i ) *out_pixel++ = *inp_pixel++; \
1482 }
1483
1484         DO_LENS(RECTILINEAR_SHRINK);
1485 }
1486
1487 void LensUnit::process_package(LoadPackage *package)
1488 {
1489         LensPackage *pkg = (LensPackage*)package;
1490
1491         switch( plugin->config.mode ) {
1492         case LensConfig::SPHERICAL_STRETCH:
1493                 process_spherical_stretch(pkg);
1494                 break;
1495         case LensConfig::SPHERICAL_SHRINK:
1496                 process_spherical_shrink(pkg);
1497                 break;
1498         case LensConfig::RECTILINEAR_STRETCH:
1499                 process_rectilinear_stretch(pkg);
1500                 break;
1501         case LensConfig::RECTILINEAR_SHRINK:
1502                 process_rectilinear_shrink(pkg);
1503                 break;
1504         }
1505 }
1506
1507
1508 LensEngine::LensEngine(LensMain *plugin)
1509  : LoadServer(plugin->PluginClient::smp + 1, plugin->PluginClient::smp + 1)
1510 // : LoadServer(1, 1)
1511 {
1512         this->plugin = plugin;
1513 }
1514
1515 LensEngine::~LensEngine()
1516 {
1517 }
1518
1519 void LensEngine::init_packages()
1520 {
1521         int row1 = 0, row2 = 0, n = LoadServer::get_total_packages();
1522         for( int i=0; i<n; row1=row2 ) {
1523                 LensPackage *package = (LensPackage*)LoadServer::get_package(i);
1524                 row2 = plugin->get_input()->get_h() * ++i / n;
1525                 package->row1 = row1;  package->row2 = row2;
1526         }
1527 }
1528
1529 LoadClient* LensEngine::new_client()
1530 {
1531         return new LensUnit(this, plugin);
1532 }
1533
1534 LoadPackage* LensEngine::new_package()
1535 {
1536         return new LensPackage;
1537 }
1538
1539