[gimp-gap] fixed move path unwanted object jumps forth and back as reported in #607927
- From: Wolfgang Hofer <wolfgangh src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp-gap] fixed move path unwanted object jumps forth and back as reported in #607927
- Date: Mon, 19 Apr 2010 06:43:17 +0000 (UTC)
commit 397624f656b88b89a478aea8246a20bb5e646719
Author: Wolfgang Hofer <wolfgangh svn gnome org>
Date: Mon Apr 19 08:44:54 2010 +0200
fixed move path unwanted object jumps forth and back as reported in #607927
ChangeLog | 16 +
docs/reference/txt/plug-in-gap-move-path.txt | 21 +-
gap/gap_mov_dialog.c | 189 ++++++++++-
gap/gap_mov_dialog.h | 16 +
gap/gap_mov_exec.c | 451 ++++++++++++++++++++------
gap/gap_mov_exec.h | 1 +
gap/gap_mov_render.c | 7 +-
7 files changed, 581 insertions(+), 120 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 76c947a..b319e61 100755
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2010-04-19 Wolfgang Hofer <hof gimp org>
+
+- move path fix for unwanted object jumps forth and back as reported in #607927
+ (the 1st frame in a segment was sometimes calculated based on the controlpoint
+ of the previous segment. this resulted in the reported pixel jumps)
+
+- added information label to the move path dialog to show max speed for current segment
+ and current segment length in pixels.
+ (this shall help to adjust ontrolpoints in a way to avoid unwanted speed jumps)
+
+ * gap/gap_mov_render.c
+ * gap/gap_mov_exec.c [.h]
+ * gap/gap_mov_dialog.c [.h]
+ * docs/reference/txt/plug-in-gap-move-path.txt
+
+
2010-03-21 Wolfgang Hofer <hof gimp org>
- added gimprc parameters to specify width and height
diff --git a/docs/reference/txt/plug-in-gap-move-path.txt b/docs/reference/txt/plug-in-gap-move-path.txt
index 6e8ef39..7534bcb 100755
--- a/docs/reference/txt/plug-in-gap-move-path.txt
+++ b/docs/reference/txt/plug-in-gap-move-path.txt
@@ -439,13 +439,19 @@ Move Path (make things move)
the keyframe is internally stored as 2 (7 - 5)
Keyframes are also used to define path segments.
- Where a Path segment includes all followin controlpoints
+ Where a Path segment includes all following controlpoints
until the next Keyframe.
Independent acceleration characteristics can be set at
those controlpoints that are the begin of a path segment.
(e.g the 1st controlpoint and all keyframes)
+ The current Segment Number, current segment length (in pixels)
+ and minimal / maximal speed (in pixels per tween) are displayed
+ below the preview.
+ The current Segment is the segment that includes the current
+ displayed controlpoint.
+
Example:
You have 500 frames and want to render an object
that stands still at coordinate 320/200 in the 1st 50 frames,
@@ -453,9 +459,18 @@ Move Path (make things move)
until frame 400, decelerates until frame 450 and stays still
at coordinate 470/150 until the end frame 500.
+ Tip:
+ To avoid unwanted speed jumps in this multi segmented
+ example, the controlpoints should be set in a way
+ that max speed value of segment B is nearly equal
+ to the max speed value of Segment C and segment D.
+ Note that changes of control point coordinates affect the
+ length of the path segment, acceleration characteristic,
+ and number of involved frames (or tweens) also have
+ influence on the speed of the object within a segment.
- #Segment A (standstill)
+ #Segment A (standstill in Segment Number 0)
[ 0] x:320 y:200
#Segment B (increasing speed due to acceleration value 20 for Movement)
@@ -478,7 +493,7 @@ Move Path (make things move)
[13] x:475 y:155
[14] x:475 y:155
- #Segment D (standstill)
+ #Segment E (standstill)
[15] x:470 y:150 keyframe:450
[16] x:470 y:150
diff --git a/gap/gap_mov_dialog.c b/gap/gap_mov_dialog.c
index c71b2e1..035fd44 100755
--- a/gap/gap_mov_dialog.c
+++ b/gap/gap_mov_dialog.c
@@ -276,6 +276,12 @@ typedef struct
GdkCursor *cursor_wait;
GdkCursor *cursor_acitve;
GimpRGB pathcolor;
+
+
+ GtkWidget *segNumberLabel;
+ GtkWidget *segLengthLabel;
+ GtkWidget *segSpeedLabel;
+
} t_mov_gui_stuff;
@@ -350,6 +356,7 @@ static void mov_grab_anchorpoints_path(t_mov_gui_stuff *mgp
);
+static void mov_upd_seg_labels (GtkWidget *widget, t_mov_gui_stuff *mgp);
static void mov_padd_callback (GtkWidget *widget,gpointer data);
static void mov_pgrab_callback (GtkWidget *widget,GdkEventButton *bevent,gpointer data);
static void mov_pins_callback (GtkWidget *widget,gpointer data);
@@ -472,9 +479,11 @@ long gap_mov_dlg_move_dialog (GapMovData *mov_ptr)
char *l_str;
t_mov_gui_stuff *mgp;
- if(gap_debug) printf("GAP-DEBUG: START gap_mov_dlg_move_dialog\n");
-
mgp = g_new( t_mov_gui_stuff, 1 );
+ if(gap_debug)
+ {
+ printf("gap_mov_dlg_move_dialog START mgp:%d\n", (int)mgp);
+ }
if(mgp == NULL)
{
printf("error can't alloc path_preview structure\n");
@@ -499,7 +508,10 @@ long gap_mov_dlg_move_dialog (GapMovData *mov_ptr)
mgp->tween_opacity_desc_adj = NULL;
mgp->trace_opacity_initial_adj = NULL;
mgp->sel_feather_radius_adj = NULL;
-
+ mgp->segNumberLabel = NULL;
+ mgp->segLengthLabel = NULL;
+ mgp->segSpeedLabel = NULL;
+
pvals = mov_ptr->val_ptr;
l_str = gap_base_strdup_del_underscore(mov_ptr->dst_ainfo_ptr->basename);
@@ -1560,6 +1572,67 @@ mov_pgrab_callback (GtkWidget *widget,
} /* end mov_pgrab_callback */
+/* --------------------------------
+ * 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)
+{
+ if(gap_debug)
+ {
+ printf("mov_upd_seg_labels START mgp:%d widget:%d\n", (int)mgp, (int)widget);
+ }
+
+ if(mgp != NULL)
+ {
+ if((mgp->segLengthLabel != NULL)
+ && (mgp->segSpeedLabel != NULL)
+ && (mgp->segNumberLabel != NULL))
+ {
+ GapMovQuery mov_query;
+ char *numString;
+
+ mov_query.pointIndexToQuery = pvals->point_idx;
+
+ if(gap_debug)
+ {
+ printf("mov_upd_seg_labels pointIndexToQuery:%d dst_range_end:%d\n"
+ , (int)mov_query.pointIndexToQuery
+ , (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
+ );
+ gtk_label_set_text( GTK_LABEL(mgp->segNumberLabel), numString);
+ g_free(numString);
+
+ numString = g_strdup_printf("%.1f"
+ , (float)mov_query.pathSegmentLengthInPixels
+ );
+ 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);
+
+ }
+ }
+}
+
+
static void
mov_padd_callback (GtkWidget *widget,
gpointer data)
@@ -1620,7 +1693,7 @@ mov_pdel_callback (GtkWidget *widget,
l_idx = pvals->point_idx_max;
if(pvals->point_idx_max == 0)
{
- /* This is the las t point to delete */
+ /* This is the last point to delete */
p_reset_points();
}
else
@@ -2089,6 +2162,8 @@ p_point_refresh(t_mov_gui_stuff *mgp)
gtk_adjustment_set_value (mgp->accSelFeatherRadius_adj,
(gdouble)mgp->accSelFeatherRadius);
+ mov_upd_seg_labels(NULL, mgp);
+
mgp->in_call = FALSE;
} /* end p_point_refresh */
@@ -3576,7 +3651,6 @@ mov_path_framerange_box_create(t_mov_gui_stuff *mgp
,gboolean vertical_layout
)
{
- GtkWidget *vcbox;
GtkWidget *master_table;
GtkWidget *table;
GtkObject *adj;
@@ -3584,6 +3658,7 @@ mov_path_framerange_box_create(t_mov_gui_stuff *mgp
gint master_rows;
gint master_cols;
gint tabcol, tabrow, boxcol, boxrow;
+ gint row;
if(vertical_layout)
{
@@ -3633,6 +3708,9 @@ mov_path_framerange_box_create(t_mov_gui_stuff *mgp
g_signal_connect (G_OBJECT (adj), "value_changed",
G_CALLBACK (gimp_int_adjustment_update),
&pvals->dst_range_start);
+ g_signal_connect (adj, "value-changed",
+ G_CALLBACK (mov_upd_seg_labels),
+ mgp);
/* the end frame scale_entry */
adj = gimp_scale_entry_new( GTK_TABLE (table), 0, 1, /* table col, row */
@@ -3651,6 +3729,9 @@ mov_path_framerange_box_create(t_mov_gui_stuff *mgp
g_signal_connect (G_OBJECT (adj), "value_changed",
G_CALLBACK (gimp_int_adjustment_update),
&pvals->dst_range_end);
+ g_signal_connect (adj, "value-changed",
+ G_CALLBACK (mov_upd_seg_labels),
+ mgp);
/* the Layerstack scale_entry */
adj = gimp_scale_entry_new( GTK_TABLE (table), 0, 2, /* table col, row */
@@ -3671,10 +3752,11 @@ mov_path_framerange_box_create(t_mov_gui_stuff *mgp
G_CALLBACK (mov_instant_int_adjustment_update),
&pvals->dst_layerstack);
- /* the vbox for checkbuttons */
- vcbox = gtk_vbox_new (FALSE, 3);
- gtk_widget_show (vcbox);
+ /* the table for checkbuttons and info labels */
+ table = gtk_table_new (3, 3, FALSE);
+ gtk_widget_show (table);
+ row = 0;
/* toggle force visibility */
check_button = gtk_check_button_new_with_label ( _("Force Visibility"));
@@ -3688,7 +3770,11 @@ mov_path_framerange_box_create(t_mov_gui_stuff *mgp
g_signal_connect (G_OBJECT (check_button), "toggled",
G_CALLBACK (mov_force_visibility_toggle_callback),
&pvals->src_force_visible);
- gtk_box_pack_start (GTK_BOX (vcbox), check_button, TRUE, TRUE, 0);
+ gtk_table_attach(GTK_TABLE(table), check_button, 0, 1, row, row+1
+ , GTK_FILL, GTK_FILL, 4, 0);
+
+
+ row = 1;
/* toggle clip_to_image */
check_button = gtk_check_button_new_with_label ( _("Clip To Frame"));
@@ -3701,11 +3787,17 @@ mov_path_framerange_box_create(t_mov_gui_stuff *mgp
g_signal_connect (G_OBJECT (check_button), "toggled",
G_CALLBACK (mov_gint_toggle_callback),
&pvals->clip_to_img);
- gtk_box_pack_start (GTK_BOX (vcbox), check_button, TRUE, TRUE, 0);
+ gtk_table_attach(GTK_TABLE(table), check_button, 0, 1, row, row+1
+ , GTK_FILL, GTK_FILL, 4, 0);
+
+
- gtk_table_attach(GTK_TABLE(master_table), vcbox, boxcol, boxcol+1, boxrow, boxrow+1
+
+
+ gtk_table_attach(GTK_TABLE(master_table), table, boxcol, boxcol+1, boxrow, boxrow+1
, GTK_FILL, GTK_FILL, 4, 0);
+
return(master_table);
} /* end mov_path_framerange_box_create */
@@ -4510,6 +4602,67 @@ mov_path_prevw_create ( GimpDrawable *drawable, t_mov_gui_stuff *mgp, gboolean v
}
+ /* segmnt information labels */
+ {
+ 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);
+
+ label = gtk_label_new(_("Segment:"));
+ gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
+ 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);
+ mgp->segLengthLabel = label;
+ gtk_table_attach(GTK_TABLE(seg_table), label, 3, 4, seg_row, seg_row+1
+ , GTK_FILL, GTK_FILL, 4, 0);
+
+ label = gtk_label_new(_("Speed Min/Max:"));
+ gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
+ gtk_widget_show (label);
+ gtk_table_attach(GTK_TABLE(seg_table), label, 4, 5, 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);
+ mgp->segSpeedLabel = label;
+ gtk_table_attach(GTK_TABLE(seg_table), label, 5, 6, seg_row, seg_row+1
+ , GTK_FILL, GTK_FILL, 4, 0);
+
+
+ gtk_table_attach(GTK_TABLE(pv_table), seg_table, 0, 1, 1, 2,
+ GTK_FILL|GTK_EXPAND, 0, 0, 0);
+
+ }
+
+
+
/* hbox_show block */
{
GtkWidget *hbox_show;
@@ -4518,7 +4671,7 @@ mov_path_prevw_create ( GimpDrawable *drawable, t_mov_gui_stuff *mgp, gboolean v
hbox_show = gtk_hbox_new (FALSE, 3);
gtk_widget_show (hbox_show);
- /* pathclor selction button */
+ /* pathclor selection button */
{
GtkWidget *color_button;
@@ -4604,8 +4757,8 @@ mov_path_prevw_create ( GimpDrawable *drawable, t_mov_gui_stuff *mgp, gboolean v
mgp);
- gtk_table_attach(GTK_TABLE(pv_table), hbox_show, 0, 1, 1, 2,
- 0, 0, 16, 0);
+ gtk_table_attach(GTK_TABLE(pv_table), hbox_show, 0, 1, 2, 3,
+ GTK_FILL, 0, 0, 0);
}
/* the preview sub table (1 row) */
@@ -4632,7 +4785,7 @@ mov_path_prevw_create ( GimpDrawable *drawable, t_mov_gui_stuff *mgp, gboolean v
mgp->preview_frame_nr_adj = GTK_ADJUSTMENT(adj);
- gtk_table_attach( GTK_TABLE(pv_table), pv_sub_table, 0, 1, 2, 3,
+ gtk_table_attach( GTK_TABLE(pv_table), pv_sub_table, 0, 1, 3, 4,
GTK_FILL|GTK_EXPAND, 0, 0, 0 );
gtk_widget_show (pv_sub_table);
@@ -4746,6 +4899,8 @@ mov_path_prevw_draw ( t_mov_gui_stuff *mgp, gint update )
if(gap_debug) printf("mov_path_prevw_draw: START update:%d\n", (int)update);
+ mov_upd_seg_labels(NULL, mgp);
+
if(mgp->pv_ptr == NULL)
{
return;
@@ -4995,6 +5150,8 @@ mov_path_keyframe_update ( GtkWidget *widget, t_mov_gui_stuff *mgp)
{
gimp_int_adjustment_update(GTK_ADJUSTMENT(widget), &mgp->keyframe_abs);
p_accel_widget_sensitivity(mgp);
+ p_points_to_tab(mgp);
+ mov_upd_seg_labels(NULL, mgp);
}
@@ -5094,6 +5251,8 @@ mov_path_acceleration_adjustment_update(GtkWidget *widget,
if(mgp == NULL) return;
old_val = *val;
gimp_int_adjustment_update(GTK_ADJUSTMENT(widget), (gpointer)val);
+ p_points_to_tab(mgp);
+ mov_upd_seg_labels(NULL, mgp);
return;
diff --git a/gap/gap_mov_dialog.h b/gap/gap_mov_dialog.h
index a37ec08..c3be9a2 100755
--- a/gap/gap_mov_dialog.h
+++ b/gap/gap_mov_dialog.h
@@ -243,6 +243,22 @@ typedef struct {
GapMovValues *val_ptr;
} GapMovData;
+
+typedef struct {
+ /* IN */
+ gint pointIndexToQuery;
+ gint startOfSegmentIndexToQuery;
+ gint endOfSegmentIndexToQuery;
+ gint tweenCount;
+
+ /* OUT */
+ gint segmentNumber;
+ gdouble pathSegmentLengthInPixels;
+ gdouble maxSpeedInPixelsPerFrame;
+ gdouble minSpeedInPixelsPerFrame;
+} GapMovQuery;
+
+
long gap_mov_dlg_move_dialog (GapMovData *mov_ptr);
#endif
diff --git a/gap/gap_mov_exec.c b/gap/gap_mov_exec.c
index add6c30..d3fe865 100755
--- a/gap/gap_mov_exec.c
+++ b/gap/gap_mov_exec.c
@@ -81,6 +81,7 @@ 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 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);
@@ -117,6 +118,7 @@ static gint p_calculate_settings_for_current_FrameTween(
, long availableCtrlPoints /* number of available controlpoints */
, gint startOfSegmentIndex
, gint endOfSegmentIndex
+ , GapMovQuery *mov_query
);
@@ -935,11 +937,12 @@ p_calculate_settings_for_current_FrameTween(
, long availableCtrlPoints /* number of available controlpoints */
, gint startOfSegmentIndex
, gint endOfSegmentIndex
- )
+ , GapMovQuery *mov_query
+ )
{
+ gint frameNrAtEndOfSegment;
gdouble tweenMultiplicator;
- gint frameNrAtEndOfSegment;
gdouble lengthFactorLinear; /* 0.0 at begin of segment 1.0 at end of segment position */
gdouble frameTweensInSegment;
gdouble currFrameTweenInSegment; /* frame number relative to 0 at each starting point of a new segment
@@ -949,11 +952,17 @@ p_calculate_settings_for_current_FrameTween(
gdouble posFactor;
gdouble posFactorMovement;
gint segmPtidx; /* calculated controlpoint index of relevant line begin with current segment */
+ gdouble prevX;
+ gdouble prevY;
posFactor = 0.0;
posFactorMovement = 0.0;
segmPtidx = -1; /* inital value -1 indicates that movement does NOT use acceleration characteristic */
+
+ prevX = cur_ptr->currX;
+ prevY = cur_ptr->currY;
+
tweenMultiplicator = 1.0;
if(val_ptr->tween_steps > 1.0)
{
@@ -961,7 +970,7 @@ p_calculate_settings_for_current_FrameTween(
}
frameNrAtEndOfSegment = p_calculate_relframe_nr_at_index(val_ptr, endOfSegmentIndex, affectedFrames);
-
+
frameTweensInSegment = abs ( frameNrAtEndOfSegment
- p_calculate_relframe_nr_at_index(val_ptr, startOfSegmentIndex, affectedFrames)
) + 1;
@@ -978,6 +987,17 @@ p_calculate_settings_for_current_FrameTween(
pathSegmentLength = p_calculate_path_segment_length(val_ptr, startOfSegmentIndex, endOfSegmentIndex);
+ if(gap_debug)
+ {
+ printf("p_mov_execute:startOfSegmentIndex:%d accPosition:%d pathSegmentLength:%.4f currFrameIndex:%d\n"
+ ,(int)startOfSegmentIndex
+ ,(int)val_ptr->point[startOfSegmentIndex].accPosition
+ ,(float)pathSegmentLength
+ ,(int)currFrameIndex
+ );
+ }
+
+
/* calculate Movement settings for the currently processed Frame (or tween)
* position dependent acceleration processing requires a path segment length > 0
* AND accPosition != 0
@@ -997,7 +1017,6 @@ p_calculate_settings_for_current_FrameTween(
cur_ptr->currX = GAP_BASE_MIX_VALUE(posFactorMovement, (gdouble)val_ptr->point[segmPtidx].p_x, (gdouble)val_ptr->point[segmPtidx +1].p_x);
cur_ptr->currY = GAP_BASE_MIX_VALUE(posFactorMovement, (gdouble)val_ptr->point[segmPtidx].p_y, (gdouble)val_ptr->point[segmPtidx +1].p_y);
-
if(gap_debug)
{
printf("p_mov_execute: currFrameIndex:%d Position, start/endOfSegmentIndex=%d/%d currFrameTweenInSegment=%d frameTweensInSegment=%d\n"
@@ -1014,6 +1033,20 @@ p_calculate_settings_for_current_FrameTween(
, (float)posFactorMovement
, (int)segmPtidx
);
+ printf("p_mov_execute: p_x[%d]:%.4f p_x[%d]:%.4f currX:%.4f\n"
+ , (int)segmPtidx
+ , (float)val_ptr->point[segmPtidx].p_x
+ , (int)segmPtidx+1
+ , (float)val_ptr->point[segmPtidx +1].p_x
+ , (float)cur_ptr->currX
+ );
+ printf("p_mov_execute: p_y[%d]:%.4f p_y[%d]:%.4f currY:%.4f\n"
+ , (int)segmPtidx
+ , (float)val_ptr->point[segmPtidx].p_y
+ , (int)segmPtidx+1
+ , (float)val_ptr->point[segmPtidx +1].p_y
+ , (float)cur_ptr->currY
+ );
}
}
else
@@ -1033,6 +1066,69 @@ p_calculate_settings_for_current_FrameTween(
}
+ /* for the query mode calculate max speed in the query segment */
+ if(mov_query != NULL)
+ {
+ gdouble dx;
+ gdouble dy;
+ gdouble pixelLengthInOneTweenStep;
+ gint refPtidx; /* index to controlpoint that marks end of current line */
+
+ dx = fabs(cur_ptr->currX - prevX);
+ dy = fabs(cur_ptr->currY - prevY);
+ pixelLengthInOneTweenStep = sqrt((dx * dx) + (dy * dy));
+
+ refPtidx = currPtidx;
+ if (segmPtidx >= 0)
+ {
+ refPtidx = segmPtidx +1;
+ }
+
+ if(gap_debug)
+ {
+ printf("p_mov_execute: pixelLengthInOneTweenStep=%f pointIndexToQuery:%d currPtidx:%d refPtidx:%d StartQuery:%d EndQuery:%d\n"
+ , (float)pixelLengthInOneTweenStep
+ , (int)mov_query->pointIndexToQuery
+ , (int)currPtidx
+ , (int)refPtidx
+ , (int)mov_query->startOfSegmentIndexToQuery
+ , (int)mov_query->endOfSegmentIndexToQuery
+ );
+ }
+
+ if((refPtidx > mov_query->startOfSegmentIndexToQuery)
+ && (refPtidx <= mov_query->endOfSegmentIndexToQuery))
+ {
+ if(mov_query->tweenCount == 0)
+ {
+ mov_query->tweenCount++;
+ if(gap_debug)
+ {
+ printf("p_mov_execute: SKIP max speed calculation at first frame of segment\n");
+ }
+ }
+ else
+ {
+ mov_query->maxSpeedInPixelsPerFrame = MAX(mov_query->maxSpeedInPixelsPerFrame, pixelLengthInOneTweenStep);
+ if (mov_query->minSpeedInPixelsPerFrame < 0)
+ {
+ mov_query->minSpeedInPixelsPerFrame = pixelLengthInOneTweenStep;
+ }
+ else
+ {
+ mov_query->minSpeedInPixelsPerFrame = MIN(mov_query->minSpeedInPixelsPerFrame, pixelLengthInOneTweenStep);
+ }
+ }
+ mov_query->pathSegmentLengthInPixels = pathSegmentLength;
+ }
+
+
+
+ }
+
+
+
+
/* calculate Opacity settings for the currently processed Frame (or tween) */
if ((val_ptr->point[startOfSegmentIndex].accOpacity != 0)
&& (frameTweensInSegment > 0))
@@ -1208,7 +1304,7 @@ p_calculate_settings_for_current_FrameTween(
/* ============================================================================
- * p_mov_execute
+ * 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.
@@ -1219,7 +1315,7 @@ p_calculate_settings_for_current_FrameTween(
* ============================================================================
*/
long
-p_mov_execute(GapMovData *mov_ptr)
+p_mov_execute_or_query(GapMovData *mov_ptr, GapMovQuery *mov_query)
{
gint l_idx;
GapMovCurrent l_current_data;
@@ -1259,7 +1355,9 @@ p_mov_execute(GapMovData *mov_ptr)
frameNrAtEndOfSegment = 0;
l_apv_layerstack = 0;
l_percentage = 0.0;
- if(mov_ptr->dst_ainfo_ptr->run_mode == GIMP_RUN_INTERACTIVE)
+
+ if((mov_ptr->dst_ainfo_ptr->run_mode == GIMP_RUN_INTERACTIVE)
+ && (mov_query == NULL))
{
if(mov_ptr->val_ptr->apv_mlayer_image < 0)
{
@@ -1328,9 +1426,12 @@ p_mov_execute(GapMovData *mov_ptr)
cur_ptr = &l_current_data;
val_ptr = mov_ptr->val_ptr;
- if(gap_image_is_alive(val_ptr->tmpsel_image_id))
+ if(mov_query == NULL)
{
- gimp_image_delete(val_ptr->tmpsel_image_id);
+ if(gap_image_is_alive(val_ptr->tmpsel_image_id))
+ {
+ gimp_image_delete(val_ptr->tmpsel_image_id);
+ }
}
val_ptr->tmpsel_image_id = -1;
@@ -1400,66 +1501,69 @@ p_mov_execute(GapMovData *mov_ptr)
cur_ptr->dst_frame_nr = val_ptr->dst_range_start;
cur_ptr->src_layers = NULL;
-
- if(mov_ptr->val_ptr->src_stepmode < GAP_STEP_FRAME)
+
+ if(mov_query == NULL)
{
- gint32 l_sel_channel_id;
- gboolean l_all_empty;
-
- if(val_ptr->src_selmode != GAP_MOV_SEL_IGNORE)
+ if(mov_ptr->val_ptr->src_stepmode < GAP_STEP_FRAME)
{
- l_all_empty = FALSE;
- if(gimp_selection_is_empty(val_ptr->src_image_id))
+ gint32 l_sel_channel_id;
+ gboolean l_all_empty;
+
+ if(val_ptr->src_selmode != GAP_MOV_SEL_IGNORE)
{
- l_all_empty = TRUE;
+ l_all_empty = FALSE;
+ if(gimp_selection_is_empty(val_ptr->src_image_id))
+ {
+ l_all_empty = TRUE;
+ }
+ l_sel_channel_id = gimp_image_get_selection(val_ptr->src_image_id);
+ gap_mov_render_create_or_replace_tempsel_image(l_sel_channel_id, val_ptr, l_all_empty);
}
- l_sel_channel_id = gimp_image_get_selection(val_ptr->src_image_id);
- gap_mov_render_create_or_replace_tempsel_image(l_sel_channel_id, val_ptr, l_all_empty);
- }
- cur_ptr->src_layers = gimp_image_get_layers (val_ptr->src_image_id, &l_nlayers);
- if(cur_ptr->src_layers == NULL)
- {
- printf("ERROR (in p_mov_execute): Got no layers from SrcImage\n");
- return -1;
+ cur_ptr->src_layers = gimp_image_get_layers (val_ptr->src_image_id, &l_nlayers);
+ if(cur_ptr->src_layers == NULL)
+ {
+ printf("ERROR (in p_mov_execute): Got no layers from SrcImage\n");
+ return -1;
+ }
+ if(l_nlayers < 1)
+ {
+ printf("ERROR (in p_mov_execute): Source Image has no layers\n");
+ return -1;
+ }
+ cur_ptr->src_last_layer = l_nlayers -1;
+
+ /* findout index of src_layer_id */
+ for(cur_ptr->src_layer_idx = 0;
+ cur_ptr->src_layer_idx < l_nlayers;
+ cur_ptr->src_layer_idx++)
+ {
+ if(cur_ptr->src_layers[cur_ptr->src_layer_idx] == val_ptr->src_layer_id)
+ {
+ cur_ptr->src_layer_idx_dbl = (gdouble)cur_ptr->src_layer_idx;
+ break;
+ }
+ }
+ cur_ptr->src_last_layer = l_nlayers -1; /* index of last layer */
}
- if(l_nlayers < 1)
+ else
{
- printf("ERROR (in p_mov_execute): Source Image has no layers\n");
- return -1;
- }
- cur_ptr->src_last_layer = l_nlayers -1;
+ /* for FRAME stepmodes we use flattened Sorce frames
+ * (instead of one multilayer source image )
+ */
+ gap_mov_render_fetch_src_frame (val_ptr, -1); /* negative value fetches the selected frame number */
+ cur_ptr->src_frame_idx = val_ptr->cache_ainfo_ptr->curr_frame_nr;
+ cur_ptr->src_frame_idx_dbl = (gdouble)cur_ptr->src_frame_idx;
- /* findout index of src_layer_id */
- for(cur_ptr->src_layer_idx = 0;
- cur_ptr->src_layer_idx < l_nlayers;
- cur_ptr->src_layer_idx++)
- {
- if(cur_ptr->src_layers[cur_ptr->src_layer_idx] == val_ptr->src_layer_id)
- {
- cur_ptr->src_layer_idx_dbl = (gdouble)cur_ptr->src_layer_idx;
- break;
- }
- }
- cur_ptr->src_last_layer = l_nlayers -1; /* index of last layer */
- }
- else
- {
- /* for FRAME stepmodes we use flattened Sorce frames
- * (instead of one multilayer source image )
- */
- gap_mov_render_fetch_src_frame (val_ptr, -1); /* negative value fetches the selected frame number */
- cur_ptr->src_frame_idx = val_ptr->cache_ainfo_ptr->curr_frame_nr;
- cur_ptr->src_frame_idx_dbl = (gdouble)cur_ptr->src_frame_idx;
+ if((val_ptr->cache_ainfo_ptr->first_frame_nr < 0)
+ && (val_ptr->src_stepmode != GAP_STEP_FRAME_NONE))
+ {
+ gap_lib_dir_ainfo(val_ptr->cache_ainfo_ptr);
+ }
- if((val_ptr->cache_ainfo_ptr->first_frame_nr < 0)
- && (val_ptr->src_stepmode != GAP_STEP_FRAME_NONE))
- {
- gap_lib_dir_ainfo(val_ptr->cache_ainfo_ptr);
+ /* set offsets (in cur_ptr) according to handle mode and cache_tmp_img dimension */
+ gap_mov_exec_set_handle_offsets(val_ptr, cur_ptr);
}
-
- /* set offsets (in cur_ptr) according to handle mode and cache_tmp_img dimension */
- gap_mov_exec_set_handle_offsets(val_ptr, cur_ptr);
}
cur_ptr->currX = (gdouble)val_ptr->point[0].p_x;
@@ -1493,6 +1597,7 @@ p_mov_execute(GapMovData *mov_ptr)
val_ptr->trace_layer_id = -1;
/* create temp images for tween processing and object tracing */
+ if(mov_query == NULL)
{
gint32 master_image_id;
@@ -1582,12 +1687,39 @@ p_mov_execute(GapMovData *mov_ptr)
l_flt_count += l_fpl;
l_flt_timing[l_ptidx] = l_flt_count;
- if(l_fpl < 1.0)
+ if((l_fpl < 1.0) && (mov_query == NULL))
{
printf("p_mov_execute: ** Error frames per line at point[%d] = %f (is less than 1.0 !!)\n",
(int)l_ptidx, (float)l_fpl);
}
}
+
+ /* in query mode: find start end end of segment that contains the pointIndexToQuery */
+ if(mov_query != NULL)
+ {
+ mov_query->tweenCount = 0;
+ mov_query->startOfSegmentIndexToQuery = 0;
+ mov_query->endOfSegmentIndexToQuery = l_points - 1;
+ for(l_ptidx=1; l_ptidx < l_points - 1; l_ptidx++)
+ {
+ if (val_ptr->point[l_ptidx].keyframe > 0)
+ {
+ if (l_ptidx <= mov_query->pointIndexToQuery)
+ {
+ mov_query->segmentNumber++;
+ mov_query->startOfSegmentIndexToQuery = l_ptidx;
+ }
+
+ if (l_ptidx > mov_query->pointIndexToQuery)
+ {
+ mov_query->endOfSegmentIndexToQuery = l_ptidx;
+ break;
+ }
+ }
+
+ }
+
+ }
if(gap_debug)
{
@@ -1611,26 +1743,46 @@ p_mov_execute(GapMovData *mov_ptr)
if(gap_debug) printf("\np_mov_execute: 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(l_rc != 0) break;
+ 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: advance to controlpoint l_ptidx=%d, l_flt_timing[l_ptidx]=%f\n"
- , (int)l_ptidx, (float)l_flt_timing[l_ptidx]);
+ printf("p_mov_execute: 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: ** ERROR overflow l_ptidx=%d\n", (int)l_ptidx);
+ if(gap_debug)
+ {
+ printf("p_mov_execute: ** ERROR overflow l_ptidx=%d\n", (int)l_ptidx);
+ }
}
}
@@ -1661,7 +1813,8 @@ p_mov_execute(GapMovData *mov_ptr)
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
@@ -1671,33 +1824,55 @@ p_mov_execute(GapMovData *mov_ptr)
, l_points
, startOfSegmentIndex
, endOfSegmentIndex
+ , mov_query
);
-
- if(val_ptr->src_stepmode < GAP_STEP_FRAME )
+
+ if(mov_query != NULL)
{
- /* advance settings for next src layer */
- p_mov_advance_src_layer(cur_ptr, val_ptr);
+ /* we run in query mode, just check if controlpoint for query is reached
+ * and stop (without rendering)
+ */
+ 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);
+ }
}
else
{
- /* advance settings for next source frame */
- p_mov_advance_src_frame(cur_ptr, val_ptr);
- }
+ if(val_ptr->src_stepmode < GAP_STEP_FRAME )
+ {
+ /* advance settings for next src layer */
+ p_mov_advance_src_layer(cur_ptr, val_ptr);
+ }
+ else
+ {
+ /* advance settings for next source frame */
+ p_mov_advance_src_frame(cur_ptr, val_ptr);
+ }
- 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(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++;
+ }
+ /* RENDER add current src_layer to current frame */
+ l_rc = p_mov_call_render(mov_ptr, cur_ptr, l_apv_layerstack);
}
- /* RENDER add current src_layer to current frame */
- l_rc = p_mov_call_render(mov_ptr, cur_ptr, l_apv_layerstack);
} /* end tweenindex subloop */
@@ -1708,7 +1883,8 @@ p_mov_execute(GapMovData *mov_ptr)
}
/* show progress */
- if(mov_ptr->dst_ainfo_ptr->run_mode == GIMP_RUN_INTERACTIVE)
+ 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);
@@ -1716,24 +1892,27 @@ p_mov_execute(GapMovData *mov_ptr)
} /* end frameindex loop */
- /* delete the tween image */
- if(val_ptr->tween_image_id >= 0)
+ if(mov_query == NULL)
{
- gimp_image_delete(val_ptr->tween_image_id);
- val_ptr->tween_image_id = -1;
- }
+ /* delete the tween image */
+ if(val_ptr->tween_image_id >= 0)
+ {
+ gimp_image_delete(val_ptr->tween_image_id);
+ val_ptr->tween_image_id = -1;
+ }
- /* delete the trace image */
- if(val_ptr->trace_image_id >= 0)
- {
- gimp_image_delete(val_ptr->trace_image_id);
- val_ptr->trace_image_id = -1;
- }
+ /* delete the trace image */
+ if(val_ptr->trace_image_id >= 0)
+ {
+ gimp_image_delete(val_ptr->trace_image_id);
+ val_ptr->trace_image_id = -1;
+ }
- /* delete the temp selection image */
- if(gap_image_is_alive(val_ptr->tmpsel_image_id))
- {
- gimp_image_delete(val_ptr->tmpsel_image_id);
+ /* 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;
@@ -1746,7 +1925,29 @@ p_mov_execute(GapMovData *mov_ptr)
return l_rc;
-} /* end p_mov_execute */
+} /* 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.
+ * ============================================================================
+ */
+static long
+p_mov_execute(GapMovData *mov_ptr)
+{
+ GapMovQuery *mov_query;
+
+ mov_query = NULL;
+ return(p_mov_execute_or_query(mov_ptr, mov_query));
+}
+
+
/* ============================================================================
@@ -2828,6 +3029,56 @@ gap_mov_exec_move_path(GimpRunMode run_mode, gint32 image_id, GapMovValues *pval
} /* end gap_mov_exec_move_path */
+
+
+/* ============================================================================
+ * gap_mov_exec_query
+ *
+ * fill information of the mov_query struct.
+ * ============================================================================
+ */
+void
+gap_mov_exec_query(GapMovValues *val_ptr, GapAnimInfo *ainfo_ptr, GapMovQuery *mov_query)
+{
+ GapMovData l_mov_data;
+ GapMovData *l_mov_ptr;
+ GapMovValues l_mov_vals;
+ GapMovValues *l_pvals;
+
+ l_mov_ptr = &l_mov_data;
+ l_pvals = &l_mov_vals;
+
+ if((mov_query != NULL) && (val_ptr != NULL))
+ {
+ /* init query results */
+ mov_query->pathSegmentLengthInPixels = 0.0;
+ mov_query->maxSpeedInPixelsPerFrame = 0.0;
+ mov_query->minSpeedInPixelsPerFrame = -1.0;
+ mov_query->segmentNumber = 0;
+ /* copy settings */
+ memcpy(l_pvals, val_ptr, sizeof(GapMovValues));
+ l_mov_ptr->val_ptr = l_pvals;
+ l_mov_ptr->dst_ainfo_ptr = ainfo_ptr;
+
+ /* init local cached src image for anim preview generation.
+ * (never mix cached src image for normal and anim preview
+ * because anim previews are often scaled down)
+ */
+ l_pvals->cache_src_image_id = -1;
+ l_pvals->cache_tmp_image_id = -1;
+ 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)
+ {
+ mov_query->minSpeedInPixelsPerFrame = -1.0;
+ }
+ }
+}
+
+
/* ============================================================================
* gap_mov_exec_set_handle_offsets
* set handle offsets according to handle mode and src image dimensions
diff --git a/gap/gap_mov_exec.h b/gap/gap_mov_exec.h
index dcc2338..81dca03 100644
--- a/gap/gap_mov_exec.h
+++ b/gap/gap_mov_exec.h
@@ -51,6 +51,7 @@ gint gap_mov_exec_gap_save_pointfile(char *filename, GapMovValues *pvals);
gint gap_mov_exec_gap_load_pointfile(char *filename, GapMovValues *pvals);
void gap_mov_exec_calculate_rotate_follow(GapMovValues *pvals, gdouble startangle);
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);
#endif
diff --git a/gap/gap_mov_render.c b/gap/gap_mov_render.c
index b792db9..4d594d0 100644
--- a/gap/gap_mov_render.c
+++ b/gap/gap_mov_render.c
@@ -369,7 +369,9 @@ gap_mov_render_render(gint32 image_id, GapMovValues *val_ptr, GapMovCurrent *cur
guint l_image_height;
GimpLayerModeEffects l_mode;
- if(gap_debug) printf("gap_mov_render_render: frame/layer: %ld/%ld X=%f, Y=%f\n"
+ 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",
@@ -382,7 +384,8 @@ gap_mov_render_render(gint32 image_id, GapMovValues *val_ptr, GapMovCurrent *cur
val_ptr->clip_to_img,
val_ptr->src_force_visible,
val_ptr->src_stepmode);
-
+ }
+
if(val_ptr->src_stepmode < GAP_STEP_FRAME)
{
if(gap_debug)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]