gimp-gap r800 - in trunk: . docs/reference/txt gap vid_common vid_enc_avi vid_enc_rawframes



Author: wolfgangh
Date: Wed Jan 14 19:59:24 2009
New Revision: 800
URL: http://svn.gnome.org/viewvc/gimp-gap?rev=800&view=rev

Log:
gap frame fetcher uses parasites, area replace (logo remove by resynthesizer wrapper) 

Added:
   trunk/gap/gap_morph_tween_dialog.c
   trunk/gap/gap_morph_tween_dialog.h
   trunk/gap/gap_wr_resynth.c   (contents, props changed)
Modified:
   trunk/ChangeLog
   trunk/docs/reference/txt/plug-in-gap-storyboard-master-prop.txt
   trunk/gap/Makefile.am
   trunk/gap/gap_file_util.c
   trunk/gap/gap_filter_iterators.c
   trunk/gap/gap_frame_fetcher.c
   trunk/gap/gap_image.c
   trunk/gap/gap_image.h
   trunk/gap/gap_layer_copy.c
   trunk/gap/gap_layer_copy.h
   trunk/gap/gap_morph_dialog.c
   trunk/gap/gap_morph_dialog.h
   trunk/gap/gap_morph_exec.c
   trunk/gap/gap_morph_exec.h
   trunk/gap/gap_morph_main.c
   trunk/gap/gap_morph_main.h
   trunk/gap/gap_story_dialog.c
   trunk/gap/gap_story_file.c
   trunk/gap/gap_story_file.h
   trunk/gap/gap_story_main.h
   trunk/gap/gap_story_properties.c
   trunk/gap/gap_story_render_lossless.c
   trunk/gap/gap_story_render_processor.c
   trunk/gap/gap_story_render_types.h
   trunk/gap/gap_story_syntax.c
   trunk/gap/gap_story_syntax.h
   trunk/vid_common/gap_cme_gui.c
   trunk/vid_enc_avi/gap_enc_avi_main.c
   trunk/vid_enc_rawframes/gap_enc_rawframes_main.c

Modified: trunk/docs/reference/txt/plug-in-gap-storyboard-master-prop.txt
==============================================================================
--- trunk/docs/reference/txt/plug-in-gap-storyboard-master-prop.txt	(original)
+++ trunk/docs/reference/txt/plug-in-gap-storyboard-master-prop.txt	Wed Jan 14 19:59:24 2009
@@ -58,5 +58,24 @@
       where values greater than 1.0 will amplify the volume.
       (with the risk of producing noise on overflow)
       
+    AreaFormat:
+      This format string triggers automatical logo insertation
+      for all handled clips of type MOVIE. 
+      The area format string shall contain the placeholder %s
+      that is replaced by the basename of the currently processed
+      videoclip. The placeholder %06d is replaced by the current
+      framenumber.
+      The storyboard processing builds the filename of a logo image
+      whenever a frame is fetched from a movie clip
+      and pastes the logo into the frame in case the logo image exists.
+      If the format does not contain any placeholder, the same logo
+      will be used in all handled movie clips.
+
+      Frame specific Example:
+        AreaFormat: /logo_frames/%s/logo_frame_%06d.xcf
       
+        Procesing of frame 7 of movie clip /videos/MY_VIDEO.AVI
+        will paste logo image /logo_frames/MY_VIDEO.AVI/logo_frame_000007.xcf
 
+        Procesing of frame 22 of movie clip /videos/YOUR_VIDEO.MPEG
+        will paste logo image /logo_frames/YOUR_VIDEO.MPEG/logo_frame_000022.xcf

Modified: trunk/gap/Makefile.am
==============================================================================
--- trunk/gap/Makefile.am	(original)
+++ trunk/gap/Makefile.am	Wed Jan 14 19:59:24 2009
@@ -107,6 +107,7 @@
 	gap_wr_color_levels	\
 	gap_wr_color_huesat	\
 	gap_wr_trans		\
+	gap_wr_resynth		\
 	gap_wr_opacity
 
 gap_bluebox_SOURCES = \
@@ -236,6 +237,8 @@
 	gap_morph_exec.h	\
 	gap_morph_dialog.c	\
 	gap_morph_dialog.h	\
+	gap_morph_tween_dialog.c	\
+	gap_morph_tween_dialog.h	\
 	gap_mov_dialog.h	\
 	gap_mov_exec.h		\
 	gap_libgimpgap.h	
@@ -355,6 +358,12 @@
 	gap_wr_color_huesat.c	\
 	gap_libgimpgap.h
 
+gap_wr_resynth_SOURCES = \
+	gap_wr_resynth.c	\
+	gap_lastvaldesc.c	\
+	gap_lastvaldesc.h	\
+	gap_libgimpgap.h
+
 
 if OS_WIN32
 mwindows = -mwindows
@@ -397,6 +406,7 @@
 gap_wr_color_curve_LDADD =   $(LIBGIMPGAP)  $(LIBGAPBASE) $(GIMP_LIBS)
 gap_wr_color_levels_LDADD =  $(LIBGIMPGAP)  $(LIBGAPBASE) $(GIMP_LIBS)
 gap_wr_color_huesat_LDADD =  $(LIBGIMPGAP)  $(LIBGAPBASE) $(GIMP_LIBS)
+gap_wr_resynth_LDADD =       $(LIBGIMPGAP)  $(LIBGAPBASE) $(GIMP_LIBS)
 
 EXTRA_DIST = \
 	README							\

Modified: trunk/gap/gap_file_util.c
==============================================================================
--- trunk/gap/gap_file_util.c	(original)
+++ trunk/gap/gap_file_util.c	Wed Jan 14 19:59:24 2009
@@ -331,9 +331,12 @@
 {
   struct stat  l_stat;
 
-  if (0 == g_stat(filename, &l_stat))
+  if(filename != NULL)
   {
-    return(l_stat.st_mtime);
+    if (0 == g_stat(filename, &l_stat))
+    {
+      return(l_stat.st_mtime);
+    }
   }
   return(0);
   

Modified: trunk/gap/gap_filter_iterators.c
==============================================================================
--- trunk/gap/gap_filter_iterators.c	(original)
+++ trunk/gap/gap_filter_iterators.c	Wed Jan 14 19:59:24 2009
@@ -434,63 +434,6 @@
   
 }  /* end p_delta_drawable */
 
-
-/* ---------------------------
- * p_delta_drawable_simple
- * ---------------------------
- * simple iteration for drawable id (in case val_from and val_to both refere to
- * the same image (that is already opened in the current gimp session)
- */
-static void 
-p_delta_drawable_simple(gint32 *val, gint32 val_from, gint32 val_to, gint32 total_steps, gdouble current_step)
-{
-  gint    l_nlayers;
-  gint32 *l_layers_list;
-  gint32  l_tmp_image_id;
-  gint    l_idx, l_idx_from, l_idx_to;
-
-  if(gap_debug)
-  {
-    printf("p_delta_drawable_simple: START *val drawable_id:%d (from:%d  to:%d)\n"
-      ,(int)*val
-      ,(int)val_from
-      ,(int)val_to
-      );
-  }
-  if((val_from < 0) || (val_to < 0))
-  {
-    return;
-  }
-
-  l_tmp_image_id = gimp_drawable_get_image(val_from);
-
-  /* check if from and to values are both valid drawables within the same image */
-  if ((l_tmp_image_id > 0)
-  &&  (l_tmp_image_id = gimp_drawable_get_image(val_to)))
-  {
-     l_idx_from = -1;
-     l_idx_to   = -1;
-
-     /* check the layerstack index of from and to drawable */
-     l_layers_list = gimp_image_get_layers(l_tmp_image_id, &l_nlayers);
-     for (l_idx = l_nlayers -1; l_idx >= 0; l_idx--)
-     {
-        if( l_layers_list[l_idx] == val_from ) l_idx_from = l_idx;
-        if( l_layers_list[l_idx] == val_to )   l_idx_to   = l_idx;
-
-        if((l_idx_from != -1) && (l_idx_to != -1))
-        {
-          /* OK found both index values, iterate the index (proceed to next layer) */
-          p_delta_gint(&l_idx, l_idx_from, l_idx_to, total_steps, current_step);
-          *val = l_layers_list[l_idx];
-          break;
-        }
-     }
-     g_free (l_layers_list);
-  }
-}  /* end p_delta_drawable_simple */
-
-
 /* ------------------------------------
  * p_drawable_is_alive
  * ------------------------------------
@@ -568,6 +511,70 @@
   return FALSE ;   /* INVALID image id */
 }  /* end p_drawable_is_alive */
 
+
+/* ---------------------------
+ * p_delta_drawable_simple
+ * ---------------------------
+ * simple iteration for drawable id (in case val_from and val_to both refere to
+ * the same image (that is already opened in the current gimp session)
+ */
+static void 
+p_delta_drawable_simple(gint32 *val, gint32 val_from, gint32 val_to, gint32 total_steps, gdouble current_step)
+{
+  gint    l_nlayers;
+  gint32 *l_layers_list;
+  gint32  l_tmp_image_id;
+  gint    l_idx, l_idx_from, l_idx_to;
+
+  if(gap_debug)
+  {
+    printf("p_delta_drawable_simple: START *val drawable_id:%d (from:%d  to:%d)\n"
+      ,(int)*val
+      ,(int)val_from
+      ,(int)val_to
+      );
+  }
+  if((val_from < 0) || (val_to < 0))
+  {
+    return;
+  }
+  if(p_drawable_is_alive(val_from) != TRUE)
+  {
+    return;
+  }
+  if(p_drawable_is_alive(val_to) != TRUE)
+  {
+    return;
+  }
+  l_tmp_image_id = gimp_drawable_get_image(val_from);
+
+  /* check if from and to values are both valid drawables within the same image */
+  if ((l_tmp_image_id > 0)
+  &&  (l_tmp_image_id = gimp_drawable_get_image(val_to)))
+  {
+     l_idx_from = -1;
+     l_idx_to   = -1;
+
+     /* check the layerstack index of from and to drawable */
+     l_layers_list = gimp_image_get_layers(l_tmp_image_id, &l_nlayers);
+     for (l_idx = l_nlayers -1; l_idx >= 0; l_idx--)
+     {
+        if( l_layers_list[l_idx] == val_from ) l_idx_from = l_idx;
+        if( l_layers_list[l_idx] == val_to )   l_idx_to   = l_idx;
+
+        if((l_idx_from != -1) && (l_idx_to != -1))
+        {
+          /* OK found both index values, iterate the index (proceed to next layer) */
+          p_delta_gint(&l_idx, l_idx_from, l_idx_to, total_steps, current_step);
+          *val = l_layers_list[l_idx];
+          break;
+        }
+     }
+     g_free (l_layers_list);
+  }
+}  /* end p_delta_drawable_simple */
+
+
 /* --------------------------------------------
  * p_capture_image_name_and_assign_pesistent_id
  * --------------------------------------------

Modified: trunk/gap/gap_frame_fetcher.c
==============================================================================
--- trunk/gap/gap_frame_fetcher.c	(original)
+++ trunk/gap/gap_frame_fetcher.c	Wed Jan 14 19:59:24 2009
@@ -5,6 +5,7 @@
  *  
  *  It holds a global image cache of temporary gimp images intended for
  *  read only access in various gimp-gap render processings.
+ *  (those cached images are marked with an image parasite)
  *  
  *  There are methods to get the temporary image 
  *  or to get a duplicate that has only one layer at imagesize.
@@ -13,19 +14,19 @@
  *  For videofiles it holds a cache of open videofile handles.
  *  (note that caching of videoframes is already available in the videohandle)
  *  
- *  The current implementation of the frame fetcher is NOT multithred save !
+ *  The current implementation of the frame fetcher is NOT multithread save !
  *  (the procedures may drop cached images that are still in use by a concurrent thread
- *  further the cache lists can be messe up if they are modified by concurrent threads
+ *  further the cache lists can be messed up if they are modified by concurrent threads
  *  at the same time.
  *
  *  Currently there is no support to keep track of cached images during the full length
- *  of a gimp session. This simple version of the frame fetcher is limited 
- *  to one main program (such as the storyboard or the filtermacro plug-in)
- *  and loses its information on exit of the main program.
+ *  of a gimp session. Therefore unregister of the last user does NOT drop all resources
+ *  
  *  (If there are still registrated users at exit time, the cached images are still
  *  loaded in the gimp session)
- *  TODO: a more sophisticated version of the frame fetcher may keep its information
- *        using the gimp_det_data feature or mark the cached images with a tattoo.
+ *
+ *  TODO: user registration shall be serialized and stored via gimp_set_data
+ *        to keep track over the entire gimp session.
  *
 
  *
@@ -85,10 +86,18 @@
 
 #include "gap_frame_fetcher.h"
 
-#define GAP_FFETCH_MAX_IMG_CACHE_ELEMENTS 12
+#define GAP_FFETCH_MAX_IMG_CACHE_ELEMENTS 18
 #define GAP_FFETCH_MAX_GVC_CACHE_ELEMENTS 6
 #define GAP_FFETCH_GVA_FRAMES_TO_KEEP_CACHED 36
 
+/* the lists of cached images and duplicates are implemented via GIMP image parasites,
+ * where images are simply loaded by GIMP without adding a display and marked with a non persistent parasite.
+ * the GAP_IMAGE_CACHE_PARASITE holds the modification timestamp (mtime) and full filename (inclusive terminating 0)
+ * the GAP_IMAGE_DUP_CACHE_PARASITE holds the gint32 ffetch_user_id
+ */
+
+#define GAP_IMAGE_CACHE_PARASITE "GAP-IMAGE-CACHE-PARASITE"
+#define GAP_IMAGE_DUP_CACHE_PARASITE "GAP-IMAGE-DUP-CACHE-PARASITE"
 
 
 typedef struct GapFFetchResourceUserElem
@@ -98,31 +107,6 @@
 } GapFFetchResourceUserElem;
 
 
-
-typedef struct GapFFetchDuplicatedImagesElem
-{
-   gint32  ffetch_user_id;
-   gint32  image_id;
-   void *next;
-} GapFFetchDuplicatedImagesElem;
-
-
-/* -------- types for the image cache  ------- */
-
-typedef struct GapFFetchImageCacheElem
-{
-   gint32  image_id;
-   char   *filename;
-   void *next;
-} GapFFetchImageCacheElem;
-
-typedef struct GapFFetchImageCache
-{
-  GapFFetchImageCacheElem *ic_list;
-  gint32            max_img_cache;  /* number of images to hold in the cache */
-} GapFFetchImageCache;
-
-
 /* -------- types for the video handle cache  ------- */
 
 typedef struct GapFFetchGvahandCacheElem
@@ -150,10 +134,6 @@
  *************************************************************
  */
 
-static GapFFetchDuplicatedImagesElem *global_duplicated_images = NULL;
-
-static GapFFetchImageCache *global_imcache = NULL;
-
 static GapFFetchGvahandCache *global_gvcache = NULL;
 
 static GapFFetchResourceUserElem *global_rsource_users = NULL;
@@ -163,7 +143,6 @@
  *************************************************************
  */
 static gint32         p_load_cache_image(const char* filename, gboolean addToCache);
-static void           p_drop_image_cache_elem1(GapFFetchImageCache *imcache);
 static void           p_drop_image_cache(void);
 #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT
 static void           p_drop_gvahand_cache_elem1(GapFFetchGvahandCache *gvcache);
@@ -176,32 +155,6 @@
 static void           p_add_image_to_list_of_duplicated_images(gint32 image_id, gint32 ffetch_user_id);
 
 
-/* ----------------------------------------------------
- * p_find_img_cache_by_image_id
- * ----------------------------------------------------
- */
-static GapFFetchImageCacheElem  *
-p_find_img_cache_by_image_id(gint32 image_id)
-{
-  GapFFetchImageCacheElem  *ic_ptr;
-
-  if((global_imcache == NULL) || (image_id < 0))
-  {
-    return (NULL);
-  }
-
-  for(ic_ptr = global_imcache->ic_list; ic_ptr != NULL; ic_ptr = (GapFFetchImageCacheElem *)ic_ptr->next)
-  {
-    if(ic_ptr->image_id == image_id)
-    {
-      /* image found in cache */
-      return(ic_ptr);
-    }
-  }
-
-  return (NULL);
-}  /* end  p_find_img_cache_by_image_id */
-
 
 /* ----------------------------------------------------
  * p_load_cache_image
@@ -210,115 +163,155 @@
 static gint32
 p_load_cache_image(const char* filename, gboolean addToCache)
 {
-  gint32 l_idx;
   gint32 l_image_id;
-  GapFFetchImageCacheElem  *ic_ptr;
-  GapFFetchImageCacheElem  *ic_last;
-  GapFFetchImageCacheElem  *ic_new;
-  GapFFetchImageCache  *imcache;
   char *l_filename;
 
+  gint32 *images;
+  gint    nimages;
+  gint    l_idi;
+  gint    l_number_of_cached_images;
+  gint32  l_first_chached_image_id;
+  GimpParasite  *l_parasite;
+
+
   if(filename == NULL)
   {
-    printf("p_load_cache_image: ** ERROR cant load filename == NULL!\n");
+    printf("p_load_cache_image: ** ERROR cant load filename == NULL! pid:%d\n", (int)getpid());
     return -1;
   }
 
-  if(global_imcache == NULL)
+  l_image_id = -1;
+  l_first_chached_image_id = -1;
+  l_number_of_cached_images = 0;
+  images = gimp_image_list(&nimages);
+  for(l_idi=0; l_idi < nimages; l_idi++)
   {
-    /* init the global_image cache */
-    global_imcache = g_malloc0(sizeof(GapFFetchImageCache));
-    global_imcache->ic_list = NULL;
-    global_imcache->max_img_cache = GAP_FFETCH_MAX_IMG_CACHE_ELEMENTS;
-  }
+    l_parasite = gimp_image_parasite_find(images[l_idi], GAP_IMAGE_CACHE_PARASITE);
 
-  imcache = global_imcache;
-  ic_last = imcache->ic_list;
-
-  l_idx = 0;
-  for(ic_ptr = imcache->ic_list; ic_ptr != NULL; ic_ptr = (GapFFetchImageCacheElem *)ic_ptr->next)
-  {
-    l_idx++;
-    if(strcmp(filename, ic_ptr->filename) == 0)
+    if(l_parasite)
     {
-      if(gap_debug)
+      gint32 *mtime_ptr;
+      gchar  *filename_ptr;
+      
+      mtime_ptr = (gint32 *) l_parasite->data;
+      filename_ptr = (gchar *)&l_parasite->data[sizeof(gint32)];
+    
+      l_number_of_cached_images++;
+      if (l_first_chached_image_id < 0)
+      {
+        l_first_chached_image_id = images[l_idi];
+      }
+      
+      if(strcmp(filename, filename_ptr) == 0)
       {
-        printf("FrameFetcher: p_load_cache_image CACHE-HIT :%s (image_id:%d)\n"
-          , ic_ptr->filename, (int)ic_ptr->image_id);
+        gint32 mtimefile;
+        
+        mtimefile = gap_file_get_mtime(filename);
+        if(mtimefile == *mtime_ptr)
+        {
+          /* image found in cache */
+          l_image_id = images[l_idi];
+        }
+        else
+        {
+          /* image found in cache, but has changed modification timestamp
+           * (delete from cache and reload)
+           */
+          if(gap_debug)
+          {
+            printf("FrameFetcher: DELETE because mtime changed : (image_id:%d) name:%s  mtimefile:%d mtimecache:%d  pid:%d\n"
+                  , (int)images[l_idi]
+                  , gimp_image_get_filename(images[l_idi])
+                  , (int)mtimefile
+                  , (int)*mtime_ptr
+                  , (int)getpid()
+                  );
+          }
+          gap_image_delete_immediate(images[l_idi]);
+        }
+        l_idi = nimages -1;  /* force break at next loop iteration */
       }
-      /* image found in cache, can skip load */
-      return(ic_ptr->image_id);
+      gimp_parasite_free(l_parasite);
     }
-    ic_last = ic_ptr;
+  }
+  if(images)
+  {
+    g_free(images);
+  }
+  
+  if (l_image_id >= 0)
+  {
+    if(gap_debug)
+    {
+      printf("FrameFetcher: p_load_cache_image CACHE-HIT :%s (image_id:%d) pid:%d\n"
+            , filename, (int)l_image_id, (int)getpid());
+    }
+    return(l_image_id);
   }
 
   l_filename = g_strdup(filename);
   l_image_id = gap_lib_load_image(l_filename);
   if(gap_debug)
   {
-    printf("FrameFetcher: loaded imafe from disk:%s (image_id:%d)\n"
-      , l_filename, (int)l_image_id);
+    printf("FrameFetcher: loaded image from disk:%s (image_id:%d) pid:%d\n"
+      , l_filename, (int)l_image_id, (int)getpid());
   }
 
   if((l_image_id >= 0) && (addToCache == TRUE))
   {
-    ic_new = g_malloc0(sizeof(GapFFetchImageCacheElem));
-    ic_new->filename = l_filename;
-    ic_new->image_id = l_image_id;
-
-    if(imcache->ic_list == NULL)
-    {
-      imcache->ic_list = ic_new;   /* 1.st elem starts the list */
-    }
-    else
-    {
-      ic_last->next = (GapFFetchImageCacheElem *)ic_new;  /* add new elem at end of the cache list */
-    }
-
-    if(l_idx > imcache->max_img_cache)
+    guchar *parasite_data;
+    gint32  parasite_size;
+    gint32 *parasite_mtime_ptr;
+    gchar  *parasite_filename_ptr;
+    gint32  len_filename0;           /* filename length including the terminating 0 */
+  
+    if (l_number_of_cached_images > GAP_FFETCH_MAX_IMG_CACHE_ELEMENTS)
     {
-      /* chache list has more elements than desired,
-       * drop the 1.st (oldest) entry in the chache list
+      /* the image cache already has more elements than desired,
+       * drop the 1st cached image
        */
-      p_drop_image_cache_elem1(imcache);
+      if(gap_debug)
+      {
+        printf("FrameFetcher: DELETE because cache is full: (image_id:%d)  name:%s number_of_cached_images:%d pid:%d\n"
+              , (int)l_first_chached_image_id
+              , gimp_image_get_filename(images[l_idi])
+              , (int)l_number_of_cached_images
+              , (int)getpid()
+              );
+      }
+      gap_image_delete_immediate(l_first_chached_image_id);
     }
-  }
-  else
-  {
-    g_free(l_filename);
-  }
-  return(l_image_id);
-}  /* end p_load_cache_image */
-
 
-/* ----------------------------------------------------
- * p_drop_image_cache_elem1
- * ----------------------------------------------------
- */
-static void
-p_drop_image_cache_elem1(GapFFetchImageCache *imcache)
-{
-  GapFFetchImageCacheElem  *ic_ptr;
+    /* build parasite data including mtime and full filename with terminating 0 byte */
+    len_filename0 = strlen(filename) + 1;
+    parasite_size = sizeof(gint32) + len_filename0;  
+    parasite_data = g_malloc0(parasite_size);
+    parasite_mtime_ptr = (gint32 *)parasite_data;
+    parasite_filename_ptr = (gchar *)&parasite_data[sizeof(gint32)];
+    
+    *parasite_mtime_ptr = gap_file_get_mtime(filename);
+    memcpy(parasite_filename_ptr, filename, len_filename0);
+    
+    /* attach a parasite to mark the image as part of the gap image cache */
+    l_parasite = gimp_parasite_new(GAP_IMAGE_CACHE_PARASITE
+                                   ,0  /* GIMP_PARASITE_PERSISTENT  0 for non persistent */
+                                   ,parasite_size
+                                   ,parasite_data
+                                   );
 
-  if(imcache)
-  {
-    ic_ptr = imcache->ic_list;
-    if(ic_ptr)
+    if(l_parasite)
     {
-      if(gap_debug)
-      {
-        printf("p_drop_image_cache_elem1 delete:%s (image_id:%d)\n"
-          , ic_ptr->filename, (int)ic_ptr->image_id);
-      }
-      gap_image_delete_immediate(ic_ptr->image_id);
-      g_free(ic_ptr->filename);
-      imcache->ic_list = (GapFFetchImageCacheElem  *)ic_ptr->next;
-      g_free(ic_ptr);
+      gimp_image_parasite_attach(l_image_id, l_parasite);
+      gimp_parasite_free(l_parasite);
     }
+    g_free(parasite_data);
+
   }
-}  /* end p_drop_image_cache_elem1 */
 
