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 (BEZSELECTED(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 (BEZSELECTED(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 (BEZSELECTED(next)) {
			map[i] = 1;
			return 0;
		}
	}
	
	return 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 = (BEZSELECTED(prev) || BEZSELECTED(beztn)) ? SELECT : 0;
	ab->modified = 1;
	
	return ab;
}
Example #3
0
// TODO: should we return if we hit something?
static void nearest_fcurve_vert_store (ListBase *matches, View2D *v2d, FCurve *fcu, BezTriple *bezt, FPoint *fpt, short hpoint, int mval[2])
{
	/* 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
		 */
		UI_view2d_view_to_region(v2d, bezt->vec[hpoint+1][0], bezt->vec[hpoint+1][1], &screen_co[0], &screen_co[1]);
		
		/* check if distance from mouse cursor to vert in screen space is within tolerance */
			// XXX: inlined distance calculation, since we cannot do this on ints using the math lib...
		//dist = len_v2v2(mval, screen_co);
		dist = sqrt((mval[0] - screen_co[0])*(mval[0] - screen_co[0]) + 
					(mval[1] - screen_co[1])*(mval[1] - screen_co[1]));
		
		if (dist <= GVERTSEL_TOL) {
			tNearestVertInfo *nvi = (tNearestVertInfo *)matches->last;
			short replace = 0;
			
			/* 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) && BEZSELECTED(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->bezt = bezt;
			nvi->hpoint = hpoint;
			nvi->dist = dist;
			
			nvi->sel= BEZSELECTED(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 #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 (BEZSELECTED(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
/* 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;
	
	/* 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 (BEZSELECTED(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 #6
0
/* Add the given BezTriple to the given 'list' of Keyframes */
static void add_bezt_to_keycolumns_list(DLRBT_Tree *keys, BezTriple *bezt)
{
	ActKeyColumn *new_ak=NULL;
	
	if ELEM(NULL, keys, bezt) return;
	
	/* if there are no keys already, just add as root */
	if (keys->root == NULL) {
		/* just add this as the root, then call the tree-balancing functions to validate */
		new_ak= bezt_to_new_actkeycolumn(bezt);
		keys->root= (DLRBT_Node *)new_ak;
	}
	else {
		ActKeyColumn *ak, *akp=NULL, *akn=NULL;
		
		/* traverse tree to find an existing entry to update the status of, 
		 * or a suitable point to add at
		 */
		for (ak= keys->root; ak; akp= ak, ak= akn) {
			/* check if this is a match, or whether we go left or right */
			if (ak->cfra == bezt->vec[1][0]) {
				/* set selection status and 'touched' status */
				if (BEZSELECTED(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;
				
				/* done... no need to insert */
				return;
			}
			else {
				ActKeyColumn **aknp= NULL; 
				
				/* check if go left or right, but if not available, add new node */
				if (ak->cfra < bezt->vec[1][0]) 
					aknp= &ak->right;
				else
					aknp= &ak->left;
					
				/* if this does not exist, add a new node, otherwise continue... */
				if (*aknp == NULL) {
					/* add a new node representing this, and attach it to the relevant place */
					new_ak= bezt_to_new_actkeycolumn(bezt);
					new_ak->parent= ak;
					*aknp= new_ak;
					break;
				}
				else
					akn= *aknp;
			}
		}
	}
	
	/* now, balance the tree taking into account this newly added node */
	BLI_dlrbTree_insert(keys, (DLRBT_Node *)new_ak);
}
Example #7
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 (BEZSELECTED(bezt))
		return KEYFRAME_OK_ALL;
	else
		return 0;
}
Example #8
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 (BEZSELECTED(bezt)) {
		/* if previous is not selected, we're on the tip of an iceberg */
		if (i > 0) {
			BezTriple *prev = bezt - 1;
			
			if (BEZSELECTED(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 (BEZSELECTED(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;
}
/* 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 (BEZSELECTED(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 #10
0
/* Create a ActKeyColumn from a BezTriple */
static ActKeyColumn *bezt_to_new_actkeycolumn(BezTriple *bezt)
{
	ActKeyColumn *ak= MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumn");
	
	/* store settings based on state of BezTriple */
	ak->cfra= bezt->vec[1][0];
	ak->sel= BEZSELECTED(bezt) ? SELECT : 0;
	ak->key_type= BEZKEYTYPE(bezt); 
	
	/* set 'modified', since this is used to identify long keyframes */
	ak->modified = 1;
	
	return ak;
}
/* 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 = BEZSELECTED(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 #12
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_getscale(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 || BEZSELECTED(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 #13
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;
		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 (BEZSELECTED(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 */
				BEZ_SEL(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 #14
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 (BEZSELECTED(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 (BEZSELECTED(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 were'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 #15
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;
		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 (BEZSELECTED(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 #16
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) && BEZSELECTED(bezt) == 0) return 0;
	return 1;
}
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 - same value(s)?
	 *	-> firstly, handles must have same central value as each other
	 *	-> secondly, handles which control that section of the curve must be constant
	 */
	if (prev == NULL) return;
	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 (BEZSELECTED(beztn)) ab->sel = SELECT;
				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 #18
0
/* Use a weighted moving-means method to reduce intensity of fluctuations */
void smooth_fcurve (FCurve *fcu)
{
	BezTriple *bezt;
	int i, x, totSel = 0;
	
	/* first loop through - count how many verts are selected, and fix up handles 
	 *	this is done for both modes
	 */
	bezt= fcu->bezt;
	for (i=0; i < fcu->totvert; i++, bezt++) {						
		if (BEZSELECTED(bezt)) {							
			/* line point's handles up with point's vertical position */
			bezt->vec[0][1]= bezt->vec[2][1]= bezt->vec[1][1];
			if ((bezt->h1==HD_AUTO) || (bezt->h1==HD_VECT)) bezt->h1= HD_ALIGN;
			if ((bezt->h2==HD_AUTO) || (bezt->h2==HD_VECT)) bezt->h2= HD_ALIGN;
			
			/* add value to total */
			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 (BEZSELECTED(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
		 *	- 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 previous and next */ 
		tsb= tarray;
		for (i=0; i < totSel; i++, tsb++) {
			/* don't touch end points (otherwise, curves slowly explode) */
			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 */
				*tsb->h1= (3*p2 + 5*p1 + 2*c1 + n1 + n2) / 12;
				*tsb->h3= (p2 + p1 + 2*c1 + 5*n1 + 3*n2) / 12;
			}
		}
		
		/* round 2: calculate new values and reset handles */
		tsb= tarray;
		for (i=0; i < totSel; i++, tsb++) {
			/* calculate new position by averaging handles */
			*tsb->h2 = (*tsb->h1 + *tsb->h3) / 2;
			
			/* reset handles now */
			*tsb->h1 = *tsb->h2;
			*tsb->h3 = *tsb->h2;
		}
		
		/* free memory required for tarray */
		MEM_freeN(tarray);
	}
	
	/* recalculate handles */
	calchandles_fcurve(fcu);
}
Example #19
0
static void add_bezt_to_keyblocks_list(DLRBT_Tree *blocks, FCurve *fcu, int index)
{
	ActKeyBlock *new_ab= NULL;
	BezTriple *beztn=NULL, *prev=NULL;
	BezTriple *bezt;
	int v;
	
	/* get beztriples */
	beztn= (fcu->bezt + index);
	
	/* we need to go through all beztriples, as they may not be in order (i.e. during transform) */
	// TODO: this seems to be a bit of a bottleneck
	for (v=0, bezt=fcu->bezt; v < fcu->totvert; v++, bezt++) {
		/* skip if beztriple is current */
		if (v != index) {
			/* check if beztriple is immediately before */
			if (beztn->vec[1][0] > bezt->vec[1][0]) {
				/* check if closer than previous was */
				if (prev) {
					if (prev->vec[1][0] < bezt->vec[1][0])
						prev= bezt;
				}
				else {
					prev= bezt;
				}
			}
		}
	}
	
	/* check if block needed - same value(s)?
	 *	-> firstly, handles must have same central value as each other
	 *	-> secondly, handles which control that section of the curve must be constant
	 */
	if ((!prev) || (!beztn)) return;
	if (IS_EQ(beztn->vec[1][1], prev->vec[1][1])==0) return;
	if (IS_EQ(beztn->vec[1][1], beztn->vec[0][1])==0) return;
	if (IS_EQ(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, *abp=NULL, *abn=NULL;
		
		/* try to find a keyblock that starts on the previous beztriple, and add a new one if none start there
		 * Note: we can't search from end to try to optimise 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; abp= ab, ab= abn) {
			/* check if this is a match, or whether we go left or right */
			if (ab->start == prev->vec[1][0]) {
				/* set selection status and 'touched' status */
				if (BEZSELECTED(beztn)) ab->sel = SELECT;
				ab->modified += 1;
				
				/* done... no need to insert */
				return;
			}
			else {
				ActKeyBlock **abnp= NULL; 
				
				/* 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 #20
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 (BEZSELECTED(bezt)) {
						BEZ_DESEL(bezt);
					}
					else {
						BEZ_SEL(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) {
					BEZ_SEL(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 (BEZSELECTED(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, ANIMTYPE_FCURVE);
	}

	/* free temp sample data for filtering */
	MEM_freeN(nvi);
}