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