+  g_free(l_filename);
 
+  return(l_image_id);
+}  /* end p_load_cache_image */
 
 /* ----------------------------------------------------
  * p_drop_image_cache
@@ -328,25 +321,54 @@
 static void
 p_drop_image_cache(void)
 {
-  GapFFetchImageCache *imcache;
-
+  gint32 *images;
+  gint    nimages;
+  gint    l_idi;
+  
   if(gap_debug)
   {
-    printf("p_drop_image_cache START\n");
+    printf("p_drop_image_cache START pid:%d\n", (int) getpid());
   }
-  imcache = global_imcache;
-  if(imcache)
+
+  images = gimp_image_list(&nimages);
+  for(l_idi=0; l_idi < nimages; l_idi++)
   {
-    while(imcache->ic_list)
+    GimpParasite  *l_parasite;
+  
+    l_parasite = gimp_image_parasite_find(images[l_idi], GAP_IMAGE_CACHE_PARASITE);
+
+    if(gap_debug)
     {
-      p_drop_image_cache_elem1(imcache);
+      printf("FrameFetcher: CHECK (image_id:%d) name:%s pid:%d\n"
+            , (int)images[l_idi]
+            , gimp_image_get_filename(images[l_idi])
+            , (int)getpid()
+            );
+    }
+
+    if(l_parasite)
+    {
+      if(gap_debug)
+      {
+        printf("FrameFetcher: DELETE (image_id:%d) name:%s pid:%d\n"
+              , (int)images[l_idi]
+              , gimp_image_get_filename(images[l_idi])
+              , (int)getpid()
+              );
+      }
+      /* delete image from the duplicates cache */
+      gap_image_delete_immediate(images[l_idi]);
+      gimp_parasite_free(l_parasite);
     }
   }
-  global_imcache = NULL;
+  if(images)
+  {
+    g_free(images);
+  }
 
   if(gap_debug)
   {
-    printf("p_drop_image_cache END\n");
+    printf("p_drop_image_cache END pid:%d\n", (int)getpid());
   }
 
 }  /* end p_drop_image_cache */
@@ -528,13 +550,20 @@
 static void
 p_add_image_to_list_of_duplicated_images(gint32 image_id, gint32 ffetch_user_id)
 {
-  GapFFetchDuplicatedImagesElem *dupElem;
-  
-  dupElem = g_new(GapFFetchDuplicatedImagesElem, 1);
-  dupElem->next = global_duplicated_images;
-  dupElem->image_id = image_id;
-  dupElem->ffetch_user_id = ffetch_user_id;
-  global_duplicated_images = dupElem;
+  GimpParasite  *l_parasite;
+
+  /* attach a parasite to mark the image as part of the gap image duplicates cache */
+  l_parasite = gimp_parasite_new(GAP_IMAGE_DUP_CACHE_PARASITE
+                                 ,0  /* GIMP_PARASITE_PERSISTENT  0 for non persistent */
+                                 , sizeof(gint32)     /* size of parasite data */
+                                 ,&ffetch_user_id     /* parasite data */
+                                 );
+
+  if(l_parasite)
+  {
+    gimp_image_parasite_attach(image_id, l_parasite);
+    gimp_parasite_free(l_parasite);
+  }
 }   /* end p_add_image_to_list_of_duplicated_images */
 
 
@@ -547,35 +576,56 @@
 void
 gap_frame_fetch_delete_list_of_duplicated_images(gint32 ffetch_user_id)
 {
-  GapFFetchDuplicatedImagesElem *dupElem;
-  GapFFetchDuplicatedImagesElem *nextDupElem;
-  
-  dupElem = global_duplicated_images;
-  while(dupElem)
+  gint32 *images;
+  gint    nimages;
+  gint    l_idi;
+
+  images = gimp_image_list(&nimages);
+  for(l_idi=0; l_idi < nimages; l_idi++)
   {
-    nextDupElem = dupElem->next;
+    GimpParasite  *l_parasite;
+  
+    l_parasite = gimp_image_parasite_find(images[l_idi], GAP_IMAGE_DUP_CACHE_PARASITE);
 
-    if (((ffetch_user_id == dupElem->ffetch_user_id) || (ffetch_user_id < 0))
-    && (dupElem->image_id >= 0))
+    if(gap_debug)
     {
-      gap_image_delete_immediate(dupElem->image_id);
-      dupElem->image_id = -1;  /* set image invalid */
+      printf("FrameFetcher: check (image_id:%d) name:%s pid:%d\n"
+            , (int)images[l_idi]
+            , gimp_image_get_filename(images[l_idi])
+            , (int)getpid()
+            );
     }
 
-    if (ffetch_user_id < 0)
+    if(l_parasite)
     {
-      g_free(dupElem);
+      gint32 *ffetch_user_id_ptr;
+      
+      ffetch_user_id_ptr = (gint32 *) l_parasite->data;
+      if((*ffetch_user_id_ptr == ffetch_user_id) || (ffetch_user_id < 0))
+      {
+        if(gap_debug)
+        {
+          printf("FrameFetcher: DELETE duplicate %s (image_id:%d) user_id:%d (%d)  name:%s pid:%d\n"
+                , gimp_image_get_filename(images[l_idi])
+                , (int)images[l_idi]
+                , (int)ffetch_user_id
+                , (int)*ffetch_user_id_ptr
+                , gimp_image_get_filename(images[l_idi])
+                , (int)getpid()
+                );
+        }
+        /* delete image from the duplicates cache */
+        gap_image_delete_immediate(images[l_idi]);
+      }
+      gimp_parasite_free(l_parasite);
     }
-
-    dupElem = nextDupElem;
   }
-  if (ffetch_user_id < 0)
+  if(images)
   {
-    global_duplicated_images = NULL;
+    g_free(images);
   }
-}  /* end gap_frame_fetch_delete_list_of_duplicated_images */
-
 
+}  /* end gap_frame_fetch_delete_list_of_duplicated_images */
 
 
 
@@ -616,6 +666,7 @@
   gint32 dup_image_id;
 
   resulting_layer = -1;
+  dup_image_id = -1;
   image_id = p_load_cache_image(filename, addToCache);
   if (image_id < 0)
   {
@@ -657,17 +708,22 @@
 
   if (addToCache != TRUE)
   {
-    GapFFetchImageCacheElem *ic_elem;
-    
-    ic_elem = p_find_img_cache_by_image_id(image_id);
-    
-    if (ic_elem == NULL)
+    GimpParasite  *l_parasite;
+
+    l_parasite = gimp_image_parasite_find(image_id, GAP_IMAGE_CACHE_PARASITE);
+
+    if(l_parasite)
+    {
+      gimp_parasite_free(l_parasite);
+    }
+    else
     {
       /* the original image is not cached
        * (delete it because the caller gets the preprocessed duplicate)
        */
       gap_image_delete_immediate(image_id);
     }
+    
   }
 
   return(resulting_layer);
@@ -791,7 +847,7 @@
   
   for(usr_ptr = global_rsource_users; usr_ptr != NULL; usr_ptr = (GapFFetchResourceUserElem *)usr_ptr->next)
   {
-    printf("usr_ptr->ffetch_user_id: %d  usr_ptr:%d\n", usr_ptr->ffetch_user_id, usr_ptr);
+    /* printf("usr_ptr->ffetch_user_id: %d  usr_ptr:%d\n", usr_ptr->ffetch_user_id, usr_ptr); */
   
     if (usr_ptr->ffetch_user_id >= 0)
     {
@@ -814,10 +870,11 @@
   
   if(gap_debug)
   {
-    printf("gap_frame_fetch_register_user: REGISTRATED ffetch_user_id:%d  caller_name:%s  new_usr_ptr:%d\n"
+    printf("gap_frame_fetch_register_user: REGISTRATED ffetch_user_id:%d  caller_name:%s  new_usr_ptr:%d pid:%d\n"
           , new_usr_ptr->ffetch_user_id
           , caller_name
-          , new_usr_ptr
+          , (int)&new_usr_ptr
+          , (int) getpid()
           );
   }
   return (max_ffetch_user_id);
@@ -832,7 +889,15 @@
  *  cached images and videohandles are kept.
  *  until the last resource user calls this procedure.
  *  if there are no more registered users all
- *  cached resources and duplicates are dropped)
+ *  cached videohandle resources and temporary image duplicates are dropped)
+ * Current restriction:
+ *  the current implementation keeps user registration in global data
+ *  but filtermacros and storyboard processor typically are running in separate
+ *  processes an therefore each process has its own global data.
+ *  an empty list of users does not really indicate
+ *  that there are no more users (another process may still have users
+ *  of cached images)
+ *  therefore cached images are NOT dropped
  */
 void
 gap_frame_fetch_unregister_user(gint32 ffetch_user_id)
@@ -842,8 +907,9 @@
 
   if(gap_debug)
   {
-    printf("gap_frame_fetch_unregister_user: UNREGISTER ffetch_user_id:%d\n"
+    printf("gap_frame_fetch_unregister_user: UNREGISTER ffetch_user_id:%d pid:%d\n"
           , ffetch_user_id
+          , (int) getpid()
           );
   }
 
@@ -864,9 +930,10 @@
   {
     if(gap_debug)
     {
-      printf("gap_frame_fetch_unregister_user: no more resource users, DROP cached resources\n");
+      printf("gap_frame_fetch_unregister_user: no more resource users, DROP cached duplicates and video handles\n");
     }
-    gap_frame_fetch_drop_resources();    
+    gap_frame_fetch_delete_list_of_duplicated_images(-1);
+    p_drop_vidhandle_cache();
   }
 
 }  /* end gap_frame_fetch_unregister_user */

Modified: trunk/gap/gap_image.c
==============================================================================
--- trunk/gap/gap_image.c	(original)
+++ trunk/gap/gap_image.c	Wed Jan 14 19:59:24 2009
@@ -34,6 +34,7 @@
 
 
 #include <gap_image.h>
+#include <gap_layer_copy.h>
 
 extern int gap_debug;
 
@@ -259,3 +260,164 @@
   }
   return (l_layer_id);
 }  /* end gap_image_get_any_layer */
+
+
+ 
+/* ------------------------------------
+ * gap_image_merge_to_specified_layer
+ * ------------------------------------
+ * remove all other layers from the image except the specified layer_id
+ * (by removing other layers, make ref_layer_id visible and perform merging)
+ */
+gint32
+gap_image_merge_to_specified_layer(gint32 ref_layer_id, GimpMergeType mergemode)
+{
+  gint32  l_image_id;
+
+  l_image_id = gimp_drawable_get_image(ref_layer_id);
+  if(l_image_id >= 0)
+  {
+    gint32  l_idx;
+    gint    l_nlayers;
+    gint32 *l_layers_list;
+    
+    l_layers_list = gimp_image_get_layers(l_image_id, &l_nlayers);
+    if(l_layers_list != NULL)
+    {
+      for(l_idx = 0; l_idx < l_nlayers; l_idx++)
+      {
+        gboolean l_visible;
+        
+        if (l_layers_list[l_idx] == ref_layer_id)
+        {
+          gimp_drawable_set_visible(l_layers_list[l_idx], TRUE);
+        }
+        else
+        {
+          gimp_image_remove_layer(l_image_id, l_layers_list[l_idx]);
+        }
+      }
+      g_free (l_layers_list);
+      return (gap_image_merge_visible_layers(l_image_id, mergemode));
+    }
+  }
+  return (-1);
+
+}  /* end gap_image_merge_to_specified_layer */
+
+
+/* -------------------------------------------------------
+ * gap_image_set_selection_from_selection_or_drawable
+ * -------------------------------------------------------
+ * create a selection in the specified image_id.
+ * The selection is a scaled copy of the selection in another image,
+ * refered by ref_drawable_id, or a Grayscale copy of the specified ref_drawable_id
+ * (in case the refered image has no selection or the flag force_from_drawable is TRUE)
+ *
+ *  - operates on a duplicate of the image refered by ref_drawable_id.
+ *  - this duplicate is scaled to same size as specified image_id
+ *
+ * return TRUE in case the selection was successfully created .
+ */
+gboolean
+gap_image_set_selection_from_selection_or_drawable(gint32 image_id, gint32 ref_drawable_id
+  , gboolean force_from_drawable)
+{
+  gint32        l_aux_channel_id;
+  gint32        ref_image_id;
+  gint32        work_drawable_id;   /* the duplicate of the layer that is used as selction mask */
+  gint32        dup_image_id;
+  gboolean has_selection;
+  gboolean non_empty;
+  gint     x1, y1, x2, y2;
+
+  if ((image_id < 0) || (ref_drawable_id < 0))
+  {
+    return (FALSE);
+  }
+  ref_image_id = gimp_drawable_get_image(ref_drawable_id);
+
+  if (ref_image_id < 0)
+  {
+    printf("ref_drawable_id does not refere to a valid image layer_id:%d\n", (int)ref_drawable_id);
+    return (FALSE);
+  }
+
+
+
+  dup_image_id = gimp_image_duplicate(ref_image_id);
+  if (dup_image_id < 0)
+  {
+    printf("duplicating of image failed, refered souce image_id:%d\n", (int)ref_image_id);
+    return (FALSE);
+  }
+  /* clear undo stack */
+  if (gimp_image_undo_is_enabled(dup_image_id))
+  {
+    gimp_image_undo_disable(dup_image_id);
+  }
+
+  if ((gimp_image_width(image_id) != gimp_image_width(dup_image_id))
+  ||  (gimp_image_height(image_id) != gimp_image_height(dup_image_id)))
+  {
+     if(gap_debug)
+     {
+       printf("scaling tmp image_id: %d\n", (int)dup_image_id);
+     }
+     gimp_image_scale(dup_image_id, gimp_image_width(image_id), gimp_image_height(image_id));
+  }
+
+  has_selection  = gimp_selection_bounds(ref_image_id, &non_empty, &x1, &y1, &x2, &y2);
+  if ((has_selection) && (non_empty) && (force_from_drawable != TRUE))
+  {
+    /* use scaled copy of the already exisating selection in the refered image */
+    work_drawable_id = gimp_image_get_selection(dup_image_id);
+  }
+  else
+  {
+    gint32        active_layer_stackposition;
+
+    /* create selection as gray copy of the alt_selection layer */
+
+    active_layer_stackposition = gap_layer_get_stackposition(ref_image_id, ref_drawable_id);
+
+    if(gimp_image_base_type(dup_image_id) != GIMP_GRAY)
+    {
+       if(gap_debug)
+       {
+         printf("convert to GRAYSCALE tmp image_id: %d\n", (int)dup_image_id);
+       }
+       gimp_image_convert_grayscale(dup_image_id);
+    }
+    work_drawable_id = gap_layer_get_id_by_stackposition(dup_image_id, active_layer_stackposition);
+    gimp_layer_resize_to_image_size (work_drawable_id);
+  }
+
+  gimp_selection_all(image_id);
+  //l_sel_channel_id = gimp_image_get_selection(image_id);
+  l_aux_channel_id = gimp_selection_save(image_id);
+  
+  /* copy the work drawable (layer or channel) into the selection channel
+   * the work layer is a grayscale copy GRAY or GRAYA of the alt_selection layer
+   *  that is already scaled and resized to fit the size of the target image
+   * the work channel is the scaled selection of the image refred by ref_drawable_id
+   *
+   * copying is done into an auxiliary channel from where we regulary load the selection.
+   * this is done because subseqent queries of the selection boudaries will deliver
+   * full channel size rectangle after a direct copy into the selection.
+   */
+  gap_layer_copy_picked_channel (l_aux_channel_id  /* dst_drawable_id*/
+                              , 0                  /* dst_channel_pick */
+                              , work_drawable_id   /* src_drawable_id */
+                              , 0                  /* src_channel_pick */
+                              , FALSE              /* gboolean shadow */
+                              );
+
+  gimp_selection_load(l_aux_channel_id);
+  gimp_image_remove_channel(image_id, l_aux_channel_id);
+
+  gap_image_delete_immediate(dup_image_id);
+  return (TRUE);
+
+}  /* end gap_image_set_selection_from_selection_or_drawable */
+

Modified: trunk/gap/gap_image.h
==============================================================================
--- trunk/gap/gap_image.h	(original)
+++ trunk/gap/gap_image.h	Wed Jan 14 19:59:24 2009
@@ -50,6 +50,10 @@
 gboolean  gap_image_is_alive(gint32 image_id);
 gint32    gap_image_get_any_layer(gint32 image_id);
 
+gint32    gap_image_merge_to_specified_layer(gint32 ref_layer_id, GimpMergeType mergemode);
+gboolean  gap_image_set_selection_from_selection_or_drawable(gint32 image_id, gint32 ref_drawable_id
+                              , gboolean force_from_drawable);
+
 
 #endif
 

Modified: trunk/gap/gap_layer_copy.c
==============================================================================
--- trunk/gap/gap_layer_copy.c	(original)
+++ trunk/gap/gap_layer_copy.c	Wed Jan 14 19:59:24 2009
@@ -667,6 +667,34 @@
 }  /* end gap_layer_get_stackposition */
 
 
+/* ---------------------------------
+ * gap_layer_get_id_by_stackposition
+ * ---------------------------------
+ * return -1 if the specified image has no layer at specified stackposition
+ */
+gint32
+gap_layer_get_id_by_stackposition(gint32 image_id, gint32 stackposition)
+{
+  gint          l_nlayers;
+  gint32       *l_layers_list;
+  gint32        l_layer_id;
+
+  l_layer_id = -1;
+  l_layers_list = gimp_image_get_layers(image_id, &l_nlayers);
+  if(l_layers_list != NULL)
+  {
+    if ((stackposition >= 0) && (stackposition < l_nlayers))
+    {
+      l_layer_id = l_layers_list[stackposition];
+    }
+    g_free (l_layers_list);
+  }
+
+  return (l_layer_id);
+
+}  /* end gap_layer_get_id_by_stackposition */
+
+
 /* ------------------------
  * gap_layer_make_duplicate
  * ------------------------
@@ -818,3 +846,4 @@
   return (l_new_layer_id);
 
 }  /* end gap_layer_create_layer_from_alpha  */
+

Modified: trunk/gap/gap_layer_copy.h
==============================================================================
--- trunk/gap/gap_layer_copy.h	(original)
+++ trunk/gap/gap_layer_copy.h	Wed Jan 14 19:59:24 2009
@@ -79,6 +79,7 @@
 void   gap_layer_copy_paste_drawable(gint32 image_id, gint32 dst_drawable_id, gint32 src_drawable_id);
 
 gint32 gap_layer_get_stackposition(gint32 image_id, gint32 ref_layer_id);
+gint32 gap_layer_get_id_by_stackposition(gint32 image_id, gint32 stackposition);
 
 
 gint32  gap_layer_make_duplicate(gint32 src_layer_id, gint32 image_id

Modified: trunk/gap/gap_morph_dialog.c
==============================================================================
--- trunk/gap/gap_morph_dialog.c	(original)
+++ trunk/gap/gap_morph_dialog.c	Wed Jan 14 19:59:24 2009
@@ -187,7 +187,7 @@
 static void         on_show_lines_toggled_callback(GtkWidget *widget, GapMorphGUIParams *mgup);
 static void         on_use_quality_wp_selection_toggled_callback(GtkWidget *widget, GapMorphGUIParams *mgup);
 static void         on_use_gravity_toggled_callback(GtkWidget *widget, GapMorphGUIParams *mgup);
-static void         on_multiple_pointsets_toggled_callback(GtkWidget *widget, GapMorphGUIParams *mgup);
+static void         on_have_workpointsets_toggled_callback(GtkWidget *widget, GapMorphGUIParams *mgup);
 static void         on_create_tween_layers_toggled_callback(GtkWidget *widget, GapMorphGUIParams *mgup);
 
 static void         on_radio_op_mode_callback(GtkWidget *widget, gint32 op_mode);
@@ -229,7 +229,7 @@
       mgup->mgpp->use_quality_wp_selection = FALSE;
       mgup->mgpp->use_gravity = FALSE;
       mgup->mgpp->create_tween_layers = TRUE;
-      mgup->mgpp->multiple_pointsets = FALSE;
+      mgup->mgpp->have_workpointsets = FALSE;
       p_upd_widget_values(mgup);
       break;
     case GTK_RESPONSE_OK:
@@ -286,8 +286,8 @@
                                     , mgup->mgpp->use_gravity);
        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mgup->create_tween_layers_checkbutton)
                                     , mgup->mgpp->create_tween_layers);
-       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mgup->multiple_pointsets_checkbutton)
-                                    , mgup->mgpp->multiple_pointsets);
+       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mgup->have_workpointsets_checkbutton)
+                                    , mgup->mgpp->have_workpointsets);
 
   }
 }  /* end p_upd_widget_values */
@@ -2822,17 +2822,17 @@
 }  /* end on_use_gravity_toggled_callback */
 
 /* --------------------------------------
- * on_multiple_pointsets_toggled_callback
+ * on_have_workpointsets_toggled_callback
  * --------------------------------------
  */
 static void
-on_multiple_pointsets_toggled_callback(GtkWidget *widget, GapMorphGUIParams *mgup)
+on_have_workpointsets_toggled_callback(GtkWidget *widget, GapMorphGUIParams *mgup)
 {
   if(mgup)
   {
-    if(GTK_TOGGLE_BUTTON (mgup->multiple_pointsets_checkbutton)->active)
+    if(GTK_TOGGLE_BUTTON (mgup->have_workpointsets_checkbutton)->active)
     {
-      mgup->mgpp->multiple_pointsets = TRUE;
+      mgup->mgpp->have_workpointsets = TRUE;
       gtk_widget_show(mgup->workpoint_file_lower_label);
       gtk_widget_show(mgup->workpoint_file_upper_label);
       gtk_widget_show(mgup->workpoint_lower_label);
@@ -2840,14 +2840,14 @@
     }
     else
     {
-      mgup->mgpp->multiple_pointsets = FALSE;
+      mgup->mgpp->have_workpointsets = FALSE;
       gtk_widget_hide(mgup->workpoint_file_lower_label);
       gtk_widget_hide(mgup->workpoint_file_upper_label);
       gtk_widget_hide(mgup->workpoint_lower_label);
       gtk_widget_hide(mgup->workpoint_upper_label);
     }
   }
-}  /* end on_multiple_pointsets_toggled_callback */
+}  /* end on_have_workpointsets_toggled_callback */
 
 
 /* ---------------------------------------
@@ -3878,15 +3878,15 @@
 
   /* the multiple pointsets checkbutton */
   checkbutton = gtk_check_button_new_with_label ( _("Multiple Pointsets"));
