4 * Copyright (C) 2008 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
22 #include "bcdisplayinfo.h"
29 #include "loadbalance.h"
30 #include "pluginvclient.h"
40 #define WITHIN(a, b, c) ((((a) <= (b)) && ((b) <= (c))) ? 1 : 0)
46 #define DEPTH_MIN 1.00
47 #define DEPTH_MAX 100.00
48 #define ANGLE_MIN 1.00
49 #define ANGLE_MAX 360.00
66 void reset(int clear);
67 void copy_from(PolarConfig &src);
68 int equivalent(PolarConfig &src);
69 void interpolate(PolarConfig &prev,
75 int polar_to_rectangular;
84 class PolarFText : public BC_TumbleTextBox
87 PolarFText(PolarWindow *window, PolarEffect *plugin,
88 PolarFSlider *slider, float *output, int x, int y, float min, float max);
98 class PolarFSlider : public BC_FSlider
101 PolarFSlider(PolarEffect *plugin,
102 PolarFText *text, float *output, int x, int y,
103 float min, float max, int w);
112 class PolarReset : public BC_GenericButton
115 PolarReset(PolarEffect *plugin, PolarWindow *window, int x, int y);
122 class PolarClr : public BC_Button
125 PolarClr(PolarEffect *plugin, PolarWindow *window, int x, int y, int clear);
133 class PolarWindow : public PluginClientWindow
136 PolarWindow(PolarEffect *plugin);
137 void create_objects();
138 void update_gui(int clear);
141 PolarFText *depth_text;
142 PolarFSlider *depth_slider;
145 PolarFText *angle_text;
146 PolarFSlider *angle_slider;
156 class PolarPackage : public LoadPackage
163 class PolarUnit : public LoadClient
166 PolarUnit(PolarEffect *plugin, PolarEngine *server);
167 void process_package(LoadPackage *package);
171 class PolarEngine : public LoadServer
174 PolarEngine(PolarEffect *plugin, int cpus);
175 void init_packages();
176 LoadClient* new_client();
177 LoadPackage* new_package();
181 class PolarEffect : public PluginVClient
184 PolarEffect(PluginServer *server);
187 PLUGIN_CLASS_MEMBERS(PolarConfig)
188 int process_realtime(VFrame *input, VFrame *output);
190 void save_data(KeyFrame *keyframe);
191 void read_data(KeyFrame *keyframe);
196 VFrame *input, *output;
197 int need_reconfigure;
202 REGISTER_PLUGIN(PolarEffect)
206 PolarConfig::PolarConfig()
211 void PolarConfig::reset(int clear)
214 case RESET_DEPTH : depth = 1.0;
216 case RESET_ANGLE : angle = 1.0;
224 polar_to_rectangular = 1;
229 void PolarConfig::copy_from(PolarConfig &src)
231 this->angle = src.angle;
232 this->depth = src.depth;
233 this->backwards = src.backwards;
234 this->invert = src.invert;
235 this->polar_to_rectangular = src.polar_to_rectangular;
238 int PolarConfig::equivalent(PolarConfig &src)
240 return EQUIV(this->angle, src.angle) && EQUIV(this->depth, src.depth);
243 void PolarConfig::interpolate(PolarConfig &prev,
249 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
250 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
252 this->depth = prev.depth * prev_scale + next.depth * next_scale;
253 this->angle = prev.angle * prev_scale + next.angle * next_scale;
261 PolarWindow::PolarWindow(PolarEffect *plugin)
262 : PluginClientWindow(plugin,
269 this->plugin = plugin;
272 void PolarWindow::create_objects()
274 int xs10 = xS(10), xs200 = xS(200);
275 int ys10 = yS(10), ys30 = yS(30), ys40 = yS(40);
276 int x = xs10, y = ys10;
277 int x2 = xS(80), x3 = xS(180);
278 int clr_x = get_w()-x - xS(22); // note: clrBtn_w = 22
283 add_subwindow(new BC_Title(x, y, _("Depth:")));
284 depth_text = new PolarFText(this, plugin,
285 0, &plugin->config.depth, (x + x2), y, DEPTH_MIN, DEPTH_MAX);
286 depth_text->create_objects();
287 depth_slider = new PolarFSlider(plugin,
288 depth_text, &plugin->config.depth, x3, y, DEPTH_MIN, DEPTH_MAX, xs200);
289 add_subwindow(depth_slider);
290 depth_text->slider = depth_slider;
291 clr_x = x3 + depth_slider->get_w() + x;
292 add_subwindow(depth_Clr = new PolarClr(plugin, this, clr_x, y, RESET_DEPTH));
295 add_subwindow(new BC_Title(x, y, _("Angle:")));
296 angle_text = new PolarFText(this, plugin,
297 0, &plugin->config.angle, (x + x2), y, ANGLE_MIN, ANGLE_MAX);
298 angle_text->create_objects();
299 angle_slider = new PolarFSlider(plugin,
300 angle_text, &plugin->config.angle, x3, y, ANGLE_MIN, ANGLE_MAX, xs200);
301 add_subwindow(angle_slider);
302 angle_text->slider = angle_slider;
303 add_subwindow(angle_Clr = new PolarClr(plugin, this, clr_x, y, RESET_ANGLE));
307 add_subwindow(bar = new BC_Bar(x, y, get_w()-2*x));
309 add_subwindow(reset = new PolarReset(plugin, this, x, y));
316 void PolarWindow::update_gui(int clear)
320 depth_text->update(plugin->config.depth);
321 depth_slider->update(plugin->config.depth);
324 angle_text->update(plugin->config.angle);
325 angle_slider->update(plugin->config.angle);
329 depth_text->update(plugin->config.depth);
330 depth_slider->update(plugin->config.depth);
331 angle_text->update(plugin->config.angle);
332 angle_slider->update(plugin->config.angle);
341 PolarFText::PolarFText(PolarWindow *window, PolarEffect *plugin,
342 PolarFSlider *slider, float *output, int x, int y, float min, float max)
343 : BC_TumbleTextBox(window, *output,
344 min, max, x, y, xS(60), 2)
346 this->window = window;
347 this->plugin = plugin;
348 this->output = output;
349 this->slider = slider;
355 PolarFText::~PolarFText()
359 int PolarFText::handle_event()
361 *output = atof(get_text());
362 if(*output > max) *output = max;
363 if(*output < min) *output = min;
364 slider->update(*output);
365 plugin->send_configure_change();
370 PolarFSlider::PolarFSlider(PolarEffect *plugin,
371 PolarFText *text, float *output, int x, int y, float min, float max, int w)
372 : BC_FSlider(x, y, 0, w, w, min, max, *output)
374 this->plugin = plugin;
375 this->output = output;
377 enable_show_value(0); // Hide caption
380 PolarFSlider::~PolarFSlider()
384 int PolarFSlider::handle_event()
386 *output = get_value();
387 text->update(*output);
388 plugin->send_configure_change();
393 PolarReset::PolarReset(PolarEffect *plugin, PolarWindow *window, int x, int y)
394 : BC_GenericButton(x, y, _("Reset"))
396 this->plugin = plugin;
397 this->window = window;
399 PolarReset::~PolarReset()
402 int PolarReset::handle_event()
404 plugin->config.reset(RESET_ALL);
405 window->update_gui(RESET_ALL);
406 plugin->send_configure_change();
411 PolarClr::PolarClr(PolarEffect *plugin, PolarWindow *window, int x, int y, int clear)
412 : BC_Button(x, y, plugin->get_theme()->get_image_set("reset_button"))
414 this->plugin = plugin;
415 this->window = window;
418 PolarClr::~PolarClr()
421 int PolarClr::handle_event()
423 // clear==1 ==> Depth slider
424 // clear==2 ==> Angle slider
425 plugin->config.reset(clear);
426 window->update_gui(clear);
427 plugin->send_configure_change();
434 PolarEffect::PolarEffect(PluginServer *server)
435 : PluginVClient(server)
437 need_reconfigure = 1;
443 PolarEffect::~PolarEffect()
446 if(temp_frame) delete temp_frame;
447 if(engine) delete engine;
452 const char* PolarEffect::plugin_title() { return N_("Polar"); }
453 int PolarEffect::is_realtime() { return 1; }
458 NEW_WINDOW_MACRO(PolarEffect, PolarWindow)
460 void PolarEffect::update_gui()
464 load_configuration();
465 thread->window->lock_window();
466 ((PolarWindow*)thread->window)->angle_text->update(config.angle);
467 ((PolarWindow*)thread->window)->angle_slider->update(config.angle);
468 ((PolarWindow*)thread->window)->depth_text->update(config.depth);
469 ((PolarWindow*)thread->window)->depth_slider->update(config.depth);
470 thread->window->unlock_window();
474 LOAD_CONFIGURATION_MACRO(PolarEffect, PolarConfig)
478 void PolarEffect::save_data(KeyFrame *keyframe)
482 // cause data to be stored directly in text
483 output.set_shared_output(keyframe->xbuf);
484 output.tag.set_title("POLAR");
485 output.tag.set_property("DEPTH", config.depth);
486 output.tag.set_property("ANGLE", config.angle);
488 output.tag.set_title("/POLAR");
490 output.append_newline();
491 output.terminate_string();
494 void PolarEffect::read_data(KeyFrame *keyframe)
498 input.set_shared_input(keyframe->xbuf);
500 while(!input.read_tag())
502 if(input.tag.title_is("POLAR"))
504 config.depth = input.tag.get_property("DEPTH", config.depth);
505 config.angle = input.tag.get_property("ANGLE", config.angle);
510 int PolarEffect::process_realtime(VFrame *input, VFrame *output)
512 need_reconfigure |= load_configuration();
515 this->output = output;
517 if(EQUIV(config.depth, 0) || EQUIV(config.angle, 0))
519 if(input->get_rows()[0] != output->get_rows()[0])
520 output->copy_from(input);
524 if(input->get_rows()[0] == output->get_rows()[0])
527 temp_frame = new VFrame(input->get_w(), input->get_h(),
528 input->get_color_model(), 0);
529 temp_frame->copy_from(input);
530 this->input = temp_frame;
534 if(!engine) engine = new PolarEngine(this, PluginClient::smp + 1);
536 engine->process_packages();
545 PolarPackage::PolarPackage()
553 PolarUnit::PolarUnit(PolarEffect *plugin, PolarEngine *server)
556 this->plugin = plugin;
560 static int calc_undistorted_coords(int wx,
566 int polar_to_rectangular,
576 double xx, xm, ym, yy;
580 double xmax, ymax, rmax;
581 double x_calc, y_calc;
583 double circle, angl, t;
601 angl = (double)angle / 180.0 * M_PI;
603 if(polar_to_rectangular)
610 atan(((double)(wx - cen_x)) /
611 ((double)(wy - cen_y)));
612 r = sqrt(SQR(wx - cen_x) +
618 phi = atan(((double)(wx - cen_x)) /
619 ((double)(cen_y - wy)));
620 r = sqrt(SQR(wx - cen_x) +
635 atan(((double)(cen_x -wx)) /
636 ((double)(cen_y - wy)));
637 r = sqrt(SQR(cen_x - wx) +
644 atan(((double)(cen_x - wx)) /
645 ((double)(wy - cen_y)));
646 r = sqrt(SQR(cen_x - wx) +
657 m = fabs(((double)(wy - cen_y)) /
658 ((double)(wx - cen_x)));
665 if(m <= ((double)(y2 - y1) /
685 rmax = sqrt((double)(SQR(xmax) + SQR(ymax)));
687 t = ((cen_y - y1) < (cen_x - x1)) ? (cen_y - y1) : (cen_x - x1);
688 rmax = (rmax - t) / 100 * (100 - circle) + t;
690 phi = fmod(phi + angl, 2 * M_PI);
693 x_calc = x2 - 1 - (x2 - x1 - 1) / (2 * M_PI) * phi;
695 x_calc = (x2 - x1 - 1) / (2 * M_PI) * phi + x1;
698 y_calc = (y2 - y1) / rmax * r + y1;
700 y_calc = y2 - (y2 - y1) / rmax * r;
702 xi = (int)(x_calc + 0.5);
703 yi = (int)(y_calc + 0.5);
705 if(WITHIN(0, xi, w - 1) && WITHIN(0, yi, h - 1))
720 phi = (2 * M_PI) * (x2 - wx) / xdiff;
722 phi = (2 * M_PI) * (wx - x1) / xdiff;
724 phi = fmod (phi + angl, 2 * M_PI);
726 if(phi >= 1.5 * M_PI)
727 phi2 = 2 * M_PI - phi;
732 if(phi >= 0.5 * M_PI)
739 m = (double)1.0 / xx;
743 if(m <= ((double)(ydiff) / (double)(xdiff)))
762 rmax = sqrt((double)(SQR(xmax) + SQR(ymax)));
764 t = ((ym - y1) < (xm - x1)) ? (ym - y1) : (xm - x1);
766 rmax = (rmax - t) / 100.0 * (100 - circle) + t;
769 r = rmax * (double)((wy - y1) / (double)(ydiff));
771 r = rmax * (double)((y2 - wy) / (double)(ydiff));
776 if(phi >= 1.5 * M_PI)
778 x_calc = (double)xm - xx;
779 y_calc = (double)ym - yy;
784 x_calc = (double)xm - xx;
785 y_calc = (double)ym + yy;
788 if(phi >= 0.5 * M_PI)
790 x_calc = (double)xm + xx;
791 y_calc = (double)ym + yy;
795 x_calc = (double)xm + xx;
796 y_calc = (double)ym - yy;
799 xi = (int)(x_calc + 0.5);
800 yi = (int)(y_calc + 0.5);
802 if(WITHIN(0, xi, w - 1) &&
803 WITHIN(0, yi, h - 1))
819 static double bilinear(double x, double y, double *values)
825 if(x < 0.0) x += 1.0;
826 if(y < 0.0) y += 1.0;
828 m0 = values[0] + x * (values[1] - values[0]);
829 m1 = values[2] + x * (values[3] - values[2]);
830 return m0 + y * (m1 - m0);
833 #define GET_PIXEL(x, y, components, input_rows) \
834 input_rows[CLIP((y), 0, ((h) - 1))] + components * CLIP((x), 0, ((w) - 1))
836 #define POLAR_MACRO(type, max, components, chroma_offset) \
838 type **in_rows = (type**)plugin->input->get_rows(); \
839 type **out_rows = (type**)plugin->output->get_rows(); \
842 for(int y = pkg->row1; y < pkg->row2; y++) \
844 type *output_row = out_rows[y]; \
846 for(int x = 0; x < w; x++) \
848 type *output_pixel = output_row + x * components; \
849 if(calc_undistorted_coords(x, \
853 plugin->config.depth, \
854 plugin->config.angle, \
855 plugin->config.polar_to_rectangular, \
856 plugin->config.backwards, \
857 plugin->config.invert, \
863 type *pixel1 = GET_PIXEL((int)cx, (int)cy, components, in_rows); \
864 type *pixel2 = GET_PIXEL((int)cx + 1, (int)cy, components, in_rows); \
865 type *pixel3 = GET_PIXEL((int)cx, (int)cy + 1, components, in_rows); \
866 type *pixel4 = GET_PIXEL((int)cx + 1, (int)cy + 1, components, in_rows); \
868 values[0] = pixel1[0]; \
869 values[1] = pixel2[0]; \
870 values[2] = pixel3[0]; \
871 values[3] = pixel4[0]; \
872 output_pixel[0] = (type)bilinear(cx, cy, values); \
874 values[0] = pixel1[1]; \
875 values[1] = pixel2[1]; \
876 values[2] = pixel3[1]; \
877 values[3] = pixel4[1]; \
878 output_pixel[1] = (type)bilinear(cx, cy, values); \
880 values[0] = pixel1[2]; \
881 values[1] = pixel2[2]; \
882 values[2] = pixel3[2]; \
883 values[3] = pixel4[2]; \
884 output_pixel[2] = (type)bilinear(cx, cy, values); \
886 if(components == 4) \
888 values[0] = pixel1[3]; \
889 values[1] = pixel2[3]; \
890 values[2] = pixel3[3]; \
891 values[3] = pixel4[3]; \
892 output_pixel[3] = (type)bilinear(cx, cy, values); \
897 output_pixel[0] = 0; \
898 output_pixel[1] = chroma_offset; \
899 output_pixel[2] = chroma_offset; \
900 if(components == 4) output_pixel[3] = max; \
907 void PolarUnit::process_package(LoadPackage *package)
909 PolarPackage *pkg = (PolarPackage*)package;
910 int w = plugin->input->get_w();
911 int h = plugin->input->get_h();
914 double cen_x = (double)(w - 1) / 2.0;
915 double cen_y = (double)(h - 1) / 2.0;
917 switch(plugin->input->get_color_model())
920 POLAR_MACRO(float, 1, 3, 0x0)
923 POLAR_MACRO(float, 1, 4, 0x0)
926 POLAR_MACRO(unsigned char, 0xff, 3, 0x0)
929 POLAR_MACRO(unsigned char, 0xff, 4, 0x0)
932 POLAR_MACRO(uint16_t, 0xffff, 3, 0x0)
934 case BC_RGBA16161616:
935 POLAR_MACRO(uint16_t, 0xffff, 4, 0x0)
938 POLAR_MACRO(unsigned char, 0xff, 3, 0x80)
941 POLAR_MACRO(unsigned char, 0xff, 4, 0x80)
944 POLAR_MACRO(uint16_t, 0xffff, 3, 0x8000)
946 case BC_YUVA16161616:
947 POLAR_MACRO(uint16_t, 0xffff, 4, 0x8000)
955 PolarEngine::PolarEngine(PolarEffect *plugin, int cpus)
956 : LoadServer(cpus, cpus)
958 this->plugin = plugin;
961 void PolarEngine::init_packages()
963 for(int i = 0; i < LoadServer::get_total_packages(); i++)
965 PolarPackage *pkg = (PolarPackage*)get_package(i);
966 pkg->row1 = plugin->input->get_h() * i / LoadServer::get_total_packages();
967 pkg->row2 = plugin->input->get_h() * (i + 1) / LoadServer::get_total_packages();
971 LoadClient* PolarEngine::new_client()
973 return new PolarUnit(plugin, this);
976 LoadPackage* PolarEngine::new_package()
978 return new PolarPackage;