fix mask vframe setup, add unshared vframe constructor
[goodguy/history.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         350,
124         290,
125         350,
126         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 x = 10, y = 10;
154         BC_Title *title;
155
156         add_subwindow(title = new BC_Title(x, y, _("Type:")));
157         add_subwindow(shape = new TimeFrontShape(plugin,
158                 this,
159                 x + title->get_w() + 10,
160                 y));
161         shape->create_objects();
162         y += 40;
163         shape_x = x;
164         shape_y = y;
165         y += 140;
166         add_subwindow(title = new BC_Title(x, y, _("Time range:")));
167         add_subwindow(frame_range = new TimeFrontFrameRange(plugin, x + title->get_w() + 10, y));
168         frame_range_x = x + frame_range->get_w() + 10;
169         frame_range_y = y;
170         y += 35;
171         update_shape();
172
173         add_subwindow(invert = new TimeFrontInvert(plugin, x, y));
174         add_subwindow(show_grayscale = new TimeFrontShowGrayscale(plugin, x+ 100, y));
175
176
177         show_window();
178         flush();
179 }
180
181 void TimeFrontWindow::update_shape()
182 {
183         int x = shape_x, y = shape_y;
184
185         if(plugin->config.shape == TimeFrontConfig::LINEAR)
186         {
187                 delete center_x_title;
188                 delete center_y_title;
189                 delete center_x;
190                 delete center_y;
191                 delete track_usage_title;
192                 delete track_usage;
193                 center_x_title = 0;
194                 center_y_title = 0;
195                 center_x = 0;
196                 center_y = 0;
197                 track_usage_title = 0;
198                 track_usage = 0;
199                 if(!angle)
200                 {
201                         add_subwindow(angle_title = new BC_Title(x, y, _("Angle:")));
202                         add_subwindow(angle = new TimeFrontAngle(plugin, x + angle_title->get_w() + 10, y));
203                 }
204                 if(!rate){
205                         y = shape_y + 40;
206
207                         add_subwindow(rate_title = new BC_Title(x, y, _("Rate:")));
208                         add_subwindow(rate = new TimeFrontRate(plugin,
209                                 x + rate_title->get_w() + 10,
210                                 y));
211                         rate->create_objects();
212                         y += 40;
213                         add_subwindow(in_radius_title = new BC_Title(x, y, _("Inner radius:")));
214                         add_subwindow(in_radius = new TimeFrontInRadius(plugin, x + in_radius_title->get_w() + 10, y));
215                         y += 30;
216                         add_subwindow(out_radius_title = new BC_Title(x, y, _("Outer radius:")));
217                         add_subwindow(out_radius = new TimeFrontOutRadius(plugin, x + out_radius_title->get_w() + 10, y));
218                         y += 35;
219
220                 }
221         } else
222         if(plugin->config.shape == TimeFrontConfig::RADIAL)
223         {
224                 delete angle_title;
225                 delete angle;
226                 delete track_usage_title;
227                 delete track_usage;
228                 angle_title = 0;
229                 angle = 0;
230                 track_usage_title = 0;
231                 track_usage = 0;
232                 if(!center_x)
233                 {
234                         add_subwindow(center_x_title = new BC_Title(x, y, _("Center X:")));
235                         add_subwindow(center_x = new TimeFrontCenterX(plugin,
236                                 x + center_x_title->get_w() + 10,
237                                 y));
238                         x += center_x_title->get_w() + 10 + center_x->get_w() + 10;
239                         add_subwindow(center_y_title = new BC_Title(x, y, _("Center Y:")));
240                         add_subwindow(center_y = new TimeFrontCenterY(plugin,
241                                 x + center_y_title->get_w() + 10,
242                                 y));
243                 }
244
245
246                 if(!rate)
247                 {
248                         y = shape_y + 40;
249                         x = shape_x;
250                         add_subwindow(rate_title = new BC_Title(x, y, _("Rate:")));
251                         add_subwindow(rate = new TimeFrontRate(plugin,
252                                 x + rate_title->get_w() + 10,
253                                 y));
254                         rate->create_objects();
255                         y += 40;
256                         add_subwindow(in_radius_title = new BC_Title(x, y, _("Inner radius:")));
257                         add_subwindow(in_radius = new TimeFrontInRadius(plugin, x + in_radius_title->get_w() + 10, y));
258                         y += 30;
259                         add_subwindow(out_radius_title = new BC_Title(x, y, _("Outer radius:")));
260                         add_subwindow(out_radius = new TimeFrontOutRadius(plugin, x + out_radius_title->get_w() + 10, y));
261                         y += 35;
262                 }
263         } else
264         if(plugin->config.shape == TimeFrontConfig::OTHERTRACK)
265         {
266                 delete center_x_title;
267                 delete center_y_title;
268                 delete center_x;
269                 delete center_y;
270                 delete angle_title;
271                 delete angle;
272                 delete rate_title;
273                 delete rate;
274                 delete in_radius_title;
275                 delete in_radius;
276                 delete out_radius_title;
277                 delete out_radius;
278                 center_x_title = 0;
279                 center_y_title = 0;
280                 center_x = 0;
281                 center_y = 0;
282                 angle_title = 0;
283                 angle = 0;
284                 rate_title = 0;
285                 rate = 0;
286                 in_radius_title = 0;
287                 in_radius = 0;
288                 out_radius_title = 0;
289                 out_radius = 0;
290                 if(!track_usage)
291                 {
292                         add_subwindow(track_usage_title = new BC_Title(x, y, _("As timefront use:")));
293                         add_subwindow(track_usage = new TimeFrontTrackUsage(plugin,
294                                 this,
295                                 x + track_usage_title->get_w() + 10,
296                                 y));
297                         track_usage->create_objects();
298
299                 }
300         } else
301         if(plugin->config.shape == TimeFrontConfig::ALPHA)
302         {
303                 delete center_x_title;
304                 delete center_y_title;
305                 delete center_x;
306                 delete center_y;
307                 delete angle_title;
308                 delete angle;
309                 delete rate_title;
310                 delete rate;
311                 delete in_radius_title;
312                 delete in_radius;
313                 delete out_radius_title;
314                 delete out_radius;
315                 delete track_usage_title;
316                 delete track_usage;
317                 center_x_title = 0;
318                 center_y_title = 0;
319                 center_x = 0;
320                 center_y = 0;
321                 angle_title = 0;
322                 angle = 0;
323                 rate_title = 0;
324                 rate = 0;
325                 in_radius_title = 0;
326                 in_radius = 0;
327                 out_radius_title = 0;
328                 out_radius = 0;
329                 track_usage_title = 0;
330                 track_usage = 0;
331
332         }
333
334 }
335
336
337
338
339
340
341
342
343
344
345
346
347
348 TimeFrontShape::TimeFrontShape(TimeFrontMain *plugin,
349         TimeFrontWindow *gui,
350         int x,
351         int y)
352  : BC_PopupMenu(x, y, 230, to_text(plugin->config.shape), 1)
353 {
354         this->plugin = plugin;
355         this->gui = gui;
356 }
357 void TimeFrontShape::create_objects()
358 {
359         add_item(new BC_MenuItem(to_text(TimeFrontConfig::LINEAR)));
360         add_item(new BC_MenuItem(to_text(TimeFrontConfig::RADIAL)));
361         add_item(new BC_MenuItem(to_text(TimeFrontConfig::ALPHA)));
362         add_item(new BC_MenuItem(to_text(TimeFrontConfig::OTHERTRACK)));
363 }
364 char* TimeFrontShape::to_text(int shape)
365 {
366         switch(shape)
367         {
368                 case TimeFrontConfig::LINEAR:
369                         return _("Linear");
370                 case TimeFrontConfig::OTHERTRACK:
371                         return _("Other track as timefront");
372                 case TimeFrontConfig::ALPHA:
373                         return _("Alpha as timefront");
374                 default:
375                         return _("Radial");
376         }
377 }
378 int TimeFrontShape::from_text(char *text)
379 {
380         if(!strcmp(text, to_text(TimeFrontConfig::LINEAR)))
381                 return TimeFrontConfig::LINEAR;
382         if(!strcmp(text, to_text(TimeFrontConfig::OTHERTRACK)))
383                 return TimeFrontConfig::OTHERTRACK;
384         if(!strcmp(text, to_text(TimeFrontConfig::ALPHA)))
385                 return TimeFrontConfig::ALPHA;
386         return TimeFrontConfig::RADIAL;
387 }
388 int TimeFrontShape::handle_event()
389 {
390         plugin->config.shape = from_text(get_text());
391         gui->update_shape();
392         gui->show_window();
393         plugin->send_configure_change();
394         return 1;
395 }
396
397
398 TimeFrontTrackUsage::TimeFrontTrackUsage(TimeFrontMain *plugin,
399         TimeFrontWindow *gui, int x, int y)
400  : BC_PopupMenu(x, y, 140, to_text(plugin->config.track_usage), 1)
401 {
402         this->plugin = plugin;
403         this->gui = gui;
404 }
405 void TimeFrontTrackUsage::create_objects()
406 {
407         add_item(new BC_MenuItem(to_text(TimeFrontConfig::OTHERTRACK_INTENSITY)));
408         add_item(new BC_MenuItem(to_text(TimeFrontConfig::OTHERTRACK_ALPHA)));
409 }
410 char* TimeFrontTrackUsage::to_text(int track_usage)
411 {
412         switch(track_usage)
413         {
414                 case TimeFrontConfig::OTHERTRACK_INTENSITY:
415                         return _("Intensity");
416                 case TimeFrontConfig::OTHERTRACK_ALPHA:
417                         return _("Alpha mask");
418                 default:
419                         return _("Unknown");
420         }
421 }
422 int TimeFrontTrackUsage::from_text(char *text)
423 {
424         if(!strcmp(text, to_text(TimeFrontConfig::OTHERTRACK_INTENSITY)))
425                 return TimeFrontConfig::OTHERTRACK_INTENSITY;
426         if(!strcmp(text, to_text(TimeFrontConfig::OTHERTRACK_ALPHA)))
427                 return TimeFrontConfig::OTHERTRACK_ALPHA;
428
429         return TimeFrontConfig::OTHERTRACK_INTENSITY;
430 }
431 int TimeFrontTrackUsage::handle_event()
432 {
433         plugin->config.track_usage = from_text(get_text());
434         gui->update_shape();
435         gui->show_window();
436         plugin->send_configure_change();
437         return 1;
438 }
439
440
441
442
443 TimeFrontCenterX::TimeFrontCenterX(TimeFrontMain *plugin, int x, int y)
444  : BC_FPot(x, y, plugin->config.center_x, 0, 100)
445 {
446         this->plugin = plugin;
447 }
448 int TimeFrontCenterX::handle_event()
449 {
450         plugin->config.center_x = get_value();
451         plugin->send_configure_change();
452         return 1;
453 }
454
455
456
457 TimeFrontCenterY::TimeFrontCenterY(TimeFrontMain *plugin, int x, int y)
458  : BC_FPot(x, y, plugin->config.center_y, 0, 100)
459 {
460         this->plugin = plugin;
461 }
462
463 int TimeFrontCenterY::handle_event()
464 {
465         plugin->config.center_y = get_value();
466         plugin->send_configure_change();
467         return 1;
468 }
469
470
471
472
473 TimeFrontAngle::TimeFrontAngle(TimeFrontMain *plugin, int x, int y)
474  : BC_FPot(x,
475         y,
476         plugin->config.angle,
477         -180,
478         180)
479 {
480         this->plugin = plugin;
481 }
482
483 int TimeFrontAngle::handle_event()
484 {
485         plugin->config.angle = get_value();
486         plugin->send_configure_change();
487         return 1;
488 }
489
490
491 TimeFrontRate::TimeFrontRate(TimeFrontMain *plugin, int x, int y)
492  : BC_PopupMenu(x,
493         y,
494         155,
495         to_text(plugin->config.rate),
496         1)
497 {
498         this->plugin = plugin;
499 }
500 void TimeFrontRate::create_objects()
501 {
502         add_item(new BC_MenuItem(to_text(TimeFrontConfig::LINEAR)));
503         add_item(new BC_MenuItem(to_text(TimeFrontConfig::LOG)));
504         add_item(new BC_MenuItem(to_text(TimeFrontConfig::SQUARE)));
505 }
506 char* TimeFrontRate::to_text(int shape)
507 {
508         switch(shape)
509         {
510                 case TimeFrontConfig::LINEAR:
511                         return _("Linear");
512                 case TimeFrontConfig::LOG:
513                         return _("Log");
514                 default:
515                         return C_("Square");
516         }
517 }
518 int TimeFrontRate::from_text(char *text)
519 {
520         if(!strcmp(text, to_text(TimeFrontConfig::LINEAR)))
521                 return TimeFrontConfig::LINEAR;
522         if(!strcmp(text, to_text(TimeFrontConfig::LOG)))
523                 return TimeFrontConfig::LOG;
524         return TimeFrontConfig::SQUARE;
525 }
526 int TimeFrontRate::handle_event()
527 {
528         plugin->config.rate = from_text(get_text());
529         plugin->send_configure_change();
530         return 1;
531 }
532
533
534
535 TimeFrontInRadius::TimeFrontInRadius(TimeFrontMain *plugin, int x, int y)
536  : BC_FSlider(x,
537         y,
538         0,
539         200,
540         200,
541         (float)0,
542         (float)100,
543         (float)plugin->config.in_radius)
544 {
545         this->plugin = plugin;
546 }
547
548 int TimeFrontInRadius::handle_event()
549 {
550         plugin->config.in_radius = get_value();
551         plugin->send_configure_change();
552         return 1;
553 }
554
555
556 TimeFrontOutRadius::TimeFrontOutRadius(TimeFrontMain *plugin, int x, int y)
557  : BC_FSlider(x,
558         y,
559         0,
560         200,
561         200,
562         (float)0,
563         (float)100,
564         (float)plugin->config.out_radius)
565 {
566         this->plugin = plugin;
567 }
568
569 int TimeFrontOutRadius::handle_event()
570 {
571         plugin->config.out_radius = get_value();
572         plugin->send_configure_change();
573         return 1;
574 }
575
576 TimeFrontFrameRange::TimeFrontFrameRange(TimeFrontMain *plugin, int x, int y)
577  : BC_ISlider(x,
578         y,
579         0,
580         200,
581         200,
582         (int)1,
583         (int)255,
584         (int)plugin->config.frame_range)
585 {
586         this->plugin = plugin;
587 }
588
589 int TimeFrontFrameRange::handle_event()
590 {
591         plugin->config.frame_range = get_value();
592         plugin->send_configure_change();
593         return 1;
594 }
595
596
597 TimeFrontInvert::TimeFrontInvert(TimeFrontMain *client, int x, int y)
598  : BC_CheckBox(x,
599         y,
600         client->config.invert,
601         _("Inversion"))
602 {
603         this->plugin = client;
604 }
605
606 int TimeFrontInvert::handle_event()
607 {
608         plugin->config.invert = get_value();
609         plugin->send_configure_change();
610         return 1;
611 }
612
613 TimeFrontShowGrayscale::TimeFrontShowGrayscale(TimeFrontMain *client, int x, int y)
614  : BC_CheckBox(x,
615         y,
616         client->config.show_grayscale,
617         _("Show grayscale (for tuning"))
618 {
619         this->plugin = client;
620 }
621
622 int TimeFrontShowGrayscale::handle_event()
623 {
624         plugin->config.show_grayscale = get_value();
625         plugin->send_configure_change();
626         return 1;
627 }
628
629
630
631 TimeFrontMain::TimeFrontMain(PluginServer *server)
632  : PluginVClient(server)
633 {
634
635         need_reconfigure = 1;
636         gradient = 0;
637         engine = 0;
638         overlayer = 0;
639 }
640
641 TimeFrontMain::~TimeFrontMain()
642 {
643
644
645         if(gradient) delete gradient;
646         if(engine) delete engine;
647         if(overlayer) delete overlayer;
648 }
649
650 const char* TimeFrontMain::plugin_title() { return _("TimeFront"); }
651 int TimeFrontMain::is_realtime() { return 1; }
652 int TimeFrontMain::is_multichannel() { return 1; }
653
654
655
656 NEW_WINDOW_MACRO(TimeFrontMain, TimeFrontWindow)
657
658 LOAD_CONFIGURATION_MACRO(TimeFrontMain, TimeFrontConfig)
659
660 int TimeFrontMain::is_synthesis()
661 {
662         return 1;
663 }
664
665 #define GRADIENTFROMAVG(type, inttype, components, maxval) \
666         for(int i = 0; i < tfframe->get_h(); i++) \
667         { \
668                 type *in_row = (type *)tfframe->get_rows()[i]; \
669                 unsigned char *grad_row = gradient->get_rows()[i]; \
670                 for(int j = 0; j < tfframe->get_w(); j++) \
671                 { \
672                         inttype tmp =   (inttype) in_row[j * components] + \
673                                                   in_row[j * components + 1] + \
674                                                   in_row[j * components + 2]; \
675                         if (components == 3) \
676                                 grad_row[j] = (unsigned char) (CLIP((float)config.frame_range * tmp / maxval / 3, 0.0F, config.frame_range)); \
677                         else if(components == 4) \
678                                 grad_row[j] = (unsigned char) (CLIP((float)config.frame_range * tmp * in_row[j * components + 3] / maxval / maxval / 3, 0.0F, config.frame_range)); \
679                 } \
680         }
681
682 #define GRADIENTFROMCHANNEL(type, components, max, channel) \
683         for(int i = 0; i < tfframe->get_h(); i++) \
684         { \
685                 type *in_row = (type *)tfframe->get_rows()[i]; \
686                 unsigned char *grad_row = gradient->get_rows()[i]; \
687                 for(int j = 0; j < tfframe->get_w(); j++) \
688                 { \
689                         if (components == 3) \
690                                 grad_row[j] = (unsigned char) (CLIP((float)config.frame_range * in_row[j * components + channel] / max, 0.0F, config.frame_range)); \
691                         else if(components == 4) \
692                                 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)); \
693                 } \
694         }
695
696 #define SETALPHA(type, max) \
697         for(int i = 0; i < outframes[0]->get_h(); i++) \
698         { \
699                 type *out_row = (type *)outframes[0]->get_rows()[i]; \
700                 for(int j = 0; j < outframes[0]->get_w(); j++) \
701                 { \
702                         out_row[j * 4 + 3] = max; \
703                 } \
704         }
705
706 #define GRADIENTTOPICTURE(type, inttype, components, max, invertion) \
707         for(int i = 0; i < height; i++) \
708         { \
709                 type *out_row = (type *)outframes[0]->get_rows()[i]; \
710                 unsigned char *grad_row = gradient->get_rows()[i]; \
711                 for (int j = 0; j < width; j++) \
712                 { \
713                         out_row[0] = (inttype)max * (invertion grad_row[0]) / config.frame_range; \
714                         out_row[1] = (inttype)max * (invertion grad_row[0]) / config.frame_range; \
715                         out_row[2] = (inttype)max * (invertion grad_row[0]) / config.frame_range; \
716                         if (components == 4) \
717                                 out_row[3] = max; \
718                         out_row += components; \
719                         grad_row ++; \
720                 } \
721         }
722
723 #define GRADIENTTOYUVPICTURE(type, inttype, components, max, invertion) \
724         for(int i = 0; i < height; i++) \
725         { \
726                 type *out_row = (type *)outframes[0]->get_rows()[i]; \
727                 unsigned char *grad_row = gradient->get_rows()[i]; \
728                 for (int j = 0; j < width; j++) \
729                 { \
730                         out_row[0] = (inttype)max * (invertion grad_row[0]) / config.frame_range; \
731                         out_row[1] = max/2; \
732                         out_row[2] = max/2; \
733                         if (components == 4) \
734                                 out_row[3] = max; \
735                         out_row += components; \
736                         grad_row ++; \
737                 } \
738         }
739
740 #define COMPOSITEIMAGE(type, components, invertion) \
741         for (int i = 0; i < height; i++) \
742         { \
743                 type *out_row = (type *)outframes[0]->get_rows()[i]; \
744                 unsigned char *gradient_row = gradient->get_rows()[i]; \
745                 for (int j = 0; j < width; j++) \
746                 { \
747                         unsigned int choice = invertion gradient_row[j]; \
748                         { \
749                                 out_row[0] = framelist[choice]->get_rows()[i][j * components + 0]; \
750                                 out_row[1] = framelist[choice]->get_rows()[i][j * components + 1]; \
751                                 out_row[2] = framelist[choice]->get_rows()[i][j * components + 2]; \
752                                 if (components == 4) \
753                                         out_row[3] = framelist[choice]->get_rows()[i][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->get_data(), MESSAGESIZE);
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->get_data(), strlen(keyframe->get_data()));
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