[gimp-gap] implemented acceleration charactersitics for MovePath #607927



commit 78e398d7fa7a98c9315d589fbde636e17e0925cb
Author: Wolfgang Hofer <wolfgangh svn gnome org>
Date:   Sun Feb 7 12:34:20 2010 +0100

    implemented acceleration charactersitics for MovePath #607927

 ChangeLog            |   13 +
 gap/Makefile.am      |    4 +
 gap/gap_accel_char.c |   82 +++++
 gap/gap_accel_char.h |   48 +++
 gap/gap_accel_da.c   |  224 +++++++++++++
 gap/gap_accel_da.h   |   50 +++
 gap/gap_mov_dialog.c |  497 +++++++++++++++++++++++++++--
 gap/gap_mov_dialog.h |   20 ++-
 gap/gap_mov_exec.c   |  861 ++++++++++++++++++++++++++++++++++++++++++++------
 9 files changed, 1673 insertions(+), 126 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 9b5d4d7..0fa5428 100755
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2010-02-07 Wolfgang Hofer <hof gimp org>
+
+- implementation for acceleration characteristic support im MovePath
+  (as suggested in #607927)
+  
+  * gap/gap_accel_char.c [.h]  # NEW files
+  * gap/gap_accel_da.c [.h]    # NEW files
+  * gap/Makefile.am
+
+  * gap/gap_mov_exec.c
+  * gap/gap_mov_dialog.c [.h]
+
+
 2010-01-16 Wolfgang Hofer <hof gimp org>
 - applied patch provided at #607040 that fixes the crash when selcting
    controlpoint color.
diff --git a/gap/Makefile.am b/gap/Makefile.am
index c2b8b2f..0a8bb9a 100644
--- a/gap/Makefile.am
+++ b/gap/Makefile.am
@@ -34,6 +34,10 @@ noinst_LIBRARIES = $(LIBGIMPGAP) $(LIBGAPSTORY)
 
 BASE_SOURCES = \
 	gap-intl.h		\
+	gap_accel_char.c	\
+	gap_accel_char.h	\
+	gap_accel_da.c		\
+	gap_accel_da.h		\
 	gap_arr_dialog.c	\
 	gap_arr_dialog.h	\
 	gap_audio_util.c	\
diff --git a/gap/gap_accel_char.c b/gap/gap_accel_char.c
new file mode 100644
index 0000000..9ff6fe9
--- /dev/null
+++ b/gap/gap_accel_char.c
@@ -0,0 +1,82 @@
+/*  gap_accel_char.c
+ *
+ *  This module handles GAP acceleration characteristics calculation.
+ */
+/* The GIMP -- an image manipulation program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * 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.
+ */
+
+/* revision history:
+ * version 2.7.0; 2010/02/06  hof: created
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <gtk/gtk.h>
+#include <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+#include "gap_accel_char.h"
+
+
+/* ---------------------------------------
+ * gap_accelMixFactor
+ * ---------------------------------------
+ * this proecdure implements hardcoded acceleration characteristics.
+ *     
+ * accelCharacteristic: 
+ *  0 is used to turn off acceleration
+ *  1 specified constant speed
+ *
+ * positive values > 1 represent acceleration, 
+ + negative values < -1  for deceleration
+ *
+ * orig_factor: a positive gdouble in the range 0.0 to 1.0
+ * returns modified mix_factor in the range 0.0 to 1.0 according to specified accelCharacteristic
+ * the returned value is equal to orig_factor for accelCharacteristic -1, 0 amd 1
+ */
+gdouble 
+gap_accelMixFactor(gdouble orig_factor, gint accelCharacteristic)
+{
+  gdouble mix;
+  gdouble accelPower;
+  
+  switch (accelCharacteristic)
+  {
+    case 0:
+    case 1:
+    case -1:
+      mix = orig_factor;
+      break;
+    default:
+      if (accelCharacteristic > 0)
+      {
+        accelPower = 1 + ((accelCharacteristic -1) / 10.0);
+        mix = pow(orig_factor, accelPower);
+      }
+      else
+      {
+        accelPower = 1 + (((0 - accelCharacteristic) -1) / 10.0);
+        mix = 1.0 - pow((1.0 - orig_factor), accelPower);
+      }
+      break;
+  }
+
+  return (mix);  
+}  /* end gap_accelMixFactor */
diff --git a/gap/gap_accel_char.h b/gap/gap_accel_char.h
new file mode 100644
index 0000000..5249748
--- /dev/null
+++ b/gap/gap_accel_char.h
@@ -0,0 +1,48 @@
+/*  gap_accel_char.h
+ *
+ *  This module handles GAP acceleration characteristics calculation.
+ */
+/* The GIMP -- an image manipulation program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * 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.
+ */
+
+/* revision history:
+ * version 2.7.0; 2010/02/06  hof: created
+ */
+
+#ifndef _GAP_ACCEL_CHAR_H
+#define _GAP_ACCEL_CHAR_H
+
+#include <gtk/gtk.h>
+#include <libgimp/gimp.h>
+
+
+/* ---------------------------------------
+ * gap_accelMixFactor
+ * ---------------------------------------
+ * this proecdure implements hardcoded acceleration characteristics.
+ *     
+ * accelCharacteristic: 0 and 1 for linear, positive values for acceleration, negative values for deceleration
+ *
+ * orig_factor: a positive gdouble in the range 0.0 to 1.0
+ * returns modified mix_factor in the range 0.0 to 1.0 according to specified accelCharacteristic
+ */
+gdouble 
+gap_accelMixFactor(gdouble orig_factor, gint accelCharacteristic);
+
+
+#endif
diff --git a/gap/gap_accel_da.c b/gap/gap_accel_da.c
new file mode 100644
index 0000000..54d1281
--- /dev/null
+++ b/gap/gap_accel_da.c
@@ -0,0 +1,224 @@
+/*  gap_accel_da.c
+ *
+ *  This module handles GAP acceleration characteristics drawing area.
+ */
+/* The GIMP -- an image manipulation program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * 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.
+ */
+
+/* revision history:
+ * version 2.7.0; 2010/02/06  hof: created
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <gtk/gtk.h>
+#include <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+#include "gap_accel_char.h"
+#include "gap_accel_da.h"
+#include "gap-intl.h"
+#include "gap_lib_common_defs.h"
+
+
+extern int gap_debug;  /* 1 == print debug infos , 0 dont print debug infos */
+
+
+#define MIX_CHANNEL(b, a, m)  (((a * m) + (b * (255 - m))) / 255)
+#define PREVIEW_BG_GRAY1 80
+#define PREVIEW_BG_GRAY2 180
+
+#define PREVIEW_BG_GRAY1_GDK 0x505050
+#define PREVIEW_BG_GRAY2_GDK 0xb4b4b4
+
+
+#define GRAPH_RADIUS           3
+
+
+static gint  gap_accel_repaint (GtkWidget *, GdkEvent *,
+                                GapAccelWidget *);
+
+/* ------------------------------
+ * gap_pview_new
+ * ------------------------------
+ * pv_check_size is checkboard size in pixels
+ * (for transparent pixels)
+ */
+GapAccelWidget *
+gap_accel_new(gint width, gint height, gint accelerationCharacteristic)
+{
+  GapAccelWidget *accel_ptr;
+  
+ 
+  accel_ptr = g_malloc0(sizeof(GapAccelWidget));
+
+  accel_ptr->accelerationCharacteristic = accelerationCharacteristic;
+  accel_ptr->width = width;
+  accel_ptr->height = height;
+  accel_ptr->pixWidth = accel_ptr->width + GRAPH_RADIUS * 4;
+  accel_ptr->pixHeight = accel_ptr->height+ GRAPH_RADIUS * 4;
+
+
+  accel_ptr->da_widget = gtk_drawing_area_new ();
+  gtk_widget_set_size_request (accel_ptr->da_widget
+                              , accel_ptr->pixWidth
+                              , accel_ptr->pixHeight
+                              );
+
+  gtk_widget_set_events (accel_ptr->da_widget, GDK_EXPOSURE_MASK);
+
+/*
+  gtk_container_add (GTK_CONTAINER (abox), accel_ptr->da_widget);
+  gtk_widget_show (accel_ptr->da_widget);
+*/
+
+  g_signal_connect (accel_ptr->da_widget, "event",
+                    G_CALLBACK (gap_accel_repaint),
+                    accel_ptr);
+
+
+
+
+  return(accel_ptr);
+}  /* end gap_pview_new */
+
+
+
+/* ------------------------------
+ * gap_accel_render
+ * ------------------------------
+ */
+void
+gap_accel_render (GapAccelWidget *accel_ptr, gint accelerationCharacteristic)
+{
+  accel_ptr->accelerationCharacteristic = accelerationCharacteristic;
+  gap_accel_repaint(NULL, NULL, accel_ptr);
+}
+
+/* ------------------------------
+ * gap_accel_repaint
+ * ------------------------------
+ */
+static gint
+gap_accel_repaint(GtkWidget *wgt, GdkEvent *evt,
+  GapAccelWidget *accel_ptr)
+{
+  GtkStyle *graph_style;
+  gint      i;
+
+  if(accel_ptr->da_widget == NULL)
+  {
+     if(gap_debug)
+     {
+       printf("gap_accel_repaint: drawing area graph is NULL (render request ignored\n");
+     }
+     return (FALSE);
+  }
+  if(accel_ptr->da_widget->window == NULL)
+  {
+     if(gap_debug)
+     {
+       printf("gap_accel_repaint: window pointer is NULL (render request ignored\n");
+     }
+     return (FALSE);
+  }
+
+  
+  graph_style = gtk_widget_get_style (accel_ptr->da_widget);
+  
+  
+  /*  Clear the pixmap  */
+  gdk_draw_rectangle (accel_ptr->da_widget->window, graph_style->bg_gc[GTK_STATE_NORMAL],
+                      TRUE, 0, 0, accel_ptr->pixWidth, accel_ptr->pixHeight);
+
+
+  /*  Draw the grid lines (or just outline if acceleration is not active */
+  for (i = 0; i < 5; i++)
+  {
+      if ((i == 0) || (i==4) || (accel_ptr->accelerationCharacteristic != 0))
+      {
+        gdouble xf;
+        gdouble yf;
+        gint    xi;
+        gint    yi;
+        
+        xf = (gdouble)i * ((gdouble)accel_ptr->width / 4.0);
+        yf = (gdouble)i * ((gdouble)accel_ptr->height / 4.0);
+        xi = xf;
+        yi = yf;
+        
+        gdk_draw_line (accel_ptr->da_widget->window, graph_style->dark_gc[GTK_STATE_NORMAL],
+                     GRAPH_RADIUS, yi + GRAPH_RADIUS,
+                     accel_ptr->width + GRAPH_RADIUS, yi + GRAPH_RADIUS);
+        gdk_draw_line (accel_ptr->da_widget->window, graph_style->dark_gc[GTK_STATE_NORMAL],
+                     xi + GRAPH_RADIUS, GRAPH_RADIUS,
+                     xi + GRAPH_RADIUS, accel_ptr->height + GRAPH_RADIUS);
+
+      }
+  }
+
+ 
+  /*  Draw the the acceleration curve according to accelerationCharacteristic
+   *  when acceleration is active 
+   */
+  if(accel_ptr->accelerationCharacteristic != 0)
+  {
+       gdouble xFactor;
+       gdouble yFactor;
+       gdouble yF;
+       
+       /*  Draw the active curve  */
+       for (i = 0; i < accel_ptr->width; i++)
+       {
+           gint cx, cy, px, py;
+         
+           xFactor = (gdouble)i / (MAX(1.0, (gdouble)accel_ptr->width));
+           yFactor = gap_accelMixFactor(xFactor,  accel_ptr->accelerationCharacteristic);
+           yF = (gdouble)accel_ptr->height * yFactor;
+
+
+           cx = i + GRAPH_RADIUS;
+           cy = (accel_ptr->height) - yF  + GRAPH_RADIUS;
+           
+           if(gap_debug)
+           {
+             printf("point[%03d] x:%04d y:%04d  xf:%f yf:%f\n"
+               ,(int)i
+               ,(int)cx
+               ,(int)cy
+               ,(float)xFactor
+               ,(float)yFactor
+               );
+           }
+           if(i>0)
+           {
+              gdk_draw_line (accel_ptr->da_widget->window, graph_style->black_gc,
+                     px, py,
+                     cx, cy
+                     );
+           }
+           px = cx;
+           py = cy;
+       }
+  }
+
+  return FALSE;
+
+}  /* end gap_accel_repaint */
diff --git a/gap/gap_accel_da.h b/gap/gap_accel_da.h
new file mode 100644
index 0000000..546da08
--- /dev/null
+++ b/gap/gap_accel_da.h
@@ -0,0 +1,50 @@
+/*  gap_accel_da.h
+ *
+ *  This module handles GAP acceleration characteristics drawing area.
+ */
+/* The GIMP -- an image manipulation program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * 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.
+ */
+
+/* revision history:
+ * version 2.7.0; 2010/02/06  hof: created
+ */
+
+#ifndef _GAP_ACCEL_DA_H
+#define _GAP_ACCEL_DA_H
+
+#include <gtk/gtk.h>
+#include <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+
+
+typedef struct GapAccelWidget
+{
+  GtkWidget *da_widget;                    /* the graph drawing_area */
+  gint       accelerationCharacteristic;
+  gint       width;
+  gint       height;
+  gint       pixWidth;
+  gint       pixHeight;
+  
+} GapAccelWidget;
+
+GapAccelWidget   *gap_accel_new(gint width, gint height, gint accelerationCharacteristic);
+
+void       gap_accel_render (GapAccelWidget *accel_ptr, gint accelerationCharacteristic);
+
+#endif
diff --git a/gap/gap_mov_dialog.c b/gap/gap_mov_dialog.c
index 5d2dbb9..675ba49 100755
--- a/gap/gap_mov_dialog.c
+++ b/gap/gap_mov_dialog.c
@@ -125,6 +125,7 @@
 #include "gap_arr_dialog.h"
 
 #include "gap_pview_da.h"
+#include "gap_accel_da.h"
 #include "gap_stock.h"
 
 
@@ -220,6 +221,14 @@ typedef struct
   GtkAdjustment *trace_opacity_initial_adj;
   GtkAdjustment *trace_opacity_desc_adj;
   GtkAdjustment *tween_steps_adj;
+  
+  GtkAdjustment *accPosition_adj;
+  GtkAdjustment *accOpacity_adj;
+  GtkAdjustment *accSize_adj;
+  GtkAdjustment *accRotation_adj;
+  GtkAdjustment *accPerspective_adj;
+  GtkAdjustment *accSelFeatherRadius_adj;
+
 
   gchar          point_index_text[POINT_INDEX_LABEL_LENGTH];
   GtkWidget     *point_index_frame;
@@ -238,6 +247,14 @@ typedef struct
   gdouble        tbry;     /* 0.0 upto 10.0 transform y bot right */
   gdouble        sel_feather_radius;
 
+  /* acceleration characteristics */
+  gint           accPosition;
+  gint           accOpacity;
+  gint           accSize;
+  gint           accRotation;
+  gint           accPerspective;
+  gint           accSelFeatherRadius;
+
   gint           keyframe_abs;
   gint           max_frame;
 
@@ -266,6 +283,8 @@ typedef struct
 
        long        gap_mov_dlg_move_dialog             (GapMovData *mov_ptr);
 static void        p_update_point_index_text (t_mov_gui_stuff *mgp);
+static void        p_set_sensitivity_by_adjustment(GtkAdjustment *adj, gboolean sensitive);
+static void        p_accel_widget_sensitivity(t_mov_gui_stuff *mgp);
 static void        p_points_from_tab         (t_mov_gui_stuff *mgp);
 static void        p_points_to_tab           (t_mov_gui_stuff *mgp);
 static void        p_point_refresh           (t_mov_gui_stuff *mgp);
@@ -283,6 +302,7 @@ static gint        mov_dialog ( GimpDrawable *drawable, t_mov_gui_stuff *mgp,
                                 gint min, gint max);
 static GtkWidget * mov_modify_tab_create (t_mov_gui_stuff *mgp);
 static GtkWidget * mov_trans_tab_create  (t_mov_gui_stuff *mgp);
+static GtkWidget * mov_acc_tab_create  (t_mov_gui_stuff *mgp);
 static GtkWidget * mov_selection_handling_tab_create (t_mov_gui_stuff *mgp);
 
 static void        mov_path_prevw_create ( GimpDrawable *drawable,
@@ -302,9 +322,11 @@ static void        mov_instant_double_adjustment_update (GtkObject *obj, gpointe
 static void        mov_path_colorbutton_update ( GimpColorButton *widget, t_mov_gui_stuff *mgp);
 static void        mov_path_keycolorbutton_clicked ( GimpColorButton *widget, t_mov_gui_stuff *mgp);
 static void        mov_path_keycolorbutton_changed ( GimpColorButton *widget, t_mov_gui_stuff *mgp);
+static void        mov_path_keyframe_update ( GtkWidget *widget, t_mov_gui_stuff *mgp );
 static void        mov_path_x_adjustment_update ( GtkWidget *widget, gpointer data );
 static void        mov_path_y_adjustment_update ( GtkWidget *widget, gpointer data );
 static void        mov_path_tfactor_adjustment_update( GtkWidget *widget, gdouble *val);
+static void        mov_path_acceleration_adjustment_update( GtkWidget *widget, gint *val);
 static void        mov_path_feather_adjustment_update( GtkWidget *widget, gdouble *val );
 static void        mov_selmode_menu_callback (GtkWidget *widget, t_mov_gui_stuff *mgp);
 
@@ -395,6 +417,25 @@ p_mov_spinbutton_new(GtkTable *table
                     ,gchar    *tooltip_text
                     ,gchar    *privatetip
                     );
+GtkObject *
+p_mov_acc_spinbutton_new(GtkTable *table
+                    ,gint      col
+                    ,gint      row
+                    ,gchar    *label_text
+                    ,gint      scale_width      /* dummy, not used */
+                    ,gint      spinbutton_width
+                    ,gdouble   initial_val
+                    ,gdouble   lower            /* dummy, not used */
+                    ,gdouble   upper            /* dummy, not used */
+                    ,gdouble   sstep
+                    ,gdouble   pagestep
+                    ,gint      digits
+                    ,gboolean  constrain
+                    ,gdouble   umin
+                    ,gdouble   umax
+                    ,gchar    *tooltip_text
+                    ,gchar    *privatetip
+                    );
 static void  mov_fit_initial_shell_window(t_mov_gui_stuff *mgp);
 static void  mov_shell_window_size_allocate (GtkWidget       *widget,
                                              GtkAllocation   *allocation,
@@ -1172,6 +1213,13 @@ p_copy_point(gint to_idx, gint from_idx)
     pvals->point[to_idx].tbry = pvals->point[from_idx].tbry;
     pvals->point[to_idx].sel_feather_radius = pvals->point[from_idx].sel_feather_radius;
 
+    pvals->point[to_idx].accPosition = pvals->point[from_idx].accPosition;
+    pvals->point[to_idx].accOpacity = pvals->point[from_idx].accOpacity;
+    pvals->point[to_idx].accSize = pvals->point[from_idx].accSize;
+    pvals->point[to_idx].accRotation = pvals->point[from_idx].accRotation;
+    pvals->point[to_idx].accPerspective = pvals->point[from_idx].accPerspective;
+    pvals->point[to_idx].accSelFeatherRadius = pvals->point[from_idx].accSelFeatherRadius;
+
     /* do not copy keyframe */
     pvals->point[to_idx].keyframe_abs = 0;
     pvals->point[to_idx].keyframe = 0;
@@ -2026,6 +2074,20 @@ p_point_refresh(t_mov_gui_stuff *mgp)
   gtk_adjustment_set_value (mgp->sel_feather_radius_adj,
                             (gdouble)mgp->sel_feather_radius);
 
+
+  gtk_adjustment_set_value (mgp->accPosition_adj,
+                            (gdouble)mgp->accPosition);
+  gtk_adjustment_set_value (mgp->accOpacity_adj,
+                            (gdouble)mgp->accOpacity);
+  gtk_adjustment_set_value (mgp->accSize_adj,
+                            (gdouble)mgp->accSize);
+  gtk_adjustment_set_value (mgp->accRotation_adj,
+                            (gdouble)mgp->accRotation);
+  gtk_adjustment_set_value (mgp->accPerspective_adj,
+                            (gdouble)mgp->accPerspective);
+  gtk_adjustment_set_value (mgp->accSelFeatherRadius_adj,
+                            (gdouble)mgp->accSelFeatherRadius);
+
   mgp->in_call = FALSE;
 }       /* end p_point_refresh */
 
@@ -2459,6 +2521,72 @@ mov_instant_apply_callback(GtkWidget *widget, t_mov_gui_stuff *mgp)
 }  /* end mov_instant_apply_callback */
 
 
+
+/* ------------------------------------------
+ * p_set_sensitivity_by_adjustment
+ * ------------------------------------------
+ * get the optional attached spinbutton and scale
+ * and set the specified sensitivity when attached widget is present.
+ */
+static void
+p_set_sensitivity_by_adjustment(GtkAdjustment *adj, gboolean sensitive)
+{
+  if(adj != NULL)
+  {
+    GtkWidget *spinbutton;
+    GtkWidget *scale;
+    
+    spinbutton = GTK_WIDGET(g_object_get_data (G_OBJECT (adj), "spinbutton"));
+    if(spinbutton)
+    {
+      gtk_widget_set_sensitive(spinbutton, sensitive);
+    }
+    scale = GTK_WIDGET(g_object_get_data (G_OBJECT (adj), "scale"));
+    if(scale)
+    {
+      gtk_widget_set_sensitive(scale, sensitive);
+    }
+  }
+}  /* end p_set_sensitivity_by_adjustment */
+
+
+/* ----------------------------------
+ * p_accel_widget_sensitivity
+ * ----------------------------------
+ * set sensitivity for all acceleration characteristic widgets 
+ * Those widgets are sensitive for the first conrolpoint
+ * and for keframes that are NOT the last controlpoint.
+ */
+static void
+p_accel_widget_sensitivity(t_mov_gui_stuff *mgp)
+{
+  gboolean sensitive;
+    
+  sensitive = FALSE;
+  if(pvals->point_idx == 0) 
+  {
+    sensitive = TRUE;
+  }
+  else
+  {
+    if ((pvals->point_idx != pvals->point_idx_max) 
+    && ((pvals->point[pvals->point_idx].keyframe > 0) || (mgp->keyframe_abs > 0)))
+    {
+      sensitive = TRUE;
+    }
+  }
+
+  p_set_sensitivity_by_adjustment(mgp->accPosition_adj, sensitive);
+  p_set_sensitivity_by_adjustment(mgp->accOpacity_adj, sensitive);
+  p_set_sensitivity_by_adjustment(mgp->accSize_adj, sensitive);
+  p_set_sensitivity_by_adjustment(mgp->accRotation_adj, sensitive);
+  p_set_sensitivity_by_adjustment(mgp->accPerspective_adj, sensitive);
+  p_set_sensitivity_by_adjustment(mgp->accSelFeatherRadius_adj, sensitive);
+
+
+}  /* end p_accel_widget_sensitivity */
+
+
 /* ============================================================================
  * procedures to handle POINTS - TABLE
  * ============================================================================
@@ -2468,9 +2596,6 @@ mov_instant_apply_callback(GtkWidget *widget, t_mov_gui_stuff *mgp)
 static void
 p_points_from_tab(t_mov_gui_stuff *mgp)
 {
-  GtkWidget *scale;
-  GtkWidget *spinbutton;
-
   mgp->p_x      = pvals->point[pvals->point_idx].p_x;
   mgp->p_y      = pvals->point[pvals->point_idx].p_y;
   mgp->opacity  = pvals->point[pvals->point_idx].opacity;
@@ -2488,36 +2613,27 @@ p_points_from_tab(t_mov_gui_stuff *mgp)
   mgp->sel_feather_radius  = pvals->point[pvals->point_idx].sel_feather_radius;
   mgp->keyframe_abs = pvals->point[pvals->point_idx].keyframe_abs;
 
+  mgp->accPosition         = pvals->point[pvals->point_idx].accPosition;
+  mgp->accOpacity          = pvals->point[pvals->point_idx].accOpacity;
+  mgp->accSize             = pvals->point[pvals->point_idx].accSize;
+  mgp->accRotation         = pvals->point[pvals->point_idx].accRotation;
+  mgp->accPerspective      = pvals->point[pvals->point_idx].accPerspective;
+  mgp->accSelFeatherRadius = pvals->point[pvals->point_idx].accSelFeatherRadius;
+
+
   if(( mgp->keyframe_adj != NULL) && (mgp->startup != TRUE))
   {
-   /*   findout the gtk_widgets (scale and spinbutton) connected
-    *   to mgp->keyframe_adj
-    *   and set_sensitive to TRUE or FALSE
-    */
-    scale = GTK_WIDGET(g_object_get_data (G_OBJECT (mgp->keyframe_adj), "scale"));
-    spinbutton = GTK_WIDGET(g_object_get_data (G_OBJECT (mgp->keyframe_adj), "spinbutton"));
-
-    if(spinbutton == NULL)
-    {
-      return;
-    }
-    if(gap_debug)
-    {
-      printf("p_points_from_tab: scale %x spinbutton %x\n",
-              (int)scale, (int)spinbutton);
-    }
+    gboolean sensitive;
+    
+    sensitive = TRUE;
     if((pvals->point_idx == 0) || (pvals->point_idx == pvals->point_idx_max))
     {
-      gtk_widget_set_sensitive(spinbutton, FALSE);
-      if(scale)
-        gtk_widget_set_sensitive(scale, FALSE);
-    }
-    else
-    {
-      gtk_widget_set_sensitive(spinbutton, TRUE);
-      if(scale)
-        gtk_widget_set_sensitive(scale, TRUE);
+      sensitive = FALSE;
     }
+    p_set_sensitivity_by_adjustment(mgp->keyframe_adj, sensitive);
+    
+    p_accel_widget_sensitivity(mgp);
+    
   }
 }
 
