Refactor: fcurve bounds functions #105177
|
@ -366,24 +366,21 @@ int BKE_fcurve_pathcache_find_array(struct FCurvePathCache *fcache,
|
|||
int fcurve_result_len);
|
||||
|
||||
/**
|
||||
* Calculate the extents of F-Curve's keyframes.
|
||||
* Calculate the x range of the given F-Curve's data.
|
||||
*/
|
||||
ChrisLend marked this conversation as resolved
|
||||
bool BKE_fcurve_calc_range(
|
||||
const struct FCurve *fcu, float *min, float *max, bool do_sel_only, bool do_min_length);
|
||||
bool BKE_fcurve_calc_range(const struct FCurve *fcu, float *min, float *max, bool do_sel_only);
|
||||
ChrisLend marked this conversation as resolved
Sybren A. Stüvel
commented
Return parameters should be prefixed with And it's weird, French is not my favourite language, I'm not even that good at it. But still when I read Return parameters should be prefixed with `r_`. I think this is an excellent opportunity to tackle that too.
And it's weird, French is not my favourite language, I'm not even that good at it. But still when I read `do_sel_only` I'm thinking "only salt?". No strong opinion here, but at the risk of doing even more in the same patch, I wouldn't mind if that parameter were renamed to `use_selected_keys_only`. I'll leave the final decision on whether to include that change or not to you though.
|
||||
|
||||
/**
|
||||
* Calculate the extents of F-Curve's data.
|
||||
* \param range Only calculate the bounds of the FCurve in the given range.
|
||||
* Calculate the x and y extents of F-Curve's data.
|
||||
* \param frame_range Only calculate the bounds of the FCurve in the given range.
|
||||
* Does the full range if NULL.
|
||||
* \return true if the bounds have been found.
|
||||
*/
|
||||
bool BKE_fcurve_calc_bounds(const struct FCurve *fcu,
|
||||
float *xmin,
|
||||
float *xmax,
|
||||
float *ymin,
|
||||
float *ymax,
|
||||
bool do_sel_only,
|
||||
bool include_handles,
|
||||
const float range[2]);
|
||||
const float frame_range[2],
|
||||
struct rctf *r_bounds);
|
||||
|
||||
/**
|
||||
* Return an array of keyed frames, rounded to `interval`.
|
||||
|
|
|
@ -1408,7 +1408,7 @@ void calc_action_range(const bAction *act, float *start, float *end, short incl_
|
|||
* single-keyframe curves will increase the overall length by
|
||||
* a phantom frame (#50354)
|
||||
*/
|
||||
BKE_fcurve_calc_range(fcu, &nmin, &nmax, false, false);
|
||||
BKE_fcurve_calc_range(fcu, &nmin, &nmax, false);
|
||||
|
||||
/* compare to the running tally */
|
||||
min = min_ff(min, nmin);
|
||||
|
|
|
@ -556,248 +556,225 @@ int BKE_fcurve_bezt_binarysearch_index(const BezTriple array[],
|
|||
|
||||
/* ...................................... */
|
||||
|
||||
/* Helper for calc_fcurve_* functions -> find first and last BezTriple to be used. */
|
||||
static bool get_fcurve_end_keyframes(const FCurve *fcu,
|
||||
BezTriple **first,
|
||||
BezTriple **last,
|
||||
const bool do_sel_only,
|
||||
const float range[2])
|
||||
/* Get the first and last index to the bezt array that satisfies the given parameters.
|
||||
* \param do_sel_only Only accept indices of bezt that are selected. Is a subset of frame_range.
|
||||
* \param frame_range Only consider keyframes in that frame interval. Can be NULL.
|
||||
*/
|
||||
static bool get_bounding_bezt_indices(const FCurve *fcu,
|
||||
const bool do_sel_only,
|
||||
const float frame_range[2],
|
||||
int *r_first,
|
||||
int *r_last)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
/* Init outputs. */
|
||||
*first = NULL;
|
||||
*last = NULL;
|
||||
|
||||
/* Sanity checks. */
|
||||
if (fcu->bezt == NULL) {
|
||||
return found;
|
||||
return false;
|
||||
}
|
||||
|
||||
int first_index = 0;
|
||||
int last_index = fcu->totvert - 1;
|
||||
*r_first = 0;
|
||||
*r_last = fcu->totvert - 1;
|
||||
|
||||
if (range != NULL) {
|
||||
bool found = false;
|
||||
if (frame_range != NULL) {
|
||||
/* If a range is passed in find the first and last keyframe within that range. */
|
||||
bool replace = false;
|
||||
first_index = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, range[0], fcu->totvert, &replace);
|
||||
last_index = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, range[1], fcu->totvert, &replace);
|
||||
*r_first = BKE_fcurve_bezt_binarysearch_index(
|
||||
fcu->bezt, frame_range[0], fcu->totvert, &replace);
|
||||
*r_last = BKE_fcurve_bezt_binarysearch_index(
|
||||
fcu->bezt, frame_range[1], fcu->totvert, &replace);
|
||||
|
||||
/* If first and last index are the same, no keyframes were found in the range. */
|
||||
if (first_index == last_index) {
|
||||
return found;
|
||||
if (*r_first == *r_last) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* The binary search returns an index where a keyframe would be inserted,
|
||||
so it needs to be clamped to ensure it is in range of the array. */
|
||||
first_index = clamp_i(first_index, 0, fcu->totvert - 1);
|
||||
last_index = clamp_i(last_index - 1, 0, fcu->totvert - 1);
|
||||
*r_first = clamp_i(*r_first, 0, fcu->totvert - 1);
|
||||
*r_last = clamp_i(*r_last - 1, 0, fcu->totvert - 1);
|
||||
}
|
||||
|
||||
/* Only include selected items? */
|
||||
if (do_sel_only) {
|
||||
/* Find first selected. */
|
||||
for (int i = first_index; i <= last_index; i++) {
|
||||
for (int i = *r_first; i <= *r_last; i++) {
|
||||
BezTriple *bezt = &fcu->bezt[i];
|
||||
if (BEZT_ISSEL_ANY(bezt)) {
|
||||
*first = bezt;
|
||||
*r_first = i;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find last selected. */
|
||||
for (int i = last_index; i >= first_index; i--) {
|
||||
for (int i = *r_last; i >= *r_first; i--) {
|
||||
BezTriple *bezt = &fcu->bezt[i];
|
||||
if (BEZT_ISSEL_ANY(bezt)) {
|
||||
*last = bezt;
|
||||
*r_last = i;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
*first = &fcu->bezt[first_index];
|
||||
*last = &fcu->bezt[last_index];
|
||||
found = true;
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
bool BKE_fcurve_calc_bounds(const FCurve *fcu,
|
||||
float *xmin,
|
||||
float *xmax,
|
||||
float *ymin,
|
||||
float *ymax,
|
||||
const bool do_sel_only,
|
||||
const bool include_handles,
|
||||
const float range[2])
|
||||
static void calculate_bezt_bounds_x(BezTriple *bezt_array,
|
||||
const int index_range[2],
|
||||
const bool include_handles,
|
||||
float *r_min,
|
||||
float *r_max)
|
||||
{
|
||||
float xminv = 999999999.0f, xmaxv = -999999999.0f;
|
||||
float yminv = 999999999.0f, ymaxv = -999999999.0f;
|
||||
bool foundvert = false;
|
||||
|
||||
const bool use_range = range != NULL;
|
||||
|
||||
if (fcu->totvert) {
|
||||
if (fcu->bezt) {
|
||||
|
||||
if (xmin || xmax) {
|
||||
BezTriple *bezt_first = NULL, *bezt_last = NULL;
|
||||
foundvert = get_fcurve_end_keyframes(fcu, &bezt_first, &bezt_last, do_sel_only, range);
|
||||
|
||||
if (bezt_first) {
|
||||
BLI_assert(bezt_last != NULL);
|
||||
foundvert = true;
|
||||
if (include_handles) {
|
||||
xminv = min_fff(xminv, bezt_first->vec[0][0], bezt_first->vec[1][0]);
|
||||
xmaxv = max_fff(xmaxv, bezt_last->vec[1][0], bezt_last->vec[2][0]);
|
||||
}
|
||||
else {
|
||||
xminv = min_ff(xminv, bezt_first->vec[1][0]);
|
||||
xmaxv = max_ff(xmaxv, bezt_last->vec[1][0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Only loop over keyframes to find extents for values if needed. */
|
||||
if (ymin || ymax) {
|
||||
BezTriple *bezt, *prevbezt = NULL;
|
||||
|
||||
int i;
|
||||
for (bezt = fcu->bezt, i = 0; i < fcu->totvert; prevbezt = bezt, bezt++, i++) {
|
||||
if (use_range && (bezt->vec[1][0] < range[0] || bezt->vec[1][0] > range[1])) {
|
||||
continue;
|
||||
}
|
||||
if ((do_sel_only == false) || BEZT_ISSEL_ANY(bezt)) {
|
||||
/* Keyframe itself. */
|
||||
yminv = min_ff(yminv, bezt->vec[1][1]);
|
||||
ymaxv = max_ff(ymaxv, bezt->vec[1][1]);
|
||||
|
||||
if (include_handles) {
|
||||
/* Left handle - only if applicable.
|
||||
* NOTE: for the very first keyframe,
|
||||
* the left handle actually has no bearings on anything. */
|
||||
if (prevbezt && (prevbezt->ipo == BEZT_IPO_BEZ)) {
|
||||
yminv = min_ff(yminv, bezt->vec[0][1]);
|
||||
ymaxv = max_ff(ymaxv, bezt->vec[0][1]);
|
||||
}
|
||||
|
||||
/* Right handle - only if applicable. */
|
||||
if (bezt->ipo == BEZT_IPO_BEZ) {
|
||||
yminv = min_ff(yminv, bezt->vec[2][1]);
|
||||
ymaxv = max_ff(ymaxv, bezt->vec[2][1]);
|
||||
}
|
||||
}
|
||||
|
||||
foundvert = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (fcu->fpt) {
|
||||
/* Frame range can be directly calculated from end verts. */
|
||||
if (xmin || xmax) {
|
||||
xminv = min_ff(xminv, fcu->fpt[0].vec[0]);
|
||||
xmaxv = max_ff(xmaxv, fcu->fpt[fcu->totvert - 1].vec[0]);
|
||||
}
|
||||
|
||||
/* Only loop over keyframes to find extents for values if needed. */
|
||||
if (ymin || ymax) {
|
||||
int i = 0;
|
||||
|
||||
for (FPoint *fpt = fcu->fpt; i < fcu->totvert; fpt++, i++) {
|
||||
if (fpt->vec[1] < yminv) {
|
||||
yminv = fpt->vec[1];
|
||||
}
|
||||
if (fpt->vec[1] > ymaxv) {
|
||||
ymaxv = fpt->vec[1];
|
||||
}
|
||||
|
||||
foundvert = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (foundvert) {
|
||||
if (xmin) {
|
||||
*xmin = xminv;
|
||||
}
|
||||
if (xmax) {
|
||||
*xmax = xmaxv;
|
||||
}
|
||||
|
||||
if (ymin) {
|
||||
*ymin = yminv;
|
||||
}
|
||||
if (ymax) {
|
||||
*ymax = ymaxv;
|
||||
if (include_handles) {
|
||||
/* Need to check all handles because they might extend beyond their neighboring keys. */
|
||||
ChrisLend marked this conversation as resolved
Sybren A. Stüvel
commented
I think this should be using I think this should be using `index_range[1]`.
|
||||
for (int i = index_range[0]; i <= index_range[1]; i++) {
|
||||
BezTriple bezt = bezt_array[i];
|
||||
*r_min = min_fff(*r_min, bezt.vec[0][0], bezt.vec[1][0]);
|
||||
*r_max = max_fff(*r_max, bezt.vec[1][0], bezt.vec[2][0]);
|
||||
}
|
||||
dr.sybren marked this conversation as resolved
Sybren A. Stüvel
commented
`bezt` can be `const`, same in the function below.
Hans Goudey
commented
Better to not make a copy at all here. Better to not make a copy at all here. `BezTriple` is a rather large struct. In C the best option is `const BezTriple *bezt = &bezt_array[i];` The compiler probably optimizes that but it's a good way to show intentions too.
|
||||
}
|
||||
else {
|
||||
if (G.debug & G_DEBUG) {
|
||||
printf("F-Curve calc bounds didn't find anything, so assuming minimum bounds of 1.0\n");
|
||||
}
|
||||
|
||||
if (xmin) {
|
||||
*xmin = use_range ? range[0] : 0.0f;
|
||||
}
|
||||
if (xmax) {
|
||||
*xmax = use_range ? range[1] : 1.0f;
|
||||
}
|
||||
|
||||
if (ymin) {
|
||||
*ymin = 0.0f;
|
||||
}
|
||||
if (ymax) {
|
||||
*ymax = 1.0f;
|
||||
}
|
||||
*r_min = bezt_array[index_range[0]].vec[1][0];
|
||||
*r_max = bezt_array[index_range[1]].vec[1][0];
|
||||
}
|
||||
ChrisLend marked this conversation as resolved
Sybren A. Stüvel
commented
If I'm right about the initial assignment to If I'm right about the initial assignment to `*r_max` using `index_range[1]`, this entire `else` block can be removed.
|
||||
|
||||
return foundvert;
|
||||
}
|
||||
|
||||
bool BKE_fcurve_calc_range(
|
||||
const FCurve *fcu, float *start, float *end, const bool do_sel_only, const bool do_min_length)
|
||||
static void calculate_bezt_bounds_y(BezTriple *bezt_array,
|
||||
const int index_range[2],
|
||||
const bool do_sel_only,
|
||||
const bool include_handles,
|
||||
float *r_min,
|
||||
float *r_max)
|
||||
{
|
||||
float min = 999999999.0f, max = -999999999.0f;
|
||||
bool foundvert = false;
|
||||
*r_min = bezt_array[index_range[0]].vec[1][1];
|
||||
*r_max = bezt_array[index_range[0]].vec[1][1];
|
||||
|
||||
if (fcu->totvert) {
|
||||
if (fcu->bezt) {
|
||||
BezTriple *bezt_first = NULL, *bezt_last = NULL;
|
||||
BezTriple *bezt, *prev_bezt = NULL;
|
||||
for (int i = index_range[0]; i <= index_range[1]; i++) {
|
||||
bezt = &bezt_array[i];
|
||||
|
||||
/* Get endpoint keyframes. */
|
||||
get_fcurve_end_keyframes(fcu, &bezt_first, &bezt_last, do_sel_only, NULL);
|
||||
if (do_sel_only && !BEZT_ISSEL_ANY(bezt)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bezt_first) {
|
||||
BLI_assert(bezt_last != NULL);
|
||||
*r_min = min_ff(*r_min, bezt->vec[1][1]);
|
||||
*r_max = max_ff(*r_max, bezt->vec[1][1]);
|
||||
|
||||
min = min_ff(min, bezt_first->vec[1][0]);
|
||||
max = max_ff(max, bezt_last->vec[1][0]);
|
||||
if (include_handles) {
|
||||
/* Left handle - only if applicable.
|
||||
* NOTE: for the very first keyframe,
|
||||
* the left handle actually has no bearings on anything. */
|
||||
if (prev_bezt && (prev_bezt->ipo == BEZT_IPO_BEZ)) {
|
||||
*r_min = min_ff(*r_min, bezt->vec[0][1]);
|
||||
dr.sybren marked this conversation as resolved
Sybren A. Stüvel
commented
This is a tricky one. If the idea is to zoom the FCurve so that all the keys and handles are on screen, it doesn't matter that the left handle has no meaning; an animator may still want to interact with it in order to edit the animation. And with, for example, "Aligned" handle type, manipulating the left handle will move the right one, and thus still has an effect. This is a tricky one. If the idea is to zoom the FCurve so that all the keys and handles are on screen, it doesn't matter that the left handle has no meaning; an animator may still want to interact with it in order to edit the animation. And with, for example, "Aligned" handle type, manipulating the left handle will move the right one, and thus still has an effect.
I was hesitant to change that because I wasn't quite sure of the purpose I was hesitant to change that because I wasn't quite sure of the purpose
I removed that logic completely now. IMO this function shouldn't concern itself with the visibility/functionality of handles.
Controversial though :)
|
||||
*r_max = max_ff(*r_max, bezt->vec[0][1]);
|
||||
}
|
||||
|
||||
foundvert = true;
|
||||
/* Right handle - only if applicable. */
|
||||
if (bezt->ipo == BEZT_IPO_BEZ) {
|
||||
*r_min = min_ff(*r_min, bezt->vec[2][1]);
|
||||
*r_max = max_ff(*r_max, bezt->vec[2][1]);
|
||||
}
|
||||
}
|
||||
else if (fcu->fpt) {
|
||||
min = min_ff(min, fcu->fpt[0].vec[0]);
|
||||
max = max_ff(max, fcu->fpt[fcu->totvert - 1].vec[0]);
|
||||
prev_bezt = bezt;
|
||||
}
|
||||
}
|
||||
|
||||
foundvert = true;
|
||||
bool BKE_fcurve_calc_bounds(const FCurve *fcu,
|
||||
const bool do_sel_only,
|
||||
const bool include_handles,
|
||||
const float frame_range[2],
|
||||
rctf *r_bounds)
|
||||
{
|
||||
if (fcu->totvert == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fcu->bezt) {
|
||||
int index_range[2];
|
||||
ChrisLend marked this conversation as resolved
Sybren A. Stüvel
commented
I think this nesting of conditionals is too deep. Better to split up the function into one for Bezier curves and one for baked points. I think this nesting of conditionals is too deep. Better to split up the function into one for Bezier curves and one for baked points.
|
||||
const bool found_indices = get_bounding_bezt_indices(
|
||||
fcu, do_sel_only, frame_range, &index_range[0], &index_range[1]);
|
||||
if (!found_indices) {
|
||||
return false;
|
||||
}
|
||||
|
||||
calculate_bezt_bounds_x(
|
||||
fcu->bezt, index_range, include_handles, &r_bounds->xmin, &r_bounds->xmax);
|
||||
calculate_bezt_bounds_y(
|
||||
fcu->bezt, index_range, do_sel_only, include_handles, &r_bounds->ymin, &r_bounds->ymax);
|
||||
}
|
||||
|
||||
else if (fcu->fpt) {
|
||||
if (frame_range != NULL) {
|
||||
bool found_indices = false;
|
||||
for (int i = 0; i < fcu->totvert; i++) {
|
||||
if (fcu->fpt[i].vec[0] < frame_range[0] || fcu->fpt[i].vec[0] > frame_range[1]) {
|
||||
dr.sybren marked this conversation as resolved
Sybren A. Stüvel
commented
Since there are no handles, you can use the ordering of the points and do a binary search for the start of the range. You can then immediately handle the Since there are no handles, you can use the ordering of the points and do a binary search for the start of the range. You can then immediately handle the `xmin`, and when the last point in the range is found, update the `xmax`. Per point you then only need to consider the y-coordinates, cutting the number of operations in half.
|
||||
continue;
|
||||
}
|
||||
if (!found_indices) {
|
||||
ChrisLend marked this conversation as resolved
Sybren A. Stüvel
commented
Initialize Initialize `r_bounds` to `±∞` (so all minimum values to `∞` and all maximum values to `-∞`). Those are valid IEEE 754 floating point values, and work well with the min/max functions. That'll remove a boolean, a condition, and half of the lines of code.
|
||||
r_bounds->xmin = fcu->fpt[i].vec[0];
|
||||
r_bounds->xmax = fcu->fpt[i].vec[0];
|
||||
r_bounds->ymin = fcu->fpt[i].vec[1];
|
||||
r_bounds->ymax = fcu->fpt[i].vec[1];
|
||||
found_indices = true;
|
||||
}
|
||||
else {
|
||||
r_bounds->xmin = min_ff(r_bounds->xmin, fcu->fpt[i].vec[0]);
|
||||
r_bounds->xmax = max_ff(r_bounds->xmax, fcu->fpt[i].vec[0]);
|
||||
r_bounds->ymin = min_ff(r_bounds->ymin, fcu->fpt[i].vec[1]);
|
||||
r_bounds->ymax = max_ff(r_bounds->ymax, fcu->fpt[i].vec[1]);
|
||||
}
|
||||
}
|
||||
return found_indices;
|
||||
ChrisLend marked this conversation as resolved
Sybren A. Stüvel
commented
Here you can return Here you can return `r_bounds->xmin <= r_bounds->xmax`.
|
||||
}
|
||||
else {
|
||||
/* X range can be directly calculated from end verts. */
|
||||
Sybren A. Stüvel
commented
A different structure of the function could work well here:
A different structure of the function could work well here:
1. Find the start/end index (either 0 resp. `totvert - 1`, or the result of a binary search)
2. Loop over the points in the index range to find the min/max y.
can you clarify that, is that in regards to finding the start index when using a frame range? can you clarify that, is that in regards to finding the start index when using a frame range?
Sybren A. Stüvel
commented
I was thinking about code like this:
This uses I'm not 100% about the name of Update: using I was thinking about code like this:
```c
static bool calculate_fpt_bounds(const FCurve *fcu, const float frame_range[2], rctf *r_bounds)
{
r_bounds->xmin = INFINITY;
r_bounds->xmax = -INFINITY;
r_bounds->ymin = INFINITY;
r_bounds->ymax = -INFINITY;
const int first_index = 0;
const int last_index = fcu->totvert - 1;
int start_index = first_index;
int end_index = last_index;
if (frame_range != NULL) {
/* Start index can be calculated because fpt has a key on every full frame. */
const float start_index_f = frame_range[0] - fcu->fpt[0].vec[0];
const float end_index_f = start_index_f + frame_range[1] - frame_range[0];
if (start_index_f > last_index || end_index_f < first_index) {
/* Range is outside of keyframe samples. */
return false;
}
/* Range might be partially covering keyframe samples. */
start_index = clamp_i(start_index_f, first_index, last_index);
end_index = clamp_i(end_index_f, first_index, last_index);
}
/* X range can be directly calculated from end verts. */
r_bounds->xmin = fcu->fpt[start_index].vec[0];
r_bounds->xmax = fcu->fpt[end_index].vec[0];
for (int i = start_index; i <= end_index; i++) {
r_bounds->ymin = min_ff(r_bounds->ymin, fcu->fpt[i].vec[1]);
r_bounds->ymax = max_ff(r_bounds->ymax, fcu->fpt[i].vec[1]);
}
return BLI_rctf_is_valid(r_bounds);
}
```
This uses `INFINITY` instead of `FLT_MAX` so that valid and invalid values can always be distinguished. And it separates "determine the start/endices" from "finding the bounds".
I'm not 100% about the name of `start_index_f`, maybe `range_start_index` would be better.
**Update:** using `BLI_rctf_is_valid()` instead of writing all of that out.
|
||||
r_bounds->xmin = fcu->fpt[0].vec[0];
|
||||
r_bounds->xmax = fcu->fpt[fcu->totvert - 1].vec[0];
|
||||
|
||||
r_bounds->ymin = fcu->fpt[0].vec[1];
|
||||
r_bounds->ymax = fcu->fpt[0].vec[1];
|
||||
for (int i = 0; i < fcu->totvert; i++) {
|
||||
r_bounds->ymin = min_ff(r_bounds->ymin, fcu->fpt[i].vec[1]);
|
||||
r_bounds->ymax = max_ff(r_bounds->ymax, fcu->fpt[i].vec[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (foundvert == false) {
|
||||
min = max = 0.0f;
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
Sybren A. Stüvel
commented
No No `else` after `return`; `clang-tidy` will complain about this.
|
||||
if (do_min_length) {
|
||||
/* Minimum length is 1 frame. */
|
||||
if (min == max) {
|
||||
max += 1.0f;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BKE_fcurve_calc_range(const FCurve *fcu, float *start, float *end, const bool do_sel_only)
|
||||
{
|
||||
float min, max = 0.0f;
|
||||
bool foundvert = false;
|
||||
|
||||
if (fcu->totvert == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fcu->bezt) {
|
||||
int index_range[2];
|
||||
foundvert = get_bounding_bezt_indices(
|
||||
fcu, do_sel_only, NULL, &index_range[0], &index_range[1]);
|
||||
if (!foundvert) {
|
||||
return false;
|
||||
}
|
||||
const bool include_handles = false;
|
||||
calculate_bezt_bounds_x(fcu->bezt, index_range, include_handles, &min, &max);
|
||||
}
|
||||
else if (fcu->fpt) {
|
||||
min = fcu->fpt[0].vec[0];
|
||||
max = fcu->fpt[fcu->totvert - 1].vec[0];
|
||||
|
||||
foundvert = true;
|
||||
}
|
||||
|
||||
*start = min;
|
||||
|
|
|
@ -3651,14 +3651,8 @@ static void get_normalized_fcurve_bounds(FCurve *fcu,
|
|||
rctf *r_bounds)
|
||||
{
|
||||
const bool fcu_selection_only = false;
|
||||
BKE_fcurve_calc_bounds(fcu,
|
||||
&r_bounds->xmin,
|
||||
&r_bounds->xmax,
|
||||
&r_bounds->ymin,
|
||||
&r_bounds->ymax,
|
||||
fcu_selection_only,
|
||||
include_handles,
|
||||
range);
|
||||
BKE_fcurve_calc_bounds(fcu, fcu_selection_only, include_handles, range, r_bounds);
|
||||
|
||||
const short mapping_flag = ANIM_get_normalization_flags(ac);
|
||||
|
||||
float offset;
|
||||
|
@ -3806,6 +3800,7 @@ static int graphkeys_view_selected_channels_exec(bContext *C, wmOperator *op)
|
|||
|
||||
if (!valid_bounds) {
|
||||
ANIM_animdata_freelist(&anim_data);
|
||||
WM_report(RPT_WARNING, "No keyframes to focus on.");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
|
@ -3892,6 +3887,7 @@ static int graphkeys_channel_view_pick_invoke(bContext *C, wmOperator *op, const
|
|||
|
||||
if (!found_bounds) {
|
||||
ANIM_animdata_freelist(&anim_data);
|
||||
WM_report(RPT_WARNING, "No keyframes to focus on.");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
|
|
|
@ -203,7 +203,7 @@ static bool get_keyframe_extents(bAnimContext *ac, float *min, float *max, const
|
|||
float tmin, tmax;
|
||||
|
||||
/* get range and apply necessary scaling before processing */
|
||||
if (BKE_fcurve_calc_range(fcu, &tmin, &tmax, onlySel, false)) {
|
||||
if (BKE_fcurve_calc_range(fcu, &tmin, &tmax, onlySel)) {
|
||||
|
||||
if (adt) {
|
||||
tmin = BKE_nla_tweakedit_remap(adt, tmin, NLATIME_CONVERT_MAP);
|
||||
|
|
|
@ -633,7 +633,7 @@ static void draw_fcurve_curve(bAnimContext *ac,
|
|||
if (!draw_extrapolation) {
|
||||
float fcu_start = 0;
|
||||
float fcu_end = 0;
|
||||
BKE_fcurve_calc_range(fcu_, &fcu_start, &fcu_end, false, false);
|
||||
BKE_fcurve_calc_range(fcu_, &fcu_start, &fcu_end, false);
|
||||
|
||||
fcu_start = BKE_nla_tweakedit_remap(adt, fcu_start, NLATIME_CONVERT_MAP);
|
||||
fcu_end = BKE_nla_tweakedit_remap(adt, fcu_end, NLATIME_CONVERT_MAP);
|
||||
|
|
|
@ -86,40 +86,39 @@ void get_graph_keyframe_extents(bAnimContext *ac,
|
|||
for (ale = anim_data.first; ale; ale = ale->next) {
|
||||
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
|
||||
FCurve *fcu = (FCurve *)ale->key_data;
|
||||
float txmin, txmax, tymin, tymax;
|
||||
rctf bounds;
|
||||
float unitFac, offset;
|
||||
|
||||
/* Get range. */
|
||||
if (BKE_fcurve_calc_bounds(
|
||||
fcu, &txmin, &txmax, &tymin, &tymax, do_sel_only, include_handles, NULL)) {
|
||||
if (BKE_fcurve_calc_bounds(fcu, do_sel_only, include_handles, NULL, &bounds)) {
|
||||
short mapping_flag = ANIM_get_normalization_flags(ac);
|
||||
|
||||
/* Apply NLA scaling. */
|
||||
if (adt) {
|
||||
txmin = BKE_nla_tweakedit_remap(adt, txmin, NLATIME_CONVERT_MAP);
|
||||
txmax = BKE_nla_tweakedit_remap(adt, txmax, NLATIME_CONVERT_MAP);
|
||||
bounds.xmin = BKE_nla_tweakedit_remap(adt, bounds.xmin, NLATIME_CONVERT_MAP);
|
||||
bounds.xmax = BKE_nla_tweakedit_remap(adt, bounds.xmax, NLATIME_CONVERT_MAP);
|
||||
}
|
||||
|
||||
/* Apply unit corrections. */
|
||||
unitFac = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset);
|
||||
tymin += offset;
|
||||
tymax += offset;
|
||||
tymin *= unitFac;
|
||||
tymax *= unitFac;
|
||||
bounds.ymin += offset;
|
||||
bounds.ymax += offset;
|
||||
bounds.ymin *= unitFac;
|
||||
bounds.ymax *= unitFac;
|
||||
|
||||
/* Try to set cur using these values, if they're more extreme than previously set values.
|
||||
*/
|
||||
if ((xmin) && (txmin < *xmin)) {
|
||||
*xmin = txmin;
|
||||
if ((xmin) && (bounds.xmin < *xmin)) {
|
||||
*xmin = bounds.xmin;
|
||||
}
|
||||
if ((xmax) && (txmax > *xmax)) {
|
||||
*xmax = txmax;
|
||||
if ((xmax) && (bounds.xmax > *xmax)) {
|
||||
*xmax = bounds.xmax;
|
||||
}
|
||||
if ((ymin) && (tymin < *ymin)) {
|
||||
*ymin = tymin;
|
||||
if ((ymin) && (bounds.ymin < *ymin)) {
|
||||
*ymin = bounds.ymin;
|
||||
}
|
||||
if ((ymax) && (tymax > *ymax)) {
|
||||
*ymax = tymax;
|
||||
if ((ymax) && (bounds.ymax > *ymax)) {
|
||||
*ymax = bounds.ymax;
|
||||
}
|
||||
|
||||
foundBounds = true;
|
||||
|
|
|
@ -586,7 +586,7 @@ static void rna_FCurve_group_set(PointerRNA *ptr,
|
|||
/* calculate time extents of F-Curve */
|
||||
static void rna_FCurve_range(FCurve *fcu, float range[2])
|
||||
{
|
||||
BKE_fcurve_calc_range(fcu, range, range + 1, false, false);
|
||||
BKE_fcurve_calc_range(fcu, range, range + 1, false);
|
||||
}
|
||||
|
||||
static bool rna_FCurve_is_empty_get(PointerRNA *ptr)
|
||||
|
|
Document what the return value means.