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