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