Merge CV, ver=5.1; ops/methods from HV, and interface from CV where possible
[goodguy/history.git] / cinelerra-5.1 / plugins / timefront / timefront.C
diff --git a/cinelerra-5.1/plugins/timefront/timefront.C b/cinelerra-5.1/plugins/timefront/timefront.C
new file mode 100644 (file)
index 0000000..ead498d
--- /dev/null
@@ -0,0 +1,1337 @@
+
+/*
+ * CINELERRA
+ * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+
+#include <math.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "bcdisplayinfo.h"
+#include "clip.h"
+#include "bchash.h"
+#include "filexml.h"
+#include "timefront.h"
+#include "keyframe.h"
+#include "language.h"
+#include "overlayframe.h"
+#include "vframe.h"
+
+
+
+
+REGISTER_PLUGIN(TimeFrontMain)
+
+
+
+
+
+
+TimeFrontConfig::TimeFrontConfig()
+{
+       angle = 0;
+       in_radius = 0;
+       out_radius = 100;
+       frame_range = 16;
+       track_usage = TimeFrontConfig::OTHERTRACK_INTENSITY;
+       shape = TimeFrontConfig::LINEAR;
+       rate = TimeFrontConfig::LINEAR;
+       center_x = 50;
+       center_y = 50;
+       invert = 0;
+       show_grayscale = 0;
+}
+
+int TimeFrontConfig::equivalent(TimeFrontConfig &that)
+{
+       return (EQUIV(angle, that.angle) &&
+               EQUIV(in_radius, that.in_radius) &&
+               EQUIV(out_radius, that.out_radius) &&
+               frame_range == that.frame_range &&
+               track_usage == that.track_usage &&
+               shape == that.shape &&
+               rate == that.rate &&
+               EQUIV(center_x, that.center_x) &&
+               EQUIV(center_y, that.center_y) && 
+               invert == that.invert &&
+               show_grayscale == that.show_grayscale);
+}
+
+void TimeFrontConfig::copy_from(TimeFrontConfig &that)
+{
+       angle = that.angle;
+       in_radius = that.in_radius;
+       out_radius = that.out_radius;
+       frame_range = that.frame_range;
+       track_usage = that.track_usage;
+       shape = that.shape;
+       rate = that.rate;
+       center_x = that.center_x;
+       center_y = that.center_y;
+       invert = that.invert;
+       show_grayscale = that.show_grayscale;
+}
+
+void TimeFrontConfig::interpolate(TimeFrontConfig &prev, 
+       TimeFrontConfig &next, 
+       long prev_frame, 
+       long next_frame, 
+       long current_frame)
+{
+       double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
+       double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
+
+
+       this->angle = (int)(prev.angle * prev_scale + next.angle * next_scale);
+       this->in_radius = (int)(prev.in_radius * prev_scale + next.in_radius * next_scale);
+       this->out_radius = (int)(prev.out_radius * prev_scale + next.out_radius * next_scale);
+       frame_range = (int)(prev.frame_range * prev_scale + next.frame_range * next_scale);
+       track_usage = prev.track_usage;
+       shape = prev.shape;
+       rate = prev.rate;
+       center_x = prev.center_x * prev_scale + next.center_x * next_scale;
+       center_y = prev.center_y * prev_scale + next.center_y * next_scale;
+       invert = prev.invert;
+       show_grayscale = prev.show_grayscale;
+}
+
+
+
+
+
+
+
+
+TimeFrontWindow::TimeFrontWindow(TimeFrontMain *plugin)
+ : PluginClientWindow(plugin,
+       350, 
+       290, 
+       350, 
+       290, 
+       0)
+{
+       this->plugin = plugin;
+       angle = 0;
+       angle_title = 0;
+       center_x = 0;
+       center_y = 0;
+       center_x_title = 0;
+       center_y_title = 0;
+       rate_title = 0;
+       rate = 0;
+       in_radius_title = 0;
+       in_radius = 0;
+       out_radius_title = 0;
+       out_radius = 0;
+       track_usage_title = 0;
+       track_usage = 0;
+       
+}
+
+TimeFrontWindow::~TimeFrontWindow()
+{
+}
+
+void TimeFrontWindow::create_objects()
+{
+       int x = 10, y = 10;
+       BC_Title *title;
+
+       add_subwindow(title = new BC_Title(x, y, _("Type:")));
+       add_subwindow(shape = new TimeFrontShape(plugin, 
+               this, 
+               x + title->get_w() + 10, 
+               y));
+       shape->create_objects();
+       y += 40;
+       shape_x = x;
+       shape_y = y;
+       y += 140;
+       add_subwindow(title = new BC_Title(x, y, _("Time range:")));
+       add_subwindow(frame_range = new TimeFrontFrameRange(plugin, x + title->get_w() + 10, y));
+       frame_range_x = x + frame_range->get_w() + 10;
+       frame_range_y = y;
+       y += 35;
+       update_shape();
+       
+       add_subwindow(invert = new TimeFrontInvert(plugin, x, y));
+       add_subwindow(show_grayscale = new TimeFrontShowGrayscale(plugin, x+ 100, y));
+
+
+       show_window();
+       flush();
+}
+
+void TimeFrontWindow::update_shape()
+{
+       int x = shape_x, y = shape_y;
+
+       if(plugin->config.shape == TimeFrontConfig::LINEAR)
+       {
+               delete center_x_title;
+               delete center_y_title;
+               delete center_x;
+               delete center_y;
+               delete track_usage_title;
+               delete track_usage;
+               center_x_title = 0;
+               center_y_title = 0;
+               center_x = 0;
+               center_y = 0;
+               track_usage_title = 0;
+               track_usage = 0;
+               if(!angle)
+               {
+                       add_subwindow(angle_title = new BC_Title(x, y, _("Angle:")));
+                       add_subwindow(angle = new TimeFrontAngle(plugin, x + angle_title->get_w() + 10, y));
+               }
+               if(!rate){
+                       y = shape_y + 40;
+       
+                       add_subwindow(rate_title = new BC_Title(x, y, _("Rate:")));
+                       add_subwindow(rate = new TimeFrontRate(plugin,
+                               x + rate_title->get_w() + 10,
+                               y));
+                       rate->create_objects();
+                       y += 40;
+                       add_subwindow(in_radius_title = new BC_Title(x, y, _("Inner radius:")));
+                       add_subwindow(in_radius = new TimeFrontInRadius(plugin, x + in_radius_title->get_w() + 10, y));
+                       y += 30;
+                       add_subwindow(out_radius_title = new BC_Title(x, y, _("Outer radius:")));
+                       add_subwindow(out_radius = new TimeFrontOutRadius(plugin, x + out_radius_title->get_w() + 10, y));
+                       y += 35;
+
+               }
+       } else
+       if(plugin->config.shape == TimeFrontConfig::RADIAL)
+       {
+               delete angle_title;
+               delete angle;
+               delete track_usage_title;
+               delete track_usage;
+               angle_title = 0;
+               angle = 0;
+               track_usage_title = 0;
+               track_usage = 0;
+               if(!center_x)
+               {
+                       add_subwindow(center_x_title = new BC_Title(x, y, _("Center X:")));
+                       add_subwindow(center_x = new TimeFrontCenterX(plugin,
+                               x + center_x_title->get_w() + 10,
+                               y));
+                       x += center_x_title->get_w() + 10 + center_x->get_w() + 10;
+                       add_subwindow(center_y_title = new BC_Title(x, y, _("Center Y:")));
+                       add_subwindow(center_y = new TimeFrontCenterY(plugin,
+                               x + center_y_title->get_w() + 10,
+                               y));
+               }
+               
+               
+               if(!rate)
+               {
+                       y = shape_y + 40;
+                       x = shape_x;
+                       add_subwindow(rate_title = new BC_Title(x, y, _("Rate:")));
+                       add_subwindow(rate = new TimeFrontRate(plugin,
+                               x + rate_title->get_w() + 10,
+                               y));
+                       rate->create_objects();
+                       y += 40;
+                       add_subwindow(in_radius_title = new BC_Title(x, y, _("Inner radius:")));
+                       add_subwindow(in_radius = new TimeFrontInRadius(plugin, x + in_radius_title->get_w() + 10, y));
+                       y += 30;
+                       add_subwindow(out_radius_title = new BC_Title(x, y, _("Outer radius:")));
+                       add_subwindow(out_radius = new TimeFrontOutRadius(plugin, x + out_radius_title->get_w() + 10, y));
+                       y += 35;
+               }
+       } else
+       if(plugin->config.shape == TimeFrontConfig::OTHERTRACK)
+       {
+               delete center_x_title;
+               delete center_y_title;
+               delete center_x;
+               delete center_y;
+               delete angle_title;
+               delete angle;
+               delete rate_title;
+               delete rate;
+               delete in_radius_title;
+               delete in_radius;
+               delete out_radius_title;
+               delete out_radius;
+               center_x_title = 0;
+               center_y_title = 0;
+               center_x = 0;
+               center_y = 0;
+               angle_title = 0;
+               angle = 0;
+               rate_title = 0;
+               rate = 0;
+               in_radius_title = 0;
+               in_radius = 0;
+               out_radius_title = 0;
+               out_radius = 0;
+               if(!track_usage)
+               {
+                       add_subwindow(track_usage_title = new BC_Title(x, y, _("As timefront use:")));
+                       add_subwindow(track_usage = new TimeFrontTrackUsage(plugin,
+                               this,
+                               x + track_usage_title->get_w() + 10,
+                               y));
+                       track_usage->create_objects();
+
+               }
+       } else
+       if(plugin->config.shape == TimeFrontConfig::ALPHA)
+       {
+               delete center_x_title;
+               delete center_y_title;
+               delete center_x;
+               delete center_y;
+               delete angle_title;
+               delete angle;
+               delete rate_title;
+               delete rate;
+               delete in_radius_title;
+               delete in_radius;
+               delete out_radius_title;
+               delete out_radius;
+               delete track_usage_title;
+               delete track_usage;
+               center_x_title = 0;
+               center_y_title = 0;
+               center_x = 0;
+               center_y = 0;
+               angle_title = 0;
+               angle = 0;
+               rate_title = 0;
+               rate = 0;
+               in_radius_title = 0;
+               in_radius = 0;
+               out_radius_title = 0;
+               out_radius = 0;
+               track_usage_title = 0;
+               track_usage = 0;
+
+       }
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+TimeFrontShape::TimeFrontShape(TimeFrontMain *plugin, 
+       TimeFrontWindow *gui, 
+       int x, 
+       int y)
+ : BC_PopupMenu(x, y, 190, to_text(plugin->config.shape), 1)
+{
+       this->plugin = plugin;
+       this->gui = gui;
+}
+void TimeFrontShape::create_objects()
+{
+       add_item(new BC_MenuItem(to_text(TimeFrontConfig::LINEAR)));
+       add_item(new BC_MenuItem(to_text(TimeFrontConfig::RADIAL)));
+       add_item(new BC_MenuItem(to_text(TimeFrontConfig::ALPHA)));
+       add_item(new BC_MenuItem(to_text(TimeFrontConfig::OTHERTRACK)));
+}
+char* TimeFrontShape::to_text(int shape)
+{
+       switch(shape)
+       {
+               case TimeFrontConfig::LINEAR:
+                       return _("Linear");
+               case TimeFrontConfig::OTHERTRACK:
+                       return _("Other track as timefront");
+               case TimeFrontConfig::ALPHA:
+                       return _("Alpha as timefront");
+               default:
+                       return _("Radial");
+       }
+}
+int TimeFrontShape::from_text(char *text)
+{
+       if(!strcmp(text, to_text(TimeFrontConfig::LINEAR))) 
+               return TimeFrontConfig::LINEAR;
+       if(!strcmp(text, to_text(TimeFrontConfig::OTHERTRACK))) 
+               return TimeFrontConfig::OTHERTRACK;
+       if(!strcmp(text, to_text(TimeFrontConfig::ALPHA))) 
+               return TimeFrontConfig::ALPHA;
+       return TimeFrontConfig::RADIAL;
+}
+int TimeFrontShape::handle_event()
+{
+       plugin->config.shape = from_text(get_text());
+       gui->update_shape();
+       plugin->send_configure_change();
+       return 1;
+}
+
+
+TimeFrontTrackUsage::TimeFrontTrackUsage(TimeFrontMain *plugin, 
+       TimeFrontWindow *gui, int x, int y)
+ : BC_PopupMenu(x, y, 140, to_text(plugin->config.track_usage), 1)
+{
+       this->plugin = plugin;
+       this->gui = gui;
+}
+void TimeFrontTrackUsage::create_objects()
+{
+       add_item(new BC_MenuItem(to_text(TimeFrontConfig::OTHERTRACK_INTENSITY)));
+       add_item(new BC_MenuItem(to_text(TimeFrontConfig::OTHERTRACK_ALPHA)));
+}
+char* TimeFrontTrackUsage::to_text(int track_usage)
+{
+       switch(track_usage)
+       {
+               case TimeFrontConfig::OTHERTRACK_INTENSITY:
+                       return _("Intensity");
+               case TimeFrontConfig::OTHERTRACK_ALPHA:
+                       return _("Alpha mask");
+               default:
+                       return _("Unknown");
+       }
+}
+int TimeFrontTrackUsage::from_text(char *text)
+{
+       if(!strcmp(text, to_text(TimeFrontConfig::OTHERTRACK_INTENSITY))) 
+               return TimeFrontConfig::OTHERTRACK_INTENSITY;
+       if(!strcmp(text, to_text(TimeFrontConfig::OTHERTRACK_ALPHA))) 
+               return TimeFrontConfig::OTHERTRACK_ALPHA;
+
+       return TimeFrontConfig::OTHERTRACK_INTENSITY;
+}
+int TimeFrontTrackUsage::handle_event()
+{
+       plugin->config.track_usage = from_text(get_text());
+       gui->update_shape();
+       plugin->send_configure_change();
+       return 1;
+}
+
+
+
+
+TimeFrontCenterX::TimeFrontCenterX(TimeFrontMain *plugin, int x, int y)
+ : BC_FPot(x, y, plugin->config.center_x, 0, 100)
+{
+       this->plugin = plugin;
+}
+int TimeFrontCenterX::handle_event()
+{
+       plugin->config.center_x = get_value();
+       plugin->send_configure_change();
+       return 1;
+}
+
+
+
+TimeFrontCenterY::TimeFrontCenterY(TimeFrontMain *plugin, int x, int y)
+ : BC_FPot(x, y, plugin->config.center_y, 0, 100)
+{
+       this->plugin = plugin;
+}
+
+int TimeFrontCenterY::handle_event()
+{
+       plugin->config.center_y = get_value();
+       plugin->send_configure_change();
+       return 1;
+}
+
+
+
+
+TimeFrontAngle::TimeFrontAngle(TimeFrontMain *plugin, int x, int y)
+ : BC_FPot(x,
+       y,
+       plugin->config.angle,
+       -180,
+       180)
+{
+       this->plugin = plugin;
+}
+
+int TimeFrontAngle::handle_event()
+{
+       plugin->config.angle = get_value();
+       plugin->send_configure_change();
+       return 1;
+}
+
+
+TimeFrontRate::TimeFrontRate(TimeFrontMain *plugin, int x, int y)
+ : BC_PopupMenu(x,
+       y,
+       100,
+       to_text(plugin->config.rate),
+       1)
+{
+       this->plugin = plugin;
+}
+void TimeFrontRate::create_objects()
+{
+       add_item(new BC_MenuItem(to_text(TimeFrontConfig::LINEAR)));
+       add_item(new BC_MenuItem(to_text(TimeFrontConfig::LOG)));
+       add_item(new BC_MenuItem(to_text(TimeFrontConfig::SQUARE)));
+}
+char* TimeFrontRate::to_text(int shape)
+{
+       switch(shape)
+       {
+               case TimeFrontConfig::LINEAR:
+                       return _("Linear");
+               case TimeFrontConfig::LOG:
+                       return _("Log");
+               default:
+                       return _("Square");
+       }
+}
+int TimeFrontRate::from_text(char *text)
+{
+       if(!strcmp(text, to_text(TimeFrontConfig::LINEAR))) 
+               return TimeFrontConfig::LINEAR;
+       if(!strcmp(text, to_text(TimeFrontConfig::LOG)))
+               return TimeFrontConfig::LOG;
+       return TimeFrontConfig::SQUARE;
+}
+int TimeFrontRate::handle_event()
+{
+       plugin->config.rate = from_text(get_text());
+       plugin->send_configure_change();
+       return 1;
+}
+
+
+
+TimeFrontInRadius::TimeFrontInRadius(TimeFrontMain *plugin, int x, int y)
+ : BC_FSlider(x,
+       y,
+       0,
+       200,
+       200,
+       (float)0,
+       (float)100,
+       (float)plugin->config.in_radius)
+{
+       this->plugin = plugin;
+}
+
+int TimeFrontInRadius::handle_event()
+{
+       plugin->config.in_radius = get_value();
+       plugin->send_configure_change();
+       return 1;
+}
+
+
+TimeFrontOutRadius::TimeFrontOutRadius(TimeFrontMain *plugin, int x, int y)
+ : BC_FSlider(x,
+       y,
+       0,
+       200,
+       200,
+       (float)0,
+       (float)100,
+       (float)plugin->config.out_radius)
+{
+       this->plugin = plugin;
+}
+
+int TimeFrontOutRadius::handle_event()
+{
+       plugin->config.out_radius = get_value();
+       plugin->send_configure_change();
+       return 1;
+}
+
+TimeFrontFrameRange::TimeFrontFrameRange(TimeFrontMain *plugin, int x, int y)
+ : BC_ISlider(x,
+       y,
+       0,
+       200,
+       200,
+       (int)1,
+       (int)255,
+       (int)plugin->config.frame_range)
+{
+       this->plugin = plugin;
+}
+
+int TimeFrontFrameRange::handle_event()
+{
+       plugin->config.frame_range = get_value();
+       plugin->send_configure_change();
+       return 1;
+}
+
+
+TimeFrontInvert::TimeFrontInvert(TimeFrontMain *client, int x, int y)
+ : BC_CheckBox(x, 
+       y, 
+       client->config.invert, 
+       _("Inversion"))
+{
+       this->plugin = client;
+}
+
+int TimeFrontInvert::handle_event()
+{
+       plugin->config.invert = get_value();
+       plugin->send_configure_change();
+       return 1;
+}
+
+TimeFrontShowGrayscale::TimeFrontShowGrayscale(TimeFrontMain *client, int x, int y)
+ : BC_CheckBox(x, 
+       y, 
+       client->config.show_grayscale, 
+       _("Show grayscale (for tuning"))
+{
+       this->plugin = client;
+}
+
+int TimeFrontShowGrayscale::handle_event()
+{
+       plugin->config.show_grayscale = get_value();
+       plugin->send_configure_change();
+       return 1;
+}
+
+
+
+TimeFrontMain::TimeFrontMain(PluginServer *server)
+ : PluginVClient(server)
+{
+       
+       need_reconfigure = 1;
+       gradient = 0;
+       engine = 0;
+       overlayer = 0;
+}
+
+TimeFrontMain::~TimeFrontMain()
+{
+       
+
+       if(gradient) delete gradient;
+       if(engine) delete engine;
+       if(overlayer) delete overlayer;
+}
+
+const char* TimeFrontMain::plugin_title() { return _("TimeFront"); }
+int TimeFrontMain::is_realtime() { return 1; }
+int TimeFrontMain::is_multichannel() { return 1; }
+
+
+
+NEW_WINDOW_MACRO(TimeFrontMain, TimeFrontWindow)
+
+LOAD_CONFIGURATION_MACRO(TimeFrontMain, TimeFrontConfig)
+
+int TimeFrontMain::is_synthesis()
+{
+       return 1;
+}
+
+#define GRADIENTFROMAVG(type, inttype, components, maxval) \
+       for(int i = 0; i < tfframe->get_h(); i++) \
+       { \
+               type *in_row = (type *)tfframe->get_rows()[i]; \
+               unsigned char *grad_row = gradient->get_rows()[i]; \
+               for(int j = 0; j < tfframe->get_w(); j++) \
+               { \
+                       inttype tmp =   (inttype) in_row[j * components] + \
+                                                 in_row[j * components + 1] + \
+                                                 in_row[j * components + 2]; \
+                       if (components == 3) \
+                               grad_row[j] = (unsigned char) (CLIP((float)config.frame_range * tmp / maxval / 3, 0.0F, config.frame_range)); \
+                       else if(components == 4) \
+                               grad_row[j] = (unsigned char) (CLIP((float)config.frame_range * tmp * in_row[j * components + 3] / maxval / maxval / 3, 0.0F, config.frame_range)); \
+               } \
+       }
+       
+#define GRADIENTFROMCHANNEL(type, components, max, channel) \
+       for(int i = 0; i < tfframe->get_h(); i++) \
+       { \
+               type *in_row = (type *)tfframe->get_rows()[i]; \
+               unsigned char *grad_row = gradient->get_rows()[i]; \
+               for(int j = 0; j < tfframe->get_w(); j++) \
+               { \
+                       if (components == 3) \
+                               grad_row[j] = (unsigned char) (CLIP((float)config.frame_range * in_row[j * components + channel] / max, 0.0F, config.frame_range)); \
+                       else if(components == 4) \
+                               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)); \
+               } \
+       }
+
+#define SETALPHA(type, max) \
+       for(int i = 0; i < outframes[0]->get_h(); i++) \
+       { \
+               type *out_row = (type *)outframes[0]->get_rows()[i]; \
+               for(int j = 0; j < outframes[0]->get_w(); j++) \
+               { \
+                       out_row[j * 4 + 3] = max; \
+               } \
+       }
+
+#define GRADIENTTOPICTURE(type, inttype, components, max, invertion) \
+       for(int i = 0; i < height; i++) \
+       { \
+               type *out_row = (type *)outframes[0]->get_rows()[i]; \
+               unsigned char *grad_row = gradient->get_rows()[i]; \
+               for (int j = 0; j < width; j++) \
+               { \
+                       out_row[0] = (inttype)max * (invertion grad_row[0]) / config.frame_range; \
+                       out_row[1] = (inttype)max * (invertion grad_row[0]) / config.frame_range; \
+                       out_row[2] = (inttype)max * (invertion grad_row[0]) / config.frame_range; \
+                       if (components == 4) \
+                               out_row[3] = max; \
+                       out_row += components; \
+                       grad_row ++; \
+               } \
+       }
+       
+#define GRADIENTTOYUVPICTURE(type, inttype, components, max, invertion) \
+       for(int i = 0; i < height; i++) \
+       { \
+               type *out_row = (type *)outframes[0]->get_rows()[i]; \
+               unsigned char *grad_row = gradient->get_rows()[i]; \
+               for (int j = 0; j < width; j++) \
+               { \
+                       out_row[0] = (inttype)max * (invertion grad_row[0]) / config.frame_range; \
+                       out_row[1] = max/2; \
+                       out_row[2] = max/2; \
+                       if (components == 4) \
+                               out_row[3] = max; \
+                       out_row += components; \
+                       grad_row ++; \
+               } \
+       }
+
+#define COMPOSITEIMAGE(type, components, invertion) \
+       for (int i = 0; i < height; i++) \
+       { \
+               type *out_row = (type *)outframes[0]->get_rows()[i]; \
+               unsigned char *gradient_row = gradient->get_rows()[i]; \
+               for (int j = 0; j < width; j++) \
+               { \
+                       unsigned int choice = invertion gradient_row[j]; \
+                       { \
+                               out_row[0] = framelist[choice]->get_rows()[i][j * components + 0]; \
+                               out_row[1] = framelist[choice]->get_rows()[i][j * components + 1]; \
+                               out_row[2] = framelist[choice]->get_rows()[i][j * components + 2]; \
+                               if (components == 4) \
+                                       out_row[3] = framelist[choice]->get_rows()[i][j * components + 3]; \
+                       } \
+                       out_row += components; \
+               } \
+       }
+
+
+
+int TimeFrontMain::process_buffer(VFrame **frame,
+               int64_t start_position,
+               double frame_rate)
+//int TimeFrontMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
+{
+       VFrame **outframes = frame;
+       VFrame *(framelist[1024]);
+       framelist[0] = new VFrame (
+               outframes[0]->get_w(),
+               outframes[0]->get_h(),
+               outframes[0]->get_color_model());
+       read_frame(framelist[0],
+               0,
+               start_position,
+               frame_rate,
+               0);
+       this->input = framelist[0];
+       this->output = outframes[0];
+       need_reconfigure |= load_configuration();
+       if (config.shape == TimeFrontConfig::OTHERTRACK)
+       {
+//             this->output = frame[1];
+               if (get_total_buffers() != 2) 
+               {
+                       // FIXME, maybe this should go to some other notification area?
+                       printf(_("ERROR: TimeFront plugin - If you are using another track for timefront, you have to have it under shared effects\n"));
+                       return 0;
+               }
+               if (outframes[0]->get_w() != outframes[1]->get_w() || outframes[0]->get_h() != outframes[1]->get_h())
+               {
+                       printf(_("Sizes of master track and timefront track do not match\n"));
+                       return 0;
+               }
+       }
+
+// Generate new gradient
+       if(need_reconfigure)
+       {
+               need_reconfigure = 0;
+
+               if(!gradient) gradient = new VFrame(
+                       outframes[0]->get_w(),
+                       outframes[0]->get_h(),
+                       BC_A8);
+
+                       
+               if (config.shape != TimeFrontConfig::OTHERTRACK &&
+                   config.shape != TimeFrontConfig::ALPHA)
+               {
+                       if(!engine) engine = new TimeFrontServer(this,
+                               get_project_smp() + 1,
+                               get_project_smp() + 1);
+                       engine->process_packages();
+               }
+               
+       }
+       if (config.shape == TimeFrontConfig::ALPHA)
+       {
+               if(!gradient) gradient = new VFrame(
+                       outframes[0]->get_w(),
+                       outframes[0]->get_h(),
+                       BC_A8);
+               VFrame *tfframe = framelist[0];
+               switch (tfframe->get_color_model())
+               {
+                       case BC_YUVA8888:
+                       case BC_RGBA8888:
+                               GRADIENTFROMCHANNEL(unsigned char, 4, 255, 3);
+
+
+                               break;
+                       case BC_RGBA_FLOAT:
+                               GRADIENTFROMCHANNEL(float, 4, 1.0f, 3);
+                               break;
+                       
+                       default:
+                               {
+                                       printf(_("TimeFront plugin error: ALPHA used, but project color model does not have alpha\n"));
+                                       return 1;
+                                       break;
+                               }
+               }
+
+       } else
+       if (config.shape == TimeFrontConfig::OTHERTRACK)
+       {
+               if(!gradient) gradient = new VFrame(
+                       outframes[0]->get_w(),
+                       outframes[0]->get_h(),
+                       BC_A8);
+               VFrame *tfframe = outframes[1];
+               read_frame(tfframe,
+                       1,
+                       start_position,
+                       frame_rate,
+                       0);
+               if (config.track_usage == TimeFrontConfig::OTHERTRACK_INTENSITY)
+               {
+                       switch (tfframe->get_color_model())
+                       {
+                               case BC_RGBA8888:
+                                       GRADIENTFROMAVG(unsigned char, unsigned short, 4, 255);       // Has to be 2 ranges bigger, sice we need precision for alpha
+                                       break;
+                               case BC_RGB888:
+                                       GRADIENTFROMAVG(unsigned char, unsigned short, 3, 255);
+                                       break;
+                               case BC_RGB_FLOAT:
+                                       GRADIENTFROMAVG(float, float, 3, 1.0f);
+                                       break;
+                               case BC_RGBA_FLOAT:
+                                       GRADIENTFROMAVG(float, float, 4, 1.0f);
+                                       break;
+                               case BC_YUV888:                                                 // We cheat and take Y component as intensity
+                                       GRADIENTFROMCHANNEL(unsigned char, 3, 255, 0);
+                                       break;
+                               case BC_YUVA8888:
+                                       GRADIENTFROMCHANNEL(unsigned char, 4, 255, 0);
+                                       break;
+                               default:
+                                       break;
+                       }
+               } else
+               if (config.track_usage == TimeFrontConfig::OTHERTRACK_ALPHA)
+               {
+                       switch (tfframe->get_color_model())
+                       {
+                               case BC_YUVA8888:
+                               case BC_RGBA8888:
+                                       GRADIENTFROMCHANNEL(unsigned char, 4, 255, 3);
+
+
+                                       break;
+                               case BC_RGBA_FLOAT:
+                                       GRADIENTFROMCHANNEL(float, 4, 1.0f, 3);
+                                       break;
+                               
+                               default:
+                                       {
+                                               printf(_("TimeFront plugin error: ALPHA track used, but project color model does not have alpha\n"));
+                                               return 1;
+                                               break;
+                                       }
+                       }
+               } else
+               {
+                       printf(_("TimeFront plugin error: unsupported track_usage parameter\n"));
+                       return 1;
+               }
+       }       
+
+       if (!config.show_grayscale)
+       {
+               for (int i = 1; i <= config.frame_range; i++) 
+               {
+                       framelist[i] = new VFrame (
+                               outframes[0]->get_w(), 
+                               outframes[0]->get_h(), 
+                               outframes[0]->get_color_model());
+
+                       read_frame(framelist[i],
+                               0,
+                               start_position - i,
+                               frame_rate,
+                               0);
+               }
+       }
+       
+
+       int width = outframes[0]->get_w();
+       int height = outframes[0]->get_h();
+       if (config.show_grayscale)
+       {
+               if (!config.invert)
+               {
+                       switch (outframes[0]->get_color_model())
+                       {
+                               case BC_RGB888:
+                                       GRADIENTTOPICTURE(unsigned char, unsigned short, 3, 255, );
+                                       break;
+                               case BC_RGBA8888:
+                                       GRADIENTTOPICTURE(unsigned char, unsigned short, 4, 255, );
+                                       break;
+                               case BC_YUV888:
+                                       GRADIENTTOYUVPICTURE(unsigned char, unsigned short, 3, 255, );
+                                       break;
+                               case BC_YUVA8888:
+                                       GRADIENTTOYUVPICTURE(unsigned char, unsigned short, 4, 255, );
+                                       break;
+                               case BC_RGB_FLOAT:
+                                       GRADIENTTOPICTURE(float, float, 3, 1.0f, );
+                                       break;
+                               case BC_RGBA_FLOAT:
+                                       GRADIENTTOPICTURE(float, float, 4, 1.0f, );
+                                       break;
+                               default:
+                                       break;
+                       }
+               } else
+               {
+                       switch (outframes[0]->get_color_model())
+                       {
+                               case BC_RGB888:
+                                       GRADIENTTOPICTURE(unsigned char, unsigned short, 3, 255, config.frame_range -);
+                                       break;
+                               case BC_RGBA8888:
+                                       GRADIENTTOPICTURE(unsigned char, unsigned short, 4, 255, config.frame_range -);
+                                       break;
+                               case BC_YUV888:
+                                       GRADIENTTOYUVPICTURE(unsigned char, unsigned short, 3, 255, config.frame_range -);
+                                       break;
+                               case BC_YUVA8888:
+                                       GRADIENTTOYUVPICTURE(unsigned char, unsigned short, 4, 255, config.frame_range -);
+                                       break;
+                               case BC_RGB_FLOAT:
+                                       GRADIENTTOPICTURE(float, float, 3, 1.0f, config.frame_range -);
+                                       break;
+                               case BC_RGBA_FLOAT:
+                                       GRADIENTTOPICTURE(float, float, 4, 1.0f, config.frame_range -);
+                                       break;
+                               default:
+                                       break;
+                       }
+               }
+       } else 
+       if (!config.invert)
+       {
+               switch (outframes[0]->get_color_model())
+               {
+                       case BC_RGB888:
+                               COMPOSITEIMAGE(unsigned char, 3, );
+                               break;
+                       case BC_RGBA8888:
+                               COMPOSITEIMAGE(unsigned char, 4, );
+                               break;
+                       case BC_YUV888:
+                               COMPOSITEIMAGE(unsigned char, 3, );
+                               break;
+                       case BC_YUVA8888:
+                               COMPOSITEIMAGE(unsigned char, 4, );
+                               break;
+                       case BC_RGB_FLOAT:
+                               COMPOSITEIMAGE(float, 3, );
+                               break;
+                       case BC_RGBA_FLOAT:
+                               COMPOSITEIMAGE(float, 4, );
+                               break;
+
+                       default:
+                               break;
+               }
+       } else
+       {
+               switch (outframes[0]->get_color_model())
+               {
+                       case BC_RGB888:
+                               COMPOSITEIMAGE(unsigned char, 3, config.frame_range -);
+                               break;
+                       case BC_RGBA8888:
+                               COMPOSITEIMAGE(unsigned char, 4, config.frame_range -);
+                               break;
+                       case BC_YUV888:
+                               COMPOSITEIMAGE(unsigned char, 3, config.frame_range -);
+                               break;
+                       case BC_YUVA8888:
+                               COMPOSITEIMAGE(unsigned char, 4, config.frame_range -);
+                               break;
+                       case BC_RGB_FLOAT:
+                               COMPOSITEIMAGE(float, 3, config.frame_range -);
+                               break;
+                       case BC_RGBA_FLOAT:
+                               COMPOSITEIMAGE(float, 4, config.frame_range -);
+                               break;
+
+                       default:
+                               break;
+               }
+       }
+       if (config.shape == TimeFrontConfig::ALPHA)
+       {
+               // Set alpha to max
+               switch (outframes[0]->get_color_model())
+               {
+                       case BC_YUVA8888:
+                       case BC_RGBA8888:
+                               SETALPHA(unsigned char, 255);
+                               break;
+                       case BC_RGBA_FLOAT:
+                               SETALPHA(float, 1.0f);
+                               break;
+                               
+                       default:
+                               break;
+               }
+       }
+
+       delete framelist[0];
+       if (!config.show_grayscale)
+       {
+               for (int i = 1; i <= config.frame_range; i++) 
+                       delete framelist[i];
+       }
+       return 0;
+}
+
+
+void TimeFrontMain::update_gui()
+{
+       if(thread)
+       {
+               if(load_configuration())
+               {
+                       thread->window->lock_window("TimeFrontMain::update_gui");
+                       ((TimeFrontWindow*)thread->window)->frame_range->update(config.frame_range);
+                       ((TimeFrontWindow*)thread->window)->shape->set_text(TimeFrontShape::to_text(config.shape));
+                       ((TimeFrontWindow*)thread->window)->show_grayscale->update(config.show_grayscale);
+                       ((TimeFrontWindow*)thread->window)->invert->update(config.invert);
+                       ((TimeFrontWindow*)thread->window)->shape->set_text(TimeFrontShape::to_text(config.shape));
+                       if (((TimeFrontWindow*)thread->window)->rate)
+                               ((TimeFrontWindow*)thread->window)->rate->set_text(TimeFrontRate::to_text(config.rate));
+                       if (((TimeFrontWindow*)thread->window)->in_radius)
+                               ((TimeFrontWindow*)thread->window)->in_radius->update(config.in_radius);
+                       if (((TimeFrontWindow*)thread->window)->out_radius)
+                               ((TimeFrontWindow*)thread->window)->out_radius->update(config.out_radius);
+                       if (((TimeFrontWindow*)thread->window)->track_usage)
+                               ((TimeFrontWindow*)thread->window)->track_usage->set_text(TimeFrontTrackUsage::to_text(config.track_usage));
+                       if(((TimeFrontWindow*)thread->window)->angle)
+                               ((TimeFrontWindow*)thread->window)->angle->update(config.angle);
+                       if(((TimeFrontWindow*)thread->window)->center_x)
+                               ((TimeFrontWindow*)thread->window)->center_x->update(config.center_x);
+                       if(((TimeFrontWindow*)thread->window)->center_y)
+                               ((TimeFrontWindow*)thread->window)->center_y->update(config.center_y);
+                       
+                       ((TimeFrontWindow*)thread->window)->update_shape();
+                       thread->window->unlock_window();
+               }
+       }
+}
+
+
+
+
+void TimeFrontMain::save_data(KeyFrame *keyframe)
+{
+       FileXML output;
+
+// cause data to be stored directly in text
+       output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
+       output.tag.set_title("TIMEFRONT");
+
+       output.tag.set_property("ANGLE", config.angle);
+       output.tag.set_property("IN_RADIUS", config.in_radius);
+       output.tag.set_property("OUT_RADIUS", config.out_radius);
+       output.tag.set_property("FRAME_RANGE", config.frame_range);
+       output.tag.set_property("SHAPE", config.shape);
+       output.tag.set_property("TRACK_USAGE", config.track_usage);
+       output.tag.set_property("RATE", config.rate);
+       output.tag.set_property("CENTER_X", config.center_x);
+       output.tag.set_property("CENTER_Y", config.center_y);
+       output.tag.set_property("INVERT", config.invert);
+       output.tag.set_property("SHOW_GRAYSCALE", config.show_grayscale);
+       output.append_tag();
+       output.tag.set_title("/TIMEFRONT");
+       output.append_tag();
+       output.append_newline();
+       output.terminate_string();
+}
+
+void TimeFrontMain::read_data(KeyFrame *keyframe)
+{
+       FileXML input;
+
+       input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
+
+       int result = 0;
+
+       while(!result)
+       {
+               result = input.read_tag();
+
+               if(!result)
+               {
+                       if(input.tag.title_is("TIMEFRONT"))
+                       {
+                               config.angle = input.tag.get_property("ANGLE", config.angle);
+                               config.rate = input.tag.get_property("RATE", config.rate);
+                               config.in_radius = input.tag.get_property("IN_RADIUS", config.in_radius);
+                               config.out_radius = input.tag.get_property("OUT_RADIUS", config.out_radius);
+                               config.frame_range = input.tag.get_property("FRAME_RANGE", config.frame_range);
+                               config.shape = input.tag.get_property("SHAPE", config.shape);
+                               config.track_usage = input.tag.get_property("TRACK_USAGE", config.track_usage);
+                               config.center_x = input.tag.get_property("CENTER_X", config.center_x);
+                               config.center_y = input.tag.get_property("CENTER_Y", config.center_y);
+                               config.invert = input.tag.get_property("INVERT", config.invert);
+                               config.show_grayscale = input.tag.get_property("SHOW_GRAYSCALE", config.show_grayscale);
+                       }
+               }
+       }
+}
+
+
+
+
+
+
+TimeFrontPackage::TimeFrontPackage()
+ : LoadPackage()
+{
+}
+
+
+
+
+TimeFrontUnit::TimeFrontUnit(TimeFrontServer *server, TimeFrontMain *plugin)
+ : LoadClient(server)
+{
+       this->plugin = plugin;
+       this->server = server;
+}
+
+
+#define LOG_RANGE 1
+
+#define CREATE_GRADIENT \
+{ \
+/* Synthesize linear gradient for lookups */ \
+ \
+       a_table = (unsigned char *)malloc(sizeof(unsigned char) * gradient_size); \
+ \
+       for(int i = 0; i < gradient_size; i++) \
+       { \
+               float opacity = 0.0; \
+               switch(plugin->config.rate) \
+               { \
+                       case TimeFrontConfig::LINEAR: \
+                               if(i < in_radius) \
+                                       opacity = 0.0; \
+                               else \
+                               if(i >= out_radius) \
+                                       opacity = 1.0; \
+                               else \
+                                       opacity = (float)(i - in_radius) / (out_radius - in_radius); \
+                               break; \
+                       case TimeFrontConfig::LOG: \
+                               opacity = 1 - exp(LOG_RANGE * -(float)(i - in_radius) / (out_radius - in_radius)); \
+                               break; \
+                       case TimeFrontConfig::SQUARE: \
+                               opacity = SQR((float)(i - in_radius) / (out_radius - in_radius)); \
+                               break; \
+               } \
+ \
+               CLAMP(opacity, 0, 1); \
+               float transparency = 1.0 - opacity; \
+               a_table[i] = (unsigned char)(out4 * opacity + in4 * transparency); \
+       } \
+ \
+       for(int i = pkg->y1; i < pkg->y2; i++) \
+       { \
+               unsigned char *out_row = plugin->gradient->get_rows()[i]; \
+ \
+               switch(plugin->config.shape) \
+               { \
+                       case TimeFrontConfig::LINEAR: \
+                               for(int j = 0; j < w; j++) \
+                               { \
+                                       int x = j - half_w; \
+                                       int y = -(i - half_h); \
+                \
+/* Rotate by effect angle */ \
+                                       int input_y = (int)(gradient_size / 2 - \
+                                               (x * sin_angle + y * cos_angle) + \
+                                               0.5); \
+                \
+/* Get gradient value from these coords */ \
+                \
+                                       if(input_y < 0) \
+                                       { \
+                                               out_row[0] = out4; \
+                                       } \
+                                       else \
+                                       if(input_y >= gradient_size) \
+                                       { \
+                                               out_row[0] = in4; \
+                                       } \
+                                       else \
+                                       { \
+                                               out_row[0] = a_table[input_y]; \
+                                       } \
+                \
+                                       out_row ++; \
+                               } \
+                               break; \
+ \
+                       case TimeFrontConfig::RADIAL: \
+                               for(int j = 0; j < w; j++) \
+                               { \
+                                       double x = j - center_x; \
+                                       double y = i - center_y; \
+                                       double magnitude = hypot(x, y); \
+                                       int input_y = (int)magnitude; \
+                                       out_row[0] = a_table[input_y]; \
+                                       out_row ++; \
+                               } \
+                               break; \
+               } \
+       } \
+}
+
+void TimeFrontUnit::process_package(LoadPackage *package)
+{
+       TimeFrontPackage *pkg = (TimeFrontPackage*)package;
+       int h = plugin->input->get_h();
+       int w = plugin->input->get_w();
+       int half_w = w / 2;
+       int half_h = h / 2;
+       int gradient_size = (int)(ceil(hypot(w, h)));
+       int in_radius = (int)(plugin->config.in_radius / 100 * gradient_size);
+       int out_radius = (int)(plugin->config.out_radius / 100 * gradient_size);
+       double sin_angle = sin(plugin->config.angle * (M_PI / 180));
+       double cos_angle = cos(plugin->config.angle * (M_PI / 180));
+       double center_x = plugin->config.center_x * w / 100;
+       double center_y = plugin->config.center_y * h / 100;
+       unsigned char *a_table = 0;
+
+       if(in_radius > out_radius)
+       {
+           in_radius ^= out_radius;
+           out_radius ^= in_radius;
+           in_radius ^= out_radius;
+       }
+
+
+       int in4 = plugin->config.frame_range;
+       int out4 = 0;
+       CREATE_GRADIENT
+
+       if(a_table) free(a_table);
+}
+
+
+
+
+
+
+TimeFrontServer::TimeFrontServer(TimeFrontMain *plugin, 
+       int total_clients, 
+       int total_packages)
+ : LoadServer(total_clients, total_packages)
+{
+       this->plugin = plugin;
+}
+
+void TimeFrontServer::init_packages()
+{
+       for(int i = 0; i < get_total_packages(); i++)
+       {
+               TimeFrontPackage *package = (TimeFrontPackage*)get_package(i);
+               package->y1 = plugin->input->get_h() * 
+                       i / 
+                       get_total_packages();
+               package->y2 = plugin->input->get_h() * 
+                       (i + 1) /
+                       get_total_packages();
+       }
+}
+
+LoadClient* TimeFrontServer::new_client()
+{
+       return new TimeFrontUnit(this, plugin);
+}
+
+LoadPackage* TimeFrontServer::new_package()
+{
+       return new TimeFrontPackage;
+}
+
+
+
+
+