Credit Andrew - fix vorbis audio which was scratchy and ensure aging plugin does...
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / timefront / timefront.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  * Copyright (C) 2003-2016 Cinelerra CV contributors
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  */
22
23 #include <math.h>
24 #include <stdint.h>
25 #include <string.h>
26
27 #include "bcdisplayinfo.h"
28 #include "clip.h"
29 #include "bchash.h"
30 #include "filexml.h"
31 #include "timefront.h"
32 #include "keyframe.h"
33 #include "language.h"
34 #include "overlayframe.h"
35 #include "vframe.h"
36
37
38
39
40 REGISTER_PLUGIN(TimeFrontMain)
41
42
43
44
45
46
47 TimeFrontConfig::TimeFrontConfig()
48 {
49         angle = 0;
50         in_radius = 0;
51         out_radius = 100;
52         frame_range = 16;
53         track_usage = TimeFrontConfig::OTHERTRACK_INTENSITY;
54         shape = TimeFrontConfig::LINEAR;
55         rate = TimeFrontConfig::LINEAR;
56         center_x = 50;
57         center_y = 50;
58         invert = 0;
59         show_grayscale = 0;
60 }
61
62 int TimeFrontConfig::equivalent(TimeFrontConfig &that)
63 {
64         return (EQUIV(angle, that.angle) &&
65                 EQUIV(in_radius, that.in_radius) &&
66                 EQUIV(out_radius, that.out_radius) &&
67                 frame_range == that.frame_range &&
68                 track_usage == that.track_usage &&
69                 shape == that.shape &&
70                 rate == that.rate &&
71                 EQUIV(center_x, that.center_x) &&
72                 EQUIV(center_y, that.center_y) &&
73                 invert == that.invert &&
74                 show_grayscale == that.show_grayscale);
75 }
76
77 void TimeFrontConfig::copy_from(TimeFrontConfig &that)
78 {
79         angle = that.angle;
80         in_radius = that.in_radius;
81         out_radius = that.out_radius;
82         frame_range = that.frame_range;
83         track_usage = that.track_usage;
84         shape = that.shape;
85         rate = that.rate;
86         center_x = that.center_x;
87         center_y = that.center_y;
88         invert = that.invert;
89         show_grayscale = that.show_grayscale;
90 }
91
92 void TimeFrontConfig::interpolate(TimeFrontConfig &prev,
93         TimeFrontConfig &next,
94         long prev_frame,
95         long next_frame,
96         long current_frame)
97 {
98         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
99         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
100
101
102         this->angle = (int)(prev.angle * prev_scale + next.angle * next_scale);
103         this->in_radius = (int)(prev.in_radius * prev_scale + next.in_radius * next_scale);
104         this->out_radius = (int)(prev.out_radius * prev_scale + next.out_radius * next_scale);
105         frame_range = (int)(prev.frame_range * prev_scale + next.frame_range * next_scale);
106         track_usage = prev.track_usage;
107         shape = prev.shape;
108         rate = prev.rate;
109         center_x = prev.center_x * prev_scale + next.center_x * next_scale;
110         center_y = prev.center_y * prev_scale + next.center_y * next_scale;
111         invert = prev.invert;
112         show_grayscale = prev.show_grayscale;
113 }
114
115
116
117
118
119
120
121
122 TimeFrontWindow::TimeFrontWindow(TimeFrontMain *plugin)
123  : PluginClientWindow(plugin,
124         xS(350),
125         yS(290),
126         xS(350),
127         yS(290),
128         0)
129 {
130         this->plugin = plugin;
131         angle = 0;
132         angle_title = 0;
133         center_x = 0;
134         center_y = 0;
135         center_x_title = 0;
136         center_y_title = 0;
137         rate_title = 0;
138         rate = 0;
139         in_radius_title = 0;
140         in_radius = 0;
141         out_radius_title = 0;
142         out_radius = 0;
143         track_usage_title = 0;
144         track_usage = 0;
145
146 }
147
148 TimeFrontWindow::~TimeFrontWindow()
149 {
150 }
151
152 void TimeFrontWindow::create_objects()
153 {
154         int xs10 = xS(10);
155         int ys10 = yS(10), ys35 = yS(35), ys40 = yS(40), ys140 = yS(140);
156         int x = xs10, y = ys10;
157         BC_Title *title;
158
159         add_subwindow(title = new BC_Title(x, y, _("Type:")));
160         add_subwindow(shape = new TimeFrontShape(plugin,
161                 this,
162                 x + title->get_w() + xs10,
163                 y));
164         shape->create_objects();
165         y += ys40;
166         shape_x = x;
167         shape_y = y;
168         y += ys140;
169         add_subwindow(title = new BC_Title(x, y, _("Time range:")));
170         add_subwindow(frame_range = new TimeFrontFrameRange(plugin, x + title->get_w() + xs10, y));
171         frame_range_x = x + frame_range->get_w() + xs10;
172         frame_range_y = y;
173         y += ys35;
174         update_shape();
175
176         add_subwindow(invert = new TimeFrontInvert(plugin, x, y));
177         add_subwindow(show_grayscale = new TimeFrontShowGrayscale(plugin, x+ xS(100), y));
178
179
180         show_window();
181         flush();
182 }
183
184 void TimeFrontWindow::update_shape()
185 {
186         int x = shape_x, y = shape_y;
187
188         if(plugin->config.shape == TimeFrontConfig::LINEAR)
189         {
190                 delete center_x_title;
191                 delete center_y_title;
192                 delete center_x;
193                 delete center_y;
194                 delete track_usage_title;
195                 delete track_usage;
196                 center_x_title = 0;
197                 center_y_title = 0;
198                 center_x = 0;
199                 center_y = 0;
200                 track_usage_title = 0;
201                 track_usage = 0;
202                 if(!angle)
203                 {
204                         add_subwindow(angle_title = new BC_Title(x, y, _("Angle:")));
205                         add_subwindow(angle = new TimeFrontAngle(plugin, x + angle_title->get_w() + xS(10), y));
206                 }
207                 if(!rate){
208                         y = shape_y + yS(40);
209
210                         add_subwindow(rate_title = new BC_Title(x, y, _("Rate:")));
211                         add_subwindow(rate = new TimeFrontRate(plugin,
212                                 x + rate_title->get_w() + xS(10),
213                                 y));
214                         rate->create_objects();
215                         y += yS(40);
216                         add_subwindow(in_radius_title = new BC_Title(x, y, _("Inner radius:")));
217                         add_subwindow(in_radius = new TimeFrontInRadius(plugin, x + in_radius_title->get_w() + xS(10), y));
218                         y += yS(30);
219                         add_subwindow(out_radius_title = new BC_Title(x, y, _("Outer radius:")));
220                         add_subwindow(out_radius = new TimeFrontOutRadius(plugin, x + out_radius_title->get_w() + xS(10), y));
221                         y += yS(35);
222
223                 }
224         } else
225         if(plugin->config.shape == TimeFrontConfig::RADIAL)
226         {
227                 delete angle_title;
228                 delete angle;
229                 delete track_usage_title;
230                 delete track_usage;
231                 angle_title = 0;
232                 angle = 0;
233                 track_usage_title = 0;
234                 track_usage = 0;
235                 if(!center_x)
236                 {
237                         add_subwindow(center_x_title = new BC_Title(x, y, _("Center X:")));
238                         add_subwindow(center_x = new TimeFrontCenterX(plugin,
239                                 x + center_x_title->get_w() + xS(10),
240                                 y));
241                         x += center_x_title->get_w() + xS(10) + center_x->get_w() + xS(10);
242                         add_subwindow(center_y_title = new BC_Title(x, y, _("Center Y:")));
243                         add_subwindow(center_y = new TimeFrontCenterY(plugin,
244                                 x + center_y_title->get_w() + xS(10),
245                                 y));
246                 }
247
248
249                 if(!rate)
250                 {
251                         y = shape_y + yS(40);
252                         x = shape_x;
253                         add_subwindow(rate_title = new BC_Title(x, y, _("Rate:")));
254                         add_subwindow(rate = new TimeFrontRate(plugin,
255                                 x + rate_title->get_w() + xS(10),
256                                 y));
257                         rate->create_objects();
258                         y += yS(40);
259                         add_subwindow(in_radius_title = new BC_Title(x, y, _("Inner radius:")));
260                         add_subwindow(in_radius = new TimeFrontInRadius(plugin, x + in_radius_title->get_w() + xS(10), y));
261                         y += yS(30);
262                         add_subwindow(out_radius_title = new BC_Title(x, y, _("Outer radius:")));
263                         add_subwindow(out_radius = new TimeFrontOutRadius(plugin, x + out_radius_title->get_w() + xS(10), y));
264                         y += yS(35);
265                 }
266         } else
267         if(plugin->config.shape == TimeFrontConfig::OTHERTRACK)
268         {
269                 delete center_x_title;
270                 delete center_y_title;
271                 delete center_x;
272                 delete center_y;
273                 delete angle_title;
274                 delete angle;
275                 delete rate_title;
276                 delete rate;
277                 delete in_radius_title;
278                 delete in_radius;
279                 delete out_radius_title;
280                 delete out_radius;
281                 center_x_title = 0;
282                 center_y_title = 0;
283                 center_x = 0;
284                 center_y = 0;
285                 angle_title = 0;
286                 angle = 0;
287                 rate_title = 0;
288                 rate = 0;
289                 in_radius_title = 0;
290                 in_radius = 0;
291                 out_radius_title = 0;
292                 out_radius = 0;
293                 if(!track_usage)
294                 {
295                         add_subwindow(track_usage_title = new BC_Title(x, y, _("As timefront use:")));
296                         add_subwindow(track_usage = new TimeFrontTrackUsage(plugin,
297                                 this,
298                                 x + track_usage_title->get_w() + xS(10),
299                                 y));
300                         track_usage->create_objects();
301
302                 }
303         } else
304         if(plugin->config.shape == TimeFrontConfig::ALPHA)
305         {
306                 delete center_x_title;
307                 delete center_y_title;
308                 delete center_x;
309                 delete center_y;
310                 delete angle_title;
311                 delete angle;
312                 delete rate_title;
313                 delete rate;
314                 delete in_radius_title;
315                 delete in_radius;
316                 delete out_radius_title;
317                 delete out_radius;
318                 delete track_usage_title;
319                 delete track_usage;
320                 center_x_title = 0;
321                 center_y_title = 0;
322                 center_x = 0;
323                 center_y = 0;
324                 angle_title = 0;
325                 angle = 0;
326                 rate_title = 0;
327                 rate = 0;
328                 in_radius_title = 0;
329                 in_radius = 0;
330                 out_radius_title = 0;
331                 out_radius = 0;
332                 track_usage_title = 0;
333                 track_usage = 0;
334
335         }
336
337 }
338
339
340
341
342
343
344
345
346
347
348
349
350
351 TimeFrontShape::TimeFrontShape(TimeFrontMain *plugin,
352         TimeFrontWindow *gui,
353         int x,
354         int y)
355  : BC_PopupMenu(x, y, xS(230), to_text(plugin->config.shape), 1)
356 {
357         this->plugin = plugin;
358         this->gui = gui;
359 }
360 void TimeFrontShape::create_objects()
361 {
362         add_item(new BC_MenuItem(to_text(TimeFrontConfig::LINEAR)));
363         add_item(new BC_MenuItem(to_text(TimeFrontConfig::RADIAL)));
364         add_item(new BC_MenuItem(to_text(TimeFrontConfig::ALPHA)));
365         add_item(new BC_MenuItem(to_text(TimeFrontConfig::OTHERTRACK)));
366 }
367 char* TimeFrontShape::to_text(int shape)
368 {
369         switch(shape)
370         {
371                 case TimeFrontConfig::LINEAR:
372                         return _("Linear");
373                 case TimeFrontConfig::OTHERTRACK:
374                         return _("Other track as timefront");
375                 case TimeFrontConfig::ALPHA:
376                         return _("Alpha as timefront");
377                 default:
378                         return _("Radial");
379         }
380 }
381 int TimeFrontShape::from_text(char *text)
382 {
383         if(!strcmp(text, to_text(TimeFrontConfig::LINEAR)))
384                 return TimeFrontConfig::LINEAR;
385         if(!strcmp(text, to_text(TimeFrontConfig::OTHERTRACK)))
386                 return TimeFrontConfig::OTHERTRACK;
387         if(!strcmp(text, to_text(TimeFrontConfig::ALPHA)))
388                 return TimeFrontConfig::ALPHA;
389         return TimeFrontConfig::RADIAL;
390 }
391 int TimeFrontShape::handle_event()
392 {
393         plugin->config.shape = from_text(get_text());
394         gui->update_shape();
395         gui->show_window();
396         plugin->send_configure_change();
397         return 1;
398 }
399
400
401 TimeFrontTrackUsage::TimeFrontTrackUsage(TimeFrontMain *plugin,
402         TimeFrontWindow *gui, int x, int y)
403  : BC_PopupMenu(x, y, xS(140), to_text(plugin->config.track_usage), 1)
404 {
405         this->plugin = plugin;
406         this->gui = gui;
407 }
408 void TimeFrontTrackUsage::create_objects()
409 {
410         add_item(new BC_MenuItem(to_text(TimeFrontConfig::OTHERTRACK_INTENSITY)));
411         add_item(new BC_MenuItem(to_text(TimeFrontConfig::OTHERTRACK_ALPHA)));
412 }
413 char* TimeFrontTrackUsage::to_text(int track_usage)
414 {
415         switch(track_usage)
416         {
417                 case TimeFrontConfig::OTHERTRACK_INTENSITY:
418                         return _("Intensity");
419                 case TimeFrontConfig::OTHERTRACK_ALPHA:
420                         return _("Alpha mask");
421                 default:
422                         return _("Unknown");
423         }
424 }
425 int TimeFrontTrackUsage::from_text(char *text)
426 {
427         if(!strcmp(text, to_text(TimeFrontConfig::OTHERTRACK_INTENSITY)))
428                 return TimeFrontConfig::OTHERTRACK_INTENSITY;
429         if(!strcmp(text, to_text(TimeFrontConfig::OTHERTRACK_ALPHA)))
430                 return TimeFrontConfig::OTHERTRACK_ALPHA;
431
432         return TimeFrontConfig::OTHERTRACK_INTENSITY;
433 }
434 int TimeFrontTrackUsage::handle_event()
435 {
436         plugin->config.track_usage = from_text(get_text());
437         gui->update_shape();
438         gui->show_window();
439         plugin->send_configure_change();
440         return 1;
441 }
442
443
444
445
446 TimeFrontCenterX::TimeFrontCenterX(TimeFrontMain *plugin, int x, int y)
447  : BC_FPot(x, y, plugin->config.center_x, 0, 100)
448 {
449         this->plugin = plugin;
450 }
451 int TimeFrontCenterX::handle_event()
452 {
453         plugin->config.center_x = get_value();
454         plugin->send_configure_change();
455         return 1;
456 }
457
458
459
460 TimeFrontCenterY::TimeFrontCenterY(TimeFrontMain *plugin, int x, int y)
461  : BC_FPot(x, y, plugin->config.center_y, 0, 100)
462 {
463         this->plugin = plugin;
464 }
465
466 int TimeFrontCenterY::handle_event()
467 {
468         plugin->config.center_y = get_value();
469         plugin->send_configure_change();
470         return 1;
471 }
472
473
474
475
476 TimeFrontAngle::TimeFrontAngle(TimeFrontMain *plugin, int x, int y)
477  : BC_FPot(x,
478         y,
479         plugin->config.angle,
480         -180,
481         180)
482 {
483         this->plugin = plugin;
484 }
485
486 int TimeFrontAngle::handle_event()
487 {
488         plugin->config.angle = get_value();
489         plugin->send_configure_change();
490         return 1;
491 }
492
493
494 TimeFrontRate::TimeFrontRate(TimeFrontMain *plugin, int x, int y)
495  : BC_PopupMenu(x, y, xS(155), to_text(plugin->config.rate), 1)
496 {
497         this->plugin = plugin;
498 }
499 void TimeFrontRate::create_objects()
500 {
501         add_item(new BC_MenuItem(to_text(TimeFrontConfig::LINEAR)));
502         add_item(new BC_MenuItem(to_text(TimeFrontConfig::LOG)));
503         add_item(new BC_MenuItem(to_text(TimeFrontConfig::SQUARE)));
504 }
505 char* TimeFrontRate::to_text(int shape)
506 {
507         switch(shape)
508         {
509                 case TimeFrontConfig::LINEAR:
510                         return _("Linear");
511                 case TimeFrontConfig::LOG:
512                         return _("Log");
513                 default:
514                         return C_("Square");
515         }
516 }
517 int TimeFrontRate::from_text(char *text)
518 {
519         if(!strcmp(text, to_text(TimeFrontConfig::LINEAR)))
520                 return TimeFrontConfig::LINEAR;
521         if(!strcmp(text, to_text(TimeFrontConfig::LOG)))
522                 return TimeFrontConfig::LOG;
523         return TimeFrontConfig::SQUARE;
524 }
525 int TimeFrontRate::handle_event()
526 {
527         plugin->config.rate = from_text(get_text());
528         plugin->send_configure_change();
529         return 1;
530 }
531
532
533
534 TimeFrontInRadius::TimeFrontInRadius(TimeFrontMain *plugin, int x, int y)
535  : BC_FSlider(x,
536         y,
537         0,
538         xS(200),
539         yS(200),
540         (float)0,
541         (float)100,
542         (float)plugin->config.in_radius)
543 {
544         this->plugin = plugin;
545 }
546
547 int TimeFrontInRadius::handle_event()
548 {
549         plugin->config.in_radius = get_value();
550         plugin->send_configure_change();
551         return 1;
552 }
553
554
555 TimeFrontOutRadius::TimeFrontOutRadius(TimeFrontMain *plugin, int x, int y)
556  : BC_FSlider(x,
557         y,
558         0,
559         xS(200),
560         yS(200),
561         (float)0,
562         (float)100,
563         (float)plugin->config.out_radius)
564 {
565         this->plugin = plugin;
566 }
567
568 int TimeFrontOutRadius::handle_event()
569 {
570         plugin->config.out_radius = get_value();
571         plugin->send_configure_change();
572         return 1;
573 }
574
575 TimeFrontFrameRange::TimeFrontFrameRange(TimeFrontMain *plugin, int x, int y)
576  : BC_ISlider(x,
577         y,
578         0,
579         xS(200),
580         yS(200),
581         (int)1,
582         (int)255,
583         (int)plugin->config.frame_range)
584 {
585         this->plugin = plugin;
586 }
587
588 int TimeFrontFrameRange::handle_event()
589 {
590         plugin->config.frame_range = get_value();
591         plugin->send_configure_change();
592         return 1;
593 }
594
595
596 TimeFrontInvert::TimeFrontInvert(TimeFrontMain *client, int x, int y)
597  : BC_CheckBox(x,
598         y,
599         client->config.invert,
600         _("Inversion"))
601 {
602         this->plugin = client;
603 }
604
605 int TimeFrontInvert::handle_event()
606 {
607         plugin->config.invert = get_value();
608         plugin->send_configure_change();
609         return 1;
610 }
611
612 TimeFrontShowGrayscale::TimeFrontShowGrayscale(TimeFrontMain *client, int x, int y)
613  : BC_CheckBox(x,
614         y,
615         client->config.show_grayscale,
616         _("Show grayscale (for tuning"))
617 {
618         this->plugin = client;
619 }
620
621 int TimeFrontShowGrayscale::handle_event()
622 {
623         plugin->config.show_grayscale = get_value();
624         plugin->send_configure_change();
625         return 1;
626 }
627
628
629
630 TimeFrontMain::TimeFrontMain(PluginServer *server)
631  : PluginVClient(server)
632 {
633
634         need_reconfigure = 1;
635         gradient = 0;
636         engine = 0;
637         overlayer = 0;
638 }
639
640 TimeFrontMain::~TimeFrontMain()
641 {
642
643
644         if(gradient) delete gradient;
645         if(engine) delete engine;
646         if(overlayer) delete overlayer;
647 }
648
649 const char* TimeFrontMain::plugin_title() { return N_("TimeFront"); }
650 int TimeFrontMain::is_realtime() { return 1; }
651 int TimeFrontMain::is_multichannel() { return 1; }
652
653
654
655 NEW_WINDOW_MACRO(TimeFrontMain, TimeFrontWindow)
656
657 LOAD_CONFIGURATION_MACRO(TimeFrontMain, TimeFrontConfig)
658
659 int TimeFrontMain::is_synthesis()
660 {
661         return 1;
662 }
663
664 #define GRADIENTFROMAVG(type, inttype, components, maxval) \
665         for(int i = 0; i < tfframe->get_h(); i++) \
666         { \
667                 type *in_row = (type *)tfframe->get_rows()[i]; \
668                 unsigned char *grad_row = gradient->get_rows()[i]; \
669                 for(int j = 0; j < tfframe->get_w(); j++) \
670                 { \
671                         inttype tmp =   (inttype) in_row[j * components] + \
672                                                   in_row[j * components + 1] + \
673                                                   in_row[j * components + 2]; \
674                         if (components == 3) \
675                                 grad_row[j] = (unsigned char) (CLIP((float)config.frame_range * tmp / maxval / 3, 0.0F, config.frame_range)); \
676                         else if(components == 4) \
677                                 grad_row[j] = (unsigned char) (CLIP((float)config.frame_range * tmp * in_row[j * components + 3] / maxval / maxval / 3, 0.0F, config.frame_range)); \
678                 } \
679         }
680
681 #define GRADIENTFROMCHANNEL(type, components, max, channel) \
682         for(int i = 0; i < tfframe->get_h(); i++) \
683         { \
684                 type *in_row = (type *)tfframe->get_rows()[i]; \
685                 unsigned char *grad_row = gradient->get_rows()[i]; \
686                 for(int j = 0; j < tfframe->get_w(); j++) \
687                 { \
688                         if (components == 3) \
689                                 grad_row[j] = (unsigned char) (CLIP((float)config.frame_range * in_row[j * components + channel] / max, 0.0F, config.frame_range)); \
690                         else if(components == 4) \
691                                 grad_row[j] = (unsigned char) (CLIP((float)config.frame_range * in_row[j * components + channel] * in_row[j * components + 3]/ max /max, 0.0F, config.frame_range)); \
692                 } \
693         }
694
695 #define SETALPHA(type, max) \
696         for(int i = 0; i < outframes[0]->get_h(); i++) \
697         { \
698                 type *out_row = (type *)outframes[0]->get_rows()[i]; \
699                 for(int j = 0; j < outframes[0]->get_w(); j++) \
700                 { \
701                         out_row[j * 4 + 3] = max; \
702                 } \
703         }
704
705 #define GRADIENTTOPICTURE(type, inttype, components, max, invertion) \
706         for(int i = 0; i < height; i++) \
707         { \
708                 type *out_row = (type *)outframes[0]->get_rows()[i]; \
709                 unsigned char *grad_row = gradient->get_rows()[i]; \
710                 for (int j = 0; j < width; j++) \
711                 { \
712                         out_row[0] = (inttype)max * (invertion grad_row[0]) / config.frame_range; \
713                         out_row[1] = (inttype)max * (invertion grad_row[0]) / config.frame_range; \
714                         out_row[2] = (inttype)max * (invertion grad_row[0]) / config.frame_range; \
715                         if (components == 4) \
716                                 out_row[3] = max; \
717                         out_row += components; \
718                         grad_row ++; \
719                 } \
720         }
721
722 #define GRADIENTTOYUVPICTURE(type, inttype, components, max, invertion) \
723         for(int i = 0; i < height; i++) \
724         { \
725                 type *out_row = (type *)outframes[0]->get_rows()[i]; \
726                 unsigned char *grad_row = gradient->get_rows()[i]; \
727                 for (int j = 0; j < width; j++) \
728                 { \
729                         out_row[0] = (inttype)max * (invertion grad_row[0]) / config.frame_range; \
730                         out_row[1] = max/2; \
731                         out_row[2] = max/2; \
732                         if (components == 4) \
733                                 out_row[3] = max; \
734                         out_row += components; \
735                         grad_row ++; \
736                 } \
737         }
738
739 #define COMPOSITEIMAGE(type, components, invertion) \
740         for (int i = 0; i < height; i++) \
741         { \
742                 type *out_row = (type *)outframes[0]->get_rows()[i]; \
743                 unsigned char *gradient_row = gradient->get_rows()[i]; \
744                 for (int j = 0; j < width; j++) \
745                 { \
746                         unsigned int choice = invertion gradient_row[j]; \
747                         { \
748                                 type *in_row = (type *)framelist[choice]->get_rows()[i]; \
749                                 out_row[0] = in_row[j * components + 0]; \
750                                 out_row[1] = in_row[j * components + 1]; \
751                                 out_row[2] = in_row[j * components + 2]; \
752                                 if (components == 4) \
753                                         out_row[3] = in_row[j * components + 3]; \
754                         } \
755                         out_row += components; \
756                 } \
757         }
758
759
760
761 int TimeFrontMain::process_buffer(VFrame **frame,
762                 int64_t start_position,
763                 double frame_rate)
764 //int TimeFrontMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
765 {
766         VFrame **outframes = frame;
767         VFrame *(framelist[1024]);
768         framelist[0] = new VFrame (outframes[0]->get_w(), outframes[0]->get_h(),
769                         outframes[0]->get_color_model(), 0);
770         read_frame(framelist[0],
771                 0,
772                 start_position,
773                 frame_rate,
774                 0);
775         this->input = framelist[0];
776         this->output = outframes[0];
777         need_reconfigure |= load_configuration();
778         if (config.shape == TimeFrontConfig::OTHERTRACK)
779         {
780 //              this->output = frame[1];
781                 if (get_total_buffers() != 2)
782                 {
783                         // FIXME, maybe this should go to some other notification area?
784                         printf(_("ERROR: TimeFront plugin - If you are using another track for timefront, you have to have it under shared effects\n"));
785                         return 0;
786                 }
787                 if (outframes[0]->get_w() != outframes[1]->get_w() || outframes[0]->get_h() != outframes[1]->get_h())
788                 {
789                         printf(_("Sizes of master track and timefront track do not match\n"));
790                         return 0;
791                 }
792         }
793
794 // Generate new gradient
795         if(need_reconfigure)
796         {
797                 need_reconfigure = 0;
798
799                 if(!gradient)
800                         gradient = new VFrame( outframes[0]->get_w(), outframes[0]->get_h(), BC_A8, 0); 
801
802                 if (config.shape != TimeFrontConfig::OTHERTRACK &&
803                     config.shape != TimeFrontConfig::ALPHA)
804                 {
805                         if(!engine) engine = new TimeFrontServer(this,
806                                 get_project_smp() + 1,
807                                 get_project_smp() + 1);
808                         engine->process_packages();
809                 }
810
811         }
812         if (config.shape == TimeFrontConfig::ALPHA)
813         {
814                 if(!gradient)
815                         gradient = new VFrame(outframes[0]->get_w(), outframes[0]->get_h(), BC_A8, 0);
816                 VFrame *tfframe = framelist[0];
817                 switch (tfframe->get_color_model())
818                 {
819                         case BC_YUVA8888:
820                         case BC_RGBA8888:
821                                 GRADIENTFROMCHANNEL(unsigned char, 4, 255, 3);
822
823
824                                 break;
825                         case BC_RGBA_FLOAT:
826                                 GRADIENTFROMCHANNEL(float, 4, 1.0f, 3);
827                                 break;
828
829                         default:
830                                 {
831                                         printf(_("TimeFront plugin error: ALPHA used, but project color model does not have alpha\n"));
832                                         return 1;
833                                         break;
834                                 }
835                 }
836
837         } else
838         if (config.shape == TimeFrontConfig::OTHERTRACK)
839         {
840                 if(!gradient)
841                         gradient = new VFrame(outframes[0]->get_w(), outframes[0]->get_h(), BC_A8, 0);
842                 VFrame *tfframe = outframes[1];
843                 read_frame(tfframe,
844                         1,
845                         start_position,
846                         frame_rate,
847                         0);
848                 if (config.track_usage == TimeFrontConfig::OTHERTRACK_INTENSITY)
849                 {
850                         switch (tfframe->get_color_model())
851                         {
852                                 case BC_RGBA8888:
853                                         GRADIENTFROMAVG(unsigned char, unsigned short, 4, 255);       // Has to be 2 ranges bigger, sice we need precision for alpha
854                                         break;
855                                 case BC_RGB888:
856                                         GRADIENTFROMAVG(unsigned char, unsigned short, 3, 255);
857                                         break;
858                                 case BC_RGB_FLOAT:
859                                         GRADIENTFROMAVG(float, float, 3, 1.0f);
860                                         break;
861                                 case BC_RGBA_FLOAT:
862                                         GRADIENTFROMAVG(float, float, 4, 1.0f);
863                                         break;
864                                 case BC_YUV888:                                                 // We cheat and take Y component as intensity
865                                         GRADIENTFROMCHANNEL(unsigned char, 3, 255, 0);
866                                         break;
867                                 case BC_YUVA8888:
868                                         GRADIENTFROMCHANNEL(unsigned char, 4, 255, 0);
869                                         break;
870                                 default:
871                                         break;
872                         }
873                 } else
874                 if (config.track_usage == TimeFrontConfig::OTHERTRACK_ALPHA)
875                 {
876                         switch (tfframe->get_color_model())
877                         {
878                                 case BC_YUVA8888:
879                                 case BC_RGBA8888:
880                                         GRADIENTFROMCHANNEL(unsigned char, 4, 255, 3);
881
882
883                                         break;
884                                 case BC_RGBA_FLOAT:
885                                         GRADIENTFROMCHANNEL(float, 4, 1.0f, 3);
886                                         break;
887
888                                 default:
889                                         {
890                                                 printf(_("TimeFront plugin error: ALPHA track used, but project color model does not have alpha\n"));
891                                                 return 1;
892                                                 break;
893                                         }
894                         }
895                 } else
896                 {
897                         printf(_("TimeFront plugin error: unsupported track_usage parameter\n"));
898                         return 1;
899                 }
900         }
901
902         if (!config.show_grayscale)
903         {
904                 for (int i = 1; i <= config.frame_range; i++)
905                 {
906                         framelist[i] = new VFrame (outframes[0]->get_w(), outframes[0]->get_h(),
907                                         outframes[0]->get_color_model(), 0);
908
909                         read_frame(framelist[i],
910                                 0,
911                                 start_position - i,
912                                 frame_rate,
913                                 0);
914                 }
915         }
916
917
918         int width = outframes[0]->get_w();
919         int height = outframes[0]->get_h();
920         if (config.show_grayscale)
921         {
922                 if (!config.invert)
923                 {
924                         switch (outframes[0]->get_color_model())
925                         {
926                                 case BC_RGB888:
927                                         GRADIENTTOPICTURE(unsigned char, unsigned short, 3, 255, );
928                                         break;
929                                 case BC_RGBA8888:
930                                         GRADIENTTOPICTURE(unsigned char, unsigned short, 4, 255, );
931                                         break;
932                                 case BC_YUV888:
933                                         GRADIENTTOYUVPICTURE(unsigned char, unsigned short, 3, 255, );
934                                         break;
935                                 case BC_YUVA8888:
936                                         GRADIENTTOYUVPICTURE(unsigned char, unsigned short, 4, 255, );
937                                         break;
938                                 case BC_RGB_FLOAT:
939                                         GRADIENTTOPICTURE(float, float, 3, 1.0f, );
940                                         break;
941                                 case BC_RGBA_FLOAT:
942                                         GRADIENTTOPICTURE(float, float, 4, 1.0f, );
943                                         break;
944                                 default:
945                                         break;
946                         }
947                 } else
948                 {
949                         switch (outframes[0]->get_color_model())
950                         {
951                                 case BC_RGB888:
952                                         GRADIENTTOPICTURE(unsigned char, unsigned short, 3, 255, config.frame_range -);
953                                         break;
954                                 case BC_RGBA8888:
955                                         GRADIENTTOPICTURE(unsigned char, unsigned short, 4, 255, config.frame_range -);
956                                         break;
957                                 case BC_YUV888:
958                                         GRADIENTTOYUVPICTURE(unsigned char, unsigned short, 3, 255, config.frame_range -);
959                                         break;
960                                 case BC_YUVA8888:
961                                         GRADIENTTOYUVPICTURE(unsigned char, unsigned short, 4, 255, config.frame_range -);
962                                         break;
963                                 case BC_RGB_FLOAT:
964                                         GRADIENTTOPICTURE(float, float, 3, 1.0f, config.frame_range -);
965                                         break;
966                                 case BC_RGBA_FLOAT:
967                                         GRADIENTTOPICTURE(float, float, 4, 1.0f, config.frame_range -);
968                                         break;
969                                 default:
970                                         break;
971                         }
972                 }
973         } else
974         if (!config.invert)
975         {
976                 switch (outframes[0]->get_color_model())
977                 {
978                         case BC_RGB888:
979                                 COMPOSITEIMAGE(unsigned char, 3, );
980                                 break;
981                         case BC_RGBA8888:
982                                 COMPOSITEIMAGE(unsigned char, 4, );
983                                 break;
984                         case BC_YUV888:
985                                 COMPOSITEIMAGE(unsigned char, 3, );
986                                 break;
987                         case BC_YUVA8888:
988                                 COMPOSITEIMAGE(unsigned char, 4, );
989                                 break;
990                         case BC_RGB_FLOAT:
991                                 COMPOSITEIMAGE(float, 3, );
992                                 break;
993                         case BC_RGBA_FLOAT:
994                                 COMPOSITEIMAGE(float, 4, );
995                                 break;
996
997                         default:
998                                 break;
999                 }
1000         } else
1001         {
1002                 switch (outframes[0]->get_color_model())
1003                 {
1004                         case BC_RGB888:
1005                                 COMPOSITEIMAGE(unsigned char, 3, config.frame_range -);
1006                                 break;
1007                         case BC_RGBA8888:
1008                                 COMPOSITEIMAGE(unsigned char, 4, config.frame_range -);
1009                                 break;
1010                         case BC_YUV888:
1011                                 COMPOSITEIMAGE(unsigned char, 3, config.frame_range -);
1012                                 break;
1013                         case BC_YUVA8888:
1014                                 COMPOSITEIMAGE(unsigned char, 4, config.frame_range -);
1015                                 break;
1016                         case BC_RGB_FLOAT:
1017                                 COMPOSITEIMAGE(float, 3, config.frame_range -);
1018                                 break;
1019                         case BC_RGBA_FLOAT:
1020                                 COMPOSITEIMAGE(float, 4, config.frame_range -);
1021                                 break;
1022
1023                         default:
1024                                 break;
1025                 }
1026         }
1027         if (config.shape == TimeFrontConfig::ALPHA)
1028         {
1029                 // Set alpha to max
1030                 switch (outframes[0]->get_color_model())
1031                 {
1032                         case BC_YUVA8888:
1033                         case BC_RGBA8888:
1034                                 SETALPHA(unsigned char, 255);
1035                                 break;
1036                         case BC_RGBA_FLOAT:
1037                                 SETALPHA(float, 1.0f);
1038                                 break;
1039
1040                         default:
1041                                 break;
1042                 }
1043         }
1044
1045         delete framelist[0];
1046         if (!config.show_grayscale)
1047         {
1048                 for (int i = 1; i <= config.frame_range; i++)
1049                         delete framelist[i];
1050         }
1051         return 0;
1052 }
1053
1054
1055 void TimeFrontMain::update_gui()
1056 {
1057         if(thread)
1058         {
1059                 if(load_configuration())
1060                 {
1061                         thread->window->lock_window("TimeFrontMain::update_gui");
1062                         ((TimeFrontWindow*)thread->window)->frame_range->update(config.frame_range);
1063                         ((TimeFrontWindow*)thread->window)->shape->set_text(TimeFrontShape::to_text(config.shape));
1064                         ((TimeFrontWindow*)thread->window)->show_grayscale->update(config.show_grayscale);
1065                         ((TimeFrontWindow*)thread->window)->invert->update(config.invert);
1066                         ((TimeFrontWindow*)thread->window)->shape->set_text(TimeFrontShape::to_text(config.shape));
1067                         if (((TimeFrontWindow*)thread->window)->rate)
1068                                 ((TimeFrontWindow*)thread->window)->rate->set_text(TimeFrontRate::to_text(config.rate));
1069                         if (((TimeFrontWindow*)thread->window)->in_radius)
1070                                 ((TimeFrontWindow*)thread->window)->in_radius->update(config.in_radius);
1071                         if (((TimeFrontWindow*)thread->window)->out_radius)
1072                                 ((TimeFrontWindow*)thread->window)->out_radius->update(config.out_radius);
1073                         if (((TimeFrontWindow*)thread->window)->track_usage)
1074                                 ((TimeFrontWindow*)thread->window)->track_usage->set_text(TimeFrontTrackUsage::to_text(config.track_usage));
1075                         if(((TimeFrontWindow*)thread->window)->angle)
1076                                 ((TimeFrontWindow*)thread->window)->angle->update(config.angle);
1077                         if(((TimeFrontWindow*)thread->window)->center_x)
1078                                 ((TimeFrontWindow*)thread->window)->center_x->update(config.center_x);
1079                         if(((TimeFrontWindow*)thread->window)->center_y)
1080                                 ((TimeFrontWindow*)thread->window)->center_y->update(config.center_y);
1081
1082                         ((TimeFrontWindow*)thread->window)->update_shape();
1083                         thread->window->unlock_window();
1084                 }
1085         }
1086 }
1087
1088
1089
1090
1091 void TimeFrontMain::save_data(KeyFrame *keyframe)
1092 {
1093         FileXML output;
1094
1095 // cause data to be stored directly in text
1096         output.set_shared_output(keyframe->xbuf);
1097         output.tag.set_title("TIMEFRONT");
1098
1099         output.tag.set_property("ANGLE", config.angle);
1100         output.tag.set_property("IN_RADIUS", config.in_radius);
1101         output.tag.set_property("OUT_RADIUS", config.out_radius);
1102         output.tag.set_property("FRAME_RANGE", config.frame_range);
1103         output.tag.set_property("SHAPE", config.shape);
1104         output.tag.set_property("TRACK_USAGE", config.track_usage);
1105         output.tag.set_property("RATE", config.rate);
1106         output.tag.set_property("CENTER_X", config.center_x);
1107         output.tag.set_property("CENTER_Y", config.center_y);
1108         output.tag.set_property("INVERT", config.invert);
1109         output.tag.set_property("SHOW_GRAYSCALE", config.show_grayscale);
1110         output.append_tag();
1111         output.tag.set_title("/TIMEFRONT");
1112         output.append_tag();
1113         output.append_newline();
1114         output.terminate_string();
1115 }
1116
1117 void TimeFrontMain::read_data(KeyFrame *keyframe)
1118 {
1119         FileXML input;
1120
1121         input.set_shared_input(keyframe->xbuf);
1122
1123         int result = 0;
1124
1125         while(!result)
1126         {
1127                 result = input.read_tag();
1128
1129                 if(!result)
1130                 {
1131                         if(input.tag.title_is("TIMEFRONT"))
1132                         {
1133                                 config.angle = input.tag.get_property("ANGLE", config.angle);
1134                                 config.rate = input.tag.get_property("RATE", config.rate);
1135                                 config.in_radius = input.tag.get_property("IN_RADIUS", config.in_radius);
1136                                 config.out_radius = input.tag.get_property("OUT_RADIUS", config.out_radius);
1137                                 config.frame_range = input.tag.get_property("FRAME_RANGE", config.frame_range);
1138                                 config.shape = input.tag.get_property("SHAPE", config.shape);
1139                                 config.track_usage = input.tag.get_property("TRACK_USAGE", config.track_usage);
1140                                 config.center_x = input.tag.get_property("CENTER_X", config.center_x);
1141                                 config.center_y = input.tag.get_property("CENTER_Y", config.center_y);
1142                                 config.invert = input.tag.get_property("INVERT", config.invert);
1143                                 config.show_grayscale = input.tag.get_property("SHOW_GRAYSCALE", config.show_grayscale);
1144                         }
1145                 }
1146         }
1147 }
1148
1149
1150
1151
1152
1153
1154 TimeFrontPackage::TimeFrontPackage()
1155  : LoadPackage()
1156 {
1157 }
1158
1159
1160
1161
1162 TimeFrontUnit::TimeFrontUnit(TimeFrontServer *server, TimeFrontMain *plugin)
1163  : LoadClient(server)
1164 {
1165         this->plugin = plugin;
1166         this->server = server;
1167 }
1168
1169
1170 #define LOG_RANGE 1
1171
1172 #define CREATE_GRADIENT \
1173 { \
1174 /* Synthesize linear gradient for lookups */ \
1175  \
1176         a_table = (unsigned char *)malloc(sizeof(unsigned char) * gradient_size); \
1177  \
1178         for(int i = 0; i < gradient_size; i++) \
1179         { \
1180                 float opacity = 0.0; \
1181                 switch(plugin->config.rate) \
1182                 { \
1183                         case TimeFrontConfig::LINEAR: \
1184                                 if(i < in_radius) \
1185                                         opacity = 0.0; \
1186                                 else \
1187                                 if(i >= out_radius) \
1188                                         opacity = 1.0; \
1189                                 else \
1190                                         opacity = (float)(i - in_radius) / (out_radius - in_radius); \
1191                                 break; \
1192                         case TimeFrontConfig::LOG: \
1193                                 opacity = 1 - exp(LOG_RANGE * -(float)(i - in_radius) / (out_radius - in_radius)); \
1194                                 break; \
1195                         case TimeFrontConfig::SQUARE: \
1196                                 opacity = SQR((float)(i - in_radius) / (out_radius - in_radius)); \
1197                                 break; \
1198                 } \
1199  \
1200                 CLAMP(opacity, 0, 1); \
1201                 float transparency = 1.0 - opacity; \
1202                 a_table[i] = (unsigned char)(out4 * opacity + in4 * transparency); \
1203         } \
1204  \
1205         for(int i = pkg->y1; i < pkg->y2; i++) \
1206         { \
1207                 unsigned char *out_row = plugin->gradient->get_rows()[i]; \
1208  \
1209                 switch(plugin->config.shape) \
1210                 { \
1211                         case TimeFrontConfig::LINEAR: \
1212                                 for(int j = 0; j < w; j++) \
1213                                 { \
1214                                         int x = j - half_w; \
1215                                         int y = -(i - half_h); \
1216                  \
1217 /* Rotate by effect angle */ \
1218                                         int input_y = (int)(gradient_size / 2 - \
1219                                                 (x * sin_angle + y * cos_angle) + \
1220                                                 0.5); \
1221                  \
1222 /* Get gradient value from these coords */ \
1223                  \
1224                                         if(input_y < 0) \
1225                                         { \
1226                                                 out_row[0] = out4; \
1227                                         } \
1228                                         else \
1229                                         if(input_y >= gradient_size) \
1230                                         { \
1231                                                 out_row[0] = in4; \
1232                                         } \
1233                                         else \
1234                                         { \
1235                                                 out_row[0] = a_table[input_y]; \
1236                                         } \
1237                  \
1238                                         out_row ++; \
1239                                 } \
1240                                 break; \
1241  \
1242                         case TimeFrontConfig::RADIAL: \
1243                                 for(int j = 0; j < w; j++) \
1244                                 { \
1245                                         double x = j - center_x; \
1246                                         double y = i - center_y; \
1247                                         double magnitude = hypot(x, y); \
1248                                         int input_y = (int)magnitude; \
1249                                         out_row[0] = a_table[input_y]; \
1250                                         out_row ++; \
1251                                 } \
1252                                 break; \
1253                 } \
1254         } \
1255 }
1256
1257 void TimeFrontUnit::process_package(LoadPackage *package)
1258 {
1259         TimeFrontPackage *pkg = (TimeFrontPackage*)package;
1260         int h = plugin->input->get_h();
1261         int w = plugin->input->get_w();
1262         int half_w = w / 2;
1263         int half_h = h / 2;
1264         int gradient_size = (int)(ceil(hypot(w, h)));
1265         int in_radius = (int)(plugin->config.in_radius / 100 * gradient_size);
1266         int out_radius = (int)(plugin->config.out_radius / 100 * gradient_size);
1267         double sin_angle = sin(plugin->config.angle * (M_PI / 180));
1268         double cos_angle = cos(plugin->config.angle * (M_PI / 180));
1269         double center_x = plugin->config.center_x * w / 100;
1270         double center_y = plugin->config.center_y * h / 100;
1271         unsigned char *a_table = 0;
1272
1273         if(in_radius > out_radius)
1274         {
1275             in_radius ^= out_radius;
1276             out_radius ^= in_radius;
1277             in_radius ^= out_radius;
1278         }
1279
1280
1281         int in4 = plugin->config.frame_range;
1282         int out4 = 0;
1283         CREATE_GRADIENT
1284
1285         if(a_table) free(a_table);
1286 }
1287
1288
1289
1290
1291
1292
1293 TimeFrontServer::TimeFrontServer(TimeFrontMain *plugin,
1294         int total_clients,
1295         int total_packages)
1296  : LoadServer(total_clients, total_packages)
1297 {
1298         this->plugin = plugin;
1299 }
1300
1301 void TimeFrontServer::init_packages()
1302 {
1303         for(int i = 0; i < get_total_packages(); i++)
1304         {
1305                 TimeFrontPackage *package = (TimeFrontPackage*)get_package(i);
1306                 package->y1 = plugin->input->get_h() *
1307                         i /
1308                         get_total_packages();
1309                 package->y2 = plugin->input->get_h() *
1310                         (i + 1) /
1311                         get_total_packages();
1312         }
1313 }
1314
1315 LoadClient* TimeFrontServer::new_client()
1316 {
1317         return new TimeFrontUnit(this, plugin);
1318 }
1319
1320 LoadPackage* TimeFrontServer::new_package()
1321 {
1322         return new TimeFrontPackage;
1323 }
1324
1325
1326
1327
1328