@@ -2542,6 +2658,14 @@ p_points_to_tab(t_mov_gui_stuff *mgp)
   pvals->point[pvals->point_idx].tbry      = mgp->tbry;
   pvals->point[pvals->point_idx].sel_feather_radius  = mgp->sel_feather_radius;
   pvals->point[pvals->point_idx].keyframe_abs  = mgp->keyframe_abs;
+  
+  pvals->point[pvals->point_idx].accPosition         = mgp->accPosition;
+  pvals->point[pvals->point_idx].accOpacity          = mgp->accOpacity;
+  pvals->point[pvals->point_idx].accSize             = mgp->accSize;
+  pvals->point[pvals->point_idx].accRotation         = mgp->accRotation;
+  pvals->point[pvals->point_idx].accPerspective      = mgp->accPerspective;
+  pvals->point[pvals->point_idx].accSelFeatherRadius = mgp->accSelFeatherRadius;
+
   if((mgp->keyframe_abs > 0)
   && (pvals->point_idx != 0)
   && (pvals->point_idx != pvals->point_idx_max))
@@ -2571,7 +2695,7 @@ p_update_point_index_text(t_mov_gui_stuff *mgp)
 
 /* ============================================================================
  * p_clear_one_point
- *   Init point table with identical 2 Points
+ *   clear one controlpoint to default values.
  * ============================================================================
  */
 void
