remove whitespace at eol
[goodguy/history.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 _("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->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);
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->get_data(), strlen(keyframe->get_data()));
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(0,
530                                 -1,
531                                 input->get_w(),
532                                 input->get_h(),
533                                 input->get_color_model(),
534                                 -1);
535                         temp_frame->copy_from(input);
536                         this->input = temp_frame;
537                 }
538
539
540                 if(!engine)
541                 {
542                         engine = new WaveServer(this, (PluginClient::smp + 1));
543                 }
544
545                 engine->process_packages();
546         }
547
548
549
550         return 0;
551 }
552
553
554
555
556
557
558 WavePackage::WavePackage()
559  : LoadPackage()
560 {
561 }
562
563
564
565
566
567
568 WaveUnit::WaveUnit(WaveEffect *plugin, WaveServer *server)
569  : LoadClient(server)
570 {
571         this->plugin = plugin;
572 }
573
574
575
576 #define WITHIN(a, b, c) ((((a) <= (b)) && ((b) <= (c))) ? 1 : 0)
577
578 static float bilinear(double  x,
579           double  y,
580           float  *v)
581 {
582         double m0, m1;
583         x = fmod(x, 1.0);
584         y = fmod(y, 1.0);
585
586         if(x < 0)
587         x += 1.0;
588         if(y < 0)
589         y += 1.0;
590
591         m0 = (1.0 - x) * v[0] + x * v[1];
592         m1 = (1.0 - x) * v[2] + x * v[3];
593
594         return((1.0 - y) * m0 + y * m1);
595 }
596
597 void WaveUnit::process_package(LoadPackage *package)
598 {
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 */
605         double amnt, d;
606         double needx, needy;
607         double dx, dy;
608         double xscale, yscale;
609         double wavelength;
610         int xi, yi;
611         float values[4];
612         float val;
613         int x1, y1, x2, y2;
614         int x1_in, y1_in, x2_in, y2_in;
615         double phase = plugin->config.phase * M_PI / 180;
616
617
618         x1 = y1 = 0;
619         x2 = w;
620         y2 = h;
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;
625
626         if (xhsiz < yhsiz)
627     {
628         xscale = yhsiz / xhsiz;
629         yscale = 1.0;
630     }
631         else if (xhsiz > yhsiz)
632     {
633         xscale = 1.0;
634         yscale = xhsiz / yhsiz;
635     }
636         else
637     {
638         xscale = 1.0;
639         yscale = 1.0;
640     }
641
642         radius  = MAX(xhsiz, yhsiz);
643
644
645         wavelength = plugin->config.wavelength / 100 * radius;
646
647
648
649
650 #define WAVE(type, components, chroma_offset) \
651 { \
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++) \
655         { \
656                 type *dest = (type*)plugin->output->get_rows()[y]; \
657  \
658                 for(int x = x1; x < x2; x++) \
659                 { \
660                         dx = (x - cen_x) * xscale; \
661                         dy = (y - cen_y) * yscale; \
662                     d = sqrt(dx * dx + dy * dy); \
663  \
664                         if(plugin->config.reflective) \
665                         { \
666                         amnt = plugin->config.amplitude *  \
667                                         fabs(sin(((d / wavelength) *  \
668                                                 (2.0 * M_PI) + \
669                                                 phase))); \
670  \
671                         needx = (amnt * dx) / xscale + cen_x; \
672                         needy = (amnt * dy) / yscale + cen_y; \
673                         } \
674                         else \
675                         { \
676                         amnt = plugin->config.amplitude *  \
677                                         sin(((d / wavelength) *  \
678                                                 (2.0 * M_PI) + \
679                                         phase)); \
680  \
681                         needx = (amnt + dx) / xscale + cen_x; \
682                         needy = (amnt + dy) / yscale + cen_y; \
683                         } \
684  \
685                         xi = (int)needx; \
686                         yi = (int)needy; \
687  \
688                         if(plugin->config.mode == SMEAR) \
689                 { \
690                         if(xi > w - 2) \
691                                 { \
692                                         xi = w - 2; \
693                                 } \
694                         else  \
695                                 if(xi < 0) \
696                                 { \
697                                         xi = 0; \
698                                 } \
699  \
700                         if(yi > h - 2) \
701                                 { \
702                                         yi = h - 2; \
703                                 } \
704                         else  \
705                                 if(yi < 0) \
706                                 { \
707                                         yi = 0; \
708                                 } \
709                 } \
710  \
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); \
717  \
718  \
719                         for(int k = 0; k < components; k++) \
720                 { \
721                         if (x1_in && y1_in) \
722                                         values[0] = *(p + k); \
723                         else \
724                                         values[0] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
725  \
726                         if (x2_in && y1_in) \
727                                         values[1] = *(p + components + k); \
728                         else \
729                                         values[1] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
730  \
731                         if (x1_in && y2_in) \
732                                         values[2] = *(p + row_size + k); \
733                         else \
734                                         values[2] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
735  \
736                         if (x2_in) \
737                                 { \
738                                         if (y2_in) \
739                                         values[3] = *(p + row_size + components + k); \
740                                         else \
741                                         values[3] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
742                                 } \
743                         else \
744                                         values[3] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
745  \
746                         val = bilinear(needx, needy, values); \
747  \
748                         *dest++ = (type)val; \
749                 } \
750                 } \
751         } \
752 }
753
754
755
756
757         switch(plugin->input->get_color_model())
758         {
759                 case BC_RGB888:
760                         WAVE(unsigned char, 3, 0x0);
761                         break;
762                 case BC_RGB_FLOAT:
763                         WAVE(float, 3, 0x0);
764                         break;
765                 case BC_YUV888:
766                         WAVE(unsigned char, 3, 0x80);
767                         break;
768                 case BC_RGB161616:
769                         WAVE(uint16_t, 3, 0x0);
770                         break;
771                 case BC_YUV161616:
772                         WAVE(uint16_t, 3, 0x8000);
773                         break;
774                 case BC_RGBA_FLOAT:
775                         WAVE(unsigned char, 4, 0x0);
776                         break;
777                 case BC_RGBA8888:
778                         WAVE(unsigned char, 4, 0x0);
779                         break;
780                 case BC_YUVA8888:
781                         WAVE(unsigned char, 4, 0x8000);
782                         break;
783                 case BC_RGBA16161616:
784                         WAVE(uint16_t, 4, 0x0);
785                         break;
786                 case BC_YUVA16161616:
787                         WAVE(uint16_t, 4, 0x8000);
788                         break;
789         }
790
791
792
793
794 }
795
796
797
798
799
800
801 WaveServer::WaveServer(WaveEffect *plugin, int cpus)
802  : LoadServer(cpus, cpus)
803 {
804         this->plugin = plugin;
805 }
806
807 void WaveServer::init_packages()
808 {
809         for(int i = 0; i < LoadServer::get_total_packages(); i++)
810         {
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();
814         }
815 }
816
817
818 LoadClient* WaveServer::new_client()
819 {
820         return new WaveUnit(plugin, this);
821 }
822
823 LoadPackage* WaveServer::new_package()
824 {
825         return new WavePackage;
826 }
827