This README_developers file should be read by Plug-In authors:

How to make a GIMP Plug-In an "Animated" one:
---------------------------------------------

First of all:

   the plugin must be able to operate on a single Drawable,
                              ----------------------------
   further it must be able to run with last_values and in interactive mode.
                              --------------------        -----------
   
   For the Animated Plugin Call we need an Iterator Procedure.
   This Procedure is named like the Plugin with the extension "_Iterator".
   The Iterator Procedure has to know the Plugin's internal datastructure
   and has to modify Its "LastValues" step by step at each call.
   
   The GAP-PDB-Browser <Image>/Filters/Animation/Filter All Layers
   checks for the existance of Iterator Procedures in the PDB
     1.)  <plugin_name>_Iterator
     2.)  <plugin_name>_iter_ALT
     
   If one of the iterator procedures was found in the PDB, the
   "Apply Varying" Button is set sensitive to allow animated calls
   for the selected procedure.
   
   
   You can generate the "plug_in_XXXX_Iterator"
   for a Plugin as separated Sourcefile, ready to compile.
   (The Plugin must be found in the PDB at generation time)
   
   # this example uses the Plugin whirlpinch
   
   1.a  # for bourne and ksh users:
   
        GAP_DEBUG=y
        export GAP_DEBUG
        
   1.b # for csh users
       setenv GAP_DEBUG y
    
   2.  # change to the directory, where you like to generate the sourcecode
       cd /usr/local/gimp-0.99.17/plug-ins/whirlpinch
   
   3.  # start the Gimp
       gimp

   4.  # open or create any image
       File->New
   
   5.  # call the GAP Plugin for Animated Filter apply
       # from within the image
       Filters->Animation->Filter all Layers
       
       # if you have set GAP_DEBUG as shown above,
       # the Window should contain the Button "Gen Code by name"
       
       # Type the name of your Plugin into the Search Inputfield
       # (Click "Search by Name" Button, to check if the Plugin
       # is available in the PDB)
       
       # Then click "Gen Code by Name" Button and then "Cancel" Button.
       
       # This will generate 4 files in the current directory:
           gen_filter_iter_forward.c
           gen_filter_iter_tab.c
           plug_in_whirl_pinch_iter_ALT.inc
           plug_in_whirl_pinch_iter.c
           
       # You can quit the gimp and delete the 3 files named "gen_filter_iter_*"
       
  6. # compile and link the generated Source,  plug_in_whirl_pinch_iter.c
     # and install the linked executeable
     # in global or private plug-in directory
     
     gimptool --install  plug_in_whirl_pinch_iter.c
     
     # (if you dont have gimptool, you can use a copy of the original Plugin's Makefile
     # and change the Plugins <name> by <name_iter> to do that job.)
     

  7. # start the gimp again,
     # and open or create an Image that has at least 3 Layers.
     # Test the "Animated Filter apply"
  
     Filters->Animation->Filter all Layers
     
     # Use the "Apply Varying" Button, 
     # it should be sensitive now (if all went well so far).
  
  8. # In case of error:
     # If you get an Error Message (in the shell, where you started the gimp)
     # that looks like:
     
        ERROR: xxxx_Iterator stored Data missmatch in size N != M
    
     # you have to change the generated code manually.
     # (check for calls to "gimp_set_data" or "gimp_get_data" that are using
     # the plugins name as key argument within the plugin's sourcecode.
     # The passed datastructure has to match exactly in size with the generated one
     # for the example above the generated structure is:
     # plug_in_whirl_pinch_iter.c: 
         typedef struct t_plug_in_whirl_pinch_Vals 
         {
           gdouble   whirl;
           gdouble   pinch;
           gdouble   radius;
         } t_plug_in_whirl_pinch_Vals;        


If you are the Author of a Plugin you may decide to include the _Iterator
within the original Sources of your Plugin. In that case you have to check
the name argument in the run procedure.




Example Code:

