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"
39 #define WITHIN(a, b, c) ((((a) <= (b)) && ((b) <= (c))) ? 1 : 0)
52 void copy_from(PolarConfig &src);
53 int equivalent(PolarConfig &src);
54 void interpolate(PolarConfig &prev,
60 int polar_to_rectangular;
69 class PolarDepth : public BC_FSlider
72 PolarDepth(PolarEffect *plugin, int x, int y);
77 class PolarAngle : public BC_FSlider
80 PolarAngle(PolarEffect *plugin, int x, int y);
85 class PolarWindow : public PluginClientWindow
88 PolarWindow(PolarEffect *plugin);
89 void create_objects();
99 class PolarPackage : public LoadPackage
106 class PolarUnit : public LoadClient
109 PolarUnit(PolarEffect *plugin, PolarEngine *server);
110 void process_package(LoadPackage *package);
114 class PolarEngine : public LoadServer
117 PolarEngine(PolarEffect *plugin, int cpus);
118 void init_packages();
119 LoadClient* new_client();
120 LoadPackage* new_package();
124 class PolarEffect : public PluginVClient
127 PolarEffect(PluginServer *server);
130 PLUGIN_CLASS_MEMBERS(PolarConfig)
131 int process_realtime(VFrame *input, VFrame *output);
133 void save_data(KeyFrame *keyframe);
134 void read_data(KeyFrame *keyframe);
139 VFrame *input, *output;
140 int need_reconfigure;
145 REGISTER_PLUGIN(PolarEffect)
149 PolarConfig::PolarConfig()
155 polar_to_rectangular = 1;
159 void PolarConfig::copy_from(PolarConfig &src)
161 this->angle = src.angle;
162 this->depth = src.depth;
163 this->backwards = src.backwards;
164 this->invert = src.invert;
165 this->polar_to_rectangular = src.polar_to_rectangular;
168 int PolarConfig::equivalent(PolarConfig &src)
170 return EQUIV(this->angle, src.angle) && EQUIV(this->depth, src.depth);
173 void PolarConfig::interpolate(PolarConfig &prev,
179 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
180 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
182 this->depth = prev.depth * prev_scale + next.depth * next_scale;
183 this->angle = prev.angle * prev_scale + next.angle * next_scale;
191 PolarWindow::PolarWindow(PolarEffect *plugin)
192 : PluginClientWindow(plugin,
199 this->plugin = plugin;
202 void PolarWindow::create_objects()
205 add_subwindow(new BC_Title(x, y, _("Depth:")));
206 add_subwindow(depth = new PolarDepth(plugin, x + 50, y));
208 add_subwindow(new BC_Title(x, y, _("Angle:")));
209 add_subwindow(angle = new PolarAngle(plugin, x + 50, y));
221 PolarDepth::PolarDepth(PolarEffect *plugin, int x, int y)
229 plugin->config.depth)
231 this->plugin = plugin;
233 int PolarDepth::handle_event()
235 plugin->config.depth = get_value();
236 plugin->send_configure_change();
244 PolarAngle::PolarAngle(PolarEffect *plugin, int x, int y)
252 plugin->config.angle)
254 this->plugin = plugin;
256 int PolarAngle::handle_event()
258 plugin->config.angle = get_value();
259 plugin->send_configure_change();
267 PolarEffect::PolarEffect(PluginServer *server)
268 : PluginVClient(server)
270 need_reconfigure = 1;
276 PolarEffect::~PolarEffect()
279 if(temp_frame) delete temp_frame;
280 if(engine) delete engine;
285 const char* PolarEffect::plugin_title() { return _("Polar"); }
286 int PolarEffect::is_realtime() { return 1; }
291 NEW_WINDOW_MACRO(PolarEffect, PolarWindow)
293 void PolarEffect::update_gui()
297 load_configuration();
298 thread->window->lock_window();
299 ((PolarWindow*)thread->window)->angle->update(config.angle);
300 ((PolarWindow*)thread->window)->depth->update(config.depth);
301 thread->window->unlock_window();
305 LOAD_CONFIGURATION_MACRO(PolarEffect, PolarConfig)
309 void PolarEffect::save_data(KeyFrame *keyframe)
313 // cause data to be stored directly in text
314 output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
315 output.tag.set_title("POLAR");
316 output.tag.set_property("DEPTH", config.depth);
317 output.tag.set_property("ANGLE", config.angle);
319 output.tag.set_title("/POLAR");
321 output.append_newline();
322 output.terminate_string();
325 void PolarEffect::read_data(KeyFrame *keyframe)
329 input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
331 while(!input.read_tag())
333 if(input.tag.title_is("POLAR"))
335 config.depth = input.tag.get_property("DEPTH", config.depth);
336 config.angle = input.tag.get_property("ANGLE", config.angle);
341 int PolarEffect::process_realtime(VFrame *input, VFrame *output)
343 need_reconfigure |= load_configuration();
346 this->output = output;
348 if(EQUIV(config.depth, 0) || EQUIV(config.angle, 0))
350 if(input->get_rows()[0] != output->get_rows()[0])
351 output->copy_from(input);
355 if(input->get_rows()[0] == output->get_rows()[0])
357 if(!temp_frame) temp_frame = new VFrame(0,
361 input->get_color_model(),
363 temp_frame->copy_from(input);
364 this->input = temp_frame;
368 if(!engine) engine = new PolarEngine(this, PluginClient::smp + 1);
370 engine->process_packages();
379 PolarPackage::PolarPackage()
387 PolarUnit::PolarUnit(PolarEffect *plugin, PolarEngine *server)
390 this->plugin = plugin;
394 static int calc_undistorted_coords(int wx,
400 int polar_to_rectangular,
410 double xx, xm, ym, yy;
414 double xmax, ymax, rmax;
415 double x_calc, y_calc;
417 double circle, angl, t;
435 angl = (double)angle / 180.0 * M_PI;
437 if(polar_to_rectangular)
444 atan(((double)(wx - cen_x)) /
445 ((double)(wy - cen_y)));
446 r = sqrt(SQR(wx - cen_x) +
452 phi = atan(((double)(wx - cen_x)) /
453 ((double)(cen_y - wy)));
454 r = sqrt(SQR(wx - cen_x) +
469 atan(((double)(cen_x -wx)) /
470 ((double)(cen_y - wy)));
471 r = sqrt(SQR(cen_x - wx) +
478 atan(((double)(cen_x - wx)) /
479 ((double)(wy - cen_y)));
480 r = sqrt(SQR(cen_x - wx) +
491 m = fabs(((double)(wy - cen_y)) /
492 ((double)(wx - cen_x)));
499 if(m <= ((double)(y2 - y1) /
519 rmax = sqrt((double)(SQR(xmax) + SQR(ymax)));
521 t = ((cen_y - y1) < (cen_x - x1)) ? (cen_y - y1) : (cen_x - x1);
522 rmax = (rmax - t) / 100 * (100 - circle) + t;
524 phi = fmod(phi + angl, 2 * M_PI);
527 x_calc = x2 - 1 - (x2 - x1 - 1) / (2 * M_PI) * phi;
529 x_calc = (x2 - x1 - 1) / (2 * M_PI) * phi + x1;
532 y_calc = (y2 - y1) / rmax * r + y1;
534 y_calc = y2 - (y2 - y1) / rmax * r;
536 xi = (int)(x_calc + 0.5);
537 yi = (int)(y_calc + 0.5);
539 if(WITHIN(0, xi, w - 1) && WITHIN(0, yi, h - 1))
554 phi = (2 * M_PI) * (x2 - wx) / xdiff;
556 phi = (2 * M_PI) * (wx - x1) / xdiff;
558 phi = fmod (phi + angl, 2 * M_PI);
560 if(phi >= 1.5 * M_PI)
561 phi2 = 2 * M_PI - phi;
566 if(phi >= 0.5 * M_PI)
573 m = (double)1.0 / xx;
577 if(m <= ((double)(ydiff) / (double)(xdiff)))
596 rmax = sqrt((double)(SQR(xmax) + SQR(ymax)));
598 t = ((ym - y1) < (xm - x1)) ? (ym - y1) : (xm - x1);
600 rmax = (rmax - t) / 100.0 * (100 - circle) + t;
603 r = rmax * (double)((wy - y1) / (double)(ydiff));
605 r = rmax * (double)((y2 - wy) / (double)(ydiff));
610 if(phi >= 1.5 * M_PI)
612 x_calc = (double)xm - xx;
613 y_calc = (double)ym - yy;
618 x_calc = (double)xm - xx;
619 y_calc = (double)ym + yy;
622 if(phi >= 0.5 * M_PI)
624 x_calc = (double)xm + xx;
625 y_calc = (double)ym + yy;
629 x_calc = (double)xm + xx;
630 y_calc = (double)ym - yy;
633 xi = (int)(x_calc + 0.5);
634 yi = (int)(y_calc + 0.5);
636 if(WITHIN(0, xi, w - 1) &&
637 WITHIN(0, yi, h - 1))
653 static double bilinear(double x, double y, double *values)
659 if(x < 0.0) x += 1.0;
660 if(y < 0.0) y += 1.0;
662 m0 = values[0] + x * (values[1] - values[0]);
663 m1 = values[2] + x * (values[3] - values[2]);
664 return m0 + y * (m1 - m0);
667 #define GET_PIXEL(x, y, components, input_rows) \
668 input_rows[CLIP((y), 0, ((h) - 1))] + components * CLIP((x), 0, ((w) - 1))
670 #define POLAR_MACRO(type, max, components, chroma_offset) \
672 type **in_rows = (type**)plugin->input->get_rows(); \
673 type **out_rows = (type**)plugin->output->get_rows(); \
676 for(int y = pkg->row1; y < pkg->row2; y++) \
678 type *output_row = out_rows[y]; \
680 for(int x = 0; x < w; x++) \
682 type *output_pixel = output_row + x * components; \
683 if(calc_undistorted_coords(x, \
687 plugin->config.depth, \
688 plugin->config.angle, \
689 plugin->config.polar_to_rectangular, \
690 plugin->config.backwards, \
691 plugin->config.invert, \
697 type *pixel1 = GET_PIXEL((int)cx, (int)cy, components, in_rows); \
698 type *pixel2 = GET_PIXEL((int)cx + 1, (int)cy, components, in_rows); \
699 type *pixel3 = GET_PIXEL((int)cx, (int)cy + 1, components, in_rows); \
700 type *pixel4 = GET_PIXEL((int)cx + 1, (int)cy + 1, components, in_rows); \
702 values[0] = pixel1[0]; \
703 values[1] = pixel2[0]; \
704 values[2] = pixel3[0]; \
705 values[3] = pixel4[0]; \
706 output_pixel[0] = (type)bilinear(cx, cy, values); \
708 values[0] = pixel1[1]; \
709 values[1] = pixel2[1]; \
710 values[2] = pixel3[1]; \
711 values[3] = pixel4[1]; \
712 output_pixel[1] = (type)bilinear(cx, cy, values); \
714 values[0] = pixel1[2]; \
715 values[1] = pixel2[2]; \
716 values[2] = pixel3[2]; \
717 values[3] = pixel4[2]; \
718 output_pixel[2] = (type)bilinear(cx, cy, values); \
720 if(components == 4) \
722 values[0] = pixel1[3]; \
723 values[1] = pixel2[3]; \
724 values[2] = pixel3[3]; \
725 values[3] = pixel4[3]; \
726 output_pixel[3] = (type)bilinear(cx, cy, values); \
731 output_pixel[0] = 0; \
732 output_pixel[1] = chroma_offset; \
733 output_pixel[2] = chroma_offset; \
734 if(components == 4) output_pixel[3] = max; \
741 void PolarUnit::process_package(LoadPackage *package)
743 PolarPackage *pkg = (PolarPackage*)package;
744 int w = plugin->input->get_w();
745 int h = plugin->input->get_h();
748 double cen_x = (double)(w - 1) / 2.0;
749 double cen_y = (double)(h - 1) / 2.0;
751 switch(plugin->input->get_color_model())
754 POLAR_MACRO(float, 1, 3, 0x0)
757 POLAR_MACRO(float, 1, 4, 0x0)
760 POLAR_MACRO(unsigned char, 0xff, 3, 0x0)
763 POLAR_MACRO(unsigned char, 0xff, 4, 0x0)
766 POLAR_MACRO(uint16_t, 0xffff, 3, 0x0)
768 case BC_RGBA16161616:
769 POLAR_MACRO(uint16_t, 0xffff, 4, 0x0)
772 POLAR_MACRO(unsigned char, 0xff, 3, 0x80)
775 POLAR_MACRO(unsigned char, 0xff, 4, 0x80)
778 POLAR_MACRO(uint16_t, 0xffff, 3, 0x8000)
780 case BC_YUVA16161616:
781 POLAR_MACRO(uint16_t, 0xffff, 4, 0x8000)
789 PolarEngine::PolarEngine(PolarEffect *plugin, int cpus)
790 : LoadServer(cpus, cpus)
792 this->plugin = plugin;
795 void PolarEngine::init_packages()
797 for(int i = 0; i < LoadServer::get_total_packages(); i++)
799 PolarPackage *pkg = (PolarPackage*)get_package(i);
800 pkg->row1 = plugin->input->get_h() * i / LoadServer::get_total_packages();
801 pkg->row2 = plugin->input->get_h() * (i + 1) / LoadServer::get_total_packages();
805 LoadClient* PolarEngine::new_client()
807 return new PolarUnit(plugin, this);
810 LoadPackage* PolarEngine::new_package()
812 return new PolarPackage;