-  mgup->multiple_pointsets_checkbutton = checkbutton;
+  mgup->have_workpointsets_checkbutton = checkbutton;
 #ifdef GAP_MORPH_DEBUG_FEATURES
   gtk_widget_show (checkbutton);
 #endif
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton), mgup->mgpp->multiple_pointsets);
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton), mgup->mgpp->have_workpointsets);
   gtk_table_attach( GTK_TABLE(table), checkbutton, 11, 13, row, row+1,
 		    GTK_FILL, 0, 0, 0 );
   g_signal_connect (checkbutton, "toggled",
-                    G_CALLBACK (on_multiple_pointsets_toggled_callback),
+                    G_CALLBACK (on_have_workpointsets_toggled_callback),
                     mgup);
   gimp_help_set_help_data(checkbutton,
                        _("ON: use 2 or more pointsets from file. "
@@ -3951,10 +3951,10 @@
   /*  Show the main container  */
   gtk_widget_show (main_vbox);
 
-  /* force multiple_pointsets callback to show/hide workpoint lables
+  /* force have_workpointsets callback to show/hide workpoint lables
    * (those labels are only visible when multiple pontsets are enabled
    */
-  on_multiple_pointsets_toggled_callback(mgup->multiple_pointsets_checkbutton, mgup);
+  on_have_workpointsets_toggled_callback(mgup->have_workpointsets_checkbutton, mgup);
   on_use_gravity_toggled_callback(mgup->use_gravity_checkbutton, mgup);
   on_use_quality_wp_selection_toggled_callback(mgup->use_quality_wp_selection_checkbutton, mgup);
 }  /* end gap_morph_create_dialog */

Modified: trunk/gap/gap_morph_dialog.h
==============================================================================
--- trunk/gap/gap_morph_dialog.h	(original)
+++ trunk/gap/gap_morph_dialog.h	Wed Jan 14 19:59:24 2009
@@ -71,7 +71,7 @@
 
   GtkObject  *num_shapepoints_adj;
   GtkWidget  *create_tween_layers_checkbutton;  
-  GtkWidget  *multiple_pointsets_checkbutton;  
+  GtkWidget  *have_workpointsets_checkbutton;  
 
   GapMorphSubWin src_win;
   GapMorphSubWin dst_win;

Modified: trunk/gap/gap_morph_exec.c
==============================================================================
--- trunk/gap/gap_morph_exec.c	(original)
+++ trunk/gap/gap_morph_exec.c	Wed Jan 14 19:59:24 2009
@@ -2,6 +2,12 @@
  * 2004.02.12 hof (Wolfgang Hofer)
  * layer morphing worker procedures
  *
+ * Note:
+ *  using multiple workpoint sets is an unfinshed feature and does not work yet.
+ *  (this feature was intended for morphing between 2 videos, where each handled video frame
+ *  can have its own workpoint set. but his is no practical solution since creating of the
+ *  workpoint files is too much manual work)
+ *
  */
 /* The GIMP -- an image manipulation program
  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
@@ -187,6 +193,23 @@
 	);
 }  /* end  p_get_tolerance */
 
+static void
+p_error_message_with_filename(GimpRunMode run_mode, const char *msg_fmt, const char *filename)
+{
+  char *l_msg;
+
+  l_msg = g_strdup_printf(msg_fmt, filename);
+  printf("%s RUN_MODE:%d\n", l_msg, (int)run_mode);
+  
+  if(run_mode != GIMP_RUN_NONINTERACTIVE)
+  {
+    g_message(l_msg);
+  }
+  g_free(l_msg);
+
+}
+
+
 
 /* ---------------------------------
  * gap_moprh_exec_save_workpointfile
@@ -299,6 +322,7 @@
 				 , gdouble *gravity_intensity
 				 , gboolean *use_gravity
 				 , gboolean *use_quality_wp_selection
+                                 , GimpRunMode run_mode
                                  )
 {
 #define POINT_REC_MAX 512
@@ -345,7 +369,7 @@
     l_len = strlen(GAP_MORPH_WORKPOINT_FILE_HEADER);
     if(strncmp(l_buff, GAP_MORPH_WORKPOINT_FILE_HEADER, l_len) != 0)
     {
-      printf("** error file: %s is no workpointfile (header is missing)\n", filename);
+      p_error_message_with_filename(run_mode, _("File: %s\n ==>is no workpointfile (header is missing)"), filename);
       fclose(l_fp);
       return (NULL);
     }
@@ -373,7 +397,7 @@
            }
            else
            {
-             printf("** error file: %s is corrupted (LAYER-SIZES: record requires 4 numbers)\n"
+             p_error_message_with_filename(run_mode, _("file: %s\n ==> is corrupted (LAYER-SIZES: record requires 4 numbers)")
                    , filename);
              fclose(l_fp);
              return (NULL);
@@ -391,7 +415,7 @@
            }
            else
            {
-             printf("** error file: %s is corrupted (TWEEN-STEPS record requires 1 number)\n"
+             p_error_message_with_filename(run_mode, _("file: %s\n ==> is corrupted (TWEEN-STEPS record requires 1 number)")
                    , filename);
              fclose(l_fp);
              return (NULL);
@@ -409,7 +433,7 @@
            }
            else
            {
-             printf("** error file: %s is corrupted (AFFECT-RADIUS record requires 1 number)\n"
+             p_error_message_with_filename(run_mode, _("file: %s ==> is corrupted (AFFECT-RADIUS record requires 1 number)")
                    , filename);
              fclose(l_fp);
              return (NULL);
@@ -431,7 +455,7 @@
            }
            else
            {
-             printf("** error file: %s is corrupted (INTENSITY record requires 1 number)\n"
+             p_error_message_with_filename(run_mode, _("file: %s\n ==>is corrupted (INTENSITY record requires 1 number)")
                    , filename);
              fclose(l_fp);
              return (NULL);
@@ -453,7 +477,7 @@
            }
            else
            {
-             printf("** error file: %s is corrupted (QUALITY-WP-SELECT record requires 1 number)\n"
+             p_error_message_with_filename(run_mode, _("file: %s\n ==>is corrupted (QUALITY-WP-SELECT record requires 1 number)")
                    , filename);
              fclose(l_fp);
              return (NULL);
@@ -487,7 +511,7 @@
            }
            else
            {
-             printf("** error file: %s is corrupted (WP: record requires 4 numbers)\n"
+             p_error_message_with_filename(run_mode, _("file: %s\n ==> is corrupted (WP: record requires 4 numbers)")
                    , filename);
              fclose(l_fp);
              return (NULL);
@@ -524,6 +548,7 @@
 				,&mgup->mgpp->gravity_intensity
 				,&mgup->mgpp->use_gravity
 				,&mgup->mgpp->use_quality_wp_selection
+                                ,mgup->mgpp->run_mode
 				);
   return(wp_list);
 }  /* end gap_moprh_exec_load_workpointfile */
@@ -553,6 +578,7 @@
 				,&wps->gravity_intensity
 				,&wps->use_gravity
 				,&wps->use_quality_wp_selection
+                                ,mgpp->run_mode
 				);
   if(wps->wp_list == NULL)
   {
@@ -598,6 +624,18 @@
     gint   ii;
     gint   wp_idx;
     
+    if(gap_debug)
+    {
+      printf("p_build_wp_set_table: using multiple workpoint sets\n"
+        " lower_basename:%s\n"
+        " upper_basename:%s\n lower_num:%d upper_num:%d\n"
+        ,lower_basename
+        ,upper_basename
+        ,(int)lower_num
+        ,(int)upper_num
+        );
+    }
+    
     
     mlayers->available_wp_sets = 0;
     for(ii=MIN(lower_num, upper_num); ii <= MAX(upper_num, lower_num); ii++)
@@ -642,6 +680,13 @@
   else
   {
     /* create 2 workpoint sets from upper and lower file */
+    if(gap_debug)
+    {
+      printf("p_build_wp_set_table: create 2 workpoint sets from upper and lower file\n lower:%s\n upper:%s\n"
+        ,mgpp->workpoint_file_lower
+        ,mgpp->workpoint_file_upper
+        );
+    }
     mlayers->available_wp_sets = 2;
     mlayers->tab_wp_sets = g_new(GapMorphWarpCoreAPI*, mlayers->available_wp_sets);
     mlayers->tab_wp_sets[0] = p_load_workpoint_set(mgpp->workpoint_file_lower, mgpp, mlayers);
@@ -1916,7 +1961,7 @@
            gdouble            pick_y;
 	   
 	   l_col = dstPR.x + x;
-	   if(mgpp->multiple_pointsets)
+	   if(mgpp->have_workpointsets)
 	   {
 	     /* pick based on 2 sets of workpoints */
              p_pixel_warp_multipick(wcap_1  /// XXXXX list1
@@ -1952,10 +1997,24 @@
      
      if(mgpp->do_progress)
      {
+       gdouble l_total_progress;
+       
        l_progress += (dstPR.w * dstPR.h);
-       gimp_progress_update(mgpp->master_progress 
-                           + (mgpp->layer_progress_step * (l_progress /l_max_progress))
-			   );
+       l_total_progress = mgpp->master_progress 
+                           + (mgpp->layer_progress_step * (l_progress /l_max_progress));
+
+       /*
+        * if)gap_debug)
+        * {
+        *   printf("Progress: mgpp->master_progress:%f mgpp->layer_progress_step:%f l_total_progress:%f\n"
+        *    ,(float)mgpp->master_progress
+        *    ,(float)mgpp->layer_progress_step
+        *    ,(float)l_total_progress
+        *    );
+        * }
+        */
+        
+       gimp_progress_update(l_total_progress);
      }
 
   }
@@ -1997,6 +2056,12 @@
   GimpPixelRgn    bgPR;
   gpointer        pr;
 
+  if(gap_debug)
+  {
+    printf("p_mix_layers START curr_mix_factor: %f\n"
+      ,(float)curr_mix_factor
+      );
+  }
 
   top_drawable = gimp_drawable_get (top_layer_id);
   bg_drawable  = gimp_drawable_get (bg_layer_id);
@@ -2152,6 +2217,22 @@
    wp_set_2 = NULL;
    wp_mix_factor = 1.0;
 
+   if(gap_debug)
+   {
+     printf("p_create_morph_tween_frame START total_steps:%d  current_step:%d\n"
+            " mgpp->create_tween_layers:%d\n"
+            " mgpp->have_workpointsets:%d\n"
+            " mlayers->available_wp_sets:%d\n"
+            " mgpp->render_mode:%d\n"
+       ,(int)total_steps
+       ,(int)current_step
+       ,(int)mgpp->create_tween_layers
+       ,(int)mgpp->have_workpointsets
+       ,(int)mlayers->available_wp_sets
+       ,(int)mgpp->render_mode
+       );
+   }
+
    if(mgpp->create_tween_layers)
    {
      /* size of the new frame */
@@ -2187,7 +2268,7 @@
      src_layer_id = mlayers->src_layers[ii];
    }
 
-   if((mgpp->multiple_pointsets)
+   if((mgpp->have_workpointsets)
    && (mlayers->available_wp_sets > 1))
    {
      gint wps_idx;
@@ -2205,7 +2286,6 @@
      wp_mix_factor = ref - (gdouble)wps_idx;
    }
 
-
    dst_drawable = gimp_drawable_get (dst_layer_id);
    
    /* create the tween frame image */
@@ -2249,8 +2329,6 @@
                                );
    gimp_image_add_layer(curr_image_id, top_layer_id, 0);
 
-   
-
 
    if(!mgpp->render_mode == GAP_MORPH_RENDER_MODE_WARP)
    {
@@ -2287,7 +2365,6 @@
 			 , wp_set_2
 			 , wp_mix_factor
                 	 );
-
        gap_morph_exec_free_workpoint_list(&curr_wp_list_1);
        gap_morph_exec_free_workpoint_list(&curr_wp_list_2);
      }
@@ -2397,7 +2474,6 @@
 //   merged_layer_id = 
 //   gap_image_merge_visible_layers(curr_image_id, GIMP_EXPAND_AS_NECESSARY);
 
-
    merged_layer_id = 
    p_mix_layers(curr_image_id
                ,bg_layer_id
@@ -2452,6 +2528,10 @@
   dst_image_id = -1;
 
 
+  if(gap_debug)
+  {
+    printf("p_get_tween_steps_and_layerstacks: START\n");
+  }
   
   if(mgpp->osrc_layer_id >= 0)
   {
@@ -2462,7 +2542,10 @@
 				             );
     for(ii=0; ii < mlayers->src_nlayers; ii++)
     {
-      if(gap_debug) printf("src: id[%d]: %d\n", (int)ii, (int)mlayers->src_layers[ii] );
+      if(gap_debug)
+      {
+        printf("src: id[%d]: %d\n", (int)ii, (int)mlayers->src_layers[ii] );
+      }
       if(mlayers->src_layers[ii] == mgpp->osrc_layer_id)
       {
         mlayers->src1_idx = ii;  /* src at 1.st step */
@@ -2496,6 +2579,12 @@
   if(mgpp->create_tween_layers)
   {
     mlayers->dst1_idx = mlayers->dst2_idx + (tween_steps -1);
+    if(gap_debug)
+    {
+      printf("p_get_tween_steps_and_layerstacks: create_tween_layers RETURN tween_steps:%d\n"
+         ,(int)tween_steps
+         );
+    }
     return(tween_steps);
   }
   
@@ -2534,6 +2623,13 @@
   
   mlayers->src1_idx = MIN((mlayers->src2_idx + (tween_steps -1)) , (mlayers->src_nlayers -1));
 
+  if(gap_debug)
+  {
+    printf("p_get_tween_steps_and_layerstacks: create_tween_layers END, RETURN tween_steps:%d\n"
+       ,(int)tween_steps
+       );
+  }
+
   return(tween_steps);
 }   /* end p_get_tween_steps_and_layerstacks */
 
@@ -2559,12 +2655,15 @@
   mlayers = &mlayers_struct;
   mlayers->tab_wp_sets = NULL;
   mlayers->available_wp_sets = 0;
-  
+
   mgpp->tween_steps = p_get_tween_steps_and_layerstacks(mgpp, mlayers);
   
-  if(mgpp->multiple_pointsets)
+  if(mgpp->have_workpointsets)
   {
-    /* check for available workpointfile sets and load them */
+    /* check for available workpointfile sets and load them.
+     * (note: this also handles the case when working with a single workpointfile
+     *  where the same workpoint file is used both as upper and lower set)
+     */
     p_build_wp_set_table(mgpp ,mlayers);
   }
   
@@ -2699,3 +2798,369 @@
   return(cp_layer_id);
   
 }  /* end gap_morph_execute */
+
+
+
+/* ----------------------------------
+ * p_create_simple_fade_tween_frame
+ * ----------------------------------
+ *
+ * return the newly created tween morphed layer
+ *
+ */
+static gint32
+p_create_simple_fade_tween_frame(gint32 total_steps
+                          ,gint32 current_step
+                          ,GapMorphGlobalParams *mgpp
+                          )
+{
+   gint32  curr_image_id;  /* a temp image of current layer size */
+   gint32  bg_layer_id;
+   gint32  top_layer_id;
+   gint32  merged_layer_id;
+   gint32  curr_width;
+   gint32  curr_height;
+   gdouble curr_opacity;
+   gint32 src_layer_id;
+   gint32 dst_layer_id;
+   GimpImageType  l_src_type;
+   
+   src_layer_id = mgpp->osrc_layer_id;
+   dst_layer_id = mgpp->fdst_layer_id;
+
+
+   /* check size of the new frame */
+   curr_width = gimp_drawable_width(src_layer_id);
+   if (curr_width != gimp_drawable_width(dst_layer_id))
+   {
+     return -1;
+   }
+
+   curr_height = gimp_drawable_height(src_layer_id);
+   if (curr_height != gimp_drawable_height(dst_layer_id))
+   {
+     return -1;
+   }
+
+
+  l_src_type    = gimp_drawable_type(src_layer_id);
+  if (l_src_type != gimp_drawable_type(dst_layer_id))
+  {
+    return -1;
+  }
+  
+  curr_image_id = -1;
+  
+  switch(l_src_type)
+  {
+    case GIMP_RGB_IMAGE:         /* 0 */
+    case GIMP_RGBA_IMAGE:        /* 1 */
+       curr_image_id = gimp_image_new(curr_width, curr_height, GIMP_RGB);
+       break;
+    case GIMP_GRAY_IMAGE:        /* 2 */
+    case GIMP_GRAYA_IMAGE:       /* 3 */
+       curr_image_id = gimp_image_new(curr_width, curr_height, GIMP_GRAY);
+       break;
+    case GIMP_INDEXED_IMAGE:     /* 4 */
+    case GIMP_INDEXEDA_IMAGE:    /* 5 */
+       return -1;
+       break;
+  }   
+
+
+   bg_layer_id = gap_layer_copy_to_image (curr_image_id, mgpp->osrc_layer_id);
+   top_layer_id = gap_layer_copy_to_image (curr_image_id, mgpp->fdst_layer_id);
+
+   /* merge BG and TOP Layer (does mix opacity according to current step) */
+   curr_opacity = p_linear_advance((gdouble)total_steps
+                                ,(gdouble)current_step
+                                ,(gdouble)0.0
+                                ,(gdouble)100.0
+                                );
+
+   merged_layer_id = 
+   p_mix_layers(curr_image_id
+               ,bg_layer_id
+	       ,top_layer_id
+	       ,curr_width
+	       ,curr_height
+	       ,(gdouble)(curr_opacity / 100.0)
+	       );
+ 
+   mgpp->master_progress += mgpp->layer_progress_step;
+
+   /* DEBUG code: show duplicate of the temporary tween image */
+   if(FALSE)
+   {
+     gint32 dup_id;
+
+     dup_id = gimp_image_duplicate(curr_image_id);
+     gimp_display_new (dup_id);
+
+   }
+
+   return(merged_layer_id);
+
+}  /* end p_create_simple_fade_tween_frame  */
+
+
+/* ----------------------------------
+ * gap_morph_render_one_of_n_tweens
+ * ----------------------------------
+ * This procedure creates only one tween (a scene between 2 video frames)
+ * according to the specified total_steps and current_step parameters.
+ * the created tween is part of a new created image
+ * that contians the tween layer.
+ *
+ * return the newly created tween morphed layer
+ *
+ */
+gint32
+gap_morph_render_one_of_n_tweens(GapMorphGlobalParams *mgpp, gdouble total_steps, gdouble current_step)
+{
+  gint32 new_layer_id;
+  GapMorphExeLayerstack mlayers_struct;
+  GapMorphExeLayerstack *mlayers;
+  
+  mlayers = &mlayers_struct;
+  mlayers->tab_wp_sets = NULL;
+  mlayers->available_wp_sets = 0;
+  new_layer_id = -1;
+  
+  p_get_tween_steps_and_layerstacks(mgpp, mlayers);
+
+  mgpp->create_tween_layers = TRUE;
+
+  /* check if workpoint filename is available */
+  if(mgpp->workpoint_file_lower)
+  {
+    if(*mgpp->workpoint_file_lower != '\0')
+    {
+      /* load a single workpointfile
+       * (note: we use general procedure p_build_wp_set_table and handle the single workpointfile
+       *  as mix of upper and lower set that both refere to the same single workpointfile)
+       */
+      p_build_wp_set_table(mgpp ,mlayers);
+      mgpp->have_workpointsets = FALSE;
+      mlayers->available_wp_sets = 0;
+    }
+  }
+  
+  /* overrule the number of steps with the explicite parameter value */
+  mgpp->tween_steps = total_steps;
+
+  if(mgpp->do_simple_fade)
+  {
+    /* we have no workpoints available
+     * in this case make an attempt with a fast fade operation
+     *  (but restricted to frames of same size and type)
+     */
+    new_layer_id =  p_create_simple_fade_tween_frame(total_steps
+                          ,current_step
+                          ,mgpp
+                          );
+    
+  }
+  
+  if( new_layer_id < 0)
+  {
+    if(gap_debug)
+    {
+      printf("calling the full morph algorithm  total_steps:%f current_step:%f\n"
+        ,(float)total_steps
+        ,(float)current_step
+        );
+    }
+    new_layer_id = p_create_morph_tween_frame(total_steps
+                          ,current_step
+                          ,mgpp
+			  ,mlayers
+                          );
+  }
+  return (gap_image_merge_to_specified_layer(new_layer_id, GIMP_CLIP_TO_IMAGE));
+}  /* end gap_morph_render_one_of_n_tweens */
+
+
+/* ----------------------------------
+ * gap_morph_render_one_tween
+ * ----------------------------------
+ * This procedure creates only one tween (a scene between 2 video frames)
+ * according to the specified mix factor (mgpp->tween_mix_factor)
+ * the created tween is part of a new created image
+ * that contians the tween layer.
+ *
+ * return the newly created tween morphed layer
+ *
+ */
+gint32
+gap_morph_render_one_tween(GapMorphGlobalParams *mgpp)
+{
+  gint32 new_layer_id;
+  gdouble total_steps;
+  gdouble current_step;
+  
+  total_steps = 1.0 * 100000;
+  current_step = CLAMP(mgpp->tween_mix_factor, 0.0, 1.0) * 100000;
+
+  
+  new_layer_id = gap_morph_render_one_of_n_tweens(mgpp, total_steps, current_step);
+
+  return (new_layer_id);
+}  /* end gap_morph_render_one_tween */
+
+
+
+/* ----------------------------------
+ * gap_morph_render_frame_tweens
+ * ----------------------------------
+ *
+ * return the newly created tween morphed layer
+ *
+ */
+gint32
+gap_morph_render_frame_tweens(GapAnimInfo *ainfo_ptr, GapMorphGlobalParams *mgpp)
+{
+  gint32 l_tween_layer_id;
+  gint32 l_tween_frame_nr;
+  gint32 l_rc;
+  gdouble total_steps;
+
+  l_tween_layer_id = -1;
+
+  total_steps = (mgpp->range_to -  mgpp->range_from);
+  mgpp->tween_steps = (mgpp->range_to -  mgpp->range_from); /// ??? - 1;
+
+  mgpp->master_progress = 0.0;
+  mgpp->layer_progress_step = 0.5 / (gdouble)(MAX(1.0, (total_steps -1.0)));
+  if(mgpp->do_progress)
+  {
+    gimp_progress_init(_("creating morph tween frames..."));
+  }
+  
+  if (mgpp->tween_steps > 0)
+  {
+    gint32 l_tmp_image_id;
+    if(ainfo_ptr->new_filename != NULL)
+    {
+      g_free(ainfo_ptr->new_filename);
+    }
+    ainfo_ptr->new_filename = gap_lib_alloc_fname(ainfo_ptr->basename,
+                                        mgpp->range_to,
+                                        ainfo_ptr->extension);
+    if(ainfo_ptr->new_filename == NULL)
+    {
+       printf("could not create frame filename for frameNr:%d\n", (int)mgpp->range_to);
+       return -1;
+    }
+
+    if(!g_file_test(ainfo_ptr->new_filename, G_FILE_TEST_EXISTS))
+    {
+       printf("target frame does not exist, name: %s\n", ainfo_ptr->new_filename);
+       if (mgpp->run_mode != GIMP_RUN_NONINTERACTIVE)
+       {
+         g_message(_("target frame does not exist, name: %s"), ainfo_ptr->new_filename);
+       }
+       return -1;
+    }
+
+    /* load current frame */
+    l_tmp_image_id = gap_lib_load_image(ainfo_ptr->new_filename);
+
+    if(gap_debug)
+    {
+      printf("gap_morph_render_frame_tweens to frame: %s  l_tmp_image_id:%d  RUN_MODE:%d\n"
+         ,ainfo_ptr->new_filename
+         ,(int)l_tmp_image_id
+         ,(int)mgpp->run_mode
+         );
+    }
+
+    mgpp->osrc_layer_id = gap_image_merge_visible_layers(gimp_image_duplicate(mgpp->image_id), GIMP_CLIP_TO_IMAGE);
+    mgpp->fdst_layer_id = gap_image_merge_visible_layers(l_tmp_image_id, GIMP_CLIP_TO_IMAGE);
+
+    if(gap_debug)
+    {
+      printf("gap_morph_render_frame_tweens osrc_layer_id:%d fdst_layer_id:%d \n"
+         ,(int)mgpp->osrc_layer_id
+         ,(int)mgpp->fdst_layer_id
+         );
+    }
+
+    for (l_tween_frame_nr = mgpp->range_from +1; l_tween_frame_nr < mgpp->range_to; l_tween_frame_nr++)
+    {
+      gint32  l_tween_tmp_image_id;
+      gdouble l_current_step;
+      
+      mgpp->master_progress = 2.0 * mgpp->layer_progress_step * (l_tween_frame_nr - (mgpp->range_from +1));
+
+      if(l_tween_layer_id >= 0)
+      {
+        /* delete the previous handled tween frame image in memory. (that is already saved to disk
+         * we keep only the last one opened)
+         */
+        gap_image_delete_immediate(gimp_drawable_get_image(l_tween_layer_id));
+      }
+      
+      l_current_step = l_tween_frame_nr - mgpp->range_from;
+      if(ainfo_ptr->new_filename != NULL)
+      {
+        g_free(ainfo_ptr->new_filename);
+      }
+      ainfo_ptr->new_filename = gap_lib_alloc_fname(ainfo_ptr->basename,
+                                          l_tween_frame_nr,
+                                          ainfo_ptr->extension);
+      if(mgpp->do_progress)
+      {
+        char *l_msg;
+        l_msg = g_strdup_printf(_("creating morph tween frame: %d"), (int)l_tween_frame_nr);
+        gimp_progress_init(l_msg);
+        g_free(l_msg);
+      }
+      if(gap_debug)
+      {
+        printf("gap_morph_render_frame_tweens creating tween:%s\n"
+           ,ainfo_ptr->new_filename
+           );
+      }
+
+      if (mgpp->overwrite_flag != TRUE)
+      {
+        if(g_file_test(ainfo_ptr->new_filename, G_FILE_TEST_EXISTS))
+        {
+          l_tween_layer_id = -1;
+          p_error_message_with_filename(mgpp->run_mode, _("file: %s already exists"), ainfo_ptr->new_filename);
+          break;
+        }
+      }
+
+      l_tween_layer_id = gap_morph_render_one_of_n_tweens(mgpp, total_steps, l_current_step);
+      l_tween_tmp_image_id = gimp_drawable_get_image(l_tween_layer_id);
+      if(gap_debug)
+      {
+        printf("gap_morph_render_frame_tweens saving tween:%s :%d\n"
+           ,ainfo_ptr->new_filename
+           ,(int)l_tween_tmp_image_id
+           );
+      }
+      l_rc = gap_lib_save_named_frame(l_tween_tmp_image_id, ainfo_ptr->new_filename);
+      if(ainfo_ptr->new_filename != NULL)
+      {
+        g_free(ainfo_ptr->new_filename);
+        ainfo_ptr->new_filename = NULL;
+      }
+      if (l_rc < 0)
+      {
+        l_tween_layer_id = -1;
+        p_error_message_with_filename(mgpp->run_mode, _("file: %s save failed"), ainfo_ptr->new_filename);
+        break;
+      }
+
+    }
+    gap_image_delete_immediate(gimp_drawable_get_image(mgpp->osrc_layer_id));
+    gap_image_delete_immediate(gimp_drawable_get_image(mgpp->fdst_layer_id));
+  }
+
+  return(l_tween_layer_id);
+
+}  /* end gap_morph_render_frame_tweens */
+

Modified: trunk/gap/gap_morph_exec.h
==============================================================================
--- trunk/gap/gap_morph_exec.h	(original)
+++ trunk/gap/gap_morph_exec.h	Wed Jan 14 19:59:24 2009
@@ -31,6 +31,7 @@
 #include "libgimp/gimp.h"
 #include "gap_morph_main.h"
 #include "gap_morph_dialog.h"
+#include "gap_libgimpgap.h"
 
 void     gap_morph_exec_free_workpoint_list(GapMorphWorkPoint **wp_list);
 gboolean gap_moprh_exec_save_workpointfile(const char *filename
@@ -54,6 +55,8 @@
 				      , gdouble *pick_y
                                       );
 gint32  gap_morph_execute(GapMorphGlobalParams *mgpp);
+gint32  gap_morph_render_one_tween(GapMorphGlobalParams *mgpp);
+gint32  gap_morph_render_frame_tweens(GapAnimInfo *ainfo_ptr, GapMorphGlobalParams *mgpp);
 
 #endif
 

Modified: trunk/gap/gap_morph_main.c
==============================================================================
--- trunk/gap/gap_morph_main.c	(original)
+++ trunk/gap/gap_morph_main.c	Wed Jan 14 19:59:24 2009
@@ -37,6 +37,7 @@
 #include "gap_morph_main.h"
 #include "gap_morph_exec.h"
 #include "gap_morph_dialog.h"
+#include "gap_morph_tween_dialog.h"
 #include "gap_pview_da.h"
 
 /* for pointfile loader (workaround) */
@@ -48,11 +49,13 @@
 #include "gap-intl.h"
 
 /* Defines */
-#define PLUG_IN_NAME        "plug_in_gap_morph_layers"
-#define PLUG_IN_PRINT_NAME  "Morph Layers"
-#define PLUG_IN_IMAGE_TYPES "RGBA, GRAYA"
-#define PLUG_IN_AUTHOR      "Wolfgang Hofer (hof gimp org)"
-#define PLUG_IN_COPYRIGHT   "Wolfgang Hofer"
+#define PLUG_IN_NAME            "plug_in_gap_morph_layers"
+#define PLUG_IN_NAME_TWEEN      "plug_in_gap_morph_tween"      /* render missing tween(s) between frames */
+#define PLUG_IN_NAME_ONE_TWEEN  "plug_in_gap_morph_one_tween"  /* single tween rendering  */
+#define PLUG_IN_PRINT_NAME      "Morph Layers"
+#define PLUG_IN_IMAGE_TYPES     "RGBA, GRAYA"
+#define PLUG_IN_AUTHOR          "Wolfgang Hofer (hof gimp org)"
+#define PLUG_IN_COPYRIGHT       "Wolfgang Hofer"
 
 
 int gap_debug = 0;  /* 1 == print debug infos , 0 dont print debug infos */
@@ -70,7 +73,7 @@
 , "\0"        /* char workpoint_file_lower[1024] */
 , "\0"        /* char workpoint_file_upper[1024] */
 , TRUE        /* gboolean            create_tween_layers */
-, FALSE       /* gboolean            multiple_pointsets */
+, FALSE       /* gboolean            have_workpointsets */
 , FALSE       /* gboolean            use_quality_wp_selection */
 , FALSE       /* gboolean            use_gravity */
 , 2.0         /* gdouble             gravity_intensity */
@@ -79,6 +82,11 @@
 , FALSE       /* gboolean            do_progress */
 , 0.0         /* gdouble             master_progress */
 , 0.0         /* gdouble             layer_progress_step */
+, 0.0         /* gdouble             tween_mix_factor */
+, -1          /*  long                range_from */
+, -1          /*  long                range_to */
+, FALSE       /* gboolean            overwrite_flag */
+, FALSE       /* gboolean            do_simple_fade */
 };
 
 
@@ -89,6 +97,7 @@
                   gint *nreturn_vals,        /* number of parameters returned */
                   GimpParam ** return_vals); /* parameters to be returned */
 
+static gint32   p_handle_PLUG_IN_NAME_TWEEN(GapMorphGlobalParams *mgpp);
 
 /* Global Variables */
 GimpPlugInInfo PLUG_IN_INFO =
@@ -109,12 +118,46 @@
                   { GIMP_PDB_INT32,    "create_tween_layers", "TRUE: Do create tween layers,  FALSE: operate on existing layers"},
                   { GIMP_PDB_STRING,   "workpoint_file_1", "Name of a Morph/Warp workpointfile"
 		                                           "(create such file(s) with the save button in the GUI at INTERACTIVE runmode)"},
-                  { GIMP_PDB_STRING,   "workpoint_file_2", "Name of an ptional 2nd Morph/Warp workpointfile."
+                  { GIMP_PDB_STRING,   "workpoint_file_2", "Name of an optional 2nd Morph/Warp workpointfile."
 		                                           " (pass an empty string or the same name as the 1st file"
 							   " if you want to operate with one workpoint file)"},
   };
 
 
+static GimpParamDef in_tween_args[] = {
+                  { GIMP_PDB_INT32,    "run_mode", "Interactive, non-interactive."},
+                  { GIMP_PDB_IMAGE,    "start_image",    "from frame image (must be a frame with GIMP-GAP typical number part in the imagefilename)" },
+                  { GIMP_PDB_DRAWABLE, "drawable", "ignored"},
+                  { GIMP_PDB_INT32,    "to_frame_nr", "frame number of the next available frame"},
+                  { GIMP_PDB_INT32,    "overwrite", "0 == do not overwrite, 1 == overrite existing frames"},
+                  { GIMP_PDB_INT32,    "do_simple_fade", "0 == use morph algorithm, 1 == use simple fade operation (ignore the workpoint_file) "},
+                  { GIMP_PDB_STRING,   "workpoint_file", "Name of a Morph/Warp workpointfile"
+		                                           "(create such file(s) with the save button in the GUI "
+                                                           "of the plug_in_gap_morph_layers, or specify an emty string"
+                                                           "that starts with 0x00 to operate as simple video fade)"},
+  };
+static GimpParamDef out_tween_args[] = {
+                  { GIMP_PDB_DRAWABLE, "tween_drawable", "the last one of the newly created tween(s) (a layer in a newly created frame image)"},
+  };
+
+static GimpParamDef in_one_tween_args[] = {
+                  { GIMP_PDB_INT32,    "run_mode", "Interactive, non-interactive."},
+                  { GIMP_PDB_IMAGE,    "image",    "(not relevant)" },
+                  { GIMP_PDB_DRAWABLE, "src_drawable", "source drawable (usually a layer)"},
+                  { GIMP_PDB_DRAWABLE, "dst_drawable", "destination drawable (usually a layer)"},
+                  { GIMP_PDB_FLOAT,    "tween_mix_factor", "a value between 0.0 and 1.0 where 0 delivers a copy of the src layer"
+                                        "1 delivers a copy of the destination layer,"
+                                        "other value deliver a mix according to morph algortihm" },
+                  { GIMP_PDB_INT32,    "do_simple_fade", "0 == use morph algorithm, 1 == use simple fade operation (ignore the workpoint_file) "},
+                  { GIMP_PDB_STRING,   "workpoint_file", "Name of a Morph/Warp workpointfile"
+		                                           "(create such file(s) with the save button in the GUI "
+                                                           "of the plug_in_gap_morph_layers, or specify an emty string"
+                                                           "that starts with 0x00 to operate as simple video fade)"},
+  };
+static GimpParamDef out_one_tween_args[] = {
+                  { GIMP_PDB_DRAWABLE, "tween_drawable", "newly created tween (a layer in a newly created image)"},
+  };
+
 MAIN ()
 
 static void query (void)
@@ -151,10 +194,139 @@
                           NULL      /* out_args */
                           );
 
