no longer need ffmpeg patch0 which was for Termux
[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 "wave.h"
23
24
25
26
27
28
29
30
31 WaveConfig::WaveConfig()
32 {
33         reset(RESET_ALL);
34 }
35
36
37 void WaveConfig::reset(int clear)
38 {
39         switch(clear) {
40                 case RESET_ALL :
41                         mode = SMEAR;
42                         reflective = 0;
43                         amplitude = 0;
44                         phase = 0;
45                         wavelength = 0;
46                         break;
47                 case RESET_AMPLITUDE : amplitude = 0;
48                         break;
49                 case RESET_PHASE : phase = 0;
50                         break;
51                 case RESET_WAVELENGTH : wavelength = 0;
52                         break;
53                 case RESET_DEFAULT_SETTINGS :
54                 default:
55                         mode = SMEAR;
56                         reflective = 0;
57                         amplitude = 10;
58                         phase = 0;
59                         wavelength = 10;
60                         break;
61         }
62 }
63
64 void WaveConfig::copy_from(WaveConfig &src)
65 {
66         this->mode = src.mode;
67         this->reflective = src.reflective;
68         this->amplitude = src.amplitude;
69         this->phase = src.phase;
70         this->wavelength = src.wavelength;
71 }
72
73 int WaveConfig::equivalent(WaveConfig &src)
74 {
75         return
76                 (this->mode == src.mode) &&
77                 EQUIV(this->reflective, src.reflective) &&
78                 EQUIV(this->amplitude, src.amplitude) &&
79                 EQUIV(this->phase, src.phase) &&
80                 EQUIV(this->wavelength, src.wavelength);
81 }
82
83 void WaveConfig::interpolate(WaveConfig &prev,
84                 WaveConfig &next,
85                 long prev_frame,
86                 long next_frame,
87                 long current_frame)
88 {
89         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
90         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
91
92         this->amplitude = prev.amplitude * prev_scale + next.amplitude * next_scale;
93         this->phase = prev.phase * prev_scale + next.phase * next_scale;
94         this->wavelength = prev.wavelength * prev_scale + next.wavelength * next_scale;
95         this->mode = prev.mode;
96         this->reflective = prev.reflective;
97 }
98
99
100
101
102
103
104
105
106 WaveSmear::WaveSmear(WaveEffect *plugin, WaveWindow *window, int x, int y)
107  : BC_Radial(x, y, plugin->config.mode == SMEAR, _("Smear"))
108 {
109         this->plugin = plugin;
110         this->window = window;
111 }
112 int WaveSmear::handle_event()
113 {
114         plugin->config.mode = SMEAR;
115         window->update_mode();
116         plugin->send_configure_change();
117         return 1;
118 }
119
120
121
122
123 WaveBlacken::WaveBlacken(WaveEffect *plugin, WaveWindow *window, int x, int y)
124  : BC_Radial(x, y, plugin->config.mode == BLACKEN, _("Blacken"))
125 {
126         this->plugin = plugin;
127         this->window = window;
128 }
129 int WaveBlacken::handle_event()
130 {
131         plugin->config.mode = BLACKEN;
132         window->update_mode();
133         plugin->send_configure_change();
134         return 1;
135 }
136
137
138
139
140
141
142 WaveReflective::WaveReflective(WaveEffect *plugin, int x, int y)
143  : BC_CheckBox(x, y, plugin->config.reflective, _("Reflective"))
144 {
145         this->plugin = plugin;
146 }
147 int WaveReflective::handle_event()
148 {
149         plugin->config.reflective = get_value();
150         plugin->send_configure_change();
151         return 1;
152 }
153
154
155 WaveFText::WaveFText(WaveWindow *gui, WaveEffect *plugin,
156         WaveFSlider *slider, float *output, int x, int y, float min, float max)
157  : BC_TumbleTextBox(gui, *output,
158         min, max, x, y, xS(60), 2)
159 {
160         this->gui = gui;
161         this->plugin = plugin;
162         this->output = output;
163         this->slider = slider;
164         this->min = min;
165         this->max = max;
166         set_increment(0.1);
167 }
168
169 WaveFText::~WaveFText()
170 {
171 }
172
173 int WaveFText::handle_event()
174 {
175         *output = atof(get_text());
176         if(*output > max) *output = max;
177         if(*output < min) *output = min;
178         slider->update(*output);
179         plugin->send_configure_change();
180         return 1;
181 }
182
183
184 WaveFSlider::WaveFSlider(WaveEffect *plugin,
185         WaveFText *text, float *output, int x, int y, float min, float max)
186  : BC_FSlider(x, y, 0, xS(180), xS(180), min, max, *output)
187 {
188         this->plugin = plugin;
189         this->output = output;
190         this->text = text;
191         enable_show_value(0); // Hide caption
192 }
193
194 WaveFSlider::~WaveFSlider()
195 {
196 }
197
198 int WaveFSlider::handle_event()
199 {
200         *output = get_value();
201         text->update(*output);
202         plugin->send_configure_change();
203         return 1;
204 }
205
206
207 WaveReset::WaveReset(WaveEffect *plugin, WaveWindow *gui, int x, int y)
208  : BC_GenericButton(x, y, _("Reset"))
209 {
210         this->plugin = plugin;
211         this->gui = gui;
212 }
213 WaveReset::~WaveReset()
214 {
215 }
216 int WaveReset::handle_event()
217 {
218         plugin->config.reset(RESET_ALL);
219         gui->update_gui(RESET_ALL);
220         plugin->send_configure_change();
221         return 1;
222 }
223
224 WaveDefaultSettings::WaveDefaultSettings(WaveEffect *plugin, WaveWindow *gui, int x, int y, int w)
225  : BC_GenericButton(x, y, w, _("Default"))
226 {
227         this->plugin = plugin;
228         this->gui = gui;
229 }
230 WaveDefaultSettings::~WaveDefaultSettings()
231 {
232 }
233 int WaveDefaultSettings::handle_event()
234 {
235         plugin->config.reset(RESET_DEFAULT_SETTINGS);
236         gui->update_gui(RESET_DEFAULT_SETTINGS);
237         plugin->send_configure_change();
238         return 1;
239 }
240
241 WaveClr::WaveClr(WaveEffect *plugin, WaveWindow *gui, int x, int y, int clear)
242  : BC_Button(x, y, plugin->get_theme()->get_image_set("reset_button"))
243 {
244         this->plugin = plugin;
245         this->gui = gui;
246         this->clear = clear;
247 }
248 WaveClr::~WaveClr()
249 {
250 }
251 int WaveClr::handle_event()
252 {
253         // clear==1 ==> Amplitude slider
254         // clear==2 ==> Phase slider
255         // clear==3 ==> Steps slider
256         plugin->config.reset(clear);
257         gui->update_gui(clear);
258         plugin->send_configure_change();
259         return 1;
260 }
261
262
263
264
265 WaveWindow::WaveWindow(WaveEffect *plugin)
266  : PluginClientWindow(plugin, xS(420), yS(160), xS(420), yS(160), 0)
267 {
268         this->plugin = plugin;
269 }
270
271 WaveWindow::~WaveWindow()
272 {
273 }
274
275 void WaveWindow::create_objects()
276 {
277         int xs10 = xS(10), xs100 = xS(100);
278         int ys10 = yS(10), ys30 = yS(30), ys40 = yS(40);
279         int x = xs10, y = ys10;
280         int x2 = xS(100), x3 = xS(200);
281         int clr_x = get_w()-x - xS(22); // note: clrBtn_w = 22
282         int defaultBtn_w = xs100;
283
284         BC_Bar *bar;
285
286 //      add_subwindow(new BC_Title(x, y, _("Mode:")));
287 //      add_subwindow(smear = new WaveSmear(plugin, this, x1, y));
288 //      y += ys20;
289 //      add_subwindow(blacken = new WaveBlacken(plugin, this, x1, y));
290 //      y += ys30;
291 //      add_subwindow(reflective = new WaveReflective(plugin, x1, y));
292 //      y += ys30;
293
294         y += ys10;
295         add_subwindow(new BC_Title(x, y, _("Amplitude:")));
296         amplitude_text = new WaveFText(this, plugin,
297                 0, &plugin->config.amplitude, (x + x2), y, AMPLITUDE_MIN, AMPLITUDE_MAX);
298         amplitude_text->create_objects();
299         amplitude_slider = new WaveFSlider(plugin,
300                 amplitude_text, &plugin->config.amplitude, x3, y, AMPLITUDE_MIN, AMPLITUDE_MAX);
301         add_subwindow(amplitude_slider);
302         amplitude_text->slider = amplitude_slider;
303         clr_x = x3 + amplitude_slider->get_w() + x;
304         add_subwindow(amplitude_Clr = new WaveClr(plugin, this, clr_x, y, RESET_AMPLITUDE));
305         y += ys30;
306
307         add_subwindow(new BC_Title(x, y, _("Phase:")));
308         phase_text = new WaveFText(this, plugin,
309                 0, &plugin->config.phase, (x + x2), y, PHASE_MIN, PHASE_MAX);
310         phase_text->create_objects();
311         phase_slider = new WaveFSlider(plugin,
312                 phase_text, &plugin->config.phase, x3, y, PHASE_MIN, PHASE_MAX);
313         add_subwindow(phase_slider);
314         phase_text->slider = phase_slider;
315         add_subwindow(phase_Clr = new WaveClr(plugin, this, clr_x, y, RESET_PHASE));
316         y += ys30;
317
318         add_subwindow(new BC_Title(x, y, _("Wavelength:")));
319         wavelength_text = new WaveFText(this, plugin,
320                 0, &plugin->config.wavelength, (x + x2), y, WAVELENGTH_MIN, WAVELENGTH_MAX);
321         wavelength_text->create_objects();
322         wavelength_slider = new WaveFSlider(plugin,
323                 wavelength_text, &plugin->config.wavelength, x3, y, WAVELENGTH_MIN, WAVELENGTH_MAX);
324         add_subwindow(wavelength_slider);
325         wavelength_text->slider = wavelength_slider;
326         add_subwindow(wavelength_Clr = new WaveClr(plugin, this, clr_x, y, RESET_WAVELENGTH));
327         y += ys40;
328
329 // Reset section
330         add_subwindow(bar = new BC_Bar(x, y, get_w()-2*x));
331         y += ys10;
332         add_subwindow(reset = new WaveReset(plugin, this, x, y));
333         add_subwindow(default_settings = new WaveDefaultSettings(plugin, this,
334                 (get_w() - xs10 - defaultBtn_w), y, defaultBtn_w));
335
336         show_window();
337         flush();
338 }
339
340 void WaveWindow::update_mode()
341 {
342 //      smear->update(plugin->config.mode == SMEAR);
343 //      blacken->update(plugin->config.mode == BLACKEN);
344 }
345
346 // for Reset button
347 void WaveWindow::update_gui(int clear)
348 {
349         switch(clear) {
350                 case RESET_AMPLITUDE :
351                         amplitude_text->update(plugin->config.amplitude);
352                         amplitude_slider->update(plugin->config.amplitude);
353                         break;
354                 case RESET_PHASE :
355                         phase_text->update(plugin->config.phase);
356                         phase_slider->update(plugin->config.phase);
357                         break;
358                 case RESET_WAVELENGTH :
359                         wavelength_text->update(plugin->config.wavelength);
360                         wavelength_slider->update(plugin->config.wavelength);
361                         break;
362                 case RESET_ALL :
363                 case RESET_DEFAULT_SETTINGS :
364                 default:
365                         amplitude_text->update(plugin->config.amplitude);
366                         amplitude_slider->update(plugin->config.amplitude);
367                         phase_text->update(plugin->config.phase);
368                         phase_slider->update(plugin->config.phase);
369                         wavelength_text->update(plugin->config.wavelength);
370                         wavelength_slider->update(plugin->config.wavelength);
371                         break;
372         }
373 }
374
375
376
377
378
379
380
381
382
383 REGISTER_PLUGIN(WaveEffect)
384
385
386
387
388 WaveEffect::WaveEffect(PluginServer *server)
389  : PluginVClient(server)
390 {
391         temp_frame = 0;
392         engine = 0;
393
394 }
395
396 WaveEffect::~WaveEffect()
397 {
398
399
400         if(temp_frame) delete temp_frame;
401         if(engine) delete engine;
402 }
403
404
405 const char* WaveEffect::plugin_title() { return N_("Wave"); }
406 int WaveEffect::is_realtime() { return 1; }
407
408
409 NEW_WINDOW_MACRO(WaveEffect, WaveWindow)
410
411 void WaveEffect::update_gui()
412 {
413         if(thread)
414         {
415                 thread->window->lock_window();
416                 load_configuration();
417                 ((WaveWindow*)thread->window)->update_mode();
418 //              thread->window->reflective->update(config.reflective);
419                 ((WaveWindow*)thread->window)->amplitude_text->update(config.amplitude);
420                 ((WaveWindow*)thread->window)->amplitude_slider->update(config.amplitude);
421                 ((WaveWindow*)thread->window)->phase_text->update(config.phase);
422                 ((WaveWindow*)thread->window)->phase_slider->update(config.phase);
423                 ((WaveWindow*)thread->window)->wavelength_text->update(config.wavelength);
424                 ((WaveWindow*)thread->window)->wavelength_slider->update(config.wavelength);
425                 thread->window->unlock_window();
426         }
427 }
428
429
430 LOAD_CONFIGURATION_MACRO(WaveEffect, WaveConfig)
431
432
433 void WaveEffect::save_data(KeyFrame *keyframe)
434 {
435         FileXML output;
436
437 // cause data to be stored directly in text
438         output.set_shared_output(keyframe->xbuf);
439         output.tag.set_title("WAVE");
440         output.tag.set_property("MODE", config.mode);
441         output.tag.set_property("REFLECTIVE", config.reflective);
442         output.tag.set_property("AMPLITUDE", config.amplitude);
443         output.tag.set_property("PHASE", config.phase);
444         output.tag.set_property("WAVELENGTH", config.wavelength);
445         output.append_tag();
446         output.tag.set_title("/WAVE");
447         output.append_tag();
448         output.append_newline();
449         output.terminate_string();
450 }
451
452 void WaveEffect::read_data(KeyFrame *keyframe)
453 {
454         FileXML input;
455
456         input.set_shared_input(keyframe->xbuf);
457
458         while(!input.read_tag())
459         {
460                 if(input.tag.title_is("WAVE"))
461                 {
462                         config.mode = input.tag.get_property("MODE", config.mode);
463                         config.reflective = input.tag.get_property("REFLECTIVE", config.reflective);
464                         config.amplitude = input.tag.get_property("AMPLITUDE", config.amplitude);
465                         config.phase = input.tag.get_property("PHASE", config.phase);
466                         config.wavelength = input.tag.get_property("WAVELENGTH", config.wavelength);
467                 }
468         }
469 }
470
471
472 int WaveEffect::process_realtime(VFrame *input, VFrame *output)
473 {
474         load_configuration();
475
476
477
478 //printf("WaveEffect::process_realtime %f %d\n", config.radius, config.use_intensity);
479         this->input = input;
480         this->output = output;
481
482         if(EQUIV(config.amplitude, 0) || EQUIV(config.wavelength, 0))
483         {
484                 if(input->get_rows()[0] != output->get_rows()[0])
485                         output->copy_from(input);
486         }
487         else
488         {
489                 if(input->get_rows()[0] == output->get_rows()[0])
490                 {
491                         if(!temp_frame) temp_frame = new VFrame(input->get_w(), input->get_h(),
492                                 input->get_color_model(), 0);
493                         temp_frame->copy_from(input);
494                         this->input = temp_frame;
495                 }
496
497
498                 if(!engine)
499                 {
500                         engine = new WaveServer(this, (PluginClient::smp + 1));
501                 }
502
503                 engine->process_packages();
504         }
505
506
507
508         return 0;
509 }
510
511
512
513
514
515
516 WavePackage::WavePackage()
517  : LoadPackage()
518 {
519 }
520
521
522
523
524
525
526 WaveUnit::WaveUnit(WaveEffect *plugin, WaveServer *server)
527  : LoadClient(server)
528 {
529         this->plugin = plugin;
530 }
531
532
533
534 #define WITHIN(a, b, c) ((((a) <= (b)) && ((b) <= (c))) ? 1 : 0)
535
536 static float bilinear(double  x,
537           double  y,
538           float  *v)
539 {
540         double m0, m1;
541         x = fmod(x, 1.0);
542         y = fmod(y, 1.0);
543
544         if(x < 0)
545         x += 1.0;
546         if(y < 0)
547         y += 1.0;
548
549         m0 = (1.0 - x) * v[0] + x * v[1];
550         m1 = (1.0 - x) * v[2] + x * v[3];
551
552         return((1.0 - y) * m0 + y * m1);
553 }
554
555 void WaveUnit::process_package(LoadPackage *package)
556 {
557         WavePackage *pkg = (WavePackage*)package;
558         int w = plugin->input->get_w();
559         int h = plugin->input->get_h();
560         double cen_x, cen_y;       /* Center of wave */
561         double xhsiz, yhsiz;       /* Half size of selection */
562         double radius;             /* Radius */
563         double amnt, d;
564         double needx, needy;
565         double dx, dy;
566         double xscale, yscale;
567         double wavelength;
568         int xi, yi;
569         float values[4];
570         float val;
571         int x1, y1, x2, y2;
572         int x1_in, y1_in, x2_in, y2_in;
573         double phase = plugin->config.phase * M_PI / 180;
574
575
576         x1 = y1 = 0;
577         x2 = w;
578         y2 = h;
579         cen_x = (double) (x2 - 1 + x1) / 2.0;
580         cen_y = (double) (y2 - 1 + y1) / 2.0;
581         xhsiz = (double) (x2 - x1) / 2.0;
582         yhsiz = (double) (y2 - y1) / 2.0;
583
584         if (xhsiz < yhsiz)
585     {
586         xscale = yhsiz / xhsiz;
587         yscale = 1.0;
588     }
589         else if (xhsiz > yhsiz)
590     {
591         xscale = 1.0;
592         yscale = xhsiz / yhsiz;
593     }
594         else
595     {
596         xscale = 1.0;
597         yscale = 1.0;
598     }
599
600         radius  = MAX(xhsiz, yhsiz);
601
602
603         wavelength = plugin->config.wavelength / 100 * radius;
604
605
606
607
608 #define WAVE(type, components, chroma_offset) \
609 { \
610         int row_size = w * components; \
611         type **in_rows = (type**)plugin->input->get_rows(); \
612         for(int y = pkg->row1; y < pkg->row2; y++) \
613         { \
614                 type *dest = (type*)plugin->output->get_rows()[y]; \
615  \
616                 for(int x = x1; x < x2; x++) \
617                 { \
618                         dx = (x - cen_x) * xscale; \
619                         dy = (y - cen_y) * yscale; \
620                     d = sqrt(dx * dx + dy * dy); \
621  \
622                         if(plugin->config.reflective) \
623                         { \
624                         amnt = plugin->config.amplitude *  \
625                                         fabs(sin(((d / wavelength) *  \
626                                                 (2.0 * M_PI) + \
627                                                 phase))); \
628  \
629                         needx = (amnt * dx) / xscale + cen_x; \
630                         needy = (amnt * dy) / yscale + cen_y; \
631                         } \
632                         else \
633                         { \
634                         amnt = plugin->config.amplitude *  \
635                                         sin(((d / wavelength) *  \
636                                                 (2.0 * M_PI) + \
637                                         phase)); \
638  \
639                         needx = (amnt + dx) / xscale + cen_x; \
640                         needy = (amnt + dy) / yscale + cen_y; \
641                         } \
642  \
643                         xi = (int)needx; \
644                         yi = (int)needy; \
645  \
646                         if(plugin->config.mode == SMEAR) \
647                 { \
648                         if(xi > w - 2) \
649                                 { \
650                                         xi = w - 2; \
651                                 } \
652                         else  \
653                                 if(xi < 0) \
654                                 { \
655                                         xi = 0; \
656                                 } \
657  \
658                         if(yi > h - 2) \
659                                 { \
660                                         yi = h - 2; \
661                                 } \
662                         else  \
663                                 if(yi < 0) \
664                                 { \
665                                         yi = 0; \
666                                 } \
667                 } \
668  \
669                         type *p = in_rows[CLIP(yi, 0, h - 1)] + \
670                                 CLIP(xi, 0, w - 1) * components; \
671                         x1_in = WITHIN(0, xi, w - 1); \
672                         y1_in = WITHIN(0, yi, h - 1); \
673                         x2_in = WITHIN(0, xi + 1, w - 1); \
674                         y2_in = WITHIN(0, yi + 1, h - 1); \
675  \
676  \
677                         for(int k = 0; k < components; k++) \
678                 { \
679                         if (x1_in && y1_in) \
680                                         values[0] = *(p + k); \
681                         else \
682                                         values[0] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
683  \
684                         if (x2_in && y1_in) \
685                                         values[1] = *(p + components + k); \
686                         else \
687                                         values[1] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
688  \
689                         if (x1_in && y2_in) \
690                                         values[2] = *(p + row_size + k); \
691                         else \
692                                         values[2] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
693  \
694                         if (x2_in) \
695                                 { \
696                                         if (y2_in) \
697                                         values[3] = *(p + row_size + components + k); \
698                                         else \
699                                         values[3] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
700                                 } \
701                         else \
702                                         values[3] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
703  \
704                         val = bilinear(needx, needy, values); \
705  \
706                         *dest++ = (type)val; \
707                 } \
708                 } \
709         } \
710 }
711
712
713
714
715         switch(plugin->input->get_color_model())
716         {
717                 case BC_RGB888:
718                         WAVE(unsigned char, 3, 0x0);
719                         break;
720                 case BC_RGB_FLOAT:
721                         WAVE(float, 3, 0x0);
722                         break;
723                 case BC_YUV888:
724                         WAVE(unsigned char, 3, 0x80);
725                         break;
726                 case BC_RGB161616:
727                         WAVE(uint16_t, 3, 0x0);
728                         break;
729                 case BC_YUV161616:
730                         WAVE(uint16_t, 3, 0x8000);
731                         break;
732                 case BC_RGBA_FLOAT:
733                         WAVE(unsigned char, 4, 0x0);
734                         break;
735                 case BC_RGBA8888:
736                         WAVE(unsigned char, 4, 0x0);
737                         break;
738                 case BC_YUVA8888:
739                         WAVE(unsigned char, 4, 0x8000);
740                         break;
741                 case BC_RGBA16161616:
742                         WAVE(uint16_t, 4, 0x0);
743                         break;
744                 case BC_YUVA16161616:
745                         WAVE(uint16_t, 4, 0x8000);
746                         break;
747         }
748
749
750
751
752 }
753
754
755
756
757
758
759 WaveServer::WaveServer(WaveEffect *plugin, int cpus)
760  : LoadServer(cpus, cpus)
761 {
762         this->plugin = plugin;
763 }
764
765 void WaveServer::init_packages()
766 {
767         for(int i = 0; i < LoadServer::get_total_packages(); i++)
768         {
769                 WavePackage *pkg = (WavePackage*)get_package(i);
770                 pkg->row1 = plugin->input->get_h() * i / LoadServer::get_total_packages();
771                 pkg->row2 = plugin->input->get_h() * (i + 1) / LoadServer::get_total_packages();
772         }
773 }
774
775
776 LoadClient* WaveServer::new_client()
777 {
778         return new WaveUnit(plugin, this);
779 }
780
781 LoadPackage* WaveServer::new_package()
782 {
783         return new WavePackage;
784 }
785