Condense the xml-cleanup into a short feature-branch
[cinelerra_cv/mob.git] / plugins / wave / wave.C
blob57ff3b4c2ca6461273c887a9a174feacd0e6745b
1 #include "bcdisplayinfo.h"
2 #include "clip.h"
3 #include "bchash.h"
4 #include "filexml.h"
5 #include "guicast.h"
6 #include "keyframe.h"
7 #include "language.h"
8 #include "loadbalance.h"
9 #include "picon_png.h"
10 #include "pluginvclient.h"
11 #include "vframe.h"
13 #include <math.h>
14 #include <stdint.h>
15 #include <string.h>
20 #define SMEAR 0
21 #define BLACKEN 1
25 class WaveEffect;
26 class WaveWindow;
29 class WaveConfig
31 public:
32         WaveConfig();
33         void copy_from(WaveConfig &src);
34         int equivalent(WaveConfig &src);
35         void interpolate(WaveConfig &prev, 
36                 WaveConfig &next, 
37                 long prev_frame, 
38                 long next_frame, 
39                 long current_frame);
40         int mode;
41         int reflective;
42         float amplitude;
43         float phase;
44         float wavelength;
47 class WaveSmear : public BC_Radial
49 public:
50         WaveSmear(WaveEffect *plugin, WaveWindow *window, int x, int y);
51         int handle_event();
52         WaveEffect *plugin;
53         WaveWindow *window;
56 class WaveBlacken : public BC_Radial
58 public:
59         WaveBlacken(WaveEffect *plugin, WaveWindow *window, int x, int y);
60         int handle_event();
61         WaveEffect *plugin;
62         WaveWindow *window;
66 class WaveReflective : public BC_CheckBox
68 public:
69         WaveReflective(WaveEffect *plugin, int x, int y);
70         int handle_event();
71         WaveEffect *plugin;
74 class WaveAmplitude : public BC_FSlider
76 public:
77         WaveAmplitude(WaveEffect *plugin, int x, int y);
78         int handle_event();
79         WaveEffect *plugin;
82 class WavePhase : public BC_FSlider
84 public:
85         WavePhase(WaveEffect *plugin, int x, int y);
86         int handle_event();
87         WaveEffect *plugin;
90 class WaveLength : public BC_FSlider
92 public:
93         WaveLength(WaveEffect *plugin, int x, int y);
94         int handle_event();
95         WaveEffect *plugin;
106 class WaveWindow : public BC_Window
108 public:
109         WaveWindow(WaveEffect *plugin, int x, int y);
110         ~WaveWindow();
111         void create_objects();
112         int close_event();
113         void update_mode();
114         WaveEffect *plugin;
115 //      WaveSmear *smear;
116 //      WaveBlacken *blacken;
117 //      WaveReflective *reflective;
118         WaveAmplitude *amplitude;
119         WavePhase *phase;
120         WaveLength *wavelength;
124 PLUGIN_THREAD_HEADER(WaveEffect, WaveThread, WaveWindow)
130 class WaveServer : public LoadServer
132 public:
133         WaveServer(WaveEffect *plugin, int cpus);
134         void init_packages();
135         LoadClient* new_client();
136         LoadPackage* new_package();
137         WaveEffect *plugin;
140 class WavePackage : public LoadPackage
142 public:
143         WavePackage();
144         int row1, row2;
147 class WaveUnit : public LoadClient
149 public:
150         WaveUnit(WaveEffect *plugin, WaveServer *server);
151         void process_package(LoadPackage *package);
152         WaveEffect *plugin;
163 class WaveEffect : public PluginVClient
165 public:
166         WaveEffect(PluginServer *server);
167         ~WaveEffect();
169         int process_realtime(VFrame *input, VFrame *output);
170         int is_realtime();
171         char* plugin_title();
172         VFrame* new_picon();
173         int load_configuration();
174         int load_defaults();
175         int save_defaults();
176         void save_data(KeyFrame *keyframe);
177         void read_data(KeyFrame *keyframe);
178         int show_gui();
179         int set_string();
180         void raise_window();
181         void update_gui();
183         WaveConfig config;
184         VFrame *temp_frame;
185         VFrame *input, *output;
186         BC_Hash *defaults;
187         WaveThread *thread;
188         WaveServer *engine;
203 WaveConfig::WaveConfig()
205         mode = SMEAR;
206         reflective = 0;
207         amplitude = 10;
208         phase = 0;
209         wavelength = 10;
212 void WaveConfig::copy_from(WaveConfig &src)
214         this->mode = src.mode;
215         this->reflective = src.reflective;
216         this->amplitude = src.amplitude;
217         this->phase = src.phase;
218         this->wavelength = src.wavelength;
221 int WaveConfig::equivalent(WaveConfig &src)
223         return 
224                 (this->mode == src.mode) &&
225                 EQUIV(this->reflective, src.reflective) &&
226                 EQUIV(this->amplitude, src.amplitude) &&
227                 EQUIV(this->phase, src.phase) &&
228                 EQUIV(this->wavelength, src.wavelength);
231 void WaveConfig::interpolate(WaveConfig &prev, 
232                 WaveConfig &next, 
233                 long prev_frame, 
234                 long next_frame, 
235                 long current_frame)
237         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
238         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
240         this->amplitude = prev.amplitude * prev_scale + next.amplitude * next_scale;
241         this->phase = prev.phase * prev_scale + next.phase * next_scale;
242         this->wavelength = prev.wavelength * prev_scale + next.wavelength * next_scale;
243         this->mode = prev.mode;
244         this->reflective = prev.reflective;
254 WaveSmear::WaveSmear(WaveEffect *plugin, WaveWindow *window, int x, int y)
255  : BC_Radial(x, y, plugin->config.mode == SMEAR, _("Smear"))
257         this->plugin = plugin;
258         this->window = window;
260 int WaveSmear::handle_event()
262         plugin->config.mode = SMEAR;
263         window->update_mode();
264         plugin->send_configure_change();
265         return 1;
271 WaveBlacken::WaveBlacken(WaveEffect *plugin, WaveWindow *window, int x, int y)
272  : BC_Radial(x, y, plugin->config.mode == BLACKEN, _("Blacken"))
274         this->plugin = plugin;
275         this->window = window;
277 int WaveBlacken::handle_event()
279         plugin->config.mode = BLACKEN;
280         window->update_mode();
281         plugin->send_configure_change();
282         return 1;
290 WaveReflective::WaveReflective(WaveEffect *plugin, int x, int y)
291  : BC_CheckBox(x, y, plugin->config.reflective, _("Reflective"))
293         this->plugin = plugin;
295 int WaveReflective::handle_event()
297         plugin->config.reflective = get_value();
298         plugin->send_configure_change();
299         return 1;
303 WaveAmplitude::WaveAmplitude(WaveEffect *plugin, int x, int y)
304  : BC_FSlider(x, 
305                         y,
306                         0,
307                         200, 
308                         200, 
309                         (float)0, 
310                         (float)100, 
311                         plugin->config.amplitude)
313         this->plugin = plugin;
315 int WaveAmplitude::handle_event()
317         plugin->config.amplitude = get_value();
318         plugin->send_configure_change();
319         return 1;
324 WavePhase::WavePhase(WaveEffect *plugin, int x, int y)
325  : BC_FSlider(x, 
326                         y,
327                         0,
328                         200, 
329                         200, 
330                         (float)0, 
331                         (float)360, 
332                         plugin->config.phase)
334         this->plugin = plugin;
336 int WavePhase::handle_event()
338         plugin->config.phase = get_value();
339         plugin->send_configure_change();
340         return 1;
343 WaveLength::WaveLength(WaveEffect *plugin, int x, int y)
344  : BC_FSlider(x, 
345                         y,
346                         0,
347                         200, 
348                         200, 
349                         (float)0, 
350                         (float)50, 
351                         plugin->config.wavelength)
353         this->plugin = plugin;
355 int WaveLength::handle_event()
357         plugin->config.wavelength = get_value();
358         plugin->send_configure_change();
359         return 1;
370 WaveWindow::WaveWindow(WaveEffect *plugin, int x, int y)
371  : BC_Window(plugin->gui_string, 
372         x, 
373         y, 
374         320, 
375         150, 
376         320, 
377         150, 
378         0, 
379         0,
380         1)
382         this->plugin = plugin;
385 WaveWindow::~WaveWindow()
389 void WaveWindow::create_objects()
391         int x = 10, y = 10, x1 = 100;
393 //      add_subwindow(new BC_Title(x, y, _("Mode:")));
394 //      add_subwindow(smear = new WaveSmear(plugin, this, x1, y));
395 //      y += 20;
396 //      add_subwindow(blacken = new WaveBlacken(plugin, this, x1, y));
397 //      y += 30;
398 //      add_subwindow(reflective = new WaveReflective(plugin, x1, y));
399 //      y += 30;
400         add_subwindow(new BC_Title(x, y, _("Amplitude:")));
401         add_subwindow(amplitude = new WaveAmplitude(plugin, x1, y));
402         y += 30;
403         add_subwindow(new BC_Title(x, y, _("Phase:")));
404         add_subwindow(phase = new WavePhase(plugin, x1, y));
405         y += 30;
406         add_subwindow(new BC_Title(x, y, _("Wavelength:")));
407         add_subwindow(wavelength = new WaveLength(plugin, x1, y));
409         show_window();
410         flush();
413 int WaveWindow::close_event()
415         set_done(1);
416         return 1;
419 void WaveWindow::update_mode()
421 //      smear->update(plugin->config.mode == SMEAR);
422 //      blacken->update(plugin->config.mode == BLACKEN);
426 PLUGIN_THREAD_OBJECT(WaveEffect, WaveThread, WaveWindow)
431 REGISTER_PLUGIN(WaveEffect)
436 WaveEffect::WaveEffect(PluginServer *server)
437  : PluginVClient(server)
439         temp_frame = 0;
440         engine = 0;
441         PLUGIN_CONSTRUCTOR_MACRO
444 WaveEffect::~WaveEffect()
446         PLUGIN_DESTRUCTOR_MACRO
448         if(temp_frame) delete temp_frame;
449         if(engine) delete engine;
453 char* WaveEffect::plugin_title() { return N_("Wave"); }
454 int WaveEffect::is_realtime() { return 1; }
456 NEW_PICON_MACRO(WaveEffect)
458 SHOW_GUI_MACRO(WaveEffect, WaveThread)
460 RAISE_WINDOW_MACRO(WaveEffect)
462 SET_STRING_MACRO(WaveEffect)
464 void WaveEffect::update_gui()
466         if(thread)
467         {
468                 thread->window->lock_window();
469                 load_configuration();
470                 thread->window->update_mode();
471 //              thread->window->reflective->update(config.reflective);
472                 thread->window->amplitude->update(config.amplitude);
473                 thread->window->phase->update(config.phase);
474                 thread->window->wavelength->update(config.wavelength);
475                 thread->window->unlock_window();
476         }
480 LOAD_CONFIGURATION_MACRO(WaveEffect, WaveConfig)
482 int WaveEffect::load_defaults()
484         char directory[BCTEXTLEN];
485 // set the default directory
486         sprintf(directory, "%swave.rc", BCASTDIR);
488 // load the defaults
489         defaults = new BC_Hash(directory);
490         defaults->load();
492         config.mode = defaults->get("MODE", config.mode);
493         config.reflective = defaults->get("REFLECTIVE", config.reflective);
494         config.amplitude = defaults->get("AMPLITUDE", config.amplitude);
495         config.phase = defaults->get("PHASE", config.phase);
496         config.wavelength = defaults->get("WAVELENGTH", config.wavelength);
497         return 0;
500 int WaveEffect::save_defaults()
502         defaults->update("MODE", config.mode);
503         defaults->update("REFLECTIVE", config.reflective);
504         defaults->update("AMPLITUDE", config.amplitude);
505         defaults->update("PHASE", config.phase);
506         defaults->update("WAVELENGTH", config.wavelength);
507         defaults->save();
508         return 0;
511 void WaveEffect::save_data(KeyFrame *keyframe)
513         FileXML output;
515 // cause data to be stored directly in text
516         output.set_shared_string(keyframe->data, MESSAGESIZE);
517         output.tag.set_title("WAVE");
518         output.tag.set_property("MODE", config.mode);
519         output.tag.set_property("REFLECTIVE", config.reflective);
520         output.tag.set_property("AMPLITUDE", config.amplitude);
521         output.tag.set_property("PHASE", config.phase);
522         output.tag.set_property("WAVELENGTH", config.wavelength);
523         output.append_tag();
524         output.tag.set_title("/WAVE");
525         output.append_tag();
526         output.terminate_string();
529 void WaveEffect::read_data(KeyFrame *keyframe)
531         FileXML input;
533         input.set_shared_string(keyframe->data, strlen(keyframe->data));
535         while(!input.read_tag())
536         {
537                 if(input.tag.title_is("WAVE"))
538                 {
539                         config.mode = input.tag.get_property("MODE", config.mode);
540                         config.reflective = input.tag.get_property("REFLECTIVE", config.reflective);
541                         config.amplitude = input.tag.get_property("AMPLITUDE", config.amplitude);
542                         config.phase = input.tag.get_property("PHASE", config.phase);
543                         config.wavelength = input.tag.get_property("WAVELENGTH", config.wavelength);
544                 }
545         }
549 int WaveEffect::process_realtime(VFrame *input, VFrame *output)
551         load_configuration();
555 //printf("WaveEffect::process_realtime %f %d\n", config.radius, config.use_intensity);
556         this->input = input;
557         this->output = output;
559         if(EQUIV(config.amplitude, 0) || EQUIV(config.wavelength, 0))
560         {
561                 if(input->get_rows()[0] != output->get_rows()[0])
562                         output->copy_from(input);
563         }
564         else
565         {
566                 if(input->get_rows()[0] == output->get_rows()[0])
567                 {
568                         if(!temp_frame) temp_frame = new VFrame(0,
569                                 input->get_w(),
570                                 input->get_h(),
571                                 input->get_color_model());
572                         temp_frame->copy_from(input);
573                         this->input = temp_frame;
574                 }
575                 
576                 
577                 if(!engine)
578                 {
579                         engine = new WaveServer(this, (PluginClient::smp + 1));
580                 }
581                 
582                 engine->process_packages();
583         }
584         
585         
586         
587         return 0;
595 WavePackage::WavePackage()
596  : LoadPackage()
605 WaveUnit::WaveUnit(WaveEffect *plugin, WaveServer *server)
606  : LoadClient(server)
608         this->plugin = plugin;
613 #define WITHIN(a, b, c) ((((a) <= (b)) && ((b) <= (c))) ? 1 : 0)
615 static float bilinear(double  x,
616           double  y,
617           float  *v)
619         double m0, m1;
620         x = fmod(x, 1.0);
621         y = fmod(y, 1.0);
623         if(x < 0)
624         x += 1.0;
625         if(y < 0)
626         y += 1.0;
628         m0 = (1.0 - x) * v[0] + x * v[1];
629         m1 = (1.0 - x) * v[2] + x * v[3];
631         return((1.0 - y) * m0 + y * m1);
634 void WaveUnit::process_package(LoadPackage *package)
636         WavePackage *pkg = (WavePackage*)package;
637         int w = plugin->input->get_w();
638         int h = plugin->input->get_h();
639         double cen_x, cen_y;       /* Center of wave */
640         double xhsiz, yhsiz;       /* Half size of selection */
641         double radius, radius2;    /* Radius and radius^2 */
642         double amnt, d;
643         double needx, needy;
644         double dx, dy;
645         double xscale, yscale;
646         double wavelength;
647         int xi, yi;
648         float values[4];
649         float val;
650         int x1, y1, x2, y2;
651         int x1_in, y1_in, x2_in, y2_in;
652         double phase = plugin->config.phase * M_PI / 180;
653         
654         
655         x1 = y1 = 0;
656         x2 = w;
657         y2 = h;
658         cen_x = (double) (x2 - 1 + x1) / 2.0;
659         cen_y = (double) (y2 - 1 + y1) / 2.0;
660         xhsiz = (double) (x2 - x1) / 2.0;
661         yhsiz = (double) (y2 - y1) / 2.0;
663         if (xhsiz < yhsiz)
664     {
665         xscale = yhsiz / xhsiz;
666         yscale = 1.0;
667     }
668         else if (xhsiz > yhsiz)
669     {
670         xscale = 1.0;
671         yscale = xhsiz / yhsiz;
672     }
673         else
674     {
675         xscale = 1.0;
676         yscale = 1.0;
677     }
679         radius  = MAX(xhsiz, yhsiz);
680         radius2 = radius * radius;
683         wavelength = plugin->config.wavelength / 100 * radius;
688 #define WAVE(type, components, chroma_offset) \
689 { \
690         int row_size = w * components; \
691         type **in_rows = (type**)plugin->input->get_rows(); \
692         for(int y = pkg->row1; y < pkg->row2; y++) \
693         { \
694                 type *dest = (type*)plugin->output->get_rows()[y]; \
696                 for(int x = x1; x < x2; x++) \
697                 { \
698                         dx = (x - cen_x) * xscale; \
699                         dy = (y - cen_y) * yscale; \
700                     d = sqrt(dx * dx + dy * dy); \
702                         if(plugin->config.reflective) \
703                         { \
704                         amnt = plugin->config.amplitude *  \
705                                         fabs(sin(((d / wavelength) *  \
706                                                 (2.0 * M_PI) + \
707                                                 phase))); \
709                         needx = (amnt * dx) / xscale + cen_x; \
710                         needy = (amnt * dy) / yscale + cen_y; \
711                         } \
712                         else \
713                         { \
714                         amnt = plugin->config.amplitude *  \
715                                         sin(((d / wavelength) *  \
716                                                 (2.0 * M_PI) + \
717                                         phase)); \
719                         needx = (amnt + dx) / xscale + cen_x; \
720                         needy = (amnt + dy) / yscale + cen_y; \
721                         } \
723                         xi = (int)needx; \
724                         yi = (int)needy; \
726                         if(plugin->config.mode == SMEAR) \
727                 { \
728                         if(xi > w - 2) \
729                                 { \
730                                         xi = w - 2; \
731                                 } \
732                         else  \
733                                 if(xi < 0) \
734                                 { \
735                                         xi = 0; \
736                                 } \
738                         if(yi > h - 2) \
739                                 { \
740                                         yi = h - 2; \
741                                 } \
742                         else  \
743                                 if(yi < 0) \
744                                 { \
745                                         yi = 0; \
746                                 } \
747                 } \
749                         type *p = in_rows[CLIP(yi, 0, h - 1)] + \
750                                 CLIP(xi, 0, w - 1) * components; \
751                         x1_in = WITHIN(0, xi, w - 1); \
752                         y1_in = WITHIN(0, yi, h - 1); \
753                         x2_in = WITHIN(0, xi + 1, w - 1); \
754                         y2_in = WITHIN(0, yi + 1, h - 1); \
757                         for(int k = 0; k < components; k++) \
758                 { \
759                         if (x1_in && y1_in) \
760                                         values[0] = *(p + k); \
761                         else \
762                                         values[0] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
764                         if (x2_in && y1_in) \
765                                         values[1] = *(p + components + k); \
766                         else \
767                                         values[1] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
769                         if (x1_in && y2_in) \
770                                         values[2] = *(p + row_size + k); \
771                         else \
772                                         values[2] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
774                         if (x2_in) \
775                                 { \
776                                         if (y2_in) \
777                                         values[3] = *(p + row_size + components + k); \
778                                         else \
779                                         values[3] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
780                                 } \
781                         else \
782                                         values[3] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
784                         val = bilinear(needx, needy, values); \
786                         *dest++ = (type)val; \
787                 } \
788                 } \
789         } \
795         switch(plugin->input->get_color_model())
796         {
797                 case BC_RGB888:
798                         WAVE(unsigned char, 3, 0x0);
799                         break;
800                 case BC_RGB_FLOAT:
801                         WAVE(float, 3, 0x0);
802                         break;
803                 case BC_YUV888:
804                         WAVE(unsigned char, 3, 0x80);
805                         break;
806                 case BC_RGB161616:
807                         WAVE(uint16_t, 3, 0x0);
808                         break;
809                 case BC_YUV161616:
810                         WAVE(uint16_t, 3, 0x8000);
811                         break;
812                 case BC_RGBA_FLOAT:
813                         WAVE(unsigned char, 4, 0x0);
814                         break;
815                 case BC_RGBA8888:
816                         WAVE(unsigned char, 4, 0x0);
817                         break;
818                 case BC_YUVA8888:
819                         WAVE(unsigned char, 4, 0x8000);
820                         break;
821                 case BC_RGBA16161616:
822                         WAVE(uint16_t, 4, 0x0);
823                         break;
824                 case BC_YUVA16161616:
825                         WAVE(uint16_t, 4, 0x8000);
826                         break;
827         }
839 WaveServer::WaveServer(WaveEffect *plugin, int cpus)
840  : LoadServer(cpus, cpus)
842         this->plugin = plugin;
845 void WaveServer::init_packages()
847         for(int i = 0; i < LoadServer::get_total_packages(); i++)
848         {
849                 WavePackage *pkg = (WavePackage*)get_package(i);
850                 pkg->row1 = plugin->input->get_h() * i / LoadServer::get_total_packages();
851                 pkg->row2 = plugin->input->get_h() * (i + 1) / LoadServer::get_total_packages();
852         }
856 LoadClient* WaveServer::new_client()
858         return new WaveUnit(plugin, this);
861 LoadPackage* WaveServer::new_package()
863         return new WavePackage;