@@ -2595,6 +2719,14 @@ p_clear_one_point(gint idx)
     pvals->point[idx].sel_feather_radius = 0.0;
     pvals->point[idx].keyframe = 0;   /* 0: controlpoint is not fixed to keyframe */
     pvals->point[idx].keyframe_abs = 0;   /* 0: controlpoint is not fixed to keyframe */
+    
+    pvals->point[idx].accPosition = 0;           /* 0: linear (e.g NO acceleration) is default */
+    pvals->point[idx].accOpacity = 0;            /* 0: linear (e.g NO acceleration) is default */
+    pvals->point[idx].accSize = 0;               /* 0: linear (e.g NO acceleration) is default */
+    pvals->point[idx].accRotation = 0;           /* 0: linear (e.g NO acceleration) is default */
+    pvals->point[idx].accPerspective = 0;        /* 0: linear (e.g NO acceleration) is default */
+    pvals->point[idx].accSelFeatherRadius = 0;   /* 0: linear (e.g NO acceleration) is default */
+
   }
 }       /* end p_clear_one_point */
 
@@ -2635,6 +2767,16 @@ p_mix_one_point(gint idx, gint ref1, gint ref2, gdouble mix_factor)
 
     pvals->point[idx].sel_feather_radius = MIX_VALUE(mix_factor, pvals->point[ref1].sel_feather_radius,  pvals->point[ref2].sel_feather_radius);
 
+
+    pvals->point[idx].accPosition         = MIX_VALUE(mix_factor, pvals->point[ref1].accPosition,          pvals->point[ref2].accPosition);
+    pvals->point[idx].accOpacity          = MIX_VALUE(mix_factor, pvals->point[ref1].accOpacity,           pvals->point[ref2].accOpacity);
+    pvals->point[idx].accSize             = MIX_VALUE(mix_factor, pvals->point[ref1].accSize,              pvals->point[ref2].accSize);
+    pvals->point[idx].accRotation         = MIX_VALUE(mix_factor, pvals->point[ref1].accRotation,          pvals->point[ref2].accRotation);
+    pvals->point[idx].accPerspective      = MIX_VALUE(mix_factor, pvals->point[ref1].accPerspective,       pvals->point[ref2].accPerspective);
+    pvals->point[idx].accSelFeatherRadius = MIX_VALUE(mix_factor, pvals->point[ref1].accSelFeatherRadius,  pvals->point[ref2].accSelFeatherRadius);
+
+
+
     pvals->point[idx].keyframe = 0;   /* 0: controlpoint is not fixed to keyframe */
     pvals->point[idx].keyframe_abs = 0;   /* 0: controlpoint is not fixed to keyframe */
   }
@@ -3874,6 +4016,159 @@ mov_trans_tab_create (t_mov_gui_stuff *mgp)
 }  /* end mov_trans_tab_create */
 
 
+
+/* -----------------------------------------
+ * mov_acc_tab_create
+ * ----------------------------------------
+ * Create  VBox with the acceleration characteristics and return it.
+ *   The VBox contains
+ *   - Transform 8x spinbutton   (0.01 upto 10.0) 4-point perspective transformation
+ */
+static GtkWidget *
+mov_acc_tab_create (t_mov_gui_stuff *mgp)
+{
+  GtkWidget      *vbox;
+  GtkWidget      *table;
+  GtkObject      *adj;
+
+#define ACC_MIN -100
+#define ACC_MAX  100
+
+  /* the vbox */
+  vbox = gtk_vbox_new (FALSE, 3);
+  gtk_container_set_border_width (GTK_CONTAINER (vbox), 2);
+
+  /* the table (2 rows) */
+  table = gtk_table_new ( 2, 9, FALSE );
+  gtk_container_set_border_width (GTK_CONTAINER (table), 2 );
+  gtk_table_set_row_spacings (GTK_TABLE (table), 2);
+  gtk_table_set_col_spacings (GTK_TABLE (table), 4);
+  gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0);
+
+
+  /*  accelaration characteristic for Position (e.g. movement) */
+  adj = p_mov_acc_spinbutton_new( GTK_TABLE (table), 0, 0,        /* table col, row */
+                          _("Movement:"),                     /* label text */
+                          SCALE_WIDTH, ENTRY_WIDTH,           /* scalesize spinsize */
+                          (gdouble)mgp->accPosition,          /* initial value */
+                          (gdouble)ACC_MIN, (gdouble)ACC_MAX, /* lower, upper */
+                          1, 10,                              /* step, page */
+                          0,                                  /* digits */
+                          FALSE,                              /* constrain */
+                          (gdouble)ACC_MIN, (gdouble)ACC_MAX, /* lower, upper (unconstrained) */
+                          _("acceleration characteristic for movement (1 for constant speed, positive: acceleration, negative: deceleration)"),
+                          NULL);    /* tooltip privatetip */
+  g_object_set_data(G_OBJECT(adj), "mgp", mgp);
+  g_signal_connect (G_OBJECT (adj), "value_changed",
+                    G_CALLBACK (mov_path_acceleration_adjustment_update),
+                    &mgp->accPosition);
+  mgp->accPosition_adj = GTK_ADJUSTMENT(adj);
+
+
+
+  /*  accelaration characteristic */
+  adj = p_mov_acc_spinbutton_new( GTK_TABLE (table), 0, 1,        /* table col, row */
+                          _("Opacity:"),                      /* label text */
+                          SCALE_WIDTH, ENTRY_WIDTH,           /* scalesize spinsize */
+                          (gdouble)mgp->accOpacity,           /* initial value */
+                          (gdouble)ACC_MIN, (gdouble)ACC_MAX, /* lower, upper */
+                          1, 10,                              /* step, page */
+                          0,                                  /* digits */
+                          FALSE,                              /* constrain */
+                          (gdouble)ACC_MIN, (gdouble)ACC_MAX, /* lower, upper (unconstrained) */
+                          _("acceleration characteristic for opacity (1 for constant speed, positive: acceleration, negative: deceleration)"),
+                          NULL);    /* tooltip privatetip */
+  g_object_set_data(G_OBJECT(adj), "mgp", mgp);
+  g_signal_connect (G_OBJECT (adj), "value_changed",
+                    G_CALLBACK (mov_path_acceleration_adjustment_update),
+                    &mgp->accOpacity);
+  mgp->accOpacity_adj = GTK_ADJUSTMENT(adj);
+
+
+
+
+  /*  accelaration characteristic for Size (e.g. Zoom) */
+  adj = p_mov_acc_spinbutton_new( GTK_TABLE (table), 3, 0,        /* table col, row */
+                          _("Scale:"),                        /* label text */
+                          SCALE_WIDTH, ENTRY_WIDTH,           /* scalesize spinsize */
+                          (gdouble)mgp->accSize,              /* initial value */
+                          (gdouble)ACC_MIN, (gdouble)ACC_MAX, /* lower, upper */
+                          1, 10,                              /* step, page */
+                          0,                                  /* digits */
+                          FALSE,                              /* constrain */
+                          (gdouble)ACC_MIN, (gdouble)ACC_MAX, /* lower, upper (unconstrained) */
+                          _("acceleration characteristic for zoom (1 for constant speed, positive: acceleration, negative: deceleration)"),
+                          NULL);    /* tooltip privatetip */
+  g_object_set_data(G_OBJECT(adj), "mgp", mgp);
+  g_signal_connect (G_OBJECT (adj), "value_changed",
+                    G_CALLBACK (mov_path_acceleration_adjustment_update),
+                    &mgp->accSize);
+  mgp->accSize_adj = GTK_ADJUSTMENT(adj);
+
+
+  /*  accelaration characteristic for Rotation */
+  adj = p_mov_acc_spinbutton_new( GTK_TABLE (table), 3, 1,        /* table col, row */
+                          _("Rotation:"),                     /* label text */
+                          SCALE_WIDTH, ENTRY_WIDTH,           /* scalesize spinsize */
+                          (gdouble)mgp->accRotation,          /* initial value */
+                          (gdouble)ACC_MIN, (gdouble)ACC_MAX, /* lower, upper */
+                          1, 10,                              /* step, page */
+                          0,                                  /* digits */
+                          FALSE,                              /* constrain */
+                          (gdouble)ACC_MIN, (gdouble)ACC_MAX, /* lower, upper (unconstrained) */
+                          _("acceleration characteristic for rotation (1 for constant speed, positive: acceleration, negative: deceleration)"),
+                          NULL);    /* tooltip privatetip */
+  g_object_set_data(G_OBJECT(adj), "mgp", mgp);
+  g_signal_connect (G_OBJECT (adj), "value_changed",
+                    G_CALLBACK (mov_path_acceleration_adjustment_update),
+                    &mgp->accRotation);
+  mgp->accRotation_adj = GTK_ADJUSTMENT(adj);
+
+  /*  accelaration characteristic for Perspective */
+  adj = p_mov_acc_spinbutton_new( GTK_TABLE (table), 6, 0,        /* table col, row */
+                          _("Perspective:"),                  /* label text */
+                          SCALE_WIDTH, ENTRY_WIDTH,           /* scalesize spinsize */
+                          (gdouble)mgp->accPerspective,       /* initial value */
+                          (gdouble)ACC_MIN, (gdouble)ACC_MAX, /* lower, upper */
+                          1, 10,                              /* step, page */
+                          0,                                  /* digits */
+                          FALSE,                              /* constrain */
+                          (gdouble)ACC_MIN, (gdouble)ACC_MAX, /* lower, upper (unconstrained) */
+                          _("acceleration characteristic for perspective (1 for constant speed, positive: acceleration, negative: deceleration)"),
+                          NULL);    /* tooltip privatetip */
+  g_object_set_data(G_OBJECT(adj), "mgp", mgp);
+  g_signal_connect (G_OBJECT (adj), "value_changed",
+                    G_CALLBACK (mov_path_acceleration_adjustment_update),
+                    &mgp->accPerspective);
+  mgp->accPerspective_adj = GTK_ADJUSTMENT(adj);
+
+
+  /*  accelaration characteristic for feather radius */
+  adj = p_mov_acc_spinbutton_new( GTK_TABLE (table), 6, 1,        /* table col, row */
+                          _("FeatherRadius:"),                /* label text */
+                          SCALE_WIDTH, ENTRY_WIDTH,           /* scalesize spinsize */
+                          (gdouble)mgp->accSelFeatherRadius,  /* initial value */
+                          (gdouble)ACC_MIN, (gdouble)ACC_MAX, /* lower, upper */
+                          1, 10,                              /* step, page */
+                          0,                                  /* digits */
+                          FALSE,                              /* constrain */
+                          (gdouble)ACC_MIN, (gdouble)ACC_MAX, /* lower, upper (unconstrained) */
+                          _("acceleration characteristic for feather radius (1 for constant speed, positive: acceleration, negative: deceleration)"),
+                          NULL);    /* tooltip privatetip */
+  g_object_set_data(G_OBJECT(adj), "mgp", mgp);
+  g_signal_connect (G_OBJECT (adj), "value_changed",
+                    G_CALLBACK (mov_path_acceleration_adjustment_update),
+                    &mgp->accSelFeatherRadius);
+  mgp->accSelFeatherRadius_adj = GTK_ADJUSTMENT(adj);
+
+
+  gtk_widget_show(table);
+  gtk_widget_show(vbox);
+
+  return vbox;
+}  /* end mov_acc_tab_create */
+
+
 /* ============================================================================
  * Create  VBox with the selection handling widgets and return it.
  * ============================================================================
@@ -3913,7 +4208,7 @@ mov_selection_handling_tab_create (t_mov_gui_stuff *mgp)
                        , NULL);
   gtk_widget_show(combo);
 
-  /* ttlx transformfactor */
+  /* Feather Radius */
   adj = gimp_scale_entry_new( GTK_TABLE (table), 0, 1,        /* table col, row */
                           _("Selection Feather Radius:"),     /* label text */
                           SCALE_WIDTH, ENTRY_WIDTH,           /* scalesize spinsize */
@@ -4064,8 +4359,8 @@ mov_path_prevw_create ( GimpDrawable *drawable, t_mov_gui_stuff *mgp, gboolean v
                           _("Fix controlpoint to keyframe number where 0 == no keyframe"),
                           NULL);    /* tooltip privatetip */
   g_signal_connect (G_OBJECT (adj), "value_changed",
-                    G_CALLBACK (gimp_int_adjustment_update),
-                    &mgp->keyframe_abs);
+                    G_CALLBACK (mov_path_keyframe_update),
+                    mgp);
   mgp->keyframe_adj = GTK_ADJUSTMENT(adj);
 
 
