From 4e731ec97bd4b689a725f4bdcd49ab1f5c68c12c Mon Sep 17 00:00:00 2001 From: mano-wii Date: Thu, 5 Sep 2019 14:34:54 -0300 Subject: Transform: Split transform_conversions into multiple files. Part of T68836 `transform conversions.c` is a file that is getting too big (almost 10,000 lines). So it's a good idea to split it into smaller files. differential revision: https://developer.blender.org/D5677 --- .../editors/transform/transform_convert_action.c | 575 +++++++++++++++++++++ 1 file changed, 575 insertions(+) create mode 100644 source/blender/editors/transform/transform_convert_action.c (limited to 'source/blender/editors/transform/transform_convert_action.c') diff --git a/source/blender/editors/transform/transform_convert_action.c b/source/blender/editors/transform/transform_convert_action.c new file mode 100644 index 00000000000..0b1d2757435 --- /dev/null +++ b/source/blender/editors/transform/transform_convert_action.c @@ -0,0 +1,575 @@ +/* + * 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) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup edtransform + */ + +#include "DNA_anim_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_mask_types.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_rect.h" + +#include "BKE_nla.h" +#include "BKE_context.h" +#include "BKE_report.h" + +#include "ED_anim_api.h" + +#include "UI_view2d.h" + +#include "transform.h" +#include "transform_convert.h" + +/* helper struct for gp-frame transforms */ +typedef struct tGPFtransdata { + float val; /* where transdata writes transform */ + int *sdata; /* pointer to gpf->framenum */ +} tGPFtransdata; + +/* -------------------------------------------------------------------- */ +/** \name Action Transform Creation + * + * \{ */ + +/* fully select selected beztriples, but only include if it's on the right side of cfra */ +static int count_fcurve_keys(FCurve *fcu, char side, float cfra, bool is_prop_edit) +{ + BezTriple *bezt; + int i, count = 0, count_all = 0; + + if (ELEM(NULL, fcu, fcu->bezt)) { + return count; + } + + /* only include points that occur on the right side of cfra */ + for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) { + if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) { + /* no need to adjust the handle selection since they are assumed + * selected (like graph editor with SIPO_NOHANDLES) */ + if (bezt->f2 & SELECT) { + count++; + } + + count_all++; + } + } + + if (is_prop_edit && count > 0) { + return count_all; + } + else { + return count; + } +} + +/* fully select selected beztriples, but only include if it's on the right side of cfra */ +static int count_gplayer_frames(bGPDlayer *gpl, char side, float cfra, bool is_prop_edit) +{ + bGPDframe *gpf; + int count = 0, count_all = 0; + + if (gpl == NULL) { + return count; + } + + /* only include points that occur on the right side of cfra */ + for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { + if (FrameOnMouseSide(side, (float)gpf->framenum, cfra)) { + if (gpf->flag & GP_FRAME_SELECT) { + count++; + } + count_all++; + } + } + + if (is_prop_edit && count > 0) { + return count_all; + } + else { + return count; + } +} + +/* fully select selected beztriples, but only include if it's on the right side of cfra */ +static int count_masklayer_frames(MaskLayer *masklay, char side, float cfra, bool is_prop_edit) +{ + MaskLayerShape *masklayer_shape; + int count = 0, count_all = 0; + + if (masklay == NULL) { + return count; + } + + /* only include points that occur on the right side of cfra */ + for (masklayer_shape = masklay->splines_shapes.first; masklayer_shape; + masklayer_shape = masklayer_shape->next) { + if (FrameOnMouseSide(side, (float)masklayer_shape->frame, cfra)) { + if (masklayer_shape->flag & MASK_SHAPE_SELECT) { + count++; + } + count_all++; + } + } + + if (is_prop_edit && count > 0) { + return count_all; + } + else { + return count; + } +} + +/* This function assigns the information to transdata */ +static void TimeToTransData(TransData *td, float *time, AnimData *adt, float ypos) +{ + /* memory is calloc'ed, so that should zero everything nicely for us */ + td->val = time; + td->ival = *(time); + + td->center[0] = td->ival; + td->center[1] = ypos; + + /* store the AnimData where this keyframe exists as a keyframe of the + * active action as td->extra. + */ + td->extra = adt; +} + +/* This function advances the address to which td points to, so it must return + * the new address so that the next time new transform data is added, it doesn't + * overwrite the existing ones... i.e. td = IcuToTransData(td, icu, ob, side, cfra); + * + * The 'side' argument is needed for the extend mode. 'B' = both sides, 'R'/'L' mean only data + * on the named side are used. + */ +static TransData *ActionFCurveToTransData(TransData *td, + TransData2D **td2dv, + FCurve *fcu, + AnimData *adt, + char side, + float cfra, + bool is_prop_edit, + float ypos) +{ + BezTriple *bezt; + TransData2D *td2d = *td2dv; + int i; + + if (ELEM(NULL, fcu, fcu->bezt)) { + return td; + } + + for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) { + /* only add selected keyframes (for now, proportional edit is not enabled) */ + if (is_prop_edit || (bezt->f2 & SELECT)) { /* note this MUST match count_fcurve_keys(), + * so can't use BEZT_ISSEL_ANY() macro */ + /* only add if on the right 'side' of the current frame */ + if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) { + TimeToTransData(td, bezt->vec[1], adt, ypos); + + if (bezt->f2 & SELECT) { + td->flag |= TD_SELECTED; + } + + /*set flags to move handles as necessary*/ + td->flag |= TD_MOVEHANDLE1 | TD_MOVEHANDLE2; + td2d->h1 = bezt->vec[0]; + td2d->h2 = bezt->vec[2]; + + copy_v2_v2(td2d->ih1, td2d->h1); + copy_v2_v2(td2d->ih2, td2d->h2); + + td++; + td2d++; + } + } + } + + *td2dv = td2d; + + return td; +} + +/* This function advances the address to which td points to, so it must return + * the new address so that the next time new transform data is added, it doesn't + * overwrite the existing ones... i.e. td = GPLayerToTransData(td, ipo, ob, side, cfra); + * + * The 'side' argument is needed for the extend mode. 'B' = both sides, 'R'/'L' mean only data + * on the named side are used. + */ +static int GPLayerToTransData(TransData *td, + tGPFtransdata *tfd, + bGPDlayer *gpl, + char side, + float cfra, + bool is_prop_edit, + float ypos) +{ + bGPDframe *gpf; + int count = 0; + + /* check for select frames on right side of current frame */ + for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { + if (is_prop_edit || (gpf->flag & GP_FRAME_SELECT)) { + if (FrameOnMouseSide(side, (float)gpf->framenum, cfra)) { + /* memory is calloc'ed, so that should zero everything nicely for us */ + td->val = &tfd->val; + td->ival = (float)gpf->framenum; + + td->center[0] = td->ival; + td->center[1] = ypos; + + tfd->val = (float)gpf->framenum; + tfd->sdata = &gpf->framenum; + + /* advance td now */ + td++; + tfd++; + count++; + } + } + } + + return count; +} + +/* refer to comment above #GPLayerToTransData, this is the same but for masks */ +static int MaskLayerToTransData(TransData *td, + tGPFtransdata *tfd, + MaskLayer *masklay, + char side, + float cfra, + bool is_prop_edit, + float ypos) +{ + MaskLayerShape *masklay_shape; + int count = 0; + + /* check for select frames on right side of current frame */ + for (masklay_shape = masklay->splines_shapes.first; masklay_shape; + masklay_shape = masklay_shape->next) { + if (is_prop_edit || (masklay_shape->flag & MASK_SHAPE_SELECT)) { + if (FrameOnMouseSide(side, (float)masklay_shape->frame, cfra)) { + /* memory is calloc'ed, so that should zero everything nicely for us */ + td->val = &tfd->val; + td->ival = (float)masklay_shape->frame; + + td->center[0] = td->ival; + td->center[1] = ypos; + + tfd->val = (float)masklay_shape->frame; + tfd->sdata = &masklay_shape->frame; + + /* advance td now */ + td++; + tfd++; + count++; + } + } + } + + return count; +} + +void createTransActionData(bContext *C, TransInfo *t) +{ + Scene *scene = t->scene; + TransData *td = NULL; + TransData2D *td2d = NULL; + tGPFtransdata *tfd = NULL; + + rcti *mask = &t->ar->v2d.mask; + rctf *datamask = &t->ar->v2d.cur; + + float xsize = BLI_rctf_size_x(datamask); + float ysize = BLI_rctf_size_y(datamask); + float xmask = BLI_rcti_size_x(mask); + float ymask = BLI_rcti_size_y(mask); + + bAnimContext ac; + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0; + + int count = 0; + float cfra; + float ypos = 1.0f / ((ysize / xsize) * (xmask / ymask)) * BLI_rctf_cent_y(&t->ar->v2d.cur); + + /* determine what type of data we are operating on */ + if (ANIM_animdata_get_context(C, &ac) == 0) { + return; + } + + /* filter data */ + if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) { + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT); + } + else { + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/); + } + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + + /* which side of the current frame should be allowed */ + if (t->mode == TFM_TIME_EXTEND) { + /* only side on which mouse is gets transformed */ + float xmouse, ymouse; + + UI_view2d_region_to_view(&ac.ar->v2d, t->mouse.imval[0], t->mouse.imval[1], &xmouse, &ymouse); + t->frame_side = (xmouse > CFRA) ? 'R' : 'L'; // XXX use t->frame_side + } + else { + /* normal transform - both sides of current frame are considered */ + t->frame_side = 'B'; + } + + /* loop 1: fully select ipo-keys and count how many BezTriples are selected */ + for (ale = anim_data.first; ale; ale = ale->next) { + AnimData *adt = ANIM_nla_mapping_get(&ac, ale); + int adt_count = 0; + /* convert current-frame to action-time (slightly less accurate, especially under + * higher scaling ratios, but is faster than converting all points) + */ + if (adt) { + cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP); + } + else { + cfra = (float)CFRA; + } + + if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) { + adt_count = count_fcurve_keys(ale->key_data, t->frame_side, cfra, is_prop_edit); + } + else if (ale->type == ANIMTYPE_GPLAYER) { + adt_count = count_gplayer_frames(ale->data, t->frame_side, cfra, is_prop_edit); + } + else if (ale->type == ANIMTYPE_MASKLAYER) { + adt_count = count_masklayer_frames(ale->data, t->frame_side, cfra, is_prop_edit); + } + else { + BLI_assert(0); + } + + if (adt_count > 0) { + count += adt_count; + ale->tag = true; + } + } + + /* stop if trying to build list if nothing selected */ + if (count == 0) { + /* cleanup temp list */ + ANIM_animdata_freelist(&anim_data); + return; + } + + TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t); + + /* allocate memory for data */ + tc->data_len = count; + + tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData(Action Editor)"); + tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "transdata2d"); + td = tc->data; + td2d = tc->data_2d; + + if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) { + tc->custom.type.data = tfd = MEM_callocN(sizeof(tGPFtransdata) * count, "tGPFtransdata"); + tc->custom.type.use_free = true; + } + + /* loop 2: build transdata array */ + for (ale = anim_data.first; ale; ale = ale->next) { + + if (is_prop_edit && !ale->tag) { + continue; + } + + cfra = (float)CFRA; + + { + AnimData *adt; + adt = ANIM_nla_mapping_get(&ac, ale); + if (adt) { + cfra = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP); + } + } + + if (ale->type == ANIMTYPE_GPLAYER) { + bGPDlayer *gpl = (bGPDlayer *)ale->data; + int i; + + i = GPLayerToTransData(td, tfd, gpl, t->frame_side, cfra, is_prop_edit, ypos); + td += i; + tfd += i; + } + else if (ale->type == ANIMTYPE_MASKLAYER) { + MaskLayer *masklay = (MaskLayer *)ale->data; + int i; + + i = MaskLayerToTransData(td, tfd, masklay, t->frame_side, cfra, is_prop_edit, ypos); + td += i; + tfd += i; + } + else { + AnimData *adt = ANIM_nla_mapping_get(&ac, ale); + FCurve *fcu = (FCurve *)ale->key_data; + + td = ActionFCurveToTransData(td, &td2d, fcu, adt, t->frame_side, cfra, is_prop_edit, ypos); + } + } + + /* calculate distances for proportional editing */ + if (is_prop_edit) { + td = tc->data; + + for (ale = anim_data.first; ale; ale = ale->next) { + AnimData *adt; + + /* F-Curve may not have any keyframes */ + if (!ale->tag) { + continue; + } + + adt = ANIM_nla_mapping_get(&ac, ale); + if (adt) { + cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP); + } + else { + cfra = (float)CFRA; + } + + if (ale->type == ANIMTYPE_GPLAYER) { + bGPDlayer *gpl = (bGPDlayer *)ale->data; + bGPDframe *gpf; + + for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { + if (gpf->flag & GP_FRAME_SELECT) { + td->dist = td->rdist = 0.0f; + } + else { + bGPDframe *gpf_iter; + int min = INT_MAX; + for (gpf_iter = gpl->frames.first; gpf_iter; gpf_iter = gpf_iter->next) { + if (gpf_iter->flag & GP_FRAME_SELECT) { + if (FrameOnMouseSide(t->frame_side, (float)gpf_iter->framenum, cfra)) { + int val = abs(gpf->framenum - gpf_iter->framenum); + if (val < min) { + min = val; + } + } + } + } + td->dist = td->rdist = min; + } + td++; + } + } + else if (ale->type == ANIMTYPE_MASKLAYER) { + MaskLayer *masklay = (MaskLayer *)ale->data; + MaskLayerShape *masklay_shape; + + for (masklay_shape = masklay->splines_shapes.first; masklay_shape; + masklay_shape = masklay_shape->next) { + if (FrameOnMouseSide(t->frame_side, (float)masklay_shape->frame, cfra)) { + if (masklay_shape->flag & MASK_SHAPE_SELECT) { + td->dist = td->rdist = 0.0f; + } + else { + MaskLayerShape *masklay_iter; + int min = INT_MAX; + for (masklay_iter = masklay->splines_shapes.first; masklay_iter; + masklay_iter = masklay_iter->next) { + if (masklay_iter->flag & MASK_SHAPE_SELECT) { + if (FrameOnMouseSide(t->frame_side, (float)masklay_iter->frame, cfra)) { + int val = abs(masklay_shape->frame - masklay_iter->frame); + if (val < min) { + min = val; + } + } + } + } + td->dist = td->rdist = min; + } + td++; + } + } + } + else { + FCurve *fcu = (FCurve *)ale->key_data; + BezTriple *bezt; + int i; + + for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) { + if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) { + if (bezt->f2 & SELECT) { + td->dist = td->rdist = 0.0f; + } + else { + BezTriple *bezt_iter; + int j; + float min = FLT_MAX; + for (j = 0, bezt_iter = fcu->bezt; j < fcu->totvert; j++, bezt_iter++) { + if (bezt_iter->f2 & SELECT) { + if (FrameOnMouseSide(t->frame_side, (float)bezt_iter->vec[1][0], cfra)) { + float val = fabs(bezt->vec[1][0] - bezt_iter->vec[1][0]); + if (val < min) { + min = val; + } + } + } + } + td->dist = td->rdist = min; + } + td++; + } + } + } + } + } + + /* cleanup temp list */ + ANIM_animdata_freelist(&anim_data); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Action Transform Flush + * + * \{ */ + +/* This function helps flush transdata written to tempdata into the gp-frames */ +void flushTransIntFrameActionData(TransInfo *t) +{ + TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t); + tGPFtransdata *tfd = tc->custom.type.data; + + /* flush data! */ + for (int i = 0; i < tc->data_len; i++, tfd++) { + *(tfd->sdata) = round_fl_to_int(tfd->val); + } +} + +/** \} */ -- cgit v1.2.3