-  // gimp_plugin_menu_branch_register("<Image>", "Video");
-  gimp_plugin_menu_register (PLUG_IN_NAME, N_("<Image>/Video/"));
+  /* the actual installation of the plugin */
+  gimp_install_procedure (PLUG_IN_NAME_TWEEN,
+                          "Render tween frames via morhing",
+                          "This plug-in creates and saves image frames that are a mix of the specified image frame and the frame with to_frame_nr, "
+                          "The typical usage is to create the frame images of missing frame numbers in a series of anim frame images. "
+			  "the overwrite flag allows overwriting of already existing frames between the start frame image "
+                          "and the frame with to_frame_nr"
+			  "Morphing is controled by workpoints. A Workpoint file can be created and edited with the help "
+			  "of the Morph feature in the Video menu. "
+			  "Note: without workpoints the resulting tween is calculated as simple fade operation. "
+			  ,
+                          PLUG_IN_AUTHOR,
+                          PLUG_IN_COPYRIGHT,
+                          GAP_VERSION_WITH_DATE,
+                          N_("Morph Tweenframes..."),
+                          PLUG_IN_IMAGE_TYPES,
+                          GIMP_PLUGIN,
+                          G_N_ELEMENTS (in_tween_args),
+                          G_N_ELEMENTS (out_tween_args),
+                          in_tween_args,
+                          out_tween_args
+                          );
+
+
+  /* the actual installation of the plugin */
+  gimp_install_procedure (PLUG_IN_NAME_ONE_TWEEN,
+                          "Render one tween via morhing",
+                          "This plug-in creates a new image that is a mix of the specified src_drawable and dst_drawable, "
+                          "the mixing is done based on a morphing transformation where the tween_mix_factor "
+			  "determines how much the result looks like source or destination. "
+                          "source and destination may differ in size and can be in different images. "
+			  "Morphing is controled by workpoints. A Workpoint file can be created and edited with the help "
+			  "of the Morph feature in the Video menu. "
+			  "Note: without workpoints the resulting tween is calculated as simple fade operation. "
+			  ,
+                          PLUG_IN_AUTHOR,
+                          PLUG_IN_COPYRIGHT,
+                          GAP_VERSION_WITH_DATE,
+                          N_("Morph One Tween..."),
+                          PLUG_IN_IMAGE_TYPES,
+                          GIMP_PLUGIN,
+                          G_N_ELEMENTS (in_one_tween_args),
+                          G_N_ELEMENTS (out_one_tween_args),
+                          in_one_tween_args,
+                          out_one_tween_args
+                          );
+
+
+  {
+    /* Menu names */
+    const char *menupath_image_video_morph = N_("<Image>/Video/Morph/");
+
+    //gimp_plugin_menu_branch_register("<Image>", "Video/Morph");
+  
+    gimp_plugin_menu_register (PLUG_IN_NAME,           menupath_image_video_morph);
+    gimp_plugin_menu_register (PLUG_IN_NAME_TWEEN,     menupath_image_video_morph);
+    gimp_plugin_menu_register (PLUG_IN_NAME_ONE_TWEEN, menupath_image_video_morph);
+  }
 }
 
