24916156ada4286bdd3863db26409fa607d72a96
[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 //              BC_MenuItem *item = get_item(0);
362 //              remove_item(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, "%slenspresets.rc", BCASTDIR);
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