Fixed initialisation of tf in file_open(). Without setting the memory to 0,
[cinelerra_cv/mob.git] / plugins / timefront / timefront.C
blob46a23e05d8459c8ce67439cfd77130def23bde8c
1 #include <math.h>
2 #include <stdint.h>
3 #include <string.h>
5 #include "bcdisplayinfo.h"
6 #include "clip.h"
7 #include "bchash.h"
8 #include "filexml.h"
9 #include "timefront.h"
10 #include "keyframe.h"
11 #include "language.h"
12 #include "overlayframe.h"
13 #include "picon_png.h"
14 #include "vframe.h"
19 REGISTER_PLUGIN(TimeFrontMain)
26 TimeFrontConfig::TimeFrontConfig()
28         angle = 0;
29         in_radius = 0;
30         out_radius = 100;
31         frame_range = 16;
32         track_usage = TimeFrontConfig::OTHERTRACK_INTENSITY;
33         shape = TimeFrontConfig::LINEAR;
34         rate = TimeFrontConfig::LINEAR;
35         center_x = 50;
36         center_y = 50;
37         invert = 0;
38         show_grayscale = 0;
41 int TimeFrontConfig::equivalent(TimeFrontConfig &that)
43         return (EQUIV(angle, that.angle) &&
44                 EQUIV(in_radius, that.in_radius) &&
45                 EQUIV(out_radius, that.out_radius) &&
46                 frame_range == that.frame_range &&
47                 track_usage == that.track_usage &&
48                 shape == that.shape &&
49                 rate == that.rate &&
50                 EQUIV(center_x, that.center_x) &&
51                 EQUIV(center_y, that.center_y) && 
52                 invert == that.invert &&
53                 show_grayscale == that.show_grayscale);
56 void TimeFrontConfig::copy_from(TimeFrontConfig &that)
58         angle = that.angle;
59         in_radius = that.in_radius;
60         out_radius = that.out_radius;
61         frame_range = that.frame_range;
62         track_usage = that.track_usage;
63         shape = that.shape;
64         rate = that.rate;
65         center_x = that.center_x;
66         center_y = that.center_y;
67         invert = that.invert;
68         show_grayscale = that.show_grayscale;
71 void TimeFrontConfig::interpolate(TimeFrontConfig &prev, 
72         TimeFrontConfig &next, 
73         long prev_frame, 
74         long next_frame, 
75         long current_frame)
77         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
78         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
81         this->angle = (int)(prev.angle * prev_scale + next.angle * next_scale);
82         this->in_radius = (int)(prev.in_radius * prev_scale + next.in_radius * next_scale);
83         this->out_radius = (int)(prev.out_radius * prev_scale + next.out_radius * next_scale);
84         frame_range = (int)(prev.frame_range * prev_scale + next.frame_range * next_scale);
85         track_usage = prev.track_usage;
86         shape = prev.shape;
87         rate = prev.rate;
88         center_x = prev.center_x * prev_scale + next.center_x * next_scale;
89         center_y = prev.center_y * prev_scale + next.center_y * next_scale;
90         invert = prev.invert;
91         show_grayscale = prev.show_grayscale;
99 PLUGIN_THREAD_OBJECT(TimeFrontMain, TimeFrontThread, TimeFrontWindow)
102 TimeFrontWindow::TimeFrontWindow(TimeFrontMain *plugin, int x, int y)
103  : BC_Window(plugin->gui_string, 
104         x,
105         y,
106         350, 
107         290, 
108         350, 
109         290, 
110         0, 
111         1)
113         this->plugin = plugin;
114         angle = 0;
115         angle_title = 0;
116         center_x = 0;
117         center_y = 0;
118         center_x_title = 0;
119         center_y_title = 0;
120         rate_title = 0;
121         rate = 0;
122         in_radius_title = 0;
123         in_radius = 0;
124         out_radius_title = 0;
125         out_radius = 0;
126         track_usage_title = 0;
127         track_usage = 0;
128         
131 TimeFrontWindow::~TimeFrontWindow()
135 int TimeFrontWindow::create_objects()
137         int x = 10, y = 10;
138         BC_Title *title;
140         add_subwindow(title = new BC_Title(x, y, _("Type:")));
141         add_subwindow(shape = new TimeFrontShape(plugin, 
142                 this, 
143                 x + title->get_w() + 10, 
144                 y));
145         shape->create_objects();
146         y += 40;
147         shape_x = x;
148         shape_y = y;
149         y += 140;
150         add_subwindow(title = new BC_Title(x, y, _("Time range:")));
151         add_subwindow(frame_range = new TimeFrontFrameRange(plugin, x + title->get_w() + 10, y));
152         frame_range_x = x + frame_range->get_w() + 10;
153         frame_range_y = y;
154         y += 35;
155         update_shape();
156         
157         add_subwindow(invert = new TimeFrontInvert(plugin, x, y));
158         add_subwindow(show_grayscale = new TimeFrontShowGrayscale(plugin, x+ 100, y));
161         show_window();
162         flush();
163         return 0;
166 void TimeFrontWindow::update_shape()
168         int x = shape_x, y = shape_y;
170         if(plugin->config.shape == TimeFrontConfig::LINEAR)
171         {
172                 delete center_x_title;
173                 delete center_y_title;
174                 delete center_x;
175                 delete center_y;
176                 delete track_usage_title;
177                 delete track_usage;
178                 center_x_title = 0;
179                 center_y_title = 0;
180                 center_x = 0;
181                 center_y = 0;
182                 track_usage_title = 0;
183                 track_usage = 0;
184                 if(!angle)
185                 {
186                         add_subwindow(angle_title = new BC_Title(x, y, _("Angle:")));
187                         add_subwindow(angle = new TimeFrontAngle(plugin, x + angle_title->get_w() + 10, y));
188                 }
189                 if(!rate){
190                         y = shape_y + 40;
191         
192                         add_subwindow(rate_title = new BC_Title(x, y, _("Rate:")));
193                         add_subwindow(rate = new TimeFrontRate(plugin,
194                                 x + rate_title->get_w() + 10,
195                                 y));
196                         rate->create_objects();
197                         y += 40;
198                         add_subwindow(in_radius_title = new BC_Title(x, y, _("Inner radius:")));
199                         add_subwindow(in_radius = new TimeFrontInRadius(plugin, x + in_radius_title->get_w() + 10, y));
200                         y += 30;
201                         add_subwindow(out_radius_title = new BC_Title(x, y, _("Outer radius:")));
202                         add_subwindow(out_radius = new TimeFrontOutRadius(plugin, x + out_radius_title->get_w() + 10, y));
203                         y += 35;
205                 }
206         } else
207         if(plugin->config.shape == TimeFrontConfig::RADIAL)
208         {
209                 delete angle_title;
210                 delete angle;
211                 delete track_usage_title;
212                 delete track_usage;
213                 angle_title = 0;
214                 angle = 0;
215                 track_usage_title = 0;
216                 track_usage = 0;
217                 if(!center_x)
218                 {
219                         add_subwindow(center_x_title = new BC_Title(x, y, _("Center X:")));
220                         add_subwindow(center_x = new TimeFrontCenterX(plugin,
221                                 x + center_x_title->get_w() + 10,
222                                 y));
223                         x += center_x_title->get_w() + 10 + center_x->get_w() + 10;
224                         add_subwindow(center_y_title = new BC_Title(x, y, _("Center Y:")));
225                         add_subwindow(center_y = new TimeFrontCenterY(plugin,
226                                 x + center_y_title->get_w() + 10,
227                                 y));
228                 }
229                 
230                 
231                 if(!rate)
232                 {
233                         y = shape_y + 40;
234                         x = shape_x;
235                         add_subwindow(rate_title = new BC_Title(x, y, _("Rate:")));
236                         add_subwindow(rate = new TimeFrontRate(plugin,
237                                 x + rate_title->get_w() + 10,
238                                 y));
239                         rate->create_objects();
240                         y += 40;
241                         add_subwindow(in_radius_title = new BC_Title(x, y, _("Inner radius:")));
242                         add_subwindow(in_radius = new TimeFrontInRadius(plugin, x + in_radius_title->get_w() + 10, y));
243                         y += 30;
244                         add_subwindow(out_radius_title = new BC_Title(x, y, _("Outer radius:")));
245                         add_subwindow(out_radius = new TimeFrontOutRadius(plugin, x + out_radius_title->get_w() + 10, y));
246                         y += 35;
247                 }
248         } else
249         if(plugin->config.shape == TimeFrontConfig::OTHERTRACK)
250         {
251                 delete center_x_title;
252                 delete center_y_title;
253                 delete center_x;
254                 delete center_y;
255                 delete angle_title;
256                 delete angle;
257                 delete rate_title;
258                 delete rate;
259                 delete in_radius_title;
260                 delete in_radius;
261                 delete out_radius_title;
262                 delete out_radius;
263                 center_x_title = 0;
264                 center_y_title = 0;
265                 center_x = 0;
266                 center_y = 0;
267                 angle_title = 0;
268                 angle = 0;
269                 rate_title = 0;
270                 rate = 0;
271                 in_radius_title = 0;
272                 in_radius = 0;
273                 out_radius_title = 0;
274                 out_radius = 0;
275                 if(!track_usage)
276                 {
277                         add_subwindow(track_usage_title = new BC_Title(x, y, _("As timefront use:")));
278                         add_subwindow(track_usage = new TimeFrontTrackUsage(plugin,
279                                 this,
280                                 x + track_usage_title->get_w() + 10,
281                                 y));
282                         track_usage->create_objects();
284                 }
285         } else
286         if(plugin->config.shape == TimeFrontConfig::ALPHA)
287         {
288                 delete center_x_title;
289                 delete center_y_title;
290                 delete center_x;
291                 delete center_y;
292                 delete angle_title;
293                 delete angle;
294                 delete rate_title;
295                 delete rate;
296                 delete in_radius_title;
297                 delete in_radius;
298                 delete out_radius_title;
299                 delete out_radius;
300                 delete track_usage_title;
301                 delete track_usage;
302                 center_x_title = 0;
303                 center_y_title = 0;
304                 center_x = 0;
305                 center_y = 0;
306                 angle_title = 0;
307                 angle = 0;
308                 rate_title = 0;
309                 rate = 0;
310                 in_radius_title = 0;
311                 in_radius = 0;
312                 out_radius_title = 0;
313                 out_radius = 0;
314                 track_usage_title = 0;
315                 track_usage = 0;
317         }
321 int TimeFrontWindow::close_event()
323 // Set result to 1 to indicate a plugin side close
324         set_done(1);
325         return 1;
338 TimeFrontShape::TimeFrontShape(TimeFrontMain *plugin, 
339         TimeFrontWindow *gui, 
340         int x, 
341         int y)
342  : BC_PopupMenu(x, y, 190, to_text(plugin->config.shape), 1)
344         this->plugin = plugin;
345         this->gui = gui;
347 void TimeFrontShape::create_objects()
349         add_item(new BC_MenuItem(to_text(TimeFrontConfig::LINEAR)));
350         add_item(new BC_MenuItem(to_text(TimeFrontConfig::RADIAL)));
351         add_item(new BC_MenuItem(to_text(TimeFrontConfig::ALPHA)));
352         add_item(new BC_MenuItem(to_text(TimeFrontConfig::OTHERTRACK)));
354 char* TimeFrontShape::to_text(int shape)
356         switch(shape)
357         {
358                 case TimeFrontConfig::LINEAR:
359                         return _("Linear");
360                 case TimeFrontConfig::OTHERTRACK:
361                         return _("Other track as timefront");
362                 case TimeFrontConfig::ALPHA:
363                         return _("Alpha as timefront");
364                 default:
365                         return _("Radial");
366         }
368 int TimeFrontShape::from_text(char *text)
370         if(!strcmp(text, to_text(TimeFrontConfig::LINEAR))) 
371                 return TimeFrontConfig::LINEAR;
372         if(!strcmp(text, to_text(TimeFrontConfig::OTHERTRACK))) 
373                 return TimeFrontConfig::OTHERTRACK;
374         if(!strcmp(text, to_text(TimeFrontConfig::ALPHA))) 
375                 return TimeFrontConfig::ALPHA;
376         return TimeFrontConfig::RADIAL;
378 int TimeFrontShape::handle_event()
380         plugin->config.shape = from_text(get_text());
381         gui->update_shape();
382         plugin->send_configure_change();
386 TimeFrontTrackUsage::TimeFrontTrackUsage(TimeFrontMain *plugin, 
387         TimeFrontWindow *gui, 
388         int x, 
389         int y)
390  : BC_PopupMenu(x, y, 140, to_text(plugin->config.track_usage), 1)
392         this->plugin = plugin;
393         this->gui = gui;
395 void TimeFrontTrackUsage::create_objects()
397         add_item(new BC_MenuItem(to_text(TimeFrontConfig::OTHERTRACK_INTENSITY)));
398         add_item(new BC_MenuItem(to_text(TimeFrontConfig::OTHERTRACK_ALPHA)));
400 char* TimeFrontTrackUsage::to_text(int track_usage)
402         switch(track_usage)
403         {
404                 case TimeFrontConfig::OTHERTRACK_INTENSITY:
405                         return _("Intensity");
406                 case TimeFrontConfig::OTHERTRACK_ALPHA:
407                         return _("Alpha mask");
408                 default:
409                         return _("Unknown");
410         }
412 int TimeFrontTrackUsage::from_text(char *text)
414         if(!strcmp(text, to_text(TimeFrontConfig::OTHERTRACK_INTENSITY))) 
415                 return TimeFrontConfig::OTHERTRACK_INTENSITY;
416         if(!strcmp(text, to_text(TimeFrontConfig::OTHERTRACK_ALPHA))) 
417                 return TimeFrontConfig::OTHERTRACK_ALPHA;
419         return TimeFrontConfig::OTHERTRACK_INTENSITY;
421 int TimeFrontTrackUsage::handle_event()
423         plugin->config.track_usage = from_text(get_text());
424         gui->update_shape();
425         plugin->send_configure_change();
431 TimeFrontCenterX::TimeFrontCenterX(TimeFrontMain *plugin, int x, int y)
432  : BC_FPot(x, y, plugin->config.center_x, 0, 100)
434         this->plugin = plugin;
436 int TimeFrontCenterX::handle_event()
438         plugin->config.center_x = get_value();
439         plugin->send_configure_change();
440         return 1;
445 TimeFrontCenterY::TimeFrontCenterY(TimeFrontMain *plugin, int x, int y)
446  : BC_FPot(x, y, plugin->config.center_y, 0, 100)
448         this->plugin = plugin;
451 int TimeFrontCenterY::handle_event()
453         plugin->config.center_y = get_value();
454         plugin->send_configure_change();
455         return 1;
461 TimeFrontAngle::TimeFrontAngle(TimeFrontMain *plugin, int x, int y)
462  : BC_FPot(x,
463         y,
464         plugin->config.angle,
465         -180,
466         180)
468         this->plugin = plugin;
471 int TimeFrontAngle::handle_event()
473         plugin->config.angle = get_value();
474         plugin->send_configure_change();
475         return 1;
479 TimeFrontRate::TimeFrontRate(TimeFrontMain *plugin, int x, int y)
480  : BC_PopupMenu(x,
481         y,
482         100,
483         to_text(plugin->config.rate),
484         1)
486         this->plugin = plugin;
488 void TimeFrontRate::create_objects()
490         add_item(new BC_MenuItem(to_text(TimeFrontConfig::LINEAR)));
491         add_item(new BC_MenuItem(to_text(TimeFrontConfig::LOG)));
492         add_item(new BC_MenuItem(to_text(TimeFrontConfig::SQUARE)));
494 char* TimeFrontRate::to_text(int shape)
496         switch(shape)
497         {
498                 case TimeFrontConfig::LINEAR:
499                         return _("Linear");
500                 case TimeFrontConfig::LOG:
501                         return _("Log");
502                 default:
503                         return _("Square");
504         }
506 int TimeFrontRate::from_text(char *text)
508         if(!strcmp(text, to_text(TimeFrontConfig::LINEAR))) 
509                 return TimeFrontConfig::LINEAR;
510         if(!strcmp(text, to_text(TimeFrontConfig::LOG)))
511                 return TimeFrontConfig::LOG;
512         return TimeFrontConfig::SQUARE;
514 int TimeFrontRate::handle_event()
516         plugin->config.rate = from_text(get_text());
517         plugin->send_configure_change();
518         return 1;
523 TimeFrontInRadius::TimeFrontInRadius(TimeFrontMain *plugin, int x, int y)
524  : BC_FSlider(x,
525         y,
526         0,
527         200,
528         200,
529         (float)0,
530         (float)100,
531         (float)plugin->config.in_radius)
533         this->plugin = plugin;
536 int TimeFrontInRadius::handle_event()
538         plugin->config.in_radius = get_value();
539         plugin->send_configure_change();
540         return 1;
544 TimeFrontOutRadius::TimeFrontOutRadius(TimeFrontMain *plugin, int x, int y)
545  : BC_FSlider(x,
546         y,
547         0,
548         200,
549         200,
550         (float)0,
551         (float)100,
552         (float)plugin->config.out_radius)
554         this->plugin = plugin;
557 int TimeFrontOutRadius::handle_event()
559         plugin->config.out_radius = get_value();
560         plugin->send_configure_change();
561         return 1;
564 TimeFrontFrameRange::TimeFrontFrameRange(TimeFrontMain *plugin, int x, int y)
565  : BC_ISlider(x,
566         y,
567         0,
568         200,
569         200,
570         (int)1,
571         (int)255,
572         (int)plugin->config.frame_range)
574         this->plugin = plugin;
577 int TimeFrontFrameRange::handle_event()
579         plugin->config.frame_range = get_value();
580         plugin->send_configure_change();
581         return 1;
585 TimeFrontInvert::TimeFrontInvert(TimeFrontMain *client, int x, int y)
586  : BC_CheckBox(x, 
587         y, 
588         client->config.invert, 
589         _("Inversion"))
591         this->plugin = client;
594 int TimeFrontInvert::handle_event()
596         plugin->config.invert = get_value();
597         plugin->send_configure_change();
598         return 1;
601 TimeFrontShowGrayscale::TimeFrontShowGrayscale(TimeFrontMain *client, int x, int y)
602  : BC_CheckBox(x, 
603         y, 
604         client->config.show_grayscale, 
605         _("Show grayscale (for tuning"))
607         this->plugin = client;
610 int TimeFrontShowGrayscale::handle_event()
612         plugin->config.show_grayscale = get_value();
613         plugin->send_configure_change();
614         return 1;
619 TimeFrontMain::TimeFrontMain(PluginServer *server)
620  : PluginVClient(server)
622         PLUGIN_CONSTRUCTOR_MACRO
623         need_reconfigure = 1;
624         gradient = 0;
625         engine = 0;
626         overlayer = 0;
629 TimeFrontMain::~TimeFrontMain()
631         PLUGIN_DESTRUCTOR_MACRO
633         if(gradient) delete gradient;
634         if(engine) delete engine;
635         if(overlayer) delete overlayer;
638 char* TimeFrontMain::plugin_title() { return N_("TimeFront"); }
639 int TimeFrontMain::is_realtime() { return 1; }
640 int TimeFrontMain::is_multichannel() { return 1; }
643 NEW_PICON_MACRO(TimeFrontMain)
645 SHOW_GUI_MACRO(TimeFrontMain, TimeFrontThread)
647 SET_STRING_MACRO(TimeFrontMain)
649 RAISE_WINDOW_MACRO(TimeFrontMain)
651 LOAD_CONFIGURATION_MACRO(TimeFrontMain, TimeFrontConfig)
653 int TimeFrontMain::is_synthesis()
655         return 1;
658 #define GRADIENTFROMAVG(type, inttype, components, maxval) \
659         for(int i = 0; i < tfframe->get_h(); i++) \
660         { \
661                 type *in_row = (type *)tfframe->get_rows()[i]; \
662                 unsigned char *grad_row = gradient->get_rows()[i]; \
663                 for(int j = 0; j < tfframe->get_w(); j++) \
664                 { \
665                         inttype tmp =   (inttype) in_row[j * components] + \
666                                                   in_row[j * components + 1] + \
667                                                   in_row[j * components + 2]; \
668                         if (components == 3) \
669                                 grad_row[j] = (unsigned char) (CLIP((float)config.frame_range * tmp / maxval / 3, 0.0F, config.frame_range)); \
670                         else if(components == 4) \
671                                 grad_row[j] = (unsigned char) (CLIP((float)config.frame_range * tmp * in_row[j * components + 3] / maxval / maxval / 3, 0.0F, config.frame_range)); \
672                 } \
673         }
674         
675 #define GRADIENTFROMCHANNEL(type, components, max, channel) \
676         for(int i = 0; i < tfframe->get_h(); i++) \
677         { \
678                 type *in_row = (type *)tfframe->get_rows()[i]; \
679                 unsigned char *grad_row = gradient->get_rows()[i]; \
680                 for(int j = 0; j < tfframe->get_w(); j++) \
681                 { \
682                         if (components == 3) \
683                                 grad_row[j] = (unsigned char) (CLIP((float)config.frame_range * in_row[j * components + channel] / max, 0.0F, config.frame_range)); \
684                         else if(components == 4) \
685                                 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)); \
686                 } \
687         }
689 #define SETALPHA(type, max) \
690         for(int i = 0; i < outframes[0]->get_h(); i++) \
691         { \
692                 type *out_row = (type *)outframes[0]->get_rows()[i]; \
693                 for(int j = 0; j < outframes[0]->get_w(); j++) \
694                 { \
695                         out_row[j * 4 + 3] = max; \
696                 } \
697         }
699 #define GRADIENTTOPICTURE(type, inttype, components, max, invertion) \
700         for(int i = 0; i < height; i++) \
701         { \
702                 type *out_row = (type *)outframes[0]->get_rows()[i]; \
703                 unsigned char *grad_row = gradient->get_rows()[i]; \
704                 for (int j = 0; j < width; j++) \
705                 { \
706                         out_row[0] = (inttype)max * (invertion grad_row[0]) / config.frame_range; \
707                         out_row[1] = (inttype)max * (invertion grad_row[0]) / config.frame_range; \
708                         out_row[2] = (inttype)max * (invertion grad_row[0]) / config.frame_range; \
709                         if (components == 4) \
710                                 out_row[3] = max; \
711                         out_row += components; \
712                         grad_row ++; \
713                 } \
714         }
715         
716 #define GRADIENTTOYUVPICTURE(type, inttype, components, max, invertion) \
717         for(int i = 0; i < height; i++) \
718         { \
719                 type *out_row = (type *)outframes[0]->get_rows()[i]; \
720                 unsigned char *grad_row = gradient->get_rows()[i]; \
721                 for (int j = 0; j < width; j++) \
722                 { \
723                         out_row[0] = (inttype)max * (invertion grad_row[0]) / config.frame_range; \
724                         out_row[1] = max/2; \
725                         out_row[2] = max/2; \
726                         if (components == 4) \
727                                 out_row[3] = max; \
728                         out_row += components; \
729                         grad_row ++; \
730                 } \
731         }
733 #define COMPOSITEIMAGE(type, components, invertion) \
734         for (int i = 0; i < height; i++) \
735         { \
736                 type *out_row = (type *)outframes[0]->get_rows()[i]; \
737                 unsigned char *gradient_row = gradient->get_rows()[i]; \
738                 for (int j = 0; j < width; j++) \
739                 { \
740                         unsigned int choice = invertion gradient_row[j]; \
741                         { \
742                                 out_row[0] = framelist[choice]->get_rows()[i][j * components + 0]; \
743                                 out_row[1] = framelist[choice]->get_rows()[i][j * components + 1]; \
744                                 out_row[2] = framelist[choice]->get_rows()[i][j * components + 2]; \
745                                 if (components == 4) \
746                                         out_row[3] = framelist[choice]->get_rows()[i][j * components + 3]; \
747                         } \
748                         out_row += components; \
749                 } \
750         }
754 int TimeFrontMain::process_buffer(VFrame **frame,
755                 int64_t start_position,
756                 double frame_rate)
757 //int TimeFrontMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
759         VFrame **outframes = frame;
760         VFrame *(framelist[1024]);
761         framelist[0] = new VFrame (0, outframes[0]->get_w(), outframes[0]->get_h(), outframes[0]->get_color_model());
762         read_frame(framelist[0],
763                 0,
764                 start_position,
765                 frame_rate);
766         this->input = framelist[0];
767         this->output = outframes[0];
768         need_reconfigure |= load_configuration();
769         if (config.shape == TimeFrontConfig::OTHERTRACK)
770         {
771 //              this->output = frame[1];
772                 if (get_total_buffers() != 2) 
773                 {
774                         // FIXME, maybe this should go to some other notification area?
775                         printf("ERROR: TimeFront plugin - If you are using another track for timefront, you have to have it under shared effects\n");
776                         return 0;
777                 }
778                 if (outframes[0]->get_w() != outframes[1]->get_w() || outframes[0]->get_h() != outframes[1]->get_h())
779                 {
780                         printf("Sizes of master track and timefront track do not match\n");
781                         return 0;
782                 }
783         }
785 // Generate new gradient
786         if(need_reconfigure)
787         {
788                 need_reconfigure = 0;
790                 if(!gradient) gradient = new VFrame(0, 
791                         outframes[0]->get_w(),
792                         outframes[0]->get_h(),
793                         BC_A8);
795                         
796                 if (config.shape != TimeFrontConfig::OTHERTRACK &&
797                     config.shape != TimeFrontConfig::ALPHA)
798                 {
799                         if(!engine) engine = new TimeFrontServer(this,
800                                 get_project_smp() + 1,
801                                 get_project_smp() + 1);
802                         engine->process_packages();
803                 }
804                 
805         }
806         if (config.shape == TimeFrontConfig::ALPHA)
807         {
808                 if(!gradient) gradient = new VFrame(0, 
809                         outframes[0]->get_w(),
810                         outframes[0]->get_h(),
811                         BC_A8);
812                 VFrame *tfframe = framelist[0];
813                 switch (tfframe->get_color_model())
814                 {
815                         case BC_YUVA8888:
816                         case BC_RGBA8888:
817                                 GRADIENTFROMCHANNEL(unsigned char, 4, 255, 3);
820                                 break;
821                         case BC_RGBA_FLOAT:
822                                 GRADIENTFROMCHANNEL(float, 4, 1.0f, 3);
823                                 break;
824                         
825                         default:
826                                 {
827                                         printf("TimeFront plugin error: ALPHA used, but project color model does not have alpha\n");
828                                         return 1;
829                                         break;
830                                 }
831                 }
833         } else
834         if (config.shape == TimeFrontConfig::OTHERTRACK)
835         {
836                 if(!gradient) gradient = new VFrame(0, 
837                         outframes[0]->get_w(),
838                         outframes[0]->get_h(),
839                         BC_A8);
840                 VFrame *tfframe = outframes[1];
841                 read_frame(tfframe,
842                         1,
843                         start_position,
844                         frame_rate);
845                 if (config.track_usage == TimeFrontConfig::OTHERTRACK_INTENSITY)
846                 {
847                         switch (tfframe->get_color_model())
848                         {
849                                 case BC_RGBA8888:
850                                         GRADIENTFROMAVG(unsigned char, unsigned short, 4, 255);       // Has to be 2 ranges bigger, sice we need precision for alpha
851                                         break;
852                                 case BC_RGB888:
853                                         GRADIENTFROMAVG(unsigned char, unsigned short, 3, 255);
854                                         break;
855                                 case BC_RGB_FLOAT:
856                                         GRADIENTFROMAVG(float, float, 3, 1.0f);
857                                         break;
858                                 case BC_RGBA_FLOAT:
859                                         GRADIENTFROMAVG(float, float, 4, 1.0f);
860                                         break;
861                                 case BC_YUV888:                                                 // We cheat and take Y component as intensity
862                                         GRADIENTFROMCHANNEL(unsigned char, 3, 255, 0);
863                                         break;
864                                 case BC_YUVA8888:
865                                         GRADIENTFROMCHANNEL(unsigned char, 4, 255, 0);
866                                         break;
867                                 default:
868                                         break;
869                         }
870                 } else
871                 if (config.track_usage == TimeFrontConfig::OTHERTRACK_ALPHA)
872                 {
873                         switch (tfframe->get_color_model())
874                         {
875                                 case BC_YUVA8888:
876                                 case BC_RGBA8888:
877                                         GRADIENTFROMCHANNEL(unsigned char, 4, 255, 3);
880                                         break;
881                                 case BC_RGBA_FLOAT:
882                                         GRADIENTFROMCHANNEL(float, 4, 1.0f, 3);
883                                         break;
884                                 
885                                 default:
886                                         {
887                                                 printf("TimeFront plugin error: ALPHA track used, but project color model does not have alpha\n");
888                                                 return 1;
889                                                 break;
890                                         }
891                         }
892                 } else
893                 {
894                         printf("TimeFront plugin error: unsupported track_usage parameter\n");
895                         return 1;
896                 }
897         }       
899         if (!config.show_grayscale)
900         {
901                 for (int i = 1; i <= config.frame_range; i++) 
902                 {
903                         framelist[i] = new VFrame (0, outframes[0]->get_w(), outframes[0]->get_h(), outframes[0]->get_color_model());
905                         read_frame(framelist[i],
906                                 0,
907                                 start_position - i,
908                                 frame_rate);
909                 }
910         }
911         
913         int width = outframes[0]->get_w();
914         int height = outframes[0]->get_h();
915         if (config.show_grayscale)
916         {
917                 if (!config.invert)
918                 {
919                         switch (outframes[0]->get_color_model())
920                         {
921                                 case BC_RGB888:
922                                         GRADIENTTOPICTURE(unsigned char, unsigned short, 3, 255, );
923                                         break;
924                                 case BC_RGBA8888:
925                                         GRADIENTTOPICTURE(unsigned char, unsigned short, 4, 255, );
926                                         break;
927                                 case BC_YUV888:
928                                         GRADIENTTOYUVPICTURE(unsigned char, unsigned short, 3, 255, );
929                                         break;
930                                 case BC_YUVA8888:
931                                         GRADIENTTOYUVPICTURE(unsigned char, unsigned short, 4, 255, );
932                                         break;
933                                 case BC_RGB_FLOAT:
934                                         GRADIENTTOPICTURE(float, float, 3, 1.0f, );
935                                         break;
936                                 case BC_RGBA_FLOAT:
937                                         GRADIENTTOPICTURE(float, float, 4, 1.0f, );
938                                         break;
939                                 default:
940                                         break;
941                         }
942                 } else
943                 {
944                         switch (outframes[0]->get_color_model())
945                         {
946                                 case BC_RGB888:
947                                         GRADIENTTOPICTURE(unsigned char, unsigned short, 3, 255, config.frame_range -);
948                                         break;
949                                 case BC_RGBA8888:
950                                         GRADIENTTOPICTURE(unsigned char, unsigned short, 4, 255, config.frame_range -);
951                                         break;
952                                 case BC_YUV888:
953                                         GRADIENTTOYUVPICTURE(unsigned char, unsigned short, 3, 255, config.frame_range -);
954                                         break;
955                                 case BC_YUVA8888:
956                                         GRADIENTTOYUVPICTURE(unsigned char, unsigned short, 4, 255, config.frame_range -);
957                                         break;
958                                 case BC_RGB_FLOAT:
959                                         GRADIENTTOPICTURE(float, float, 3, 1.0f, config.frame_range -);
960                                         break;
961                                 case BC_RGBA_FLOAT:
962                                         GRADIENTTOPICTURE(float, float, 4, 1.0f, config.frame_range -);
963                                         break;
964                                 default:
965                                         break;
966                         }
967                 }
968         } else 
969         if (!config.invert)
970         {
971                 switch (outframes[0]->get_color_model())
972                 {
973                         case BC_RGB888:
974                                 COMPOSITEIMAGE(unsigned char, 3, );
975                                 break;
976                         case BC_RGBA8888:
977                                 COMPOSITEIMAGE(unsigned char, 4, );
978                                 break;
979                         case BC_YUV888:
980                                 COMPOSITEIMAGE(unsigned char, 3, );
981                                 break;
982                         case BC_YUVA8888:
983                                 COMPOSITEIMAGE(unsigned char, 4, );
984                                 break;
985                         case BC_RGB_FLOAT:
986                                 COMPOSITEIMAGE(float, 3, );
987                                 break;
988                         case BC_RGBA_FLOAT:
989                                 COMPOSITEIMAGE(float, 4, );
990                                 break;
992                         default:
993                                 break;
994                 }
995         } else
996         {
997                 switch (outframes[0]->get_color_model())
998                 {
999                         case BC_RGB888:
1000                                 COMPOSITEIMAGE(unsigned char, 3, config.frame_range -);
1001                                 break;
1002                         case BC_RGBA8888:
1003                                 COMPOSITEIMAGE(unsigned char, 4, config.frame_range -);
1004                                 break;
1005                         case BC_YUV888:
1006                                 COMPOSITEIMAGE(unsigned char, 3, config.frame_range -);
1007                                 break;
1008                         case BC_YUVA8888:
1009                                 COMPOSITEIMAGE(unsigned char, 4, config.frame_range -);
1010                                 break;
1011                         case BC_RGB_FLOAT:
1012                                 COMPOSITEIMAGE(float, 3, config.frame_range -);
1013                                 break;
1014                         case BC_RGBA_FLOAT:
1015                                 COMPOSITEIMAGE(float, 4, config.frame_range -);
1016                                 break;
1018                         default:
1019                                 break;
1020                 }
1021         }
1022         if (config.shape == TimeFrontConfig::ALPHA)
1023         {
1024                 // Set alpha to max
1025                 switch (outframes[0]->get_color_model())
1026                 {
1027                         case BC_YUVA8888:
1028                         case BC_RGBA8888:
1029                                 SETALPHA(unsigned char, 255);
1030                                 break;
1031                         case BC_RGBA_FLOAT:
1032                                 SETALPHA(float, 1.0f);
1033                                 break;
1034                                 
1035                         default:
1036                                 break;
1037                 }
1038         }
1040         delete framelist[0];
1041         if (!config.show_grayscale)
1042         {
1043                 for (int i = 1; i <= config.frame_range; i++) 
1044                         delete framelist[i];
1045         }
1046         return 0;
1050 void TimeFrontMain::update_gui()
1052         if(thread)
1053         {
1054                 if(load_configuration())
1055                 {
1056                         thread->window->lock_window("TimeFrontMain::update_gui");
1057                         thread->window->frame_range->update(config.frame_range);
1058                         thread->window->shape->set_text(TimeFrontShape::to_text(config.shape));
1059                         thread->window->show_grayscale->update(config.show_grayscale);
1060                         thread->window->invert->update(config.invert);
1061                         thread->window->shape->set_text(TimeFrontShape::to_text(config.shape));
1062                         if (thread->window->rate)
1063                                 thread->window->rate->set_text(TimeFrontRate::to_text(config.rate));
1064                         if (thread->window->in_radius)
1065                                 thread->window->in_radius->update(config.in_radius);
1066                         if (thread->window->out_radius)
1067                                 thread->window->out_radius->update(config.out_radius);
1068                         if (thread->window->track_usage)
1069                                 thread->window->track_usage->set_text(TimeFrontTrackUsage::to_text(config.track_usage));
1070                         if(thread->window->angle)
1071                                 thread->window->angle->update(config.angle);
1072                         if(thread->window->center_x)
1073                                 thread->window->center_x->update(config.center_x);
1074                         if(thread->window->center_y)
1075                                 thread->window->center_y->update(config.center_y);
1076                         
1077                         thread->window->update_shape();
1078                         thread->window->unlock_window();
1079                 }
1080         }
1084 int TimeFrontMain::load_defaults()
1086         char directory[1024], string[1024];
1087 // set the default directory
1088         sprintf(directory, "%stimefront.rc", BCASTDIR);
1090 // load the defaults
1091         defaults = new BC_Hash(directory);
1092         defaults->load();
1094 // printf("TimeFrontMain::load_defaults %d %d %d %d\n",
1095 // config.out_r,
1096 // config.out_g,
1097 // config.out_b,
1098 // config.out_a);
1099         config.angle = defaults->get("ANGLE", config.angle);
1100         config.in_radius = defaults->get("IN_RADIUS", config.in_radius);
1101         config.out_radius = defaults->get("OUT_RADIUS", config.out_radius);
1102         config.frame_range = defaults->get("FRAME_RANGE", config.frame_range);
1103         config.shape = defaults->get("SHAPE", config.shape);
1104         config.shape = defaults->get("TRACK_USAGE", config.track_usage);
1105         config.rate = defaults->get("RATE", config.rate);
1106         config.center_x = defaults->get("CENTER_X", config.center_x);
1107         config.center_y = defaults->get("CENTER_Y", config.center_y);
1108         config.invert = defaults->get("INVERT", config.invert);
1109         config.show_grayscale = defaults->get("SHOW_GRAYSCALE", config.show_grayscale);
1110         return 0;
1114 int TimeFrontMain::save_defaults()
1116         defaults->update("ANGLE", config.angle);
1117         defaults->update("IN_RADIUS", config.in_radius);
1118         defaults->update("OUT_RADIUS", config.out_radius);
1119         defaults->update("FRAME_RANGE", config.frame_range);
1120         defaults->update("RATE", config.rate);
1121         defaults->update("SHAPE", config.shape);
1122         defaults->update("TRACK_USAGE", config.track_usage);
1123         defaults->update("CENTER_X", config.center_x);
1124         defaults->update("CENTER_Y", config.center_y);
1125         defaults->update("INVERT", config.invert);
1126         defaults->update("SHOW_GRAYSCALE", config.show_grayscale);
1127         defaults->save();
1128         return 0;
1133 void TimeFrontMain::save_data(KeyFrame *keyframe)
1135         FileXML output;
1137 // cause data to be stored directly in text
1138         output.set_shared_string(keyframe->data, MESSAGESIZE);
1139         output.tag.set_title("TIMEFRONT");
1141         output.tag.set_property("ANGLE", config.angle);
1142         output.tag.set_property("IN_RADIUS", config.in_radius);
1143         output.tag.set_property("OUT_RADIUS", config.out_radius);
1144         output.tag.set_property("FRAME_RANGE", config.frame_range);
1145         output.tag.set_property("SHAPE", config.shape);
1146         output.tag.set_property("TRACK_USAGE", config.track_usage);
1147         output.tag.set_property("RATE", config.rate);
1148         output.tag.set_property("CENTER_X", config.center_x);
1149         output.tag.set_property("CENTER_Y", config.center_y);
1150         output.tag.set_property("INVERT", config.invert);
1151         output.tag.set_property("SHOW_GRAYSCALE", config.show_grayscale);
1152         output.append_tag();
1153         output.terminate_string();
1156 void TimeFrontMain::read_data(KeyFrame *keyframe)
1158         FileXML input;
1160         input.set_shared_string(keyframe->data, strlen(keyframe->data));
1162         int result = 0;
1164         while(!result)
1165         {
1166                 result = input.read_tag();
1168                 if(!result)
1169                 {
1170                         if(input.tag.title_is("TIMEFRONT"))
1171                         {
1172                                 config.angle = input.tag.get_property("ANGLE", config.angle);
1173                                 config.rate = input.tag.get_property("RATE", config.rate);
1174                                 config.in_radius = input.tag.get_property("IN_RADIUS", config.in_radius);
1175                                 config.out_radius = input.tag.get_property("OUT_RADIUS", config.out_radius);
1176                                 config.frame_range = input.tag.get_property("FRAME_RANGE", config.frame_range);
1177                                 config.shape = input.tag.get_property("SHAPE", config.shape);
1178                                 config.track_usage = input.tag.get_property("TRACK_USAGE", config.track_usage);
1179                                 config.center_x = input.tag.get_property("CENTER_X", config.center_x);
1180                                 config.center_y = input.tag.get_property("CENTER_Y", config.center_y);
1181                                 config.invert = input.tag.get_property("INVERT", config.invert);
1182                                 config.show_grayscale = input.tag.get_property("SHOW_GRAYSCALE", config.show_grayscale);
1183                         }
1184                 }
1185         }
1193 TimeFrontPackage::TimeFrontPackage()
1194  : LoadPackage()
1201 TimeFrontUnit::TimeFrontUnit(TimeFrontServer *server, TimeFrontMain *plugin)
1202  : LoadClient(server)
1204         this->plugin = plugin;
1205         this->server = server;
1209 #define SQR(x) ((x) * (x))
1210 #define LOG_RANGE 1
1212 #define CREATE_GRADIENT \
1213 { \
1214 /* Synthesize linear gradient for lookups */ \
1216         a_table = (unsigned char *)malloc(sizeof(unsigned char) * gradient_size); \
1218         for(int i = 0; i < gradient_size; i++) \
1219         { \
1220                 float opacity; \
1221                 float transparency; \
1222                 switch(plugin->config.rate) \
1223                 { \
1224                         case TimeFrontConfig::LINEAR: \
1225                                 if(i < in_radius) \
1226                                         opacity = 0.0; \
1227                                 else \
1228                                 if(i >= out_radius) \
1229                                         opacity = 1.0; \
1230                                 else \
1231                                         opacity = (float)(i - in_radius) / (out_radius - in_radius); \
1232                                 break; \
1233                         case TimeFrontConfig::LOG: \
1234                                 opacity = 1 - exp(LOG_RANGE * -(float)(i - in_radius) / (out_radius - in_radius)); \
1235                                 break; \
1236                         case TimeFrontConfig::SQUARE: \
1237                                 opacity = SQR((float)(i - in_radius) / (out_radius - in_radius)); \
1238                                 break; \
1239                 } \
1241                 CLAMP(opacity, 0, 1); \
1242                 transparency = 1.0 - opacity; \
1243                 a_table[i] = (unsigned char)(out4 * opacity + in4 * transparency); \
1244         } \
1246         for(int i = pkg->y1; i < pkg->y2; i++) \
1247         { \
1248                 unsigned char *out_row = plugin->gradient->get_rows()[i]; \
1250                 switch(plugin->config.shape) \
1251                 { \
1252                         case TimeFrontConfig::LINEAR: \
1253                                 for(int j = 0; j < w; j++) \
1254                                 { \
1255                                         int x = j - half_w; \
1256                                         int y = -(i - half_h); \
1257                  \
1258 /* Rotate by effect angle */ \
1259                                         int input_y = (int)(gradient_size / 2 - \
1260                                                 (x * sin_angle + y * cos_angle) + \
1261                                                 0.5); \
1262                  \
1263 /* Get gradient value from these coords */ \
1264                  \
1265                                         if(input_y < 0) \
1266                                         { \
1267                                                 out_row[0] = out4; \
1268                                         } \
1269                                         else \
1270                                         if(input_y >= gradient_size) \
1271                                         { \
1272                                                 out_row[0] = in4; \
1273                                         } \
1274                                         else \
1275                                         { \
1276                                                 out_row[0] = a_table[input_y]; \
1277                                         } \
1278                  \
1279                                         out_row ++; \
1280                                 } \
1281                                 break; \
1283                         case TimeFrontConfig::RADIAL: \
1284                                 for(int j = 0; j < w; j++) \
1285                                 { \
1286                                         double x = j - center_x; \
1287                                         double y = i - center_y; \
1288                                         double magnitude = hypot(x, y); \
1289                                         int input_y = (int)magnitude; \
1290                                         out_row[0] = a_table[input_y]; \
1291                                         out_row ++; \
1292                                 } \
1293                                 break; \
1294                 } \
1295         } \
1298 void TimeFrontUnit::process_package(LoadPackage *package)
1300         TimeFrontPackage *pkg = (TimeFrontPackage*)package;
1301         int h = plugin->input->get_h();
1302         int w = plugin->input->get_w();
1303         int half_w = w / 2;
1304         int half_h = h / 2;
1305         int gradient_size = (int)(ceil(hypot(w, h)));
1306         int in_radius = (int)(plugin->config.in_radius / 100 * gradient_size);
1307         int out_radius = (int)(plugin->config.out_radius / 100 * gradient_size);
1308         double sin_angle = sin(plugin->config.angle * (M_PI / 180));
1309         double cos_angle = cos(plugin->config.angle * (M_PI / 180));
1310         double center_x = plugin->config.center_x * w / 100;
1311         double center_y = plugin->config.center_y * h / 100;
1312         unsigned char *a_table = 0;
1314         if(in_radius > out_radius)
1315         {
1316             in_radius ^= out_radius;
1317             out_radius ^= in_radius;
1318             in_radius ^= out_radius;
1319         }
1322         int in4 = plugin->config.frame_range;
1323         int out4 = 0;
1324         CREATE_GRADIENT
1326         if(a_table) free(a_table);
1334 TimeFrontServer::TimeFrontServer(TimeFrontMain *plugin, 
1335         int total_clients, 
1336         int total_packages)
1337  : LoadServer(total_clients, total_packages)
1339         this->plugin = plugin;
1342 void TimeFrontServer::init_packages()
1344         for(int i = 0; i < get_total_packages(); i++)
1345         {
1346                 TimeFrontPackage *package = (TimeFrontPackage*)get_package(i);
1347                 package->y1 = plugin->input->get_h() * 
1348                         i / 
1349                         get_total_packages();
1350                 package->y2 = plugin->input->get_h() * 
1351                         (i + 1) /
1352                         get_total_packages();
1353         }
1356 LoadClient* TimeFrontServer::new_client()
1358         return new TimeFrontUnit(this, plugin);
1361 LoadPackage* TimeFrontServer::new_package()
1363         return new TimeFrontPackage;