@@ -4075,6 +4370,7 @@ mov_path_prevw_create ( GimpDrawable *drawable, t_mov_gui_stuff *mgp, gboolean v
   {
     GtkWidget *modify_table;
     GtkWidget *transform_table;
+    GtkWidget *acceleration_table;
     GtkWidget *selhandling_table;
 
     /* set of modifier widgets for the current controlpoint */
@@ -4082,6 +4378,9 @@ mov_path_prevw_create ( GimpDrawable *drawable, t_mov_gui_stuff *mgp, gboolean v
 
     /* set of perspective transformation widgets for the current controlpoint */
     transform_table = mov_trans_tab_create(mgp);
+    
+    /* set of acceleration characteristic widgets for the current controlpoint */
+    acceleration_table = mov_acc_tab_create(mgp);
 
     /* set of perspective transformation widgets for the current controlpoint */
     selhandling_table = mov_selection_handling_tab_create(mgp);
@@ -4098,13 +4397,19 @@ mov_path_prevw_create ( GimpDrawable *drawable, t_mov_gui_stuff *mgp, gboolean v
                              , gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 1)
                              , label
                              );
-
     gtk_container_add (GTK_CONTAINER (notebook), selhandling_table);
     label = gtk_label_new(_("Selection Handling"));
     gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook)
                              , gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 2)
                              , label
                              );
+    gtk_container_add (GTK_CONTAINER (notebook), acceleration_table);
+    label = gtk_label_new(_("Acceleration"));
+    gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook)
+                             , gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 3)
+                             , label
+                             );
+
   }
   gtk_table_attach(GTK_TABLE(table), notebook, 3, 4          /* column */
                                              , 0, 3          /* all rows */
@@ -4684,6 +4989,15 @@ mov_path_keycolorbutton_changed( GimpColorButton *widget,
   }
 }  /* end mov_path_keycolorbutton_changed */
 
+
+static void
+mov_path_keyframe_update ( GtkWidget *widget, t_mov_gui_stuff *mgp)
+{
+  gimp_int_adjustment_update(GTK_ADJUSTMENT(widget), &mgp->keyframe_abs);
+  p_accel_widget_sensitivity(mgp);
+}
+
+
 /*
  *  mov_path_xy_adjustment_update
  */
@@ -4734,6 +5048,11 @@ mov_path_y_adjustment_update( GtkWidget *widget,
   }
 }
 
+/* -----------------------------------------
+ * mov_path_tfactor_adjustment_update
+ * ----------------------------------------
+ * update value for one of the perspective transformation factors
+ */
 static void
 mov_path_tfactor_adjustment_update( GtkWidget *widget,
                             gdouble *val )
@@ -4758,6 +5077,43 @@ mov_path_tfactor_adjustment_update( GtkWidget *widget,
   }
 }  /* end mov_path_tfactor_adjustment_update */
 
+/* -----------------------------------------
+ * mov_path_acceleration_adjustment_update
+ * ----------------------------------------
+ * update value for one of the acceleration characteristic values
+ */
+static void
+mov_path_acceleration_adjustment_update(GtkWidget *widget,
+                            gint *val )
+{
+  gint old_val;
+  t_mov_gui_stuff *mgp;
+  GapAccelWidget  *accel_ptr;
+
+  mgp = g_object_get_data( G_OBJECT(widget), "mgp" );
+
+  if(mgp == NULL) return;
+  old_val = *val;
+  gimp_int_adjustment_update(GTK_ADJUSTMENT(widget), (gpointer)val);
+
+  accel_ptr = g_object_get_data ( G_OBJECT(widget), "accel_ptr" );
+
+  if(accel_ptr == NULL)
+  {
+    if(gap_debug)
+    {
+      printf("accel_ptr is NULL\n");
+    }
+  }
+  
+  gap_accel_render (accel_ptr, *val);
+
+  return;
+
+}  /* end mov_path_acceleration_adjustment_update */
+
+
+
 static void
 mov_path_feather_adjustment_update( GtkWidget *widget,
                             gdouble *val )
@@ -5097,6 +5453,14 @@ p_get_prevw_drawable (t_mov_gui_stuff *mgp)
     l_curr.currTBRY      = (gdouble)mgp->tbry;
     l_curr.currSelFeatherRadius = (gdouble)mgp->sel_feather_radius;
 
+    l_curr.accPosition         = (gdouble)mgp->accPosition;
+    l_curr.accOpacity          = (gdouble)mgp->accOpacity;
+    l_curr.accSize             = (gdouble)mgp->accSize;
+    l_curr.accRotation         = (gdouble)mgp->accRotation;
+    l_curr.accPerspective      = (gdouble)mgp->accPerspective;
+    l_curr.accSelFeatherRadius = (gdouble)mgp->accSelFeatherRadius;
+
+
     l_curr.src_layer_idx   = 0;
     l_curr.src_layers      = gimp_image_get_layers (pvals->src_image_id, &l_nlayers);
 
@@ -5260,6 +5624,73 @@ p_mov_spinbutton_new(GtkTable *table
   return(adj);
 }  /* end p_mov_spinbutton_new */
 
+/* ----------------------------------
+ * p_mov_acc_spinbutton_new
+ * ----------------------------------
+ * create label and spinbutton and add to table
+ * return the adjustment of the spinbutton
+ * (for compatible parameters to gimp_scale_entry_new
+ *  there are some unused dummy parameters)
+ */
+GtkObject *
+p_mov_acc_spinbutton_new(GtkTable *table
+                    ,gint      col
+                    ,gint      row
+                    ,gchar    *label_text
+                    ,gint      scale_width      /* dummy, not used */
+                    ,gint      spinbutton_width
+                    ,gdouble   initial_val
+                    ,gdouble   lower            /* dummy, not used */
+                    ,gdouble   upper            /* dummy, not used */
+                    ,gdouble   sstep
+                    ,gdouble   pagestep
+                    ,gint      digits
+                    ,gboolean  constrain
+                    ,gdouble   umin
+                    ,gdouble   umax
+                    ,gchar    *tooltip_text
+                    ,gchar    *privatetip
+                    )
+{
+  GtkObject       *adj;
+  GapAccelWidget  *accel_ptr;
+  gint accelerationCharacteristic;
+  
+#define ACC_WGT_WIDTH 28
+#define ACC_WGT_HEIGHT 26
+
+  adj = p_mov_spinbutton_new(table
+                    ,col
+                    ,row
+                    ,label_text
+                    ,scale_width
+                    ,spinbutton_width
+                    ,initial_val
+                    ,lower
+                    ,upper
+                    ,sstep
+                    ,pagestep
+                    ,digits
+                    ,constrain
+                    ,umin
+                    ,umax
+                    ,tooltip_text
+                    ,privatetip
+                    );
+
+  accelerationCharacteristic = (int)initial_val;
+  accel_ptr = gap_accel_new(ACC_WGT_WIDTH, ACC_WGT_HEIGHT, accelerationCharacteristic);
+
+
+  gtk_table_attach( GTK_TABLE(table), accel_ptr->da_widget, col+2, col+3, row, row+1,
+                    GTK_FILL, 0, 4, 0 );
+  gtk_widget_show (accel_ptr->da_widget);
+
+  g_object_set_data (G_OBJECT (adj), "accel_ptr", accel_ptr);
+
+  return(adj);
+}  /* end p_mov_acc_spinbutton_new */
+
 
 /* --------------------------
  * mov_fit_initial_shell_window
diff --git a/gap/gap_mov_dialog.h b/gap/gap_mov_dialog.h
old mode 100644
new mode 100755
index ea2bb77..a37ec08
--- a/gap/gap_mov_dialog.h
+++ b/gap/gap_mov_dialog.h
@@ -111,6 +111,15 @@ typedef struct {
         gdouble currTBRY;     /*  transform y bot right */
         
         gdouble currSelFeatherRadius;
+
+        /* acceleration characteristics */
+        gint accPosition;
+        gint accOpacity;
+        gint accSize;
+        gint accRotation;
+        gint accPerspective;
+        gint accSelFeatherRadius;
+
 } GapMovCurrent;
 
 
@@ -134,8 +143,17 @@ typedef struct {
         gdouble tbrx;     /* 0.0 upto 10.0 transform x bot right */
         gdouble tbry;     /* 0.0 upto 10.0 transform y bot right */
 
-        /* 4-point transform distortion (perspective) */
+        /* feather radius for selection handling */
         gdouble sel_feather_radius;
+        
+        /* acceleration characteristics */
+	gint accPosition;
+	gint accOpacity;
+	gint accSize;
+	gint accRotation;
+	gint accPerspective;
+	gint accSelFeatherRadius;
+
 } GapMovPoint;
 
 #define GAP_MOV_MAX_POINT 1024
diff --git a/gap/gap_mov_exec.c b/gap/gap_mov_exec.c
old mode 100644
new mode 100755
index f561cac..22275f7
--- a/gap/gap_mov_exec.c
+++ b/gap/gap_mov_exec.c
@@ -73,6 +73,7 @@
 #include "gap_mov_render.h"
 #include "gap_pdb_calls.h"
 #include "gap_arr_dialog.h"
+#include "gap_accel_char.h"
 
 extern      int gap_debug; /* ==0  ... dont print debug infos */
 
@@ -85,6 +86,41 @@ static gdouble  p_calc_angle(gint p1x, gint p1y, gint p2x, gint p2y);
 static gdouble  p_rotatate_less_than_180(gdouble angle, gdouble angle_new, gint *turns);
 
 
+static gint     p_calculate_relframe_nr_at_index(GapMovValues *val_ptr, gint index, gint frames);
+static gint     p_findEndOfSegmentIndex(GapMovValues *val_ptr, gint startOfSegmentIndex, gint points);
+static gdouble  p_calculate_LineLength(GapMovValues *val_ptr, gint idx);
+static gdouble  p_calculate_path_segment_length(GapMovValues  *val_ptr
+                    , gint startOfSegmentIndex, gint endOfSegmentIndex);
+static gint     p_pick_controlpoint_at_curr_length(GapMovValues  *val_ptr
+                    , gint startOfSegmentIndex, gint endOfSegmentIndex, gdouble pathSegmentLength
+                    , gint accelerationCharacteristic, gdouble lengthFactorLinear
+                    , gdouble *flt_posfactor
+                    );
+static gdouble  p_calculate_posFactor_from_FrameTweens(gdouble frameTweensInSegment
+                   , gdouble currFrameTweenInSegment
+                   , gint accelerationCharacteristic
+                   );
+static gint     p_calculate_settings_for_current_FrameTween(
+                     GapMovValues  *val_ptr
+                   , GapMovCurrent *cur_ptr
+                   , gdouble framesPerLine
+                   , long     currFrameIndex    /* relative frame number where the first handled frame is 0
+                                                 * Note that the first fame is already processed outside the loop
+                                                 * therefore this procedure is typically called first time with
+                                                 * currFrameIndex value 1.
+                                                 */
+                   , long     currPtidx         /* current controlpoint index for processing without acceleration characteristic */
+                   , gdouble  flt_posfactor     /* current position factor within one line between controlpoints
+                                                 * (relevant for processing without acceleration characteristic)
+                                                 */
+                   , gdouble  affectedFrames        /* number of affected frames (in the whole Move patch operation) */
+                   , long     availableCtrlPoints   /* number of available controlpoints */
+                   , gint     startOfSegmentIndex
+                   , gint     endOfSegmentIndex
+                   );
+                    
+
+
 /* ============================================================================
  * p_add_tween_and_trace
  * ============================================================================
@@ -638,6 +674,486 @@ p_mov_advance_src_frame(GapMovCurrent *cur_ptr, GapMovValues  *pvals)
 }       /* end  p_advance_src_frame */
 
 
