remove whitespace at eol
[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 "language.h"
29 #include "lens.h"
30
31
32 #include <string.h>
33
34
35
36
37 REGISTER_PLUGIN(LensMain)
38
39
40
41
42 LensConfig::LensConfig()
43 {
44         for(int i = 0; i < FOV_CHANNELS; i++)
45                 fov[i] = 1.0;
46         aspect = 1.0;
47         radius = 1.0;
48         mode = LensConfig::SHRINK;
49         center_x = 50.0;
50         center_y = 50.0;
51         draw_guides = 0;
52 }
53
54 int LensConfig::equivalent(LensConfig &that)
55 {
56         for(int i = 0; i < FOV_CHANNELS; i++)
57                 if(!EQUIV(fov[i], that.fov[i])) return 0;
58         return EQUIV(aspect, that.aspect) &&
59                 EQUIV(radius, that.radius) &&
60                 EQUIV(center_x, that.center_x) &&
61                 EQUIV(center_y, that.center_y) &&
62                 mode == that.mode &&
63                 draw_guides == that.draw_guides;
64 }
65
66 void LensConfig::copy_from(LensConfig &that)
67 {
68         for(int i = 0; i < FOV_CHANNELS; i++)
69                 fov[i] = that.fov[i];
70         aspect = that.aspect;
71         radius = that.radius;
72         mode = that.mode;
73         center_x = that.center_x;
74         center_y = that.center_y;
75         draw_guides = that.draw_guides;
76 }
77
78 void LensConfig::interpolate(LensConfig &prev,
79         LensConfig &next,
80         int64_t prev_frame,
81         int64_t next_frame,
82         int64_t current_frame)
83 {
84         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
85         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
86
87         for(int i = 0; i < FOV_CHANNELS; i++)
88                 fov[i] = prev.fov[i] * prev_scale + next.fov[i] * next_scale;
89         aspect = prev.aspect * prev_scale + next.aspect * next_scale;
90         radius = prev.radius * prev_scale + next.radius * next_scale;
91         center_x = prev.center_x * prev_scale + next.center_x * next_scale;
92         center_y = prev.center_y * prev_scale + next.center_y * next_scale;
93         mode = prev.mode;
94         draw_guides = prev.draw_guides;
95
96         boundaries();
97 }
98
99 void LensConfig::boundaries()
100 {
101         CLAMP(center_x, 0.0, 99.0);
102         CLAMP(center_y, 0.0, 99.0);
103         for(int i = 0; i < FOV_CHANNELS; i++)
104                 CLAMP(fov[i], 0.0, 1.0);
105         CLAMP(aspect, 0.3, 3.0);
106         CLAMP(radius, 0.3, 3.0);
107 }
108
109
110
111
112 LensSlider::LensSlider(LensMain *client,
113         LensGUI *gui,
114         LensText *text,
115         float *output,
116         int x,
117         int y,
118         float min,
119         float max)
120  : BC_FSlider(x, y, 0, 200, 200, min, max, *output)
121 {
122         this->gui = gui;
123         this->client = client;
124         this->output = output;
125         this->text = text;
126         set_precision(0.01);
127 }
128
129 int LensSlider::handle_event()
130 {
131         float prev_output = *output;
132         *output = get_value();
133         text->update(*output);
134
135         float difference = *output - prev_output;
136         int is_fov = 0;
137
138         if(client->lock)
139         {
140                 for(int i = 0; i < FOV_CHANNELS; i++)
141                 {
142                         if(output == &client->config.fov[i])
143                         {
144                                 is_fov = 1;
145                                 break;
146                         }
147                 }
148
149                 if(is_fov)
150                 {
151                         for(int i = 0; i < FOV_CHANNELS; i++)
152                         {
153                                 if(output != &client->config.fov[i])
154                                 {
155                                         client->config.fov[i] += difference;
156                                         client->config.boundaries();
157                                         gui->fov_slider[i]->update(client->config.fov[i]);
158                                         gui->fov_text[i]->update(client->config.fov[i]);
159                                 }
160                         }
161                 }
162         }
163
164         client->send_configure_change();
165         return 1;
166 }
167
168
169
170 LensText::LensText(LensMain *client,
171         LensGUI *gui,
172         LensSlider *slider,
173         float *output,
174         int x,
175         int y)
176  : BC_TextBox(x, y, 100, 1, *output)
177 {
178         this->gui = gui;
179         this->client = client;
180         this->output = output;
181         this->slider = slider;
182 }
183
184 int LensText::handle_event()
185 {
186         float prev_output = *output;
187         *output = atof(get_text());
188         slider->update(*output);
189
190         float difference = *output - prev_output;
191         int is_fov = 0;
192
193         if(client->lock)
194         {
195                 for(int i = 0; i < FOV_CHANNELS; i++)
196                 {
197                         if(output == &client->config.fov[i])
198                         {
199                                 is_fov = 1;
200                                 break;
201                         }
202                 }
203
204                 if(is_fov)
205                 {
206                         for(int i = 0; i < FOV_CHANNELS; i++)
207                         {
208                                 if(output != &client->config.fov[i])
209                                 {
210                                         client->config.fov[i] += difference;
211                                         client->config.boundaries();
212                                         gui->fov_slider[i]->update(client->config.fov[i]);
213                                         gui->fov_text[i]->update(client->config.fov[i]);
214                                 }
215                         }
216                 }
217         }
218
219         client->send_configure_change();
220         return 1;
221 }
222
223
224
225 LensToggle::LensToggle(LensMain *client,
226         int *output,
227         int x,
228         int y,
229         const char *text)
230  : BC_CheckBox(x, y, *output, text)
231 {
232         this->output = output;
233         this->client = client;
234 }
235
236 int LensToggle::handle_event()
237 {
238         *output = get_value();
239         client->send_configure_change();
240         return 1;
241 }
242
243
244
245
246
247
248
249
250
251
252 LensMode::LensMode(LensMain *plugin,
253         LensGUI *gui,
254         int x,
255         int y)
256  : BC_PopupMenu(x,
257         y,
258         calculate_w(gui),
259         "",
260         1)
261 {
262         this->plugin = plugin;
263         this->gui = gui;
264 }
265
266 int LensMode::handle_event()
267 {
268         plugin->config.mode = from_text(get_text());
269         plugin->send_configure_change();
270         return 1;
271
272 }
273
274 void LensMode::create_objects()
275 {
276         add_item(new BC_MenuItem(to_text(LensConfig::SHRINK)));
277         add_item(new BC_MenuItem(to_text(LensConfig::STRETCH)));
278         add_item(new BC_MenuItem(to_text(LensConfig::RECTILINEAR_STRETCH)));
279         add_item(new BC_MenuItem(to_text(LensConfig::RECTILINEAR_SHRINK)));
280         update(plugin->config.mode);
281 }
282
283 void LensMode::update(int mode)
284 {
285         char string[BCTEXTLEN];
286         sprintf(string, "%s", to_text(mode));
287         set_text(string);
288 }
289
290 int LensMode::calculate_w(LensGUI *gui)
291 {
292         int result = 0;
293         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(LensConfig::STRETCH)));
294         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(LensConfig::SHRINK)));
295         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(LensConfig::RECTILINEAR_STRETCH)));
296         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(LensConfig::RECTILINEAR_SHRINK)));
297         return result + 50;
298 }
299
300 int LensMode::from_text(char *text)
301 {
302         if(!strcmp(text, _("Sphere Stretch"))) return LensConfig::STRETCH;
303         else
304         if(!strcmp(text, _("Sphere Shrink"))) return LensConfig::SHRINK;
305         else
306         if(!strcmp(text, _("Rectilinear Stretch"))) return LensConfig::RECTILINEAR_STRETCH;
307         else
308         if(!strcmp(text, _("Rectilinear Shrink"))) return LensConfig::RECTILINEAR_SHRINK;
309         return LensConfig::STRETCH;
310 }
311
312 const char* LensMode::to_text(int mode)
313 {
314         switch(mode)
315         {
316                 case LensConfig::STRETCH:
317                         return _("Sphere Stretch");
318                         break;
319                 case LensConfig::SHRINK:
320                         return _("Sphere Shrink");
321                         break;
322                 case LensConfig::RECTILINEAR_STRETCH:
323                         return _("Rectilinear Stretch");
324                         break;
325                 case LensConfig::RECTILINEAR_SHRINK:
326                         return _("Rectilinear Shrink");
327                         break;
328         }
329         return _("Stretch");
330 }
331
332
333
334
335
336 // LensPresets::LensPresets(LensMain *plugin,
337 //      LensGUI *gui,
338 //      int x,
339 //      int y,
340 //      int w)
341 //  : BC_PopupMenu(x,
342 //      y,
343 //      w,
344 //      "",
345 //      1)
346 // {
347 //      this->plugin = plugin;
348 //      this->gui = gui;
349 // }
350 //
351 // int LensPresets::handle_event()
352 // {
353 //      return 1;
354 // }
355 //
356 // void LensPresets::create_objects()
357 // {
358 // // Remove existing items
359 //      int total = total_items();
360 //      for(int i = 0; i < total; i++)
361 //      {
362 //              del_item();
363 //      }
364 //
365 // // Create current items
366 //      plugin->load_presets();
367 //      for(int i = 0; i < plugin->presets.total; i++)
368 //      {
369 //              add_item(new BC_MenuItem(plugin->presets.values[i]->title));
370 //      }
371 //
372 // // Update text
373 //      if(plugin->current_preset >= 0 &&
374 //              plugin->current_preset < plugin->presets.total)
375 //      {
376 //              set_text(plugin->presets.values[plugin->current_preset]->title);
377 //      }
378 //      else
379 //      {
380 //              set_text("None");
381 //      }
382 // }
383 //
384 // int LensPresets::from_text(LensMain *plugin, char *text)
385 // {
386 // }
387 //
388 // char* LensPresets::to_text(LensMain *plugin, int preset)
389 // {
390 // }
391 //
392 // void LensPresets::update(int preset)
393 // {
394 // }
395 //
396 //
397 //
398 //
399 //
400 //
401 // LensSavePreset::LensSavePreset(LensMain *plugin,
402 //      LensGUI *gui,
403 //      int x,
404 //      int y)
405 //  : BC_GenericButton(x, y, "Save Preset")
406 // {
407 //      this->plugin = plugin;
408 //      this->gui = gui;
409 // }
410 //
411 // int LensSavePreset::handle_event()
412 // {
413 // }
414 //
415 //
416 //
417 //
418 //
419 //
420 //
421 // LensDeletePreset::LensDeletePreset(LensMain *plugin,
422 //      LensGUI *gui,
423 //      int x,
424 //      int y)
425 //  : BC_GenericButton(x, y, "Delete Preset")
426 // {
427 // }
428 //
429 // int LensDeletePreset::handle_event()
430 // {
431 // }
432 //
433 //
434 //
435 //
436 //
437 //
438 //
439 // LensPresetText::LensPresetText(LensMain *plugin,
440 //      LensGUI *gui,
441 //      int x,
442 //      int y,
443 //      int w)
444 //  : BC_TextBox(x, y, w, 1, "")
445 // {
446 //      this->plugin = plugin;
447 //      this->gui = gui;
448 // }
449 //
450 // int LensPresetText::handle_event()
451 // {
452 // }
453
454
455
456
457
458
459
460
461
462
463
464
465
466 LensGUI::LensGUI(LensMain *client)
467  : PluginClientWindow(client,
468         350,
469         510,
470         350,
471         510,
472         0)
473 {
474         this->client = client;
475 }
476
477 LensGUI::~LensGUI()
478 {
479 }
480
481
482 void LensGUI::create_objects()
483 {
484         int x = 10;
485         int y = 10;
486         int x1;
487         BC_Title *title = 0;
488         LensToggle *toggle;
489
490         for(int i = 0; i < FOV_CHANNELS; i++)
491         {
492                 switch(i)
493                 {
494                         case 0: add_tool(title = new BC_Title(x, y, _("R Field of View:"))); break;
495                         case 1: add_tool(title = new BC_Title(x, y, _("G Field of View:"))); break;
496                         case 2: add_tool(title = new BC_Title(x, y, _("B Field of View:"))); break;
497                         case 3: add_tool(title = new BC_Title(x, y, _("A Field of View:"))); break;
498                 }
499
500                 y += title->get_h() + 5;
501                 add_tool(fov_slider[i] = new LensSlider(client,
502                         this,
503                         0,
504                         &client->config.fov[i],
505                         x,
506                         y,
507                         0.0001,
508                         1.0));
509                 x1 = x + fov_slider[i]->get_w() + 5;
510                 add_tool(fov_text[i] = new LensText(client,
511                         this,
512                         fov_slider[i],
513                         &client->config.fov[i],
514                         x1,
515                         y));
516                 fov_slider[i]->text = fov_text[i];
517                 y += fov_text[i]->get_h() + 5;
518         }
519
520         add_tool(toggle = new LensToggle(client,
521                 &client->lock,
522                 x,
523                 y,
524                 _("Lock")));
525         y += toggle->get_h() + 10;
526
527         BC_Bar *bar;
528         add_tool(bar = new BC_Bar(x, y, get_w() - x * 2));
529         y += bar->get_h() + 5;
530
531         add_tool(title = new BC_Title(x, y, _("Aspect Ratio:")));
532         y += title->get_h() + 5;
533         add_tool(aspect_slider = new LensSlider(client,
534                 this,
535                 0,
536                 &client->config.aspect,
537                 x,
538                 y,
539                 0.333,
540                 3.0));
541         x1 = x + aspect_slider->get_w() + 5;
542         add_tool(aspect_text = new LensText(client,
543                 this,
544                 aspect_slider,
545                 &client->config.aspect,
546                 x1,
547                 y));
548         aspect_slider->text = aspect_text;
549         y += aspect_text->get_h() + 5;
550
551
552         add_tool(title = new BC_Title(x, y, _("Radius:")));
553         y += title->get_h() + 5;
554         add_tool(radius_slider = new LensSlider(client,
555                 this,
556                 0,
557                 &client->config.radius,
558                 x,
559                 y,
560                 0.333,
561                 3.0));
562         x1 = x + radius_slider->get_w() + 5;
563         add_tool(radius_text = new LensText(client,
564                 this,
565                 radius_slider,
566                 &client->config.radius,
567                 x1,
568                 y));
569         radius_slider->text = radius_text;
570         y += radius_text->get_h() + 5;
571
572
573         add_tool(title = new BC_Title(x, y, _("Center X:")));
574         y += title->get_h() + 5;
575         add_tool(centerx_slider = new LensSlider(client,
576                 this,
577                 0,
578                 &client->config.center_x,
579                 x,
580                 y,
581                 0.0,
582                 99.0));
583         x1 = x + centerx_slider->get_w() + 5;
584         add_tool(centerx_text = new LensText(client,
585                 this,
586                 centerx_slider,
587                 &client->config.center_x,
588                 x1,
589                 y));
590         centerx_slider->text = centerx_text;
591         centerx_slider->set_precision(1.0);
592         y += centerx_text->get_h() + 5;
593
594
595         add_tool(title = new BC_Title(x, y, _("Center Y:")));
596         y += title->get_h() + 5;
597         add_tool(centery_slider = new LensSlider(client,
598                 this,
599                 0,
600                 &client->config.center_y,
601                 x,
602                 y,
603                 0.0,
604                 99.0));
605         x1 = x + centery_slider->get_w() + 5;
606         add_tool(centery_text = new LensText(client,
607                 this,
608                 centery_slider,
609                 &client->config.center_y,
610                 x1,
611                 y));
612         centery_slider->text = centery_text;
613         centery_slider->set_precision(1.0);
614         y += centery_text->get_h() + 10;
615
616         add_tool(bar = new BC_Bar(x, y, get_w() - x * 2));
617         y += bar->get_h() + 5;
618
619
620 //      add_tool(reverse = new LensToggle(client,
621 //              &client->config.reverse,
622 //              x,
623 //              y,
624 //              _("Reverse")));
625 //      y += reverse->get_h() + 5;
626
627         add_tool(draw_guides = new LensToggle(client,
628                 &client->config.draw_guides,
629                 x,
630                 y,
631                 _("Draw center")));
632         y += draw_guides->get_h() + 5;
633
634
635         add_tool(title = new BC_Title(x, y, _("Mode:")));
636         add_tool(mode = new LensMode(client,
637                 this,
638                 x + title->get_w() + 5,
639                 y));
640         mode->create_objects();
641         y += mode->get_h() + 5;
642
643
644 //      add_tool(title = new BC_Title(x, y, _("Preset:")));
645 //      add_tool(presets = new LensPresets(client,
646 //              this,
647 //              x + title->get_w() + 5,
648 //              y,
649 //              get_w() - x - title->get_w() - 50));
650 //      presets->create_objects();
651 //      y += presets->get_h() + 5;
652 //
653 //      add_tool(save_preset = new LensSavePreset(client,
654 //              this,
655 //              x,
656 //              y));
657 //      add_tool(preset_text = new LensPresetText(client,
658 //              this,
659 //              x + save_preset->get_w() + 5,
660 //              y,
661 //              get_w() - x - save_preset->get_w() - 10));
662 //      y += preset_text->get_h() + 5;
663 //      add_tool(delete_preset = new LensDeletePreset(client,
664 //              this,
665 //              x,
666 //              y));
667
668         show_window();
669         flush();
670 }
671
672
673
674
675
676
677
678 LensMain::LensMain(PluginServer *server)
679  : PluginVClient(server)
680 {
681
682         engine = 0;
683         lock = 0;
684         current_preset = -1;
685 }
686
687 LensMain::~LensMain()
688 {
689
690         delete engine;
691         presets.remove_all_objects();
692 }
693
694 NEW_WINDOW_MACRO(LensMain, LensGUI)
695 LOAD_CONFIGURATION_MACRO(LensMain, LensConfig)
696 int LensMain::is_realtime() { return 1; }
697 const char* LensMain::plugin_title() { return _("Lens"); }
698
699 void LensMain::update_gui()
700 {
701         if(thread)
702         {
703                 if(load_configuration())
704                 {
705                         ((LensGUI*)thread->window)->lock_window("LensMain::update_gui");
706                         for(int i = 0; i < FOV_CHANNELS; i++)
707                         {
708                                 ((LensGUI*)thread->window)->fov_slider[i]->update(config.fov[i]);
709                                 ((LensGUI*)thread->window)->fov_text[i]->update(config.fov[i]);
710                         }
711                         ((LensGUI*)thread->window)->aspect_slider->update(config.aspect);
712                         ((LensGUI*)thread->window)->aspect_text->update(config.aspect);
713                         ((LensGUI*)thread->window)->radius_slider->update(config.radius);
714                         ((LensGUI*)thread->window)->radius_text->update(config.radius);
715                         ((LensGUI*)thread->window)->centerx_slider->update(config.center_x);
716                         ((LensGUI*)thread->window)->centerx_text->update(config.center_x);
717                         ((LensGUI*)thread->window)->centery_slider->update(config.center_y);
718                         ((LensGUI*)thread->window)->centery_text->update(config.center_y);
719                         ((LensGUI*)thread->window)->mode->update(config.mode);
720                         ((LensGUI*)thread->window)->draw_guides->update(config.draw_guides);
721                         ((LensGUI*)thread->window)->unlock_window();
722                 }
723         }
724 }
725
726 //void LensMain::save_presets()
727 //{
728 //      char path[BCTEXTLEN], string[BCTEXTLEN];
729 //      sprintf(path, "%s/lenspresets.rc", File::get_config_path());
730 //      BC_Hash *defaults = new BC_Hash(path);
731 //
732 //// Save presets
733 //      defaults->update("TOTAL_PRESETS", presets.total);
734 //      for(int i = 0; i < presets.total; i++)
735 //      {
736 //              LensPreset *preset = presets.values[i];
737 //              sprintf(string, "TITLE_%d", i);
738 //              defaults->update(string, preset->title);
739 //
740 //              for(int j = 0; j < FOV_CHANNELS; j++)
741 //              {
742 //                      sprintf(string, "FOCAL_LENGTH_%d_%d", i, j);
743 //                      defaults->update(string, preset->fov[j]);
744 //              }
745 //
746 //              sprintf(string, "ASPECT_%d", i);
747 //              defaults->update(string, preset->aspect);
748 //              sprintf(string, "RADIUS_%d", i);
749 //              defaults->update(string, preset->radius);
750 //              sprintf(string, "MODE_%d", i);
751 //              defaults->update(string, preset->mode);
752 //      }
753 //
754 //      defaults->save();
755 //      delete defaults;
756 //}
757
758
759 void LensMain::save_data(KeyFrame *keyframe)
760 {
761         FileXML output;
762         char string[BCTEXTLEN];
763
764
765
766 // cause data to be stored directly in text
767         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
768         output.tag.set_title("LENS");
769         for(int i = 0; i < FOV_CHANNELS; i++)
770         {
771                 sprintf(string, "FOCAL_LENGTH%d", i);
772                 output.tag.set_property(string, config.fov[i]);
773         }
774         output.tag.set_property("ASPECT", config.aspect);
775         output.tag.set_property("RADIUS", config.radius);
776         output.tag.set_property("MODE", config.mode);
777         output.tag.set_property("CENTER_X", config.center_x);
778         output.tag.set_property("CENTER_Y", config.center_y);
779         output.tag.set_property("DRAW_GUIDES", config.draw_guides);
780         output.append_tag();
781         output.tag.set_title("/LENS");
782         output.append_tag();
783         output.append_newline();
784         output.terminate_string();
785
786 }
787
788
789 void LensMain::read_data(KeyFrame *keyframe)
790 {
791         FileXML input;
792         char string[BCTEXTLEN];
793
794
795         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
796
797         int result = 0;
798
799         while(!result)
800         {
801                 result = input.read_tag();
802
803                 if(!result)
804                 {
805                         if(input.tag.title_is("LENS"))
806                         {
807                                 for(int i = 0; i < FOV_CHANNELS; i++)
808                                 {
809                                         sprintf(string, "FOCAL_LENGTH%d", i);
810                                         config.fov[i] = input.tag.get_property(string, config.fov[i]);
811                                 }
812                                 config.aspect = input.tag.get_property("ASPECT", config.aspect);
813                                 config.radius = input.tag.get_property("RADIUS", config.radius);
814                                 config.mode = input.tag.get_property("MODE", config.mode);
815                                 config.center_x = input.tag.get_property("CENTER_X", config.center_x);
816                                 config.center_y = input.tag.get_property("CENTER_Y", config.center_y);
817                                 config.draw_guides = input.tag.get_property("DRAW_GUIDES", config.draw_guides);
818                         }
819                 }
820         }
821 }
822
823
824
825 int LensMain::process_buffer(VFrame *frame,
826         int64_t start_position,
827         double frame_rate)
828 {
829         VFrame *input;
830         load_configuration();
831
832         if(get_use_opengl())
833         {
834                 input = frame;
835         }
836         else
837         {
838                 input = new_temp(frame->get_w(), frame->get_h(), frame->get_color_model());
839         }
840
841         read_frame(input,
842                 0,
843                 start_position,
844                 frame_rate,
845                 get_use_opengl());
846
847
848         if(get_use_opengl())
849         {
850                 run_opengl();
851                 return 0;
852         }
853         else
854         {
855                 if(!engine) engine = new LensEngine(this);
856                 engine->process_packages();
857                 if(config.draw_guides)
858                 {
859 // Draw center
860 #define CENTER_H 20
861 #define CENTER_W 20
862 #define DRAW_GUIDES(components, type, max) \
863 { \
864         type **rows = (type**)get_output()->get_rows(); \
865         if( (center_x >= 0 && center_x < w) || (center_y >= 0 && center_y < h) ) { \
866                 type *hrow = rows[center_y] + components * (center_x - CENTER_W / 2); \
867                 for(int i = center_x - CENTER_W / 2; i <= center_x + CENTER_W / 2; i++) \
868                 { \
869                         if(i >= 0 && i < w) { \
870                                 hrow[0] = max - hrow[0]; \
871                                 hrow[1] = max - hrow[1]; \
872                                 hrow[2] = max - hrow[2]; \
873                                 hrow += components; \
874                         } \
875                 } \
876  \
877                 for(int i = center_y - CENTER_W / 2; i <= center_y + CENTER_W / 2; i++) \
878                 { \
879                         if(i >= 0 && i < h) { \
880                                 type *vrow = rows[i] + center_x * components; \
881                                 vrow[0] = max - vrow[0]; \
882                                 vrow[1] = max - vrow[1]; \
883                                 vrow[2] = max - vrow[2]; \
884                         } \
885                 } \
886         } \
887 }
888
889                         int w = get_output()->get_w();
890                         int h = get_output()->get_h();
891                         int center_x = (int)(config.center_x * w / 100);
892                         int center_y = (int)(config.center_y * h / 100);
893                         switch(get_output()->get_color_model())
894                         {
895                                 case BC_RGB_FLOAT:
896                                         DRAW_GUIDES(3, float, 1.0)
897                                         break;
898                                 case BC_RGBA_FLOAT:
899                                         DRAW_GUIDES(4, float, 1.0)
900                                         break;
901                                 case BC_RGB888:
902                                         DRAW_GUIDES(3, unsigned char, 0xff)
903                                         break;
904                                 case BC_RGBA8888:
905                                         DRAW_GUIDES(4, unsigned char, 0xff)
906                                         break;
907                                 case BC_YUV888:
908                                         DRAW_GUIDES(3, unsigned char, 0xff)
909                                         break;
910                                 case BC_YUVA8888:
911                                         DRAW_GUIDES(4, unsigned char, 0xff)
912                                         break;
913                         }
914
915                 }
916         }
917
918         return 0;
919 }
920
921
922 int LensMain::handle_opengl()
923 {
924 #ifdef HAVE_GL
925         static const char *shrink_frag =
926                 "uniform sampler2D tex;\n"
927                 "uniform vec2 texture_extents;\n"
928                 "uniform vec2 image_extents;\n"
929                 "uniform vec2 aspect;\n"
930                 "uniform vec2 center_coord;\n"
931                 "uniform vec4 border_color;\n"
932                 "uniform vec4 r;\n"
933                 "uniform vec4 max_z;\n"
934                 "void main()\n"
935                 "{\n"
936                 "       vec2 outcoord = gl_TexCoord[0].st * texture_extents;\n"
937                 "       vec2 coord_diff = outcoord - center_coord;\n"
938                 "       if(coord_diff.x == 0.0 && coord_diff.y == 0.0)\n"
939                 "       {\n"
940                 "               gl_FragColor = texture2D(tex, outcoord);\n"
941                 "       }\n"
942                 "       else\n"
943                 "       {\n"
944                 "               float z = sqrt(coord_diff.x * coord_diff.x +\n"
945                 "                                               coord_diff.y * coord_diff.y);\n"
946                 "               float a2 = atan(coord_diff.y, coord_diff.x);\n"
947                 "               vec4 a1 = asin(vec4(z, z, z, z) / r);\n"
948                 "               vec4 z_in = a1 * max_z * 2.0 / 3.14159;\n"
949                 "               vec4 in_x;\n"
950                 "               vec4 in_y;\n"
951                 "               in_x = z_in * cos(a2) * aspect.x + center_coord.x;\n"
952                 "               in_y = z_in * sin(a2) * aspect.y + center_coord.y;\n"
953                 "               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"
954                 "                       gl_FragColor.r = border_color.r;\n"
955                 "               else\n"
956                 "                       gl_FragColor.r = texture2D(tex, vec2(in_x.r, in_y.r) / texture_extents).r;\n"
957                 "               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"
958                 "                       gl_FragColor.g = border_color.g;\n"
959                 "               else\n"
960                 "                       gl_FragColor.g = texture2D(tex, vec2(in_x.g, in_y.g) / texture_extents).g;\n"
961                 "               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"
962                 "                       gl_FragColor.b = border_color.b;\n"
963                 "               else\n"
964                 "                       gl_FragColor.b = texture2D(tex, vec2(in_x.b, in_y.b) / texture_extents).b;\n"
965                 "               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"
966                 "                       gl_FragColor.a = border_color.a;\n"
967                 "               else\n"
968                 "                       gl_FragColor.a = texture2D(tex, vec2(in_x.a, in_y.a) / texture_extents).a;\n"
969                 "       }\n"
970                 "}\n";
971
972         static const char *stretch_frag =
973                 "uniform sampler2D tex;\n"
974                 "uniform vec2 texture_extents;\n"
975                 "uniform vec2 image_extents;\n"
976                 "uniform vec2 aspect;\n"
977                 "uniform vec2 center_coord;\n"
978                 "uniform vec4 border_color;\n"
979                 "uniform vec4 r;\n"
980                 "void main()\n"
981                 "{\n"
982                 "       vec2 outcoord = gl_TexCoord[0].st * texture_extents;\n"
983                 "       vec2 coord_diff = outcoord - center_coord;\n"
984                 "       float z = sqrt(coord_diff.x * coord_diff.x +\n"
985                 "                                       coord_diff.y * coord_diff.y);\n"
986                 "       vec4 a1 = (vec4(z, z, z, z) / (3.14159 * r / 2.0)) * (3.14159 / 2.0);\n"
987                 "       vec4 z_in = r * sin(a1);\n"
988                 "       float a2;\n"
989                 "       if(coord_diff.x == 0.0)\n"
990                 "       {\n"
991                 "               if(coord_diff.y < 0.0)\n"
992                 "                       a2 = 3.0 * 3.14159 / 2.0;\n"
993                 "               else\n"
994                 "                       a2 = 3.14159 / 2.0;\n"
995                 "       }\n"
996                 "       else\n"
997                 "               a2 = atan(coord_diff.y, coord_diff.x);\n"
998                 "       vec4 in_x;\n"
999                 "       vec4 in_y;\n"
1000                 "       in_x = z_in * cos(a2) * aspect.x + center_coord.x;\n"
1001                 "       in_y = z_in * sin(a2) * aspect.y + center_coord.y;\n"
1002                 "       if(in_x.r < 0.0 || in_x.r >= image_extents.x || in_y.r < 0.0 || in_y.r >= image_extents.y)\n"
1003                 "               gl_FragColor.r = border_color.r;\n"
1004                 "       else\n"
1005                 "               gl_FragColor.r = texture2D(tex, vec2(in_x.r, in_y.r) / texture_extents).r;\n"
1006                 "       if(in_x.g < 0.0 || in_x.g >= image_extents.x || in_y.g < 0.0 || in_y.g >= image_extents.y)\n"
1007                 "               gl_FragColor.g = border_color.g;\n"
1008                 "       else\n"
1009                 "               gl_FragColor.g = texture2D(tex, vec2(in_x.g, in_y.g) / texture_extents).g;\n"
1010                 "       if(in_x.b < 0.0 || in_x.b >= image_extents.x || in_y.b < 0.0 || in_y.b >= image_extents.y)\n"
1011                 "               gl_FragColor.b = border_color.b;\n"
1012                 "       else\n"
1013                 "               gl_FragColor.b = texture2D(tex, vec2(in_x.b, in_y.b) / texture_extents).b;\n"
1014                 "       if(in_x.a < 0.0 || in_x.a >= image_extents.x || in_y.a < 0.0 || in_y.a >= image_extents.y)\n"
1015                 "               gl_FragColor.a = border_color.a;\n"
1016                 "       else\n"
1017                 "               gl_FragColor.a = texture2D(tex, vec2(in_x.a, in_y.a) / texture_extents).a;\n"
1018                 "}\n";
1019
1020
1021         static const char *rectilinear_stretch_frag =
1022                 "uniform sampler2D tex;\n"
1023                 "uniform vec2 texture_extents;\n"
1024                 "uniform vec2 image_extents;\n"
1025                 "uniform vec2 aspect;\n"
1026                 "uniform vec2 center_coord;\n"
1027                 "uniform vec4 border_color;\n"
1028                 "uniform vec4 r;\n"
1029                 "uniform float radius;\n"
1030                 "void main()\n"
1031                 "{\n"
1032                 "       vec2 outcoord = gl_TexCoord[0].st * texture_extents;\n"
1033                 "       vec2 coord_diff = outcoord - center_coord;\n"
1034                 "       float z = sqrt(coord_diff.x * coord_diff.x +\n"
1035                 "                                       coord_diff.y * coord_diff.y);\n"
1036                 "       vec4 radius1 = (vec4(z, z, z, z) / r) * 2.0 * radius;\n"
1037                 "       vec4 z_in = r * atan(radius1) / (3.14159 / 2.0);\n"
1038                 "\n"
1039                 "       float angle;\n"
1040                 "       if(coord_diff.x == 0.0)\n"
1041                 "       {\n"
1042                 "               if(coord_diff.y < 0.0)\n"
1043                 "                       angle = 3.0 * 3.14159 / 2.0;\n"
1044                 "               else\n"
1045                 "                       angle = 3.14159 / 2.0;\n"
1046                 "       }\n"
1047                 "       else\n"
1048                 "               angle = atan(coord_diff.y, coord_diff.x);\n"
1049                 "       vec4 in_x;\n"
1050                 "       vec4 in_y;\n"
1051                 "\n"
1052                 "       in_x = z_in * cos(angle) * aspect.x + center_coord.x;\n"
1053                 "       in_y = z_in * sin(angle) * aspect.y + center_coord.y;\n"
1054                 "       if(in_x.r < 0.0 || in_x.r >= image_extents.x || in_y.r < 0.0 || in_y.r >= image_extents.y)\n"
1055                 "               gl_FragColor.r = border_color.r;\n"
1056                 "       else\n"
1057                 "               gl_FragColor.r = texture2D(tex, vec2(in_x.r, in_y.r) / texture_extents).r;\n"
1058                 "       if(in_x.g < 0.0 || in_x.g >= image_extents.x || in_y.g < 0.0 || in_y.g >= image_extents.y)\n"
1059                 "               gl_FragColor.g = border_color.g;\n"
1060                 "       else\n"
1061                 "               gl_FragColor.g = texture2D(tex, vec2(in_x.g, in_y.g) / texture_extents).g;\n"
1062                 "       if(in_x.b < 0.0 || in_x.b >= image_extents.x || in_y.b < 0.0 || in_y.b >= image_extents.y)\n"
1063                 "               gl_FragColor.b = border_color.b;\n"
1064                 "       else\n"
1065                 "               gl_FragColor.b = texture2D(tex, vec2(in_x.b, in_y.b) / texture_extents).b;\n"
1066                 "       if(in_x.a < 0.0 || in_x.a >= image_extents.x || in_y.a < 0.0 || in_y.a >= image_extents.y)\n"
1067                 "               gl_FragColor.a = border_color.a;\n"
1068                 "       else\n"
1069                 "               gl_FragColor.a = texture2D(tex, vec2(in_x.a, in_y.a) / texture_extents).a;\n"
1070                 "}\n";
1071
1072         static const char *rectilinear_shrink_frag =
1073                 "uniform sampler2D tex;\n"
1074                 "uniform vec2 texture_extents;\n"
1075                 "uniform vec2 image_extents;\n"
1076                 "uniform vec2 aspect;\n"
1077                 "uniform vec2 center_coord;\n"
1078                 "uniform vec4 border_color;\n"
1079                 "uniform vec4 r;\n"
1080                 "uniform float radius;\n"
1081                 "void main()\n"
1082                 "{\n"
1083                 "       vec2 outcoord = gl_TexCoord[0].st * texture_extents;\n"
1084                 "       vec2 coord_diff = outcoord - center_coord;\n"
1085                 "       float z = sqrt(coord_diff.x * coord_diff.x +\n"
1086                 "                                       coord_diff.y * coord_diff.y);\n"
1087                 "       vec4 radius1 = (vec4(z, z, z, z) / r) * 2.0 * radius;\n"
1088                 "       vec4 z_in = r * atan(radius1) / (3.14159 / 2.0);\n"
1089                 "\n"
1090                 "       float angle;\n"
1091                 "       if(coord_diff.x == 0.0)\n"
1092                 "       {\n"
1093                 "               if(coord_diff.y < 0.0)\n"
1094                 "                       angle = 3.0 * 3.14159 / 2.0;\n"
1095                 "               else\n"
1096                 "                       angle = 3.14159 / 2.0;\n"
1097                 "       }\n"
1098                 "       else\n"
1099                 "               angle = atan(coord_diff.y, coord_diff.x);\n"
1100                 "       vec4 in_x;\n"
1101                 "       vec4 in_y;\n"
1102                 "\n"
1103                 "       in_x = z_in * cos(angle) * aspect.x + center_coord.x;\n"
1104                 "       in_y = z_in * sin(angle) * aspect.y + center_coord.y;\n"
1105                 "       if(in_x.r < 0.0 || in_x.r >= image_extents.x || in_y.r < 0.0 || in_y.r >= image_extents.y)\n"
1106                 "               gl_FragColor.r = border_color.r;\n"
1107                 "       else\n"
1108                 "               gl_FragColor.r = texture2D(tex, vec2(in_x.r, in_y.r) / texture_extents).r;\n"
1109                 "       if(in_x.g < 0.0 || in_x.g >= image_extents.x || in_y.g < 0.0 || in_y.g >= image_extents.y)\n"
1110                 "               gl_FragColor.g = border_color.g;\n"
1111                 "       else\n"
1112                 "               gl_FragColor.g = texture2D(tex, vec2(in_x.g, in_y.g) / texture_extents).g;\n"
1113                 "       if(in_x.b < 0.0 || in_x.b >= image_extents.x || in_y.b < 0.0 || in_y.b >= image_extents.y)\n"
1114                 "               gl_FragColor.b = border_color.b;\n"
1115                 "       else\n"
1116                 "               gl_FragColor.b = texture2D(tex, vec2(in_x.b, in_y.b) / texture_extents).b;\n"
1117                 "       if(in_x.a < 0.0 || in_x.a >= image_extents.x || in_y.a < 0.0 || in_y.a >= image_extents.y)\n"
1118                 "               gl_FragColor.a = border_color.a;\n"
1119                 "       else\n"
1120                 "               gl_FragColor.a = texture2D(tex, vec2(in_x.a, in_y.a) / texture_extents).a;\n"
1121                 "}\n";
1122
1123         get_output()->to_texture();
1124         get_output()->enable_opengl();
1125         unsigned int frag_shader = 0;
1126
1127         switch(config.mode)
1128         {
1129         case LensConfig::SHRINK:
1130                 frag_shader = VFrame::make_shader(0, shrink_frag, 0);
1131                 break;
1132         case LensConfig::STRETCH:
1133                 frag_shader = VFrame::make_shader(0, stretch_frag, 0);
1134                 break;
1135         case LensConfig::RECTILINEAR_STRETCH:
1136                 frag_shader = VFrame::make_shader(0, rectilinear_stretch_frag, 0);
1137                 break;
1138         case LensConfig::RECTILINEAR_SHRINK:
1139                 frag_shader = VFrame::make_shader(0, rectilinear_shrink_frag, 0);
1140                 break;
1141         }
1142
1143         if(frag_shader > 0)
1144         {
1145                 float border_color[] = { 0, 0, 0, 0 };
1146                 if(BC_CModels::is_yuv(get_output()->get_color_model()))
1147                 {
1148                         border_color[1] = 0.5;
1149                         border_color[2] = 0.5;
1150                 }
1151
1152                 double x_factor = config.aspect;
1153                 double y_factor = 1.0 / config.aspect;
1154                 if(x_factor < 1) x_factor = 1;
1155                 if(y_factor < 1) y_factor = 1;
1156
1157                 glUseProgram(frag_shader);
1158                 glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0);
1159                 glUniform2f(glGetUniformLocation(frag_shader, "aspect"),
1160                         x_factor,
1161                         y_factor);
1162                 glUniform2f(glGetUniformLocation(frag_shader, "center_coord"),
1163                                 (GLfloat)get_input()->get_w() * config.center_x / 100.0,
1164                                 (GLfloat)get_input()->get_h() * config.center_y / 100.0);
1165                 glUniform2f(glGetUniformLocation(frag_shader, "texture_extents"),
1166                                 (GLfloat)get_input()->get_texture_w(),
1167                                 (GLfloat)get_input()->get_texture_h());
1168                 glUniform2f(glGetUniformLocation(frag_shader, "image_extents"),
1169                                 (GLfloat)get_input()->get_w(),
1170                                 (GLfloat)get_input()->get_h());
1171
1172                 int width = get_output()->get_w();
1173                 int height = get_output()->get_h();
1174                 float *fov = config.fov;
1175                 float dim;
1176                 float max_z;
1177                 switch(config.mode)
1178                 {
1179                         case LensConfig::SHRINK:
1180                                 dim = MAX(width, height) * config.radius;
1181                                 max_z = dim * sqrt(2.0) / 2;
1182                                 glUniform4fv(glGetUniformLocation(frag_shader, "border_color"),
1183                                                 1,
1184                                                 (GLfloat*)border_color);
1185                                 glUniform4f(glGetUniformLocation(frag_shader, "max_z"),
1186                                         max_z / fov[0],
1187                                         max_z / fov[1],
1188                                         max_z / fov[2],
1189                                         max_z / fov[3]);
1190                                 glUniform4f(glGetUniformLocation(frag_shader, "r"),
1191                                         (max_z / fov[0]) * 2 / M_PI,
1192                                         (max_z / fov[1]) * 2 / M_PI,
1193                                         (max_z / fov[2]) * 2 / M_PI,
1194                                         (max_z / fov[3]) * 2 / M_PI);
1195                                 break;
1196
1197                         case LensConfig::STRETCH:
1198                                 dim = MAX(width, height) * config.radius;
1199                                 max_z = dim * sqrt(2.0) / 2;
1200                                 glUniform4f(glGetUniformLocation(frag_shader, "r"),
1201                                         max_z / M_PI / (fov[0] / 2.0),
1202                                         max_z / M_PI / (fov[1] / 2.0),
1203                                         max_z / M_PI / (fov[2] / 2.0),
1204                                         max_z / M_PI / (fov[3] / 2.0));
1205                                 break;
1206
1207                         case LensConfig::RECTILINEAR_STRETCH:
1208                                 max_z = sqrt(SQR(width) + SQR(height)) / 2;
1209                                 glUniform4f(glGetUniformLocation(frag_shader, "r"),
1210                                         max_z / M_PI / (fov[0] / 2.0),
1211                                         max_z / M_PI / (fov[1] / 2.0),
1212                                         max_z / M_PI / (fov[2] / 2.0),
1213                                         max_z / M_PI / (fov[3] / 2.0));
1214                                 glUniform1f(glGetUniformLocation(frag_shader, "radius"),
1215                                         config.radius);
1216                                 break;
1217
1218                         case LensConfig::RECTILINEAR_SHRINK:
1219                                 max_z = sqrt(SQR(width) + SQR(height)) / 2;
1220                                 glUniform4f(glGetUniformLocation(frag_shader, "r"),
1221                                         max_z / M_PI / (fov[0] / 2.0),
1222                                         max_z / M_PI / (fov[1] / 2.0),
1223                                         max_z / M_PI / (fov[2] / 2.0),
1224                                         max_z / M_PI / (fov[3] / 2.0));
1225                                 glUniform1f(glGetUniformLocation(frag_shader, "radius"),
1226                                         config.radius);
1227                                 break;
1228                 }
1229
1230
1231                 get_output()->init_screen();
1232                 get_output()->bind_texture(0);
1233                 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
1234                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
1235                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
1236                 get_output()->draw_texture();
1237                 glUseProgram(0);
1238
1239
1240                 if(config.draw_guides)
1241                 {
1242                         int w = get_output()->get_w();
1243                         int h = get_output()->get_h();
1244                         int center_x = (int)(config.center_x * w / 100);
1245                         int center_y = (int)(config.center_y * h / 100);
1246
1247                         glDisable(GL_TEXTURE_2D);
1248                         glColor4f(0.0, 0.0, 0.0, 1.0);
1249                         glBegin(GL_LINES);
1250                         glVertex3f(center_x, -h + center_y - CENTER_H / 2, 0.0);
1251                         glVertex3f(center_x, -h + center_y + CENTER_H / 2, 0.0);
1252                         glEnd();
1253                         glBegin(GL_LINES);
1254                         glVertex3f(center_x - CENTER_W / 2, -h + center_y, 0.0);
1255                         glVertex3f(center_x + CENTER_W / 2, -h + center_y, 0.0);
1256                         glEnd();
1257                         glColor4f(1.0, 1.0, 1.0, 1.0);
1258                         glBegin(GL_LINES);
1259                         glVertex3f(center_x - 1, -h + center_y - CENTER_H / 2 - 1, 0.0);
1260                         glVertex3f(center_x - 1, -h + center_y + CENTER_H / 2 - 1, 0.0);
1261                         glEnd();
1262                         glBegin(GL_LINES);
1263                         glVertex3f(center_x - CENTER_W / 2 - 1, -h + center_y - 1, 0.0);
1264                         glVertex3f(center_x + CENTER_W / 2 - 1, -h + center_y - 1, 0.0);
1265                         glEnd();
1266                 }
1267                 get_output()->set_opengl_state(VFrame::SCREEN);
1268         }
1269
1270 #endif
1271         return 0;
1272 }
1273
1274
1275
1276
1277
1278
1279
1280
1281 LensPackage::LensPackage()
1282  : LoadPackage() {}
1283
1284
1285
1286
1287
1288 LensUnit::LensUnit(LensEngine *engine, LensMain *plugin)
1289  : LoadClient(engine)
1290 {
1291         this->plugin = plugin;
1292 }
1293
1294 LensUnit::~LensUnit()
1295 {
1296 }
1297
1298 void LensUnit::process_shrink(LensPackage *pkg)
1299 {
1300
1301         float *fov = plugin->config.fov;
1302         float aspect = plugin->config.aspect;
1303         int row1 = pkg->row1;
1304         int row2 = pkg->row2;
1305         int width = plugin->get_input()->get_w();
1306         int height = plugin->get_input()->get_h();
1307         double x_factor = aspect;
1308         double y_factor = 1.0 / aspect;
1309         if(x_factor < 1) x_factor = 1;
1310         if(y_factor < 1) y_factor = 1;
1311         double dim = MAX(width, height) * plugin->config.radius;
1312         double max_z[FOV_CHANNELS];
1313         double center_x = width * plugin->config.center_x / 100.0;
1314         double center_y = height * plugin->config.center_y / 100.0;
1315         double r[FOV_CHANNELS];
1316
1317 //      max_z[0] = sqrt(SQR(width) + SQR(height)) / 2 / fov[0];
1318 //      max_z[1] = sqrt(SQR(width) + SQR(height)) / 2 / fov[1];
1319 //      max_z[2] = sqrt(SQR(width) + SQR(height)) / 2 / fov[2];
1320 //      max_z[3] = sqrt(SQR(width) + SQR(height)) / 2 / fov[3];
1321         max_z[0] = dim * sqrt(2.0) / 2 / fov[0];
1322         max_z[1] = dim * sqrt(2.0) / 2 / fov[1];
1323         max_z[2] = dim * sqrt(2.0) / 2 / fov[2];
1324         max_z[3] = dim * sqrt(2.0) / 2 / fov[3];
1325         r[0] = max_z[0] * 2 / M_PI;
1326         r[1] = max_z[1] * 2 / M_PI;
1327         r[2] = max_z[2] * 2 / M_PI;
1328         r[3] = max_z[3] * 2 / M_PI;
1329
1330 #define DO_LENS_SHRINK(type, components, chroma) \
1331 { \
1332         type **in_rows = (type**)plugin->get_temp()->get_rows(); \
1333         type **out_rows = (type**)plugin->get_input()->get_rows(); \
1334         type black[4] = { 0, chroma, chroma, 0 }; \
1335  \
1336         for(int y = row1; y < row2; y++) \
1337         { \
1338                 type *out_row = out_rows[y]; \
1339                 type *in_row = in_rows[y]; \
1340                 double y_diff = y - center_y; \
1341  \
1342                 for(int x = 0; x < width; x++) \
1343                 { \
1344                         double x_diff = x - center_x; \
1345                         if(!x_diff && !y_diff) \
1346                         { \
1347                                 type *in_pixel = in_row + x * components; \
1348                                 for(int c = 0; c < components; c++) \
1349                                 { \
1350                                         *out_row++ = *in_pixel++; \
1351                                 } \
1352                                 continue; \
1353                         } \
1354  \
1355                         double z = sqrt(x_diff * x_diff + y_diff * y_diff); \
1356                         double a2 = atan(y_diff / x_diff); \
1357                         if(x_diff < 0.0) a2 += M_PI; \
1358  \
1359                         for(int i = 0; i < components; i++) \
1360                         { \
1361                                 if(z > r[i]) \
1362                                 { \
1363                                         *out_row++ = black[i]; \
1364                                 } \
1365                                 else \
1366                                 { \
1367                                         double a1 = asin(z / r[i]); \
1368                                         double z_in = a1 * max_z[i] * 2 / M_PI; \
1369  \
1370                                         float x_in = z_in * cos(a2) * x_factor + center_x; \
1371                                         float y_in = z_in * sin(a2) * y_factor + center_y; \
1372  \
1373                                         if(x_in < 0.0 || x_in >= width - 1 || \
1374                                                 y_in < 0.0 || y_in >= height - 1) \
1375                                         { \
1376                                                 *out_row++ = black[i]; \
1377                                         } \
1378                                         else \
1379                                         { \
1380                                                 float y1_fraction = y_in - floor(y_in); \
1381                                                 float y2_fraction = 1.0 - y1_fraction; \
1382                                                 float x1_fraction = x_in - floor(x_in); \
1383                                                 float x2_fraction = 1.0 - x1_fraction; \
1384                                                 type *in_pixel1 = in_rows[(int)y_in] + (int)x_in * components; \
1385                                                 type *in_pixel2 = in_rows[(int)y_in + 1] + (int)x_in * components; \
1386                                                 *out_row++ = (type)(in_pixel1[i] * x2_fraction * y2_fraction + \
1387                                                                         in_pixel2[i] * x2_fraction * y1_fraction + \
1388                                                                         in_pixel1[i + components] * x1_fraction * y2_fraction + \
1389                                                                         in_pixel2[i + components] * x1_fraction * y1_fraction); \
1390                                         } \
1391                                 } \
1392                         } \
1393                 } \
1394         } \
1395  \
1396         type *out_pixel = out_rows[(int)center_y] + (int)center_x * components; \
1397         type *in_pixel = in_rows[(int)center_y] + (int)center_x * components; \
1398         for(int c = 0; c < components; c++) \
1399         { \
1400                 *out_pixel++ = *in_pixel++; \
1401         } \
1402 }
1403
1404
1405                 switch(plugin->get_input()->get_color_model())
1406                 {
1407                         case BC_RGB888:
1408                                 DO_LENS_SHRINK(unsigned char, 3, 0x0);
1409                                 break;
1410                         case BC_RGBA8888:
1411                                 DO_LENS_SHRINK(unsigned char, 4, 0x0);
1412                                 break;
1413                         case BC_RGB_FLOAT:
1414                                 DO_LENS_SHRINK(float, 3, 0.0);
1415                                 break;
1416                         case BC_RGBA_FLOAT:
1417                                 DO_LENS_SHRINK(float, 4, 0.0);
1418                                 break;
1419                         case BC_YUV888:
1420                                 DO_LENS_SHRINK(unsigned char, 3, 0x80);
1421                                 break;
1422                 case BC_YUVA8888:
1423                                 DO_LENS_SHRINK(unsigned char, 4, 0x80);
1424                                 break;
1425                 }
1426 }
1427
1428 void LensUnit::process_stretch(LensPackage *pkg)
1429 {
1430         float *fov = plugin->config.fov;
1431         float aspect = plugin->config.aspect;
1432         int row1 = pkg->row1;
1433         int row2 = pkg->row2;
1434         double x_factor = aspect;
1435         double y_factor = 1.0 / aspect;
1436         if(x_factor < 1) x_factor = 1;
1437         if(y_factor < 1) y_factor = 1;
1438         int width = plugin->get_input()->get_w();
1439         int height = plugin->get_input()->get_h();
1440         double dim = MAX(width, height) * plugin->config.radius;
1441         double max_z = dim * sqrt(2.0) / 2;
1442         double center_x = width * plugin->config.center_x / 100.0;
1443         double center_y = height * plugin->config.center_y / 100.0;
1444         double r[FOV_CHANNELS];
1445
1446         r[0] = max_z / M_PI / (fov[0] / 2.0);
1447         r[1] = max_z / M_PI / (fov[1] / 2.0);
1448         r[2] = max_z / M_PI / (fov[2] / 2.0);
1449         r[3] = max_z / M_PI / (fov[3] / 2.0);
1450
1451 #define DO_LENS_STRETCH(type, components, chroma) \
1452 { \
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  \
1457         for(int y = row1; y < row2; y++) \
1458         { \
1459                 type *out_row = out_rows[y]; \
1460                 double y_diff = y - center_y; \
1461  \
1462                 for(int x = 0; x < width; x++) \
1463                 { \
1464                         double x_diff = (x - center_x); \
1465                         double z = sqrt(x_diff * x_diff + \
1466                                 y_diff * y_diff); \
1467                         double a2; \
1468                         if(x == center_x) \
1469                         { \
1470                                 if(y < center_y) \
1471                                         a2 = 3 * M_PI / 2; \
1472                                 else \
1473                                         a2 = M_PI / 2; \
1474                         } \
1475                         else \
1476                         { \
1477                                 a2 = atan(y_diff / x_diff); \
1478                         } \
1479                         if(x_diff < 0.0) a2 += M_PI; \
1480  \
1481                         for(int i = 0; i < components; i++) \
1482                         { \
1483                                 double a1 = (z / (M_PI * r[i] / 2)) * (M_PI / 2); \
1484                                 double z_in = r[i] * sin(a1); \
1485  \
1486                                 double x_in = z_in * cos(a2) * x_factor + center_x; \
1487                                 double y_in = z_in * sin(a2) * y_factor + center_y; \
1488  \
1489                                 if(x_in < 0.0 || x_in >= width - 1 || \
1490                                         y_in < 0.0 || y_in >= height - 1) \
1491                                 { \
1492                                         *out_row++ = black[i]; \
1493                                 } \
1494                                 else \
1495                                 { \
1496                                         float y1_fraction = y_in - floor(y_in); \
1497                                         float y2_fraction = 1.0 - y1_fraction; \
1498                                         float x1_fraction = x_in - floor(x_in); \
1499                                         float x2_fraction = 1.0 - x1_fraction; \
1500                                         type *in_pixel1 = in_rows[(int)y_in] + (int)x_in * components; \
1501                                         type *in_pixel2 = in_rows[(int)y_in + 1] + (int)x_in * components; \
1502                                         *out_row++ = (type)(in_pixel1[i] * x2_fraction * y2_fraction + \
1503                                                                 in_pixel2[i] * x2_fraction * y1_fraction + \
1504                                                                 in_pixel1[i + components] * x1_fraction * y2_fraction + \
1505                                                                 in_pixel2[i + components] * x1_fraction * y1_fraction); \
1506                                 } \
1507                         } \
1508                 } \
1509         } \
1510  \
1511         type *out_pixel = out_rows[(int)center_y] + (int)center_x * components; \
1512         type *in_pixel = in_rows[(int)center_y] + (int)center_x * components; \
1513         for(int c = 0; c < components; c++) \
1514         { \
1515                 *out_pixel++ = *in_pixel++; \
1516         } \
1517 }
1518
1519
1520                 switch(plugin->get_input()->get_color_model())
1521                 {
1522                         case BC_RGB888:
1523                                 DO_LENS_STRETCH(unsigned char, 3, 0x0);
1524                                 break;
1525                         case BC_RGBA8888:
1526                                 DO_LENS_STRETCH(unsigned char, 4, 0x0);
1527                                 break;
1528                         case BC_RGB_FLOAT:
1529                                 DO_LENS_STRETCH(float, 3, 0.0);
1530                                 break;
1531                         case BC_RGBA_FLOAT:
1532                                 DO_LENS_STRETCH(float, 4, 0.0);
1533                                 break;
1534                         case BC_YUV888:
1535                                 DO_LENS_STRETCH(unsigned char, 3, 0x80);
1536                                 break;
1537                         case BC_YUVA8888:
1538                                 DO_LENS_STRETCH(unsigned char, 4, 0x80);
1539                                 break;
1540                 }
1541 }
1542
1543 void LensUnit::process_rectilinear_stretch(LensPackage *pkg)
1544 {
1545         float *fov = plugin->config.fov;
1546         float aspect = plugin->config.aspect;
1547         int row1 = pkg->row1;
1548         int row2 = pkg->row2;
1549         double x_factor = aspect;
1550         double y_factor = 1.0 / aspect;
1551         if(x_factor < 1) x_factor = 1;
1552         if(y_factor < 1) y_factor = 1;
1553         int width = plugin->get_input()->get_w();
1554         int height = plugin->get_input()->get_h();
1555 //      double dim = MAX(width, height) * plugin->config.radius;
1556 //      double max_z = dim * sqrt(2.0) / 2;
1557         double max_z = sqrt(SQR(width) + SQR(height)) / 2;
1558         double center_x = width * plugin->config.center_x / 100.0;
1559         double center_y = height * plugin->config.center_y / 100.0;
1560         double r[FOV_CHANNELS];
1561
1562         r[0] = max_z / M_PI / (fov[0] / 2.0);
1563         r[1] = max_z / M_PI / (fov[1] / 2.0);
1564         r[2] = max_z / M_PI / (fov[2] / 2.0);
1565         r[3] = max_z / M_PI / (fov[3] / 2.0);
1566
1567 #define DO_LENS_RECTILINEAR_STRETCH(type, components, chroma) \
1568 { \
1569         type **in_rows = (type**)plugin->get_temp()->get_rows(); \
1570         type **out_rows = (type**)plugin->get_input()->get_rows(); \
1571         type black[4] = { 0, chroma, chroma, 0 }; \
1572  \
1573         for(int y = row1; y < row2; y++) \
1574         { \
1575                 type *out_row = out_rows[y]; \
1576                 double y_diff = y - center_y; \
1577  \
1578                 for(int x = 0; x < width; x++) \
1579                 { \
1580                         double x_diff = (x - center_x); \
1581 /* Compute magnitude */ \
1582                         double z = sqrt(x_diff * x_diff + \
1583                                 y_diff * y_diff); \
1584 /* Compute angle */ \
1585                         double angle; \
1586                         if(x == center_x) \
1587                         { \
1588                                 if(y < center_y) \
1589                                         angle = 3 * M_PI / 2; \
1590                                 else \
1591                                         angle = M_PI / 2; \
1592                         } \
1593                         else \
1594                         { \
1595                                 angle = atan(y_diff / x_diff); \
1596                         } \
1597                         if(x_diff < 0.0) angle += M_PI; \
1598  \
1599                         for(int i = 0; i < components; i++) \
1600                         { \
1601 /* Compute new radius */ \
1602                                 double radius1 = (z / r[i]) * 2 * plugin->config.radius; \
1603                                 double z_in = r[i] * atan(radius1) / (M_PI / 2); \
1604  \
1605                                 double x_in = z_in * cos(angle) * x_factor + center_x; \
1606                                 double y_in = z_in * sin(angle) * y_factor + center_y; \
1607  \
1608                                 if(x_in < 0.0 || x_in >= width - 1 || \
1609                                         y_in < 0.0 || y_in >= height - 1) \
1610                                 { \
1611                                         *out_row++ = black[i]; \
1612                                 } \
1613                                 else \
1614                                 { \
1615                                         float y1_fraction = y_in - floor(y_in); \
1616                                         float y2_fraction = 1.0 - y1_fraction; \
1617                                         float x1_fraction = x_in - floor(x_in); \
1618                                         float x2_fraction = 1.0 - x1_fraction; \
1619                                         type *in_pixel1 = in_rows[(int)y_in] + (int)x_in * components; \
1620                                         type *in_pixel2 = in_rows[(int)y_in + 1] + (int)x_in * components; \
1621                                         *out_row++ = (type)(in_pixel1[i] * x2_fraction * y2_fraction + \
1622                                                                 in_pixel2[i] * x2_fraction * y1_fraction + \
1623                                                                 in_pixel1[i + components] * x1_fraction * y2_fraction + \
1624                                                                 in_pixel2[i + components] * x1_fraction * y1_fraction); \
1625                                 } \
1626                         } \
1627                 } \
1628         } \
1629  \
1630         type *out_pixel = out_rows[(int)center_y] + (int)center_x * components; \
1631         type *in_pixel = in_rows[(int)center_y] + (int)center_x * components; \
1632         for(int c = 0; c < components; c++) \
1633         { \
1634                 *out_pixel++ = *in_pixel++; \
1635         } \
1636 }
1637
1638
1639                 switch(plugin->get_input()->get_color_model())
1640                 {
1641                         case BC_RGB888:
1642                                 DO_LENS_RECTILINEAR_STRETCH(unsigned char, 3, 0x0);
1643                                 break;
1644                         case BC_RGBA8888:
1645                                 DO_LENS_RECTILINEAR_STRETCH(unsigned char, 4, 0x0);
1646                                 break;
1647                         case BC_RGB_FLOAT:
1648                                 DO_LENS_RECTILINEAR_STRETCH(float, 3, 0.0);
1649                                 break;
1650                         case BC_RGBA_FLOAT:
1651                                 DO_LENS_RECTILINEAR_STRETCH(float, 4, 0.0);
1652                                 break;
1653                         case BC_YUV888:
1654                                 DO_LENS_RECTILINEAR_STRETCH(unsigned char, 3, 0x80);
1655                                 break;
1656                         case BC_YUVA8888:
1657                                 DO_LENS_RECTILINEAR_STRETCH(unsigned char, 4, 0x80);
1658                                 break;
1659                 }
1660 }
1661
1662 void LensUnit::process_rectilinear_shrink(LensPackage *pkg)
1663 {
1664         float *fov = plugin->config.fov;
1665         float aspect = plugin->config.aspect;
1666         int row1 = pkg->row1;
1667         int row2 = pkg->row2;
1668         double x_factor = aspect;
1669         double y_factor = 1.0 / aspect;
1670         if(x_factor < 1) x_factor = 1;
1671         if(y_factor < 1) y_factor = 1;
1672         int width = plugin->get_input()->get_w();
1673         int height = plugin->get_input()->get_h();
1674         double max_z = MAX(width, height) / 2 * plugin->config.radius;
1675         double center_x = width * plugin->config.center_x / 100.0;
1676         double center_y = height * plugin->config.center_y / 100.0;
1677         double r[FOV_CHANNELS];
1678
1679         r[0] = max_z / fov[0];
1680         r[1] = max_z / fov[1];
1681         r[2] = max_z / fov[2];
1682         r[3] = max_z / fov[3];
1683
1684 #define DO_LENS_RECTILINEAR_SHRINK(type, components, chroma) \
1685 { \
1686         type **in_rows = (type**)plugin->get_temp()->get_rows(); \
1687         type **out_rows = (type**)plugin->get_input()->get_rows(); \
1688         type black[4] = { 0, chroma, chroma, 0 }; \
1689  \
1690         for(int y = row1; y < row2; y++) \
1691         { \
1692                 type *out_row = out_rows[y]; \
1693                 double y_diff = y - center_y; \
1694  \
1695                 for(int x = 0; x < width; x++) \
1696                 { \
1697                         double x_diff = (x - center_x); \
1698 /* Compute magnitude */ \
1699                         double z = sqrt(x_diff * x_diff + \
1700                                 y_diff * y_diff); \
1701 /* Compute angle */ \
1702                         double angle; \
1703                         if(x == center_x) \
1704                         { \
1705                                 if(y < center_y) \
1706                                         angle = 3 * M_PI / 2; \
1707                                 else \
1708                                         angle = M_PI / 2; \
1709                         } \
1710                         else \
1711                         { \
1712                                 angle = atan(y_diff / x_diff); \
1713                         } \
1714                         if(x_diff < 0.0) angle += M_PI; \
1715  \
1716                         for(int i = 0; i < components; i++) \
1717                         { \
1718 /* Compute new radius */ \
1719                                 double radius1 = z / r[i]; \
1720                                 double z_in = r[i] * tan(radius1) / (M_PI / 2); \
1721  \
1722                                 double x_in = z_in * cos(angle) * x_factor + center_x; \
1723                                 double y_in = z_in * sin(angle) * y_factor + center_y; \
1724  \
1725                                 if(x_in < 0.0 || x_in >= width - 1 || \
1726                                         y_in < 0.0 || y_in >= height - 1) \
1727                                 { \
1728                                         *out_row++ = black[i]; \
1729                                 } \
1730                                 else \
1731                                 { \
1732                                         float y1_fraction = y_in - floor(y_in); \
1733                                         float y2_fraction = 1.0 - y1_fraction; \
1734                                         float x1_fraction = x_in - floor(x_in); \
1735                                         float x2_fraction = 1.0 - x1_fraction; \
1736                                         type *in_pixel1 = in_rows[(int)y_in] + (int)x_in * components; \
1737                                         type *in_pixel2 = in_rows[(int)y_in + 1] + (int)x_in * components; \
1738                                         *out_row++ = (type)(in_pixel1[i] * x2_fraction * y2_fraction + \
1739                                                                 in_pixel2[i] * x2_fraction * y1_fraction + \
1740                                                                 in_pixel1[i + components] * x1_fraction * y2_fraction + \
1741                                                                 in_pixel2[i + components] * x1_fraction * y1_fraction); \
1742                                 } \
1743                         } \
1744                 } \
1745         } \
1746  \
1747         type *out_pixel = out_rows[(int)center_y] + (int)center_x * components; \
1748         type *in_pixel = in_rows[(int)center_y] + (int)center_x * components; \
1749         for(int c = 0; c < components; c++) \
1750         { \
1751                 *out_pixel++ = *in_pixel++; \
1752         } \
1753 }
1754
1755
1756                 switch(plugin->get_input()->get_color_model())
1757                 {
1758                         case BC_RGB888:
1759                                 DO_LENS_RECTILINEAR_SHRINK(unsigned char, 3, 0x0);
1760                                 break;
1761                         case BC_RGBA8888:
1762                                 DO_LENS_RECTILINEAR_SHRINK(unsigned char, 4, 0x0);
1763                                 break;
1764                         case BC_RGB_FLOAT:
1765                                 DO_LENS_RECTILINEAR_SHRINK(float, 3, 0.0);
1766                                 break;
1767                         case BC_RGBA_FLOAT:
1768                                 DO_LENS_RECTILINEAR_SHRINK(float, 4, 0.0);
1769                                 break;
1770                         case BC_YUV888:
1771                                 DO_LENS_RECTILINEAR_SHRINK(unsigned char, 3, 0x80);
1772                                 break;
1773                         case BC_YUVA8888:
1774                                 DO_LENS_RECTILINEAR_SHRINK(unsigned char, 4, 0x80);
1775                                 break;
1776                 }
1777 }
1778
1779 void LensUnit::process_package(LoadPackage *package)
1780 {
1781         LensPackage *pkg = (LensPackage*)package;
1782
1783         switch(plugin->config.mode)
1784         {
1785                 case LensConfig::SHRINK:
1786                         process_shrink(pkg);
1787                         break;
1788                 case LensConfig::STRETCH:
1789                         process_stretch(pkg);
1790                         break;
1791                 case LensConfig::RECTILINEAR_STRETCH:
1792                         process_rectilinear_stretch(pkg);
1793                         break;
1794                 case LensConfig::RECTILINEAR_SHRINK     :
1795                         process_rectilinear_shrink(pkg);
1796                         break;
1797         }
1798 }
1799
1800
1801
1802
1803
1804 LensEngine::LensEngine(LensMain *plugin)
1805  : LoadServer(plugin->PluginClient::smp + 1, plugin->PluginClient::smp + 1)
1806 // : LoadServer(1, 1)
1807 {
1808         this->plugin = plugin;
1809 }
1810
1811 LensEngine::~LensEngine()
1812 {
1813 }
1814
1815 void LensEngine::init_packages()
1816 {
1817         for(int i = 0; i < LoadServer::get_total_packages(); i++)
1818         {
1819                 LensPackage *package = (LensPackage*)LoadServer::get_package(i);
1820                 package->row1 = plugin->get_input()->get_h() * i / LoadServer::get_total_packages();
1821                 package->row2 = plugin->get_input()->get_h() * (i + 1) / LoadServer::get_total_packages();
1822         }
1823 }
1824
1825 LoadClient* LensEngine::new_client()
1826 {
1827         return new LensUnit(this, plugin);
1828 }
1829
1830 LoadPackage* LensEngine::new_package()
1831 {
1832         return new LensPackage;
1833 }
1834
1835