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 /Filters/Animation/Filter All Layers checks for the existance of Iterator Procedures in the PDB 1.) _Iterator 2.) _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. If you have gap prerelease 0.93.00 or later you can generate the "plug_in_XXXX_Iterator" for a Plugin as seperated 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 by 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 GParamDef 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 int nargs_plugin = sizeof(args_plugin) / sizeof(args_plugin[0]); static GParamDef 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 int nargs_iter = sizeof(args_iter) / sizeof(args_iter[0]); static GParamDef *return_vals = NULL; static int nreturn_vals = 0; gimp_install_procedure("plug_in_XXXX, "plug_in_XXXX can do ....", "", "Authors Name", "Copyright", "Date", "/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, PROC_EXTENSION, 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 (char *name, int n_params, GParam *param, int *nreturn_vals, GParam **return_vals) { static GParam values[1]; GStatusType status = STATUS_SUCCESS; GRunModeType 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 = PARAM_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 == 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 = STATUS_CALLING_ERROR; } else status = STATUS_CALLING_ERROR; } values[0].type = PARAM_STATUS; values[0].type = PARAM_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" )