initial commit
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / wave / wave.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
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.
10  *
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.
15  *
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
19  *
20  */
21
22 #include "bcdisplayinfo.h"
23 #include "clip.h"
24 #include "bchash.h"
25 #include "filexml.h"
26 #include "guicast.h"
27 #include "keyframe.h"
28 #include "language.h"
29 #include "loadbalance.h"
30 #include "pluginvclient.h"
31 #include "vframe.h"
32
33 #include <math.h>
34 #include <stdint.h>
35 #include <string.h>
36
37
38
39
40 #define SMEAR 0
41 #define BLACKEN 1
42
43
44
45 class WaveEffect;
46 class WaveWindow;
47
48
49 class WaveConfig
50 {
51 public:
52         WaveConfig();
53         void copy_from(WaveConfig &src);
54         int equivalent(WaveConfig &src);
55         void interpolate(WaveConfig &prev,
56                 WaveConfig &next,
57                 long prev_frame,
58                 long next_frame,
59                 long current_frame);
60         int mode;
61         int reflective;
62         float amplitude;
63         float phase;
64         float wavelength;
65 };
66
67 class WaveSmear : public BC_Radial
68 {
69 public:
70         WaveSmear(WaveEffect *plugin, WaveWindow *window, int x, int y);
71         int handle_event();
72         WaveEffect *plugin;
73         WaveWindow *window;
74 };
75
76 class WaveBlacken : public BC_Radial
77 {
78 public:
79         WaveBlacken(WaveEffect *plugin, WaveWindow *window, int x, int y);
80         int handle_event();
81         WaveEffect *plugin;
82         WaveWindow *window;
83 };
84
85
86 class WaveReflective : public BC_CheckBox
87 {
88 public:
89         WaveReflective(WaveEffect *plugin, int x, int y);
90         int handle_event();
91         WaveEffect *plugin;
92 };
93
94 class WaveAmplitude : public BC_FSlider
95 {
96 public:
97         WaveAmplitude(WaveEffect *plugin, int x, int y);
98         int handle_event();
99         WaveEffect *plugin;
100 };
101
102 class WavePhase : public BC_FSlider
103 {
104 public:
105         WavePhase(WaveEffect *plugin, int x, int y);
106         int handle_event();
107         WaveEffect *plugin;
108 };
109
110 class WaveLength : public BC_FSlider
111 {
112 public:
113         WaveLength(WaveEffect *plugin, int x, int y);
114         int handle_event();
115         WaveEffect *plugin;
116 };
117
118
119
120
121
122
123
124
125
126 class WaveWindow : public PluginClientWindow
127 {
128 public:
129         WaveWindow(WaveEffect *plugin);
130         ~WaveWindow();
131         void create_objects();
132         void update_mode();
133         WaveEffect *plugin;
134 //      WaveSmear *smear;
135 //      WaveBlacken *blacken;
136 //      WaveReflective *reflective;
137         WaveAmplitude *amplitude;
138         WavePhase *phase;
139         WaveLength *wavelength;
140 };
141
142
143
144
145
146
147
148 class WaveServer : public LoadServer
149 {
150 public:
151         WaveServer(WaveEffect *plugin, int cpus);
152         void init_packages();
153         LoadClient* new_client();
154         LoadPackage* new_package();
155         WaveEffect *plugin;
156 };
157
158 class WavePackage : public LoadPackage
159 {
160 public:
161         WavePackage();
162         int row1, row2;
163 };
164
165 class WaveUnit : public LoadClient
166 {
167 public:
168         WaveUnit(WaveEffect *plugin, WaveServer *server);
169         void process_package(LoadPackage *package);
170         WaveEffect *plugin;
171 };
172
173
174
175
176
177
178
179
180
181 class WaveEffect : public PluginVClient
182 {
183 public:
184         WaveEffect(PluginServer *server);
185         ~WaveEffect();
186
187         PLUGIN_CLASS_MEMBERS(WaveConfig)
188         int process_realtime(VFrame *input, VFrame *output);
189         int is_realtime();
190         void save_data(KeyFrame *keyframe);
191         void read_data(KeyFrame *keyframe);
192         void update_gui();
193
194         VFrame *temp_frame;
195         VFrame *input, *output;
196         WaveServer *engine;
197 };
198
199
200
201
202
203
204
205
206
207
208
209
210
211 WaveConfig::WaveConfig()
212 {
213         mode = SMEAR;
214         reflective = 0;
215         amplitude = 10;
216         phase = 0;
217         wavelength = 10;
218 }
219
220 void WaveConfig::copy_from(WaveConfig &src)
221 {
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;
227 }
228
229 int WaveConfig::equivalent(WaveConfig &src)
230 {
231         return
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);
237 }
238
239 void WaveConfig::interpolate(WaveConfig &prev,
240                 WaveConfig &next,
241                 long prev_frame,
242                 long next_frame,
243                 long current_frame)
244 {
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);
247
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;
253 }
254
255
256
257
258
259
260
261
262 WaveSmear::WaveSmear(WaveEffect *plugin, WaveWindow *window, int x, int y)
263  : BC_Radial(x, y, plugin->config.mode == SMEAR, _("Smear"))
264 {
265         this->plugin = plugin;
266         this->window = window;
267 }
268 int WaveSmear::handle_event()
269 {
270         plugin->config.mode = SMEAR;
271         window->update_mode();
272         plugin->send_configure_change();
273         return 1;
274 }
275
276
277
278
279 WaveBlacken::WaveBlacken(WaveEffect *plugin, WaveWindow *window, int x, int y)
280  : BC_Radial(x, y, plugin->config.mode == BLACKEN, _("Blacken"))
281 {
282         this->plugin = plugin;
283         this->window = window;
284 }
285 int WaveBlacken::handle_event()
286 {
287         plugin->config.mode = BLACKEN;
288         window->update_mode();
289         plugin->send_configure_change();
290         return 1;
291 }
292
293
294
295
296
297
298 WaveReflective::WaveReflective(WaveEffect *plugin, int x, int y)
299  : BC_CheckBox(x, y, plugin->config.reflective, _("Reflective"))
300 {
301         this->plugin = plugin;
302 }
303 int WaveReflective::handle_event()
304 {
305         plugin->config.reflective = get_value();
306         plugin->send_configure_change();
307         return 1;
308 }
309
310
311 WaveAmplitude::WaveAmplitude(WaveEffect *plugin, int x, int y)
312  : BC_FSlider(x,
313                         y,
314                         0,
315                         200,
316                         200,
317                         (float)0,
318                         (float)100,
319                         plugin->config.amplitude)
320 {
321         this->plugin = plugin;
322 }
323 int WaveAmplitude::handle_event()
324 {
325         plugin->config.amplitude = get_value();
326         plugin->send_configure_change();
327         return 1;
328 }
329
330
331
332 WavePhase::WavePhase(WaveEffect *plugin, int x, int y)
333  : BC_FSlider(x,
334                         y,
335                         0,
336                         200,
337                         200,
338                         (float)0,
339                         (float)360,
340                         plugin->config.phase)
341 {
342         this->plugin = plugin;
343 }
344 int WavePhase::handle_event()
345 {
346         plugin->config.phase = get_value();
347         plugin->send_configure_change();
348         return 1;
349 }
350
351 WaveLength::WaveLength(WaveEffect *plugin, int x, int y)
352  : BC_FSlider(x,
353                         y,
354                         0,
355                         200,
356                         200,
357                         (float)0,
358                         (float)50,
359                         plugin->config.wavelength)
360 {
361         this->plugin = plugin;
362 }
363 int WaveLength::handle_event()
364 {
365         plugin->config.wavelength = get_value();
366         plugin->send_configure_change();
367         return 1;
368 }
369
370
371
372
373
374
375
376
377
378 WaveWindow::WaveWindow(WaveEffect *plugin)
379  : PluginClientWindow(plugin, 335, 150, 335, 150, 0)
380 {
381         this->plugin = plugin;
382 }
383
384 WaveWindow::~WaveWindow()
385 {
386 }
387
388 void WaveWindow::create_objects()
389 {
390         int x = 10, y = 10, x1 = 115;
391
392 //      add_subwindow(new BC_Title(x, y, _("Mode:")));
393 //      add_subwindow(smear = new WaveSmear(plugin, this, x1, y));
394 //      y += 20;
395 //      add_subwindow(blacken = new WaveBlacken(plugin, this, x1, y));
396 //      y += 30;
397 //      add_subwindow(reflective = new WaveReflective(plugin, x1, y));
398 //      y += 30;
399         add_subwindow(new BC_Title(x, y, _("Amplitude:")));
400         add_subwindow(amplitude = new WaveAmplitude(plugin, x1, y));
401         y += 30;
402         add_subwindow(new BC_Title(x, y, _("Phase:")));
403         add_subwindow(phase = new WavePhase(plugin, x1, y));
404         y += 30;
405         add_subwindow(new BC_Title(x, y, _("Wavelength:")));
406         add_subwindow(wavelength = new WaveLength(plugin, x1, y));
407
408         show_window();
409         flush();
410 }
411
412 void WaveWindow::update_mode()
413 {
414 //      smear->update(plugin->config.mode == SMEAR);
415 //      blacken->update(plugin->config.mode == BLACKEN);
416 }
417
418
419
420
421
422
423
424 REGISTER_PLUGIN(WaveEffect)
425
426
427
428
429 WaveEffect::WaveEffect(PluginServer *server)
430  : PluginVClient(server)
431 {
432         temp_frame = 0;
433         engine = 0;
434
435 }
436
437 WaveEffect::~WaveEffect()
438 {
439
440
441         if(temp_frame) delete temp_frame;
442         if(engine) delete engine;
443 }
444
445
446 const char* WaveEffect::plugin_title() { return N_("Wave"); }
447 int WaveEffect::is_realtime() { return 1; }
448
449
450 NEW_WINDOW_MACRO(WaveEffect, WaveWindow)
451
452 void WaveEffect::update_gui()
453 {
454         if(thread)
455         {
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();
464         }
465 }
466
467
468 LOAD_CONFIGURATION_MACRO(WaveEffect, WaveConfig)
469
470
471 void WaveEffect::save_data(KeyFrame *keyframe)
472 {
473         FileXML output;
474
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);
483         output.append_tag();
484         output.tag.set_title("/WAVE");
485         output.append_tag();
486         output.append_newline();
487         output.terminate_string();
488 }
489
490 void WaveEffect::read_data(KeyFrame *keyframe)
491 {
492         FileXML input;
493
494         input.set_shared_input(keyframe->xbuf);
495
496         while(!input.read_tag())
497         {
498                 if(input.tag.title_is("WAVE"))
499                 {
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);
505                 }
506         }
507 }
508
509
510 int WaveEffect::process_realtime(VFrame *input, VFrame *output)
511 {
512         load_configuration();
513
514
515
516 //printf("WaveEffect::process_realtime %f %d\n", config.radius, config.use_intensity);
517         this->input = input;
518         this->output = output;
519
520         if(EQUIV(config.amplitude, 0) || EQUIV(config.wavelength, 0))
521         {
522                 if(input->get_rows()[0] != output->get_rows()[0])
523                         output->copy_from(input);
524         }
525         else
526         {
527                 if(input->get_rows()[0] == output->get_rows()[0])
528                 {
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;
533                 }
534
535
536                 if(!engine)
537                 {
538                         engine = new WaveServer(this, (PluginClient::smp + 1));
539                 }
540
541                 engine->process_packages();
542         }
543
544
545
546         return 0;
547 }
548
549
550
551
552
553
554 WavePackage::WavePackage()
555  : LoadPackage()
556 {
557 }
558
559
560
561
562
563
564 WaveUnit::WaveUnit(WaveEffect *plugin, WaveServer *server)
565  : LoadClient(server)
566 {
567         this->plugin = plugin;
568 }
569
570
571
572 #define WITHIN(a, b, c) ((((a) <= (b)) && ((b) <= (c))) ? 1 : 0)
573
574 static float bilinear(double  x,
575           double  y,
576           float  *v)
577 {
578         double m0, m1;
579         x = fmod(x, 1.0);
580         y = fmod(y, 1.0);
581
582         if(x < 0)
583         x += 1.0;
584         if(y < 0)
585         y += 1.0;
586
587         m0 = (1.0 - x) * v[0] + x * v[1];
588         m1 = (1.0 - x) * v[2] + x * v[3];
589
590         return((1.0 - y) * m0 + y * m1);
591 }
592
593 void WaveUnit::process_package(LoadPackage *package)
594 {
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 */
601         double amnt, d;
602         double needx, needy;
603         double dx, dy;
604         double xscale, yscale;
605         double wavelength;
606         int xi, yi;
607         float values[4];
608         float val;
609         int x1, y1, x2, y2;
610         int x1_in, y1_in, x2_in, y2_in;
611         double phase = plugin->config.phase * M_PI / 180;
612
613
614         x1 = y1 = 0;
615         x2 = w;
616         y2 = h;
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;
621
622         if (xhsiz < yhsiz)
623     {
624         xscale = yhsiz / xhsiz;
625         yscale = 1.0;
626     }
627         else if (xhsiz > yhsiz)
628     {
629         xscale = 1.0;
630         yscale = xhsiz / yhsiz;
631     }
632         else
633     {
634         xscale = 1.0;
635         yscale = 1.0;
636     }
637
638         radius  = MAX(xhsiz, yhsiz);
639
640
641         wavelength = plugin->config.wavelength / 100 * radius;
642
643
644
645
646 #define WAVE(type, components, chroma_offset) \
647 { \
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++) \
651         { \
652                 type *dest = (type*)plugin->output->get_rows()[y]; \
653  \
654                 for(int x = x1; x < x2; x++) \
655                 { \
656                         dx = (x - cen_x) * xscale; \
657                         dy = (y - cen_y) * yscale; \
658                     d = sqrt(dx * dx + dy * dy); \
659  \
660                         if(plugin->config.reflective) \
661                         { \
662                         amnt = plugin->config.amplitude *  \
663                                         fabs(sin(((d / wavelength) *  \
664                                                 (2.0 * M_PI) + \
665                                                 phase))); \
666  \
667                         needx = (amnt * dx) / xscale + cen_x; \
668                         needy = (amnt * dy) / yscale + cen_y; \
669                         } \
670                         else \
671                         { \
672                         amnt = plugin->config.amplitude *  \
673                                         sin(((d / wavelength) *  \
674                                                 (2.0 * M_PI) + \
675                                         phase)); \
676  \
677                         needx = (amnt + dx) / xscale + cen_x; \
678                         needy = (amnt + dy) / yscale + cen_y; \
679                         } \
680  \
681                         xi = (int)needx; \
682                         yi = (int)needy; \
683  \
684                         if(plugin->config.mode == SMEAR) \
685                 { \
686                         if(xi > w - 2) \
687                                 { \
688                                         xi = w - 2; \
689                                 } \
690                         else  \
691                                 if(xi < 0) \
692                                 { \
693                                         xi = 0; \
694                                 } \
695  \
696                         if(yi > h - 2) \
697                                 { \
698                                         yi = h - 2; \
699                                 } \
700                         else  \
701                                 if(yi < 0) \
702                                 { \
703                                         yi = 0; \
704                                 } \
705                 } \
706  \
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); \
713  \
714  \
715                         for(int k = 0; k < components; k++) \
716                 { \
717                         if (x1_in && y1_in) \
718                                         values[0] = *(p + k); \
719                         else \
720                                         values[0] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
721  \
722                         if (x2_in && y1_in) \
723                                         values[1] = *(p + components + k); \
724                         else \
725                                         values[1] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
726  \
727                         if (x1_in && y2_in) \
728                                         values[2] = *(p + row_size + k); \
729                         else \
730                                         values[2] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
731  \
732                         if (x2_in) \
733                                 { \
734                                         if (y2_in) \
735                                         values[3] = *(p + row_size + components + k); \
736                                         else \
737                                         values[3] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
738                                 } \
739                         else \
740                                         values[3] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
741  \
742                         val = bilinear(needx, needy, values); \
743  \
744                         *dest++ = (type)val; \
745                 } \
746                 } \
747         } \
748 }
749
750
751
752
753         switch(plugin->input->get_color_model())
754         {
755                 case BC_RGB888:
756                         WAVE(unsigned char, 3, 0x0);
757                         break;
758                 case BC_RGB_FLOAT:
759                         WAVE(float, 3, 0x0);
760                         break;
761                 case BC_YUV888:
762                         WAVE(unsigned char, 3, 0x80);
763                         break;
764                 case BC_RGB161616:
765                         WAVE(uint16_t, 3, 0x0);
766                         break;
767                 case BC_YUV161616:
768                         WAVE(uint16_t, 3, 0x8000);
769                         break;
770                 case BC_RGBA_FLOAT:
771                         WAVE(unsigned char, 4, 0x0);
772                         break;
773                 case BC_RGBA8888:
774                         WAVE(unsigned char, 4, 0x0);
775                         break;
776                 case BC_YUVA8888:
777                         WAVE(unsigned char, 4, 0x8000);
778                         break;
779                 case BC_RGBA16161616:
780                         WAVE(uint16_t, 4, 0x0);
781                         break;
782                 case BC_YUVA16161616:
783                         WAVE(uint16_t, 4, 0x8000);
784                         break;
785         }
786
787
788
789
790 }
791
792
793
794
795
796
797 WaveServer::WaveServer(WaveEffect *plugin, int cpus)
798  : LoadServer(cpus, cpus)
799 {
800         this->plugin = plugin;
801 }
802
803 void WaveServer::init_packages()
804 {
805         for(int i = 0; i < LoadServer::get_total_packages(); i++)
806         {
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();
810         }
811 }
812
813
814 LoadClient* WaveServer::new_client()
815 {
816         return new WaveUnit(plugin, this);
817 }
818
819 LoadPackage* WaveServer::new_package()
820 {
821         return new WavePackage;
822 }
823