+/* ----------------------------------
+ * p_handle_PLUG_IN_NAME_TWEEN
+ * ----------------------------------
+ *
+ * return the newly created tween morphed layer
+ *
+ */
+static gint32
+p_handle_PLUG_IN_NAME_TWEEN(GapMorphGlobalParams *mgpp)
+{
+  gint32 l_tween_layer_id;
+  GapAnimInfo *ainfo_ptr;
+
+  gboolean       l_rc;
+  gboolean       l_run_flag;
+
+  l_tween_layer_id = -1;
+  l_rc = FALSE;
+  l_run_flag = TRUE;
+
+  ainfo_ptr = gap_lib_alloc_ainfo(mgpp->image_id, mgpp->run_mode);
+  if(ainfo_ptr != NULL)
+  {
+    if (0 == gap_lib_dir_ainfo(ainfo_ptr))
+    {
+      mgpp->range_from = ainfo_ptr->curr_frame_nr;
+      /* mgpp->range_to is already set at noninteractive call. for interacive cals this is set in the following dialog
+       */
+      if(mgpp->run_mode == GIMP_RUN_INTERACTIVE)
+      {
+         if(0 != gap_lib_chk_framechange(ainfo_ptr)) { l_run_flag = FALSE; }
+         else
+         {
+           if(*ainfo_ptr->extension == '\0' && ainfo_ptr->frame_cnt == 0)
+           {
+             /* plugin was called on a frame without extension and without framenumer in its name
+              * (typical for new created images named like 'Untitled' 
+              */
+               g_message(_("Operation cancelled.\n"
+                         "GAP video plug-ins only work with filenames\n"
+                         "that end in numbers like _000001.xcf.\n"
+                         "==> Rename your image, then try again."));
+               return -1;
+           }
+           l_rc = gap_morph_frame_tweens_dialog(ainfo_ptr, mgpp);
+           mgpp->do_progress = TRUE;
+         }
+
+         if((0 != gap_lib_chk_framechange(ainfo_ptr)) || (!l_rc))
+         {
+            l_run_flag = FALSE;
+         }
+
+      }
+
+      if(l_run_flag == TRUE)
+      {
+         /* render tween frames and write them as framefiles to disc () */
+         l_tween_layer_id = gap_morph_render_frame_tweens(ainfo_ptr, mgpp);
+      }
+
+    }
+    gap_lib_free_ainfo(&ainfo_ptr);
+  }
+
+  return(l_tween_layer_id);
+
+}  /* end p_handle_PLUG_IN_NAME_TWEEN */
+
+/* -------------------------------------
+ * run
+ * -------------------------------------
+ */
 static void
 run (const gchar *name,          /* name of plugin */
      gint nparams,               /* number of in-paramters */
@@ -177,20 +349,26 @@
   GimpPDBStatusType status = GIMP_PDB_SUCCESS;
 
   /* always return at least the status to the caller. */
-  static GimpParam values[1];
+  static GimpParam values[2];
 
   INIT_I18N();
 
-
   l_env = g_getenv("GAP_DEBUG");
   if(l_env != NULL)
   {
     if((*l_env != 'n') && (*l_env != 'N')) gap_debug = 1;
   }
 
-  if(gap_debug) fprintf(stderr, "\n\nDEBUG: run %s\n", name);
+  if(gap_debug)
+  {
+    printf("\n\nDEBUG: run %s  RUN_MODE:%d\n", name, (int)run_mode);
+  }
 
   run_flag = FALSE;
+  if (strcmp(name, PLUG_IN_NAME_TWEEN) == 0)
+  {
+    run_flag = TRUE;
+  }
   /* initialize the return of the status */
   values[0].type = GIMP_PDB_STATUS;
   values[0].data.d_status = status;
@@ -202,24 +380,41 @@
   image_id = param[1].data.d_int32;
   drawable_id = param[2].data.d_drawable;
   mgpp->do_progress = FALSE;
+  mgpp->image_id = image_id;
+  mgpp->run_mode = run_mode;
+
 
 
   switch (run_mode)
   {
     case GIMP_RUN_INTERACTIVE:
-      /* Possibly retrieve data from a previous run */
-      gimp_get_data (PLUG_IN_NAME, mgpp);
-      mgpp->osrc_layer_id          = drawable_id;
-      mgpp->fdst_layer_id          = gap_morph_exec_find_dst_drawable(image_id, drawable_id);
-      run_flag = gap_morph_dialog(mgpp);
-      mgpp->do_progress            = TRUE;
+      if (strcmp(name, PLUG_IN_NAME) == 0)
+      {
+        /* Possibly retrieve data from a previous run */
+        gimp_get_data (PLUG_IN_NAME, mgpp);
+        mgpp->osrc_layer_id          = drawable_id;
+        mgpp->fdst_layer_id          = gap_morph_exec_find_dst_drawable(image_id, drawable_id);
+        run_flag = gap_morph_dialog(mgpp);
+        mgpp->do_progress            = TRUE;
+      }
+      else if (strcmp(name, PLUG_IN_NAME_ONE_TWEEN) == 0)
+      {
+        mgpp->tween_mix_factor       = 0.5;
+        /* Possibly retrieve data from a previous run */
+        gimp_get_data (PLUG_IN_NAME_ONE_TWEEN, mgpp);
+        mgpp->osrc_layer_id          = drawable_id;
+        mgpp->fdst_layer_id          = gap_morph_exec_find_dst_drawable(image_id, drawable_id);
+        run_flag = gap_morph_one_tween_dialog(mgpp);
+        mgpp->do_progress            = TRUE;
+      }
       break;
 
     case GIMP_RUN_NONINTERACTIVE:
       /* check to see if invoked with the correct number of parameters */
-      if (nparams == G_N_ELEMENTS (in_args))
+      if ((nparams == G_N_ELEMENTS (in_args))
+      && (strcmp(name, PLUG_IN_NAME) == 0))
       {
-          mgpp->multiple_pointsets     = TRUE;  /* use pointset(s) from file */
+          mgpp->have_workpointsets     = TRUE;  /* use pointset(s) from file */
 	  
 	  /* set defaults for params that may be specified in the workpointfiles
 	   * (the defaults will take effect only if the file does not contain such settings)
@@ -273,6 +468,99 @@
 	  
 	  run_flag = TRUE;
       }
+      else if ((nparams == G_N_ELEMENTS (in_one_tween_args))
+      && (strcmp(name, PLUG_IN_NAME_ONE_TWEEN) == 0))
+      {
+	  /* set defaults for params that may be specified in the workpointfiles
+	   * (the defaults will take effect only if the file does not contain such settings)
+	   */
+	  mgpp->use_quality_wp_selection = FALSE;
+          mgpp->have_workpointsets     = FALSE;  /* operate with a single workpointfile */
+	  mgpp->use_gravity = FALSE;
+	  mgpp->gravity_intensity = 2.0;
+	  mgpp->affect_radius = 100.0;
+          mgpp->tween_steps = 1;  /* (in this mode always render only one tween) */
+          mgpp->render_mode = GAP_MORPH_RENDER_MODE_MORPH;
+          mgpp->create_tween_layers = TRUE;
+	  
+          mgpp->osrc_layer_id          = param[2].data.d_drawable;
+          mgpp->fdst_layer_id          = param[3].data.d_drawable;
+          mgpp->tween_mix_factor       = param[4].data.d_float;
+          mgpp->do_simple_fade         = (param[5].data.d_int32 != 0);
+	  if(param[6].data.d_string != NULL)
+	  {
+	    if(param[6].data.d_string[0] != '\0')
+	    {
+	      g_snprintf(mgpp->workpoint_file_lower
+	              , sizeof(mgpp->workpoint_file_lower)
+		      , "%s", param[6].data.d_string);
+	      g_snprintf(mgpp->workpoint_file_upper
+	              , sizeof(mgpp->workpoint_file_upper)
+		      , "%s", param[6].data.d_string);
+	    }
+	    else
+	    {
+              mgpp->have_workpointsets     = FALSE;  /* no pointset file available */
+            }
+	    run_flag = TRUE;
+	  }
+	  else
+	  {
+            printf("%s: noninteractive call requires a not-NULL workpoint_file parameter\n"
+        	    , PLUG_IN_NAME_ONE_TWEEN
+        	    );
+            status = GIMP_PDB_CALLING_ERROR;
+	  }
+	  
+	  
+      }
+      else if ((nparams == G_N_ELEMENTS (in_one_tween_args))
+      && (strcmp(name, PLUG_IN_NAME_TWEEN) == 0))
+      {
+	  /* set defaults for params that may be specified in the workpointfiles
+	   * (the defaults will take effect only if the file does not contain such settings)
+	   */
+	  mgpp->use_quality_wp_selection = FALSE;
+          mgpp->have_workpointsets     = FALSE;  /* operate with a single workpointfile */
+	  mgpp->use_gravity = FALSE;
+	  mgpp->gravity_intensity = 2.0;
+	  mgpp->affect_radius = 100.0;
+          mgpp->tween_steps = 1;  /* (will be calculated later as difference of handled frame numbers) */
+          mgpp->render_mode = GAP_MORPH_RENDER_MODE_MORPH;
+          mgpp->create_tween_layers = TRUE;
+	  
+          mgpp->osrc_layer_id = -1;  /* is created later as merged copy of the specified image */
+          mgpp->fdst_layer_id = -1;   /* is created later as merged copy of the frame rfered by to_frame_nr parameter  */        
+          mgpp->range_to = param[3].data.d_int32;
+          mgpp->overwrite_flag = (param[4].data.d_int32 != 0);
+          mgpp->do_simple_fade = (param[5].data.d_int32 != 0);
+          mgpp->tween_mix_factor       = 1.0;  /* not relevant here */
+	  if(param[6].data.d_string != NULL)
+	  {
+	    if(param[6].data.d_string[0] != '\0')
+	    {
+	      g_snprintf(mgpp->workpoint_file_lower
+	              , sizeof(mgpp->workpoint_file_lower)
+		      , "%s", param[6].data.d_string);
+	      g_snprintf(mgpp->workpoint_file_upper
+	              , sizeof(mgpp->workpoint_file_upper)
+		      , "%s", param[6].data.d_string);
+	    }
+	    else
+	    {
+              mgpp->have_workpointsets     = FALSE;  /* no pointset file available */
+	    }
+	    run_flag = TRUE;
+	  }
+	  else
+	  {
+            printf("%s: noninteractive call requires a not-NULL workpoint_file parameter\n"
+        	    , PLUG_IN_NAME_TWEEN
+        	    );
+            status = GIMP_PDB_CALLING_ERROR;
+	  }
+	  
+      }
       else
       {
         printf("%s: noninteractive call wrong nuber %d of params were passed. (%d params are required)\n"
@@ -285,12 +573,15 @@
       break;
 
     case GIMP_RUN_WITH_LAST_VALS:
-      /* Possibly retrieve data from a previous run */
-      gimp_get_data (PLUG_IN_NAME, mgpp);
-      mgpp->osrc_layer_id          = drawable_id;
-      mgpp->fdst_layer_id          = gap_morph_exec_find_dst_drawable(image_id, drawable_id);
-      run_flag = gap_morph_dialog(mgpp);
-      mgpp->do_progress            = TRUE;
+      if (strcmp(name, PLUG_IN_NAME) == 0)
+      {
+        /* Possibly retrieve data from a previous run */
+        gimp_get_data (PLUG_IN_NAME, mgpp);
+        mgpp->osrc_layer_id          = drawable_id;
+        mgpp->fdst_layer_id          = gap_morph_exec_find_dst_drawable(image_id, drawable_id);
+        run_flag = gap_morph_dialog(mgpp);
+        mgpp->do_progress            = TRUE;
+      }
       break;
 
     default:
@@ -300,15 +591,48 @@
   if ((status == GIMP_PDB_SUCCESS)
   && (run_flag))
   {
+    if (strcmp(name, PLUG_IN_NAME) == 0)
+    {
+      gap_morph_execute(mgpp);
+      /* Store variable states for next run */
+      if (run_mode == GIMP_RUN_INTERACTIVE)
+      {
+        gimp_set_data (PLUG_IN_NAME, mgpp, sizeof (GapMorphGlobalParams));
+      }
+    }
+    else if ((strcmp(name, PLUG_IN_NAME_ONE_TWEEN) == 0) || (strcmp(name, PLUG_IN_NAME_TWEEN) == 0))
+    {
+      gint32 tween_layer_id;
+      
+      if (strcmp(name, PLUG_IN_NAME_ONE_TWEEN) == 0)
+      {
+        tween_layer_id = gap_morph_render_one_tween(mgpp);
+      }
+      else if (strcmp(name, PLUG_IN_NAME_TWEEN) == 0)
+      {
+        tween_layer_id = p_handle_PLUG_IN_NAME_TWEEN(mgpp);
+      }
+
+
+      values[1].type = GIMP_PDB_DRAWABLE;
+      values[1].data.d_int32 = tween_layer_id;
+      values[1].data.d_drawable = tween_layer_id;
+      *nreturn_vals = 2;
+      if (tween_layer_id < 0)
+      {
+        status = GIMP_PDB_EXECUTION_ERROR;
+      }
+      else
+      {
+         if (run_mode == GIMP_RUN_INTERACTIVE)
+         {
+           /* Store variable states for next run */
+           gimp_set_data (name, mgpp, sizeof (GapMorphGlobalParams));
+           gimp_display_new(gimp_drawable_get_image(tween_layer_id));
+         }
+      }
+    }
 
-    mgpp->image_id = image_id;
-    mgpp->run_mode = run_mode;
-    
-    gap_morph_execute(mgpp);
-
-    /* Store variable states for next run */
-    if (run_mode == GIMP_RUN_INTERACTIVE)
-      gimp_set_data (PLUG_IN_NAME, mgpp, sizeof (GapMorphGlobalParams));
   }
   values[0].data.d_status = status;
 }       /* end run */

Modified: trunk/gap/gap_morph_main.h
==============================================================================
--- trunk/gap/gap_morph_main.h	(original)
+++ trunk/gap/gap_morph_main.h	Wed Jan 14 19:59:24 2009
@@ -85,7 +85,7 @@
   char                workpoint_file_upper[GAP_MORPH_WORKPOINT_FILENAME_MAX_LENGTH];
 
   gboolean            create_tween_layers;       /* FALSE: operate on existing layers only */
-  gboolean            multiple_pointsets;        /* FALSE: use the default workpointset master_wp_list
+  gboolean            have_workpointsets;        /* FALSE: use the default workpointset master_wp_list
                                                   * TRUE: use lower_wp_list and upper_wp_list
 						  *       foreach handled frame the
 						  *       lower and upper list are fetched from 
@@ -102,7 +102,11 @@
   gdouble             master_progress;
   gdouble             layer_progress_step;
 
-
+  gdouble             tween_mix_factor;  /* 0.0 upto 1.0 wher 0.0 gives source layer 1.0 dest layer as resut */
+  gint32              range_from;
+  gint32              range_to;
+  gboolean            overwrite_flag;
+  gboolean            do_simple_fade;   /* bypass morph algortihm when renderiing tweens and use simple fade instead */
 } GapMorphGlobalParams;
 
 typedef struct GapMorphWarpCoreAPI  { /* nickname: wcap */

Added: trunk/gap/gap_morph_tween_dialog.c
==============================================================================
--- (empty file)
+++ trunk/gap/gap_morph_tween_dialog.c	Wed Jan 14 19:59:24 2009
@@ -0,0 +1,536 @@
+/*  gap_morph_one_tween_dialog.c
+ *
+ *  This module handles the GAP morph tween dialog
+ */
+/* 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.
+ */
+
+#include "config.h"
+
+#include <gtk/gtk.h>
+#include <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+
+#include "gap_morph_main.h"
+#include "gap_morph_tween_dialog.h"
+#include "gap-intl.h"
+
+extern int gap_debug;  /* 1 == print debug infos , 0 dont print debug infos */
+
+#define SCALE_WIDTH  200
+#define SPIN_BUTTON_WIDTH 60
+
+typedef struct MorphTweenGui { /* nickname: mtg */
+     GapMorphGlobalParams *mgpp;
+     GtkWidget *morph_filesel;
+     GtkWidget *morph_entry;
+  } MorphTweenGui;
+  
+  
+/* ----------------------------
+ * p_selectionConstraintFunc
+ * ----------------------------
+ *
+ */
+static gint
+p_selectionConstraintFunc (gint32   image_id,
+               gint32   drawable_id,
+               gpointer data)
+{
+  if (image_id < 0)
+    return FALSE;
+
+  /* dont accept layers from indexed images */
+  if (gimp_drawable_is_indexed (drawable_id))
+    return FALSE;
+
+  return TRUE;
+}  /* end p_selectionConstraintFunc */
+
+/* -----------------------------
+ * p_layerSelectionComboCallback
+ * -----------------------------
+ *
+ */
+static void
+p_layerSelectionComboCallback (GtkWidget *widget)
+{
+  gint idValue;
+  gint32 *layerIdPtr;
+
+  if(gap_debug)
+  {
+    printf("p_layerSelectionComboCallback START\n");
+  }
+
+  gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget), &idValue);
+  layerIdPtr = g_object_get_data (G_OBJECT (widget), "layerIdPtr");
+
+  if(gap_debug)
+  {
+    printf("p_layerSelectionComboCallback idValue:%d\n", idValue);
+  }
+  
+  if (layerIdPtr)
+  {
+    *layerIdPtr = idValue;
+  }
+
+}  /* end p_layerSelectionComboCallback */
+
+
+
+
+/* --------------------------
+ * FILESEL
+ * --------------------------
+ */
+static void
+p_filesel_close_cb(GtkWidget *widget, MorphTweenGui *mtg)
+{
+  if(mtg->morph_filesel == NULL) return;  /* filesel is already closed */
+
+  gtk_widget_destroy(GTK_WIDGET(mtg->morph_filesel));
+  mtg->morph_filesel = NULL;
+}
+
+static void
+p_filesel_ok_cb(GtkWidget *widget, MorphTweenGui *mtg)
+{
+  const gchar *filename;
+
+  if(mtg->morph_filesel == NULL) return;  /* filesel is already closed */
+
+  filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION (mtg->morph_filesel));
+
+  gtk_entry_set_text(GTK_ENTRY(mtg->morph_entry), filename);
+
+  p_filesel_close_cb(widget, mtg);
+}
+
+/* --------------------------------------
+ * p_filesel_open_cb
+ * --------------------------------------
+ */
+static void
+p_filesel_open_cb(GtkWidget *widget, MorphTweenGui *mtg)
+{
+  GtkWidget *filesel;
+  GapMorphGlobalParams *mgpp;
+
+  if(mtg->morph_filesel != NULL)
+  {
+    gtk_window_present(GTK_WINDOW(mtg->morph_filesel));
+    return;  /* filesel is already open */
+  }
+  
+  filesel = gtk_file_selection_new (_("Enter Morph Workpoint filename"));
+  mtg->morph_filesel = filesel;
+  mgpp =  mtg->mgpp;
+
+  gtk_window_set_position (GTK_WINDOW (filesel), GTK_WIN_POS_MOUSE);
+
+  gtk_file_selection_set_filename (GTK_FILE_SELECTION (filesel),
+				   &mgpp->workpoint_file_lower[0]);
+  gtk_widget_show (filesel);
+
+  g_signal_connect (G_OBJECT (filesel), "destroy",
+		    G_CALLBACK (p_filesel_close_cb),
+		    mtg);
+
+  g_signal_connect (G_OBJECT (GTK_FILE_SELECTION (filesel)->ok_button),
+		   "clicked",
+                    G_CALLBACK (p_filesel_ok_cb),
+		    mtg);
+  g_signal_connect (G_OBJECT (GTK_FILE_SELECTION (filesel)->cancel_button),
+		   "clicked",
+                    G_CALLBACK (p_filesel_close_cb),
+		    mtg);
+}
+
+/* -----------------------------------------------------
+ * p_check_workpoint_file_and_use_single_fade_if_missing
+ * -----------------------------------------------------
+ */
+static void
+p_check_workpoint_file_and_use_single_fade_if_missing(GapMorphGlobalParams *mgpp)
+{
+   if(g_file_test(&mgpp->workpoint_file_lower[0], G_FILE_TEST_EXISTS))
+   {
+     mgpp->do_simple_fade     = FALSE;  /* use morph algortihm when workpoint file is available */
+   }
+   else
+   {
+     mgpp->do_simple_fade     = TRUE;  /* use simple fade because we have no workpoint file */
+   }
+}
+
+/* --------------------------------------
+ * p_morph_workpoint_entry_update_cb
+ * --------------------------------------
+ */
+static void
+p_morph_workpoint_entry_update_cb(GtkWidget *widget, GapMorphGlobalParams *mgpp)
+{
+   g_snprintf(&mgpp->workpoint_file_lower[0]
+	   , sizeof(mgpp->workpoint_file_lower)
+	   , "%s"
+           , gtk_entry_get_text(GTK_ENTRY(widget))
+           );
+   g_snprintf(&mgpp->workpoint_file_upper[0]
+	   , sizeof(mgpp->workpoint_file_upper)
+	   , "%s"
+           , gtk_entry_get_text(GTK_ENTRY(widget))
+           );
+   if(gap_debug)
+   {
+     printf("p_morph_workpoint_entry_update_cb  workpoint_file_lower: %s\n"
+       , &mgpp->workpoint_file_lower[0]);
+   }
+
+   p_check_workpoint_file_and_use_single_fade_if_missing(mgpp);
+   
+}  /* end p_morph_workpoint_entry_update_cb */
+
+
+
+/* --------------------------------------
+ * p_create_morph_workpoint_entry
+ * --------------------------------------
+ */
+static void
+p_create_morph_workpoint_entry(GapMorphGlobalParams *mgpp, MorphTweenGui *mtg, gint row, GtkWidget *table)
+{
+  GtkWidget *entry;
+  GtkWidget *label;
+  GtkWidget *button;
+
+  /* morph workpoint entry */
+  label = gtk_label_new (_("Morph Workpoint file:"));
+  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+  gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
+                    GTK_FILL, GTK_FILL, 4, 0);
+  gtk_widget_show (label);
+
+  entry = gtk_entry_new();
+  mtg->morph_entry = entry;
+  gtk_widget_set_size_request(entry, SCALE_WIDTH, -1);
+  if(mgpp->workpoint_file_lower[0] != '\0')
+  {
+    gtk_entry_set_text(GTK_ENTRY(entry), &mgpp->workpoint_file_lower[0]);
+  }
+  gtk_table_attach(GTK_TABLE(table), entry, 1, 2, row, row + 1, GTK_FILL, GTK_FILL | GTK_EXPAND, 4, 0);
+  gimp_help_set_help_data(entry, _("Name of a Workpointfile created with the Morph feature\n"
+                                   "(note that tweens are created via simple fade operations when no workpointfile is available))"), NULL);
+  gtk_widget_show(entry);
+
+  g_signal_connect(G_OBJECT(entry), "changed",
+		   G_CALLBACK (p_morph_workpoint_entry_update_cb),
+		   mgpp);
+    
+    
+  /* Button  to invoke filebrowser */  
+  button = gtk_button_new_with_label ( "..." );
+  gtk_widget_set_size_request(button, SPIN_BUTTON_WIDTH, -1);
+  g_object_set_data (G_OBJECT (button), "mgpp", (gpointer)mgpp);
+  gtk_table_attach( GTK_TABLE(table), button, 2, 3, row, row +1,
+		    0, 0, 0, 0 );
+  gtk_widget_show (button);
+  g_signal_connect (G_OBJECT (button), "clicked",
+		    G_CALLBACK (p_filesel_open_cb),
+		    mtg);
+}  /* end p_create_morph_workpoint_entry */
+
+/* --------------------------------------
+ * gap_morph_one_tween_dialog
+ * --------------------------------------
+ */
+gboolean
+gap_morph_one_tween_dialog(GapMorphGlobalParams *mgpp)
+{
+  MorphTweenGui  morphTweenGui;
+  MorphTweenGui  *mtg;
+  GtkWidget *dialog;
+  GtkWidget *main_vbox;
+  GtkWidget *label;
+  GtkWidget *table;
+  GtkWidget *combo;
+  GtkObject *adj;
+  gint       row;
+  gboolean   run;
+
+  mtg = &morphTweenGui;
+  mtg->mgpp = mgpp;
+  mtg->morph_filesel = NULL;
+  p_check_workpoint_file_and_use_single_fade_if_missing(mgpp);
+
+  gimp_ui_init (GAP_MORPH_TWEEN_PLUGIN_NAME, TRUE);
+
+  dialog = gimp_dialog_new (_("Create one tween"), GAP_MORPH_TWEEN_PLUGIN_NAME,
+                            NULL, 0,
+                            gimp_standard_help_func, GAP_MORPH_TWEEN_HELP_ID,
+
+                            GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                            GTK_STOCK_OK,     GTK_RESPONSE_OK,
+
+                            NULL);
+
+
+  gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
+                                           GTK_RESPONSE_OK,
+                                           GTK_RESPONSE_CANCEL,
+                                           -1);
+
+  gimp_window_set_transient (GTK_WINDOW (dialog));
+
+  main_vbox = gtk_vbox_new (FALSE, 12);
+  gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
+  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), main_vbox);
+  gtk_widget_show (main_vbox);
+
+
+  /* Controls */
+  table = gtk_table_new (3, 3, FALSE);
+  gtk_table_set_col_spacings (GTK_TABLE (table), 6);
+  gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+  gtk_box_pack_start (GTK_BOX (main_vbox), table, FALSE, FALSE, 0);
+  gtk_widget_show (table);
+
+  row = 0;
+
+  adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row,
+                              _("tween mix:"), SCALE_WIDTH, 7,
+                              mgpp->tween_mix_factor, 0.0, 1.0, 0.1, 0.1, 3,
+                              TRUE, 0, 0,
+                              NULL, NULL);
+  g_signal_connect (adj, "value-changed",
+                    G_CALLBACK (gimp_double_adjustment_update),
+                    &mgpp->tween_mix_factor);
+
+  row++;
+
+  /* layer combo_box (source) */
+  label = gtk_label_new (_("Source Layer:"));
+  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+  gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
+                    GTK_FILL, GTK_FILL, 4, 0);
+  gtk_widget_show (label);
+
+  /* layer combo_box (Sample from where to pick the alternative selection */
+  combo = gimp_layer_combo_box_new (p_selectionConstraintFunc, NULL);
+
+  g_object_set_data (G_OBJECT (combo), "layerIdPtr", &mgpp->osrc_layer_id);
+  gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (combo), mgpp->osrc_layer_id,
+                              G_CALLBACK (p_layerSelectionComboCallback),
+                              NULL);
+
+  gtk_table_attach (GTK_TABLE (table), combo, 1, 3, row, row + 1,
+                    GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
+  gtk_widget_show (combo);
+
+  row++;
+
+  /* layer combo_box (source) */
+  label = gtk_label_new (_("Destination Layer:"));
+  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+  gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
+                    GTK_FILL, GTK_FILL, 4, 0);
+  gtk_widget_show (label);
+
+  /* layer combo_box (Sample from where to pick the alternative selection */
+  combo = gimp_layer_combo_box_new (p_selectionConstraintFunc, NULL);
+
+  g_object_set_data (G_OBJECT (combo), "layerIdPtr", &mgpp->fdst_layer_id);
+  gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (combo), mgpp->fdst_layer_id,
+                              G_CALLBACK (p_layerSelectionComboCallback),
+                              NULL);
+
+  gtk_table_attach (GTK_TABLE (table), combo, 1, 3, row, row + 1,
+                    GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
+  gtk_widget_show (combo);
+
+  row++;
+
+  p_create_morph_workpoint_entry(mgpp, mtg, row, table);
+
+  /* Done */
+
+  gtk_widget_show (dialog);
+
+  run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
+
+  gtk_widget_destroy (dialog);
+
+  return run;
+} /* end gap_morph_one_tween_dialog */
+
+
+/* --------------------------------------
+ * gap_morph_frame_tweens_dialog
+ * --------------------------------------
+ */
+gboolean
+gap_morph_frame_tweens_dialog(GapAnimInfo *ainfo_ptr, GapMorphGlobalParams *mgpp)
+{
+  MorphTweenGui  morphTweenGui;
+  MorphTweenGui  *mtg;
+  GtkWidget *dialog;
+  GtkWidget *main_vbox;
+  GtkWidget *table;
+  GtkObject *adj;
+  GtkWidget *scale;
+  GtkWidget *spinbutton;
+  GtkWidget *label;
+  gint       row;
+  gboolean   run;
+  gboolean   isFrameMissing;
+
+  mgpp->range_from = ainfo_ptr->curr_frame_nr;
+  mgpp->range_to = ainfo_ptr->frame_nr_after_curr_frame_nr;
+  mtg = &morphTweenGui;
+  mtg->mgpp = mgpp;
+  mtg->morph_filesel = NULL;
+  isFrameMissing = FALSE;
+  p_check_workpoint_file_and_use_single_fade_if_missing(mgpp);
+
+
+  if(gap_debug)
+  {
+    printf("gap_morph_frame_tweens_dialog: mgpp->range_from%d  mgpp->range_to:%d  first:%d, curr:%d, last:%d after_curr:%d\n"
+      , (int)mgpp->range_from
+      , (int)mgpp->range_to
+      , (int)ainfo_ptr->first_frame_nr
+      , (int)ainfo_ptr->curr_frame_nr
+      , (int)ainfo_ptr->last_frame_nr
+      , (int)ainfo_ptr->frame_nr_after_curr_frame_nr
+      );
+  }
+
+  isFrameMissing = (ainfo_ptr->curr_frame_nr +1) != ainfo_ptr->frame_nr_after_curr_frame_nr;
+
+  gimp_ui_init (GAP_MORPH_TWEEN_PLUGIN_NAME, TRUE);
+
+  dialog = gimp_dialog_new (_("Create Tween Frames"), GAP_MORPH_TWEEN_PLUGIN_NAME,
+                            NULL, 0,
+                            gimp_standard_help_func, GAP_MORPH_TWEEN_HELP_ID,
+
+                            GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                            GTK_STOCK_OK,     GTK_RESPONSE_OK,
+
+                            NULL);
+
+
+  gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
+                                           GTK_RESPONSE_OK,
+                                           GTK_RESPONSE_CANCEL,
+                                           -1);
+
+  gimp_window_set_transient (GTK_WINDOW (dialog));
+
+  main_vbox = gtk_vbox_new (FALSE, 12);
+  gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
+  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), main_vbox);
+  gtk_widget_show (main_vbox);
+
+
+  /* Controls */
+  table = gtk_table_new (3, 3, FALSE);
+  gtk_table_set_col_spacings (GTK_TABLE (table), 6);
+  gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+  gtk_box_pack_start (GTK_BOX (main_vbox), table, FALSE, FALSE, 0);
+  gtk_widget_show (table);
+
+  row = 0;
+  /* morph workpoint entry */
+  label = gtk_label_new (_("Information:"));
+  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+  gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
+                    GTK_FILL, GTK_FILL, 4, 0);
+  gtk_widget_show (label);
+
+  if (isFrameMissing)
+  {
+    char *msg;
+    msg = g_strdup_printf(_("this operation creates %d mising frames between frame %d and %d")
+                         ,(int)(mgpp->range_to - mgpp->range_from) -1
+                         ,(int)mgpp->range_from
+                         ,(int)mgpp->range_to
+                         );
+    label = gtk_label_new (msg);
+    g_free(msg);
+    mgpp->overwrite_flag = FALSE;
+  }
+  else
+  {
+    label = gtk_label_new (_("WARNING this operation will overwrite all frames between the specified frame range"));
+    mgpp->overwrite_flag = TRUE;
+  }
+  gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
+  gtk_table_attach (GTK_TABLE (table), label, 1, 3, row, row + 1,
+                    GTK_FILL, GTK_FILL, 4, 0);
+  gtk_widget_show (label);
+
+  row++;
+
+  adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row,
+                              _("From:"), SCALE_WIDTH, 7,
+                              mgpp->range_from, ainfo_ptr->first_frame_nr, ainfo_ptr->last_frame_nr, 1.0, 10.0, 0,
+                              TRUE, 0, 0,
+                              NULL, NULL);
+  g_signal_connect (adj, "value-changed",
+                    G_CALLBACK (gimp_int_adjustment_update),
+                    &mgpp->range_from);
+
+  scale = g_object_get_data(G_OBJECT (adj), "scale");
+  spinbutton = g_object_get_data(G_OBJECT (adj), "spinbutton");
+  gtk_widget_set_sensitive(scale, FALSE);
+  gtk_widget_set_sensitive(spinbutton, FALSE);
+
+  row++;
+
+  adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row,
+                              _("To:"), SCALE_WIDTH, 7,
+                              mgpp->range_to, mgpp->range_from +1, ainfo_ptr->last_frame_nr, 1.0, 10.0, 0,
+                              TRUE, 0, 0,
+                              NULL, NULL);
+  g_signal_connect (adj, "value-changed",
+                    G_CALLBACK (gimp_int_adjustment_update),
+                    &mgpp->range_to);
+  if (isFrameMissing)
+  {
+    scale = g_object_get_data(G_OBJECT (adj), "scale");
+    spinbutton = g_object_get_data(G_OBJECT (adj), "spinbutton");
+    gtk_widget_set_sensitive(scale, FALSE);
+    gtk_widget_set_sensitive(spinbutton, FALSE);
+  }
+
+  row++;
+
+  p_create_morph_workpoint_entry(mgpp, mtg, row, table);
+  
+  /* Done */
+
+  gtk_widget_show (dialog);
+
+  run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
+
+  gtk_widget_destroy (dialog);
+
+  return run;
+} /* end gap_morph_frame_tweens_dialog */
+

Added: trunk/gap/gap_morph_tween_dialog.h
==============================================================================
--- (empty file)
+++ trunk/gap/gap_morph_tween_dialog.h	Wed Jan 14 19:59:24 2009
@@ -0,0 +1,44 @@
+/*  gap_morph_one_tween_dialog.h
+ *
+ *  This module handles the GAP morph tween dialog
+ */
+/* 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.1.0a; 2004/03/31  hof: created
+ */
+
+#ifndef _gap_morph_tween_dialog_H
+#define _gap_morph_tween_dialog_H
+
+#include "libgimp/gimp.h"
+#include "gap_libgimpgap.h"
+#include "gap_morph_main.h"
+#include "gap_libgimpgap.h"
+
+#define GAP_MORPH_ONE_TWEEN_PLUGIN_NAME    "plug_in_gap_morph_one_tween"
+#define GAP_MORPH_ONE_TWEEN_HELP_ID        "plug-in-gap-morph-one-tween"
+
+#define GAP_MORPH_TWEEN_PLUGIN_NAME    "plug_in_gap_morph_tween"
+#define GAP_MORPH_TWEEN_HELP_ID        "plug-in-gap-morph-tween"
+
+gboolean   gap_morph_one_tween_dialog(GapMorphGlobalParams *mgpp);
+gboolean   gap_morph_frame_tweens_dialog(GapAnimInfo *ainfo_ptr, GapMorphGlobalParams *mgpp);
+
+#endif

