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)
58 void reset(int clear);
59 void copy_from(PolarConfig &src);
60 int equivalent(PolarConfig &src);
61 void interpolate(PolarConfig &prev,
67 int polar_to_rectangular;
76 class PolarDepth : public BC_FSlider
79 PolarDepth(PolarEffect *plugin, int x, int y);
84 class PolarAngle : public BC_FSlider
87 PolarAngle(PolarEffect *plugin, int x, int y);
92 class PolarReset : public BC_GenericButton
95 PolarReset(PolarEffect *plugin, PolarWindow *window, int x, int y);
102 class PolarSliderClr : public BC_Button
105 PolarSliderClr(PolarEffect *plugin, PolarWindow *window, int x, int y, int w, int clear);
113 class PolarWindow : public PluginClientWindow
116 PolarWindow(PolarEffect *plugin);
117 void create_objects();
118 void update_gui(int clear);
123 PolarSliderClr *depthClr;
124 PolarSliderClr *angleClr;
131 class PolarPackage : public LoadPackage
138 class PolarUnit : public LoadClient
141 PolarUnit(PolarEffect *plugin, PolarEngine *server);
142 void process_package(LoadPackage *package);
146 class PolarEngine : public LoadServer
149 PolarEngine(PolarEffect *plugin, int cpus);
150 void init_packages();
151 LoadClient* new_client();
152 LoadPackage* new_package();
156 class PolarEffect : public PluginVClient
159 PolarEffect(PluginServer *server);
162 PLUGIN_CLASS_MEMBERS(PolarConfig)
163 int process_realtime(VFrame *input, VFrame *output);
165 void save_data(KeyFrame *keyframe);
166 void read_data(KeyFrame *keyframe);
171 VFrame *input, *output;
172 int need_reconfigure;
177 REGISTER_PLUGIN(PolarEffect)
181 PolarConfig::PolarConfig()
186 void PolarConfig::reset(int clear)
189 case RESET_DEPTH : depth = 1.0;
191 case RESET_ANGLE : angle = 1.0;
199 polar_to_rectangular = 1;
204 void PolarConfig::copy_from(PolarConfig &src)
206 this->angle = src.angle;
207 this->depth = src.depth;
208 this->backwards = src.backwards;
209 this->invert = src.invert;
210 this->polar_to_rectangular = src.polar_to_rectangular;
213 int PolarConfig::equivalent(PolarConfig &src)
215 return EQUIV(this->angle, src.angle) && EQUIV(this->depth, src.depth);
218 void PolarConfig::interpolate(PolarConfig &prev,
224 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
225 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
227 this->depth = prev.depth * prev_scale + next.depth * next_scale;
228 this->angle = prev.angle * prev_scale + next.angle * next_scale;
236 PolarWindow::PolarWindow(PolarEffect *plugin)
237 : PluginClientWindow(plugin,
244 this->plugin = plugin;
247 void PolarWindow::create_objects()
249 int xs10 = xS(10), xs50 = xS(50);
250 int ys10 = yS(10), ys40 = yS(40);
251 int x = xs10, y = ys10, x1 = x + xs50;
252 int x2 = 0; int clrBtn_w = xs50;
254 add_subwindow(new BC_Title(x, y, _("Depth:")));
255 add_subwindow(depth = new PolarDepth(plugin, x1, y));
256 x2 = x1 + depth->get_w() + xs10;
257 add_subwindow(depthClr = new PolarSliderClr(plugin, this, x2, y, clrBtn_w, RESET_DEPTH));
260 add_subwindow(new BC_Title(x, y, _("Angle:")));
261 add_subwindow(angle = new PolarAngle(plugin, x1, y));
262 add_subwindow(angleClr = new PolarSliderClr(plugin, this, x2, y, clrBtn_w, RESET_ANGLE));
264 add_subwindow(reset = new PolarReset(plugin, this, x, y));
271 void PolarWindow::update_gui(int clear)
274 case RESET_DEPTH : depth->update(plugin->config.depth);
276 case RESET_ANGLE : angle->update(plugin->config.angle);
280 depth->update(plugin->config.depth);
281 angle->update(plugin->config.angle);
290 PolarDepth::PolarDepth(PolarEffect *plugin, int x, int y)
298 plugin->config.depth)
300 this->plugin = plugin;
302 int PolarDepth::handle_event()
304 plugin->config.depth = get_value();
305 plugin->send_configure_change();
313 PolarAngle::PolarAngle(PolarEffect *plugin, int x, int y)
321 plugin->config.angle)
323 this->plugin = plugin;
325 int PolarAngle::handle_event()
327 plugin->config.angle = get_value();
328 plugin->send_configure_change();
334 PolarReset::PolarReset(PolarEffect *plugin, PolarWindow *window, int x, int y)
335 : BC_GenericButton(x, y, _("Reset"))
337 this->plugin = plugin;
338 this->window = window;
340 PolarReset::~PolarReset()
343 int PolarReset::handle_event()
345 plugin->config.reset(RESET_ALL);
346 window->update_gui(RESET_ALL);
347 plugin->send_configure_change();
352 PolarSliderClr::PolarSliderClr(PolarEffect *plugin, PolarWindow *window, int x, int y, int w, int clear)
353 : BC_Button(x, y, w, plugin->get_theme()->get_image_set("reset_button"))
355 this->plugin = plugin;
356 this->window = window;
359 PolarSliderClr::~PolarSliderClr()
362 int PolarSliderClr::handle_event()
364 // clear==1 ==> Depth slider
365 // clear==2 ==> Angle slider
366 plugin->config.reset(clear);
367 window->update_gui(clear);
368 plugin->send_configure_change();
375 PolarEffect::PolarEffect(PluginServer *server)
376 : PluginVClient(server)
378 need_reconfigure = 1;
384 PolarEffect::~PolarEffect()
387 if(temp_frame) delete temp_frame;
388 if(engine) delete engine;
393 const char* PolarEffect::plugin_title() { return N_("Polar"); }
394 int PolarEffect::is_realtime() { return 1; }
399 NEW_WINDOW_MACRO(PolarEffect, PolarWindow)
401 void PolarEffect::update_gui()
405 load_configuration();
406 thread->window->lock_window();
407 ((PolarWindow*)thread->window)->angle->update(config.angle);
408 ((PolarWindow*)thread->window)->depth->update(config.depth);
409 thread->window->unlock_window();
413 LOAD_CONFIGURATION_MACRO(PolarEffect, PolarConfig)
417 void PolarEffect::save_data(KeyFrame *keyframe)
421 // cause data to be stored directly in text
422 output.set_shared_output(keyframe->xbuf);
423 output.tag.set_title("POLAR");
424 output.tag.set_property("DEPTH", config.depth);
425 output.tag.set_property("ANGLE", config.angle);
427 output.tag.set_title("/POLAR");
429 output.append_newline();
430 output.terminate_string();
433 void PolarEffect::read_data(KeyFrame *keyframe)
437 input.set_shared_input(keyframe->xbuf);
439 while(!input.read_tag())
441 if(input.tag.title_is("POLAR"))
443 config.depth = input.tag.get_property("DEPTH", config.depth);
444 config.angle = input.tag.get_property("ANGLE", config.angle);
449 int PolarEffect::process_realtime(VFrame *input, VFrame *output)
451 need_reconfigure |= load_configuration();
454 this->output = output;
456 if(EQUIV(config.depth, 0) || EQUIV(config.angle, 0))
458 if(input->get_rows()[0] != output->get_rows()[0])
459 output->copy_from(input);
463 if(input->get_rows()[0] == output->get_rows()[0])
466 temp_frame = new VFrame(input->get_w(), input->get_h(),
467 input->get_color_model(), 0);
468 temp_frame->copy_from(input);
469 this->input = temp_frame;
473 if(!engine) engine = new PolarEngine(this, PluginClient::smp + 1);
475 engine->process_packages();
484 PolarPackage::PolarPackage()
492 PolarUnit::PolarUnit(PolarEffect *plugin, PolarEngine *server)
495 this->plugin = plugin;
499 static int calc_undistorted_coords(int wx,
505 int polar_to_rectangular,
515 double xx, xm, ym, yy;
519 double xmax, ymax, rmax;
520 double x_calc, y_calc;
522 double circle, angl, t;
540 angl = (double)angle / 180.0 * M_PI;
542 if(polar_to_rectangular)
549 atan(((double)(wx - cen_x)) /
550 ((double)(wy - cen_y)));
551 r = sqrt(SQR(wx - cen_x) +
557 phi = atan(((double)(wx - cen_x)) /
558 ((double)(cen_y - wy)));
559 r = sqrt(SQR(wx - cen_x) +
574 atan(((double)(cen_x -wx)) /
575 ((double)(cen_y - wy)));
576 r = sqrt(SQR(cen_x - wx) +
583 atan(((double)(cen_x - wx)) /
584 ((double)(wy - cen_y)));
585 r = sqrt(SQR(cen_x - wx) +
596 m = fabs(((double)(wy - cen_y)) /
597 ((double)(wx - cen_x)));
604 if(m <= ((double)(y2 - y1) /
624 rmax = sqrt((double)(SQR(xmax) + SQR(ymax)));
626 t = ((cen_y - y1) < (cen_x - x1)) ? (cen_y - y1) : (cen_x - x1);
627 rmax = (rmax - t) / 100 * (100 - circle) + t;
629 phi = fmod(phi + angl, 2 * M_PI);
632 x_calc = x2 - 1 - (x2 - x1 - 1) / (2 * M_PI) * phi;
634 x_calc = (x2 - x1 - 1) / (2 * M_PI) * phi + x1;
637 y_calc = (y2 - y1) / rmax * r + y1;
639 y_calc = y2 - (y2 - y1) / rmax * r;
641 xi = (int)(x_calc + 0.5);
642 yi = (int)(y_calc + 0.5);
644 if(WITHIN(0, xi, w - 1) && WITHIN(0, yi, h - 1))
659 phi = (2 * M_PI) * (x2 - wx) / xdiff;
661 phi = (2 * M_PI) * (wx - x1) / xdiff;
663 phi = fmod (phi + angl, 2 * M_PI);
665 if(phi >= 1.5 * M_PI)
666 phi2 = 2 * M_PI - phi;
671 if(phi >= 0.5 * M_PI)
678 m = (double)1.0 / xx;
682 if(m <= ((double)(ydiff) / (double)(xdiff)))
701 rmax = sqrt((double)(SQR(xmax) + SQR(ymax)));
703 t = ((ym - y1) < (xm - x1)) ? (ym - y1) : (xm - x1);
705 rmax = (rmax - t) / 100.0 * (100 - circle) + t;
708 r = rmax * (double)((wy - y1) / (double)(ydiff));
710 r = rmax * (double)((y2 - wy) / (double)(ydiff));
715 if(phi >= 1.5 * M_PI)
717 x_calc = (double)xm - xx;
718 y_calc = (double)ym - yy;
723 x_calc = (double)xm - xx;
724 y_calc = (double)ym + yy;
727 if(phi >= 0.5 * M_PI)
729 x_calc = (double)xm + xx;
730 y_calc = (double)ym + yy;
734 x_calc = (double)xm + xx;
735 y_calc = (double)ym - yy;
738 xi = (int)(x_calc + 0.5);
739 yi = (int)(y_calc + 0.5);
741 if(WITHIN(0, xi, w - 1) &&
742 WITHIN(0, yi, h - 1))
758 static double bilinear(double x, double y, double *values)
764 if(x < 0.0) x += 1.0;
765 if(y < 0.0) y += 1.0;
767 m0 = values[0] + x * (values[1] - values[0]);
768 m1 = values[2] + x * (values[3] - values[2]);
769 return m0 + y * (m1 - m0);
772 #define GET_PIXEL(x, y, components, input_rows) \
773 input_rows[CLIP((y), 0, ((h) - 1))] + components * CLIP((x), 0, ((w) - 1))
775 #define POLAR_MACRO(type, max, components, chroma_offset) \
777 type **in_rows = (type**)plugin->input->get_rows(); \
778 type **out_rows = (type**)plugin->output->get_rows(); \
781 for(int y = pkg->row1; y < pkg->row2; y++) \
783 type *output_row = out_rows[y]; \
785 for(int x = 0; x < w; x++) \
787 type *output_pixel = output_row + x * components; \
788 if(calc_undistorted_coords(x, \
792 plugin->config.depth, \
793 plugin->config.angle, \
794 plugin->config.polar_to_rectangular, \
795 plugin->config.backwards, \
796 plugin->config.invert, \
802 type *pixel1 = GET_PIXEL((int)cx, (int)cy, components, in_rows); \
803 type *pixel2 = GET_PIXEL((int)cx + 1, (int)cy, components, in_rows); \
804 type *pixel3 = GET_PIXEL((int)cx, (int)cy + 1, components, in_rows); \
805 type *pixel4 = GET_PIXEL((int)cx + 1, (int)cy + 1, components, in_rows); \
807 values[0] = pixel1[0]; \
808 values[1] = pixel2[0]; \
809 values[2] = pixel3[0]; \
810 values[3] = pixel4[0]; \
811 output_pixel[0] = (type)bilinear(cx, cy, values); \
813 values[0] = pixel1[1]; \
814 values[1] = pixel2[1]; \
815 values[2] = pixel3[1]; \
816 values[3] = pixel4[1]; \
817 output_pixel[1] = (type)bilinear(cx, cy, values); \
819 values[0] = pixel1[2]; \
820 values[1] = pixel2[2]; \
821 values[2] = pixel3[2]; \
822 values[3] = pixel4[2]; \
823 output_pixel[2] = (type)bilinear(cx, cy, values); \
825 if(components == 4) \
827 values[0] = pixel1[3]; \
828 values[1] = pixel2[3]; \
829 values[2] = pixel3[3]; \
830 values[3] = pixel4[3]; \
831 output_pixel[3] = (type)bilinear(cx, cy, values); \
836 output_pixel[0] = 0; \
837 output_pixel[1] = chroma_offset; \
838 output_pixel[2] = chroma_offset; \
839 if(components == 4) output_pixel[3] = max; \
846 void PolarUnit::process_package(LoadPackage *package)
848 PolarPackage *pkg = (PolarPackage*)package;
849 int w = plugin->input->get_w();
850 int h = plugin->input->get_h();
853 double cen_x = (double)(w - 1) / 2.0;
854 double cen_y = (double)(h - 1) / 2.0;
856 switch(plugin->input->get_color_model())
859 POLAR_MACRO(float, 1, 3, 0x0)
862 POLAR_MACRO(float, 1, 4, 0x0)
865 POLAR_MACRO(unsigned char, 0xff, 3, 0x0)
868 POLAR_MACRO(unsigned char, 0xff, 4, 0x0)
871 POLAR_MACRO(uint16_t, 0xffff, 3, 0x0)
873 case BC_RGBA16161616:
874 POLAR_MACRO(uint16_t, 0xffff, 4, 0x0)
877 POLAR_MACRO(unsigned char, 0xff, 3, 0x80)
880 POLAR_MACRO(unsigned char, 0xff, 4, 0x80)
883 POLAR_MACRO(uint16_t, 0xffff, 3, 0x8000)
885 case BC_YUVA16161616:
886 POLAR_MACRO(uint16_t, 0xffff, 4, 0x8000)
894 PolarEngine::PolarEngine(PolarEffect *plugin, int cpus)
895 : LoadServer(cpus, cpus)
897 this->plugin = plugin;
900 void PolarEngine::init_packages()
902 for(int i = 0; i < LoadServer::get_total_packages(); i++)
904 PolarPackage *pkg = (PolarPackage*)get_package(i);
905 pkg->row1 = plugin->input->get_h() * i / LoadServer::get_total_packages();
906 pkg->row2 = plugin->input->get_h() * (i + 1) / LoadServer::get_total_packages();
910 LoadClient* PolarEngine::new_client()
912 return new PolarUnit(plugin, this);
915 LoadPackage* PolarEngine::new_package()
917 return new PolarPackage;