initial commit
[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 0;
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 N_("TimeFront"); }
649 int TimeFrontMain::is_realtime() { return 1; }
650 int TimeFrontMain::is_multichannel() { return 1; }
651
652
653
654 NEW_WINDOW_MACRO(TimeFrontMain, TimeFrontWindow)
655
656 LOAD_CONFIGURATION_MACRO(TimeFrontMain, TimeFrontConfig)
657
658 int TimeFrontMain::is_synthesis()
659 {
660         return 1;
661 }
662
663 #define GRADIENTFROMAVG(type, inttype, components, maxval) \
664         for(int i = 0; i < tfframe->get_h(); i++) \
665         { \
666                 type *in_row = (type *)tfframe->get_rows()[i]; \
667                 unsigned char *grad_row = gradient->get_rows()[i]; \
668                 for(int j = 0; j < tfframe->get_w(); j++) \
669                 { \
670                         inttype tmp =   (inttype) in_row[j * components] + \
671                                                   in_row[j * components + 1] + \
672                                                   in_row[j * components + 2]; \
673                         if (components == 3) \
674                                 grad_row[j] = (unsigned char) (CLIP((float)config.frame_range * tmp / maxval / 3, 0.0F, config.frame_range)); \
675                         else if(components == 4) \
676                                 grad_row[j] = (unsigned char) (CLIP((float)config.frame_range * tmp * in_row[j * components + 3] / maxval / maxval / 3, 0.0F, config.frame_range)); \
677                 } \
678         }
679         
680 #define GRADIENTFROMCHANNEL(type, components, max, channel) \
681         for(int i = 0; i < tfframe->get_h(); i++) \
682         { \
683                 type *in_row = (type *)tfframe->get_rows()[i]; \
684                 unsigned char *grad_row = gradient->get_rows()[i]; \
685                 for(int j = 0; j < tfframe->get_w(); j++) \
686                 { \
687                         if (components == 3) \
688                                 grad_row[j] = (unsigned char) (CLIP((float)config.frame_range * in_row[j * components + channel] / max, 0.0F, config.frame_range)); \
689                         else if(components == 4) \
690                                 grad_row[j] = (unsigned char) (CLIP((float)config.frame_range * in_row[j * components + channel] * in_row[j * components + 3]/ max /max, 0.0F, config.frame_range)); \
691                 } \
692         }
693
694 #define SETALPHA(type, max) \
695         for(int i = 0; i < outframes[0]->get_h(); i++) \
696         { \
697                 type *out_row = (type *)outframes[0]->get_rows()[i]; \
698                 for(int j = 0; j < outframes[0]->get_w(); j++) \
699                 { \
700                         out_row[j * 4 + 3] = max; \
701                 } \
702         }
703
704 #define GRADIENTTOPICTURE(type, inttype, components, max, invertion) \
705         for(int i = 0; i < height; i++) \
706         { \
707                 type *out_row = (type *)outframes[0]->get_rows()[i]; \
708                 unsigned char *grad_row = gradient->get_rows()[i]; \
709                 for (int j = 0; j < width; j++) \
710                 { \
711                         out_row[0] = (inttype)max * (invertion grad_row[0]) / config.frame_range; \
712                         out_row[1] = (inttype)max * (invertion grad_row[0]) / config.frame_range; \
713                         out_row[2] = (inttype)max * (invertion grad_row[0]) / config.frame_range; \
714                         if (components == 4) \
715                                 out_row[3] = max; \
716                         out_row += components; \
717                         grad_row ++; \
718                 } \
719         }
720         
721 #define GRADIENTTOYUVPICTURE(type, inttype, components, max, invertion) \
722         for(int i = 0; i < height; i++) \
723         { \
724                 type *out_row = (type *)outframes[0]->get_rows()[i]; \
725                 unsigned char *grad_row = gradient->get_rows()[i]; \
726                 for (int j = 0; j < width; j++) \
727                 { \
728                         out_row[0] = (inttype)max * (invertion grad_row[0]) / config.frame_range; \
729                         out_row[1] = max/2; \
730                         out_row[2] = max/2; \
731                         if (components == 4) \
732                                 out_row[3] = max; \
733                         out_row += components; \
734                         grad_row ++; \
735                 } \
736         }
737
738 #define COMPOSITEIMAGE(type, components, invertion) \
739         for (int i = 0; i < height; i++) \
740         { \
741                 type *out_row = (type *)outframes[0]->get_rows()[i]; \
742                 unsigned char *gradient_row = gradient->get_rows()[i]; \
743                 for (int j = 0; j < width; j++) \
744                 { \
745                         unsigned int choice = invertion gradient_row[j]; \
746                         { \
747                                 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         this->input = framelist[0];
775         this->output = outframes[0];
776         need_reconfigure |= load_configuration();
777         if (config.shape == TimeFrontConfig::OTHERTRACK)
778         {
779 //              this->output = frame[1];
780                 if (get_total_buffers() != 2) 
781                 {
782                         // FIXME, maybe this should go to some other notification area?
783                         printf("ERROR: TimeFront plugin - If you are using another track for timefront, you have to have it under shared effects\n");
784                         return 0;
785                 }
786                 if (outframes[0]->get_w() != outframes[1]->get_w() || outframes[0]->get_h() != outframes[1]->get_h())
787                 {
788                         printf("Sizes of master track and timefront track do not match\n");
789                         return 0;
790                 }
791         }
792
793 // Generate new gradient
794         if(need_reconfigure)
795         {
796                 need_reconfigure = 0;
797
798                 if(!gradient) gradient = new VFrame(
799                         outframes[0]->get_w(),
800                         outframes[0]->get_h(),
801                         BC_A8);
802
803                         
804                 if (config.shape != TimeFrontConfig::OTHERTRACK &&
805                     config.shape != TimeFrontConfig::ALPHA)
806                 {
807                         if(!engine) engine = new TimeFrontServer(this,
808                                 get_project_smp() + 1,
809                                 get_project_smp() + 1);
810                         engine->process_packages();
811                 }
812                 
813         }
814         if (config.shape == TimeFrontConfig::ALPHA)
815         {
816                 if(!gradient) gradient = new VFrame(
817                         outframes[0]->get_w(),
818                         outframes[0]->get_h(),
819                         BC_A8);
820                 VFrame *tfframe = framelist[0];
821                 switch (tfframe->get_color_model())
822                 {
823                         case BC_YUVA8888:
824                         case BC_RGBA8888:
825                                 GRADIENTFROMCHANNEL(unsigned char, 4, 255, 3);
826
827
828                                 break;
829                         case BC_RGBA_FLOAT:
830                                 GRADIENTFROMCHANNEL(float, 4, 1.0f, 3);
831                                 break;
832                         
833                         default:
834                                 {
835                                         printf("TimeFront plugin error: ALPHA used, but project color model does not have alpha\n");
836                                         return 1;
837                                         break;
838                                 }
839                 }
840
841         } else
842         if (config.shape == TimeFrontConfig::OTHERTRACK)
843         {
844                 if(!gradient) gradient = new VFrame(
845                         outframes[0]->get_w(),
846                         outframes[0]->get_h(),
847                         BC_A8);
848                 VFrame *tfframe = outframes[1];
849                 read_frame(tfframe,
850                         1,
851                         start_position,
852                         frame_rate);
853                 if (config.track_usage == TimeFrontConfig::OTHERTRACK_INTENSITY)
854                 {
855                         switch (tfframe->get_color_model())
856                         {
857                                 case BC_RGBA8888:
858                                         GRADIENTFROMAVG(unsigned char, unsigned short, 4, 255);       // Has to be 2 ranges bigger, sice we need precision for alpha
859                                         break;
860                                 case BC_RGB888:
861                                         GRADIENTFROMAVG(unsigned char, unsigned short, 3, 255);
862                                         break;
863                                 case BC_RGB_FLOAT:
864                                         GRADIENTFROMAVG(float, float, 3, 1.0f);
865                                         break;
866                                 case BC_RGBA_FLOAT:
867                                         GRADIENTFROMAVG(float, float, 4, 1.0f);
868                                         break;
869                                 case BC_YUV888:                                                 // We cheat and take Y component as intensity
870                                         GRADIENTFROMCHANNEL(unsigned char, 3, 255, 0);
871                                         break;
872                                 case BC_YUVA8888:
873                                         GRADIENTFROMCHANNEL(unsigned char, 4, 255, 0);
874                                         break;
875                                 default:
876                                         break;
877                         }
878                 } else
879                 if (config.track_usage == TimeFrontConfig::OTHERTRACK_ALPHA)
880                 {
881                         switch (tfframe->get_color_model())
882                         {
883                                 case BC_YUVA8888:
884                                 case BC_RGBA8888:
885                                         GRADIENTFROMCHANNEL(unsigned char, 4, 255, 3);
886
887
888                                         break;
889                                 case BC_RGBA_FLOAT:
890                                         GRADIENTFROMCHANNEL(float, 4, 1.0f, 3);
891                                         break;
892                                 
893                                 default:
894                                         {
895                                                 printf("TimeFront plugin error: ALPHA track used, but project color model does not have alpha\n");
896                                                 return 1;
897                                                 break;
898                                         }
899                         }
900                 } else
901                 {
902                         printf("TimeFront plugin error: unsupported track_usage parameter\n");
903                         return 1;
904                 }
905         }       
906
907         if (!config.show_grayscale)
908         {
909                 for (int i = 1; i <= config.frame_range; i++) 
910                 {
911                         framelist[i] = new VFrame (
912                                 outframes[0]->get_w(), 
913                                 outframes[0]->get_h(), 
914                                 outframes[0]->get_color_model());
915
916                         read_frame(framelist[i],
917                                 0,
918                                 start_position - i,
919                                 frame_rate);
920                 }
921         }
922         
923
924         int width = outframes[0]->get_w();
925         int height = outframes[0]->get_h();
926         if (config.show_grayscale)
927         {
928                 if (!config.invert)
929                 {
930                         switch (outframes[0]->get_color_model())
931                         {
932                                 case BC_RGB888:
933                                         GRADIENTTOPICTURE(unsigned char, unsigned short, 3, 255, );
934                                         break;
935                                 case BC_RGBA8888:
936                                         GRADIENTTOPICTURE(unsigned char, unsigned short, 4, 255, );
937                                         break;
938                                 case BC_YUV888:
939                                         GRADIENTTOYUVPICTURE(unsigned char, unsigned short, 3, 255, );
940                                         break;
941                                 case BC_YUVA8888:
942                                         GRADIENTTOYUVPICTURE(unsigned char, unsigned short, 4, 255, );
943                                         break;
944                                 case BC_RGB_FLOAT:
945                                         GRADIENTTOPICTURE(float, float, 3, 1.0f, );
946                                         break;
947                                 case BC_RGBA_FLOAT:
948                                         GRADIENTTOPICTURE(float, float, 4, 1.0f, );
949                                         break;
950                                 default:
951                                         break;
952                         }
953                 } else
954                 {
955                         switch (outframes[0]->get_color_model())
956                         {
957                                 case BC_RGB888:
958                                         GRADIENTTOPICTURE(unsigned char, unsigned short, 3, 255, config.frame_range -);
959                                         break;
960                                 case BC_RGBA8888:
961                                         GRADIENTTOPICTURE(unsigned char, unsigned short, 4, 255, config.frame_range -);
962                                         break;
963                                 case BC_YUV888:
964                                         GRADIENTTOYUVPICTURE(unsigned char, unsigned short, 3, 255, config.frame_range -);
965                                         break;
966                                 case BC_YUVA8888:
967                                         GRADIENTTOYUVPICTURE(unsigned char, unsigned short, 4, 255, config.frame_range -);
968                                         break;
969                                 case BC_RGB_FLOAT:
970                                         GRADIENTTOPICTURE(float, float, 3, 1.0f, config.frame_range -);
971                                         break;
972                                 case BC_RGBA_FLOAT:
973                                         GRADIENTTOPICTURE(float, float, 4, 1.0f, config.frame_range -);
974                                         break;
975                                 default:
976                                         break;
977                         }
978                 }
979         } else 
980         if (!config.invert)
981         {
982                 switch (outframes[0]->get_color_model())
983                 {
984                         case BC_RGB888:
985                                 COMPOSITEIMAGE(unsigned char, 3, );
986                                 break;
987                         case BC_RGBA8888:
988                                 COMPOSITEIMAGE(unsigned char, 4, );
989                                 break;
990                         case BC_YUV888:
991                                 COMPOSITEIMAGE(unsigned char, 3, );
992                                 break;
993                         case BC_YUVA8888:
994                                 COMPOSITEIMAGE(unsigned char, 4, );
995                                 break;
996                         case BC_RGB_FLOAT:
997                                 COMPOSITEIMAGE(float, 3, );
998                                 break;
999                         case BC_RGBA_FLOAT:
1000                                 COMPOSITEIMAGE(float, 4, );
1001                                 break;
1002
1003                         default:
1004                                 break;
1005                 }
1006         } else
1007         {
1008                 switch (outframes[0]->get_color_model())
1009                 {
1010                         case BC_RGB888:
1011                                 COMPOSITEIMAGE(unsigned char, 3, config.frame_range -);
1012                                 break;
1013                         case BC_RGBA8888:
1014                                 COMPOSITEIMAGE(unsigned char, 4, config.frame_range -);
1015                                 break;
1016                         case BC_YUV888:
1017                                 COMPOSITEIMAGE(unsigned char, 3, config.frame_range -);
1018                                 break;
1019                         case BC_YUVA8888:
1020                                 COMPOSITEIMAGE(unsigned char, 4, config.frame_range -);
1021                                 break;
1022                         case BC_RGB_FLOAT:
1023                                 COMPOSITEIMAGE(float, 3, config.frame_range -);
1024                                 break;
1025                         case BC_RGBA_FLOAT:
1026                                 COMPOSITEIMAGE(float, 4, config.frame_range -);
1027                                 break;
1028
1029                         default:
1030                                 break;
1031                 }
1032         }
1033         if (config.shape == TimeFrontConfig::ALPHA)
1034         {
1035                 // Set alpha to max
1036                 switch (outframes[0]->get_color_model())
1037                 {
1038                         case BC_YUVA8888:
1039                         case BC_RGBA8888:
1040                                 SETALPHA(unsigned char, 255);
1041                                 break;
1042                         case BC_RGBA_FLOAT:
1043                                 SETALPHA(float, 1.0f);
1044                                 break;
1045                                 
1046                         default:
1047                                 break;
1048                 }
1049         }
1050
1051         delete framelist[0];
1052         if (!config.show_grayscale)
1053         {
1054                 for (int i = 1; i <= config.frame_range; i++) 
1055                         delete framelist[i];
1056         }
1057         return 0;
1058 }
1059
1060
1061 void TimeFrontMain::update_gui()
1062 {
1063         if(thread)
1064         {
1065                 if(load_configuration())
1066                 {
1067                         thread->window->lock_window("TimeFrontMain::update_gui");
1068                         ((TimeFrontWindow*)thread->window)->frame_range->update(config.frame_range);
1069                         ((TimeFrontWindow*)thread->window)->shape->set_text(TimeFrontShape::to_text(config.shape));
1070                         ((TimeFrontWindow*)thread->window)->show_grayscale->update(config.show_grayscale);
1071                         ((TimeFrontWindow*)thread->window)->invert->update(config.invert);
1072                         ((TimeFrontWindow*)thread->window)->shape->set_text(TimeFrontShape::to_text(config.shape));
1073                         if (((TimeFrontWindow*)thread->window)->rate)
1074                                 ((TimeFrontWindow*)thread->window)->rate->set_text(TimeFrontRate::to_text(config.rate));
1075                         if (((TimeFrontWindow*)thread->window)->in_radius)
1076                                 ((TimeFrontWindow*)thread->window)->in_radius->update(config.in_radius);
1077                         if (((TimeFrontWindow*)thread->window)->out_radius)
1078                                 ((TimeFrontWindow*)thread->window)->out_radius->update(config.out_radius);
1079                         if (((TimeFrontWindow*)thread->window)->track_usage)
1080                                 ((TimeFrontWindow*)thread->window)->track_usage->set_text(TimeFrontTrackUsage::to_text(config.track_usage));
1081                         if(((TimeFrontWindow*)thread->window)->angle)
1082                                 ((TimeFrontWindow*)thread->window)->angle->update(config.angle);
1083                         if(((TimeFrontWindow*)thread->window)->center_x)
1084                                 ((TimeFrontWindow*)thread->window)->center_x->update(config.center_x);
1085                         if(((TimeFrontWindow*)thread->window)->center_y)
1086                                 ((TimeFrontWindow*)thread->window)->center_y->update(config.center_y);
1087                         
1088                         ((TimeFrontWindow*)thread->window)->update_shape();
1089                         thread->window->unlock_window();
1090                 }
1091         }
1092 }
1093
1094
1095
1096
1097 void TimeFrontMain::save_data(KeyFrame *keyframe)
1098 {
1099         FileXML output;
1100
1101 // cause data to be stored directly in text
1102         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
1103         output.tag.set_title("TIMEFRONT");
1104
1105         output.tag.set_property("ANGLE", config.angle);
1106         output.tag.set_property("IN_RADIUS", config.in_radius);
1107         output.tag.set_property("OUT_RADIUS", config.out_radius);
1108         output.tag.set_property("FRAME_RANGE", config.frame_range);
1109         output.tag.set_property("SHAPE", config.shape);
1110         output.tag.set_property("TRACK_USAGE", config.track_usage);
1111         output.tag.set_property("RATE", config.rate);
1112         output.tag.set_property("CENTER_X", config.center_x);
1113         output.tag.set_property("CENTER_Y", config.center_y);
1114         output.tag.set_property("INVERT", config.invert);
1115         output.tag.set_property("SHOW_GRAYSCALE", config.show_grayscale);
1116         output.append_tag();
1117         output.terminate_string();
1118 }
1119
1120 void TimeFrontMain::read_data(KeyFrame *keyframe)
1121 {
1122         FileXML input;
1123
1124         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
1125
1126         int result = 0;
1127
1128         while(!result)
1129         {
1130                 result = input.read_tag();
1131
1132                 if(!result)
1133                 {
1134                         if(input.tag.title_is("TIMEFRONT"))
1135                         {
1136                                 config.angle = input.tag.get_property("ANGLE", config.angle);
1137                                 config.rate = input.tag.get_property("RATE", config.rate);
1138                                 config.in_radius = input.tag.get_property("IN_RADIUS", config.in_radius);
1139                                 config.out_radius = input.tag.get_property("OUT_RADIUS", config.out_radius);
1140                                 config.frame_range = input.tag.get_property("FRAME_RANGE", config.frame_range);
1141                                 config.shape = input.tag.get_property("SHAPE", config.shape);
1142                                 config.track_usage = input.tag.get_property("TRACK_USAGE", config.track_usage);
1143                                 config.center_x = input.tag.get_property("CENTER_X", config.center_x);
1144                                 config.center_y = input.tag.get_property("CENTER_Y", config.center_y);
1145                                 config.invert = input.tag.get_property("INVERT", config.invert);
1146                                 config.show_grayscale = input.tag.get_property("SHOW_GRAYSCALE", config.show_grayscale);
1147                         }
1148                 }
1149         }
1150 }
1151
1152
1153
1154
1155
1156
1157 TimeFrontPackage::TimeFrontPackage()
1158  : LoadPackage()
1159 {
1160 }
1161
1162
1163
1164
1165 TimeFrontUnit::TimeFrontUnit(TimeFrontServer *server, TimeFrontMain *plugin)
1166  : LoadClient(server)
1167 {
1168         this->plugin = plugin;
1169         this->server = server;
1170 }
1171
1172
1173 #define LOG_RANGE 1
1174
1175 #define CREATE_GRADIENT \
1176 { \
1177 /* Synthesize linear gradient for lookups */ \
1178  \
1179         a_table = (unsigned char *)malloc(sizeof(unsigned char) * gradient_size); \
1180  \
1181         for(int i = 0; i < gradient_size; i++) \
1182         { \
1183                 float opacity = 0.0; \
1184                 switch(plugin->config.rate) \
1185                 { \
1186                         case TimeFrontConfig::LINEAR: \
1187                                 if(i < in_radius) \
1188                                         opacity = 0.0; \
1189                                 else \
1190                                 if(i >= out_radius) \
1191                                         opacity = 1.0; \
1192                                 else \
1193                                         opacity = (float)(i - in_radius) / (out_radius - in_radius); \
1194                                 break; \
1195                         case TimeFrontConfig::LOG: \
1196                                 opacity = 1 - exp(LOG_RANGE * -(float)(i - in_radius) / (out_radius - in_radius)); \
1197                                 break; \
1198                         case TimeFrontConfig::SQUARE: \
1199                                 opacity = SQR((float)(i - in_radius) / (out_radius - in_radius)); \
1200                                 break; \
1201                 } \
1202  \
1203                 CLAMP(opacity, 0, 1); \
1204                 float transparency = 1.0 - opacity; \
1205                 a_table[i] = (unsigned char)(out4 * opacity + in4 * transparency); \
1206         } \
1207  \
1208         for(int i = pkg->y1; i < pkg->y2; i++) \
1209         { \
1210                 unsigned char *out_row = plugin->gradient->get_rows()[i]; \
1211  \
1212                 switch(plugin->config.shape) \
1213                 { \
1214                         case TimeFrontConfig::LINEAR: \
1215                                 for(int j = 0; j < w; j++) \
1216                                 { \
1217                                         int x = j - half_w; \
1218                                         int y = -(i - half_h); \
1219                  \
1220 /* Rotate by effect angle */ \
1221                                         int input_y = (int)(gradient_size / 2 - \
1222                                                 (x * sin_angle + y * cos_angle) + \
1223                                                 0.5); \
1224                  \
1225 /* Get gradient value from these coords */ \
1226                  \
1227                                         if(input_y < 0) \
1228                                         { \
1229                                                 out_row[0] = out4; \
1230                                         } \
1231                                         else \
1232                                         if(input_y >= gradient_size) \
1233                                         { \
1234                                                 out_row[0] = in4; \
1235                                         } \
1236                                         else \
1237                                         { \
1238                                                 out_row[0] = a_table[input_y]; \
1239                                         } \
1240                  \
1241                                         out_row ++; \
1242                                 } \
1243                                 break; \
1244  \
1245                         case TimeFrontConfig::RADIAL: \
1246                                 for(int j = 0; j < w; j++) \
1247                                 { \
1248                                         double x = j - center_x; \
1249                                         double y = i - center_y; \
1250                                         double magnitude = hypot(x, y); \
1251                                         int input_y = (int)magnitude; \
1252                                         out_row[0] = a_table[input_y]; \
1253                                         out_row ++; \
1254                                 } \
1255                                 break; \
1256                 } \
1257         } \
1258 }
1259
1260 void TimeFrontUnit::process_package(LoadPackage *package)
1261 {
1262         TimeFrontPackage *pkg = (TimeFrontPackage*)package;
1263         int h = plugin->input->get_h();
1264         int w = plugin->input->get_w();
1265         int half_w = w / 2;
1266         int half_h = h / 2;
1267         int gradient_size = (int)(ceil(hypot(w, h)));
1268         int in_radius = (int)(plugin->config.in_radius / 100 * gradient_size);
1269         int out_radius = (int)(plugin->config.out_radius / 100 * gradient_size);
1270         double sin_angle = sin(plugin->config.angle * (M_PI / 180));
1271         double cos_angle = cos(plugin->config.angle * (M_PI / 180));
1272         double center_x = plugin->config.center_x * w / 100;
1273         double center_y = plugin->config.center_y * h / 100;
1274         unsigned char *a_table = 0;
1275
1276         if(in_radius > out_radius)
1277         {
1278             in_radius ^= out_radius;
1279             out_radius ^= in_radius;
1280             in_radius ^= out_radius;
1281         }
1282
1283
1284         int in4 = plugin->config.frame_range;
1285         int out4 = 0;
1286         CREATE_GRADIENT
1287
1288         if(a_table) free(a_table);
1289 }
1290
1291
1292
1293
1294
1295
1296 TimeFrontServer::TimeFrontServer(TimeFrontMain *plugin, 
1297         int total_clients, 
1298         int total_packages)
1299  : LoadServer(total_clients, total_packages)
1300 {
1301         this->plugin = plugin;
1302 }
1303
1304 void TimeFrontServer::init_packages()
1305 {
1306         for(int i = 0; i < get_total_packages(); i++)
1307         {
1308                 TimeFrontPackage *package = (TimeFrontPackage*)get_package(i);
1309                 package->y1 = plugin->input->get_h() * 
1310                         i / 
1311                         get_total_packages();
1312                 package->y2 = plugin->input->get_h() * 
1313                         (i + 1) /
1314                         get_total_packages();
1315         }
1316 }
1317
1318 LoadClient* TimeFrontServer::new_client()
1319 {
1320         return new TimeFrontUnit(this, plugin);
1321 }
1322
1323 LoadPackage* TimeFrontServer::new_package()
1324 {
1325         return new TimeFrontPackage;
1326 }
1327
1328
1329
1330
1331