add lens default interp for opengl
[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                 "uniform float radius;\n"
951                 "void main()\n"
952                 "{\n"
953                 "       vec2 outcoord = gl_TexCoord[0].st * texture_extents;\n"
954                 "       vec2 coord_diff = outcoord - center_coord;\n"
955                 "       float z = sqrt(coord_diff.x * coord_diff.x +\n"
956                 "                                       coord_diff.y * coord_diff.y);\n"
957                 "       vec4 radius1 = (vec4(z, z, z, z) / r) * 2.0 * radius;\n"
958                 "       vec4 z_in = r * atan(radius1) / (3.14159 / 2.0);\n"
959                 "\n"
960                 "       float angle;\n"
961                 "       if( coord_diff.x == 0.0 )\n"
962                 "       {\n"
963                 "               if( coord_diff.y < 0.0 )\n"
964                 "                       angle = 3.0 * 3.14159 / 2.0;\n"
965                 "               else\n"
966                 "                       angle = 3.14159 / 2.0;\n"
967                 "       }\n"
968                 "       else\n"
969                 "               angle = atan(coord_diff.y, coord_diff.x);\n"
970                 "       vec4 in_x;\n"
971                 "       vec4 in_y;\n"
972                 "\n"
973                 "       in_x = z_in * cos(angle) * aspect.x + center_coord.x;\n"
974                 "       in_y = z_in * sin(angle) * aspect.y + center_coord.y;\n"
975                 "       if( in_x.r < 0.0 || in_x.r >= image_extents.x || in_y.r < 0.0 || in_y.r >= image_extents.y )\n"
976                 "               gl_FragColor.r = border_color.r;\n"
977                 "       else\n"
978                 "               gl_FragColor.r = texture2D(tex, vec2(in_x.r, in_y.r) / texture_extents).r;\n"
979                 "       if( in_x.g < 0.0 || in_x.g >= image_extents.x || in_y.g < 0.0 || in_y.g >= image_extents.y )\n"
980                 "               gl_FragColor.g = border_color.g;\n"
981                 "       else\n"
982                 "               gl_FragColor.g = texture2D(tex, vec2(in_x.g, in_y.g) / texture_extents).g;\n"
983                 "       if( in_x.b < 0.0 || in_x.b >= image_extents.x || in_y.b < 0.0 || in_y.b >= image_extents.y )\n"
984                 "               gl_FragColor.b = border_color.b;\n"
985                 "       else\n"
986                 "               gl_FragColor.b = texture2D(tex, vec2(in_x.b, in_y.b) / texture_extents).b;\n"
987                 "       if( in_x.a < 0.0 || in_x.a >= image_extents.x || in_y.a < 0.0 || in_y.a >= image_extents.y )\n"
988                 "               gl_FragColor.a = border_color.a;\n"
989                 "       else\n"
990                 "               gl_FragColor.a = texture2D(tex, vec2(in_x.a, in_y.a) / texture_extents).a;\n"
991                 "}\n";
992
993         get_output()->to_texture();
994         get_output()->enable_opengl();
995         unsigned int frag_shader = 0;
996
997         switch( config.mode )
998         {
999         case LensConfig::SPHERICAL_SHRINK:
1000                 frag_shader = VFrame::make_shader(0, shrink_frag, 0);
1001                 break;
1002         case LensConfig::SPHERICAL_STRETCH:
1003                 frag_shader = VFrame::make_shader(0, stretch_frag, 0);
1004                 break;
1005         case LensConfig::RECTILINEAR_STRETCH:
1006                 frag_shader = VFrame::make_shader(0, rectilinear_stretch_frag, 0);
1007                 break;
1008         case LensConfig::RECTILINEAR_SHRINK:
1009                 frag_shader = VFrame::make_shader(0, rectilinear_shrink_frag, 0);
1010                 break;
1011         }
1012
1013         if( frag_shader > 0 ) {
1014                 float border_color[] = { 0, 0, 0, 0 };
1015                 if( BC_CModels::is_yuv(get_output()->get_color_model()) ) {
1016                         border_color[1] = 0.5;
1017                         border_color[2] = 0.5;
1018                 }
1019
1020                 double x_factor = config.aspect;
1021                 double y_factor = 1.0 / config.aspect;
1022                 if( x_factor < 1 ) x_factor = 1;
1023                 if( y_factor < 1 ) y_factor = 1;
1024
1025                 glUseProgram(frag_shader);
1026                 glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0);
1027                 glUniform2f(glGetUniformLocation(frag_shader, "aspect"),
1028                         x_factor,
1029                         y_factor);
1030                 glUniform2f(glGetUniformLocation(frag_shader, "center_coord"),
1031                                 (GLfloat)get_input()->get_w() * config.center_x / 100.0,
1032                                 (GLfloat)get_input()->get_h() * config.center_y / 100.0);
1033                 glUniform2f(glGetUniformLocation(frag_shader, "texture_extents"),
1034                                 (GLfloat)get_input()->get_texture_w(),
1035                                 (GLfloat)get_input()->get_texture_h());
1036                 glUniform2f(glGetUniformLocation(frag_shader, "image_extents"),
1037                                 (GLfloat)get_input()->get_w(),
1038                                 (GLfloat)get_input()->get_h());
1039
1040                 int width = get_output()->get_w();
1041                 int height = get_output()->get_h();
1042                 float *fov = config.fov;
1043                 float dim;
1044                 float max_z;
1045                 switch( config.mode )
1046                 {
1047                         case LensConfig::SPHERICAL_SHRINK:
1048                                 dim = MAX(width, height) * config.radius;
1049                                 max_z = dim * sqrt(2.0) / 2;
1050                                 glUniform4fv(glGetUniformLocation(frag_shader, "border_color"),
1051                                                 1,
1052                                                 (GLfloat*)border_color);
1053                                 glUniform4f(glGetUniformLocation(frag_shader, "max_z"),
1054                                         max_z / fov[0],
1055                                         max_z / fov[1],
1056                                         max_z / fov[2],
1057                                         max_z / fov[3]);
1058                                 glUniform4f(glGetUniformLocation(frag_shader, "r"),
1059                                         (max_z / fov[0]) * 2 / M_PI,
1060                                         (max_z / fov[1]) * 2 / M_PI,
1061                                         (max_z / fov[2]) * 2 / M_PI,
1062                                         (max_z / fov[3]) * 2 / M_PI);
1063                                 break;
1064
1065                         case LensConfig::SPHERICAL_STRETCH:
1066                                 dim = MAX(width, height) * config.radius;
1067                                 max_z = dim * sqrt(2.0) / 2;
1068                                 glUniform4f(glGetUniformLocation(frag_shader, "r"),
1069                                         max_z / M_PI / (fov[0] / 2.0),
1070                                         max_z / M_PI / (fov[1] / 2.0),
1071                                         max_z / M_PI / (fov[2] / 2.0),
1072                                         max_z / M_PI / (fov[3] / 2.0));
1073                                 break;
1074
1075                         case LensConfig::RECTILINEAR_STRETCH:
1076                                 max_z = sqrt(SQR(width) + SQR(height)) / 2;
1077                                 glUniform4f(glGetUniformLocation(frag_shader, "r"),
1078                                         max_z / M_PI / (fov[0] / 2.0),
1079                                         max_z / M_PI / (fov[1] / 2.0),
1080                                         max_z / M_PI / (fov[2] / 2.0),
1081                                         max_z / M_PI / (fov[3] / 2.0));
1082                                 glUniform1f(glGetUniformLocation(frag_shader, "radius"),
1083                                         config.radius);
1084                                 break;
1085
1086                         case LensConfig::RECTILINEAR_SHRINK:
1087                                 max_z = sqrt(SQR(width) + SQR(height)) / 2;
1088                                 glUniform4f(glGetUniformLocation(frag_shader, "r"),
1089                                         max_z / M_PI / (fov[0] / 2.0),
1090                                         max_z / M_PI / (fov[1] / 2.0),
1091                                         max_z / M_PI / (fov[2] / 2.0),
1092                                         max_z / M_PI / (fov[3] / 2.0));
1093                                 glUniform1f(glGetUniformLocation(frag_shader, "radius"),
1094                                         config.radius);
1095                                 break;
1096                 }
1097
1098
1099                 get_output()->init_screen();
1100                 get_output()->bind_texture(0);
1101                 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
1102                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
1103                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
1104                 get_output()->draw_texture();
1105                 glUseProgram(0);
1106
1107
1108                 if( config.draw_guides ) {
1109                         int w = get_output()->get_w();
1110                         int h = get_output()->get_h();
1111                         int center_x = (int)(config.center_x * w / 100);
1112                         int center_y = (int)(config.center_y * h / 100);
1113
1114                         glDisable(GL_TEXTURE_2D);
1115                         glColor4f(0.0, 0.0, 0.0, 1.0);
1116                         glBegin(GL_LINES);
1117                         glVertex3f(center_x, -h + center_y - CENTER_H / 2, 0.0);
1118                         glVertex3f(center_x, -h + center_y + CENTER_H / 2, 0.0);
1119                         glEnd();
1120                         glBegin(GL_LINES);
1121                         glVertex3f(center_x - CENTER_W / 2, -h + center_y, 0.0);
1122                         glVertex3f(center_x + CENTER_W / 2, -h + center_y, 0.0);
1123                         glEnd();
1124                         glColor4f(1.0, 1.0, 1.0, 1.0);
1125                         glBegin(GL_LINES);
1126                         glVertex3f(center_x - 1, -h + center_y - CENTER_H / 2 - 1, 0.0);
1127                         glVertex3f(center_x - 1, -h + center_y + CENTER_H / 2 - 1, 0.0);
1128                         glEnd();
1129                         glBegin(GL_LINES);
1130                         glVertex3f(center_x - CENTER_W / 2 - 1, -h + center_y - 1, 0.0);
1131                         glVertex3f(center_x + CENTER_W / 2 - 1, -h + center_y - 1, 0.0);
1132                         glEnd();
1133                 }
1134                 get_output()->set_opengl_state(VFrame::SCREEN);
1135         }
1136
1137 #endif
1138         return 0;
1139 }
1140
1141 // do using specified interpolation
1142 #define DO_LENS(type) \
1143         int icolor_model = plugin->get_input()->get_color_model(); \
1144         switch( plugin->config.interp ) { \
1145         case LensConfig::INTERP_NEAREST: \
1146                 switch( icolor_model ) { \
1147                 case BC_RGB888: \
1148                         DO_LENS_##type(unsigned char, 3, 0xff, 0x0, nearest); \
1149                         break; \
1150                 case BC_RGBA8888: \
1151                         DO_LENS_##type(unsigned char, 4, 0xff, 0x0, nearest); \
1152                         break; \
1153                 case BC_RGB_FLOAT: \
1154                         DO_LENS_##type(float, 3, 1.0, 0.0, nearest); \
1155                         break; \
1156                 case BC_RGBA_FLOAT: \
1157                         DO_LENS_##type(float, 4, 1.0, 0.0, nearest); \
1158                         break; \
1159                 case BC_YUV888: \
1160                         DO_LENS_##type(unsigned char, 3, 0xff, 0x80, nearest); \
1161                         break; \
1162                 case BC_YUVA8888: \
1163                         DO_LENS_##type(unsigned char, 4, 0xff, 0x80, nearest); \
1164                         break; \
1165                 } \
1166                 break; \
1167         case LensConfig::INTERP_DEFAULT: \
1168         case LensConfig::INTERP_BILINEAR: \
1169                 switch( icolor_model ) { \
1170                 case BC_RGB888: \
1171                         DO_LENS_##type(unsigned char, 3, 0xff, 0x0, bi_linear); \
1172                         break; \
1173                 case BC_RGBA8888: \
1174                         DO_LENS_##type(unsigned char, 4, 0xff, 0x0, bi_linear); \
1175                         break; \
1176                 case BC_RGB_FLOAT: \
1177                         DO_LENS_##type(float, 3, 1.0, 0.0, bi_linear); \
1178                         break; \
1179                 case BC_RGBA_FLOAT: \
1180                         DO_LENS_##type(float, 4, 1.0, 0.0, bi_linear); \
1181                         break; \
1182                 case BC_YUV888: \
1183                         DO_LENS_##type(unsigned char, 3, 0xff, 0x80, bi_linear); \
1184                         break; \
1185                 case BC_YUVA8888: \
1186                         DO_LENS_##type(unsigned char, 4, 0xff, 0x80, bi_linear); \
1187                         break; \
1188                 } \
1189                 break; \
1190         case LensConfig::INTERP_BICUBIC: \
1191                 switch( icolor_model ) { \
1192                 case BC_RGB888: \
1193                         DO_LENS_##type(unsigned char, 3, 0xff, 0x0, bi_cubic); \
1194                         break; \
1195                 case BC_RGBA8888: \
1196                         DO_LENS_##type(unsigned char, 4, 0xff, 0x0, bi_cubic); \
1197                         break; \
1198                 case BC_RGB_FLOAT: \
1199                         DO_LENS_##type(float, 3, 1.0, 0.0, bi_cubic); \
1200                         break; \
1201                 case BC_RGBA_FLOAT: \
1202                         DO_LENS_##type(float, 4, 1.0, 0.0, bi_cubic); \
1203                         break; \
1204                 case BC_YUV888: \
1205                         DO_LENS_##type(unsigned char, 3, 0xff, 0x80, bi_cubic); \
1206                         break; \
1207                 case BC_YUVA8888: \
1208                         DO_LENS_##type(unsigned char, 4, 0xff, 0x80, bi_cubic); \
1209                         break; \
1210                 } \
1211                 break; \
1212         }
1213
1214 LensPackage::LensPackage()
1215  : LoadPackage()
1216 {
1217 }
1218
1219 LensUnit::LensUnit(LensEngine *engine, LensMain *plugin)
1220  : LoadClient(engine)
1221 {
1222         this->plugin = plugin;
1223 }
1224
1225 LensUnit::~LensUnit()
1226 {
1227 }
1228
1229 void LensUnit::process_spherical_stretch(LensPackage *pkg)
1230 {
1231         float *fov = plugin->config.fov;
1232         float aspect = plugin->config.aspect;
1233         int row1 = pkg->row1;
1234         int row2 = pkg->row2;
1235         double x_factor = aspect;
1236         double y_factor = 1.0 / aspect;
1237         if( x_factor < 1 ) x_factor = 1;
1238         if( y_factor < 1 ) y_factor = 1;
1239         int width = plugin->get_input()->get_w();
1240         int height = plugin->get_input()->get_h();
1241         double dim = MAX(width, height) * plugin->config.radius;
1242         double max_z = dim * sqrt(2.0) / 2;
1243         double center_x = width * plugin->config.center_x / 100.0;
1244         double center_y = height * plugin->config.center_y / 100.0;
1245         double r[FOV_CHANNELS];
1246
1247         r[0] = max_z / M_PI / (fov[0] / 2.0);
1248         r[1] = max_z / M_PI / (fov[1] / 2.0);
1249         r[2] = max_z / M_PI / (fov[2] / 2.0);
1250         r[3] = max_z / M_PI / (fov[3] / 2.0);
1251
1252 #define DO_LENS_SPHERICAL_STRETCH(type, components, max, chroma, interp) { \
1253         type **in_rows = (type**)plugin->get_temp()->get_rows(); \
1254         type **out_rows = (type**)plugin->get_input()->get_rows(); \
1255         type black[4] = { 0, chroma, chroma, 0 }; \
1256         INTERP_SETUP(in_rows, max, 0,0, width,height); \
1257  \
1258         for( int y=row1; y<row2; ++y ) { \
1259                 type *out_row = out_rows[y]; \
1260                 double y_diff = y - center_y; \
1261                 for( int x=0; x<width; ++x ) { \
1262                         double x_diff = (x - center_x); \
1263                         double z = sqrt(x_diff * x_diff + y_diff * y_diff); \
1264                         double a2 = x != center_x ? atan(y_diff / x_diff) : \
1265                                 y < center_y ? 3*M_PI/2 : M_PI/2; \
1266                         if( x_diff < 0.0 ) a2 += M_PI; \
1267                         for( int i=0; i<components; ++i ) { \
1268                                 double a1 = (z / (M_PI * r[i] / 2)) * (M_PI / 2); \
1269                                 double z_in = r[i] * sin(a1); \
1270                                 double x_in = z_in * cos(a2) * x_factor + center_x; \
1271                                 double y_in = z_in * sin(a2) * y_factor + center_y; \
1272                                 interp##_SETUP(type, components, x_in, y_in); \
1273                                 for( int j=0; j<i; ++j ) interp##_next(); \
1274                                 *out_row++ = interp##_interp(black[i], black[i]); \
1275                         } \
1276                 } \
1277         } \
1278  \
1279         type *out_pixel = out_rows[(int)center_y] + (int)center_x * components; \
1280         type *inp_pixel = in_rows[(int)center_y] + (int)center_x * components; \
1281         for( int i=0; i<components; ++i ) *out_pixel++ = *inp_pixel++; \
1282 }
1283
1284         DO_LENS(SPHERICAL_STRETCH);
1285 }
1286
1287 void LensUnit::process_spherical_shrink(LensPackage *pkg)
1288 {
1289
1290         float *fov = plugin->config.fov;
1291         float aspect = plugin->config.aspect;
1292         int row1 = pkg->row1;
1293         int row2 = pkg->row2;
1294         int width = plugin->get_input()->get_w();
1295         int height = plugin->get_input()->get_h();
1296         double x_factor = aspect;
1297         double y_factor = 1.0 / aspect;
1298         if( x_factor < 1 ) x_factor = 1;
1299         if( y_factor < 1 ) y_factor = 1;
1300         double dim = MAX(width, height) * plugin->config.radius;
1301         double max_z[FOV_CHANNELS];
1302         double center_x = width * plugin->config.center_x / 100.0;
1303         double center_y = height * plugin->config.center_y / 100.0;
1304         double r[FOV_CHANNELS];
1305
1306 //      max_z[0] = sqrt(SQR(width) + SQR(height)) / 2 / fov[0];
1307 //      max_z[1] = sqrt(SQR(width) + SQR(height)) / 2 / fov[1];
1308 //      max_z[2] = sqrt(SQR(width) + SQR(height)) / 2 / fov[2];
1309 //      max_z[3] = sqrt(SQR(width) + SQR(height)) / 2 / fov[3];
1310         max_z[0] = dim * sqrt(2.0) / 2 / fov[0];
1311         max_z[1] = dim * sqrt(2.0) / 2 / fov[1];
1312         max_z[2] = dim * sqrt(2.0) / 2 / fov[2];
1313         max_z[3] = dim * sqrt(2.0) / 2 / fov[3];
1314         r[0] = max_z[0] * 2 / M_PI;
1315         r[1] = max_z[1] * 2 / M_PI;
1316         r[2] = max_z[2] * 2 / M_PI;
1317         r[3] = max_z[3] * 2 / M_PI;
1318
1319 #define DO_LENS_SPHERICAL_SHRINK(type, components, max, chroma, interp) { \
1320         type **in_rows = (type**)plugin->get_temp()->get_rows(); \
1321         type **out_rows = (type**)plugin->get_input()->get_rows(); \
1322         type black[4] = { 0, chroma, chroma, 0 }; \
1323         INTERP_SETUP(in_rows, max, 0,0, width,height); \
1324  \
1325         for( int y=row1; y<row2; ++y ) { \
1326                 type *out_row = out_rows[y]; \
1327                 type *in_row = in_rows[y]; \
1328                 double y_diff = y - center_y; \
1329                 for( int x=0; x<width; ++x ) { \
1330                         double x_diff = x - center_x; \
1331                         if( !x_diff && !y_diff ) { \
1332                                 type *inp_pixel = in_row + x * components; \
1333                                 for( int c=0; c<components; ++c ) \
1334                                         *out_row++ = *inp_pixel++; \
1335                                 continue; \
1336                         } \
1337                         double z = sqrt(x_diff * x_diff + y_diff * y_diff); \
1338                         double a2 = atan(y_diff / x_diff); \
1339                         if( x_diff < 0.0 ) a2 += M_PI; \
1340                         for( int i=0; i<components; ++i ) { \
1341                                 if( z > r[i] ) { *out_row++ = black[i]; continue; } \
1342                                 double a1 = asin(z / r[i]); \
1343                                 double z_in = a1 * max_z[i] * 2 / M_PI; \
1344                                 float x_in = z_in * cos(a2) * x_factor + center_x; \
1345                                 float y_in = z_in * sin(a2) * y_factor + center_y; \
1346                                 interp##_SETUP(type, components, x_in, y_in); \
1347                                 for( int j=0; j<i; ++j ) interp##_next(); \
1348                                 *out_row++ = interp##_interp(black[i], black[i]); \
1349                         } \
1350                 } \
1351         } \
1352  \
1353         type *out_pixel = out_rows[(int)center_y] + (int)center_x * components; \
1354         type *inp_pixel = in_rows[(int)center_y] + (int)center_x * components; \
1355         for( int i=0; i<components; ++i ) *out_pixel++ = *inp_pixel++; \
1356 }
1357
1358         DO_LENS(SPHERICAL_SHRINK);
1359 }
1360
1361 void LensUnit::process_rectilinear_stretch(LensPackage *pkg)
1362 {
1363         float *fov = plugin->config.fov;
1364         float aspect = plugin->config.aspect;
1365         int row1 = pkg->row1;
1366         int row2 = pkg->row2;
1367         double x_factor = aspect;
1368         double y_factor = 1.0 / aspect;
1369         if( x_factor < 1 ) x_factor = 1;
1370         if( y_factor < 1 ) y_factor = 1;
1371         int width = plugin->get_input()->get_w();
1372         int height = plugin->get_input()->get_h();
1373 //      double dim = MAX(width, height) * plugin->config.radius;
1374 //      double max_z = dim * sqrt(2.0) / 2;
1375         double max_z = sqrt(SQR(width) + SQR(height)) / 2;
1376         double center_x = width * plugin->config.center_x / 100.0;
1377         double center_y = height * plugin->config.center_y / 100.0;
1378         double r[FOV_CHANNELS];
1379
1380         r[0] = max_z / M_PI / (fov[0] / 2.0);
1381         r[1] = max_z / M_PI / (fov[1] / 2.0);
1382         r[2] = max_z / M_PI / (fov[2] / 2.0);
1383         r[3] = max_z / M_PI / (fov[3] / 2.0);
1384
1385 #define DO_LENS_RECTILINEAR_STRETCH(type, components, max, chroma, interp) { \
1386         type **in_rows = (type**)plugin->get_temp()->get_rows(); \
1387         type **out_rows = (type**)plugin->get_input()->get_rows(); \
1388         type black[4] = { 0, chroma, chroma, 0 }; \
1389         INTERP_SETUP(in_rows, max, 0,0, width,height); \
1390  \
1391         for( int y=row1; y<row2; ++y ) { \
1392                 type *out_row = out_rows[y]; \
1393                 double y_diff = y - center_y; \
1394                 for( int x=0; x<width; ++x ) { \
1395                         double x_diff = (x - center_x); /* Compute magnitude / angle */ \
1396                         double z = sqrt(x_diff * x_diff + y_diff * y_diff); \
1397                         double angle = x != center_x ? atan(y_diff / x_diff) : \
1398                                 y < center_y ? 3*M_PI/2 : M_PI/2; \
1399                         if( x_diff < 0.0 ) angle += M_PI; \
1400                         for( int i=0; i<components; ++i ) { /* Compute new radius */ \
1401                                 double radius1 = (z / r[i]) * 2 * plugin->config.radius; \
1402                                 double z_in = r[i] * atan(radius1) / (M_PI / 2); \
1403                                 double x_in = z_in * cos(angle) * x_factor + center_x; \
1404                                 double y_in = z_in * sin(angle) * y_factor + center_y; \
1405                                 interp##_SETUP(type, components, x_in, y_in); \
1406                                 for( int j=0; j<i; ++j ) interp##_next(); \
1407                                 *out_row++ = interp##_interp(black[i], black[i]); \
1408                         } \
1409                 } \
1410         } \
1411  \
1412         type *out_pixel = out_rows[(int)center_y] + (int)center_x * components; \
1413         type *inp_pixel = in_rows[(int)center_y] + (int)center_x * components; \
1414         for( int i=0; i<components; ++i ) *out_pixel++ = *inp_pixel++; \
1415 }
1416
1417         DO_LENS(RECTILINEAR_STRETCH);
1418 }
1419
1420 void LensUnit::process_rectilinear_shrink(LensPackage *pkg)
1421 {
1422         float *fov = plugin->config.fov;
1423         float aspect = plugin->config.aspect;
1424         int row1 = pkg->row1;
1425         int row2 = pkg->row2;
1426         double x_factor = aspect;
1427         double y_factor = 1.0 / aspect;
1428         if( x_factor < 1 ) x_factor = 1;
1429         if( y_factor < 1 ) y_factor = 1;
1430         int width = plugin->get_input()->get_w();
1431         int height = plugin->get_input()->get_h();
1432         double max_z = MAX(width, height) / 2 * plugin->config.radius;
1433         double center_x = width * plugin->config.center_x / 100.0;
1434         double center_y = height * plugin->config.center_y / 100.0;
1435         double r[FOV_CHANNELS];
1436
1437         r[0] = max_z / fov[0];
1438         r[1] = max_z / fov[1];
1439         r[2] = max_z / fov[2];
1440         r[3] = max_z / fov[3];
1441
1442 #define DO_LENS_RECTILINEAR_SHRINK(type, components, max, chroma, interp) { \
1443         type **in_rows = (type**)plugin->get_temp()->get_rows(); \
1444         type **out_rows = (type**)plugin->get_input()->get_rows(); \
1445         type black[4] = { 0, chroma, chroma, 0 }; \
1446         INTERP_SETUP(in_rows, max, 0,0, width,height); \
1447  \
1448         for( int y=row1; y<row2; ++y ) { \
1449                 type *out_row = out_rows[y]; \
1450                 double y_diff = y - center_y; \
1451                 for( int x=0; x<width; ++x ) { \
1452                         double x_diff = (x - center_x); /* Compute magnitude/angle */ \
1453                         double z = sqrt(x_diff * x_diff + y_diff * y_diff); \
1454                         double angle = x != center_x ? atan(y_diff / x_diff) : \
1455                                 y < center_y ? 3*M_PI/2 : M_PI/2; \
1456                         if( x_diff < 0.0 ) angle += M_PI; \
1457                         for( int i=0; i<components; ++i ) { /* Compute new radius */ \
1458                                 double radius1 = z / r[i]; \
1459                                 double z_in = r[i] * tan(radius1) / (M_PI / 2); \
1460                                 double x_in = z_in * cos(angle) * x_factor + center_x; \
1461                                 double y_in = z_in * sin(angle) * y_factor + center_y; \
1462                                 interp##_SETUP(type, components, x_in, y_in); \
1463                                 for( int j=0; j<i; ++j ) interp##_next(); \
1464                                 *out_row++ = interp##_interp(black[i], black[i]); \
1465                         } \
1466                 } \
1467         } \
1468  \
1469         type *out_pixel = out_rows[(int)center_y] + (int)center_x * components; \
1470         type *inp_pixel = in_rows[(int)center_y] + (int)center_x * components; \
1471         for( int i=0; i<components; ++i ) *out_pixel++ = *inp_pixel++; \
1472 }
1473
1474         DO_LENS(RECTILINEAR_SHRINK);
1475 }
1476
1477 void LensUnit::process_package(LoadPackage *package)
1478 {
1479         LensPackage *pkg = (LensPackage*)package;
1480
1481         switch( plugin->config.mode ) {
1482         case LensConfig::SPHERICAL_STRETCH:
1483                 process_spherical_stretch(pkg);
1484                 break;
1485         case LensConfig::SPHERICAL_SHRINK:
1486                 process_spherical_shrink(pkg);
1487                 break;
1488         case LensConfig::RECTILINEAR_STRETCH:
1489                 process_rectilinear_stretch(pkg);
1490                 break;
1491         case LensConfig::RECTILINEAR_SHRINK:
1492                 process_rectilinear_shrink(pkg);
1493                 break;
1494         }
1495 }
1496
1497
1498 LensEngine::LensEngine(LensMain *plugin)
1499  : LoadServer(plugin->PluginClient::smp + 1, plugin->PluginClient::smp + 1)
1500 // : LoadServer(1, 1)
1501 {
1502         this->plugin = plugin;
1503 }
1504
1505 LensEngine::~LensEngine()
1506 {
1507 }
1508
1509 void LensEngine::init_packages()
1510 {
1511         int row1 = 0, row2 = 0, n = LoadServer::get_total_packages();
1512         for( int i=0; i<n; row1=row2 ) {
1513                 LensPackage *package = (LensPackage*)LoadServer::get_package(i);
1514                 row2 = plugin->get_input()->get_h() * ++i / n;
1515                 package->row1 = row1;  package->row2 = row2;
1516         }
1517 }
1518
1519 LoadClient* LensEngine::new_client()
1520 {
1521         return new LensUnit(this, plugin);
1522 }
1523
1524 LoadPackage* LensEngine::new_package()
1525 {
1526         return new LensPackage;
1527 }
1528
1529