float (*BKE_mask_spline_differentiate_with_resolution(MaskSpline *spline, unsigned int *tot_diff_point, const unsigned int resol ))[2] { MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline); MaskSplinePoint *point_curr, *point_prev; float (*diff_points)[2], (*fp)[2]; const int tot = BKE_mask_spline_differentiate_calc_total(spline, resol); int a; if (spline->tot_point <= 1) { /* nothing to differentiate */ *tot_diff_point = 0; return NULL; } /* len+1 because of 'forward_diff_bezier' function */ *tot_diff_point = tot; diff_points = fp = MEM_mallocN((tot + 1) * sizeof(*diff_points), "mask spline vets"); a = spline->tot_point - 1; if (spline->flag & MASK_SPLINE_CYCLIC) a++; point_prev = points_array; point_curr = point_prev + 1; while (a--) { BezTriple *bezt_prev; BezTriple *bezt_curr; int j; if (a == 0 && (spline->flag & MASK_SPLINE_CYCLIC)) point_curr = points_array; bezt_prev = &point_prev->bezt; bezt_curr = &point_curr->bezt; for (j = 0; j < 2; j++) { BKE_curve_forward_diff_bezier(bezt_prev->vec[1][j], bezt_prev->vec[2][j], bezt_curr->vec[0][j], bezt_curr->vec[1][j], &(*fp)[j], resol, 2 * sizeof(float)); } fp += resol; if (a == 0 && (spline->flag & MASK_SPLINE_CYCLIC) == 0) { copy_v2_v2(*fp, bezt_curr->vec[1]); } point_prev = point_curr; point_curr++; } return diff_points; }
static PyObject *M_Geometry_interpolate_bezier(PyObject *UNUSED(self), PyObject *args) { VectorObject *vec_k1, *vec_h1, *vec_k2, *vec_h2; int resolu; int dims; int i; float *coord_array, *fp; PyObject *list; float k1[4] = {0.0, 0.0, 0.0, 0.0}; float h1[4] = {0.0, 0.0, 0.0, 0.0}; float k2[4] = {0.0, 0.0, 0.0, 0.0}; float h2[4] = {0.0, 0.0, 0.0, 0.0}; if (!PyArg_ParseTuple(args, "O!O!O!O!i:interpolate_bezier", &vector_Type, &vec_k1, &vector_Type, &vec_h1, &vector_Type, &vec_h2, &vector_Type, &vec_k2, &resolu)) { return NULL; } if (resolu <= 1) { PyErr_SetString(PyExc_ValueError, "resolution must be 2 or over"); return NULL; } if (BaseMath_ReadCallback(vec_k1) == -1 || BaseMath_ReadCallback(vec_h1) == -1 || BaseMath_ReadCallback(vec_k2) == -1 || BaseMath_ReadCallback(vec_h2) == -1) { return NULL; } dims = MAX4(vec_k1->size, vec_h1->size, vec_h2->size, vec_k2->size); for (i = 0; i < vec_k1->size; i++) k1[i] = vec_k1->vec[i]; for (i = 0; i < vec_h1->size; i++) h1[i] = vec_h1->vec[i]; for (i = 0; i < vec_k2->size; i++) k2[i] = vec_k2->vec[i]; for (i = 0; i < vec_h2->size; i++) h2[i] = vec_h2->vec[i]; coord_array = MEM_callocN(dims * (resolu) * sizeof(float), "interpolate_bezier"); for (i = 0; i < dims; i++) { BKE_curve_forward_diff_bezier(k1[i], h1[i], h2[i], k2[i], coord_array + i, resolu - 1, sizeof(float) * dims); } list = PyList_New(resolu); fp = coord_array; for (i = 0; i < resolu; i++, fp = fp + dims) { PyList_SET_ITEM(list, i, Vector_CreatePyObject(fp, dims, Py_NEW, NULL)); } MEM_freeN(coord_array); return list; }
/* 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; }
/* 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(); }
static void curve_to_displist(Curve *cu, ListBase *nubase, ListBase *dispbase, const bool for_render, const bool use_render_resolution) { Nurb *nu; DispList *dl; BezTriple *bezt, *prevbezt; BPoint *bp; float *data; int a, len, resolu; const bool editmode = (!for_render && (cu->editnurb || cu->editfont)); nu = nubase->first; while (nu) { if (nu->hide == 0 || editmode == false) { if (use_render_resolution && cu->resolu_ren != 0) resolu = cu->resolu_ren; else resolu = nu->resolu; if (!BKE_nurb_check_valid_u(nu)) { /* pass */ } else if (nu->type == CU_BEZIER) { /* count */ len = 0; a = nu->pntsu - 1; if (nu->flagu & CU_NURB_CYCLIC) a++; prevbezt = nu->bezt; bezt = prevbezt + 1; while (a--) { if (a == 0 && (nu->flagu & CU_NURB_CYCLIC)) bezt = nu->bezt; if (prevbezt->h2 == HD_VECT && bezt->h1 == HD_VECT) len++; else len += resolu; if (a == 0 && (nu->flagu & CU_NURB_CYCLIC) == 0) len++; prevbezt = bezt; bezt++; } dl = MEM_callocN(sizeof(DispList), "makeDispListbez"); /* len+1 because of 'forward_diff_bezier' function */ dl->verts = MEM_mallocN((len + 1) * sizeof(float[3]), "dlverts"); BLI_addtail(dispbase, dl); dl->parts = 1; dl->nr = len; dl->col = nu->mat_nr; dl->charidx = nu->charidx; data = dl->verts; /* check that (len != 2) so we don't immediately loop back on ourselves */ if (nu->flagu & CU_NURB_CYCLIC && (dl->nr != 2)) { dl->type = DL_POLY; a = nu->pntsu; } else { dl->type = DL_SEGM; a = nu->pntsu - 1; } prevbezt = nu->bezt; bezt = prevbezt + 1; while (a--) { if (a == 0 && dl->type == DL_POLY) bezt = nu->bezt; if (prevbezt->h2 == HD_VECT && bezt->h1 == HD_VECT) { copy_v3_v3(data, prevbezt->vec[1]); data += 3; } else { int j; for (j = 0; j < 3; j++) { BKE_curve_forward_diff_bezier(prevbezt->vec[1][j], prevbezt->vec[2][j], bezt->vec[0][j], bezt->vec[1][j], data + j, resolu, 3 * sizeof(float)); } data += 3 * resolu; } if (a == 0 && dl->type == DL_SEGM) { copy_v3_v3(data, bezt->vec[1]); } prevbezt = bezt; bezt++; } } else if (nu->type == CU_NURBS) { len = (resolu * SEGMENTSU(nu)); dl = MEM_callocN(sizeof(DispList), "makeDispListsurf"); dl->verts = MEM_mallocN(len * sizeof(float[3]), "dlverts"); BLI_addtail(dispbase, dl); dl->parts = 1; dl->nr = len; dl->col = nu->mat_nr; dl->charidx = nu->charidx; data = dl->verts; if (nu->flagu & CU_NURB_CYCLIC) dl->type = DL_POLY; else dl->type = DL_SEGM; BKE_nurb_makeCurve(nu, data, NULL, NULL, NULL, resolu, 3 * sizeof(float)); } else if (nu->type == CU_POLY) { len = nu->pntsu; dl = MEM_callocN(sizeof(DispList), "makeDispListpoly"); dl->verts = MEM_mallocN(len * sizeof(float[3]), "dlverts"); BLI_addtail(dispbase, dl); dl->parts = 1; dl->nr = len; dl->col = nu->mat_nr; dl->charidx = nu->charidx; data = dl->verts; if ((nu->flagu & CU_NURB_CYCLIC) && (dl->nr != 2)) { dl->type = DL_POLY; } else { dl->type = DL_SEGM; } a = len; bp = nu->bp; while (a--) { copy_v3_v3(data, bp->vec); bp++; data += 3; } } } nu = nu->next; } }
/** only called from #BKE_mask_spline_feather_differentiated_points_with_resolution() ! */ static float (*mask_spline_feather_differentiated_points_with_resolution__double( MaskSpline *spline, unsigned int *tot_feather_point, const unsigned int resol, const bool do_feather_isect))[2] { MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline); MaskSplinePoint *point_curr, *point_prev; float (*feather)[2], (*fp)[2]; const int tot = BKE_mask_spline_differentiate_calc_total(spline, resol); int a; if (spline->tot_point <= 1) { /* nothing to differentiate */ *tot_feather_point = 0; return NULL; } /* len+1 because of 'forward_diff_bezier' function */ *tot_feather_point = tot; feather = fp = MEM_mallocN((tot + 1) * sizeof(*feather), "mask spline vets"); a = spline->tot_point - 1; if (spline->flag & MASK_SPLINE_CYCLIC) a++; point_prev = points_array; point_curr = point_prev + 1; while (a--) { BezTriple local_prevbezt; BezTriple local_bezt; float point_prev_n[2], point_curr_n[2], tvec[2]; float weight_prev, weight_curr; float len_base, len_feather, len_scalar; BezTriple *bezt_prev; BezTriple *bezt_curr; int j; if (a == 0 && (spline->flag & MASK_SPLINE_CYCLIC)) point_curr = points_array; bezt_prev = &point_prev->bezt; bezt_curr = &point_curr->bezt; /* modified copy for feather */ local_prevbezt = *bezt_prev; local_bezt = *bezt_curr; bezt_prev = &local_prevbezt; bezt_curr = &local_bezt; /* calc the normals */ sub_v2_v2v2(tvec, bezt_prev->vec[1], bezt_prev->vec[0]); normalize_v2(tvec); point_prev_n[0] = -tvec[1]; point_prev_n[1] = tvec[0]; sub_v2_v2v2(tvec, bezt_curr->vec[1], bezt_curr->vec[0]); normalize_v2(tvec); point_curr_n[0] = -tvec[1]; point_curr_n[1] = tvec[0]; weight_prev = bezt_prev->weight; weight_curr = bezt_curr->weight; mul_v2_fl(point_prev_n, weight_prev); mul_v2_fl(point_curr_n, weight_curr); /* before we transform verts */ len_base = len_v2v2(bezt_prev->vec[1], bezt_curr->vec[1]); // add_v2_v2(bezt_prev->vec[0], point_prev_n); // not needed add_v2_v2(bezt_prev->vec[1], point_prev_n); add_v2_v2(bezt_prev->vec[2], point_prev_n); add_v2_v2(bezt_curr->vec[0], point_curr_n); add_v2_v2(bezt_curr->vec[1], point_curr_n); // add_v2_v2(bezt_curr->vec[2], point_curr_n); // not needed len_feather = len_v2v2(bezt_prev->vec[1], bezt_curr->vec[1]); /* scale by chane in length */ len_scalar = len_feather / len_base; dist_ensure_v2_v2fl(bezt_prev->vec[2], bezt_prev->vec[1], len_scalar * len_v2v2(bezt_prev->vec[2], bezt_prev->vec[1])); dist_ensure_v2_v2fl(bezt_curr->vec[0], bezt_curr->vec[1], len_scalar * len_v2v2(bezt_curr->vec[0], bezt_curr->vec[1])); for (j = 0; j < 2; j++) { BKE_curve_forward_diff_bezier(bezt_prev->vec[1][j], bezt_prev->vec[2][j], bezt_curr->vec[0][j], bezt_curr->vec[1][j], &(*fp)[j], resol, 2 * sizeof(float)); } /* scale by the uw's */ if (point_prev->tot_uw) { for (j = 0; j < resol; j++, fp++) { float u = (float) j / resol; float weight_uw, weight_scalar; float co[2]; /* TODO - these calls all calculate similar things * could be unified for some speed */ BKE_mask_point_segment_co(spline, point_prev, u, co); weight_uw = BKE_mask_point_weight(spline, point_prev, u); weight_scalar = BKE_mask_point_weight_scalar(spline, point_prev, u); dist_ensure_v2_v2fl(*fp, co, len_v2v2(*fp, co) * (weight_uw / weight_scalar)); } } else { fp += resol; } if (a == 0 && (spline->flag & MASK_SPLINE_CYCLIC) == 0) { copy_v2_v2(*fp, bezt_curr->vec[1]); } point_prev = point_curr; point_curr++; } if ((spline->flag & MASK_SPLINE_NOINTERSECT) && do_feather_isect) { BKE_mask_spline_feather_collapse_inner_loops(spline, feather, tot); } return feather; }
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; }