+
+
+
+
+/* -----------------------------------
+ * p_calculate_relframe_nr_at_index
+ * -----------------------------------
+ * IN points is the number of processing relevant controlpoints
+ * returns the index of the last controlpoint in the path segment that starts at specified index
+ * Note that path segment includes all controlpoints up to the next keyframe inclusive. If no keyframe
+ * present ther is only one big segment from first to last controlpoint.
+ */
+static gint
+p_calculate_relframe_nr_at_index(GapMovValues *val_ptr, gint index, gint frames)
+{
+  if (index <= 0)
+  {
+    return (1);
+  }
+  
+  if(index  < val_ptr->point_idx_max )
+  {
+    if (val_ptr->point[index].keyframe > 0)
+    {
+      return (1 + val_ptr->point[index].keyframe);
+    }
+  }
+
+  return (frames);
+
+}  /* end p_calculate_relframe_nr_at_index */
+
+
+/* -----------------------------------
+ * p_findEndOfSegmentIndex
+ * -----------------------------------
+ * IN points is the number of processing relevant controlpoints
+ * returns the index of the last controlpoint in the segment that starts 
+ * at specified startOfSegmentIndex.
+ * the segment ends at next KEYFRAME or at the last controlpoint (that is an implicite keyframe)
+ */
+static gint
+p_findEndOfSegmentIndex(GapMovValues *val_ptr, gint startOfSegmentIndex, gint points)
+{
+  gint ii;
+  
+  for (ii= startOfSegmentIndex +1; ii < points; ii++)
+  {
+    if (val_ptr->point[ii].keyframe > 0)
+    {
+      /* checked controlpoint is a keyframe */
+      return (ii);
+    }
+  }
+  
+  return (points -1);
+}  /* end p_findEndOfSegmentIndex */
+
+
+/* -----------------------------------
+ * p_calculate_LineLength
+ * -----------------------------------
+ * returns the length (in pixels) between the controlpont at the specified index idx
+ * and the next controlpoint at idx +1
+ * returns 0 in case the specified index is out of valid range
+ */
+static gdouble
+p_calculate_LineLength(GapMovValues *val_ptr, gint idx)
+{
+  gdouble dx;
+  gdouble dy;
+  gdouble len;
+
+  if ((idx < 0) || (idx >= val_ptr->point_idx_max))
+  {
+    return (0.0);
+  }
+  
+  dx = abs (val_ptr->point[idx].p_x - val_ptr->point[idx +1].p_x);
+  dy = abs (val_ptr->point[idx].p_y - val_ptr->point[idx +1].p_y);
+  
+  len = sqrt((dx * dx) + (dy * dy));
+  
+  return (len);
+  
+}  /* end p_calculate_LineLength */
+
+
+/* -----------------------------------
+ * p_calculate_path_segment_length
+ * -----------------------------------
+ *
+ */
+static gdouble
+p_calculate_path_segment_length(GapMovValues  *val_ptr
+   , gint startOfSegmentIndex, gint endOfSegmentIndex)
+{
+  gint idx;
+  gdouble lenSum;
+  
+  lenSum = 0;
+  for(idx=startOfSegmentIndex; idx < endOfSegmentIndex; idx++)
+  {
+    lenSum += p_calculate_LineLength(val_ptr, idx);
+  }
+  return (lenSum);
+}  /* end p_calculate_path_segment_length */
+
+
+/* -----------------------------------
+ * p_pick_controlpoint_at_curr_length
+ * -----------------------------------
+ * returns the relevant controlpoint index 
+ * at specified currentLen in pixels (eg. current position length within the specified
+ * path segment that starts at controlpoint startOfSegmentIndex)
+ *
+ * IN:  startOfSegmentIndex
+ * IN:  endOfSegmentIndex
+ * IN:  pathSegmentLength length in pixels (0 at stastOfSegment, upto segment length)
+ * IN:  
+ * OUT: flt_posfactor
+ */
+static gint
+p_pick_controlpoint_at_curr_length(GapMovValues  *val_ptr
+   , gint startOfSegmentIndex, gint endOfSegmentIndex, gdouble pathSegmentLength
+   , gint accelerationCharacteristic, gdouble lengthFactorLinear
+   , gdouble *flt_posfactor
+   )
+{
+   gint idx;
+   gdouble lenSum;
+   gdouble lenSumPrev;
+   gdouble currentLen;
+   gdouble lengthFactorAcc;         /* 0.0 at begin of segment 1.0 at end of segment position */
+
+   /* calculate length factor (0.0 to 1.0) respecting position specific acceleartion characteristic */
+   lengthFactorAcc = gap_accelMixFactor(lengthFactorLinear, accelerationCharacteristic);
+   currentLen = pathSegmentLength * lengthFactorAcc;
+   
+   
+   
+   
+   lenSum = 0;
+   lenSumPrev = 0;
+   
+   for(idx = startOfSegmentIndex; idx <= endOfSegmentIndex; idx++)
+   {
+     gdouble lineLen;
+     
+     lineLen = p_calculate_LineLength(val_ptr, idx);
+     lenSum += lineLen;
+ 
+     if(lenSum >= currentLen)
+     {
+       gdouble l_flt_posfactor;
+       l_flt_posfactor = (currentLen - lenSumPrev) / MAX(1.0, lineLen);
+
+       if(gap_debug)
+       {
+         printf("  p_pick_controlpoint_at_curr_length[%d]  lenSum:%f currentLen:%f lengthFactorAcc:%f\n"
+            ,(int)idx
+            ,(float) lenSum
+            ,(float) currentLen
+            ,(float) lengthFactorAcc
+            );
+       }
+      
+       
+       *flt_posfactor =  CLAMP (l_flt_posfactor, 0.0, 1.0);
+       return (idx);
+     }
+    lenSumPrev = lenSum;
+  }
+   
+  *flt_posfactor = 0;
+  return (endOfSegmentIndex);
+
+}  /* end p_pick_controlpoint_at_curr_length */
+
+/* --------------------------------------
+ * p_calculate_posFactor_from_FrameTweens
+ * --------------------------------------
+ * returns the relevant positionFactor for the 
+ * specified currFrameTweenInSegment and frameTweensInSegment
+ * respecting the specified acceleration characteristic 
+ *
+ */
+static gdouble
+p_calculate_posFactor_from_FrameTweens(gdouble frameTweensInSegment
+   , gdouble currFrameTweenInSegment
+   , gint accelerationCharacteristic
+   )
+{
+  gdouble factorLinear;         /* 0.0 at begin of segment 1.0 at end of segment */
+  gdouble posFactorAcc;         /* 0.0 at begin of segment 1.0 at end of segment */
+
+  factorLinear = currFrameTweenInSegment / (MAX (1.0, frameTweensInSegment));
+  factorLinear = CLAMP (factorLinear, 0.0, 1.0);
+  
+  /* calculate length factor (0.0 to 1.0) respecting position specific acceleartion characteristic */
+  posFactorAcc = gap_accelMixFactor(factorLinear, accelerationCharacteristic);
+   
+   
+  return (posFactorAcc);
+
+}  /* end p_calculate_posFactor_from_FrameTweens */
+
+
+/* -------------------------------------------
+ * p_calculate_settings_for_current_FrameTween
+ * -------------------------------------------
+ * calculate settings for the currently processed
+ * Frame (or tween) according to the controlpoints.
+ * supports older behavior of GIMP-GAP-2.6 and prior 
+ * and the extended variant with accerlaration characteristics
+ * per path segment.
+ * mode without acceleration characteristic (GIMP-GAP-2.6 behvior)
+ * ========================================
+ *   This mode is selected by acceleration characteristic value 0.
+ *   In this mode the flt_posfactor specifies the position within one line
+ *   between the controlpoints with index [l_ptidx -1] and [l_ptidx]
+ *  
+ * Mode with acceleration characteristic:
+ * ========================================
+ *   a Path segment includes all controlpoints between two keyframes
+ *   (e.g controlpoints where keyframe > 0) Note that first and last contolpoint
+ *   are implicite keyframes.
+ *   In case none of the contolpoints has keyframe > 0, all controlpoints
+ *   are in just one segment that starts at first and ends at last controlpoint.
+ *
+ *   The current movement position depends on the length of the current
+ *   path segment and on the specified acceleration characteristic for movement.
+ *   acc characteristic 1 is constant speed mode, 2 or more is acceleration, -2 or less deceleration
+ *   The line within the path segment is calculated by picking
+ *   the relevant ctrlPtidx.
+ *
+ *   in case acceleration characteristic values != 0 are used for any other settings than position,
+ *   then all controlpoints that are NON keyframes are ignored for other settings than position (x,y).
+ *   Those settings (opacity, size ...) are then calculated from the 
+ *   controlpoint at start and end of the path segment.
+ *   (note that first and last controlpoint are
+ *    implicite keyframes and therefore always relevant)
+ */
+static gint
+p_calculate_settings_for_current_FrameTween(
+     GapMovValues  *val_ptr
+   , GapMovCurrent *cur_ptr
+   , gdouble framesPerLine
+   , long     currFrameIndex    /* relative frame number where the first handled frame is 0
+                                 * Note that the first fame is already processed outside the loop
+                                 * therefore this procedure is typically called first time with
+                                 * currFrameIndex value 1.
+                                 */
+   , long     currPtidx         /* current controlpoint index for processing without acceleration characteristic */
+   , gdouble  flt_posfactor     /* current position factor within one line between controlpoints
+                                 * (relevant for processing without acceleration characteristic)
+                                 */
+   , gdouble  affectedFrames        /* number of affected frames (in the whole Move patch operation) */
+   , long     availableCtrlPoints   /* number of available controlpoints */
+   , gint     startOfSegmentIndex
+   , gint     endOfSegmentIndex
+  )
+{
+/* MIX_VALUE  0.0 <= factor <= 1.0
+ *  result is a  for factor 0.0
+ *            b  for factor 1.0
+ *            mix for factors inbetween
+ */
+#define MIX_VALUE(factor, a, b) ((a * (1.0 - factor)) +  (b * factor))
+
+  gdouble tweenMultiplicator;
+  gint frameNrAtEndOfSegment;
+  gdouble lengthFactorLinear;      /* 0.0 at begin of segment 1.0 at end of segment position */
+  gdouble frameTweensInSegment;
+  gdouble currFrameTweenInSegment; /* frame number relative to 0 at each starting point of a new segment 
+                                    * tweens can have non integer frame number like 1.5 or 1.3333 or 1.25 etc....
+                                    */
+  gdouble pathSegmentLength;
+  
+  gdouble  posFactor;
+
+  posFactor = 0.0;
+
+  tweenMultiplicator = 1.0;
+  if(val_ptr->tween_steps > 1.0)
+  {
+    tweenMultiplicator = val_ptr->tween_steps +1;
+  }
+
+  frameNrAtEndOfSegment = p_calculate_relframe_nr_at_index(val_ptr, endOfSegmentIndex, affectedFrames);
+  
+  frameTweensInSegment = abs ( frameNrAtEndOfSegment
+                             - p_calculate_relframe_nr_at_index(val_ptr, startOfSegmentIndex, affectedFrames)
+                             ) + 1;
+  frameTweensInSegment *= tweenMultiplicator;
+  
+  
+  
+  currFrameTweenInSegment = 
+     tweenMultiplicator * (abs (currFrameIndex - val_ptr->point[startOfSegmentIndex].keyframe)); /// TODO check for reverse order processing ???
+  currFrameTweenInSegment += (val_ptr->tween_steps - val_ptr->twix);
+  
+  /* calculate length factor respecting position in the path segment where 0 is at begin 1 at end */
+  lengthFactorLinear = currFrameTweenInSegment / MAX(frameTweensInSegment, 1);
+
+  pathSegmentLength = p_calculate_path_segment_length(val_ptr, startOfSegmentIndex, endOfSegmentIndex);
+
+  /* calculate Movement settings for the currently processed Frame (or tween)
+   * position dependent acceleration processing requires a path segment length > 0
+   * AND accPosition != 0
+   */
+  if ((val_ptr->point[startOfSegmentIndex].accPosition != 0)
+  && (pathSegmentLength > 0))
+  {
+    /* acceleration characteristic processing */
+    gint     segmPtidx;  /* calculated controlpoint index of relevant line begin with current segment */
+
+    segmPtidx = p_pick_controlpoint_at_curr_length(val_ptr
+         , startOfSegmentIndex, endOfSegmentIndex, pathSegmentLength
+         , val_ptr->point[startOfSegmentIndex].accPosition
+         , lengthFactorLinear
+         , &posFactor
+         );
+
+    cur_ptr->currX  =       MIX_VALUE(posFactor, (gdouble)val_ptr->point[segmPtidx].p_x,      (gdouble)val_ptr->point[segmPtidx +1].p_x);
+    cur_ptr->currY  =       MIX_VALUE(posFactor, (gdouble)val_ptr->point[segmPtidx].p_y,      (gdouble)val_ptr->point[segmPtidx +1].p_y);
+
+
+    if(gap_debug)
+    {
+       printf("p_mov_execute: currFrameIndex:%d Position, start/endOfSegmentIndex=%d/%d currFrameTweenInSegment=%d  frameTweensInSegment=%d\n"
+             , (int)currFrameIndex
+             , (int)startOfSegmentIndex
+             , (int)endOfSegmentIndex
+             , (int)currFrameTweenInSegment
+             , (int)frameTweensInSegment
+             );
+       printf("p_mov_execute: Position, frameNrAtEndOfSegment=%d\n", (int)frameNrAtEndOfSegment);
+       printf("p_mov_execute: Position, lengthFactorLinear=%f\n", (float)lengthFactorLinear);
+       printf("p_mov_execute: Position, pathSegmentLength=%f\n", (float)pathSegmentLength);
+       printf("p_mov_execute: Position, posFactor=%f  segmPtidx=%d\n"
+             , (float)posFactor
+             , (int)segmPtidx
+             );
+    }
+  }
+  else
+  {
+    /* No acceleration characteristic specified for movement (compatible to GAP 2.6.x release behavior) */
+    if(gap_debug) 
+    {
+      printf("p_mov_execute: framesPerLine=%f, flt_posfactor=%f\n"
+           , (float)framesPerLine
+           , (float)flt_posfactor
+           );
+    }
+
+
+    cur_ptr->currX  =       MIX_VALUE(flt_posfactor, (gdouble)val_ptr->point[currPtidx -1].p_x,      (gdouble)val_ptr->point[currPtidx].p_x);
+    cur_ptr->currY  =       MIX_VALUE(flt_posfactor, (gdouble)val_ptr->point[currPtidx -1].p_y,      (gdouble)val_ptr->point[currPtidx].p_y);
+  }
+
+
+  /* calculate Opacity settings for the currently processed Frame (or tween) */
+  if ((val_ptr->point[startOfSegmentIndex].accOpacity != 0)
+  && (frameTweensInSegment > 0))
+  {
+    /* acceleration characteristic processing for opacity */
+    posFactor = p_calculate_posFactor_from_FrameTweens(frameTweensInSegment
+                                                      , currFrameTweenInSegment
+                                                      , val_ptr->point[startOfSegmentIndex].accOpacity
+                                                      );
+    cur_ptr->currOpacity  = MIX_VALUE(posFactor, (gdouble)val_ptr->point[startOfSegmentIndex].opacity,  (gdouble)val_ptr->point[endOfSegmentIndex].opacity);
+  }
+  else
+  {
+    /* No acceleration characteristic specified for opacity (compatible to GAP 2.6.x release behavior) */
+    cur_ptr->currOpacity  = MIX_VALUE(flt_posfactor, (gdouble)val_ptr->point[currPtidx -1].opacity,  (gdouble)val_ptr->point[currPtidx].opacity);
+  }
+
+
+  /* calculate Zoom (e.g. Size) settings for the currently processed Frame (or tween) */
+  if ((val_ptr->point[startOfSegmentIndex].accSize != 0)
+  && (frameTweensInSegment > 0))
+  {
+    /* acceleration characteristic processing for opacity */
+    posFactor = p_calculate_posFactor_from_FrameTweens(frameTweensInSegment
+                                                      , currFrameTweenInSegment
+                                                      , val_ptr->point[startOfSegmentIndex].accSize
+                                                      );
+    cur_ptr->currWidth    = MIX_VALUE(posFactor, (gdouble)val_ptr->point[startOfSegmentIndex].w_resize, (gdouble)val_ptr->point[endOfSegmentIndex].w_resize);
+    cur_ptr->currHeight   = MIX_VALUE(posFactor, (gdouble)val_ptr->point[startOfSegmentIndex].h_resize, (gdouble)val_ptr->point[endOfSegmentIndex].h_resize);
+  }
+  else
+  {
+    cur_ptr->currWidth    = MIX_VALUE(flt_posfactor, (gdouble)val_ptr->point[currPtidx -1].w_resize, (gdouble)val_ptr->point[currPtidx].w_resize);
+    cur_ptr->currHeight   = MIX_VALUE(flt_posfactor, (gdouble)val_ptr->point[currPtidx -1].h_resize, (gdouble)val_ptr->point[currPtidx].h_resize);
+  }
+
+
+  /* calculate Rotation settings for the currently processed Frame (or tween) */
+  if ((val_ptr->point[startOfSegmentIndex].accRotation != 0)
+  && (frameTweensInSegment > 0))
+  {
+    /* acceleration characteristic processing for rotation */
+    posFactor = p_calculate_posFactor_from_FrameTweens(frameTweensInSegment
+                                                      , currFrameTweenInSegment
+                                                      , val_ptr->point[startOfSegmentIndex].accRotation
+                                                      );
+    cur_ptr->currRotation = MIX_VALUE(posFactor, (gdouble)val_ptr->point[startOfSegmentIndex].rotation, (gdouble)val_ptr->point[endOfSegmentIndex].rotation);
+  }
+  else
+  {
+    cur_ptr->currRotation = MIX_VALUE(flt_posfactor, (gdouble)val_ptr->point[currPtidx -1].rotation, (gdouble)val_ptr->point[currPtidx].rotation);
+ 
+    if(gap_debug)
+    {
+      printf("p_mov_execute: framesPerLine=%f, flt_posfactor=%f\n"
+           , (float)framesPerLine
+           , (float)flt_posfactor
+           );
+      printf("ROTATE [%02d] %f    [%02d] %f       MIX: %f\n"
+          , (int)currPtidx-1,  (float)val_ptr->point[currPtidx -1].rotation
+          , (int)currPtidx,    (float)val_ptr->point[currPtidx].rotation
+          , (float)cur_ptr->currRotation);
+    }
+
+  }
+
+  /* calculate Perspective settings for the currently processed Frame (or tween) */
+  if ((val_ptr->point[startOfSegmentIndex].accPerspective != 0)
+  && (frameTweensInSegment > 0))
+  {
+    /* acceleration characteristic processing for rotation */
+    posFactor = p_calculate_posFactor_from_FrameTweens(frameTweensInSegment
+                                                      , currFrameTweenInSegment
+                                                      , val_ptr->point[startOfSegmentIndex].accPerspective
+                                                      );
+    cur_ptr->currTTLX     = MIX_VALUE(posFactor, (gdouble)val_ptr->point[startOfSegmentIndex].ttlx,     (gdouble)val_ptr->point[endOfSegmentIndex].ttlx);
+    cur_ptr->currTTLY     = MIX_VALUE(posFactor, (gdouble)val_ptr->point[startOfSegmentIndex].ttly,     (gdouble)val_ptr->point[endOfSegmentIndex].ttly);
+    cur_ptr->currTTRX     = MIX_VALUE(posFactor, (gdouble)val_ptr->point[startOfSegmentIndex].ttrx,     (gdouble)val_ptr->point[endOfSegmentIndex].ttrx);
+    cur_ptr->currTTRY     = MIX_VALUE(posFactor, (gdouble)val_ptr->point[startOfSegmentIndex].ttry,     (gdouble)val_ptr->point[endOfSegmentIndex].ttry);
+    cur_ptr->currTBLX     = MIX_VALUE(posFactor, (gdouble)val_ptr->point[startOfSegmentIndex].tblx,     (gdouble)val_ptr->point[endOfSegmentIndex].tblx);
+    cur_ptr->currTBLY     = MIX_VALUE(posFactor, (gdouble)val_ptr->point[startOfSegmentIndex].tbly,     (gdouble)val_ptr->point[endOfSegmentIndex].tbly);
+    cur_ptr->currTBRX     = MIX_VALUE(posFactor, (gdouble)val_ptr->point[startOfSegmentIndex].tbrx,     (gdouble)val_ptr->point[endOfSegmentIndex].tbrx);
+    cur_ptr->currTBRY     = MIX_VALUE(posFactor, (gdouble)val_ptr->point[startOfSegmentIndex].tbry,     (gdouble)val_ptr->point[endOfSegmentIndex].tbry);
+  }
+  else
+  {
+    cur_ptr->currTTLX     = MIX_VALUE(flt_posfactor, (gdouble)val_ptr->point[currPtidx -1].ttlx,     (gdouble)val_ptr->point[currPtidx].ttlx);
+    cur_ptr->currTTLY     = MIX_VALUE(flt_posfactor, (gdouble)val_ptr->point[currPtidx -1].ttly,     (gdouble)val_ptr->point[currPtidx].ttly);
+    cur_ptr->currTTRX     = MIX_VALUE(flt_posfactor, (gdouble)val_ptr->point[currPtidx -1].ttrx,     (gdouble)val_ptr->point[currPtidx].ttrx);
+    cur_ptr->currTTRY     = MIX_VALUE(flt_posfactor, (gdouble)val_ptr->point[currPtidx -1].ttry,     (gdouble)val_ptr->point[currPtidx].ttry);
+    cur_ptr->currTBLX     = MIX_VALUE(flt_posfactor, (gdouble)val_ptr->point[currPtidx -1].tblx,     (gdouble)val_ptr->point[currPtidx].tblx);
+    cur_ptr->currTBLY     = MIX_VALUE(flt_posfactor, (gdouble)val_ptr->point[currPtidx -1].tbly,     (gdouble)val_ptr->point[currPtidx].tbly);
+    cur_ptr->currTBRX     = MIX_VALUE(flt_posfactor, (gdouble)val_ptr->point[currPtidx -1].tbrx,     (gdouble)val_ptr->point[currPtidx].tbrx);
+    cur_ptr->currTBRY     = MIX_VALUE(flt_posfactor, (gdouble)val_ptr->point[currPtidx -1].tbry,     (gdouble)val_ptr->point[currPtidx].tbry);
+  }
+
+  /* calculate Selection Feather Radius settings for the currently processed Frame (or tween) */
+  if ((val_ptr->point[startOfSegmentIndex].accSelFeatherRadius != 0)
+  && (frameTweensInSegment > 0))
+  {
+    /* acceleration characteristic processing for rotation */
+    posFactor = p_calculate_posFactor_from_FrameTweens(frameTweensInSegment
+                                                      , currFrameTweenInSegment
+                                                      , val_ptr->point[startOfSegmentIndex].accSelFeatherRadius
+                                                      );
+    cur_ptr->currSelFeatherRadius = MIX_VALUE(posFactor, (gdouble)val_ptr->point[startOfSegmentIndex].sel_feather_radius,     (gdouble)val_ptr->point[endOfSegmentIndex].sel_feather_radius);
+  }
+  else
+  {
+    cur_ptr->currSelFeatherRadius = MIX_VALUE(flt_posfactor, (gdouble)val_ptr->point[currPtidx -1].sel_feather_radius,     (gdouble)val_ptr->point[currPtidx].sel_feather_radius);
+  }
+
+  return(frameNrAtEndOfSegment);
+}  /* end p_calculate_settings_for_current_FrameTween */
+
+
+
 /* ============================================================================
  * p_mov_execute
  * Copy layer(s) from Sourceimage to given destination frame range,
@@ -652,20 +1168,13 @@ p_mov_advance_src_frame(GapMovCurrent *cur_ptr, GapMovValues  *pvals)
 long
 p_mov_execute(GapMovData *mov_ptr)
 {
-/* MIX_VALUE  0.0 <= factor <= 1.0
- *  result is a  for factor 0.0
- *            b  for factor 1.0
- *            mix for factors inbetween
- */
-#define MIX_VALUE(factor, a, b) ((a * (1.0 - factor)) +  (b * factor))
-  gint l_idx;
+   gint l_idx;
    GapMovCurrent l_current_data;
    GapMovCurrent *cur_ptr;
    GapMovValues  *val_ptr;
 
    gdouble  l_percentage;
    gdouble  l_fpl;             /* frames_per_line */
