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