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, 335, 150, 335, 150, 0)
381 this->plugin = plugin;
384 WaveWindow::~WaveWindow()
388 void WaveWindow::create_objects()
390 int x = 10, y = 10, x1 = 115;
392 // add_subwindow(new BC_Title(x, y, _("Mode:")));
393 // add_subwindow(smear = new WaveSmear(plugin, this, x1, y));
395 // add_subwindow(blacken = new WaveBlacken(plugin, this, x1, y));
397 // add_subwindow(reflective = new WaveReflective(plugin, x1, y));
399 add_subwindow(new BC_Title(x, y, _("Amplitude:")));
400 add_subwindow(amplitude = new WaveAmplitude(plugin, x1, y));
402 add_subwindow(new BC_Title(x, y, _("Phase:")));
403 add_subwindow(phase = new WavePhase(plugin, x1, y));
405 add_subwindow(new BC_Title(x, y, _("Wavelength:")));
406 add_subwindow(wavelength = new WaveLength(plugin, x1, y));
412 void WaveWindow::update_mode()
414 // smear->update(plugin->config.mode == SMEAR);
415 // blacken->update(plugin->config.mode == BLACKEN);
424 REGISTER_PLUGIN(WaveEffect)
429 WaveEffect::WaveEffect(PluginServer *server)
430 : PluginVClient(server)
437 WaveEffect::~WaveEffect()
441 if(temp_frame) delete temp_frame;
442 if(engine) delete engine;
446 const char* WaveEffect::plugin_title() { return N_("Wave"); }
447 int WaveEffect::is_realtime() { return 1; }
450 NEW_WINDOW_MACRO(WaveEffect, WaveWindow)
452 void WaveEffect::update_gui()
456 thread->window->lock_window();
457 load_configuration();
458 ((WaveWindow*)thread->window)->update_mode();
459 // thread->window->reflective->update(config.reflective);
460 ((WaveWindow*)thread->window)->amplitude->update(config.amplitude);
461 ((WaveWindow*)thread->window)->phase->update(config.phase);
462 ((WaveWindow*)thread->window)->wavelength->update(config.wavelength);
463 thread->window->unlock_window();
468 LOAD_CONFIGURATION_MACRO(WaveEffect, WaveConfig)
471 void WaveEffect::save_data(KeyFrame *keyframe)
475 // cause data to be stored directly in text
476 output.set_shared_output(keyframe->xbuf);
477 output.tag.set_title("WAVE");
478 output.tag.set_property("MODE", config.mode);
479 output.tag.set_property("REFLECTIVE", config.reflective);
480 output.tag.set_property("AMPLITUDE", config.amplitude);
481 output.tag.set_property("PHASE", config.phase);
482 output.tag.set_property("WAVELENGTH", config.wavelength);
484 output.tag.set_title("/WAVE");
486 output.append_newline();
487 output.terminate_string();
490 void WaveEffect::read_data(KeyFrame *keyframe)
494 input.set_shared_input(keyframe->xbuf);
496 while(!input.read_tag())
498 if(input.tag.title_is("WAVE"))
500 config.mode = input.tag.get_property("MODE", config.mode);
501 config.reflective = input.tag.get_property("REFLECTIVE", config.reflective);
502 config.amplitude = input.tag.get_property("AMPLITUDE", config.amplitude);
503 config.phase = input.tag.get_property("PHASE", config.phase);
504 config.wavelength = input.tag.get_property("WAVELENGTH", config.wavelength);
510 int WaveEffect::process_realtime(VFrame *input, VFrame *output)
512 load_configuration();
516 //printf("WaveEffect::process_realtime %f %d\n", config.radius, config.use_intensity);
518 this->output = output;
520 if(EQUIV(config.amplitude, 0) || EQUIV(config.wavelength, 0))
522 if(input->get_rows()[0] != output->get_rows()[0])
523 output->copy_from(input);
527 if(input->get_rows()[0] == output->get_rows()[0])
529 if(!temp_frame) temp_frame = new VFrame(input->get_w(), input->get_h(),
530 input->get_color_model(), 0);
531 temp_frame->copy_from(input);
532 this->input = temp_frame;
538 engine = new WaveServer(this, (PluginClient::smp + 1));
541 engine->process_packages();
554 WavePackage::WavePackage()
564 WaveUnit::WaveUnit(WaveEffect *plugin, WaveServer *server)
567 this->plugin = plugin;
572 #define WITHIN(a, b, c) ((((a) <= (b)) && ((b) <= (c))) ? 1 : 0)
574 static float bilinear(double x,
587 m0 = (1.0 - x) * v[0] + x * v[1];
588 m1 = (1.0 - x) * v[2] + x * v[3];
590 return((1.0 - y) * m0 + y * m1);
593 void WaveUnit::process_package(LoadPackage *package)
595 WavePackage *pkg = (WavePackage*)package;
596 int w = plugin->input->get_w();
597 int h = plugin->input->get_h();
598 double cen_x, cen_y; /* Center of wave */
599 double xhsiz, yhsiz; /* Half size of selection */
600 double radius; /* Radius */
604 double xscale, yscale;
610 int x1_in, y1_in, x2_in, y2_in;
611 double phase = plugin->config.phase * M_PI / 180;
617 cen_x = (double) (x2 - 1 + x1) / 2.0;
618 cen_y = (double) (y2 - 1 + y1) / 2.0;
619 xhsiz = (double) (x2 - x1) / 2.0;
620 yhsiz = (double) (y2 - y1) / 2.0;
624 xscale = yhsiz / xhsiz;
627 else if (xhsiz > yhsiz)
630 yscale = xhsiz / yhsiz;
638 radius = MAX(xhsiz, yhsiz);
641 wavelength = plugin->config.wavelength / 100 * radius;
646 #define WAVE(type, components, chroma_offset) \
648 int row_size = w * components; \
649 type **in_rows = (type**)plugin->input->get_rows(); \
650 for(int y = pkg->row1; y < pkg->row2; y++) \
652 type *dest = (type*)plugin->output->get_rows()[y]; \
654 for(int x = x1; x < x2; x++) \
656 dx = (x - cen_x) * xscale; \
657 dy = (y - cen_y) * yscale; \
658 d = sqrt(dx * dx + dy * dy); \
660 if(plugin->config.reflective) \
662 amnt = plugin->config.amplitude * \
663 fabs(sin(((d / wavelength) * \
667 needx = (amnt * dx) / xscale + cen_x; \
668 needy = (amnt * dy) / yscale + cen_y; \
672 amnt = plugin->config.amplitude * \
673 sin(((d / wavelength) * \
677 needx = (amnt + dx) / xscale + cen_x; \
678 needy = (amnt + dy) / yscale + cen_y; \
684 if(plugin->config.mode == SMEAR) \
707 type *p = in_rows[CLIP(yi, 0, h - 1)] + \
708 CLIP(xi, 0, w - 1) * components; \
709 x1_in = WITHIN(0, xi, w - 1); \
710 y1_in = WITHIN(0, yi, h - 1); \
711 x2_in = WITHIN(0, xi + 1, w - 1); \
712 y2_in = WITHIN(0, yi + 1, h - 1); \
715 for(int k = 0; k < components; k++) \
717 if (x1_in && y1_in) \
718 values[0] = *(p + k); \
720 values[0] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
722 if (x2_in && y1_in) \
723 values[1] = *(p + components + k); \
725 values[1] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
727 if (x1_in && y2_in) \
728 values[2] = *(p + row_size + k); \
730 values[2] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
735 values[3] = *(p + row_size + components + k); \
737 values[3] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
740 values[3] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
742 val = bilinear(needx, needy, values); \
744 *dest++ = (type)val; \
753 switch(plugin->input->get_color_model())
756 WAVE(unsigned char, 3, 0x0);
762 WAVE(unsigned char, 3, 0x80);
765 WAVE(uint16_t, 3, 0x0);
768 WAVE(uint16_t, 3, 0x8000);
771 WAVE(unsigned char, 4, 0x0);
774 WAVE(unsigned char, 4, 0x0);
777 WAVE(unsigned char, 4, 0x8000);
779 case BC_RGBA16161616:
780 WAVE(uint16_t, 4, 0x0);
782 case BC_YUVA16161616:
783 WAVE(uint16_t, 4, 0x8000);
797 WaveServer::WaveServer(WaveEffect *plugin, int cpus)
798 : LoadServer(cpus, cpus)
800 this->plugin = plugin;
803 void WaveServer::init_packages()
805 for(int i = 0; i < LoadServer::get_total_packages(); i++)
807 WavePackage *pkg = (WavePackage*)get_package(i);
808 pkg->row1 = plugin->input->get_h() * i / LoadServer::get_total_packages();
809 pkg->row2 = plugin->input->get_h() * (i + 1) / LoadServer::get_total_packages();
814 LoadClient* WaveServer::new_client()
816 return new WaveUnit(plugin, this);
819 LoadPackage* WaveServer::new_package()
821 return new WavePackage;