-   gdouble  l_flt_posfactor;
    long     l_frame_step;
    gdouble  l_frames;
    long     l_cnt;
@@ -681,6 +1190,10 @@ p_mov_execute(GapMovData *mov_ptr)
    gint     l_apv_layerstack;
    gdouble  l_flt_timing[GAP_MOV_MAX_POINT];   /* timing table in relative frame numbers (0.0 == the first handled frame) */
 
+   gint startOfSegmentIndex;
+   gint endOfSegmentIndex;
+   gint frameNrAtEndOfSegment;
+
 
    if(mov_ptr->val_ptr->src_image_id < 0)
    {
@@ -690,6 +1203,7 @@ p_mov_execute(GapMovData *mov_ptr)
       return -1;
    }
 
+  frameNrAtEndOfSegment = 0;
   l_apv_layerstack = 0;
   l_percentage = 0.0;
   if(mov_ptr->dst_ainfo_ptr->run_mode == GIMP_RUN_INTERACTIVE)
@@ -744,6 +1258,13 @@ p_mov_execute(GapMovData *mov_ptr)
       printf("tbrx[%d] :%.3f\n", l_idx, (float)mov_ptr->val_ptr->point[l_idx].tbrx);
       printf("tbry[%d] :%.3f\n", l_idx, (float)mov_ptr->val_ptr->point[l_idx].tbry);
 
