diff options
author | Campbell Barton <ideasman42@gmail.com> | 2012-06-04 19:44:42 +0400 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2012-06-04 19:44:42 +0400 |
commit | 8ffeca1f604879b17aa77256bed11b8586f60e4d (patch) | |
tree | b6b5d998a779e750526a3df26d76aba8f9006970 /source | |
parent | a3f855f35d53602571236278f1f983b658a5cb6e (diff) |
copy mask file from tomato branch, sorry dont know how to do multiple of these at a time...
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/blenkernel/intern/mask.c | 2095 |
1 files changed, 2095 insertions, 0 deletions
diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c new file mode 100644 index 00000000000..870a84df66a --- /dev/null +++ b/source/blender/blenkernel/intern/mask.c @@ -0,0 +1,2095 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2012 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation, + * Sergey Sharybin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/mask.c + * \ingroup bke + */ + +#include <stddef.h> +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" +#include "BLI_path_util.h" +#include "BLI_string.h" +#include "BLI_listbase.h" +#include "BLI_math.h" + +#include "DNA_mask_types.h" +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_movieclip_types.h" +#include "DNA_tracking_types.h" + +#include "BKE_curve.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_mask.h" +#include "BKE_tracking.h" +#include "BKE_movieclip.h" +#include "BKE_utildefines.h" + +#include "raskter.h" + +MaskSplinePoint *BKE_mask_spline_point_array(MaskSpline *spline) +{ + return spline->points_deform ? spline->points_deform : spline->points; +} + +MaskSplinePoint *BKE_mask_spline_point_array_from_point(MaskSpline *spline, MaskSplinePoint *point_ref) +{ + if ((point_ref >= spline->points) && (point_ref < &spline->points[spline->tot_point])) { + return spline->points; + } + + if ((point_ref >= spline->points_deform) && (point_ref < &spline->points_deform[spline->tot_point])) { + return spline->points_deform; + } + + BLI_assert(!"wrong array"); + return NULL; +} + +/* mask layers */ + +MaskLayer *BKE_mask_layer_new(Mask *mask, const char *name) +{ + MaskLayer *masklay = MEM_callocN(sizeof(MaskLayer), __func__); + + if (name && name[0]) + BLI_strncpy(masklay->name, name, sizeof(masklay->name)); + else + strcpy(masklay->name, "MaskLayer"); + + BLI_addtail(&mask->masklayers, masklay); + + BKE_mask_layer_unique_name(mask, masklay); + + mask->masklay_tot++; + + masklay->alpha = 1.0f; + + return masklay; +} + +/* note: may still be hidden, caller needs to check */ +MaskLayer *BKE_mask_layer_active(Mask *mask) +{ + return BLI_findlink(&mask->masklayers, mask->masklay_act); +} + +void BKE_mask_layer_active_set(Mask *mask, MaskLayer *masklay) +{ + mask->masklay_act = BLI_findindex(&mask->masklayers, masklay); +} + +void BKE_mask_layer_remove(Mask *mask, MaskLayer *masklay) +{ + BLI_remlink(&mask->masklayers, masklay); + BKE_mask_layer_free(masklay); + + mask->masklay_tot--; + + if (mask->masklay_act >= mask->masklay_tot) + mask->masklay_act = mask->masklay_tot - 1; +} + +void BKE_mask_layer_unique_name(Mask *mask, MaskLayer *masklay) +{ + BLI_uniquename(&mask->masklayers, masklay, "MaskLayer", '.', offsetof(MaskLayer, name), sizeof(masklay->name)); +} + +/* splines */ + +MaskSpline *BKE_mask_spline_add(MaskLayer *masklay) +{ + MaskSpline *spline; + + spline = MEM_callocN(sizeof(MaskSpline), "new mask spline"); + BLI_addtail(&masklay->splines, spline); + + /* spline shall have one point at least */ + spline->points = MEM_callocN(sizeof(MaskSplinePoint), "new mask spline point"); + spline->tot_point = 1; + + /* cyclic shapes are more usually used */ + // spline->flag |= MASK_SPLINE_CYCLIC; // disable because its not so nice for drawing. could be done differently + + spline->weight_interp = MASK_SPLINE_INTERP_LINEAR; + + BKE_mask_parent_init(&spline->parent); + + return spline; +} + +static int BKE_mask_spline_resolution(MaskSpline *spline, int width, int height) +{ + float max_segment = 0.01f; + int i, resol = 1; + + if (width != 0 && height != 0) { + if (width >= height) + max_segment = 1.0f / (float) width; + else + max_segment = 1.0f / (float) height; + } + + for (i = 0; i < spline->tot_point; i++) { + MaskSplinePoint *point = &spline->points[i]; + MaskSplinePoint *next_point; + BezTriple *bezt, *next_bezt; + float a, b, c, len; + int cur_resol; + + if (i == spline->tot_point - 1) { + if (spline->flag & MASK_SPLINE_CYCLIC) + next_point = &spline->points[0]; + else + break; + } + else + next_point = &spline->points[i + 1]; + + bezt = &point->bezt; + next_bezt = &next_point->bezt; + + a = len_v3v3(bezt->vec[1], bezt->vec[2]); + b = len_v3v3(bezt->vec[2], next_bezt->vec[0]); + c = len_v3v3(next_bezt->vec[0], next_bezt->vec[1]); + + len = a + b + c; + cur_resol = len / max_segment; + + resol = MAX2(resol, cur_resol); + } + + return resol; +} + +static int BKE_mask_spline_feather_resolution(MaskSpline *spline, int width, int height) +{ + const float max_segment = 0.005; + int resol = BKE_mask_spline_resolution(spline, width, height); + float max_jump = 0.0f; + int i; + + for (i = 0; i < spline->tot_point; i++) { + MaskSplinePoint *point = &spline->points[i]; + float prev_u, prev_w; + int j; + + prev_u = 0.0f; + prev_w = point->bezt.weight; + + for (j = 0; j < point->tot_uw; j++) { + float jump = fabsf((point->uw[j].w - prev_w) / (point->uw[j].u - prev_u)); + + max_jump = MAX2(max_jump, jump); + + prev_u = point->uw[j].u; + prev_w = point->uw[j].w; + } + } + + resol += max_jump / max_segment; + + return resol; +} + +float (*BKE_mask_spline_differentiate_with_resolution(MaskSpline *spline, int width, int height, + int *tot_diff_point))[2] +{ + MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline); + + MaskSplinePoint *point, *prev; + float (*diff_points)[2], (*fp)[2]; + int a, len, resol = BKE_mask_spline_resolution(spline, width, height); + + if (spline->tot_point <= 1) { + /* nothing to differentiate */ + *tot_diff_point = 0; + return NULL; + } + + /* count */ + len = (spline->tot_point - 1) * resol; + + if (spline->flag & MASK_SPLINE_CYCLIC) + len += resol; + else + len++; + + /* len+1 because of 'forward_diff_bezier' function */ + *tot_diff_point = len; + diff_points = fp = MEM_mallocN((len + 1) * sizeof(*diff_points), "mask spline vets"); + + a = spline->tot_point - 1; + if (spline->flag & MASK_SPLINE_CYCLIC) + a++; + + prev = points_array; + point = prev + 1; + + while (a--) { + BezTriple *prevbezt; + BezTriple *bezt; + int j; + + if (a == 0 && (spline->flag & MASK_SPLINE_CYCLIC)) + point = points_array; + + prevbezt = &prev->bezt; + bezt = &point->bezt; + + for (j = 0; j < 2; j++) { + BKE_curve_forward_diff_bezier(prevbezt->vec[1][j], prevbezt->vec[2][j], + bezt->vec[0][j], bezt->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->vec[1]); + } + + prev = point; + point++; + } + + return diff_points; +} + +float (*BKE_mask_spline_differentiate(MaskSpline *spline, int *tot_diff_point))[2] +{ + return BKE_mask_spline_differentiate_with_resolution(spline, 0, 0, tot_diff_point); +} + +float (*BKE_mask_spline_feather_differentiated_points_with_resolution(MaskSpline *spline, int width, int height, + int *tot_feather_point))[2] +{ + MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline); + + float (*feather)[2], (*fp)[2]; + int i, j, tot, resol = BKE_mask_spline_feather_resolution(spline, width, height); + + tot = resol * spline->tot_point; + feather = fp = MEM_mallocN(tot * sizeof(*feather), "mask spline feather diff points"); + + for (i = 0; i < spline->tot_point; i++) { + MaskSplinePoint *point = &points_array[i]; + + for (j = 0; j < resol; j++, fp++) { + float u = (float) j / resol, weight; + float co[2], n[2]; + + /* TODO - these calls all calculate similar things + * could be unified for some speed */ + BKE_mask_point_segment_co(spline, point, u, co); + BKE_mask_point_normal(spline, point, u, n); + weight = BKE_mask_point_weight(spline, point, u); + + madd_v2_v2v2fl(*fp, co, n, weight); + } + } + + *tot_feather_point = tot; + + return feather; +} + +float (*BKE_mask_spline_feather_differentiated_points(MaskSpline *spline, int *tot_feather_point))[2] +{ + return BKE_mask_spline_feather_differentiated_points_with_resolution(spline, 0, 0, tot_feather_point); +} + +float (*BKE_mask_spline_feather_points(MaskSpline *spline, int *tot_feather_point))[2] +{ + MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline); + + int i, tot = 0; + float (*feather)[2], (*fp)[2]; + + /* count */ + for (i = 0; i < spline->tot_point; i++) { + MaskSplinePoint *point = &points_array[i]; + + tot += point->tot_uw + 1; + } + + /* create data */ + feather = fp = MEM_mallocN(tot * sizeof(*feather), "mask spline feather points"); + + for (i = 0; i < spline->tot_point; i++) { + MaskSplinePoint *point = &points_array[i]; + BezTriple *bezt = &point->bezt; + float weight, n[2]; + int j; + + BKE_mask_point_normal(spline, point, 0.0f, n); + weight = BKE_mask_point_weight(spline, point, 0.0f); + + madd_v2_v2v2fl(*fp, bezt->vec[1], n, weight); + fp++; + + for (j = 0; j < point->tot_uw; j++) { + float u = point->uw[j].u; + float co[2]; + + BKE_mask_point_segment_co(spline, point, u, co); + BKE_mask_point_normal(spline, point, u, n); + weight = BKE_mask_point_weight(spline, point, u); + + madd_v2_v2v2fl(*fp, co, n, weight); + fp++; + } + } + + *tot_feather_point = tot; + + return feather; +} + +void BKE_mask_point_direction_switch(MaskSplinePoint *point) +{ + const int tot_uw = point->tot_uw; + const int tot_uw_half = tot_uw / 2; + int i; + + if (tot_uw < 2) { + return; + } + + /* count */ + for (i = 0; i < tot_uw_half; i++) { + MaskSplinePointUW *uw_a = &point->uw[i]; + MaskSplinePointUW *uw_b = &point->uw[tot_uw - (i + 1)]; + SWAP(MaskSplinePointUW, *uw_a, *uw_b); + } + for (i = 0; i < tot_uw; i++) { + MaskSplinePointUW *uw = &point->uw[i]; + uw->u = 1.0f - uw->u; + } +} + +//typedef (float)[MASK_OBJECT_SHAPE_ELEM_SIZE] MaskLayerShapeElem; + +typedef struct MaskLayerShapeElem { + float value[MASK_OBJECT_SHAPE_ELEM_SIZE]; +} MaskLayerShapeElem; + +void BKE_mask_spline_direction_switch(MaskLayer *masklay, MaskSpline *spline) +{ + const int tot_point = spline->tot_point; + const int tot_point_half = tot_point / 2; + int i, i_prev; + + if (tot_point < 2) { + return; + } + + /* count */ + for (i = 0; i < tot_point_half; i++) { + MaskSplinePoint *point_a = &spline->points[i]; + MaskSplinePoint *point_b = &spline->points[tot_point - (i + 1)]; + SWAP(MaskSplinePoint, *point_a, *point_b); + } + + /* correct UW's */ + i_prev = tot_point - 1; + for (i = 0; i < tot_point; i++) { + + BKE_mask_point_direction_switch(&spline->points[i]); + + SWAP(MaskSplinePointUW *, spline->points[i].uw, spline->points[i_prev].uw); + SWAP(int, spline->points[i].tot_uw, spline->points[i_prev].tot_uw); + + i_prev = i; + } + + /* correct animation */ + if (masklay->splines_shapes.first) { + MaskLayerShape *masklay_shape; + + const int spline_index = BKE_mask_layer_shape_spline_to_index(masklay, spline); + + for (masklay_shape = masklay->splines_shapes.first; + masklay_shape; + masklay_shape = masklay_shape->next) + { + MaskLayerShapeElem *fp_arr = (MaskLayerShapeElem *)masklay_shape->data; + + for (i = 0; i < tot_point_half; i++) { + MaskLayerShapeElem *fp_a = &fp_arr[spline_index + (i) ]; + MaskLayerShapeElem *fp_b = &fp_arr[spline_index + (tot_point - (i + 1))]; + SWAP(MaskLayerShapeElem, *fp_a, *fp_b); + } + } + } +} + + +float BKE_mask_spline_project_co(MaskSpline *spline, MaskSplinePoint *point, float start_u, const float co[2]) +{ + const float proj_eps = 1e-3; + const float proj_eps_squared = proj_eps * proj_eps; + const int N = 1000; + float u = -1.0f, du = 1.0f / N, u1 = start_u, u2 = start_u; + float ang = -1.0f; + + while (u1 > 0.0f || u2 < 1.0f) { + float n1[2], n2[2], co1[2], co2[2]; + float v1[2], v2[2]; + float ang1, ang2; + + if (u1 >= 0.0f) { + BKE_mask_point_segment_co(spline, point, u1, co1); + BKE_mask_point_normal(spline, point, u1, n1); + sub_v2_v2v2(v1, co, co1); + + if (len_squared_v2(v1) > proj_eps_squared) { + ang1 = angle_v2v2(v1, n1); + if (ang1 > M_PI / 2.0f) + ang1 = M_PI - ang1; + + if (ang < 0.0f || ang1 < ang) { + ang = ang1; + u = u1; + } + } + else { + u = u1; + break; + } + } + + if (u2 <= 1.0f) { + BKE_mask_point_segment_co(spline, point, u2, co2); + BKE_mask_point_normal(spline, point, u2, n2); + sub_v2_v2v2(v2, co, co2); + + if (len_squared_v2(v2) > proj_eps_squared) { + ang2 = angle_v2v2(v2, n2); + if (ang2 > M_PI / 2.0f) + ang2 = M_PI - ang2; + + if (ang2 < ang) { + ang = ang2; + u = u2; + } + } + else { + u = u2; + break; + } + } + + u1 -= du; + u2 += du; + } + + return u; +} + +/* point */ + +int BKE_mask_point_has_handle(MaskSplinePoint *point) +{ + BezTriple *bezt = &point->bezt; + + return bezt->h1 == HD_ALIGN; +} + +void BKE_mask_point_handle(MaskSplinePoint *point, float handle[2]) +{ + float vec[2]; + + sub_v2_v2v2(vec, point->bezt.vec[0], point->bezt.vec[1]); + + handle[0] = (point->bezt.vec[1][0] + vec[1]); + handle[1] = (point->bezt.vec[1][1] - vec[0]); +} + +void BKE_mask_point_set_handle(MaskSplinePoint *point, float loc[2], int keep_direction, + float orig_handle[2], float orig_vec[3][3]) +{ + BezTriple *bezt = &point->bezt; + float v1[2], v2[2], vec[2]; + + if (keep_direction) { + sub_v2_v2v2(v1, loc, orig_vec[1]); + sub_v2_v2v2(v2, orig_handle, orig_vec[1]); + + project_v2_v2v2(vec, v1, v2); + + if (dot_v2v2(v2, vec) > 0) { + float len = len_v2(vec); + + sub_v2_v2v2(v1, orig_vec[0], orig_vec[1]); + + mul_v2_fl(v1, len / len_v2(v1)); + + add_v2_v2v2(bezt->vec[0], bezt->vec[1], v1); + sub_v2_v2v2(bezt->vec[2], bezt->vec[1], v1); + } + else { + copy_v3_v3(bezt->vec[0], bezt->vec[1]); + copy_v3_v3(bezt->vec[2], bezt->vec[1]); + } + } + else { + sub_v2_v2v2(v1, loc, bezt->vec[1]); + + v2[0] = -v1[1]; + v2[1] = v1[0]; + + add_v2_v2v2(bezt->vec[0], bezt->vec[1], v2); + sub_v2_v2v2(bezt->vec[2], bezt->vec[1], v2); + } +} + +float *BKE_mask_point_segment_feather_diff_with_resolution(MaskSpline *spline, MaskSplinePoint *point, + int width, int height, + int *tot_feather_point) +{ + float *feather, *fp; + int i, resol = BKE_mask_spline_feather_resolution(spline, width, height); + + feather = fp = MEM_callocN(2 * resol * sizeof(float), "mask point spline feather diff points"); + + for (i = 0; i < resol; i++, fp += 2) { + float u = (float)(i % resol) / resol, weight; + float co[2], n[2]; + + BKE_mask_point_segment_co(spline, point, u, co); + BKE_mask_point_normal(spline, point, u, n); + weight = BKE_mask_point_weight(spline, point, u); + + fp[0] = co[0] + n[0] * weight; + fp[1] = co[1] + n[1] * weight; + } + + *tot_feather_point = resol; + + return feather; +} + +float *BKE_mask_point_segment_feather_diff(MaskSpline *spline, MaskSplinePoint *point, int *tot_feather_point) +{ + return BKE_mask_point_segment_feather_diff_with_resolution(spline, point, 0, 0, tot_feather_point); +} + +float *BKE_mask_point_segment_diff_with_resolution(MaskSpline *spline, MaskSplinePoint *point, + int width, int height, int *tot_diff_point) +{ + MaskSplinePoint *points_array = BKE_mask_spline_point_array_from_point(spline, point); + + BezTriple *bezt, *next; + float *diff_points, *fp; + int j, resol = BKE_mask_spline_resolution(spline, width, height); + + bezt = &point->bezt; + + if (point == &points_array[spline->tot_point - 1]) { + if (spline->flag & MASK_SPLINE_CYCLIC) + next = &(points_array[0].bezt); + else + next = NULL; + } + else next = &((point + 1))->bezt; + + if (!next) + return NULL; + + /* resol+1 because of 'forward_diff_bezier' function */ + *tot_diff_point = resol + 1; + diff_points = fp = MEM_callocN((resol + 1) * 2 * sizeof(float), "mask segment vets"); + + for (j = 0; j < 2; j++) { + BKE_curve_forward_diff_bezier(bezt->vec[1][j], bezt->vec[2][j], + next->vec[0][j], next->vec[1][j], + fp + j, resol, 2 * sizeof(float)); + } + + copy_v2_v2(fp + 2 * resol, next->vec[1]); + + return diff_points; +} + +float *BKE_mask_point_segment_diff(MaskSpline *spline, MaskSplinePoint *point, int *tot_diff_point) +{ + return BKE_mask_point_segment_diff_with_resolution(spline, point, 0, 0, tot_diff_point); +} + +void BKE_mask_point_segment_co(MaskSpline *spline, MaskSplinePoint *point, float u, float co[2]) +{ + MaskSplinePoint *points_array = BKE_mask_spline_point_array_from_point(spline, point); + + BezTriple *bezt = &point->bezt, *next; + float q0[2], q1[2], q2[2], r0[2], r1[2]; + + if (point == &points_array[spline->tot_point - 1]) { + if (spline->flag & MASK_SPLINE_CYCLIC) + next = &(points_array[0].bezt); + else + next = NULL; + } + else next = &((point + 1))->bezt; + + if (!next) { + copy_v2_v2(co, bezt->vec[1]); + return; + } + + interp_v2_v2v2(q0, bezt->vec[1], bezt->vec[2], u); + interp_v2_v2v2(q1, bezt->vec[2], next->vec[0], u); + interp_v2_v2v2(q2, next->vec[0], next->vec[1], u); + + interp_v2_v2v2(r0, q0, q1, u); + interp_v2_v2v2(r1, q1, q2, u); + + interp_v2_v2v2(co, r0, r1, u); +} + +void BKE_mask_point_normal(MaskSpline *spline, MaskSplinePoint *point, float u, float n[2]) +{ + MaskSplinePoint *points_array = BKE_mask_spline_point_array_from_point(spline, point); + + BezTriple *bezt = &point->bezt, *next; + float q0[2], q1[2], q2[2], r0[2], r1[2], vec[2]; + + if (point == &points_array[spline->tot_point - 1]) { + if (spline->flag & MASK_SPLINE_CYCLIC) + next = &(points_array[0].bezt); + else + next = NULL; + } + else { + next = &((point + 1))->bezt; + } + + if (!next) { + BKE_mask_point_handle(point, vec); + + sub_v2_v2v2(n, vec, bezt->vec[1]); + normalize_v2(n); + return; + } + + interp_v2_v2v2(q0, bezt->vec[1], bezt->vec[2], u); + interp_v2_v2v2(q1, bezt->vec[2], next->vec[0], u); + interp_v2_v2v2(q2, next->vec[0], next->vec[1], u); + + interp_v2_v2v2(r0, q0, q1, u); + interp_v2_v2v2(r1, q1, q2, u); + + sub_v2_v2v2(vec, r1, r0); + + n[0] = -vec[1]; + n[1] = vec[0]; + + normalize_v2(n); +} + +float BKE_mask_point_weight(MaskSpline *spline, MaskSplinePoint *point, float u) +{ + MaskSplinePoint *points_array = BKE_mask_spline_point_array_from_point(spline, point); + + BezTriple *bezt = &point->bezt, *bezt_next; + float cur_u, cur_w, next_u, next_w, fac; + int i; + + if (point == &points_array[spline->tot_point - 1]) { + if (spline->flag & MASK_SPLINE_CYCLIC) { + bezt_next = &(points_array[0].bezt); + } + else { + bezt_next = NULL; + } + } + else { + bezt_next = &((point + 1))->bezt; + } + + if (!bezt_next) + return bezt->weight; + + for (i = 0; i < point->tot_uw + 1; i++) { + + if (i == 0) { + cur_u = 0.0f; + cur_w = bezt->weight; + } + else { + cur_u = point->uw[i - 1].u; + cur_w = point->uw[i - 1].w; + } + + if (i == point->tot_uw) { + next_u = 1.0f; + next_w = bezt_next->weight; + } + else { + next_u = point->uw[i].u; + next_w = point->uw[i].w; + } + + if (u >= cur_u && u <= next_u) { + break; + } + } + + fac = (u - cur_u) / (next_u - cur_u); + + if (spline->weight_interp == MASK_SPLINE_INTERP_EASE) + return cur_w + (next_w - cur_w) * (3.0f * fac * fac - 2.0f * fac * fac * fac); + else + return (1.0f - fac) * cur_w + fac * next_w; +} + +MaskSplinePointUW *BKE_mask_point_sort_uw(MaskSplinePoint *point, MaskSplinePointUW *uw) +{ + if (point->tot_uw > 1) { + int idx = uw - point->uw; + + if (idx > 0 && point->uw[idx - 1].u > uw->u) { + while (idx > 0 && point->uw[idx - 1].u > point->uw[idx].u) { + SWAP(MaskSplinePointUW, point->uw[idx - 1], point->uw[idx]); + idx--; + } + } + + if (idx < point->tot_uw - 1 && point->uw[idx + 1].u < uw->u) { + while (idx < point->tot_uw - 1 && point->uw[idx + 1].u < point->uw[idx].u) { + SWAP(MaskSplinePointUW, point->uw[idx + 1], point->uw[idx]); + idx++; + } + } + + return &point->uw[idx]; + } + + return uw; +} + +void BKE_mask_point_add_uw(MaskSplinePoint *point, float u, float w) +{ + if (!point->uw) + point->uw = MEM_callocN(sizeof(*point->uw), "mask point uw"); + else + point->uw = MEM_reallocN(point->uw, (point->tot_uw + 1) * sizeof(*point->uw)); + + point->uw[point->tot_uw].u = u; + point->uw[point->tot_uw].w = w; + + point->tot_uw++; + + BKE_mask_point_sort_uw(point, &point->uw[point->tot_uw - 1]); +} + +void BKE_mask_point_select_set(MaskSplinePoint *point, const short do_select) +{ + int i; + + if (do_select) { + MASKPOINT_SEL_ALL(point); + } + else { + MASKPOINT_DESEL_ALL(point); + } + + for (i = 0; i < point->tot_uw; i++) { + if (do_select) { + point->uw[i].flag |= SELECT; + } + else { + point->uw[i].flag &= ~SELECT; + } + } +} + +void BKE_mask_point_select_set_handle(MaskSplinePoint *point, const short do_select) +{ + if (do_select) { + MASKPOINT_SEL_HANDLE(point); + } + else { + MASKPOINT_DESEL_HANDLE(point); + } +} + +/* only mask block itself */ +static Mask *mask_alloc(const char *name) +{ + Mask *mask; + + mask = BKE_libblock_alloc(&G.main->mask, ID_MSK, name); + + return mask; +} + +Mask *BKE_mask_new(const char *name) +{ + Mask *mask; + char mask_name[MAX_ID_NAME - 2]; + + if (name && name[0]) + BLI_strncpy(mask_name, name, sizeof(mask_name)); + else + strcpy(mask_name, "Mask"); + + mask = mask_alloc(mask_name); + + return mask; +} + +void BKE_mask_point_free(MaskSplinePoint *point) +{ + if (point->uw) + MEM_freeN(point->uw); +} + +void BKE_mask_spline_free(MaskSpline *spline) +{ + int i = 0; + + for (i = 0; i < spline->tot_point; i++) { + MaskSplinePoint *point; + point = &spline->points[i]; + BKE_mask_point_free(point); + + if (spline->points_deform) { + point = &spline->points_deform[i]; + BKE_mask_point_free(point); + } + } + + MEM_freeN(spline->points); + + if (spline->points_deform) { + MEM_freeN(spline->points_deform); + } + + MEM_freeN(spline); +} + +MaskSpline *BKE_mask_spline_copy(MaskSpline *spline) +{ + MaskSpline *nspline = MEM_callocN(sizeof(MaskSpline), "new spline"); + int i; + + *nspline = *spline; + + nspline->points_deform = NULL; + nspline->points = MEM_dupallocN(nspline->points); + + for (i = 0; i < nspline->tot_point; i++) { + MaskSplinePoint *point = &nspline->points[i]; + + if (point->uw) + point->uw = MEM_dupallocN(point->uw); + } + + return nspline; +} + +void BKE_mask_layer_shape_free(MaskLayerShape *masklay_shape) +{ + MEM_freeN(masklay_shape->data); + + MEM_freeN(masklay_shape); +} + +void BKE_mask_layer_free(MaskLayer *masklay) +{ + MaskSpline *spline; + MaskLayerShape *masklay_shape; + + /* free splines */ + spline = masklay->splines.first; + while (spline) { + MaskSpline *next_spline = spline->next; + + BLI_remlink(&masklay->splines, spline); + BKE_mask_spline_free(spline); + + spline = next_spline; + } + + /* free animation data */ + masklay_shape = masklay->splines_shapes.first; + while (masklay_shape) { + MaskLayerShape *next_masklay_shape = masklay_shape->next; + + BLI_remlink(&masklay->splines_shapes, masklay_shape); + BKE_mask_layer_shape_free(masklay_shape); + + masklay_shape = next_masklay_shape; + } + + MEM_freeN(masklay); +} + +void BKE_mask_free(Mask *mask) +{ + MaskLayer *masklay = mask->masklayers.first; + + while (masklay) { + MaskLayer *next_masklay = masklay->next; + + BLI_remlink(&mask->masklayers, masklay); + BKE_mask_layer_free(masklay); + + masklay = next_masklay; + } +} + +void BKE_mask_unlink(Main *bmain, Mask *mask) +{ + bScreen *scr; + ScrArea *area; + SpaceLink *sl; + + for (scr = bmain->screen.first; scr; scr = scr->id.next) { + for (area = scr->areabase.first; area; area = area->next) { + for (sl = area->spacedata.first; sl; sl = sl->next) { + if (sl->spacetype == SPACE_CLIP) { + SpaceClip *sc = (SpaceClip *) sl; + + if (sc->mask == mask) + sc->mask = NULL; + } + } + } + } + + mask->id.us = 0; +} + +void BKE_mask_coord_from_movieclip(MovieClip *clip, MovieClipUser *user, float r_co[2], const float co[2]) +{ + int width, height; + + /* scaling for the clip */ + BKE_movieclip_get_size(clip, user, &width, &height); + + if (width == height) { + r_co[0] = co[0]; + r_co[1] = co[1]; + } + else if (width < height) { + r_co[0] = ((co[0] - 0.5f) * ((float)width / (float)height)) + 0.5f; + r_co[1] = co[1]; + } + else { /* (width > height) */ + r_co[0] = co[0]; + r_co[1] = ((co[1] - 0.5f) * ((float)height / (float)width)) + 0.5f; + } +} + +/* as above but divide */ +void BKE_mask_coord_to_movieclip(MovieClip *clip, MovieClipUser *user, float r_co[2], const float co[2]) +{ + int width, height; + + /* scaling for the clip */ + BKE_movieclip_get_size(clip, user, &width, &height); + + if (width == height) { + r_co[0] = co[0]; + r_co[1] = co[1]; + } + else if (width < height) { + r_co[0] = ((co[0] - 0.5f) / ((float)width / (float)height)) + 0.5f; + r_co[1] = co[1]; + } + else { /* (width > height) */ + r_co[0] = co[0]; + r_co[1] = ((co[1] - 0.5f) / ((float)height / (float)width)) + 0.5f; + } +} + +static int BKE_mask_evaluate_parent(MaskParent *parent, float ctime, float r_co[2]) +{ + if (!parent) + return FALSE; + + if ((parent->flag & MASK_PARENT_ACTIVE) == 0) + return FALSE; + + if (parent->id_type == ID_MC) { + if (parent->id) { + MovieClip *clip = (MovieClip *) parent->id; + MovieTracking *tracking = (MovieTracking *) &clip->tracking; + MovieTrackingObject *ob = BKE_tracking_named_object(tracking, parent->parent); + + if (ob) { + MovieTrackingTrack *track = BKE_tracking_named_track(tracking, ob, parent->sub_parent); + + MovieClipUser user = {0}; + user.framenr = ctime; + + if (track) { + MovieTrackingMarker *marker = BKE_tracking_get_marker(track, ctime); + float marker_pos_ofs[2]; + add_v2_v2v2(marker_pos_ofs, marker->pos, track->offset); + BKE_mask_coord_from_movieclip(clip, &user, r_co, marker_pos_ofs); + + return TRUE; + } + } + } + } + + return FALSE; +} + +int BKE_mask_evaluate_parent_delta(MaskParent *parent, float ctime, float r_delta[2]) +{ + float parent_co[2]; + + if (BKE_mask_evaluate_parent(parent, ctime, parent_co)) { + sub_v2_v2v2(r_delta, parent_co, parent->parent_orig); + return TRUE; + } + else { + return FALSE; + } +} + +static void mask_calc_point_handle(MaskSplinePoint *point, MaskSplinePoint *prev_point, MaskSplinePoint *next_point) +{ + BezTriple *bezt = &point->bezt; + BezTriple *prev_bezt = NULL, *next_bezt = NULL; + //int handle_type = bezt->h1; + + if (prev_point) + prev_bezt = &prev_point->bezt; + + if (next_point) + next_bezt = &next_point->bezt; + +#if 1 + if (prev_bezt || next_bezt) { + BKE_nurb_handle_calc(bezt, prev_bezt, next_bezt, 0); + } +#else + if (handle_type == HD_VECT) { + BKE_nurb_handle_calc(bezt, prev_bezt, next_bezt, 0); + } + else if (handle_type == HD_AUTO) { + BKE_nurb_handle_calc(bezt, prev_bezt, next_bezt, 0); + } + else if (handle_type == HD_ALIGN) { + float v1[3], v2[3]; + float vec[3], h[3]; + + sub_v3_v3v3(v1, bezt->vec[0], bezt->vec[1]); + sub_v3_v3v3(v2, bezt->vec[2], bezt->vec[1]); + add_v3_v3v3(vec, v1, v2); + + if (len_v3(vec) > 1e-3) { + h[0] = vec[1]; + h[1] = -vec[0]; + h[2] = 0.0f; + } + else { + copy_v3_v3(h, v1); + } + + add_v3_v3v3(bezt->vec[0], bezt->vec[1], h); + sub_v3_v3v3(bezt->vec[2], bezt->vec[1], h); + } +#endif +} + +void BKE_mask_get_handle_point_adjacent(Mask *UNUSED(mask), MaskSpline *spline, MaskSplinePoint *point, + MaskSplinePoint **r_point_prev, MaskSplinePoint **r_point_next) +{ + MaskSplinePoint *prev_point, *next_point; + int i = (int)(point - spline->points); + + BLI_assert(i >= i && i < spline->tot_point); + + if (i == 0) { + if (spline->flag & MASK_SPLINE_CYCLIC) { + prev_point = &spline->points[spline->tot_point - 1]; + } + else { + prev_point = NULL; + } + } + else { + prev_point = point - 1; + } + + if (i == spline->tot_point - 1) { + if (spline->flag & MASK_SPLINE_CYCLIC) { + next_point = &spline->points[0]; + } + else { + next_point = NULL; + } + } + else { + next_point = point + 1; + } + + *r_point_prev = prev_point; + *r_point_next = next_point; +} + +/* calculates the tanget of a point by its previous and next + * (ignoring handles - as if its a poly line) */ +void BKE_mask_calc_tangent_polyline(Mask *mask, MaskSpline *spline, MaskSplinePoint *point, float t[2]) +{ + float tvec_a[2], tvec_b[2]; + + MaskSplinePoint *prev_point, *next_point; + + BKE_mask_get_handle_point_adjacent(mask, spline, point, + &prev_point, &next_point); + + if (prev_point) { + sub_v2_v2v2(tvec_a, point->bezt.vec[1], prev_point->bezt.vec[1]); + normalize_v2(tvec_a); + } + else { + zero_v2(tvec_a); + } + + if (next_point) { + sub_v2_v2v2(tvec_b, next_point->bezt.vec[1], point->bezt.vec[1]); + normalize_v2(tvec_b); + } + else { + zero_v2(tvec_b); + } + + add_v2_v2v2(t, tvec_a, tvec_b); + normalize_v2(t); +} + +void BKE_mask_calc_handle_point(Mask *mask, MaskSpline *spline, MaskSplinePoint *point) +{ + MaskSplinePoint *prev_point, *next_point; + + BKE_mask_get_handle_point_adjacent(mask, spline, point, + &prev_point, &next_point); + + mask_calc_point_handle(point, prev_point, next_point); +} + +static void enforce_dist_v2_v2fl(float v1[2], const float v2[2], const float dist) +{ + if (!equals_v2v2(v2, v1)) { + float nor[2]; + + sub_v2_v2v2(nor, v1, v2); + normalize_v2(nor); + madd_v2_v2v2fl(v1, v2, nor, dist); + } +} + +void BKE_mask_calc_handle_adjacent_interp(Mask *mask, MaskSpline *spline, MaskSplinePoint *point, const float u) +{ + /* TODO! - make this interpolate between siblings - not always midpoint! */ + int length_tot = 0; + float length_average = 0.0f; + float weight_average = 0.0f; + + + MaskSplinePoint *prev_point, *next_point; + + BLI_assert(u >= 0.0f && u <= 1.0f); + + BKE_mask_get_handle_point_adjacent(mask, spline, point, + &prev_point, &next_point); + + if (prev_point && next_point) { + length_average = ((len_v2v2(prev_point->bezt.vec[0], prev_point->bezt.vec[1]) * (1.0f - u)) + + (len_v2v2(next_point->bezt.vec[2], next_point->bezt.vec[1]) * u)); + + weight_average = (prev_point->bezt.weight * (1.0f - u) + + next_point->bezt.weight * u); + length_tot = 1; + } + else { + if (prev_point) { + length_average += len_v2v2(prev_point->bezt.vec[0], prev_point->bezt.vec[1]); + weight_average += prev_point->bezt.weight; + length_tot++; + } + + if (next_point) { + length_average += len_v2v2(next_point->bezt.vec[2], next_point->bezt.vec[1]); + weight_average += next_point->bezt.weight; + length_tot++; + } + } + + if (length_tot) { + length_average /= (float)length_tot; + weight_average /= (float)length_tot; + + enforce_dist_v2_v2fl(point->bezt.vec[0], point->bezt.vec[1], length_average); + enforce_dist_v2_v2fl(point->bezt.vec[2], point->bezt.vec[1], length_average); + point->bezt.weight = weight_average; + } +} + + +/** + * \brief Resets auto handles even for non-auto bezier points + * + * Useful for giving sane defaults. + */ +void BKE_mask_calc_handle_point_auto(Mask *mask, MaskSpline *spline, MaskSplinePoint *point, + const short do_recalc_length) +{ + MaskSplinePoint *prev_point, *next_point; + const char h_back[2] = {point->bezt.h1, point->bezt.h2}; + const float length_average = (do_recalc_length) ? 0.0f /* dummy value */ : + (len_v3v3(point->bezt.vec[0], point->bezt.vec[1]) + + len_v3v3(point->bezt.vec[1], point->bezt.vec[2])) / 2.0f; + + BKE_mask_get_handle_point_adjacent(mask, spline, point, + &prev_point, &next_point); + + point->bezt.h1 = HD_AUTO; + point->bezt.h2 = HD_AUTO; + mask_calc_point_handle(point, prev_point, next_point); + + point->bezt.h1 = h_back[0]; + point->bezt.h2 = h_back[1]; + + /* preserve length by applying it back */ + if (do_recalc_length == FALSE) { + enforce_dist_v2_v2fl(point->bezt.vec[0], point->bezt.vec[1], length_average); + enforce_dist_v2_v2fl(point->bezt.vec[2], point->bezt.vec[1], length_average); + } +} + +void BKE_mask_calc_handles(Mask *mask) +{ + MaskLayer *masklay; + + for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { + MaskSpline *spline; + + for (spline = masklay->splines.first; spline; spline = spline->next) { + int i; + + for (i = 0; i < spline->tot_point; i++) { + BKE_mask_calc_handle_point(mask, spline, &spline->points[i]); + + /* could be done in a different function... */ + if (spline->points_deform) { + BKE_mask_calc_handle_point(mask, spline, &spline->points[i]); + } + } + } + } +} + +void BKE_mask_update_deform(Mask *mask) +{ + MaskLayer *masklay; + + for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { + MaskSpline *spline; + + for (spline = masklay->splines.first; spline; spline = spline->next) { + int i; + + for (i = 0; i < spline->tot_point; i++) { + const int i_prev = (i - 1) % spline->tot_point; + const int i_next = (i + 1) % spline->tot_point; + + BezTriple *bezt_prev = &spline->points[i_prev].bezt; + BezTriple *bezt = &spline->points[i].bezt; + BezTriple *bezt_next = &spline->points[i_next].bezt; + + BezTriple *bezt_def_prev = &spline->points_deform[i_prev].bezt; + BezTriple *bezt_def = &spline->points_deform[i].bezt; + BezTriple *bezt_def_next = &spline->points_deform[i_next].bezt; + + float w_src[4]; + int j; + + for (j = 0; j <= 2; j += 2) { /* (0, 2) */ + printf("--- %d %d, %d, %d\n", i, j, i_prev, i_next); + barycentric_weights_v2(bezt_prev->vec[1], bezt->vec[1], bezt_next->vec[1], + bezt->vec[j], w_src); + interp_v3_v3v3v3(bezt_def->vec[j], + bezt_def_prev->vec[1], bezt_def->vec[1], bezt_def_next->vec[1], w_src); + } + } + } + } +} + +void BKE_mask_spline_ensure_deform(MaskSpline *spline) +{ + int allocated_points = (MEM_allocN_len(spline->points_deform) / sizeof(*spline->points_deform)); + // printf("SPLINE ALLOC %p %d\n", spline->points_deform, allocated_points); + + if (spline->points_deform == NULL || allocated_points != spline->tot_point) { + printf("alloc new deform spline\n"); + + if (spline->points_deform) { + int i; + + for (i = 0; i < allocated_points; i++) { + MaskSplinePoint *point = &spline->points_deform[i]; + BKE_mask_point_free(point); + } + + MEM_freeN(spline->points_deform); + } + + spline->points_deform = MEM_callocN(sizeof(*spline->points_deform) * spline->tot_point, __func__); + } + else { + // printf("alloc spline done\n"); + } +} + +void BKE_mask_evaluate(Mask *mask, float ctime, const int do_newframe) +{ + MaskLayer *masklay; + + for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { + + /* animation if available */ + if (do_newframe) { + MaskLayerShape *masklay_shape_a; + MaskLayerShape *masklay_shape_b; + int found; + + if ((found = BKE_mask_layer_shape_find_frame_range(masklay, (int)ctime, + &masklay_shape_a, &masklay_shape_b))) + { + if (found == 1) { +#if 0 + printf("%s: exact %d %d (%d)\n", __func__, (int)ctime, BLI_countlist(&masklay->splines_shapes), + masklay_shape_a->frame); +#endif + + BKE_mask_layer_shape_to_mask(masklay, masklay_shape_a); + } + else if (found == 2) { + float w = masklay_shape_b->frame - masklay_shape_a->frame; +#if 0 + printf("%s: tween %d %d (%d %d)\n", __func__, (int)ctime, BLI_countlist(&masklay->splines_shapes), + masklay_shape_a->frame, masklay_shape_b->frame); +#endif + BKE_mask_layer_shape_to_mask_interp(masklay, masklay_shape_a, masklay_shape_b, + (ctime - masklay_shape_a->frame) / w); + } + else { + /* always fail, should never happen */ + BLI_assert(found == 2); + } + } + } + /* animation done... */ + } + + BKE_mask_calc_handles(mask); + + + for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { + MaskSpline *spline; + int i; + + for (spline = masklay->splines.first; spline; spline = spline->next) { + + BKE_mask_spline_ensure_deform(spline); + + for (i = 0; i < spline->tot_point; i++) { + MaskSplinePoint *point = &spline->points[i]; + MaskSplinePoint *point_deform = &spline->points_deform[i]; + float delta[2]; + + BKE_mask_point_free(point_deform); + + *point_deform = *point; + point_deform->uw = point->uw ? MEM_dupallocN(point->uw) : NULL; + + if (BKE_mask_evaluate_parent_delta(&point->parent, ctime, delta)) { + add_v2_v2(point_deform->bezt.vec[0], delta); + add_v2_v2(point_deform->bezt.vec[1], delta); + add_v2_v2(point_deform->bezt.vec[2], delta); + } + } + } + } +} + +/* the purpose of this function is to ensure spline->points_deform is never out of date. + * for now re-evaluate all. eventually this might work differently */ +void BKE_mask_update_display(Mask *mask, float ctime) +{ +#if 0 + MaskLayer *masklay; + + for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { + MaskSpline *spline; + + for (spline = masklay->splines.first; spline; spline = spline->next) { + if (spline->points_deform) { + int i = 0; + + for (i = 0; i < spline->tot_point; i++) { + MaskSplinePoint *point; + + if (spline->points_deform) { + point = &spline->points_deform[i]; + BKE_mask_point_free(point); + } + } + if (spline->points_deform) { + MEM_freeN(spline->points_deform); + } + + spline->points_deform = NULL; + } + } + } +#endif + + BKE_mask_evaluate(mask, ctime, FALSE); +} + +void BKE_mask_evaluate_all_masks(Main *bmain, float ctime, const int do_newframe) +{ + Mask *mask; + + for (mask = bmain->mask.first; mask; mask = mask->id.next) { + BKE_mask_evaluate(mask, ctime, do_newframe); + } +} + +void BKE_mask_update_scene(Main *bmain, Scene *scene, const int do_newframe) +{ + Mask *mask; + + for (mask = bmain->mask.first; mask; mask = mask->id.next) { + if (mask->id.flag & LIB_ID_RECALC) { + BKE_mask_evaluate_all_masks(bmain, CFRA, do_newframe); + } + } +} + +void BKE_mask_parent_init(MaskParent *parent) +{ + parent->id_type = ID_MC; +} + + +/* *** own animation/shapekey implimentation *** + * BKE_mask_layer_shape_XXX */ + +int BKE_mask_layer_shape_totvert(MaskLayer *masklay) +{ + int tot = 0; + MaskSpline *spline; + + for (spline = masklay->splines.first; spline; spline = spline->next) { + tot += spline->tot_point; + } + + return tot; +} + +static void mask_layer_shape_from_mask_point(BezTriple *bezt, float fp[MASK_OBJECT_SHAPE_ELEM_SIZE]) +{ + copy_v2_v2(&fp[0], bezt->vec[0]); + copy_v2_v2(&fp[2], bezt->vec[1]); + copy_v2_v2(&fp[4], bezt->vec[2]); + fp[6] = bezt->weight; + fp[7] = bezt->radius; +} + +static void mask_layer_shape_to_mask_point(BezTriple *bezt, float fp[MASK_OBJECT_SHAPE_ELEM_SIZE]) +{ + copy_v2_v2(bezt->vec[0], &fp[0]); + copy_v2_v2(bezt->vec[1], &fp[2]); + copy_v2_v2(bezt->vec[2], &fp[4]); + bezt->weight = fp[6]; + bezt->radius = fp[7]; +} + +/* these functions match. copy is swapped */ +void BKE_mask_layer_shape_from_mask(MaskLayer *masklay, MaskLayerShape *masklay_shape) +{ + int tot = BKE_mask_layer_shape_totvert(masklay); + + if (masklay_shape->tot_vert == tot) { + float *fp = masklay_shape->data; + + MaskSpline *spline; + for (spline = masklay->splines.first; spline; spline = spline->next) { + int i; + for (i = 0; i < spline->tot_point; i++) { + mask_layer_shape_from_mask_point(&spline->points[i].bezt, fp); + fp += MASK_OBJECT_SHAPE_ELEM_SIZE; + } + } + } + else { + printf("%s: vert mismatch %d != %d (frame %d)\n", + __func__, masklay_shape->tot_vert, tot, masklay_shape->frame); + } +} + +void BKE_mask_layer_shape_to_mask(MaskLayer *masklay, MaskLayerShape *masklay_shape) +{ + int tot = BKE_mask_layer_shape_totvert(masklay); + + if (masklay_shape->tot_vert == tot) { + float *fp = masklay_shape->data; + + MaskSpline *spline; + for (spline = masklay->splines.first; spline; spline = spline->next) { + int i; + for (i = 0; i < spline->tot_point; i++) { + mask_layer_shape_to_mask_point(&spline->points[i].bezt, fp); + fp += MASK_OBJECT_SHAPE_ELEM_SIZE; + } + } + } + else { + printf("%s: vert mismatch %d != %d (frame %d)\n", + __func__, masklay_shape->tot_vert, tot, masklay_shape->frame); + } +} + +BLI_INLINE void interp_v2_v2v2_flfl(float target[2], const float a[2], const float b[2], + const float t, const float s) +{ + target[0] = s * a[0] + t * b[0]; + target[1] = s * a[1] + t * b[1]; +} + +/* linear interpolation only */ +void BKE_mask_layer_shape_to_mask_interp(MaskLayer *masklay, + MaskLayerShape *masklay_shape_a, + MaskLayerShape *masklay_shape_b, + const float fac) +{ + int tot = BKE_mask_layer_shape_totvert(masklay); + if (masklay_shape_a->tot_vert == tot && masklay_shape_b->tot_vert == tot) { + float *fp_a = masklay_shape_a->data; + float *fp_b = masklay_shape_b->data; + const float ifac = 1.0f - fac; + + MaskSpline *spline; + for (spline = masklay->splines.first; spline; spline = spline->next) { + int i; + for (i = 0; i < spline->tot_point; i++) { + BezTriple *bezt = &spline->points[i].bezt; + /* *** BKE_mask_layer_shape_from_mask - swapped *** */ + interp_v2_v2v2_flfl(bezt->vec[0], fp_a, fp_b, fac, ifac); fp_a += 2; fp_b += 2; + interp_v2_v2v2_flfl(bezt->vec[1], fp_a, fp_b, fac, ifac); fp_a += 2; fp_b += 2; + interp_v2_v2v2_flfl(bezt->vec[2], fp_a, fp_b, fac, ifac); fp_a += 2; fp_b += 2; + bezt->weight = (fp_a[0] * ifac) + (fp_b[0] * fac); + bezt->radius = (fp_a[1] * ifac) + (fp_b[1] * fac); fp_a += 2; fp_b += 2; + } + } + } + else { + printf("%s: vert mismatch %d != %d != %d (frame %d - %d)\n", + __func__, masklay_shape_a->tot_vert, masklay_shape_b->tot_vert, tot, + masklay_shape_a->frame, masklay_shape_b->frame); + } +} + +MaskLayerShape *BKE_mask_layer_shape_find_frame(MaskLayer *masklay, int frame) +{ + MaskLayerShape *masklay_shape; + + for (masklay_shape = masklay->splines_shapes.first; + masklay_shape; + masklay_shape = masklay_shape->next) + { + if (frame == masklay_shape->frame) { + return masklay_shape; + } + else if (frame < masklay_shape->frame) { + break; + } + } + + return NULL; +} + +/* when returning 2 - the frame isnt found but before/after frames are */ +int BKE_mask_layer_shape_find_frame_range(MaskLayer *masklay, int frame, + MaskLayerShape **r_masklay_shape_a, + MaskLayerShape **r_masklay_shape_b) +{ + MaskLayerShape *masklay_shape; + + for (masklay_shape = masklay->splines_shapes.first; + masklay_shape; + masklay_shape = masklay_shape->next) + { + if (frame == masklay_shape->frame) { + *r_masklay_shape_a = masklay_shape; + *r_masklay_shape_b = NULL; + return 1; + } + else if (frame < masklay_shape->frame) { + if (masklay_shape->prev) { + *r_masklay_shape_a = masklay_shape->prev; + *r_masklay_shape_b = masklay_shape; + return 2; + } + else { + *r_masklay_shape_a = masklay_shape; + *r_masklay_shape_b = NULL; + return 1; + } + } + } + + *r_masklay_shape_a = NULL; + *r_masklay_shape_b = NULL; + + return 0; +} + +MaskLayerShape *BKE_mask_layer_shape_varify_frame(MaskLayer *masklay, int frame) +{ + MaskLayerShape *masklay_shape; + + masklay_shape = BKE_mask_layer_shape_find_frame(masklay, frame); + + if (masklay_shape == NULL) { + int tot_vert = BKE_mask_layer_shape_totvert(masklay); + + masklay_shape = MEM_mallocN(sizeof(MaskLayerShape), __func__); + masklay_shape->frame = frame; + masklay_shape->tot_vert = tot_vert; + masklay_shape->data = MEM_mallocN(tot_vert * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE, __func__); + + BLI_addtail(&masklay->splines_shapes, masklay_shape); + + BKE_mask_layer_shape_sort(masklay); + } + +#if 0 + { + MaskLayerShape *masklay_shape; + int i = 0; + for (masklay_shape = masklay->splines_shapes.first; + masklay_shape; + masklay_shape = masklay_shape->next) + { + printf("mask %d, %d\n", i++, masklay_shape->frame); + } + } +#endif + + return masklay_shape; +} + +void BKE_mask_layer_shape_unlink(MaskLayer *masklay, MaskLayerShape *masklay_shape) +{ + BLI_remlink(&masklay->splines_shapes, masklay_shape); + + BKE_mask_layer_shape_free(masklay_shape); +} + +static int mask_layer_shape_sort_cb(void *masklay_shape_a_ptr, void *masklay_shape_b_ptr) +{ + MaskLayerShape *masklay_shape_a = (MaskLayerShape *)masklay_shape_a_ptr; + MaskLayerShape *masklay_shape_b = (MaskLayerShape *)masklay_shape_b_ptr; + + if (masklay_shape_a->frame < masklay_shape_b->frame) return -1; + else if (masklay_shape_a->frame > masklay_shape_b->frame) return 1; + else return 0; +} + +void BKE_mask_layer_shape_sort(MaskLayer *masklay) +{ + BLI_sortlist(&masklay->splines_shapes, mask_layer_shape_sort_cb); +} + +int BKE_mask_layer_shape_spline_from_index(MaskLayer *masklay, int index, + MaskSpline **r_masklay_shape, int *r_index) +{ + MaskSpline *spline; + + for (spline = masklay->splines.first; spline; spline = spline->next) { + if (index < spline->tot_point) { + *r_masklay_shape = spline; + *r_index = index; + return TRUE; + } + index -= spline->tot_point; + } + + return FALSE; +} + +int BKE_mask_layer_shape_spline_to_index(MaskLayer *masklay, MaskSpline *spline) +{ + MaskSpline *spline_iter; + int i_abs = 0; + for (spline_iter = masklay->splines.first; + spline_iter && spline_iter != spline; + i_abs += spline_iter->tot_point, spline_iter = spline_iter->next) + { + /* pass */ + } + + return i_abs; +} + +/* basic 2D interpolation functions, could make more comprehensive later */ +static void interp_weights_uv_v2_calc(float r_uv[2], const float pt[2], const float pt_a[2], const float pt_b[2]) +{ + float pt_on_line[2]; + r_uv[0] = closest_to_line_v2(pt_on_line, pt, pt_a, pt_b); + r_uv[1] = (len_v2v2(pt_on_line, pt) / len_v2v2(pt_a, pt_b)) * + ((line_point_side_v2(pt_a, pt_b, pt) < 0.0f) ? -1.0 : 1.0); /* this line only sets the sign */ +} + + +static void interp_weights_uv_v2_apply(const float uv[2], float r_pt[2], const float pt_a[2], const float pt_b[2]) +{ + const float dvec[2] = {pt_b[0] - pt_a[0], + pt_b[1] - pt_a[1]}; + + /* u */ + madd_v2_v2v2fl(r_pt, pt_a, dvec, uv[0]); + + /* v */ + r_pt[0] += -dvec[1] * uv[1]; + r_pt[1] += dvec[0] * uv[1]; +} + +/* when a now points added - resize all shapekey array */ +void BKE_mask_layer_shape_changed_add(MaskLayer *masklay, int index, + int do_init, int do_init_interpolate) +{ + MaskLayerShape *masklay_shape; + + /* spline index from masklay */ + MaskSpline *spline; + int spline_point_index; + + if (BKE_mask_layer_shape_spline_from_index(masklay, index, + &spline, &spline_point_index)) + { + /* sanity check */ + /* the point has already been removed in this array so subtract one when comparing with the shapes */ + int tot = BKE_mask_layer_shape_totvert(masklay) - 1; + + /* for interpolation */ + /* TODO - assumes closed curve for now */ + float uv[3][2]; /* 3x 2D handles */ + const int pi_curr = spline_point_index; + const int pi_prev = ((spline_point_index - 1) + spline->tot_point) % spline->tot_point; + const int pi_next = (spline_point_index + 1) % spline->tot_point; + + const int index_offset = index - spline_point_index; + /* const int pi_curr_abs = index; */ + const int pi_prev_abs = pi_prev + index_offset; + const int pi_next_abs = pi_next + index_offset; + + int i; + if (do_init_interpolate) { + for (i = 0; i < 3; i++) { + interp_weights_uv_v2_calc(uv[i], + spline->points[pi_curr].bezt.vec[i], + spline->points[pi_prev].bezt.vec[i], + spline->points[pi_next].bezt.vec[i]); + } + } + + for (masklay_shape = masklay->splines_shapes.first; + masklay_shape; + masklay_shape = masklay_shape->next) + { + if (tot == masklay_shape->tot_vert) { + float *data_resized; + + masklay_shape->tot_vert++; + data_resized = MEM_mallocN(masklay_shape->tot_vert * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE, __func__); + if (index > 0) { + memcpy(data_resized, + masklay_shape->data, + index * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE); + } + + if (index != masklay_shape->tot_vert - 1) { + memcpy(&data_resized[(index + 1) * MASK_OBJECT_SHAPE_ELEM_SIZE], + masklay_shape->data + (index * MASK_OBJECT_SHAPE_ELEM_SIZE), + (masklay_shape->tot_vert - (index + 1)) * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE); + } + + if (do_init) { + float *fp = &data_resized[index * MASK_OBJECT_SHAPE_ELEM_SIZE]; + + mask_layer_shape_from_mask_point(&spline->points[spline_point_index].bezt, fp); + + if (do_init_interpolate && spline->tot_point > 2) { + for (i = 0; i < 3; i++) { + interp_weights_uv_v2_apply(uv[i], + &fp[i * 2], + &data_resized[(pi_prev_abs * MASK_OBJECT_SHAPE_ELEM_SIZE) + (i * 2)], + &data_resized[(pi_next_abs * MASK_OBJECT_SHAPE_ELEM_SIZE) + (i * 2)]); + } + } + } + else { + memset(&data_resized[index * MASK_OBJECT_SHAPE_ELEM_SIZE], + 0, + sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE); + } + + MEM_freeN(masklay_shape->data); + masklay_shape->data = data_resized; + } + else { + printf("%s: vert mismatch %d != %d (frame %d)\n", + __func__, masklay_shape->tot_vert, tot, masklay_shape->frame); + } + } + } +} + + +/* move array to account for removed point */ +void BKE_mask_layer_shape_changed_remove(MaskLayer *masklay, int index, int count) +{ + MaskLayerShape *masklay_shape; + + /* the point has already been removed in this array so add one when comparing with the shapes */ + int tot = BKE_mask_layer_shape_totvert(masklay); + + for (masklay_shape = masklay->splines_shapes.first; + masklay_shape; + masklay_shape = masklay_shape->next) + { + if (tot == masklay_shape->tot_vert - count) { + float *data_resized; + + masklay_shape->tot_vert -= count; + data_resized = MEM_mallocN(masklay_shape->tot_vert * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE, __func__); + if (index > 0) { + memcpy(data_resized, + masklay_shape->data, + index * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE); + } + + if (index != masklay_shape->tot_vert) { + memcpy(&data_resized[index * MASK_OBJECT_SHAPE_ELEM_SIZE], + masklay_shape->data + ((index + count) * MASK_OBJECT_SHAPE_ELEM_SIZE), + (masklay_shape->tot_vert - index) * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE); + } + + MEM_freeN(masklay_shape->data); + masklay_shape->data = data_resized; + } + else { + printf("%s: vert mismatch %d != %d (frame %d)\n", + __func__, masklay_shape->tot_vert - count, tot, masklay_shape->frame); + } + } +} + +/* local functions */ +static void invert_vn_vn(float *array, const int size) +{ + float *arr = array + (size - 1); + int i = size; + while (i--) { + *(arr) = 1.0f - *(arr); + arr--; + } +} + +static void m_invert_vn_vn(float *array, const float f, const int size) +{ + float *arr = array + (size - 1); + int i = size; + while (i--) { + *(arr) = 1.0f - (*(arr) * f); + arr--; + } +} + +static void linear_clamp_vn_vn(float *array, const int size) +{ + float *arr = array + (size - 1); + + int i = size; + while (i--) { + if (*arr <= 0.0f) *arr = 0.0f; + else if (*arr >= 1.0f) *arr = 1.0f; + else *arr = srgb_to_linearrgb(*arr); + arr--; + } +} + +/* rasterization */ +void BKE_mask_rasterize(Mask *mask, int width, int height, float *buffer) +{ + MaskLayer *masklay; + + /* temp blending buffer */ + const int buffer_size = width * height; + float *buffer_tmp = MEM_mallocN(sizeof(float) * buffer_size, __func__); + float max_dseg_len = 0.0f; + + if (width >= height) { + max_dseg_len = (float)(width); + } + else { + max_dseg_len = (float)(height); + } + max_dseg_len = 1.0f / max_dseg_len; + + for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { + MaskSpline *spline; + float alpha; + + if (masklay->restrictflag & MASK_RESTRICT_RENDER) { + continue; + } + + memset(buffer_tmp, 0, sizeof(float) * buffer_size); + + for (spline = masklay->splines.first; spline; spline = spline->next) { + float (*diff_points)[2]; + int tot_diff_point; + + float (*diff_feather_points)[2]; + int tot_diff_feather_points; + + diff_points = BKE_mask_spline_differentiate_with_resolution(spline, width, height, &tot_diff_point); + if (tot_diff_point) { + diff_feather_points = + BKE_mask_spline_feather_differentiated_points_with_resolution(spline, width, height, + &tot_diff_feather_points); + } + + /* TODO, make this optional! */ + if (width != height) { + float *fp; + float *ffp; + int i; + float asp; + + if (width < height) { + fp = &diff_points[0][0]; + ffp = &diff_feather_points[0][0]; + asp = (float)width / (float)height; + } + else { + fp = &diff_points[0][1]; + ffp = &diff_feather_points[0][1]; + asp = (float)height / (float)width; + } + + for (i = 0; i < tot_diff_point; i++, fp += 2) { + (*fp) = (((*fp) - 0.5f) / asp) + 0.5f; + } + for (i = 0; i < tot_diff_feather_points; i++, ffp += 2) { + (*ffp) = (((*ffp) - 0.5f) / asp) + 0.5f; + } + } + + if (tot_diff_point) { + PLX_raskterize((float (*)[2])diff_points, tot_diff_point, + buffer_tmp, width, height); + + if (tot_diff_feather_points) { + PLX_raskterize_feather((float (*)[2])diff_points, tot_diff_point, + (float (*)[2])diff_feather_points, tot_diff_feather_points, + buffer_tmp, width, height); + MEM_freeN(diff_feather_points); + } + + MEM_freeN(diff_points); + } + } + + /* blend with original */ + if (masklay->blend_flag & MASK_BLENDFLAG_INVERT) { + /* apply alpha multiply before inverting */ + if (masklay->alpha != 1.0f) { + m_invert_vn_vn(buffer_tmp, masklay->alpha, buffer_size); + } + else { + invert_vn_vn(buffer_tmp, buffer_size); + } + + alpha = 1.0f; + } + else { + alpha = masklay->alpha; + } + + switch (masklay->blend) { + case MASK_BLEND_SUBTRACT: + { + if (alpha == 1.0f) { + sub_vn_vn(buffer, buffer_tmp, buffer_size); + } + else { + msub_vn_vn(buffer, buffer_tmp, alpha, buffer_size); + } + break; + } + case MASK_BLEND_ADD: + default: + { + if (alpha == 1.0f) { + add_vn_vn(buffer, buffer_tmp, buffer_size); + } + else { + madd_vn_vn(buffer, buffer_tmp, alpha, buffer_size); + } + break; + } + } + + /* clamp at the end */ + linear_clamp_vn_vn(buffer, buffer_size); + } + + MEM_freeN(buffer_tmp); +} |