Example #1
0
static short selmap_build_bezier_more(KeyframeEditData *ked, BezTriple *bezt)
{
	FCurve *fcu = ked->fcu;
	char *map = ked->data;
	int i = ked->curIndex;
	
	/* if current is selected, just make sure it stays this way */
	if (BEZT_ISSEL_ANY(bezt)) {
		map[i] = 1;
		return 0;
	}
	
	/* if previous is selected, that means that selection should extend across */
	if (i > 0) {
		BezTriple *prev = bezt - 1;
		
		if (BEZT_ISSEL_ANY(prev)) {
			map[i] = 1;
			return 0;
		}
	}
	
	/* if next is selected, that means that selection should extend across */
	if (i < (fcu->totvert - 1)) {
		BezTriple *next = bezt + 1;
		
		if (BEZT_ISSEL_ANY(next)) {
			map[i] = 1;
			return 0;
		}
	}
	
	return 0;
}
Example #2
0
// TODO: should we return if we hit something?
static void nearest_fcurve_vert_store(
        ListBase *matches, View2D *v2d, FCurve *fcu, eAnim_ChannelType ctype,
        BezTriple *bezt, FPoint *fpt, short hpoint, const int mval[2], float unit_scale, float offset)
{
	/* Keyframes or Samples? */
	if (bezt) {
		int screen_co[2], dist;
		
		/* convert from data-space to screen coordinates 
		 * NOTE: hpoint+1 gives us 0,1,2 respectively for each handle, 
		 *  needed to access the relevant vertex coordinates in the 3x3
		 *  'vec' matrix
		 */
		if (UI_view2d_view_to_region_clip(v2d,
		                                  bezt->vec[hpoint + 1][0], (bezt->vec[hpoint + 1][1] + offset) * unit_scale,
		                                  &screen_co[0], &screen_co[1]) &&
		    /* check if distance from mouse cursor to vert in screen space is within tolerance */
		    ((dist = len_v2v2_int(mval, screen_co)) <= GVERTSEL_TOL))
		{
			tNearestVertInfo *nvi = (tNearestVertInfo *)matches->last;
			bool replace = false;
			
			/* if there is already a point for the F-Curve, check if this point is closer than that was */
			if ((nvi) && (nvi->fcu == fcu)) {
				/* replace if we are closer, or if equal and that one wasn't selected but we are... */
				if ((nvi->dist > dist) || ((nvi->sel == 0) && BEZT_ISSEL_ANY(bezt)))
					replace = 1;
			}
			/* add new if not replacing... */
			if (replace == 0)
				nvi = MEM_callocN(sizeof(tNearestVertInfo), "Nearest Graph Vert Info - Bezt");
			
			/* store values */
			nvi->fcu = fcu;
			nvi->ctype = ctype;
			
			nvi->bezt = bezt;
			nvi->hpoint = hpoint;
			nvi->dist = dist;
			
			nvi->sel = BEZT_ISSEL_ANY(bezt); // XXX... should this use the individual verts instead?
			
			/* add to list of matches if appropriate... */
			if (replace == 0)
				BLI_addtail(matches, nvi);
		}
	}
	else if (fpt) {
		/* TODO... */
	}
}
Example #3
0
/* Create a ActKeyColumn for a pair of BezTriples */
static ActKeyBlock *bezts_to_new_actkeyblock(BezTriple *prev, BezTriple *beztn)
{
	ActKeyBlock *ab = MEM_callocN(sizeof(ActKeyBlock), "ActKeyBlock");

	ab->start = prev->vec[1][0];
	ab->end = beztn->vec[1][0];
	ab->val = beztn->vec[1][1];

	ab->sel = (BEZT_ISSEL_ANY(prev) || BEZT_ISSEL_ANY(beztn)) ? SELECT : 0;
	ab->modified = 1;

	if (BEZKEYTYPE(beztn) == BEZT_KEYTYPE_MOVEHOLD)
		ab->flag |= ACTKEYBLOCK_FLAG_MOVING_HOLD;

	return ab;
}
Example #4
0
/* get 'active' keyframe for panel editing */
static short get_active_fcurve_keyframe_edit(FCurve *fcu, BezTriple **bezt, BezTriple **prevbezt)
{
	BezTriple *b;
	int i;
	
	/* zero the pointers */
	*bezt = *prevbezt = NULL;
	
	/* sanity checks */
	if ((fcu->bezt == NULL) || (fcu->totvert == 0))
		return 0;
		
	/* find first selected keyframe for now, and call it the active one 
	 *	- this is a reasonable assumption, given that whenever anyone 
	 *	  wants to edit numerically, there is likely to only be 1 vert selected
	 */
	for (i = 0, b = fcu->bezt; i < fcu->totvert; i++, b++) {
		if (BEZT_ISSEL_ANY(b)) {
			/* found 
			 *	- 'previous' is either the one before, of the keyframe itself (which is still fine)
			 *		XXX: we can just make this null instead if needed
			 */
			*prevbezt = (i > 0) ? b - 1 : b;
			*bezt = b;
			
			return 1;
		}
	}
	
	/* not found */
	return 0;
}
Example #5
0
static int paintcurve_delete_point_exec(bContext *C, wmOperator *op)
{
	Paint *p = BKE_paint_get_active_from_context(C);
	Brush *br = p->brush;
	PaintCurve *pc;
	PaintCurvePoint *pcp;
	wmWindow *window = CTX_wm_window(C);
	ARegion *ar = CTX_wm_region(C);
	int i;
	int tot_del = 0;
	pc = br->paint_curve;

	if (!pc || pc->tot_points == 0) {
		return OPERATOR_CANCELLED;
	}

	ED_paintcurve_undo_push(C, op, pc);

#define DELETE_TAG 2

	for (i = 0, pcp = pc->points; i < pc->tot_points; i++, pcp++) {
		if (BEZT_ISSEL_ANY(&pcp->bez)) {
			pcp->bez.f2 |= DELETE_TAG;
			tot_del++;
		}
	}

	if (tot_del > 0) {
		int j = 0;
		int new_tot = pc->tot_points - tot_del;
		PaintCurvePoint *points_new = NULL;
		if (new_tot > 0)
			points_new = MEM_mallocN(new_tot * sizeof(PaintCurvePoint), "PaintCurvePoint");

		for (i = 0, pcp = pc->points; i < pc->tot_points; i++, pcp++) {
			if (!(pcp->bez.f2 & DELETE_TAG)) {
				points_new[j] = pc->points[i];

				if ((i + 1) == pc->add_index) {
					BKE_paint_curve_clamp_endpoint_add_index(pc, j);
				}
				j++;
			}
			else if ((i + 1) == pc->add_index) {
				/* prefer previous point */
				pc->add_index = j;
			}
		}
		MEM_freeN(pc->points);

		pc->points = points_new;
		pc->tot_points = new_tot;
	}

#undef DELETE_TAG

	WM_paint_cursor_tag_redraw(window, ar);

	return OPERATOR_FINISHED;
}
Example #6
0
static short ok_bezier_selected(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
{
	/* this macro checks all beztriple handles for selection... 
	 * only one of the verts has to be selected for this to be ok...
	 */
	if (BEZT_ISSEL_ANY(bezt))
		return KEYFRAME_OK_ALL;
	else
		return 0;
}
Example #7
0
static short selmap_build_bezier_less(KeyframeEditData *ked, BezTriple *bezt)
{
	FCurve *fcu = ked->fcu;
	char *map = ked->data;
	int i = ked->curIndex;
	
	/* if current is selected, check the left/right keyframes
	 * since it might need to be deselected (but otherwise no)
	 */
	if (BEZT_ISSEL_ANY(bezt)) {
		/* if previous is not selected, we're on the tip of an iceberg */
		if (i > 0) {
			BezTriple *prev = bezt - 1;
			
			if (BEZT_ISSEL_ANY(prev) == 0)
				return 0;
		}
		else if (i == 0) {
			/* current keyframe is selected at an endpoint, so should get deselected */
			return 0;
		}
		
		/* if next is not selected, we're on the tip of an iceberg */
		if (i < (fcu->totvert - 1)) {
			BezTriple *next = bezt + 1;
			
			if (BEZT_ISSEL_ANY(next) == 0)
				return 0;
		}
		else if (i == (fcu->totvert - 1)) {
			/* current keyframe is selected at an endpoint, so should get deselected */
			return 0;
		}
		
		/* if we're still here, that means that keyframe should remain untouched */
		map[i] = 1;
	}
	
	return 0;
}
Example #8
0
/* Node updater callback used for building ActKeyColumns from BezTriples */
static void nupdate_ak_bezt(void *node, void *data)
{
	ActKeyColumn *ak = (ActKeyColumn *)node;
	BezTriple *bezt = (BezTriple *)data;

	/* set selection status and 'touched' status */
	if (BEZT_ISSEL_ANY(bezt)) ak->sel = SELECT;
	ak->modified += 1;

	/* for keyframe type, 'proper' keyframes have priority over breakdowns (and other types for now) */
	if (BEZKEYTYPE(bezt) == BEZT_KEYTYPE_KEYFRAME)
		ak->key_type = BEZT_KEYTYPE_KEYFRAME;
}
Example #9
0
/* New node callback used for building ActKeyColumns from BezTriples */
static DLRBT_Node *nalloc_ak_bezt(void *data)
{
	ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumn");
	BezTriple *bezt = (BezTriple *)data;

	/* store settings based on state of BezTriple */
	ak->cfra = bezt->vec[1][0];
	ak->sel = BEZT_ISSEL_ANY(bezt) ? SELECT : 0;
	ak->key_type = BEZKEYTYPE(bezt);

	/* set 'modified', since this is used to identify long keyframes */
	ak->modified = 1;

	return (DLRBT_Node *)ak;
}
Example #10
0
/* helper func - draw handle vertices only for an F-Curve (if it is not protected) */
static void draw_fcurve_vertices_handles(FCurve *fcu, SpaceIpo *sipo, View2D *v2d, short sel, short sel_handle_only, float units_scale)
{
	BezTriple *bezt = fcu->bezt;
	BezTriple *prevbezt = NULL;
	float hsize, xscale, yscale;
	int i;
	
	/* get view settings */
	hsize = UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE) * U.pixelsize;
	UI_view2d_scale_get(v2d, &xscale, &yscale);

	/* Compensate OGL scale sued for unit mapping, so circle will be circle, not ellipse */
	yscale *= units_scale;
	
	/* set handle color */
	if (sel) UI_ThemeColor(TH_HANDLE_VERTEX_SELECT);
	else UI_ThemeColor(TH_HANDLE_VERTEX);
	
	/* anti-aliased lines for more consistent appearance */
	if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) glEnable(GL_LINE_SMOOTH);
	glEnable(GL_BLEND);
	
	for (i = 0; i < fcu->totvert; i++, prevbezt = bezt, bezt++) {
		/* Draw the editmode handles for a bezier curve (others don't have handles) 
		 * if their selection status matches the selection status we're drawing for
		 *	- first handle only if previous beztriple was bezier-mode
		 *	- second handle only if current beztriple is bezier-mode
		 *
		 * Also, need to take into account whether the keyframe was selected
		 * if a Graph Editor option to only show handles of selected keys is on.
		 */
		if (!sel_handle_only || BEZT_ISSEL_ANY(bezt)) {
			if ((!prevbezt && (bezt->ipo == BEZT_IPO_BEZ)) || (prevbezt && (prevbezt->ipo == BEZT_IPO_BEZ))) {
				if ((bezt->f1 & SELECT) == sel) /* && v2d->cur.xmin < bezt->vec[0][0] < v2d->cur.xmax)*/
					draw_fcurve_handle_control(bezt->vec[0][0], bezt->vec[0][1], xscale, yscale, hsize);
			}
			
			if (bezt->ipo == BEZT_IPO_BEZ) {
				if ((bezt->f3 & SELECT) == sel) /* && v2d->cur.xmin < bezt->vec[2][0] < v2d->cur.xmax)*/
					draw_fcurve_handle_control(bezt->vec[2][0], bezt->vec[2][1], xscale, yscale, hsize);
			}
		}
	}
	
	if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) glDisable(GL_LINE_SMOOTH);
	glDisable(GL_BLEND);
}
Example #11
0
static char paintcurve_point_side_index(const BezTriple *bezt, const bool is_first, const char fallback)
{
	/* when matching, guess based on endpoint side */
	if (BEZT_ISSEL_ANY(bezt)) {
		if ((bezt->f1 & SELECT) == (bezt->f3 & SELECT)) {
			return is_first ? SEL_F1 : SEL_F3;
		}
		else if (bezt->f1 & SELECT) {
			return SEL_F1;
		}
		else if (bezt->f3  & SELECT) {
			return SEL_F3;
		}
		else {
			return fallback;
		}
	}
	else {
		return 0;
	}
}
Example #12
0
static void add_bezt_to_keyblocks_list(DLRBT_Tree *blocks, BezTriple *first_bezt, BezTriple *beztn)
{
	ActKeyBlock *new_ab = NULL;
	BezTriple *prev = NULL;

	/* get the BezTriple immediately before the given one which has the same value */
	if (beztn != first_bezt) {
		/* XXX: Unless I'm overlooking some details from the past, this should be sufficient?
		 *      The old code did some elaborate stuff trying to find keyframe columns for
		 *      the given BezTriple, then step backwards to the column before that, and find
		 *      an appropriate BezTriple with matching values there. Maybe that was warranted
		 *      in the past, but now, that list is only ever filled with keyframes from the
		 *      current FCurve.
		 *
		 *      -- Aligorith (20140415)
		 */
		prev = beztn - 1;
	}


	/* check if block needed */
	if (prev == NULL) return;

	if (BEZKEYTYPE(beztn) == BEZT_KEYTYPE_MOVEHOLD) {
		/* Animator tagged a "moving hold"
		 *   - Previous key must also be tagged as a moving hold, otherwise
		 *     we're just dealing with the first of a pair, and we don't
		 *     want to be creating any phantom holds...
		 */
		if (BEZKEYTYPE(prev) != BEZT_KEYTYPE_MOVEHOLD)
			return;
	}
	else {
		/* Check for same values...
		 *  - Handles must have same central value as each other
		 *  - Handles which control that section of the curve must be constant
		 */
		if (IS_EQF(beztn->vec[1][1], prev->vec[1][1]) == 0) return;

		if (IS_EQF(beztn->vec[1][1], beztn->vec[0][1]) == 0) return;
		if (IS_EQF(prev->vec[1][1], prev->vec[2][1]) == 0) return;
	}

	/* if there are no blocks already, just add as root */
	if (blocks->root == NULL) {
		/* just add this as the root, then call the tree-balancing functions to validate */
		new_ab = bezts_to_new_actkeyblock(prev, beztn);
		blocks->root = (DLRBT_Node *)new_ab;
	}
	else {
		ActKeyBlock *ab, *abn = NULL;

		/* try to find a keyblock that starts on the previous beztriple, and add a new one if none start there
		 * Note: we perform a tree traversal here NOT a standard linked-list traversal...
		 * Note: we can't search from end to try to optimize this as it causes errors there's
		 *      an A ___ B |---| B situation
		 */
		// FIXME: here there is a bug where we are trying to get the summary for the following channels
		//		A|--------------|A ______________ B|--------------|B
		//		A|------------------------------------------------|A
		//		A|----|A|---|A|-----------------------------------|A
		for (ab = blocks->root; ab; ab = abn) {
			/* check if this is a match, or whether we go left or right
			 * NOTE: we now use a float threshold to prevent precision errors causing problems with summaries
			 */
			if (IS_EQT(ab->start, prev->vec[1][0], BEZT_BINARYSEARCH_THRESH)) {
				/* set selection status and 'touched' status */
				if (BEZT_ISSEL_ANY(beztn))
					ab->sel = SELECT;

				/* XXX: only when the first one was a moving hold? */
				if (BEZKEYTYPE(beztn) == BEZT_KEYTYPE_MOVEHOLD)
					ab->flag |= ACTKEYBLOCK_FLAG_MOVING_HOLD;

				ab->modified++;

				/* done... no need to insert */
				return;
			}
			else {
				ActKeyBlock **abnp = NULL; /* branch to go down - used to hook new blocks to parents */

				/* check if go left or right, but if not available, add new node */
				if (ab->start < prev->vec[1][0])
					abnp = &ab->right;
				else
					abnp = &ab->left;

				/* if this does not exist, add a new node, otherwise continue... */
				if (*abnp == NULL) {
					/* add a new node representing this, and attach it to the relevant place */
					new_ab = bezts_to_new_actkeyblock(prev, beztn);
					new_ab->parent = ab;
					*abnp = new_ab;
					break;
				}
				else
					abn = *abnp;
			}
		}
	}

	/* now, balance the tree taking into account this newly added node */
	BLI_dlrbTree_insert(blocks, (DLRBT_Node *)new_ab);
}
Example #13
0
/* Evaluates the curves between each selected keyframe on each frame, and keys the value  */
void sample_fcurve(FCurve *fcu)
{
	BezTriple *bezt, *start = NULL, *end = NULL;
	TempFrameValCache *value_cache, *fp;
	int sfra, range;
	int i, n, nIndex;

	if (fcu->bezt == NULL) /* ignore baked */
		return;
	
	/* find selected keyframes... once pair has been found, add keyframes  */
	for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
		/* check if selected, and which end this is */
		if (BEZT_ISSEL_ANY(bezt)) {
			if (start) {
				/* set end */
				end = bezt;
				
				/* cache values then add keyframes using these values, as adding
				 * keyframes while sampling will affect the outcome...
				 *	- only start sampling+adding from index=1, so that we don't overwrite original keyframe
				 */
				range = (int)(ceil(end->vec[1][0] - start->vec[1][0]));
				sfra = (int)(floor(start->vec[1][0]));
				
				if (range) {
					value_cache = MEM_callocN(sizeof(TempFrameValCache) * range, "IcuFrameValCache");
					
					/* sample values */
					for (n = 1, fp = value_cache; n < range && fp; n++, fp++) {
						fp->frame = (float)(sfra + n);
						fp->val = evaluate_fcurve(fcu, fp->frame);
					}
					
					/* add keyframes with these, tagging as 'breakdowns' */
					for (n = 1, fp = value_cache; n < range && fp; n++, fp++) {
						nIndex = insert_vert_fcurve(fcu, fp->frame, fp->val, 1);
						BEZKEYTYPE(fcu->bezt + nIndex) = BEZT_KEYTYPE_BREAKDOWN;
					}
					
					/* free temp cache */
					MEM_freeN(value_cache);
					
					/* as we added keyframes, we need to compensate so that bezt is at the right place */
					bezt = fcu->bezt + i + range - 1;
					i += (range - 1);
				}
				
				/* bezt was selected, so it now marks the start of a whole new chain to search */
				start = bezt;
				end = NULL;
			}
			else {
				/* just set start keyframe */
				start = bezt;
				end = NULL;
			}
		}
	}
	
	/* recalculate channel's handles? */
	calchandles_fcurve(fcu);
}
Example #14
0
/* option 1) select keyframe directly under mouse */
static void mouse_graph_keys(bAnimContext *ac, const int mval[2], short select_mode, short curves_only)
{
	SpaceIpo *sipo = (SpaceIpo *)ac->sl;
	tNearestVertInfo *nvi;
	BezTriple *bezt = NULL;
	
	/* find the beztriple that we're selecting, and the handle that was clicked on */
	nvi = find_nearest_fcurve_vert(ac, mval);
	
	/* check if anything to select */
	if (nvi == NULL)
		return;
	
	/* deselect all other curves? */
	if (select_mode == SELECT_REPLACE) {
		/* reset selection mode */
		select_mode = SELECT_ADD;
		
		/* deselect all other keyframes (+ F-Curves too) */
		deselect_graph_keys(ac, 0, SELECT_SUBTRACT, true);
		
		/* deselect other channels too, but only only do this if 
		 * selection of channel when the visibility of keyframes 
		 * doesn't depend on this 
		 */
		if ((sipo->flag & SIPO_SELCUVERTSONLY) == 0)
			ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
	}
	
	/* if points can be selected on this F-Curve */
	// TODO: what about those with no keyframes?
	if ((curves_only == 0) && ((nvi->fcu->flag & FCURVE_PROTECTED) == 0)) {
		/* only if there's keyframe */
		if (nvi->bezt) {
			bezt = nvi->bezt; /* used to check bezt seletion is set */
			/* depends on selection mode */
			if (select_mode == SELECT_INVERT) {
				/* keyframe - invert select of all */
				if (nvi->hpoint == NEAREST_HANDLE_KEY) {
					if (BEZT_ISSEL_ANY(bezt)) {
						BEZT_DESEL_ALL(bezt);
					}
					else {
						BEZT_SEL_ALL(bezt);
					}
				}
				
				/* handles - toggle selection of relevant handle */
				else if (nvi->hpoint == NEAREST_HANDLE_LEFT) {
					/* toggle selection */
					bezt->f1 ^= SELECT;
				}
				else {
					/* toggle selection */
					bezt->f3 ^= SELECT;
				}
			}
			else {
				/* if the keyframe was clicked on, select all verts of given beztriple */
				if (nvi->hpoint == NEAREST_HANDLE_KEY) {
					BEZT_SEL_ALL(bezt);
				}
				/* otherwise, select the handle that applied */
				else if (nvi->hpoint == NEAREST_HANDLE_LEFT) 
					bezt->f1 |= SELECT;
				else 
					bezt->f3 |= SELECT;
			}
		}
		else if (nvi->fpt) {
			// TODO: need to handle sample points
		}
	}
	else {
		KeyframeEditFunc select_cb;
		KeyframeEditData ked;
		
		/* initialize keyframe editing data */
		memset(&ked, 0, sizeof(KeyframeEditData));
		
		/* set up BezTriple edit callbacks */
		select_cb = ANIM_editkeyframes_select(select_mode);
		
		/* select all keyframes */
		ANIM_fcurve_keyframes_loop(&ked, nvi->fcu, NULL, select_cb, NULL);
	}
	
	/* only change selection of channel when the visibility of keyframes doesn't depend on this */
	if ((sipo->flag & SIPO_SELCUVERTSONLY) == 0) {
		/* select or deselect curve? */
		if (bezt) {
			/* take selection status from item that got hit, to prevent flip/flop on channel 
			 * selection status when shift-selecting (i.e. "SELECT_INVERT") points
			 */
			if (BEZT_ISSEL_ANY(bezt))
				nvi->fcu->flag |= FCURVE_SELECTED;
			else
				nvi->fcu->flag &= ~FCURVE_SELECTED;
		}
		else {
			/* didn't hit any channel, so just apply that selection mode to the curve's selection status */
			if (select_mode == SELECT_INVERT)
				nvi->fcu->flag ^= FCURVE_SELECTED;
			else if (select_mode == SELECT_ADD)
				nvi->fcu->flag |= FCURVE_SELECTED;
		}
	}

	/* set active F-Curve (NOTE: sync the filter flags with findnearest_fcurve_vert) */
	/* needs to be called with (sipo->flag & SIPO_SELCUVERTSONLY) otherwise the active flag won't be set [#26452] */
	if (nvi->fcu->flag & FCURVE_SELECTED) {
		int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
		ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, nvi->fcu, nvi->ctype);
	}

	/* free temp sample data for filtering */
	MEM_freeN(nvi);
}
Example #15
0
// XXX also need to check for int-values only?
static bool fcurve_handle_sel_check(SpaceIpo *sipo, BezTriple *bezt)
{
	if (sipo->flag & SIPO_NOHANDLES) return 0;
	if ((sipo->flag & SIPO_SELVHANDLESONLY) && BEZT_ISSEL_ANY(bezt) == 0) return 0;
	return 1;
}
Example #16
0
// TODO: introduce scaling factor for weighting falloff
void smooth_fcurve(FCurve *fcu)
{
	BezTriple *bezt;
	int i, x, totSel = 0;

	if (fcu->bezt == NULL) {
		return;
	}

	/* first loop through - count how many verts are selected */
	bezt = fcu->bezt;
	for (i = 0; i < fcu->totvert; i++, bezt++) {
		if (BEZT_ISSEL_ANY(bezt))
			totSel++;
	}
	
	/* if any points were selected, allocate tSmooth_Bezt points to work on */
	if (totSel >= 3) {
		tSmooth_Bezt *tarray, *tsb;
		
		/* allocate memory in one go */
		tsb = tarray = MEM_callocN(totSel * sizeof(tSmooth_Bezt), "tSmooth_Bezt Array");
		
		/* populate tarray with data of selected points */
		bezt = fcu->bezt;
		for (i = 0, x = 0; (i < fcu->totvert) && (x < totSel); i++, bezt++) {
			if (BEZT_ISSEL_ANY(bezt)) {
				/* tsb simply needs pointer to vec, and index */
				tsb->h1 = &bezt->vec[0][1];
				tsb->h2 = &bezt->vec[1][1];
				tsb->h3 = &bezt->vec[2][1];
				
				/* advance to the next tsb to populate */
				if (x < totSel - 1)
					tsb++;
				else
					break;
			}
		}
			
		/* calculate the new smoothed F-Curve's with weighted averages:
		 *	- this is done with two passes to avoid progressive corruption errors
		 *	- uses 5 points for each operation (which stores in the relevant handles)
		 *	-   previous: w/a ratio = 3:5:2:1:1
		 *	-   next: w/a ratio = 1:1:2:5:3
		 */
		
		/* round 1: calculate smoothing deltas and new values */ 
		tsb = tarray;
		for (i = 0; i < totSel; i++, tsb++) {
			/* don't touch end points (otherwise, curves slowly explode, as we don't have enough data there) */
			if (ELEM(i, 0, (totSel - 1)) == 0) {
				const tSmooth_Bezt *tP1 = tsb - 1;
				const tSmooth_Bezt *tP2 = (i - 2 > 0) ? (tsb - 2) : (NULL);
				const tSmooth_Bezt *tN1 = tsb + 1;
				const tSmooth_Bezt *tN2 = (i + 2 < totSel) ? (tsb + 2) : (NULL);
				
				const float p1 = *tP1->h2;
				const float p2 = (tP2) ? (*tP2->h2) : (*tP1->h2);
				const float c1 = *tsb->h2;
				const float n1 = *tN1->h2;
				const float n2 = (tN2) ? (*tN2->h2) : (*tN1->h2);
				
				/* calculate previous and next, then new position by averaging these */
				tsb->y1 = (3 * p2 + 5 * p1 + 2 * c1 + n1 + n2) / 12;
				tsb->y3 = (p2 + p1 + 2 * c1 + 5 * n1 + 3 * n2) / 12;
				
				tsb->y2 = (tsb->y1 + tsb->y3) / 2;
			}
		}
		
		/* round 2: apply new values */
		tsb = tarray;
		for (i = 0; i < totSel; i++, tsb++) {
			/* don't touch end points, as their values weren't touched above */
			if (ELEM(i, 0, (totSel - 1)) == 0) {
				/* y2 takes the average of the 2 points */
				*tsb->h2 = tsb->y2;
				
				/* handles are weighted between their original values and the averaged values */
				*tsb->h1 = ((*tsb->h1) * 0.7f) + (tsb->y1 * 0.3f); 
				*tsb->h3 = ((*tsb->h3) * 0.7f) + (tsb->y3 * 0.3f);
			}
		}
		
		/* free memory required for tarray */
		MEM_freeN(tarray);
	}
	
	/* recalculate handles */
	calchandles_fcurve(fcu);
}
Example #17
0
/* draw lines for F-Curve handles only (this is only done in EditMode)
 * note: draw_fcurve_handles_check must be checked before running this. */
