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"
53 void copy_from(WaveConfig &src);
54 int equivalent(WaveConfig &src);
55 void interpolate(WaveConfig &prev,
67 class WaveSmear : public BC_Radial
70 WaveSmear(WaveEffect *plugin, WaveWindow *window, int x, int y);
76 class WaveBlacken : public BC_Radial
79 WaveBlacken(WaveEffect *plugin, WaveWindow *window, int x, int y);
86 class WaveReflective : public BC_CheckBox
89 WaveReflective(WaveEffect *plugin, int x, int y);
94 class WaveAmplitude : public BC_FSlider
97 WaveAmplitude(WaveEffect *plugin, int x, int y);
102 class WavePhase : public BC_FSlider
105 WavePhase(WaveEffect *plugin, int x, int y);
110 class WaveLength : public BC_FSlider
113 WaveLength(WaveEffect *plugin, int x, int y);
126 class WaveWindow : public PluginClientWindow
129 WaveWindow(WaveEffect *plugin);
131 void create_objects();
135 // WaveBlacken *blacken;
136 // WaveReflective *reflective;
137 WaveAmplitude *amplitude;
139 WaveLength *wavelength;
148 class WaveServer : public LoadServer
151 WaveServer(WaveEffect *plugin, int cpus);
152 void init_packages();
153 LoadClient* new_client();
154 LoadPackage* new_package();
158 class WavePackage : public LoadPackage
165 class WaveUnit : public LoadClient
168 WaveUnit(WaveEffect *plugin, WaveServer *server);
169 void process_package(LoadPackage *package);
181 class WaveEffect : public PluginVClient
184 WaveEffect(PluginServer *server);
187 PLUGIN_CLASS_MEMBERS(WaveConfig)
188 int process_realtime(VFrame *input, VFrame *output);
190 void save_data(KeyFrame *keyframe);
191 void read_data(KeyFrame *keyframe);
195 VFrame *input, *output;
211 WaveConfig::WaveConfig()
220 void WaveConfig::copy_from(WaveConfig &src)
222 this->mode = src.mode;
223 this->reflective = src.reflective;
224 this->amplitude = src.amplitude;
225 this->phase = src.phase;
226 this->wavelength = src.wavelength;
229 int WaveConfig::equivalent(WaveConfig &src)
232 (this->mode == src.mode) &&
233 EQUIV(this->reflective, src.reflective) &&
234 EQUIV(this->amplitude, src.amplitude) &&
235 EQUIV(this->phase, src.phase) &&
236 EQUIV(this->wavelength, src.wavelength);
239 void WaveConfig::interpolate(WaveConfig &prev,
245 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
246 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
248 this->amplitude = prev.amplitude * prev_scale + next.amplitude * next_scale;
249 this->phase = prev.phase * prev_scale + next.phase * next_scale;
250 this->wavelength = prev.wavelength * prev_scale + next.wavelength * next_scale;
251 this->mode = prev.mode;
252 this->reflective = prev.reflective;
262 WaveSmear::WaveSmear(WaveEffect *plugin, WaveWindow *window, int x, int y)
263 : BC_Radial(x, y, plugin->config.mode == SMEAR, _("Smear"))
265 this->plugin = plugin;
266 this->window = window;
268 int WaveSmear::handle_event()
270 plugin->config.mode = SMEAR;
271 window->update_mode();
272 plugin->send_configure_change();
279 WaveBlacken::WaveBlacken(WaveEffect *plugin, WaveWindow *window, int x, int y)
280 : BC_Radial(x, y, plugin->config.mode == BLACKEN, _("Blacken"))
282 this->plugin = plugin;
283 this->window = window;
285 int WaveBlacken::handle_event()
287 plugin->config.mode = BLACKEN;
288 window->update_mode();
289 plugin->send_configure_change();
298 WaveReflective::WaveReflective(WaveEffect *plugin, int x, int y)
299 : BC_CheckBox(x, y, plugin->config.reflective, _("Reflective"))
301 this->plugin = plugin;
303 int WaveReflective::handle_event()
305 plugin->config.reflective = get_value();
306 plugin->send_configure_change();
311 WaveAmplitude::WaveAmplitude(WaveEffect *plugin, int x, int y)
319 plugin->config.amplitude)
321 this->plugin = plugin;
323 int WaveAmplitude::handle_event()
325 plugin->config.amplitude = get_value();
326 plugin->send_configure_change();
332 WavePhase::WavePhase(WaveEffect *plugin, int x, int y)
340 plugin->config.phase)
342 this->plugin = plugin;
344 int WavePhase::handle_event()
346 plugin->config.phase = get_value();
347 plugin->send_configure_change();
351 WaveLength::WaveLength(WaveEffect *plugin, int x, int y)
359 plugin->config.wavelength)
361 this->plugin = plugin;
363 int WaveLength::handle_event()
365 plugin->config.wavelength = get_value();
366 plugin->send_configure_change();
378 WaveWindow::WaveWindow(WaveEffect *plugin)
379 : PluginClientWindow(plugin,
386 this->plugin = plugin;
389 WaveWindow::~WaveWindow()
393 void WaveWindow::create_objects()
395 int x = 10, y = 10, x1 = 100;
397 // add_subwindow(new BC_Title(x, y, _("Mode:")));
398 // add_subwindow(smear = new WaveSmear(plugin, this, x1, y));
400 // add_subwindow(blacken = new WaveBlacken(plugin, this, x1, y));
402 // add_subwindow(reflective = new WaveReflective(plugin, x1, y));
404 add_subwindow(new BC_Title(x, y, _("Amplitude:")));
405 add_subwindow(amplitude = new WaveAmplitude(plugin, x1, y));
407 add_subwindow(new BC_Title(x, y, _("Phase:")));
408 add_subwindow(phase = new WavePhase(plugin, x1, y));
410 add_subwindow(new BC_Title(x, y, _("Wavelength:")));
411 add_subwindow(wavelength = new WaveLength(plugin, x1, y));
417 void WaveWindow::update_mode()
419 // smear->update(plugin->config.mode == SMEAR);
420 // blacken->update(plugin->config.mode == BLACKEN);
429 REGISTER_PLUGIN(WaveEffect)
434 WaveEffect::WaveEffect(PluginServer *server)
435 : PluginVClient(server)
442 WaveEffect::~WaveEffect()
446 if(temp_frame) delete temp_frame;
447 if(engine) delete engine;
451 const char* WaveEffect::plugin_title() { return _("Wave"); }
452 int WaveEffect::is_realtime() { return 1; }
455 NEW_WINDOW_MACRO(WaveEffect, WaveWindow)
457 void WaveEffect::update_gui()
461 thread->window->lock_window();
462 load_configuration();
463 ((WaveWindow*)thread->window)->update_mode();
464 // thread->window->reflective->update(config.reflective);
465 ((WaveWindow*)thread->window)->amplitude->update(config.amplitude);
466 ((WaveWindow*)thread->window)->phase->update(config.phase);
467 ((WaveWindow*)thread->window)->wavelength->update(config.wavelength);
468 thread->window->unlock_window();
473 LOAD_CONFIGURATION_MACRO(WaveEffect, WaveConfig)
476 void WaveEffect::save_data(KeyFrame *keyframe)
480 // cause data to be stored directly in text
481 output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
482 output.tag.set_title("WAVE");
483 output.tag.set_property("MODE", config.mode);
484 output.tag.set_property("REFLECTIVE", config.reflective);
485 output.tag.set_property("AMPLITUDE", config.amplitude);
486 output.tag.set_property("PHASE", config.phase);
487 output.tag.set_property("WAVELENGTH", config.wavelength);
489 output.terminate_string();
492 void WaveEffect::read_data(KeyFrame *keyframe)
496 input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
498 while(!input.read_tag())
500 if(input.tag.title_is("WAVE"))
502 config.mode = input.tag.get_property("MODE", config.mode);
503 config.reflective = input.tag.get_property("REFLECTIVE", config.reflective);
504 config.amplitude = input.tag.get_property("AMPLITUDE", config.amplitude);
505 config.phase = input.tag.get_property("PHASE", config.phase);
506 config.wavelength = input.tag.get_property("WAVELENGTH", config.wavelength);
512 int WaveEffect::process_realtime(VFrame *input, VFrame *output)
514 load_configuration();
518 //printf("WaveEffect::process_realtime %f %d\n", config.radius, config.use_intensity);
520 this->output = output;
522 if(EQUIV(config.amplitude, 0) || EQUIV(config.wavelength, 0))
524 if(input->get_rows()[0] != output->get_rows()[0])
525 output->copy_from(input);
529 if(input->get_rows()[0] == output->get_rows()[0])
531 if(!temp_frame) temp_frame = new VFrame(0,
535 input->get_color_model(),
537 temp_frame->copy_from(input);
538 this->input = temp_frame;
544 engine = new WaveServer(this, (PluginClient::smp + 1));
547 engine->process_packages();
560 WavePackage::WavePackage()
570 WaveUnit::WaveUnit(WaveEffect *plugin, WaveServer *server)
573 this->plugin = plugin;
578 #define WITHIN(a, b, c) ((((a) <= (b)) && ((b) <= (c))) ? 1 : 0)
580 static float bilinear(double x,
593 m0 = (1.0 - x) * v[0] + x * v[1];
594 m1 = (1.0 - x) * v[2] + x * v[3];
596 return((1.0 - y) * m0 + y * m1);
599 void WaveUnit::process_package(LoadPackage *package)
601 WavePackage *pkg = (WavePackage*)package;
602 int w = plugin->input->get_w();
603 int h = plugin->input->get_h();
604 double cen_x, cen_y; /* Center of wave */
605 double xhsiz, yhsiz; /* Half size of selection */
606 double radius; /* Radius */
610 double xscale, yscale;
616 int x1_in, y1_in, x2_in, y2_in;
617 double phase = plugin->config.phase * M_PI / 180;
623 cen_x = (double) (x2 - 1 + x1) / 2.0;
624 cen_y = (double) (y2 - 1 + y1) / 2.0;
625 xhsiz = (double) (x2 - x1) / 2.0;
626 yhsiz = (double) (y2 - y1) / 2.0;
630 xscale = yhsiz / xhsiz;
633 else if (xhsiz > yhsiz)
636 yscale = xhsiz / yhsiz;
644 radius = MAX(xhsiz, yhsiz);
647 wavelength = plugin->config.wavelength / 100 * radius;
652 #define WAVE(type, components, chroma_offset) \
654 int row_size = w * components; \
655 type **in_rows = (type**)plugin->input->get_rows(); \
656 for(int y = pkg->row1; y < pkg->row2; y++) \
658 type *dest = (type*)plugin->output->get_rows()[y]; \
660 for(int x = x1; x < x2; x++) \
662 dx = (x - cen_x) * xscale; \
663 dy = (y - cen_y) * yscale; \
664 d = sqrt(dx * dx + dy * dy); \
666 if(plugin->config.reflective) \
668 amnt = plugin->config.amplitude * \
669 fabs(sin(((d / wavelength) * \
673 needx = (amnt * dx) / xscale + cen_x; \
674 needy = (amnt * dy) / yscale + cen_y; \
678 amnt = plugin->config.amplitude * \
679 sin(((d / wavelength) * \
683 needx = (amnt + dx) / xscale + cen_x; \
684 needy = (amnt + dy) / yscale + cen_y; \
690 if(plugin->config.mode == SMEAR) \
713 type *p = in_rows[CLIP(yi, 0, h - 1)] + \
714 CLIP(xi, 0, w - 1) * components; \
715 x1_in = WITHIN(0, xi, w - 1); \
716 y1_in = WITHIN(0, yi, h - 1); \
717 x2_in = WITHIN(0, xi + 1, w - 1); \
718 y2_in = WITHIN(0, yi + 1, h - 1); \
721 for(int k = 0; k < components; k++) \
723 if (x1_in && y1_in) \
724 values[0] = *(p + k); \
726 values[0] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
728 if (x2_in && y1_in) \
729 values[1] = *(p + components + k); \
731 values[1] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
733 if (x1_in && y2_in) \
734 values[2] = *(p + row_size + k); \
736 values[2] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
741 values[3] = *(p + row_size + components + k); \
743 values[3] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
746 values[3] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
748 val = bilinear(needx, needy, values); \
750 *dest++ = (type)val; \
759 switch(plugin->input->get_color_model())
762 WAVE(unsigned char, 3, 0x0);
768 WAVE(unsigned char, 3, 0x80);
771 WAVE(uint16_t, 3, 0x0);
774 WAVE(uint16_t, 3, 0x8000);
777 WAVE(unsigned char, 4, 0x0);
780 WAVE(unsigned char, 4, 0x0);
783 WAVE(unsigned char, 4, 0x8000);
785 case BC_RGBA16161616:
786 WAVE(uint16_t, 4, 0x0);
788 case BC_YUVA16161616:
789 WAVE(uint16_t, 4, 0x8000);
803 WaveServer::WaveServer(WaveEffect *plugin, int cpus)
804 : LoadServer(cpus, cpus)
806 this->plugin = plugin;
809 void WaveServer::init_packages()
811 for(int i = 0; i < LoadServer::get_total_packages(); i++)
813 WavePackage *pkg = (WavePackage*)get_package(i);
814 pkg->row1 = plugin->input->get_h() * i / LoadServer::get_total_packages();
815 pkg->row2 = plugin->input->get_h() * (i + 1) / LoadServer::get_total_packages();
820 LoadClient* WaveServer::new_client()
822 return new WaveUnit(plugin, this);
825 LoadPackage* WaveServer::new_package()
827 return new WavePackage;