コード例 #1
0
/* NOTE: this is exported to other modules that use the ActKeyColumns for finding keyframes */
short compare_ak_cfraPtr(void *node, void *data)
{
	ActKeyColumn *ak = (ActKeyColumn *)node;
	const float *cframe = data;
	float val = *cframe;
	
	if (IS_EQT(val, ak->cfra, BEZT_BINARYSEARCH_THRESH))
		return 0;
	
	if (val < ak->cfra)
		return -1;
	else if (val > ak->cfra)
		return 1;
	else
		return 0;
}
コード例 #2
0
/* Basic F-Curve 'cleanup' function that removes 'double points' and unnecessary keyframes on linear-segments only */
void clean_fcurve(FCurve *fcu, float thresh)
{
	BezTriple *old_bezts, *bezt, *beztn;
	BezTriple *lastb;
	int totCount, i;
	
	/* check if any points  */
	if ((fcu == NULL) || (fcu->bezt == NULL) || (fcu->totvert <= 1))
		return;
	
	/* make a copy of the old BezTriples, and clear F-Curve */
	old_bezts = fcu->bezt;
	totCount = fcu->totvert;
	fcu->bezt = NULL;
	fcu->totvert = 0;
	
	/* now insert first keyframe, as it should be ok */
	bezt = old_bezts;
	insert_vert_fcurve(fcu, bezt->vec[1][0], bezt->vec[1][1], 0);
	
	/* Loop through BezTriples, comparing them. Skip any that do 
	 * not fit the criteria for "ok" points.
	 */
	for (i = 1; i < totCount; i++) {
		float prev[2], cur[2], next[2];
		
		/* get BezTriples and their values */
		if (i < (totCount - 1)) {
			beztn = (old_bezts + (i + 1));
			next[0] = beztn->vec[1][0]; next[1] = beztn->vec[1][1];
		}
		else {
			beztn = NULL;
			next[0] = next[1] = 0.0f;
		}
		lastb = (fcu->bezt + (fcu->totvert - 1));
		bezt = (old_bezts + i);
		
		/* get references for quicker access */
		prev[0] = lastb->vec[1][0]; prev[1] = lastb->vec[1][1];
		cur[0] = bezt->vec[1][0]; cur[1] = bezt->vec[1][1];
		
		/* check if current bezt occurs at same time as last ok */
		if (IS_EQT(cur[0], prev[0], thresh)) {
			/* If there is a next beztriple, and if occurs at the same time, only insert 
			 * if there is a considerable distance between the points, and also if the 
			 * current is further away than the next one is to the previous.
			 */
			if (beztn && (IS_EQT(cur[0], next[0], thresh)) && 
			    (IS_EQT(next[1], prev[1], thresh) == 0))
			{
				/* only add if current is further away from previous */
				if (cur[1] > next[1]) {
					if (IS_EQT(cur[1], prev[1], thresh) == 0) {
						/* add new keyframe */
						insert_vert_fcurve(fcu, cur[0], cur[1], 0);
					}
				}
			}
			else {
				/* only add if values are a considerable distance apart */
				if (IS_EQT(cur[1], prev[1], thresh) == 0) {
					/* add new keyframe */
					insert_vert_fcurve(fcu, cur[0], cur[1], 0);
				}
			}
		}
		else {
			/* checks required are dependent on whether this is last keyframe or not */
			if (beztn) {
				/* does current have same value as previous and next? */
				if (IS_EQT(cur[1], prev[1], thresh) == 0) {
					/* add new keyframe*/
					insert_vert_fcurve(fcu, cur[0], cur[1], 0);
				}
				else if (IS_EQT(cur[1], next[1], thresh) == 0) {
					/* add new keyframe */
					insert_vert_fcurve(fcu, cur[0], cur[1], 0);
				}
			}
			else {
				/* add if value doesn't equal that of previous */
				if (IS_EQT(cur[1], prev[1], thresh) == 0) {
					/* add new keyframe */
					insert_vert_fcurve(fcu, cur[0], cur[1], 0);
				}
			}
		}
	}
	
	/* now free the memory used by the old BezTriples */
	if (old_bezts)
		MEM_freeN(old_bezts);
}
コード例 #3
0
ファイル: keyframes_general.c プロジェクト: Moguri/blender
/* Basic F-Curve 'cleanup' function that removes 'double points' and unnecessary keyframes on linear-segments only
 * optionally clears up curve if one keyframe with default value remains */