Modified: trunk/gap/gap_story_dialog.c
==============================================================================
--- trunk/gap/gap_story_dialog.c	(original)
+++ trunk/gap/gap_story_dialog.c	Wed Jan 14 19:59:24 2009
@@ -8680,7 +8680,7 @@
 static void
 p_tabw_master_prop_dialog(GapStbTabWidgets *tabw, gboolean new_flag)
 {
-  GapArrArg  argv[11];
+  GapArrArg  argv[12];
   static char *radio_args[4]  = { N_("automatic"), "libmpeg3", "libavformat", "quicktime4linux" };
   static char *radio_aspect_args[3]  = { N_("none"), "4:3", "16:9"};
   gint   l_ii;
@@ -8701,6 +8701,8 @@
   gchar    buf_preferred_decoder[60];
   gchar    buf_aspect_string[40];
   gchar   *label_txt;
+  gchar    l_master_insert_area_format[GAP_STORY_MAX_STORYFILENAME_LEN];
+
   gboolean l_rc;
 
   stb_dst = p_tabw_get_stb_ptr (tabw);
@@ -8719,7 +8721,7 @@
   gap_story_get_master_pixelsize(stb_dst, &l_master_width, &l_master_height);
 
   label_txt = NULL;
-  l_ii = 0; l_ii_width = l_ii;
+  l_ii = 0;
   if(new_flag)
   {
     gap_arr_arg_init(&argv[l_ii], GAP_ARR_WGT_FILESEL);
@@ -8928,6 +8930,25 @@
   argv[l_ii].flt_default = argv[l_ii].flt_ret;
 
   l_ii++;
+  l_master_insert_area_format[0] = '\0';
+  if (stb_dst->master_insert_area_format)
+  {
+    g_snprintf(&l_master_insert_area_format[0], sizeof(l_master_insert_area_format), "%s"
+            , stb_dst->master_insert_area_format
+            );
+  }
+  gap_arr_arg_init(&argv[l_ii], GAP_ARR_WGT_FILESEL);
+  argv[l_ii].label_txt = _("AreaFormat:");
+  argv[l_ii].entry_width = 250;       /* pixel */
+  argv[l_ii].help_txt  = _("Format string for area replacement in movie clips. (e.g automatic logo insert)"
+                           "this string shall contain \%s as placeholder for the basename of a videoclip and "
+                           "optional \%06d as placeholder for the framenumber.");
+  argv[l_ii].text_buf_len = sizeof(l_master_insert_area_format);
+  argv[l_ii].text_buf_ret = &l_master_insert_area_format[0];
+
+
+
+  l_ii++;
   gap_arr_arg_init(&argv[l_ii], GAP_ARR_WGT_DEFAULT_BUTTON);
   argv[l_ii].label_txt =  _("Reset");                /* should use GIMP_STOCK_RESET if possible */
   argv[l_ii].help_txt  = _("Reset parameters to inital values");
@@ -8988,6 +9009,7 @@
        {
          if(strcmp(stb_dst->preferred_decoder, buf_preferred_decoder) != 0)
          {
+           stb_dst->unsaved_changes = TRUE;
            g_free(stb_dst->preferred_decoder);
            stb_dst->preferred_decoder = g_strdup(buf_preferred_decoder);
 
@@ -9000,6 +9022,7 @@
        }
        else
        {
+           stb_dst->unsaved_changes = TRUE;
            stb_dst->preferred_decoder = g_strdup(buf_preferred_decoder);
            gap_story_vthumb_close_videofile(sgpp);
        }
@@ -9008,12 +9031,42 @@
      {
        if(stb_dst->preferred_decoder)
        {
+         stb_dst->unsaved_changes = TRUE;
          g_free(stb_dst->preferred_decoder);
        }
        stb_dst->preferred_decoder = NULL;
      }
 
-     /* check for changes of master properties */
+
+     if (l_master_insert_area_format[0] != '\0')
+     {
+       if (stb_dst->master_insert_area_format)
+       {
+         if (strcmp(stb_dst->master_insert_area_format, &l_master_insert_area_format[0]) != 0)
+         {
+           stb_dst->unsaved_changes = TRUE;
+         }
+         g_free(stb_dst->master_insert_area_format);
+       }
+       else
+       {
+           stb_dst->unsaved_changes = TRUE;
+       }
+       stb_dst->master_insert_area_format = g_strdup(&l_master_insert_area_format[0]);
+     }
+     else
+     {
+       if (stb_dst->master_insert_area_format)
+       {
+         stb_dst->unsaved_changes = TRUE;
+         g_free(stb_dst->master_insert_area_format);
+         stb_dst->master_insert_area_format = NULL;
+       }
+     }
+
+
+
+     /* check for further changes of master properties */
      if((stb_dst->master_width        != stb_dup->master_width)
      || (stb_dst->master_height       != stb_dup->master_height)
      || (stb_dst->master_framerate    != stb_dup->master_framerate)

Modified: trunk/gap/gap_story_file.c
==============================================================================
--- trunk/gap/gap_story_file.c	(original)
+++ trunk/gap/gap_story_file.c	Wed Jan 14 19:59:24 2009
@@ -303,22 +303,26 @@
     return;
   }
 
-  printf("master_type         : %d\n", (int)stb->master_type );
-  printf("master_width        : %d\n", (int)stb->master_width );
-  printf("master_height       : %d\n", (int)stb->master_height );
-  printf("master_framerate    : %f\n", (float)stb->master_framerate );
-  printf("master_aspect_ratio : %f (%d : %d)\n"
+  printf("master_type               : %d\n", (int)stb->master_type );
+  printf("master_width              : %d\n", (int)stb->master_width );
+  printf("master_height             : %d\n", (int)stb->master_height );
+  printf("master_framerate          : %f\n", (float)stb->master_framerate );
+  printf("master_aspect_ratio       : %f (%d : %d)\n"
             , (float)stb->master_aspect_ratio
             , (int)stb->master_aspect_width
             , (int)stb->master_aspect_height
             );
-  printf("master_1is_toplayer : %d\n", (int)stb->master_vtrack1_is_toplayer );
-  printf("layout_cols         : %d\n", (int)stb->layout_cols );
-  printf("layout_rows         : %d\n", (int)stb->layout_rows );
-  printf("layout_thumbsize    : %d\n", (int)stb->layout_thumbsize );
+  printf("master_1is_toplayer       : %d\n", (int)stb->master_vtrack1_is_toplayer );
+  if (stb->master_insert_area_format)
+  {
+    printf("master_insert_area_format :%s", stb->master_insert_area_format);
+  }
+  printf("layout_cols               : %d\n", (int)stb->layout_cols );
+  printf("layout_rows               : %d\n", (int)stb->layout_rows );
+  printf("layout_thumbsize          : %d\n", (int)stb->layout_thumbsize );
 
-  printf("stb_parttype        : %d\n", (int)stb->stb_parttype );
-  printf("stb_unique_id       : %d\n", (int)stb->stb_unique_id );
+  printf("stb_parttype              : %d\n", (int)stb->stb_parttype );
+  printf("stb_unique_id             : %d\n", (int)stb->stb_unique_id );
 
   GapStorySection *active_section;
   
@@ -618,6 +622,7 @@
     stb->master_aspect_ratio = 0.0;  /* 0.0 for none */
     stb->master_aspect_width = 0;
     stb->master_aspect_height = 0;
+    stb->master_insert_area_format = NULL;
 
     stb->layout_cols = -1;
     stb->layout_rows = -1;
@@ -1465,6 +1470,10 @@
     {
       g_free(stb->warnline);
     }
+    if(stb->master_insert_area_format)
+    {
+      g_free(stb->master_insert_area_format);
+    }
 
     /* Note: Dont try to g_free stb->currline
      * it points to memory that is controlled (and already free'd) by the parser
@@ -3146,6 +3155,15 @@
       if(*l_wordval[1]) { stb->preferred_decoder = g_strdup(l_wordval[1]); }
       goto cleanup;  /* master RECORD does not create frame range elements */
   }
+  /* Master informations: GAP_STBKEY_VID_MASTER_INSERT_AREA */
+  if (strcmp(l_record_key, GAP_STBKEY_VID_MASTER_INSERT_AREA) == 0)
+  {
+      char *l_format_ptr   = l_wordval[1];
+      if(*l_format_ptr) {  p_flip_dir_separators(l_format_ptr);;
+                           stb->master_insert_area_format = g_strdup(l_format_ptr);
+                        }
+      goto cleanup;  /* master RECORD does not create frame range elements */
+  }
 
 
   /* Master informations: GAP_STBKEY_AUD_MASTER_VOLUME */
@@ -4938,6 +4956,21 @@
     }
   }
 
+  if (stb->master_insert_area_format)
+  {
+    if(*stb->master_insert_area_format != '\0')
+    {
+      gap_stb_syntax_get_parname_tab(GAP_STBKEY_VID_MASTER_INSERT_AREA
+                                    ,&l_parnam_tab
+                                    );
+      fprintf(fp, "%s  %s:\"%s\"\n"
+           , GAP_STBKEY_VID_MASTER_INSERT_AREA
+           , l_parnam_tab.parname[1]
+           , stb->master_insert_area_format
+           );
+    }
+  }
+
 }  /* end p_story_save_header */
 
 
@@ -7082,6 +7115,10 @@
   {
     stb_dup->preferred_decoder = g_strdup(stb_ptr->preferred_decoder);
   }
+  if(stb_ptr->master_insert_area_format)
+  {
+    stb_dup->master_insert_area_format = g_strdup(stb_ptr->master_insert_area_format);
+  }
 
   stb_dup->layout_cols = stb_ptr->layout_cols;
   stb_dup->layout_rows = stb_ptr->layout_rows;
@@ -7765,10 +7802,26 @@
       stb->master_samplerate  = stb_sample->master_samplerate;
       stb->master_volume      = stb_sample->master_volume;
       stb->unsaved_changes = TRUE;
+      if(stb->preferred_decoder)
+      {
+        g_free(stb->preferred_decoder);
+        stb->preferred_decoder  = NULL;
+      }
       if(stb_sample->preferred_decoder)
       {
         stb->preferred_decoder  = g_strdup(stb_sample->preferred_decoder);
       }
+      
+      if(stb->master_insert_area_format)
+      {
+        g_free(stb->master_insert_area_format);
+        stb->master_insert_area_format  = NULL;
+      }
+      if(stb_sample->master_insert_area_format)
+      {
+        stb->master_insert_area_format = g_strdup(stb_sample->master_insert_area_format);
+      }
+      
     }
   }
 }  /* end gap_story_set_properties_like_sample_storyboard */
@@ -9263,3 +9316,20 @@
   }
   return (vref_list);
 }  /* end gap_story_get_video_file_ref_list */
+
+
+/* -------------------------------------
+ * gap_story_build_basename
+ * -------------------------------------
+ * return a duplicate of the basename part of the specified filename.
+ *        leading directory path and drive letter (for WinOS) is cut off
+ * the caller is responsible to g_free the returned string.
+ */
+char *
+gap_story_build_basename(const char *filename)
+{
+  char *basename;
+
+  basename = g_filename_display_basename(filename);
+  return(basename);
+}  /* end gap_story_build_basename */

Modified: trunk/gap/gap_story_file.h
==============================================================================
--- trunk/gap/gap_story_file.h	(original)
+++ trunk/gap/gap_story_file.h	Wed Jan 14 19:59:24 2009
@@ -276,7 +276,9 @@
 
      gboolean       unsaved_changes;
      GapStoryEditSettings *edit_settings;
-  }  GapStoryBoard;
+     
+     gchar         *master_insert_area_format;
+ }  GapStoryBoard;
 
  
   typedef struct GapStoryLocateRet {
@@ -472,5 +474,6 @@
                           , const char *preferred_decoder
                           , gint32          max_ref_framenr);
 GapStoryVideoFileRef * gap_story_get_video_file_ref_list(GapStoryBoard *stb);
+char *                 gap_story_build_basename(const char *filename);
 
 #endif

Modified: trunk/gap/gap_story_main.h
==============================================================================
--- trunk/gap/gap_story_main.h	(original)
+++ trunk/gap/gap_story_main.h	Wed Jan 14 19:59:24 2009
@@ -172,6 +172,7 @@
   GtkWidget  *dur_time_label;
   GtkWidget  *pingpong_toggle;
   GtkWidget  *comment_entry;
+  GtkWidget  *pw_fmac_filesel;
   GtkWidget  *fmac_entry;
   GtkObject  *pw_spinbutton_from_adj;
   GtkObject  *pw_spinbutton_to_adj;

Modified: trunk/gap/gap_story_properties.c
==============================================================================
--- trunk/gap/gap_story_properties.c	(original)
+++ trunk/gap/gap_story_properties.c	Wed Jan 14 19:59:24 2009
@@ -153,6 +153,9 @@
 static void     p_filesel_pw_ok_cb (GtkWidget *widget, GapStbPropWidget *pw);
 static void     p_filesel_pw_close_cb ( GtkWidget *widget, GapStbPropWidget *pw);
 static void     p_pw_filesel_button_cb ( GtkWidget *w, GapStbPropWidget *pw);
+static void     p_pw_fmac_filesel_pw_ok_cb (GtkWidget *widget, GapStbPropWidget *pw);
+static void     p_pw_fmac_filesel_pw_close_cb ( GtkWidget *widget, GapStbPropWidget *pw);
+static void     p_pw_fmac_filesel_button_cb ( GtkWidget *w, GapStbPropWidget *pw);
 static void     p_pw_comment_entry_update_cb(GtkWidget *widget, GapStbPropWidget *pw);
 static void     p_pw_fmac_entry_update_cb(GtkWidget *widget, GapStbPropWidget *pw);
 static void     p_pw_update_info_labels_and_cliptype_senstivity(GapStbPropWidget *pw);
@@ -939,12 +942,12 @@
         stb_elem = stb_elem_new;
 
         if(gap_debug)
-	{
-	  printf("AUTO SCENE NEW_ELEM linked to list: drop:%d, video_id:%d\n"
-	       ,(int)drop_th_data
-	       ,(int)video_id
-	       );
-	}
+        {
+          printf("AUTO SCENE NEW_ELEM linked to list: drop:%d, video_id:%d\n"
+               ,(int)drop_th_data
+               ,(int)video_id
+               );
+        }
 
         if((stb_elem->record_type == GAP_STBREC_VID_MOVIE)
         && (drop_th_data)
@@ -1128,7 +1131,7 @@
                     , l_th_bpp
                     , TRUE         /* allow_grab_src_data */
                     , stb_elem_refptr->flip_request
-		    , GAP_STB_FLIP_NONE  /* flip_status */
+                    , GAP_STB_FLIP_NONE  /* flip_status */
                     );
        if(!l_th_data_was_grabbed)
        {
@@ -1168,7 +1171,7 @@
      gap_pview_render_f_from_pixbuf (pv_ptr
                                     , pixbuf
                                     , stb_elem_refptr->flip_request
-		                    , GAP_STB_FLIP_NONE  /* flip_status */
+                                    , GAP_STB_FLIP_NONE  /* flip_status */
                                     );
      g_object_unref(pixbuf);
    }
@@ -1194,7 +1197,7 @@
         gap_pview_render_f_from_image (pv_ptr
                                     , l_image_id
                                     , stb_elem_refptr->flip_request
-		                    , GAP_STB_FLIP_NONE  /* flip_status */
+                                    , GAP_STB_FLIP_NONE  /* flip_status */
                                     );
 
         /* create thumbnail (to speed up acces next time) */
@@ -2359,6 +2362,106 @@
 
 /* ==================================================== END FILESEL stuff ======  */
 
+/* ==================================================== START FMAC FILESEL stuff ======  */
+/* --------------------------------
+ * p_pw_fmac_filesel_pw_ok_cb
+ * --------------------------------
+ */
+static void
+p_pw_fmac_filesel_pw_ok_cb (GtkWidget *widget
+                   ,GapStbPropWidget *pw)
+{
+  const gchar *fmacname;
+  gchar *dup_fmacname;
+
+  if(pw == NULL) return;
+  if(pw->pw_fmac_filesel == NULL) return;
+
+  dup_fmacname = NULL;
+  fmacname = gtk_file_selection_get_filename (GTK_FILE_SELECTION (pw->pw_fmac_filesel));
+  if(fmacname)
+  {
+    dup_fmacname = g_strdup(fmacname);
+  }
+
+  gtk_widget_destroy(GTK_WIDGET(pw->pw_fmac_filesel));
+
+  if(dup_fmacname)
+  {
+    gtk_entry_set_text(GTK_ENTRY(pw->fmac_entry), dup_fmacname);
+    g_free(dup_fmacname);
+  }
+
+  pw->pw_fmac_filesel = NULL;
+}  /* end p_pw_fmac_filesel_pw_ok_cb */
+
+
+/* -----------------------------
+ * p_pw_fmac_filesel_pw_close_cb
+ * -----------------------------
+ */
+static void
+p_pw_fmac_filesel_pw_close_cb ( GtkWidget *widget
+                      , GapStbPropWidget *pw)
+{
+  if(pw->pw_fmac_filesel == NULL) return;
+
+  gtk_widget_destroy(GTK_WIDGET(pw->pw_fmac_filesel));
+  pw->pw_fmac_filesel = NULL;   /* indicate that filesel is closed */
+
+}  /* end p_pw_fmac_filesel_pw_close_cb */
+
+
+
+/* -----------------------------
+ * p_pw_fmac_filesel_button_cb
+ * -----------------------------
+ */
+static void
+p_pw_fmac_filesel_button_cb ( GtkWidget *w
+                       , GapStbPropWidget *pw)
+{
+  GtkWidget *filesel = NULL;
+
+  if(pw->scene_detection_busy)
+  {
+     return;
+  }
+
+  if(pw->pw_fmac_filesel != NULL)
+  {
+     gtk_window_present(GTK_WINDOW(pw->pw_fmac_filesel));
+     return;   /* filesel is already open */
+  }
+  if(pw->stb_elem_refptr == NULL) { return; }
+
+  filesel = gtk_file_selection_new ( _("Set Filtermacro Filename"));
+  pw->pw_fmac_filesel = filesel;
+
+  gtk_window_set_position (GTK_WINDOW (filesel), GTK_WIN_POS_MOUSE);
+  g_signal_connect (GTK_FILE_SELECTION (filesel)->ok_button,
+                    "clicked", G_CALLBACK (p_pw_fmac_filesel_pw_ok_cb),
+                    pw);
+  g_signal_connect (GTK_FILE_SELECTION (filesel)->cancel_button,
+                    "clicked", G_CALLBACK (p_pw_fmac_filesel_pw_close_cb),
+                    pw);
+  g_signal_connect (filesel, "destroy",
+                    G_CALLBACK (p_pw_fmac_filesel_pw_close_cb),
+                    pw);
+
+
+  if(pw->stb_elem_refptr->filtermacro_file)
+  {
+    gtk_file_selection_set_filename (GTK_FILE_SELECTION (filesel),
+                                     pw->stb_elem_refptr->filtermacro_file);
+  }
+  gtk_widget_show (filesel);
+
+}  /* end p_pw_fmac_filesel_button_cb */
+
+
+/* ==================================================== END FMAC FILESEL stuff ======  */
+
 
 
 /* ----------------------------
@@ -3061,80 +3164,80 @@
   {
     case GAP_STB_TARGET_STORYBOARD_ELEM:
       {
-	GapStbFrameWidget **fw_drop_ptr;
+        GapStbFrameWidget **fw_drop_ptr;
 
-	fw_drop_ptr = (GapStbFrameWidget **)selection_data->data;
-	fw_drop = *fw_drop_ptr;
-	if(gap_debug)
-	{
+        fw_drop_ptr = (GapStbFrameWidget **)selection_data->data;
+        fw_drop = *fw_drop_ptr;
+        if(gap_debug)
+        {
           printf("on_clip_elements_dropped_as_mask_ref FW_DROP:%d\n", (int)fw_drop);
         }
-	if (fw_drop == NULL)
-	{
+        if (fw_drop == NULL)
+        {
           return;
-	}
-	tabw_src = (GapStbTabWidgets *)fw_drop->tabw;
-	if ((tabw_src == NULL)
-	|| ((tabw_src != sgpp->cll_widgets) && (tabw_src != sgpp->stb_widgets)))
-	{
+        }
+        tabw_src = (GapStbTabWidgets *)fw_drop->tabw;
+        if ((tabw_src == NULL)
+        || ((tabw_src != sgpp->cll_widgets) && (tabw_src != sgpp->stb_widgets)))
+        {
           /* if tabw of the droped frame widget
            * is not equal to one of stb_widgets or cll_widgets
            * assume that the sender was another application
            * which is not supported for drop type GAP_STB_TARGET_STORYBOARD_ELEM.
            */
           return;
-	}
+        }
 
-	if(fw_drop->stb_elem_refptr)
-	{
-	  gchar *mask_name_new;
-	  
-	  GapStoryElem *known_maskdef_elem;
-	  
-	  
-	  p_pw_push_undo_and_set_unsaved_changes(pw);
-	  
-	  mask_name_new = NULL;
-	  known_maskdef_elem = gap_story_find_maskdef_equal_to_ref_elem(pw->stb_refptr
-	                          , fw_drop->stb_elem_refptr);
+        if(fw_drop->stb_elem_refptr)
+        {
+          gchar *mask_name_new;
+          
+          GapStoryElem *known_maskdef_elem;
+          
+          
+          p_pw_push_undo_and_set_unsaved_changes(pw);
+          
+          mask_name_new = NULL;
+          known_maskdef_elem = gap_story_find_maskdef_equal_to_ref_elem(pw->stb_refptr
+                                  , fw_drop->stb_elem_refptr);
           if(known_maskdef_elem)
           {
             mask_name_new = g_strdup(known_maskdef_elem->mask_name);
           }
           else
           {
-	    GapStoryElem *stb_elem_dup;
+            GapStoryElem *stb_elem_dup;
             
-	    mask_name_new = gap_story_generate_unique_maskname(pw->stb_refptr);
+            mask_name_new = gap_story_generate_unique_maskname(pw->stb_refptr);
             /* implicite create a new mask definition from the dropped
              * clip and change properties of current pw to refere
              * to the newly created mask definition
              */
-	    stb_elem_dup = gap_story_elem_duplicate(fw_drop->stb_elem_refptr);
+            stb_elem_dup = gap_story_elem_duplicate(fw_drop->stb_elem_refptr);
             if(stb_elem_dup->mask_name)
             {
               g_free(stb_elem_dup->mask_name);
             }
             stb_elem_dup->mask_name = g_strdup(mask_name_new);
-	    stb_elem_dup->track = GAP_STB_MASK_TRACK_NUMBER;
-	    gap_story_list_append_elem(pw->stb_refptr, stb_elem_dup);
+            stb_elem_dup->track = GAP_STB_MASK_TRACK_NUMBER;
+            gap_story_list_append_elem(pw->stb_refptr, stb_elem_dup);
             pw->go_recreate_request = TRUE;
           }
-	  
-	  /* set mask reference */
-	  if(mask_name_new)
-	  {
-	    if(pw->stb_elem_refptr->mask_name)
-	    {
-	      g_free(pw->stb_elem_refptr->mask_name);
-	    }
-	    pw->stb_elem_refptr->mask_name = g_strdup(mask_name_new);
-	    gtk_entry_set_text(GTK_ENTRY(pw->pw_mask_name_entry), mask_name_new);
-	    g_free(mask_name_new);
+          
+          /* set mask reference */
+          if(mask_name_new)
+          {
+            if(pw->stb_elem_refptr->mask_name)
+            {
+              g_free(pw->stb_elem_refptr->mask_name);
+            }
+            pw->stb_elem_refptr->mask_name = g_strdup(mask_name_new);
+            gtk_entry_set_text(GTK_ENTRY(pw->pw_mask_name_entry), mask_name_new);
+            g_free(mask_name_new);
             p_pw_render_layermask(pw);
-	  }
-	  p_pw_update_properties(pw);
-	}
+          }
+          p_pw_update_properties(pw);
+        }
 
       }
       break;
@@ -3520,6 +3623,7 @@
   pw->dur_time_label = NULL;
   pw->pingpong_toggle = NULL;
   pw->comment_entry = NULL;
+  pw->pw_fmac_filesel = NULL;
   pw->fmac_entry = NULL;
   pw->pw_spinbutton_from_adj = NULL;
   pw->pw_spinbutton_to_adj = NULL;
@@ -4424,28 +4528,47 @@
 
 
 
-  /* the filtermacro entry */
-  entry = gtk_entry_new ();
-  gtk_widget_set_size_request(entry, PW_ENTRY_WIDTH, -1);
-  if(pw->stb_elem_refptr)
+  /* filtermacro entry and filesel invoker button */
   {
-    if(pw->stb_elem_refptr->filtermacro_file)
+    GtkWidget *hbox_fmac;
+  
+    hbox_fmac = gtk_hbox_new (FALSE, 1);
+    gtk_widget_show (hbox_fmac);
+    gtk_table_attach_defaults (GTK_TABLE(table), hbox_fmac, 1, 2, row, row+1);
+
+    /* the filtermacro entry */
+    entry = gtk_entry_new ();
+    gtk_widget_set_size_request(entry, PW_ENTRY_WIDTH, -1);
+    if(pw->stb_elem_refptr)
     {
-      gtk_entry_set_text(GTK_ENTRY(entry), pw->stb_elem_refptr->filtermacro_file);
+      if(pw->stb_elem_refptr->filtermacro_file)
+      {
+        gtk_entry_set_text(GTK_ENTRY(entry), pw->stb_elem_refptr->filtermacro_file);
+      }
     }
-  }
 
