4 * Copyright (C) 2017 Adam Williams <broadcast at earthling dot net>
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.
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.
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
23 #include "bcdisplayinfo.h"
25 #include "bcsignals.h"
36 // largely based on equations from http://paulbourke.net/dome/fish2/
40 REGISTER_PLUGIN(Fuse360Main)
45 Fuse360Config::Fuse360Config()
58 mode = Fuse360Config::DO_NOTHING;
61 int Fuse360Config::equivalent(Fuse360Config &that)
63 if(EQUIV(fov, that.fov) &&
64 EQUIV(radius_x, that.radius_x) &&
65 EQUIV(radius_y, that.radius_y) &&
66 EQUIV(feather, that.feather) &&
67 EQUIV(center_x, that.center_x) &&
68 EQUIV(center_y, that.center_y) &&
69 EQUIV(distance_x, that.distance_x) &&
70 EQUIV(distance_y, that.distance_y) &&
71 EQUIV(translate_x, that.translate_x) &&
72 EQUIV(rotation, that.rotation) &&
74 draw_guides == that.draw_guides)
84 void Fuse360Config::copy_from(Fuse360Config &that)
89 void Fuse360Config::interpolate(Fuse360Config &prev,
93 int64_t current_frame)
95 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
96 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
98 fov = prev.fov * prev_scale + next.fov * next_scale;
99 radius_x = prev.radius_x * prev_scale + next.radius_x * next_scale;
100 radius_y = prev.radius_y * prev_scale + next.radius_y * next_scale;
101 feather = prev.feather * prev_scale + next.feather * next_scale;
102 center_x = prev.center_x * prev_scale + next.center_x * next_scale;
103 center_y = prev.center_y * prev_scale + next.center_y * next_scale;
104 distance_x = prev.distance_x * prev_scale + next.distance_x * next_scale;
105 distance_y = prev.distance_y * prev_scale + next.distance_y * next_scale;
106 rotation = prev.rotation * prev_scale + next.rotation * next_scale;
107 translate_x = prev.translate_x * prev_scale + next.translate_x * next_scale;
108 draw_guides = prev.draw_guides;
114 void Fuse360Config::boundaries()
116 CLAMP(fov, 0.0, 1.0);
117 CLAMP(radius_x, 0.3, 1.0);
118 CLAMP(radius_y, 0.3, 1.0);
119 CLAMP(feather, 0, 50);
120 CLAMP(center_x, 0.0, 99.0);
121 CLAMP(center_y, 0.0, 99.0);
122 CLAMP(distance_x, 0.0, 100.0);
123 CLAMP(distance_y, -50.0, 50.0);
124 CLAMP(translate_x, -100, 100);
125 CLAMP(rotation, -180, 180);
131 Fuse360Slider::Fuse360Slider(Fuse360Main *client,
139 : BC_FSlider(x, y, 0, 200, 200, min, max, *output)
142 this->client = client;
143 this->output = output;
148 int Fuse360Slider::handle_event()
150 float prev_output = *output;
151 *output = get_value();
152 text->update(*output);
155 client->send_configure_change();
161 Fuse360Text::Fuse360Text(Fuse360Main *client,
163 Fuse360Slider *slider,
167 : BC_TextBox(x, y, 100, 1, *output)
170 this->client = client;
171 this->output = output;
172 this->slider = slider;
175 int Fuse360Text::handle_event()
177 float prev_output = *output;
178 *output = atof(get_text());
179 slider->update(*output);
182 client->send_configure_change();
188 Fuse360Toggle::Fuse360Toggle(Fuse360Main *client,
193 : BC_CheckBox(x, y, *output, text)
195 this->output = output;
196 this->client = client;
199 int Fuse360Toggle::handle_event()
201 *output = get_value();
202 client->send_configure_change();
215 Fuse360Mode::Fuse360Mode(Fuse360Main *plugin,
225 this->plugin = plugin;
229 int Fuse360Mode::handle_event()
231 plugin->config.mode = from_text(get_text());
232 plugin->send_configure_change();
237 void Fuse360Mode::create_objects()
239 add_item(new BC_MenuItem(to_text(Fuse360Config::DO_NOTHING)));
240 add_item(new BC_MenuItem(to_text(Fuse360Config::STRETCHXY)));
241 add_item(new BC_MenuItem(to_text(Fuse360Config::STANDARD)));
242 add_item(new BC_MenuItem(to_text(Fuse360Config::BLEND)));
243 update(plugin->config.mode);
246 void Fuse360Mode::update(int mode)
248 char string[BCTEXTLEN];
249 sprintf(string, "%s", to_text(mode));
253 int Fuse360Mode::calculate_w(Fuse360GUI *gui)
256 result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(Fuse360Config::STRETCHXY)));
257 result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(Fuse360Config::STANDARD)));
258 result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(Fuse360Config::BLEND)));
259 result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(Fuse360Config::DO_NOTHING)));
263 int Fuse360Mode::from_text(char *text)
265 for(int i = 0; i < 4; i++)
267 if(!strcmp(text, to_text(i)))
273 return Fuse360Config::STRETCHXY;
276 const char* Fuse360Mode::to_text(int mode)
280 case Fuse360Config::DO_NOTHING:
283 case Fuse360Config::STRETCHXY:
286 case Fuse360Config::STANDARD:
287 return "Equirectangular";
308 Fuse360GUI::Fuse360GUI(Fuse360Main *client)
309 : PluginClientWindow(client,
316 this->client = client;
319 Fuse360GUI::~Fuse360GUI()
324 void Fuse360GUI::create_objects()
331 Fuse360Toggle *toggle;
333 // add_tool(title = new BC_Title(x, y, _("Field of View:")));
334 // y += title->get_h() + 5;
335 // add_tool(fov_slider = new Fuse360Slider(client,
338 // &client->config.fov,
345 // x1 = x + fov_slider->get_w() + margin;
346 // add_tool(fov_text = new Fuse360Text(client,
349 // &client->config.fov,
352 // fov_slider->text = fov_text;
353 // y += fov_text->get_h() + margin;
358 add_tool(title = new BC_Title(x, y, _("Eye Radius X:")));
359 y += title->get_h() + 5;
360 add_tool(radiusx_slider = new Fuse360Slider(client,
363 &client->config.radius_x,
368 x1 = x + radiusx_slider->get_w() + margin;
369 add_tool(radiusx_text = new Fuse360Text(client,
372 &client->config.radius_x,
375 radiusx_slider->text = radiusx_text;
376 y += radiusx_text->get_h() + 5;
379 add_tool(title = new BC_Title(x, y, _("Eye Radius Y:")));
380 y += title->get_h() + margin;
381 add_tool(radiusy_slider = new Fuse360Slider(client,
384 &client->config.radius_y,
389 x1 = x + radiusy_slider->get_w() + margin;
390 add_tool(radiusy_text = new Fuse360Text(client,
393 &client->config.radius_y,
396 radiusy_slider->text = radiusy_text;
397 y += radiusy_text->get_h() + margin;
400 // add_tool(title = new BC_Title(x, y, _("Center X:")));
401 // y += title->get_h() + 5;
402 // add_tool(centerx_slider = new Fuse360Slider(client,
405 // &client->config.center_x,
410 // x1 = x + centerx_slider->get_w() + margin;
411 // add_tool(centerx_text = new Fuse360Text(client,
414 // &client->config.center_x,
417 // centerx_slider->text = centerx_text;
418 // centerx_slider->set_precision(0.1);
419 // y += centerx_text->get_h() + margin;
422 // add_tool(title = new BC_Title(x, y, _("Center Y:")));
423 // y += title->get_h() + 5;
424 // add_tool(centery_slider = new Fuse360Slider(client,
427 // &client->config.center_y,
432 // x1 = x + centery_slider->get_w() + margin;
433 // add_tool(centery_text = new Fuse360Text(client,
436 // &client->config.center_y,
439 // centery_slider->text = centery_text;
440 // centery_slider->set_precision(0.1);
441 // y += centery_text->get_h() + margin;
446 add_tool(title = new BC_Title(x, y, _("X Eye Spacing:")));
447 y += title->get_h() + 5;
448 add_tool(distancex_slider = new Fuse360Slider(client,
451 &client->config.distance_x,
456 x1 = x + distancex_slider->get_w() + margin;
457 add_tool(distancex_text = new Fuse360Text(client,
460 &client->config.distance_x,
463 distancex_slider->text = distancex_text;
464 distancex_slider->set_precision(0.1);
465 y += distancex_text->get_h() + margin;
473 add_tool(title = new BC_Title(x, y, _("Y Eye Spacing:")));
474 y += title->get_h() + 5;
475 add_tool(distancey_slider = new Fuse360Slider(client,
478 &client->config.distance_y,
483 x1 = x + distancey_slider->get_w() + margin;
484 add_tool(distancey_text = new Fuse360Text(client,
487 &client->config.distance_y,
490 distancey_slider->text = distancey_text;
491 distancey_slider->set_precision(0.1);
492 y += distancey_text->get_h() + margin;
499 add_tool(title = new BC_Title(x, y, _("X Translation:")));
500 y += title->get_h() + 5;
501 add_tool(translatex_slider = new Fuse360Slider(client,
504 &client->config.translate_x,
509 x1 = x + translatex_slider->get_w() + margin;
510 add_tool(translatex_text = new Fuse360Text(client,
513 &client->config.translate_x,
516 translatex_slider->text = translatex_text;
517 translatex_slider->set_precision(0.1);
518 y += translatex_text->get_h() + margin;
525 add_tool(title = new BC_Title(x, y, _("Feather:")));
526 y += title->get_h() + 5;
527 add_tool(feather_slider = new Fuse360Slider(client,
530 &client->config.feather,
535 x1 = x + feather_slider->get_w() + margin;
536 add_tool(feather_text = new Fuse360Text(client,
539 &client->config.feather,
542 feather_slider->text = feather_text;
543 feather_slider->set_precision(1);
544 y += feather_text->get_h() + margin;
551 add_tool(title = new BC_Title(x, y, _("Rotation:")));
552 y += title->get_h() + 5;
553 add_tool(rotation_slider = new Fuse360Slider(client,
556 &client->config.rotation,
561 x1 = x + rotation_slider->get_w() + margin;
562 add_tool(rotation_text = new Fuse360Text(client,
565 &client->config.rotation,
568 rotation_slider->text = rotation_text;
569 rotation_slider->set_precision(0.1);
570 y += rotation_text->get_h() + margin;
578 //printf("Fuse360GUI::create_objects %d %f\n", __LINE__, client->config.distance);
581 add_tool(draw_guides = new Fuse360Toggle(client,
582 &client->config.draw_guides,
586 y += draw_guides->get_h() + margin;
589 add_tool(title = new BC_Title(x, y, _("Mode:")));
590 add_tool(mode = new Fuse360Mode(client,
592 x + title->get_w() + margin,
594 mode->create_objects();
595 y += mode->get_h() + margin;
609 Fuse360Main::Fuse360Main(PluginServer *server)
610 : PluginVClient(server)
616 Fuse360Main::~Fuse360Main()
622 NEW_WINDOW_MACRO(Fuse360Main, Fuse360GUI)
623 LOAD_CONFIGURATION_MACRO(Fuse360Main, Fuse360Config)
624 int Fuse360Main::is_realtime() { return 1; }
625 const char* Fuse360Main::plugin_title() { return "360 Fuser"; }
627 void Fuse360Main::update_gui()
631 if(load_configuration())
633 ((Fuse360GUI*)thread->window)->lock_window("Fuse360Main::update_gui");
634 // ((Fuse360GUI*)thread->window)->fov_slider->update(config.fov);
635 // ((Fuse360GUI*)thread->window)->fov_text->update(config.fov);
636 ((Fuse360GUI*)thread->window)->radiusx_slider->update(config.radius_x);
637 ((Fuse360GUI*)thread->window)->radiusx_text->update(config.radius_x);
638 ((Fuse360GUI*)thread->window)->radiusy_slider->update(config.radius_y);
639 ((Fuse360GUI*)thread->window)->radiusy_text->update(config.radius_y);
640 // ((Fuse360GUI*)thread->window)->centerx_slider->update(config.center_x);
641 // ((Fuse360GUI*)thread->window)->centerx_text->update(config.center_x);
642 // ((Fuse360GUI*)thread->window)->centery_slider->update(config.center_y);
643 // ((Fuse360GUI*)thread->window)->centery_text->update(config.center_y);
644 ((Fuse360GUI*)thread->window)->distancex_slider->update(config.distance_x);
645 ((Fuse360GUI*)thread->window)->distancex_text->update(config.distance_x);
646 ((Fuse360GUI*)thread->window)->distancey_slider->update(config.distance_y);
647 ((Fuse360GUI*)thread->window)->distancey_text->update(config.distance_y);
648 ((Fuse360GUI*)thread->window)->translatex_slider->update(config.translate_x);
649 ((Fuse360GUI*)thread->window)->translatex_text->update(config.translate_x);
650 ((Fuse360GUI*)thread->window)->feather_slider->update(config.feather);
651 ((Fuse360GUI*)thread->window)->feather_text->update(config.feather);
652 ((Fuse360GUI*)thread->window)->rotation_slider->update(config.rotation);
653 ((Fuse360GUI*)thread->window)->rotation_text->update(config.rotation);
654 ((Fuse360GUI*)thread->window)->mode->update(config.mode);
655 ((Fuse360GUI*)thread->window)->draw_guides->update(config.draw_guides);
656 ((Fuse360GUI*)thread->window)->unlock_window();
662 void Fuse360Main::save_data(KeyFrame *keyframe)
665 char string[BCTEXTLEN];
669 // cause data to be stored directly in text
670 output.set_shared_string(keyframe->get_data(), MESSAGESIZE);
671 output.tag.set_title("360FUSER");
672 output.tag.set_property("FOCAL_LENGTH", config.fov);
673 output.tag.set_property("RADIUS_X", config.radius_x);
674 output.tag.set_property("RADIUS_Y", config.radius_y);
675 output.tag.set_property("FEATHER", config.feather);
676 output.tag.set_property("CENTER_X", config.center_x);
677 output.tag.set_property("CENTER_Y", config.center_y);
678 output.tag.set_property("DISTANCE_X", config.distance_x);
679 output.tag.set_property("DISTANCE_Y", config.distance_y);
680 output.tag.set_property("TRANSLATE_X", config.translate_x);
681 output.tag.set_property("ROTATION", config.rotation);
682 output.tag.set_property("DRAW_GUIDES", config.draw_guides);
683 output.tag.set_property("MODE", config.mode);
685 output.terminate_string();
690 void Fuse360Main::read_data(KeyFrame *keyframe)
693 char string[BCTEXTLEN];
696 input.set_shared_string(keyframe->get_data(), strlen(keyframe->get_data()));
702 result = input.read_tag();
706 if(input.tag.title_is("360FUSER"))
708 config.fov = input.tag.get_property("FOCAL_LENGTH", config.fov);
709 config.radius_x = input.tag.get_property("RADIUS_X", config.radius_x);
710 config.radius_y = input.tag.get_property("RADIUS_Y", config.radius_y);
711 config.feather = input.tag.get_property("FEATHER", config.feather);
712 config.center_x = input.tag.get_property("CENTER_X", config.center_x);
713 config.center_y = input.tag.get_property("CENTER_Y", config.center_y);
714 config.distance_x = input.tag.get_property("DISTANCE_X", config.distance_x);
715 config.distance_y = input.tag.get_property("DISTANCE_Y", config.distance_y);
716 config.translate_x = input.tag.get_property("TRANSLATE_X", config.translate_x);
717 config.rotation = input.tag.get_property("ROTATION", config.rotation);
718 config.draw_guides = input.tag.get_property("DRAW_GUIDES", config.draw_guides);
719 config.mode = input.tag.get_property("MODE", config.mode);
727 int Fuse360Main::process_buffer(VFrame *frame,
728 int64_t start_position,
731 load_configuration();
733 VFrame *input = new_temp(frame->get_w(), frame->get_h(), frame->get_color_model());
744 if(!EQUIV(config.rotation, 0))
746 int center_x = w / 2;
747 int center_y = h / 2;
748 int center_x1 = w / 4;
749 int center_y1 = h / 2;
750 int center_x2 = w * 3 / 4;
751 int center_y2 = h / 2;
755 radius_x = config.radius_x * w / 2;
756 radius_y = config.radius_y * h;
758 if(!affine) affine = new AffineEngine(PluginClient::smp + 1,
759 PluginClient::smp + 1);
760 affine->set_in_pivot(center_x1, center_y1);
761 affine->set_in_viewport(0, 0, center_x, h);
762 affine->set_out_viewport(0, 0, center_x, h);
763 affine->rotate(get_output(),
767 affine->set_in_pivot(center_x2, center_y2);
768 affine->set_in_viewport(center_x, 0, w - center_x, h);
769 affine->set_out_viewport(center_x, 0, w - center_x, h);
770 affine->rotate(get_output(),
774 input->copy_from(get_output());
775 get_output()->clear_frame();
779 if(config.mode == Fuse360Config::DO_NOTHING)
781 get_output()->copy_from(input);
786 if(!engine) engine = new Fuse360Engine(this);
787 engine->process_packages();
792 if(config.draw_guides)
795 get_output()->draw_line(center_x, 0, center_x, h);
798 get_output()->draw_oval(center_x1 - radius_x + distance_x,
799 center_y1 - radius_y + distance_y,
800 center_x1 + radius_x + distance_x,
801 center_y1 + radius_y + distance_y);
802 get_output()->draw_oval(center_x2 - radius_x - distance_x,
803 center_y2 - radius_y - distance_y,
804 center_x2 + radius_x - distance_x,
805 center_y2 + radius_y - distance_y);
808 get_output()->draw_line(feather_x1, 0, feather_x1, h);
809 get_output()->draw_line(feather_x2, 0, feather_x2, h);
818 void Fuse360Main::calculate_extents()
820 w = get_output()->get_w();
821 h = get_output()->get_h();
824 center_x1 = w * 1 / 4;
826 center_x2 = w * 3 / 4;
830 distance_x = (int)((50 - config.distance_x) * w / 100 / 2);
831 distance_y = (int)(config.distance_y * h / 100 / 2);
832 feather = (int)(config.feather * w / 100);
833 feather_x1 = center_x - (int)(config.feather * w / 100 / 2);
834 feather_x2 = center_x + (int)(config.feather * w / 100 / 2);
835 radius_x = config.radius_x * w / 2;
836 radius_y = config.radius_y * h;
837 //printf("Fuse360Main::calculate_extents %d radius_y=%d\n", __LINE__, radius_y);
844 Fuse360Package::Fuse360Package()
851 Fuse360Unit::Fuse360Unit(Fuse360Engine *engine, Fuse360Main *plugin)
854 this->plugin = plugin;
858 Fuse360Unit::~Fuse360Unit()
864 void Fuse360Unit::process_blend(Fuse360Package *pkg)
866 VFrame *input = plugin->get_temp();
867 VFrame *output = plugin->get_output();
869 int row1 = pkg->row1;
870 int row2 = pkg->row2;
871 int width = input->get_w();
872 int height = input->get_h();
874 #define PROCESS_BLEND(type, components, chroma) \
876 type **in_rows = (type**)input->get_rows(); \
877 type **out_rows = (type**)output->get_rows(); \
878 type black[4] = { 0, chroma, chroma, 0 }; \
880 for(int y = row1; y < row2; y++) \
882 type *out_row = out_rows[y]; \
883 type *in_row = in_rows[y]; \
885 for(int x = 0; x < width; x++) \
892 switch(plugin->get_input()->get_color_model())
895 PROCESS_BLEND(unsigned char, 3, 0x0);
898 PROCESS_BLEND(unsigned char, 4, 0x0);
901 PROCESS_BLEND(float, 3, 0.0);
904 PROCESS_BLEND(float, 4, 0.0);
907 PROCESS_BLEND(unsigned char, 3, 0x80);
910 PROCESS_BLEND(unsigned char, 4, 0x80);
917 #define BLEND_PIXEL(type, components) \
918 if(x_in < 0.0 || x_in >= w - 1 || \
919 y_in < 0.0 || y_in >= h - 1) \
921 *out_row++ = black[0]; \
922 *out_row++ = black[1]; \
923 *out_row++ = black[2]; \
924 if(components == 4) *out_row++ = black[3]; \
928 float y1_fraction = y_in - floor(y_in); \
929 float y2_fraction = 1.0 - y1_fraction; \
930 float x1_fraction = x_in - floor(x_in); \
931 float x2_fraction = 1.0 - x1_fraction; \
932 type *in_pixel1 = in_rows[(int)y_in] + (int)x_in * components; \
933 type *in_pixel2 = in_rows[(int)y_in + 1] + (int)x_in * components; \
934 for(int i = 0; i < components; i++) \
936 *out_row++ = (type)(in_pixel1[i] * x2_fraction * y2_fraction + \
937 in_pixel2[i] * x2_fraction * y1_fraction + \
938 in_pixel1[i + components] * x1_fraction * y2_fraction + \
939 in_pixel2[i + components] * x1_fraction * y1_fraction); \
944 // interpolate 2 eyes
945 #define BLEND_PIXEL2(type, components) \
946 type pixel1[components], pixel2[components]; \
948 /* calculate the left eye */ \
949 if(x_in1 < 0.0 || x_in1 >= w - 1 || \
950 y_in1 < 0.0 || y_in1 >= h - 1) \
952 pixel1[0] = black[0]; \
953 pixel1[1] = black[1]; \
954 pixel1[2] = black[2]; \
955 if(components == 4) pixel1[3] = black[3]; \
959 float y1_fraction = y_in1 - floor(y_in1); \
960 float y2_fraction = 1.0 - y1_fraction; \
961 float x1_fraction = x_in1 - floor(x_in1); \
962 float x2_fraction = 1.0 - x1_fraction; \
963 type *in_pixel1 = in_rows[(int)y_in1] + (int)x_in1 * components; \
964 type *in_pixel2 = in_rows[(int)y_in1 + 1] + (int)x_in1 * components; \
965 for(int i = 0; i < components; i++) \
967 pixel1[i] = (type)(in_pixel1[i] * x2_fraction * y2_fraction + \
968 in_pixel2[i] * x2_fraction * y1_fraction + \
969 in_pixel1[i + components] * x1_fraction * y2_fraction + \
970 in_pixel2[i + components] * x1_fraction * y1_fraction); \
975 /* calculate the right eye */ \
976 if(x_in2 < 0.0 || x_in2 >= w - 1 || \
977 y_in2 < 0.0 || y_in2 >= h - 1) \
979 pixel2[0] = black[0]; \
980 pixel2[1] = black[1]; \
981 pixel2[2] = black[2]; \
982 if(components == 4) pixel2[3] = black[3]; \
986 float y1_fraction = y_in2 - floor(y_in2); \
987 float y2_fraction = 1.0 - y1_fraction; \
988 float x1_fraction = x_in2 - floor(x_in2); \
989 float x2_fraction = 1.0 - x1_fraction; \
990 type *in_pixel1 = in_rows[(int)y_in2] + (int)x_in2 * components; \
991 type *in_pixel2 = in_rows[(int)y_in2 + 1] + (int)x_in2 * components; \
992 for(int i = 0; i < components; i++) \
994 pixel2[i] = (type)(in_pixel1[i] * x2_fraction * y2_fraction + \
995 in_pixel2[i] * x2_fraction * y1_fraction + \
996 in_pixel1[i + components] * x1_fraction * y2_fraction + \
997 in_pixel2[i + components] * x1_fraction * y1_fraction); \
1001 /* blend the 2 eyes */ \
1002 for(int i = 0; i < components; i++) \
1004 *out_row++ = (type)(pixel1[i] * (1.0f - fraction) + \
1005 pixel2[i] * fraction); \
1011 #define COLORSPACE_SWITCH(function) \
1012 switch(plugin->get_input()->get_color_model()) \
1015 function(unsigned char, 3, 0x0); \
1018 function(unsigned char, 4, 0x0); \
1020 case BC_RGB_FLOAT: \
1021 function(float, 3, 0.0); \
1023 case BC_RGBA_FLOAT: \
1024 function(float, 4, 0.0); \
1027 function(unsigned char, 3, 0x80); \
1030 function(unsigned char, 4, 0x80); \
1035 double Fuse360Unit::calculate_max_z(double a, double r)
1037 if(a < 0) a += 2 * M_PI;
1041 return r / cos(a); // bottom right edge
1044 if(a < 3 * M_PI / 4)
1046 return r / cos(M_PI / 2 - a); // bottom edge
1049 if(a < 5 * M_PI / 4)
1051 return r / cos(M_PI - a); // left edge
1054 if(a < 7 * M_PI / 4)
1056 return r / cos(3 * M_PI / 2 - a); // top edge
1060 return r / cos(a); // top right edge
1064 void Fuse360Unit::process_stretch(Fuse360Package *pkg)
1066 VFrame *input = plugin->get_temp();
1067 VFrame *output = plugin->get_output();
1069 float fov = plugin->config.fov;
1070 int row1 = pkg->row1;
1071 int row2 = pkg->row2;
1072 int center_x1 = plugin->center_x1;
1073 int center_x2 = plugin->center_x2;
1074 int center_y1 = plugin->center_y1;
1075 int center_y2 = plugin->center_y2;
1076 int center_x = plugin->center_x;
1077 int center_y = plugin->center_y;
1080 double radius = plugin->radius_x;
1083 #define PROCESS_STRETCH(type, components, chroma) \
1085 type **in_rows = (type**)input->get_rows(); \
1086 type **out_rows = (type**)output->get_rows(); \
1087 type black[4] = { 0, chroma, chroma, 0 }; \
1089 for(int y = row1; y < row2; y++) \
1091 type *out_row = out_rows[y]; \
1092 type *in_row = in_rows[y]; \
1093 double y_diff = y - center_y1; \
1096 for(int x = 0; x < center_x; x++) \
1098 double x_diff = x - center_x1; \
1099 /* polar output coordinate */ \
1100 double z = hypot(x_diff, y_diff); \
1101 double a = atan2(y_diff, x_diff); \
1103 /* scale the magnitude to the radius */ \
1104 double scaled_z = z * radius / calculate_max_z(a, radius); \
1105 /* xy input coordinate */ \
1106 double x_in = scaled_z * cos(a) + center_x1; \
1107 double y_in = scaled_z * sin(a) + center_y1; \
1109 if(x_in < center_x) \
1111 BLEND_PIXEL(type, components) \
1116 for(int y = row1; y < row2; y++) \
1118 type *out_row = out_rows[y] + center_x * components; \
1119 type *in_row = in_rows[y]; \
1120 double y_diff = y - center_y2; \
1123 for(int x = center_x; x < w; x++) \
1125 double x_diff = x - center_x2; \
1126 /* polar output coordinate */ \
1127 double z = hypot(x_diff, y_diff); \
1128 double a = atan2(y_diff, x_diff); \
1130 /* scale the magnitude to the radius */ \
1131 double scaled_z = z * radius / calculate_max_z(a, radius); \
1132 /* xy input coordinate */ \
1133 double x_in = scaled_z * cos(a) + center_x2; \
1134 double y_in = scaled_z * sin(a) + center_y2; \
1136 if(x_in >= center_x) \
1138 BLEND_PIXEL(type, components) \
1146 COLORSPACE_SWITCH(PROCESS_STRETCH)
1153 void Fuse360Unit::process_standard(Fuse360Package *pkg)
1155 VFrame *input = plugin->get_temp();
1156 VFrame *output = plugin->get_output();
1158 float fov = plugin->config.fov;
1159 int row1 = pkg->row1;
1160 int row2 = pkg->row2;
1161 int center_x1 = plugin->center_x1;
1162 int center_x2 = plugin->center_x2;
1163 int center_y1 = plugin->center_y1;
1164 int center_y2 = plugin->center_y2;
1165 int center_x = plugin->center_x;
1166 int center_y = plugin->center_y;
1167 int feather = plugin->feather;
1168 int feather_x1 = plugin->feather_x1;
1169 int feather_x2 = plugin->feather_x2;
1172 float radius_x = plugin->radius_x;
1173 float radius_y = plugin->radius_y;
1174 int distance_x = plugin->distance_x;
1175 int distance_y = plugin->distance_y;
1176 // field of view of the fisheye
1179 #define PROCESS_STANDARD(type, components, chroma) \
1181 type **in_rows = (type**)input->get_rows(); \
1182 type **out_rows = (type**)output->get_rows(); \
1183 type black[4] = { 0, chroma, chroma, 0 }; \
1186 for(int y = row1; y < row2; y++) \
1188 type *out_row = out_rows[y]; \
1190 /* -M_PI/2 to M_PI/2 */ \
1191 float y_diff = y - center_y1; \
1192 /* polar angles */ \
1193 float phi = M_PI / 2 * (y_diff / radius_y); \
1194 for(int x = 0; x < feather_x1; x++) \
1196 float x_diff = x - center_x1; \
1197 /* polar angles */ \
1198 /* -M_PI/2 to M_PI/2 */ \
1199 float theta = M_PI / 2 * (x_diff / radius_x); \
1200 /* vector in 3D space */ \
1201 float vect_x = cos(phi) * sin(theta); \
1202 float vect_y = cos(phi) * cos(theta); \
1203 float vect_z = sin(phi); \
1204 /* fisheye angle & radius */ \
1205 float theta2 = atan2(vect_z, vect_x); \
1206 float phi2 = atan2(hypot(vect_x, vect_z), vect_y); \
1207 float r = radius_x * 2 * phi2 / FOV; \
1208 /* pixel in fisheye space */ \
1209 float x_in = center_x1 + r * cos(theta2); \
1210 float y_in = center_y1 + r * sin(theta2); \
1212 BLEND_PIXEL(type, components) \
1219 for(int y = row1; y < row2; y++) \
1221 type *out_row = out_rows[y] + components * feather_x2; \
1223 /* -M_PI/2 to M_PI/2 */ \
1224 float y_diff = y - center_y2; \
1225 /* polar angles */ \
1226 float phi = M_PI / 2 * (y_diff / radius_y); \
1227 for(int x = feather_x2; x < w; x++) \
1229 float x_diff = x - center_x2; \
1230 /* polar angles */ \
1231 /* -M_PI/2 to M_PI/2 */ \
1232 float theta = M_PI / 2 * (x_diff / radius_x); \
1233 /* vector in 3D space */ \
1234 float vect_x = cos(phi) * sin(theta); \
1235 float vect_y = cos(phi) * cos(theta); \
1236 float vect_z = sin(phi); \
1237 /* fisheye angle & radius */ \
1238 float theta2 = atan2(vect_z, vect_x); \
1239 float phi2 = atan2(hypot(vect_x, vect_z), vect_y); \
1240 float r = radius_x * 2 * phi2 / FOV; \
1241 /* pixel in fisheye space */ \
1242 float x_in = center_x2 + r * cos(theta2); \
1243 float y_in = center_y2 + r * sin(theta2); \
1245 BLEND_PIXEL(type, components) \
1252 COLORSPACE_SWITCH(PROCESS_STANDARD)
1257 void Fuse360Unit::process_package(LoadPackage *package)
1259 Fuse360Package *pkg = (Fuse360Package*)package;
1261 switch(plugin->config.mode)
1263 case Fuse360Config::STRETCHXY:
1264 process_stretch(pkg);
1266 case Fuse360Config::STANDARD:
1267 process_standard(pkg);
1269 case Fuse360Config::BLEND:
1279 Fuse360Engine::Fuse360Engine(Fuse360Main *plugin)
1280 // : LoadServer(plugin->PluginClient::smp + 1, plugin->PluginClient::smp + 1)
1283 this->plugin = plugin;
1286 Fuse360Engine::~Fuse360Engine()
1290 void Fuse360Engine::init_packages()
1292 for(int i = 0; i < LoadServer::get_total_packages(); i++)
1294 Fuse360Package *package = (Fuse360Package*)LoadServer::get_package(i);
1295 package->row1 = plugin->get_input()->get_h() * i / LoadServer::get_total_packages();
1296 package->row2 = plugin->get_input()->get_h() * (i + 1) / LoadServer::get_total_packages();
1300 LoadClient* Fuse360Engine::new_client()
1302 return new Fuse360Unit(this, plugin);
1305 LoadPackage* Fuse360Engine::new_package()
1307 return new Fuse360Package;