Example #1
0
/* helper func - draw one repeat of an F-Curve */
static void draw_fcurve_curve_bezts(bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d)
{
	BezTriple *prevbezt = fcu->bezt;
	BezTriple *bezt = prevbezt + 1;
	float v1[2], v2[2], v3[2], v4[2];
	float *fp, data[120];
	float fac = 0.0f;
	int b = fcu->totvert - 1;
	int resol;
	float unit_scale;
	short mapping_flag = ANIM_get_normalization_flags(ac);

	/* apply unit mapping */
	glPushMatrix();
	unit_scale = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag);
	glScalef(1.0f, unit_scale, 1.0f);

	glBegin(GL_LINE_STRIP);
	
	/* extrapolate to left? */
	if (prevbezt->vec[1][0] > v2d->cur.xmin) {
		/* left-side of view comes before first keyframe, so need to extend as not cyclic */
		v1[0] = v2d->cur.xmin;
		
		/* y-value depends on the interpolation */
		if ((fcu->extend == FCURVE_EXTRAPOLATE_CONSTANT) || (prevbezt->ipo == BEZT_IPO_CONST) || (fcu->totvert == 1)) {
			/* just extend across the first keyframe's value */
			v1[1] = prevbezt->vec[1][1];
		}
		else if (prevbezt->ipo == BEZT_IPO_LIN) {
			/* extrapolate linear dosnt use the handle, use the next points center instead */
			fac = (prevbezt->vec[1][0] - bezt->vec[1][0]) / (prevbezt->vec[1][0] - v1[0]);
			if (fac) fac = 1.0f / fac;
			v1[1] = prevbezt->vec[1][1] - fac * (prevbezt->vec[1][1] - bezt->vec[1][1]);
		}
		else {
			/* based on angle of handle 1 (relative to keyframe) */
			fac = (prevbezt->vec[0][0] - prevbezt->vec[1][0]) / (prevbezt->vec[1][0] - v1[0]);
			if (fac) fac = 1.0f / fac;
			v1[1] = prevbezt->vec[1][1] - fac * (prevbezt->vec[0][1] - prevbezt->vec[1][1]);
		}
		
		glVertex2fv(v1);
	}
	
	/* if only one keyframe, add it now */
	if (fcu->totvert == 1) {
		v1[0] = prevbezt->vec[1][0];
		v1[1] = prevbezt->vec[1][1];
		glVertex2fv(v1);
	}
	
	/* draw curve between first and last keyframe (if there are enough to do so) */
	/* TODO: optimize this to not have to calc stuff out of view too? */
	while (b--) {
		if (prevbezt->ipo == BEZT_IPO_CONST) {
			/* Constant-Interpolation: draw segment between previous keyframe and next, but holding same value */
			v1[0] = prevbezt->vec[1][0];
			v1[1] = prevbezt->vec[1][1];
			glVertex2fv(v1);
			
			v1[0] = bezt->vec[1][0];
			v1[1] = prevbezt->vec[1][1];
			glVertex2fv(v1);
		}
		else if (prevbezt->ipo == BEZT_IPO_LIN) {
			/* Linear interpolation: just add one point (which should add a new line segment) */
			v1[0] = prevbezt->vec[1][0];
			v1[1] = prevbezt->vec[1][1];
			glVertex2fv(v1);
		}
		else {
			/* Bezier-Interpolation: draw curve as series of segments between keyframes 
			 *	- resol determines number of points to sample in between keyframes
			 */
			
			/* resol depends on distance between points (not just horizontal) OR is a fixed high res */
			/* TODO: view scale should factor into this someday too... */
			if (fcu->driver) 
				resol = 32;
			else 
				resol = (int)(5.0f * len_v2v2(bezt->vec[1], prevbezt->vec[1]));
			
			if (resol < 2) {
				/* only draw one */
				v1[0] = prevbezt->vec[1][0];
				v1[1] = prevbezt->vec[1][1];
				glVertex2fv(v1);
			}
			else {
				/* clamp resolution to max of 32 */
				/* NOTE: higher values will crash */
				if (resol > 32) resol = 32;
				
				v1[0] = prevbezt->vec[1][0];
				v1[1] = prevbezt->vec[1][1];
				v2[0] = prevbezt->vec[2][0];
				v2[1] = prevbezt->vec[2][1];
				
				v3[0] = bezt->vec[0][0];
				v3[1] = bezt->vec[0][1];
				v4[0] = bezt->vec[1][0];
				v4[1] = bezt->vec[1][1];
				
				correct_bezpart(v1, v2, v3, v4);
				
				BKE_curve_forward_diff_bezier(v1[0], v2[0], v3[0], v4[0], data, resol, sizeof(float) * 3);
				BKE_curve_forward_diff_bezier(v1[1], v2[1], v3[1], v4[1], data + 1, resol, sizeof(float) * 3);
				
				for (fp = data; resol; resol--, fp += 3)
					glVertex2fv(fp);
			}
		}
		
		/* get next pointers */
		prevbezt = bezt;
		bezt++;
		
		/* last point? */
		if (b == 0) {
			v1[0] = prevbezt->vec[1][0];
			v1[1] = prevbezt->vec[1][1];
			glVertex2fv(v1);
		}
	}
	
	/* extrapolate to right? (see code for left-extrapolation above too) */
	if (prevbezt->vec[1][0] < v2d->cur.xmax) {
		v1[0] = v2d->cur.xmax;
		
		/* y-value depends on the interpolation */
		if ((fcu->extend == FCURVE_EXTRAPOLATE_CONSTANT) || (fcu->flag & FCURVE_INT_VALUES) || (prevbezt->ipo == BEZT_IPO_CONST) || (fcu->totvert == 1)) {
			/* based on last keyframe's value */
			v1[1] = prevbezt->vec[1][1];
		}
		else if (prevbezt->ipo == BEZT_IPO_LIN) {
			/* extrapolate linear dosnt use the handle, use the previous points center instead */
			bezt = prevbezt - 1;
			fac = (prevbezt->vec[1][0] - bezt->vec[1][0]) / (prevbezt->vec[1][0] - v1[0]);
			if (fac) fac = 1.0f / fac;
			v1[1] = prevbezt->vec[1][1] - fac * (prevbezt->vec[1][1] - bezt->vec[1][1]);
		}
		else {
			/* based on angle of handle 1 (relative to keyframe) */
			fac = (prevbezt->vec[2][0] - prevbezt->vec[1][0]) / (prevbezt->vec[1][0] - v1[0]);
			if (fac) fac = 1.0f / fac;
			v1[1] = prevbezt->vec[1][1] - fac * (prevbezt->vec[2][1] - prevbezt->vec[1][1]);
		}
		
		glVertex2fv(v1);
	}
	
	glEnd();
	glPopMatrix();
}
Example #2
0
/* only creates a table for a single channel in CurveMapping */
static void curvemap_make_table(CurveMap *cuma, rctf *clipr)
{
	CurveMapPoint *cmp = cuma->curve;
	BezTriple *bezt;
	float *fp, *allpoints, *lastpoint, curf, range;
	int a, totpoint;
	
	if (cuma->curve == NULL) return;
	
	/* default rect also is table range */
	cuma->mintable = clipr->xmin;
	cuma->maxtable = clipr->xmax;
	
	/* hrmf... we now rely on blender ipo beziers, these are more advanced */
	bezt = MEM_callocN(cuma->totpoint * sizeof(BezTriple), "beztarr");
	
	for (a = 0; a < cuma->totpoint; a++) {
		cuma->mintable = MIN2(cuma->mintable, cmp[a].x);
		cuma->maxtable = MAX2(cuma->maxtable, cmp[a].x);
		bezt[a].vec[1][0] = cmp[a].x;
		bezt[a].vec[1][1] = cmp[a].y;
		if (cmp[a].flag & CUMA_VECTOR)
			bezt[a].h1 = bezt[a].h2 = HD_VECT;
		else
			bezt[a].h1 = bezt[a].h2 = HD_AUTO;
	}
	
	for (a = 0; a < cuma->totpoint; a++) {
		if (a == 0)
			calchandle_curvemap(bezt, NULL, bezt + 1, 0);
		else if (a == cuma->totpoint - 1)
			calchandle_curvemap(bezt + a, bezt + a - 1, NULL, 0);
		else
			calchandle_curvemap(bezt + a, bezt + a - 1, bezt + a + 1, 0);
	}
	
	/* first and last handle need correction, instead of pointing to center of next/prev, 
	 * we let it point to the closest handle */
	if (cuma->totpoint > 2) {
		float hlen, nlen, vec[3];
		
		if (bezt[0].h2 == HD_AUTO) {
			
			hlen = len_v3v3(bezt[0].vec[1], bezt[0].vec[2]); /* original handle length */
			/* clip handle point */
			copy_v3_v3(vec, bezt[1].vec[0]);
			if (vec[0] < bezt[0].vec[1][0])
				vec[0] = bezt[0].vec[1][0];
			
			sub_v3_v3(vec, bezt[0].vec[1]);
			nlen = len_v3(vec);
			if (nlen > FLT_EPSILON) {
				mul_v3_fl(vec, hlen / nlen);
				add_v3_v3v3(bezt[0].vec[2], vec, bezt[0].vec[1]);
				sub_v3_v3v3(bezt[0].vec[0], bezt[0].vec[1], vec);
			}
		}
		a = cuma->totpoint - 1;
		if (bezt[a].h2 == HD_AUTO) {
			
			hlen = len_v3v3(bezt[a].vec[1], bezt[a].vec[0]); /* original handle length */
			/* clip handle point */
			copy_v3_v3(vec, bezt[a - 1].vec[2]);
			if (vec[0] > bezt[a].vec[1][0])
				vec[0] = bezt[a].vec[1][0];
			
			sub_v3_v3(vec, bezt[a].vec[1]);
			nlen = len_v3(vec);
			if (nlen > FLT_EPSILON) {
				mul_v3_fl(vec, hlen / nlen);
				add_v3_v3v3(bezt[a].vec[0], vec, bezt[a].vec[1]);
				sub_v3_v3v3(bezt[a].vec[2], bezt[a].vec[1], vec);
			}
		}
	}	
	/* make the bezier curve */
	if (cuma->table)
		MEM_freeN(cuma->table);
	totpoint = (cuma->totpoint - 1) * CM_RESOL;
	fp = allpoints = MEM_callocN(totpoint * 2 * sizeof(float), "table");
	
	for (a = 0; a < cuma->totpoint - 1; a++, fp += 2 * CM_RESOL) {
		correct_bezpart(bezt[a].vec[1], bezt[a].vec[2], bezt[a + 1].vec[0], bezt[a + 1].vec[1]);
		BKE_curve_forward_diff_bezier(bezt[a].vec[1][0], bezt[a].vec[2][0], bezt[a + 1].vec[0][0], bezt[a + 1].vec[1][0], fp, CM_RESOL - 1, 2 * sizeof(float));
		BKE_curve_forward_diff_bezier(bezt[a].vec[1][1], bezt[a].vec[2][1], bezt[a + 1].vec[0][1], bezt[a + 1].vec[1][1], fp + 1, CM_RESOL - 1, 2 * sizeof(float));
	}
	
	/* store first and last handle for extrapolation, unit length */
	cuma->ext_in[0] = bezt[0].vec[0][0] - bezt[0].vec[1][0];
	cuma->ext_in[1] = bezt[0].vec[0][1] - bezt[0].vec[1][1];
	range = sqrt(cuma->ext_in[0] * cuma->ext_in[0] + cuma->ext_in[1] * cuma->ext_in[1]);
	cuma->ext_in[0] /= range;
	cuma->ext_in[1] /= range;

	a = cuma->totpoint - 1;
	cuma->ext_out[0] = bezt[a].vec[1][0] - bezt[a].vec[2][0];
	cuma->ext_out[1] = bezt[a].vec[1][1] - bezt[a].vec[2][1];
	range = sqrt(cuma->ext_out[0] * cuma->ext_out[0] + cuma->ext_out[1] * cuma->ext_out[1]);
	cuma->ext_out[0] /= range;
	cuma->ext_out[1] /= range;
	
	/* cleanup */
	MEM_freeN(bezt);

	range = CM_TABLEDIV * (cuma->maxtable - cuma->mintable);
	cuma->range = 1.0f / range;
	
	/* now make a table with CM_TABLE equal x distances */
	fp = allpoints;
	lastpoint = allpoints + 2 * (totpoint - 1);
	cmp = MEM_callocN((CM_TABLE + 1) * sizeof(CurveMapPoint), "dist table");

	for (a = 0; a <= CM_TABLE; a++) {
		curf = cuma->mintable + range * (float)a;
		cmp[a].x = curf;
		
		/* get the first x coordinate larger than curf */
		while (curf >= fp[0] && fp != lastpoint) {
			fp += 2;
		}
		if (fp == allpoints || (curf >= fp[0] && fp == lastpoint))
			cmp[a].y = curvemap_calc_extend(cuma, curf, allpoints, lastpoint);
		else {
			float fac1 = fp[0] - fp[-2];
			float fac2 = fp[0] - curf;
			if (fac1 > FLT_EPSILON)
				fac1 = fac2 / fac1;
			else
				fac1 = 0.0f;
			cmp[a].y = fac1 * fp[-1] + (1.0f - fac1) * fp[1];
		}
	}
	
	MEM_freeN(allpoints);
	cuma->table = cmp;
}
Example #3
0
static float normalization_factor_get(Scene *scene, FCurve *fcu, short flag, float *r_offset)
{
	float factor = 1.0f, offset = 0.0f;

	if (flag & ANIM_UNITCONV_RESTORE) {
		if (r_offset)
			*r_offset = fcu->prev_offset;

		return 1.0f / fcu->prev_norm_factor;
	}

	if (flag & ANIM_UNITCONV_NORMALIZE_FREEZE) {
		if (r_offset)
			*r_offset = fcu->prev_offset;
		if (fcu->prev_norm_factor == 0.0f) {
			/* Happens when Auto Normalize was disabled before
			 * any curves were displayed.
			 */
			return 1.0f;
		}
		return fcu->prev_norm_factor;
	}

	if (G.moving & G_TRANSFORM_FCURVES) {
		if (r_offset)
			*r_offset = fcu->prev_offset;
		if (fcu->prev_norm_factor == 0.0f) {
			/* Same as above. */
			return 1.0f;
		}
		return fcu->prev_norm_factor;
	}

	fcu->prev_norm_factor = 1.0f;
	if (fcu->bezt) {
		const bool use_preview_only = PRVRANGEON;
		const BezTriple *bezt;
		int i;
		float max_coord = -FLT_MAX;
		float min_coord = FLT_MAX;
		float range;

		if (fcu->totvert < 1) {
			return 1.0f;
		}

		for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
			if (use_preview_only && !IN_RANGE_INCL(bezt->vec[1][0],
			                                       scene->r.psfra,
			                                       scene->r.pefra))
			{
				continue;
			}

			if (i == 0) {
				/* We ignore extrapolation flags and handle here, and use the
				 * control point position only. so we normalize "interesting"
				 * part of the curve.
				 *
				 * Here we handle left extrapolation.
				 */
				max_coord = max_ff(max_coord, bezt->vec[1][1]);

				min_coord = min_ff(min_coord, bezt->vec[1][1]);
			}
			else {
				const BezTriple *prev_bezt = bezt - 1;
				if (prev_bezt->ipo == BEZT_IPO_CONST) {
					/* Constant interpolation: previous CV value is used up
					 * to the current keyframe.
					 */
					max_coord = max_ff(max_coord, bezt->vec[1][1]);
					min_coord = min_ff(min_coord, bezt->vec[1][1]);
				}
				else if (prev_bezt->ipo == BEZT_IPO_LIN) {
					/* Linear interpolation: min/max using both previous and
					 * and current CV.
					 */
					max_coord = max_ff(max_coord, bezt->vec[1][1]);
					min_coord = min_ff(min_coord, bezt->vec[1][1]);
					max_coord = max_ff(max_coord, prev_bezt->vec[1][1]);
					min_coord = min_ff(min_coord, prev_bezt->vec[1][1]);
				}
				else if (prev_bezt->ipo == BEZT_IPO_BEZ) {
					const int resol = fcu->driver
					        ? 32
					        : min_ii((int)(5.0f * len_v2v2(bezt->vec[1], prev_bezt->vec[1])), 32);
					if (resol < 2) {
						max_coord = max_ff(max_coord, prev_bezt->vec[1][1]);
						min_coord = min_ff(min_coord, prev_bezt->vec[1][1]);
					}
					else {
						float data[120];
						float v1[2], v2[2], v3[2], v4[2];

						v1[0] = prev_bezt->vec[1][0];
						v1[1] = prev_bezt->vec[1][1];
						v2[0] = prev_bezt->vec[2][0];
						v2[1] = prev_bezt->vec[2][1];

						v3[0] = bezt->vec[0][0];
						v3[1] = bezt->vec[0][1];
						v4[0] = bezt->vec[1][0];
						v4[1] = bezt->vec[1][1];

						correct_bezpart(v1, v2, v3, v4);

						BKE_curve_forward_diff_bezier(v1[0], v2[0], v3[0], v4[0], data, resol, sizeof(float) * 3);
						BKE_curve_forward_diff_bezier(v1[1], v2[1], v3[1], v4[1], data + 1, resol, sizeof(float) * 3);

						for (int j = 0; j <= resol; ++j) {
							const float *fp = &data[j * 3];
							max_coord = max_ff(max_coord, fp[1]);
							min_coord = min_ff(min_coord, fp[1]);
						}
					}
				}
			}
		}

		if (max_coord > min_coord) {
			range = max_coord - min_coord;
			if (range > FLT_EPSILON) {
				factor = 2.0f / range;
			}
			offset = -min_coord - range / 2.0f;
		}
		else if (max_coord == min_coord) {
			factor = 1.0f;
			offset = -min_coord;
		}
	}
	BLI_assert(factor != 0.0f);
	if (r_offset) {
		*r_offset = offset;
	}

	fcu->prev_norm_factor = factor;
	fcu->prev_offset = offset;
	return factor;
}