plugin fixes and upgrades
[goodguy/history.git] / cinelerra-5.0 / 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, 190, 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         plugin->send_configure_change();
393         return 1;
394 }
395
396
397 TimeFrontTrackUsage::TimeFrontTrackUsage(TimeFrontMain *plugin, 
398         TimeFrontWindow *gui, int x, int y)
399  : BC_PopupMenu(x, y, 140, to_text(plugin->config.track_usage), 1)
400 {
401         this->plugin = plugin;
402         this->gui = gui;
403 }
404 void TimeFrontTrackUsage::create_objects()
405 {
406         add_item(new BC_MenuItem(to_text(TimeFrontConfig::OTHERTRACK_INTENSITY)));
407         add_item(new BC_MenuItem(to_text(TimeFrontConfig::OTHERTRACK_ALPHA)));
408 }
409 char* TimeFrontTrackUsage::to_text(int track_usage)
410 {
411         switch(track_usage)
412         {
413                 case TimeFrontConfig::OTHERTRACK_INTENSITY:
414                         return _("Intensity");
415                 case TimeFrontConfig::OTHERTRACK_ALPHA:
416                         return _("Alpha mask");
417                 default:
418                         return _("Unknown");
419         }
420 }
421 int TimeFrontTrackUsage::from_text(char *text)
422 {
423         if(!strcmp(text, to_text(TimeFrontConfig::OTHERTRACK_INTENSITY))) 
424                 return TimeFrontConfig::OTHERTRACK_INTENSITY;
425         if(!strcmp(text, to_text(TimeFrontConfig::OTHERTRACK_ALPHA))) 
426                 return TimeFrontConfig::OTHERTRACK_ALPHA;
427
428         return TimeFrontConfig::OTHERTRACK_INTENSITY;
429 }
430 int TimeFrontTrackUsage::handle_event()
431 {
432         plugin->config.track_usage = from_text(get_text());
433         gui->update_shape();
434         plugin->send_configure_change();
435         return 1;
436 }
437
438
439
440
441 TimeFrontCenterX::TimeFrontCenterX(TimeFrontMain *plugin, int x, int y)
442  : BC_FPot(x, y, plugin->config.center_x, 0, 100)
443 {
444         this->plugin = plugin;
445 }
446 int TimeFrontCenterX::handle_event()
447 {
448         plugin->config.center_x = get_value();
449         plugin->send_configure_change();
450         return 1;
451 }
452
453
454
455 TimeFrontCenterY::TimeFrontCenterY(TimeFrontMain *plugin, int x, int y)
456  : BC_FPot(x, y, plugin->config.center_y, 0, 100)
457 {
458         this->plugin = plugin;
459 }
460
461 int TimeFrontCenterY::handle_event()
462 {
463         plugin->config.center_y = get_value();
464         plugin->send_configure_change();
465         return 1;
466 }
467
468
469
470
471 TimeFrontAngle::TimeFrontAngle(TimeFrontMain *plugin, int x, int y)
472  : BC_FPot(x,
473         y,
474         plugin->config.angle,
475         -180,
476         180)
477 {
478         this->plugin = plugin;
479 }
480
481 int TimeFrontAngle::handle_event()
482 {
483         plugin->config.angle = get_value();
484         plugin->send_configure_change();
485         return 1;
486 }
487
488
489 TimeFrontRate::TimeFrontRate(TimeFrontMain *plugin, int x, int y)
490  : BC_PopupMenu(x,
491         y,
492         100,
493         to_text(plugin->config.rate),
494         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 _("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         200,
538         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         200,
559         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         200,
579         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 _("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                                 out_row[0] = framelist[choice]->get_rows()[i][j * components + 0]; \
748                                 out_row[1] = framelist[choice]->get_rows()[i][j * components + 1]; \
749                                 out_row[2] = framelist[choice]->get_rows()[i][j * components + 2]; \
750                                 if (components == 4) \
751                                         out_row[3] = framelist[choice]->get_rows()[i][j * components + 3]; \
752                         } \
753                         out_row += components; \
754                 } \
755         }
756
757
758
759 int TimeFrontMain::process_buffer(VFrame **frame,
760                 int64_t start_position,
761                 double frame_rate)
762 //int TimeFrontMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
763 {
764         VFrame **outframes = frame;
765         VFrame *(framelist[1024]);
766         framelist[0] = new VFrame (
767                 outframes[0]->get_w(),
768                 outframes[0]->get_h(),
769                 outframes[0]->get_color_model());
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) gradient = new VFrame(
800                         outframes[0]->get_w(),
801                         outframes[0]->get_h(),
802                         BC_A8);
803
804                         
805                 if (config.shape != TimeFrontConfig::OTHERTRACK &&
806                     config.shape != TimeFrontConfig::ALPHA)
807                 {
808                         if(!engine) engine = new TimeFrontServer(this,
809                                 get_project_smp() + 1,
810                                 get_project_smp() + 1);
811                         engine->process_packages();
812                 }
813                 
814         }
815         if (config.shape == TimeFrontConfig::ALPHA)
816         {
817                 if(!gradient) gradient = new VFrame(
818                         outframes[0]->get_w(),
819                         outframes[0]->get_h(),
820                         BC_A8);
821                 VFrame *tfframe = framelist[0];
822                 switch (tfframe->get_color_model())
823                 {
824                         case BC_YUVA8888:
825                         case BC_RGBA8888:
826                                 GRADIENTFROMCHANNEL(unsigned char, 4, 255, 3);
827
828
829                                 break;
830                         case BC_RGBA_FLOAT:
831                                 GRADIENTFROMCHANNEL(float, 4, 1.0f, 3);
832                                 break;
833                         
834                         default:
835                                 {
836                                         printf(_("TimeFront plugin error: ALPHA used, but project color model does not have alpha\n"));
837                                         return 1;
838                                         break;
839                                 }
840                 }
841
842         } else
843         if (config.shape == TimeFrontConfig::OTHERTRACK)
844         {
845                 if(!gradient) gradient = new VFrame(
846                         outframes[0]->get_w(),
847                         outframes[0]->get_h(),
848                         BC_A8);
849                 VFrame *tfframe = outframes[1];
850                 read_frame(tfframe,
851                         1,
852                         start_position,
853                         frame_rate,
854                         0);
855                 if (config.track_usage == TimeFrontConfig::OTHERTRACK_INTENSITY)
856                 {
857                         switch (tfframe->get_color_model())
858                         {
859                                 case BC_RGBA8888:
860                                         GRADIENTFROMAVG(unsigned char, unsigned short, 4, 255);       // Has to be 2 ranges bigger, sice we need precision for alpha
861                                         break;
862                                 case BC_RGB888:
863                                         GRADIENTFROMAVG(unsigned char, unsigned short, 3, 255);
864                                         break;
865                                 case BC_RGB_FLOAT:
866                                         GRADIENTFROMAVG(float, float, 3, 1.0f);
867                                         break;
868                                 case BC_RGBA_FLOAT:
869                                         GRADIENTFROMAVG(float, float, 4, 1.0f);
870                                         break;
871                                 case BC_YUV888:                                                 // We cheat and take Y component as intensity
872                                         GRADIENTFROMCHANNEL(unsigned char, 3, 255, 0);
873                                         break;
874                                 case BC_YUVA8888:
875                                         GRADIENTFROMCHANNEL(unsigned char, 4, 255, 0);
876                                         break;
877                                 default:
878                                         break;
879                         }
880                 } else
881                 if (config.track_usage == TimeFrontConfig::OTHERTRACK_ALPHA)
882                 {
883                         switch (tfframe->get_color_model())
884                         {
885                                 case BC_YUVA8888:
886                                 case BC_RGBA8888:
887                                         GRADIENTFROMCHANNEL(unsigned char, 4, 255, 3);
888
889
890                                         break;
891                                 case BC_RGBA_FLOAT:
892                                         GRADIENTFROMCHANNEL(float, 4, 1.0f, 3);
893                                         break;
894                                 
895                                 default:
896                                         {
897                                                 printf(_("TimeFront plugin error: ALPHA track used, but project color model does not have alpha\n"));
898                                                 return 1;
899                                                 break;
900                                         }
901                         }
902                 } else
903                 {
904                         printf(_("TimeFront plugin error: unsupported track_usage parameter\n"));
905                         return 1;
906                 }
907         }       
908
909         if (!config.show_grayscale)
910         {
911                 for (int i = 1; i <= config.frame_range; i++) 
912                 {
913                         framelist[i] = new VFrame (
914                                 outframes[0]->get_w(), 
915                                 outframes[0]->get_h(), 
916                                 outframes[0]->get_color_model());
917
918                         read_frame(framelist[i],
919                                 0,
920                                 start_position - i,
921                                 frame_rate,
922                                 0);
923                 }
924         }
925         
926
927         int width = outframes[0]->get_w();
928         int height = outframes[0]->get_h();
929         if (config.show_grayscale)
930         {
931                 if (!config.invert)
932                 {
933                         switch (outframes[0]->get_color_model())
934                         {
935                                 case BC_RGB888:
936                                         GRADIENTTOPICTURE(unsigned char, unsigned short, 3, 255, );
937                                         break;
938                                 case BC_RGBA8888:
939                                         GRADIENTTOPICTURE(unsigned char, unsigned short, 4, 255, );
940                                         break;
941                                 case BC_YUV888:
942                                         GRADIENTTOYUVPICTURE(unsigned char, unsigned short, 3, 255, );
943                                         break;
944                                 case BC_YUVA8888:
945                                         GRADIENTTOYUVPICTURE(unsigned char, unsigned short, 4, 255, );
946                                         break;
947                                 case BC_RGB_FLOAT:
948                                         GRADIENTTOPICTURE(float, float, 3, 1.0f, );
949                                         break;
950                                 case BC_RGBA_FLOAT:
951                                         GRADIENTTOPICTURE(float, float, 4, 1.0f, );
952                                         break;
953                                 default:
954                                         break;
955                         }
956                 } else
957                 {
958                         switch (outframes[0]->get_color_model())
959                         {
960                                 case BC_RGB888:
961                                         GRADIENTTOPICTURE(unsigned char, unsigned short, 3, 255, config.frame_range -);
962                                         break;
963                                 case BC_RGBA8888:
964                                         GRADIENTTOPICTURE(unsigned char, unsigned short, 4, 255, config.frame_range -);
965                                         break;
966                                 case BC_YUV888:
967                                         GRADIENTTOYUVPICTURE(unsigned char, unsigned short, 3, 255, config.frame_range -);
968                                         break;
969                                 case BC_YUVA8888:
970                                         GRADIENTTOYUVPICTURE(unsigned char, unsigned short, 4, 255, config.frame_range -);
971                                         break;
972                                 case BC_RGB_FLOAT:
973                                         GRADIENTTOPICTURE(float, float, 3, 1.0f, config.frame_range -);
974                                         break;
975                                 case BC_RGBA_FLOAT:
976                                         GRADIENTTOPICTURE(float, float, 4, 1.0f, config.frame_range -);
977                                         break;
978                                 default:
979                                         break;
980                         }
981                 }
982         } else 
983         if (!config.invert)
984         {
985                 switch (outframes[0]->get_color_model())
986                 {
987                         case BC_RGB888:
988                                 COMPOSITEIMAGE(unsigned char, 3, );
989                                 break;
990                         case BC_RGBA8888:
991                                 COMPOSITEIMAGE(unsigned char, 4, );
992                                 break;
993                         case BC_YUV888:
994                                 COMPOSITEIMAGE(unsigned char, 3, );
995                                 break;
996                         case BC_YUVA8888:
997                                 COMPOSITEIMAGE(unsigned char, 4, );
998                                 break;
999                         case BC_RGB_FLOAT:
1000                                 COMPOSITEIMAGE(float, 3, );
1001                                 break;
1002                         case BC_RGBA_FLOAT:
1003                                 COMPOSITEIMAGE(float, 4, );
1004                                 break;
1005
1006                         default:
1007                                 break;
1008                 }
1009         } else
1010         {
1011                 switch (outframes[0]->get_color_model())
1012                 {
1013                         case BC_RGB888:
1014                                 COMPOSITEIMAGE(unsigned char, 3, config.frame_range -);
1015                                 break;
1016                         case BC_RGBA8888:
1017                                 COMPOSITEIMAGE(unsigned char, 4, config.frame_range -);
1018                                 break;
1019                         case BC_YUV888:
1020                                 COMPOSITEIMAGE(unsigned char, 3, config.frame_range -);
1021                                 break;
1022                         case BC_YUVA8888:
1023                                 COMPOSITEIMAGE(unsigned char, 4, config.frame_range -);
1024                                 break;
1025                         case BC_RGB_FLOAT:
1026                                 COMPOSITEIMAGE(float, 3, config.frame_range -);
1027                                 break;
1028                         case BC_RGBA_FLOAT:
1029                                 COMPOSITEIMAGE(float, 4, config.frame_range -);
1030                                 break;
1031
1032                         default:
1033                                 break;
1034                 }
1035         }
1036         if (config.shape == TimeFrontConfig::ALPHA)
1037         {
1038                 // Set alpha to max
1039                 switch (outframes[0]->get_color_model())
1040                 {
1041                         case BC_YUVA8888:
1042                         case BC_RGBA8888:
1043                                 SETALPHA(unsigned char, 255);
1044                                 break;
1045                         case BC_RGBA_FLOAT:
1046                                 SETALPHA(float, 1.0f);
1047                                 break;
1048                                 
1049                         default:
1050                                 break;
1051                 }
1052         }
1053
1054         delete framelist[0];
1055         if (!config.show_grayscale)
1056         {
1057                 for (int i = 1; i <= config.frame_range; i++) 
1058                         delete framelist[i];
1059         }
1060         return 0;
1061 }
1062
1063
1064 void TimeFrontMain::update_gui()
1065 {
1066         if(thread)
1067         {
1068                 if(load_configuration())
1069                 {
1070                         thread->window->lock_window("TimeFrontMain::update_gui");
1071                         ((TimeFrontWindow*)thread->window)->frame_range->update(config.frame_range);
1072                         ((TimeFrontWindow*)thread->window)->shape->set_text(TimeFrontShape::to_text(config.shape));
1073                         ((TimeFrontWindow*)thread->window)->show_grayscale->update(config.show_grayscale);
1074                         ((TimeFrontWindow*)thread->window)->invert->update(config.invert);
1075                         ((TimeFrontWindow*)thread->window)->shape->set_text(TimeFrontShape::to_text(config.shape));
1076                         if (((TimeFrontWindow*)thread->window)->rate)
1077                                 ((TimeFrontWindow*)thread->window)->rate->set_text(TimeFrontRate::to_text(config.rate));
1078                         if (((TimeFrontWindow*)thread->window)->in_radius)
1079                                 ((TimeFrontWindow*)thread->window)->in_radius->update(config.in_radius);
1080                         if (((TimeFrontWindow*)thread->window)->out_radius)
1081                                 ((TimeFrontWindow*)thread->window)->out_radius->update(config.out_radius);
1082                         if (((TimeFrontWindow*)thread->window)->track_usage)
1083                                 ((TimeFrontWindow*)thread->window)->track_usage->set_text(TimeFrontTrackUsage::to_text(config.track_usage));
1084                         if(((TimeFrontWindow*)thread->window)->angle)
1085                                 ((TimeFrontWindow*)thread->window)->angle->update(config.angle);
1086                         if(((TimeFrontWindow*)thread->window)->center_x)
1087                                 ((TimeFrontWindow*)thread->window)->center_x->update(config.center_x);
1088                         if(((TimeFrontWindow*)thread->window)->center_y)
1089                                 ((TimeFrontWindow*)thread->window)->center_y->update(config.center_y);
1090                         
1091                         ((TimeFrontWindow*)thread->window)->update_shape();
1092                         thread->window->unlock_window();
1093                 }
1094         }
1095 }
1096
1097
1098
1099
1100 void TimeFrontMain::save_data(KeyFrame *keyframe)
1101 {
1102         FileXML output;
1103
1104 // cause data to be stored directly in text
1105         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
1106         output.tag.set_title("TIMEFRONT");
1107
1108         output.tag.set_property("ANGLE", config.angle);
1109         output.tag.set_property("IN_RADIUS", config.in_radius);
1110         output.tag.set_property("OUT_RADIUS", config.out_radius);
1111         output.tag.set_property("FRAME_RANGE", config.frame_range);
1112         output.tag.set_property("SHAPE", config.shape);
1113         output.tag.set_property("TRACK_USAGE", config.track_usage);
1114         output.tag.set_property("RATE", config.rate);
1115         output.tag.set_property("CENTER_X", config.center_x);
1116         output.tag.set_property("CENTER_Y", config.center_y);
1117         output.tag.set_property("INVERT", config.invert);
1118         output.tag.set_property("SHOW_GRAYSCALE", config.show_grayscale);
1119         output.append_tag();
1120         output.tag.set_title("/TIMEFRONT");
1121         output.append_tag();
1122         output.append_newline();
1123         output.terminate_string();
1124 }
1125
1126 void TimeFrontMain::read_data(KeyFrame *keyframe)
1127 {
1128         FileXML input;
1129
1130         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
1131
1132         int result = 0;
1133
1134         while(!result)
1135         {
1136                 result = input.read_tag();
1137
1138                 if(!result)
1139                 {
1140                         if(input.tag.title_is("TIMEFRONT"))
1141                         {
1142                                 config.angle = input.tag.get_property("ANGLE", config.angle);
1143                                 config.rate = input.tag.get_property("RATE", config.rate);
1144                                 config.in_radius = input.tag.get_property("IN_RADIUS", config.in_radius);
1145                                 config.out_radius = input.tag.get_property("OUT_RADIUS", config.out_radius);
1146                                 config.frame_range = input.tag.get_property("FRAME_RANGE", config.frame_range);
1147                                 config.shape = input.tag.get_property("SHAPE", config.shape);
1148                                 config.track_usage = input.tag.get_property("TRACK_USAGE", config.track_usage);
1149                                 config.center_x = input.tag.get_property("CENTER_X", config.center_x);
1150                                 config.center_y = input.tag.get_property("CENTER_Y", config.center_y);
1151                                 config.invert = input.tag.get_property("INVERT", config.invert);
1152                                 config.show_grayscale = input.tag.get_property("SHOW_GRAYSCALE", config.show_grayscale);
1153                         }
1154                 }
1155         }
1156 }
1157
1158
1159
1160
1161
1162
1163 TimeFrontPackage::TimeFrontPackage()
1164  : LoadPackage()
1165 {
1166 }
1167
1168
1169
1170
1171 TimeFrontUnit::TimeFrontUnit(TimeFrontServer *server, TimeFrontMain *plugin)
1172  : LoadClient(server)
1173 {
1174         this->plugin = plugin;
1175         this->server = server;
1176 }
1177
1178
1179 #define LOG_RANGE 1
1180
1181 #define CREATE_GRADIENT \
1182 { \
1183 /* Synthesize linear gradient for lookups */ \
1184  \
1185         a_table = (unsigned char *)malloc(sizeof(unsigned char) * gradient_size); \
1186  \
1187         for(int i = 0; i < gradient_size; i++) \
1188         { \
1189                 float opacity = 0.0; \
1190                 switch(plugin->config.rate) \
1191                 { \
1192                         case TimeFrontConfig::LINEAR: \
1193                                 if(i < in_radius) \
1194                                         opacity = 0.0; \
1195                                 else \
1196                                 if(i >= out_radius) \
1197                                         opacity = 1.0; \
1198                                 else \
1199                                         opacity = (float)(i - in_radius) / (out_radius - in_radius); \
1200                                 break; \
1201                         case TimeFrontConfig::LOG: \
1202                                 opacity = 1 - exp(LOG_RANGE * -(float)(i - in_radius) / (out_radius - in_radius)); \
1203                                 break; \
1204                         case TimeFrontConfig::SQUARE: \
1205                                 opacity = SQR((float)(i - in_radius) / (out_radius - in_radius)); \
1206                                 break; \
1207                 } \
1208  \
1209                 CLAMP(opacity, 0, 1); \
1210                 float transparency = 1.0 - opacity; \
1211                 a_table[i] = (unsigned char)(out4 * opacity + in4 * transparency); \
1212         } \
1213  \
1214         for(int i = pkg->y1; i < pkg->y2; i++) \
1215         { \
1216                 unsigned char *out_row = plugin->gradient->get_rows()[i]; \
1217  \
1218                 switch(plugin->config.shape) \
1219                 { \
1220                         case TimeFrontConfig::LINEAR: \
1221                                 for(int j = 0; j < w; j++) \
1222                                 { \
1223                                         int x = j - half_w; \
1224                                         int y = -(i - half_h); \
1225                  \
1226 /* Rotate by effect angle */ \
1227                                         int input_y = (int)(gradient_size / 2 - \
1228                                                 (x * sin_angle + y * cos_angle) + \
1229                                                 0.5); \
1230                  \
1231 /* Get gradient value from these coords */ \
1232                  \
1233                                         if(input_y < 0) \
1234                                         { \
1235                                                 out_row[0] = out4; \
1236                                         } \
1237                                         else \
1238                                         if(input_y >= gradient_size) \
1239                                         { \
1240                                                 out_row[0] = in4; \
1241                                         } \
1242                                         else \
1243                                         { \
1244                                                 out_row[0] = a_table[input_y]; \
1245                                         } \
1246                  \
1247                                         out_row ++; \
1248                                 } \
1249                                 break; \
1250  \
1251                         case TimeFrontConfig::RADIAL: \
1252                                 for(int j = 0; j < w; j++) \
1253                                 { \
1254                                         double x = j - center_x; \
1255                                         double y = i - center_y; \
1256                                         double magnitude = hypot(x, y); \
1257                                         int input_y = (int)magnitude; \
1258                                         out_row[0] = a_table[input_y]; \
1259                                         out_row ++; \
1260                                 } \
1261                                 break; \
1262                 } \
1263         } \
1264 }
1265
1266 void TimeFrontUnit::process_package(LoadPackage *package)
1267 {
1268         TimeFrontPackage *pkg = (TimeFrontPackage*)package;
1269         int h = plugin->input->get_h();
1270         int w = plugin->input->get_w();
1271         int half_w = w / 2;
1272         int half_h = h / 2;
1273         int gradient_size = (int)(ceil(hypot(w, h)));
1274         int in_radius = (int)(plugin->config.in_radius / 100 * gradient_size);
1275         int out_radius = (int)(plugin->config.out_radius / 100 * gradient_size);
1276         double sin_angle = sin(plugin->config.angle * (M_PI / 180));
1277         double cos_angle = cos(plugin->config.angle * (M_PI / 180));
1278         double center_x = plugin->config.center_x * w / 100;
1279         double center_y = plugin->config.center_y * h / 100;
1280         unsigned char *a_table = 0;
1281
1282         if(in_radius > out_radius)
1283         {
1284             in_radius ^= out_radius;
1285             out_radius ^= in_radius;
1286             in_radius ^= out_radius;
1287         }
1288
1289
1290         int in4 = plugin->config.frame_range;
1291         int out4 = 0;
1292         CREATE_GRADIENT
1293
1294         if(a_table) free(a_table);
1295 }
1296
1297
1298
1299
1300
1301
1302 TimeFrontServer::TimeFrontServer(TimeFrontMain *plugin, 
1303         int total_clients, 
1304         int total_packages)
1305  : LoadServer(total_clients, total_packages)
1306 {
1307         this->plugin = plugin;
1308 }
1309
1310 void TimeFrontServer::init_packages()
1311 {
1312         for(int i = 0; i < get_total_packages(); i++)
1313         {
1314                 TimeFrontPackage *package = (TimeFrontPackage*)get_package(i);
1315                 package->y1 = plugin->input->get_h() * 
1316                         i / 
1317                         get_total_packages();
1318                 package->y2 = plugin->input->get_h() * 
1319                         (i + 1) /
1320                         get_total_packages();
1321         }
1322 }
1323
1324 LoadClient* TimeFrontServer::new_client()
1325 {
1326         return new TimeFrontUnit(this, plugin);
1327 }
1328
1329 LoadPackage* TimeFrontServer::new_package()
1330 {
1331         return new TimeFrontPackage;
1332 }
1333
1334
1335
1336
1337