Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/transform/transform_convert_curve.c
- This file was added.
| /* | |||||
| * 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_curve_types.h" | |||||
| #include "MEM_guardedalloc.h" | |||||
| #include "BLI_math.h" | |||||
| #include "BKE_context.h" | |||||
| #include "BKE_curve.h" | |||||
| #include "BKE_report.h" | |||||
| #include "transform.h" | |||||
| #include "transform_convert.h" | |||||
| /* -------------------------------------------------------------------- */ | |||||
| /** \name Curve/Surfaces Transform Creation | |||||
| * | |||||
| * \{ */ | |||||
| /** | |||||
| * For the purpose of transform code we need to behave as if handles are selected, | |||||
| * even when they aren't (see special case below). | |||||
| */ | |||||
| static int bezt_select_to_transform_triple_flag(const BezTriple *bezt, const bool hide_handles) | |||||
| { | |||||
| int flag = 0; | |||||
| if (hide_handles) { | |||||
| if (bezt->f2 & SELECT) { | |||||
| flag = (1 << 0) | (1 << 1) | (1 << 2); | |||||
| } | |||||
| } | |||||
| else { | |||||
| flag = (((bezt->f1 & SELECT) ? (1 << 0) : 0) | ((bezt->f2 & SELECT) ? (1 << 1) : 0) | | |||||
| ((bezt->f3 & SELECT) ? (1 << 2) : 0)); | |||||
| } | |||||
| /* Special case for auto & aligned handles: | |||||
| * When a center point is being moved without the handles, | |||||
| * leaving the handles stationary makes no sense and only causes strange behavior, | |||||
| * where one handle is arbitrarily anchored, the other one is aligned and lengthened | |||||
| * based on where the center point is moved. Also a bug when cancelling, see: T52007. | |||||
| * | |||||
| * A more 'correct' solution could be to store handle locations in 'TransDataCurveHandleFlags'. | |||||
| * However that doesn't resolve odd behavior, so best transform the handles in this case. | |||||
| */ | |||||
| if ((flag != ((1 << 0) | (1 << 1) | (1 << 2))) && (flag & (1 << 1))) { | |||||
| if (ELEM(bezt->h1, HD_AUTO, HD_ALIGN) && ELEM(bezt->h2, HD_AUTO, HD_ALIGN)) { | |||||
| flag = (1 << 0) | (1 << 1) | (1 << 2); | |||||
| } | |||||
| } | |||||
| return flag; | |||||
| } | |||||
| void createTransCurveVerts(TransInfo *t) | |||||
| { | |||||
| #define SEL_F1 (1 << 0) | |||||
| #define SEL_F2 (1 << 1) | |||||
| #define SEL_F3 (1 << 2) | |||||
| t->data_len_all = 0; | |||||
| FOREACH_TRANS_DATA_CONTAINER (t, tc) { | |||||
| Curve *cu = tc->obedit->data; | |||||
| BLI_assert(cu->editnurb != NULL); | |||||
| BezTriple *bezt; | |||||
| BPoint *bp; | |||||
| int a; | |||||
| int count = 0, countsel = 0; | |||||
| const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0; | |||||
| View3D *v3d = t->view; | |||||
| short hide_handles = (v3d != NULL) ? | |||||
| ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) : | |||||
| false; | |||||
| /* count total of vertices, check identical as in 2nd loop for making transdata! */ | |||||
| ListBase *nurbs = BKE_curve_editNurbs_get(cu); | |||||
| for (Nurb *nu = nurbs->first; nu; nu = nu->next) { | |||||
| if (nu->type == CU_BEZIER) { | |||||
| for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) { | |||||
| if (bezt->hide == 0) { | |||||
| const int bezt_tx = bezt_select_to_transform_triple_flag(bezt, hide_handles); | |||||
| if (bezt_tx & SEL_F1) { | |||||
| countsel++; | |||||
| } | |||||
| if (bezt_tx & SEL_F2) { | |||||
| countsel++; | |||||
| } | |||||
| if (bezt_tx & SEL_F3) { | |||||
| countsel++; | |||||
| } | |||||
| if (is_prop_edit) { | |||||
| count += 3; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| else { | |||||
| for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) { | |||||
| if (bp->hide == 0) { | |||||
| if (is_prop_edit) { | |||||
| count++; | |||||
| } | |||||
| if (bp->f1 & SELECT) { | |||||
| countsel++; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| /* note: in prop mode we need at least 1 selected */ | |||||
| if (countsel == 0) { | |||||
| tc->data_len = 0; | |||||
| continue; | |||||
| } | |||||
| if (is_prop_edit) { | |||||
| tc->data_len = count; | |||||
| } | |||||
| else { | |||||
| tc->data_len = countsel; | |||||
| } | |||||
| tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Curve EditMode)"); | |||||
| t->data_len_all += tc->data_len; | |||||
| } | |||||
| transform_around_single_fallback(t); | |||||
| t->data_len_all = -1; | |||||
| FOREACH_TRANS_DATA_CONTAINER (t, tc) { | |||||
| if (tc->data_len == 0) { | |||||
| continue; | |||||
| } | |||||
| Curve *cu = tc->obedit->data; | |||||
| BezTriple *bezt; | |||||
| BPoint *bp; | |||||
| int a; | |||||
| const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0; | |||||
| View3D *v3d = t->view; | |||||
| short hide_handles = (v3d != NULL) ? | |||||
| ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) : | |||||
| false; | |||||
| float mtx[3][3], smtx[3][3]; | |||||
| copy_m3_m4(mtx, tc->obedit->obmat); | |||||
| pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON); | |||||
| TransData *td = tc->data; | |||||
| ListBase *nurbs = BKE_curve_editNurbs_get(cu); | |||||
| for (Nurb *nu = nurbs->first; nu; nu = nu->next) { | |||||
| if (nu->type == CU_BEZIER) { | |||||
| TransData *head, *tail; | |||||
| head = tail = td; | |||||
| for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) { | |||||
| if (bezt->hide == 0) { | |||||
| TransDataCurveHandleFlags *hdata = NULL; | |||||
| float axismtx[3][3]; | |||||
| if (t->around == V3D_AROUND_LOCAL_ORIGINS) { | |||||
| float normal[3], plane[3]; | |||||
| BKE_nurb_bezt_calc_normal(nu, bezt, normal); | |||||
| BKE_nurb_bezt_calc_plane(nu, bezt, plane); | |||||
| if (createSpaceNormalTangent(axismtx, normal, plane)) { | |||||
| /* pass */ | |||||
| } | |||||
| else { | |||||
| normalize_v3(normal); | |||||
| axis_dominant_v3_to_m3(axismtx, normal); | |||||
| invert_m3(axismtx); | |||||
| } | |||||
| } | |||||
| /* Elements that will be transform (not always a match to selection). */ | |||||
| const int bezt_tx = bezt_select_to_transform_triple_flag(bezt, hide_handles); | |||||
| if (is_prop_edit || bezt_tx & SEL_F1) { | |||||
| copy_v3_v3(td->iloc, bezt->vec[0]); | |||||
| td->loc = bezt->vec[0]; | |||||
| copy_v3_v3(td->center, | |||||
| bezt->vec[(hide_handles || (t->around == V3D_AROUND_LOCAL_ORIGINS) || | |||||
| (bezt->f2 & SELECT)) ? | |||||
| 1 : | |||||
| 0]); | |||||
| if (hide_handles) { | |||||
| if (bezt->f2 & SELECT) { | |||||
| td->flag = TD_SELECTED; | |||||
| } | |||||
| else { | |||||
| td->flag = 0; | |||||
| } | |||||
| } | |||||
| else { | |||||
| if (bezt->f1 & SELECT) { | |||||
| td->flag = TD_SELECTED; | |||||
| } | |||||
| else { | |||||
| td->flag = 0; | |||||
| } | |||||
| } | |||||
| td->ext = NULL; | |||||
| td->val = NULL; | |||||
| hdata = initTransDataCurveHandles(td, bezt); | |||||
| copy_m3_m3(td->smtx, smtx); | |||||
| copy_m3_m3(td->mtx, mtx); | |||||
| if (t->around == V3D_AROUND_LOCAL_ORIGINS) { | |||||
| copy_m3_m3(td->axismtx, axismtx); | |||||
| } | |||||
| td++; | |||||
| tail++; | |||||
| } | |||||
| /* This is the Curve Point, the other two are handles */ | |||||
| if (is_prop_edit || bezt_tx & SEL_F2) { | |||||
| copy_v3_v3(td->iloc, bezt->vec[1]); | |||||
| td->loc = bezt->vec[1]; | |||||
| copy_v3_v3(td->center, td->loc); | |||||
| if (bezt->f2 & SELECT) { | |||||
| td->flag = TD_SELECTED; | |||||
| } | |||||
| else { | |||||
| td->flag = 0; | |||||
| } | |||||
| td->ext = NULL; | |||||
| /* TODO - make points scale */ | |||||
| if (t->mode == TFM_CURVE_SHRINKFATTEN) { /* || t->mode==TFM_RESIZE) {*/ | |||||
| td->val = &(bezt->radius); | |||||
| td->ival = bezt->radius; | |||||
| } | |||||
| else if (t->mode == TFM_TILT) { | |||||
| td->val = &(bezt->tilt); | |||||
| td->ival = bezt->tilt; | |||||
| } | |||||
| else { | |||||
| td->val = NULL; | |||||
| } | |||||
| copy_m3_m3(td->smtx, smtx); | |||||
| copy_m3_m3(td->mtx, mtx); | |||||
| if (t->around == V3D_AROUND_LOCAL_ORIGINS) { | |||||
| copy_m3_m3(td->axismtx, axismtx); | |||||
| } | |||||
| if ((bezt_tx & SEL_F1) == 0 && (bezt_tx & SEL_F3) == 0) { | |||||
| /* If the middle is selected but the sides arnt, this is needed */ | |||||
| if (hdata == NULL) { | |||||
| /* if the handle was not saved by the previous handle */ | |||||
| hdata = initTransDataCurveHandles(td, bezt); | |||||
| } | |||||
| } | |||||
| td++; | |||||
| tail++; | |||||
| } | |||||
| if (is_prop_edit || bezt_tx & SEL_F3) { | |||||
| copy_v3_v3(td->iloc, bezt->vec[2]); | |||||
| td->loc = bezt->vec[2]; | |||||
| copy_v3_v3(td->center, | |||||
| bezt->vec[(hide_handles || (t->around == V3D_AROUND_LOCAL_ORIGINS) || | |||||
| (bezt->f2 & SELECT)) ? | |||||
| 1 : | |||||
| 2]); | |||||
| if (hide_handles) { | |||||
| if (bezt->f2 & SELECT) { | |||||
| td->flag = TD_SELECTED; | |||||
| } | |||||
| else { | |||||
| td->flag = 0; | |||||
| } | |||||
| } | |||||
| else { | |||||
| if (bezt->f3 & SELECT) { | |||||
| td->flag = TD_SELECTED; | |||||
| } | |||||
| else { | |||||
| td->flag = 0; | |||||
| } | |||||
| } | |||||
| td->ext = NULL; | |||||
| td->val = NULL; | |||||
| if (hdata == NULL) { | |||||
| /* if the handle was not saved by the previous handle */ | |||||
| hdata = initTransDataCurveHandles(td, bezt); | |||||
| } | |||||
| copy_m3_m3(td->smtx, smtx); | |||||
| copy_m3_m3(td->mtx, mtx); | |||||
| if (t->around == V3D_AROUND_LOCAL_ORIGINS) { | |||||
| copy_m3_m3(td->axismtx, axismtx); | |||||
| } | |||||
| td++; | |||||
| tail++; | |||||
| } | |||||
| (void)hdata; /* quiet warning */ | |||||
| } | |||||
| else if (is_prop_edit && head != tail) { | |||||
| calc_distanceCurveVerts(head, tail - 1); | |||||
| head = tail; | |||||
| } | |||||
| } | |||||
| if (is_prop_edit && head != tail) { | |||||
| calc_distanceCurveVerts(head, tail - 1); | |||||
| } | |||||
| /* TODO - in the case of tilt and radius we can also avoid allocating the | |||||
| * initTransDataCurveHandles but for now just don't change handle types */ | |||||
| if (ELEM(t->mode, TFM_CURVE_SHRINKFATTEN, TFM_TILT, TFM_DUMMY) == 0) { | |||||
| /* sets the handles based on their selection, | |||||
| * do this after the data is copied to the TransData */ | |||||
| BKE_nurb_handles_test(nu, !hide_handles); | |||||
| } | |||||
| } | |||||
| else { | |||||
| TransData *head, *tail; | |||||
| head = tail = td; | |||||
| for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) { | |||||
| if (bp->hide == 0) { | |||||
| if (is_prop_edit || (bp->f1 & SELECT)) { | |||||
| float axismtx[3][3]; | |||||
| if (t->around == V3D_AROUND_LOCAL_ORIGINS) { | |||||
| if (nu->pntsv == 1) { | |||||
| float normal[3], plane[3]; | |||||
| BKE_nurb_bpoint_calc_normal(nu, bp, normal); | |||||
| BKE_nurb_bpoint_calc_plane(nu, bp, plane); | |||||
| if (createSpaceNormalTangent(axismtx, normal, plane)) { | |||||
| /* pass */ | |||||
| } | |||||
| else { | |||||
| normalize_v3(normal); | |||||
| axis_dominant_v3_to_m3(axismtx, normal); | |||||
| invert_m3(axismtx); | |||||
| } | |||||
| } | |||||
| } | |||||
| copy_v3_v3(td->iloc, bp->vec); | |||||
| td->loc = bp->vec; | |||||
| copy_v3_v3(td->center, td->loc); | |||||
| if (bp->f1 & SELECT) { | |||||
| td->flag = TD_SELECTED; | |||||
| } | |||||
| else { | |||||
| td->flag = 0; | |||||
| } | |||||
| td->ext = NULL; | |||||
| if (t->mode == TFM_CURVE_SHRINKFATTEN || t->mode == TFM_RESIZE) { | |||||
| td->val = &(bp->radius); | |||||
| td->ival = bp->radius; | |||||
| } | |||||
| else { | |||||
| td->val = &(bp->tilt); | |||||
| td->ival = bp->tilt; | |||||
| } | |||||
| copy_m3_m3(td->smtx, smtx); | |||||
| copy_m3_m3(td->mtx, mtx); | |||||
| if (t->around == V3D_AROUND_LOCAL_ORIGINS) { | |||||
| if (nu->pntsv == 1) { | |||||
| copy_m3_m3(td->axismtx, axismtx); | |||||
| } | |||||
| } | |||||
| td++; | |||||
| tail++; | |||||
| } | |||||
| } | |||||
| else if (is_prop_edit && head != tail) { | |||||
| calc_distanceCurveVerts(head, tail - 1); | |||||
| head = tail; | |||||
| } | |||||
| } | |||||
| if (is_prop_edit && head != tail) { | |||||
| calc_distanceCurveVerts(head, tail - 1); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| #undef SEL_F1 | |||||
| #undef SEL_F2 | |||||
| #undef SEL_F3 | |||||
| } | |||||
| /** \} */ | |||||