-  gtk_table_attach_defaults (GTK_TABLE(table), entry, 1, 2, row, row+1);
-  g_signal_connect(G_OBJECT(entry), "changed",
+    gtk_box_pack_start (GTK_BOX (hbox_fmac), entry, TRUE, TRUE, 1);
+
+    g_signal_connect(G_OBJECT(entry), "changed",
                      G_CALLBACK(p_pw_fmac_entry_update_cb),
                      pw);
-  gtk_widget_show (entry);
-  gimp_help_set_help_data (entry, _("filter macro to be performed when frames "
+    gtk_widget_show (entry);
+    gimp_help_set_help_data (entry, _("filter macro to be performed when frames "
                                     "of this clips are rendered. "
                                     "A 2nd macrofile is implicite referenced by naming convetion "
                                     "via the keyword .VARYING (as suffix or before the extension)")
                                            , NULL);
-  pw->fmac_entry = entry;
+    pw->fmac_entry = entry;
+
+
+    /* the filesel invoker button */
+    button = gtk_button_new_with_label ("...");
+    gtk_box_pack_start (GTK_BOX (hbox_fmac), button, FALSE, FALSE, 1);
+    g_signal_connect(G_OBJECT(button), "clicked",
+                     G_CALLBACK(p_pw_fmac_filesel_button_cb),
+                     pw);
+    gtk_widget_show (button);
+  }
 
 
   /* fmac_total_steps threshold spinbutton */

Modified: trunk/gap/gap_story_render_lossless.c
==============================================================================
--- trunk/gap/gap_story_render_lossless.c	(original)
+++ trunk/gap/gap_story_render_lossless.c	Wed Jan 14 19:59:24 2009
@@ -603,7 +603,7 @@
  {
    FILE *fp;
    char *fname;
-   char *l_env;
+   const char *l_env;
    gint32 l_dump_chunk_frames;
 
    l_dump_chunk_frames = 0;
@@ -796,7 +796,7 @@
           gint32 check_flags_result;
           gint32 check_flags_mask;
           gboolean is_mpeg_integrity_check_done;
-          const char *vcodec_name_chunk;
+          char *vcodec_name_chunk;
         
           vcodec_name_chunk = GVA_get_codec_name(l_frn_elem->gvahand
                                                  ,GVA_VIDEO_CODEC

Modified: trunk/gap/gap_story_render_processor.c
==============================================================================
--- trunk/gap/gap_story_render_processor.c	(original)
+++ trunk/gap/gap_story_render_processor.c	Wed Jan 14 19:59:24 2009
@@ -248,7 +248,8 @@
 
 static void       p_clear_vattr_array(GapStoryRenderVTrackArray *vtarr);
 
-
+static gboolean   p_fmt_string_has_framenumber_format(const char *fmt_string);
+static gboolean   p_fmt_string_has_videobasename_format(const char *fmt_string);
 static void       p_storyboard_analyze(GapStoryBoard *stb
                       , gint32 *mainsection_frame_count
                       , GapStoryRenderVidHandle *vidhand
@@ -367,6 +368,17 @@
                       , const char *section_name
                       );
 static void       p_stb_render_result_monitoring(GapStbFetchData *gfd, gint32 master_frame_nr);
+
+
+static void       p_paste_logo_pattern(gint32 drawable_id
+                      , gint32 logo_pattern_id
+                      , gint32 offsetX
+                      , gint32 offsetY
+                      );
+
+static void       p_do_insert_area_processing(GapStbFetchData *gfd
+                      , GapStoryRenderVidHandle *vidhand);
+
   
 static gint32     p_story_render_fetch_composite_image_private(GapStoryRenderVidHandle *vidhand
                     , gint32 master_frame_nr  /* starts at 1 */
@@ -2127,6 +2139,86 @@
   }
 }  /* end p_clear_vattr_array */
 
+/* -------------------------------------
+ * p_fmt_string_has_framenumber_format
+ * -------------------------------------
+ * return true if the specified format string contains "%06d" (or "%02d" up to "%09d")
+ *        false if the format has no such numeric part for the framenumber.
+ *
+ */
+static gboolean
+p_fmt_string_has_framenumber_format(const char *fmt_string)
+{
+  const char *ptr;
+  gboolean l_found;
+  
+  l_found = FALSE;
+  ptr = fmt_string;
+  while(ptr)
+  {
+    if(ptr[0] == '\0')
+    {
+      break;
+    }
+    
+    if (ptr[0] == '%')
+    {
+      if(ptr[1] != '\0')
+      {
+        if(ptr[2] != '\0')
+        {
+          if(ptr[3] != '\0')
+          {
+            if((ptr[1] == '0') && (ptr[3] == 'd'))
+            {
+              if((ptr[2] >= '2') && (ptr[2] <= '9'))
+              {
+                l_found = TRUE;
+                break;
+              }
+            }
+          }
+        }
+      }
+    }
+    ptr++;
+  }
+  return (l_found);
+  
+}  /* end p_fmt_string_has_framenumber_format */
+
+/* -------------------------------------
+ * p_fmt_string_has_videobasename_format
+ * -------------------------------------
+ * return true if the specified format string contains "%s"
+ *        false if the format has no such videobasename placeholder part.
+ *
+ */
+static gboolean
+p_fmt_string_has_videobasename_format(const char *fmt_string)
+{
+  const char *ptr;
+  gboolean l_found;
+  
+  l_found = FALSE;
+  ptr = fmt_string;
+  while(ptr)
+  {
+    if(ptr[0] == '\0')
+    {
+      break;
+    }
+    
+    if ((ptr[0] == '%') && (ptr[1] == 's'))
+    {
+      l_found = TRUE;
+      break;
+    }
+    ptr++;
+  }
+  return (l_found);
+  
+}  /* end p_fmt_string_has_videobasename_format */
 
 /* ----------------------------------------------------
  * p_storyboard_analyze
@@ -2185,6 +2277,16 @@
     vidhand->preferred_decoder = g_strdup(stb->preferred_decoder);
   }
 
+  vidhand->master_insert_area_format = NULL;
+  if(stb->master_insert_area_format)
+  {
+    vidhand->master_insert_area_format = g_strdup(stb->master_insert_area_format);
+    vidhand->master_insert_area_format_has_framenumber =
+      p_fmt_string_has_framenumber_format(vidhand->master_insert_area_format);
+    vidhand->master_insert_area_format_has_videobasename =
+      p_fmt_string_has_videobasename_format(vidhand->master_insert_area_format);
+  }
+
   if(stb->master_volume >= 0)
   {
     vidhand->master_volume = stb->master_volume;
@@ -3467,6 +3569,10 @@
 
   vidhand->frn_list = NULL;
   vidhand->preferred_decoder = NULL;
+  vidhand->master_insert_area_format = NULL;
+  vidhand->master_insert_area_format_has_videobasename = FALSE;
+  vidhand->master_insert_area_format_has_framenumber = FALSE;
+  
   vidhand->do_gimp_progress = do_gimp_progress;
   *vidhand->progress = 0.0;
   vidhand->sterr = p_new_stb_error();
@@ -4004,6 +4110,19 @@
                               , (int)total_steps
                               );
        }
+       
+       if(! gimp_drawable_has_alpha (layer_id))
+       {
+         /* some filtermacros do not work with layer that do not have an alpha channel
+          * and cause gimp to fail on attempt to call gimp_pixel_rgn_init
+          * with both dirty and shadow flag set to TRUE
+          * in this situation GIMP displays the error message
+          *    "expected tile ack and received: 5"
+          *    and causes the called plug-in to exit immediate without success
+          * Therfore always add an alpha channel before calling a filtermacro.
+          */
+          gimp_layer_add_alpha(layer_id);
+       }
 
        if((filtermacro_file_to == NULL)
        || (total_steps <= 1))
@@ -4109,8 +4228,6 @@
     gap_story_render_debug_print_frame_elem(frn_elem, -77);
   }
 
-  layer_id = gap_layer_flip(layer_id, flip_request);
-
   /* execute input track specific  filtermacro (optional if supplied)
    * local_stepcount  (usually delivered by procedure p_fetch_framename)
    *  is used to define fmac_current_step
@@ -4124,6 +4241,16 @@
                       , frn_elem->fmac_total_steps
                     );
 
+  if(gap_debug)
+  {
+    printf("p_transform_and_add_layer: FILTERMACRO DONE at layer_id: %d, tmp_image_id:%d\n"
+      , (int)layer_id
+      ,(int)tmp_image_id );
+  }
+
+  layer_id = gap_layer_flip(layer_id, flip_request);
+
+
   /* expand layer to tmp image size (before applying any scaling) */
   gimp_layer_resize_to_image_size(layer_id);
 
@@ -4455,7 +4582,7 @@
      gimp_pixel_rgn_get_rect (&pixel_rgn, pixelrow_data
                               , 0
                               , l_src_row
-			      , drawable->width
+                              , drawable->width
                               , 1);
      for(l_idx=0;l_idx < l_rowstride; l_idx += drawable->bpp)
      {
@@ -5146,6 +5273,159 @@
 }  /* end p_stb_render_result_monitoring */
 
 
+/* ------------------------
+ * p_paste_logo_pattern
+ * ------------------------  
+ * replace logo area with the specified logo pattern
+ */
+static void
+p_paste_logo_pattern(gint32 drawable_id
+  , gint32 logo_pattern_id
+  , gint32 offsetX
+  , gint32 offsetY
+  )
+{
+  gint32        l_fsel_layer_id;
+  gint          l_src_offset_x;
+  gint          l_src_offset_y;
+  gint32        image_id;
+
+  image_id = gimp_drawable_get_image(drawable_id);
+  gimp_selection_all(gimp_drawable_get_image(logo_pattern_id));
+
+  /* findout the offsets of the replacement_pattern layer within the source Image */
+  gimp_drawable_offsets(logo_pattern_id, &l_src_offset_x, &l_src_offset_y );
+
+  gimp_edit_copy(logo_pattern_id);
+  l_fsel_layer_id = gimp_edit_paste(drawable_id, TRUE);  /* FALSE paste clear selection */
+  gimp_selection_none(gimp_drawable_get_image(logo_pattern_id));
+
+  if(gap_debug)
+  {
+    gint          l_fsel_offset_x;
+    gint          l_fsel_offset_y;
+
+    gimp_drawable_offsets(l_fsel_layer_id, &l_fsel_offset_x, &l_fsel_offset_y );
+
+    printf("p_paste_logo_pattern: l_src_offsets: (%d %d) fsel:(%d %d) final offsets: (%d %d) rep_id:%d\n"
+      ,(int)l_src_offset_x
+      ,(int)l_src_offset_y
+      ,(int)l_fsel_offset_x
+      ,(int)l_fsel_offset_y
+      ,(int)(offsetX + l_src_offset_x)
+      ,(int)(offsetY + l_src_offset_y)
+      ,(int)logo_pattern_id
+      );
+  }
+
+  gimp_layer_set_offsets(l_fsel_layer_id
+                        , offsetX + l_src_offset_x
+                        , offsetY + l_src_offset_y);
+  
+  gimp_floating_sel_anchor(l_fsel_layer_id);
+
+} /* end p_copy_and_paste_replacement_pattern */
+
+
+
+/* -------------------------------------
+ * p_do_insert_area_processing
+ * -------------------------------------
+ */
+static void
+p_do_insert_area_processing(GapStbFetchData *gfd
+  , GapStoryRenderVidHandle *vidhand)
+{
+  char *logo_imagename;
+  char *videofilename_without_path;
+  
+  
+  videofilename_without_path = gap_story_build_basename(gfd->framename);
+  
+  if (vidhand->master_insert_area_format_has_framenumber)
+  {
+    if (vidhand->master_insert_area_format_has_videobasename)
+    {
+      logo_imagename =
+         g_strdup_printf(vidhand->master_insert_area_format
+                       , videofilename_without_path
+                       , gfd->localframe_index   /* videoFrameNr */
+                       );
+    }
+    else
+    {
+      logo_imagename =
+         g_strdup_printf(vidhand->master_insert_area_format
+                       , gfd->localframe_index   /* videoFrameNr */
+                       );
+    }
+  }
+  else
+  {
+    if (vidhand->master_insert_area_format_has_videobasename)
+    {
+      logo_imagename =
+         g_strdup_printf(vidhand->master_insert_area_format
+                       , videofilename_without_path
+                       );
+    }
+    else
+    {
+      logo_imagename = g_strdup(vidhand->master_insert_area_format);
+    }
+  }
+
+  if(gap_debug)
+  {
+    printf("p_do_insert_area_processing: format:%s\n video:%s\n logo_imagename:%s\n"
+        , vidhand->master_insert_area_format
+        , videofilename_without_path
+        , logo_imagename
+        );
+  }
+
+
+  if(g_file_test(logo_imagename, G_FILE_TEST_EXISTS))
+  {
+    gint32 logo_image_id;
+    gint32 logo_layer_id;
+    
+    if (vidhand->master_insert_area_format_has_framenumber)
+    {
+      logo_image_id = gap_lib_load_image(logo_imagename);
+    }
+    else
+    {
+      /* use framefetcher cache in case all frames shall get the same logo */
+      logo_image_id = gap_frame_fetch_orig_image(vidhand->ffetch_user_id
+                            , logo_imagename
+                            , TRUE /*  enable caching */
+                           );
+    }
+    
+    if(logo_image_id < 0)
+    {
+      printf("p_do_insert_area_processing: ERROR could not load logo_imagename:%s\n", logo_imagename);
+      return;
+    }
+    
+    
+    gimp_selection_none(logo_image_id);
+    logo_layer_id = p_prepare_RGB_image(logo_image_id);
+
+    p_paste_logo_pattern(gfd->layer_id
+                         , logo_layer_id
+                         , 0, 0  /* offest_X, offset_Y */
+                         );
+    if (vidhand->master_insert_area_format_has_framenumber)
+    {
+      /* do not keep individual per frame logo images cached
+       */
+      gap_image_delete_immediate(logo_image_id);
+    }
+  }
+
+}  /* end p_do_insert_area_processing */
 
 /* --------------------------------------------
  * p_story_render_fetch_composite_image_private
@@ -5291,13 +5571,19 @@
                }
              }
            }
-           g_free(gfd->framename);
            if(gfd->tmp_image_id < 0)
            {
+              g_free(gfd->framename);
               return -1;
            }
            gfd->layer_id = p_prepare_RGB_image(gfd->tmp_image_id);
+           if((gfd->frn_type == GAP_FRN_MOVIE) && (vidhand->master_insert_area_format))
+           {
+             p_do_insert_area_processing(gfd, vidhand);
+           }
+           
            p_conditional_delace_drawable(gfd, gfd->layer_id);
+           g_free(gfd->framename);
          }
        }
 

Modified: trunk/gap/gap_story_render_types.h
==============================================================================
--- trunk/gap/gap_story_render_types.h	(original)
+++ trunk/gap/gap_story_render_types.h	Wed Jan 14 19:59:24 2009
@@ -291,6 +291,9 @@
   GapStoryRenderAudioRangeElem    *aud_list;
   GapStoryRenderErrors            *sterr;
   char                         *preferred_decoder;
+  char                         *master_insert_area_format;    /* Format for logo replacement */
+  gboolean                      master_insert_area_format_has_videobasename;
+  gboolean                      master_insert_area_format_has_framenumber;
 
   /* master video settings found in the storyboard file */
   gdouble  master_framerate;

Modified: trunk/gap/gap_story_syntax.c
==============================================================================
--- trunk/gap/gap_story_syntax.c	(original)
+++ trunk/gap/gap_story_syntax.c	Wed Jan 14 19:59:24 2009
@@ -280,6 +280,10 @@
                ,"decoder"
                ,NULL
                );
+  p_add_keyword(GAP_STBKEY_VID_MASTER_INSERT_AREA
+               ,"format"
+               ,NULL
+               );
   p_add_keyword(GAP_STBKEY_MAIN_SECTION
                ,NULL
                );

Modified: trunk/gap/gap_story_syntax.h
==============================================================================
--- trunk/gap/gap_story_syntax.h	(original)
+++ trunk/gap/gap_story_syntax.h	Wed Jan 14 19:59:24 2009
@@ -43,6 +43,7 @@
 #define GAP_STBKEY_VID_MASTER_FRAME_ASPECT  "VID_MASTER_FRAME_ASPECT"
 #define GAP_STBKEY_VID_MASTER_LAYERSTACK    "VID_MASTER_LAYERSTACK"
 #define GAP_STBKEY_VID_PREFERRED_DECODER    "VID_PREFERRED_DECODER"
+#define GAP_STBKEY_VID_MASTER_INSERT_AREA   "VID_MASTER_INSERT_AREA"
 
 #define GAP_STBKEY_MAIN_SECTION             "MAIN_SECTION"
 #define GAP_STBKEY_SUB_SECTION              "SUB_SECTION"