+      printf("accPosition        [%d] :%d\n", l_idx, (int)mov_ptr->val_ptr->point[l_idx].accPosition);
+      printf("accOpacity         [%d] :%d\n", l_idx, (int)mov_ptr->val_ptr->point[l_idx].accOpacity);
+      printf("accSize            [%d] :%d\n", l_idx, (int)mov_ptr->val_ptr->point[l_idx].accSize);
+      printf("accRotation        [%d] :%d\n", l_idx, (int)mov_ptr->val_ptr->point[l_idx].accRotation);
+      printf("accPerspective     [%d] :%d\n", l_idx, (int)mov_ptr->val_ptr->point[l_idx].accPerspective);
+      printf("accSelFeatherRadius[%d] :%d\n", l_idx, (int)mov_ptr->val_ptr->point[l_idx].accSelFeatherRadius);
+      
       printf("keyframe[%d] :%d\n", l_idx, mov_ptr->val_ptr->point[l_idx].keyframe);
       printf("keyframe_abs[%d] :%d\n", l_idx, mov_ptr->val_ptr->point[l_idx].keyframe_abs);
     }
@@ -792,7 +1313,7 @@ p_mov_execute(GapMovData *mov_ptr)
    {
       /* copy point[0] to point [1] because we need at least 2
        * points for the algorithms below to work.
-       * (simulates a line with lenght 0, to move along)
+       * (simulates a line with length 0, to move along)
        */
       if(gap_debug) printf("p_mov_execute: added a 2nd Point\n");
       val_ptr->point[1].p_x = val_ptr->point[0].p_x;
@@ -811,9 +1332,18 @@ p_mov_execute(GapMovData *mov_ptr)
       val_ptr->point[1].tbry = val_ptr->point[0].tbry;
       val_ptr->point[1].sel_feather_radius = val_ptr->point[0].sel_feather_radius;
 
+      val_ptr->point[1].accPosition         = val_ptr->point[0].accPosition;
+      val_ptr->point[1].accOpacity          = val_ptr->point[0].accOpacity;
+      val_ptr->point[1].accSize             = val_ptr->point[0].accSize;
+      val_ptr->point[1].accRotation         = val_ptr->point[0].accRotation;
+      val_ptr->point[1].accPerspective      = val_ptr->point[0].accPerspective;
+      val_ptr->point[1].accSelFeatherRadius = val_ptr->point[0].accSelFeatherRadius;
+
       l_points = 2;
    }
 
+   startOfSegmentIndex = 0;
+   endOfSegmentIndex = l_points -1;  /* initial value in case all points are in only 1 segment */
 
    cur_ptr->dst_frame_nr = val_ptr->dst_range_start;
    cur_ptr->src_layers = NULL;
@@ -859,7 +1389,7 @@ p_mov_execute(GapMovData *mov_ptr)
         }
      }
      cur_ptr->src_last_layer = l_nlayers -1;   /* index of last layer */