query()
{
  static GimpParamDef args_plugin[] =
  {
    {PARAM_INT32, "run_mode", "non-interactive"},
    {PARAM_IMAGE, "image", "the image"},
    {PARAM_DRAWABLE, "drawable", "the drawable"},
    {PARAM_INT32, "value", "my_parameter value"},
  };
  static gint nargs_plugin = G_N_ELEMENTS (args_plugin);

  static GimpParamDef args_iter[] =
  {
    {PARAM_INT32, "run_mode", "non-interactive"},
    {PARAM_INT32, "total_steps", "total number of steps (# of layers-1 to apply the related plug-in)"},
    {PARAM_FLOAT, "current_step", "current (for linear iterations this is the layerstack position, otherwise some value inbetween)"},
    {PARAM_INT32, "len_struct", "length of stored data structure with id is equal to the plug_in  proc_name"},
  };
  static gint nargs_iter = G_N_ELEMENTS (args_iter);

  static GimpParamDef *return_vals = NULL;
  static gint nreturn_vals = 0;

  gimp_install_procedure("plug_in_XXXX,
			 "plug_in_XXXX can do ....",
			 "",
			 "Authors Name",
			 "Copyright",
			 "Date",
			 "<Image>/Filters/Effects/XXXX",
		         "RGB*, INDEXED*, GRAY*",
                         PROC_PLUG_IN,
			 nargs_plugin, nreturn_vals,
			 args_plugin, return_vals);


  gimp_install_procedure("plug_in_XXXX_Iterator,
			 "This extension calculates the modified values for one iterationstep for the call of plug_in_XXXX",
			 "",
			 "Authors Name",
			 "Copyright",
			 "Date",
			 NULL,    /* do not appear in menus */
			 NULL,
			 GIMP_PLUGIN,
			 nargs_iter, nreturn_vals,
			 args_iter, return_vals);
}




static void p_delta_long(long *val, long val_from, long val_to, gint32 total_steps, gdouble current_step)
{
    double     delta;

    if(total_steps < 1) return;

    delta = ((double)(val_to - val_from) / (double)total_steps) * ((double)total_steps - current_step);
    *val  = val_from + delta; 

}



static void
run (const gchar      *name,
     gint              n_params,
     const GimpParam  *param,
     gint             *nreturn_vals,
     GimpParam       **return_vals)
{
  static GimpParam   values[1];
  GimpPDBStatusType  status = GIMP_PDB_SUCCESS;
  GimpRunMode        run_mode;
  gint32             len_struct;
  gint32             total_steps;
  gdouble            current_step;

  long    pval;                 /* plug_in_XXXX has one parameter of type long */
  long   *pval_from, *pval_to;  /* values for 1.st and last layer
                                 * when they were processed by "plug_in_gap_layers_run_animfilter"
                                 */

  *nreturn_vals = 1;
  *return_vals = values;
  values[0].type = GIMP_PDB_STATUS;
 
  
  run_mode = param[0].data.d_int32;
  
  if (strcmp (name, "plug_in_XXXX") == 0)
  {
     ....  /* start the plugin itself */
  }
  else  if (strcmp (name, "plug_in_XXXX_Iterator") == 0)
  {
      /* Iterator procedure is usually called from
       * "plug_in_gap_layers_run_animfilter"
       * (always run noninteractive)
       */
      if ((run_mode == GIMP_RUN_NONINTERACTIVE) && (n_params == 4))
      {
        total_steps  =  param[1].data.d_int32;
        current_step =  param[2].data.d_float;
        len_struct   =  param[3].data.d_int32;

        if(len_struct == sizeof(pval))
        {
          /* get _FROM and _TO data, 
           * This data was stored by plug_in_gap_layers_run_animfilter
           */
        
          gimp_get_data("plug_in_XXXX_ITER_FROM", pval_from); 
          gimp_get_data("plug_in_XXXX_ITER_TO",   pval_to); 

          p_delta_long(&pval, *pval_from, *pval_to, total_steps, current_step);

          gimp_set_data("plug_in_XXXX", &pval, sizeof(pval));
        }
        else status = GIMP_PDB_CALLING_ERROR;
      }
      else status = GIMP_PDB_CALLING_ERROR;
  }

   values[0].type = GIMP_PDB_STATUS;
   values[0].data.d_status = status;
}


Important for Plugin_Authors:
   I have made Iterator Procedures for more than 50 existing Procedures.
   (see gap_filter_iterators.c and subdirectories iter_ALT/*/*.inc)
   If your Plugin is found in gap_filter_iterators.c, and You make updates 
   to your Plugin's interface, you should write (or generate) your own _Iterator Procedure,
   to keep its Animated capabilities intact.
   (You don't need to change gap sources to do that, because the Iterator
   named "plug_in_XXXX_Iterator" is used rather than "plug_in_XXXX_Iterator_ALT" )
