Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormano-wii <germano.costa@ig.com.br>2019-09-05 20:34:54 +0300
committermano-wii <germano.costa@ig.com.br>2019-09-05 20:35:38 +0300
commit4e731ec97bd4b689a725f4bdcd49ab1f5c68c12c (patch)
tree2d38d51d080bc50f6e0e9d4cdc9afb0895744140 /source/blender/editors/transform/transform_convert_action.c
parentc90b81172b30b15e4f2f9e6a9a454f1d177176ac (diff)
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
Diffstat (limited to 'source/blender/editors/transform/transform_convert_action.c')
-rw-r--r--source/blender/editors/transform/transform_convert_action.c575
1 files changed, 575 insertions, 0 deletions
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);
+ }
+}
+
+/** \} */