void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, bool cleardefault)
{
	FCurve *fcu = (FCurve *)ale->key_data;
	BezTriple *old_bezts, *bezt, *beztn;
	BezTriple *lastb;
	int totCount, i;
	
	/* check if any points  */
	if ((fcu == NULL) || (fcu->bezt == NULL) || (fcu->totvert == 0) ||
	    (!cleardefault && fcu->totvert == 1))
	{
		return;
	}

	/* make a copy of the old BezTriples, and clear F-Curve */
	old_bezts = fcu->bezt;
	totCount = fcu->totvert;
	fcu->bezt = NULL;
	fcu->totvert = 0;
	
	/* now insert first keyframe, as it should be ok */
	bezt = old_bezts;
	insert_vert_fcurve(fcu, bezt->vec[1][0], bezt->vec[1][1], 0);
	if (!(bezt->f2 & SELECT)) {
		lastb = fcu->bezt;
		lastb->f1 = lastb->f2 = lastb->f3 = 0;
	}
	
	/* Loop through BezTriples, comparing them. Skip any that do 
	 * not fit the criteria for "ok" points.
	 */
	for (i = 1; i < totCount; i++) {
		float prev[2], cur[2], next[2];

		/* get BezTriples and their values */
		if (i < (totCount - 1)) {
			beztn = (old_bezts + (i + 1));
			next[0] = beztn->vec[1][0]; next[1] = beztn->vec[1][1];
		}
		else {
			beztn = NULL;
			next[0] = next[1] = 0.0f;
		}
		lastb = (fcu->bezt + (fcu->totvert - 1));
		bezt = (old_bezts + i);

		/* get references for quicker access */
		prev[0] = lastb->vec[1][0]; prev[1] = lastb->vec[1][1];
		cur[0] = bezt->vec[1][0]; cur[1] = bezt->vec[1][1];

		if (!(bezt->f2 & SELECT)) {
			insert_vert_fcurve(fcu, cur[0], cur[1], 0);
			lastb = (fcu->bezt + (fcu->totvert - 1));
			lastb->f1 = lastb->f2 = lastb->f3 = 0;
			continue;
		}
		
		/* check if current bezt occurs at same time as last ok */
		if (IS_EQT(cur[0], prev[0], thresh)) {
			/* If there is a next beztriple, and if occurs at the same time, only insert 
			 * if there is a considerable distance between the points, and also if the 
			 * current is further away than the next one is to the previous.
			 */
			if (beztn && (IS_EQT(cur[0], next[0], thresh)) &&
			    (IS_EQT(next[1], prev[1], thresh) == 0))
			{
				/* only add if current is further away from previous */
				if (cur[1] > next[1]) {
					if (IS_EQT(cur[1], prev[1], thresh) == 0) {
						/* add new keyframe */
						insert_vert_fcurve(fcu, cur[0], cur[1], 0);
					}
				}
			}
			else {
				/* only add if values are a considerable distance apart */
				if (IS_EQT(cur[1], prev[1], thresh) == 0) {
					/* add new keyframe */
					insert_vert_fcurve(fcu, cur[0], cur[1], 0);
				}
			}
		}
		else {
			/* checks required are dependent on whether this is last keyframe or not */
			if (beztn) {
				/* does current have same value as previous and next? */
				if (IS_EQT(cur[1], prev[1], thresh) == 0) {
					/* add new keyframe*/
					insert_vert_fcurve(fcu, cur[0], cur[1], 0);
				}
				else if (IS_EQT(cur[1], next[1], thresh) == 0) {
					/* add new keyframe */
					insert_vert_fcurve(fcu, cur[0], cur[1], 0);
				}
			}
			else {
				/* add if value doesn't equal that of previous */
				if (IS_EQT(cur[1], prev[1], thresh) == 0) {
					/* add new keyframe */
					insert_vert_fcurve(fcu, cur[0], cur[1], 0);
				}
			}
		}
	}
	
	/* now free the memory used by the old BezTriples */
	if (old_bezts)
		MEM_freeN(old_bezts);

	/* final step, if there is just one key in fcurve, check if it's
	 * the default value and if is, remove fcurve completely. */
	if (cleardefault && fcu->totvert == 1) {
		float default_value = 0.0f;
		PointerRNA id_ptr, ptr;
		PropertyRNA *prop;
		RNA_id_pointer_create(ale->id, &id_ptr);

		/* get property to read from, and get value as appropriate */
		if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) {
			if (RNA_property_type(prop) == PROP_FLOAT)
				default_value = RNA_property_float_get_default_index(&ptr, prop, fcu->array_index);
		}

		if (fcu->bezt->vec[1][1] == default_value) {
			clear_fcurve_keys(fcu);

			/* check if curve is really unused and if it is, return signal for deletion */
			if ((list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0) &&
			    (fcu->driver == NULL))
			{
				AnimData *adt = ale->adt;
				ANIM_fcurve_delete_from_animdata(ac, adt, fcu);
				ale->key_data = NULL;
			}
		}
	}
}
コード例 #4
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 - 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);
}
コード例 #5
0
ファイル: fmodifier.c プロジェクト: wangyxuan/blender
int BKE_fcm_envelope_find_index(FCM_EnvelopeData array[],
                                float frame,
                                int arraylen,
                                bool *r_exists)
{
  int start = 0, end = arraylen;
  int loopbreaker = 0, maxloop = arraylen * 2;

  /* initialize exists-flag first */
  *r_exists = false;

  /* sneaky optimizations (don't go through searching process if...):
   * - keyframe to be added is to be added out of current bounds
   * - keyframe to be added would replace one of the existing ones on bounds
   */
  if ((arraylen <= 0) || (array == NULL)) {
    CLOG_WARN(&LOG, "encountered invalid array");
    return 0;
  }
  else {
    /* check whether to add before/after/on */
    float framenum;

    /* 'First' Point (when only one point, this case is used) */
    framenum = array[0].time;
    if (IS_EQT(frame, framenum, BINARYSEARCH_FRAMEEQ_THRESH)) {
      *r_exists = true;
      return 0;
    }
    else if (frame < framenum) {
      return 0;
    }

    /* 'Last' Point */
    framenum = array[(arraylen - 1)].time;
    if (IS_EQT(frame, framenum, BINARYSEARCH_FRAMEEQ_THRESH)) {
      *r_exists = true;
      return (arraylen - 1);
    }
    else if (frame > framenum) {
      return arraylen;
    }
  }

  /* most of the time, this loop is just to find where to put it
   * - 'loopbreaker' is just here to prevent infinite loops
   */
  for (loopbreaker = 0; (start <= end) && (loopbreaker < maxloop); loopbreaker++) {
    /* compute and get midpoint */
    int mid = start + ((end - start) /
                       2); /* we calculate the midpoint this way to avoid int overflows... */
    float midfra = array[mid].time;

    /* check if exactly equal to midpoint */
    if (IS_EQT(frame, midfra, BINARYSEARCH_FRAMEEQ_THRESH)) {
      *r_exists = true;
      return mid;
    }

    /* repeat in upper/lower half */
    if (frame > midfra) {
      start = mid + 1;
    }
    else if (frame < midfra) {
      end = mid - 1;
    }
  }

  /* print error if loop-limit exceeded */
  if (loopbreaker == (maxloop - 1)) {
    CLOG_ERROR(&LOG, "binary search was taking too long");

    // include debug info
    CLOG_ERROR(&LOG,
               "\tround = %d: start = %d, end = %d, arraylen = %d",
               loopbreaker,
               start,
               end,
               arraylen);
  }

  /* not found, so return where to place it */
  return start;
}