bg/clr color tweaks, clear borders rework, fc31 depends
[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 WaveAmplitude::WaveAmplitude(WaveEffect *plugin, int x, int y)
156  : BC_FSlider(x,
157                         y,
158                         0,
159                         xS(200),
160                         yS(200),
161                         (float)0,
162                         (float)100,
163                         plugin->config.amplitude)
164 {
165         this->plugin = plugin;
166 }
167 int WaveAmplitude::handle_event()
168 {
169         plugin->config.amplitude = get_value();
170         plugin->send_configure_change();
171         return 1;
172 }
173
174
175
176 WavePhase::WavePhase(WaveEffect *plugin, int x, int y)
177  : BC_FSlider(x,
178                         y,
179                         0,
180                         xS(200),
181                         yS(200),
182                         (float)0,
183                         (float)360,
184                         plugin->config.phase)
185 {
186         this->plugin = plugin;
187 }
188 int WavePhase::handle_event()
189 {
190         plugin->config.phase = get_value();
191         plugin->send_configure_change();
192         return 1;
193 }
194
195 WaveLength::WaveLength(WaveEffect *plugin, int x, int y)
196  : BC_FSlider(x,
197                         y,
198                         0,
199                         xS(200),
200                         yS(200),
201                         (float)0,
202                         (float)50,
203                         plugin->config.wavelength)
204 {
205         this->plugin = plugin;
206 }
207 int WaveLength::handle_event()
208 {
209         plugin->config.wavelength = get_value();
210         plugin->send_configure_change();
211         return 1;
212 }
213
214 WaveReset::WaveReset(WaveEffect *plugin, WaveWindow *gui, int x, int y)
215  : BC_GenericButton(x, y, _("Reset"))
216 {
217         this->plugin = plugin;
218         this->gui = gui;
219 }
220 WaveReset::~WaveReset()
221 {
222 }
223 int WaveReset::handle_event()
224 {
225         plugin->config.reset(RESET_ALL);
226         gui->update_gui(RESET_ALL);
227         plugin->send_configure_change();
228         return 1;
229 }
230
231 WaveDefaultSettings::WaveDefaultSettings(WaveEffect *plugin, WaveWindow *gui, int x, int y, int w)
232  : BC_GenericButton(x, y, w, _("Default"))
233 {
234         this->plugin = plugin;
235         this->gui = gui;
236 }
237 WaveDefaultSettings::~WaveDefaultSettings()
238 {
239 }
240 int WaveDefaultSettings::handle_event()
241 {
242         plugin->config.reset(RESET_DEFAULT_SETTINGS);
243         gui->update_gui(RESET_DEFAULT_SETTINGS);
244         plugin->send_configure_change();
245         return 1;
246 }
247
248 WaveSliderClr::WaveSliderClr(WaveEffect *plugin, WaveWindow *gui, int x, int y, int w, int clear)
249  : BC_Button(x, y, w, plugin->get_theme()->get_image_set("reset_button"))
250 {
251         this->plugin = plugin;
252         this->gui = gui;
253         this->clear = clear;
254 }
255 WaveSliderClr::~WaveSliderClr()
256 {
257 }
258 int WaveSliderClr::handle_event()
259 {
260         // clear==1 ==> Amplitude slider
261         // clear==2 ==> Phase slider
262         // clear==3 ==> Steps slider
263         plugin->config.reset(clear);
264         gui->update_gui(clear);
265         plugin->send_configure_change();
266         return 1;
267 }
268
269
270
271
272 WaveWindow::WaveWindow(WaveEffect *plugin)
273  : PluginClientWindow(plugin, xS(385), yS(140), xS(385), yS(140), 0)
274 {
275         this->plugin = plugin;
276 }
277
278 WaveWindow::~WaveWindow()
279 {
280 }
281
282 void WaveWindow::create_objects()
283 {
284         int xs10 = xS(10), xs50 = xS(50), xs100 = xS(100), xs115 = xS(115);
285         int ys10 = yS(10), ys30 = yS(30), ys40 = yS(40);
286         int x = xs10, y = ys10, x1 = xs115;
287         int x2 = 0; int clrBtn_w = xs50;
288         int defaultBtn_w = xs100;
289
290 //      add_subwindow(new BC_Title(x, y, _("Mode:")));
291 //      add_subwindow(smear = new WaveSmear(plugin, this, x1, y));
292 //      y += ys20;
293 //      add_subwindow(blacken = new WaveBlacken(plugin, this, x1, y));
294 //      y += ys30;
295 //      add_subwindow(reflective = new WaveReflective(plugin, x1, y));
296 //      y += ys30;
297         add_subwindow(new BC_Title(x, y, _("Amplitude:")));
298         add_subwindow(amplitude = new WaveAmplitude(plugin, x1, y));
299         x2 = x1 + amplitude->get_w() + xs10;
300         add_subwindow(amplitudeClr = new WaveSliderClr(plugin, this, x2, y, clrBtn_w, RESET_AMPLITUDE));
301
302         y += ys30;
303         add_subwindow(new BC_Title(x, y, _("Phase:")));
304         add_subwindow(phase = new WavePhase(plugin, x1, y));
305         add_subwindow(phaseClr = new WaveSliderClr(plugin, this, x2, y, clrBtn_w, RESET_PHASE));
306
307         y += ys30;
308         add_subwindow(new BC_Title(x, y, _("Wavelength:")));
309         add_subwindow(wavelength = new WaveLength(plugin, x1, y));
310         add_subwindow(wavelengthClr = new WaveSliderClr(plugin, this, x2, y, clrBtn_w, RESET_WAVELENGTH));
311
312         y += ys40;
313         add_subwindow(reset = new WaveReset(plugin, this, x, y));
314         add_subwindow(default_settings = new WaveDefaultSettings(plugin, this,
315                 (xS(385) - xs10 - defaultBtn_w), y, defaultBtn_w));
316
317         show_window();
318         flush();
319 }
320
321 void WaveWindow::update_mode()
322 {
323 //      smear->update(plugin->config.mode == SMEAR);
324 //      blacken->update(plugin->config.mode == BLACKEN);
325 }
326
327 // for Reset button
328 void WaveWindow::update_gui(int clear)
329 {
330         switch(clear) {
331                 case RESET_AMPLITUDE : amplitude->update(plugin->config.amplitude);
332                         break;
333                 case RESET_PHASE : phase->update(plugin->config.phase);
334                         break;
335                 case RESET_WAVELENGTH : wavelength->update(plugin->config.wavelength);
336                         break;
337                 case RESET_ALL :
338                 case RESET_DEFAULT_SETTINGS :
339                 default:
340                         amplitude->update(plugin->config.amplitude);
341                         phase->update(plugin->config.phase);
342                         wavelength->update(plugin->config.wavelength);
343                         break;
344         }
345 }
346
347
348
349
350
351
352
353
354
355 REGISTER_PLUGIN(WaveEffect)
356
357
358
359
360 WaveEffect::WaveEffect(PluginServer *server)
361  : PluginVClient(server)
362 {
363         temp_frame = 0;
364         engine = 0;
365
366 }
367
368 WaveEffect::~WaveEffect()
369 {
370
371
372         if(temp_frame) delete temp_frame;
373         if(engine) delete engine;
374 }
375
376
377 const char* WaveEffect::plugin_title() { return N_("Wave"); }
378 int WaveEffect::is_realtime() { return 1; }
379
380
381 NEW_WINDOW_MACRO(WaveEffect, WaveWindow)
382
383 void WaveEffect::update_gui()
384 {
385         if(thread)
386         {
387                 thread->window->lock_window();
388                 load_configuration();
389                 ((WaveWindow*)thread->window)->update_mode();
390 //              thread->window->reflective->update(config.reflective);
391                 ((WaveWindow*)thread->window)->amplitude->update(config.amplitude);
392                 ((WaveWindow*)thread->window)->phase->update(config.phase);
393                 ((WaveWindow*)thread->window)->wavelength->update(config.wavelength);
394                 thread->window->unlock_window();
395         }
396 }
397
398
399 LOAD_CONFIGURATION_MACRO(WaveEffect, WaveConfig)
400
401
402 void WaveEffect::save_data(KeyFrame *keyframe)
403 {
404         FileXML output;
405
406 // cause data to be stored directly in text
407         output.set_shared_output(keyframe->xbuf);
408         output.tag.set_title("WAVE");
409         output.tag.set_property("MODE", config.mode);
410         output.tag.set_property("REFLECTIVE", config.reflective);
411         output.tag.set_property("AMPLITUDE", config.amplitude);
412         output.tag.set_property("PHASE", config.phase);
413         output.tag.set_property("WAVELENGTH", config.wavelength);
414         output.append_tag();
415         output.tag.set_title("/WAVE");
416         output.append_tag();
417         output.append_newline();
418         output.terminate_string();
419 }
420
421 void WaveEffect::read_data(KeyFrame *keyframe)
422 {
423         FileXML input;
424
425         input.set_shared_input(keyframe->xbuf);
426
427         while(!input.read_tag())
428         {
429                 if(input.tag.title_is("WAVE"))
430                 {
431                         config.mode = input.tag.get_property("MODE", config.mode);
432                         config.reflective = input.tag.get_property("REFLECTIVE", config.reflective);
433                         config.amplitude = input.tag.get_property("AMPLITUDE", config.amplitude);
434                         config.phase = input.tag.get_property("PHASE", config.phase);
435                         config.wavelength = input.tag.get_property("WAVELENGTH", config.wavelength);
436                 }
437         }
438 }
439
440
441 int WaveEffect::process_realtime(VFrame *input, VFrame *output)
442 {
443         load_configuration();
444
445
446
447 //printf("WaveEffect::process_realtime %f %d\n", config.radius, config.use_intensity);
448         this->input = input;
449         this->output = output;
450
451         if(EQUIV(config.amplitude, 0) || EQUIV(config.wavelength, 0))
452         {
453                 if(input->get_rows()[0] != output->get_rows()[0])
454                         output->copy_from(input);
455         }
456         else
457         {
458                 if(input->get_rows()[0] == output->get_rows()[0])
459                 {
460                         if(!temp_frame) temp_frame = new VFrame(input->get_w(), input->get_h(),
461                                 input->get_color_model(), 0);
462                         temp_frame->copy_from(input);
463                         this->input = temp_frame;
464                 }
465
466
467                 if(!engine)
468                 {
469                         engine = new WaveServer(this, (PluginClient::smp + 1));
470                 }
471
472                 engine->process_packages();
473         }
474
475
476
477         return 0;
478 }
479
480
481
482
483
484
485 WavePackage::WavePackage()
486  : LoadPackage()
487 {
488 }
489
490
491
492
493
494
495 WaveUnit::WaveUnit(WaveEffect *plugin, WaveServer *server)
496  : LoadClient(server)
497 {
498         this->plugin = plugin;
499 }
500
501
502
503 #define WITHIN(a, b, c) ((((a) <= (b)) && ((b) <= (c))) ? 1 : 0)
504
505 static float bilinear(double  x,
506           double  y,
507           float  *v)
508 {
509         double m0, m1;
510         x = fmod(x, 1.0);
511         y = fmod(y, 1.0);
512
513         if(x < 0)
514         x += 1.0;
515         if(y < 0)
516         y += 1.0;
517
518         m0 = (1.0 - x) * v[0] + x * v[1];
519         m1 = (1.0 - x) * v[2] + x * v[3];
520
521         return((1.0 - y) * m0 + y * m1);
522 }
523
524 void WaveUnit::process_package(LoadPackage *package)
525 {
526         WavePackage *pkg = (WavePackage*)package;
527         int w = plugin->input->get_w();
528         int h = plugin->input->get_h();
529         double cen_x, cen_y;       /* Center of wave */
530         double xhsiz, yhsiz;       /* Half size of selection */
531         double radius;             /* Radius */
532         double amnt, d;
533         double needx, needy;
534         double dx, dy;
535         double xscale, yscale;
536         double wavelength;
537         int xi, yi;
538         float values[4];
539         float val;
540         int x1, y1, x2, y2;
541         int x1_in, y1_in, x2_in, y2_in;
542         double phase = plugin->config.phase * M_PI / 180;
543
544
545         x1 = y1 = 0;
546         x2 = w;
547         y2 = h;
548         cen_x = (double) (x2 - 1 + x1) / 2.0;
549         cen_y = (double) (y2 - 1 + y1) / 2.0;
550         xhsiz = (double) (x2 - x1) / 2.0;
551         yhsiz = (double) (y2 - y1) / 2.0;
552
553         if (xhsiz < yhsiz)
554     {
555         xscale = yhsiz / xhsiz;
556         yscale = 1.0;
557     }
558         else if (xhsiz > yhsiz)
559     {
560         xscale = 1.0;
561         yscale = xhsiz / yhsiz;
562     }
563         else
564     {
565         xscale = 1.0;
566         yscale = 1.0;
567     }
568
569         radius  = MAX(xhsiz, yhsiz);
570
571
572         wavelength = plugin->config.wavelength / 100 * radius;
573
574
575
576
577 #define WAVE(type, components, chroma_offset) \
578 { \
579         int row_size = w * components; \
580         type **in_rows = (type**)plugin->input->get_rows(); \
581         for(int y = pkg->row1; y < pkg->row2; y++) \
582         { \
583                 type *dest = (type*)plugin->output->get_rows()[y]; \
584  \
585                 for(int x = x1; x < x2; x++) \
586                 { \
587                         dx = (x - cen_x) * xscale; \
588                         dy = (y - cen_y) * yscale; \
589                     d = sqrt(dx * dx + dy * dy); \
590  \
591                         if(plugin->config.reflective) \
592                         { \
593                         amnt = plugin->config.amplitude *  \
594                                         fabs(sin(((d / wavelength) *  \
595                                                 (2.0 * M_PI) + \
596                                                 phase))); \
597  \
598                         needx = (amnt * dx) / xscale + cen_x; \
599                         needy = (amnt * dy) / yscale + cen_y; \
600                         } \
601                         else \
602                         { \
603                         amnt = plugin->config.amplitude *  \
604                                         sin(((d / wavelength) *  \
605                                                 (2.0 * M_PI) + \
606                                         phase)); \
607  \
608                         needx = (amnt + dx) / xscale + cen_x; \
609                         needy = (amnt + dy) / yscale + cen_y; \
610                         } \
611  \
612                         xi = (int)needx; \
613                         yi = (int)needy; \
614  \
615                         if(plugin->config.mode == SMEAR) \
616                 { \
617                         if(xi > w - 2) \
618                                 { \
619                                         xi = w - 2; \
620                                 } \
621                         else  \
622                                 if(xi < 0) \
623                                 { \
624                                         xi = 0; \
625                                 } \
626  \
627                         if(yi > h - 2) \
628                                 { \
629                                         yi = h - 2; \
630                                 } \
631                         else  \
632                                 if(yi < 0) \
633                                 { \
634                                         yi = 0; \
635                                 } \
636                 } \
637  \
638                         type *p = in_rows[CLIP(yi, 0, h - 1)] + \
639                                 CLIP(xi, 0, w - 1) * components; \
640                         x1_in = WITHIN(0, xi, w - 1); \
641                         y1_in = WITHIN(0, yi, h - 1); \
642                         x2_in = WITHIN(0, xi + 1, w - 1); \
643                         y2_in = WITHIN(0, yi + 1, h - 1); \
644  \
645  \
646                         for(int k = 0; k < components; k++) \
647                 { \
648                         if (x1_in && y1_in) \
649                                         values[0] = *(p + k); \
650                         else \
651                                         values[0] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
652  \
653                         if (x2_in && y1_in) \
654                                         values[1] = *(p + components + k); \
655                         else \
656                                         values[1] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
657  \
658                         if (x1_in && y2_in) \
659                                         values[2] = *(p + row_size + k); \
660                         else \
661                                         values[2] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
662  \
663                         if (x2_in) \
664                                 { \
665                                         if (y2_in) \
666                                         values[3] = *(p + row_size + components + k); \
667                                         else \
668                                         values[3] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
669                                 } \
670                         else \
671                                         values[3] = ((k == 1 || k == 2) ? 0 : chroma_offset); \
672  \
673                         val = bilinear(needx, needy, values); \
674  \
675                         *dest++ = (type)val; \
676                 } \
677                 } \
678         } \
679 }
680
681
682
683
684         switch(plugin->input->get_color_model())
685         {
686                 case BC_RGB888:
687                         WAVE(unsigned char, 3, 0x0);
688                         break;
689                 case BC_RGB_FLOAT:
690                         WAVE(float, 3, 0x0);
691                         break;
692                 case BC_YUV888:
693                         WAVE(unsigned char, 3, 0x80);
694                         break;
695                 case BC_RGB161616:
696                         WAVE(uint16_t, 3, 0x0);
697                         break;
698                 case BC_YUV161616:
699                         WAVE(uint16_t, 3, 0x8000);
700                         break;
701                 case BC_RGBA_FLOAT:
702                         WAVE(unsigned char, 4, 0x0);
703                         break;
704                 case BC_RGBA8888:
705                         WAVE(unsigned char, 4, 0x0);
706                         break;
707                 case BC_YUVA8888:
708                         WAVE(unsigned char, 4, 0x8000);
709                         break;
710                 case BC_RGBA16161616:
711                         WAVE(uint16_t, 4, 0x0);
712                         break;
713                 case BC_YUVA16161616:
714                         WAVE(uint16_t, 4, 0x8000);
715                         break;
716         }
717
718
719
720
721 }
722
723
724
725
726
727
728 WaveServer::WaveServer(WaveEffect *plugin, int cpus)
729  : LoadServer(cpus, cpus)
730 {
731         this->plugin = plugin;
732 }
733
734 void WaveServer::init_packages()
735 {
736         for(int i = 0; i < LoadServer::get_total_packages(); i++)
737         {
738                 WavePackage *pkg = (WavePackage*)get_package(i);
739                 pkg->row1 = plugin->input->get_h() * i / LoadServer::get_total_packages();
740                 pkg->row2 = plugin->input->get_h() * (i + 1) / LoadServer::get_total_packages();
741         }
742 }
743
744
745 LoadClient* WaveServer::new_client()
746 {
747         return new WaveUnit(plugin, this);
748 }
749
750 LoadPackage* WaveServer::new_package()
751 {
752         return new WavePackage;
753 }
754