This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/editors/util/ed_transverts.c
Germano Cavalcante f674976edd Curve: Remove 'CU_2D' flag used for nurbs
This fixes T86440

As the CU_2D flag is set for nurbs, a Curve can have 2D nurbs mixed with 3D.

But the UI does not allow this mixing. It updates all nurbs to 2D or 3D when set.

So remove this specific flag for nurbs.

This may break old files, since 2D curves with mixed 3D are now set as 3D.

Differential Revision: https://developer.blender.org/D10738
2021-04-01 10:54:49 -03:00

525 lines
15 KiB
C

/*
* 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 edutil
*/
#include "MEM_guardedalloc.h"
#include "DNA_armature_types.h"
#include "DNA_curve_types.h"
#include "DNA_lattice_types.h"
#include "DNA_meta_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BKE_DerivedMesh.h"
#include "BKE_armature.h"
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_editmesh.h"
#include "BKE_lattice.h"
#include "BKE_mesh_iterators.h"
#include "DEG_depsgraph.h"
#include "ED_armature.h"
#include "ED_transverts.h" /* own include */
/* copied from editobject.c, now uses (almost) proper depgraph */
void ED_transverts_update_obedit(TransVertStore *tvs, Object *obedit)
{
const int mode = tvs->mode;
BLI_assert(ED_transverts_check_obedit(obedit) == true);
DEG_id_tag_update(obedit->data, 0);
if (obedit->type == OB_MESH) {
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BM_mesh_normals_update(em->bm);
}
else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
Curve *cu = obedit->data;
ListBase *nurbs = BKE_curve_editNurbs_get(cu);
Nurb *nu = nurbs->first;
while (nu) {
/* keep handles' vectors unchanged */
if (nu->bezt && (mode & TM_SKIP_HANDLES)) {
int a = nu->pntsu;
TransVert *tv = tvs->transverts;
BezTriple *bezt = nu->bezt;
while (a--) {
if (bezt->hide == 0) {
bool skip_handle = false;
if (bezt->f2 & SELECT) {
skip_handle = (mode & TM_SKIP_HANDLES) != 0;
}
if ((bezt->f1 & SELECT) && !skip_handle) {
BLI_assert(tv->loc == bezt->vec[0]);
tv++;
}
if (bezt->f2 & SELECT) {
float v[3];
if (((bezt->f1 & SELECT) && !skip_handle) == 0) {
sub_v3_v3v3(v, tv->loc, tv->oldloc);
add_v3_v3(bezt->vec[0], v);
}
if (((bezt->f3 & SELECT) && !skip_handle) == 0) {
sub_v3_v3v3(v, tv->loc, tv->oldloc);
add_v3_v3(bezt->vec[2], v);
}
BLI_assert(tv->loc == bezt->vec[1]);
tv++;
}
if ((bezt->f3 & SELECT) && !skip_handle) {
BLI_assert(tv->loc == bezt->vec[2]);
tv++;
}
}
bezt++;
}
}
if (CU_IS_2D(cu)) {
BKE_nurb_project_2d(nu);
}
BKE_nurb_handles_test(nu, true, false); /* test for bezier too */
nu = nu->next;
}
}
else if (obedit->type == OB_ARMATURE) {
bArmature *arm = obedit->data;
EditBone *ebo;
TransVert *tv = tvs->transverts;
int a = 0;
/* Ensure all bone tails are correctly adjusted */
for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
/* adjust tip if both ends selected */
if ((ebo->flag & BONE_ROOTSEL) && (ebo->flag & BONE_TIPSEL)) {
if (tv) {
float diffvec[3];
sub_v3_v3v3(diffvec, tv->loc, tv->oldloc);
add_v3_v3(ebo->tail, diffvec);
a++;
if (a < tvs->transverts_tot) {
tv++;
}
}
}
}
/* Ensure all bones are correctly adjusted */
for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
if ((ebo->flag & BONE_CONNECTED) && ebo->parent) {
/* If this bone has a parent tip that has been moved */
if (ebo->parent->flag & BONE_TIPSEL) {
copy_v3_v3(ebo->head, ebo->parent->tail);
}
/* If this bone has a parent tip that has NOT been moved */
else {
copy_v3_v3(ebo->parent->tail, ebo->head);
}
}
}
if (arm->flag & ARM_MIRROR_EDIT) {
ED_armature_edit_transform_mirror_update(obedit);
}
}
else if (obedit->type == OB_LATTICE) {
Lattice *lt = obedit->data;
if (lt->editlatt->latt->flag & LT_OUTSIDE) {
outside_lattice(lt->editlatt->latt);
}
}
}
static void set_mapped_co(void *vuserdata,
int index,
const float co[3],
const float UNUSED(no[3]),
const short UNUSED(no_s[3]))
{
void **userdata = vuserdata;
BMEditMesh *em = userdata[0];
TransVert *tv = userdata[1];
BMVert *eve = BM_vert_at_index(em->bm, index);
if (BM_elem_index_get(eve) != TM_INDEX_SKIP) {
tv = &tv[BM_elem_index_get(eve)];
/* be clever, get the closest vertex to the original,
* behaves most logically when the mirror modifier is used for eg T33051*/
if ((tv->flag & TX_VERT_USE_MAPLOC) == 0) {
/* first time */
copy_v3_v3(tv->maploc, co);
tv->flag |= TX_VERT_USE_MAPLOC;
}
else {
/* find best location to use */
if (len_squared_v3v3(eve->co, co) < len_squared_v3v3(eve->co, tv->maploc)) {
copy_v3_v3(tv->maploc, co);
}
}
}
}
bool ED_transverts_check_obedit(Object *obedit)
{
return (ELEM(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL));
}
void ED_transverts_create_from_obedit(TransVertStore *tvs, Object *obedit, const int mode)
{
Nurb *nu;
BezTriple *bezt;
BPoint *bp;
TransVert *tv = NULL;
MetaElem *ml;
BMVert *eve;
EditBone *ebo;
int a;
tvs->transverts_tot = 0;
if (obedit->type == OB_MESH) {
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;
BMIter iter;
void *userdata[2] = {em, NULL};
/*int proptrans = 0; */ /*UNUSED*/
/* abuses vertex index all over, set, just set dirty here,
* perhaps this could use its own array instead? - campbell */
/* transform now requires awareness for select mode, so we tag the f1 flags in verts */
tvs->transverts_tot = 0;
if (em->selectmode & SCE_SELECT_VERTEX) {
BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
BM_elem_index_set(eve, TM_INDEX_ON); /* set_dirty! */
tvs->transverts_tot++;
}
else {
BM_elem_index_set(eve, TM_INDEX_OFF); /* set_dirty! */
}
}
}
else if (em->selectmode & SCE_SELECT_EDGE) {
BMEdge *eed;
BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
BM_elem_index_set(eve, TM_INDEX_OFF); /* set_dirty! */
}
BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
BM_elem_index_set(eed->v1, TM_INDEX_ON); /* set_dirty! */
BM_elem_index_set(eed->v2, TM_INDEX_ON); /* set_dirty! */
}
}
BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
if (BM_elem_index_get(eve) == TM_INDEX_ON) {
tvs->transverts_tot++;
}
}
}
else {
BMFace *efa;
BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
BM_elem_index_set(eve, TM_INDEX_OFF); /* set_dirty! */
}
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
BMIter liter;
BMLoop *l;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
BM_elem_index_set(l->v, TM_INDEX_ON); /* set_dirty! */
}
}
}
BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
if (BM_elem_index_get(eve) == TM_INDEX_ON) {
tvs->transverts_tot++;
}
}
}
/* for any of the 3 loops above which all dirty the indices */
bm->elem_index_dirty |= BM_VERT;
/* and now make transverts */
if (tvs->transverts_tot) {
tv = tvs->transverts = MEM_callocN(tvs->transverts_tot * sizeof(TransVert), __func__);
a = 0;
BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
if (BM_elem_index_get(eve)) {
BM_elem_index_set(eve, a); /* set_dirty! */
copy_v3_v3(tv->oldloc, eve->co);
tv->loc = eve->co;
tv->flag = (BM_elem_index_get(eve) == TM_INDEX_ON) ? SELECT : 0;
if (mode & TM_CALC_NORMALS) {
tv->flag |= TX_VERT_USE_NORMAL;
copy_v3_v3(tv->normal, eve->no);
}
tv++;
a++;
}
else {
BM_elem_index_set(eve, TM_INDEX_SKIP); /* set_dirty! */
}
}
/* set dirty already, above */
userdata[1] = tvs->transverts;
}
if (tvs->transverts && em->mesh_eval_cage) {
BM_mesh_elem_table_ensure(bm, BM_VERT);
BKE_mesh_foreach_mapped_vert(em->mesh_eval_cage, set_mapped_co, userdata, MESH_FOREACH_NOP);
}
}
else if (obedit->type == OB_ARMATURE) {
bArmature *arm = obedit->data;
int totmalloc = BLI_listbase_count(arm->edbo);
totmalloc *= 2; /* probably overkill but bones can have 2 trans verts each */
tv = tvs->transverts = MEM_callocN(totmalloc * sizeof(TransVert), __func__);
for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
if (ebo->layer & arm->layer) {
const bool tipsel = (ebo->flag & BONE_TIPSEL) != 0;
const bool rootsel = (ebo->flag & BONE_ROOTSEL) != 0;
const bool rootok = (!(ebo->parent && (ebo->flag & BONE_CONNECTED) &&
(ebo->parent->flag & BONE_TIPSEL)));
if ((tipsel && rootsel) || (rootsel)) {
/* Don't add the tip (unless mode & TM_ALL_JOINTS, for getting all joints),
* otherwise we get zero-length bones as tips will snap to the same
* location as heads.
*/
if (rootok) {
copy_v3_v3(tv->oldloc, ebo->head);
tv->loc = ebo->head;
tv->flag = SELECT;
tv++;
tvs->transverts_tot++;
}
if ((mode & TM_ALL_JOINTS) && (tipsel)) {
copy_v3_v3(tv->oldloc, ebo->tail);
tv->loc = ebo->tail;
tv->flag = SELECT;
tv++;
tvs->transverts_tot++;
}
}
else if (tipsel) {
copy_v3_v3(tv->oldloc, ebo->tail);
tv->loc = ebo->tail;
tv->flag = SELECT;
tv++;
tvs->transverts_tot++;
}
}
}
}
else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
Curve *cu = obedit->data;
int totmalloc = 0;
ListBase *nurbs = BKE_curve_editNurbs_get(cu);
for (nu = nurbs->first; nu; nu = nu->next) {
if (nu->type == CU_BEZIER) {
totmalloc += 3 * nu->pntsu;
}
else {
totmalloc += nu->pntsu * nu->pntsv;
}
}
tv = tvs->transverts = MEM_callocN(totmalloc * sizeof(TransVert), __func__);
nu = nurbs->first;
while (nu) {
if (nu->type == CU_BEZIER) {
a = nu->pntsu;
bezt = nu->bezt;
while (a--) {
if (bezt->hide == 0) {
bool skip_handle = false;
if (bezt->f2 & SELECT) {
skip_handle = (mode & TM_SKIP_HANDLES) != 0;
}
if ((bezt->f1 & SELECT) && !skip_handle) {
copy_v3_v3(tv->oldloc, bezt->vec[0]);
tv->loc = bezt->vec[0];
tv->flag = bezt->f1 & SELECT;
if (mode & TM_CALC_NORMALS) {
tv->flag |= TX_VERT_USE_NORMAL;
BKE_nurb_bezt_calc_plane(nu, bezt, tv->normal);
}
tv++;
tvs->transverts_tot++;
}
if (bezt->f2 & SELECT) {
copy_v3_v3(tv->oldloc, bezt->vec[1]);
tv->loc = bezt->vec[1];
tv->flag = bezt->f2 & SELECT;
if (mode & TM_CALC_NORMALS) {
tv->flag |= TX_VERT_USE_NORMAL;
BKE_nurb_bezt_calc_plane(nu, bezt, tv->normal);
}
tv++;
tvs->transverts_tot++;
}
if ((bezt->f3 & SELECT) && !skip_handle) {
copy_v3_v3(tv->oldloc, bezt->vec[2]);
tv->loc = bezt->vec[2];
tv->flag = bezt->f3 & SELECT;
if (mode & TM_CALC_NORMALS) {
tv->flag |= TX_VERT_USE_NORMAL;
BKE_nurb_bezt_calc_plane(nu, bezt, tv->normal);
}
tv++;
tvs->transverts_tot++;
}
}
bezt++;
}
}
else {
a = nu->pntsu * nu->pntsv;
bp = nu->bp;
while (a--) {
if (bp->hide == 0) {
if (bp->f1 & SELECT) {
copy_v3_v3(tv->oldloc, bp->vec);
tv->loc = bp->vec;
tv->flag = bp->f1 & SELECT;
tv++;
tvs->transverts_tot++;
}
}
bp++;
}
}
nu = nu->next;
}
}
else if (obedit->type == OB_MBALL) {
MetaBall *mb = obedit->data;
int totmalloc = BLI_listbase_count(mb->editelems);
tv = tvs->transverts = MEM_callocN(totmalloc * sizeof(TransVert), __func__);
ml = mb->editelems->first;
while (ml) {
if (ml->flag & SELECT) {
tv->loc = &ml->x;
copy_v3_v3(tv->oldloc, tv->loc);
tv->flag = SELECT;
tv++;
tvs->transverts_tot++;
}
ml = ml->next;
}
}
else if (obedit->type == OB_LATTICE) {
Lattice *lt = obedit->data;
bp = lt->editlatt->latt->def;
a = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw;
tv = tvs->transverts = MEM_callocN(a * sizeof(TransVert), __func__);
while (a--) {
if (bp->f1 & SELECT) {
if (bp->hide == 0) {
copy_v3_v3(tv->oldloc, bp->vec);
tv->loc = bp->vec;
tv->flag = bp->f1 & SELECT;
tv++;
tvs->transverts_tot++;
}
}
bp++;
}
}
if (!tvs->transverts_tot && tvs->transverts) {
/* Prevent memory leak. happens for curves/lattices due to
* difficult condition of adding points to trans data. */
MEM_freeN(tvs->transverts);
tvs->transverts = NULL;
}
tvs->mode = mode;
}
void ED_transverts_free(TransVertStore *tvs)
{
MEM_SAFE_FREE(tvs->transverts);
tvs->transverts_tot = 0;
}
bool ED_transverts_poll(bContext *C)
{
Object *obedit = CTX_data_edit_object(C);
if (obedit) {
if (ED_transverts_check_obedit(obedit)) {
return true;
}
}
return false;
}