-     }
+   }
    else
    {
      /* for FRAME stepmodes we use flattened Sorce frames
@@ -895,6 +1425,15 @@ p_mov_execute(GapMovData *mov_ptr)
    cur_ptr->currTBRY = (gdouble)val_ptr->point[0].tbry;
    cur_ptr->currSelFeatherRadius = (gdouble)val_ptr->point[0].sel_feather_radius;
 
+   cur_ptr->accPosition         = val_ptr->point[0].accPosition;
+   cur_ptr->accOpacity          = val_ptr->point[0].accOpacity;
+   cur_ptr->accSize             = val_ptr->point[0].accSize;
+   cur_ptr->accRotation         = val_ptr->point[0].accRotation;
+   cur_ptr->accPerspective      = val_ptr->point[0].accPerspective;
+   cur_ptr->accSelFeatherRadius = val_ptr->point[0].accSelFeatherRadius;
+
+
+
    val_ptr->tween_image_id = -1;
    val_ptr->tween_layer_id = -1;
    val_ptr->trace_image_id = -1;
@@ -1006,7 +1545,7 @@ p_mov_execute(GapMovData *mov_ptr)
      }
    }
 
-
+  
   /* loop for each frame within the range (may step up or down) */
   l_ptidx = 1;
   cur_ptr->dst_frame_nr = val_ptr->dst_range_start;
@@ -1052,48 +1591,37 @@ p_mov_execute(GapMovData *mov_ptr)
        */
       for (val_ptr->twix = val_ptr->tween_steps; val_ptr->twix >= 0; val_ptr->twix--)
       {
+        gdouble l_flt_posfactor;
+        
         if(l_fpl != 0.0)
         {
-          l_flt_posfactor  = (   (((gdouble)l_fridx * l_tw_cnt) - (gdouble)val_ptr->twix)
+            l_flt_posfactor  = (   (((gdouble)l_fridx * l_tw_cnt) - (gdouble)val_ptr->twix)
                                - (l_flt_timing[l_ptidx -1] * l_tw_cnt)
                              ) / (l_fpl * l_tw_cnt);
         }
         else
         {
-           l_flt_posfactor = 1.0;
-           if(gap_debug) printf("p_mov_execute: ** ERROR l_fpl is 0.0 frames per line\n");
+            l_flt_posfactor = 1.0;
+            if(gap_debug) printf("p_mov_execute: ** ERROR l_fpl is 0.0 frames per line\n");
         }
-
-
-        if(gap_debug) printf("p_mov_execute: l_fpl=%f, l_flt_posfactor=%f\n", (float)l_fpl, (float)l_flt_posfactor);
-
+        
         l_flt_posfactor = CLAMP (l_flt_posfactor, 0.0, 1.0);
+      
+        endOfSegmentIndex = p_findEndOfSegmentIndex(val_ptr, startOfSegmentIndex, l_points);
+      
+        frameNrAtEndOfSegment = p_calculate_settings_for_current_FrameTween(val_ptr, cur_ptr
+             , l_fpl
+             , l_fridx
+             , l_ptidx
+             , l_flt_posfactor
+             , l_frames
+             , l_points
+             , startOfSegmentIndex
+             , endOfSegmentIndex
+             );
 
-        cur_ptr->currX  =       MIX_VALUE(l_flt_posfactor, (gdouble)val_ptr->point[l_ptidx -1].p_x,      (gdouble)val_ptr->point[l_ptidx].p_x);
-        cur_ptr->currY  =       MIX_VALUE(l_flt_posfactor, (gdouble)val_ptr->point[l_ptidx -1].p_y,      (gdouble)val_ptr->point[l_ptidx].p_y);
-        cur_ptr->currOpacity  = MIX_VALUE(l_flt_posfactor, (gdouble)val_ptr->point[l_ptidx -1].opacity,  (gdouble)val_ptr->point[l_ptidx].opacity);
-        cur_ptr->currWidth    = MIX_VALUE(l_flt_posfactor, (gdouble)val_ptr->point[l_ptidx -1].w_resize, (gdouble)val_ptr->point[l_ptidx].w_resize);
-        cur_ptr->currHeight   = MIX_VALUE(l_flt_posfactor, (gdouble)val_ptr->point[l_ptidx -1].h_resize, (gdouble)val_ptr->point[l_ptidx].h_resize);
-        cur_ptr->currRotation = MIX_VALUE(l_flt_posfactor, (gdouble)val_ptr->point[l_ptidx -1].rotation, (gdouble)val_ptr->point[l_ptidx].rotation);
-        cur_ptr->currTTLX     = MIX_VALUE(l_flt_posfactor, (gdouble)val_ptr->point[l_ptidx -1].ttlx,     (gdouble)val_ptr->point[l_ptidx].ttlx);
-        cur_ptr->currTTLY     = MIX_VALUE(l_flt_posfactor, (gdouble)val_ptr->point[l_ptidx -1].ttly,     (gdouble)val_ptr->point[l_ptidx].ttly);
-        cur_ptr->currTTRX     = MIX_VALUE(l_flt_posfactor, (gdouble)val_ptr->point[l_ptidx -1].ttrx,     (gdouble)val_ptr->point[l_ptidx].ttrx);
-        cur_ptr->currTTRY     = MIX_VALUE(l_flt_posfactor, (gdouble)val_ptr->point[l_ptidx -1].ttry,     (gdouble)val_ptr->point[l_ptidx].ttry);
-        cur_ptr->currTBLX     = MIX_VALUE(l_flt_posfactor, (gdouble)val_ptr->point[l_ptidx -1].tblx,     (gdouble)val_ptr->point[l_ptidx].tblx);
-        cur_ptr->currTBLY     = MIX_VALUE(l_flt_posfactor, (gdouble)val_ptr->point[l_ptidx -1].tbly,     (gdouble)val_ptr->point[l_ptidx].tbly);
-        cur_ptr->currTBRX     = MIX_VALUE(l_flt_posfactor, (gdouble)val_ptr->point[l_ptidx -1].tbrx,     (gdouble)val_ptr->point[l_ptidx].tbrx);
-        cur_ptr->currTBRY     = MIX_VALUE(l_flt_posfactor, (gdouble)val_ptr->point[l_ptidx -1].tbry,     (gdouble)val_ptr->point[l_ptidx].tbry);
-        cur_ptr->currSelFeatherRadius = MIX_VALUE(l_flt_posfactor, (gdouble)val_ptr->point[l_ptidx -1].sel_feather_radius,     (gdouble)val_ptr->point[l_ptidx].sel_feather_radius);
 
 
-        if(gap_debug)
-        {
-          printf("ROTATE [%02d] %f    [%02d] %f       MIX: %f\n"
-          , (int)l_ptidx-1,  (float)val_ptr->point[l_ptidx -1].rotation
-          , (int)l_ptidx,    (float)val_ptr->point[l_ptidx].rotation
-          , (float)cur_ptr->currRotation);
-        }
-
         if(val_ptr->src_stepmode < GAP_STEP_FRAME )
         {
            /* advance settings for next src layer */
@@ -1119,6 +1647,12 @@ p_mov_execute(GapMovData *mov_ptr)
         l_rc = p_mov_call_render(mov_ptr, cur_ptr, l_apv_layerstack);
 
       }  /* end tweenindex subloop */
+      
+      /* advance to next path segment */
+      if(l_fridx >= frameNrAtEndOfSegment)
+      {
+         startOfSegmentIndex = endOfSegmentIndex;
+      }
 
       /* show progress */
       if(mov_ptr->dst_ainfo_ptr->run_mode == GIMP_RUN_INTERACTIVE)
@@ -1414,9 +1948,10 @@ gap_mov_exec_conv_keyframe_to_abs(gint rel_keyframe, GapMovValues *pvals)
 }
 
 
-/* ============================================================================
+
+/* ----------------------------------
  * gap_mov_exec_gap_save_pointfile
- * ============================================================================
+ * ----------------------------------
  */
 gint
 gap_mov_exec_gap_save_pointfile(char *filename, GapMovValues *pvals)
@@ -1436,7 +1971,14 @@ gap_mov_exec_gap_save_pointfile(char *filename, GapMovValues *pvals)
     fprintf(l_fp, "# x  y   width height opacity rotation feather_radius number_of_optional_params [8 perspective transform factors] [rel_keyframe]\n");
     for(l_idx = 0; l_idx <= pvals->point_idx_max; l_idx++)
     {
-      gint num_optional_params;
+      gint optional_params_indicator;
+      gboolean writePerspective;
+      gboolean writeAccelerationCharacteristics;
+      gboolean writeKeyframe;
+
+      writePerspective = FALSE;
+      writeAccelerationCharacteristics = FALSE;
+      writeKeyframe = FALSE;
 
       fprintf(l_fp, "%04d %04d "
                     , (int)pvals->point[l_idx].p_x
@@ -1448,7 +1990,7 @@ gap_mov_exec_gap_save_pointfile(char *filename, GapMovValues *pvals)
       gap_base_fprintf_gdouble(l_fp, pvals->point[l_idx].rotation, 3, 3, " ");
       gap_base_fprintf_gdouble(l_fp, pvals->point[l_idx].sel_feather_radius, 3, 3, " ");
 
-      num_optional_params = 0;
+      optional_params_indicator = 0;
 
       /* conditional write transformation (only if there is any) */
       if(pvals->point[l_idx].ttlx != 1.0
@@ -1461,18 +2003,49 @@ gap_mov_exec_gap_save_pointfile(char *filename, GapMovValues *pvals)
       || pvals->point[l_idx].tbry != 1.0
       )
       {
-        num_optional_params = 8;
+        optional_params_indicator += 8;
+        writePerspective = TRUE;
       }
+
+      /* conditional write acceleration characteristics
+       * relevant information can occur at first controlpoint
+       * or on keyframes but never for the last controlpoint)
+       */
+      if (pvals->point[l_idx].accPosition != 0)
+      {
+        if (l_idx == 0) 
+        {
+          writeAccelerationCharacteristics = TRUE;
+        }
+        else
+        {
+          if ((l_idx < pvals->point_idx_max)
+          && ((int)pvals->point[l_idx].keyframe > 0))
+          {
+            writeAccelerationCharacteristics = TRUE;
+          }
+        }
+        
+        if (writeAccelerationCharacteristics == TRUE)
+        {
+          optional_params_indicator += 6;
+        }
+      }
+
+      /* check for writing keyframe
+       * (the implicite keyframes at first and last controlpoints are not written to file)
+       */
       if((l_idx > 0)
       && (l_idx < pvals->point_idx_max)
       && ((int)pvals->point[l_idx].keyframe > 0))
       {
-        num_optional_params++;
+        optional_params_indicator++;
+        writeKeyframe = TRUE;
       }
 
-      fprintf(l_fp, "   %02d ", (int)num_optional_params);
+      fprintf(l_fp, "   %02d ", (int)optional_params_indicator);
 
-      if(num_optional_params >= 8)
+      if(writePerspective == TRUE)
       {
         fprintf(l_fp, " ");
         gap_base_fprintf_gdouble(l_fp, pvals->point[l_idx].ttlx, 2, 3, " ");
@@ -1488,10 +2061,21 @@ gap_mov_exec_gap_save_pointfile(char *filename, GapMovValues *pvals)
         gap_base_fprintf_gdouble(l_fp, pvals->point[l_idx].tbry, 2, 3, " ");
       }
 
+
+      if(writeAccelerationCharacteristics == TRUE)
+      {
+        fprintf(l_fp, " %02d %02d %02d %02d %02d %02d"
+           , (int)pvals->point[l_idx].accPosition 
+           , (int)pvals->point[l_idx].accOpacity
+           , (int)pvals->point[l_idx].accSize
+           , (int)pvals->point[l_idx].accRotation
+           , (int)pvals->point[l_idx].accPerspective
+           , (int)pvals->point[l_idx].accSelFeatherRadius
+           );
+      }
+
       /* conditional write keyframe */
-      if((l_idx > 0)
-      && (l_idx < pvals->point_idx_max)
-      && ((int)pvals->point[l_idx].keyframe > 0))
+      if(writeKeyframe == TRUE)
       {
         fprintf(l_fp, " %d"
                      , (int)gap_mov_exec_conv_keyframe_to_rel(pvals->point[l_idx].keyframe_abs, pvals)
@@ -1508,9 +2092,9 @@ gap_mov_exec_gap_save_pointfile(char *filename, GapMovValues *pvals)
 
 
 
-/* ============================================================================
+/* ----------------------------------
  * gap_mov_exec_gap_load_pointfile
- * ============================================================================
+ * ----------------------------------
  * return 0 if Load was OK,
  * return -2 when load has read inconsistent pointfile
  *           and the pointtable needs to be reset (dialog has to call p_reset_points)
@@ -1519,7 +2103,7 @@ gint
 gap_mov_exec_gap_load_pointfile(char *filename, GapMovValues *pvals)
 {
 #define POINT_REC_MAX 512
-#define MAX_NUMVALUES_PER_LINE 17
+#define MAX_NUMVALUES_PER_LINE 23
   FILE   *l_fp;
   gint    l_idx;
   char    l_buff[POINT_REC_MAX +1 ];
@@ -1549,38 +2133,34 @@ gap_mov_exec_gap_load_pointfile(char *filename, GapMovValues *pvals)
          l_cnt = gap_base_sscan_flt_numbers(l_ptr, &l_farr[0], MAX_NUMVALUES_PER_LINE);
          l_i1 = (gint)l_farr[0];
          l_i2 = (gint)l_farr[1];
+         
+         if(gap_debug)
+         {
+            gint ii;
+            
+            printf("scanned %d numbers\n", l_cnt);
+            for(ii=0; ii < l_cnt; ii++)
+            {
+              printf("  value[%02d] : %f\n", (int)ii, (float)l_farr[ii]);
+            }
+         }
          if(l_idx == -1)
          {
            if((l_cnt < 2) || (l_i2 > GAP_MOV_MAX_POINT) || (l_i1 > l_i2))
            {
              break;
-            }
+           }
            pvals->point_idx     = l_i1;
            pvals->point_idx_max = l_i2 -1;
            l_idx = 0;
          }
          else
          {
-           gdouble num_optional_params;
+           gint    optional_params_indicator;
            gint    key_idx;
-           /* the older format used in GAP.1.2 has 6 or 7 integer numbers per line
-            * and should be compatible and readable by this code.
-            *
-            * the new format has 2 integer values (p_x, p_y)
-            * and 5 float values (w_resize, h_resize, opacity, rotation, feather_radius)
-            * and 1 int value num_optional_params (telling how much will follow)
-            * the rest of the line is optional
-            *  8  additional float values (transformation factors) 7th upto 14th parameter
-            *  1  integer values (keyframe) as 7th parameter
-            *         or as 15th parameter (if transformation factors are present too)
-            */
-           if((l_cnt != 6) && (l_cnt != 7)   /* for compatibility to old format */
-           && (l_cnt != 8) && (l_cnt != 9) && (l_cnt != 16) && (l_cnt != 17))
-           {
-             /* invalid pointline format detected */
-             l_rc = -2;  /* have to call p_reset_points() when called from dialog window */
-             break;
-           }
+           gint    acc_idx;
+           gint    perspective_idx;
+
            pvals->point[l_idx].keyframe_abs = 0;
            pvals->point[l_idx].keyframe = 0;
            pvals->point[l_idx].p_x      = l_i1;
@@ -1598,23 +2178,104 @@ gap_mov_exec_gap_load_pointfile(char *filename, GapMovValues *pvals)
            pvals->point[l_idx].opacity  = l_farr[4];
            pvals->point[l_idx].rotation = l_farr[5];
            pvals->point[l_idx].sel_feather_radius = 0.0;
+
+           pvals->point[l_idx].accPosition         = 0;
+           pvals->point[l_idx].accOpacity          = 0;
+           pvals->point[l_idx].accSize             = 0;
+           pvals->point[l_idx].accRotation         = 0;
+           pvals->point[l_idx].accPerspective      = 0;
+           pvals->point[l_idx].accSelFeatherRadius = 0;
+
+          /* the older format used in GAP.1.2 has 6 or 7 integer numbers per line
+            * and is still readable by this code.
+            *
+            * the new format has 2 integer values (p_x, p_y)
+            * and 5 float values (w_resize, h_resize, opacity, rotation, feather_radius)
+            * and 1 int value optional_params_indicator (telling how much and what kind of parameter will follow)
+            * possible optional parameter(s) are:
+            * (if all of them are present, then in the order as listed below)
+            *
+            *     8  float values for the transformation factors
+            *     6  int values for acceleration characteristics (since GIMP_GAP 2.7.x)
+            *     1  int value for keyframe information (not present at first and last controlpoint)
+            */
+           if((l_cnt != 6) && (l_cnt != 7)   /* for compatibility to old format */
+           && (l_cnt != 8) && (l_cnt != 9)   && (l_cnt != 16) && (l_cnt != 17)  /* for GAP 2.6.x format */
+           && (l_cnt != 14) && (l_cnt != 15) && (l_cnt != 22) && (l_cnt != 23) )
+           {
+             /* invalid pointline format detected */
+             l_rc = -2;  /* have to call p_reset_points() when called from dialog window */
+
+             printf("invalid move path pointfile %d numbers per line are not supported\n", (int)l_cnt);
+             break;
+           }
+
+           optional_params_indicator = 0;
+           key_idx = -1;
+           acc_idx = -1;
+           perspective_idx = -1;
+
            if(l_cnt >= 8)
            {
              pvals->point[l_idx].sel_feather_radius = l_farr[6];
-             num_optional_params = l_farr[7];
+             optional_params_indicator = l_farr[7];
            }
-           if(l_cnt >= 16)
+
+
+           if(gap_debug)
            {
-             pvals->point[l_idx].ttlx = l_farr[8];
-             pvals->point[l_idx].ttly = l_farr[9];
-             pvals->point[l_idx].ttrx = l_farr[10];
-             pvals->point[l_idx].ttry = l_farr[11];
-             pvals->point[l_idx].tblx = l_farr[12];
-             pvals->point[l_idx].tbly = l_farr[13];
-             pvals->point[l_idx].tbrx = l_farr[14];
-             pvals->point[l_idx].tbry = l_farr[15];
+             printf("gap_mov_exec_gap_load_pointfile  optional_params_indicator:%d\n", optional_params_indicator);
            }
-           key_idx = -1;
+
+
+           switch (optional_params_indicator)
+           {
+               case 0:
+                   break;
+               case 1:
+                   /* have one keyframe value */
+                   key_idx = 8;
+                   break;
+               case 6:
+                   /* have six accelerate characteristic values */
+                   acc_idx = 8;
+                   break;
+               case 7:
+                   /* have six accelerate characteristic values 
+                    * and one keyframe value
+                    */
+                   acc_idx = 8;
+                   key_idx = 8 + 6;
+                   break;
+               case 8:
+                   /* have eight perspective values */
+                   perspective_idx = 8;
+                   break;
+               case 9:
+                   /* have eight perspective values
+                    * and one keyframe value
+                    */
+                   perspective_idx = 8;
+                   key_idx         = 8 + 8;
+                   break;
+               case 14:
+                   /* have eight perspective values
+                    * and six accelerate characteristic values
+                    */
+                   perspective_idx = 8;
+                   acc_idx         = 8 + 8;
+                   break;
+               case 15:
+                   /* have eight perspective values
+                    * and six accelerate characteristic values
+                    * and one keyframe value
+                    */
+                   perspective_idx = 8;
+                   acc_idx         = 8 + 8;
+                   key_idx         = 8 + 8 + 6;
+                   break;
+           }
+
            if(l_idx > 0)
            {
              switch(l_cnt)
@@ -1622,14 +2283,30 @@ gap_mov_exec_gap_load_pointfile(char *filename, GapMovValues *pvals)
                case 7:
                    key_idx = 6; /* for compatibilty with old format */
                    break;
-               case 9:
-                   key_idx = 8;
-                   break;
-               case 17:
-                   key_idx = 16;
-                   break;
              }
            }
+
+           if(perspective_idx >= 0)
+           {
+             pvals->point[l_idx].ttlx = l_farr[perspective_idx];
+             pvals->point[l_idx].ttly = l_farr[perspective_idx +1];
+             pvals->point[l_idx].ttrx = l_farr[perspective_idx +2];
+             pvals->point[l_idx].ttry = l_farr[perspective_idx +3];
+             pvals->point[l_idx].tblx = l_farr[perspective_idx +4];
+             pvals->point[l_idx].tbly = l_farr[perspective_idx +5];
+             pvals->point[l_idx].tbrx = l_farr[perspective_idx +6];
+             pvals->point[l_idx].tbry = l_farr[perspective_idx +7];
+           }
+           if(acc_idx >= 0)
+           {
+             pvals->point[l_idx].accPosition         = l_farr[acc_idx];
+             pvals->point[l_idx].accOpacity          = l_farr[acc_idx +1];
+             pvals->point[l_idx].accSize             = l_farr[acc_idx +2];
+             pvals->point[l_idx].accRotation         = l_farr[acc_idx +3];
+             pvals->point[l_idx].accPerspective      = l_farr[acc_idx +4];
+             pvals->point[l_idx].accSelFeatherRadius = l_farr[acc_idx +5];
+           }
+
            if(key_idx > 0)
            {
              pvals->point[l_idx].keyframe = l_farr[key_idx];



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]