Added: trunk/gap/gap_wr_resynth.c
==============================================================================
--- (empty file)
+++ trunk/gap/gap_wr_resynth.c	Wed Jan 14 19:59:24 2009
@@ -0,0 +1,773 @@
+/* gap_wr_resynth.c
+ *   provides automated animated apply support for the 3rd party resynthesizer plug-in.
+ *   Useful to remove unwanted logos when processing video frames.
+ * PRECONDITIONS:
+ *   Requires resynthesizer plug-in.
+ *  (resynthesizer-0.16.tar.gz is available in the gimp plug-in registry)
+ *  NOTE this wrapper also supports an extended variant plug-in-resynthesizer-s
+ *       that has an additional seed parameter.
+ */
+
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * Copyright (C) 2008 Wolfgang Hofer
+ * hof gimp org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <gtk/gtk.h>
+#include <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+
+#include "gap_lastvaldesc.h"
+#include "gap_lastvaldesc.h"
+#include "gap_libgimpgap.h"
+
+#include "gap-intl.h"
+
+/***** Macro definitions  *****/
+#define PLUG_IN_PROC        "plug_in_wr_resynth"
+#define PLUG_IN_VERSION     "0.16"
+#define PLUG_IN_AUTHOR      "Wolfgang Hofer (hof gimp org)"
+#define PLUG_IN_COPYRIGHT   "Wolfgang Hofer"
+
+#define PLUG_IN_BINARY  "gap_wr_resynth"
+
+
+#define PLUG_IN_RESYNTHESIZER            "plug-in-resynthesizer"
+#define PLUG_IN_RESYNTHESIZER_WITH_SEED  "plug-in-resynthesizer-s"  /* unpublished prvate version */
+
+
+
+/***** Magic numbers *****/
+
+#define SCALE_WIDTH  200
+#define SPIN_BUTTON_WIDTH 60
+
+/***** Types *****/
+
+
+typedef struct {
+  gint32  corpus_border_radius;
+  gint32  alt_selection;
+  gint32  seed;
+} TransValues;
+
+static TransValues glob_vals =
+{
+   20           /* corpus_border_radius */
+,  -1           /* alt_selection (drawable id or -1 for using original selection) */
+, 4711          /* seed for random number generator */
+};
+
+
+
+
+/***** Prototypes *****/
+
+static void query (void);
+static void run   (const gchar      *name,
+                   gint              nparams,
+                   const GimpParam  *param,
+                   gint             *nreturn_vals,
+                   GimpParam       **return_vals);
+
+static gint p_selectionConstraintFunc (gint32   image_id,
+               gint32   drawable_id,
+               gpointer data);
+static gboolean p_dialog(TransValues *val_ptr, gint32 drawable_id);
+static gint32 p_process_layer(gint32 image_id, gint32 drawable_id, TransValues *val_ptr);
+
+/***** Variables *****/
+
+const GimpPlugInInfo PLUG_IN_INFO =
+{
+  NULL,   /* init_proc  */
+  NULL,   /* quit_proc  */
+  query,  /* query_proc */
+  run     /* run_proc   */
+};
+
+static GimpParamDef in_args[] = {
+    { GIMP_PDB_INT32,    "run-mode",             "Interactive, non-interactive" },
+    { GIMP_PDB_IMAGE,    "image",                "Input image"                  },
+    { GIMP_PDB_DRAWABLE, "drawable",             "The drawable (typically a layer)"               },
+    { GIMP_PDB_INT32,    "corpus_border_radius", "Radius to take texture from"     },
+    { GIMP_PDB_DRAWABLE, "alt_selection",        "id of a drawable to replace the selection (use -1 to operate with selection of the input image)"     },
+    { GIMP_PDB_INT32,    "seed",                 "seed for random numbers (use -1 to init with current time)"     }
+  };
+
+
+static gint global_number_in_args = G_N_ELEMENTS (in_args);
+static gint global_number_out_args = 0;
+
+/* Global Variables */
+int gap_debug = 0;  /* 1 == print debug infos , 0 dont print debug infos */
+
+
+/***** Functions *****/
+
+MAIN()
+
+/* ------------------
+ * query
+ * ------------------
+ */
+static void
+query (void)
+{
+
+  static GimpLastvalDef lastvals[] =
+  {
+    GIMP_LASTVALDEF_GINT32          (GIMP_ITER_TRUE,  glob_vals.corpus_border_radius,  "corpus_border_radius"),
+    GIMP_LASTVALDEF_DRAWABLE        (GIMP_ITER_TRUE,  glob_vals.alt_selection,         "alt_selection"),
+    GIMP_LASTVALDEF_GINT32          (GIMP_ITER_TRUE,  glob_vals.seed,                  "seed")
+  };
+
+  /* registration for last values buffer structure (useful for animated filter apply) */
+  gimp_lastval_desc_register(PLUG_IN_PROC,
+                             &glob_vals,
+                             sizeof(glob_vals),
+                             G_N_ELEMENTS (lastvals),
+                             lastvals);
+
+
+  gimp_install_procedure (PLUG_IN_PROC,
+                          N_("Smart selection eraser."),
+                          "Remove an object from an image by extending surrounding texture to cover it. "
+                          "The object can be represented by the current selection  "
+                          "or by an alternative selction (provided as parameter alt_selection) "
+                          "If the image, that is refered by the alt_selction drawable_id has a selction "
+                          "then the refred selection is used to identify the object. "
+                          "otherwise a grayscale copy of the alt_selection drawable_id will be used "
+                          "to identify the object that shall be replaced. "
+                          "alt_selection value -1 indicates that the selection of the input image shall be used. "
+                          "Requires resynthesizer plug-in. (available in the gimp plug-in registry) "
+                          "The smart selection eraser wrapper provides ability to run in GIMP_GAP filtermacros "
+                          "when processing video frames (typically for removing unwanted logos from video frames)."
+                          "(using the same seed value for all frames is recommanded) ",
+                          "Wolfgang Hofer",
+                          "Wolfgang Hofer",
+                          PLUG_IN_VERSION,
+                          N_("Smart selection eraser..."),
+                          "RGB*, GRAY*",
+                          GIMP_PLUGIN,
+                          global_number_in_args, global_number_out_args,
+                          in_args, NULL);
+
+  {
+    /* Menu names */
+    const char *menupath_image_video_layer = N_("<Image>/Video/Layer/Enhance/");
+
+    gimp_plugin_menu_register (PLUG_IN_PROC, menupath_image_video_layer);
+  }
+
+}  /* end query */
+
+
+static void
+run (const gchar *name,          /* name of plugin */
+     gint nparams,               /* number of in-paramters */
+     const GimpParam * param,    /* in-parameters */
+     gint *nreturn_vals,         /* number of out-parameters */
+     GimpParam ** return_vals)   /* out-parameters */
+{
+  const gchar *l_env;
+  gint32       image_id = -1;
+  gint32       drawable_id = -1;
+  gint32       trans_drawable_id = -1;
+
+  /* Get the runmode from the in-parameters */
+  GimpRunMode run_mode = param[0].data.d_int32;
+
+  /* status variable, use it to check for errors in invocation usualy only
+     during non-interactive calling */
+  GimpPDBStatusType status = GIMP_PDB_SUCCESS;
+
+  /* always return at least the status to the caller. */
+  static GimpParam values[2];
+
+  INIT_I18N();
+
+  l_env = g_getenv("GAP_DEBUG");
+  if(l_env != NULL)
+  {
+    if((*l_env != 'n') && (*l_env != 'N')) gap_debug = 1;
+  }
+
+  if(gap_debug) printf("\n\nDEBUG: run %s\n", name);
+
+  /* initialize the return of the status */
+  values[0].type = GIMP_PDB_STATUS;
+  values[0].data.d_status = status;
+  values[1].type = GIMP_PDB_DRAWABLE;
+  values[1].data.d_drawable = -1;
+  *nreturn_vals = 1;
+  *return_vals = values;
+
+
+  /* get image and drawable */
+  image_id = param[1].data.d_int32;
+  drawable_id = param[2].data.d_int32;
+
+  if (strcmp (name, PLUG_IN_PROC) == 0)
+  {
+    if(gimp_drawable_is_layer(drawable_id))
+    {
+      gboolean run_flag;
+
+      /* Initial values */
+      glob_vals.corpus_border_radius = 20;
+      glob_vals.alt_selection = -1;
+      run_flag = TRUE;
+
+      /* Possibly retrieve data from a previous run */
+      gimp_get_data (name, &glob_vals);
+
+      switch (run_mode)
+       {
+        case GIMP_RUN_INTERACTIVE:
+
+          /* Get information from the dialog */
+          run_flag = p_dialog(&glob_vals, drawable_id);
+          break;
+
+        case GIMP_RUN_NONINTERACTIVE:
+          /* check to see if invoked with the correct number of parameters */
+          if (nparams >= global_number_in_args)
+          {
+             glob_vals.corpus_border_radius = param[3].data.d_int32;
+             glob_vals.alt_selection = param[4].data.d_int32;
+             glob_vals.seed = param[5].data.d_int32;
+          }
+          else
+          {
+            status = GIMP_PDB_CALLING_ERROR;
+          }
+          break;
+
+        case GIMP_RUN_WITH_LAST_VALS:
+          break;
+
+        default:
+          break;
+      }
+
+
+
+      /* here the action starts, we transform the drawable */
+      if(run_flag)
+      {
+        trans_drawable_id = p_process_layer(image_id
+                                             , drawable_id
+                                             , &glob_vals
+                                             );
+        if (trans_drawable_id < 0)
+        {
+           status = GIMP_PDB_CALLING_ERROR;
+        }
+        else
+        {
+           values[1].data.d_drawable = drawable_id;
+
+           /* Store variable states for next run
+            * (the parameters for the transform wrapper plugins are stored
+            *  even if they contain just a dummy
+            *  this is done to fullfill the GIMP-GAP LAST_VALUES conventions
+            *  for filtermacro and animated calls)
+            */
+           if (run_mode == GIMP_RUN_INTERACTIVE)
+           {
+             gimp_set_data (name, &glob_vals, sizeof (TransValues));
+           }
+        }
+      }
+    }
+    else
+    {
+       status = GIMP_PDB_CALLING_ERROR;
+       if (run_mode == GIMP_RUN_INTERACTIVE)
+       {
+         g_message(_("The plug-in %s\noperates only on layers\n"
+                     "(but was called on mask or channel)")
+                  , name
+                  );
+       }
+    }
+
+  }
+  else
+  {
+    status = GIMP_PDB_CALLING_ERROR;
+  }
+
+
+  if (status == GIMP_PDB_SUCCESS)
+  {
+
+    /* If run mode is interactive, flush displays, else (script) don't
+     * do it, as the screen updates would make the scripts slow
+     */
+    if (run_mode != GIMP_RUN_NONINTERACTIVE)
+      gimp_displays_flush ();
+
+  }
+  values[0].data.d_status = status;
+}       /* end run */
+
+
+/* ----------------------------
+ * p_selectionConstraintFunc
+ * ----------------------------
+ *
+ */
+static gint
+p_selectionConstraintFunc (gint32   image_id,
+               gint32   drawable_id,
+               gpointer data)
+{
+  if (image_id < 0)
+    return FALSE;
+
+  /* dont accept layers from indexed images */
+  if (gimp_drawable_is_indexed (drawable_id))
+    return FALSE;
+
+  return TRUE;
+}  /* end p_selectionConstraintFunc */
+
+
+/* ----------------------------
+ * p_selectionComboCallback
+ * ----------------------------
+ *
+ */
+static void
+p_selectionComboCallback (GtkWidget *widget)
+{
+  gint idValue;
+
+  if(gap_debug)
+  {
+    printf("p_selectionComboCallback START\n");
+  }
+
+  gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget), &idValue);
+
+  if(gap_debug)
+  {
+    printf("p_selectionComboCallback idValue:%d\n", idValue);
+  }
+  glob_vals.alt_selection = idValue;
+
+}  /* end p_selectionComboCallback */
+
+
+/* --------------------------
+ * p_dialog
+ * --------------------------
+ */
+static gboolean
+p_dialog (TransValues *val_ptr, gint32 drawable_id)
+{
+  GtkWidget *dialog;
+  GtkWidget *main_vbox;
+  GtkWidget *label;
+  GtkWidget *table;
+  GtkWidget *combo;
+  GtkObject *adj;
+  gint       row;
+  gboolean   run;
+  gboolean   isResynthesizerInstalled;
+
+  gint nparams_resynth;
+  gint nparams_resynth_s;
+
+
+  nparams_resynth_s = gap_pdb_procedure_available(PLUG_IN_RESYNTHESIZER_WITH_SEED);
+  nparams_resynth = gap_pdb_procedure_available(PLUG_IN_RESYNTHESIZER);
+  isResynthesizerInstalled = ((nparams_resynth_s >= 0) || (nparams_resynth >= 0));
+  val_ptr->alt_selection = -1;
+
+  gimp_ui_init (PLUG_IN_BINARY, TRUE);
+
+  if (isResynthesizerInstalled)
+  {
+    dialog = gimp_dialog_new (_("Smart selection eraser"), PLUG_IN_BINARY,
+                            NULL, 0,
+                            gimp_standard_help_func, PLUG_IN_PROC,
+
+                            GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                            GTK_STOCK_OK,     GTK_RESPONSE_OK,
+
+                            NULL);
+
+  }
+  else
+  {
+    dialog = gimp_dialog_new (_("Smart selection eraser"), PLUG_IN_BINARY,
+                            NULL, 0,
+                            gimp_standard_help_func, PLUG_IN_PROC,
+
+                            GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+
+                            NULL);
+
+  }
+
+  gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
+                                           GTK_RESPONSE_OK,
+                                           GTK_RESPONSE_CANCEL,
+                                           -1);
+
+  gimp_window_set_transient (GTK_WINDOW (dialog));
+
+  main_vbox = gtk_vbox_new (FALSE, 12);
+  gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
+  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), main_vbox);
+  gtk_widget_show (main_vbox);
+
+
+  /* Controls */
+  table = gtk_table_new (3, 3, FALSE);
+  gtk_table_set_col_spacings (GTK_TABLE (table), 6);
+  gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+  gtk_box_pack_start (GTK_BOX (main_vbox), table, FALSE, FALSE, 0);
+  gtk_widget_show (table);
+
+  row = 0;
+  if (isResynthesizerInstalled != TRUE)
+  {
+    label = gtk_label_new (_("The Resynthesizer plug-in is required for this operation but is not installed"
+                             "Resynthesizer is available at the gimp plug-in registry"));
+    gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
+    gtk_table_attach (GTK_TABLE (table), label, 0, 2, row, row + 1,
+                      GTK_FILL, GTK_FILL, 4, 0);
+    gtk_widget_show (label);
+
+    row++;
+  }
+  adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row,
+                              _("Border Radius:"), SCALE_WIDTH, 7,
+                              val_ptr->corpus_border_radius, 0.0, 1000.0, 1.0, 10.0, 0,
+                              TRUE, 0, 0,
+                              NULL, NULL);
+  g_signal_connect (adj, "value-changed",
+                    G_CALLBACK (gimp_int_adjustment_update),
+                    &val_ptr->corpus_border_radius);
+
+  row++;
+
+  if (nparams_resynth_s > 0)
+  {
+    adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row,
+                              _("Seed:"), SCALE_WIDTH, 7,
+                              val_ptr->seed, -1.0, 10000.0, 1.0, 10.0, 0,
+                              TRUE, 0, 0,
+                              NULL, NULL);
+    g_signal_connect (adj, "value-changed",
+                    G_CALLBACK (gimp_int_adjustment_update),
+                    &val_ptr->seed);
+
+    row++;
+  }
+
+  /* layer combo_box (alt_selection) */
+  label = gtk_label_new (_("Set Selection:"));
+  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+  gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
+                    GTK_FILL, GTK_FILL, 4, 0);
+  gtk_widget_show (label);
+
+  /* layer combo_box (Sample from where to pick the alternative selection */
+  combo = gimp_layer_combo_box_new (p_selectionConstraintFunc, NULL);
+
+  gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (combo), drawable_id,
+                              G_CALLBACK (p_selectionComboCallback),
+                              NULL);
+
+  gtk_table_attach (GTK_TABLE (table), combo, 1, 3, row, row + 1,
+                    GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
+  gtk_widget_show (combo);
+
+  /* Done */
+
+  gtk_widget_show (dialog);
+
+  run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
+
+  gtk_widget_destroy (dialog);
+
+  return run;
+}  /* end p_dialog */
+
+
+/* --------------------------------
+ * p_pdb_call_resynthesizer
+ * --------------------------------
+ * check if non official variant with additional seed parameter
+ * is installed. if not use the official published resynthesizer 0.16
+ */
+static gboolean
+p_pdb_call_resynthesizer(gint32 image_id, gint32 layer_id, gint32 corpus_layer_id, gint32 seed)
+{
+   char            *l_called_proc;
+   GimpParam       *return_vals;
+   int              nreturn_vals;
+   gint             nparams_resynth_s;
+
+   nparams_resynth_s = gap_pdb_procedure_available(PLUG_IN_RESYNTHESIZER_WITH_SEED);
+   if (nparams_resynth_s >= 0)
+   {
+         l_called_proc = PLUG_IN_RESYNTHESIZER_WITH_SEED;
+     return_vals = gimp_run_procedure (l_called_proc,
+                                 &nreturn_vals,
+                                 GIMP_PDB_INT32,     GIMP_RUN_NONINTERACTIVE,
+                                 GIMP_PDB_IMAGE,     image_id,
+                                 GIMP_PDB_DRAWABLE,  layer_id,          /* input drawable (to be processed) */
+                                 GIMP_PDB_INT32,     0,                 /* vtile Make tilable vertically */
+                                 GIMP_PDB_INT32,     0,                 /* htile Make tilable horizontally */
+                                 GIMP_PDB_INT32,     1,                 /* Dont change border pixels */
+                                 GIMP_PDB_INT32,     corpus_layer_id,   /* corpus, Layer to use as corpus */
+                                 GIMP_PDB_INT32,    -1,                 /* inmask Layer to use as input mask, -1 for none */
+                                 GIMP_PDB_INT32,    -1,                 /* outmask Layer to use as output mask, -1 for none */
+                                 GIMP_PDB_FLOAT,     0.0,               /* map_weight Weight to give to map, if map is used */
+                                 GIMP_PDB_FLOAT,     0.117,             /* autism Sensitivity to outliers */
+                                 GIMP_PDB_INT32,     16,                /* neighbourhood Neighbourhood size */
+                                 GIMP_PDB_INT32,     500,               /* trys Search thoroughness */
+                                 GIMP_PDB_INT32,     seed,              /* seed for random number generation */
+                                 GIMP_PDB_END);
+   }
+   else
+   {
+         l_called_proc = PLUG_IN_RESYNTHESIZER;
+     return_vals = gimp_run_procedure (l_called_proc,
+                                 &nreturn_vals,
+                                 GIMP_PDB_INT32,     GIMP_RUN_NONINTERACTIVE,
+                                 GIMP_PDB_IMAGE,     image_id,
+                                 GIMP_PDB_DRAWABLE,  layer_id,          /* input drawable (to be processed) */
+                                 GIMP_PDB_INT32,     0,                 /* vtile Make tilable vertically */
+                                 GIMP_PDB_INT32,     0,                 /* htile Make tilable horizontally */
+                                 GIMP_PDB_INT32,     1,                 /* Dont change border pixels */
+                                 GIMP_PDB_INT32,     corpus_layer_id,   /* corpus, Layer to use as corpus */
+                                 GIMP_PDB_INT32,    -1,                 /* inmask Layer to use as input mask, -1 for none */
+                                 GIMP_PDB_INT32,    -1,                 /* outmask Layer to use as output mask, -1 for none */
+                                 GIMP_PDB_FLOAT,     0.0,               /* map_weight Weight to give to map, if map is used */
+                                 GIMP_PDB_FLOAT,     0.117,             /* autism Sensitivity to outliers */
+                                 GIMP_PDB_INT32,     16,                /* neighbourhood Neighbourhood size */
+                                 GIMP_PDB_INT32,     500,               /* trys Search thoroughness */
+                                 GIMP_PDB_END);
+   }
+
+   if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS)
+   {
+      gimp_destroy_params(return_vals, nreturn_vals);
+      return (TRUE);
+   }
+
+   g_message(_("The call of plug-in %s\nfailed.\n"
+               "probably the 3rd party plug-in resynthesizer is not installed or is not compatible to version:%s")
+              , l_called_proc
+              , "resynthesizer-0.16"
+            );
+   gimp_destroy_params(return_vals, nreturn_vals);
+   printf("GAP: Error: PDB call of %s failed (image_id:%d), d_status:%d\n"
+          , l_called_proc
+          , (int)image_id
+          , (int)return_vals[0].data.d_status
+          );
+   return(FALSE);
+}       /* end p_pdb_call_resynthesizer */
+
+/* --------------------------
+ * p_create_corpus_layer
+ * --------------------------
+ * create the corpus layer that builds the reference pattern
+ * for the resynthesizer call. The reference pattern is built
+ * as duplicate of the original image reduced to the area around the current selection.
+ * (grown by corpus_border_radius)
+ * Note that the duplicate image has a selection, that includes the gorwn area
+ * around the orignal selection, but EXCLUDES the original selection
+ * (that is the area holding the object that has to be replaced
+ * by pattern of the surrounding area)
+ * returns the layer_id of the reference pattern.
+ */
+static gint32
+p_create_corpus_layer(gint32 image_id, gint32 drawable_id, TransValues *val_ptr)
+{
+  gint32 dup_image_id;
+  gint32 channel_id;
+  gint32 channel_2_id;
+  GimpRGB  bck_color;
+  GimpRGB  white_opaque_color;
+  gboolean has_selection;
+  gboolean non_empty;
+  gint     x1, y1, x2, y2;
+  gint32   active_layer_stackposition;
+  gint32   active_dup_layer_id;
+
+
+  active_layer_stackposition = gap_layer_get_stackposition(image_id, drawable_id);
+
+  dup_image_id = gimp_image_duplicate(image_id);
+
+  channel_id = gimp_selection_save(dup_image_id);
+  gimp_selection_grow(dup_image_id, val_ptr->corpus_border_radius);
+  gimp_selection_invert(dup_image_id);
+
+  gimp_context_get_background(&bck_color);
+  channel_2_id = gimp_selection_save(dup_image_id);
+
+  gimp_selection_load(channel_id);
+
+  gimp_rgba_set_uchar (&white_opaque_color, 255, 255, 255, 255);
+  gimp_context_set_background(&white_opaque_color);
+  gimp_edit_clear(channel_2_id);
+
+
+  gimp_context_set_background(&bck_color);  /* restore original background color */
+
+  gimp_selection_load(channel_2_id);
+
+  gimp_selection_invert(dup_image_id);
+
+  has_selection  = gimp_selection_bounds(dup_image_id, &non_empty, &x1, &y1, &x2, &y2);
+  gimp_image_crop(dup_image_id, (x2 - x1), (y2 - y1), x1, y1);
+
+  gimp_selection_invert(dup_image_id);
+  active_dup_layer_id = gap_layer_get_id_by_stackposition(dup_image_id, active_layer_stackposition);
+
+  if (1==0)
+  {
+    /* debug code shows the duplicate image by adding a display */
+    gimp_display_new(dup_image_id);
+  }
+  return (active_dup_layer_id);
+
+}  /* end p_create_corpus_layer */
+
+
+
+/* --------------------------
+ * p_set_alt_selection
+ * --------------------------
+ * create selection as Grayscale copy of the specified alt_selection layer
+ *  - operates on a duplicate of the image references by alt_selection
+ *  - this duplicate is scaled to same size as specified image_id
+ *
+ * - if alt_selection refers to an image that has a selction
+ *   then use this selction instead of the layer itself.
+ */
+static gboolean
+p_set_alt_selection(gint32 image_id, gint32 drawable_id, TransValues *val_ptr)
+{
+  if(gap_debug)
+  {
+    printf("p_set_alt_selection: drawable_id:%d  alt_selection:%d\n"
+      ,(int)drawable_id
+      ,(int)val_ptr->alt_selection
+      );
+  }
+
+  if ((drawable_id == val_ptr->alt_selection) || (drawable_id < 0))
+  {
+    return (FALSE);
+  }
+  return (gap_image_set_selection_from_selection_or_drawable(image_id, val_ptr->alt_selection, FALSE));
+}
+
+
+/* --------------------------
+ * p_process_layer
+ * --------------------------
+ */
+static gint32
+p_process_layer(gint32 image_id, gint32 drawable_id, TransValues *val_ptr)
+{
+  gboolean has_selection;
+  gboolean non_empty;
+  gboolean alt_selection_success;
+  gint     x1, y1, x2, y2;
+  gint32   trans_drawable_id;
+
+  if(gap_debug)
+  {
+    printf("corpus_border_radius: %d\n", (int)val_ptr->corpus_border_radius);
+    printf("alt_selection: %d\n", (int)val_ptr->alt_selection);
+    printf("seed: %d\n", (int)val_ptr->seed);
+  }
+
+  gimp_image_undo_group_start(image_id);
+
+
+  trans_drawable_id = -1;
+  alt_selection_success = FALSE;
+
+  if(val_ptr->alt_selection >= 0)
+  {
+    if(gap_debug)
+    {
+      printf("creating alt_selection: %d\n", (int)val_ptr->alt_selection);
+    }
+    alt_selection_success = p_set_alt_selection(image_id, drawable_id, val_ptr);
+  }
+
+  has_selection  = gimp_selection_bounds(image_id, &non_empty, &x1, &y1, &x2, &y2);
+
+  /* here the action starts, we create the corpus_layer_id that builds the reference pattern
+   * (the corpus is created in a spearate image and has an expanded selection
+   * that excludes the unwanted parts)
+   * then start the resynthesizer plug-in to replace selcted (e.g. unwanted parts) of the
+   * processed layer (e.g. drawable_id)
+   */
+  if (non_empty)
+  {
+    gint32 corpus_layer_id;
+    gint32 corpus_image_id;
+
+    trans_drawable_id = drawable_id;
+
+    corpus_layer_id = p_create_corpus_layer(image_id, drawable_id, val_ptr);
+
+    p_pdb_call_resynthesizer(image_id, drawable_id, corpus_layer_id, val_ptr->seed);
+
+    /* delete the temporary working duplicate */
+    corpus_image_id = gimp_drawable_get_image(corpus_layer_id);
+    gimp_image_delete(corpus_image_id);
+  }
+  else
+  {
+    g_message("Please make a selection (cant operate on empty selection)");
+  }
+
+  if(alt_selection_success)
+  {
+    gimp_selection_none(image_id);
+  }
+
+  gimp_image_undo_group_end(image_id);
+
+  return (trans_drawable_id);
+
+}  /* end p_process_layer */
+

Modified: trunk/vid_common/gap_cme_gui.c
==============================================================================
--- trunk/vid_common/gap_cme_gui.c	(original)
+++ trunk/vid_common/gap_cme_gui.c	Wed Jan 14 19:59:24 2009
@@ -2728,7 +2728,7 @@
                     (GtkAttachOptions) (0), 0, 0);
 
 
-  label = gtk_label_new ("1");
+  label = gtk_label_new ("######");
   gpp->cme__label_enc_stat_frames_total          = label;
   gtk_widget_show (label);
   gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
@@ -2747,7 +2747,7 @@
                     (GtkAttachOptions) (0), 0, 0);
 
 
-  label = gtk_label_new ("0");
+  label = gtk_label_new ("######");
   gpp->cme__label_enc_stat_frames_done          = label;
   gtk_widget_show (label);
   gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
@@ -2766,7 +2766,7 @@
                     (GtkAttachOptions) (0), 0, 0);
 
 
-  label = gtk_label_new ("0");
+  label = gtk_label_new ("######");
   gpp->cme__label_enc_stat_frames_encoded          = label;
   gtk_widget_show (label);
   gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
@@ -2785,7 +2785,7 @@
                     (GtkAttachOptions) (0), 0, 0);
 
 
-  label = gtk_label_new ("0");
+  label = gtk_label_new ("######");
   gpp->cme__label_enc_stat_frames_copied_lossless          = label;
   gtk_widget_show (label);
   gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
@@ -3874,7 +3874,7 @@
   if(label)
   {
     char *buffer;
-    buffer = g_strdup_printf("%d", value);
+    buffer = g_strdup_printf("%6d", value);
     /* repeat the right alingnment of the label
      * (without this workaround my gtk version 2.10.14 shows just
      * the highest digit of the number, probably because the size at creation time

Modified: trunk/vid_enc_avi/gap_enc_avi_main.c
==============================================================================
--- trunk/vid_enc_avi/gap_enc_avi_main.c	(original)
+++ trunk/vid_enc_avi/gap_enc_avi_main.c	Wed Jan 14 19:59:24 2009
@@ -857,7 +857,7 @@
         }
       }
       
-      //if(gap_debug)
+      if(gap_debug)
       {
         printf("l_dont_recode_frames:%d\n", l_dont_recode_frames);
       }
@@ -905,7 +905,7 @@
         /* 1:1 lossless copy one VIDEO FRAME */
         l_cnt_reused_frames++;
 
-        //if (gap_debug)
+        if (gap_debug)
         {
           printf("DEBUG: 1:1 copy of frame %d (fetch as chunk OK) chunk_ptr:%d  chunk_size:%d chunk_hdr_size:%d\n"
               , (int)l_cur_frame_nr
@@ -929,7 +929,7 @@
         gint32  l_app0_len;
 
         l_cnt_encoded_frames++;
-        //if (gap_debug)
+        if (gap_debug)
         {
 	  printf("DEBUG: saving recoded frame %d (fetch as chunk FAILED)\n", (int)l_cur_frame_nr);
         }
@@ -967,8 +967,7 @@
           buffer = gap_gve_jpeg_drawable_encode_jpeg(l_drawable, epp->jpeg_interlaced,
                                         &l_FRAME_size, epp->jpeg_quality, epp->jpeg_odd_even, FALSE, l_app0_buffer, l_app0_len);
         }
-        else if ((strcmp(epp->codec_name, GAP_AVI_CODEC_JPEG) == 0)
-        || (strcmp(epp->codec_name, GAP_AVI_CODEC_MJPG) == 0))
+        else if (strcmp(epp->codec_name, GAP_AVI_CODEC_PNG) == 0)
         {
           /* Compress the picture into a PNG */
           buffer = gap_gve_png_drawable_encode_png(l_drawable, epp->png_interlaced,
@@ -993,10 +992,6 @@
 	    }
             buffer = gap_gve_raw_BGR_drawable_encode(l_drawable, &l_FRAME_size, l_vflip, l_app0_buffer, l_app0_len);
           }
-          else if (strcmp(epp->codec_name, GAP_AVI_CODEC_PNG) == 0)
-          {
-            printf("PNG codec not implemented yet.\n");
-          }
 #ifdef ENABLE_LIBXVIDCORE
           else
           {

Modified: trunk/vid_enc_rawframes/gap_enc_rawframes_main.c
==============================================================================
--- trunk/vid_enc_rawframes/gap_enc_rawframes_main.c	(original)
+++ trunk/vid_enc_rawframes/gap_enc_rawframes_main.c	Wed Jan 14 19:59:24 2009
@@ -721,7 +721,7 @@
   GimpRunMode    l_save_runmode;
   GapGveMasterEncoderStatus encStatus;
 
-  //if(gap_debug)
+  if(gap_debug)
   {
      printf("p_rawframe_encode: START\n");
      printf("  videoname: %s\n", gpp->val.videoname);
@@ -755,7 +755,7 @@
   if(p_is_videoname_jpeg(gpp->val.videoname) == TRUE)
   {
     l_check_flags += GAP_VID_CHCHK_FLAG_JPG;
-    //if(gap_debug)
+    if(gap_debug)
     {
       printf("check fetched chunks for JPEG frames activated\n");
     }
@@ -857,7 +857,7 @@
         gboolean l_saveOk;
         
         l_cnt_reused_frames++;
-        //if (gap_debug)
+        if (gap_debug)
         {
 	  printf("DEBUG: 1:1 copy of frame %d (fetch as chunk OK) chunk_ptr:%d  chunk_size:%d chunk_hdr_size:%d\n"
               , (int)l_cur_frame_nr
@@ -877,7 +877,7 @@
       else
       {
         l_cnt_encoded_frames++;
-        //if (gap_debug)
+        if (gap_debug)
         {
 	  printf("DEBUG: saving recoded frame %d (fetch as chunk FAILED)\n", (int)l_cur_frame_nr);
         }



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