[gimp-gap] movepath transformation support in storyboard and modify frames
- From: Wolfgang Hofer <wolfgangh src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp-gap] movepath transformation support in storyboard and modify frames
- Date: Tue, 26 Apr 2011 18:38:00 +0000 (UTC)
commit f67c8d085df325d6120bc37e7e93faa29760c5ab
Author: Wolfgang Hofer <wolfgangh svn gnome org>
Date: Tue Apr 26 20:33:21 2011 +0200
movepath transformation support in storyboard and modify frames
ChangeLog | 64 ++
NEWS | 8 +-
docs/STORYBOARD_FILE_DOC.txt | 711 ------------
docs/reference/txt/STORYBOARD_FILE_DOC.txt | 247 ++++-
gap/Makefile.am | 33 +-
gap/gap_bluebox.h | 5 +-
gap/gap_main.c | 377 +-------
gap/gap_mov_dialog.c | 465 +++++++--
gap/gap_mov_dialog.h | 64 +-
gap/gap_mov_exec.c | 1386 +++++++++++++++++++----
gap/gap_mov_exec.h | 23 +
gap/gap_mov_main.c | 713 ++++++++++++
gap/gap_mov_render.c | 596 +++++++++-
gap/gap_mov_xml_par.c | 1651 ++++++++++++++++++++++++++++
gap/gap_mov_xml_par.h | 52 +
gap/gap_story_att_trans_dlg.c | 756 ++++++++++++-
gap/gap_story_file.c | 145 +++-
gap/gap_story_file.h | 5 +-
gap/gap_story_main.h | 3 +
gap/gap_story_properties.c | 26 +-
gap/gap_story_render_lossless.c | 83 +-
gap/gap_story_render_processor.c | 1274 ++++++++++++++++------
gap/gap_story_render_processor.h | 18 +-
gap/gap_story_render_types.h | 11 +
gap/gap_story_syntax.c | 9 +
gap/gap_story_syntax.h | 1 +
gap/gap_story_vthumb.c | 5 +-
gap/gap_xml_util.c | 347 ++++++
gap/gap_xml_util.h | 56 +
po/POTFILES.in | 1 +
30 files changed, 7188 insertions(+), 1947 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index ebfd90e..eaea9f0 100755
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,69 @@
2011-04-26 Wolfgang Hofer <hof gimp org>
+- Storyboard render processor now supports processing
+ of new transition attribute record VID_MOVE_PATH
+ (based on the new singleframe mode of the move path feature)
+
+- Move Path now supports save of all settings (controlpoints and other relevant settings)
+ using a new XML stuctured fileformat.
+ Note that the old controlpoint file format is still supported both for load and save.
+ The new format is selected implicite by finename extension .xml
+
+- New plug-in to call the MovePath for rendering only one frame where the
+ moving object is an already existing layer of the frame and all parameters
+ are provided via xml parameterfile
+ (this new feature is intended to be called as filter with the modify frames
+ feature)
+
+- The MovePath feature is still limited to process image types RGB
+ (both for the frame and the moving object)
+ Therefore the PDB requstration was changed
+ from "RGB*, INDEXED*, GRAY*"
+ to "RGB*"
+
+ to disable the MovePath feature on unsupported frame types.
+ (see also remarks at bugzilla #645303)
+
+
+- the MovePath feature now is built as separate plug-in with its own main
+ procedure to handle run and query.
+
+- added a new gimprc parameter that enables logging of the
+ relevant render parameters each time the movePath feature
+ renders a frame. This parameter defaults to "no" in productive environment
+ and is intended for debug and analyse purpose.
+ This logging was used as base for regression tests on the current changes.
+
+ (video-move-path-log-render-params "yes")
+
+
+ * NEWS
+ * po/POTFILES.in
+ * gap/Makefile.am
+ * gap/gap_bluebox.h
+ * gap/gap_main.c
+ * gap/gap_mov_dialog.c [.h]
+ * gap/gap_mov_exec.c [.h]
+ * gap/gap_mov_main.c # NEW FILE
+ * gap/gap_mov_render.c [.h]
+ * gap/gap_mov_xml_par.c [.h] # NEW FILES
+ * gap/gap_xml_util.c [.h] # NEW FILES
+
+ * gap/gap_story_main.h
+ * gap/gap_story_file.c [.h]
+ * gap/gap_story_render_processor.c [.h]
+ * gap/gap_story_render_lossless.c
+ * gap/gap_story_render_types.h
+ * gap/gap_story_syntax.c [.h]
+ * gap/gap_story_vthumb.c
+ * gap/gap_story_properties.c
+
+ * gap/gap_story_att_trans_dlg.c
+ * docs/reference/txt/STORYBOARD_FILE_DOC.txt
+
+
+2011-04-26 Wolfgang Hofer <hof gimp org>
+
- applied patch that fixes string typos provided by Christian Kirbach at #648607
* gap/gap_morph_tween_dialog.c
diff --git a/NEWS b/NEWS
index e7f324d..fe02224 100644
--- a/NEWS
+++ b/NEWS
@@ -18,6 +18,10 @@ Here is a short overview whats new in GIMP-GAP-2.7.0:
- support to run gimp_color_balance tool as animated filter
(added wrapper plug-in).
+ - new plug-in to apply the MovePath functionality
+ (transitions and move object along path)
+ in a "process one frame per call" style, intended to be called as filter
+ with the modify frames feature.
- GIMP-GAP now supports speed control of movements and other transitions
via Acceleration characteristic presets. Those presets are available
@@ -32,7 +36,9 @@ Here is a short overview whats new in GIMP-GAP-2.7.0:
(that replaces the "Apply Varying" button of older GIMP_GAP releases)
-- The Storyboard now supports rotatation of the processed clips by any angle.
+- The Storyboard now supports rotatation of the processed clips by any angle
+ and more complex transistions similar to the move path feature
+ (based on settings saved with the Movepath dialog as xml parameter file)
- A new storyboard processing feature allows adding external transparency
for clip type movie. This is done via format string that refers to
diff --git a/docs/reference/txt/STORYBOARD_FILE_DOC.txt b/docs/reference/txt/STORYBOARD_FILE_DOC.txt
index 9189749..2f97d75 100644
--- a/docs/reference/txt/STORYBOARD_FILE_DOC.txt
+++ b/docs/reference/txt/STORYBOARD_FILE_DOC.txt
@@ -1,4 +1,4 @@
-STORYBOARD_FILES 2010.11.02:
+STORYBOARD_FILES 2011.04.14:
General
@@ -539,7 +539,7 @@ VID_SILENCE
DEFAULT: 0
VID_ROTATE
- This record is used to define rotate treansitions,
+ This record is used to define rotate transitions,
by changing the rotation angle of the processed frames in the specified Videotrack slightly from one value
to another.
@@ -695,8 +695,13 @@ VID_MOVE_X and VID_MOVE_Y
VID_FIT_SIZE
- Define how to match input framesize with the size of
- the resulting video (VID_MASTER_SIZE).
+ Define how to match input framesize with the target size.
+ The target size is typically the size of the resulting video (VID_MASTER_SIZE).
+ except in scenarios where a movepath transistion is active.
+ In this special case the input frame is processed as moving object
+ of this transition and the target size refers to the scaled size
+ (preScaleWidth, preScaleHeight) of the recorded moving object.
+
Notes:
- The Input Frame is placed in the center of the
@@ -705,6 +710,29 @@ VID_FIT_SIZE
- Zooming may cause additional Scaling. The VID_FIT_SIZE record
describes the normal Size (where zoom is set to 1.0)
+ - In case the input Frame is processed by a movepath transistion
+ the target size depends on the size of the moving object and the framesize
+ in the xml_paramfile and on the VID_MASTER_SIZE.
+ (see VID_MOVE_PATH below)
+
+ Example:
+ in the xml_paramfile the frame size 640x400 pixels and the
+ moving object size was 320x240 pixels.
+
+ <frame_description width="640" height="400"
+ <moving_object width="320" height="240"
+
+ The actual rendering shall be done at double frame size VID_MASTER_SIZE 1280 x 800 pixels.
+ In this example the target size of the pre-scaled moving object is 640 x 480 pixels
+
+ target size calculation:
+ preScaleWidth = recordedMovingObjWidth * masterWidth / recordedFrameWidth
+ 640 = 320 * 1280 / 640
+ preScaleHeight = recordedMovingObjHeight * masterHeight / recordedFrameWidth
+ 480 = 240 * 800 / 400
+
+
+
- WARNING: settings that disable scaling
(e.g. use fixed width or height at original source image size)
do NOT follow changes of the resulting VID_MASTER_SIZE.
@@ -727,9 +755,15 @@ VID_FIT_SIZE
(2) track ... integer tracknumer
[3] mode ... One of the Keywords "width" "height" "none" or "both"
width: Scale that only width does exactly
- fit to the resulting video, height is unchanged
+ fit to the resulting video,
+ height is unchanged original input frame height,
+ or adjusted to keep the proportions of the input frame
+ (depends on the proportions setting)
height: Scale that only height does exactly
- fit to the resulting video, width is unchanged
+ fit to the resulting video,
+ width is unchanged original input frame width,
+ or adjusted to keep the proportions of the input frame
+ (depends on the proportions setting)
both: Scale that both width and height do exactly
fit to the resulting video
none: Do not Scale the input frame at all
@@ -747,11 +781,182 @@ VID_FIT_SIZE
background if there no such frames.
change_proportions:
allow proportion changes at scaling.
- Stretch the image to fit the resulting
- video.
DEFAULT: "change_proportions"
+
+ This Example shows how an Input Frame of size 400x400 pixel is automatically scaled
+ to fit into a video at size 1280 x 800
+
+ +------+
+ |######| Input Frame width: 400
+ |######| Input Frame height: 400
+ |######|
+ |######|
+ +------+
+
+
+ ==== scenarios that allow changing proportions of the moving object =====
+
+ o) VID_FIT_SIZE mode=both proportions=change_proportions
+
+ +-------------------------------------+
+ |#####################################| scaled copy of input frame: 1280 x 800
+ |#####################################| video size: 1280 x 800
+ |#####################################|
+ |#####################################|
+ |#####################################|
+ |#####################################|
+ |#####################################|
+ |#####################################|
+ |#####################################|
+ |#####################################|
+ |#####################################|
+ |#####################################|
+ +-------------------------------------+
+
+ o) VID_FIT_SIZE mode=width proportions=change_proportions
+
+ +-------------------------------------+
+ | | scaled copy of input frame: 1280 x 400
+ | | video size: 1280 x 800
+ | |
+ +-------------------------------------+
+ |#####################################|
+ |#####################################|
+ |#####################################|
+ |#####################################|
+ +-------------------------------------+
+ | |
+ | |
+ | |
+ +-------------------------------------+
+
+
+ o) VID_FIT_SIZE mode=height proportions=change_proportions
+
+ +--------------+------+---------------+
+ | |######| | scaled copy of input frame: 400 x 800
+ | |######| | video size: 1280 x 800
+ | |######| |
+ | |######| |
+ | |######| |
+ | |######| |
+ | |######| |
+ | |######| |
+ | |######| |
+ | |######| |
+ | |######| |
+ | |######| |
+ +--------------+------+---------------+
+
+
+ ==== scenarios that keep proportions of the moving object =====
+
+ o) VID_FIT_SIZE mode=both proportions=keep_proportions
+
+ The input frame is scaled to fit into video size rectangle
+ since the input frame has different proportions than the video size
+ there will be transparent borders. (where the black background
+ or clips of other tracks on lower stack position shows through)
+
+ +-------+---------------------+-------+
+ | |#####################| | scaled copy of input frame: 800 x 800
+ | |#####################| | video size: 1280 x 800
+ | |#####################| |
+ | |#####################| |
+ | |#####################| |
+ | |#####################| |
+ | |#####################| |
+ | |#####################| |
+ | |#####################| |
+ | |#####################| |
+ | |#####################| |
+ | |#####################| |
+ +-------+---------------------+-------+
+
+
+ o) VID_FIT_SIZE mode=width proportions=keep_proportions
+
+ The input frame is scaled to width 1280 pixels
+ and height 1280 pixels to keep the proportions.
+ But this cuts off the parts that do not fit into
+ the video height of 800 pixels.
+
+
+
+ +-------------------------------------+
+ |.....................................|
+ |.....................................|
+ +-------------------------------------+
+ |#####################################| scaled copy of input frame: 1280 x 1280
+ |#####################################| video size: 1280 x 800
+ |#####################################|
+ |#####################################|
+ |#####################################|
+ |#####################################|
+ |#####################################|
+ |#####################################|
+ |#####################################|
+ |#####################################|
+ |#####################################|
+ |#####################################|
+ +-------------------------------------+
+ |.....................................|
+ |.....................................|
+ +-------------------------------------+
+
+ o) VID_FIT_SIZE mode=height proportions=keep_proportions
+
+ The input frame is scaled to height 800 pixels.
+ keeping the proportions of the input frame results in width of 800 pixels
+ that gives transparent stripes left and right.
+
+
+ +-------+---------------------+-------+
+ | |#####################| | scaled copy of input frame: 800 x 800
+ | |#####################| | video size: 1280 x 800
+ | |#####################| |
+ | |#####################| |
+ | |#####################| |
+ | |#####################| |
+ | |#####################| |
+ | |#####################| |
+ | |#####################| |
+ | |#####################| |
+ | |#####################| |
+ | |#####################| |
+ +-------+---------------------+-------+
+
+
+
+ o) VID_FIT_SIZE mode=none
+
+ No automatic scaling is done to fit into video size.
+ (the proportions seting is not relevant in this case)
+
+ +-------------------------------------+
+ | | scaled copy of input frame: 400 x 400
+ | | video size: 1280 x 800
+ | |
+ | +------+ |
+ | |######| |
+ | |######| |
+ | |######| |
+ | |######| |
+ | +------+ |
+ | |
+ | |
+ | |
+ +-------------------------------------+
+
+
+
+
+
+
+
+
VID_OVERLAP
Define overlapping frames within one track.
The specified number of frames will overlap previous frames of the same track.
@@ -800,6 +1005,32 @@ VID_OVERLAP
00195 B.mpg 000100
+
+VID_MOVE_PATH
+ This record is used to define a set of complex transformations on the current video track (layer)
+ Those transformations can include movement along a path, scaling, rotation, perspective transformation,
+ opacity changes ... (see the GIMP-GAP MovePath feature for more details)
+
+ to another.
+
+ (1) Record Key ... VID_MOVE_PATH
+ (2) track ... integer tracknumer
+ (3) frame_from ... Start frame number specifies the phase
+ where to start in the move path (typically start at 1)
+ (4) frame_to ... End frame number specifies the phase
+ where to end in the move path
+ (5) nframes ... duration of the effect
+ in number of frames (integer)
+ In case nframes is greater than total_frames
+ the transistions of the end
+ The duration Value 0 disables move transitions.
+ (6) accel ... an integer value specifiying acceleration characteristic
+ DEFAULT: 0 ** other values are currently ignored
+
+ (7) xml_paramfile ... name of the paramterfile for the move path plugin.
+
+
+
AUD_PLAY_SOUND
This record is used for playback of portions of an audiofile,
with optional fade effects. Please note that all audiotracks
diff --git a/gap/Makefile.am b/gap/Makefile.am
old mode 100644
new mode 100755
index 4eedebb..26620f1
--- a/gap/Makefile.am
+++ b/gap/Makefile.am
@@ -79,13 +79,28 @@ BASE_SOURCES = \
gap_timeconv.h \
gap_stock.c \
gap_stock.h \
+ gap_xml_util.c \
+ gap_xml_util.h \
gap_vin.c \
gap_vin.h
+
+MOVEPATH_SOURCES = \
+ gap_bluebox.c \
+ gap_bluebox.h \
+ gap_mov_dialog.c \
+ gap_mov_dialog.h \
+ gap_mov_exec.c \
+ gap_mov_exec.h \
+ gap_mov_render.c \
+ gap_mov_render.h \
+ gap_mov_xml_par.c \
+ gap_mov_xml_par.h
+
libgimpgap_a_SOURCES = $(BASE_SOURCES)
-libgapstory_a_SOURCES = $(BASE_SOURCES) \
+libgapstory_a_SOURCES = $(BASE_SOURCES) $(MOVEPATH_SOURCES) \
gap_frame_fetcher.c \
gap_frame_fetcher.h \
gap_fmac_name.c \
@@ -108,6 +123,7 @@ libexec_PROGRAMS = \
gap_bluebox \
gap_colormask \
gap_plugins \
+ gap_movepath \
gap_filter \
gap_fmac \
gap_fmac_varying \
@@ -164,12 +180,6 @@ gap_plugins_SOURCES = \
gap_mod_layer.h \
gap_mod_layer_dialog.c \
gap_mod_layer_dialog.h \
- gap_mov_dialog.c \
- gap_mov_dialog.h \
- gap_mov_exec.c \
- gap_mov_exec.h \
- gap_mov_render.c \
- gap_mov_render.h \
gap_navi_activtable.c \
gap_navi_activtable.h \
gap_range_ops.c \
@@ -180,6 +190,14 @@ gap_plugins_SOURCES = \
gap_split.h \
gap_libgimpgap.h
+gap_movepath_SOURCES = $(MOVEPATH_SOURCES) \
+ gap_base_ops.c \
+ gap_base_ops.h \
+ gap_mov_main.c \
+ gap_lastvaldesc.c \
+ gap_lastvaldesc.h \
+ gap_libgimpgap.h
+
gap_filter_SOURCES = \
gap_dbbrowser_utils.c \
gap_dbbrowser_utils.h \
@@ -438,6 +456,7 @@ LDADD = $(GIMP_LIBS)
gap_plugins_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS)
+gap_movepath_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS)
gap_bluebox_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS)
gap_colormask_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS)
gap_filter_LDADD = $(GAPVIDEOAPI) $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS)
diff --git a/gap/gap_bluebox.h b/gap/gap_bluebox.h
index 6e03598..8611535 100644
--- a/gap/gap_bluebox.h
+++ b/gap/gap_bluebox.h
@@ -32,6 +32,10 @@
#define GAP_BLUEBOX_DATA_KEY_VALS "plug_in_bluebox"
#define GAP_BLUEBOX_HELP_ID "plug-in-bluebox"
+
+#include <gtk/gtk.h>
+#include "libgimp/gimp.h"
+
typedef enum
{
GAP_BLUBOX_THRES_RGB
@@ -40,7 +44,6 @@ typedef enum
,GAP_BLUBOX_THRES_ALL
} GapBlueboxThresMode;
-#include "libgimp/gimp.h"
typedef struct GapBlueboxVals {
GimpRGB keycolor;
GapBlueboxThresMode thres_mode;
diff --git a/gap/gap_main.c b/gap/gap_main.c
index 75f267a..c271c5d 100644
--- a/gap/gap_main.c
+++ b/gap/gap_main.c
@@ -39,6 +39,7 @@
*/
/* revision history:
+ * 2011/03/09 hof: - moved code for Move Path features to gap_mov_main.c module
* gimp 2.1.0a; 2004/04/05 hof: - Move Path added option to keep the original paintmode of the src_layer
* gimp 1.3.24a; 2004/01/17 hof: - get main version from config.h, fixed PDB docs for plug_in_gap_modify
* gimp 1.3.23b; 2003/12/06 hof: - updated main version
@@ -116,7 +117,6 @@
#include "gap_match.h"
#include "gap_range_ops.h"
#include "gap_split.h"
-#include "gap_mov_exec.h"
#include "gap_mod_layer.h"
#include "gap_arr_dialog.h"
#include "gap_pdb_calls.h"
@@ -145,9 +145,6 @@ int gap_debug = 0;
#define PLUGIN_NAME_GAP_DUP "plug_in_gap_dup"
#define PLUGIN_NAME_GAP_DENSITY "plug_in_gap_density"
#define PLUGIN_NAME_GAP_EXCHG "plug_in_gap_exchg"
-#define PLUGIN_NAME_GAP_MOVE "plug_in_gap_move"
-#define PLUGIN_NAME_GAP_MOVE_PATH_EXT "plug_in_gap_move_path_ext"
-#define PLUGIN_NAME_GAP_MOVE_PATH_EXT2 "plug_in_gap_move_path_ext2"
#define PLUGIN_NAME_GAP_RANGE_TO_MULTILAYER "plug_in_gap_range_to_multilayer"
#define PLUGIN_NAME_GAP_RANGE_FLATTEN "plug_in_gap_range_flatten"
#define PLUGIN_NAME_GAP_RANGE_LAYER_DEL "plug_in_gap_range_layer_del"
@@ -255,138 +252,6 @@ GimpPlugInInfo PLUG_IN_INFO =
};
static int nargs_exchg = G_N_ELEMENTS (args_exchg);
- static GimpParamDef args_mov[] =
- {
- {GIMP_PDB_INT32, "run_mode", "Interactive"},
- {GIMP_PDB_IMAGE, "image", "Input image (one of the video frames)"},
- {GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)"},
- };
-
- static GimpParamDef args_mov_path_ext[] =
- {
- {GIMP_PDB_INT32, "run_mode", "non-interactive"},
- {GIMP_PDB_IMAGE, "dst_image", "Destination image (one of the video frames), where to insert the animated source layers"},
- {GIMP_PDB_DRAWABLE, "drawable", "drawable (unused)"},
- {GIMP_PDB_INT32, "range_from", "destination frame nr to start"},
- {GIMP_PDB_INT32, "range_to", "destination frame nr to stop (can be lower than range_from)"},
- {GIMP_PDB_INT32, "nr", "layerstack position where to insert source layer (0 == on top)"},
- /* source specs */
- { GIMP_PDB_LAYER, "src_layer_id", "starting LayerID of SourceObject. (use any Multilayeranimated Image, or a video frame of anoter Animation)"},
- { GIMP_PDB_INT32, "src_stepmode", "0-5 derive inserted object as copy of one layer from a multilayer src_image \n"
- "100-105 derive inserted object as copy of merged visible layers of a source video frame \n"
- "0: Layer Loop 1: Layer Loop reverse 2: Layer Once 3: Layer Once reverse 4: Layer PingPong \n"
- "5: None (use onle the selected src_layer)\n"
- "100: Frame Loop 101: Frame Loop reverse 102: Frame Once 103: Frame Once reverse 104: Frame PingPong \n"
- "105: Frame None (use onle the flat copy of the selected frame)\n"
- },
- { GIMP_PDB_INT32, "src_handle", "0: handle left top 1: handle left bottom \n"
- "2: handle right top 3: handle right bottom \n"
- "4: handle center"},
- { GIMP_PDB_INT32, "src_paintmode", "4444: keep original paintmode of src_layer 0: GIMP_NORMAL_MODE (see GimpLayerModeEffects -- libgimp/gimpenums.h -- for more information)"},
- { GIMP_PDB_INT32, "src_force_visible", "1: Set inserted layres visible, 0: insert layers as is"},
- { GIMP_PDB_INT32, "clip_to_img", "1: Clip inserted layers to Image size of the destination video frame, 0: dont clip"},
- /* extras */
- { GIMP_PDB_INT32, "rotation_follow", "0: NO automatic calculation (use the rotation array parameters as it is) \n"
- "1: Automatic calculation of rotation, following the path vectors, (Ignore rotation array parameters)\n"},
- { GIMP_PDB_FLOAT, "startangle", "start angle for the first contolpoint (only used if rotation-follow is on)"},
-
- /* new features of the _ext[ended] API */
- {GIMP_PDB_FLOAT, "step_speed_factor", "Allows stepping Source and Destination at different speed. (0.1 upto 50 where 1.0 does step snychron, 2.0 Src makes 2 Steps while Destination makes 1 step) "},
- {GIMP_PDB_INT32, "tween_steps", "0 upto 50, Number of virtual Frames to calculate between 2 destination Frames. (use value 0 if no tween processing should be done)"},
- {GIMP_PDB_FLOAT, "tween_opacity_initial", "opacity 0.0 upto 100.0 for the tween step that is nearest to the (next) real frame"},
- {GIMP_PDB_FLOAT, "tween_opacity_desc", "descending opacity 0.0 upto 100.0 for the othertween steps"},
- {GIMP_PDB_INT32, "tracelayer_enable", "TRUE: calculate a tracelayer (with all steps of the moving objects since first step)"},
- {GIMP_PDB_FLOAT, "trace_opacity_initial", "opacity 0.0 upto 100.0 for the nearest tracestep to the actual destination frame"},
- {GIMP_PDB_FLOAT, "trace_opacity_desc", "descending opacity 0.0 upto 100.0 for fading out older positions (that are done before the actual step)"},
- {GIMP_PDB_INT32, "apply_bluebox", "TRUE: apply blubox filter (using bluebox param VALUES of last successful bluebox run)"},
- {GIMP_PDB_INT32, "src_selmode", "0: ignore selections in all source images\n"
- "1: use one selection (from the inital source image) for all handled src layers \n"
- "2: use selections in all source images (for stepmodes 0-5 there is only one source image)"},
-
-
- /* CONTROLPOINT Arrays (the _ext API uses FLOAT arrays for more precision) */
- { GIMP_PDB_INT32, "argc_p_x", "number of controlpoints"},
- { GIMP_PDB_INT32ARRAY, "p_x", "Controlpoint x-koordinate"},
- { GIMP_PDB_INT32, "argc_p_y", "number of controlpoints"},
- { GIMP_PDB_INT32ARRAY, "p_y", "Controlpoint y-koordinate"},
- { GIMP_PDB_INT32, "argc_opacity", "number of controlpoints"},
- { GIMP_PDB_FLOATARRAY, "opacity", "Controlpoint opacity value 0 <= value <= 100"},
- { GIMP_PDB_INT32, "argc_w_resize", "number of controlpoints"},
- { GIMP_PDB_FLOATARRAY, "w_resize", "width scaling in percent"},
- { GIMP_PDB_INT32, "argc_h_resize", "number of controlpoints"},
- { GIMP_PDB_FLOATARRAY, "h_resize", "height scaling in percent"},
- { GIMP_PDB_INT32, "argc_rotation", "number of controlpoints"},
- { GIMP_PDB_FLOATARRAY, "rotation", "rotation in degrees"},
- { GIMP_PDB_INT32, "argc_keyframe_abs", "number of controlpoints"},
- { GIMP_PDB_INT32ARRAY, "keyframe_abs", "n: fix controlpoint to this frame number, 0: for controlpoints that are not fixed to a frame."},
-
- /* new CONTROLPOINT ARRAY items of the _ext[ended] API */
- { GIMP_PDB_INT32, "argc_ttlx", "number of controlpoints"},
- { GIMP_PDB_FLOATARRAY, "ttlx", "perspective transformfactor for top left X Coordinate (0.0 upto 5.0, value 1.0 does no trasformation)"},
- { GIMP_PDB_INT32, "argc_ttly", "number of controlpoints"},
- { GIMP_PDB_FLOATARRAY, "ttly", "perspective transformfactor for top left Y Coordinate (0.0 upto 5.0, value 1.0 does no trasformation)"},
- { GIMP_PDB_INT32, "argc_ttrx", "number of controlpoints"},
- { GIMP_PDB_FLOATARRAY, "ttrx", "perspective transformfactor for top right X Coordinate (0.0 upto 5.0, value 1.0 does no trasformation)"},
- { GIMP_PDB_INT32, "argc_ttry", "number of controlpoints"},
- { GIMP_PDB_FLOATARRAY, "ttry", "perspective transformfactor for top right Y Coordinate (0.0 upto 5.0, value 1.0 does no trasformation)"},
- { GIMP_PDB_INT32, "argc_tblx", "number of controlpoints"},
- { GIMP_PDB_FLOATARRAY, "tblx", "perspective transformfactor for bottom left X Coordinate (0.0 upto 5.0, value 1.0 does no trasformation)"},
- { GIMP_PDB_INT32, "argc_tbly", "number of controlpoints"},
- { GIMP_PDB_FLOATARRAY, "tbly", "perspective transformfactor for bottom left Y Coordinate (0.0 upto 5.0, value 1.0 does no trasformation)"},
- { GIMP_PDB_INT32, "argc_tbrx", "number of controlpoints"},
- { GIMP_PDB_FLOATARRAY, "tbrx", "perspective transformfactor for bottom right X Coordinate (0.0 upto 5.0, value 1.0 does no trasformation)"},
- { GIMP_PDB_INT32, "argc_tbry", "number of controlpoints"},
- { GIMP_PDB_FLOATARRAY, "tbry", "perspective transformfactor for bottom right Y Coordinate (0.0 upto 5.0, value 1.0 does no trasformation)"},
- { GIMP_PDB_INT32, "argc_sel", "number of controlpoints"},
- { GIMP_PDB_FLOATARRAY, "sel_feather_radius", "feather radius for selections"},
- };
- static int nargs_mov_path_ext = G_N_ELEMENTS (args_mov_path_ext);
-
- static GimpParamDef args_mov_path_ext2[] =
- {
- {GIMP_PDB_INT32, "run_mode", "non-interactive"},
- {GIMP_PDB_IMAGE, "dst_image", "Destination image (one of the video frames), where to insert the animated source layers"},
- {GIMP_PDB_DRAWABLE, "drawable", "drawable (unused)"},
- {GIMP_PDB_INT32, "range_from", "destination frame nr to start"},
- {GIMP_PDB_INT32, "range_to", "destination frame nr to stop (can be lower than range_from)"},
- {GIMP_PDB_INT32, "nr", "layerstack position where to insert source layer (0 == on top)"},
- /* source specs */
- { GIMP_PDB_LAYER, "src_layer_id", "starting LayerID of SourceObject. (use any Multilayeranimated Image, or an video frame of anoter Animation)"},
- { GIMP_PDB_INT32, "src_stepmode", "0-5 derive inserted object as copy of one layer from a multilayer src_image \n"
- "100-105 derive inserted object as copy of merged visible layers of a source video frame \n"
- "0: Layer Loop 1: Layer Loop reverse 2: Layer Once 3: Layer Once reverse 4: Layer PingPong \n"
- "5: None (use onle the selected src_layer)\n"
- "100: Frame Loop 101: Frame Loop reverse 102: Frame Once 103: Frame Once reverse 104: Frame PingPong \n"
- "105: Frame None (use onle the flat copy of the selected frame)\n"
- },
- { GIMP_PDB_INT32, "src_handle", "0: handle left top 1: handle left bottom \n"
- "2: handle right top 3: handle right bottom \n"
- "4: handle center"},
- { GIMP_PDB_INT32, "src_paintmode", "4444: keep original paintmode of src_layer 0: GIMP_NORMAL_MODE (see GimpLayerModeEffects -- libgimp/gimpenums.h -- for more information)"},
- { GIMP_PDB_INT32, "src_force_visible", "1: Set inserted layres visible, 0: insert layers as is"},
- { GIMP_PDB_INT32, "clip_to_img", "1: Clip inserted layers to Image size of the destination video frame, 0: dont clip"},
- /* extras */
- { GIMP_PDB_INT32, "rotation_follow", "0: NO automatic calculation (use the rotation array parameters as it is) \n"
- "1: Automatic calculation of rotation, following the path vectors, (Ignore rotation array parameters)\n"},
- { GIMP_PDB_FLOAT, "startangle", "start angle for the first contolpoint (only used if rotation-follow is on)"},
-
- /* new features of the _ext[ended] API */
- {GIMP_PDB_FLOAT, "step_speed_factor", "Allows stepping Source and Destination at different speed. (0.1 upto 50 where 1.0 does step snychron, 2.0 Src makes 2 Steps while Destination makes 1 step) "},
- {GIMP_PDB_INT32, "tween_steps", "0 upto 50, Number of virtual Frames to calculate between 2 destination Frames. (use value 0 if no tween processing should be done)"},
- {GIMP_PDB_FLOAT, "tween_opacity_initial", "opacity 0.0 upto 100.0 for the tween step that is nearest to the (next) real frame"},
- {GIMP_PDB_FLOAT, "tween_opacity_desc", "descending opacity 0.0 upto 100.0 for the othertween steps"},
- {GIMP_PDB_INT32, "tracelayer_enable", "TRUE: calculate a tracelayer (with all steps of the moving objects since first step)"},
- {GIMP_PDB_FLOAT, "trace_opacity_initial", "opacity 0.0 upto 100.0 for the nearest tracestep to the actual destination frame"},
- {GIMP_PDB_FLOAT, "trace_opacity_desc", "descending opacity 0.0 upto 100.0 for fading out older positions (that are done before the actual step)"},
- {GIMP_PDB_INT32, "apply_bluebox", "TRUE: apply blubox filter (using bluebox param VALUES of last successful bluebox run)"},
-
- /* CONTROLPOINTs from file */
- { GIMP_PDB_STRING, "pointfile", "a file with contolpoints (readable text file with one line per controlpoint)"},
- };
- static int nargs_mov_path_ext2 = G_N_ELEMENTS (args_mov_path_ext2);
-
-
-
static GimpParamDef args_f2multi[] =
{
{GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"},
@@ -807,85 +672,6 @@ query ()
nargs_exchg, nreturn_std,
args_exchg, return_std);
- gimp_install_procedure(PLUGIN_NAME_GAP_MOVE,
- "This plugin copies layer(s) from one sourceimage to multiple frames on disk, varying position, size and opacity.",
- "For NONINTERACTIVE PDB interfaces see also (plug_in_gap_move_path_ext, plug_in_gap_move_path_ext2)",
- "Wolfgang Hofer (hof gimp org)",
- "Wolfgang Hofer",
- GAP_VERSION_WITH_DATE,
- N_("Move Path..."),
- "RGB*, INDEXED*, GRAY*",
- GIMP_PLUGIN,
- G_N_ELEMENTS (args_mov), nreturn_std,
- args_mov, return_std);
-
- l_help_str = g_strdup_printf(
- "This plugin inserts one layer in each frame of the selected frame range of an Animation\n"
- " (specified by the dst_image parameter).\n"
- " An Animation is a series of numbered video frame images on disk where only the current\n"
- " Frame is opened in the gimp\n"
- " The inserted layer is derived from another (multilayer)image\n"
- " or from another Animation (as merged copy of the visible layers in a source frame)\n"
- " the affected destination frame range is selected by the range_from and range_to parameters\n"
- " the src_stepmode parameter controls how to derive the layer that is to be inserted.\n"
- " With the Controlpoint Parameters you can control position (coordinates),\n"
- " size, rotation, perspective and opacity values of the inserted layer\n"
- " If you want to move an Object from position AX/AY to BX/BY in a straight line within the range of 24 frames\n"
- " you need 2 Contolpoints, if you want the object to move following a path\n"
- " you need some more Controlpoints to do that.\n"
- " With the rotation_follow Parameter you can force automatic calculation of the rotation for the inserted\n"
- " layer according to the path vectors it is moving along.\n"
- " A controlpoint can be fixed to a special framenumber using the keyframe_abs controlpoint-parameter.\n"
- " Restrictions:\n"
- " - keyframe_abs numbers must be 0 (== not fixed) or a frame_number within the affected frame range\n"
- " - keyframes_abs must be in sequence (ascending or descending)\n"
- " - the first and last controlpoint are always implicit keyframes, and should be passed with keyframe_abs = 0\n"
- " - the number of controlpoints is limited to a maximum of %d.\n"
- " the number of controlpoints must be passed in all argc_* parameters\n"
- "If the TraceLayer feature is turned on, an additional layer\n"
- " is inserted below the moving object. This Tracelayer shows all steps\n"
- " of the moving object since the 1st Frame.\n"
- "With TweenSteps you can calculate virtual Frames between 2 destination frames\n"
- " all these Steps are collected in another additional Layer.\n"
- " this Tweenlayer is added below the moving Object in all handled destination Frames\n"
- "See also (plug_in_gap_move_path, plug_in_gap_move)",
- (int)GAP_MOV_MAX_POINT);
-
- gimp_install_procedure(PLUGIN_NAME_GAP_MOVE_PATH_EXT,
- "This plugin copies layer(s) from one sourceimage or source animation to multiple frames on disk,\n"
- "with varying position, size, perspective and opacity.\n"
- ,
- l_help_str,
- "Wolfgang Hofer (hof gimp org)",
- "Wolfgang Hofer",
- GAP_VERSION_WITH_DATE,
- NULL, /* do not appear in menus */
- "RGB*, INDEXED*, GRAY*",
- GIMP_PLUGIN,
- nargs_mov_path_ext, nreturn_std,
- args_mov_path_ext, return_std);
- g_free(l_help_str);
-
- gimp_install_procedure(PLUGIN_NAME_GAP_MOVE_PATH_EXT2,
- "This plugin copies layer(s) from one sourceimage or source animation to multiple frames on disk,\n"
- "with varying position, size, perspective and opacity.\n"
- ,
- "This plugin is just another Interface for the MovePath (plug_in_gap_move_path_ext)\n"
- " using a File to specify Controlpoints (rather than Array parameters).\n"
- " Notes:\n"
- " - you can create a controlpoint file with in the MovePath Dialog (interactive call of plug_in_gap_move)\n"
- " - for more infos about controlpoints see help of (plug_in_gap_move_path)\n"
- ,
- "Wolfgang Hofer (hof gimp org)",
- "Wolfgang Hofer",
- GAP_VERSION_WITH_DATE,
- NULL, /* do not appear in menus */
- "RGB*, INDEXED*, GRAY*",
- GIMP_PLUGIN,
- nargs_mov_path_ext2, nreturn_std,
- args_mov_path_ext2, return_std);
-
-
gimp_install_procedure(PLUGIN_NAME_GAP_RANGE_TO_MULTILAYER,
"This plugin creates a new image from the given range of frame-images. Each frame is converted to one layer in the new image, according to flatten_mode. (the frames on disk are not changed).",
@@ -1145,7 +931,6 @@ query ()
gimp_plugin_menu_register (PLUGIN_NAME_GAP_DUP, menupath_image_video);
gimp_plugin_menu_register (PLUGIN_NAME_GAP_DENSITY, menupath_image_video);
gimp_plugin_menu_register (PLUGIN_NAME_GAP_EXCHG, menupath_image_video);
- gimp_plugin_menu_register (PLUGIN_NAME_GAP_MOVE, menupath_image_video);
gimp_plugin_menu_register (PLUGIN_NAME_GAP_RANGE_TO_MULTILAYER, menupath_image_video);
gimp_plugin_menu_register (PLUGIN_NAME_GAP_RANGE_FLATTEN, menupath_image_video);
gimp_plugin_menu_register (PLUGIN_NAME_GAP_RANGE_LAYER_DEL, menupath_image_video);
@@ -1537,166 +1322,6 @@ run (const gchar *name
l_rc_image = gap_base_exchg(run_mode, image_id, nr);
}
}
- else if (strcmp (name, PLUGIN_NAME_GAP_MOVE) == 0)
- {
- GapMovValues *pvals;
-
- pvals = g_new (GapMovValues, 1);
- if (run_mode == GIMP_RUN_NONINTERACTIVE)
- {
- status = GIMP_PDB_CALLING_ERROR;
- }
-
- if (status == GIMP_PDB_SUCCESS)
- {
- l_rc_image = gap_mov_exec_move_path(run_mode, image_id, pvals, NULL, 0, 0);
- }
- g_free(pvals);
- }
- else if ((strcmp (name, PLUGIN_NAME_GAP_MOVE_PATH_EXT) == 0)
- || (strcmp (name, PLUGIN_NAME_GAP_MOVE_PATH_EXT2) == 0))
- {
- GapMovValues *pvals;
- gchar *pointfile;
- gint l_idx;
- gint l_numpoints;
- gint l_rotation_follow;
- gint32 l_startangle;
-
- pointfile = NULL;
- pvals = g_new (GapMovValues, 1);
- l_rotation_follow = 0;
- l_startangle = 0;
-
- pvals->dst_image_id = image_id;
- pvals->tmp_image_id = -1;
- pvals->tmpsel_image_id = -1;
- pvals->tmpsel_channel_id = -1;
- pvals->apv_mode = 0;
- pvals->apv_src_frame = -1;
- pvals->apv_mlayer_image = -1;
- pvals->apv_gap_paste_buff = NULL;
- pvals->apv_framerate = 24;
- pvals->apv_scalex = 100.0;
- pvals->apv_scaley = 100.0;
- pvals->cache_src_image_id = -1;
- pvals->cache_tmp_image_id = -1;
- pvals->cache_tmp_layer_id = -1;
- pvals->cache_frame_number = -1;
- pvals->cache_ainfo_ptr = NULL;
- pvals->point_idx = 0;
- pvals->point_idx_max = 0;
- pvals->src_apply_bluebox = 0;
- pvals->bbp = NULL;
-
- pvals->step_speed_factor = 1.0;
- pvals->tracelayer_enable = FALSE;
- pvals->trace_opacity_initial = 100.0;
- pvals->trace_opacity_desc = 80.0;
- pvals->tween_steps = 0;
- pvals->tween_opacity_initial = 80.0;
- pvals->tween_opacity_desc = 80.0;
-
- if (run_mode == GIMP_RUN_NONINTERACTIVE)
- {
- if ( ((n_params != nargs_mov_path_ext) && (strcmp (name, PLUGIN_NAME_GAP_MOVE_PATH_EXT) == 0))
- || ((n_params != nargs_mov_path_ext2) && (strcmp (name, PLUGIN_NAME_GAP_MOVE_PATH_EXT2) == 0)))
- {
- status = GIMP_PDB_CALLING_ERROR;
- }
- else
- {
- pvals->dst_range_start = param[3].data.d_int32;
- pvals->dst_range_end = param[4].data.d_int32;
- pvals->dst_layerstack = param[5].data.d_int32;
-
- pvals->src_layer_id = param[6].data.d_layer;
- pvals->src_stepmode = param[7].data.d_int32;
- pvals->src_handle = param[8].data.d_int32;
- pvals->src_paintmode = param[9].data.d_int32;
- pvals->src_force_visible = param[10].data.d_int32;
- pvals->clip_to_img = param[11].data.d_int32;
-
- l_rotation_follow = param[12].data.d_int32;
- l_startangle = param[13].data.d_float;
-
- pvals->step_speed_factor = param[14].data.d_float;
- pvals->tween_steps = param[15].data.d_int32;
- pvals->tween_opacity_initial = param[16].data.d_float;
- pvals->tween_opacity_desc = param[17].data.d_float;
- pvals->tracelayer_enable = param[18].data.d_int32;
- pvals->trace_opacity_initial = param[19].data.d_float;
- pvals->trace_opacity_desc = param[20].data.d_float;
- pvals->src_apply_bluebox = param[21].data.d_int32;
- pvals->src_selmode = param[22].data.d_int32;
-
- if (strcmp (name, PLUGIN_NAME_GAP_MOVE_PATH_EXT) == 0)
- {
- /* PLUGIN_NAME_GAP_MOVE_PATH_EXT passes controlpoints as array parameters */
- l_numpoints = param[23].data.d_int32;
- if ((l_numpoints != param[25].data.d_int32)
- || (l_numpoints != param[27].data.d_int32)
- || (l_numpoints != param[29].data.d_int32)
- || (l_numpoints != param[31].data.d_int32)
- || (l_numpoints != param[33].data.d_int32)
- || (l_numpoints != param[35].data.d_int32)
- || (l_numpoints != param[37].data.d_int32)
- || (l_numpoints != param[39].data.d_int32)
- || (l_numpoints != param[41].data.d_int32)
- || (l_numpoints != param[43].data.d_int32)
- || (l_numpoints != param[45].data.d_int32)
- || (l_numpoints != param[47].data.d_int32)
- || (l_numpoints != param[49].data.d_int32)
- || (l_numpoints != param[51].data.d_int32)
- || (l_numpoints != param[53].data.d_int32))
- {
- printf("plug_in_gap_move_path_ext: CallingError: different numbers in the controlpoint array argc parameters\n");
- status = GIMP_PDB_CALLING_ERROR;
- }
- else
- {
- pvals->point_idx_max = l_numpoints -1;
- for(l_idx = 0; l_idx < l_numpoints; l_idx++)
- {
- pvals->point[l_idx].p_x = param[24].data.d_int32array[l_idx];
- pvals->point[l_idx].p_y = param[26].data.d_int32array[l_idx];
- pvals->point[l_idx].opacity = param[28].data.d_floatarray[l_idx];
- pvals->point[l_idx].w_resize = param[30].data.d_floatarray[l_idx];
- pvals->point[l_idx].h_resize = param[32].data.d_floatarray[l_idx];
- pvals->point[l_idx].rotation = param[34].data.d_floatarray[l_idx];
- pvals->point[l_idx].keyframe_abs = param[36].data.d_int32array[l_idx];
- /* pvals->point[l_idx].keyframe = ; */ /* relative keyframes are calculated later */
- pvals->point[l_idx].ttlx = param[38].data.d_floatarray[l_idx];
- pvals->point[l_idx].ttly = param[40].data.d_floatarray[l_idx];
- pvals->point[l_idx].ttrx = param[42].data.d_floatarray[l_idx];
- pvals->point[l_idx].ttry = param[44].data.d_floatarray[l_idx];
- pvals->point[l_idx].tblx = param[46].data.d_floatarray[l_idx];
- pvals->point[l_idx].tbly = param[48].data.d_floatarray[l_idx];
- pvals->point[l_idx].tbrx = param[50].data.d_floatarray[l_idx];
- pvals->point[l_idx].tbry = param[52].data.d_floatarray[l_idx];
- pvals->point[l_idx].sel_feather_radius = param[54].data.d_floatarray[l_idx];
- }
- }
- }
- else
- {
- /* PLUGIN_NAME_GAP_MOVE_PATH_EXT2 operates with controlpoint file */
- if(param[23].data.d_string != NULL)
- {
- pointfile = g_strdup(param[23].data.d_string);
- }
- }
- }
-
- }
-
- if (status == GIMP_PDB_SUCCESS)
- {
- l_rc_image = gap_mov_exec_move_path(run_mode, image_id, pvals, pointfile, l_rotation_follow, (gdouble)l_startangle);
- }
- g_free(pvals);
- if(pointfile != NULL) g_free(pointfile);
- }
else if (strcmp (name, PLUGIN_NAME_GAP_RANGE_TO_MULTILAYER) == 0)
{
*nreturn_vals = nreturn_f2multi + 1;
diff --git a/gap/gap_mov_dialog.c b/gap/gap_mov_dialog.c
index 035fd44..d674249 100644
--- a/gap/gap_mov_dialog.c
+++ b/gap/gap_mov_dialog.c
@@ -118,6 +118,7 @@
#include "gap_lib.h"
#include "gap_image.h"
#include "gap_mov_exec.h"
+#include "gap_mov_xml_par.h"
#include "gap_mov_dialog.h"
#include "gap_mov_render.h"
#include "gap_pdb_calls.h"
@@ -205,7 +206,20 @@ typedef struct
GtkAdjustment *keyframe_adj;
GtkAdjustment *preview_frame_nr_adj;
+ GimpColorButton *bluebox_keycolor_color_button;
+ GtkAdjustment *dst_range_start_adj;
+ GtkAdjustment *dst_range_end_adj;
+ GtkAdjustment *dst_layerstack_adj;
+ GtkWidget *src_force_visible_check_button;
+ GtkWidget *clip_to_img_check_button;
+ GtkWidget *tracelayer_enable_check_button;
+ GtkWidget *src_apply_bluebox_check_button;
+ GtkWidget *paintmode_combo;
+ GtkWidget *stepmode_combo;
+ GtkWidget *handlemode_combo;
+ GtkWidget *src_selmode_combo;
GtkWidget *src_layer_combo;
+
GtkWidget *constrain; /* scale width/height keeps ratio constant */
GtkAdjustment *ttlx_adj;
GtkAdjustment *ttly_adj;
@@ -222,7 +236,7 @@ typedef struct
GtkAdjustment *trace_opacity_initial_adj;
GtkAdjustment *trace_opacity_desc_adj;
GtkAdjustment *tween_steps_adj;
-
+
GtkAdjustment *accPosition_adj;
GtkAdjustment *accOpacity_adj;
GtkAdjustment *accSize_adj;
@@ -276,12 +290,12 @@ typedef struct
GdkCursor *cursor_wait;
GdkCursor *cursor_acitve;
GimpRGB pathcolor;
-
-
+
+
GtkWidget *segNumberLabel;
GtkWidget *segLengthLabel;
GtkWidget *segSpeedLabel;
-
+
} t_mov_gui_stuff;
@@ -299,6 +313,7 @@ static void p_pick_nearest_point (gint px, gint py);
static void p_reset_points ();
static void p_clear_one_point (gint idx);
static void p_mix_one_point(gint idx, gint ref1, gint ref2, gdouble mix_factor);
+static void p_refresh_widgets_after_load(t_mov_gui_stuff *mgp);
static void p_load_points (char *filename);
static void p_save_points (char *filename, t_mov_gui_stuff *mgp);
@@ -511,7 +526,22 @@ long gap_mov_dlg_move_dialog (GapMovData *mov_ptr)
mgp->segNumberLabel = NULL;
mgp->segLengthLabel = NULL;
mgp->segSpeedLabel = NULL;
-
+
+ mgp->dst_range_start_adj = NULL;
+ mgp->dst_range_end_adj = NULL;
+ mgp->dst_layerstack_adj = NULL;
+ mgp->src_force_visible_check_button = NULL;
+ mgp->clip_to_img_check_button = NULL;
+ mgp->tracelayer_enable_check_button = NULL;
+ mgp->src_apply_bluebox_check_button = NULL;
+ mgp->bluebox_keycolor_color_button = NULL;
+ mgp->paintmode_combo = NULL;
+ mgp->stepmode_combo = NULL;
+ mgp->handlemode_combo = NULL;
+ mgp->src_selmode_combo = NULL;
+ mgp->src_layer_combo = NULL;
+
+
pvals = mov_ptr->val_ptr;
l_str = gap_base_strdup_del_underscore(mov_ptr->dst_ainfo_ptr->basename);
@@ -1285,7 +1315,7 @@ mov_grab_bezier_path(t_mov_gui_stuff *mgp, gint32 vectors_id, gint32 stroke_id,
gdouble slope;
gboolean valid;
gboolean success;
-
+
success = gimp_vectors_stroke_get_point_at_dist(vectors_id
, stroke_id
@@ -1383,7 +1413,7 @@ mov_grab_anchorpoints_path(t_mov_gui_stuff *mgp,
*/
switch (l_ti)
{
- case GAP_BEZIER_ANCHOR_X_INDEX: point_x = (gint)points_details[l_ii]; break;
+ case GAP_BEZIER_ANCHOR_X_INDEX: point_x = (gint)points_details[l_ii]; break;
case GAP_BEZIER_ANCHOR_Y_INDEX: point_y = (gint)points_details[l_ii]; break;
default: break;
}
@@ -1464,7 +1494,7 @@ mov_pgrab_callback (GtkWidget *widget,
{
printf("vectorname :%s\n", vectorname);
}
-
+
stroke_ids = gimp_vectors_get_strokes(vectors_id, &num_stroke_ids);
if(gap_debug)
@@ -1473,7 +1503,7 @@ mov_pgrab_callback (GtkWidget *widget,
, (int)num_stroke_ids
);
}
-
+
if (num_stroke_ids < 1)
{
g_message(_("No stroke ids found in path:\n"
@@ -1576,7 +1606,7 @@ mov_pgrab_callback (GtkWidget *widget,
* mov_upd_seg_labels
* --------------------------------
* update information about max speed and path segment length
- *
+ *
*/
static void
mov_upd_seg_labels(GtkWidget *widget, t_mov_gui_stuff *mgp)
@@ -1594,7 +1624,7 @@ mov_upd_seg_labels(GtkWidget *widget, t_mov_gui_stuff *mgp)
{
GapMovQuery mov_query;
char *numString;
-
+
mov_query.pointIndexToQuery = pvals->point_idx;
if(gap_debug)
@@ -1604,10 +1634,10 @@ mov_upd_seg_labels(GtkWidget *widget, t_mov_gui_stuff *mgp)
, (int)pvals->dst_range_end
);
}
-
+
/* query path segment length and max speed per frame values */
gap_mov_exec_query(pvals, mgp->ainfo_ptr, &mov_query);
-
+
numString = g_strdup_printf("%d"
, (int)mov_query.segmentNumber
);
@@ -1619,15 +1649,15 @@ mov_upd_seg_labels(GtkWidget *widget, t_mov_gui_stuff *mgp)
);
gtk_label_set_text( GTK_LABEL(mgp->segLengthLabel), numString);
g_free(numString);
-
-
+
+
numString = g_strdup_printf("%.1f / %.1f"
, (float)mov_query.minSpeedInPixelsPerFrame
, (float)mov_query.maxSpeedInPixelsPerFrame
);
gtk_label_set_text( GTK_LABEL(mgp->segSpeedLabel), numString);
g_free(numString);
-
+
}
}
}
@@ -2041,7 +2071,130 @@ mov_psave_callback (GtkWidget *widget,
mgp);
}
+/* --------------------------------
+ * p_refresh_widgets_after_load
+ * --------------------------------
+ * refresh widgets according to the new values
+ * after loading settings from an xml parameter file.
+ * This includes all widgets representing controlpoint data
+ * and other render relevant parameter data loaded from the xml file.
+ * except:
+ * - the src_layer (the moving object)
+ * (the layer id of the object saved to the parameter file
+ * may no longer exist at load time)
+ *
+ * Note that not render relvant widgets are not
+ * included in the xml paramter file and are not refreshed here.
+ */
+static void
+p_refresh_widgets_after_load(t_mov_gui_stuff *mgp)
+{
+ if(mgp == NULL)
+ {
+ return;
+ }
+
+ p_point_refresh(mgp);
+
+ if(mgp->paintmode_combo != NULL)
+ {
+ gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (mgp->paintmode_combo), pvals->src_paintmode);
+ }
+ if (mgp->stepmode_combo != NULL)
+ {
+ gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (mgp->stepmode_combo), pvals->src_stepmode);
+ }
+ if (mgp->handlemode_combo != NULL)
+ {
+ gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (mgp->handlemode_combo), pvals->src_handle);
+ }
+ if (mgp->src_selmode_combo != NULL)
+ {
+ gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (mgp->src_selmode_combo), pvals->src_selmode);
+ }
+
+ if(mgp->step_speed_factor_adj != NULL)
+ {
+ gtk_adjustment_set_value(mgp->step_speed_factor_adj, pvals->step_speed_factor);
+ }
+
+
+ if(mgp->dst_range_start_adj != NULL)
+ {
+ gtk_adjustment_set_value(mgp->dst_range_start_adj, pvals->dst_range_start);
+ }
+ if(mgp->dst_range_end_adj != NULL)
+ {
+ gtk_adjustment_set_value(mgp->dst_range_end_adj, pvals->dst_range_end);
+ }
+ if(mgp->dst_layerstack_adj != NULL)
+ {
+ gtk_adjustment_set_value(mgp->dst_layerstack_adj, pvals->dst_layerstack);
+ }
+
+
+ if(mgp->tween_steps_adj != NULL)
+ {
+ gtk_adjustment_set_value(mgp->tween_steps_adj, pvals->tween_steps);
+ }
+ if(mgp->tween_opacity_initial_adj != NULL)
+ {
+ gtk_adjustment_set_value(mgp->tween_opacity_initial_adj, pvals->tween_opacity_initial);
+ }
+ if(mgp->tween_opacity_desc_adj != NULL)
+ {
+ gtk_adjustment_set_value(mgp->tween_opacity_desc_adj, pvals->tween_opacity_desc);
+ }
+ if(mgp->trace_opacity_initial_adj != NULL)
+ {
+ gtk_adjustment_set_value(mgp->trace_opacity_initial_adj, pvals->trace_opacity_initial);
+ }
+ if(mgp->trace_opacity_desc_adj != NULL)
+ {
+ gtk_adjustment_set_value(mgp->trace_opacity_desc_adj, pvals->trace_opacity_desc);
+ }
+
+ if(mgp->tracelayer_enable_check_button != NULL)
+ {
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mgp->tracelayer_enable_check_button),
+ pvals->tracelayer_enable);
+ }
+
+ if (mgp->src_force_visible_check_button != NULL)
+ {
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mgp->src_force_visible_check_button),
+ pvals->src_force_visible);
+ }
+
+ if (mgp->clip_to_img_check_button != NULL)
+ {
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mgp->clip_to_img_check_button),
+ pvals->clip_to_img);
+ }
+
+ if (mgp->src_apply_bluebox_check_button != NULL)
+ {
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mgp->src_apply_bluebox_check_button),
+ pvals->src_apply_bluebox);
+ }
+
+ if (mgp->bluebox_keycolor_color_button != NULL)
+ {
+ if(pvals->bbp != NULL)
+ {
+ gimp_color_button_set_color(mgp->bluebox_keycolor_color_button, &pvals->bbp->vals.keycolor);
+ }
+ }
+
+} /* end p_refresh_widgets_after_load */
+
+
+/* ---------------------------------
+ * p_points_load_from_file
+ * ---------------------------------
+ *
+ */
static void
p_points_load_from_file (GtkWidget *widget,
t_mov_gui_stuff *mgp)
@@ -2064,11 +2217,15 @@ p_points_load_from_file (GtkWidget *widget,
mgp->filesel = NULL;
p_load_points(mgp->pointfile_name);
- p_point_refresh(mgp);
+ p_refresh_widgets_after_load(mgp);
mov_set_instant_apply_request(mgp);
} /* end p_points_load_from_file */
-
+/* ---------------------------------
+ * p_points_save_to_file
+ * ---------------------------------
+ *
+ */
static void
p_points_save_to_file (GtkWidget *widget,
t_mov_gui_stuff *mgp)
@@ -2163,7 +2320,7 @@ p_point_refresh(t_mov_gui_stuff *mgp)
(gdouble)mgp->accSelFeatherRadius);
mov_upd_seg_labels(NULL, mgp);
-
+
mgp->in_call = FALSE;
} /* end p_point_refresh */
@@ -2611,7 +2768,7 @@ p_set_sensitivity_by_adjustment(GtkAdjustment *adj, gboolean sensitive)
{
GtkWidget *spinbutton;
GtkWidget *scale;
-
+
spinbutton = GTK_WIDGET(g_object_get_data (G_OBJECT (adj), "spinbutton"));
if(spinbutton)
{
@@ -2629,7 +2786,7 @@ p_set_sensitivity_by_adjustment(GtkAdjustment *adj, gboolean sensitive)
/* ----------------------------------
* p_accel_widget_sensitivity
* ----------------------------------
- * set sensitivity for all acceleration characteristic widgets
+ * set sensitivity for all acceleration characteristic widgets
* Those widgets are sensitive for the first conrolpoint
* and for keframes that are NOT the last controlpoint.
*/
@@ -2637,15 +2794,15 @@ static void
p_accel_widget_sensitivity(t_mov_gui_stuff *mgp)
{
gboolean sensitive;
-
+
sensitive = FALSE;
- if(pvals->point_idx == 0)
+ if(pvals->point_idx == 0)
{
sensitive = TRUE;
}
else
{
- if ((pvals->point_idx != pvals->point_idx_max)
+ if ((pvals->point_idx != pvals->point_idx_max)
&& ((pvals->point[pvals->point_idx].keyframe > 0) || (mgp->keyframe_abs > 0)))
{
sensitive = TRUE;
@@ -2700,16 +2857,16 @@ p_points_from_tab(t_mov_gui_stuff *mgp)
if(( mgp->keyframe_adj != NULL) && (mgp->startup != TRUE))
{
gboolean sensitive;
-
+
sensitive = TRUE;
if((pvals->point_idx == 0) || (pvals->point_idx == pvals->point_idx_max))
{
sensitive = FALSE;
}
p_set_sensitivity_by_adjustment(mgp->keyframe_adj, sensitive);
-
+
p_accel_widget_sensitivity(mgp);
-
+
}
}
@@ -2734,7 +2891,7 @@ p_points_to_tab(t_mov_gui_stuff *mgp)
pvals->point[pvals->point_idx].tbry = mgp->tbry;
pvals->point[pvals->point_idx].sel_feather_radius = mgp->sel_feather_radius;
pvals->point[pvals->point_idx].keyframe_abs = mgp->keyframe_abs;
-
+
pvals->point[pvals->point_idx].accPosition = mgp->accPosition;
pvals->point[pvals->point_idx].accOpacity = mgp->accOpacity;
pvals->point[pvals->point_idx].accSize = mgp->accSize;
@@ -2795,7 +2952,7 @@ p_clear_one_point(gint idx)
pvals->point[idx].sel_feather_radius = 0.0;
pvals->point[idx].keyframe = 0; /* 0: controlpoint is not fixed to keyframe */
pvals->point[idx].keyframe_abs = 0; /* 0: controlpoint is not fixed to keyframe */
-
+
pvals->point[idx].accPosition = 0; /* 0: linear (e.g NO acceleration) is default */
pvals->point[idx].accOpacity = 0; /* 0: linear (e.g NO acceleration) is default */
pvals->point[idx].accSize = 0; /* 0: linear (e.g NO acceleration) is default */
@@ -2872,19 +3029,92 @@ void p_reset_points()
pvals->point[0].p_y = 0;
} /* end p_reset_points */
-/* ============================================================================
+/* ---------------------------------
+ * p_filename_ends_with_etension_xml
+ * ---------------------------------
+ */
+static gboolean
+p_filename_ends_with_etension_xml(const char *filename)
+{
+ int l_len;
+ gboolean l_xml;
+
+ l_xml = FALSE;
+ l_len = strlen(filename);
+ if(l_len >= 3)
+ {
+ const char *l_extension;
+ l_extension = &filename[l_len -3];
+ if (strcmp("xml", l_extension) == 0)
+ {
+ l_xml = TRUE;
+ }
+ if (strcmp("XML", l_extension) == 0)
+ {
+ l_xml = TRUE;
+ }
+ }
+
+ return(l_xml);
+
+}
+
+/* -----------------------------
* p_load_points
+ * -----------------------------
+ * supports pointfile format(s) of older gimp-gap releases that
+ * only contains the path controlpoints table
+ * and also loads from the newer move path parameterfile in xml format
+ * that can contain all parameter settings.
+ *
+ * old pointfile:
* load point table (from named file into global pvals)
* (reset points if load failed)
+ * new xml file:
+ * load all settings into global pvals including the point table.
+ * Note that the xml load affects all settings (except the src_layer_id that represents
+ * the moving object)
+ * in case some settings (such as perspective settings, bluebox settings ...)
+ * are not present in the xml file
+ * the missing settings are replaced by default values.
* ============================================================================
*/
-
void
p_load_points(char *filename)
{
gint l_rc;
gint l_errno;
+ if (p_filename_ends_with_etension_xml(filename))
+ {
+ gboolean l_xmlOk;
+
+ l_xmlOk = gap_mov_xml_par_load(filename, pvals
+ ,gimp_image_width(pvals->dst_image_id)
+ ,gimp_image_height(pvals->dst_image_id)
+ );
+ if (!l_xmlOk)
+ {
+
+ if(l_errno != 0)
+ {
+ g_message(_("ERROR: Could not open xml parameterfile\n"
+ "filename: '%s'\n%s")
+ ,filename, g_strerror (l_errno));
+ }
+ else
+ {
+ g_message(_("ERROR: Could not read parameterfile\n"
+ "filename: '%s'\n(Is not a valid move path xml parameterfile file)")
+ ,filename);
+ }
+
+
+ }
+
+ return;
+ }
+
l_rc = gap_mov_exec_gap_load_pointfile(filename, pvals);
l_errno = errno;
@@ -2909,10 +3139,14 @@ p_load_points(char *filename)
}
} /* end p_load_points */
-/* ============================================================================
+
+
+/* ----------------------------
* p_save_points
+ * ----------------------------
+ * depending on the filename extension (.xml)
* save point table (from global pvals into named file)
- * ============================================================================
+ *
*/
static void
p_save_points(char *filename, t_mov_gui_stuff *mgp)
@@ -2928,7 +3162,14 @@ p_save_points(char *filename, t_mov_gui_stuff *mgp)
if(l_wr_permission)
{
- l_rc = gap_mov_exec_gap_save_pointfile(filename, pvals);
+ if (p_filename_ends_with_etension_xml(filename))
+ {
+ l_rc = gap_mov_xml_par_save(filename, pvals);
+ }
+ else
+ {
+ l_rc = gap_mov_exec_gap_save_pointfile(filename, pvals);
+ }
l_errno = errno;
if(l_rc != 0)
@@ -3005,29 +3246,31 @@ mov_src_sel_create(t_mov_gui_stuff *mgp)
gtk_table_attach(GTK_TABLE(table), label, 2, 3, 0, 1, GTK_FILL, 0, 4, 0);
gtk_widget_show(label);
- combo = gimp_int_combo_box_new (_("Normal"), GIMP_NORMAL_MODE,
- _("Dissolve"), GIMP_DISSOLVE_MODE,
- _("Multiply"), GIMP_MULTIPLY_MODE,
- _("Divide"), GIMP_DIVIDE_MODE,
- _("Screen"), GIMP_SCREEN_MODE,
- _("Overlay"), GIMP_OVERLAY_MODE,
- _("Dodge"), GIMP_DODGE_MODE,
- _("Burn"), GIMP_BURN_MODE,
- _("Hard Light"), GIMP_HARDLIGHT_MODE,
- _("Soft Light"), GIMP_SOFTLIGHT_MODE,
- _("Grain Extract"), GIMP_GRAIN_EXTRACT_MODE,
- _("Grain Merge"), GIMP_GRAIN_MERGE_MODE,
- _("Difference"), GIMP_DIFFERENCE_MODE,
- _("Addition"), GIMP_ADDITION_MODE,
- _("Subtract"), GIMP_SUBTRACT_MODE,
- _("Darken Only"), GIMP_DARKEN_ONLY_MODE,
- _("Lighten Only"), GIMP_LIGHTEN_ONLY_MODE,
- _("Hue"), GIMP_HUE_MODE,
- _("Saturation"), GIMP_SATURATION_MODE,
- _("Color"), GIMP_COLOR_MODE,
- _("Value"), GIMP_VALUE_MODE,
- _("Keep Paintmode"), GAP_MOV_KEEP_SRC_PAINTMODE,
- NULL);
+ combo = gimp_int_combo_box_new (_("Normal"), GIMP_NORMAL_MODE,
+ _("Dissolve"), GIMP_DISSOLVE_MODE,
+ _("Behind"), GIMP_BEHIND_MODE,
+ _("Multiply"), GIMP_MULTIPLY_MODE,
+ _("Divide"), GIMP_DIVIDE_MODE,
+ _("Screen"), GIMP_SCREEN_MODE,
+ _("Overlay"), GIMP_OVERLAY_MODE,
+ _("Dodge"), GIMP_DODGE_MODE,
+ _("Burn"), GIMP_BURN_MODE,
+ _("Hard Light"), GIMP_HARDLIGHT_MODE,
+ _("Soft Light"), GIMP_SOFTLIGHT_MODE,
+ _("Grain Extract"), GIMP_GRAIN_EXTRACT_MODE,
+ _("Grain Merge"), GIMP_GRAIN_MERGE_MODE,
+ _("Difference"), GIMP_DIFFERENCE_MODE,
+ _("Addition"), GIMP_ADDITION_MODE,
+ _("Subtract"), GIMP_SUBTRACT_MODE,
+ _("Darken Only"), GIMP_DARKEN_ONLY_MODE,
+ _("Lighten Only"), GIMP_LIGHTEN_ONLY_MODE,
+ _("Hue"), GIMP_HUE_MODE,
+ _("Saturation"), GIMP_SATURATION_MODE,
+ _("Color"), GIMP_COLOR_MODE,
+ _("Color Erase"), GIMP_COLOR_ERASE_MODE,
+ _("Value"), GIMP_VALUE_MODE,
+ _("Keep Paintmode"), GAP_MOV_KEEP_SRC_PAINTMODE,
+ NULL);
gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (combo),
GIMP_NORMAL_MODE, /* initial int value */
@@ -3039,6 +3282,7 @@ mov_src_sel_create(t_mov_gui_stuff *mgp)
_("Paintmode")
, NULL);
gtk_widget_show(combo);
+ mgp->paintmode_combo = combo;
@@ -3108,6 +3352,7 @@ mov_src_sel_create(t_mov_gui_stuff *mgp)
_("How to fetch the next source layer at the next handled frame")
, NULL);
gtk_widget_show(combo);
+ mgp->stepmode_combo = combo;
/* Source Image Handle menu */
@@ -3136,6 +3381,7 @@ mov_src_sel_create(t_mov_gui_stuff *mgp)
_("How to place the Source layer at controlpoint coordinates")
, NULL);
gtk_widget_show(combo);
+ mgp->handlemode_combo = combo;
gtk_widget_show( table );
@@ -3182,6 +3428,7 @@ mov_advanced_tab_create(t_mov_gui_stuff *mgp)
/* toggle bluebox */
check_button = gtk_check_button_new_with_label ( _("Bluebox"));
+ mgp->src_apply_bluebox_check_button = check_button;
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button),
pvals->src_apply_bluebox);
gimp_help_set_help_data(check_button,
@@ -3213,6 +3460,7 @@ mov_advanced_tab_create(t_mov_gui_stuff *mgp)
25, 12, /* WIDTH, HEIGHT, */
&pvals->bbp_pv->vals.keycolor,
GIMP_COLOR_AREA_FLAT);
+ mgp->bluebox_keycolor_color_button = (GimpColorButton *)color_button;
/* dont know if it is possible to remove the signal handler for the "clicked" signal
* on the gimp_color_button.
@@ -3244,6 +3492,7 @@ mov_advanced_tab_create(t_mov_gui_stuff *mgp)
/* toggle Tracelayer */
check_button = gtk_check_button_new_with_label ( _("Tracelayer"));
+ mgp->tracelayer_enable_check_button = check_button;
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button),
pvals->tracelayer_enable);
gimp_help_set_help_data(check_button,
@@ -3653,7 +3902,8 @@ mov_path_framerange_box_create(t_mov_gui_stuff *mgp
{
GtkWidget *master_table;
GtkWidget *table;
- GtkObject *adj;
+ //GtkObject *adj;
+ GtkAdjustment *adj;
GtkWidget *check_button;
gint master_rows;
gint master_cols;
@@ -3711,6 +3961,7 @@ mov_path_framerange_box_create(t_mov_gui_stuff *mgp
g_signal_connect (adj, "value-changed",
G_CALLBACK (mov_upd_seg_labels),
mgp);
+ mgp->dst_range_start_adj = adj;
/* the end frame scale_entry */
adj = gimp_scale_entry_new( GTK_TABLE (table), 0, 1, /* table col, row */
@@ -3732,6 +3983,7 @@ mov_path_framerange_box_create(t_mov_gui_stuff *mgp
g_signal_connect (adj, "value-changed",
G_CALLBACK (mov_upd_seg_labels),
mgp);
+ mgp->dst_range_end_adj = adj;
/* the Layerstack scale_entry */
adj = gimp_scale_entry_new( GTK_TABLE (table), 0, 2, /* table col, row */
@@ -3751,6 +4003,7 @@ mov_path_framerange_box_create(t_mov_gui_stuff *mgp
g_signal_connect (G_OBJECT (adj), "value_changed",
G_CALLBACK (mov_instant_int_adjustment_update),
&pvals->dst_layerstack);
+ mgp->dst_layerstack_adj = adj;
/* the table for checkbuttons and info labels */
table = gtk_table_new (3, 3, FALSE);
@@ -3772,7 +4025,7 @@ mov_path_framerange_box_create(t_mov_gui_stuff *mgp
&pvals->src_force_visible);
gtk_table_attach(GTK_TABLE(table), check_button, 0, 1, row, row+1
, GTK_FILL, GTK_FILL, 4, 0);
-
+ mgp->src_force_visible_check_button = check_button;
row = 1;
@@ -3789,8 +4042,7 @@ mov_path_framerange_box_create(t_mov_gui_stuff *mgp
&pvals->clip_to_img);
gtk_table_attach(GTK_TABLE(table), check_button, 0, 1, row, row+1
, GTK_FILL, GTK_FILL, 4, 0);
-
-
+ mgp->clip_to_img_check_button = check_button;
@@ -4299,6 +4551,7 @@ mov_selection_handling_tab_create (t_mov_gui_stuff *mgp)
_("How to handle selections in the source image")
, NULL);
gtk_widget_show(combo);
+ mgp->src_selmode_combo = combo;
/* Feather Radius */
adj = gimp_scale_entry_new( GTK_TABLE (table), 0, 1, /* table col, row */
@@ -4339,8 +4592,10 @@ mov_selection_handling_tab_create (t_mov_gui_stuff *mgp)
* - 2 spinbuttons X/Y, used for positioning
* - Keyframe spinbutton integer (0 to max_frame)
* - Notebook with following sub tables:
- * - transform SubTable 4-point perspective transformation
- * - modify SubTable for Resize(Scaling), Opacity and Rotation
+ * - transform SubTable 4-point perspective transformation
+ * - modify SubTable for Resize(Scaling), Opacity and Rotation
+ * - selection SubTable for selection handling (mode and feather radius)
+ * - acceleration SubTable for acceleration characteristics
* ============================================================================
*/
static void
@@ -4470,7 +4725,7 @@ mov_path_prevw_create ( GimpDrawable *drawable, t_mov_gui_stuff *mgp, gboolean v
/* set of perspective transformation widgets for the current controlpoint */
transform_table = mov_trans_tab_create(mgp);
-
+
/* set of acceleration characteristic widgets for the current controlpoint */
acceleration_table = mov_acc_tab_create(mgp);
@@ -4602,14 +4857,14 @@ mov_path_prevw_create ( GimpDrawable *drawable, t_mov_gui_stuff *mgp, gboolean v
}
- /* segmnt information labels */
+ /* segment information labels (to show min/max speed in pixels per frame) */
{
GtkWidget *label;
GtkWidget *seg_table;
gint seg_row;
-
+
seg_row = 0;
-
+
/* the preview sub table (1 row) */
seg_table = gtk_table_new ( 1, 6, FALSE );
gtk_widget_show (seg_table);
@@ -4619,22 +4874,22 @@ mov_path_prevw_create ( GimpDrawable *drawable, t_mov_gui_stuff *mgp, gboolean v
gtk_widget_show (label);
gtk_table_attach(GTK_TABLE(seg_table), label, 0, 1, seg_row, seg_row+1
, GTK_FILL, GTK_FILL, 4, 0);
-
+
label = gtk_label_new("0");
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
gtk_widget_show (label);
mgp->segNumberLabel = label;
gtk_table_attach(GTK_TABLE(seg_table), label, 1, 2, seg_row, seg_row+1
, GTK_FILL, GTK_FILL, 4, 0);
-
+
label = gtk_label_new(_("Length:"));
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
gtk_widget_show (label);
gtk_table_attach(GTK_TABLE(seg_table), label, 2, 3, seg_row, seg_row+1
, GTK_FILL, GTK_FILL, 4, 0);
-
-
+
+
label = gtk_label_new("0.0");
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
gtk_widget_show (label);
@@ -4658,7 +4913,7 @@ mov_path_prevw_create ( GimpDrawable *drawable, t_mov_gui_stuff *mgp, gboolean v
gtk_table_attach(GTK_TABLE(pv_table), seg_table, 0, 1, 1, 2,
GTK_FILL|GTK_EXPAND, 0, 0, 0);
-
+
}
@@ -5569,6 +5824,7 @@ p_get_prevw_drawable (t_mov_gui_stuff *mgp)
GapMovCurrent l_curr;
gint l_nlayers;
+ l_curr.isSingleFrame = FALSE;
/* check if we have a source layer (to add to the preview) */
if((pvals->src_layer_id >= 0) && (pvals->src_image_id >= 0))
@@ -5801,7 +6057,7 @@ p_mov_acc_spinbutton_new(GtkTable *table
GtkObject *adj;
GapAccelWidget *accel_wgt;
gint32 accelerationCharacteristic;
-
+
#define ACC_WGT_WIDTH 28
#define ACC_WGT_HEIGHT 26
@@ -6008,3 +6264,66 @@ mov_pview_size_allocate_callback(GtkWidget *widget
}
} /* end mov_pview_size_allocate_callback */
+
+
+
+/* -----------------------------------
+ * gap_mov_dlg_move_dialog_singleframe
+ * -----------------------------------
+ * return 0 : OK, got params from the dialog
+ * -1: user has cancelled the dialog
+ */
+gint
+gap_mov_dlg_move_dialog_singleframe(GapMovSingleFrame *singleFramePtr)
+{
+ static GapArrArg argv[3];
+ gint l_ii;
+ gint l_ii_frame_phase;
+ gint l_ii_total_frames;
+
+ l_ii = 0;
+ gap_arr_arg_init(&argv[l_ii], GAP_ARR_WGT_FILESEL);
+ argv[l_ii].label_txt = _("MovePath xmlfile:");
+ argv[l_ii].entry_width = 400;
+ argv[l_ii].help_txt = _("Name of the file containing move path paramters and controlpoints in XML format");
+ argv[l_ii].text_buf_len = sizeof(singleFramePtr->xml_paramfile);
+ argv[l_ii].text_buf_ret = singleFramePtr->xml_paramfile;
+
+ l_ii++;
+ l_ii_total_frames = l_ii;
+ gap_arr_arg_init(&argv[l_ii], GAP_ARR_WGT_INT_PAIR);
+ argv[l_ii].constraint = TRUE;
+ argv[l_ii].label_txt = _("Total Frames:");
+ argv[l_ii].help_txt = _("Total number of frames");
+ argv[l_ii].int_min = (gint)1;
+ argv[l_ii].int_max = (gint)MAX(10000, singleFramePtr->total_frames);
+ argv[l_ii].int_ret = (gint)singleFramePtr->total_frames;
+ argv[l_ii].has_default = TRUE;
+ argv[l_ii].int_default = (gint)50;
+
+ l_ii++;
+ l_ii_frame_phase = l_ii;
+ gap_arr_arg_init(&argv[l_ii], GAP_ARR_WGT_INT_PAIR);
+ argv[l_ii].constraint = TRUE;
+ argv[l_ii].label_txt = _("Current Frame:");
+ argv[l_ii].help_txt = _("Curent Frame number (e.g. phase to be phase Total number of frames");
+ argv[l_ii].int_min = (gint)1;
+ argv[l_ii].int_max = (gint)MAX(10000, singleFramePtr->total_frames);
+ argv[l_ii].int_ret = (gint)CLAMP(singleFramePtr->frame_phase, 1, argv[l_ii].int_max);
+ argv[l_ii].has_default = TRUE;
+ argv[l_ii].int_default = argv[l_ii].int_ret;
+
+
+ if(TRUE == gap_arr_ok_cancel_dialog( _("Copy Audiofile as Wavefile"),
+ _("Settings"),
+ G_N_ELEMENTS(argv), argv))
+ {
+ singleFramePtr->total_frames = (gint32)(argv[l_ii_total_frames].int_ret);
+ singleFramePtr->frame_phase = (gint32)(argv[l_ii_frame_phase].int_ret);
+
+ return (0); /* OK */
+ }
+
+ return (-1); /* dialog cancelled */
+
+} /* end gap_mov_dlg_move_dialog_singleframe */
diff --git a/gap/gap_mov_dialog.h b/gap/gap_mov_dialog.h
index 6c996eb..7b73e2b 100644
--- a/gap/gap_mov_dialog.h
+++ b/gap/gap_mov_dialog.h
@@ -32,7 +32,7 @@
* gimp 1.3.20c; 2003/09/29 hof: new features: perspective transformation, tween_layer and trace_layer
* changed opacity, rotation and resize from int to gdouble
* gimp 1.3.14a; 2003/05/24 hof: moved render procedures to module gap_mov_render
- * gimp 1.1.29b; 2000/11/19 hof: new feature: FRAME based Stepmodes,
+ * gimp 1.1.29b; 2000/11/19 hof: new feature: FRAME based Stepmodes,
* increased controlpoint Limit GAP_MOV_MAX_POINT (from 256 -> 1024)
* gimp 1.1.20a; 2000/04/25 hof: support for keyframes, anim_preview
* version 0.96.02; 1998.07.25 hof: added clip_to_img
@@ -42,6 +42,12 @@
#define GAP_MOV_KEEP_SRC_PAINTMODE 4444
+#define GAP_MOV_INT_VERSION 2
+
+#define GAP_MOVPATH_XML_FILENAME_MAX_LENGTH 1024
+#define GAP_MOVEPATH_GIMPRC_LOG_RENDER_PARAMS "video-move-path-log-render-params"
+
+
typedef enum
{
GAP_STEP_LOOP = 0,
@@ -95,7 +101,7 @@ typedef struct {
gdouble currX, currY;
gint l_handleX;
gint l_handleY;
-
+
gdouble currOpacity;
gdouble currWidth;
gdouble currHeight;
@@ -109,7 +115,7 @@ typedef struct {
gdouble currTBLY; /* transform y bot left */
gdouble currTBRX; /* transform x bot right */
gdouble currTBRY; /* transform y bot right */
-
+
gdouble currSelFeatherRadius;
/* acceleration characteristics */
@@ -120,6 +126,15 @@ typedef struct {
gint accPerspective;
gint accSelFeatherRadius;
+ gboolean isSingleFrame; /* TRUE when processing in single frame mode */
+ gboolean keep_proportions;
+ gboolean fit_width;
+ gboolean fit_height;
+ gint32 singleMovObjLayerId;
+ gint32 singleMovObjImageId;
+
+ gint32 processedLayerId; /* id of the layer that was processed in the current render step */
+
} GapMovCurrent;
@@ -129,10 +144,10 @@ typedef struct {
gdouble w_resize; /* width resize 10 upto 300% */
gdouble h_resize; /* height resize 10 upto 300% */
gdouble rotation; /* rotatation +- degrees */
-
+
gint keyframe_abs;
gint keyframe;
-
+
/* 4-point transform distortion (perspective) */
gdouble ttlx; /* 0.0 upto 10.0 transform x top left */
gdouble ttly; /* 0.0 upto 10.0 transform y top left */
@@ -145,7 +160,7 @@ typedef struct {
/* feather radius for selection handling */
gdouble sel_feather_radius;
-
+
/* acceleration characteristics */
gint accPosition;
gint accOpacity;
@@ -165,6 +180,16 @@ typedef struct {
*/
typedef struct {
+ gint32 version;
+ gint32 recordedObjWidth; /* witdh of the moving object layer (at recording time of the move path settings) */
+ gint32 recordedObjHeight; /* height of the moving object layer (at recording time of the move path settings) */
+ gint32 recordedFrameWidth; /* witdh of the frame (at recording time of the move path settings) */
+ gint32 recordedFrameHeight; /* height of the frame (at recording time of the move path settings) */
+ gint32 total_frames;
+ gint32 src_layerstack;
+ gchar *src_filename;
+
+
gint32 src_image_id; /* source image */
gint32 src_layer_id; /* id of layer (to begin with) */
GapMovHandle src_handle;
@@ -194,7 +219,7 @@ typedef struct {
gint dst_range_end;
gint dst_layerstack;
- /* for dialog only */
+ /* for dialog only */
gint32 dst_image_id; /* frame image */
gint32 tmp_image_id; /* temp. flattened preview image */
gint32 tmp_alt_image_id; /* temp. preview image (preloaded preview frame) */
@@ -210,7 +235,7 @@ typedef struct {
* -1 if we are not in anim_preview mode
*/
gchar *apv_gap_paste_buff; /* Optional PasteBuffer (to store preview frames)
- * "/tmp/gimp_video_paste_buffer/gap_pasteframe_"
+ * "/tmp/gimp_video_paste_buffer/gap_pasteframe_"
* NULL if we do not copy frames to a paste_buffer
*/
@@ -219,7 +244,7 @@ typedef struct {
gdouble apv_scaley;
/* for FRAME based stepmodes */
- gint32 cache_src_image_id; /* id of the source image (from where cache image was copied) */
+ gint32 cache_src_image_id; /* id of the source image (from where cache image was copied) */
gint32 cache_tmp_image_id; /* id of a cached flattened copy of the src image */
gint32 cache_tmp_layer_id; /* the only visible layer in the cached image */
gint32 cache_frame_number;
@@ -235,23 +260,36 @@ typedef struct {
/* for the bluebox filter */
GapBlueboxGlobalParams *bbp;
GapBlueboxGlobalParams *bbp_pv;
-
+
} GapMovValues;
typedef struct {
- GapAnimInfo *dst_ainfo_ptr; /* destination frames */
+ gint32 drawable_id; /* the layer in the frame image to be processed (e.g. moved and transofrmed) */
+ gint32 frame_phase; /* current frame number starting at 1 */
+ gint32 total_frames;
+ gboolean keep_proportions;
+ gboolean fit_width;
+ gboolean fit_height;
+ gchar xml_paramfile[GAP_MOVPATH_XML_FILENAME_MAX_LENGTH];
+} GapMovSingleFrame;
+
+
+typedef struct {
+ GapAnimInfo *dst_ainfo_ptr; /* destination frames */
+ GapMovSingleFrame *singleFramePtr; /* NULL when processing multiple frames */
GapMovValues *val_ptr;
} GapMovData;
+
typedef struct {
/* IN */
gint pointIndexToQuery;
gint startOfSegmentIndexToQuery;
gint endOfSegmentIndexToQuery;
gint tweenCount;
-
+
/* OUT */
gint segmentNumber;
gdouble pathSegmentLengthInPixels;
@@ -261,5 +299,7 @@ typedef struct {
long gap_mov_dlg_move_dialog (GapMovData *mov_ptr);
+gint gap_mov_dlg_move_dialog_singleframe(GapMovSingleFrame *singleFramePtr);
+
#endif
diff --git a/gap/gap_mov_exec.c b/gap/gap_mov_exec.c
index 98fc37f..282bb1f 100644
--- a/gap/gap_mov_exec.c
+++ b/gap/gap_mov_exec.c
@@ -74,6 +74,7 @@
#include "gap_pdb_calls.h"
#include "gap_arr_dialog.h"
#include "gap_accel_char.h"
+#include "gap_mov_xml_par.h"
extern int gap_debug; /* ==0 ... dont print debug infos */
@@ -81,8 +82,19 @@ static void p_add_tween_and_trace(gint32 dest_image_id, GapMovData *mov_ptr, Gap
static gint p_mov_call_render(GapMovData *mov_ptr, GapMovCurrent *cur_ptr, gint apv_layerstack);
static void p_mov_advance_src_layer(GapMovCurrent *cur_ptr, GapMovValues *pvals);
static void p_mov_advance_src_frame(GapMovCurrent *cur_ptr, GapMovValues *pvals);
-static long p_mov_execute_or_query(GapMovData *mov_ptr, GapMovQuery *mov_query);
-static long p_mov_execute(GapMovData *mov_ptr);
+
+static void p_log_current_render_params(GapMovData *mov_ptr, GapMovCurrent *cur_ptr);
+static void p_printf_log_parameters(GapMovData *mov_ptr);
+static void gap_mov_exec_set_handle_offsets_singleframe(GapMovValues *val_ptr, GapMovCurrent *cur_ptr);
+static void p_add_2nd_controlpoint(GapMovValues *val_ptr);
+static void p_init_curr_ptr_with_1st_controlpoint(GapMovCurrent *cur_ptr, GapMovValues *val_ptr, GapMovSingleFrame *singleFramePtr);
+static gint32 p_duplicate_layer(gint32 layerId);
+
+static long p_mov_execute_or_query(GapMovData *mov_ptr, GapMovQuery *mov_query);
+static gint32 p_mov_execute_singleframe(GapMovData *mov_ptr);
+
+
+static long p_mov_execute(GapMovData *mov_ptr);
static gdouble p_calc_angle(gint p1x, gint p1y, gint p2x, gint p2y);
static gdouble p_rotatate_less_than_180(gdouble angle, gdouble angle_new, gint *turns);
@@ -120,7 +132,10 @@ static gint p_calculate_settings_for_current_FrameTween(
, gint endOfSegmentIndex
, GapMovQuery *mov_query
);
-
+
+
+
+
/* ============================================================================
@@ -243,11 +258,16 @@ p_mov_call_render(GapMovData *mov_ptr, GapMovCurrent *cur_ptr, gint apv_layersta
int l_rc;
char *l_fname;
char *l_name;
+ GapMovSingleFrame *singleFramePtr;
l_rc = 0;
ainfo_ptr = mov_ptr->dst_ainfo_ptr;
+ singleFramePtr = mov_ptr->singleFramePtr;
- if(mov_ptr->val_ptr->twix > 0)
+ p_log_current_render_params(mov_ptr, cur_ptr);
+
+ if((mov_ptr->val_ptr->twix > 0)
+ && (singleFramePtr == NULL))
{
/* We are rendering a virtual frame (a tween) */
/* ------------------------------------------ */
@@ -312,28 +332,44 @@ p_mov_call_render(GapMovData *mov_ptr, GapMovCurrent *cur_ptr, gint apv_layersta
gimp_image_add_layer (mov_ptr->val_ptr->tween_image_id, l_new_layer_id, 0 /* top of layerstack */ );
}
}
- else l_rc = -1;
+ else
+ {
+ l_rc = -1;
+ }
}
else
{
if(mov_ptr->val_ptr->apv_mlayer_image < 0)
{
- /* We are generating the Animation on the ORIGINAL FRAMES */
- /* ------------------------------------------------------ */
- if(ainfo_ptr->new_filename != NULL) g_free(ainfo_ptr->new_filename);
- ainfo_ptr->new_filename = gap_lib_alloc_fname(ainfo_ptr->basename,
- cur_ptr->dst_frame_nr,
- ainfo_ptr->extension);
- if(ainfo_ptr->new_filename == NULL)
- return -1;
+ if(singleFramePtr == NULL)
+ {
+ /* We are generating the Animation on the ORIGINAL FRAMES */
+ /* ------------------------------------------------------ */
+ if(ainfo_ptr->new_filename != NULL) g_free(ainfo_ptr->new_filename);
+ ainfo_ptr->new_filename = gap_lib_alloc_fname(ainfo_ptr->basename,
+ cur_ptr->dst_frame_nr,
+ ainfo_ptr->extension);
+ if(ainfo_ptr->new_filename == NULL)
+ return -1;
- /* load next frame to render */
- l_tmp_image_id = gap_lib_load_image(ainfo_ptr->new_filename);
- if(l_tmp_image_id < 0)
- return -1;
+ /* load next frame to render */
+ l_tmp_image_id = gap_lib_load_image(ainfo_ptr->new_filename);
+ if(l_tmp_image_id < 0)
+ {
+ return -1;
+ }
- gimp_image_undo_disable (l_tmp_image_id);
+ gimp_image_undo_disable (l_tmp_image_id);
+ }
+ else
+ {
+ l_tmp_image_id = mov_ptr->val_ptr->dst_image_id;
+ if (l_tmp_image_id < 0)
+ {
+ l_tmp_image_id = gimp_drawable_get_image(singleFramePtr->drawable_id);
+ }
+ }
/* call render procedure for current image */
@@ -344,11 +380,19 @@ p_mov_call_render(GapMovData *mov_ptr, GapMovCurrent *cur_ptr, gint apv_layersta
*/
p_add_tween_and_trace(l_tmp_image_id, mov_ptr, cur_ptr);
- /* if OK: save the rendered frame back to disk */
- if(gap_lib_save_named_frame(l_tmp_image_id, ainfo_ptr->new_filename) < 0)
- l_rc = -1;
+ if(singleFramePtr == NULL)
+ {
+ /* if OK: save the rendered frame back to disk (but not in singleframes mode) */
+ if(gap_lib_save_named_frame(l_tmp_image_id, ainfo_ptr->new_filename) < 0)
+ {
+ l_rc = -1;
+ }
+ }
+ }
+ else
+ {
+ l_rc = -1;
}
- else l_rc = -1;
}
else
{
@@ -369,8 +413,10 @@ p_mov_call_render(GapMovData *mov_ptr, GapMovCurrent *cur_ptr, gint apv_layersta
ainfo_ptr->extension);
l_tmp_image_id = gap_lib_load_image(ainfo_ptr->new_filename);
if(l_tmp_image_id < 0)
+ {
return -1;
-
+ }
+
gimp_image_undo_disable (l_tmp_image_id);
if((mov_ptr->val_ptr->apv_scalex != 100.0) || (mov_ptr->val_ptr->apv_scaley != 100.0))
@@ -462,9 +508,14 @@ p_mov_call_render(GapMovData *mov_ptr, GapMovCurrent *cur_ptr, gint apv_layersta
}
}
-
- /* destroy the tmp image */
- gimp_image_delete(l_tmp_image_id);
+ if(singleFramePtr == NULL)
+ {
+ /* destroy the tmp image
+ * (but not in singleframes mode. Note that in singleframe mode l_tmp_image_id
+ * referes to the image from where we were invoked)
+ */
+ gimp_image_delete(l_tmp_image_id);
+ }
return l_rc;
} /* end p_mov_call_render */
@@ -686,7 +737,7 @@ p_mov_advance_src_frame(GapMovCurrent *cur_ptr, GapMovValues *pvals)
* IN points is the number of processing relevant controlpoints
* returns the index of the last controlpoint in the path segment that starts at specified index
* Note that path segment includes all controlpoints up to the next keyframe inclusive. If no keyframe
- * present ther is only one big segment from first to last controlpoint.
+ * present there is only one big segment from first to last controlpoint.
*/
static gint
p_calculate_relframe_nr_at_index(GapMovValues *val_ptr, gint index, gint frames)
@@ -695,7 +746,7 @@ p_calculate_relframe_nr_at_index(GapMovValues *val_ptr, gint index, gint frames)
{
return (1);
}
-
+
if(index < val_ptr->point_idx_max )
{
if (val_ptr->point[index].keyframe > 0)
@@ -713,7 +764,7 @@ p_calculate_relframe_nr_at_index(GapMovValues *val_ptr, gint index, gint frames)
* p_findEndOfSegmentIndex
* -----------------------------------
* IN points is the number of processing relevant controlpoints
- * returns the index of the last controlpoint in the segment that starts
+ * returns the index of the last controlpoint in the segment that starts
* at specified startOfSegmentIndex.
* the segment ends at next KEYFRAME or at the last controlpoint (that is an implicite keyframe)
*/
@@ -721,7 +772,7 @@ static gint
p_findEndOfSegmentIndex(GapMovValues *val_ptr, gint startOfSegmentIndex, gint points)
{
gint ii;
-
+
for (ii= startOfSegmentIndex +1; ii < points; ii++)
{
if (val_ptr->point[ii].keyframe > 0)
@@ -730,7 +781,7 @@ p_findEndOfSegmentIndex(GapMovValues *val_ptr, gint startOfSegmentIndex, gint po
return (ii);
}
}
-
+
return (points -1);
} /* end p_findEndOfSegmentIndex */
@@ -753,14 +804,14 @@ p_calculate_LineLength(GapMovValues *val_ptr, gint idx)
{
return (0.0);
}
-
+
dx = abs (val_ptr->point[idx].p_x - val_ptr->point[idx +1].p_x);
dy = abs (val_ptr->point[idx].p_y - val_ptr->point[idx +1].p_y);
-
+
len = sqrt((dx * dx) + (dy * dy));
-
+
return (len);
-
+
} /* end p_calculate_LineLength */
@@ -775,7 +826,7 @@ p_calculate_path_segment_length(GapMovValues *val_ptr
{
gint idx;
gdouble lenSum;
-
+
lenSum = 0;
for(idx=startOfSegmentIndex; idx < endOfSegmentIndex; idx++)
{
@@ -788,14 +839,14 @@ p_calculate_path_segment_length(GapMovValues *val_ptr
/* -----------------------------------
* p_pick_controlpoint_at_curr_length
* -----------------------------------
- * returns the relevant controlpoint index
+ * returns the relevant controlpoint index
* at specified currentLen in pixels (eg. current position length within the specified
* path segment that starts at controlpoint startOfSegmentIndex)
*
* IN: startOfSegmentIndex
* IN: endOfSegmentIndex
* IN: pathSegmentLength length in pixels (0 at stastOfSegment, upto segment length)
- * IN:
+ * IN:
* OUT: flt_posfactor
*/
static gint
@@ -814,20 +865,20 @@ p_pick_controlpoint_at_curr_length(GapMovValues *val_ptr
/* calculate length factor (0.0 to 1.0) respecting position specific acceleartion characteristic */
lengthFactorAcc = gap_accelMixFactor(lengthFactorLinear, accelerationCharacteristic);
currentLen = pathSegmentLength * lengthFactorAcc;
-
-
-
-
+
+
+
+
lenSum = 0;
lenSumPrev = 0;
-
+
for(idx = startOfSegmentIndex; idx <= endOfSegmentIndex; idx++)
{
gdouble lineLen;
-
+
lineLen = p_calculate_LineLength(val_ptr, idx);
lenSum += lineLen;
-
+
if(lenSum >= currentLen)
{
gdouble l_flt_posfactor;
@@ -842,14 +893,14 @@ p_pick_controlpoint_at_curr_length(GapMovValues *val_ptr
,(float) lengthFactorAcc
);
}
-
-
+
+
*flt_posfactor = CLAMP (l_flt_posfactor, 0.0, 1.0);
return (idx);
}
lenSumPrev = lenSum;
}
-
+
*flt_posfactor = 0;
return (endOfSegmentIndex);
@@ -858,9 +909,9 @@ p_pick_controlpoint_at_curr_length(GapMovValues *val_ptr
/* --------------------------------------
* p_calculate_posFactor_from_FrameTweens
* --------------------------------------
- * returns the relevant positionFactor for the
+ * returns the relevant positionFactor for the
* specified currFrameTweenInSegment and frameTweensInSegment
- * respecting the specified acceleration characteristic
+ * respecting the specified acceleration characteristic
*
*/
static gdouble
@@ -874,11 +925,11 @@ p_calculate_posFactor_from_FrameTweens(gdouble frameTweensInSegment
factorLinear = currFrameTweenInSegment / (MAX (1.0, frameTweensInSegment));
factorLinear = CLAMP (factorLinear, 0.0, 1.0);
-
+
/* calculate length factor (0.0 to 1.0) respecting position specific acceleartion characteristic */
posFactorAcc = gap_accelMixFactor(factorLinear, accelerationCharacteristic);
-
-
+
+
return (posFactorAcc);
} /* end p_calculate_posFactor_from_FrameTweens */
@@ -889,7 +940,7 @@ p_calculate_posFactor_from_FrameTweens(gdouble frameTweensInSegment
* -------------------------------------------
* calculate settings for the currently processed
* Frame (or tween) according to the controlpoints.
- * supports older behavior of GIMP-GAP-2.6 and prior
+ * supports older behavior of GIMP-GAP-2.6 and prior
* and the extended variant with accerlaration characteristics
* per path segment.
* mode without acceleration characteristic (GIMP-GAP-2.6 behvior)
@@ -897,7 +948,7 @@ p_calculate_posFactor_from_FrameTweens(gdouble frameTweensInSegment
* This mode is selected by acceleration characteristic value 0.
* In this mode the flt_posfactor specifies the position within one line
* between the controlpoints with index [l_ptidx -1] and [l_ptidx]
- *
+ *
* Mode with acceleration characteristic:
* ========================================
* a Path segment includes all controlpoints between two keyframes
@@ -914,7 +965,7 @@ p_calculate_posFactor_from_FrameTweens(gdouble frameTweensInSegment
*
* in case acceleration characteristic values != 0 are used for any other settings than position,
* then all controlpoints that are NON keyframes are ignored for other settings than position (x,y).
- * Those settings (opacity, size ...) are then calculated from the
+ * Those settings (opacity, size ...) are then calculated from the
* controlpoint at start and end of the path segment.
* (note that first and last controlpoint are
* implicite keyframes and therefore always relevant)
@@ -945,7 +996,7 @@ p_calculate_settings_for_current_FrameTween(
gdouble tweenMultiplicator;
gdouble lengthFactorLinear; /* 0.0 at begin of segment 1.0 at end of segment position */
gdouble frameTweensInSegment;
- gdouble currFrameTweenInSegment; /* frame number relative to 0 at each starting point of a new segment
+ gdouble currFrameTweenInSegment; /* frame number relative to 0 at each starting point of a new segment
* tweens can have non integer frame number like 1.5 or 1.3333 or 1.25 etc....
*/
gdouble pathSegmentLength;
@@ -975,13 +1026,13 @@ p_calculate_settings_for_current_FrameTween(
- p_calculate_relframe_nr_at_index(val_ptr, startOfSegmentIndex, affectedFrames)
) + 1;
frameTweensInSegment *= tweenMultiplicator;
-
-
-
- currFrameTweenInSegment =
- tweenMultiplicator * (abs (currFrameIndex - val_ptr->point[startOfSegmentIndex].keyframe)); /// TODO check for reverse order processing ???
+
+
+
+ currFrameTweenInSegment =
+ tweenMultiplicator * (abs (currFrameIndex - val_ptr->point[startOfSegmentIndex].keyframe));
currFrameTweenInSegment += (val_ptr->tween_steps - val_ptr->twix);
-
+
/* calculate length factor respecting position in the path segment where 0 is at begin 1 at end */
lengthFactorLinear = currFrameTweenInSegment / MAX(frameTweensInSegment, 1);
@@ -997,7 +1048,13 @@ p_calculate_settings_for_current_FrameTween(
);
}
-
+ cur_ptr->accPosition = val_ptr->point[startOfSegmentIndex].accPosition;
+ cur_ptr->accOpacity = val_ptr->point[startOfSegmentIndex].accOpacity;
+ cur_ptr->accSize = val_ptr->point[startOfSegmentIndex].accSize;
+ cur_ptr->accRotation = val_ptr->point[startOfSegmentIndex].accRotation;
+ cur_ptr->accPerspective = val_ptr->point[startOfSegmentIndex].accPerspective;
+ cur_ptr->accSelFeatherRadius = val_ptr->point[startOfSegmentIndex].accSelFeatherRadius;
+
/* calculate Movement settings for the currently processed Frame (or tween)
* position dependent acceleration processing requires a path segment length > 0
* AND accPosition != 0
@@ -1052,7 +1109,7 @@ p_calculate_settings_for_current_FrameTween(
else
{
/* No acceleration characteristic specified for movement (compatible to GAP 2.6.x release behavior) */
- if(gap_debug)
+ if(gap_debug)
{
printf("p_mov_execute: framesPerLine=%f, flt_posfactor=%f\n"
, (float)framesPerLine
@@ -1084,7 +1141,7 @@ p_calculate_settings_for_current_FrameTween(
refPtidx = segmPtidx +1;
}
- if(gap_debug)
+ if(gap_debug)
{
printf("p_mov_execute: pixelLengthInOneTweenStep=%f pointIndexToQuery:%d currPtidx:%d refPtidx:%d StartQuery:%d EndQuery:%d\n"
, (float)pixelLengthInOneTweenStep
@@ -1102,7 +1159,7 @@ p_calculate_settings_for_current_FrameTween(
if(mov_query->tweenCount == 0)
{
mov_query->tweenCount++;
- if(gap_debug)
+ if(gap_debug)
{
printf("p_mov_execute: SKIP max speed calculation at first frame of segment\n");
}
@@ -1123,10 +1180,8 @@ p_calculate_settings_for_current_FrameTween(
}
-
- }
-
+ }
/* calculate Opacity settings for the currently processed Frame (or tween) */
@@ -1157,7 +1212,6 @@ p_calculate_settings_for_current_FrameTween(
}
-
/* calculate Zoom (e.g. Size) settings for the currently processed Frame (or tween) */
if ((val_ptr->point[startOfSegmentIndex].accSize != 0)
&& (frameTweensInSegment > 0))
@@ -1227,7 +1281,7 @@ p_calculate_settings_for_current_FrameTween(
else
{
cur_ptr->currRotation = GAP_BASE_MIX_VALUE(flt_posfactor, (gdouble)val_ptr->point[currPtidx -1].rotation, (gdouble)val_ptr->point[currPtidx].rotation);
-
+
if(gap_debug)
{
printf("p_mov_execute: framesPerLine=%f, flt_posfactor=%f\n"
@@ -1310,22 +1364,315 @@ p_calculate_settings_for_current_FrameTween(
} /* end p_calculate_settings_for_current_FrameTween */
+/* --------------------------------
+ * p_log_current_render_params
+ * --------------------------------
+ * log current render parameters to stdout (for test and analyse purpose)
+ */
+static void
+p_log_current_render_params(GapMovData *mov_ptr, GapMovCurrent *cur_ptr)
+{
+ gboolean defaultFlag;
-/* ============================================================================
+ defaultFlag = FALSE;
+ if(gap_debug)
+ {
+ defaultFlag = TRUE;
+ }
+
+ if(gap_base_get_gimprc_gboolean_value(GAP_MOVEPATH_GIMPRC_LOG_RENDER_PARAMS, defaultFlag))
+ {
+ GapMovValues *val_ptr;
+
+ val_ptr = mov_ptr->val_ptr;
+
+ printf("\nCurrent Render Params: dst_frame_nr:%ld tweenIndex:%d src_layer_idx:%ld\n"
+ " currX:%f currY:%f\n"
+ " Width:%f Height:%f\n"
+ " Opacity:%f Rotate:%f clip_to_img:%d force_visibility:%d\n"
+ " src_stepmode:%d handleX:%d handleY:%d currSelFeatherRadius:%f\n",
+ cur_ptr->dst_frame_nr, (int)val_ptr->twix, cur_ptr->src_layer_idx,
+ cur_ptr->currX, cur_ptr->currY,
+ cur_ptr->currWidth,
+ cur_ptr->currHeight,
+ cur_ptr->currOpacity,
+ cur_ptr->currRotation,
+ val_ptr->clip_to_img,
+ val_ptr->src_force_visible,
+ val_ptr->src_stepmode,
+ cur_ptr->l_handleX,
+ cur_ptr->l_handleY,
+ cur_ptr->currSelFeatherRadius
+ );
+
+ printf(" Perspective Factors: [0] %.3f %.3f [1] %.3f %.3f [2] %.3f %.3f [3] %.3f %.3f\n"
+ ,(float)cur_ptr->currTTLX
+ ,(float)cur_ptr->currTTLY
+ ,(float)cur_ptr->currTTRX
+ ,(float)cur_ptr->currTTRY
+ ,(float)cur_ptr->currTBLX
+ ,(float)cur_ptr->currTBLY
+ ,(float)cur_ptr->currTBRX
+ ,(float)cur_ptr->currTBRY
+ );
+ printf(" accPosition:%d accOpacity:%d accSize:%d accRotation:%d accPerspective:%d accSelFeatherRadius:%d\n"
+ ,(int)cur_ptr->accPosition
+ ,(int)cur_ptr->accOpacity
+ ,(int)cur_ptr->accSize
+ ,(int)cur_ptr->accRotation
+ ,(int)cur_ptr->accPerspective
+ ,(int)cur_ptr->accSelFeatherRadius
+ );
+ }
+
+} /* end p_log_current_render_params */
+
+
+/* --------------------------------
+ * p_printf_log_parameters
+ * --------------------------------
+ *
+ */
+static void
+p_printf_log_parameters(GapMovData *mov_ptr)
+{
+ gint l_idx;
+
+ printf("apv_mlayer_image: %ld\n", (long)mov_ptr->val_ptr->apv_mlayer_image);
+ printf("apv_mode: %ld\n", (long)mov_ptr->val_ptr->apv_mode);
+ printf("apv_scale x: %f y:%f\n", (float)mov_ptr->val_ptr->apv_scalex, (float)mov_ptr->val_ptr->apv_scaley);
+ if(mov_ptr->val_ptr->apv_gap_paste_buff)
+ {
+ printf("apv_gap_paste_buf: %s\n", mov_ptr->val_ptr->apv_gap_paste_buff);
+ }
+ else
+ {
+ printf("apv_gap_paste_buf: ** IS NULL ** (do not copy to paste buffer)\n");
+ }
+ printf("src_image_id :%ld\n", (long)mov_ptr->val_ptr->src_image_id);
+ printf("src_layer_id :%ld\n", (long)mov_ptr->val_ptr->src_layer_id);
+ printf("src_handle :%d\n", mov_ptr->val_ptr->src_handle);
+ printf("src_stepmode :%d\n", mov_ptr->val_ptr->src_stepmode);
+ printf("src_paintmode :%d\n", mov_ptr->val_ptr->src_paintmode);
+ printf("clip_to_img :%d\n", mov_ptr->val_ptr->clip_to_img);
+ printf("dst_range_start :%d\n", (int)mov_ptr->val_ptr->dst_range_start);
+ printf("dst_range_end :%d\n", (int)mov_ptr->val_ptr->dst_range_end);
+ printf("dst_layerstack :%d\n", (int)mov_ptr->val_ptr->dst_layerstack);
+ for(l_idx = 0; l_idx <= mov_ptr->val_ptr->point_idx_max; l_idx++)
+ {
+ printf("p_x[%d] :%d\n", l_idx, mov_ptr->val_ptr->point[l_idx].p_x);
+ printf("p_y[%d] :%d\n", l_idx, mov_ptr->val_ptr->point[l_idx].p_y);
+ printf("opacity[%d] :%.3f\n", l_idx, (float)mov_ptr->val_ptr->point[l_idx].opacity);
+ printf("w_resize[%d] :%.3f\n", l_idx, (float)mov_ptr->val_ptr->point[l_idx].w_resize);
+ printf("h_resize[%d] :%.3f\n", l_idx, (float)mov_ptr->val_ptr->point[l_idx].h_resize);
+ printf("rotation[%d] :%.3f\n", l_idx, (float)mov_ptr->val_ptr->point[l_idx].rotation);
+ printf("ttlx[%d] :%.3f\n", l_idx, (float)mov_ptr->val_ptr->point[l_idx].ttlx);
+ printf("ttly[%d] :%.3f\n", l_idx, (float)mov_ptr->val_ptr->point[l_idx].ttly);
+ printf("ttrx[%d] :%.3f\n", l_idx, (float)mov_ptr->val_ptr->point[l_idx].ttrx);
+ printf("ttry[%d] :%.3f\n", l_idx, (float)mov_ptr->val_ptr->point[l_idx].ttry);
+ printf("tblx[%d] :%.3f\n", l_idx, (float)mov_ptr->val_ptr->point[l_idx].tblx);
+ printf("tbly[%d] :%.3f\n", l_idx, (float)mov_ptr->val_ptr->point[l_idx].tbly);
+ printf("tbrx[%d] :%.3f\n", l_idx, (float)mov_ptr->val_ptr->point[l_idx].tbrx);
+ printf("tbry[%d] :%.3f\n", l_idx, (float)mov_ptr->val_ptr->point[l_idx].tbry);
+
+ printf("accPosition [%d] :%d\n", l_idx, (int)mov_ptr->val_ptr->point[l_idx].accPosition);
+ printf("accOpacity [%d] :%d\n", l_idx, (int)mov_ptr->val_ptr->point[l_idx].accOpacity);
+ printf("accSize [%d] :%d\n", l_idx, (int)mov_ptr->val_ptr->point[l_idx].accSize);
+ printf("accRotation [%d] :%d\n", l_idx, (int)mov_ptr->val_ptr->point[l_idx].accRotation);
+ printf("accPerspective [%d] :%d\n", l_idx, (int)mov_ptr->val_ptr->point[l_idx].accPerspective);
+ printf("accSelFeatherRadius[%d] :%d\n", l_idx, (int)mov_ptr->val_ptr->point[l_idx].accSelFeatherRadius);
+
+ printf("keyframe[%d] :%d\n", l_idx, mov_ptr->val_ptr->point[l_idx].keyframe);
+ printf("keyframe_abs[%d] :%d\n", l_idx, mov_ptr->val_ptr->point[l_idx].keyframe_abs);
+ }
+ printf("\n");
+
+} /* end p_printf_log_parameters */
+
+
+/* -------------------------------------------
+ * gap_mov_exec_set_handle_offsets_singleframe
+ * -------------------------------------------
+ *
+ */
+static void
+gap_mov_exec_set_handle_offsets_singleframe(GapMovValues *val_ptr, GapMovCurrent *cur_ptr)
+{
+ guint l_src_width, l_src_height; /* dimensions of the source image */
+
+ /* get dimensions of source image (in single frame mode: same as frame image) */
+ l_src_width = gimp_image_width(cur_ptr->singleMovObjImageId);
+ l_src_height = gimp_image_height(cur_ptr->singleMovObjImageId);
+
+ cur_ptr->l_handleX = 0.0;
+ cur_ptr->l_handleY = 0.0;
+ switch(val_ptr->src_handle)
+ {
+ case GAP_HANDLE_LEFT_BOT:
+ cur_ptr->l_handleY += l_src_height;
+ break;
+ case GAP_HANDLE_RIGHT_TOP:
+ cur_ptr->l_handleX += l_src_width;
+ break;
+ case GAP_HANDLE_RIGHT_BOT:
+ cur_ptr->l_handleX += l_src_width;
+ cur_ptr->l_handleY += l_src_height;
+ break;
+ case GAP_HANDLE_CENTER:
+ cur_ptr->l_handleX += (l_src_width / 2);
+ cur_ptr->l_handleY += (l_src_height / 2);
+ break;
+ case GAP_HANDLE_LEFT_TOP:
+ default:
+ break;
+ }
+} /* end gap_mov_exec_set_handle_offsets_singleframe */
+
+
+
+/* --------------------------------
+ * p_add_2nd_controlpoint
+ * --------------------------------
+ *
+ */
+static void
+p_add_2nd_controlpoint(GapMovValues *val_ptr)
+{
+ /* copy point[0] to point [1] because we need at least 2
+ * points for the algorithms below to work.
+ * (simulates a line with length 0, to move along)
+ */
+ if(gap_debug)
+ {
+ printf("p_mov_execute: added a 2nd Point\n");
+ }
+ val_ptr->point[1].p_x = val_ptr->point[0].p_x;
+ val_ptr->point[1].p_y = val_ptr->point[0].p_y;
+ val_ptr->point[1].opacity = val_ptr->point[0].opacity;
+ val_ptr->point[1].w_resize = val_ptr->point[0].w_resize;
+ val_ptr->point[1].h_resize = val_ptr->point[0].h_resize;
+ val_ptr->point[1].rotation = val_ptr->point[0].rotation;
+ val_ptr->point[1].ttlx = val_ptr->point[0].ttlx;
+ val_ptr->point[1].ttly = val_ptr->point[0].ttly;
+ val_ptr->point[1].ttrx = val_ptr->point[0].ttrx;
+ val_ptr->point[1].ttry = val_ptr->point[0].ttry;
+ val_ptr->point[1].tblx = val_ptr->point[0].tblx;
+ val_ptr->point[1].tbly = val_ptr->point[0].tbly;
+ val_ptr->point[1].tbrx = val_ptr->point[0].tbrx;
+ val_ptr->point[1].tbry = val_ptr->point[0].tbry;
+ val_ptr->point[1].sel_feather_radius = val_ptr->point[0].sel_feather_radius;
+
+ val_ptr->point[1].accPosition = val_ptr->point[0].accPosition;
+ val_ptr->point[1].accOpacity = val_ptr->point[0].accOpacity;
+ val_ptr->point[1].accSize = val_ptr->point[0].accSize;
+ val_ptr->point[1].accRotation = val_ptr->point[0].accRotation;
+ val_ptr->point[1].accPerspective = val_ptr->point[0].accPerspective;
+ val_ptr->point[1].accSelFeatherRadius = val_ptr->point[0].accSelFeatherRadius;
+
+} /* end p_add_2nd_controlpoint */
+
+
+/* -------------------------------------
+ * p_init_curr_ptr_with_1st_controlpoint
+ * -------------------------------------
+ * init current values with settings from the 1st controlpoint
+ * in case of single frame processing mode (singleFramePtr != NULL)
+ * init the id of the relevant layer (singleMovObjLayerId) that may be
+ * already part of the processed frame or may be a layer in another image.
+ */
+static void
+p_init_curr_ptr_with_1st_controlpoint(GapMovCurrent *cur_ptr, GapMovValues *val_ptr, GapMovSingleFrame *singleFramePtr)
+{
+ cur_ptr->currX = (gdouble)val_ptr->point[0].p_x;
+ cur_ptr->currY = (gdouble)val_ptr->point[0].p_y;
+ cur_ptr->currOpacity = (gdouble)val_ptr->point[0].opacity;
+ cur_ptr->currWidth = (gdouble)val_ptr->point[0].w_resize;
+ cur_ptr->currHeight = (gdouble)val_ptr->point[0].h_resize;
+ cur_ptr->currRotation = (gdouble)val_ptr->point[0].rotation;
+ cur_ptr->currTTLX = (gdouble)val_ptr->point[0].ttlx;
+ cur_ptr->currTTLY = (gdouble)val_ptr->point[0].ttly;
+ cur_ptr->currTTRX = (gdouble)val_ptr->point[0].ttrx;
+ cur_ptr->currTTRY = (gdouble)val_ptr->point[0].ttry;
+ cur_ptr->currTBLX = (gdouble)val_ptr->point[0].tblx;
+ cur_ptr->currTBLY = (gdouble)val_ptr->point[0].tbly;
+ cur_ptr->currTBRX = (gdouble)val_ptr->point[0].tbrx;
+ cur_ptr->currTBRY = (gdouble)val_ptr->point[0].tbry;
+ cur_ptr->currSelFeatherRadius = (gdouble)val_ptr->point[0].sel_feather_radius;
+
+ cur_ptr->accPosition = val_ptr->point[0].accPosition;
+ cur_ptr->accOpacity = val_ptr->point[0].accOpacity;
+ cur_ptr->accSize = val_ptr->point[0].accSize;
+ cur_ptr->accRotation = val_ptr->point[0].accRotation;
+ cur_ptr->accPerspective = val_ptr->point[0].accPerspective;
+ cur_ptr->accSelFeatherRadius = val_ptr->point[0].accSelFeatherRadius;
+
+
+ cur_ptr->isSingleFrame = FALSE;
+ cur_ptr->processedLayerId = -1;
+ cur_ptr->singleMovObjLayerId = -1;
+ cur_ptr->singleMovObjImageId = -1;
+ cur_ptr->keep_proportions = FALSE;
+ cur_ptr->fit_width = FALSE;
+ cur_ptr->fit_height = FALSE;
+
+ if (singleFramePtr != NULL)
+ {
+ cur_ptr->isSingleFrame = TRUE;
+ cur_ptr->singleMovObjLayerId = singleFramePtr->drawable_id;
+ cur_ptr->singleMovObjImageId = gimp_drawable_get_image(cur_ptr->singleMovObjLayerId);
+ cur_ptr->keep_proportions = singleFramePtr->keep_proportions;
+ cur_ptr->fit_width = singleFramePtr->fit_width;
+ cur_ptr->fit_height = singleFramePtr->fit_height;
+ }
+
+ val_ptr->tween_image_id = -1;
+ val_ptr->tween_layer_id = -1;
+ val_ptr->trace_image_id = -1;
+ val_ptr->trace_layer_id = -1;
+
+} /* end p_init_curr_ptr_with_1st_controlpoint */
+
+
+/* --------------------------------
+ * p_duplicate_layer
+ * --------------------------------
+ *
+ */
+static gint32
+p_duplicate_layer(gint32 layerId)
+{
+ gint32 dupLayerId;
+ gint32 imageId;
+
+
+ imageId = gimp_drawable_get_image(layerId);
+ gimp_image_set_active_layer(imageId, layerId);
+ dupLayerId = gimp_layer_copy(layerId);
+ gimp_image_add_layer(imageId, dupLayerId, -1 /* -1 place above active layer */);
+
+ return(dupLayerId);
+
+} /* end p_duplicate_layer */
+
+
+
+
+/* -----------------------
* p_mov_execute_or_query
+ * -----------------------
* Copy layer(s) from Sourceimage to given destination frame range,
- * varying koordinates and opacity of the copied layer.
- * To each affected destination frame exactly one copy of a source layer is added.
+ * varying koordinates and opacity and perform other transformations
+ * according to controlpoint settings on the copied layer.
+ * To each affected destination frame one copy of a source layer is added.
+ * (more than one layer is added in case of tween processing and tracelayer processing)
* The source layer is iterated through all layers of the sourceimage
* according to stemmode parameter.
* For the placement the layers act as if their size is equal to their
* Sourceimages size.
- * ============================================================================
*/
long
p_mov_execute_or_query(GapMovData *mov_ptr, GapMovQuery *mov_query)
{
- gint l_idx;
GapMovCurrent l_current_data;
GapMovCurrent *cur_ptr;
GapMovValues *val_ptr;
@@ -1380,54 +1727,7 @@ p_mov_execute_or_query(GapMovData *mov_ptr, GapMovQuery *mov_query)
if(gap_debug)
{
printf("p_mov_execute: values got from dialog:\n");
- printf("apv_mlayer_image: %ld\n", (long)mov_ptr->val_ptr->apv_mlayer_image);
- printf("apv_mode: %ld\n", (long)mov_ptr->val_ptr->apv_mode);
- printf("apv_scale x: %f y:%f\n", (float)mov_ptr->val_ptr->apv_scalex, (float)mov_ptr->val_ptr->apv_scaley);
- if(mov_ptr->val_ptr->apv_gap_paste_buff)
- {
- printf("apv_gap_paste_buf: %s\n", mov_ptr->val_ptr->apv_gap_paste_buff);
- }
- else
- {
- printf("apv_gap_paste_buf: ** IS NULL ** (do not copy to paste buffer)\n");
- }
- printf("src_image_id :%ld\n", (long)mov_ptr->val_ptr->src_image_id);
- printf("src_layer_id :%ld\n", (long)mov_ptr->val_ptr->src_layer_id);
- printf("src_handle :%d\n", mov_ptr->val_ptr->src_handle);
- printf("src_stepmode :%d\n", mov_ptr->val_ptr->src_stepmode);
- printf("src_paintmode :%d\n", mov_ptr->val_ptr->src_paintmode);
- printf("clip_to_img :%d\n", mov_ptr->val_ptr->clip_to_img);
- printf("dst_range_start :%d\n", (int)mov_ptr->val_ptr->dst_range_start);
- printf("dst_range_end :%d\n", (int)mov_ptr->val_ptr->dst_range_end);
- printf("dst_layerstack :%d\n", (int)mov_ptr->val_ptr->dst_layerstack);
- for(l_idx = 0; l_idx <= mov_ptr->val_ptr->point_idx_max; l_idx++)
- {
- printf("p_x[%d] :%d\n", l_idx, mov_ptr->val_ptr->point[l_idx].p_x);
- printf("p_y[%d] :%d\n", l_idx, mov_ptr->val_ptr->point[l_idx].p_y);
- printf("opacity[%d] :%.3f\n", l_idx, (float)mov_ptr->val_ptr->point[l_idx].opacity);
- printf("w_resize[%d] :%.3f\n", l_idx, (float)mov_ptr->val_ptr->point[l_idx].w_resize);
- printf("h_resize[%d] :%.3f\n", l_idx, (float)mov_ptr->val_ptr->point[l_idx].h_resize);
- printf("rotation[%d] :%.3f\n", l_idx, (float)mov_ptr->val_ptr->point[l_idx].rotation);
- printf("ttlx[%d] :%.3f\n", l_idx, (float)mov_ptr->val_ptr->point[l_idx].ttlx);
- printf("ttly[%d] :%.3f\n", l_idx, (float)mov_ptr->val_ptr->point[l_idx].ttly);
- printf("ttrx[%d] :%.3f\n", l_idx, (float)mov_ptr->val_ptr->point[l_idx].ttrx);
- printf("ttry[%d] :%.3f\n", l_idx, (float)mov_ptr->val_ptr->point[l_idx].ttry);
- printf("tblx[%d] :%.3f\n", l_idx, (float)mov_ptr->val_ptr->point[l_idx].tblx);
- printf("tbly[%d] :%.3f\n", l_idx, (float)mov_ptr->val_ptr->point[l_idx].tbly);
- printf("tbrx[%d] :%.3f\n", l_idx, (float)mov_ptr->val_ptr->point[l_idx].tbrx);
- printf("tbry[%d] :%.3f\n", l_idx, (float)mov_ptr->val_ptr->point[l_idx].tbry);
-
- printf("accPosition [%d] :%d\n", l_idx, (int)mov_ptr->val_ptr->point[l_idx].accPosition);
- printf("accOpacity [%d] :%d\n", l_idx, (int)mov_ptr->val_ptr->point[l_idx].accOpacity);
- printf("accSize [%d] :%d\n", l_idx, (int)mov_ptr->val_ptr->point[l_idx].accSize);
- printf("accRotation [%d] :%d\n", l_idx, (int)mov_ptr->val_ptr->point[l_idx].accRotation);
- printf("accPerspective [%d] :%d\n", l_idx, (int)mov_ptr->val_ptr->point[l_idx].accPerspective);
- printf("accSelFeatherRadius[%d] :%d\n", l_idx, (int)mov_ptr->val_ptr->point[l_idx].accSelFeatherRadius);
-
- printf("keyframe[%d] :%d\n", l_idx, mov_ptr->val_ptr->point[l_idx].keyframe);
- printf("keyframe_abs[%d] :%d\n", l_idx, mov_ptr->val_ptr->point[l_idx].keyframe_abs);
- }
- printf("\n");
+ p_printf_log_parameters(mov_ptr);
}
l_rc = 0;
@@ -1444,6 +1744,7 @@ p_mov_execute_or_query(GapMovData *mov_ptr, GapMovQuery *mov_query)
val_ptr->tmpsel_image_id = -1;
val_ptr->tmpsel_channel_id = -1;
+ val_ptr->twix = 0;
/* set offsets (in cur_ptr) according to handle mode and src_img dimension */
gap_mov_exec_set_handle_offsets(val_ptr, cur_ptr);
@@ -1473,35 +1774,8 @@ p_mov_execute_or_query(GapMovData *mov_ptr, GapMovQuery *mov_query)
if(l_points < 2)
{
- /* copy point[0] to point [1] because we need at least 2
- * points for the algorithms below to work.
- * (simulates a line with length 0, to move along)
- */
- if(gap_debug) printf("p_mov_execute: added a 2nd Point\n");
- val_ptr->point[1].p_x = val_ptr->point[0].p_x;
- val_ptr->point[1].p_y = val_ptr->point[0].p_y;
- val_ptr->point[1].opacity = val_ptr->point[0].opacity;
- val_ptr->point[1].w_resize = val_ptr->point[0].w_resize;
- val_ptr->point[1].h_resize = val_ptr->point[0].h_resize;
- val_ptr->point[1].rotation = val_ptr->point[0].rotation;
- val_ptr->point[1].ttlx = val_ptr->point[0].ttlx;
- val_ptr->point[1].ttly = val_ptr->point[0].ttly;
- val_ptr->point[1].ttrx = val_ptr->point[0].ttrx;
- val_ptr->point[1].ttry = val_ptr->point[0].ttry;
- val_ptr->point[1].tblx = val_ptr->point[0].tblx;
- val_ptr->point[1].tbly = val_ptr->point[0].tbly;
- val_ptr->point[1].tbrx = val_ptr->point[0].tbrx;
- val_ptr->point[1].tbry = val_ptr->point[0].tbry;
- val_ptr->point[1].sel_feather_radius = val_ptr->point[0].sel_feather_radius;
-
- val_ptr->point[1].accPosition = val_ptr->point[0].accPosition;
- val_ptr->point[1].accOpacity = val_ptr->point[0].accOpacity;
- val_ptr->point[1].accSize = val_ptr->point[0].accSize;
- val_ptr->point[1].accRotation = val_ptr->point[0].accRotation;
- val_ptr->point[1].accPerspective = val_ptr->point[0].accPerspective;
- val_ptr->point[1].accSelFeatherRadius = val_ptr->point[0].accSelFeatherRadius;
-
- l_points = 2;
+ p_add_2nd_controlpoint(val_ptr);
+ l_points = 2;
}
startOfSegmentIndex = 0;
@@ -1509,7 +1783,7 @@ p_mov_execute_or_query(GapMovData *mov_ptr, GapMovQuery *mov_query)
cur_ptr->dst_frame_nr = val_ptr->dst_range_start;
cur_ptr->src_layers = NULL;
-
+
if(mov_query == NULL)
{
if(mov_ptr->val_ptr->src_stepmode < GAP_STEP_FRAME)
@@ -1574,35 +1848,8 @@ p_mov_execute_or_query(GapMovData *mov_ptr, GapMovQuery *mov_query)
}
}
- cur_ptr->currX = (gdouble)val_ptr->point[0].p_x;
- cur_ptr->currY = (gdouble)val_ptr->point[0].p_y;
- cur_ptr->currOpacity = (gdouble)val_ptr->point[0].opacity;
- cur_ptr->currWidth = (gdouble)val_ptr->point[0].w_resize;
- cur_ptr->currHeight = (gdouble)val_ptr->point[0].h_resize;
- cur_ptr->currRotation = (gdouble)val_ptr->point[0].rotation;
- cur_ptr->currTTLX = (gdouble)val_ptr->point[0].ttlx;
- cur_ptr->currTTLY = (gdouble)val_ptr->point[0].ttly;
- cur_ptr->currTTRX = (gdouble)val_ptr->point[0].ttrx;
- cur_ptr->currTTRY = (gdouble)val_ptr->point[0].ttry;
- cur_ptr->currTBLX = (gdouble)val_ptr->point[0].tblx;
- cur_ptr->currTBLY = (gdouble)val_ptr->point[0].tbly;
- cur_ptr->currTBRX = (gdouble)val_ptr->point[0].tbrx;
- cur_ptr->currTBRY = (gdouble)val_ptr->point[0].tbry;
- cur_ptr->currSelFeatherRadius = (gdouble)val_ptr->point[0].sel_feather_radius;
-
- cur_ptr->accPosition = val_ptr->point[0].accPosition;
- cur_ptr->accOpacity = val_ptr->point[0].accOpacity;
- cur_ptr->accSize = val_ptr->point[0].accSize;
- cur_ptr->accRotation = val_ptr->point[0].accRotation;
- cur_ptr->accPerspective = val_ptr->point[0].accPerspective;
- cur_ptr->accSelFeatherRadius = val_ptr->point[0].accSelFeatherRadius;
-
-
-
- val_ptr->tween_image_id = -1;
- val_ptr->tween_layer_id = -1;
- val_ptr->trace_image_id = -1;
- val_ptr->trace_layer_id = -1;
+ p_init_curr_ptr_with_1st_controlpoint(cur_ptr, val_ptr, NULL);
+
/* create temp images for tween processing and object tracing */
if(mov_query == NULL)
@@ -1701,7 +1948,7 @@ p_mov_execute_or_query(GapMovData *mov_ptr, GapMovQuery *mov_query)
(int)l_ptidx, (float)l_fpl);
}
}
-
+
/* in query mode: find start end end of segment that contains the pointIndexToQuery */
if(mov_query != NULL)
{
@@ -1717,16 +1964,16 @@ p_mov_execute_or_query(GapMovData *mov_ptr, GapMovQuery *mov_query)
mov_query->segmentNumber++;
mov_query->startOfSegmentIndexToQuery = l_ptidx;
}
-
+
if (l_ptidx > mov_query->pointIndexToQuery)
{
mov_query->endOfSegmentIndexToQuery = l_ptidx;
break;
}
}
-
+
}
-
+
}
if(gap_debug)
@@ -1738,7 +1985,7 @@ p_mov_execute_or_query(GapMovData *mov_ptr, GapMovQuery *mov_query)
}
}
-
+
/* loop for each frame within the range (may step up or down) */
l_ptidx = 1;
cur_ptr->dst_frame_nr = val_ptr->dst_range_start;
@@ -1769,12 +2016,12 @@ p_mov_execute_or_query(GapMovData *mov_ptr, GapMovQuery *mov_query)
startOfSegmentIndex = endOfSegmentIndex;
}
}
-
+
/* change deltas for next line of the move path */
if(l_ptidx < l_points-1)
{
l_ptidx++;
-
+
if(gap_debug)
{
printf("p_mov_execute: advance to controlpoint l_ptidx=%d, l_flt_timing[l_ptidx]=%f startOfSegmentIndex:%d endOfSegmentIndex:%d\n"
@@ -1805,7 +2052,7 @@ p_mov_execute_or_query(GapMovData *mov_ptr, GapMovQuery *mov_query)
for (val_ptr->twix = val_ptr->tween_steps; val_ptr->twix >= 0; val_ptr->twix--)
{
gdouble l_flt_posfactor;
-
+
if(l_fpl != 0.0)
{
l_flt_posfactor = ( (((gdouble)l_fridx * l_tw_cnt) - (gdouble)val_ptr->twix)
@@ -1817,9 +2064,9 @@ p_mov_execute_or_query(GapMovData *mov_ptr, GapMovQuery *mov_query)
l_flt_posfactor = 1.0;
if(gap_debug) printf("p_mov_execute: ** ERROR l_fpl is 0.0 frames per line\n");
}
-
+
l_flt_posfactor = CLAMP (l_flt_posfactor, 0.0, 1.0);
-
+
endOfSegmentIndex = p_findEndOfSegmentIndex(val_ptr, startOfSegmentIndex, l_points);
frameNrAtEndOfSegment = p_calculate_relframe_nr_at_index(val_ptr, endOfSegmentIndex, l_frames);
@@ -1836,20 +2083,20 @@ p_mov_execute_or_query(GapMovData *mov_ptr, GapMovQuery *mov_query)
);
-
+
if(mov_query != NULL)
{
/* we run in query mode, just check if controlpoint for query is reached
* and stop (without rendering)
*/
- if(gap_debug)
+ if(gap_debug)
{
printf("BREAK check: endOfSegmentIndexToQuery:%d l_ptidx:%d\n"
, (int)mov_query->endOfSegmentIndexToQuery
, (int)l_ptidx
);
}
-
+
if(l_ptidx > mov_query->endOfSegmentIndexToQuery)
{
return (l_rc);
@@ -1883,7 +2130,7 @@ p_mov_execute_or_query(GapMovData *mov_ptr, GapMovQuery *mov_query)
}
} /* end tweenindex subloop */
-
+
/* advance to next path segment */
if(l_fridx >= frameNrAtEndOfSegment)
{
@@ -1935,34 +2182,457 @@ p_mov_execute_or_query(GapMovData *mov_ptr, GapMovQuery *mov_query)
} /* end p_mov_execute_or_query */
-/* ============================================================================
- * p_mov_execute
- * Copy layer(s) from Sourceimage to given destination frame range,
- * varying koordinates and opacity of the copied layer.
- * To each affected destination frame exactly one copy of a source layer is added.
- * The source layer is iterated through all layers of the sourceimage
- * according to stemmode parameter.
- * For the placement the layers act as if their size is equal to their
- * Sourceimages size.
- * ============================================================================
+
+
+/* ---------------------------
+ * p_mov_execute_singleframe
+ * ---------------------------
+ * transform and move layer (specified by mov_ptr->singleFramePtr->drawable_id)
+ * according to move path controlpoints in one destination frame
+ * at the specified pahse (e.g. frame number within a frame range)
+ *
+ * in case the mov_ptr->singleFramePtr->drawable_id is NOT already part
+ * of the processed frame it will be copied to the frame and
+ * the transformation is done on the copy
+ * -- typical secnario when called from storyboard processor --
+ * Otherwise transformation is done on the original
+ * -- typical scenario when called via PDB (as filter in the modify frames feature)
+ *
+ * return the layer_id of the processed resulting layer or -1 on error
+ * (note that additional layers will be created when tween processing is active)
*/
-static long
-p_mov_execute(GapMovData *mov_ptr)
+static gint32
+p_mov_execute_singleframe(GapMovData *mov_ptr)
{
- GapMovQuery *mov_query;
+ GapMovCurrent l_current_data;
+ GapMovCurrent *cur_ptr;
+ GapMovValues *val_ptr;
- mov_query = NULL;
- return(p_mov_execute_or_query(mov_ptr, mov_query));
-}
+ gdouble l_percentage;
+ gdouble l_fpl; /* frames_per_line */
+ long l_frame_step;
+ gdouble l_frames;
+ long l_cnt;
+ long l_points;
+ long l_ptidx;
+ long l_prev_keyptidx;
+ long l_fridx;
+ gdouble l_flt_count;
+ gint32 l_rc;
+ gint l_idk;
+ gint l_prev_keyframe;
+ gint l_apv_layerstack;
+ gdouble l_flt_timing[GAP_MOV_MAX_POINT]; /* timing table in relative frame numbers (0.0 == the first handled frame) */
+ gint startOfSegmentIndex;
+ gint endOfSegmentIndex;
+ gint frameNrAtEndOfSegment;
+ GapMovSingleFrame *singleFramePtr;
+ gint32 *tweenLayerIdTable;
+ tweenLayerIdTable = NULL;
+ singleFramePtr = mov_ptr->singleFramePtr;
+ if(singleFramePtr == NULL)
+ {
+ printf("ERROR p_mov_execute_singleframe must not be called wit singleFramePtr NULL!\n");
+ }
-/* ============================================================================
- * gap_mov_exec_anim_preview
- * Generate an animated preview for the move path
- * ============================================================================
- */
+
+ frameNrAtEndOfSegment = 0;
+ l_apv_layerstack = 0;
+ l_percentage = 0.0;
+
+ if(mov_ptr->dst_ainfo_ptr->run_mode == GIMP_RUN_INTERACTIVE)
+ {
+ gimp_progress_init( _("Transforming layer according to move path frame_phase..."));
+ }
+
+ if(gap_debug)
+ {
+ printf("p_mov_execute_singleframe: values got from dialog:\n");
+ p_printf_log_parameters(mov_ptr);
+ }
+
+ l_rc = 0;
+ cur_ptr = &l_current_data;
+ val_ptr = mov_ptr->val_ptr;
+
+ if(gap_image_is_alive(val_ptr->tmpsel_image_id))
+ {
+ gimp_image_delete(val_ptr->tmpsel_image_id);
+ }
+
+ val_ptr->tmpsel_image_id = -1;
+ val_ptr->tmpsel_channel_id = -1;
+ val_ptr->twix = 0;
+
+
+ /* only ascending range processing in single frames mode */
+ l_frame_step = 1;
+ if(singleFramePtr->total_frames > 0)
+ {
+ l_cnt = singleFramePtr->total_frames;
+ }
+ else
+ {
+ l_cnt = 1 + abs(val_ptr->dst_range_end - val_ptr->dst_range_start);
+ }
+
+ l_frames = (gdouble)l_cnt; /* nr. of affected frames */
+ l_points = val_ptr->point_idx_max +1; /* nr. of available points */
+
+ if(l_points > l_frames)
+ {
+ /* cut off some points if we got more than frames */
+ l_points = l_cnt;
+ }
+
+ if(l_points < 2)
+ {
+ p_add_2nd_controlpoint(val_ptr);
+ l_points = 2;
+ }
+
+ startOfSegmentIndex = 0;
+ endOfSegmentIndex = l_points -1; /* initial value in case all points are in only 1 segment */
+
+ cur_ptr->dst_frame_nr = 1;
+ cur_ptr->src_layers = NULL;
+ cur_ptr->src_last_layer = -1;
+ p_init_curr_ptr_with_1st_controlpoint(cur_ptr, val_ptr, singleFramePtr);
+
+ /* set offsets (in cur_ptr) according to handle mode and src_img dimension */
+ gap_mov_exec_set_handle_offsets_singleframe(val_ptr, cur_ptr);
+
+ /* mov_ptr->val_ptr->src_stepmode is ignored in singleframes mode
+ * (e.g. behaves like GAP_STEP_FRAME_NONE)
+ */
+ {
+ gint32 l_sel_channel_id;
+ gboolean l_all_empty;
+
+ if(val_ptr->src_selmode != GAP_MOV_SEL_IGNORE)
+ {
+ l_all_empty = FALSE;
+ if(gimp_selection_is_empty(cur_ptr->singleMovObjImageId))
+ {
+ l_all_empty = TRUE;
+ }
+ l_sel_channel_id = gimp_image_get_selection(cur_ptr->singleMovObjImageId);
+ gap_mov_render_create_or_replace_tempsel_image(l_sel_channel_id, val_ptr, l_all_empty);
+ }
+
+ }
+
+
+ /* create duplicate layers for tween processing (or render first frame) */
+ {
+ gint32 iTween;
+
+
+ /* optional create tweens (n copies of the singleMovObjLayerId) */
+ if (singleFramePtr->frame_phase > 1)
+ {
+ tweenLayerIdTable = g_new(gint32, val_ptr->tween_steps +1);
+ tweenLayerIdTable[0] = cur_ptr->singleMovObjLayerId;
+ for(iTween = 1; iTween <= val_ptr->tween_steps; iTween++)
+ {
+ /* make copies of the cur_ptr->singleMovObjLayerId (one copy foreach tween) */
+ tweenLayerIdTable[iTween] = p_duplicate_layer(cur_ptr->singleMovObjLayerId);
+ }
+ }
+ else
+ {
+ /* RENDER the 1.st frame outside the frameindex loop,
+ * ------ ----
+ * without care about tweens
+ */
+ l_rc = p_mov_call_render(mov_ptr, cur_ptr, l_apv_layerstack);
+ if(l_rc >= 0)
+ {
+ l_rc = cur_ptr->processedLayerId;
+ }
+ return (l_rc);
+ }
+
+ }
+
+
+ /* how many frames are affected from one line of the moving path */
+ l_fpl = ((gdouble)l_frames - 1.0) / ((gdouble)(l_points -1));
+ if(gap_debug)
+ {
+ printf("p_mov_execute_singleframe: initial l_fpl=%f\n", l_fpl);
+ }
+
+ /* calculate l_flt_timing controlpoint timing table considering keyframes */
+ l_prev_keyptidx = 0;
+ l_prev_keyframe = 0;
+ l_flt_timing[0] = 0.0;
+ l_flt_timing[l_points -1] = l_frames -1;
+ l_flt_count = 0.0;
+ for(l_ptidx=1; l_ptidx < l_points - 1; l_ptidx++)
+ {
+ /* search for keyframes */
+ if(l_ptidx > l_prev_keyptidx)
+ {
+ for(l_idk = l_ptidx; l_idk < l_points; l_idk++)
+ {
+ if(l_idk == l_points -1)
+ {
+ /* last point is always an implicite keyframe */
+ l_fpl = ((gdouble)((l_frames -1) - l_prev_keyframe)) / ((gdouble)((l_idk - l_ptidx) +1));
+ l_prev_keyframe = l_frames -1;
+
+ l_prev_keyptidx = l_idk;
+ if(gap_debug) printf("p_mov_execute_singleframe: last point is implicite keyframe l_fpl=%f\n", l_fpl);
+ break;
+ }
+ else
+ {
+ if (val_ptr->point[l_idk].keyframe > 0)
+ {
+ /* found a keyframe, have to recalculate frames_per_line */
+ l_fpl = ((gdouble)(val_ptr->point[l_idk].keyframe - l_prev_keyframe)) / ((gdouble)((l_idk - l_ptidx) +1));
+ l_prev_keyframe = val_ptr->point[l_idk].keyframe;
+
+ l_prev_keyptidx = l_idk;
+ if(gap_debug) printf("p_mov_execute_singleframe: keyframe l_fpl=%f\n", l_fpl);
+ break;
+ }
+ }
+ }
+ }
+ l_flt_count += l_fpl;
+ l_flt_timing[l_ptidx] = l_flt_count;
+
+ if(l_fpl < 1.0)
+ {
+ printf("p_mov_execute_singleframe: ** Error frames per line at point[%d] = %f (is less than 1.0 !!)\n",
+ (int)l_ptidx, (float)l_fpl);
+ }
+ }
+
+ if(gap_debug)
+ {
+ printf("p_mov_execute_singleframe: --- CONTROLPOINT relative frametiming TABLE -----\n");
+ for(l_ptidx=0; l_ptidx < l_points; l_ptidx++)
+ {
+ printf("p_mov_execute_singleframe: l_flt_timing[%02d] = %f\n", (int)l_ptidx, (float)l_flt_timing[l_ptidx]);
+ }
+ }
+
+
+ /* loop for each frame within the range (may step up or down) */
+ l_ptidx = 1;
+ cur_ptr->dst_frame_nr = 1;
+
+ /* frameindex loop */
+ for(l_fridx = 1; l_fridx < l_cnt; l_fridx++)
+ {
+ gdouble l_tw_cnt; /* number of tweens (including the real frame) 1 if no tweens present */
+ gboolean isProcessingFramePhase;
+
+ isProcessingFramePhase = FALSE;
+ if((singleFramePtr->frame_phase == l_fridx +1)
+ || (l_fridx +1 == l_cnt))
+ {
+ isProcessingFramePhase = TRUE;
+ }
+
+ if(gap_debug)
+ {
+ printf("\np_mov_execute_singleframe: l_fridx=%ld, l_flt_timing[l_ptidx]=%f, l_rc=%d l_ptidx=%d, l_prev_keyptidx=%d\n",
+ l_fridx, (float)l_flt_timing[l_ptidx], (int)l_rc, (int)l_ptidx, (int)l_prev_keyptidx);
+ if (isProcessingFramePhase)
+ {
+ printf("Now l_fridx is the frame index that triggers processing relevant Single Frame Phase\n");
+ }
+ }
+ if(l_rc != 0)
+ {
+ break;
+ }
+
+ /* advance frame_nr, (1st frame was done outside this loop) */
+ cur_ptr->dst_frame_nr += l_frame_step; /* +1 or -1 */
+
+ if((gdouble)l_fridx > l_flt_timing[l_ptidx])
+ {
+ /* fix for object jumps forth and back as reported in #607927 */
+ if(val_ptr->point[l_ptidx].keyframe > 0)
+ {
+ if((endOfSegmentIndex != l_points -1) && (endOfSegmentIndex > 0))
+ {
+ startOfSegmentIndex = endOfSegmentIndex;
+ }
+ }
+
+ /* change deltas for next line of the move path */
+ if(l_ptidx < l_points-1)
+ {
+ l_ptidx++;
+
+ if(gap_debug)
+ {
+ printf("p_mov_execute_singleframe: advance to controlpoint l_ptidx=%d, l_flt_timing[l_ptidx]=%f startOfSegmentIndex:%d endOfSegmentIndex:%d\n"
+ , (int)l_ptidx
+ , (float)l_flt_timing[l_ptidx]
+ , (int)startOfSegmentIndex
+ , (int)endOfSegmentIndex
+ );
+ }
+ }
+ else
+ {
+ if(gap_debug)
+ {
+ printf("p_mov_execute_singleframe: ** ERROR overflow l_ptidx=%d\n", (int)l_ptidx);
+ }
+ }
+ }
+
+ l_fpl = (l_flt_timing[l_ptidx] - l_flt_timing[l_ptidx -1]); /* float frames per line */
+
+ l_tw_cnt = (gdouble)(val_ptr->tween_steps +1);
+
+ /* loop for the tweens
+ * (tweens are virtual frames between the previous and the current frame)
+ * when val_ptr->twix is down to 0, the current real frame is reached
+ */
+ for (val_ptr->twix = val_ptr->tween_steps; val_ptr->twix >= 0; val_ptr->twix--)
+ {
+ gdouble l_flt_posfactor;
+
+ if(l_fpl != 0.0)
+ {
+ l_flt_posfactor = ( (((gdouble)l_fridx * l_tw_cnt) - (gdouble)val_ptr->twix)
+ - (l_flt_timing[l_ptidx -1] * l_tw_cnt)
+ ) / (l_fpl * l_tw_cnt);
+ }
+ else
+ {
+ l_flt_posfactor = 1.0;
+ if(gap_debug) printf("p_mov_execute_singleframe: ** ERROR l_fpl is 0.0 frames per line\n");
+ }
+
+ l_flt_posfactor = CLAMP (l_flt_posfactor, 0.0, 1.0);
+
+ endOfSegmentIndex = p_findEndOfSegmentIndex(val_ptr, startOfSegmentIndex, l_points);
+ frameNrAtEndOfSegment = p_calculate_relframe_nr_at_index(val_ptr, endOfSegmentIndex, l_frames);
+
+ frameNrAtEndOfSegment = p_calculate_settings_for_current_FrameTween(val_ptr, cur_ptr
+ , l_fpl
+ , l_fridx
+ , l_ptidx
+ , l_flt_posfactor
+ , l_frames
+ , l_points
+ , startOfSegmentIndex
+ , endOfSegmentIndex
+ , NULL /* mov_query */
+ );
+
+
+
+ if(l_frame_step < 0)
+ {
+ /* if we step down, we have to insert the layer
+ * as lowest layer in the existing layerstack
+ * of the animated preview multilayer image.
+ * (if we step up, we always use 0 as l_apv_layerstack,
+ * that means always insert on top of the layerstack)
+ */
+ l_apv_layerstack++;
+ }
+
+ if (isProcessingFramePhase)
+ {
+ cur_ptr->singleMovObjLayerId = tweenLayerIdTable[val_ptr->twix];
+
+
+ /* RENDER add current src_layer to current frame */
+ l_rc = p_mov_call_render(mov_ptr, cur_ptr, l_apv_layerstack);
+ }
+
+ } /* end tweenindex subloop */
+
+ if (isProcessingFramePhase)
+ {
+ /* returncode handling (id of the resulting processed layer) */
+ if(l_rc >= 0)
+ {
+ l_rc = cur_ptr->processedLayerId;
+ }
+ /* stop after the relevant single frame (and its tweens) was already processed */
+ break;
+ }
+
+ /* advance to next path segment */
+ if(l_fridx >= frameNrAtEndOfSegment)
+ {
+ startOfSegmentIndex = endOfSegmentIndex;
+ }
+
+ ///* show progress */ // TODO
+ //if((mov_ptr->dst_ainfo_ptr->run_mode == GIMP_RUN_INTERACTIVE)
+ //&& (mov_query == NULL))
+ //{
+ // l_percentage = (gdouble)l_fridx / (gdouble)(l_cnt -1);
+ // gimp_progress_update (l_percentage);
+ //}
+
+ } /* end frameindex loop */
+
+ /* delete the temp selection image */
+ if(gap_image_is_alive(val_ptr->tmpsel_image_id))
+ {
+ gimp_image_delete(val_ptr->tmpsel_image_id);
+ }
+
+ val_ptr->tmpsel_image_id = -1;
+ val_ptr->tmpsel_channel_id = -1;
+
+ if (tweenLayerIdTable != NULL)
+ {
+ g_free(tweenLayerIdTable);
+ }
+
+ return l_rc;
+
+} /* end p_mov_execute_singleframe */
+
+
+
+/* ============================================================================
+ * p_mov_execute
+ * Copy layer(s) from Sourceimage to given destination frame range,
+ * varying koordinates and opacity of the copied layer.
+ * To each affected destination frame exactly one copy of a source layer is added.
+ * The source layer is iterated through all layers of the sourceimage
+ * according to stemmode parameter.
+ * For the placement the layers act as if their size is equal to their
+ * Sourceimages size.
+ * ============================================================================
+ */
+static long
+p_mov_execute(GapMovData *mov_ptr)
+{
+ GapMovQuery *mov_query;
+
+ mov_query = NULL;
+ return(p_mov_execute_or_query(mov_ptr, mov_query));
+}
+
+
+
+
+/* ============================================================================
+ * gap_mov_exec_anim_preview
+ * Generate an animated preview for the move path
+ * ============================================================================
+ */
gint32
gap_mov_exec_anim_preview(GapMovValues *pvals_orig, GapAnimInfo *ainfo_ptr, gint preview_frame_nr)
{
@@ -2275,7 +2945,7 @@ gap_mov_exec_gap_save_pointfile(char *filename, GapMovValues *pvals)
*/
if (pvals->point[l_idx].accPosition != 0)
{
- if (l_idx == 0)
+ if (l_idx == 0)
{
writeAccelerationCharacteristics = TRUE;
}
@@ -2287,7 +2957,7 @@ gap_mov_exec_gap_save_pointfile(char *filename, GapMovValues *pvals)
writeAccelerationCharacteristics = TRUE;
}
}
-
+
if (writeAccelerationCharacteristics == TRUE)
{
optional_params_indicator += 6;
@@ -2327,7 +2997,7 @@ gap_mov_exec_gap_save_pointfile(char *filename, GapMovValues *pvals)
if(writeAccelerationCharacteristics == TRUE)
{
fprintf(l_fp, " %02d %02d %02d %02d %02d %02d"
- , (int)pvals->point[l_idx].accPosition
+ , (int)pvals->point[l_idx].accPosition
, (int)pvals->point[l_idx].accOpacity
, (int)pvals->point[l_idx].accSize
, (int)pvals->point[l_idx].accRotation
@@ -2395,11 +3065,11 @@ gap_mov_exec_gap_load_pointfile(char *filename, GapMovValues *pvals)
l_cnt = gap_base_sscan_flt_numbers(l_ptr, &l_farr[0], MAX_NUMVALUES_PER_LINE);
l_i1 = (gint)l_farr[0];
l_i2 = (gint)l_farr[1];
-
+
if(gap_debug)
{
gint ii;
-
+
printf("scanned %d numbers\n", l_cnt);
for(ii=0; ii < l_cnt; ii++)
{
@@ -2503,7 +3173,7 @@ gap_mov_exec_gap_load_pointfile(char *filename, GapMovValues *pvals)
acc_idx = 8;
break;
case 7:
- /* have six accelerate characteristic values
+ /* have six accelerate characteristic values
* and one keyframe value
*/
acc_idx = 8;
@@ -2948,6 +3618,7 @@ gap_mov_exec_move_path(GimpRunMode run_mode, gint32 image_id, GapMovValues *pval
if(ainfo_ptr != NULL)
{
l_mov_data.val_ptr = pvals;
+ l_mov_data.singleFramePtr = NULL;
if(NULL != l_mov_data.val_ptr)
{
if (0 == gap_lib_dir_ainfo(ainfo_ptr))
@@ -3055,7 +3726,7 @@ gap_mov_exec_query(GapMovValues *val_ptr, GapAnimInfo *ainfo_ptr, GapMovQuery *m
l_mov_ptr = &l_mov_data;
l_pvals = &l_mov_vals;
-
+
if((mov_query != NULL) && (val_ptr != NULL))
{
/* init query results */
@@ -3077,7 +3748,7 @@ gap_mov_exec_query(GapMovValues *val_ptr, GapAnimInfo *ainfo_ptr, GapMovQuery *m
l_pvals->cache_tmp_layer_id = -1;
l_pvals->cache_frame_number = -1;
l_pvals->cache_ainfo_ptr = NULL;
-
+
p_mov_execute_or_query(l_mov_ptr, mov_query);
if(mov_query->minSpeedInPixelsPerFrame < 0)
{
@@ -3087,6 +3758,9 @@ gap_mov_exec_query(GapMovValues *val_ptr, GapAnimInfo *ainfo_ptr, GapMovQuery *m
}
+
+
+
/* ============================================================================
* gap_mov_exec_set_handle_offsets
* set handle offsets according to handle mode and src image dimensions
@@ -3134,3 +3808,261 @@ void gap_mov_exec_set_handle_offsets(GapMovValues *val_ptr, GapMovCurrent *cur_p
}
} /* end gap_mov_exec_set_handle_offsets */
+
+
+/* ------------------------------------
+ * gap_mov_exec_new_GapMovValues
+ * ------------------------------------
+ */
+GapMovValues *gap_mov_exec_new_GapMovValues()
+{
+ GapMovValues *pvals;
+
+ pvals = g_new (GapMovValues, 1);
+
+ pvals->version = GAP_MOV_INT_VERSION;
+ pvals->recordedFrameWidth = 0; /* witdh of the frame (at recording time of the move path settings) */
+ pvals->recordedFrameHeight = 0; /* height of the frame (at recording time of the move path settings) */
+ pvals->recordedObjWidth = 0;
+ pvals->recordedObjHeight = 0;
+ pvals->total_frames = 0;
+ pvals->src_layerstack = 0;
+ pvals->src_filename = NULL;
+
+
+
+ pvals->dst_image_id = -1;
+ pvals->tmp_image_id = -1;
+ pvals->tmpsel_image_id = -1;
+ pvals->tmpsel_channel_id = -1;
+ pvals->apv_mode = 0;
+ pvals->apv_src_frame = -1;
+ pvals->apv_mlayer_image = -1;
+ pvals->apv_gap_paste_buff = NULL;
+ pvals->apv_framerate = 24;
+ pvals->apv_scalex = 100.0;
+ pvals->apv_scaley = 100.0;
+ pvals->cache_src_image_id = -1;
+ pvals->cache_tmp_image_id = -1;
+ pvals->cache_tmp_layer_id = -1;
+ pvals->cache_frame_number = -1;
+ pvals->cache_ainfo_ptr = NULL;
+ pvals->point_idx = 0;
+ pvals->point_idx_max = 0;
+ pvals->src_apply_bluebox = 0;
+ pvals->bbp = NULL;
+
+ pvals->step_speed_factor = 1.0;
+ pvals->tracelayer_enable = FALSE;
+ pvals->trace_opacity_initial = 100.0;
+ pvals->trace_opacity_desc = 80.0;
+ pvals->tween_steps = 0;
+ pvals->tween_opacity_initial = 80.0;
+ pvals->tween_opacity_desc = 80.0;
+
+ return(pvals);
+
+} /* end gap_mov_exec_new_GapMovValues */
+
+
+/* ----------------------------------
+ * gap_mov_exec_move_path_singleframe
+ * ----------------------------------
+ * return image_id (of the new loaded current frame) on success
+ * or -1 on errors
+ */
+gint32
+gap_mov_exec_move_path_singleframe(GimpRunMode run_mode, gint32 image_id
+ , GapMovValues *pvals, GapMovSingleFrame *singleFramePtr)
+{
+ gint32 l_rc;
+ GapAnimInfo *ainfo_ptr;
+ GapMovData l_mov_data;
+
+ l_rc = -1;
+ ainfo_ptr = gap_lib_alloc_ainfo(image_id, run_mode);
+ if(ainfo_ptr != NULL)
+ {
+ l_mov_data.val_ptr = pvals;
+ l_mov_data.singleFramePtr = singleFramePtr;
+
+ if(NULL != l_mov_data.val_ptr)
+ {
+ l_mov_data.val_ptr->cache_src_image_id = -1;
+ l_mov_data.dst_ainfo_ptr = ainfo_ptr;
+
+ if (run_mode == GIMP_RUN_INTERACTIVE)
+ {
+ /* Dialog for singleframes mode
+ */
+ l_rc = gap_mov_dlg_move_dialog_singleframe (singleFramePtr);
+ }
+ else
+ {
+ l_rc = 0;
+ }
+
+
+ if(l_rc >= 0)
+ {
+ /* get parameters and controlpoints from xml_paramfile */
+ if (singleFramePtr->xml_paramfile != NULL)
+ {
+ gboolean isXmlLoadOk;
+
+ isXmlLoadOk = gap_mov_xml_par_load(singleFramePtr->xml_paramfile
+ , pvals
+ , gimp_image_width(image_id)
+ , gimp_image_height(image_id)
+ );
+
+
+ if (!isXmlLoadOk)
+ {
+ l_rc = -1;
+ if (run_mode != GIMP_RUN_NONINTERACTIVE)
+ {
+ g_message(("could not load MovePath settings from file: %s")
+ , singleFramePtr->xml_paramfile);
+ }
+ printf("Execution Error: could not load MovePath settings from file: %s\n",
+ singleFramePtr->xml_paramfile);
+ }
+
+ //if(gap_debug)
+ //{
+ // gap_mov_xml_par_save("pvals_after_load.xml", pvals);
+ //}
+
+ }
+
+ }
+
+
+ if(l_rc >= 0)
+ {
+ /* START of the singleframe PROCESSING */
+ l_rc = p_mov_execute_singleframe(&l_mov_data);
+ }
+
+ if(l_mov_data.val_ptr->cache_tmp_image_id >= 0)
+ {
+ if(gap_debug)
+ {
+ printf("gap_move: DELETE cache_tmp_image_id:%d\n",
+ (int)l_mov_data.val_ptr->cache_tmp_image_id);
+ }
+ /* destroy the cached frame image */
+ gimp_image_delete(l_mov_data.val_ptr->cache_tmp_image_id);
+ }
+
+ }
+
+ gap_lib_free_ainfo(&ainfo_ptr);
+ }
+
+ if (l_rc < 0)
+ {
+ return -1;
+ }
+
+ return(l_rc);
+} /* end gap_mov_exec_move_path_singleframe */
+
+
+/* --------------------------------------
+ * gap_mov_exec_check_valid_xml_paramfile
+ * --------------------------------------
+ * return TRUE on valid movepat xml parameterfile
+ */
+gboolean
+gap_mov_exec_check_valid_xml_paramfile(const char *filename)
+{
+ gboolean isXmlLoadOk;
+ GapMovValues *pvals;
+
+ isXmlLoadOk = FALSE;
+ pvals = gap_mov_exec_new_GapMovValues();
+
+ if(filename != NULL)
+ {
+ if(*filename != '\0')
+ {
+ isXmlLoadOk = gap_mov_xml_par_load(filename
+ , pvals
+ , 640 /* fake actual width */
+ , 480 /* fake actual height */
+ );
+ }
+ }
+ g_free(pvals);
+
+ return (isXmlLoadOk);
+
+} /* end gap_mov_exec_check_valid_xml_paramfile */
+
+
+/* ---------------------------------------------
+ * gap_mov_exec_move_path_singleframe_directcall
+ * ---------------------------------------------
+ * this procedure renders one frame of a movepath sequence.
+ * it is typically called by the storyboard processor.
+ * return the processed layer id
+ */
+gint32
+gap_mov_exec_move_path_singleframe_directcall(gint32 frame_image_id
+ , gint32 drawable_id
+ , gboolean keep_proportions
+ , gboolean fit_width
+ , gboolean fit_height
+ , gint32 frame_phase
+ , const char *xml_paramfile)
+{
+ GapMovValues *pvals;
+ gint32 result_layer_id;
+ GapMovSingleFrame singleframevals;
+
+
+ result_layer_id = -1;
+
+ /* init pvals with default values (to provide defined settings
+ * for optional data that may not be present in the xml parameter file)
+ */
+ pvals = gap_mov_exec_new_GapMovValues();
+ pvals->dst_image_id = frame_image_id;
+
+
+ singleframevals.drawable_id = drawable_id;
+ singleframevals.frame_phase = frame_phase;
+ singleframevals.total_frames = -1; /* get path length (total frames) from xml paramfile */
+ singleframevals.keep_proportions = keep_proportions;
+ singleframevals.fit_width = fit_width;
+ singleframevals.fit_height = fit_height;
+ g_snprintf(&singleframevals.xml_paramfile[0], sizeof(singleframevals.xml_paramfile), "%s", xml_paramfile);
+
+ if(gap_debug)
+ {
+ printf("\ngap_mov_exec_move_path_singleframe_directcall:"
+ " drawable_id:%d frame_image_id:%d frame_phase:%d\n"
+ ,(int)singleframevals.drawable_id
+ ,(int)frame_image_id
+ ,(int)singleframevals.frame_phase
+ );
+ }
+
+
+ result_layer_id = gap_mov_exec_move_path_singleframe(GIMP_RUN_NONINTERACTIVE
+ , frame_image_id, pvals, &singleframevals);
+ if(gap_debug)
+ {
+ printf("gap_mov_exec_move_path_singleframe_directcall:"
+ " result_layer_id:%d orig_drawable_id:%d\n"
+ ,(int)result_layer_id
+ ,(int)drawable_id
+ );
+ }
+
+ g_free(pvals);
+ return (result_layer_id);
+
+} /* end gap_mov_exec_move_path_singleframe_directcall */
diff --git a/gap/gap_mov_exec.h b/gap/gap_mov_exec.h
index 81dca03..53e1948 100644
--- a/gap/gap_mov_exec.h
+++ b/gap/gap_mov_exec.h
@@ -43,6 +43,9 @@
gint32 gap_mov_exec_move_path(GimpRunMode run_mode, gint32 image_id, GapMovValues *pvals, gchar *pointfile, gint rotation_follow, gdouble startangle);
gint32 gap_mov_exec_anim_preview(GapMovValues *pvals_orig, GapAnimInfo *ainfo_ptr, gint preview_frame_nr);
+gint32 gap_mov_exec_move_path_singleframe(GimpRunMode run_mode, gint32 image_id
+ , GapMovValues *pvals, GapMovSingleFrame *singleFramePtr);
+
gchar *gap_mov_exec_chk_keyframes(GapMovValues *pvals);
gint gap_mov_exec_conv_keyframe_to_rel(gint abs_keyframe, GapMovValues *pvals);
@@ -53,6 +56,26 @@ void gap_mov_exec_calculate_rotate_follow(GapMovValues *pvals, gdouble starta
void gap_mov_exec_set_handle_offsets(GapMovValues *val_ptr, GapMovCurrent *cur_ptr);
void gap_mov_exec_query(GapMovValues *val_ptr, GapAnimInfo *ainfo_ptr, GapMovQuery *mov_query);
+GapMovValues *gap_mov_exec_new_GapMovValues();
+
+gboolean gap_mov_exec_check_valid_xml_paramfile(const char *filename);
+
+/* ---------------------------------------------
+ * gap_mov_exec_move_path_singleframe_directcall
+ * ---------------------------------------------
+ * this procedure renders one frame of a movepath sequence.
+ * it is typically called by the storyboard processor.
+ * return the processed layer id
+ */
+gint32 gap_mov_exec_move_path_singleframe_directcall(gint32 frame_image_id
+ , gint32 drawable_id
+ , gboolean keep_proportions
+ , gboolean fit_width
+ , gboolean fit_height
+ , gint32 frame_phase
+ , const char *xml_paramfile
+ );
+
#endif
diff --git a/gap/gap_mov_main.c b/gap/gap_mov_main.c
new file mode 100644
index 0000000..fa3e74c
--- /dev/null
+++ b/gap/gap_mov_main.c
@@ -0,0 +1,713 @@
+/* gap_mov_main.c
+ * 2011.03.09 hof (Wolfgang Hofer)
+ *
+ * GAP ... Gimp Animation Package
+ *
+ * This Module contains:
+ * - MAIN of the GAP Move Path Plugin (and its non interactive variants)
+ * - query registration of GAP Procedures (Video Menu) in the PDB
+ * - run invoke the selected GAP procedure by its PDB name
+ *
+ */
+/* 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:
+ * 2011/03/09 hof: created (moved already existing code from gap_main.c to this new module)
+ */
+
+
+#include "config.h"
+
+/* SYTEM (UNIX) includes */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+/* GIMP includes */
+#include "gtk/gtk.h"
+#include "libgimp/gimp.h"
+#include "libgimp/gimpui.h"
+
+/* GAP includes */
+#include "gap_lib.h"
+#include "gimplastvaldesc.h"
+#include "gap_image.h"
+#include "gap_base_ops.h"
+#include "gap_lock.h"
+#include "gap_mov_exec.h"
+
+#include "gap-intl.h"
+
+
+/* ------------------------
+ * global gap DEBUG switch
+ * ------------------------
+ */
+
+/* int gap_debug = 1; */ /* print debug infos */
+/* int gap_debug = 0; */ /* 0: dont print debug infos */
+
+int gap_debug = 0;
+
+#define PLUGIN_NAME_GAP_MOVE "plug_in_gap_move"
+#define PLUGIN_NAME_GAP_MOVE_PATH_EXT "plug_in_gap_move_path_ext"
+#define PLUGIN_NAME_GAP_MOVE_PATH_EXT2 "plug_in_gap_move_path_ext2"
+#define PLUGIN_NAME_GAP_MOVE_SINGLEFRAME "plug-in-move-path-singleframe"
+
+
+static void query(void);
+static void run(const gchar *name
+ , gint n_params
+ , const GimpParam *param
+ , gint *nreturn_vals
+ , GimpParam **return_vals);
+
+GimpPlugInInfo PLUG_IN_INFO =
+{
+ NULL, /* init_proc */
+ NULL, /* quit_proc */
+ query, /* query_proc */
+ run, /* run_proc */
+};
+
+ static GapMovSingleFrame singleframevals;
+
+ static GimpParamDef return_std[] =
+ {
+ { GIMP_PDB_IMAGE, "curr_frame_image", "the resulting current frame image id" }
+ };
+ static int nreturn_std = G_N_ELEMENTS(return_std) ;
+
+ static GimpParamDef return_single[] =
+ {
+ { GIMP_PDB_DRAWABLE, "resulting_layer", "the resulting processed layer id" }
+ };
+ static int nreturn_single = G_N_ELEMENTS(return_single) ;
+
+
+ static GimpParamDef args_mov[] =
+ {
+ {GIMP_PDB_INT32, "run_mode", "Interactive"},
+ {GIMP_PDB_IMAGE, "image", "Input image (one of the video frames)"},
+ {GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)"},
+ };
+
+ static GimpParamDef args_mov_path_ext[] =
+ {
+ {GIMP_PDB_INT32, "run_mode", "non-interactive"},
+ {GIMP_PDB_IMAGE, "dst_image", "Destination image (one of the video frames), where to insert the animated source layers"},
+ {GIMP_PDB_DRAWABLE, "drawable", "drawable (unused)"},
+ {GIMP_PDB_INT32, "range_from", "destination frame nr to start"},
+ {GIMP_PDB_INT32, "range_to", "destination frame nr to stop (can be lower than range_from)"},
+ {GIMP_PDB_INT32, "nr", "layerstack position where to insert source layer (0 == on top)"},
+ /* source specs */
+ { GIMP_PDB_LAYER, "src_layer_id", "starting LayerID of SourceObject. (use any Multilayeranimated Image, or a video frame of anoter Animation)"},
+ { GIMP_PDB_INT32, "src_stepmode", "0-5 derive inserted object as copy of one layer from a multilayer src_image \n"
+ "100-105 derive inserted object as copy of merged visible layers of a source video frame \n"
+ "0: Layer Loop 1: Layer Loop reverse 2: Layer Once 3: Layer Once reverse 4: Layer PingPong \n"
+ "5: None (use onle the selected src_layer)\n"
+ "100: Frame Loop 101: Frame Loop reverse 102: Frame Once 103: Frame Once reverse 104: Frame PingPong \n"
+ "105: Frame None (use onle the flat copy of the selected frame)\n"
+ },
+ { GIMP_PDB_INT32, "src_handle", "0: handle left top 1: handle left bottom \n"
+ "2: handle right top 3: handle right bottom \n"
+ "4: handle center"},
+ { GIMP_PDB_INT32, "src_paintmode", "4444: keep original paintmode of src_layer 0: GIMP_NORMAL_MODE (see GimpLayerModeEffects -- libgimp/gimpenums.h -- for more information)"},
+ { GIMP_PDB_INT32, "src_force_visible", "1: Set inserted layres visible, 0: insert layers as is"},
+ { GIMP_PDB_INT32, "clip_to_img", "1: Clip inserted layers to Image size of the destination video frame, 0: dont clip"},
+ /* extras */
+ { GIMP_PDB_INT32, "rotation_follow", "0: NO automatic calculation (use the rotation array parameters as it is) \n"
+ "1: Automatic calculation of rotation, following the path vectors, (Ignore rotation array parameters)\n"},
+ { GIMP_PDB_FLOAT, "startangle", "start angle for the first contolpoint (only used if rotation-follow is on)"},
+
+ /* new features of the _ext[ended] API */
+ {GIMP_PDB_FLOAT, "step_speed_factor", "Allows stepping Source and Destination at different speed. (0.1 upto 50 where 1.0 does step snychron, 2.0 Src makes 2 Steps while Destination makes 1 step) "},
+ {GIMP_PDB_INT32, "tween_steps", "0 upto 50, Number of virtual Frames to calculate between 2 destination Frames. (use value 0 if no tween processing should be done)"},
+ {GIMP_PDB_FLOAT, "tween_opacity_initial", "opacity 0.0 upto 100.0 for the tween step that is nearest to the (next) real frame"},
+ {GIMP_PDB_FLOAT, "tween_opacity_desc", "descending opacity 0.0 upto 100.0 for the othertween steps"},
+ {GIMP_PDB_INT32, "tracelayer_enable", "TRUE: calculate a tracelayer (with all steps of the moving objects since first step)"},
+ {GIMP_PDB_FLOAT, "trace_opacity_initial", "opacity 0.0 upto 100.0 for the nearest tracestep to the actual destination frame"},
+ {GIMP_PDB_FLOAT, "trace_opacity_desc", "descending opacity 0.0 upto 100.0 for fading out older positions (that are done before the actual step)"},
+ {GIMP_PDB_INT32, "apply_bluebox", "TRUE: apply blubox filter (using bluebox param VALUES of last successful bluebox run)"},
+ {GIMP_PDB_INT32, "src_selmode", "0: ignore selections in all source images\n"
+ "1: use one selection (from the inital source image) for all handled src layers \n"
+ "2: use selections in all source images (for stepmodes 0-5 there is only one source image)"},
+
+
+ /* CONTROLPOINT Arrays (the _ext API uses FLOAT arrays for more precision) */
+ { GIMP_PDB_INT32, "argc_p_x", "number of controlpoints"},
+ { GIMP_PDB_INT32ARRAY, "p_x", "Controlpoint x-koordinate"},
+ { GIMP_PDB_INT32, "argc_p_y", "number of controlpoints"},
+ { GIMP_PDB_INT32ARRAY, "p_y", "Controlpoint y-koordinate"},
+ { GIMP_PDB_INT32, "argc_opacity", "number of controlpoints"},
+ { GIMP_PDB_FLOATARRAY, "opacity", "Controlpoint opacity value 0 <= value <= 100"},
+ { GIMP_PDB_INT32, "argc_w_resize", "number of controlpoints"},
+ { GIMP_PDB_FLOATARRAY, "w_resize", "width scaling in percent"},
+ { GIMP_PDB_INT32, "argc_h_resize", "number of controlpoints"},
+ { GIMP_PDB_FLOATARRAY, "h_resize", "height scaling in percent"},
+ { GIMP_PDB_INT32, "argc_rotation", "number of controlpoints"},
+ { GIMP_PDB_FLOATARRAY, "rotation", "rotation in degrees"},
+ { GIMP_PDB_INT32, "argc_keyframe_abs", "number of controlpoints"},
+ { GIMP_PDB_INT32ARRAY, "keyframe_abs", "n: fix controlpoint to this frame number, 0: for controlpoints that are not fixed to a frame."},
+
+ /* new CONTROLPOINT ARRAY items of the _ext[ended] API */
+ { GIMP_PDB_INT32, "argc_ttlx", "number of controlpoints"},
+ { GIMP_PDB_FLOATARRAY, "ttlx", "perspective transformfactor for top left X Coordinate (0.0 upto 5.0, value 1.0 does no trasformation)"},
+ { GIMP_PDB_INT32, "argc_ttly", "number of controlpoints"},
+ { GIMP_PDB_FLOATARRAY, "ttly", "perspective transformfactor for top left Y Coordinate (0.0 upto 5.0, value 1.0 does no trasformation)"},
+ { GIMP_PDB_INT32, "argc_ttrx", "number of controlpoints"},
+ { GIMP_PDB_FLOATARRAY, "ttrx", "perspective transformfactor for top right X Coordinate (0.0 upto 5.0, value 1.0 does no trasformation)"},
+ { GIMP_PDB_INT32, "argc_ttry", "number of controlpoints"},
+ { GIMP_PDB_FLOATARRAY, "ttry", "perspective transformfactor for top right Y Coordinate (0.0 upto 5.0, value 1.0 does no trasformation)"},
+ { GIMP_PDB_INT32, "argc_tblx", "number of controlpoints"},
+ { GIMP_PDB_FLOATARRAY, "tblx", "perspective transformfactor for bottom left X Coordinate (0.0 upto 5.0, value 1.0 does no trasformation)"},
+ { GIMP_PDB_INT32, "argc_tbly", "number of controlpoints"},
+ { GIMP_PDB_FLOATARRAY, "tbly", "perspective transformfactor for bottom left Y Coordinate (0.0 upto 5.0, value 1.0 does no trasformation)"},
+ { GIMP_PDB_INT32, "argc_tbrx", "number of controlpoints"},
+ { GIMP_PDB_FLOATARRAY, "tbrx", "perspective transformfactor for bottom right X Coordinate (0.0 upto 5.0, value 1.0 does no trasformation)"},
+ { GIMP_PDB_INT32, "argc_tbry", "number of controlpoints"},
+ { GIMP_PDB_FLOATARRAY, "tbry", "perspective transformfactor for bottom right Y Coordinate (0.0 upto 5.0, value 1.0 does no trasformation)"},
+ { GIMP_PDB_INT32, "argc_sel", "number of controlpoints"},
+ { GIMP_PDB_FLOATARRAY, "sel_feather_radius", "feather radius for selections"},
+ };
+ static int nargs_mov_path_ext = G_N_ELEMENTS (args_mov_path_ext);
+
+ static GimpParamDef args_mov_path_ext2[] =
+ {
+ {GIMP_PDB_INT32, "run_mode", "non-interactive"},
+ {GIMP_PDB_IMAGE, "dst_image", "Destination image (one of the video frames), where to insert the animated source layers"},
+ {GIMP_PDB_DRAWABLE, "drawable", "drawable (unused)"},
+ {GIMP_PDB_INT32, "range_from", "destination frame nr to start"},
+ {GIMP_PDB_INT32, "range_to", "destination frame nr to stop (can be lower than range_from)"},
+ {GIMP_PDB_INT32, "nr", "layerstack position where to insert source layer (0 == on top)"},
+ /* source specs */
+ { GIMP_PDB_LAYER, "src_layer_id", "starting LayerID of SourceObject. (use any Multilayeranimated Image, or an video frame of anoter Animation)"},
+ { GIMP_PDB_INT32, "src_stepmode", "0-5 derive inserted object as copy of one layer from a multilayer src_image \n"
+ "100-105 derive inserted object as copy of merged visible layers of a source video frame \n"
+ "0: Layer Loop 1: Layer Loop reverse 2: Layer Once 3: Layer Once reverse 4: Layer PingPong \n"
+ "5: None (use onle the selected src_layer)\n"
+ "100: Frame Loop 101: Frame Loop reverse 102: Frame Once 103: Frame Once reverse 104: Frame PingPong \n"
+ "105: Frame None (use onle the flat copy of the selected frame)\n"
+ },
+ { GIMP_PDB_INT32, "src_handle", "0: handle left top 1: handle left bottom \n"
+ "2: handle right top 3: handle right bottom \n"
+ "4: handle center"},
+ { GIMP_PDB_INT32, "src_paintmode", "4444: keep original paintmode of src_layer 0: GIMP_NORMAL_MODE (see GimpLayerModeEffects -- libgimp/gimpenums.h -- for more information)"},
+ { GIMP_PDB_INT32, "src_force_visible", "1: Set inserted layres visible, 0: insert layers as is"},
+ { GIMP_PDB_INT32, "clip_to_img", "1: Clip inserted layers to Image size of the destination video frame, 0: dont clip"},
+ /* extras */
+ { GIMP_PDB_INT32, "rotation_follow", "0: NO automatic calculation (use the rotation array parameters as it is) \n"
+ "1: Automatic calculation of rotation, following the path vectors, (Ignore rotation array parameters)\n"},
+ { GIMP_PDB_FLOAT, "startangle", "start angle for the first contolpoint (only used if rotation-follow is on)"},
+
+ /* new features of the _ext[ended] API */
+ {GIMP_PDB_FLOAT, "step_speed_factor", "Allows stepping Source and Destination at different speed. (0.1 upto 50 where 1.0 does step snychron, 2.0 Src makes 2 Steps while Destination makes 1 step) "},
+ {GIMP_PDB_INT32, "tween_steps", "0 upto 50, Number of virtual Frames to calculate between 2 destination Frames. (use value 0 if no tween processing should be done)"},
+ {GIMP_PDB_FLOAT, "tween_opacity_initial", "opacity 0.0 upto 100.0 for the tween step that is nearest to the (next) real frame"},
+ {GIMP_PDB_FLOAT, "tween_opacity_desc", "descending opacity 0.0 upto 100.0 for the othertween steps"},
+ {GIMP_PDB_INT32, "tracelayer_enable", "TRUE: calculate a tracelayer (with all steps of the moving objects since first step)"},
+ {GIMP_PDB_FLOAT, "trace_opacity_initial", "opacity 0.0 upto 100.0 for the nearest tracestep to the actual destination frame"},
+ {GIMP_PDB_FLOAT, "trace_opacity_desc", "descending opacity 0.0 upto 100.0 for fading out older positions (that are done before the actual step)"},
+ {GIMP_PDB_INT32, "apply_bluebox", "TRUE: apply blubox filter (using bluebox param VALUES of last successful bluebox run)"},
+
+ /* CONTROLPOINTs from file */
+ { GIMP_PDB_STRING, "pointfile", "a file with contolpoints (readable text file with one line per controlpoint)"},
+ };
+ static int nargs_mov_path_ext2 = G_N_ELEMENTS (args_mov_path_ext2);
+
+
+ static GimpParamDef args_mov_path_single_frame[] =
+ {
+ {GIMP_PDB_INT32, "run_mode", "non-interactive"},
+ {GIMP_PDB_IMAGE, "dst_image", "Destination image (one of the video frames), where to insert the animated source layers"},
+ {GIMP_PDB_DRAWABLE, "drawable", "drawable to be transfromed and moved according to current phase"},
+ {GIMP_PDB_INT32, "frame_phase", "current frame nr starting at 1 (e.g. phase of movent and transformation along path)"},
+ {GIMP_PDB_INT32, "total_frames", "number of frames for the full movement/transformation. (value 0 uses the recorded number of frames from the xml file)"},
+ {GIMP_PDB_STRING, "xml_paramfile", "a file with move path parameter settings in XML format "},
+ };
+ static int nargs_mov_path_single_frame = G_N_ELEMENTS (args_mov_path_single_frame);
+
+
+
+
+
+
+MAIN ()
+
+static void
+query ()
+{
+ gchar *l_help_str;
+
+ static GimpLastvalDef lastvals[] =
+ {
+ GIMP_LASTVALDEF_GINT32 (GIMP_ITER_FALSE, singleframevals.drawable_id, "drawable_id"),
+ GIMP_LASTVALDEF_GINT32 (GIMP_ITER_TRUE, singleframevals.frame_phase, "frame_phase"),
+ GIMP_LASTVALDEF_GINT32 (GIMP_ITER_FALSE, singleframevals.total_frames, "total_frames"),
+ GIMP_LASTVALDEF_GCHAR (GIMP_ITER_FALSE, singleframevals.xml_paramfile[0], "xml_paramfile"),
+ };
+
+
+ gimp_plugin_domain_register (GETTEXT_PACKAGE, LOCALEDIR);
+
+ /* registration for last values buffer structure (for animated filter apply) */
+ gimp_lastval_desc_register(PLUGIN_NAME_GAP_MOVE_SINGLEFRAME,
+ &singleframevals,
+ sizeof(singleframevals),
+ G_N_ELEMENTS (lastvals),
+ lastvals);
+
+
+ gimp_install_procedure(PLUGIN_NAME_GAP_MOVE,
+ "This plugin copies layer(s) from one sourceimage to multiple frames on disk, varying position, size and opacity.",
+ "For NONINTERACTIVE PDB interfaces see also (plug_in_gap_move_path_ext, plug_in_gap_move_path_ext2)",
+ "Wolfgang Hofer (hof gimp org)",
+ "Wolfgang Hofer",
+ GAP_VERSION_WITH_DATE,
+ N_("Move Path..."),
+ "RGB*",
+ GIMP_PLUGIN,
+ G_N_ELEMENTS (args_mov), nreturn_std,
+ args_mov, return_std);
+
+ l_help_str = g_strdup_printf(
+ "This plugin inserts one layer in each frame of the selected frame range of an Animation\n"
+ " (specified by the dst_image parameter).\n"
+ " An Animation is a series of numbered video frame images on disk where only the current\n"
+ " Frame is opened in the gimp\n"
+ " The inserted layer is derived from another (multilayer)image\n"
+ " or from another Animation (as merged copy of the visible layers in a source frame)\n"
+ " the affected destination frame range is selected by the range_from and range_to parameters\n"
+ " the src_stepmode parameter controls how to derive the layer that is to be inserted.\n"
+ " With the Controlpoint Parameters you can control position (coordinates),\n"
+ " size, rotation, perspective and opacity values of the inserted layer\n"
+ " If you want to move an Object from position AX/AY to BX/BY in a straight line within the range of 24 frames\n"
+ " you need 2 Contolpoints, if you want the object to move following a path\n"
+ " you need some more Controlpoints to do that.\n"
+ " With the rotation_follow Parameter you can force automatic calculation of the rotation for the inserted\n"
+ " layer according to the path vectors it is moving along.\n"
+ " A controlpoint can be fixed to a special framenumber using the keyframe_abs controlpoint-parameter.\n"
+ " Restrictions:\n"
+ " - keyframe_abs numbers must be 0 (== not fixed) or a frame_number within the affected frame range\n"
+ " - keyframes_abs must be in sequence (ascending or descending)\n"
+ " - the first and last controlpoint are always implicit keyframes, and should be passed with keyframe_abs = 0\n"
+ " - the number of controlpoints is limited to a maximum of %d.\n"
+ " the number of controlpoints must be passed in all argc_* parameters\n"
+ "If the TraceLayer feature is turned on, an additional layer\n"
+ " is inserted below the moving object. This Tracelayer shows all steps\n"
+ " of the moving object since the 1st Frame.\n"
+ "With TweenSteps you can calculate virtual Frames between 2 destination frames\n"
+ " all these Steps are collected in another additional Layer.\n"
+ " this Tweenlayer is added below the moving Object in all handled destination Frames\n"
+ "See also (plug_in_gap_move_path, plug_in_gap_move)",
+ (int)GAP_MOV_MAX_POINT);
+
+ gimp_install_procedure(PLUGIN_NAME_GAP_MOVE_PATH_EXT,
+ "This plugin copies layer(s) from one sourceimage or source animation to multiple frames on disk,\n"
+ "with varying position, size, perspective and opacity.\n"
+ ,
+ l_help_str,
+ "Wolfgang Hofer (hof gimp org)",
+ "Wolfgang Hofer",
+ GAP_VERSION_WITH_DATE,
+ NULL, /* do not appear in menus */
+ "RGB*",
+ GIMP_PLUGIN,
+ nargs_mov_path_ext, nreturn_std,
+ args_mov_path_ext, return_std);
+ g_free(l_help_str);
+
+ gimp_install_procedure(PLUGIN_NAME_GAP_MOVE_PATH_EXT2,
+ "This plugin copies layer(s) from one sourceimage or source animation to multiple frames on disk,\n"
+ "with varying position, size, perspective and opacity.\n"
+ ,
+ "This plugin is just another Interface for the MovePath (plug_in_gap_move_path_ext)\n"
+ " using a File to specify Controlpoints (rather than Array parameters).\n"
+ " Notes:\n"
+ " - you can create a controlpoint file with in the MovePath Dialog (interactive call of plug_in_gap_move)\n"
+ " - for more infos about controlpoints see help of (plug_in_gap_move_path)\n"
+ ,
+ "Wolfgang Hofer (hof gimp org)",
+ "Wolfgang Hofer",
+ GAP_VERSION_WITH_DATE,
+ NULL, /* do not appear in menus */
+ "RGB*",
+ GIMP_PLUGIN,
+ nargs_mov_path_ext2, nreturn_std,
+ args_mov_path_ext2, return_std);
+
+
+ gimp_install_procedure(PLUGIN_NAME_GAP_MOVE_SINGLEFRAME,
+ "This plugin transforms and moves the specified layer according to the settings of the \n"
+ "specified move path xml parameterfile and to the specified frame_phase parameter.\n"
+ ,
+ "This plugin is intended to run as filter in the gimp-gap modify frames feature\n"
+ " to transform and move an already existng layer along a path where each frame \n"
+ " is processed in a separate call of this plug-in. The frame_phase parameter \n"
+ " shall start at 1 in the 1st call and shall count up to total_frames in the other calls.\n"
+ " Notes:\n"
+ " - you can create the xml parameterfile with in the MovePath Dialog (interactive call of plug_in_gap_move)\n"
+ ,
+ "Wolfgang Hofer (hof gimp org)",
+ "Wolfgang Hofer",
+ GAP_VERSION_WITH_DATE,
+ N_("Move Path Singleframe..."),
+ "RGB*",
+ GIMP_PLUGIN,
+ nargs_mov_path_single_frame, nreturn_single,
+ args_mov_path_single_frame, return_single);
+
+
+
+
+ {
+ /* Menu names */
+ const char *menupath_image_video = N_("<Image>/Video/");
+
+ //gimp_plugin_menu_branch_register("<Image>", "Video");
+
+ gimp_plugin_menu_register (PLUGIN_NAME_GAP_MOVE, menupath_image_video);
+ gimp_plugin_menu_register (PLUGIN_NAME_GAP_MOVE_SINGLEFRAME, menupath_image_video);
+ }
+} /* end query */
+
+
+
+static void
+run (const gchar *name
+ , gint n_params
+ , const GimpParam *param
+ , gint *nreturn_vals
+ , GimpParam **return_vals)
+{
+ const char *l_env;
+
+ static GimpParam values[20];
+ GimpRunMode run_mode;
+ GimpRunMode lock_run_mode;
+ GimpPDBStatusType status;
+ gint32 image_id;
+ gint32 lock_image_id;
+
+
+ gint32 l_rc_image;
+
+ /* init std return values status and image (as used in most of the gap plug-ins) */
+ *nreturn_vals = 2;
+ *return_vals = values;
+ status = GIMP_PDB_SUCCESS;
+ values[0].type = GIMP_PDB_STATUS;
+ values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
+ values[1].type = GIMP_PDB_IMAGE;
+ values[1].data.d_int32 = -1;
+
+ l_rc_image = -1;
+
+
+ l_env = g_getenv("GAP_DEBUG");
+ if(l_env != NULL)
+ {
+ if((*l_env != 'n') && (*l_env != 'N')) gap_debug = 1;
+ }
+
+ run_mode = param[0].data.d_int32;
+ lock_run_mode = run_mode;
+
+ if(gap_debug)
+ {
+ printf("\ngap_mov_main: debug name = %s\n", name);
+ }
+
+ /* gimp_ui_init is sometimes needed even in NON-Interactive
+ * runmodes.
+ * because thumbnail handling uses the procedure gdk_pixbuf_new_from_file
+ * that will crash if not initialized
+ * so better init always, just to be on the save side.
+ * (most diaolgs do init a 2.nd time but this worked well)
+ */
+ gimp_ui_init ("gap_mov_main", FALSE);
+
+ image_id = param[1].data.d_image;
+ if(!gap_image_is_alive(image_id))
+ {
+ printf("GAP plug-in was called on INVALID IMAGE_ID:%d (terminating)\n",
+ (int)image_id);
+ status = GIMP_PDB_EXECUTION_ERROR;
+ values[0].data.d_status = status;
+ return ;
+ }
+ lock_image_id = image_id;
+
+
+ /* ---------------------------
+ * check for LOCKS
+ * ---------------------------
+ */
+ if(gap_lock_check_for_lock(lock_image_id, lock_run_mode))
+ {
+ status = GIMP_PDB_EXECUTION_ERROR;
+ values[0].data.d_status = status;
+ return ;
+ }
+
+
+ /* set LOCK on current image (for all gap_plugins) */
+ gap_lock_set_lock(lock_image_id);
+
+ INIT_I18N();
+
+ if (strcmp (name, PLUGIN_NAME_GAP_MOVE) == 0)
+ {
+ GapMovValues *pvals;
+
+ pvals = gap_mov_exec_new_GapMovValues();
+ pvals->dst_image_id = image_id;
+ if (run_mode == GIMP_RUN_NONINTERACTIVE)
+ {
+ status = GIMP_PDB_CALLING_ERROR;
+ }
+
+ if (status == GIMP_PDB_SUCCESS)
+ {
+ l_rc_image = gap_mov_exec_move_path(run_mode, image_id, pvals, NULL, 0, 0);
+ }
+ g_free(pvals);
+ }
+ else if (strcmp (name, PLUGIN_NAME_GAP_MOVE_SINGLEFRAME) == 0)
+ {
+ GapMovValues *pvals;
+ gint l_dataSize;
+
+ values[1].type = GIMP_PDB_DRAWABLE;
+
+ /* init pvals with default values (to provide defined settings
+ * for optional data that may not be present in the xml parameter file)
+ */
+ pvals = gap_mov_exec_new_GapMovValues();
+ pvals->dst_image_id = image_id;
+
+ /* Possibly retrieve data from a previous run */
+ l_dataSize = gimp_get_data_size(PLUGIN_NAME_GAP_MOVE_SINGLEFRAME);
+ if(l_dataSize == sizeof(singleframevals))
+ {
+ gimp_get_data (PLUGIN_NAME_GAP_MOVE_SINGLEFRAME, &singleframevals);
+ }
+
+ singleframevals.drawable_id = param[2].data.d_drawable;
+ singleframevals.keep_proportions = FALSE;
+ singleframevals.fit_width = TRUE;
+ singleframevals.fit_height = TRUE;
+
+ if (run_mode == GIMP_RUN_NONINTERACTIVE)
+ {
+ if (n_params != nargs_mov_path_single_frame)
+ {
+ status = GIMP_PDB_CALLING_ERROR;
+ }
+ else
+ {
+ singleframevals.frame_phase = param[3].data.d_int32;
+ singleframevals.total_frames = param[4].data.d_int32;
+ if(param[5].data.d_string != NULL)
+ {
+ if(param[23].data.d_string != NULL)
+ {
+ g_snprintf(&singleframevals.xml_paramfile[0], sizeof(singleframevals.xml_paramfile)
+ , "%s"
+ , param[5].data.d_string
+ );
+ }
+ }
+ else
+ {
+ status = GIMP_PDB_CALLING_ERROR;
+ }
+ }
+
+ }
+
+ if (status == GIMP_PDB_SUCCESS)
+ {
+ gint32 l_rc_layer_id;
+
+ l_rc_layer_id = gap_mov_exec_move_path_singleframe(run_mode, image_id, pvals, &singleframevals);
+ values[1].data.d_int32 = l_rc_layer_id; /* return layer id of the resulting (processed) layer */
+ if(l_rc_image >= 0)
+ {
+ gimp_set_data(PLUGIN_NAME_GAP_MOVE_SINGLEFRAME, &singleframevals, sizeof(singleframevals));
+ }
+ }
+ g_free(pvals);
+
+ }
+ else if ((strcmp (name, PLUGIN_NAME_GAP_MOVE_PATH_EXT) == 0)
+ || (strcmp (name, PLUGIN_NAME_GAP_MOVE_PATH_EXT2) == 0))
+ {
+ GapMovValues *pvals;
+ gchar *pointfile;
+ gint l_idx;
+ gint l_numpoints;
+ gint l_rotation_follow;
+ gint32 l_startangle;
+
+ pointfile = NULL;
+ pvals = gap_mov_exec_new_GapMovValues();
+ pvals->dst_image_id = image_id;
+ l_rotation_follow = 0;
+ l_startangle = 0;
+
+
+ if (run_mode == GIMP_RUN_NONINTERACTIVE)
+ {
+ if ( ((n_params != nargs_mov_path_ext) && (strcmp (name, PLUGIN_NAME_GAP_MOVE_PATH_EXT) == 0))
+ || ((n_params != nargs_mov_path_ext2) && (strcmp (name, PLUGIN_NAME_GAP_MOVE_PATH_EXT2) == 0)))
+ {
+ status = GIMP_PDB_CALLING_ERROR;
+ }
+ else
+ {
+ pvals->dst_range_start = param[3].data.d_int32;
+ pvals->dst_range_end = param[4].data.d_int32;
+ pvals->dst_layerstack = param[5].data.d_int32;
+
+ pvals->src_layer_id = param[6].data.d_layer;
+ pvals->src_stepmode = param[7].data.d_int32;
+ pvals->src_handle = param[8].data.d_int32;
+ pvals->src_paintmode = param[9].data.d_int32;
+ pvals->src_force_visible = param[10].data.d_int32;
+ pvals->clip_to_img = param[11].data.d_int32;
+
+ l_rotation_follow = param[12].data.d_int32;
+ l_startangle = param[13].data.d_float;
+
+ pvals->step_speed_factor = param[14].data.d_float;
+ pvals->tween_steps = param[15].data.d_int32;
+ pvals->tween_opacity_initial = param[16].data.d_float;
+ pvals->tween_opacity_desc = param[17].data.d_float;
+ pvals->tracelayer_enable = param[18].data.d_int32;
+ pvals->trace_opacity_initial = param[19].data.d_float;
+ pvals->trace_opacity_desc = param[20].data.d_float;
+ pvals->src_apply_bluebox = param[21].data.d_int32;
+ pvals->src_selmode = param[22].data.d_int32;
+
+ if (strcmp (name, PLUGIN_NAME_GAP_MOVE_PATH_EXT) == 0)
+ {
+ /* PLUGIN_NAME_GAP_MOVE_PATH_EXT passes controlpoints as array parameters */
+ l_numpoints = param[23].data.d_int32;
+ if ((l_numpoints != param[25].data.d_int32)
+ || (l_numpoints != param[27].data.d_int32)
+ || (l_numpoints != param[29].data.d_int32)
+ || (l_numpoints != param[31].data.d_int32)
+ || (l_numpoints != param[33].data.d_int32)
+ || (l_numpoints != param[35].data.d_int32)
+ || (l_numpoints != param[37].data.d_int32)
+ || (l_numpoints != param[39].data.d_int32)
+ || (l_numpoints != param[41].data.d_int32)
+ || (l_numpoints != param[43].data.d_int32)
+ || (l_numpoints != param[45].data.d_int32)
+ || (l_numpoints != param[47].data.d_int32)
+ || (l_numpoints != param[49].data.d_int32)
+ || (l_numpoints != param[51].data.d_int32)
+ || (l_numpoints != param[53].data.d_int32))
+ {
+ printf("plug_in_gap_move_path_ext: CallingError: different numbers in the controlpoint array argc parameters\n");
+ status = GIMP_PDB_CALLING_ERROR;
+ }
+ else
+ {
+ pvals->point_idx_max = l_numpoints -1;
+ for(l_idx = 0; l_idx < l_numpoints; l_idx++)
+ {
+ pvals->point[l_idx].p_x = param[24].data.d_int32array[l_idx];
+ pvals->point[l_idx].p_y = param[26].data.d_int32array[l_idx];
+ pvals->point[l_idx].opacity = param[28].data.d_floatarray[l_idx];
+ pvals->point[l_idx].w_resize = param[30].data.d_floatarray[l_idx];
+ pvals->point[l_idx].h_resize = param[32].data.d_floatarray[l_idx];
+ pvals->point[l_idx].rotation = param[34].data.d_floatarray[l_idx];
+ pvals->point[l_idx].keyframe_abs = param[36].data.d_int32array[l_idx];
+ /* pvals->point[l_idx].keyframe = ; */ /* relative keyframes are calculated later */
+ pvals->point[l_idx].ttlx = param[38].data.d_floatarray[l_idx];
+ pvals->point[l_idx].ttly = param[40].data.d_floatarray[l_idx];
+ pvals->point[l_idx].ttrx = param[42].data.d_floatarray[l_idx];
+ pvals->point[l_idx].ttry = param[44].data.d_floatarray[l_idx];
+ pvals->point[l_idx].tblx = param[46].data.d_floatarray[l_idx];
+ pvals->point[l_idx].tbly = param[48].data.d_floatarray[l_idx];
+ pvals->point[l_idx].tbrx = param[50].data.d_floatarray[l_idx];
+ pvals->point[l_idx].tbry = param[52].data.d_floatarray[l_idx];
+ pvals->point[l_idx].sel_feather_radius = param[54].data.d_floatarray[l_idx];
+ }
+ }
+ }
+ else
+ {
+ /* PLUGIN_NAME_GAP_MOVE_PATH_EXT2 operates with controlpoint file */
+ if(param[23].data.d_string != NULL)
+ {
+ pointfile = g_strdup(param[23].data.d_string);
+ }
+ }
+ }
+
+ }
+
+ if (status == GIMP_PDB_SUCCESS)
+ {
+ l_rc_image = gap_mov_exec_move_path(run_mode, image_id, pvals, pointfile, l_rotation_follow, (gdouble)l_startangle);
+ }
+ g_free(pvals);
+ if(pointfile != NULL)
+ {
+ g_free(pointfile);
+ }
+ }
+
+ /* ---------- return handling --------- */
+
+ if(l_rc_image < 0)
+ {
+ if(gap_debug)
+ {
+ printf("gap_mov_main: return GIMP_PDB_EXECUTION_ERROR\n");
+ }
+ status = GIMP_PDB_EXECUTION_ERROR;
+ }
+ else
+ {
+ if(gap_debug) printf("gap_mov_main: return OK\n");
+ /* most gap_plug-ins return an image_id in values[1] */
+ if (values[1].type == GIMP_PDB_IMAGE)
+ {
+ if(gap_debug)
+ {
+ printf("gap_mov_main: return image_id:%d\n", (int)l_rc_image);
+ }
+ values[1].data.d_int32 = l_rc_image; /* return image id of the resulting (current frame) image */
+ }
+ }
+
+ if (run_mode != GIMP_RUN_NONINTERACTIVE)
+ {
+ gimp_displays_flush();
+ }
+
+ values[0].data.d_status = status;
+
+ /* remove LOCK on this image for all gap_plugins */
+ gap_lock_remove_lock(lock_image_id);
+}
diff --git a/gap/gap_mov_render.c b/gap/gap_mov_render.c
index 4d594d0..e0173e6 100644
--- a/gap/gap_mov_render.c
+++ b/gap/gap_mov_render.c
@@ -78,6 +78,11 @@ static void p_mov_transform_perspective(gint32 layer_id
, guint *new_height
);
+static void p_mov_calculate_scale_factors(gint32 image_id, GapMovValues *val_ptr, GapMovCurrent *cur_ptr
+ , guint orig_width, guint orig_height
+ , gdouble *retScaleWidthPercent
+ , gdouble *retScaleheightPercent
+ );
#define BOUNDS(a,x,y) ((a < x) ? x : ((a > y) ? y : a))
@@ -93,7 +98,7 @@ p_get_paintmode(int mode, gint32 src_layer_id)
if(mode == GAP_MOV_KEEP_SRC_PAINTMODE)
{
GimpLayerModeEffects l_mode;
-
+
l_mode = gimp_layer_get_mode(src_layer_id);
return (l_mode);
}
@@ -346,11 +351,367 @@ p_mov_transform_perspective(gint32 layer_id
} /* end p_mov_transform_perspective */
-/* ============================================================================
+
+
+
+/* ----------------------------------------
+ * p_mov_calculate_scale_factors
+ * ----------------------------------------
+ * In case of single frame mode rendering is done with
+ * settings that were saved (recorded) based on frame and moving object size(s)
+ * that may differ from actual sizes at render time.
+ * The scaling factors are adjusted for automatically
+ * pre-scaling depending on scenarios that are controled by 3 flags.
+ *
+ *
+ * Example:
+ * recorded sizes of the frame and the moving object:
+ *
+ * +---------------------+ recordedFrameWidth: 640
+ * | | recordedFrameHeight: 400
+ * | +-------+ |
+ * | |#######| | recordedObjWidth: 320
+ * | |#######| | recordedObjHeight: 240
+ * | +-------+ |
+ * | |
+ * | |
+ * +---------------------+
+ *
+ * actual rendering shall be done on frame size 1280x400
+ * on a moving object of size 400 x 400.
+ *
+ * +------+
+ * |######| orig_width: 400
+ * |######| orig_height: 400
+ * |######|
+ * |######|
+ * +------+
+ *
+ * Prescaling will depending on 3 flags:
+ *
+ * ==== scenarios that allow changing proportions of the moving object =====
+ *
+ * o) fit_width = TRUE, fit_height = TRUE, keep_proportions = FALSE
+ * In this scenario the moving object is pre-scaled to
+ * preScaleWidth and preScaleHeight. This gives same relations
+ * of the moving object / frame as the relations were at recording time,
+ * but deform proportions of the moving object from square to rectangle shape.
+ *
+ * +-------------------------------------+ renderImageWidth: 1280
+ * | | renderImageHeight: 800
+ * | |
+ * | +--------------+ |
+ * | |##############| | preScaleWidth: 640
+ * | |##############| | preScaleHeight: 480
+ * | |##############| |
+ * | |##############| |
+ * | +--------------+ | renderObjWidth: 640
+ * | | renderObjHeight: 480
+ * | |
+ * | |
+ * | |
+ * +-------------------------------------+
+ *
+ * o) fit_width = TRUE, fit_height = FALSE, keep_proportions = FALSE
+ * In this scenario the moving object is scaled to preScaleWidth
+ * and keeps its original height.
+ *
+ * +-------------------------------------+ renderImageWidth: 1280
+ * | | renderImageHeight: 800
+ * | |
+ * | +--------------+ |
+ * | +--------------+ | preScaleWidth: 640
+ * | |##############| | preScaleHeight: 480
+ * | |##############| |
+ * | +--------------+ |
+ * | +--------------+ | renderObjWidth: 640
+ * | | renderObjHeight: 400
+ * | |
+ * | |
+ * | |
+ * +-------------------------------------+
+ *
+ * o) fit_width = FALSE, fit_height = TRUE, keep_proportions = FALSE
+ * In this scenario the moving object is scaled to preScaleHeight
+ * and keeps its original width.
+ *
+ * +-------------------------------------+ renderImageWidth: 1280
+ * | | renderImageHeight: 800
+ * | |
+ * | +---+------+---+ |
+ * | | |######| | | preScaleWidth: 640
+ * | | |######| | | preScaleHeight: 480
+ * | | |######| | |
+ * | | |######| | |
+ * | +---+------+---+ | renderObjWidth: 400
+ * | | renderObjHeight: 480
+ * | |
+ * | |
+ * | |
+ * +-------------------------------------+
+ *
+ *
+ *
+ * ==== scenarios that keep proportions of the moving object =====
+ *
+ *
+ * o) fit_width = TRUE, fit_height = TRUE, keep_proportions = TRUE
+ * In this scenario the moving object is pre-scaled to fit into a rectangle
+ * of size preScaleWidth x preScaleHeight, keeping its original proportions.
+ *
+ * +-------------------------------------+ renderImageWidth: 1280
+ * | | renderImageHeight: 800
+ * | |
+ * | +--+--------+--+ |
+ * | | |########| | | preScaleWidth: 640
+ * | | |########| | | preScaleHeight: 480
+ * | | |########| | |
+ * | | |########| | |
+ * | +--+--------+--+ | renderObjWidth: 480
+ * | | renderObjHeight: 480
+ * | |
+ * | |
+ * | |
+ * +-------------------------------------+
+ *
+ * o) fit_width = TRUE, fit_height = FALSE, keep_proportions = TRUE
+ * In this scenario the moving object is pre-scaled to preScaleWidth
+ * keeping its original proportions.
+ *
+ * +-------------------------------------+ renderImageWidth: 1280
+ * | | renderImageHeight: 800
+ * | +--------------+ |
+ * | +##############+ |
+ * | |##############| | preScaleWidth: 640
+ * | |##############| | preScaleHeight: 480
+ * | |##############| |
+ * | |##############| |
+ * | +##############+ | renderObjWidth: 640
+ * | +--------------+ | renderObjHeight: 640
+ * | |
+ * | |
+ * | |
+ * +-------------------------------------+
+ *
+ * o) fit_width = FALSE, fit_height = TRUE, keep_proportions = TRUE
+ * In this scenario the moving object is pre-scaled to preScaleHeight
+ * keeping its original proportions.
+ *
+ * +-------------------------------------+ renderImageWidth: 1280
+ * | | renderImageHeight: 800
+ * | |
+ * | +--+--------+--+ |
+ * | | |########| | | preScaleWidth: 640
+ * | | |########| | | preScaleHeight: 480
+ * | | |########| | |
+ * | | |########| | |
+ * | +--+--------+--+ | renderObjWidth: 480
+ * | | renderObjHeight: 480
+ * | |
+ * | |
+ * | |
+ * +-------------------------------------+
+ *
+ * o) fit_width = FALSE, fit_height = FALSE, (keep_proportions NOT relevant)
+ * In this scenario the moving object is not pre-scaled scaled
+ * (therefore propotions are unchanged even in case keep_proportions flag is FALSE)
+ *
+ * +-------------------------------------+ renderImageWidth: 1280
+ * | | renderImageHeight: 800
+ * | |
+ * | +--------------+ |
+ * | | +######+ | | preScaleWidth: 640
+ * | | |######| | | preScaleHeight: 480
+ * | | |######| | |
+ * | | +######+ | |
+ * | +--------------+ | renderObjWidth: 400
+ * | | renderObjHeight: 400
+ * | |
+ * | |
+ * | |
+ * +-------------------------------------+
+ *
+ *
+ * Note: the examples above show frame/moving object scenarios with handle object
+ * at center settings and with current scale 100%
+ * (cur_ptr->currWidth == 100 cur_ptr->currHeight == 100)
+ *
+ */
+static void
+p_mov_calculate_scale_factors(gint32 image_id, GapMovValues *val_ptr, GapMovCurrent *cur_ptr
+ , guint orig_width, guint orig_height
+ , gdouble *retScaleWidthPercent
+ , gdouble *retScaleheightPercent
+ )
+{
+ gdouble scaleWidthPercent;
+ gdouble scaleHeightPercent;
+
+
+ scaleWidthPercent = cur_ptr->currWidth;
+ scaleHeightPercent = cur_ptr->currHeight;
+
+
+ if((cur_ptr->isSingleFrame)
+ && (orig_width != 0)
+ && (orig_height != 0))
+ {
+ gint32 renderImageWidth;
+ gint32 renderImageHeight;
+ gdouble preScaleWidth;
+ gdouble preScaleHeight;
+ gdouble preScaleWidthFactor;
+ gdouble preScaleHeightFactor;
+
+ gdouble result_width; /* resulting width at unscaled size (e.g. 100%) */
+ gdouble result_height; /* resulting height at unscaled size (e.g. 100%) */
+ gdouble origWidth;
+ gdouble origHeight;
+
+ origWidth = orig_width;
+ origHeight = orig_height;
+
+
+ renderImageWidth = gimp_image_width(image_id);
+ renderImageHeight = gimp_image_height(image_id);
+ preScaleWidth = origWidth;
+ preScaleHeight = origHeight;
+ preScaleWidthFactor = 1.0;
+ preScaleHeightFactor = 1.0;
+
+ /* calculate preScaleWidth */
+ if((val_ptr->recordedFrameWidth != renderImageWidth)
+ || (val_ptr->recordedObjWidth != orig_width))
+ {
+ if(val_ptr->recordedFrameWidth != 0)
+ {
+ preScaleWidth = (gdouble)val_ptr->recordedObjWidth * (gdouble)renderImageWidth / (gdouble)val_ptr->recordedFrameWidth;
+ }
+ }
+
+ /* calculate preScaleHeight */
+ if((val_ptr->recordedFrameHeight != renderImageHeight)
+ || (val_ptr->recordedObjHeight != orig_height))
+ {
+ if(val_ptr->recordedFrameHeight != 0)
+ {
+ preScaleHeight = (gdouble)val_ptr->recordedObjHeight * (gdouble)renderImageHeight / (gdouble)val_ptr->recordedFrameHeight;
+ }
+ }
+
+
+
+ /* calculate (unscaled) result sizes according to flags */
+ result_width = orig_width;
+ result_height = orig_height;
+
+ if(cur_ptr->keep_proportions)
+ {
+ gdouble actualObjProportion;
+
+ actualObjProportion = origWidth / origHeight;
+
+
+ if((cur_ptr->fit_width) && (cur_ptr->fit_height))
+ {
+ result_width = preScaleHeight * actualObjProportion;
+ result_height = preScaleHeight;
+
+ if(result_width > preScaleWidth)
+ {
+ result_width = preScaleWidth;
+ result_height = preScaleWidth / actualObjProportion;
+ }
+ }
+ else
+ {
+ if(cur_ptr->fit_height)
+ {
+ result_height = preScaleHeight;
+ result_width = (gdouble)preScaleHeight * actualObjProportion;
+ }
+ if(cur_ptr->fit_width)
+ {
+ result_width = preScaleWidth;
+ result_height = (gdouble)preScaleHeight / actualObjProportion;
+ }
+ }
+
+ }
+ else
+ {
+ if(cur_ptr->fit_height)
+ {
+ result_height = preScaleHeight;
+ }
+ if(cur_ptr->fit_width)
+ {
+ result_width = preScaleWidth;
+ }
+ }
+
+ preScaleWidthFactor = result_width / origWidth;
+ preScaleHeightFactor = result_height / origHeight;
+
+ scaleWidthPercent = cur_ptr->currWidth * preScaleWidthFactor;
+ scaleHeightPercent = cur_ptr->currHeight * preScaleHeightFactor;
+
+
+
+ if(gap_debug)
+ {
+ printf("p_mov_calculate_scale_factors RESULTS:\n");
+ printf(" FrameSize Recorded:(%d x %d) Actual:(%d x %d) MovObjSize Recorded:(%d x %d) Actual:(%d x %d)\n"
+ ,(int)val_ptr->recordedFrameWidth
+ ,(int)val_ptr->recordedFrameHeight
+ ,(int)renderImageWidth
+ ,(int)renderImageHeight
+ ,(int)val_ptr->recordedObjWidth
+ ,(int)val_ptr->recordedObjHeight
+ ,(int)orig_width
+ ,(int)orig_height
+ );
+ printf(" Prescale flags fit_width:%d fit_height:%d keep_proportions:%d result_width:%.4f result_height:%.4f\n"
+ ,cur_ptr->fit_width
+ ,cur_ptr->fit_height
+ ,cur_ptr->keep_proportions
+ ,(float)result_width
+ ,(float)result_height
+ );
+ printf(" Prescale WxH: (%.3f x %.3f) factors:(%.3f %.3f) scaleWidthPercent:%.3f scaleHeightPercent:%.3f\n"
+ ,(float)preScaleWidth
+ ,(float)preScaleHeight
+ ,(float)preScaleWidthFactor
+ ,(float)preScaleHeightFactor
+ ,(float)scaleWidthPercent
+ ,(float)scaleHeightPercent
+ );
+ }
+ }
+
+
+ /* deliver result values */
+ *retScaleWidthPercent = scaleWidthPercent;
+ *retScaleheightPercent = scaleHeightPercent;
+
+} /* end p_mov_calculate_scale_factors */
+
+
+
+/* -----------------------------------
* gap_mov_render_render
- * insert current source layer into image
- * at current settings (position, size opacity ...)
- * ============================================================================
+ * -----------------------------------
+ * process transformations (current settings position, size opacity ...)
+ * for the current source layer.
+ *
+ * In case current source layer is not already part of the processed frame (image_id)
+ * insert a copy of the current source layer into the processed frame.
+ * and do perform the transformations on the inserted copy.
+ *
+ * Note: in singleframe mode the current source layer may be already
+ * part of the processed frame. In this special case perform the
+ * transformations directly on the source layer.
+ *
*/
gint
gap_mov_render_render(gint32 image_id, GapMovValues *val_ptr, GapMovCurrent *cur_ptr)
@@ -361,6 +722,8 @@ gap_mov_render_render(gint32 image_id, GapMovValues *val_ptr, GapMovCurrent *cur
gint l_src_offset_x, l_src_offset_y; /* layeroffsets as they were in src_image */
guint l_new_width;
guint l_new_height;
+ guint l_potential_new_width;
+ guint l_potential_new_height;
guint l_orig_width;
guint l_orig_height;
gint l_resized_flag;
@@ -368,13 +731,16 @@ gap_mov_render_render(gint32 image_id, GapMovValues *val_ptr, GapMovCurrent *cur
guint l_image_width;
guint l_image_height;
GimpLayerModeEffects l_mode;
+ gdouble scaleWidthPercent;
+ gdouble scaleHeightPercent;
- if(gap_debug)
+ if(gap_debug)
{
printf("gap_mov_render_render: frame/layer: %ld/%ld X=%f, Y=%f\n"
" Width=%f Height=%f\n"
" Opacity=%f Rotate=%f clip_to_img = %d force_visibility = %d\n"
- " src_stepmode = %d\n",
+ " src_stepmode = %d\n"
+ " singleMovObjLayerId=%d singleMovObjIMAGEId=%d (frame)image_id=%d\n",
cur_ptr->dst_frame_nr, cur_ptr->src_layer_idx,
cur_ptr->currX, cur_ptr->currY,
cur_ptr->currWidth,
@@ -383,60 +749,121 @@ gap_mov_render_render(gint32 image_id, GapMovValues *val_ptr, GapMovCurrent *cur
cur_ptr->currRotation,
val_ptr->clip_to_img,
val_ptr->src_force_visible,
- val_ptr->src_stepmode);
+ val_ptr->src_stepmode,
+ cur_ptr->singleMovObjLayerId,
+ gimp_drawable_get_image(cur_ptr->singleMovObjLayerId),
+ image_id
+ );
}
-
- if(val_ptr->src_stepmode < GAP_STEP_FRAME)
+
+ if(cur_ptr->isSingleFrame)
{
- if(gap_debug)
- {
- printf("gap_mov_render_render: Before gap_layer_copy_to_dest_image image_id:%d src_layer_id:%d\n"
- ,(int)image_id, (int)cur_ptr->src_layers[cur_ptr->src_layer_idx]);
- }
l_mode = p_get_paintmode(val_ptr->src_paintmode
- ,cur_ptr->src_layers[cur_ptr->src_layer_idx]
+ ,cur_ptr->singleMovObjLayerId
);
- /* make a copy of the current source layer
- * (using current opacity & paintmode values)
- */
- l_cp_layer_id = gap_layer_copy_to_dest_image(image_id,
- cur_ptr->src_layers[cur_ptr->src_layer_idx],
- cur_ptr->currOpacity,
- l_mode,
- &l_src_offset_x,
- &l_src_offset_y);
+ if(gimp_drawable_get_image(cur_ptr->singleMovObjLayerId) == image_id)
+ {
+ /* the moving object layer id is already part of the processed frame image */
+ l_cp_layer_id = cur_ptr->singleMovObjLayerId;
+ /* findout the offsets of the original layer within the source Image */
+ gimp_drawable_offsets(l_cp_layer_id, &l_src_offset_x, &l_src_offset_y );
+ }
+ else
+ {
+ /* the moving object layer id must be coped to the processed frame image
+ * (this is typically used when called from the storyboard processor
+ * where the frame image is just an empty temporary image without any layers)
+ */
+ if(val_ptr->src_stepmode >= GAP_STEP_FRAME)
+ {
+ gimp_layer_resize_to_image_size(cur_ptr->singleMovObjLayerId);
+ }
+
+ /* make a copy of the moving object layer
+ * (using current opacity & paintmode values at initial unscaled size)
+ * and add the copied layer at dst_layerstack
+ * (layerstack position is not important on an empty image)
+ */
+ l_cp_layer_id = gap_layer_copy_to_dest_image(image_id,
+ cur_ptr->singleMovObjLayerId,
+ cur_ptr->currOpacity,
+ l_mode,
+ &l_src_offset_x,
+ &l_src_offset_y);
+ if(l_cp_layer_id < 0)
+ {
+ cur_ptr->processedLayerId = -1;
+ return -1;
+ }
+ gimp_image_add_layer(image_id, l_cp_layer_id, val_ptr->dst_layerstack);
+
+ }
+
+
}
else
{
+ if(val_ptr->src_stepmode < GAP_STEP_FRAME)
+ {
+ if(gap_debug)
+ {
+ printf("gap_mov_render_render: Before gap_layer_copy_to_dest_image image_id:%d src_layer_id:%d\n"
+ ,(int)image_id, (int)cur_ptr->src_layers[cur_ptr->src_layer_idx]);
+ }
+ l_mode = p_get_paintmode(val_ptr->src_paintmode
+ ,cur_ptr->src_layers[cur_ptr->src_layer_idx]
+ );
+ /* make a copy of the current source layer
+ * (using current opacity & paintmode values)
+ */
+ l_cp_layer_id = gap_layer_copy_to_dest_image(image_id,
+ cur_ptr->src_layers[cur_ptr->src_layer_idx],
+ cur_ptr->currOpacity,
+ l_mode,
+ &l_src_offset_x,
+ &l_src_offset_y);
+ }
+ else
+ {
+ if(gap_debug)
+ {
+ printf("gap_mov_render_render: Before gap_layer_copy_to_dest_image image_id:%d cache_tmp_layer_id:%d\n"
+ ,(int)image_id, (int)val_ptr->cache_tmp_layer_id);
+ }
+ l_mode = p_get_paintmode(val_ptr->src_paintmode
+ ,val_ptr->cache_tmp_layer_id
+ );
+ /* for FRAME based stepmodes use the flattened layer in the cached frame image */
+ l_cp_layer_id = gap_layer_copy_to_dest_image(image_id,
+ val_ptr->cache_tmp_layer_id,
+ cur_ptr->currOpacity,
+ l_mode,
+ &l_src_offset_x,
+ &l_src_offset_y);
+ }
+ /* add the copied layer to current destination image */
if(gap_debug)
{
- printf("gap_mov_render_render: Before gap_layer_copy_to_dest_image image_id:%d cache_tmp_layer_id:%d\n"
- ,(int)image_id, (int)val_ptr->cache_tmp_layer_id);
+ printf("gap_mov_render_render: after layer copy layer_id=%d\n", (int)l_cp_layer_id);
+ }
+ if(l_cp_layer_id < 0)
+ {
+ cur_ptr->processedLayerId = -1;
+ return -1;
}
- l_mode = p_get_paintmode(val_ptr->src_paintmode
- ,val_ptr->cache_tmp_layer_id
- );
- /* for FRAME based stepmodes use the flattened layer in the cahed frame image */
- l_cp_layer_id = gap_layer_copy_to_dest_image(image_id,
- val_ptr->cache_tmp_layer_id,
- cur_ptr->currOpacity,
- l_mode,
- &l_src_offset_x,
- &l_src_offset_y);
- }
-
- /* add the copied layer to current destination image */
- if(gap_debug) printf("gap_mov_render_render: after layer copy layer_id=%d\n", (int)l_cp_layer_id);
- if(l_cp_layer_id < 0)
- {
- return -1;
+ gimp_image_add_layer(image_id, l_cp_layer_id,
+ val_ptr->dst_layerstack);
+ if(gap_debug)
+ {
+ printf("gap_mov_render_render: after add layer\n");
+ }
}
- gimp_image_add_layer(image_id, l_cp_layer_id,
- val_ptr->dst_layerstack);
- if(gap_debug) printf("gap_mov_render_render: after add layer\n");
+ /* set processedLayerId (for return handling in singleframe mode) */
+ cur_ptr->processedLayerId = l_cp_layer_id;
+
if(val_ptr->src_force_visible)
{
@@ -483,17 +910,50 @@ gap_mov_render_render(gint32 image_id, GapMovValues *val_ptr, GapMovCurrent *cur
);
}
- if((cur_ptr->currWidth * cur_ptr->currHeight) > (100.0 * 100.0))
+
+ /* scale percentage values (where 100.0 is original size without scaling) */
+ scaleWidthPercent = cur_ptr->currWidth;
+ scaleHeightPercent = cur_ptr->currHeight;
+
+ /* re-calculate scale percentage values
+ * (for automatically pre-scaling in case of singleframes processing) */
+ p_mov_calculate_scale_factors(image_id, val_ptr, cur_ptr
+ , l_orig_width, l_orig_height
+ , &scaleWidthPercent
+ , &scaleHeightPercent
+ );
+
+
+
+
+
+ if((scaleWidthPercent * scaleHeightPercent) > (100.0 * 100.0))
{
- /* have to scale layer (enlarge) */
- l_resized_flag = 1;
+ l_potential_new_width = (l_orig_width * scaleWidthPercent) / 100;
+ l_potential_new_height = (l_orig_height * scaleHeightPercent) / 100;
+
+ if((l_potential_new_width != l_new_width)
+ || (l_potential_new_height != l_new_height))
+ {
+ /* have to scale layer (enlarge) */
+ l_resized_flag = 1;
+
+ l_new_width = l_potential_new_width;
+ l_new_height = l_potential_new_height;
- l_new_width = (l_orig_width * cur_ptr->currWidth) / 100;
- l_new_height = (l_orig_height * cur_ptr->currHeight) / 100;
- gimp_layer_scale(l_cp_layer_id, l_new_width, l_new_height, 0);
+ if(gap_debug)
+ {
+ printf("SCALING-1 to size (%d x %d)\n"
+ ,(int)l_new_width
+ ,(int)l_new_height
+ );
+ }
+
+ gimp_layer_scale(l_cp_layer_id, l_new_width, l_new_height, 0);
+ }
- /* do 4-point perspective stuff (after enlarge) */
- p_mov_transform_perspective(l_cp_layer_id
+ /* do 4-point perspective stuff (after enlarge) */
+ p_mov_transform_perspective(l_cp_layer_id
, val_ptr
, cur_ptr
, &l_resized_flag
@@ -512,14 +972,24 @@ gap_mov_render_render(gint32 image_id, GapMovValues *val_ptr, GapMovCurrent *cur
, &l_new_height
);
- if((cur_ptr->currWidth > 100.01) || (cur_ptr->currWidth < 99.99)
- || (cur_ptr->currHeight > 100.01) || (cur_ptr->currHeight < 99.99))
+ l_potential_new_width = (l_new_width * scaleWidthPercent) / 100;
+ l_potential_new_height = (l_new_height * scaleHeightPercent) / 100;
+
+ if((l_potential_new_width != l_new_width)
+ || (l_potential_new_height != l_new_height))
{
/* have to scale layer */
l_resized_flag = 1;
- l_new_width = (l_new_width * cur_ptr->currWidth) / 100;
- l_new_height = (l_new_height * cur_ptr->currHeight) / 100;
+ l_new_width = l_potential_new_width;
+ l_new_height = l_potential_new_height;
+ if(gap_debug)
+ {
+ printf("SCALING-2 to size (%d x %d)\n"
+ ,(int)l_new_width
+ ,(int)l_new_height
+ );
+ }
gimp_layer_scale(l_cp_layer_id, l_new_width, l_new_height, 0);
}
}
@@ -640,16 +1110,20 @@ gap_mov_render_render(gint32 image_id, GapMovValues *val_ptr, GapMovCurrent *cur
val_ptr->trace_layer_id = gap_image_merge_visible_layers(val_ptr->trace_image_id, l_mergemode);
}
- if(gap_debug) printf("GAP gap_mov_render_render: exit OK\n");
+ if(gap_debug)
+ {
+ printf("GAP gap_mov_render_render: exit OK\n");
+ }
return 0;
} /* end gap_mov_render_render */
+
/* ============================================================================
* gap_mov_render_fetch_src_frame
* fetch the requested video frame SourceImage into cache_tmp_image_id
* and
- * - reduce all visible layer to one layer (cache_tmp_layer_id)
+ * - reduce all visible layers to one layer (cache_tmp_layer_id)
* - (scale to animated preview size if called for AnimPreview )
* - reuse cached image (for subsequent calls for the same framenumber
* of the same source image -- for GAP_STEP_FRAME_NONE
diff --git a/gap/gap_mov_xml_par.c b/gap/gap_mov_xml_par.c
new file mode 100644
index 0000000..eaf39e4
--- /dev/null
+++ b/gap/gap_mov_xml_par.c
@@ -0,0 +1,1651 @@
+/* gap_mov_xml_par.c
+ * 2011.03.09 hof (Wolfgang Hofer)
+ *
+ * GAP ... Gimp Animation Plugins
+ *
+ * Move Path : XML parameterfile load and save procedures.
+ * The XML parameterfile contains full information of all parameters
+ * available in the move path feature including:
+ * version
+ * frame description, moving object description
+ * tweens, trace layer, bluebox settings and controlpoints.
+ *
+ * Note that the old pointfile format is still supported
+ * but not handled here.
+ * (the old pointfile format is limited to information about the controlpoints that build the path
+ * see gap_mov_exec module for load/save support of the old pointfile format)
+ *
+ */
+/* 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:
+ * 2011.03.09 hof: created.
+ */
+
+#include "config.h"
+
+/* SYTEM (UNIX) includes */
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <errno.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <glib/gstdio.h>
+
+/* GIMP includes */
+#include "gtk/gtk.h"
+#include "libgimp/gimp.h"
+
+/* GAP includes */
+#include "gap_libgapbase.h"
+#include "gap-intl.h"
+#include "gap_lib.h"
+#include "gap_mov_dialog.h"
+#include "gap_mov_exec.h"
+#include "gap_mov_render.h"
+#include "gap_mov_xml_par.h"
+#include "gap_accel_char.h"
+#include "gap_bluebox.h"
+#include "gap_xml_util.h"
+
+
+/* The xml tokens (element and attribute names) */
+#define GAP_MOVPATH_XML_TOKEN_ROOT "gimp_gap_move_path_parameters"
+#define GAP_MOVPATH_XML_TOKEN_VERSION "version"
+#define GAP_MOVPATH_XML_TOKEN_FRAME_DESCRIPTION "frame_description"
+#define GAP_MOVPATH_XML_TOKEN_WIDTH "width"
+#define GAP_MOVPATH_XML_TOKEN_HEIGHT "height"
+#define GAP_MOVPATH_XML_TOKEN_RANGE_FROM "range_from"
+#define GAP_MOVPATH_XML_TOKEN_RANGE_TO "range_to"
+#define GAP_MOVPATH_XML_TOKEN_TOTAL_FRAMES "total_frames"
+#define GAP_MOVPATH_XML_TOKEN_TWEEN "tween"
+#define GAP_MOVPATH_XML_TOKEN_TWEEN_STEPS "tween_steps"
+#define GAP_MOVPATH_XML_TOKEN_TWEEN_OPACITY_INITIAL "tween_opacity_initial"
+#define GAP_MOVPATH_XML_TOKEN_TWEEN_OPACITY_DESC "tween_opacity_desc"
+#define GAP_MOVPATH_XML_TOKEN_TRACE "trace"
+#define GAP_MOVPATH_XML_TOKEN_TRACELAYER_ENABLE "tracelayer_enable"
+#define GAP_MOVPATH_XML_TOKEN_TRACE_OPACITY_INITIAL "trace_opacity_initial"
+#define GAP_MOVPATH_XML_TOKEN_TRACE_OPACITY_DESC "trace_opacity_desc"
+#define GAP_MOVPATH_XML_TOKEN_MOVING_OBJECT "moving_object"
+#define GAP_MOVPATH_XML_TOKEN_SRC_STEPMODE "src_stepmode"
+#define GAP_MOVPATH_XML_TOKEN_SRC_HANDLE "src_handle"
+#define GAP_MOVPATH_XML_TOKEN_SRC_SELMODE "src_selmode"
+#define GAP_MOVPATH_XML_TOKEN_SRC_PAINTMODE "src_paintmode"
+#define GAP_MOVPATH_XML_TOKEN_DST_LAYERSTACK "dst_layerstack"
+#define GAP_MOVPATH_XML_TOKEN_STEP_SPEED_FACTOR "step_speed_factor"
+#define GAP_MOVPATH_XML_TOKEN_SRC_FORCE_VISIBLE "src_force_visible"
+#define GAP_MOVPATH_XML_TOKEN_CLIP_TO_IMG "clip_to_img"
+#define GAP_MOVPATH_XML_TOKEN_SRC_APPLY_BLUEBOX "src_apply_bluebox"
+#define GAP_MOVPATH_XML_TOKEN_SRC_LAYER_ID "src_layer_id"
+#define GAP_MOVPATH_XML_TOKEN_SRC_LAYERSTACK "src_layerstack"
+#define GAP_MOVPATH_XML_TOKEN_SRC_FILENAME "src_filename"
+#define GAP_MOVPATH_XML_TOKEN_BLUEBOX_PARAMETERS "gimp_gap_bluebox_parameters"
+#define GAP_MOVPATH_XML_TOKEN_THRES_MODE "thres_mode"
+#define GAP_MOVPATH_XML_TOKEN_THRES_R "thres_r"
+#define GAP_MOVPATH_XML_TOKEN_THRES_G "thres_g"
+#define GAP_MOVPATH_XML_TOKEN_THRES_B "thres_b"
+#define GAP_MOVPATH_XML_TOKEN_THRES_H "thres_h"
+#define GAP_MOVPATH_XML_TOKEN_THRES_S "thres_s"
+#define GAP_MOVPATH_XML_TOKEN_THRES_V "thres_v"
+#define GAP_MOVPATH_XML_TOKEN_THRES "thres"
+#define GAP_MOVPATH_XML_TOKEN_TOLERANCE "tolerance"
+#define GAP_MOVPATH_XML_TOKEN_GROW "grow"
+#define GAP_MOVPATH_XML_TOKEN_FEATHER_EDGES "feather_edges"
+#define GAP_MOVPATH_XML_TOKEN_FEATHER_RADIUS "feather_radius"
+#define GAP_MOVPATH_XML_TOKEN_SOURCE_ALPHA "source_alpha"
+#define GAP_MOVPATH_XML_TOKEN_TARGET_ALPHA "target_alpha"
+#define GAP_MOVPATH_XML_TOKEN_KEYCOLOR_R "keycolor_r"
+#define GAP_MOVPATH_XML_TOKEN_KEYCOLOR_G "keycolor_g"
+#define GAP_MOVPATH_XML_TOKEN_KEYCOLOR_B "keycolor_b"
+#define GAP_MOVPATH_XML_TOKEN_CONTROLPOINTS "controlpoints"
+#define GAP_MOVPATH_XML_TOKEN_CURRENT_POINT "current_point"
+#define GAP_MOVPATH_XML_TOKEN_NUMBER_OF_POINTS "number_of_points"
+#define GAP_MOVPATH_XML_TOKEN_CONTROLPOINT "controlpoint"
+#define GAP_MOVPATH_XML_TOKEN_PX "px"
+#define GAP_MOVPATH_XML_TOKEN_PY "py"
+#define GAP_MOVPATH_XML_TOKEN_KEYFRAME "keyframe"
+#define GAP_MOVPATH_XML_TOKEN_SEL_FEATHER_RADIUS "sel_feather_radius"
+#define GAP_MOVPATH_XML_TOKEN_W_RESIZE "width_resize"
+#define GAP_MOVPATH_XML_TOKEN_H_RESIZE "height_resize"
+#define GAP_MOVPATH_XML_TOKEN_OPACITY "opacity"
+#define GAP_MOVPATH_XML_TOKEN_ROTATION "rotation"
+#define GAP_MOVPATH_XML_TOKEN_TTLX "ttlx"
+#define GAP_MOVPATH_XML_TOKEN_TTLY "ttly"
+#define GAP_MOVPATH_XML_TOKEN_TTRX "ttrx"
+#define GAP_MOVPATH_XML_TOKEN_TTRY "ttry"
+#define GAP_MOVPATH_XML_TOKEN_TBLX "tblx"
+#define GAP_MOVPATH_XML_TOKEN_TBLY "tbly"
+#define GAP_MOVPATH_XML_TOKEN_TBRX "tbrx"
+#define GAP_MOVPATH_XML_TOKEN_TBRY "tbry"
+#define GAP_MOVPATH_XML_TOKEN_ACC_POSITION "acc_position"
+#define GAP_MOVPATH_XML_TOKEN_ACC_OPACITY "acc_opacity"
+#define GAP_MOVPATH_XML_TOKEN_ACC_SIZE "acc_size"
+#define GAP_MOVPATH_XML_TOKEN_ACC_ROTATION "acc_rotation"
+#define GAP_MOVPATH_XML_TOKEN_ACC_PERSPECTIVE "acc_perspective"
+#define GAP_MOVPATH_XML_TOKEN_ACC_SEL_FEATHER_RADIUS "acc_sel_feather_radius"
+
+
+
+
+/* user data passed to parser fuctions */
+typedef struct {
+ GapMovValues *pvals;
+ gboolean isScopeValid;
+ gboolean isParseOk;
+ gint errorLineNumber;
+} GapMovXmlUserData;
+
+/* Function signatures for parsing xml elements and attributes
+ */
+typedef void (*GapMovXmlElementParseFunctionType) (const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ GapMovXmlUserData *userDataPtr,
+ gint count
+ );
+
+
+/* functions for parsing the XML elements */
+
+static void p_xml_parse_element_root(const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ GapMovXmlUserData *userDataPtr,
+ gint count);
+static void p_xml_parse_element_frame_description(const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ GapMovXmlUserData *userDataPtr,
+ gint count);
+static void p_xml_parse_element_tween(const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ GapMovXmlUserData *userDataPtr,
+ gint count);
+static void p_xml_parse_element_trace(const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ GapMovXmlUserData *userDataPtr,
+ gint count);
+static void p_xml_parse_element_moving_object(const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ GapMovXmlUserData *userDataPtr,
+ gint count);
+static void p_xml_parse_element_trace(const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ GapMovXmlUserData *userDataPtr,
+ gint count);
+static void p_xml_parse_element_bluebox_parameters(const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ GapMovXmlUserData *userDataPtr,
+ gint count);
+static void p_xml_parse_element_controlpoints(const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ GapMovXmlUserData *userDataPtr,
+ gint count);
+static void p_xml_parse_element_controlpoint(const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ GapMovXmlUserData *userDataPtr,
+ gint count);
+
+
+
+
+typedef struct JmpTableElement
+{
+ gint count;
+ gboolean isRequired;
+ const gchar *name;
+ GapMovXmlElementParseFunctionType func_ptr;
+} JmpTableElement;
+
+
+/* ------------------------
+ * STATIC DATA
+ * ------------------------
+ */
+
+
+extern int gap_debug; /* ==0 ... dont print debug infos */
+
+
+/* jump table describes the supported xml element names and their parsing functions */
+static JmpTableElement jmpTableElement[] = {
+ {0, TRUE, GAP_MOVPATH_XML_TOKEN_ROOT, p_xml_parse_element_root }
+ ,{0, TRUE, GAP_MOVPATH_XML_TOKEN_FRAME_DESCRIPTION, p_xml_parse_element_frame_description }
+ ,{0, FALSE, GAP_MOVPATH_XML_TOKEN_TWEEN, p_xml_parse_element_tween }
+ ,{0, FALSE, GAP_MOVPATH_XML_TOKEN_TRACE, p_xml_parse_element_trace }
+ ,{0, TRUE, GAP_MOVPATH_XML_TOKEN_MOVING_OBJECT, p_xml_parse_element_moving_object }
+ ,{0, FALSE, GAP_MOVPATH_XML_TOKEN_BLUEBOX_PARAMETERS, p_xml_parse_element_bluebox_parameters }
+ ,{0, TRUE, GAP_MOVPATH_XML_TOKEN_CONTROLPOINTS, p_xml_parse_element_controlpoints }
+ ,{0, TRUE, GAP_MOVPATH_XML_TOKEN_CONTROLPOINT, p_xml_parse_element_controlpoint }
+ ,{0, FALSE, NULL, NULL }
+};
+
+
+static const GEnumValue valuesGapMovHandle[] =
+{
+ { GAP_HANDLE_LEFT_TOP, "GAP_HANDLE_LEFT_TOP", NULL },
+ { GAP_HANDLE_LEFT_BOT, "GAP_HANDLE_LEFT_BOT", NULL },
+ { GAP_HANDLE_RIGHT_TOP, "GAP_HANDLE_RIGHT_TOP", NULL },
+ { GAP_HANDLE_RIGHT_BOT, "GAP_HANDLE_RIGHT_BOT", NULL },
+ { GAP_HANDLE_CENTER, "GAP_HANDLE_CENTER", NULL },
+ { 0, NULL, NULL }
+};
+
+static const GEnumValue valuesGapMovStepMode[] =
+{
+ { GAP_STEP_LOOP, "GAP_STEP_LOOP", NULL },
+ { GAP_STEP_LOOP_REV, "GAP_STEP_LOOP_REV", NULL },
+ { GAP_STEP_ONCE, "GAP_STEP_ONCE", NULL },
+ { GAP_STEP_ONCE_REV, "GAP_STEP_ONCE_REV", NULL },
+ { GAP_STEP_PING_PONG, "GAP_STEP_PING_PONG", NULL },
+ { GAP_STEP_NONE, "GAP_STEP_NONE", NULL },
+ { GAP_STEP_FRAME_LOOP, "GAP_STEP_FRAME_LOOP", NULL },
+ { GAP_STEP_FRAME_LOOP_REV, "GAP_STEP_FRAME_LOOP_REV", NULL },
+ { GAP_STEP_FRAME_ONCE, "GAP_STEP_FRAME_ONCE", NULL },
+ { GAP_STEP_FRAME_ONCE_REV, "GAP_STEP_FRAME_ONCE_REV", NULL },
+ { GAP_STEP_FRAME_PING_PONG, "GAP_STEP_FRAME_PING_PONG", NULL },
+ { GAP_STEP_FRAME_NONE, "GAP_STEP_FRAME_NONE", NULL },
+ { 0, NULL, NULL }
+};
+
+static const GEnumValue valuesGapMovSelMode[] =
+{
+ { GAP_MOV_SEL_IGNORE, "GAP_MOV_SEL_IGNORE", NULL },
+ { GAP_MOV_SEL_INITIAL, "GAP_MOV_SEL_INITIAL", NULL },
+ { GAP_MOV_SEL_FRAME_SPECIFIC, "GAP_MOV_SEL_FRAME_SPECIFIC", NULL },
+ { 0, NULL, NULL }
+};
+
+static const GEnumValue valuesGimpPaintmode[] =
+{
+ { GIMP_NORMAL_MODE, "GIMP_NORMAL_MODE", "normal-mode" },
+ { GIMP_DISSOLVE_MODE, "GIMP_DISSOLVE_MODE", "dissolve-mode" },
+ { GIMP_BEHIND_MODE, "GIMP_BEHIND_MODE", "behind-mode" },
+ { GIMP_MULTIPLY_MODE, "GIMP_MULTIPLY_MODE", "multiply-mode" },
+ { GIMP_SCREEN_MODE, "GIMP_SCREEN_MODE", "screen-mode" },
+ { GIMP_OVERLAY_MODE, "GIMP_OVERLAY_MODE", "overlay-mode" },
+ { GIMP_DIFFERENCE_MODE, "GIMP_DIFFERENCE_MODE", "difference-mode" },
+ { GIMP_ADDITION_MODE, "GIMP_ADDITION_MODE", "addition-mode" },
+ { GIMP_SUBTRACT_MODE, "GIMP_SUBTRACT_MODE", "subtract-mode" },
+ { GIMP_DARKEN_ONLY_MODE, "GIMP_DARKEN_ONLY_MODE", "darken-only-mode" },
+ { GIMP_LIGHTEN_ONLY_MODE, "GIMP_LIGHTEN_ONLY_MODE", "lighten-only-mode" },
+ { GIMP_HUE_MODE, "GIMP_HUE_MODE", "hue-mode" },
+ { GIMP_SATURATION_MODE, "GIMP_SATURATION_MODE", "saturation-mode" },
+ { GIMP_COLOR_MODE, "GIMP_COLOR_MODE", "color-mode" },
+ { GIMP_VALUE_MODE, "GIMP_VALUE_MODE", "value-mode" },
+ { GIMP_DIVIDE_MODE, "GIMP_DIVIDE_MODE", "divide-mode" },
+ { GIMP_DODGE_MODE, "GIMP_DODGE_MODE", "dodge-mode" },
+ { GIMP_BURN_MODE, "GIMP_BURN_MODE", "burn-mode" },
+ { GIMP_HARDLIGHT_MODE, "GIMP_HARDLIGHT_MODE", "hardlight-mode" },
+ { GIMP_SOFTLIGHT_MODE, "GIMP_SOFTLIGHT_MODE", "softlight-mode" },
+ { GIMP_GRAIN_EXTRACT_MODE, "GIMP_GRAIN_EXTRACT_MODE", "grain-extract-mode" },
+ { GIMP_GRAIN_MERGE_MODE, "GIMP_GRAIN_MERGE_MODE", "grain-merge-mode" },
+ { GIMP_COLOR_ERASE_MODE, "GIMP_COLOR_ERASE_MODE", "color-erase-mode" },
+ { GAP_MOV_KEEP_SRC_PAINTMODE, "GAP_MOV_KEEP_SRC_PAINTMODE", "keep-paintmode" },
+ { 0, NULL, NULL }
+};
+
+
+
+static const GEnumValue valuesGapBlueboxThresMode[] =
+{
+ { GAP_BLUBOX_THRES_RGB, "GAP_BLUBOX_THRES_RGB", NULL },
+ { GAP_BLUBOX_THRES_HSV, "GAP_BLUBOX_THRES_HSV", NULL },
+ { GAP_BLUBOX_THRES_VAL, "GAP_BLUBOX_THRES_VAL", NULL },
+ { GAP_BLUBOX_THRES_ALL, "GAP_BLUBOX_THRES_ALL", NULL },
+ { 0, NULL, NULL }
+};
+
+
+
+/*
+ * XML PARSER procedures
+ */
+
+
+
+/* --------------------------------------
+ * p_xml_parse_value_GapMovHandle
+ * --------------------------------------
+ */
+static gboolean
+p_xml_parse_value_GapMovHandle(const gchar *attribute_value, GapMovHandle *valDestPtr)
+{
+ gboolean isOk;
+ gint value;
+
+ isOk = gap_xml_parse_EnumValue_as_gint(attribute_value, &value, &valuesGapMovHandle[0]);
+ if(isOk)
+ {
+ *valDestPtr = value;
+ }
+ return (isOk);
+
+} /* end p_xml_parse_value_GapMovHandle */
+
+
+
+/* --------------------------------------
+ * p_xml_parse_value_GapMovStepMode
+ * --------------------------------------
+ */
+static gboolean
+p_xml_parse_value_GapMovStepMode(const gchar *attribute_value, GapMovStepMode *valDestPtr)
+{
+ gboolean isOk;
+ gint value;
+
+ isOk = gap_xml_parse_EnumValue_as_gint(attribute_value, &value, &valuesGapMovStepMode[0]);
+ if(isOk)
+ {
+ *valDestPtr = value;
+ }
+ return (isOk);
+
+} /* end p_xml_parse_value_GapMovStepMode */
+
+
+/* --------------------------------------
+ * p_xml_parse_value_GapMovSelMode
+ * --------------------------------------
+ */
+static gboolean
+p_xml_parse_value_GapMovSelMode(const gchar *attribute_value, GapMovSelMode *valDestPtr)
+{
+ gboolean isOk;
+ gint value;
+
+ isOk = gap_xml_parse_EnumValue_as_gint(attribute_value, &value, &valuesGapMovSelMode[0]);
+ if(isOk)
+ {
+ *valDestPtr = value;
+ }
+ return (isOk);
+
+} /* end p_xml_parse_value_GapMovSelMode */
+
+
+/* ---------------------------------------
+ * p_xml_parse_value_GimpPaintmode_as_gint
+ * ---------------------------------------
+ */
+static gboolean
+p_xml_parse_value_GimpPaintmode_as_gint(const gchar *attribute_value, gint *valDestPtr)
+{
+ gboolean isOk;
+ gint value;
+
+ isOk = gap_xml_parse_EnumValue_as_gint(attribute_value, &value, &valuesGimpPaintmode[0]);
+ if(isOk)
+ {
+ *valDestPtr = value;
+ }
+ return (isOk);
+
+} /* end gap_xml_parse_value_GimpPaintmode */
+
+
+/* ----------------------------------------
+ * p_xml_parse_value_GapBlueboxThresMode
+ * ----------------------------------------
+ */
+static gboolean
+p_xml_parse_value_GapBlueboxThresMode(const gchar *attribute_value, GapBlueboxThresMode *valDestPtr)
+{
+ gboolean isOk;
+ gint value;
+
+ isOk = gap_xml_parse_EnumValue_as_gint(attribute_value, &value, &valuesGapBlueboxThresMode[0]);
+ if(isOk)
+ {
+ *valDestPtr = value;
+ }
+ return (isOk);
+
+} /* end p_xml_parse_value_GapBlueboxThresMode */
+
+
+
+
+/* --------------------------------------
+ * p_xml_parse_element_root
+ * --------------------------------------
+ */
+static void
+p_xml_parse_element_root(const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ GapMovXmlUserData *userDataPtr,
+ gint count)
+{
+ const gchar **name_cursor = attribute_names;
+ const gchar **value_cursor = attribute_values;
+
+ if(count > 0)
+ {
+ userDataPtr->isParseOk = FALSE;
+ }
+
+ while ((*name_cursor) && (userDataPtr->isParseOk))
+ {
+ if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_VERSION) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gint32(*value_cursor, &userDataPtr->pvals->version);
+ }
+ name_cursor++;
+ value_cursor++;
+ }
+} /* end p_xml_parse_element_root */
+
+
+
+
+/* --------------------------------------
+ * p_xml_parse_element_frame_description
+ * --------------------------------------
+ */
+static void
+p_xml_parse_element_frame_description(const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ GapMovXmlUserData *userDataPtr,
+ gint count)
+{
+ const gchar **name_cursor = attribute_names;
+ const gchar **value_cursor = attribute_values;
+
+ if(count > 0)
+ {
+ userDataPtr->isParseOk = FALSE;
+ }
+
+ while ((*name_cursor) && (userDataPtr->isParseOk))
+ {
+ if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_WIDTH) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gint32(*value_cursor, &userDataPtr->pvals->recordedFrameWidth);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_HEIGHT) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gint32(*value_cursor, &userDataPtr->pvals->recordedFrameHeight);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_RANGE_FROM) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gint(*value_cursor, &userDataPtr->pvals->dst_range_start);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_RANGE_TO) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gint(*value_cursor, &userDataPtr->pvals->dst_range_end);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_RANGE_TO) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gint32(*value_cursor, &userDataPtr->pvals->total_frames);
+ }
+
+ name_cursor++;
+ value_cursor++;
+ }
+} /* end p_xml_parse_element_frame_description */
+
+
+/* --------------------------------------
+ * p_xml_parse_element_tween
+ * --------------------------------------
+ */
+static void
+p_xml_parse_element_tween(const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ GapMovXmlUserData *userDataPtr,
+ gint count)
+{
+ const gchar **name_cursor = attribute_names;
+ const gchar **value_cursor = attribute_values;
+
+ if(count > 0)
+ {
+ userDataPtr->isParseOk = FALSE;
+ }
+
+ while ((*name_cursor) && (userDataPtr->isParseOk))
+ {
+ if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_TWEEN_STEPS) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gint(*value_cursor, &userDataPtr->pvals->tween_steps);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_TWEEN_OPACITY_INITIAL) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gdouble(*value_cursor, &userDataPtr->pvals->tween_opacity_initial);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_TWEEN_OPACITY_DESC) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gdouble(*value_cursor, &userDataPtr->pvals->tween_opacity_desc);
+ }
+ name_cursor++;
+ value_cursor++;
+ }
+} /* end p_xml_parse_element_tween */
+
+
+
+
+/* --------------------------------------
+ * p_xml_parse_element_trace
+ * --------------------------------------
+ */
+static void
+p_xml_parse_element_trace(const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ GapMovXmlUserData *userDataPtr,
+ gint count)
+{
+ const gchar **name_cursor = attribute_names;
+ const gchar **value_cursor = attribute_values;
+
+ if(count > 0)
+ {
+ userDataPtr->isParseOk = FALSE;
+ }
+
+ while ((*name_cursor) && (userDataPtr->isParseOk))
+ {
+ if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_TRACELAYER_ENABLE) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gboolean_as_gint(*value_cursor, &userDataPtr->pvals->tracelayer_enable);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_TRACE_OPACITY_INITIAL) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gdouble(*value_cursor, &userDataPtr->pvals->trace_opacity_initial);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_TRACE_OPACITY_DESC) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gdouble(*value_cursor, &userDataPtr->pvals->trace_opacity_desc);
+ }
+ name_cursor++;
+ value_cursor++;
+ }
+} /* end p_xml_parse_element_trace */
+
+
+
+
+/* --------------------------------------
+ * p_xml_parse_element_moving_object
+ * --------------------------------------
+ */
+static void
+p_xml_parse_element_moving_object(const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ GapMovXmlUserData *userDataPtr,
+ gint count)
+{
+ const gchar **name_cursor = attribute_names;
+ const gchar **value_cursor = attribute_values;
+
+ if(count > 0)
+ {
+ userDataPtr->isParseOk = FALSE;
+ }
+
+ while ((*name_cursor) && (userDataPtr->isParseOk))
+ {
+ if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_SRC_STEPMODE) == 0)
+ {
+ userDataPtr->isParseOk = p_xml_parse_value_GapMovStepMode(*value_cursor, &userDataPtr->pvals->src_stepmode);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_WIDTH) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gint32(*value_cursor, &userDataPtr->pvals->recordedObjWidth);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_HEIGHT) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gint32(*value_cursor, &userDataPtr->pvals->recordedObjHeight);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_SRC_HANDLE) == 0)
+ {
+ userDataPtr->isParseOk = p_xml_parse_value_GapMovHandle(*value_cursor, &userDataPtr->pvals->src_handle);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_SRC_SELMODE) == 0)
+ {
+ userDataPtr->isParseOk = p_xml_parse_value_GapMovSelMode(*value_cursor, &userDataPtr->pvals->src_selmode);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_SRC_PAINTMODE) == 0)
+ {
+ userDataPtr->isParseOk = p_xml_parse_value_GimpPaintmode_as_gint(*value_cursor, &userDataPtr->pvals->src_paintmode);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_DST_LAYERSTACK) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gint(*value_cursor, &userDataPtr->pvals->dst_layerstack);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_STEP_SPEED_FACTOR) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gdouble(*value_cursor, &userDataPtr->pvals->step_speed_factor);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_SRC_FORCE_VISIBLE) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gboolean_as_gint(*value_cursor, &userDataPtr->pvals->src_force_visible);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_CLIP_TO_IMG) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gboolean_as_gint(*value_cursor, &userDataPtr->pvals->clip_to_img);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_SRC_APPLY_BLUEBOX) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gboolean_as_gint(*value_cursor, &userDataPtr->pvals->src_apply_bluebox);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_SRC_LAYERSTACK) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gint32(*value_cursor, &userDataPtr->pvals->src_layerstack);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_SRC_FILENAME) == 0)
+ {
+ if(userDataPtr->pvals->src_filename != NULL)
+ {
+ g_free(userDataPtr->pvals->src_filename);
+ userDataPtr->pvals->src_filename = NULL;
+ }
+ if(*value_cursor != NULL)
+ {
+ userDataPtr->pvals->src_filename = g_strdup(*value_cursor);
+ }
+ }
+
+ name_cursor++;
+ value_cursor++;
+ }
+} /* end p_xml_parse_element_moving_object */
+
+
+/* --------------------------------------
+ * p_xml_parse_element_bluebox_parameters
+ * --------------------------------------
+ */
+static void
+p_xml_parse_element_bluebox_parameters(const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ GapMovXmlUserData *userDataPtr,
+ gint count)
+{
+ const gchar **name_cursor = attribute_names;
+ const gchar **value_cursor = attribute_values;
+
+ GapBlueboxGlobalParams *bbp;
+
+ if(count > 0)
+ {
+ userDataPtr->isParseOk = FALSE;
+ }
+
+ if(userDataPtr->pvals->bbp == NULL)
+ {
+ gint32 layer_id;
+
+ layer_id = -1;
+ userDataPtr->pvals->bbp = gap_bluebox_bbp_new(layer_id);
+ gap_bluebox_init_default_vals(userDataPtr->pvals->bbp);
+ }
+ bbp = userDataPtr->pvals->bbp;
+
+
+ while ((*name_cursor) && (userDataPtr->isParseOk))
+ {
+ if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_THRES_MODE) == 0)
+ {
+ userDataPtr->isParseOk = p_xml_parse_value_GapBlueboxThresMode(*value_cursor, &bbp->vals.thres_mode);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_THRES_R) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gdouble(*value_cursor, &bbp->vals.thres_r);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_THRES_G) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gdouble(*value_cursor, &bbp->vals.thres_g);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_THRES_B) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gdouble(*value_cursor, &bbp->vals.thres_b);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_THRES_H) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gdouble(*value_cursor, &bbp->vals.thres_h);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_THRES_S) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gdouble(*value_cursor, &bbp->vals.thres_s);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_THRES_V) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gdouble(*value_cursor, &bbp->vals.thres_v);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_THRES) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gdouble(*value_cursor, &bbp->vals.thres);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_TOLERANCE) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gdouble(*value_cursor, &bbp->vals.tolerance);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_GROW) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gdouble(*value_cursor, &bbp->vals.grow);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_FEATHER_EDGES) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gboolean_as_gint(*value_cursor, &bbp->vals.feather_edges);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_FEATHER_RADIUS) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gdouble(*value_cursor, &bbp->vals.feather_radius);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_SOURCE_ALPHA) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gdouble(*value_cursor, &bbp->vals.source_alpha);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_TARGET_ALPHA) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gdouble(*value_cursor, &bbp->vals.target_alpha);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_KEYCOLOR_R) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gdouble(*value_cursor, &bbp->vals.keycolor.r);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_KEYCOLOR_G) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gdouble(*value_cursor, &bbp->vals.keycolor.g);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_KEYCOLOR_B) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gdouble(*value_cursor, &bbp->vals.keycolor.b);
+ }
+
+ name_cursor++;
+ value_cursor++;
+ }
+} /* end p_xml_parse_element_bluebox_parameters */
+
+
+/* --------------------------------------
+ * p_xml_parse_element_controlpoints
+ * --------------------------------------
+ */
+static void
+p_xml_parse_element_controlpoints(const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ GapMovXmlUserData *userDataPtr,
+ gint count)
+{
+ const gchar **name_cursor = attribute_names;
+ const gchar **value_cursor = attribute_values;
+
+ if(count > 0)
+ {
+ userDataPtr->isParseOk = FALSE;
+ }
+
+ while ((*name_cursor) && (userDataPtr->isParseOk))
+ {
+ if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_CURRENT_POINT) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gint(*value_cursor, &userDataPtr->pvals->point_idx);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_NUMBER_OF_POINTS) == 0)
+ {
+ gint numberOfPoints;
+ userDataPtr->isParseOk = gap_xml_parse_value_gint(*value_cursor, &numberOfPoints);
+
+ if(userDataPtr->isParseOk)
+ {
+ if((numberOfPoints < GAP_MOV_MAX_POINT) && (numberOfPoints > 0))
+ {
+ userDataPtr->pvals->point_idx_max = numberOfPoints -1;
+ }
+ else
+ {
+ userDataPtr->isParseOk = FALSE;
+ }
+ }
+
+ }
+
+ name_cursor++;
+ value_cursor++;
+ }
+} /* end p_xml_parse_element_controlpoints */
+
+
+
+/* ----------------------------------------
+ * p_set_load_defaults_for_one_controlpoint
+ * ----------------------------------------
+ */
+static void
+p_set_load_defaults_for_one_controlpoint(GapMovValues *pvals, gint idx)
+{
+ if((idx >= 0) && (idx < GAP_MOV_MAX_POINT))
+ {
+ pvals->point[idx].p_x = 0;
+ pvals->point[idx].p_y = 0;
+ pvals->point[idx].opacity = 100.0; /* 100 percent (no transparecy) */
+ pvals->point[idx].w_resize = 100.0; /* 100% no resizize (1:1) */
+ pvals->point[idx].h_resize = 100.0; /* 100% no resizize (1:1) */
+ pvals->point[idx].rotation = 0.0; /* no rotation (0 degree) */
+ /* 1.0 for all perspective transform factors (== no perspective transformation) */
+ pvals->point[idx].ttlx = 1.0;
+ pvals->point[idx].ttly = 1.0;
+ pvals->point[idx].ttrx = 1.0;
+ pvals->point[idx].ttry = 1.0;
+ pvals->point[idx].tblx = 1.0;
+ pvals->point[idx].tbly = 1.0;
+ pvals->point[idx].tbrx = 1.0;
+ pvals->point[idx].tbry = 1.0;
+ pvals->point[idx].sel_feather_radius = 0.0;
+ pvals->point[idx].keyframe = 0; /* 0: controlpoint is not fixed to keyframe */
+ pvals->point[idx].keyframe_abs = 0; /* 0: controlpoint is not fixed to keyframe */
+
+ pvals->point[idx].accPosition = 0; /* 0: linear (e.g NO acceleration) is default */
+ pvals->point[idx].accOpacity = 0; /* 0: linear (e.g NO acceleration) is default */
+ pvals->point[idx].accSize = 0; /* 0: linear (e.g NO acceleration) is default */
+ pvals->point[idx].accRotation = 0; /* 0: linear (e.g NO acceleration) is default */
+ pvals->point[idx].accPerspective = 0; /* 0: linear (e.g NO acceleration) is default */
+ pvals->point[idx].accSelFeatherRadius = 0; /* 0: linear (e.g NO acceleration) is default */
+
+ }
+
+} /* end p_set_load_defaults_for_one_controlpoint */
+
+
+
+/* --------------------------------------
+ * p_xml_parse_element_controlpoint
+ * --------------------------------------
+ */
+static void
+p_xml_parse_element_controlpoint(const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ GapMovXmlUserData *userDataPtr,
+ gint count)
+{
+ const gchar **name_cursor = attribute_names;
+ const gchar **value_cursor = attribute_values;
+
+ if(count >= GAP_MOV_MAX_POINT)
+ {
+ userDataPtr->isParseOk = FALSE;
+ }
+
+ p_set_load_defaults_for_one_controlpoint(userDataPtr->pvals, count);
+
+ while ((*name_cursor) && (userDataPtr->isParseOk))
+ {
+ if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_PX) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gint(*value_cursor, &userDataPtr->pvals->point[count].p_x);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_PY) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gint(*value_cursor, &userDataPtr->pvals->point[count].p_y);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_KEYFRAME) == 0)
+ {
+ gint keyframe;
+
+ userDataPtr->isParseOk = gap_xml_parse_value_gint(*value_cursor, &keyframe);
+ userDataPtr->pvals->point[count].keyframe = keyframe;
+ userDataPtr->pvals->point[count].keyframe_abs = gap_mov_exec_conv_keyframe_to_abs(keyframe, userDataPtr->pvals);
+
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_SEL_FEATHER_RADIUS) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gdouble(*value_cursor, &userDataPtr->pvals->point[count].sel_feather_radius);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_W_RESIZE) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gdouble(*value_cursor, &userDataPtr->pvals->point[count].w_resize);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_H_RESIZE) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gdouble(*value_cursor, &userDataPtr->pvals->point[count].h_resize);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_OPACITY) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gdouble(*value_cursor, &userDataPtr->pvals->point[count].opacity);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_ROTATION) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gdouble(*value_cursor, &userDataPtr->pvals->point[count].rotation);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_TTLX) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gdouble(*value_cursor, &userDataPtr->pvals->point[count].ttlx);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_TTLY) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gdouble(*value_cursor, &userDataPtr->pvals->point[count].ttly);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_TTRX) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gdouble(*value_cursor, &userDataPtr->pvals->point[count].ttrx);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_TTRY) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gdouble(*value_cursor, &userDataPtr->pvals->point[count].ttry);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_TBLX) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gdouble(*value_cursor, &userDataPtr->pvals->point[count].tblx);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_TBLY) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gdouble(*value_cursor, &userDataPtr->pvals->point[count].tbly);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_TBRX) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gdouble(*value_cursor, &userDataPtr->pvals->point[count].tbrx);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_TBRY) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gdouble(*value_cursor, &userDataPtr->pvals->point[count].tbry);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_ACC_POSITION) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gint(*value_cursor, &userDataPtr->pvals->point[count].accPosition);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_ACC_OPACITY) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gint(*value_cursor, &userDataPtr->pvals->point[count].accOpacity);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_ACC_SIZE) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gint(*value_cursor, &userDataPtr->pvals->point[count].accSize);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_ACC_ROTATION) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gint(*value_cursor, &userDataPtr->pvals->point[count].accRotation);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_ACC_PERSPECTIVE) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gint(*value_cursor, &userDataPtr->pvals->point[count].accPerspective);
+ }
+ else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_ACC_SEL_FEATHER_RADIUS) == 0)
+ {
+ userDataPtr->isParseOk = gap_xml_parse_value_gint(*value_cursor, &userDataPtr->pvals->point[count].accSelFeatherRadius);
+ }
+
+ name_cursor++;
+ value_cursor++;
+ }
+} /* end p_xml_parse_element_controlpoint */
+
+
+/* --------------------------------------
+ * p_start_xml_element
+ * --------------------------------------
+ * handler function to be called by the GMarkupParser
+ * this handler is called each time the parser recognizes
+ * the start event of an xml element.
+ */
+static void
+p_start_xml_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ GapMovXmlUserData *userDataPtr,
+ GError **error)
+{
+ gint jj;
+
+ if(gap_debug)
+ {
+ printf("p_start_xml_element: %s\n", element_name);
+ }
+
+ if(userDataPtr == NULL)
+ {
+ return;
+ }
+
+ for(jj=0; jmpTableElement[jj].name != NULL; jj++)
+ {
+ if(strcmp(jmpTableElement[jj].name, element_name) == 0)
+ {
+ if ((jj==0) && (jmpTableElement[jj].count == 0))
+ {
+ userDataPtr->isScopeValid = TRUE;
+ }
+ if(!userDataPtr->isScopeValid)
+ {
+ /* stop parsing when outsided of known namespace
+ * (and stop on duplicate root element too)
+ */
+ return;
+ }
+
+ /* call token specific parse function */
+ jmpTableElement[jj].func_ptr(element_name
+ , attribute_names
+ , attribute_values
+ , userDataPtr
+ , jmpTableElement[jj].count
+ );
+ }
+ if(!userDataPtr->isParseOk)
+ {
+ return;
+ }
+ }
+
+} /* end p_start_xml_element */
+
+
+
+/* --------------------------------------
+ * p_end_xml_element
+ * --------------------------------------
+ * handler function to be called by the GMarkupParser
+ * this handler is called each time the parser recognizes
+ * the end event of an xml element
+ */
+static void
+p_end_xml_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ GapMovXmlUserData *userDataPtr,
+ GError **error)
+{
+ if(gap_debug)
+ {
+ printf("p_end_xml_element: %s\n", element_name);
+ }
+ if(userDataPtr == NULL)
+ {
+ return;
+ }
+
+ if(userDataPtr->isScopeValid)
+ {
+ gint jj;
+
+ for(jj=0; jmpTableElement[jj].name != NULL; jj++)
+ {
+ if(strcmp(jmpTableElement[jj].name, element_name) == 0)
+ {
+ jmpTableElement[jj].count++;
+ }
+ }
+
+ }
+
+} /* end p_end_xml_element */
+
+
+
+/* ------------------------------------------
+ * p_transform_path_coordinate
+ * ------------------------------------------
+ * transforms path coordinate value, typically from recorded size
+ * to actual size.
+ * Note that the path coordinates in the XML file are stored in unit pixels,
+ * refering to the frame image (recordedFrameWidth / recordedFrameHeight) where the move path dialog
+ * was invoked from and that typically did write the XML file when
+ * move path settings were saved in XML format.
+ *
+ * This procedure is used to transform the path coordinates to actual frame
+ * size at loading time.
+ */
+static gint
+p_transform_path_coordinate(gint value, gint32 recordedSize, gint32 actualSize)
+{
+
+ if((recordedSize != 0) && (actualSize != recordedSize))
+ {
+ gdouble newValue;
+ gint newIntValue;
+
+ newValue = ((gdouble)value * (gdouble)actualSize) / (gdouble)recordedSize;
+ newIntValue = rint(newValue);
+
+ return (newIntValue);
+ }
+
+ return(value);
+
+}
+
+
+/* ------------------------------------------
+ * p_copy_transformed_values
+ * ------------------------------------------
+ *
+ */
+static void
+p_copy_transformed_values(GapMovValues *dstValues, GapMovValues *srcValues
+ , gint32 actualFrameWidth, gint32 actualFrameHeight)
+{
+ gint ii;
+
+ dstValues->version = srcValues->version;
+ dstValues->recordedFrameWidth = srcValues->recordedFrameWidth;
+ dstValues->recordedFrameHeight = srcValues->recordedFrameHeight;
+ dstValues->recordedObjWidth = srcValues->recordedObjWidth;
+ dstValues->recordedObjHeight = srcValues->recordedObjHeight;
+ dstValues->dst_range_start = srcValues->dst_range_start;
+ dstValues->dst_range_end = srcValues->dst_range_end;
+ dstValues->total_frames = srcValues->total_frames;
+ dstValues->tween_steps = srcValues->tween_steps;
+ dstValues->tween_opacity_initial = srcValues->tween_opacity_initial;
+ dstValues->tween_opacity_desc = srcValues->tween_opacity_desc;
+ dstValues->tracelayer_enable = srcValues->tracelayer_enable;
+ dstValues->trace_opacity_initial = srcValues->trace_opacity_initial;
+ dstValues->trace_opacity_desc = srcValues->trace_opacity_desc;
+ dstValues->src_stepmode = srcValues->src_stepmode;
+ dstValues->src_handle = srcValues->src_handle;
+ dstValues->src_selmode = srcValues->src_selmode;
+ dstValues->src_paintmode = srcValues->src_paintmode;
+ dstValues->dst_layerstack = srcValues->dst_layerstack;
+ dstValues->step_speed_factor = srcValues->step_speed_factor;
+ dstValues->src_force_visible = srcValues->src_force_visible;
+ dstValues->clip_to_img = srcValues->clip_to_img;
+ dstValues->src_apply_bluebox = srcValues->src_apply_bluebox;
+ dstValues->src_layerstack = srcValues->src_layerstack;
+
+ if(dstValues->src_filename != NULL)
+ {
+ g_free(dstValues->src_filename);
+ dstValues->src_filename = NULL;
+ }
+ if(srcValues->src_filename != NULL)
+ {
+ dstValues->src_filename = g_strdup(srcValues->src_filename);
+ }
+
+ if(dstValues->bbp != NULL)
+ {
+ g_free(dstValues->bbp);
+ dstValues->bbp = NULL;
+ }
+ if(srcValues->bbp != NULL)
+ {
+ dstValues->bbp = g_new(GapBlueboxGlobalParams, 1);
+ memcpy(dstValues->bbp, srcValues->bbp, sizeof(GapBlueboxGlobalParams));
+ }
+
+
+ dstValues->point_idx = srcValues->point_idx;
+ dstValues->point_idx_max = srcValues->point_idx_max;
+
+ /* copy controlpoint data for all points and transform coordinates */
+ for(ii=0; ii <= srcValues->point_idx_max; ii++)
+ {
+ memcpy(&dstValues->point[ii], &srcValues->point[ii], sizeof(GapMovPoint));
+
+ dstValues->point[ii].p_x = p_transform_path_coordinate(srcValues->point[ii].p_x
+ , srcValues->recordedFrameWidth
+ , actualFrameWidth
+ );
+ dstValues->point[ii].p_y = p_transform_path_coordinate(srcValues->point[ii].p_y
+ , srcValues->recordedFrameHeight
+ , actualFrameHeight
+ );
+
+ }
+
+} /* end p_copy_transformed_values */
+
+
+/* ------------------------------------------
+ * gap_mov_xml_par_load
+ * ------------------------------------------
+ * (use actualFrameWidth and actualFrameHeight value 0 in case no transformation
+ * is desired)
+ */
+gboolean
+gap_mov_xml_par_load(const char *filename, GapMovValues *productiveValues
+ ,gint32 actualFrameWidth, gint32 actualFrameHeight)
+{
+ /* The list of what handler does what.
+ * this implementation uses only start and end element events
+ */
+ static GMarkupParser parserFuctions = {
+ p_start_xml_element,
+ p_end_xml_element,
+ NULL,
+ NULL,
+ NULL
+ };
+
+ gint jj;
+ char *textBuffer;
+ gsize lengthTextBuffer;
+ gboolean isOk;
+ GapMovValues *tmpValues;
+ GapMovXmlUserData *userDataPtr;
+
+ isOk = TRUE;
+ tmpValues = gap_mov_exec_new_GapMovValues();
+ tmpValues->dst_image_id = productiveValues->dst_image_id;
+ userDataPtr = g_new(GapMovXmlUserData, 1);
+ userDataPtr->pvals = tmpValues;
+
+ ///p_init_default_values(tmpValues); /// (?) TODO
+
+ userDataPtr->isScopeValid = FALSE;
+ userDataPtr->isParseOk = TRUE;
+
+ for(jj=0; jmpTableElement[jj].name != NULL; jj++)
+ {
+ jmpTableElement[jj].count = 0;
+ }
+
+ GMarkupParseContext *context = g_markup_parse_context_new (
+ &parserFuctions /* GMarkupParser */
+ , 0 /* GMarkupParseFlags flags */
+ , userDataPtr /* gpointer user_data */
+ , NULL /* GDestroyNotify user_data_dnotify */
+ );
+
+ if (g_file_get_contents (filename, &textBuffer, &lengthTextBuffer, NULL) != TRUE)
+ {
+ printf("Couldn't load XML file:%s\n", filename);
+ return(FALSE);
+ }
+
+
+ if (g_markup_parse_context_parse (context, textBuffer, lengthTextBuffer, NULL) != TRUE)
+ {
+ printf("Parse failed of file: %s\n", filename);
+ // g_markup_parse_context_parse returns FALSE even when parsing seems to be OK
+ // TODO: findout what makes g_markup_parse_context_parse work with proper returncode...
+ // return(FALSE);
+ }
+
+ /* check for mandatory elements */
+ if(userDataPtr->isParseOk)
+ {
+ for(jj=0; jmpTableElement[jj].name != NULL; jj++)
+ {
+ if(jmpTableElement[jj].isRequired)
+ {
+ if(jmpTableElement[jj].count < 1)
+ {
+ printf("required XML element:%s was not found in file:%s\n"
+ , jmpTableElement[jj].name
+ , filename
+ );
+ userDataPtr->isParseOk = FALSE;
+ }
+ }
+ }
+
+ }
+
+ if(userDataPtr->isParseOk)
+ {
+ /* copy loaded values and transform coordinates from recorded frame size
+ * to actual frame size
+ */
+ p_copy_transformed_values(productiveValues, tmpValues, actualFrameWidth, actualFrameHeight);
+ }
+
+ isOk = userDataPtr->isParseOk;
+
+ g_free(textBuffer);
+ g_markup_parse_context_free (context);
+
+ if(tmpValues->bbp != NULL)
+ {
+ g_free(tmpValues->bbp);
+ }
+ if(tmpValues->src_filename != NULL)
+ {
+ g_free(tmpValues->src_filename);
+ }
+ g_free(tmpValues);
+
+ g_free(userDataPtr);
+
+
+ return (isOk);
+
+} /* end gap_mov_xml_par_load */
+
+
+
+
+
+/*
+ * XML WRITER procedure
+ */
+
+
+/* --------------------------------------
+ * gap_mov_xml_par_save
+ * --------------------------------------
+ * save all move path parameter settings to file in XML notation.
+ */
+gint
+gap_mov_xml_par_save(char *filename, GapMovValues *pvals)
+{
+ FILE *l_fp;
+ gint l_idx;
+
+ if(filename == NULL) return -1;
+
+ l_fp = g_fopen(filename, "w+");
+ if(l_fp != NULL)
+ {
+ gboolean isTraceLayerEnabled;
+ gboolean writeResizeValues;
+ gboolean writeRotateValues;
+ gboolean writeOpacityValues;
+ gboolean writeFeatherRadiusValues;
+
+ fprintf(l_fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+
+ /* root */
+ fprintf(l_fp, "<%s ", GAP_MOVPATH_XML_TOKEN_ROOT);
+ gap_xml_write_int_value(l_fp, GAP_MOVPATH_XML_TOKEN_VERSION, pvals->version);
+ fprintf(l_fp, "/>\n");
+
+ /* attributes for description of the processed frames */
+ {
+ gint32 total_frames;
+
+ total_frames = 1 + abs(pvals->dst_range_end - pvals->dst_range_start);
+
+ fprintf(l_fp, " <%s ", GAP_MOVPATH_XML_TOKEN_FRAME_DESCRIPTION);
+ gap_xml_write_int_value(l_fp, GAP_MOVPATH_XML_TOKEN_WIDTH, gimp_image_width(pvals->dst_image_id));
+ gap_xml_write_int_value(l_fp, GAP_MOVPATH_XML_TOKEN_HEIGHT, gimp_image_height(pvals->dst_image_id));
+ gap_xml_write_int_value(l_fp, GAP_MOVPATH_XML_TOKEN_RANGE_FROM, pvals->dst_range_start);
+ gap_xml_write_int_value(l_fp, GAP_MOVPATH_XML_TOKEN_RANGE_TO, pvals->dst_range_end);
+ gap_xml_write_int_value(l_fp, GAP_MOVPATH_XML_TOKEN_TOTAL_FRAMES, total_frames);
+ fprintf(l_fp, "/>\n");
+ }
+
+
+ /* attributes for tween processing */
+ fprintf(l_fp, " <%s ", GAP_MOVPATH_XML_TOKEN_TWEEN);
+ gap_xml_write_int_value(l_fp, GAP_MOVPATH_XML_TOKEN_TWEEN_STEPS, pvals->tween_steps);
+ if(pvals->tween_steps != 0)
+ {
+ gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_TWEEN_OPACITY_INITIAL, pvals->tween_opacity_initial, 1, 3);
+ gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_TWEEN_OPACITY_DESC, pvals->tween_opacity_desc, 1, 3);
+ }
+ fprintf(l_fp, "/>\n");
+
+ /* attributes for trace layer generation */
+ isTraceLayerEnabled = (pvals->tracelayer_enable != 0);
+ fprintf(l_fp, " <%s ", GAP_MOVPATH_XML_TOKEN_TRACE);
+ gap_xml_write_gint_as_gboolean_value(l_fp, GAP_MOVPATH_XML_TOKEN_TRACELAYER_ENABLE, isTraceLayerEnabled);
+ if(isTraceLayerEnabled)
+ {
+ gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_TRACE_OPACITY_INITIAL, pvals->trace_opacity_initial, 1, 3);
+ gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_TRACE_OPACITY_DESC, pvals->trace_opacity_desc, 1, 3);
+ }
+ fprintf(l_fp, "/>\n");
+
+ /* attributes of the moving_object */
+ {
+ char *src_filename;
+ gint32 src_image_id;
+
+ src_image_id = gimp_drawable_get_image(pvals->src_layer_id);
+
+ fprintf(l_fp, " <%s ", GAP_MOVPATH_XML_TOKEN_MOVING_OBJECT);
+ gap_xml_write_int_value(l_fp, GAP_MOVPATH_XML_TOKEN_SRC_LAYER_ID, pvals->src_layer_id);
+ gap_xml_write_int_value(l_fp, GAP_MOVPATH_XML_TOKEN_SRC_LAYERSTACK, pvals->src_layerstack);
+ gap_xml_write_int_value(l_fp, GAP_MOVPATH_XML_TOKEN_WIDTH, gimp_image_width(src_image_id));
+ gap_xml_write_int_value(l_fp, GAP_MOVPATH_XML_TOKEN_HEIGHT, gimp_image_height(src_image_id));
+
+ src_filename = gimp_image_get_filename(src_image_id);
+ if(src_filename != NULL)
+ {
+ gap_xml_write_string_value(l_fp, GAP_MOVPATH_XML_TOKEN_SRC_FILENAME, src_filename);
+ g_free(src_filename);
+ }
+ fprintf(l_fp, "\n ");
+ gap_xml_write_EnumValue(l_fp, GAP_MOVPATH_XML_TOKEN_SRC_HANDLE, pvals->src_handle, &valuesGapMovHandle[0]);
+ fprintf(l_fp, "\n ");
+ gap_xml_write_EnumValue(l_fp, GAP_MOVPATH_XML_TOKEN_SRC_STEPMODE, pvals->src_stepmode, &valuesGapMovStepMode[0]);
+ gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_STEP_SPEED_FACTOR, pvals->step_speed_factor, 1, 5);
+ fprintf(l_fp, "\n ");
+ gap_xml_write_EnumValue(l_fp, GAP_MOVPATH_XML_TOKEN_SRC_SELMODE, pvals->src_selmode, &valuesGapMovSelMode[0]);
+ fprintf(l_fp, "\n ");
+ gap_xml_write_EnumValue(l_fp, GAP_MOVPATH_XML_TOKEN_SRC_PAINTMODE, pvals->src_paintmode, &valuesGimpPaintmode[0]);
+ fprintf(l_fp, "\n ");
+ gap_xml_write_int_value(l_fp, GAP_MOVPATH_XML_TOKEN_DST_LAYERSTACK, pvals->dst_layerstack);
+ gap_xml_write_gint_as_gboolean_value(l_fp, GAP_MOVPATH_XML_TOKEN_SRC_FORCE_VISIBLE, pvals->src_force_visible);
+ gap_xml_write_gint_as_gboolean_value(l_fp, GAP_MOVPATH_XML_TOKEN_CLIP_TO_IMG, pvals->clip_to_img);
+ gap_xml_write_gint_as_gboolean_value(l_fp, GAP_MOVPATH_XML_TOKEN_SRC_APPLY_BLUEBOX, pvals->src_apply_bluebox);
+ fprintf(l_fp, "\n");
+
+ /* attributes for applying bluebox transparency processing */
+ if((pvals->src_apply_bluebox) && (pvals->bbp != NULL))
+ {
+ fprintf(l_fp, " <%s ", GAP_MOVPATH_XML_TOKEN_BLUEBOX_PARAMETERS);
+ fprintf(l_fp, "\n ");
+ gap_xml_write_EnumValue(l_fp, GAP_MOVPATH_XML_TOKEN_THRES_MODE, pvals->bbp->vals.thres_mode, &valuesGapBlueboxThresMode[0]);
+ fprintf(l_fp, "\n ");
+ gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_THRES_R, pvals->bbp->vals.thres_r, 1, 5);
+ gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_THRES_G, pvals->bbp->vals.thres_g, 1, 5);
+ gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_THRES_B, pvals->bbp->vals.thres_b, 1, 5);
+ fprintf(l_fp, "\n ");
+ gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_THRES_H, pvals->bbp->vals.thres_h, 1, 5);
+ gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_THRES_S, pvals->bbp->vals.thres_s, 1, 5);
+ gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_THRES_V, pvals->bbp->vals.thres_v, 1, 5);
+ fprintf(l_fp, "\n ");
+ gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_THRES, pvals->bbp->vals.thres, 1, 5);
+ gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_TOLERANCE, pvals->bbp->vals.tolerance, 1, 5);
+ gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_GROW, pvals->bbp->vals.grow, 1, 5);
+ fprintf(l_fp, "\n ");
+ gap_xml_write_gint_as_gboolean_value(l_fp, GAP_MOVPATH_XML_TOKEN_FEATHER_EDGES, pvals->bbp->vals.feather_edges);
+ gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_FEATHER_RADIUS, pvals->bbp->vals.feather_radius, 1, 3);
+ fprintf(l_fp, "\n ");
+ gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_SOURCE_ALPHA, pvals->bbp->vals.source_alpha, 1, 3);
+ gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_TARGET_ALPHA, pvals->bbp->vals.target_alpha, 1, 3);
+ fprintf(l_fp, "\n ");
+ gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_KEYCOLOR_R, pvals->bbp->vals.keycolor.r, 1, 3);
+ gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_KEYCOLOR_G, pvals->bbp->vals.keycolor.g, 1, 3);
+ gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_KEYCOLOR_B, pvals->bbp->vals.keycolor.b, 1, 3);
+
+ fprintf(l_fp, "\n");
+ fprintf(l_fp, " >\n");
+ fprintf(l_fp, " </%s>\n", GAP_MOVPATH_XML_TOKEN_BLUEBOX_PARAMETERS);
+
+ }
+
+ fprintf(l_fp, " >\n");
+ fprintf(l_fp, " </%s>\n", GAP_MOVPATH_XML_TOKEN_MOVING_OBJECT);
+ }
+
+ fprintf(l_fp, "\n");
+
+ /* controlpoints */
+
+ fprintf(l_fp, " <%s ", GAP_MOVPATH_XML_TOKEN_CONTROLPOINTS);
+ gap_xml_write_int_value(l_fp, GAP_MOVPATH_XML_TOKEN_CURRENT_POINT, pvals->point_idx);
+ gap_xml_write_int_value(l_fp, GAP_MOVPATH_XML_TOKEN_NUMBER_OF_POINTS, pvals->point_idx_max +1);
+ fprintf(l_fp, " >\n");
+
+ /* check for conditonal write
+ * (to keep files smaller and more readable we skip writing of some information
+ * that is equal to the default value in all controlpoints)
+ */
+ writeResizeValues = FALSE;
+ writeRotateValues = FALSE;
+ writeOpacityValues = FALSE;
+ writeFeatherRadiusValues = FALSE;
+ for(l_idx = 0; l_idx <= pvals->point_idx_max; l_idx++)
+ {
+ if((pvals->point[l_idx].w_resize != 100.0)
+ || (pvals->point[l_idx].h_resize != 100.0))
+ {
+ writeResizeValues = TRUE;
+ }
+
+ if(pvals->point[l_idx].opacity != 100.0)
+ {
+ writeOpacityValues = TRUE;
+ }
+
+ if(pvals->point[l_idx].rotation != 0.0)
+ {
+ writeRotateValues = TRUE;
+ }
+
+ if(pvals->point[l_idx].sel_feather_radius != 0.0)
+ {
+ writeFeatherRadiusValues = TRUE;
+ }
+
+ }
+
+ /* write controlpoints loop */
+ for(l_idx = 0; l_idx <= pvals->point_idx_max; l_idx++)
+ {
+ gdouble px;
+ gdouble py;
+ gboolean writeAccelerationCharacteristics;
+
+ px = pvals->point[l_idx].p_x;
+ py = pvals->point[l_idx].p_y;
+
+ /* write basic attributes of the controlpoint */
+
+ fprintf(l_fp, " <%s ", GAP_MOVPATH_XML_TOKEN_CONTROLPOINT);
+ gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_PX, px, 5, 0);
+ gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_PY, py, 5, 0);
+ if(writeResizeValues)
+ {
+ gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_W_RESIZE, pvals->point[l_idx].w_resize, 3, 3);
+ gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_H_RESIZE, pvals->point[l_idx].h_resize, 3, 3);
+ }
+ if(writeOpacityValues)
+ {
+ gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_OPACITY, pvals->point[l_idx].opacity, 3, 1);
+ }
+ if(writeRotateValues)
+ {
+ gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_ROTATION, pvals->point[l_idx].rotation, 4, 1);
+ }
+ if(writeFeatherRadiusValues)
+ {
+ gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_SEL_FEATHER_RADIUS, pvals->point[l_idx].sel_feather_radius, 3, 1);
+ }
+
+ /* conditional write perspective transformation (only if there is any) */
+ if(pvals->point[l_idx].ttlx != 1.0
+ || pvals->point[l_idx].ttly != 1.0
+ || pvals->point[l_idx].ttrx != 1.0
+ || pvals->point[l_idx].ttry != 1.0
+ || pvals->point[l_idx].tblx != 1.0
+ || pvals->point[l_idx].tbly != 1.0
+ || pvals->point[l_idx].tbrx != 1.0
+ || pvals->point[l_idx].tbry != 1.0
+ )
+ {
+ fprintf(l_fp, "\n ");
+ gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_TTLX, pvals->point[l_idx].ttlx, 2, 3);
+ gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_TTLY, pvals->point[l_idx].ttly, 2, 3);
+ gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_TTRX, pvals->point[l_idx].ttrx, 2, 3);
+ gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_TTRY, pvals->point[l_idx].ttry, 2, 3);
+ gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_TBLX, pvals->point[l_idx].tblx, 2, 3);
+ gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_TBLY, pvals->point[l_idx].tbly, 2, 3);
+ gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_TBRX, pvals->point[l_idx].tbrx, 2, 3);
+ gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_TBRY, pvals->point[l_idx].tbry, 2, 3);
+ }
+
+ writeAccelerationCharacteristics = FALSE;
+ /* conditional write acceleration characteristics
+ * relevant information can occur at first controlpoint
+ * or on keyframes but never for the last controlpoint)
+ */
+ if ((pvals->point[l_idx].accPosition != 0)
+ || (pvals->point[l_idx].accOpacity != 0)
+ || (pvals->point[l_idx].accSize != 0)
+ || (pvals->point[l_idx].accRotation != 0)
+ || (pvals->point[l_idx].accPerspective != 0)
+ || (pvals->point[l_idx].accSelFeatherRadius != 0))
+ {
+ if (l_idx == 0)
+ {
+ writeAccelerationCharacteristics = TRUE;
+ }
+ else
+ {
+ if ((l_idx < pvals->point_idx_max)
+ && ((int)pvals->point[l_idx].keyframe > 0))
+ {
+ writeAccelerationCharacteristics = TRUE;
+ }
+ }
+
+ }
+
+ if (writeAccelerationCharacteristics == TRUE)
+ {
+ fprintf(l_fp, "\n ");
+ gap_xml_write_int_value(l_fp, GAP_MOVPATH_XML_TOKEN_ACC_POSITION, pvals->point[l_idx].accPosition);
+ gap_xml_write_int_value(l_fp, GAP_MOVPATH_XML_TOKEN_ACC_OPACITY, pvals->point[l_idx].accOpacity);
+ gap_xml_write_int_value(l_fp, GAP_MOVPATH_XML_TOKEN_ACC_SIZE, pvals->point[l_idx].accSize);
+ gap_xml_write_int_value(l_fp, GAP_MOVPATH_XML_TOKEN_ACC_ROTATION, pvals->point[l_idx].accRotation);
+ gap_xml_write_int_value(l_fp, GAP_MOVPATH_XML_TOKEN_ACC_PERSPECTIVE, pvals->point[l_idx].accPerspective);
+ gap_xml_write_int_value(l_fp, GAP_MOVPATH_XML_TOKEN_ACC_SEL_FEATHER_RADIUS, pvals->point[l_idx].accSelFeatherRadius);
+ }
+
+ /* check for writing keyframe
+ * (the implicite keyframes at first and last controlpoints are not written to file)
+ */
+ if((l_idx > 0)
+ && (l_idx < pvals->point_idx_max)
+ && ((int)pvals->point[l_idx].keyframe > 0))
+ {
+ int keyframe;
+
+ fprintf(l_fp, "\n ");
+ keyframe = gap_mov_exec_conv_keyframe_to_rel(pvals->point[l_idx].keyframe_abs, pvals);
+ gap_xml_write_int_value(l_fp, GAP_MOVPATH_XML_TOKEN_KEYFRAME, keyframe);
+
+ }
+
+ fprintf(l_fp, "/>\n"); /* end of GAP_MOVPATH_XML_TOKEN_CONTROLPOINT */
+
+ }
+
+ fprintf(l_fp, " </%s>\n", GAP_MOVPATH_XML_TOKEN_CONTROLPOINTS);
+ fprintf(l_fp, "</%s>", GAP_MOVPATH_XML_TOKEN_ROOT);
+
+ fclose(l_fp);
+ return 0;
+ }
+ return -1;
+} /* end gap_mov_xml_par_save */
diff --git a/gap/gap_mov_xml_par.h b/gap/gap_mov_xml_par.h
new file mode 100644
index 0000000..b2d0a0d
--- /dev/null
+++ b/gap/gap_mov_xml_par.h
@@ -0,0 +1,52 @@
+/* gap_mov_xml_par.h
+ * 2011.03.09 hof (Wolfgang Hofer)
+ *
+ * GAP ... Gimp Animation Plugins
+ *
+ * Move Path : XML parameterfile load and save procedures.
+ * The XML parameterfile contains full information of all parameters
+ * available in the move path feature including:
+ * version
+ * frame description, moving object description
+ * tweens, trace layer, bluebox settings and controlpoints.
+ *
+ * Note that the old pointfile format is still supported
+ * but not handled here.
+ * (the old pointfile format is limited to information about the controlpoints that build the path
+ * see gap_mov_exec module for load/save support of the old pointfile format)
+ *
+ */
+/* 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:
+ * 2011.03.09 hof: created.
+ */
+#ifndef _GAP_MOV_XML_PAR_H
+#define _GAP_MOV_XML_PAR_H
+
+#include "libgimp/gimp.h"
+#include "gap_mov_dialog.h"
+
+
+gboolean gap_mov_xml_par_load(const char *filename, GapMovValues *productiveValues
+ ,gint32 actualFrameWidth, gint32 actualFrameHeight);
+gint gap_mov_xml_par_save(char *filename, GapMovValues *pvals);
+
+#endif
+
diff --git a/gap/gap_story_att_trans_dlg.c b/gap/gap_story_att_trans_dlg.c
index e75f3d2..fdb9990 100644
--- a/gap/gap_story_att_trans_dlg.c
+++ b/gap/gap_story_att_trans_dlg.c
@@ -43,6 +43,7 @@
#include "gap_story_undo.h"
#include "gap_story_dialog.h"
#include "gap_story_file.h"
+#include "gap_story_render_processor.h"
#include "gap_story_att_trans_dlg.h"
#include "gap_pview_da.h"
#include "gap_stock.h"
@@ -145,11 +146,27 @@ static gint32 p_create_deco_layer(GapStbAttrWidget *attw, gint32 image_id);
static void p_create_gfx_image(GapStbAttrWidget *attw, gint img_idx);
static void p_delete_gfx_images(GapStbAttrWidget *attw);
static void p_adjust_stackposition(gint32 image_id, gint32 layer_id, gint position);
+
+
+static gboolean p_create_transformed_layer_movepath(gint32 image_id
+ , gint32 origsize_layer_id
+ , gint32 *layer_id_ptr
+ , GapStoryCalcAttr *calculated
+ , gint32 stackposition, const char *layername
+ , GapStbAttrWidget *attw
+ , gint img_idx
+ );
+
static void p_create_transformed_layer(gint32 image_id
, gint32 origsize_layer_id
, gint32 *layer_id_ptr
, GapStoryCalcAttr *calculated
- , gint32 stackposition, const char *layername);
+ , gint32 stackposition
+ , const char *layername
+ , GapStbAttrWidget *attw
+ , gint img_idx
+ , gboolean enableMovepath
+ );
static gboolean p_calculate_prefetch_visibility(GapStbAttrWidget *attw, gint img_idx);
static void p_render_gfx(GapStbAttrWidget *attw, gint img_idx);
@@ -196,8 +213,18 @@ static gint32 p_fetch_video_frame_as_layer(GapStbMainGlobalParams *sgpp
static gint32 p_fetch_imagefile_as_layer (const char *img_filename
, gint32 image_id
);
+static gint32 p_fetch_layer_from_animimage (const char *img_filename
+ , gint32 localframe_index, gint32 image_id
+ );
-
+static void p_attw_movepath_filesel_pw_ok_cb (GtkWidget *widget
+ ,GapStbAttrWidget *attw);
+static void p_attw_movepath_filesel_pw_close_cb ( GtkWidget *widget
+ , GapStbAttrWidget *attw);
+static void p_attw_movepath_filesel_button_cb ( GtkWidget *w
+ , GapStbAttrWidget *attw);
+static void p_attw_movepath_file_validity_check(GapStbAttrWidget *attw);
+static void p_attw_movepath_file_entry_update_cb(GtkWidget *widget, GapStbAttrWidget *attw);
static void p_attw_comment_entry_update_cb(GtkWidget *widget, GapStbAttrWidget *attw);
static void p_init_layer_info(GapStbAttrLayerInfo *linfo);
@@ -237,13 +264,30 @@ static void p_create_and_attach_att_arr_widgets(const char *row_title
static gdouble
p_getConvertFactor(gint att_type_idx)
{
- if (att_type_idx == GAP_STB_ATT_TYPE_ROTATE)
+ if ((att_type_idx == GAP_STB_ATT_TYPE_ROTATE)
+ || (att_type_idx == GAP_STB_ATT_TYPE_MOVEPATH))
{
return 1.0;
}
return (CONVERT_TO_100PERCENT);
}
+/* ----------------------------------------------------
+ * p_debug_dup_image
+ * ----------------------------------------------------
+ * Duplicate image, and open a display for the duplicate
+ * (Procedure is used for debug only
+ */
+static void
+p_debug_dup_image(gint32 image_id)
+{
+ gint32 l_dup_image_id;
+
+ l_dup_image_id = gimp_image_duplicate(image_id);
+ gimp_display_new(l_dup_image_id);
+} /* end p_debug_dup_image */
+
+
/* ---------------------------------
* p_attw_prop_response
* ---------------------------------
@@ -275,6 +319,12 @@ p_attw_prop_response(GtkWidget *widget
dlg = attw->attw_prop_dialog;
if(dlg)
{
+ if(attw->movepath_filesel != NULL)
+ {
+ /* force close in case file selection dialog is still open */
+ p_attw_movepath_filesel_pw_close_cb(attw->movepath_filesel, attw);
+ }
+
p_delete_gfx_images(attw);
if(attw->go_timertag >= 0)
{
@@ -290,12 +340,13 @@ p_attw_prop_response(GtkWidget *widget
}
} /* end p_attw_prop_response */
+
/* --------------------------------------
* p_attw_push_undo_and_set_unsaved_changes
* --------------------------------------
* this procedure is called in most cases when
* a transition attribute property has changed.
- * (note that the Undo push implementation filter out
+ * (note that the Undo push implementation filters out
* multiple attribute property changes on the same object in sequence)
*/
static void
@@ -339,6 +390,16 @@ p_attw_prop_reset_all(GapStbAttrWidget *attw)
gap_story_elem_copy(attw->stb_elem_refptr, attw->stb_elem_bck);
+ if(attw->stb_elem_refptr->att_movepath_file_xml)
+ {
+ gtk_entry_set_text(GTK_ENTRY(attw->movepath_file_entry), attw->stb_elem_refptr->att_movepath_file_xml);
+ }
+ else
+ {
+ gtk_entry_set_text(GTK_ENTRY(attw->movepath_file_entry), "");
+ }
+
+
comment_set = FALSE;
if(attw->stb_elem_refptr->comment)
{
@@ -483,8 +544,10 @@ p_attw_update_properties(GapStbAttrWidget *attw)
/* ------------------------------------
* p_attw_update_sensitivity
* ------------------------------------
- * set sensitivity of all 5 from/to, dur attribute widgets
+ * set sensitivity of all from/to, dur attribute widgets
* according to their enable flag.
+ * the row with widget for the movepath settings depends
+ * on the movepath_file_xml_is_valid flag
*/
static void
p_attw_update_sensitivity(GapStbAttrWidget *attw)
@@ -504,6 +567,14 @@ p_attw_update_sensitivity(GapStbAttrWidget *attw)
for(ii=0; ii < GAP_STB_ATT_TYPES_ARRAY_MAX; ii++)
{
sensitive = attw->stb_elem_refptr->att_arr_enable[ii];
+ if (ii == GAP_STB_ATT_TYPE_MOVEPATH)
+ {
+ gtk_widget_set_sensitive(attw->att_rows[ii].enable_toggle, attw->movepath_file_xml_is_valid);
+ if(attw->movepath_file_xml_is_valid != TRUE)
+ {
+ sensitive = FALSE;
+ }
+ }
gtk_widget_set_sensitive(attw->att_rows[ii].spinbutton_from, sensitive);
gtk_widget_set_sensitive(attw->att_rows[ii].spinbutton_to, sensitive);
@@ -752,7 +823,7 @@ p_attw_gdouble_adjustment_callback(GtkObject *obj, gdouble *val)
gdouble l_val;
gint att_type_idx;
- att_type_idx = g_object_get_data( G_OBJECT(obj), "att_type_idx" );
+ att_type_idx = (gint) g_object_get_data( G_OBJECT(obj), "att_type_idx" );
attw = g_object_get_data( G_OBJECT(obj), OBJ_DATA_KEY_ATTW );
if(attw)
{
@@ -968,10 +1039,7 @@ p_attw_preview_events_cb (GtkWidget *widget
/* debug code to display a copy of the image */
if(1==0)
{
- gint32 dup_id;
-
- dup_id = gimp_image_duplicate(attw->gfx_tab[img_idx].image_id);
- gimp_display_new(dup_id);
+ p_debug_dup_image(attw->gfx_tab[img_idx].image_id);
}
return FALSE;
@@ -1413,25 +1481,248 @@ p_adjust_stackposition(gint32 image_id, gint32 layer_id, gint position)
/* -----------------------------------------
+ * p_is_width_or_height_fixed
+ * -----------------------------------------
+ * return TRUE in case either width or height is fixed
+ * (e.g. is disabled to be scaled to fit target size)
+ */
+static gboolean
+p_is_width_or_height_fixed(gboolean fit_width, gboolean fit_height, gboolean keep_proportions)
+{
+ if ((fit_width == FALSE) && (fit_height == FALSE))
+ {
+ return (TRUE);
+ }
+
+ if ((fit_width != fit_height) && (keep_proportions == FALSE))
+ {
+ return (TRUE);
+ }
+
+ return (FALSE);
+
+} /* end p_is_width_or_height_fixed */
+
+
+
+/* -----------------------------------------
+ * p_create_transformed_layer_movepath
+ * -----------------------------------------
+ * create transformed copy of the specified origsize_layer_id,
+ * according to movepath rendering and current transformation settings.
+ */
+static gboolean
+p_create_transformed_layer_movepath(gint32 image_id
+ , gint32 origsize_layer_id
+ , gint32 *layer_id_ptr
+ , GapStoryCalcAttr *calculated
+ , gint32 stackposition, const char *layername
+ , GapStbAttrWidget *attw
+ , gint img_idx
+ )
+{
+ char *movepath_file_xml;
+ gboolean keep_proportions;
+ gboolean fit_width;
+ gboolean fit_height;
+ gint master_width;
+ gint master_height;
+ gint32 new_layer_id;
+ gint32 mov_obj_image_id;
+ gint32 mov_obj_layer_id;
+ gdouble att_tab[GAP_STB_ATT_GFX_ARRAY_MAX][GAP_STB_ATT_TYPES_ARRAY_MAX];
+ gint ii;
+
+ if(attw == NULL)
+ {
+ printf("** INTERNAL ERROR p_create_transformed_layer_movepath called with attw is NULL\n");
+ return (FALSE);
+ }
+ if(attw->stb_refptr == NULL)
+ {
+ printf("** INTERNAL ERROR p_create_transformed_layer_movepath called with stb_refptr is NULL\n");
+ return (FALSE);
+ }
+
+ if(attw->movepath_file_xml_is_valid != TRUE)
+ {
+ return (FALSE);
+ }
+
+ master_width = attw->stb_refptr->master_width;
+ master_height = attw->stb_refptr->master_height;
+ keep_proportions = attw->stb_elem_refptr->att_keep_proportions;
+ fit_width = attw->stb_elem_refptr->att_fit_width;
+ fit_height = attw->stb_elem_refptr->att_fit_height;
+ movepath_file_xml = attw->stb_elem_refptr->att_movepath_file_xml;
+ for(ii=0; ii < GAP_STB_ATT_TYPES_ARRAY_MAX; ii++)
+ {
+ if(attw->stb_elem_refptr->att_arr_enable[ii] == TRUE)
+ {
+ att_tab[0][ii] = attw->stb_elem_refptr->att_arr_value_from[ii];
+ att_tab[1][ii] = attw->stb_elem_refptr->att_arr_value_to[ii];
+ }
+ else
+ {
+ att_tab[0][ii] = gap_story_get_default_attribute(ii);
+ att_tab[1][ii] = gap_story_get_default_attribute(ii);
+ }
+ }
+
+ if(movepath_file_xml == NULL)
+ {
+ return (FALSE);
+ }
+ if(origsize_layer_id < 0)
+ {
+ return (FALSE);
+ }
+
+
+ /* recreate the current layer at stackposition 2 */
+
+ /* create image with 1:1 copy of the origsize_layer_id */
+ mov_obj_image_id = gimp_image_new( gimp_drawable_width(origsize_layer_id)
+ , gimp_drawable_height(origsize_layer_id)
+ , GIMP_RGB
+ );
+ gimp_image_undo_disable (mov_obj_image_id);
+ mov_obj_layer_id = gimp_layer_new_from_drawable(origsize_layer_id, mov_obj_image_id);
+
+
+ if(mov_obj_layer_id >= 0)
+ {
+ gimp_drawable_set_visible(mov_obj_layer_id, TRUE);
+ if(! gimp_drawable_has_alpha(mov_obj_layer_id))
+ {
+ /* have to add alpha channel */
+ gimp_layer_add_alpha(mov_obj_layer_id);
+ }
+ gimp_image_add_layer(mov_obj_image_id, mov_obj_layer_id, 0);
+ gimp_layer_set_offsets(mov_obj_layer_id, 0, 0);
+ }
+
+ //if(img_idx == 0)
+ //{
+ // p_debug_dup_image(mov_obj_image_id);
+ //}
+
+ /* prescale to preview size in case fixed witdh or height
+ * (we can skip the prescale in other modes, because the non fixed modes
+ * allow scaling to render size in the movepath render processing)
+ */
+ if (p_is_width_or_height_fixed(fit_width, fit_height, keep_proportions) == TRUE)
+ {
+ gint scaled_width;
+ gint scaled_height;
+
+ scaled_width = gimp_image_width(mov_obj_image_id) * gimp_image_width(image_id) / master_width;
+ scaled_height = gimp_image_height(mov_obj_image_id) * gimp_image_height(image_id) / master_height;
+ gimp_image_scale(mov_obj_image_id, scaled_width, scaled_height);
+ }
+
+ /* call storyboard processor that does movepath and other transformations
+ * (note that processing is done at size of the preview image that is 2 times larger
+ * than the wanted result because
+ */
+ new_layer_id = gap_story_render_transform_with_movepath_processing(image_id
+ , mov_obj_image_id
+ , mov_obj_layer_id
+ , keep_proportions
+ , fit_width
+ , fit_height
+ , att_tab [img_idx][GAP_STB_ATT_TYPE_ROTATE] /* rotation in degree */
+ , att_tab [img_idx][GAP_STB_ATT_TYPE_OPACITY] /* 0.0 upto 1.0 */
+ , att_tab [img_idx][GAP_STB_ATT_TYPE_ZOOM_X] /* 0.0 upto 10.0 where 1.0 = 1:1 */
+ , att_tab [img_idx][GAP_STB_ATT_TYPE_ZOOM_Y] /* 0.0 upto 10.0 where 1.0 = 1:1 */
+ , att_tab [img_idx][GAP_STB_ATT_TYPE_MOVE_X] /* -1.0 upto +1.0 where 0 = no move, -1 is left outside */
+ , att_tab [img_idx][GAP_STB_ATT_TYPE_MOVE_Y] /* -1.0 upto +1.0 where 0 = no move, -1 is top outside */
+ , movepath_file_xml
+ , att_tab [img_idx][GAP_STB_ATT_TYPE_MOVEPATH] /* movepath_framePhase */
+ );
+
+ gimp_layer_resize_to_image_size(new_layer_id);
+
+ gimp_layer_scale(new_layer_id
+ , gimp_drawable_width(new_layer_id) * PVIEW_TO_MASTER_SCALE
+ , gimp_drawable_height(new_layer_id) * PVIEW_TO_MASTER_SCALE
+ , TRUE /* TRUE: centered local on layer */
+ );
+
+
+ if(gap_debug)
+ {
+ printf("p_create_transformed_layer_movepath: "
+ "new_layer_id:%d new_layers_image_id:%d mov_obj_image_id:%d (preview)image_id:%d\n"
+ ,(int)new_layer_id
+ ,(int)gimp_drawable_get_image(new_layer_id)
+ ,(int)mov_obj_image_id
+ ,(int)image_id
+ );
+ }
+ if(mov_obj_image_id >= 0)
+ {
+ gap_image_delete_immediate(mov_obj_image_id);
+ }
+
+
+ gimp_drawable_set_visible(new_layer_id, TRUE);
+
+ p_adjust_stackposition(image_id, new_layer_id, stackposition);
+
+ gimp_layer_set_opacity(new_layer_id
+ , calculated->opacity
+ );
+ *layer_id_ptr = new_layer_id;
+
+ return (TRUE);
+
+} /* end p_create_transformed_layer_movepath */
+
+
+/* -----------------------------------------
* p_create_transformed_layer
* -----------------------------------------
* create transformed copy of the specified origsize_layer_id,
* according to calculated transformation settings.
+ *
*/
static void
p_create_transformed_layer(gint32 image_id
, gint32 origsize_layer_id
, gint32 *layer_id_ptr
, GapStoryCalcAttr *calculated
- , gint32 stackposition, const char *layername)
+ , gint32 stackposition
+ , const char *layername
+ , GapStbAttrWidget *attw
+ , gint img_idx
+ , gboolean enableMovepath
+ )
{
- /* if size is not equal calculated size remove curr layer
+ char *movepath_file_xml;
+
+ movepath_file_xml = NULL;
+ if((attw != NULL)
+ && (enableMovepath))
+ {
+ if(attw->stb_elem_refptr != NULL)
+ {
+ if (attw->stb_elem_refptr->att_arr_enable[GAP_STB_ATT_TYPE_MOVEPATH] == TRUE)
+ {
+ movepath_file_xml = attw->stb_elem_refptr->att_movepath_file_xml;
+ }
+ }
+ }
+
+ /* if size is not equal calculated size
+ * or movepath rendering necessary then remove curr layer
* to force recreation in desired size
*/
if (*layer_id_ptr >= 0)
{
if ((gimp_drawable_width(*layer_id_ptr) != calculated->width)
- || (gimp_drawable_height(*layer_id_ptr) != calculated->height))
+ || (gimp_drawable_height(*layer_id_ptr) != calculated->height)
+ || (movepath_file_xml != NULL))
{
gimp_image_remove_layer( image_id
, *layer_id_ptr);
@@ -1444,11 +1735,34 @@ p_create_transformed_layer(gint32 image_id
{
gint32 new_layer_id;
+ if(movepath_file_xml != NULL)
+ {
+ gboolean movepathOk;
+
+ movepathOk = p_create_transformed_layer_movepath(image_id
+ , origsize_layer_id
+ , layer_id_ptr
+ , calculated
+ , stackposition
+ , layername
+ , attw
+ , img_idx
+ );
+ if(movepathOk == TRUE)
+ {
+ return;
+ }
+ /* else fallback to rendering without movepath transformations */
+ }
new_layer_id = gimp_layer_copy(origsize_layer_id);
gimp_image_add_layer (image_id, new_layer_id, stackposition);
gimp_drawable_set_name(new_layer_id, layername);
+
gimp_layer_scale(new_layer_id, calculated->width, calculated->height, 0);
+
+
+
gimp_drawable_set_visible(new_layer_id, TRUE);
*layer_id_ptr = new_layer_id;
@@ -1464,7 +1778,6 @@ p_create_transformed_layer(gint32 image_id
gap_story_transform_rotate_layer(image_id, *layer_id_ptr, calculated->rotate);
-
gimp_layer_set_opacity(*layer_id_ptr
, calculated->opacity
);
@@ -1534,6 +1847,9 @@ p_render_gfx(GapStbAttrWidget *attw, gint img_idx)
, &calculate_pref_attributes
, LAYERSTACK_PREF
, LAYERNAME_PREF
+ , attw
+ , img_idx
+ , FALSE /* do not enableMovepath */
);
@@ -1548,6 +1864,9 @@ p_render_gfx(GapStbAttrWidget *attw, gint img_idx)
, &calculate_curr_attributes
, LAYERSTACK_CURR
, LAYERNAME_CURR
+ , attw
+ , img_idx
+ , TRUE /* enableMovepath */
);
prefetch_visible = p_calculate_prefetch_visibility(attw, img_idx);
@@ -1685,8 +2004,7 @@ p_stb_req_equals_layer_info(GapStbAttrLayerInfo *linfo
, GapStoryLocateRet *stb_ret
, const char *filename)
{
- if (stb_ret->stb_elem->record_type
- != linfo->layer_record_type)
+ if (stb_ret->stb_elem->record_type != linfo->layer_record_type)
{
return(FALSE);
}
@@ -1820,7 +2138,6 @@ p_orig_layer_frame_fetcher(GapStbAttrWidget *attw
l_layer_id = -1;
l_filename = NULL;
-
{
GapStoryLocateRet *stb_ret;
GapStorySection *section;
@@ -1837,9 +2154,10 @@ p_orig_layer_frame_fetcher(GapStbAttrWidget *attw
{
gboolean is_up_to_date;
- l_filename = gap_story_get_filename_from_elem_nr(stb_ret->stb_elem
+ l_filename = gap_story_get_filename_from_elem_nr_anim(stb_ret->stb_elem
, stb_ret->ret_framenr
);
+
is_up_to_date = p_check_orig_layer_up_to_date(image_id
,orig_layer_id_ptr
,derived_layer_id_ptr
@@ -1847,6 +2165,7 @@ p_orig_layer_frame_fetcher(GapStbAttrWidget *attw
,stb_ret
,l_filename
);
+
if(is_up_to_date)
{
g_free(stb_ret);
@@ -1854,6 +2173,7 @@ p_orig_layer_frame_fetcher(GapStbAttrWidget *attw
{
g_free(l_filename);
}
+
return; /* orig_layer is still up to date, done */
}
@@ -1886,10 +2206,67 @@ p_orig_layer_frame_fetcher(GapStbAttrWidget *attw
}
}
}
+ else if(stb_ret->stb_elem->record_type == GAP_STBREC_VID_COLOR)
+ {
+ l_layer_id = gimp_layer_new(image_id, "color"
+ ,gimp_image_width(image_id)
+ ,gimp_image_height(image_id)
+ ,GIMP_RGBA_IMAGE
+ ,100.0 /* Opacity */
+ ,GIMP_NORMAL_MODE
+ );
+ gimp_image_add_layer(image_id, l_layer_id, LAYERSTACK_TOP);
+ gap_layer_clear_to_color(l_layer_id
+ , stb_ret->stb_elem->color_red
+ , stb_ret->stb_elem->color_green
+ , stb_ret->stb_elem->color_blue
+ , stb_ret->stb_elem->color_alpha
+ );
+
+ linfo->layer_record_type = stb_ret->stb_elem->record_type;
+ linfo->layer_local_framenr = 0;
+ linfo->layer_seltrack = 1;
+ if (linfo->layer_filename != NULL)
+ {
+ g_free(linfo->layer_filename);
+ linfo->layer_filename = NULL;
+ }
+
+ }
+ else if(stb_ret->stb_elem->record_type == GAP_STBREC_VID_ANIMIMAGE)
+ {
+ if(gap_debug)
+ {
+ printf("GAP_STBREC_VID_ANIMIMAGE: l_filename:%s ret_framenr:%d\n"
+ , l_filename
+ , stb_ret->ret_framenr
+ );
+ }
+ if(l_filename)
+ {
+ /* fetch_full_sized_frame */
+ l_layer_id = p_fetch_layer_from_animimage(l_filename
+ ,stb_ret->ret_framenr
+ ,image_id
+ );
+ if(l_layer_id > 0)
+ {
+ l_layer_id = gap_layer_flip(l_layer_id, stb_ret->stb_elem->flip_request);
+
+ linfo->layer_record_type = stb_ret->stb_elem->record_type;
+ linfo->layer_local_framenr = stb_ret->ret_framenr;
+ linfo->layer_seltrack = 1;
+ if (linfo->layer_filename != NULL)
+ {
+ g_free(linfo->layer_filename);
+ linfo->layer_filename = g_strdup(l_filename);
+ }
+ }
+ }
+ }
else
{
/* record type is IMAGE or FRAME, fetch full size image
- * TODO: anim frame and COLOR not handled
*/
l_layer_id = p_fetch_imagefile_as_layer(l_filename
,image_id
@@ -2163,6 +2540,8 @@ p_fetch_video_frame_as_layer(GapStbMainGlobalParams *sgpp
/* ---------------------------------
* p_fetch_imagefile_as_layer
* ---------------------------------
+ * add the specified image filename as new layer on top of layerstack in the specified image_id.
+ * The newly added layer is a copy of the composite view (e.g. a merge of its visible layers)
*/
static gint32
p_fetch_imagefile_as_layer (const char *img_filename
@@ -2187,20 +2566,13 @@ p_fetch_imagefile_as_layer (const char *img_filename
gint l_src_offset_x, l_src_offset_y;
gimp_image_undo_disable (l_tmp_image_id);
- l_layer_id = gimp_image_flatten(l_tmp_image_id);
- if(l_layer_id < 0)
+ l_layer_id = gap_image_merge_visible_layers(l_tmp_image_id, GIMP_CLIP_TO_IMAGE);
+
+ if(!gimp_drawable_has_alpha(l_layer_id))
{
- l_layer_id = gimp_layer_new(l_tmp_image_id, LAYERNAME_ORIG,
- 1,
- 1,
- ((gint)(gimp_image_base_type(l_tmp_image_id)) * 2),
- 100.0, /* Opacity full opaque */
- 0); /* NORMAL */
- gimp_image_add_layer(l_tmp_image_id, l_layer_id, LAYERSTACK_TOP);
- gimp_layer_set_offsets(l_layer_id, -1, -1);
- l_layer_id = gimp_image_flatten(l_tmp_image_id);
+ gimp_layer_add_alpha(l_layer_id);
}
- gimp_layer_add_alpha(l_layer_id);
+ gimp_layer_resize_to_image_size(l_layer_id);
/* copy the layer from the temp image to the preview multilayer image */
l_new_layer_id = gap_layer_copy_to_dest_image(image_id,
@@ -2217,11 +2589,246 @@ p_fetch_imagefile_as_layer (const char *img_filename
gimp_image_delete(l_tmp_image_id);
}
-
return(l_new_layer_id);
+
} /* end p_fetch_imagefile_as_layer */
+/* ---------------------------------
+ * p_fetch_layer_from_animimage
+ * ---------------------------------
+ * pick layer at specified localframe_index (e.g. layerstack_position) from specified
+ * multilayer animimage on disk (specified via filename)
+ * and add a copy of this layer as new layer on top of layerstack in the specified image_id.
+ */
+static gint32
+p_fetch_layer_from_animimage (const char *img_filename
+ , gint32 localframe_index, gint32 image_id
+ )
+{
+ gint32 l_tmp_image_id;
+ gint32 l_new_layer_id;
+
+ l_new_layer_id = -1;
+
+ if(gap_debug)
+ {
+ printf("p_fetch_layer_from_animimage START localframe_index:%d img_filename:%s\n"
+ ,(int)localframe_index
+ ,img_filename
+ );
+ }
+
+
+
+ {
+ char *l_filename;
+ l_filename = g_strdup(img_filename);
+ l_tmp_image_id = gap_lib_load_image(l_filename);
+ g_free(l_filename);
+ }
+
+ if(l_tmp_image_id >= 0)
+ {
+ gint l_src_offset_x, l_src_offset_y;
+ gint l_nlayers;
+ gint32 *l_layers_list;
+
+ gimp_image_undo_disable (l_tmp_image_id);
+
+ l_layers_list = gimp_image_get_layers(l_tmp_image_id, &l_nlayers);
+
+ if(gap_debug)
+ {
+ printf("p_fetch_layer_from_animimage l_nlayers:%d localframe_index:%d img_filename:%s\n"
+ ,(int)l_nlayers
+ ,(int)localframe_index
+ ,img_filename
+ );
+ }
+
+
+ if(l_layers_list != NULL)
+ {
+ if((localframe_index < l_nlayers)
+ && (localframe_index >= 0))
+ {
+ gimp_drawable_set_visible(l_layers_list[localframe_index], TRUE);
+ if (0 != gimp_layer_get_apply_mask(l_layers_list[localframe_index]))
+ {
+ /* the layer has an active mask, apply the mask now
+ * because copying from the layer ignores the mask
+ */
+ gimp_layer_remove_mask(l_layers_list[localframe_index], GIMP_MASK_APPLY);
+ }
+ gimp_layer_resize_to_image_size(l_layers_list[localframe_index]);
+
+ /* copy the picked layer from the temp image to the preview multilayer image */
+ l_new_layer_id = gap_layer_copy_to_dest_image(image_id,
+ l_layers_list[localframe_index],
+ 100.0, /* opacity full */
+ 0, /* NORMAL */
+ &l_src_offset_x,
+ &l_src_offset_y
+ );
+
+ gimp_image_add_layer (image_id, l_new_layer_id, LAYERSTACK_TOP);
+
+ }
+ g_free (l_layers_list);
+ }
+
+ /* destroy the tmp image */
+ gimp_image_delete(l_tmp_image_id);
+ }
+
+
+ return(l_new_layer_id);
+} /* end p_fetch_layer_from_animimage */
+
+
+/* ==================================================== START MOVEPATH FILESEL stuff ====== */
+/* --------------------------------
+ * p_attw_movepath_filesel_pw_ok_cb
+ * --------------------------------
+ */
+static void
+p_attw_movepath_filesel_pw_ok_cb (GtkWidget *widget
+ ,GapStbAttrWidget *attw)
+{
+ const gchar *movepathFilename;
+ gchar *dup_movepathFilename;
+
+ if(attw == NULL) return;
+ if(attw->movepath_filesel == NULL) return;
+
+ dup_movepathFilename = NULL;
+ movepathFilename = gtk_file_selection_get_filename (GTK_FILE_SELECTION (attw->movepath_filesel));
+ if(movepathFilename)
+ {
+ dup_movepathFilename = g_strdup(movepathFilename);
+ }
+
+ gtk_widget_destroy(GTK_WIDGET(attw->movepath_filesel));
+
+ if(dup_movepathFilename)
+ {
+ gtk_entry_set_text(GTK_ENTRY(attw->movepath_file_entry), dup_movepathFilename);
+ g_free(dup_movepathFilename);
+ }
+
+ attw->movepath_filesel = NULL;
+} /* end p_attw_movepath_filesel_pw_ok_cb */
+
+
+/* -----------------------------------
+ * p_attw_movepath_filesel_pw_close_cb
+ * -----------------------------------
+ */
+static void
+p_attw_movepath_filesel_pw_close_cb ( GtkWidget *widget
+ , GapStbAttrWidget *attw)
+{
+ if(attw->movepath_filesel == NULL) return;
+
+ gtk_widget_destroy(GTK_WIDGET(attw->movepath_filesel));
+ attw->movepath_filesel = NULL; /* indicate that filesel is closed */
+
+} /* end p_attw_movepath_filesel_pw_close_cb */
+
+
+
+/* ---------------------------------
+ * p_attw_movepath_filesel_button_cb
+ * ---------------------------------
+ */
+static void
+p_attw_movepath_filesel_button_cb ( GtkWidget *w
+ , GapStbAttrWidget *attw)
+{
+ GtkWidget *filesel = NULL;
+
+ if(attw->attw_prop_dialog == NULL)
+ {
+ return;
+ }
+
+ if(attw->movepath_filesel != NULL)
+ {
+ gtk_window_present(GTK_WINDOW(attw->movepath_filesel));
+ return; /* filesel is already open */
+ }
+ if(attw->stb_elem_refptr == NULL) { return; }
+
+ filesel = gtk_file_selection_new ( _("Set Movepath Parameterfile (XML)"));
+ attw->movepath_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_attw_movepath_filesel_pw_ok_cb),
+ attw);
+ g_signal_connect (GTK_FILE_SELECTION (filesel)->cancel_button,
+ "clicked", G_CALLBACK (p_attw_movepath_filesel_pw_close_cb),
+ attw);
+ g_signal_connect (filesel, "destroy",
+ G_CALLBACK (p_attw_movepath_filesel_pw_close_cb),
+ attw);
+
+
+ if(attw->stb_elem_refptr->att_movepath_file_xml)
+ {
+ gtk_file_selection_set_filename (GTK_FILE_SELECTION (filesel),
+ attw->stb_elem_refptr->att_movepath_file_xml);
+ }
+ gtk_widget_show (filesel);
+
+} /* end p_attw_movepath_filesel_button_cb */
+
+
+/* ==================================================== END MOVEPATH FILESEL stuff ====== */
+
+/* ------------------------------------
+ * p_attw_movepath_file_validity_check
+ * ------------------------------------
+ */
+static void
+p_attw_movepath_file_validity_check(GapStbAttrWidget *attw)
+{
+ if(attw == NULL) { return; }
+ attw->movepath_file_xml_is_valid = FALSE;
+
+ if(attw->stb_elem_refptr == NULL) { return; }
+
+
+ attw->movepath_file_xml_is_valid = gap_mov_exec_check_valid_xml_paramfile(attw->stb_elem_refptr->att_movepath_file_xml);
+
+ p_attw_update_sensitivity(attw);
+ p_attw_update_properties(attw);
+
+} /* end p_attw_movepath_file_validity_check */
+
+
+/* ------------------------------------
+ * p_attw_movepath_file_entry_update_cb
+ * ------------------------------------
+ */
+static void
+p_attw_movepath_file_entry_update_cb(GtkWidget *widget, GapStbAttrWidget *attw)
+{
+ if(attw == NULL) { return; }
+ if(attw->stb_elem_refptr == NULL) { return; }
+
+ p_attw_push_undo_and_set_unsaved_changes(attw);
+
+ if(attw->stb_elem_refptr->att_movepath_file_xml)
+ {
+ g_free(attw->stb_elem_refptr->att_movepath_file_xml);
+ }
+ attw->stb_elem_refptr->att_movepath_file_xml = g_strdup(gtk_entry_get_text(GTK_ENTRY(widget)));
+
+ p_attw_movepath_file_validity_check(attw);
+
+} /* end p_attw_movepath_file_entry_update_cb */
/* ------------------------------
@@ -2233,10 +2840,8 @@ p_attw_comment_entry_update_cb(GtkWidget *widget, GapStbAttrWidget *attw)
{
if(attw == NULL) { return; }
if(attw->stb_elem_refptr == NULL) { return; }
- if(attw->stb_refptr)
- {
- attw->stb_refptr->unsaved_changes = TRUE;
- }
+
+ p_attw_push_undo_and_set_unsaved_changes(attw);
if(attw->stb_elem_refptr->comment == NULL)
{
@@ -2253,6 +2858,7 @@ p_attw_comment_entry_update_cb(GtkWidget *widget, GapStbAttrWidget *attw)
}
} /* end p_attw_comment_entry_update_cb */
+
/* ---------------------------------------
* p_init_layer_info
* ---------------------------------------
@@ -2506,7 +3112,7 @@ p_create_and_attach_att_arr_widgets(const char *row_title
gtk_widget_set_size_request (spinbutton, 80, -1);
gimp_help_set_help_data (spinbutton, from_tooltip, NULL);
- g_object_set_data(G_OBJECT(adj), "att_type_idx", att_type_idx);
+ g_object_set_data(G_OBJECT(adj), "att_type_idx", (gpointer)att_type_idx);
g_object_set_data(G_OBJECT(adj), OBJ_DATA_KEY_ATTW, attw);
g_signal_connect (G_OBJECT (adj), "value_changed",
G_CALLBACK (p_attw_gdouble_adjustment_callback),
@@ -2549,7 +3155,7 @@ p_create_and_attach_att_arr_widgets(const char *row_title
gtk_widget_set_size_request (spinbutton, 80, -1);
gimp_help_set_help_data (spinbutton, to_tooltip, NULL);
- g_object_set_data(G_OBJECT(adj), "att_type_idx", att_type_idx);
+ g_object_set_data(G_OBJECT(adj), "att_type_idx", (gpointer)att_type_idx);
g_object_set_data(G_OBJECT(adj), OBJ_DATA_KEY_ATTW, attw);
g_signal_connect (G_OBJECT (adj), "value_changed",
G_CALLBACK (p_attw_gdouble_adjustment_callback),
@@ -2676,6 +3282,8 @@ gap_story_attw_properties_dialog (GapStbAttrWidget *attw)
tabw = (GapStbTabWidgets *)attw->tabw;
if(tabw == NULL) { return (NULL); }
+ attw->movepath_filesel = NULL;
+
if(attw->stb_elem_bck)
{
dlg = gimp_dialog_new (_("Transition Attributes"), "gap_story_attr_properties"
@@ -3014,6 +3622,36 @@ gap_story_attw_properties_dialog (GapStbAttrWidget *attw)
, &attw->stb_elem_refptr->att_arr_value_accel[att_type_idx]
);
+ row++;
+ att_type_idx = GAP_STB_ATT_TYPE_MOVEPATH;
+ p_create_and_attach_att_arr_widgets(_("Move Path:")
+ , attw
+ , table
+ , row
+ , col
+ , att_type_idx
+ , 1.0 /* lower constraint for the from/to values */
+ , 10000.0 /* upper constraint for the from/to values */
+ , 1.0 /* step increment for the from/to values */
+ , 10.0 /* page increment for the from/to values */
+ , 0.0 /* page size for the from/to values */
+ , 0 /* digits for the from/to values */
+ , _("ON: Enable move path transistions using settings provided via a movepath parameter file")
+ , &attw->stb_elem_refptr->att_arr_enable[att_type_idx]
+ , _("frame number (phase) of the movement/transition along path for the first handled frame"
+ " where 1 is the begin of the path using settings of the 1st controlpoint"
+ " in the movepath parameter file")
+ , &attw->stb_elem_refptr->att_arr_value_from[att_type_idx]
+ , _("frame number (phase) of the movement/transition along path for the last handled frame."
+ " note that frame numbers higher than (or equal to) total frames in the movepath parameter file"
+ " uses settings of the last controlpoint in this file.")
+ , &attw->stb_elem_refptr->att_arr_value_to[att_type_idx]
+ , _("number of frames")
+ , &attw->stb_elem_refptr->att_arr_value_dur[att_type_idx]
+ , _("acceleration characteristic (currently ignored)")
+ , &attw->stb_elem_refptr->att_arr_value_accel[att_type_idx]
+ );
+
}
@@ -3048,6 +3686,46 @@ gap_story_attw_properties_dialog (GapStbAttrWidget *attw)
);
}
+ row++;
+
+
+ {
+ GtkWidget *button;
+
+
+ /* the movepath label */
+ label = gtk_label_new (_("Movepath File:"));
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ gtk_table_attach_defaults (GTK_TABLE(table), label, 0, 1, row, row+1);
+ gtk_widget_show (label);
+
+
+ /* the movepath entry */
+ entry = gtk_entry_new ();
+ gtk_widget_set_size_request(entry, ATTW_COMMENT_WIDTH, -1);
+ if(attw->stb_elem_refptr)
+ {
+ if(attw->stb_elem_refptr->att_movepath_file_xml)
+ {
+ gtk_entry_set_text(GTK_ENTRY(entry), attw->stb_elem_refptr->att_movepath_file_xml);
+ }
+ }
+ gtk_table_attach_defaults (GTK_TABLE(table), entry, 1, 8, row, row+1);
+ g_signal_connect(G_OBJECT(entry), "changed",
+ G_CALLBACK(p_attw_movepath_file_entry_update_cb),
+ attw);
+ gtk_widget_show (entry);
+ attw->movepath_file_entry = entry;
+
+ /* the filesel invoker button */
+ button = gtk_button_new_with_label ("...");
+ gtk_table_attach_defaults (GTK_TABLE(table), button, 8, 10, row, row+1);
+ g_signal_connect(G_OBJECT(button), "clicked",
+ G_CALLBACK(p_attw_movepath_filesel_button_cb),
+ attw);
+ gtk_widget_show (button);
+
+ }
row++;
@@ -3079,7 +3757,7 @@ gap_story_attw_properties_dialog (GapStbAttrWidget *attw)
gtk_widget_show (entry);
attw->comment_entry = entry;
-
+ p_attw_movepath_file_validity_check(attw);
p_attw_update_sensitivity(attw);
/* Show the main containers */
diff --git a/gap/gap_story_file.c b/gap/gap_story_file.c
index 69637b6..f8f6dea 100644
--- a/gap/gap_story_file.c
+++ b/gap/gap_story_file.c
@@ -82,6 +82,7 @@ static const char *gtab_att_transition_key_words[GAP_STB_ATT_TYPES_ARRAY_MAX] =
, GAP_STBKEY_VID_ZOOM_X
, GAP_STBKEY_VID_ZOOM_Y
, GAP_STBKEY_VID_ROTATE
+ , GAP_STBKEY_VID_MOVEPATH
};
@@ -274,6 +275,10 @@ gap_story_debug_print_elem(GapStoryElem *stb_elem)
);
}
}
+ if(stb_elem->att_movepath_file_xml != NULL)
+ {
+ printf(" att_movepath_file_xml: %s\n", stb_elem->att_movepath_file_xml);
+ }
printf(" overlap: %d\n", (int)stb_elem->att_overlap);
}
@@ -758,7 +763,9 @@ gap_story_new_elem(GapStoryRecordType record_type)
stb_elem->att_arr_value_dur[ii] = 1; /* number of frames to change from -> to value */
stb_elem->att_arr_value_accel[ii] = 0; /* per default use no acceleration characteristic */
}
+ stb_elem->att_arr_value_to[GAP_STB_ATT_TYPE_MOVEPATH] = 100.0;
}
+ stb_elem->att_movepath_file_xml = NULL;
/* init members for Audio Record types */
stb_elem->aud_filename = NULL;
@@ -1301,14 +1308,15 @@ gap_story_upd_elem_from_filename(GapStoryElem *stb_elem, const char *filename)
static void
p_free_stb_elem(GapStoryElem *stb_elem)
{
- if(stb_elem->orig_filename) { g_free(stb_elem->orig_filename);}
- if(stb_elem->orig_src_line) { g_free(stb_elem->orig_src_line);}
- if(stb_elem->basename) { g_free(stb_elem->basename);}
- if(stb_elem->ext) { g_free(stb_elem->ext);}
- if(stb_elem->filtermacro_file) { g_free(stb_elem->filtermacro_file);}
- if(stb_elem->colormask_file) { g_free(stb_elem->colormask_file);}
- if(stb_elem->preferred_decoder) { g_free(stb_elem->preferred_decoder);}
- if(stb_elem->mask_name) { g_free(stb_elem->mask_name);}
+ if(stb_elem->orig_filename) { g_free(stb_elem->orig_filename);}
+ if(stb_elem->orig_src_line) { g_free(stb_elem->orig_src_line);}
+ if(stb_elem->basename) { g_free(stb_elem->basename);}
+ if(stb_elem->ext) { g_free(stb_elem->ext);}
+ if(stb_elem->filtermacro_file) { g_free(stb_elem->filtermacro_file);}
+ if(stb_elem->colormask_file) { g_free(stb_elem->colormask_file);}
+ if(stb_elem->preferred_decoder) { g_free(stb_elem->preferred_decoder);}
+ if(stb_elem->mask_name) { g_free(stb_elem->mask_name);}
+ if(stb_elem->att_movepath_file_xml) { g_free(stb_elem->att_movepath_file_xml);}
} /* end p_free_stb_elem */
@@ -3327,13 +3335,14 @@ p_story_parse_line(GapStoryBoard *stb, char *longline
|| (strcmp(l_record_key, GAP_STBKEY_VID_MOVE_X) == 0)
|| (strcmp(l_record_key, GAP_STBKEY_VID_MOVE_Y) == 0)
|| (strcmp(l_record_key, GAP_STBKEY_VID_FIT_SIZE) == 0)
+ || (strcmp(l_record_key, GAP_STBKEY_VID_MOVEPATH) == 0)
|| (strcmp(l_record_key, GAP_STBKEY_VID_OVERLAP) == 0))
{
- char *l_track_ptr = l_wordval[1];
- char *l_from_ptr = l_wordval[2];
- char *l_to_ptr = l_wordval[3];
- char *l_dur_ptr = l_wordval[4];
- char *l_accel_ptr = l_wordval[5];
+ char *l_track_ptr = l_wordval[1];
+ char *l_from_ptr = l_wordval[2];
+ char *l_to_ptr = l_wordval[3];
+ char *l_dur_ptr = l_wordval[4];
+ char *l_accel_ptr = l_wordval[5];
gint32 l_track_nr;
@@ -3344,6 +3353,38 @@ p_story_parse_line(GapStoryBoard *stb, char *longline
}
+ /* ATTRIBUTE: GAP_STBKEY_VID_MOVEPATH */
+ if (strcmp(l_record_key, GAP_STBKEY_VID_MOVEPATH) == 0)
+ {
+ char *l_xml_ptr = l_wordval[6];
+ gboolean elem_already_in_the_list = FALSE;
+
+ ii = GAP_STB_ATT_TYPE_MOVEPATH;
+
+ stb_elem = p_get_att_transition_elem(stb, &elem_already_in_the_list, l_track_nr);
+ if(stb_elem)
+ {
+ stb_elem->att_arr_enable[ii] = TRUE;
+ stb_elem->file_line_nr = longlinenr;
+ stb_elem->orig_src_line = g_strdup(multi_lines);
+ stb_elem->track = l_track_nr;
+ if(*l_from_ptr) { stb_elem->att_arr_value_from[ii] = p_scan_gdouble(l_from_ptr, 1.0, 10000.0, stb); }
+ if(*l_to_ptr) { stb_elem->att_arr_value_to[ii] = p_scan_gdouble(l_to_ptr, 0.0, 10000.0, stb); }
+ else { stb_elem->att_arr_value_to[ii] = stb_elem->att_arr_value_from[ii]; }
+ if(*l_dur_ptr) { stb_elem->att_arr_value_dur[ii] = p_scan_gint32(l_dur_ptr, 0, 10000, stb); }
+ if(*l_xml_ptr) { stb_elem->att_movepath_file_xml = g_strdup(l_xml_ptr); }
+ else { stb_elem->att_arr_enable[ii] = FALSE; }
+
+ p_assign_accel_attr(stb_elem, stb, l_accel_ptr, ii);
+
+ if(elem_already_in_the_list != TRUE)
+ {
+ gap_story_list_append_elem(stb, stb_elem);
+ }
+ }
+ goto cleanup;
+ }
+
/* ATTRIBUTE: GAP_STBKEY_VID_OVERLAP */
if (strcmp(l_record_key, GAP_STBKEY_VID_OVERLAP) == 0)
{
@@ -4848,7 +4889,20 @@ p_story_save_att_transition(FILE *fp, GapStoryElem *stb_elem)
for(ii=0; ii < GAP_STB_ATT_TYPES_ARRAY_MAX; ii++)
{
- if(stb_elem->att_arr_enable[ii])
+ gboolean writeEnable;
+
+ writeEnable = stb_elem->att_arr_enable[ii];
+ if((ii == GAP_STB_ATT_TYPE_MOVEPATH)
+ && (stb_elem->att_movepath_file_xml != NULL))
+ {
+ if(stb_elem->att_movepath_file_xml[0] == '\0')
+ {
+ /* disable movepath in case of empty filename */
+ writeEnable = FALSE;
+ }
+ }
+
+ if(writeEnable)
{
gchar l_from_str[G_ASCII_DTOSTR_BUF_SIZE];
gchar l_to_str[G_ASCII_DTOSTR_BUF_SIZE];
@@ -4866,16 +4920,20 @@ p_story_save_att_transition(FILE *fp, GapStoryElem *stb_elem)
,stb_elem->att_arr_value_to[ii]
);
- fprintf(fp, "%s "
+ fprintf(fp, "%s "
, gtab_att_transition_key_words[ii]
);
- if(ii !=0 )
+ if(ii != 6)
{
- /* print one extra space
- * VID_MOVE_X, VID_MOVE_Y, VID_ZOOM_X, VID_ZOOM_Y VID_ROTATE
- * are 1 character shorter than VID_OPACITY
- */
fprintf(fp, " ");
+ if(ii != 0 )
+ {
+ /* print one extra space
+ * VID_MOVE_X, VID_MOVE_Y, VID_ZOOM_X, VID_ZOOM_Y VID_ROTATE
+ * are 1 character shorter than VID_OPACITY
+ */
+ fprintf(fp, " ");
+ }
}
fprintf(fp, "%s:%d %s:%s %s:%s %s:%d"
@@ -4890,6 +4948,13 @@ p_story_save_att_transition(FILE *fp, GapStoryElem *stb_elem)
, l_parnam_tab.parname[5] , stb_elem->att_arr_value_accel[ii]
);
}
+ if((ii == GAP_STB_ATT_TYPE_MOVEPATH)
+ && (stb_elem->att_movepath_file_xml != NULL))
+ {
+ fprintf(fp, " %s:\"%s\""
+ , l_parnam_tab.parname[6] , stb_elem->att_movepath_file_xml
+ );
+ }
fprintf(fp, "\n");
}
}
@@ -6119,6 +6184,7 @@ p_story_get_filename_from_elem (GapStoryElem *stb_elem, gint32 in_framenr)
/* --------------------------------
* gap_story_get_filename_from_elem
* gap_story_get_filename_from_elem_nr
+ * gap_story_get_filename_from_elem_nr_anim
* --------------------------------
*/
char *
@@ -6133,6 +6199,39 @@ gap_story_get_filename_from_elem_nr (GapStoryElem *stb_elem, gint32 in_framenr)
return(p_story_get_filename_from_elem(stb_elem, in_framenr));
} /* end gap_story_get_filename_from_elem_nr */
+char *
+gap_story_get_filename_from_elem_nr_anim (GapStoryElem *stb_elem, gint32 in_framenr)
+{
+ char *filename;
+
+ filename = NULL;
+ if(stb_elem)
+ {
+ switch(stb_elem->record_type)
+ {
+ case GAP_STBREC_VID_MOVIE:
+ case GAP_STBREC_VID_ANIMIMAGE:
+ case GAP_STBREC_VID_IMAGE:
+ filename = g_strdup(stb_elem->orig_filename);
+ break;
+ case GAP_STBREC_VID_FRAMES:
+ if(in_framenr < 0)
+ {
+ in_framenr = stb_elem->from_frame;
+ }
+ filename = gap_lib_alloc_fname(stb_elem->basename
+ , in_framenr
+ , stb_elem->ext
+ );
+
+ break;
+ default:
+ break;
+ }
+ }
+ return(filename);
+} /* end gap_story_get_filename_from_elem_nr_anim */
+
/* ---------------------------------
@@ -6876,6 +6975,7 @@ gap_story_elem_duplicate(GapStoryElem *stb_elem)
if(stb_elem->filtermacro_file) stb_elem_dup->filtermacro_file = g_strdup(stb_elem->filtermacro_file);
if(stb_elem->colormask_file) stb_elem_dup->colormask_file = g_strdup(stb_elem->colormask_file);
if(stb_elem->preferred_decoder) stb_elem_dup->preferred_decoder = g_strdup(stb_elem->preferred_decoder);
+ if(stb_elem->att_movepath_file_xml) stb_elem_dup->att_movepath_file_xml = g_strdup(stb_elem->att_movepath_file_xml);
stb_elem_dup->seltrack = stb_elem->seltrack;
stb_elem_dup->exact_seek = stb_elem->exact_seek;
stb_elem_dup->delace = stb_elem->delace;
@@ -7031,6 +7131,8 @@ gap_story_elem_copy(GapStoryElem *stb_elem_dst, GapStoryElem *stb_elem)
stb_elem_dst->att_arr_value_accel[ii] = stb_elem->att_arr_value_accel[ii];
}
}
+ stb_elem_dst->att_movepath_file_xml = NULL;
+ if(stb_elem->att_movepath_file_xml) stb_elem_dst->att_movepath_file_xml = g_strdup(stb_elem->att_movepath_file_xml);
stb_elem_dst->flip_request = stb_elem->flip_request;
stb_elem_dst->att_overlap = stb_elem->att_overlap;
@@ -8922,10 +9024,11 @@ gdouble
gap_story_get_default_attribute(gint att_typ_idx)
{
if ((att_typ_idx == GAP_STB_ATT_TYPE_OPACITY)
+ || (att_typ_idx == GAP_STB_ATT_TYPE_MOVEPATH)
|| (att_typ_idx == GAP_STB_ATT_TYPE_ZOOM_X)
|| (att_typ_idx == GAP_STB_ATT_TYPE_ZOOM_Y))
{
- return (1.0); /* 1.0 indicates fully opaque, or no scaling */
+ return (1.0); /* 1.0 indicates fully opaque, or no scaling or frame 1 for movepath */
}
return (0.0); /* indicates centerd positioning or rotate 0 degree */
} /* end gap_story_get_default_attribute */
diff --git a/gap/gap_story_file.h b/gap/gap_story_file.h
index d3e4ae2..467f1eb 100644
--- a/gap/gap_story_file.h
+++ b/gap/gap_story_file.h
@@ -39,13 +39,14 @@
/* transition attribute types
* (values are used as index for look-up tables)
*/
-#define GAP_STB_ATT_TYPES_ARRAY_MAX 6
+#define GAP_STB_ATT_TYPES_ARRAY_MAX 7
#define GAP_STB_ATT_TYPE_OPACITY 0
#define GAP_STB_ATT_TYPE_MOVE_X 1
#define GAP_STB_ATT_TYPE_MOVE_Y 2
#define GAP_STB_ATT_TYPE_ZOOM_X 3
#define GAP_STB_ATT_TYPE_ZOOM_Y 4
#define GAP_STB_ATT_TYPE_ROTATE 5
+#define GAP_STB_ATT_TYPE_MOVEPATH 6
#define GAP_STB_MASK_SECTION_NAME "Masks"
@@ -186,6 +187,7 @@
gint32 att_arr_value_dur[GAP_STB_ATT_TYPES_ARRAY_MAX]; /* number of frames to change from -> to value */
gint32 att_arr_value_accel[GAP_STB_ATT_TYPES_ARRAY_MAX]; /* acceleration characteristics */
gint32 att_overlap; /* number of overlapping frames (value > 0 will generate a shadow track) */
+ gchar *att_movepath_file_xml;
/* new members for Audio Record types */
char *aud_filename;
@@ -388,6 +390,7 @@ gint32 gap_story_get_framenr_by_story_id(GapStorySection *section,
gint32 gap_story_get_expanded_framenr_by_story_id(GapStorySection *section, gint32 story_id, gint32 in_track);
char * gap_story_get_filename_from_elem(GapStoryElem *stb_elem);
char * gap_story_get_filename_from_elem_nr(GapStoryElem *stb_elem, gint32 in_framenr);
+char * gap_story_get_filename_from_elem_nr_anim(GapStoryElem *stb_elem, gint32 in_framenr);
GapStoryElem * gap_story_fetch_nth_active_elem(GapStoryBoard *stb
, gint32 seq_nr
, gint32 in_track
diff --git a/gap/gap_story_main.h b/gap/gap_story_main.h
index 8f8c95f..48a908a 100644
--- a/gap/gap_story_main.h
+++ b/gap/gap_story_main.h
@@ -322,6 +322,9 @@ typedef struct GapStbAttrWidget /* nickname: attw */
GtkWidget *button_overlap_dur;
GtkWidget *comment_entry;
+ GtkWidget *movepath_file_entry;
+ GtkWidget *movepath_filesel;
+ gboolean movepath_file_xml_is_valid;
struct GapStbAttrWidget *next;
} GapStbAttrWidget;
diff --git a/gap/gap_story_properties.c b/gap/gap_story_properties.c
index 0a2a5ae..1b811ed 100644
--- a/gap/gap_story_properties.c
+++ b/gap/gap_story_properties.c
@@ -1694,13 +1694,15 @@ p_pw_check_ainfo_range(GapStbPropWidget *pw, char *filename)
,pw->stb_refptr
,pw->stb_elem_refptr
);
+ if(pw->stb_elem_refptr->record_type == GAP_STBREC_VID_ANIMIMAGE)
+ {
+ l_lower = 0;
+ }
if(velem)
{
- l_upper = velem->total_frames;
- if(pw->stb_elem_refptr->record_type == GAP_STBREC_VID_ANIMIMAGE)
+ if(pw->stb_elem_refptr->record_type == GAP_STBREC_VID_SECTION)
{
- l_lower = 0;
- l_upper--;
+ l_upper = velem->total_frames;
}
}
}
@@ -2816,7 +2818,8 @@ p_pw_update_framenr_labels(GapStbPropWidget *pw, gint32 framenr)
{
char txt_buf[100];
gdouble l_speed_fps;
-
+ gint32 l_framenr_zero;
+
if(pw == NULL) { return; }
if(pw->stb_elem_refptr == NULL) { return; }
@@ -2827,6 +2830,15 @@ p_pw_update_framenr_labels(GapStbPropWidget *pw, gint32 framenr)
gtk_label_set_text ( GTK_LABEL(pw->pw_framenr_label), txt_buf);
l_speed_fps = GAP_STORY_DEFAULT_FRAMERATE;
+ l_framenr_zero = framenr -1;
+ if(pw->stb_elem_refptr->record_type == GAP_STBREC_VID_ANIMIMAGE)
+ {
+ /* animimage framenr (e.g. layerstack position) starts at 0
+ * (other clips typically start with framenr 1)
+ */
+ l_framenr_zero = framenr;
+ }
+
if(pw->stb_refptr)
{
if(pw->stb_refptr->master_framerate > 0)
@@ -2838,7 +2850,9 @@ p_pw_update_framenr_labels(GapStbPropWidget *pw, gint32 framenr)
// TODO: can not show the exact frametime for
// clips that do not start at frame 1
- gap_timeconv_framenr_to_timestr(framenr -1
+
+
+ gap_timeconv_framenr_to_timestr(l_framenr_zero
, l_speed_fps
, txt_buf
, sizeof(txt_buf)
diff --git a/gap/gap_story_render_lossless.c b/gap/gap_story_render_lossless.c
index 9913f2d..d951884 100644
--- a/gap/gap_story_render_lossless.c
+++ b/gap/gap_story_render_lossless.c
@@ -339,31 +339,15 @@ p_check_chunk_fetch_possible(GapStoryRenderVidHandle *vidhand
, GapStoryRenderFrameRangeElem **frn_elem /* OUT: pointer to relevant frame range element */
)
{
+ GapStbFetchData gapStbFetchData;
+ GapStbFetchData *gfd;
gint32 l_track;
gchar *l_framename;
gchar *l_videofile;
- gdouble l_rotate;
- gdouble l_opacity;
- gdouble l_scale_x;
- gdouble l_scale_y;
- gdouble l_move_x;
- gdouble l_move_y;
- GapStoryRenderFrameRangeElem *l_frn_elem_2;
- gint32 l_localframe_index;
- gint32 l_local_stepcount;
- gdouble l_localframe_tween_rest;
- gboolean l_keep_proportions;
- gboolean l_fit_width;
- gboolean l_fit_height;
- GapStoryRenderFrameType l_frn_type;
- char *l_trak_filtermacro_file;
- gdouble l_red_f;
- gdouble l_green_f;
- gdouble l_blue_f;
- gdouble l_alpha_f;
gint l_cnt_active_tracks;
+ gfd = &gapStbFetchData;
*video_frame_nr = -1;
*frn_elem = NULL;
@@ -380,68 +364,51 @@ p_check_chunk_fetch_possible(GapStoryRenderVidHandle *vidhand
l_framename = p_fetch_framename(vidhand->frn_list
, master_frame_nr /* starts at 1 */
, l_track
- , &l_frn_type
- , &l_trak_filtermacro_file
- , &l_localframe_index /* used for ANIMIMAGE and Videoframe Number, -1 for all other types */
- , &l_local_stepcount
- , &l_localframe_tween_rest
- , &l_keep_proportions
- , &l_fit_width
- , &l_fit_height
- , &l_red_f
- , &l_green_f
- , &l_blue_f
- , &l_alpha_f
- , &l_rotate
- , &l_opacity /* output opacity 0.0 upto 1.0 */
- , &l_scale_x /* output 0.0 upto 10.0 where 1.0 is 1:1 */
- , &l_scale_y /* output 0.0 upto 10.0 where 1.0 is 1:1 */
- , &l_move_x /* output -1.0 upto 1.0 where 0.0 is centered */
- , &l_move_y /* output -1.0 upto 1.0 where 0.0 is centered */
- , &l_frn_elem_2 /* output selected to the relevant framerange element */
+ , gfd
);
if(gap_debug)
{
- printf("l_track:%d l_frn_type:%d\n", (int)l_track, (int)l_frn_type);
+ printf("l_track:%d gfd->frn_type:%d\n", (int)l_track, (int)gfd->frn_type);
}
- if(l_frn_type != GAP_FRN_SILENCE)
+ if(gfd->frn_type != GAP_FRN_SILENCE)
{
l_cnt_active_tracks++;
}
- if((l_framename) || (l_frn_type == GAP_FRN_COLOR))
+ if((l_framename) || (gfd->frn_type == GAP_FRN_COLOR))
{
if(l_framename)
{
- if((l_frn_type == GAP_FRN_MOVIE)
- || (l_frn_type == GAP_FRN_IMAGE)
- || (l_frn_type == GAP_FRN_FRAMES))
+ if((gfd->frn_type == GAP_FRN_MOVIE)
+ || (gfd->frn_type == GAP_FRN_IMAGE)
+ || (gfd->frn_type == GAP_FRN_FRAMES))
{
if(l_cnt_active_tracks == 1)
{
/* check for transformations */
- if((l_opacity == 1.0)
- && (l_rotate == 0.0)
- && (l_scale_x == 1.0)
- && (l_scale_y == 1.0)
- && (l_move_x == 0.0)
- && (l_move_y == 0.0)
- && (l_fit_width)
- && (l_fit_height)
- && (!l_keep_proportions)
- && (l_frn_elem_2->flip_request == GAP_STB_FLIP_NONE)
- && (l_frn_elem_2->mask_name == NULL)
- && (l_trak_filtermacro_file == NULL))
+ if((gfd->opacity == 1.0)
+ && (gfd->rotate == 0.0)
+ && (gfd->scale_x == 1.0)
+ && (gfd->scale_y == 1.0)
+ && (gfd->move_x == 0.0)
+ && (gfd->move_y == 0.0)
+ && (gfd->fit_width)
+ && (gfd->fit_height)
+ && (!gfd->keep_proportions)
+ && (gfd->frn_elem->flip_request == GAP_STB_FLIP_NONE)
+ && (gfd->frn_elem->mask_name == NULL)
+ && (gfd->trak_filtermacro_file == NULL)
+ && (gfd->movepath_file_xml == NULL))
{
if(gap_debug)
{
printf("gap_story_render_fetch_composite_image_or_chunk: video:%s\n", l_framename);
}
l_videofile = g_strdup(l_framename);
- *video_frame_nr = l_localframe_index;
- *frn_elem = l_frn_elem_2;
+ *video_frame_nr = gfd->localframe_index;
+ *frn_elem = gfd->frn_elem;
}
else
{
diff --git a/gap/gap_story_render_processor.c b/gap/gap_story_render_processor.c
index 1f5d088..f7a98d8 100644
--- a/gap/gap_story_render_processor.c
+++ b/gap/gap_story_render_processor.c
@@ -79,6 +79,7 @@
#include "gap_fmac_name.h"
#include "gap_frame_fetcher.h"
#include "gap_accel_char.h"
+#include "gap_mov_exec.h"
/* data for the storyboard proceesor frame fetching
@@ -104,7 +105,15 @@ typedef struct GapStbFetchData { /* nick: gfd */
gboolean fit_width;
gboolean fit_height;
GapStoryRenderFrameType frn_type;
- char *trak_filtermacro_file;
+ const char *trak_filtermacro_file; /* dont g_free this ! */
+
+ gdouble red_f;
+ gdouble green_f;
+ gdouble blue_f;
+ gdouble alpha_f;
+ const char *movepath_file_xml; /* dont g_free this ! */
+ gdouble movepath_framePhase;
+
/* performance stuff for bypass render engine (where possible) */
GapStoryFetchResult *gapStoryFetchResult;
@@ -219,29 +228,11 @@ static gdouble p_attribute__at_step(gint32 frame_step /* current frame (since s
static void p_select_section_by_name(GapStoryRenderVidHandle *vidhand
, const char *section_name);
-static char * p_fetch_framename (GapStoryRenderFrameRangeElem *frn_list
+static char* p_fetch_framename (GapStoryRenderFrameRangeElem *frn_list
, gint32 master_frame_nr /* starts at 1 */
, gint32 track
- , GapStoryRenderFrameType *frn_type
- , char **filtermacro_file
- , gint32 *localframe_index /* used only for ANIMIMAGE and videoclip, -1 for all other types */
- , gint32 *local_stepcount /* nth frame within this clip, starts with 0 */
- , gdouble *localframe_tween_rest /* non-integer part of the position. value < 1.0 for tween fetching */
- , gboolean *keep_proportions
- , gboolean *fit_width
- , gboolean *fit_height
- , gdouble *red_f
- , gdouble *green_f
- , gdouble *blue_f
- , gdouble *alpha_f
- , gdouble *rotate /* output rotate in degree */
- , gdouble *opacity /* output opacity 0.0 upto 1.0 */
- , gdouble *scale_x /* output 0.0 upto 10.0 where 1.0 is 1:1 */
- , gdouble *scale_y /* output 0.0 upto 10.0 where 1.0 is 1:1 */
- , gdouble *move_x /* output -1.0 upto 1.0 where 0.0 is centered */
- , gdouble *move_y /* output -1.0 upto 1.0 where 0.0 is centered */
- , GapStoryRenderFrameRangeElem **frn_elem_ptr /* OUT pointer to the relevant framerange element */
- );
+ , GapStbFetchData *gfd /* out: result structure of the fetch */
+ );
static void p_calculate_frames_to_handle(GapStoryRenderFrameRangeElem *frn_elem);
static GapStoryRenderFrameRangeElem * p_new_framerange_element(
@@ -381,10 +372,36 @@ static gint32 p_exec_filtermacro(gint32 image_id
, gint32 total_steps
, gint accelerationCharacteristic
);
-static gboolean p_transform_operate_on_full_layer(GapStoryCalcAttr *calculated
+static gboolean p_transform_operate_on_full_layer(GapStoryCalcAttr *calculated
, gint32 comp_image_id, gint32 tmp_image_id
, GapStoryRenderFrameRangeElem *frn_elem
);
+static void p_transform_rotate_layer_at(gint32 image_id, gint32 layer_id, gdouble rotate
+ , gint image_offset_x, gint image_offset_y);
+static gint32 p_transform_with_movepath_processing( gint32 comp_image_id
+ , gint32 tmp_image_id
+ , gint32 layer_id
+ , gboolean keep_proportions
+ , gboolean fit_width
+ , gboolean fit_height
+ , gdouble rotate /* rotation in degree */
+ , gdouble opacity /* 0.0 upto 1.0 */
+ , gdouble scale_x /* 0.0 upto 10.0 where 1.0 = 1:1 */
+ , gdouble scale_y /* 0.0 upto 10.0 where 1.0 = 1:1 */
+ , gdouble move_x /* -1.0 upto +1.0 where 0 = no move, -1 is left outside */
+ , gdouble move_y /* -1.0 upto +1.0 where 0 = no move, -1 is top outside */
+ , GapStoryRenderFrameRangeElem *frn_elem
+ , GapStoryRenderVidHandle *vidhand
+ , gint32 local_stepcount
+ , const char *movepath_file_xml
+ , gdouble movepath_framePhase
+ );
+static void p_transform_postprocessing(gint32 new_layer_id
+ , GapStoryRenderFrameRangeElem *frn_elem
+ , GapStoryRenderVidHandle *vidhand
+ , gdouble opacity
+ , gint32 local_stepcount
+ );
static gint32 p_transform_and_add_layer( gint32 comp_image_id
, gint32 tmp_image_id
, gint32 layer_id
@@ -397,11 +414,13 @@ static gint32 p_transform_and_add_layer( gint32 comp_image_id
, gdouble scale_y /* 0.0 upto 10.0 where 1.0 = 1:1 */
, gdouble move_x /* -1.0 upto +1.0 where 0 = no move, -1 is left outside */
, gdouble move_y /* -1.0 upto +1.0 where 0 = no move, -1 is top outside */
- , char *filtermacro_file
+ , const char *filtermacro_file
, gint32 flip_request
, GapStoryRenderFrameRangeElem *frn_elem
, GapStoryRenderVidHandle *vidhand
, gint32 local_stepcount
+ , const char *movepath_file_xml
+ , gdouble movepath_framePhase
);
static gint32 p_create_unicolor_image(gint32 *layer_id, gint32 width , gint32 height
, gdouble r_f, gdouble g_f, gdouble b_f, gdouble a_f);
@@ -753,6 +772,12 @@ gap_story_render_debug_print_frame_elem(GapStoryRenderFrameRangeElem *frn_elem,
printf(" [%d] move_y_dur : %d\n", (int)l_idx, (int)frn_elem->move_y_dur );
printf(" [%d] move_y_accel : %d\n", (int)l_idx, (int)frn_elem->move_y_accel );
printf(" [%d] move_y_frames_done : %d\n", (int)l_idx, (int)frn_elem->move_y_frames_done );
+
+ printf(" [%d] movepath_from : %f\n", (int)l_idx, (float)frn_elem->movepath_from );
+ printf(" [%d] movepath_to : %f\n", (int)l_idx, (float)frn_elem->movepath_to );
+ printf(" [%d] movepath_dur : %d\n", (int)l_idx, (int)frn_elem->movepath_dur );
+ printf(" [%d] movepath_frames_done : %d\n", (int)l_idx, (int)frn_elem->movepath_frames_done );
+
}
} /* end gap_story_render_debug_print_frame_elem */
@@ -1301,44 +1326,32 @@ p_select_section_by_name(GapStoryRenderVidHandle *vidhand, const char *section_n
} /* end p_select_section_by_name */
+
/* ----------------------------------------------------
* p_fetch_framename
* ----------------------------------------------------
- * fetch framename for a given master_frame_nr in the given video track
+ * fetch frame access (framename or videofilename framenumber)
+ * and transition values relevant for a given master_frame_nr in the given video track
* within a storyboard framerange list.
* (simple animations without a storyboard file
* are represented by a short storyboard framerange list that has
* just one element entry at track 1).
*
- * output gduoble attribute values (opacity, scale, move) for the frame
+ * output is written to the specified GapStbFetchData structure
+ * that contains gdouble attribute values (opacity, scale, move) for the frame
* at track and master_frame_nr position.
*
- * return the name of the frame (that is to be displayed at position master_frame_nr).
- * return NULL if there is no frame at desired track and master_frame_nr
+ * Note gfd->framename can refere to the relevant frame image that is one of a series of frames
+ * (imagefiles) on disc. But it may also refere to a videofilename or to a multilayer image.
+ * (in this cases localframe_index referes to the relevant framenumber in the videofile
+ * or to the layerstack position in the multilayer image)
+ * gfd->framename is set to NULL if there is no frame at desired track and master_frame_nr
*/
static char *
p_fetch_framename(GapStoryRenderFrameRangeElem *frn_list
, gint32 master_frame_nr /* starts at 1 */
, gint32 track
- , GapStoryRenderFrameType *frn_type
- , char **filtermacro_file
- , gint32 *localframe_index /* starts at 1, used for ANIMIMAGE and VIDEOFILES, -1 for all other types */
- , gint32 *local_stepcount /* nth frame within this clip, starts with 0 */
- , gdouble *localframe_tween_rest /* non-integer part of the position. value < 1.0 for tween fetching */
- , gboolean *keep_proportions
- , gboolean *fit_width
- , gboolean *fit_height
- , gdouble *red_f
- , gdouble *green_f
- , gdouble *blue_f
- , gdouble *alpha_f
- , gdouble *rotate /* output rotate in degree */
- , gdouble *opacity /* output opacity 0.0 upto 1.0 */
- , gdouble *scale_x /* output 0.0 upto 10.0 where 1.0 is 1:1 */
- , gdouble *scale_y /* output 0.0 upto 10.0 where 1.0 is 1:1 */
- , gdouble *move_x /* output -1.0 upto 1.0 where 0.0 is centered */
- , gdouble *move_y /* output -1.0 upto 1.0 where 0.0 is centered */
- , GapStoryRenderFrameRangeElem **frn_elem_ptr /* OUT pointer to the relevant framerange element */
+ , GapStbFetchData *gfd /* out: result structure of the fetch */
)
{
GapStoryRenderFrameRangeElem *frn_elem;
@@ -1353,25 +1366,27 @@ p_fetch_framename(GapStoryRenderFrameRangeElem *frn_list
l_framename = NULL;
/* default attributes (used if storyboard does not define settings) */
- *rotate = 0.0;
- *opacity = 1.0;
- *scale_x = 1.0;
- *scale_y = 1.0;
- *move_x = 0.0;
- *move_y = 0.0;
- *localframe_index = -1;
- *local_stepcount = 0;
- *localframe_tween_rest = 0.0;
- *frn_type = GAP_FRN_SILENCE;
- *keep_proportions = FALSE;
- *fit_width = TRUE;
- *fit_height = TRUE;
- *red_f = 0.0;
- *green_f = 0.0;
- *blue_f = 0.0;
- *alpha_f = 1.0;
- *filtermacro_file = NULL;
- *frn_elem_ptr = NULL;
+ gfd->rotate = 0.0;
+ gfd->opacity = 1.0;
+ gfd->scale_x = 1.0;
+ gfd->scale_y = 1.0;
+ gfd->move_x = 0.0;
+ gfd->move_y = 0.0;
+ gfd->localframe_index = -1;
+ gfd->local_stepcount = 0;
+ gfd->localframe_tween_rest = 0.0;
+ gfd->frn_type = GAP_FRN_SILENCE;
+ gfd->keep_proportions = FALSE;
+ gfd->fit_width = TRUE;
+ gfd->fit_height = TRUE;
+ gfd->red_f = 0.0;
+ gfd->green_f = 0.0;
+ gfd->blue_f = 0.0;
+ gfd->alpha_f = 1.0;
+ gfd->trak_filtermacro_file = NULL;
+ gfd->frn_elem = NULL;
+ gfd->movepath_file_xml = NULL;
+ gfd->movepath_framePhase = 0;
l_found_at_idx=0;
for (frn_elem = frn_list; frn_elem != NULL; frn_elem = (GapStoryRenderFrameRangeElem *)frn_elem->next)
@@ -1399,20 +1414,20 @@ p_fetch_framename(GapStoryRenderFrameRangeElem *frn_list
fnrInt = fnr; /* truncate to integer */
- *localframe_tween_rest = fnr - fnrInt;
+ gfd->localframe_tween_rest = fnr - fnrInt;
if(gap_debug)
{
printf("fnr:%.4f, fnrInt:%d localframe_tween_rest:%.4f\n"
,(float)fnr
,(int)fnrInt
- ,(float)*localframe_tween_rest
+ ,(float)gfd->localframe_tween_rest
);
}
}
- *local_stepcount = master_frame_nr - l_frame_group_count;
- *local_stepcount -= 1;
+ gfd->local_stepcount = master_frame_nr - l_frame_group_count;
+ gfd->local_stepcount -= 1;
switch(frn_elem->frn_type)
{
@@ -1425,12 +1440,12 @@ p_fetch_framename(GapStoryRenderFrameRangeElem *frn_list
break;
case GAP_FRN_ANIMIMAGE:
l_framename = g_strdup(frn_elem->basename); /* use 1:1 basename for ainimated single images */
- *localframe_index = l_fnr; /* local frame number is index in the layerstack */
+ gfd->localframe_index = l_fnr; /* local frame number is index in the layerstack */
break;
case GAP_FRN_MOVIE:
/* video file frame numners start at 1 */
l_framename = g_strdup(frn_elem->basename); /* use 1:1 basename for videofiles */
- *localframe_index = l_fnr; /* local frame number is the wanted video frame number */
+ gfd->localframe_index = l_fnr; /* local frame number is the wanted video frame number */
break;
case GAP_FRN_FRAMES:
l_framename = gap_lib_alloc_fname(frn_elem->basename
@@ -1441,25 +1456,25 @@ p_fetch_framename(GapStoryRenderFrameRangeElem *frn_list
case GAP_FRN_SECTION:
/* frame numners in storyboard sections start at 1 */
l_framename = g_strdup(frn_elem->basename); /* section_name 1:1 for STB sections */
- *localframe_index = l_fnr; /* local frame number is the wanted video frame number */
+ gfd->localframe_index = l_fnr; /* local frame number is the wanted video frame number */
break;
}
/* return values for current fixed attribute settings
*/
- *frn_type = frn_elem->frn_type;
- *keep_proportions = frn_elem->keep_proportions;
- *fit_width = frn_elem->fit_width;
- *fit_height = frn_elem->fit_height;
- *red_f = frn_elem->red_f;
- *green_f = frn_elem->green_f;
- *blue_f = frn_elem->blue_f;
- *alpha_f = frn_elem->alpha_f;
- *filtermacro_file = frn_elem->filtermacro_file;
+ gfd->frn_type = frn_elem->frn_type;
+ gfd->keep_proportions = frn_elem->keep_proportions;
+ gfd->fit_width = frn_elem->fit_width;
+ gfd->fit_height = frn_elem->fit_height;
+ gfd->red_f = frn_elem->red_f;
+ gfd->green_f = frn_elem->green_f;
+ gfd->blue_f = frn_elem->blue_f;
+ gfd->alpha_f = frn_elem->alpha_f;
+ gfd->trak_filtermacro_file = frn_elem->filtermacro_file;
frn_elem->last_master_frame_access = master_frame_nr;
- *frn_elem_ptr = frn_elem; /* deliver pointer to the current frn_elem */
+ gfd->frn_elem = frn_elem; /* deliver pointer to the current frn_elem */
/* calculate effect attributes for the current step
@@ -1468,48 +1483,89 @@ p_fetch_framename(GapStoryRenderFrameRangeElem *frn_list
l_step = (master_frame_nr - 1) - l_frame_group_count;
- *rotate = p_attribute_query_at_step(l_step
+ gfd->rotate = p_attribute_query_at_step(l_step
, frn_elem->rotate_from
, frn_elem->rotate_to
, frn_elem->rotate_dur
, frn_elem->rotate_frames_done
, frn_elem->rotate_accel
);
- *opacity = p_attribute_query_at_step(l_step
+ gfd->opacity = p_attribute_query_at_step(l_step
, frn_elem->opacity_from
, frn_elem->opacity_to
, frn_elem->opacity_dur
, frn_elem->opacity_frames_done
, frn_elem->opacity_accel
);
- *scale_x = p_attribute_query_at_step(l_step
+ gfd->scale_x = p_attribute_query_at_step(l_step
, frn_elem->scale_x_from
, frn_elem->scale_x_to
, frn_elem->scale_x_dur
, frn_elem->scale_x_frames_done
, frn_elem->scale_x_accel
);
- *scale_y = p_attribute_query_at_step(l_step
+ gfd->scale_y = p_attribute_query_at_step(l_step
, frn_elem->scale_y_from
, frn_elem->scale_y_to
, frn_elem->scale_y_dur
, frn_elem->scale_y_frames_done
, frn_elem->scale_y_accel
);
- *move_x = p_attribute_query_at_step(l_step
+ gfd->move_x = p_attribute_query_at_step(l_step
, frn_elem->move_x_from
, frn_elem->move_x_to
, frn_elem->move_x_dur
, frn_elem->move_x_frames_done
, frn_elem->move_x_accel
);
- *move_y = p_attribute_query_at_step(l_step
+ gfd->move_y = p_attribute_query_at_step(l_step
, frn_elem->move_y_from
, frn_elem->move_y_to
, frn_elem->move_y_dur
, frn_elem->move_y_frames_done
, frn_elem->move_y_accel
);
+
+ /* movepath transition handling */
+ if(frn_elem->movepath_file_xml != NULL)
+ {
+ gint32 l_steps_since_transition_start;
+ gdouble phase;
+
+ l_steps_since_transition_start = frn_elem->movepath_frames_done + l_step;
+ phase = 1.0;
+
+
+ if (l_steps_since_transition_start < frn_elem->movepath_dur)
+ {
+ gint32 duration;
+ gint accel;
+
+ accel = 0;
+ duration = abs(frn_elem->movepath_to - frn_elem->movepath_from);
+ gfd->movepath_file_xml = frn_elem->movepath_file_xml;
+ phase = p_attribute_query_at_step(l_step
+ , frn_elem->movepath_from
+ , frn_elem->movepath_to
+ , duration
+ , frn_elem->movepath_frames_done
+ , accel
+ );
+ gfd->movepath_framePhase = rint(phase);
+ }
+ if(gap_debug)
+ {
+ printf("FETCH: l_steps_since_transition_start:%d movepath_dur:%d movepath_framePhase:%d (phase:%.4f)\n"
+ , (int)l_steps_since_transition_start
+ , (int)frn_elem->movepath_dur
+ , (int)gfd->movepath_framePhase
+ , (float)phase
+ );
+ }
+
+ }
+
+
break;
}
l_frame_group_count += l_frames_to_handle;
@@ -1519,24 +1575,32 @@ p_fetch_framename(GapStoryRenderFrameRangeElem *frn_list
if(gap_debug)
{
- printf("p_fetch_framename: track:%d master_frame_nr:%d framename:%s: found_at_idx:%d rotate:%f opa:%f scale:%f %f move:%f %f layerstack_idx:%d\n"
+ printf("p_fetch_framename: track:%d master_frame_nr:%d framename:%s: found_at_idx:%d rotate:%f opa:%f scale:%f %f move:%f %f layerstack_idx:%d"
, (int)track
, (int)master_frame_nr
, l_framename
, (int)l_found_at_idx
- , (float)*rotate
- , (float)*opacity
- , (float)*scale_x
- , (float)*scale_y
- , (float)*move_x
- , (float)*move_y
- , (int)*localframe_index
+ , (float)gfd->rotate
+ , (float)gfd->opacity
+ , (float)gfd->scale_x
+ , (float)gfd->scale_y
+ , (float)gfd->move_x
+ , (float)gfd->move_y
+ , (int)gfd->localframe_index
);
+ if(gfd->movepath_file_xml != NULL)
+ {
+ printf(" movepath_framePhase:%f XML:%s"
+ ,(float)gfd->movepath_framePhase
+ ,gfd->movepath_file_xml
+ );
+ }
+ printf("\n");
}
- return l_framename;
-} /* end p_fetch_framename */
+ return (l_framename);
+} /* end p_fetch_framename */
/* ---------------------------------
@@ -1698,7 +1762,17 @@ p_new_framerange_element(GapStoryRenderFrameType frn_type
frn_elem->seltrack = seltrack;
frn_elem->exact_seek = exact_seek;
frn_elem->delace = delace;
+
+ frn_elem->movepath_from = 0.0;
+ frn_elem->movepath_to = 0.0;
+ frn_elem->movepath_frames_done = 0;
+ frn_elem->movepath_dur = 0;
+ frn_elem->movepath_file_xml = NULL;
+
+
frn_elem->next = NULL;
+
+
if(ext)
@@ -1850,6 +1924,7 @@ p_step_all_vtrack_attributes(gint32 track
vtarr->attr[track].scale_y_frames_done += frames_to_handle;
vtarr->attr[track].move_x_frames_done += frames_to_handle;
vtarr->attr[track].move_y_frames_done += frames_to_handle;
+ vtarr->attr[track].movepath_frames_done += frames_to_handle;
} /* end p_step_all_vtrack_attributes */
@@ -1930,6 +2005,18 @@ p_set_vtrack_attributes(GapStoryRenderFrameRangeElem *frn_elem
frn_elem->move_y_frames_done = vtarr->attr[track].move_y_frames_done;
+ frn_elem->movepath_from = vtarr->attr[track].movepath_from;
+ frn_elem->movepath_to = vtarr->attr[track].movepath_to;
+ frn_elem->movepath_dur = vtarr->attr[track].movepath_dur;
+ /// frn_elem->movepath_accel = vtarr->attr[track].movepath_accel; // (?)
+ frn_elem->movepath_frames_done = vtarr->attr[track].movepath_frames_done;
+ frn_elem->movepath_file_xml = NULL;
+ if ((vtarr->attr[track].movepath_file_xml != NULL)
+ && (vtarr->attr[track].movepath_frames_done <= vtarr->attr[track].movepath_dur))
+ {
+ frn_elem->movepath_file_xml = g_strdup(vtarr->attr[track].movepath_file_xml);
+ }
+
/* advance mask_framecount */
vtarr->attr[track].mask_framecount += frn_elem->frames_to_handle;
@@ -2181,6 +2268,12 @@ p_copy_vattr_values(gint32 src_track
vtarr->attr[dst_track].move_y_accel = vtarr->attr[src_track].move_y_accel;
vtarr->attr[dst_track].move_y_frames_done = vtarr->attr[src_track].move_y_frames_done;
+ vtarr->attr[dst_track].movepath_from = vtarr->attr[src_track].movepath_from;
+ vtarr->attr[dst_track].movepath_to = vtarr->attr[src_track].movepath_to;
+ vtarr->attr[dst_track].movepath_dur = vtarr->attr[src_track].movepath_dur;
+ vtarr->attr[dst_track].movepath_frames_done = vtarr->attr[src_track].movepath_frames_done;
+ vtarr->attr[dst_track].movepath_file_xml = vtarr->attr[src_track].movepath_file_xml;
+
} /* end p_copy_vattr_values */
@@ -2454,6 +2547,13 @@ p_clear_vattr_array(GapStoryRenderVTrackArray *vtarr)
vtarr->attr[l_idx].move_y_dur = 0;
vtarr->attr[l_idx].move_y_accel = 0;
vtarr->attr[l_idx].move_y_frames_done = 0;
+
+ vtarr->attr[l_idx].movepath_from = 0.0;
+ vtarr->attr[l_idx].movepath_to = 0.0;
+ vtarr->attr[l_idx].movepath_dur = 0;
+ vtarr->attr[l_idx].movepath_frames_done = 0;
+ vtarr->attr[l_idx].movepath_file_xml = NULL;
+
}
} /* end p_clear_vattr_array */
@@ -2790,6 +2890,33 @@ p_storyboard_analyze(GapStoryBoard *stb
vtarr->attr[l_track].scale_y_accel = stb_elem->att_arr_value_accel[ii];
vtarr->attr[l_track].scale_y_frames_done = 0;
break;
+ case GAP_STB_ATT_TYPE_MOVEPATH:
+ vtarr->attr[l_track].movepath_from = stb_elem->att_arr_value_from[ii];
+ vtarr->attr[l_track].movepath_to = stb_elem->att_arr_value_to[ii];
+ vtarr->attr[l_track].movepath_dur = stb_elem->att_arr_value_dur[ii];
+ vtarr->attr[l_track].movepath_frames_done = 0;
+ /* no need to strdup for the vattr table here.
+ * becaue we use the reference to the original data in this table
+ * (therefore dont g_free
+ * the g_strdup is done later when the movepath_file_xml is
+ * set in the individual GapStoryRenderFrameRangeElem frn_elem
+ * (see p_set_vtrack_attributes)
+ */
+ vtarr->attr[l_track].movepath_file_xml = NULL;
+ if(stb_elem->att_movepath_file_xml != NULL)
+ {
+ if(stb_elem->att_movepath_file_xml[0] != '\0')
+ {
+ gboolean is_valid;
+
+ is_valid = gap_mov_exec_check_valid_xml_paramfile(stb_elem->att_movepath_file_xml);
+ if (is_valid)
+ {
+ vtarr->attr[l_track].movepath_file_xml = stb_elem->att_movepath_file_xml;
+ }
+ }
+ }
+ break;
}
}
}
@@ -3311,6 +3438,7 @@ p_free_framerange_list(GapStoryRenderFrameRangeElem * frn_list)
if(frn_elem->basename) { g_free(frn_elem->basename);}
if(frn_elem->ext) { g_free(frn_elem->ext);}
if(frn_elem->filtermacro_file) { g_free(frn_elem->filtermacro_file);}
+ if(frn_elem->movepath_file_xml) { g_free(frn_elem->movepath_file_xml);}
#ifdef GAP_ENABLE_VIDEOAPI_SUPPORT
if(frn_elem->gvahand) { p_call_GVA_close(frn_elem->gvahand);}
@@ -4046,8 +4174,7 @@ p_open_video_handle_private( gboolean ignore_audio
&& (input_mode == GAP_RNGTYPE_LAYER)
&& (imagename))
{
- gint32 l_from; render_section->frn_list = frn_elem;
-
+ gint32 l_from;
gint32 l_to;
l_from = frame_from;
@@ -4697,6 +4824,429 @@ p_transform_operate_on_full_layer(GapStoryCalcAttr *calculated, gint32 comp_imag
} /* end p_transform_operate_on_full_layer */
+/* ----------------------------------------------------
+ * p_transform_rotate_layer_at
+ * ----------------------------------------------------
+ * rotate layer by the specified angle in degree
+ * the center of the rotation is specified in image coordinates
+ * via image_offset_x and image_offset_y.
+ */
+void
+p_transform_rotate_layer_at(gint32 image_id, gint32 layer_id, gdouble rotate
+ , gint image_offset_x, gint image_offset_y)
+{
+ gint32 l_mask_id;
+ gint32 l_center_x;
+ gint32 l_center_y;
+ gdouble l_angle_rad;
+ gdouble l_angle_deg;
+ gint l_layer_offset_x;
+ gint l_layer_offset_y;
+
+ l_angle_deg = rotate;
+ while(l_angle_deg >= 360.0)
+ {
+ l_angle_deg -=360;
+ }
+ while(l_angle_deg <= -360.0)
+ {
+ l_angle_deg +=360;
+ }
+
+ if ((l_angle_deg < 0.05) && (l_angle_deg > -0.05))
+ {
+ /* ignore very small rotations */
+ return;
+ }
+ l_angle_rad = (l_angle_deg * G_PI) / 180.0;
+
+ /* check for layermask */
+ l_mask_id = gimp_layer_get_mask(layer_id);
+ if(l_mask_id >= 0)
+ {
+ /* apply the layermask
+ * some transitions (especially rotate) can't operate proper on
+ * layers with masks !
+ * (tests with gimp_rotate resulted in trashed images,
+ * even if the mask was rotated too)
+ */
+ gimp_layer_remove_mask (layer_id, GIMP_MASK_APPLY);
+ }
+
+ /* remove selection (if there is one)
+ * if there is a selection transitions (gimp_rotate)
+ * will create new layer and do not operate on l_cp_layer_id
+ */
+ gimp_selection_none(image_id);
+
+ gimp_drawable_offsets(layer_id, &l_layer_offset_x, &l_layer_offset_y );
+
+ /* calculate rotation center in layer coordinates */
+ l_center_x = image_offset_x + l_layer_offset_x;
+ l_center_y = image_offset_y + l_layer_offset_y;
+
+ if(gap_debug)
+ {
+ printf("p_transform_rotate_layer_at: called at layer_id:%d l_angle_deg:%.4f\n"
+ " image_offset_x:%d image_offset_y:%d\n"
+ " l_layer_offset_x:%d l_layer_offset_y:%d l_center_x:%d l_center_y:%d"
+ , (int)layer_id
+ , (float)l_angle_deg
+ , (int)image_offset_x
+ , (int)image_offset_y
+ , (int)l_layer_offset_x
+ , (int)l_layer_offset_y
+ , (int)l_center_x
+ , (int)l_center_y
+ );
+ }
+
+
+ /* perform rotation of the layer (rotation also changes size as needed) */
+ gimp_drawable_transform_rotate_default(layer_id
+ , l_angle_rad
+ , FALSE /* auto_center */
+ , l_center_x
+ , l_center_y
+ , TRUE /* interpolation */
+ , FALSE /* clip_results */
+ );
+
+
+} /* end p_transform_rotate_layer_at */
+
+
+
+
+
+
+/* ----------------------------------------------------
+ * p_transform_with_movepath_processing
+ * ----------------------------------------------------
+ * - copy the layer (layer_id) from tmp_image to the composite image
+ * and apply movepath processing for complex transformations on the copied layer.
+ * - the source Layer (layer_id) must be part of tmp_image_id
+ * - additionally to the movepath transitions
+ * also set opacity, move, scale and rotate the result layer of movepath processing
+ * according to video attributes
+ * - optional apply transparency in case mask is attached (anchored to clip or master)
+ * In case mask is anchored to clip, it is applied BEFORE movepath transformations
+ *
+ * return the new created layer id in the comp_image_id
+ * (that is already added to the composte image on top of layerstack
+ * and is already transformed
+ * -- except postprocessing for mask anchor master and opacity )
+ */
+static gint32
+p_transform_with_movepath_processing( gint32 comp_image_id
+ , gint32 tmp_image_id
+ , gint32 layer_id
+ , gboolean keep_proportions
+ , gboolean fit_width
+ , gboolean fit_height
+ , gdouble rotate /* rotation in degree */
+ , gdouble opacity /* 0.0 upto 1.0 */
+ , gdouble scale_x /* 0.0 upto 10.0 where 1.0 = 1:1 */
+ , gdouble scale_y /* 0.0 upto 10.0 where 1.0 = 1:1 */
+ , gdouble move_x /* -1.0 upto +1.0 where 0 = no move, -1 is left outside */
+ , gdouble move_y /* -1.0 upto +1.0 where 0 = no move, -1 is top outside */
+ , GapStoryRenderFrameRangeElem *frn_elem
+ , GapStoryRenderVidHandle *vidhand
+ , gint32 local_stepcount
+ , const char *movepath_file_xml
+ , gdouble movepath_framePhase
+ )
+{
+ gint32 vid_width;
+ gint32 vid_height;
+ gint32 l_new_layer_id;
+ gint32 l_movepath_layer_id;
+ gint32 l_tmp_movpath_image_id;
+ gint32 l_empty_layer_id;
+
+ gint l_base_offset_x;
+ gint l_base_offset_y;
+ gint l_mov_dx;
+ gint l_mov_dy;
+ gint result_width;
+ gint result_height;
+
+ GapStoryCalcAttr calculate_attributes;
+ GapStoryCalcAttr *calculated;
+
+
+
+ if(gap_debug)
+ {
+ printf("\n--\np_transform_with_movepath_processing: called at layer_id: %d, tmp_image_id:%d comp_image_id:%d\n"
+ , (int)layer_id
+ , (int)tmp_image_id
+ , (int)comp_image_id
+ );
+ if(frn_elem != NULL)
+ {
+ gap_story_render_debug_print_frame_elem(frn_elem, -77);
+ }
+ }
+
+ l_tmp_movpath_image_id = -1;
+
+
+ vid_width = gimp_image_width(comp_image_id);
+ vid_height = gimp_image_height(comp_image_id);
+
+ if(frn_elem != NULL)
+ {
+ /* process mask before the movepath transitions
+ * (but only in case when not achored to master, e.g anchored to clip)
+ */
+ if((frn_elem->mask_name != NULL)
+ && (frn_elem->mask_anchor != GAP_MSK_ANCHOR_MASTER))
+ {
+ /* fetch and add mask at calculated scaled size of layer_id */
+ p_fetch_and_add_layermask(vidhand
+ , frn_elem
+ , local_stepcount
+ , tmp_image_id
+ , layer_id
+ , frn_elem->mask_anchor
+ );
+ /* apply the mask (necessary because some of the following transformations on this layer
+ * would ignore the layer mask)
+ */
+ gimp_layer_remove_mask(layer_id, GIMP_MASK_APPLY);
+ }
+ }
+
+
+ /* create a temporary image in composite video size with a transparent layer
+ * (this image acts as frame for the movepath processing,
+ * and the layer_id acts as the moving object -- to be transformed --)
+ */
+ l_tmp_movpath_image_id = gimp_image_new(vid_width, vid_height, GIMP_RGB);
+ gimp_image_undo_disable(l_tmp_movpath_image_id);
+
+
+ l_empty_layer_id = gimp_layer_new(l_tmp_movpath_image_id, "empty",
+ vid_width, vid_height,
+ GIMP_RGBA_IMAGE,
+ 100.0, /* Opacity */
+ GIMP_NORMAL_MODE);
+ gimp_image_add_layer(l_tmp_movpath_image_id, l_empty_layer_id, 0);
+ gap_layer_clear_to_color(l_empty_layer_id
+ , 0.0, 0.0, 0.0, 0.0 /* r,g,b,a (black full transparent) */
+ );
+
+ gap_mov_exec_move_path_singleframe_directcall(l_tmp_movpath_image_id
+ , layer_id
+ , keep_proportions
+ , fit_width
+ , fit_height
+ , movepath_framePhase
+ , movepath_file_xml
+ );
+
+ l_movepath_layer_id = gap_image_merge_visible_layers(l_tmp_movpath_image_id
+ , GIMP_EXPAND_AS_NECESSARY
+ );
+
+ /* at this point the complex movepath transformation is done
+ * and the result is available as layer l_movepath_layer_id
+ * note that fit size flags were already handled in the movepath transformation.
+ *
+ * further processing continues with the result of movepath processing
+ * (the image l_tmp_movpath_image_id)
+ * note that the resulting layer (l_movepath_layer_id) may be oversized,
+ * e.g may overlap image boudaries due to the movepath transformations
+ * (when the clip to image flag was not active in movepath processing)
+ */
+ if(gap_debug)
+ {
+ printf("p_transform_and_add_layer: MOVEPATH DONE at layer_id: %d (l_movepath_layer_id:%d), tmp_image_id:%d\n"
+ , (int)layer_id
+ , (int)l_movepath_layer_id
+ , (int)tmp_image_id
+ );
+ }
+
+ /* findout the offsets of the layer within the Image */
+ gimp_drawable_offsets(l_movepath_layer_id, &l_base_offset_x, &l_base_offset_y );
+
+ /* handle movement */
+ l_mov_dx = rint((gdouble)vid_width * move_x);
+ l_mov_dy = rint((gdouble)vid_height * move_y);
+ if((l_mov_dx != 0) || (l_mov_dy != 0))
+ {
+ gimp_layer_set_offsets(l_movepath_layer_id
+ , l_base_offset_x + l_mov_dx
+ , l_base_offset_y + l_mov_dy
+ );
+ }
+
+ /* handle rotation where the center of the rotation
+ * is center of the frame image + movment offset (l_mov_dx / l_mov_dy)
+ */
+ p_transform_rotate_layer_at(l_tmp_movpath_image_id
+ , l_movepath_layer_id
+ , rotate
+ , (vid_width / 2.0) + l_mov_dx
+ , (vid_height / 2.0) + l_mov_dy
+ );
+
+ /* handle scaling */
+ result_width = MAX(1, rint(((gdouble)vid_width * scale_x)));
+ result_height = MAX(1, rint(((gdouble)vid_height * scale_y)));
+
+ if((result_width != vid_width)
+ || (result_height != vid_height))
+ {
+ gint offs_x;
+ gint offs_y;
+
+ if(gap_debug)
+ {
+ printf("DEBUG: p_transform_with_movepath_processing scaling tmp image from %dx%d to %dx%d\n"
+ , (int)gimp_image_width(l_tmp_movpath_image_id)
+ , (int)gimp_image_height(l_tmp_movpath_image_id)
+ , (int)result_width
+ , (int)result_width
+ );
+
+ }
+
+
+ if((result_width >= vid_width)
+ && (result_height >= vid_height))
+ {
+ /* handle enlarge image in both dimensions scenario */
+ gimp_image_scale(l_tmp_movpath_image_id, result_width, result_height);
+ offs_x = rint((result_width - vid_width) / 2.0);
+ offs_y = rint((result_height - vid_height) / 2.0);
+ gimp_image_crop(l_tmp_movpath_image_id, vid_width, vid_height, offs_x, offs_y);
+ }
+ else if ((result_width <= vid_width)
+ && (result_height <= vid_height))
+ {
+ /* handle shrink image in both dimensions scenario */
+ gimp_image_scale(l_tmp_movpath_image_id, result_width, result_height);
+ offs_x = rint((vid_width - result_width) / 2.0);
+ offs_y = rint((vid_height - result_height) / 2.0);
+
+ /* resize image canvas back to coposite videoframe size */
+ gimp_image_resize(l_tmp_movpath_image_id, vid_width, vid_height, offs_x, offs_y);
+ }
+ else if ((result_width > vid_width)
+ && (result_height <= vid_height))
+ {
+ /* handle enlarge width but shrink height scenario */
+ /* 1. enlarge width, keep same image height */
+ gimp_image_scale(l_tmp_movpath_image_id, result_width, vid_height);
+ offs_x = rint((result_width - vid_width) / 2.0);
+ offs_y = 0;
+ gimp_image_crop(l_tmp_movpath_image_id, vid_width, vid_height, offs_x, offs_y);
+
+ /* 2. shrink height, keep same image width */
+ gimp_image_scale(l_tmp_movpath_image_id, vid_width, result_height);
+ offs_x = 0;
+ offs_y = rint((vid_height - result_height) / 2.0);
+
+ /* resize image canvas back to coposite videoframe size */
+ gimp_image_resize(l_tmp_movpath_image_id, vid_width, vid_height, offs_x, offs_y);
+
+ }
+ else if ((result_width < vid_width)
+ && (result_height >= vid_height))
+ {
+ /* handle enlarge height but shrink width scenario */
+ /* 1. enlarge height, keep same image width */
+ gimp_image_scale(l_tmp_movpath_image_id, vid_width, result_height);
+ offs_x = 0;
+ offs_y = rint((result_height - vid_height) / 2.0);
+ gimp_image_crop(l_tmp_movpath_image_id, vid_width, vid_height, offs_x, offs_y);
+
+ /* 2. shrink width, keep same image height */
+ gimp_image_scale(l_tmp_movpath_image_id, result_width, vid_height);
+ offs_x = rint((vid_width - result_width) / 2.0);
+ offs_y = 0;
+
+ /* resize image canvas back to coposite videoframe size */
+ gimp_image_resize(l_tmp_movpath_image_id, vid_width, vid_height, offs_x, offs_y);
+
+ }
+
+
+
+ }
+
+ /* trim resulting layer to imagesize after all transformations
+ * (move, rotate, and scale) are processed
+ * This includes both extesion to image size and crop parts outside boundaries.
+ */
+ gimp_layer_resize_to_image_size(l_movepath_layer_id);
+
+ /* make 1:1 copy of the l_movepath_layer_id (that has already same size as
+ * the composite image and is already transformed)
+ * and add to the composite image (at top)
+ */
+ l_new_layer_id = gimp_layer_new_from_drawable(l_movepath_layer_id, comp_image_id);
+ if(l_new_layer_id >= 0)
+ {
+ if(! gimp_drawable_has_alpha(l_new_layer_id))
+ {
+ /* have to add alpha channel */
+ gimp_layer_add_alpha(l_new_layer_id);
+ }
+ gimp_image_add_layer(comp_image_id, l_new_layer_id, 0);
+ gimp_layer_set_offsets(l_new_layer_id, 0, 0);
+ }
+
+//p_debug_dup_image(l_tmp_movpath_image_id);
+
+
+ if(l_tmp_movpath_image_id >= 0)
+ {
+ gap_image_delete_immediate(l_tmp_movpath_image_id);
+ }
+
+ return(l_new_layer_id);
+
+} /* end p_transform_with_movepath_processing */
+
+
+/* ----------------------------------
+ * p_transform_postprocessing
+ * ----------------------------------
+ * perform the final processing steps on the transformed
+ * layer. This includes applying mask (but only in case mask is anchored to master)
+ * and setting the opacity.
+ */
+static void
+p_transform_postprocessing(gint32 new_layer_id
+ , GapStoryRenderFrameRangeElem *frn_elem
+ , GapStoryRenderVidHandle *vidhand
+ , gdouble opacity
+ , gint32 local_stepcount
+ )
+{
+
+ if((frn_elem->mask_name != NULL)
+ && (frn_elem->mask_anchor == GAP_MSK_ANCHOR_MASTER))
+ {
+ p_fetch_and_add_layermask(vidhand
+ , frn_elem
+ , local_stepcount
+ , gimp_drawable_get_image(new_layer_id)
+ , new_layer_id
+ , frn_elem->mask_anchor
+ );
+
+ }
+
+ gimp_layer_set_opacity(new_layer_id, opacity);
+
+} /* end p_transform_postprocessing */
+
+
/* ----------------------------------------------------
* p_transform_and_add_layer
@@ -4723,11 +5273,13 @@ p_transform_and_add_layer( gint32 comp_image_id
, gdouble scale_y /* 0.0 upto 10.0 where 1.0 = 1:1 */
, gdouble move_x /* -1.0 upto +1.0 where 0 = no move, -1 is left outside */
, gdouble move_y /* -1.0 upto +1.0 where 0 = no move, -1 is top outside */
- , char *filtermacro_file
+ , const char *filtermacro_file
, gint32 flip_request
, GapStoryRenderFrameRangeElem *frn_elem
, GapStoryRenderVidHandle *vidhand
, gint32 local_stepcount
+ , const char *movepath_file_xml
+ , gdouble movepath_framePhase
)
{
gint32 vid_width;
@@ -4735,10 +5287,14 @@ p_transform_and_add_layer( gint32 comp_image_id
gint32 l_new_layer_id;
gint32 l_fsel_layer_id;
gint32 l_fmac_layer_id;
+ gint32 l_movepath_layer_id;
+ gint32 l_tmp_image_id;
+
GapStoryCalcAttr calculate_attributes;
GapStoryCalcAttr *calculated;
static gint32 funcId = -1;
+ static gint32 funcIdPath = -1;
static gint32 funcIdFull = -1;
static gint32 funcIdScale = -1;
static gint32 funcIdRotate = -1;
@@ -4746,6 +5302,7 @@ p_transform_and_add_layer( gint32 comp_image_id
static gint32 funcIdClipScale = -1;
GAP_TIMM_GET_FUNCTION_ID(funcId, "p_transform_and_add_layer");
+ GAP_TIMM_GET_FUNCTION_ID(funcIdPath, "p_transform_and_add_layer.PathFullsize");
GAP_TIMM_GET_FUNCTION_ID(funcIdFull, "p_transform_and_add_layer.Fullsize");
GAP_TIMM_GET_FUNCTION_ID(funcIdScale, "p_transform_and_add_layer.ScaleFullsize");
GAP_TIMM_GET_FUNCTION_ID(funcIdRotate, "p_transform_and_add_layer.RotateFullsize");
@@ -4764,12 +5321,14 @@ p_transform_and_add_layer( gint32 comp_image_id
gap_story_render_debug_print_frame_elem(frn_elem, -77);
}
+ l_tmp_image_id = tmp_image_id;
+
/* execute input track specific filtermacro (optional if supplied)
* local_stepcount (usually delivered by procedure p_fetch_framename)
* is used to define fmac_current_step
* (starts at 0)
*/
- l_fmac_layer_id = p_exec_filtermacro(tmp_image_id
+ l_fmac_layer_id = p_exec_filtermacro(l_tmp_image_id
, layer_id
, filtermacro_file
, frn_elem->filtermacro_file_to
@@ -4780,283 +5339,353 @@ p_transform_and_add_layer( gint32 comp_image_id
if(gap_debug)
{
- printf("p_transform_and_add_layer: FILTERMACRO DONE at layer_id: %d (l_fmac_layer_id:%d), tmp_image_id:%d\n"
+ printf("p_transform_and_add_layer: FILTERMACRO DONE at layer_id: %d (l_fmac_layer_id:%d), l_tmp_image_id:%d\n"
, (int)layer_id
, (int)l_fmac_layer_id
- , (int)tmp_image_id
+ , (int)l_tmp_image_id
);
}
+
+
+ calculated = &calculate_attributes;
+
layer_id = gap_layer_flip(l_fmac_layer_id, flip_request);
+ /* execute complex move path transformation (if movepath xml settings present) */
+ if(movepath_file_xml != NULL)
+ {
+ GAP_TIMM_START_FUNCTION(funcIdPath);
+
+ l_new_layer_id = p_transform_with_movepath_processing(comp_image_id
+ , tmp_image_id
+ , layer_id
+ , keep_proportions
+ , fit_width
+ , fit_height
+ , rotate /* rotation in degree */
+ , opacity /* 0.0 upto 1.0 */
+ , scale_x /* 0.0 upto 10.0 where 1.0 = 1:1 */
+ , scale_y /* 0.0 upto 10.0 where 1.0 = 1:1 */
+ , move_x /* -1.0 upto +1.0 where 0 = no move, -1 is left outside */
+ , move_y /* -1.0 upto +1.0 where 0 = no move, -1 is top outside */
+ , frn_elem
+ , vidhand
+ , local_stepcount
+ , movepath_file_xml
+ , movepath_framePhase
+ );
- /* expand layer to tmp image size (before applying any scaling) */
- gimp_layer_resize_to_image_size(layer_id);
+ calculated->opacity = CLAMP(opacity * 100.0, 0.0, 100.0);
+ GAP_TIMM_STOP_FUNCTION(funcIdPath);
+ }
+ else
+ {
- vid_width = gimp_image_width(comp_image_id);
- vid_height = gimp_image_height(comp_image_id);
+ vid_width = gimp_image_width(comp_image_id);
+ vid_height = gimp_image_height(comp_image_id);
- /* calculate scaling, offsets and opacity according to current attributes */
- gap_story_file_calculate_render_attributes(&calculate_attributes
- , vid_width
- , vid_height
- , vid_width
- , vid_height
- , gimp_image_width(tmp_image_id)
- , gimp_image_height(tmp_image_id)
- , keep_proportions
- , fit_width
- , fit_height
- , rotate
- , opacity
- , scale_x
- , scale_y
- , move_x
- , move_y
- );
+ /* expand layer to tmp image size (before applying any scaling) */
+ gimp_layer_resize_to_image_size(layer_id);
+
+ /* calculate scaling, offsets and opacity according to current attributes */
+ gap_story_file_calculate_render_attributes(&calculate_attributes
+ , vid_width
+ , vid_height
+ , vid_width
+ , vid_height
+ , gimp_image_width(l_tmp_image_id)
+ , gimp_image_height(l_tmp_image_id)
+ , keep_proportions
+ , fit_width
+ , fit_height
+ , rotate
+ , opacity
+ , scale_x
+ , scale_y
+ , move_x
+ , move_y
+ );
- calculated = &calculate_attributes;
+ calculated = &calculate_attributes;
- /* add a new transparent layer to composite image */
- l_new_layer_id = gimp_layer_new(comp_image_id
+ /* add a new transparent layer to the composite image */
+ l_new_layer_id = gimp_layer_new(comp_image_id
, "pasted_track"
, vid_width
, vid_height
, GIMP_RGBA_IMAGE
, 0.0 /* Opacity full transparent */
,GIMP_NORMAL_MODE);
- gimp_image_add_layer(comp_image_id, l_new_layer_id, 0);
- gap_layer_clear_to_color(l_new_layer_id, 0.0, 0.0, 0.0, 0.0);
-
-
- if(TRUE == p_transform_operate_on_full_layer(calculated, comp_image_id, tmp_image_id, frn_elem))
- {
- GAP_TIMM_START_FUNCTION(funcIdFull);
+ gimp_image_add_layer(comp_image_id, l_new_layer_id, 0);
+ gap_layer_clear_to_color(l_new_layer_id, 0.0, 0.0, 0.0, 0.0);
- /* operate on layer in full calculated size */
- if(gap_debug)
- {
- printf("p_transform operate on FULL size layer\n");
- }
- /* check size and scale source layer_id to calculated size
- */
- if ((gimp_image_width(tmp_image_id) != calculated->width)
- || (gimp_image_height(tmp_image_id) != calculated->height) )
+ if (TRUE == p_transform_operate_on_full_layer(calculated, comp_image_id, l_tmp_image_id, frn_elem))
{
+ GAP_TIMM_START_FUNCTION(funcIdFull);
+
+ /* operate on layer in full calculated size */
+ /* ---------------------------------------- */
if(gap_debug)
{
- printf("DEBUG: p_transform_and_add_layer scaling layer from %dx%d to %dx%d\n"
- , (int)gimp_image_width(tmp_image_id)
- , (int)gimp_image_height(tmp_image_id)
+ printf("p_transform operate on FULL size layer\n");
+ }
+ /* check size and scale source layer_id to calculated size
+ */
+ if ((gimp_image_width(l_tmp_image_id) != calculated->width)
+ || (gimp_image_height(l_tmp_image_id) != calculated->height) )
+ {
+ if(gap_debug)
+ {
+ printf("DEBUG: p_transform_and_add_layer scaling tmp image from %dx%d to %dx%d\n"
+ , (int)gimp_image_width(l_tmp_image_id)
+ , (int)gimp_image_height(l_tmp_image_id)
, (int)calculated->width
, (int)calculated->height
);
+ }
+ GAP_TIMM_START_FUNCTION(funcIdScale);
+ gimp_layer_scale(layer_id, calculated->width, calculated->height
+ , FALSE /* FALSE: centered at image TRUE: centered local on layer */
+ );
+ GAP_TIMM_STOP_FUNCTION(funcIdScale);
}
- GAP_TIMM_START_FUNCTION(funcIdScale);
- gimp_layer_scale(layer_id, calculated->width, calculated->height
- , FALSE /* FALSE: centered at image TRUE: centered local on layer */
- );
- GAP_TIMM_STOP_FUNCTION(funcIdScale);
- }
- if((frn_elem->mask_name != NULL)
- && (frn_elem->mask_anchor != GAP_MSK_ANCHOR_MASTER))
- {
- /* fetch and add mask at calculated scaled size of layer_id */
- p_fetch_and_add_layermask(vidhand
+ if((frn_elem->mask_name != NULL)
+ && (frn_elem->mask_anchor != GAP_MSK_ANCHOR_MASTER))
+ {
+ /* fetch and add mask at calculated scaled size of layer_id */
+ p_fetch_and_add_layermask(vidhand
, frn_elem
, local_stepcount
- , tmp_image_id
+ , l_tmp_image_id
, layer_id
, frn_elem->mask_anchor
);
- /* apply the mask (necessary because the following copy with this layer
- * as source would ignore the layer mask)
- */
- gimp_layer_remove_mask(layer_id, GIMP_MASK_APPLY);
-
- }
+ /* apply the mask (necessary because the following copy with this layer
+ * as source would ignore the layer mask)
+ */
+ gimp_layer_remove_mask(layer_id, GIMP_MASK_APPLY);
+ }
- if((rotate > 0.05) || (rotate < -0.05))
- {
- gint32 l_orig_width;
- gint32 l_orig_height;
+ if((rotate > 0.05) || (rotate < -0.05))
+ {
+ gint32 l_orig_width;
+ gint32 l_orig_height;
- l_orig_width = gimp_drawable_width(layer_id);
- l_orig_height = gimp_drawable_height(layer_id);
+ l_orig_width = gimp_drawable_width(layer_id);
+ l_orig_height = gimp_drawable_height(layer_id);
- GAP_TIMM_START_FUNCTION(funcIdRotate);
+ GAP_TIMM_START_FUNCTION(funcIdRotate);
- gap_story_transform_rotate_layer(tmp_image_id, layer_id, rotate);
+ gap_story_transform_rotate_layer(l_tmp_image_id, layer_id, rotate);
- GAP_TIMM_STOP_FUNCTION(funcIdRotate);
+ GAP_TIMM_STOP_FUNCTION(funcIdRotate);
- /* recalculate offests to compensate size changes caused by rotation */
- calculated->x_offs = calculated->x_offs + (l_orig_width / 2.0) - (gimp_drawable_width(layer_id) / 2.0);
- calculated->y_offs = calculated->y_offs + (l_orig_height / 2.0) - (gimp_drawable_height(layer_id) / 2.0);
- }
+ /* recalculate offests to compensate size changes caused by rotation */
+ calculated->x_offs = calculated->x_offs + (l_orig_width / 2.0) - (gimp_drawable_width(layer_id) / 2.0);
+ calculated->y_offs = calculated->y_offs + (l_orig_height / 2.0) - (gimp_drawable_height(layer_id) / 2.0);
+ }
- /* copy from tmp_image and paste to composite_image
- * force copying of the complete layer by clearing the selection
- */
- gimp_selection_none(tmp_image_id);
- gimp_edit_copy(layer_id);
- l_fsel_layer_id = gimp_edit_paste(l_new_layer_id, FALSE); /* FALSE paste clear selection */
+ /* copy from tmp_image and paste to composite_image
+ * force copying of the complete layer by clearing the selection
+ */
+ gimp_selection_none(l_tmp_image_id);
+ gimp_edit_copy(layer_id);
+ l_fsel_layer_id = gimp_edit_paste(l_new_layer_id, FALSE); /* FALSE paste clear selection */
- gimp_layer_set_offsets(l_fsel_layer_id
+ gimp_layer_set_offsets(l_fsel_layer_id
, calculated->x_offs
, calculated->y_offs
);
- gimp_floating_sel_anchor(l_fsel_layer_id);
-
- GAP_TIMM_STOP_FUNCTION(funcIdFull);
- }
- else
- {
- GAP_TIMM_START_FUNCTION(funcIdClipped);
+ gimp_floating_sel_anchor(l_fsel_layer_id);
- /* operate on clipped rectangle size (rotation not handled in this case) */
- if(gap_debug)
- {
- printf("p_transform operate on CLIPPED RECTANGLE\n");
- }
-
- if ((calculated->visible_width <= 0) || (calculated->visible_height <= 0))
- {
- /* nothing will be visible (width or height is 0), so we can skip copying and scaling */
- return (l_new_layer_id); /* that is still fully transparent */
- }
-
- if((frn_elem->mask_name != NULL)
- && (frn_elem->mask_anchor != GAP_MSK_ANCHOR_MASTER))
- {
- /* add and apply layermask at original unscaled tmp_image size */
- p_fetch_and_add_layermask(vidhand
- , frn_elem
- , local_stepcount
- , tmp_image_id
- , layer_id
- , frn_elem->mask_anchor
- );
- /* apply the mask (necessary because the following copy with this layer
- * as source would ignore the layer mask)
- */
- gimp_layer_remove_mask(layer_id, GIMP_MASK_APPLY);
+ GAP_TIMM_STOP_FUNCTION(funcIdFull);
}
-
-
-
- /* copy selected clipped source rectangle from tmp_image to composite image
- * as floating selection attached to l_new_layer_id (visble part at source size)
- */
+ else
{
- gdouble sx;
- gdouble sy;
- gdouble swidth;
- gdouble sheight;
+ GAP_TIMM_START_FUNCTION(funcIdClipped);
- sx = 0;
- if (calculated->x_offs < 0)
+ /* operate on clipped rectangle size (rotation not handled in this case) */
+ /* --------------------------------------------------------------------- */
+ if(gap_debug)
{
- sx = (0 - calculated->x_offs) *
- ((gdouble)gimp_image_width(tmp_image_id) / MAX((gdouble)calculated->width, 1.0));
+ printf("p_transform operate on CLIPPED RECTANGLE\n");
}
- sy = 0;
- if (calculated->y_offs < 0)
+ if ((calculated->visible_width <= 0) || (calculated->visible_height <= 0))
{
- sy = (0 - calculated->y_offs) *
- ((gdouble)gimp_image_height(tmp_image_id) / MAX((gdouble)calculated->height, 1.0));
+ /* nothing will be visible (width or height is 0), so we can skip copying and scaling */
+ return (l_new_layer_id); /* that is still fully transparent */
}
- swidth = calculated->visible_width * gimp_image_width(tmp_image_id) / MAX(calculated->width, 1);
- sheight = calculated->visible_height * gimp_image_height(tmp_image_id) / MAX(calculated->height, 1);
-
- if(gap_debug)
+ if((frn_elem->mask_name != NULL)
+ && (frn_elem->mask_anchor != GAP_MSK_ANCHOR_MASTER))
{
- printf("p_transform source rectangle offset sx:%.4f, sy:%.4f, swidth:%.4f, sheight:%.4f\n"
- , (float)sx
- , (float)sy
- , (float)swidth
- , (float)sheight
- );
+ /* add and apply layermask at original unscaled tmp_image size */
+ p_fetch_and_add_layermask(vidhand
+ , frn_elem
+ , local_stepcount
+ , l_tmp_image_id
+ , layer_id
+ , frn_elem->mask_anchor
+ );
+ /* apply the mask (necessary because the following copy with this layer
+ * as source would ignore the layer mask)
+ */
+ gimp_layer_remove_mask(layer_id, GIMP_MASK_APPLY);
}
- gimp_rect_select(tmp_image_id
+ /* copy selected clipped source rectangle from tmp_image to composite image
+ * as floating selection attached to l_new_layer_id (visble part at source size)
+ */
+ {
+ gdouble sx;
+ gdouble sy;
+ gdouble swidth;
+ gdouble sheight;
+
+ sx = 0;
+ if (calculated->x_offs < 0)
+ {
+ sx = (0 - calculated->x_offs) *
+ ((gdouble)gimp_image_width(l_tmp_image_id) / MAX((gdouble)calculated->width, 1.0));
+ }
+
+ sy = 0;
+ if (calculated->y_offs < 0)
+ {
+ sy = (0 - calculated->y_offs) *
+ ((gdouble)gimp_image_height(l_tmp_image_id) / MAX((gdouble)calculated->height, 1.0));
+ }
+
+ swidth = calculated->visible_width * gimp_image_width(l_tmp_image_id) / MAX(calculated->width, 1);
+ sheight = calculated->visible_height * gimp_image_height(l_tmp_image_id) / MAX(calculated->height, 1);
+
+ if(gap_debug)
+ {
+ printf("p_transform source rectangle offset sx:%.4f, sy:%.4f, swidth:%.4f, sheight:%.4f\n"
+ , (float)sx
+ , (float)sy
+ , (float)swidth
+ , (float)sheight
+ );
+ }
+
+ gimp_rect_select(l_tmp_image_id
, sx, sy
, swidth, sheight
, GIMP_CHANNEL_OP_REPLACE
, FALSE /* feather flag */
, 0.0 /* feather_radius */
);
- }
+ }
- gimp_edit_copy(layer_id);
- l_fsel_layer_id = gimp_edit_paste(l_new_layer_id, FALSE); /* FALSE paste clear selection */
+ gimp_edit_copy(layer_id);
+ l_fsel_layer_id = gimp_edit_paste(l_new_layer_id, FALSE); /* FALSE paste clear selection */
- /* scale floating selection to visible target size */
- if ((gimp_drawable_width(l_fsel_layer_id) != calculated->visible_width)
- || (gimp_drawable_height(l_fsel_layer_id) != calculated->visible_height) )
- {
- GAP_TIMM_START_FUNCTION(funcIdClipScale);
+ /* scale floating selection to visible target size */
+ if ((gimp_drawable_width(l_fsel_layer_id) != calculated->visible_width)
+ || (gimp_drawable_height(l_fsel_layer_id) != calculated->visible_height) )
+ {
+ GAP_TIMM_START_FUNCTION(funcIdClipScale);
- gimp_layer_scale(l_fsel_layer_id, calculated->visible_width, calculated->visible_height
+ gimp_layer_scale(l_fsel_layer_id, calculated->visible_width, calculated->visible_height
, FALSE /* FALSE: centered at image TRUE: centered local on layer */
);
- GAP_TIMM_STOP_FUNCTION(funcIdClipScale);
- }
+ GAP_TIMM_STOP_FUNCTION(funcIdClipScale);
+ }
- /* move floating selection according to target offsets
- * (negative offsets are truncated to 0
- * because this case is already handled by selecting only the visible clipped rectangle)
- */
- gimp_layer_set_offsets(l_fsel_layer_id
- , MAX(0, calculated->x_offs)
- , MAX(0, calculated->y_offs)
- );
+ /* move floating selection according to target offsets
+ * (negative offsets are truncated to 0
+ * because this case is already handled by selecting only the visible clipped rectangle)
+ */
+ gimp_layer_set_offsets(l_fsel_layer_id
+ , MAX(0, calculated->x_offs)
+ , MAX(0, calculated->y_offs)
+ );
+
+ gimp_floating_sel_anchor(l_fsel_layer_id);
- gimp_floating_sel_anchor(l_fsel_layer_id);
+ GAP_TIMM_STOP_FUNCTION(funcIdClipped);
- GAP_TIMM_STOP_FUNCTION(funcIdClipped);
+ } /* end processing on CLIPPED part */
}
-// if((rotate > 0.05) || (rotate < -0.05))
-// {
-// gap_story_transform_rotate_layer(comp_image_id, l_new_layer_id, rotate);
-// }
+ /* final common processing to be applied on the newly added layer */
+ p_transform_postprocessing(l_new_layer_id
+ , frn_elem
+ , vidhand
+ , calculated->opacity
+ , local_stepcount
+ );
+ GAP_TIMM_STOP_FUNCTION(funcId);
- if((frn_elem->mask_name != NULL)
- && (frn_elem->mask_anchor == GAP_MSK_ANCHOR_MASTER))
- {
- p_fetch_and_add_layermask(vidhand
- , frn_elem
- , local_stepcount
- , comp_image_id
- , l_new_layer_id
- , frn_elem->mask_anchor
- );
+ return(l_new_layer_id);
+} /* end p_transform_and_add_layer */
- }
- gimp_layer_set_opacity(l_new_layer_id, calculated->opacity);
- GAP_TIMM_STOP_FUNCTION(funcId);
+/* ---------------------------------------------------
+ * gap_story_render_transform_with_movepath_processing
+ * ---------------------------------------------------
+ * move path processing variant for render preview purpose
+ * (without mask handling)
+ */
+gint32
+gap_story_render_transform_with_movepath_processing(gint32 comp_image_id
+ , gint32 tmp_image_id /* must contain layer_id */
+ , gint32 layer_id
+ , gboolean keep_proportions
+ , gboolean fit_width
+ , gboolean fit_height
+ , gdouble rotate /* rotation in degree */
+ , gdouble opacity /* 0.0 upto 1.0 */
+ , gdouble scale_x /* 0.0 upto 10.0 where 1.0 = 1:1 */
+ , gdouble scale_y /* 0.0 upto 10.0 where 1.0 = 1:1 */
+ , gdouble move_x /* -1.0 upto +1.0 where 0 = no move, -1 is left outside */
+ , gdouble move_y /* -1.0 upto +1.0 where 0 = no move, -1 is top outside */
+ , const char *movepath_file_xml
+ , gdouble movepath_framePhase
+ )
+{
+ gint32 l_new_layer_id;
+
+ l_new_layer_id = p_transform_with_movepath_processing(comp_image_id
+ , tmp_image_id
+ , layer_id
+ , keep_proportions
+ , fit_width
+ , fit_height
+ , rotate /* rotation in degree */
+ , opacity /* 0.0 upto 1.0 */
+ , scale_x /* 0.0 upto 10.0 where 1.0 = 1:1 */
+ , scale_y /* 0.0 upto 10.0 where 1.0 = 1:1 */
+ , move_x /* -1.0 upto +1.0 where 0 = no move, -1 is left outside */
+ , move_y /* -1.0 upto +1.0 where 0 = no move, -1 is top outside */
+ , NULL /* frn_elem */
+ , NULL /* vidhand */
+ , 0 /* local_stepcount */
+ , movepath_file_xml
+ , movepath_framePhase
+ );
+ return (l_new_layer_id);
+
+} /* end gap_story_render_transform_with_movepath_processing */
- return(l_new_layer_id);
-} /* end p_transform_and_add_layer */
/* ----------------------------------------------------
@@ -7775,10 +8404,6 @@ p_story_render_bypass_where_possible(GapStoryRenderVidHandle *vidhand
gchar *videofileName;
gboolean isByPassRenderEngine;
gint32 l_track;
- gdouble l_red_f;
- gdouble l_green_f;
- gdouble l_blue_f;
- gdouble l_alpha_f;
isByPassRenderEngine = FALSE;
gfd = &gapStbFetchData;
@@ -7805,25 +8430,7 @@ p_story_render_bypass_where_possible(GapStoryRenderVidHandle *vidhand
gfd->framename = p_fetch_framename(vidhand->frn_list
, master_frame_nr /* starts at 1 */
, l_track
- , &gfd->frn_type
- , &gfd->trak_filtermacro_file
- , &gfd->localframe_index /* used only for ANIMIMAGE, SECTION and Videoframe Number, -1 for all other types */
- , &gfd->local_stepcount /* nth frame within this clip */
- , &gfd->localframe_tween_rest /* non integer part of local position (in case stepsize != 1) */
- , &gfd->keep_proportions
- , &gfd->fit_width
- , &gfd->fit_height
- , &l_red_f
- , &l_green_f
- , &l_blue_f
- , &l_alpha_f
- , &gfd->rotate /* output rotateion in degree */
- , &gfd->opacity /* output opacity 0.0 upto 1.0 */
- , &gfd->scale_x /* output 0.0 upto 10.0 where 1.0 is 1:1 */
- , &gfd->scale_y /* output 0.0 upto 10.0 where 1.0 is 1:1 */
- , &gfd->move_x /* output -1.0 upto 1.0 where 0.0 is centered */
- , &gfd->move_y /* output -1.0 upto 1.0 where 0.0 is centered */
- , &gfd->frn_elem /* output selected to the relevant framerange element */
+ , gfd
);
if(gap_debug)
@@ -7854,6 +8461,8 @@ p_story_render_bypass_where_possible(GapStoryRenderVidHandle *vidhand
&& (gfd->frn_elem->flip_request == GAP_STB_FLIP_NONE)
&& (gfd->frn_elem->mask_name == NULL)
&& (p_isFiltermacroActive(gfd->trak_filtermacro_file) != TRUE)
+ && (gfd->movepath_file_xml == NULL)
+ && (gfd->movepath_framePhase = 0.0)
// Fit options are not relevant when clip and master size are exact the same
// and no scaling is done.
// && (gfd->fit_width)
@@ -7865,7 +8474,7 @@ p_story_render_bypass_where_possible(GapStoryRenderVidHandle *vidhand
isAutoInsertActive = FALSE;
- if(vidhand->master_insert_alpha_format == TRUE)
+ if(vidhand->master_insert_alpha_format != NULL)
{
char *alpha_imagename;
alpha_imagename = p_get_insert_alpha_filename(gfd, vidhand);
@@ -7877,7 +8486,7 @@ p_story_render_bypass_where_possible(GapStoryRenderVidHandle *vidhand
g_free(alpha_imagename);
}
- if((vidhand->master_insert_area_format == TRUE)
+ if((vidhand->master_insert_area_format != NULL)
&& (isAutoInsertActive != TRUE))
{
char *logo_imagename;
@@ -8020,11 +8629,6 @@ p_story_render_fetch_composite_image_private(GapStoryRenderVidHandle *vidhand
gint32 l_track;
- gdouble l_red_f;
- gdouble l_green_f;
- gdouble l_blue_f;
- gdouble l_alpha_f;
-
static gint32 funcId = -1;
static gint32 funcIdDirect = -1;
static gint32 funcIdDirectScale = -1;
@@ -8123,25 +8727,7 @@ p_story_render_fetch_composite_image_private(GapStoryRenderVidHandle *vidhand
gfd->framename = p_fetch_framename(vidhand->frn_list
, master_frame_nr /* starts at 1 */
, l_track
- , &gfd->frn_type
- , &gfd->trak_filtermacro_file
- , &gfd->localframe_index /* used only for ANIMIMAGE, SECTION and Videoframe Number, -1 for all other types */
- , &gfd->local_stepcount /* nth frame within this clip */
- , &gfd->localframe_tween_rest /* non integer part of local position (in case stepsize != 1) */
- , &gfd->keep_proportions
- , &gfd->fit_width
- , &gfd->fit_height
- , &l_red_f
- , &l_green_f
- , &l_blue_f
- , &l_alpha_f
- , &gfd->rotate /* output rotateion in degree */
- , &gfd->opacity /* output opacity 0.0 upto 1.0 */
- , &gfd->scale_x /* output 0.0 upto 10.0 where 1.0 is 1:1 */
- , &gfd->scale_y /* output 0.0 upto 10.0 where 1.0 is 1:1 */
- , &gfd->move_x /* output -1.0 upto 1.0 where 0.0 is centered */
- , &gfd->move_y /* output -1.0 upto 1.0 where 0.0 is centered */
- , &gfd->frn_elem /* output selected to the relevant framerange element */
+ , gfd
);
@@ -8152,10 +8738,10 @@ p_story_render_fetch_composite_image_private(GapStoryRenderVidHandle *vidhand
gfd->tmp_image_id = p_create_unicolor_image(&gfd->layer_id
, vid_width
, vid_height
- , l_red_f
- , l_green_f
- , l_blue_f
- , l_alpha_f
+ , gfd->red_f
+ , gfd->green_f
+ , gfd->blue_f
+ , gfd->alpha_f
);
}
@@ -8303,6 +8889,8 @@ p_story_render_fetch_composite_image_private(GapStoryRenderVidHandle *vidhand
,gfd->frn_elem
,vidhand
,gfd->local_stepcount
+ ,gfd->movepath_file_xml
+ ,gfd->movepath_framePhase
);
gap_image_delete_immediate(gfd->tmp_image_id);
}
diff --git a/gap/gap_story_render_processor.h b/gap/gap_story_render_processor.h
index f9523a7..891ca9b 100644
--- a/gap/gap_story_render_processor.h
+++ b/gap/gap_story_render_processor.h
@@ -129,7 +129,7 @@ typedef struct GapStoryFetchResult {
gboolean force_keyframe; /* the calling encoder should encode an I-Frame when true */
gint32 video_frame_chunk_size; /* total size of frame (may include a videoformat specific frameheader) */
gint32 video_frame_chunk_hdr_size; /* size of videoformat specific frameheader (0 if has no hdr) */
- unsigned char *video_frame_chunk_data /* copy of the already compressed video frame from source video */
+ unsigned char *video_frame_chunk_data; /* copy of the already compressed video frame from source video */
} GapStoryFetchResult;
@@ -358,4 +358,20 @@ guchar * gap_story_render_fetch_composite_vthumb(GapStoryRenderVidHandle *stb_c
, gint32 width, gint32 height
);
+gint32 gap_story_render_transform_with_movepath_processing(gint32 comp_image_id
+ , gint32 tmp_image_id /* must contain layer_id */
+ , gint32 layer_id
+ , gboolean keep_proportions
+ , gboolean fit_width
+ , gboolean fit_height
+ , gdouble rotate /* rotation in degree */
+ , gdouble opacity /* 0.0 upto 1.0 */
+ , gdouble scale_x /* 0.0 upto 10.0 where 1.0 = 1:1 */
+ , gdouble scale_y /* 0.0 upto 10.0 where 1.0 = 1:1 */
+ , gdouble move_x /* -1.0 upto +1.0 where 0 = no move, -1 is left outside */
+ , gdouble move_y /* -1.0 upto +1.0 where 0 = no move, -1 is top outside */
+ , const char *movepath_file_xml
+ , gdouble movepath_framePhase
+ );
+
#endif /* GAP_STORY_RENDER_PROCESSOR_H */
diff --git a/gap/gap_story_render_types.h b/gap/gap_story_render_types.h
index dc0414f..c6c1cc0 100644
--- a/gap/gap_story_render_types.h
+++ b/gap/gap_story_render_types.h
@@ -204,6 +204,11 @@ typedef struct GapStoryRenderFrameRangeElem /* nick: frn_elem */
gint rotate_accel; /* acceleration characteristic for opacity transformation */
gint32 rotate_frames_done; /* already processed frames since begin of transition */
+ gdouble movepath_from; /* 1.0 to path length in frames */
+ gdouble movepath_to; /* 1.0 to path length in frames */
+ gint32 movepath_frames_done;
+ gint32 movepath_dur; /* number of frames to change from -> to value */
+ char *movepath_file_xml; /* XML parameter file for movepath transitions */
void *next;
} GapStoryRenderFrameRangeElem; /* used for storyboard processing */
@@ -299,6 +304,12 @@ typedef struct GapStoryRenderVTrackAttrElem
gint scale_y_accel;
gint32 scale_y_frames_done;
+ gdouble movepath_from; /* 1.0 to path length in frames */
+ gdouble movepath_to; /* 1.0 to path length in frames */
+ gint32 movepath_frames_done;
+ gint32 movepath_dur; /* number of frames to change from -> to value */
+ char *movepath_file_xml; /* (dont g_free this) XML parameter file for movepath transitions */
+
} GapStoryRenderVTrackAttrElem; /* Video track attributes used for storyboard processing */
typedef struct GapStoryRenderVTrackArray
diff --git a/gap/gap_story_syntax.c b/gap/gap_story_syntax.c
index d1d5312..63594ab 100644
--- a/gap/gap_story_syntax.c
+++ b/gap/gap_story_syntax.c
@@ -494,6 +494,15 @@ p_create_syntax_list(void)
,"nframes"
,NULL
);
+ p_add_keyword(GAP_STBKEY_VID_MOVEPATH
+ ,"track"
+ ,"frame_from"
+ ,"frame_to"
+ ,"nframes"
+ ,"accel"
+ ,"xml_paramfile"
+ ,NULL
+ );
p_add_keyword(GAP_STBKEY_MASK_MOVIE
,"mask_name"
,"file"
diff --git a/gap/gap_story_syntax.h b/gap/gap_story_syntax.h
index 44a630d..fe1750d 100644
--- a/gap/gap_story_syntax.h
+++ b/gap/gap_story_syntax.h
@@ -65,6 +65,7 @@
#define GAP_STBKEY_VID_MOVE_Y "VID_MOVE_Y"
#define GAP_STBKEY_VID_FIT_SIZE "VID_FIT_SIZE"
#define GAP_STBKEY_VID_OVERLAP "VID_OVERLAP"
+#define GAP_STBKEY_VID_MOVEPATH "VID_MOVEPATH"
#define GAP_STBKEY_MASK_IMAGE "MASK_IMAGE"
#define GAP_STBKEY_MASK_ANIMIMAGE "MASK_ANIMIMAGE"
diff --git a/gap/gap_story_vthumb.c b/gap/gap_story_vthumb.c
index ef9a24f..3a70f30 100644
--- a/gap/gap_story_vthumb.c
+++ b/gap/gap_story_vthumb.c
@@ -658,9 +658,12 @@ gap_story_vthumb_get_velem_no_movie(GapStbMainGlobalParams *sgpp
velem->section_id = section_id;
if(stb_elem->record_type == GAP_STBREC_VID_SECTION)
{
- velem->total_frames = stb_elem->nframes;
velem->total_frames = gap_story_count_total_frames_in_section(referenced_section);
}
+ else
+ {
+ velem->total_frames = stb_elem->nframes;
+ }
velem->next = sgpp->video_list;
sgpp->video_list = velem;
diff --git a/gap/gap_xml_util.c b/gap/gap_xml_util.c
new file mode 100644
index 0000000..08c04e9
--- /dev/null
+++ b/gap/gap_xml_util.c
@@ -0,0 +1,347 @@
+/* gap_xml_util.c
+ * 2011.03.09 hof (Wolfgang Hofer)
+ *
+ * This module contains procedures to parse basic datatypes from string and write to file.
+ * Intended for use in parser functions called by GMarkupParser
+ * to read data from attributes in XML elements.
+ *
+ */
+/* 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:
+ * 2011.03.09 hof: created.
+ */
+
+#include "config.h"
+#include "gap_base.h"
+#include "gap_xml_util.h"
+
+/* --------------------------------------
+ * gap_xml_parse_value_gdouble
+ * --------------------------------------
+ */
+gboolean
+gap_xml_parse_value_gdouble(const gchar *attribute_value, gdouble *valDestPtr)
+{
+ gchar *endptr;
+
+ *valDestPtr = g_ascii_strtod(attribute_value, &endptr);
+ if(attribute_value == endptr)
+ {
+ /* pointer was not advanced (no float number could be scanned */
+ return (FALSE);
+ }
+ return(TRUE);
+}
+
+/* --------------------------------------
+ * gap_xml_parse_value_gint32
+ * --------------------------------------
+ */
+gboolean
+gap_xml_parse_value_gint32(const gchar *attribute_value, gint32 *valDestPtr)
+{
+ gint64 value64;
+ gchar *endptr;
+
+ value64 = g_ascii_strtoll(attribute_value, &endptr, 10);
+ if(attribute_value == endptr)
+ {
+ /* pointer was not advanced (no int number could be scanned */
+ return (FALSE);
+ }
+ *valDestPtr = value64;
+ return (TRUE);
+}
+
+/* --------------------------------------
+ * gap_xml_parse_value_gint
+ * --------------------------------------
+ */
+gboolean
+gap_xml_parse_value_gint(const gchar *attribute_value, gint *valDestPtr)
+{
+ gint64 value64;
+ gchar *endptr;
+
+ value64 = g_ascii_strtoll(attribute_value, &endptr, 10);
+ if(attribute_value == endptr)
+ {
+ /* pointer was not advanced (no int number could be scanned */
+ return (FALSE);
+ }
+ *valDestPtr = value64;
+ return (TRUE);
+}
+
+
+
+/* --------------------------------------
+ * gap_xml_parse_value_gboolean
+ * --------------------------------------
+ */
+gboolean
+gap_xml_parse_value_gboolean(const gchar *attribute_value, gboolean *valDestPtr)
+{
+ gboolean isOk = TRUE;
+
+ *valDestPtr = FALSE;
+ if (strcmp("TRUE", attribute_value) == 0)
+ {
+ *valDestPtr = TRUE;
+ }
+ else if(strcmp("FALSE", attribute_value) == 0)
+ {
+ *valDestPtr = FALSE;
+ }
+ else
+ {
+ gint intVal;
+
+ isOk = gap_xml_parse_value_gint(attribute_value, &intVal);
+ if(isOk)
+ {
+ *valDestPtr = (intVal != 0);
+ }
+ }
+
+ return (isOk);
+
+} /* end gap_xml_parse_value_gboolean */
+
+
+
+/* --------------------------------------
+ * gap_xml_parse_value_gboolean_as_gint
+ * --------------------------------------
+ */
+gboolean
+gap_xml_parse_value_gboolean_as_gint(const gchar *attribute_value, gint *valDestPtr)
+{
+ gboolean val;
+ gboolean isOk;
+
+ val = FALSE;
+ isOk = gap_xml_parse_value_gboolean(attribute_value, &val);
+ if(val)
+ {
+ *valDestPtr = 1;
+ }
+ else
+ {
+ *valDestPtr = 0;
+ }
+
+ return (isOk);
+
+} /* end gap_xml_parse_value_gboolean_as_gint */
+
+
+/* --------------------------------------
+ * gap_xml_parse_EnumValue_as_gint
+ * --------------------------------------
+ */
+gboolean
+gap_xml_parse_EnumValue_as_gint(const gchar *attribute_value, gint *valDestPtr,
+const GEnumValue *enumValuesTable)
+{
+ gboolean isOk = FALSE;
+ gint ii;
+
+ for(ii=0; enumValuesTable[ii].value_name != NULL; ii++)
+ {
+ if (strcmp(enumValuesTable[ii].value_name, attribute_value) == 0)
+ {
+ *valDestPtr = enumValuesTable[ii].value;
+ isOk = TRUE;
+ break;
+ }
+ if(enumValuesTable[ii].value_nick != NULL)
+ {
+ if (strcmp(enumValuesTable[ii].value_nick, attribute_value) == 0)
+ {
+ *valDestPtr = enumValuesTable[ii].value;
+ isOk = TRUE;
+ break;
+ }
+ }
+ }
+
+ return (isOk);
+
+} /* end gap_xml_parse_EnumValue_as_gint */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/* --------------------------------------
+ * gap_xml_write_gboolean_value
+ * --------------------------------------
+ */
+void
+gap_xml_write_gboolean_value(FILE *fp, const char *name, gboolean value)
+{
+ if(value)
+ {
+ fprintf(fp, "%s=\"TRUE\" ", name);
+ }
+ else
+ {
+ fprintf(fp, "%s=\"FALSE\" ", name);
+ }
+}
+
+/* --------------------------------------
+ * gap_xml_write_gint_as_gboolean_value
+ * --------------------------------------
+ */
+void
+gap_xml_write_gint_as_gboolean_value(FILE *fp, const char *name, gint value)
+{
+ if(value)
+ {
+ fprintf(fp, "%s=\"TRUE\" ", name);
+ }
+ else
+ {
+ fprintf(fp, "%s=\"FALSE\" ", name);
+ }
+}
+
+/* --------------------------------------
+ * gap_xml_write_int_value
+ * --------------------------------------
+ */
+void
+gap_xml_write_int_value(FILE *fp, const char *name, gint32 value)
+{
+ fprintf(fp, "%s=\"%d\" ", name, (int)value);
+}
+
+/* --------------------------------------
+ * gap_xml_write_gdouble_value
+ * --------------------------------------
+ */
+void
+gap_xml_write_gdouble_value(FILE *fp, const char *name, gdouble value, gint digits, gint precision_digits)
+{
+ fprintf(fp, "%s=\"", name);
+ gap_base_fprintf_gdouble(fp, value, digits, precision_digits, "");
+ fprintf(fp, "\" ");
+}
+
+
+/* --------------------------------------
+ * gap_xml_write_string_value
+ * --------------------------------------
+ * write escaped string value.
+ * Note that utf8 compliant strings are written unchanged
+ * but utf8 non compliant strings are changed where all
+ * characters that are not 7-bit ascii encoded will be replaced by '_'
+ * (to force utf8 compatibility)
+ */
+void
+gap_xml_write_string_value(FILE *fp, const char *name, const char *value)
+{
+ gchar *utf8String;
+ gchar *escapedUtf8String;
+ gboolean utf8_compliant;
+
+
+ if(value == NULL)
+ {
+ fprintf(fp, "%s=\"\" ", name);
+ return;
+ }
+
+ utf8_compliant = g_utf8_validate(value, -1, NULL);
+ if(utf8_compliant)
+ {
+ utf8String = g_strdup(value);
+ }
+ else
+ {
+ gint ii;
+ gint len;
+
+ len = strlen(value);
+
+ utf8String = g_malloc(len +1);
+
+ /* copy 7-bit ascii characters and replace other characters by "_" */
+ for(ii=0; ii < len; ii++)
+ {
+ if(value[ii] <= 0x7f)
+ {
+ utf8String[ii] = value[ii];
+ }
+ else
+ {
+ utf8String[ii] = '_';
+ }
+ }
+ utf8String[ii] = '\0';
+ }
+
+ escapedUtf8String = g_markup_printf_escaped("%s", utf8String);
+
+ fprintf(fp, "%s=\"%s\" ", name, escapedUtf8String);
+
+ g_free(utf8String);
+ g_free(escapedUtf8String);
+
+}
+
+
+/* --------------------------------------
+ * gap_xml_write_EnumValue
+ * --------------------------------------
+ */
+void
+gap_xml_write_EnumValue(FILE *fp, const char *name, gint value,
+ const GEnumValue *enumValuesTable)
+{
+ gint ii;
+
+ for(ii=0; enumValuesTable[ii].value_name != NULL; ii++)
+ {
+ if (enumValuesTable[ii].value == value)
+ {
+ gap_xml_write_string_value(fp, name,enumValuesTable[ii].value_name);
+ return;
+ }
+ }
+
+ /* fallback: write unknown value as int */
+ gap_xml_write_int_value(fp, name, value);
+
+} /* end p_parse_xml_value_GimpPaintmode */
+
diff --git a/gap/gap_xml_util.h b/gap/gap_xml_util.h
new file mode 100644
index 0000000..82230c8
--- /dev/null
+++ b/gap/gap_xml_util.h
@@ -0,0 +1,56 @@
+/* gap_xml_util.h
+ * 2011.03.09 hof (Wolfgang Hofer)
+ *
+ * GAP ... Gimp Animation Plugins
+ *
+ * functions to parse and write XML attributes for basic data types.
+ *
+ */
+/* 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:
+ * 2011.03.09 hof: created.
+ */
+#ifndef _GAP_XML_UTIL_H
+#define _GAP_XML_UTIL_H
+
+#include <glib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libgimp/gimp.h"
+
+gboolean gap_xml_parse_value_gdouble(const gchar *attribute_value, gdouble *valDestPtr);
+gboolean gap_xml_parse_value_gint32(const gchar *attribute_value, gint32 *valDestPtr);
+gboolean gap_xml_parse_value_gint(const gchar *attribute_value, gint *valDestPtr);
+gboolean gap_xml_parse_value_gboolean(const gchar *attribute_value, gboolean *valDestPtr);
+gboolean gap_xml_parse_value_gboolean_as_gint(const gchar *attribute_value, gint *valDestPtr);
+gboolean gap_xml_parse_EnumValue_as_gint(const gchar *attribute_value, gint
+*valDestPtr, const GEnumValue *enumValuesTable);
+
+void gap_xml_write_gboolean_value(FILE *fp, const char *name, gboolean value);
+void gap_xml_write_gint_as_gboolean_value(FILE *fp, const char *name, gint value);
+void gap_xml_write_int_value(FILE *fp, const char *name, gint32 value);
+void gap_xml_write_gdouble_value(FILE *fp, const char *name, gdouble value, gint digits, gint precision_digits);
+void gap_xml_write_string_value(FILE *fp, const char *name, const char *value);
+void gap_xml_write_EnumValue(FILE *fp, const char *name, gint value, const GEnumValue *enumValuesTable);
+
+#endif
+
+
diff --git a/po/POTFILES.in b/po/POTFILES.in
index c193302..ed11178 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -30,6 +30,7 @@ gap/gap_morph_exec.c
gap/gap_morph_main.c
gap/gap_morph_shape.c
gap/gap_morph_tween_dialog.c
+gap/gap_mov_main.c
gap/gap_mov_dialog.c
gap/gap_mov_exec.c
gap/gap_mpege.c
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]