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