static void draw_fcurve_handles(SpaceIpo *sipo, FCurve *fcu)
{
	int sel, b;
	
	/* a single call to GL_LINES here around these calls should be sufficient to still
	 * get separate line segments, but which aren't wrapped with GL_LINE_STRIP every time we
	 * want a single line
	 */
	glBegin(GL_LINES);
	
	/* slightly hacky, but we want to draw unselected points before selected ones 
	 * so that selected points are clearly visible
	 */
	for (sel = 0; sel < 2; sel++) {
		BezTriple *bezt = fcu->bezt, *prevbezt = NULL;
		int basecol = (sel) ? TH_HANDLE_SEL_FREE : TH_HANDLE_FREE;
		const float *fp;
		unsigned char col[4];
		
		for (b = 0; b < fcu->totvert; b++, prevbezt = bezt, bezt++) {
			/* if only selected keyframes can get their handles shown, 
			 * check that keyframe is selected
			 */
			if (sipo->flag & SIPO_SELVHANDLESONLY) {
				if (BEZT_ISSEL_ANY(bezt) == 0)
					continue;
			}
			
			/* draw handle with appropriate set of colors if selection is ok */
			if ((bezt->f2 & SELECT) == sel) {
				fp = bezt->vec[0];
				
				/* only draw first handle if previous segment had handles */
				if ((!prevbezt && (bezt->ipo == BEZT_IPO_BEZ)) || (prevbezt && (prevbezt->ipo == BEZT_IPO_BEZ))) {
					UI_GetThemeColor3ubv(basecol + bezt->h1, col);
					col[3] = fcurve_display_alpha(fcu) * 255;
					glColor4ubv((GLubyte *)col);
					
					glVertex2fv(fp); glVertex2fv(fp + 3);
				}
				
				/* only draw second handle if this segment is bezier */
				if (bezt->ipo == BEZT_IPO_BEZ) {
					UI_GetThemeColor3ubv(basecol + bezt->h2, col);
					col[3] = fcurve_display_alpha(fcu) * 255;
					glColor4ubv((GLubyte *)col);
					
					glVertex2fv(fp + 3); glVertex2fv(fp + 6);
				}
			}
			else {
				/* only draw first handle if previous segment was had handles, and selection is ok */
				if (((bezt->f1 & SELECT) == sel) &&
				    ((!prevbezt && (bezt->ipo == BEZT_IPO_BEZ)) || (prevbezt && (prevbezt->ipo == BEZT_IPO_BEZ))))
				{
					fp = bezt->vec[0];
					UI_GetThemeColor3ubv(basecol + bezt->h1, col);
					col[3] = fcurve_display_alpha(fcu) * 255;
					glColor4ubv((GLubyte *)col);
					
					glVertex2fv(fp); glVertex2fv(fp + 3);
				}
				
				/* only draw second handle if this segment is bezier, and selection is ok */
				if (((bezt->f3 & SELECT) == sel) &&
				    (bezt->ipo == BEZT_IPO_BEZ))
				{
					fp = bezt->vec[1];
					UI_GetThemeColor3ubv(basecol + bezt->h2, col);
					col[3] = fcurve_display_alpha(fcu) * 255;
					glColor4ubv((GLubyte *)col);
					
					glVertex2fv(fp); glVertex2fv(fp + 3);
				}
			}
		}
	}
	
	glEnd();  /* GL_LINES */
}
Example #18
0
/* This function adds data to the keyframes copy/paste buffer, freeing existing data first */
short copy_animedit_keys(bAnimContext *ac, ListBase *anim_data)
{	
	bAnimListElem *ale;
	Scene *scene = ac->scene;
	
	/* clear buffer first */
	free_anim_copybuf();
	
	/* assume that each of these is an F-Curve */
	for (ale = anim_data->first; ale; ale = ale->next) {
		FCurve *fcu = (FCurve *)ale->key_data;
		tAnimCopybufItem *aci;
		BezTriple *bezt, *nbezt, *newbuf;
		int i;
		
		/* firstly, check if F-Curve has any selected keyframes
		 *	- skip if no selected keyframes found (so no need to create unnecessary copy-buffer data)
		 *	- this check should also eliminate any problems associated with using sample-data
		 */
		if (ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, ANIM_editkeyframes_ok(BEZT_OK_SELECTED), NULL) == 0)
			continue;
		
		/* init copybuf item info */
		aci = MEM_callocN(sizeof(tAnimCopybufItem), "AnimCopybufItem");
		aci->id = ale->id;
		aci->id_type = GS(ale->id->name);
		aci->grp = fcu->grp;
		aci->rna_path = MEM_dupallocN(fcu->rna_path);
		aci->array_index = fcu->array_index;
		
		/* detect if this is a bone. We do that here rather than during pasting because ID pointers will get invalidated if we undo.
		 * storing the relevant information here helps avoiding crashes if we undo-repaste */
		if ((aci->id_type == ID_OB) && (((Object *)aci->id)->type == OB_ARMATURE) && aci->rna_path) {
			Object *ob = (Object *)aci->id;
			bPoseChannel *pchan;
			char *bone_name;

			bone_name = BLI_str_quoted_substrN(aci->rna_path, "pose.bones[");
			pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
			if (pchan) {
				aci->is_bone = true;
			}
			if (bone_name) MEM_freeN(bone_name);
		}
		
		BLI_addtail(&animcopybuf, aci);
		
		/* add selected keyframes to buffer */
		/* TODO: currently, we resize array every time we add a new vert -
		 * this works ok as long as it is assumed only a few keys are copied */
		for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
			if (BEZT_ISSEL_ANY(bezt)) {
				/* add to buffer */
				newbuf = MEM_callocN(sizeof(BezTriple) * (aci->totvert + 1), "copybuf beztriple");
				
				/* assume that since we are just re-sizing the array, just copy all existing data across */
				if (aci->bezt)
					memcpy(newbuf, aci->bezt, sizeof(BezTriple) * (aci->totvert));
				
				/* copy current beztriple across too */
				nbezt = &newbuf[aci->totvert];
				*nbezt = *bezt;
				
				/* ensure copy buffer is selected so pasted keys are selected */
				BEZT_SEL_ALL(nbezt);
				
				/* free old array and set the new */
				if (aci->bezt) MEM_freeN(aci->bezt);
				aci->bezt = newbuf;
				aci->totvert++;
				
				/* check if this is the earliest frame encountered so far */
				if (bezt->vec[1][0] < animcopy_firstframe)
					animcopy_firstframe = bezt->vec[1][0];
				if (bezt->vec[1][0] > animcopy_lastframe)
					animcopy_lastframe = bezt->vec[1][0];
			}
		}
		
	}
	
	/* check if anything ended up in the buffer */
	if (ELEM(NULL, animcopybuf.first, animcopybuf.last))
		return -1;

	/* in case 'relative' paste method is used */
	animcopy_cfra = CFRA;

	/* everything went fine */
	return 0;
}
Example #19
0
/* propagate just works along each F-Curve in turn */
static void pose_propagate_fcurve(wmOperator *op, Object *ob, FCurve *fcu,
                                  float startFrame, tPosePropagate_ModeData modeData)
{
	const int mode = RNA_enum_get(op->ptr, "mode");
	
	BezTriple *bezt;
	float refVal = 0.0f;
	bool keyExists;
	int i, match;
	short first = 1;
	
	/* skip if no keyframes to edit */
	if ((fcu->bezt == NULL) || (fcu->totvert < 2))
		return;
		
	/* find the reference value from bones directly, which means that the user
	 * doesn't need to firstly keyframe the pose (though this doesn't mean that 
	 * they can't either)
	 */
	if (!pose_propagate_get_refVal(ob, fcu, &refVal))
		return;
	
	/* find the first keyframe to start propagating from 
	 *	- if there's a keyframe on the current frame, we probably want to save this value there too
	 *	  since it may be as of yet unkeyed
	 *  - if starting before the starting frame, don't touch the key, as it may have had some valid
	 *	  values
	 *  - if only doing selected keyframes, start from the first one
	 */
	if (mode != POSE_PROPAGATE_SELECTED_KEYS) {
		match = binarysearch_bezt_index(fcu->bezt, startFrame, fcu->totvert, &keyExists);
		
		if (fcu->bezt[match].vec[1][0] < startFrame)
			i = match + 1;
		else
			i = match;
	}
	else {
		/* selected - start from first keyframe */
		i = 0;
	}
	
	for (bezt = &fcu->bezt[i]; i < fcu->totvert; i++, bezt++) {
		/* additional termination conditions based on the operator 'mode' property go here... */
		if (ELEM(mode, POSE_PROPAGATE_BEFORE_FRAME, POSE_PROPAGATE_SMART_HOLDS)) {
			/* stop if keyframe is outside the accepted range */
			if (bezt->vec[1][0] > modeData.end_frame)
				break; 
		}
		else if (mode == POSE_PROPAGATE_NEXT_KEY) {
			/* stop after the first keyframe has been processed */
			if (first == 0)
				break;
		}
		else if (mode == POSE_PROPAGATE_LAST_KEY) {
			/* only affect this frame if it will be the last one */
			if (i != (fcu->totvert - 1))
				continue;
		}
		else if (mode == POSE_PROPAGATE_SELECTED_MARKERS) {
			/* only allow if there's a marker on this frame */
			CfraElem *ce = NULL;
			
			/* stop on matching marker if there is one */
			for (ce = modeData.sel_markers.first; ce; ce = ce->next) {
				if (ce->cfra == iroundf(bezt->vec[1][0]))
					break;
			}
			
			/* skip this keyframe if no marker */
			if (ce == NULL)
				continue;
		}
		else if (mode == POSE_PROPAGATE_SELECTED_KEYS) {
			/* only allow if this keyframe is already selected - skip otherwise */
			if (BEZT_ISSEL_ANY(bezt) == 0)
				continue;
		}
		
		/* just flatten handles, since values will now be the same either side... */
		/* TODO: perhaps a fade-out modulation of the value is required here (optional once again)? */
		bezt->vec[0][1] = bezt->vec[1][1] = bezt->vec[2][1] = refVal;
		
		/* select keyframe to indicate that it's been changed */
		bezt->f2 |= SELECT;
		first = 0;
	}
}