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 _("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->get_data(), MESSAGESIZE);
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->get_data(), strlen(keyframe->get_data()));
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(0,
533 input->get_color_model(),
535 temp_frame->copy_from(input);
536 this->input = temp_frame;
542 engine = new WaveServer(this, (PluginClient::smp + 1));
545 engine->process_packages();
558 WavePackage::WavePackage()
568 WaveUnit::WaveUnit(WaveEffect *plugin, WaveServer *server)
571 this->plugin = plugin;
576 #define WITHIN(a, b, c) ((((a) <= (b)) && ((b) <= (c))) ? 1 : 0)
578 static float bilinear(double x,
591 m0 = (1.0 - x) * v[0] + x * v[1];
592 m1 = (1.0 - x) * v[2] + x * v[3];
594 return((1.0 - y) * m0 + y * m1);
597 void WaveUnit::process_package(LoadPackage *package)
599 WavePackage *pkg = (WavePackage*)package;
600 int w = plugin->input->get_w();
601 int h = plugin->input->get_h();
602 double cen_x, cen_y; /* Center of wave */
603 double xhsiz, yhsiz; /* Half size of selection */
604 double radius; /* Radius */
608 double xscale, yscale;
614 int x1_in, y1_in, x2_in, y2_in;
615 double phase = plugin->config.phase * M_PI / 180;
621 cen_x = (double) (x2 - 1 + x1) / 2.0;
622 cen_y = (double) (y2 - 1 + y1) / 2.0;
623 xhsiz = (double) (x2 - x1) / 2.0;
624 yhsiz = (double) (y2 - y1) / 2.0;
628 xscale = yhsiz / xhsiz;
631 else if (xhsiz > yhsiz)
634 yscale = xhsiz / yhsiz;
642 radius = MAX(xhsiz, yhsiz);
645 wavelength = plugin->config.wavelength / 100 * radius;
650 #define WAVE(type, components, chroma_offset) \
652 int row_size = w * components; \
653 type **in_rows = (type**)plugin->input->get_rows(); \
654 for(int y = pkg->row1; y < pkg->row2; y++) \
656 type *dest = (type*)plugin->output->get_rows()[y]; \
658 for(int x = x1; x < x2; x++) \
660 dx = (x - cen_x) * xscale; \
661 dy = (y - cen_y) * yscale; \
662 d = sqrt(dx * dx + dy * dy); \
664 if(plugin->config.reflective) \
666 amnt = plugin->config.amplitude * \
667 fabs(sin(((d / wavelength) * \
671 needx = (amnt * dx) / xscale + cen_x; \
672 needy = (amnt * dy) / yscale + cen_y; \
676 amnt = plugin->config.amplitude * \
677 sin(((d / wavelength) * \
681 needx = (amnt + dx) / xscale + cen_x; \
682 needy = (amnt + dy) / yscale + cen_y; \
688 if(plugin->config.mode == SMEAR) \
711 type *p = in_rows[CLIP(yi, 0, h - 1)] + \
712 CLIP(xi, 0, w - 1) * components; \
713 x1_in = WITHIN(0, xi, w - 1); \
714 y1_in = WITHIN(0, yi, h - 1); \
715 x2_in = WITHIN(0, xi + 1, w - 1); \
716 y2_in = WITHIN(0, yi + 1, h - 1); \
719 for(int k = 0; k < components; k++) \
721 if (x1_in && y1_in) \
722 values[0] = *(p + k); \
724 values[0] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
726 if (x2_in && y1_in) \
727 values[1] = *(p + components + k); \
729 values[1] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
731 if (x1_in && y2_in) \
732 values[2] = *(p + row_size + k); \
734 values[2] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
739 values[3] = *(p + row_size + components + k); \
741 values[3] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
744 values[3] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
746 val = bilinear(needx, needy, values); \
748 *dest++ = (type)val; \
757 switch(plugin->input->get_color_model())
760 WAVE(unsigned char, 3, 0x0);
766 WAVE(unsigned char, 3, 0x80);
769 WAVE(uint16_t, 3, 0x0);
772 WAVE(uint16_t, 3, 0x8000);
775 WAVE(unsigned char, 4, 0x0);
778 WAVE(unsigned char, 4, 0x0);
781 WAVE(unsigned char, 4, 0x8000);
783 case BC_RGBA16161616:
784 WAVE(uint16_t, 4, 0x0);
786 case BC_YUVA16161616:
787 WAVE(uint16_t, 4, 0x8000);
801 WaveServer::WaveServer(WaveEffect *plugin, int cpus)
802 : LoadServer(cpus, cpus)
804 this->plugin = plugin;
807 void WaveServer::init_packages()
809 for(int i = 0; i < LoadServer::get_total_packages(); i++)
811 WavePackage *pkg = (WavePackage*)get_package(i);
812 pkg->row1 = plugin->input->get_h() * i / LoadServer::get_total_packages();
813 pkg->row2 = plugin->input->get_h() * (i + 1) / LoadServer::get_total_packages();
818 LoadClient* WaveServer::new_client()
820 return new WaveUnit(plugin, this);
823 LoadPackage* WaveServer::new_package()
825 return new WavePackage;